Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is it not possible to apply different constraints at each timestep? #12

Open
kr-jschoi opened this issue May 17, 2024 · 1 comment
Open

Comments

@kr-jschoi
Copy link

I checked the examples using rockit and spectool that you provided, and it seems that unlike what is described in the paper, it is not possible to apply different constraints at each timestep (ustage). (It only allows applying the same constraints at t0, tf, and across all timesteps.) Is the ability to apply different constraints at each timestep a feature that is planned for development later?

@lvanroye
Copy link
Collaborator

lvanroye commented May 17, 2024

Hello,

In rockit this is not possible, but in spectool it is.

Spectool is designed in such a way that the specification maps directly to the fatrop problem specification (of the paper). What you are looking for is ustages. A ustage contains all the functional quantities (dynamics, costf, constraints) that are related to a single time step. Any problem that fits into the fatrop formulation can be build up as a sequence of ustages.

consider the following python example which first defines a list of dynamics, costfs and constraints and then later builds up the spectool problem.

import casadi as cs
import fatropy.spectool as sp

ocp = sp.Ocp()

x = ocp.state(2)
u = ocp.control()
dt = 0.01
N = 100

xp1 = x + dt*cs.vertcat(x[1], u)

dyns = [xp1 for i in range(N-1)]
costs = [cs.sumsqr(x) + cs.sum1(x)*0.001*i for i in range(N)]
constr = [u>0.001*i for i in range(N)]

for dyni, costi, contri in zip(dyns[:-1], costs[:-1], constr[:-1]):
    ustagei = ocp.new_ustage()
    ustagei.set_next(x, dyni)
    ustagei.add_objective(costi)
    ustagei.subject_to(contri)

ustageN = ocp.new_ustage()
ustageN.subject_to(constr[-1])
ustageN.add_objective(costs[-1])

ocp.solver("fatrop", {"expand":True, "jit":True})  
ocp_fun = ocp.to_function("ocp", [], [ocp.sample(x)[1]])

print(ocp_fun())

For reference, in addition to the ustage (u means mu from micro) fatrop also has the notion of a stage. A stage (of length N) is inspired by the rockit framework and it is basically implemented as a sequence of three microstages:

  • ustage t0
  • ustage mid (which is repeated N-1 times)
  • ustage tf
    The dynamics across the whole stage stay the same. We implemented this stage concept, as it is a pattern that appears in many applications. It is not really necessary, as you can always build up your problem from ustages, but in many cases using stages instead of microstages can improve the conciseness and readiblity of your code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants