 # @expression v.s. @constraint (when to use what)

I’m pretty sure this question will be redundant, but I could not find an answer anywhere. My question is more like asking a style guide so that my code can avoid any unnecessary build/calculation time.

Q1. My guess is basically I should use `@expression` whenever possible rather than using `@constraint` to reduce the size of an optimization problem. Can anyone confirm this?

Q2. In pre-solve or any internal process to determine the class of optimization (either provided by JuMP or Solvers), can one be faster than the other? For example, in model2 below, it is straightforward that the objective is quadratic (variable x variable), but I’m not sure how model1 determines it is quadratic (variable x expression).

In the examples below, `model1` uses `@expression` to define the objective while `model2` uses `@constraint`.

``````using JuMP, Ipopt
model1 = Model(Ipopt.Optimizer)
@variables(model1, begin
x >= 0
y >= 0
end)
ex = @expression(model1, 2x + y - 1)
@objective(model1, Min, 2 * x * ex - 1)
optimize!(model1)
value(ex)
``````
``````using JuMP, Ipopt
model2 = Model(Ipopt.Optimizer)
@variables(model2, begin
x >= 0
y >= 0
ex
end)
@constraint(model2, ex == 2x + y - 1)
@objective(model2, Min, 2 * x * ex - 1)
optimize!(model2)
value(model2[:ex])
``````
1 Like

Yes. Expressions get substituted into the final model. The constraint approach will add an extra decision variable and an extra constraint. Some solvers have presolve routines that take care of this, but others, like Ipopt, don’t.

Your second question is related: the substitution happens at the JuMP level before the problem reaches the solver. So the solver will see the objective `4 * x^2 + 2 * x * y - 2x - 1` in the first model.

To summarize: expressions are uniformly good. They can make the code more readable, and JuMP can (in some cases) build the problem more efficiently (particularly `@NLexpression` when used in `@NLconstraint` and `@NLobjective`. `@expression` less so).

4 Likes

@odow Thank you for the clear explanation!

1 Like

Is `ex = 2x + y - 1` equivalent to `ex = @expression(model1, 2x + y - 1)`? In the following example, both approaches lead to the same result and `typeof(ex) = AffExpr`.

``````using JuMP, GLPK
model1 = Model(GLPK.Optimizer)
@variables(model1, begin
x >= 0
y >= 0
end)
# ex = @expression(model1, 2x + y - 1)
ex = 2x + y - 1
@show typeof(ex)
@objective(model1, Min, 2 * x + ex - 1)
optimize!(model1)
value(ex)
``````
1 Like
1 Like

Thank you. I just noticed it. In short, `ex = @expression(model1, 2x + y - 1)` is preferred:

Use JuMP’s macros (or `add_to_expression!` to build expressions. Avoid constructing expressions outside the macros.

As a side note, it may be better to define a named expression with `@expression(model1, ex, 2x + y - 1)` such that we can access it later in a different scope with `model[:ex]`, e.g., when a `model` is returned from a builder function.

1 Like