@@ -318,6 +318,50 @@ function test_quadratic()
318318 return
319319end
320320
321+ function test_poor_numerics ()
322+ μ = [0.006898463772627643 , - 0.02972609131603086 ]
323+ Q = [0.030446 0.00393731 ; 0.00393731 0.00713285 ]
324+ N = 2
325+ model = MOA. Optimizer (Ipopt. Optimizer)
326+ MOI. set (model, MOA. Algorithm (), MOA. EpsilonConstraint ())
327+ MOI. set (model, MOA. SolutionLimit (), 10 )
328+ MOI. set (model, MOI. Silent (), true )
329+ w = MOI. add_variables (model, N)
330+ sharpe = MOI. add_variable (model)
331+ MOI. add_constraint .(model, w, MOI. GreaterThan (0.0 ))
332+ MOI. add_constraint .(model, w, MOI. LessThan (1.0 ))
333+ MOI. add_constraint (model, sum (1.0 * w[i] for i in 1 : N), MOI. EqualTo (1.0 ))
334+ variance = Expr (:call , :+ )
335+ for i in 1 : N, j in 1 : N
336+ push! (variance. args, Expr (:call , :* , Q[i, j], w[i], w[j]))
337+ end
338+ nlp = MOI. Nonlinear. Model ()
339+ MOI. Nonlinear. add_constraint (
340+ nlp,
341+ :(($ (μ[1 ]) * $ (w[1 ]) + $ (μ[2 ]) * $ (w[2 ])) / sqrt ($ variance) - $ sharpe),
342+ MOI. EqualTo (0.0 ),
343+ )
344+ evaluator = MOI. Nonlinear. Evaluator (
345+ nlp,
346+ MOI. Nonlinear. SparseReverseMode (),
347+ [w; sharpe],
348+ )
349+ MOI. set (model, MOI. NLPBlock (), MOI. NLPBlockData (evaluator))
350+ f = MOI. Utilities. operate (vcat, Float64, μ' * w, sharpe)
351+ MOI. set (model, MOI. ObjectiveSense (), MOI. MAX_SENSE)
352+ MOI. set (model, MOI. ObjectiveFunction {typeof(f)} (), f)
353+ MOI. optimize! (model)
354+ @test MOI. get (model, MOI. ResultCount ()) == 1
355+ for i in 1 : MOI. get (model, MOI. ResultCount ())
356+ w_sol = MOI. get (model, MOI. VariablePrimal (i), w)
357+ sharpe_sol = MOI. get (model, MOI. VariablePrimal (i), sharpe)
358+ y = MOI. get (model, MOI. ObjectiveValue (i))
359+ @test y ≈ [μ' * w_sol, sharpe_sol]
360+ end
361+ @test MOI. get (model, MOI. TerminationStatus ()) == MOI. OPTIMAL
362+ return
363+ end
364+
321365end
322366
323367TestEpsilonConstraint. run_tests ()
0 commit comments