|
1 | 1 | function add_variables!(model, var::AbstractVariable)
|
2 |
| - var.id_hash == objectid(:constant) && |
3 |
| - error("Internal error: constant used as variable") |
4 |
| - return if sign(var) == ComplexSign() |
| 2 | + if sign(var) == ComplexSign() |
5 | 3 | L = MOI.add_variables(model, length(var))
|
6 | 4 | R = MOI.add_variables(model, length(var))
|
7 | 5 | return (L, R)
|
8 |
| - else |
9 |
| - return MOI.add_variables(model, length(var)) |
10 | 6 | end
|
| 7 | + return MOI.add_variables(model, length(var)) |
11 | 8 | end
|
12 | 9 |
|
13 | 10 | """
|
14 |
| - solve!(problem::Problem, optimizer_factory; |
| 11 | + solve!( |
| 12 | + problem::Problem, |
| 13 | + optimizer_factory; |
15 | 14 | silent_solver = false,
|
16 | 15 | )
|
17 | 16 |
|
18 |
| -Solves the problem, populating `problem.optval` with the optimal value, |
19 |
| -as well as the values of the variables (accessed by [`evaluate`](@ref)) |
20 |
| -and constraint duals (accessed by `cons.dual`), where applicable. |
| 17 | +Solves the problem, populating `problem.optval` with the optimal value, as well |
| 18 | +as the values of the variables (accessed by [`evaluate`](@ref)) and constraint |
| 19 | +duals (accessed by `cons.dual`), where applicable. |
| 20 | +
|
21 | 21 | Optional keyword arguments:
|
22 |
| -* `silent_solver`: whether the solver should be silent (and not emit output or logs) during the solution process. |
| 22 | +
|
| 23 | + * `silent_solver`: whether the solver should be silent (and not emit output or |
| 24 | + logs) during the solution process. |
23 | 25 | """
|
24 | 26 | function solve!(p::Problem, optimizer_factory; silent_solver = false)
|
25 |
| - context = Context(p, optimizer_factory) |
26 |
| - model = context.model |
27 |
| - |
28 |
| - if silent_solver |
29 |
| - MOI.set(model, MOI.Silent(), true) |
30 |
| - end |
31 |
| - |
32 |
| - # check DCPness |
33 | 27 | if problem_vexity(p) in (ConcaveVexity(), NotDcp())
|
34 | 28 | throw(DCPViolationError())
|
35 | 29 | end
|
36 |
| - |
| 30 | + context = Context(p, optimizer_factory) |
| 31 | + if silent_solver |
| 32 | + MOI.set(context.model, MOI.Silent(), true) |
| 33 | + end |
37 | 34 | if context.detected_infeasible_during_formulation[]
|
38 | 35 | p.status = MOI.INFEASIBLE
|
39 | 36 | else
|
40 |
| - MOI.optimize!(model) |
41 |
| - p.status = MOI.get(model, MOI.TerminationStatus()) |
| 37 | + MOI.optimize!(context.model) |
| 38 | + p.status = MOI.get(context.model, MOI.TerminationStatus()) |
42 | 39 | end
|
43 |
| - |
44 |
| - p.model = model |
45 |
| - |
| 40 | + p.model = context.model |
46 | 41 | if p.status != MOI.OPTIMAL
|
47 | 42 | @warn "Problem wasn't solved optimally" status = p.status
|
48 | 43 | end
|
49 |
| - |
50 |
| - dual_status = MOI.get(model, MOI.DualStatus()) |
51 |
| - primal_status = MOI.get(model, MOI.PrimalStatus()) |
52 |
| - |
53 |
| - var_to_indices = context.var_id_to_moi_indices |
54 |
| - id_to_variables = context.id_to_variables |
55 |
| - |
56 |
| - if primal_status != MOI.NO_SOLUTION |
57 |
| - for (id, var_indices) in var_to_indices |
58 |
| - var = id_to_variables[id] |
59 |
| - vexity(var) == ConstVexity() && continue |
60 |
| - if var_indices isa Tuple |
61 |
| - vectorized_value_re = |
62 |
| - MOI.get(model, MOI.VariablePrimal(), var_indices[1]) |
63 |
| - vectorized_value_im = |
64 |
| - MOI.get(model, MOI.VariablePrimal(), var_indices[2]) |
65 |
| - set_value!( |
66 |
| - var, |
67 |
| - unpackvec(vectorized_value_re, size(var), false) + |
68 |
| - im * unpackvec(vectorized_value_im, size(var), false), |
69 |
| - ) |
70 |
| - else |
71 |
| - vectorized_value = |
72 |
| - MOI.get(model, MOI.VariablePrimal(), var_indices) |
73 |
| - set_value!( |
74 |
| - var, |
75 |
| - unpackvec( |
76 |
| - vectorized_value, |
77 |
| - size(var), |
78 |
| - iscomplex(sign(var)), |
79 |
| - ), |
80 |
| - ) |
81 |
| - end |
82 |
| - end |
83 |
| - else |
84 |
| - for (id, var_indices) in var_to_indices |
85 |
| - var = id_to_variables[id] |
86 |
| - vexity(var) == ConstVexity() && continue |
| 44 | + primal_status = MOI.get(context.model, MOI.PrimalStatus()) |
| 45 | + for (id, indices) in context.var_id_to_moi_indices |
| 46 | + var = context.id_to_variables[id] |
| 47 | + if vexity(var) == ConstVexity() |
| 48 | + continue # Fixed variable |
| 49 | + elseif primal_status == MOI.NO_SOLUTION |
87 | 50 | set_value!(var, nothing)
|
| 51 | + elseif indices isa Tuple # Complex-valued variable |
| 52 | + primal_re = MOI.get(p.model, MOI.VariablePrimal(), indices[1]) |
| 53 | + primal_im = MOI.get(p.model, MOI.VariablePrimal(), indices[2]) |
| 54 | + set_value!( |
| 55 | + var, |
| 56 | + _unpack_vector(primal_re, size(var)) + |
| 57 | + im * _unpack_vector(primal_im, size(var)), |
| 58 | + ) |
| 59 | + else |
| 60 | + @assert !iscomplex(sign(var)) |
| 61 | + primal = MOI.get(p.model, MOI.VariablePrimal(), indices) |
| 62 | + set_value!(var, _unpack_vector(primal, size(var))) |
88 | 63 | end
|
89 | 64 | end
|
90 |
| - |
91 |
| - if dual_status != MOI.NO_SOLUTION |
92 |
| - for (constr, MOI_constr_indices) in pairs(context.constr_to_moi_inds) |
93 |
| - populate_dual!(model, constr, MOI_constr_indices) |
94 |
| - end |
95 |
| - else |
96 |
| - # Empty duals |
97 |
| - for constr in keys(context.constr_to_moi_inds) |
98 |
| - constr.dual = nothing |
| 65 | + dual_status = MOI.get(context.model, MOI.DualStatus()) |
| 66 | + for (c, indices) in context.constr_to_moi_inds |
| 67 | + if dual_status == MOI.NO_SOLUTION |
| 68 | + c.dual = nothing |
| 69 | + else |
| 70 | + populate_dual!(context.model, c, indices) |
99 | 71 | end
|
100 | 72 | end
|
101 |
| - |
102 |
| - return nothing |
| 73 | + return |
103 | 74 | end
|
104 | 75 |
|
105 |
| -function populate_dual!(model::MOI.ModelLike, constr::Constraint, ::Nothing) |
106 |
| - constr.dual = nothing |
107 |
| - return nothing |
| 76 | +function populate_dual!(::MOI.ModelLike, c::Constraint, ::Nothing) |
| 77 | + # If the Constraint does not support `populate_dual!` it must return |
| 78 | + # `nothing` from `_add_constraint!`. |
| 79 | + c.dual = nothing |
| 80 | + return |
108 | 81 | end
|
109 | 82 |
|
110 |
| -# This is type unstable! |
111 |
| -function unpackvec(v::AbstractVector, size::Tuple{Int,Int}, iscomplex::Bool) |
112 |
| - if iscomplex && length(v) == 2 |
113 |
| - return v[1] + im * v[2] |
114 |
| - elseif iscomplex |
115 |
| - l = length(v) ÷ 2 |
116 |
| - # use views? |
117 |
| - return reshape(v[1:l], size) + im * reshape(v[l+1:end], size) |
118 |
| - elseif length(v) == 1 |
| 83 | +function _unpack_vector(v::AbstractVector, size::Tuple{Int,Int}) |
| 84 | + if length(v) == 1 |
119 | 85 | return v[]
|
120 |
| - else |
121 |
| - return reshape(v, size) |
122 | 86 | end
|
| 87 | + return reshape(v, size) |
123 | 88 | end
|
0 commit comments