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
Parameters:
__init__(problem, phase_id)[source]#
Parameters:
Return type:

None

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:

None

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.

Return type:

MX

Parameters:

integrand_expr (MX | float | int)

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.

Return type:

None

Parameters:

constraint_expressions (MX | float | int)

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

Return type:

None

Parameters:

constraint_expressions (MX | float | int)

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:

None

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:

None

Parameters:
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.

Return type:

Phase

Parameters:

phase_id (int)

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.

Return type:

None

Parameters:

parameter_guesses (float)

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.

Return type:

None

Parameters:

objective_expr (MX | float | int)

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)
validate_multiphase_configuration()[source]#
Return type:

None