From 95d93575ef04e202130cc6a478362c0d6b54cfcc Mon Sep 17 00:00:00 2001 From: odow Date: Tue, 5 Aug 2025 08:42:40 +1200 Subject: [PATCH] [Nonlinear] parse x*x as x^2 in Nonlinear.Model --- src/Nonlinear/parse.jl | 42 ++++++++++++++++++++++++++++--------- test/Nonlinear/Nonlinear.jl | 12 +++++------ 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/src/Nonlinear/parse.jl b/src/Nonlinear/parse.jl index 66dee02eab..05fd684429 100644 --- a/src/Nonlinear/parse.jl +++ b/src/Nonlinear/parse.jl @@ -345,18 +345,40 @@ function parse_expression( x::MOI.ScalarQuadraticTerm, parent_index::Int, ) - id_mul = data.operators.multivariate_operator_to_id[:*] - push!(expr.nodes, Node(NODE_CALL_MULTIVARIATE, id_mul, parent_index)) - mul_parent = length(expr.nodes) - coef = x.coefficient + # There are four cases: + # (1): 1 * x * x --> ^(x, 2) + # (2): a * x * x --> *(a, ^(x, 2)) + # (3): a * x * y --> *(a, x, y) + # (4): 1 * x * y --> *(x, y) if x.variable_1 == x.variable_2 - coef /= 2 - end - if !isone(coef) - parse_expression(data, expr, coef, mul_parent) + # Case (1): 1 * x * x --> ^(x, 2) + # Case (2): a * x * x --> *(a, ^(x, 2)) + coef = x.coefficient / 2 + parent = parent_index + if !isone(coef) + id = data.operators.multivariate_operator_to_id[:*] + push!(expr.nodes, Node(NODE_CALL_MULTIVARIATE, id, parent_index)) + parent = length(expr.nodes) + parse_expression(data, expr, coef, parent) + parent + end + id = data.operators.multivariate_operator_to_id[:^] + push!(expr.nodes, Node(NODE_CALL_MULTIVARIATE, id, parent)) + pow_parent = length(expr.nodes) + parse_expression(data, expr, x.variable_1, pow_parent) + parse_expression(data, expr, 2, pow_parent) + else + # Case (3): a * x * y --> *(a, x, y) + # Case (4): 1 * x * y --> *(x, y) + id_mul = data.operators.multivariate_operator_to_id[:*] + push!(expr.nodes, Node(NODE_CALL_MULTIVARIATE, id_mul, parent_index)) + mul_parent = length(expr.nodes) + if !isone(x.coefficient) + parse_expression(data, expr, x.coefficient, mul_parent) + end + parse_expression(data, expr, x.variable_1, mul_parent) + parse_expression(data, expr, x.variable_2, mul_parent) end - parse_expression(data, expr, x.variable_1, mul_parent) - parse_expression(data, expr, x.variable_2, mul_parent) return end diff --git a/test/Nonlinear/Nonlinear.jl b/test/Nonlinear/Nonlinear.jl index 5c85b4b0b6..65c9a30c32 100644 --- a/test/Nonlinear/Nonlinear.jl +++ b/test/Nonlinear/Nonlinear.jl @@ -1167,13 +1167,13 @@ function test_scalar_nonlinear_function_parse_scalarquadraticfunction() MOI.ScalarQuadraticFunction(qterms, terms, 0.0) => :(0.0), MOI.ScalarQuadraticFunction(qterms, terms, 1.0) => :(1.0), MOI.ScalarQuadraticFunction(qterms, [aterm], 0.0) => :(2.0 * $x), - (1.0 * x * x + 1.0 * x + 1.0) => :($x * $x + $x + 1), - (1.0 * x * x + 1.0 * x) => :($x * $x + $x), - (1.0 * x * x + 2.0 * x) => :($x * $x + 2.0 * $x), - (2.0 * x * x + 2.0 * x) => :(2.0 * $x * $x + 2.0 * $x), - (1.0 * x * x) => :($x * $x), + (1.0 * x * x + 1.0 * x + 1.0) => :($x^2 + $x + 1), + (1.0 * x * x + 1.0 * x) => :($x^2 + $x), + (1.0 * x * x + 2.0 * x) => :($x^2 + 2.0 * $x), + (2.0 * x * x + 2.0 * x) => :(2.0 * $x^2 + 2.0 * $x), + (1.0 * x * x) => :($x^2), (1.5 * x * x + 2.5 * x * y + 3.5 * x + 2.0) => - :(1.5 * $x * $x + 2.5 * $x * $y + 3.5 * $x + 2.0), + :(1.5 * $x^2 + 2.5 * $x * $y + 3.5 * $x + 2.0), ) nlp_model = MOI.Nonlinear.Model() f1 = MOI.Nonlinear.add_expression(nlp_model, f)