Skip to content
PREDICT-EPFLPublic

About

Make your optimal control problems scale

Resources

Stars

3 stars

Watchers

0 watching

Forks

Repository files navigation

scaly

Scaly is a modelling and code-generation library for optimal control. You describe dynamics, costs and constraints once, and use the same description from prototyping in Python to deployment using generated C code.

import numpy as np
import scaly as sc

N = 20  # the decision vector w stacks N + 1 states of size 2, then N controls

@sc.function(sc.arg("x", 2), sc.arg("u", 1), sc.arg("xnext", 2))
def defect(x: sc.Expr, u: sc.Expr, xnext: sc.Expr) -> sc.Expr:
    return x + 0.1 * sc.concat([x[1:], u]) - xnext

@sc.problem(vars=sc.arg("w", 3 * N + 2), params=sc.arg("x0", 2))
def multiple_shooting(w: sc.Expr, x0: sc.Expr) -> sc.ProblemSpec[sc.Expr]:
    xs, us = w[: 2 * N + 2].reshape((N + 1, 2)), w[2 * N + 2 :].reshape((N, 1))
    defects = sc.vmap(defect, N)(xs[:-1], us, xs[1:]).vec()  # one loop, not N copies
    return sc.ProblemSpec(minimize=sc.sumsqr(xs) + 0.1 * sc.sumsqr(us), eq=(xs[0] - x0, defects))

solve = sc.solver(multiple_shooting, "ipopt")
w_opt, *_ = solve(np.array([1.0, 0.0]))

Behind the scenes, scaly traces the costs, constraints and their derivatives, generates and compiles on the fly C code to call them within the solver. You can also generate the same C code in a specific directory so you can embed it into an external application, either from Python:

from pathlib import Path
from scaly.codegen import write_module

write_module(solve, Path("generated/"))  # generated/multiple_shooting_ipopt.h and .c

or from the command line, naming the module and the function in it:

uv run scaly_codegen mymodule:solve -o generated/

Features

  • Wrap symbolic expressions in functions that you can compose freely. Differentiating a function (e.g. with sc.gradient) creates another function.
  • The input-output dependencies of a function are analyzed statically to generate efficient code for sparse Jacobians and Hessians.
  • Repeated structure (from sc.vmap) stays a loop. A horizon of identical stages compiles to one loop body, so the generated code stays small as the horizon grows.
  • The generated C code has a stable signature that is intentionally close to CasADi's for easy integration with existing tools.
  • Interfaces to quadratic and nonlinear optimization solvers such as PIQP and IPOPT are shipped with scaly. These interfaces are implemented as separate packages, allowing anyone to implement a custom solver plugin.
  • The core library is pure Python and only depends on NumPy and SciPy. The generated code is self-contained C (except for solver code that may depend on external libraries).

Installation

Scaly requires Python 3.12 or newer, on Linux and macOS, and only requires a C compiler to be pre-installed. Using uv:

# install just the core library
uv add scaly    
# or with an additional solver interface
uv add "scaly[ipopt]"
# or with all solvers
uv add "scaly[solvers]"

You can of course also use pip by replacing uv add with pip install.

See Installation for more details.

Documentation

The documentation has a user guide, a description of how the compiler works, benchmark results against CasADi, and the API reference.

Scaly is still in development and the public API can still change between minor versions. See versioning policy for more details.

Acknowledgements

Scaly is developed by Tudor A. Oancea (main developer) and Colin N. Jones (methods and math), at the Predictive control lab from EPFL. This project is funded by the Swiss National Science Foundation through the NCCR Automation (grant agreement 51NF40_180545).

AI usage disclosure

This project has been substantially developed using AI coding agents (Claude, Codex and others), under the direction and review of the authors, who are responsible for the result.

License

BSD-2-Clause. See LICENSE.md.

About

Make your optimal control problems scale

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages