How to use time-dependant parameters in InfiniteOpt

I am using InfiniteOpt and I would like to have a parameter time-dependent.

For example, in their “eating the cake” optimal consumption model, I would like to define the utility function with a multiplier that change with time:

using InfiniteOpt, Ipopt, Plots
ρ = 0.025  # discount rate
k = 100.0  # utility bliss point
T = 10.0   # life horizon
r = 0.05   # interest rate
B0 = 100.0 # endowment
mult1 = 1000 # multiplier of the first period
mult2 = 10   # multiplier of the second period
tswitch = 8  # time switch between multipliers
u(c,t; k=k) = t < tswitch ? mult1 * -(c - k)^2 : mult2 * -(c - k)^2        # utility function with the switch
discount(t; ρ=ρ) = exp(-ρ*t) # discount function
BC(B, c; r=r) = r*B - c      # budget constraint
opt = Ipopt.Optimizer   # desired solver
ns = 1_000;             # number of points in the time grid
m = InfiniteModel(opt)
@infinite_parameter(m, t in [0, T], num_supports = ns)
@variable(m, B, Infinite(t)) ## state variables
@variable(m, c, Infinite(t)) ## control variables
@objective(m, Max, integral(u(c,t), t, weight_func = discount))
@constraint(m, B(0) == B0)
@constraint(m, B(T) == 0)
@constraint(m, c1, deriv(B, t) == BC(B, c; r=r))
optimize!(m)
termination_status(m)
c_opt = value(c)
B_opt = value(B)
ts = supports(t)
opt_obj = objective_value(m) # V(B0, 0)
ix = 2:(length(ts)-1) # index for plotting
plot(ts[ix],   B_opt[ix], lab = "B: wealth balance")
plot!(ts[ix],  c_opt[ix], lab = "c: consumption")

This snippet however returns me an TypeError: non-boolean (NLPExpr) used in boolean context. I have tried with other solutions (the time-dependent exogenous parameter is a vector) but with no success :-/

At a guess, you might need:

function u(c, t; k = k)
    InfiniteOpt.ifelse(t < tswitch, mult1 * -(c - k)^2, mult2 * -(c - k)^2)
end

This is not particularly well documented.

I got there by recognizing that we probably wanted ifelse(t < tswitch, ...), and then I got an error WARNING: both InfiniteOpt and Base export "ifelse"; uses of it in module Main must be qualified that pointed me to InfiniteOpt.ifelse.

cc @pulsipher.

1 Like

I did something like this by describing the system with multiple stages. There is a somewhat long discussion where @pulsipher helped me a lot!

1 Like