@@ -23,3 +23,218 @@ function MOI.set(o::Optimizer, attr::MOI.NLPBlock, data::MOI.NLPBlockData)
2323 end
2424 return nothing
2525end
26+
27+ # MOI.ScalarNonlinearFunction
28+
29+ function MOI. supports_constraint (
30+ :: Optimizer ,
31+ :: Type{MOI.ScalarNonlinearFunction} ,
32+ :: Type{S} ,
33+ ) where {S<: BOUNDS }
34+ return true
35+ end
36+
37+ function MOI. add_constraint (
38+ model:: Optimizer ,
39+ f:: MOI.ScalarNonlinearFunction ,
40+ s:: BOUNDS ,
41+ )
42+ allow_modification (model)
43+ expr = NonlinExpr ()
44+ root = _SCIPcreateExpr (model, f, expr)
45+ l, u = bounds (model, s)
46+ cons__ = Ref {Ptr{SCIP_CONS}} (C_NULL )
47+ @SCIP_CALL SCIPcreateConsBasicNonlinear (model, cons__, " " , root[], l, u)
48+ @SCIP_CALL SCIPaddCons (model, cons__[])
49+ push! (model. inner. nonlinear_storage, expr)
50+ cr = store_cons! (model. inner, cons__)
51+ ci = MOI. ConstraintIndex {MOI.ScalarNonlinearFunction,typeof(s)} (cr. val)
52+ register! (model, ci)
53+ register! (model, cons (model, ci), cr)
54+ return ci
55+ end
56+
57+ function _SCIPcreateExpr (model:: Optimizer , f:: Real , expr:: NonlinExpr )
58+ ret = Ref {Ptr{SCIP_EXPR}} (C_NULL )
59+ @SCIP_CALL SCIPcreateExprValue (model, ret, f, C_NULL , C_NULL )
60+ push! (expr. exprs, ret)
61+ return ret
62+ end
63+
64+ function _SCIPcreateExpr (
65+ model:: Optimizer ,
66+ f:: MOI.VariableIndex ,
67+ expr:: NonlinExpr ,
68+ )
69+ ret = Ref {Ptr{SCIP_EXPR}} (C_NULL )
70+ v = var (model, f)
71+ @SCIP_CALL SCIPcreateExprVar (model, ret, v, C_NULL , C_NULL )
72+ push! (expr. exprs, ret)
73+ return ret
74+ end
75+
76+ function _SCIPcreateExpr (
77+ model:: Optimizer ,
78+ f:: MOI.ScalarNonlinearFunction ,
79+ expr:: NonlinExpr ,
80+ )
81+ ret = Ref {Ptr{SCIP_EXPR}} (C_NULL )
82+ if f. head == :+
83+ children = map (arg -> _SCIPcreateExpr (model, arg, expr)[], f. args)
84+ @SCIP_CALL SCIPcreateExprSum (
85+ model,
86+ ret,
87+ length (f. args), # int nchildren
88+ children, # SCIP_EXPR **children,
89+ ones (Float64, length (f. args)), # SCIP_REAL *coefficients
90+ 0.0 , # SCIP_Real constant
91+ C_NULL ,
92+ C_NULL ,
93+ )
94+ elseif f. head == :*
95+ x = map (arg -> _SCIPcreateExpr (model, arg, expr)[], f. args)
96+ n = length (f. args)
97+ @SCIP_CALL SCIPcreateExprProduct (model, ret, n, x, 1.0 , C_NULL , C_NULL )
98+ elseif f. head == :/
99+ # Convert x / y --> x * y^-1
100+ @assert length (f. args) == 2
101+ xy = map (f. args) do arg
102+ return _SCIPcreateExpr (model, arg, expr)[]
103+ end
104+ ret_y = Ref {Ptr{SCIP_EXPR}} (C_NULL )
105+ @SCIP_CALL SCIPcreateExprPow (model, ret_y, xy[2 ], - 1 , C_NULL , C_NULL )
106+ @SCIP_CALL SCIPcreateExprProduct (model, ret, 2 , xy, 1.0 , C_NULL , C_NULL )
107+ elseif f. head == :-
108+ @assert 1 <= length (f. args) <= 2
109+ children = map (f. args) do arg
110+ return _SCIPcreateExpr (model, arg, expr)[]
111+ end
112+ n = length (f. args)
113+ coefficients = ones (Float64, n)
114+ coefficients[end ] = - 1.0
115+ @SCIP_CALL SCIPcreateExprSum (
116+ model,
117+ ret,
118+ n,
119+ children,
120+ coefficients,
121+ 0.0 ,
122+ C_NULL ,
123+ C_NULL ,
124+ )
125+ elseif f. head == :^
126+ @assert length (f. args) == 2
127+ if ! (f. args[2 ] isa Real)
128+ throw (MOI. UnsupportedNonlinearOperator (f. head))
129+ end
130+ child = _SCIPcreateExpr (model, first (f. args), expr)
131+ expon = convert (Float64, f. args[2 ])
132+ @SCIP_CALL SCIPcreateExprPow (model, ret, child[], expon, C_NULL , C_NULL )
133+ elseif f. head == :abs
134+ child = _SCIPcreateExpr (model, only (f. args), expr)
135+ @SCIP_CALL SCIPcreateExprAbs (model, ret, child[], C_NULL , C_NULL )
136+ elseif f. head == :exp
137+ child = _SCIPcreateExpr (model, only (f. args), expr)
138+ @SCIP_CALL SCIPcreateExprExp (model, ret, child[], C_NULL , C_NULL )
139+ elseif f. head == :log
140+ child = _SCIPcreateExpr (model, only (f. args), expr)
141+ @SCIP_CALL SCIPcreateExprLog (model, ret, child[], C_NULL , C_NULL )
142+ elseif f. head == :sin
143+ child = _SCIPcreateExpr (model, only (f. args), expr)
144+ @SCIP_CALL SCIPcreateExprSin (model, ret, child[], C_NULL , C_NULL )
145+ elseif f. head == :cos
146+ child = _SCIPcreateExpr (model, only (f. args), expr)
147+ @SCIP_CALL SCIPcreateExprCos (model, ret, child[], C_NULL , C_NULL )
148+ elseif f. head == :sqrt
149+ child = _SCIPcreateExpr (model, only (f. args), expr)
150+ @SCIP_CALL SCIPcreateExprPow (model, ret, child[], 0.5 , C_NULL , C_NULL )
151+ else
152+ throw (MOI. UnsupportedNonlinearOperator (f. head))
153+ end
154+ push! (expr. exprs, ret)
155+ return ret
156+ end
157+
158+ function _SCIPcreateExpr (
159+ model:: Optimizer ,
160+ f:: MOI.ScalarAffineFunction ,
161+ expr:: NonlinExpr ,
162+ )
163+ ret = Ref {Ptr{SCIP_EXPR}} (C_NULL )
164+ n = length (f. terms)
165+ children = map (f. terms) do term
166+ return _SCIPcreateExpr (model, term. variable, expr)[]
167+ end
168+ coefficients = map (f. terms) do term
169+ return convert (Float64, term. coefficient)
170+ end
171+ @SCIP_CALL SCIPcreateExprSum (
172+ model,
173+ ret,
174+ n,
175+ children,
176+ coefficients,
177+ f. constant,
178+ C_NULL ,
179+ C_NULL ,
180+ )
181+ push! (expr. exprs, ret)
182+ return ret
183+ end
184+
185+ function _SCIPcreateExpr (
186+ model:: Optimizer ,
187+ f:: MOI.ScalarQuadraticFunction ,
188+ expr:: NonlinExpr ,
189+ )
190+ ret = Ref {Ptr{SCIP_EXPR}} (C_NULL )
191+ children = map (f. affine_terms) do term
192+ return _SCIPcreateExpr (model, term. variable, expr)[]
193+ end
194+ coefficients = map (f. affine_terms) do term
195+ return convert (Float64, term. coefficient)
196+ end
197+ for term in f. quadratic_terms
198+ ret_xy = Ref {Ptr{SCIP_EXPR}} (C_NULL )
199+ x = _SCIPcreateExpr (model, term. variable_1, expr)
200+ y = _SCIPcreateExpr (model, term. variable_2, expr)
201+ scale = ifelse (term. variable_1 == term. variable_2, 0.5 , 1.0 )
202+ @SCIP_CALL SCIPcreateExprProduct (
203+ model,
204+ ret_xy,
205+ 2 ,
206+ [x[], y[]],
207+ 1.0 ,
208+ C_NULL ,
209+ C_NULL ,
210+ )
211+ push! (children, ret_xy[])
212+ push! (expr. exprs, ret_xy)
213+ push! (coefficients, scale * term. coefficient)
214+ end
215+ @SCIP_CALL SCIPcreateExprSum (
216+ model,
217+ ret,
218+ length (children),
219+ children,
220+ coefficients,
221+ f. constant,
222+ C_NULL ,
223+ C_NULL ,
224+ )
225+ push! (expr. exprs, ret)
226+ return ret
227+ end
228+
229+ function MOI. get (
230+ o:: Optimizer ,
231+ :: MOI.ConstraintPrimal ,
232+ ci:: MOI.ConstraintIndex{MOI.ScalarNonlinearFunction} ,
233+ )
234+ _throw_if_invalid (o, ci)
235+ c = cons (o, ci)
236+ expr_ref = SCIPgetExprNonlinear (c)
237+ sol = SCIPgetBestSol (o)
238+ @SCIP_CALL SCIPevalExpr (o, expr_ref, sol, Clonglong (0 ))
239+ return SCIPexprGetEvalValue (expr_ref)
240+ end
0 commit comments