maptor.problem.core_problem#
Classes for defining optimal control problems.
- class maptor.problem.core_problem.Phase(problem, phase_id)[source]#
Bases:
object
Single phase definition for multiphase optimal control problems.
A Phase represents one segment of a multiphase trajectory with its own time domain, state variables, control inputs, dynamics, and constraints. Phases can be linked together through symbolic constraints to create complex multiphase missions.
The Phase class provides a fluent interface for defining:
Time variables with boundary conditions
State variables with initial, final, and path constraints
Control variables with bounds
System dynamics as differential equations
Integral cost terms and constraints
Path constraints applied throughout the phase
Event constraints at phase boundaries
Mesh discretization for numerical solution
- Note:
Phase objects are created through Problem.set_phase() and should not be instantiated directly.
- Examples:
Basic single-phase problem setup:
>>> problem = mtor.Problem("Rocket Ascent") >>> phase = problem.set_phase(1) >>> >>> # Define time and variables >>> t = phase.time(initial=0, final=10) >>> h = phase.state("altitude", initial=0, final=1000) >>> v = phase.state("velocity", initial=0) >>> T = phase.control("thrust", boundary=(0, 2000)) >>> >>> # Set dynamics >>> phase.dynamics({h: v, v: T/1000 - 9.81}) >>> >>> # Add constraints and mesh >>> phase.path_constraints(h >= 0, T <= 1500) >>> phase.mesh([5, 5], [-1, 0, 1])
Multiphase trajectory with automatic linking:
>>> # Phase 1: Boost >>> p1 = problem.set_phase(1) >>> t1 = p1.time(initial=0, final=120) >>> h1 = p1.state("altitude", initial=0) >>> v1 = p1.state("velocity", initial=0) >>> # ... dynamics and constraints >>> >>> # Phase 2: Coast (automatically linked) >>> p2 = problem.set_phase(2) >>> t2 = p2.time(initial=t1.final, final=300) # Continuous time >>> h2 = p2.state("altitude", initial=h1.final) # Continuous altitude >>> v2 = p2.state("velocity", initial=v1.final) # Continuous velocity >>> # ... dynamics for coast phase
- time(initial=0.0, final=None)[source]#
Define the time variable for this phase with boundary conditions.
Creates the time coordinate for this phase with comprehensive constraint specification. Supports fixed times, bounded ranges, and symbolic expressions for multiphase trajectory continuity.
- Return type:
TimeVariableImpl
- Parameters:
- Args:
initial: Initial time constraint with full constraint syntax:
float: Fixed initial time (e.g., 0.0)
(lower, upper): Bounded initial time range (e.g., (0, 10))
(None, upper): Upper bounded only (e.g., (None, 5))
(lower, None): Lower bounded only (e.g., (2, None))
ca.MX: Symbolic expression for phase linking
None: Unconstrained initial time (optimization variable)
final: Final time constraint with full constraint syntax:
float: Fixed final time (e.g., 100.0)
(lower, upper): Bounded final time range (e.g., (90, 110))
(None, upper): Upper bounded only (e.g., (None, 200))
(lower, None): Lower bounded only (e.g., (50, None))
ca.MX: Symbolic expression for phase linking
None: Free final time (optimization variable)
- Returns:
TimeVariableImpl: Time variable with .initial and .final properties
- Examples:
Fixed values:
>>> t = phase.time(initial=0.0, final=10.0)
Ranges:
>>> t = phase.time(initial=(0, 5), final=(8, 12))
Single-sided bounds:
>>> t = phase.time(initial=(None, 5), final=(10, None))
Free variables:
>>> t = phase.time() # Both free
Symbolic linking:
>>> t2 = phase2.time(initial=t1.final)
- state(name, initial=None, final=None, boundary=None)[source]#
Define a state variable with comprehensive constraint specification.
Creates a state variable with exhaustive constraint capabilities including boundary conditions, path bounds, and symbolic multiphase linking. All constraint types support the full constraint syntax.
- Return type:
StateVariableImpl
- Parameters:
- Args:
name: Unique state variable name within this phase initial: Initial state constraint with full syntax:
float: Fixed initial value (e.g., 0.0)
(lower, upper): Bounded initial range (e.g., (0, 10))
(None, upper): Upper bounded only (e.g., (None, 100))
(lower, None): Lower bounded only (e.g., (50, None))
ca.MX: Symbolic expression for multiphase continuity
None: Unconstrained initial state
final: Final state constraint with full syntax:
float: Fixed final value (e.g., 1000.0)
(lower, upper): Bounded final range (e.g., (990, 1010))
(None, upper): Upper bounded only (e.g., (None, 1200))
(lower, None): Lower bounded only (e.g., (800, None))
ca.MX: Symbolic expression for multiphase continuity
None: Unconstrained final state
boundary: Path constraint applied throughout trajectory:
float: State equals this value at all times
(lower, upper): State bounds throughout (e.g., (0, 1000))
(None, upper): Upper path bound only (e.g., (None, 500))
(lower, None): Lower path bound only (e.g., (0, None))
None: No path bounds
- Returns:
StateVariableImpl: State variable with .initial and .final properties
- Examples:
Fixed values:
>>> altitude = phase.state("altitude", initial=0.0, final=1000.0)
Ranges:
>>> position = phase.state("position", initial=(0, 5), final=(95, 105))
Single-sided bounds:
>>> velocity = phase.state("velocity", initial=0, final=(None, 200))
Path bounds:
>>> mass = phase.state("mass", boundary=(100, 1000))
All constraint types:
>>> state = phase.state("x", initial=(0, 10), final=(90, 110), boundary=(0, None))
Symbolic linking:
>>> h2 = phase2.state("altitude", initial=h1.final)
Unconstrained:
>>> free_state = phase.state("free_variable")
- control(name, boundary=None)[source]#
Define a control variable with comprehensive bound specification.
Creates a control input with exhaustive constraint capabilities. Control variables represent actuator commands that can be optimized subject to physical or design limitations.
- Return type:
MX
- Parameters:
- Args:
name: Unique control variable name within this phase boundary: Control bounds with full constraint syntax:
float: Fixed control value (e.g., 100.0)
(lower, upper): Symmetric/asymmetric bounds (e.g., (-50, 100))
(None, upper): Upper bound only (e.g., (None, 1000))
(lower, None): Lower bound only (e.g., (0, None))
None: Unconstrained control
- Returns:
ca.MX: Control variable for use in dynamics and cost functions
- Examples:
Bounded control:
>>> thrust = phase.control("thrust", boundary=(0, 2000))
Single-sided bounds:
>>> power = phase.control("power", boundary=(0, None)) >>> brake = phase.control("brake", boundary=(None, 100))
Fixed value:
>>> constant = phase.control("thrust", boundary=1500)
Unconstrained:
>>> free_control = phase.control("force")
- dynamics(dynamics_dict)[source]#
Define differential equations with comprehensive expression support.
Specifies system ODEs describing state evolution. Dynamics expressions can involve states, controls, time, parameters, and arbitrary mathematical relationships. Must provide dynamics for all states in the phase.
- Return type:
- Parameters:
dynamics_dict (dict[MX | StateVariableImpl, MX | float | int | StateVariableImpl])
- Args:
- dynamics_dict: Maps state variables to time derivatives (dx/dt).
Keys: State variables from state() method Values: Expressions for derivatives using states, controls, parameters
- Examples:
Basic dynamics:
>>> pos = phase.state("position") >>> vel = phase.state("velocity") >>> thrust = phase.control("thrust") >>> phase.dynamics({pos: vel, vel: thrust - 0.1*vel})
With mass:
>>> mass = phase.state("mass", initial=1000) >>> phase.dynamics({ ... pos: vel, ... vel: thrust/mass - 9.81, ... mass: -thrust * 0.001 ... })
With parameters:
>>> drag_coeff = problem.parameter("drag") >>> phase.dynamics({pos: vel, vel: thrust - drag_coeff*vel**2})
Multiple states/controls:
>>> phase.dynamics({ ... x: vx, ... y: vy, ... vx: fx, ... vy: fy - 9.81 ... })
- add_integral(integrand_expr)[source]#
Add integral term with comprehensive integrand expression support.
Creates integral variables for cost functions, constraint integrals, and accumulated quantities. Supports arbitrary expressions involving states, controls, time, and parameters.
- Args:
- integrand_expr: Expression to integrate over phase duration.
Can involve any combination of states, controls, time, parameters.
- Returns:
ca.MX: Integral variable for use in objectives and constraints
- Examples:
Quadratic cost:
>>> cost = phase.add_integral(x**2 + u**2) >>> problem.minimize(cost)
Resource consumption:
>>> fuel = phase.add_integral(thrust * 0.001)
Distance traveled:
>>> distance = phase.add_integral(velocity)
Multiple integrals:
>>> energy = phase.add_integral(thrust**2) >>> fuel = phase.add_integral(thrust * rate) >>> problem.minimize(energy + 10*fuel)
- path_constraints(*constraint_expressions)[source]#
Add path constraints enforced continuously throughout the trajectory.
Path constraints are enforced at all collocation points, ensuring conditions hold throughout the phase. Use for safety limits, physical bounds, and trajectory shaping that cannot be expressed through state boundary parameters.
- Args:
*constraint_expressions: Constraint expressions enforced continuously
- Examples:
State bounds:
>>> phase.path_constraints(altitude >= 0, velocity <= 250)
Control bounds:
>>> phase.path_constraints(thrust >= 0, thrust <= 2000)
Complex expressions:
>>> phase.path_constraints((x-50)**2 + (y-50)**2 >= 100)
Multiple constraints:
>>> phase.path_constraints( ... altitude >= 0, ... velocity <= 200, ... acceleration <= 20 ... )
- event_constraints(*constraint_expressions)[source]#
Add event constraints for expressions not representable as state/control bounds.
Primary Purpose: Constraints on integral terms, static parameters, cross-phase expressions, and complex mathematical relationships that cannot be expressed through state initial/final/boundary or control boundary parameters.
When to use event_constraints vs state parameters: - Use state parameters for simple state boundaries: state(“x”, final=(90, 110)) - Use event_constraints for integrals, parameters, and complex expressions
- Args:
*constraint_expressions: Constraint expressions involving:
Integral terms from phase.add_integral()
Static parameters from problem.parameter()
Cross-phase linking expressions
Complex mathematical relationships
Multi-variable constraint expressions
- Examples:
Integral constraints:
>>> fuel_used = phase.add_integral(thrust * 0.001) >>> phase.event_constraints(fuel_used <= 100)
Parameter constraints:
>>> mass = problem.parameter("mass", boundary=(100, 1000)) >>> phase.event_constraints(mass >= 200)
Cross-phase linking:
>>> phase2.event_constraints(h2.initial == h1.final)
Complex expressions:
>>> phase.event_constraints(x.final**2 + y.final**2 >= 100)
- mesh(polynomial_degrees, mesh_points)[source]#
Configure pseudospectral mesh with comprehensive discretization control.
Defines mesh discretization for Radau pseudospectral method with precise control over polynomial degrees and interval distribution. Critical for balancing solution accuracy with computational efficiency.
- Return type:
- Parameters:
- Args:
- polynomial_degrees: Polynomial degree for each mesh interval.
Higher degrees: better accuracy, more computational cost. Typical range: 3-12, up to 15 for very smooth solutions.
- mesh_points: Normalized mesh points in [-1, 1] defining interval
boundaries. Length must equal len(polynomial_degrees) + 1. Points automatically scaled to actual phase time domain.
- Examples:
Uniform mesh:
>>> phase.mesh([4, 4, 4], [-1, -1/3, 1/3, 1])
Non-uniform intervals:
>>> phase.mesh([6, 4], [-1, -0.5, 1])
High accuracy:
>>> phase.mesh([10, 10], [-1, 0, 1])
Single interval:
>>> phase.mesh([5], [-1, 1])
- guess(states=None, controls=None, initial_time=None, terminal_time=None, integrals=None)[source]#
Provide initial guess for this phase’s optimization variables.
Supplies starting values for NLP solver with phase-specific variable coverage. Arrays must match this phase’s mesh configuration exactly.
- Return type:
- Parameters:
states (Sequence[ndarray[tuple[int, ...], dtype[floating[Any]]] | ndarray[tuple[int, ...], dtype[integer[Any]]] | Sequence[float] | Sequence[int] | list[float] | list[int] | Sequence[Sequence[float]] | Sequence[Sequence[int]] | list[list[float]] | list[list[int]]] | None)
controls (Sequence[ndarray[tuple[int, ...], dtype[floating[Any]]] | ndarray[tuple[int, ...], dtype[integer[Any]]] | Sequence[float] | Sequence[int] | list[float] | list[int] | Sequence[Sequence[float]] | Sequence[Sequence[int]] | list[list[float]] | list[list[int]]] | None)
initial_time (float | None)
terminal_time (float | None)
integrals (float | ndarray[tuple[int, ...], dtype[floating[Any]]] | ndarray[tuple[int, ...], dtype[integer[Any]]] | Sequence[float] | Sequence[int] | list[float] | list[int] | Sequence[Sequence[float]] | Sequence[Sequence[int]] | list[list[float]] | list[list[int]] | None)
- Args:
- states: State trajectory guess per mesh interval.
Structure: [interval_arrays] Each interval_array: shape (num_states, num_collocation_points)
- controls: Control trajectory guess per mesh interval.
Structure: [interval_arrays] Each interval_array: shape (num_controls, num_mesh_points)
initial_time: Initial time guess for this phase.
terminal_time: Final time guess for this phase.
- integrals: Integral value guess for this phase.
float: Single integral
array: Multiple integrals
- Examples:
Basic single phase:
>>> states_guess = [np.array([[0, 1, 2, 3, 4], [0, 0, 1, 2, 3]])] >>> controls_guess = [np.array([[1, 1, 1, 1]])] >>> phase.guess(states=states_guess, controls=controls_guess, terminal_time=10.0)
With integrals:
>>> phase.guess(states=states_guess, integrals=50.0)
- class maptor.problem.core_problem.Problem(name='Multiphase Problem')[source]#
Bases:
object
Multiphase optimal control problem definition and configuration interface.
The Problem class is the main entry point for defining optimal control problems in MAPTOR. It supports both single-phase and multiphase trajectory optimization with automatic phase linking, static parameter optimization, and comprehensive constraint specification.
Key capabilities:
Multiphase trajectory definition with automatic continuity
Static parameter optimization (design variables)
Flexible objective functions (minimize/maximize any expression)
Initial guess specification for improved convergence
Solver configuration and validation
Cross-phase constraints and event handling
The Problem follows a builder pattern where you incrementally define phases, variables, dynamics, constraints, and objectives before solving.
- Examples:
Single-phase minimum time problem:
>>> import maptor as mtor >>> >>> problem = mtor.Problem("Minimum Time") >>> phase = problem.set_phase(1) >>> >>> # Variables and dynamics >>> t = phase.time(initial=0.0) >>> x = phase.state("position", initial=0, final=1) >>> v = phase.state("velocity", initial=0) >>> u = phase.control("force", boundary=(-1, 1)) >>> >>> phase.dynamics({x: v, v: u}) >>> problem.minimize(t.final) >>> >>> # Solve >>> phase.mesh([5, 5], [-1, 0, 1]) >>> solution = mtor.solve_fixed_mesh(problem)
Multiphase rocket trajectory:
>>> problem = mtor.Problem("Rocket Launch") >>> >>> # Boost phase >>> boost = problem.set_phase(1) >>> t1 = boost.time(initial=0, final=120) >>> h1 = boost.state("altitude", initial=0) >>> v1 = boost.state("velocity", initial=0) >>> m1 = boost.state("mass", initial=1000) >>> T1 = boost.control("thrust", boundary=(0, 2000)) >>> >>> boost.dynamics({ ... h1: v1, ... v1: T1/m1 - 9.81, ... m1: -T1 * 0.001 ... }) >>> >>> # Coast phase with automatic continuity >>> coast = problem.set_phase(2) >>> t2 = coast.time(initial=t1.final, final=300) >>> h2 = coast.state("altitude", initial=h1.final) >>> v2 = coast.state("velocity", initial=v1.final) >>> m2 = coast.state("mass", initial=m1.final) >>> >>> coast.dynamics({h2: v2, v2: -9.81, m2: 0}) >>> >>> # Objective and solve >>> problem.minimize(-h2.final) # Maximize final altitude >>> # ... mesh configuration and solve
Problem with static parameters:
>>> problem = mtor.Problem("Design Optimization") >>> >>> # Design parameters to optimize >>> engine_mass = problem.parameter("engine_mass", boundary=(50, 200)) >>> thrust_level = problem.parameter("max_thrust", boundary=(1000, 5000)) >>> >>> # Use parameters in dynamics >>> total_mass = vehicle_mass + engine_mass >>> phase.dynamics({v: thrust_level/total_mass - 9.81}) >>> >>> # Multi-objective: maximize performance, minimize mass >>> performance = altitude.final >>> mass_penalty = engine_mass * 10 >>> problem.minimize(mass_penalty - performance)
- Parameters:
name (str)
- __init__(name='Multiphase Problem')[source]#
Initialize a new optimal control problem.
- Args:
name: Descriptive name for the problem (used in logging and output)
- Examples:
>>> problem = mtor.Problem("Spacecraft Trajectory") >>> problem = mtor.Problem("Robot Path Planning") >>> problem = mtor.Problem() # Uses default name
- Parameters:
name (str)
- Return type:
None
- set_phase(phase_id)[source]#
Create and configure a new phase in the multiphase problem.
Each phase represents a distinct segment of the trajectory with its own time domain, dynamics, and constraints. Phases can be linked through symbolic boundary constraints for trajectory continuity.
- Args:
- phase_id: Unique integer identifier for this phase. Phases are solved
in order of their IDs, so use sequential numbering (1, 2, 3…).
- Returns:
Phase: Phase object for defining variables, dynamics, and constraints
- Raises:
ValueError: If phase_id already exists
- Examples:
Single phase problem:
>>> problem = mtor.Problem("Single Phase") >>> phase = problem.set_phase(1) >>> # Define phase variables, dynamics, constraints...
Sequential multiphase problem:
>>> problem = mtor.Problem("Three Phase Mission") >>> >>> # Launch phase >>> launch = problem.set_phase(1) >>> # ... configure launch phase >>> >>> # Coast phase >>> coast = problem.set_phase(2) >>> # ... configure coast phase >>> >>> # Landing phase >>> landing = problem.set_phase(3) >>> # ... configure landing phase
Phase naming convention:
>>> # Use descriptive variable names for clarity >>> ascent_phase = problem.set_phase(1) >>> orbit_phase = problem.set_phase(2) >>> descent_phase = problem.set_phase(3)
- parameter(name, boundary=None)[source]#
Define a static parameter for design optimization with exhaustive constraint syntax.
Creates optimization variables that remain constant throughout the mission but can be varied to optimize performance. Supports all constraint types for comprehensive design space specification.
- Return type:
MX
- Parameters:
- Args:
name: Unique parameter name boundary: Parameter constraint with full syntax:
float: Fixed parameter value (e.g., 1000.0)
(lower, upper): Bounded parameter range (e.g., (100, 500))
(None, upper): Upper bounded only (e.g., (None, 1000))
(lower, None): Lower bounded only (e.g., (0, None))
None: Unconstrained parameter
- Returns:
ca.MX: Parameter variable for use across all phases
- Examples:
Bounded parameter:
>>> mass = problem.parameter("mass", boundary=(100, 500))
Single-sided bounds:
>>> area = problem.parameter("area", boundary=(10, None)) >>> drag = problem.parameter("drag", boundary=(None, 0.5))
Fixed parameter:
>>> gravity = problem.parameter("gravity", boundary=9.81)
Unconstrained:
>>> free_param = problem.parameter("design_var")
- parameter_guess(**parameter_guesses)[source]#
Set initial guesses for static parameters.
- Args:
**parameter_guesses: Parameter names mapped to guess values
- Examples:
>>> mass = problem.parameter("mass", boundary=(100, 500)) >>> drag = problem.parameter("drag", boundary=(0, 0.1)) >>> problem.parameter_guess(mass=300.0, drag=0.05)
- minimize(objective_expr)[source]#
Set objective function with comprehensive expression support.
Defines scalar optimization objective supporting final states, integral terms, static parameters, and complex multi-phase expressions. Can combine multiple objective components with arbitrary mathematical relationships.
- Args:
objective_expr: Scalar expression to minimize. Supports:
Final state values (state.final)
Integral terms (from add_integral())
Static parameters (from parameter())
Time variables (time.final)
Complex mathematical combinations
- Examples:
Minimum time:
>>> problem.minimize(t.final)
Final state:
>>> problem.minimize(-altitude.final) # Maximize altitude
Integral cost:
>>> energy = phase.add_integral(thrust**2) >>> problem.minimize(energy)
Multi-objective:
>>> fuel_cost = phase.add_integral(thrust * price) >>> time_cost = t.final * rate >>> problem.minimize(fuel_cost + time_cost)
Parameter optimization:
>>> mass = problem.parameter("mass") >>> problem.minimize(mass - performance)