@@ -3,12 +3,36 @@ defaultmethod() = :Logarithmic
3
3
4
4
type PWLData
5
5
counter:: Int
6
- PWLData () = new (0 )
6
+ branchvars:: Vector{Int}
7
+ PWLData () = new (0 ,Int[])
7
8
end
8
9
9
10
function initPWL! (m:: JuMP.Model )
10
11
if ! haskey (m. ext, :PWL )
11
12
m. ext[:PWL ] = PWLData ()
13
+ JuMP. setsolvehook (m, function solvehook (m; kwargs... )
14
+ if ! isempty (m. ext[:PWL ]. branchvars)
15
+ JuMP. build (m)
16
+ function branchcallback (d:: MathProgBase.MathProgCallbackData )
17
+ state = MathProgBase. cbgetstate (d)
18
+ if state == :MIPSol
19
+ MathProgBase. cbgetmipsolution (d,m. colVal)
20
+ else
21
+ MathProgBase. cbgetlpsolution (d,m. colVal)
22
+ end
23
+ moment_curve_branch_callback (m, d)
24
+ end
25
+ CPLEX. setbranchcallback! (m. internalModel, branchcallback)
26
+ function incumbentcallback (d:: MathProgBase.MathProgCallbackData )
27
+ state = MathProgBase. cbgetstate (d)
28
+ @assert state == :MIPIncumbent
29
+ m. colVal = copy (d. sol)
30
+ moment_curve_incumbent_callback (m, d)
31
+ end
32
+ CPLEX. setincumbentcallback! (m. internalModel, incumbentcallback)
33
+ end
34
+ JuMP. solve (m; ignore_solve_hook= true , kwargs... )
35
+ end )
12
36
end
13
37
nothing
14
38
end
@@ -76,8 +100,8 @@ function piecewiselinear(m::JuMP.Model, x::JuMP.Variable, pwl::UnivariatePWLFunc
76
100
sos2_symmetric_celaya_formulation! (m, λ)
77
101
elseif method == :SOS2
78
102
JuMP. addSOS2 (m, [i* λ[i] for i in 1 : n])
79
- else
80
- error ( " Unrecognized method $method " )
103
+ elseif method == :MomentCurve
104
+ sos2_moment_curve_formulation! (m, λ )
81
105
end
82
106
end
83
107
z
@@ -575,3 +599,65 @@ function piecewiselinear(m::JuMP.Model, x₁::JuMP.Variable, x₂::JuMP.Variable
575
599
end
576
600
z
577
601
end
602
+
603
+ function sos2_moment_curve_formulation! (m:: JuMP.Model , λ)
604
+ counter = m. ext[:PWL ]. counter
605
+ d = length (λ)- 1
606
+ y = JuMP. @variable (m, [i= 1 : 2 ], Int, lowerbound= 1 , upperbound= d^ i, basename= " y_$counter " )
607
+ for i in 1 : d
608
+ JuMP. @constraints (m, begin
609
+ - 2 i* λ[1 ] + sum ((v^ 2 - (2 i+ 1 )* v+ 2 min (0 ,i+ 1 - v))* λ[v] for v in 2 : d) + (d^ 2 - (2 i+ 1 )* d)λ[d+ 1 ] ≤ - (2 i+ 1 )* y[1 ] + y[2 ]
610
+ - 2 i* λ[1 ] + sum ((v^ 2 - (2 i+ 1 )* v+ 2 max (0 ,i+ 1 - v))* λ[v] for v in 2 : d) + (d^ 2 - (2 i+ 1 )* d)λ[d+ 1 ] ≥ - (2 i+ 1 )* y[1 ] + y[2 ]
611
+ end )
612
+ end
613
+ push! (m. ext[:PWL ]. branchvars, JuMP. linearindex (y[1 ]))
614
+ nothing
615
+ end
616
+
617
+ function sos2_moment_curve_formulation! (m:: JuMP.Model , λ)
618
+ counter = m. ext[:PWL ]. counter
619
+ d = length (λ)- 1
620
+ y = JuMP. @variable (m, [i= 1 : 2 ], Int, lowerbound= 1 , upperbound= d^ i, basename= " y_$counter " )
621
+ for i in 1 : d
622
+ JuMP. @constraints (m, begin
623
+ - 2 i* λ[1 ] + sum ((v^ 2 - (2 i+ 1 )* v+ 2 min (0 ,i+ 1 - v))* λ[v] for v in 2 : d) + (d^ 2 - (2 i+ 1 )* d)λ[d+ 1 ] ≤ - (2 i+ 1 )* y[1 ] + y[2 ]
624
+ - 2 i* λ[1 ] + sum ((v^ 2 - (2 i+ 1 )* v+ 2 max (0 ,i+ 1 - v))* λ[v] for v in 2 : d) + (d^ 2 - (2 i+ 1 )* d)λ[d+ 1 ] ≥ - (2 i+ 1 )* y[1 ] + y[2 ]
625
+ end )
626
+ end
627
+ push! (m. ext[:PWL ]. branchvars, JuMP. linearindex (y[1 ]))
628
+ nothing
629
+ end
630
+
631
+ function moment_curve_branch_callback (m, cb)
632
+ # if CPLEX was gonna branch anyway, just use their branching decision
633
+ if ! isempty (cb. nodes)
634
+ unsafe_store! (cb. userinteraction_p, Cint (0 ))
635
+ return nothing
636
+ end
637
+ xval = MathProgBase. cbgetlpsolution (cb)
638
+ TOL = 1e-4
639
+ for i in branchvars
640
+ if (ceil (xval[i]) - xval[i] > TOL) && (xval[i]- floor (xval[i]) > TOL)
641
+ branch_ind = i
642
+ y = [JuMP. Variable (m, i), JuMP. Variable (m, i+ 1 )]
643
+ break
644
+ end
645
+ end
646
+ l, u = MathProgBase. cbgetnodelb (cb), MathProgBase. cbgetnodeub (cb)
647
+ uᶠ, lᶜ = floor (xval[branch_id]), ceil (xval[branch_id])
648
+ addbranch (cb, (uᶠ- l )* (y[2 ]- l ^ 2 ) ≤ (uᶠ^ 2 - l ^ 2 )* (y[1 ]- l ))
649
+ addbranch (cb, (u - lᶜ)* (y[2 ]- lᶜ^ 2 ) ≤ (u ^ 2 - lᶜ^ 2 )* (y[1 ]- lᶜ))
650
+ nothing
651
+ end
652
+
653
+ function moment_curve_incumbent_callback (m, cb)
654
+ xval = MathProgBase. cbgetmipsolution (cb)
655
+ for i in m. ext[:PWL ]. branchvars
656
+ if ! isapprox (xval[i]^ 2 , xval[i+ 1 ], rtol= 1e-4 )
657
+ CPLEX. rejectincumbent (cb)
658
+ return nothing
659
+ end
660
+ end
661
+ CPLEX. acceptincumbent (cb)
662
+ return nothing
663
+ end
0 commit comments