11# Conversion from JuMP array types to MOI ArrayNonlinearFunction,
2- # to Julia Expr for ArrayDiff parsing, and NLPBlock setup helpers.
2+ # to Julia Expr for ArrayDiff parsing, and NLPBlock setup via
3+ # JuMP.set_objective_function override.
34
45# ── moi_function: JuMP → MOI ─────────────────────────────────────────────────
56
@@ -115,41 +116,14 @@ function to_expr(x::Expr)
115116 return x
116117end
117118
118- # ── Scalar expression from array operations ────── ────────────────────────────
119+ # ── to_expr for JuMP scalar nonlinear expressions ────────────────────────────
119120
120- """
121- ArrayScalarExpr
122-
123- A scalar-valued expression that operates on array subexpressions (e.g.,
124- `dot(A, B)`, `sum(A)`, `norm(A)`). This is the result type of scalar
125- reductions on `GenericArrayExpr`.
126- """
127- struct ArrayScalarExpr
128- head:: Symbol
129- args:: Vector{Any}
130- end
131-
132- function to_expr (x:: ArrayScalarExpr )
121+ function to_expr (x:: JuMP.GenericNonlinearExpr )
133122 return Expr (:call , x. head, Any[to_expr (a) for a in x. args]. .. )
134123end
135124
136- """
137- ArrayDiff.dot(x, y)
138-
139- Compute the dot product (sum of elementwise products) of two array expressions.
140- Returns an `ArrayScalarExpr` (scalar).
141- """
142- function dot (x, y)
143- return ArrayScalarExpr (:dot , Any[x, y])
144- end
145-
146- """
147- ArrayDiff.sumsq(x)
148-
149- Compute the sum of squares of an array expression. Equivalent to `dot(x, x)`.
150- """
151- function sumsq (x)
152- return dot (x, x)
125+ function to_expr (x:: JuMP.GenericVariableRef )
126+ return JuMP. index (x)
153127end
154128
155129# ── parse_expression for ArrayNonlinearFunction ──────────────────────────────
@@ -172,48 +146,43 @@ function parse_expression(
172146 return parse_expression (data, expr, to_expr (x), parent_index)
173147end
174148
175- # ── NLPBlock setup helpers ────────────────────────────── ─────────────────────
149+ # ── Detect whether a JuMP expression contains array args ─────────────────────
176150
177- """
178- set_nlp_objective!(jmodel::JuMP.Model, sense, objective)
179-
180- Build an `ArrayDiff.Model` from the given `objective` expression (which may be
181- an `ArrayScalarExpr`, `GenericArrayExpr`, `ArrayNonlinearFunction`, or plain
182- `Expr`), create an `ArrayDiff.Evaluator` with first-order AD, and set the
183- resulting `MOI.NLPBlockData` on the JuMP model's backend.
184-
185- ## Example
186-
187- ```julia
188- model = Model(NLopt.Optimizer)
189- @variable(model, W[1:n, 1:n], container = ArrayDiff.ArrayOfVariables)
190- Y = W * X
191- diff = Y - target
192- ArrayDiff.set_nlp_objective!(model, MOI.MIN_SENSE, ArrayDiff.sumsq(diff))
193- optimize!(model)
194- ```
195- """
196- function set_nlp_objective! (
197- jmodel:: JuMP.Model ,
198- sense:: MOI.OptimizationSense ,
199- objective,
200- )
201- # Collect ordered variables
151+ _has_array_args (:: Any ) = false
152+ _has_array_args (:: AbstractJuMPArray ) = true
153+ _has_array_args (:: ArrayNonlinearFunction ) = true
154+
155+ function _has_array_args (x:: JuMP.GenericNonlinearExpr )
156+ return any (_has_array_args, x. args)
157+ end
158+
159+ # ── Override set_objective_function for array-valued nonlinear expressions ────
160+
161+ function _set_arraydiff_nlp_block! (
162+ jmodel:: JuMP.GenericModel{T} ,
163+ func:: JuMP.GenericNonlinearExpr{JuMP.GenericVariableRef{T}} ,
164+ ) where {T}
202165 vars = JuMP. all_variables (jmodel)
203166 ordered_variables = [JuMP. index (v) for v in vars]
204-
205- # Build ArrayDiff Model
206167 ad_model = Model ()
207- obj_expr = to_expr (objective )
168+ obj_expr = to_expr (func )
208169 set_objective (ad_model, obj_expr)
209-
210- # Create evaluator (first-order AD)
211170 evaluator = Evaluator (ad_model, Mode (), ordered_variables)
212171 nlp_data = MOI. NLPBlockData (evaluator)
172+ MOI. set (JuMP. backend (jmodel), MOI. NLPBlock (), nlp_data)
173+ return
174+ end
213175
214- # Set on the JuMP backend
215- backend = JuMP. backend (jmodel)
216- MOI. set (backend, MOI. NLPBlock (), nlp_data)
217- MOI. set (backend, MOI. ObjectiveSense (), sense)
176+ function JuMP. set_objective_function (
177+ model:: JuMP.GenericModel{T} ,
178+ func:: JuMP.GenericNonlinearExpr{JuMP.GenericVariableRef{T}} ,
179+ ) where {T<: Real }
180+ if _has_array_args (func)
181+ return _set_arraydiff_nlp_block! (model, func)
182+ end
183+ # Fall back to standard JuMP: convert to MOI and set on backend.
184+ f = JuMP. moi_function (func)
185+ attr = MOI. ObjectiveFunction {typeof(f)} ()
186+ MOI. set (JuMP. backend (model), attr, f)
218187 return
219188end
0 commit comments