Skip to content

Commit

Permalink
Update tuto custom data (#962)
Browse files Browse the repository at this point in the history
* update customer data tuto

* mineure

---------
  • Loading branch information
najaverzat authored Jul 4, 2023
1 parent dea2220 commit fd9ba7b
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 30 deletions.
51 changes: 22 additions & 29 deletions docs/src/start/custom_data.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# # [Custom Variables and Cuts](@id tuto_custom_data)
#
# Coluna allows users to attach custom data to variables and constraints.
# This data are useful to store information about the variable or constraint in a custom
# This data is useful to store information about the variables or constraints in a custom
# format much easier to process than extracted information from the formulation
# (coefficient matrix, bounds, costs, and right-hand side).
#
Expand Down Expand Up @@ -42,43 +42,39 @@ coluna = JuMP.optimizer_with_attributes(
)
);

# ## Modelling for identical subproblems
#

# Let's define the model.
# Let's $B$ the set of bins and $I$ the set of items.
# We introduce variable $y_b$ that is equal to 1 if a bin $b$ is used and 0 otherwise.
# We introduce variable $x_{b,i}$ that is equal to 1 if item $i$ is put in a bin $b$ and 0 otherwise.
#
# This is a special case of Dantzig-Wolfe decomposition because there is one subproblem per bin.
# However, bins are identical so we are going to use the multiplicity feature of the decomposition

model = BlockModel(coluna);

# We must assign three items.
# We must assign three items:
I = [1, 2, 3];

# Since we use multiplicity, `B` will represent the type of bins.
# So here, we declare one type of bin only.
# And we have three bins:
B = [1, 2, 3];

@axis(B, [1]);
# Each bin is defining a subproblem, we declare our axis:
@axis(axis, collect(B));

# We declare variable `y[b]`. Its value in the model will be the aggregation of its value for
# all bins of type `b`. So here, if we use three bins of type 1, `y[1]` will be equal to 3.
# We declare subproblem variables `y[b]`:

@variable(model, y[b in B], Bin);
@variable(model, y[b in axis], Bin);

# Same with variable `x[b,i]`, its value in the model is the aggregation of its value for all bins of type `b`
# And `x[b,i]`:

@variable(model, x[b in B, i in I], Bin);
@variable(model, x[b in axis, i in I], Bin);

# Each item must be assigned to one bin.
# Each item must be assigned to one bin:

@constraint(model, sp[i in I], sum(x[b,i] for b in B) == 1);
@constraint(model, sp[i in I], sum(x[b,i] for b in axis) == 1);

# We minimize the number of bins and we declare the decomposition.
# We minimize the number of bins and we declare the decomposition:

@objective(model, Min, sum(y[b] for b in B))
@dantzig_wolfe_decomposition(model, dec, B);
@objective(model, Min, sum(y[b] for b in axis))
@dantzig_wolfe_decomposition(model, dec, axis);


# ## Custom data for non-robust cuts
Expand All @@ -88,7 +84,7 @@ I = [1, 2, 3];
# containing one pair `(1,2)`, `(1, 3)`, or `(2, 3)` of items.
# We are going to introduce the following non-robust cut to make the master LP solution integral:

# $$sum_{s in S if length(s) >= 2} λ_s <= 1$$
# $$\sum\limits_{s \in S~if~length(s) \geq 2} λ_s \leq 1$$
#
# where :
# - $S$ is the set of possible bin assignments generated by the pricing problem.
Expand Down Expand Up @@ -132,7 +128,7 @@ function Coluna.MathProg.computecoeff(
return (var_custom_data.nb_items >= constr_custom_data.min_items) ? 1.0 : 0.0
end

# ## Pricing callback and subproblem multiplicity
# ## Pricing callback

# We define the pricing callback that will generate the bin with best-reduced cost.
# Be careful, when using non-robust cuts, you must take into account the contribution of the
Expand All @@ -142,6 +138,7 @@ function my_pricing_callback(cbdata)
## Get the reduced costs of the original variables.
I = [1, 2, 3]
b = BlockDecomposition.callback_spid(cbdata, model)

rc_y = BlockDecomposition.callback_reduced_cost(cbdata, y[b])
rc_x = [BlockDecomposition.callback_reduced_cost(cbdata, x[b, i]) for i in I]

Expand Down Expand Up @@ -172,6 +169,7 @@ function my_pricing_callback(cbdata)
best_s = s
end
end
@show best_s
## build the best one and submit
solcost = best_rc
solvars = JuMP.VariableRef[]
Expand All @@ -190,22 +188,17 @@ function my_pricing_callback(cbdata)
solvarvals,
MyCustomVarData(length(best_s)) # attach a custom data to the column
)

MOI.submit(model, BlockDecomposition.PricingDualBound(cbdata), solcost)
return
end

# The pricing callback is done, we define it as the solver of our pricing problem.
# We also specify that the lower multiplicity of the master problem is 0 and the upper
# multiplicity is 3. It means that the final solution to the problem can use a least 0 bin
# and at most 3 bins.

subproblems = BlockDecomposition.getsubproblems(dec)
BlockDecomposition.specify!.(
subproblems,
lower_multiplicity = 0,
upper_multiplicity = 3,
solver = my_pricing_callback
)
);


# ## Non-robust cut separation callback.
Expand Down
2 changes: 1 addition & 1 deletion docs/src/start/identical_sp.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# # Identical subproblems
# # [Identical subproblems](@id tuto_identical_sp)

# Let us see an example of resolution using the advantage of identical subproblems with Dantzig-Wolfe and a variant of the Generalized Assignment Problem.

Expand Down

0 comments on commit fd9ba7b

Please sign in to comment.