Summing exponential expressions in NLP

I have the NLP below that I want to solve with JuMP. The problem transforms the original time-series x_t into a new time-series x'_t with a different integral but the same shape and extremes. The objective function minimizes the difference between the integral of the transformed time-series and a target value. The first constraint defines the transformation based on the three variables \alpha,\beta and \gamma. Finally, the last two constraints fix the extreme values of the transformed time-series.

min (u -\sum_t x'_t)^2
x'_t = \alpha \cdot x_t^\beta + \gamma \forall t
x'_{t_{min}} = a_{min}
x'_{t_{max}} = a_{max}

My current Julia code looks like this:

model = Model(Ipopt.Optimizer)

% define transformation variables
exp_var = @variable(model, exp, lower_bound = 0.0, upper_bound = 1000, start = rand(0:25))
multi_var = @variable(model, multi, lower_bound = 0.0, upper_bound = 1000, start = rand(0:25))
add_var = @variable(model, add, lower_bound = -1000, upper_bound = 1000, start = rand(-25:25))

% define time-series variable
scaledTs_var = @variable(model, tSteps[1:numSteps])

% definition of transformed time-series
@NLconstraint(model, def[i = 1:numSteps], scaledTs_var[i] == multi_var * ts_arr[i]^exp_var + add_var)

% enforce extremes
@constraint(model, minVal, scaledTs_var[minStep_int] == min_fl)
@constraint(model, maxVal, scaledTs_var[maxStep_int] == max_fl)

% set objective
@objective(model, Min, (sum(scaledTs_var)- utz_fl)^2)

However, this formulation is not really robust and frequently the solver fails. I used to solve this with GAMS and learned that most NLP solvers handle this problem much better if I just substitute the transformed time-series in the problem like this:

min (u - \sum_t (\alpha \cdot x_t^\beta + \gamma))^2
\alpha \cdot x_{t_{min}} ^\beta + \gamma = a_{min}
\alpha \cdot x_{t_{max}} ^\beta + \gamma = a_{max}

The problem is that in Julia I can’t sum the exponential expressions in the objective function.

@objective(model, Min, (sum(map(i → multi_var * ts_arr[i]^exp_var + add_var,1:numSteps))- utz_fl)^2)

The code above just returns:

LoadError: begin...end blocks are not supported in nonlinear macros. The nonlinear expression must be a single statement.

I wasn’t able to reproduce your error because the code didn’t run (some missing values). If you have an example that reproduces the error, it would be good to post it.

In general you can sum exponential expressions in JuMP, at least this works:

using JuMP, Ipopt

####Me being creative with missing variables
numSteps = 50
minStep_int = 1
maxStep_int = 2
min_fl = 1
max_fl = 1
utz_fl = 0
ts_arr=ones(1,numSteps)
####
model = Model(Ipopt.Optimizer)

exp_var = @variable(model, exp, lower_bound = 0.0, upper_bound = 1000, start = rand(0:25))
multi_var = @variable(model, multi, lower_bound = 0.0, upper_bound = 1000, start = rand(0:25))
add_var = @variable(model, add, lower_bound = -1000, upper_bound = 1000, start = rand(-25:25))

scaledTs_var = @variable(model, tSteps[1:numSteps])

@NLconstraint(model, def[i = 1:numSteps], scaledTs_var[i] == multi_var * ts_arr[i]^exp_var + add_var)

@constraint(model, minVal, scaledTs_var[minStep_int] == min_fl)
@constraint(model, maxVal, scaledTs_var[maxStep_int] == max_fl)

# @objective(model, Min, (sum(scaledTs_var)- utz_fl)^2)  
# @objective(model, Min, (sum(map(i → multi_var * ts_arr[i]^exp_var + add_var,1:numSteps))- utz_fl)^2)

@NLobjective(model, Min, (sum(multi_var * ts_arr[i]^exp_var + add_var for i=1:numSteps)- utz_fl)^2)
2 Likes