How to replace macro argument with expr as being typed manually?

Given a macro @NLobjective which have the following usage example: @NLobjective(m, Min, 11 x² - 484 x + 12358)
I want to write a function that returns the last expression 11 x² - 484 x + 12358.
Function implementation:

function CreateEq(x::VariableRef, arr::Array)
    s = 0
    for i in arr
        s += (x-i)^2
    end
    return :(@NLobjective(m, Min, begin $(s) end))
end

given x and S = [5,6,7,9,11,16,20,22,23,24,99]

Output from eval(CreateEq(x,S)) is understood in a different way that writing @NLobjective(m, Min, 11 x² - 484 x + 12358) and gives the following error message:

ERROR: Unexpected quadratic expression 11 x² - 484 x + 12358 in nonlinear expression. Quadratic expressions (e.g., created using @expression) and nonlinear expressions cannot be mixed.

Questions:

  • How to make begin $(s) end be substituted as manually writing 11 x² - 484 x + 12358?

What are you trying to achieve? There is probably a better way to do it.

Do you want something like?

function create_eq(model, x, arr)
    return @expression(model, sum((x - i)^2 for i in arr))
end

I want to get around this setup:

 my_expr = CreateEq(x,S)
 @variable(m, aux)
 @constraint(m, aux == my_expr)

I have tried your function using this: @NLobjective(m, Min, @eval(create_eq(m,x,S))), but it gives the same error

So I assume you want to include an affine or quadratic expression within a nonlinear objective? And you followed the work-around in the docs? http://www.juliaopt.org/JuMP.jl/v0.19.2/nlp/#Syntax-notes-1

At present, the work-around is recommended:

function create_eq(model, x, arr)
    aux = @variable(model)
    @constraint(model, aux == sum((x - i)^2 for i in arr))
    return aux
end

model = Model()
@variable(model, x)
ex = create_eq(model, x, [1, 2, 3])
@NLobjective(model, Min, ex)

Also, please read PSA: make it easier to help you, and provide a minimal working example.

1 Like

Yes, that is it.

Thanks I will use your solution.

Here is the solution:

function CreateEq(x::VariableRef, arr::Array)
    s = Expr(:call,:+)
    for i in arr
        push!(s.args, :((x - $i)^2))
    end
    return s
end

call it like that for macros:

 eval(:(@NLobjective(m, Min, $(CreateEq(x,S)))))