diff --git a/src/nlp_expr.jl b/src/nlp_expr.jl index ec04e4f415d..bbbdf6c11ee 100644 --- a/src/nlp_expr.jl +++ b/src/nlp_expr.jl @@ -85,6 +85,9 @@ struct GenericNonlinearExpr{V<:AbstractVariableRef} <: AbstractJuMPScalar head::Symbol, args::Vararg{Any}, ) where {V<:AbstractVariableRef} + for arg in args + _throw_if_not_real(arg) + end return new{V}(head, Any[a for a in args]) end @@ -92,6 +95,9 @@ struct GenericNonlinearExpr{V<:AbstractVariableRef} <: AbstractJuMPScalar head::Symbol, args::Vector{Any}, ) where {V<:AbstractVariableRef} + for arg in args + _throw_if_not_real(arg) + end return new{V}(head, args) end end @@ -291,6 +297,12 @@ function Base.one(::Type{GenericNonlinearExpr{V}}) where {V} return GenericNonlinearExpr{V}(:+, 1.0) end +Base.conj(x::GenericNonlinearExpr) = x +Base.real(x::GenericNonlinearExpr) = x +Base.imag(x::GenericNonlinearExpr) = zero(x) +Base.abs2(x::GenericNonlinearExpr) = x^2 +Base.isreal(::GenericNonlinearExpr) = true + # Univariate operators _is_real(::Any) = false diff --git a/test/test_nlp_expr.jl b/test/test_nlp_expr.jl index 2450e06c1eb..23ba19c781e 100644 --- a/test/test_nlp_expr.jl +++ b/test/test_nlp_expr.jl @@ -1035,4 +1035,61 @@ function test_convert_float_nonlinear_expr() return end +function test_nlp_adjoint() + model = Model() + @variable(model, x) + y = sin(x) + @test y' === y + @test conj(y) === y + @test real(y) === y + @test isequal_canonical(imag(y), zero(y)) + @test isequal_canonical(abs2(y), y^2) + @test isreal(y) + return +end + +function test_nlp_matrix_adjoint() + model = Model() + @variable(model, x[1:2]) + y = sin.(x) + @test isequal_canonical( + @expression(model, expr, y' * y), + NonlinearExpr(:+, Any[0.0, y[2]*y[2], y[1]*y[1]]), + ) + return +end + +function test_error_complex_literal_pow() + model = Model() + @variable(model, x in ComplexPlane()) + @test_throws( + ErrorException( + "Cannot build `GenericNonlinearExpr` because a term is complex-" * + "valued: `($x)::$(typeof(x))`", + ), + x^3, + ) + return +end + +function test_error_nonlinear_expr_complex_constructor() + model = Model() + @variable(model, x in ComplexPlane()) + @test_throws( + ErrorException( + "Cannot build `GenericNonlinearExpr` because a term is complex-" * + "valued: `($x)::$(typeof(x))`", + ), + NonlinearExpr(:^, Any[x, 3]), + ) + @test_throws( + ErrorException( + "Cannot build `GenericNonlinearExpr` because a term is complex-" * + "valued: `($x)::$(typeof(x))`", + ), + NonlinearExpr(:^, x, 3), + ) + return +end + end # module diff --git a/test/test_operator.jl b/test/test_operator.jl index c4d5a47cadd..0a94f273ae5 100644 --- a/test/test_operator.jl +++ b/test/test_operator.jl @@ -621,7 +621,6 @@ function test_complex_pow() @test y^0 == (1.0 + 0im) @test y^1 == y @test y^2 == y * y - @test isequal_canonical(y^3, NonlinearExpr(:^, Any[y, 3])) return end