mechanics_dsl package

Submodules

mechanics_dsl.compiler module

Main compiler and system serialization for MechanicsDSL

class mechanics_dsl.compiler.SystemSerializer[source]

Bases: object

Serialize and deserialize compiled physics systems

static export_system(compiler: PhysicsCompiler, filename: str, format: str = 'json') bool[source]

Export compiled system to file

Parameters:
  • compiler – PhysicsCompiler instance

  • filename – Output filename

  • format – Export format (‘json’ or ‘pickle’)

Returns:

True if successful

static import_system(filename: str, allow_pickle: bool = False) dict | None[source]

Import system state from file with validation.

Parameters:
  • filename – Input filename (validated)

  • allow_pickle – Required to be True to load .pkl/.pickle files. Pickle deserialization can execute arbitrary code, so this is refused by default. Only enable for fully trusted local files (e.g. ones you produced yourself).

Returns:

System state dictionary or None if failed

Raises:
  • TypeError – If filename is not a string

  • ValueError – If filename is invalid

  • FileNotFoundError – If file doesn’t exist

class mechanics_dsl.compiler.ParticleGenerator[source]

Bases: object

Generates discrete particle positions from geometric regions

static generate(region: RegionDef, spacing: float) List[Tuple[float, float]][source]

Generate grid of particles within a region.

class mechanics_dsl.compiler.PhysicsCompiler[source]

Bases: object

Main compiler class.

Production-ready physics DSL compiler with comprehensive validation, cross-platform support, and security hardening.

Features: - Cross-platform timeout support (Windows/Unix) - Safe AST-based parsing (no eval()) - Comprehensive input validation - Specific exception handling - Extensive type hints - Production-ready error recovery

Example

>>> compiler = PhysicsCompiler()
>>> result = compiler.compile_dsl("\system{pendulum}\lagrangian{x^2}")
>>> if result['success']:
...     solution = compiler.simulate((0, 10))
...     compiler.animate(solution)
cleanup() None[source]

Cleanup resources and trigger garbage collection.

compile_dsl(dsl_source: str, use_hamiltonian: bool = False, use_constraints: bool = True) dict[source]

Complete compilation pipeline with comprehensive validation.

Parameters:
  • dsl_source – DSL source code (must be non-empty string)

  • use_hamiltonian – Force Hamiltonian formulation

  • use_constraints – Apply constraint handling

Returns:

Compilation result dictionary with ‘success’ key

Raises:
  • TypeError – If dsl_source is not a string

  • ValueError – If dsl_source is empty or invalid

Example

>>> compiler = PhysicsCompiler()
>>> result = compiler.compile_dsl(r"\system{test}\lagrangian{x^2}")
>>> assert result['success']
analyze_semantics()[source]

Extract system information from AST

get_coordinates() List[str][source]

Extract generalized coordinates (exclude constants).

Uses the registry module’s is_likely_coordinate() function to determine which variables are dynamic coordinates vs. constants/parameters.

Returns:

List of coordinate variable names

process_fluids()[source]

Generate particles for all fluid and boundary definitions

derive_equations() Dict[str, Expr][source]

Derive equations using Lagrangian formulation (Patched for Forces)

derive_constrained_equations() Dict[str, Expr][source]

Derive equations with constraints using Lagrange multipliers

derive_hamiltonian_equations() Tuple[List[Expr], List[Expr]][source]

Derive equations using Hamiltonian formulation

setup_simulation(equations)[source]

Configure numerical simulator

simulate(t_span: Tuple[float, float] = (0, 10), num_points: int = 1000, **kwargs) dict[source]

Run numerical simulation

animate(solution: dict, show: bool = True)[source]

Create animation from solution

export_animation(solution: dict, filename: str, fps: int = 30, dpi: int = 100) str[source]

Export animation to file

plot_energy(solution: dict)[source]

Plot energy analysis

plot_phase_space(solution: dict, coordinate_index: int = 0)[source]

Plot phase space

print_equations()[source]

Print derived equations

get_info() dict[source]

Get comprehensive system information

export_system(filename: str, format: str = 'json') bool[source]

Export system state to file

export(target: str, filename: str) str[source]

Generate standalone simulation code for a target language.

Parameters:
  • target – Target language identifier (see _GENERATOR_REGISTRY for the list, e.g. ‘cpp’, ‘python’, ‘rust’, ‘julia’, ‘cuda’, …).

  • filename – Output file path for the generated source.

Returns:

Path to the generated file.

Raises:
  • ValueError – If target is not supported or the compiler has no equations yet.

  • IOError – If the file cannot be written.

static import_system(filename: str, allow_pickle: bool = False) PhysicsCompiler | None[source]

Import system state from file.

See SystemSerializer.import_system for the semantics of allow_pickle; pickle loading is refused by default.

compile_to_cpp(filename: str = 'simulation.cpp', target: str = 'standard', compile_binary: bool = True) bool[source]

Generate C++ code for multiple targets.

Parameters:
  • filename – Output filename

  • target – ‘standard’, ‘raylib’, ‘arduino’, ‘wasm’, ‘openmp’, ‘python’

  • compile_binary – Whether to run the compiler (g++, emcc, etc.)

mechanics_dsl.solver module

MechanicsDSL Solver Package

This package provides numerical simulation capabilities for physics systems defined in MechanicsDSL.

Modules:

core: Main NumericalSimulator class symplectic: Structure-preserving symplectic integrators for Hamiltonian systems variational: Discrete variational integrators from Hamilton’s principle

Symplectic Integrators:

StormerVerlet, Leapfrog, Yoshida4, Ruth3, McLachlan4 - Preserve symplectic structure and bounded energy error - Ideal for long-time integration of Hamiltonian systems

Variational Integrators:

MidpointVariational, TrapezoidalVariational, GalerkinVariational - Derived from discrete Hamilton’s principle - Exactly preserve momentum maps (Noether’s theorem)

Quick Start:
>>> from mechanics_dsl.solver import NumericalSimulator
>>> from mechanics_dsl.solver.symplectic import StormerVerlet
>>> verlet = StormerVerlet()
>>> result = verlet.integrate(t_span, q0, p0, h, grad_T, grad_V)
class mechanics_dsl.solver.NumericalSimulator(symbolic_engine: SymbolicEngine)[source]

Bases: object

Enhanced numerical simulator with better stability and diagnostics

set_parameters(params: Dict[str, float])[source]

Set physical parameters

set_initial_conditions(conditions: Dict[str, float])[source]

Set initial conditions

add_constraint(constraint_expr: Expr)[source]

Add a constraint equation

compile_equations(accelerations: Dict[str, Expr], coordinates: List[str])[source]

Compile symbolic equations to numerical functions

compile_hamiltonian_equations(q_dots: List[Expr], p_dots: List[Expr], coordinates: List[str])[source]

Compile Hamiltonian equations

equations_of_motion(t: float, y: ndarray) ndarray[source]

ODE system for numerical integration with comprehensive bounds checking and validation.

Parameters:
  • t – Current time

  • y – State vector

Returns:

Derivative vector dydt

simulate(t_span: Tuple[float, float], num_points: int = 1000, method: str = None, rtol: float = None, atol: float = None, detect_stiff: bool = True) dict[source]

Run numerical simulation with adaptive integration and diagnostics.

Parameters:
  • t_span – Time span (t_start, t_end) where t_start < t_end

  • num_points – Number of output points (must be >= 2)

  • method – Integration method (‘RK45’, ‘LSODA’, ‘Radau’, etc.)

  • rtol – Relative tolerance (must be in (0, 1))

  • atol – Absolute tolerance (must be positive)

  • detect_stiff – Whether to detect stiff systems

Returns:

Dictionary with solution data and metadata, always contains ‘success’ key

Raises:
  • TypeError – If arguments have wrong types

  • ValueError – If arguments are out of valid ranges

Example

>>> solution = simulator.simulate((0, 10), num_points=1000)
>>> if solution['success']:
...     t = solution['t']
...     y = solution['y']
async simulate_async(t_span: Tuple[float, float], num_points: int = 1000, method: str | None = None, rtol: float | None = None, atol: float | None = None, detect_stiff: bool = True, executor: Executor | None = None) Dict[str, Any][source]

Run numerical simulation asynchronously.

This method runs the simulation in a thread pool executor to avoid blocking the event loop. Useful for: - Jupyter notebooks (keeps the kernel responsive) - Async web backends (FastAPI, aiohttp) - GUI applications with async event loops

Parameters:
  • t_span – Time span (t_start, t_end)

  • num_points – Number of output points

  • method – Integration method (‘RK45’, ‘LSODA’, ‘Radau’, etc.)

  • rtol – Relative tolerance

  • atol – Absolute tolerance

  • detect_stiff – Whether to detect stiff systems

  • executor – Optional custom executor (defaults to ThreadPoolExecutor)

Returns:

Dictionary with solution data and metadata

Example

>>> import asyncio
>>> async def main():
...     result = await simulator.simulate_async((0, 10), num_points=1000)
...     print(f"Success: {result['success']}")
>>> asyncio.run(main())

Note

For CPU-bound simulations, consider using ProcessPoolExecutor for true parallelism (requires picklable equations).

async simulate_batch_async(simulations: List[Dict[str, Any]], max_concurrent: int = 4) List[Dict[str, Any]][source]

Run multiple simulations concurrently.

Useful for parameter sweeps, sensitivity analysis, or ensemble simulations where many similar systems need to be simulated.

Parameters:
  • simulations – List of simulation parameter dicts, each containing: - t_span: Tuple[float, float] (required) - num_points: int (optional, default 1000) - method: str (optional) - rtol: float (optional) - atol: float (optional)

  • max_concurrent – Maximum concurrent simulations

Returns:

List of simulation results in the same order as input

Example

>>> simulations = [
...     {'t_span': (0, 10), 'num_points': 500},
...     {'t_span': (0, 20), 'num_points': 1000},
... ]
>>> results = await simulator.simulate_batch_async(simulations)
class mechanics_dsl.solver.SymplecticIntegrator[source]

Bases: ABC

Base class for symplectic integrators.

All symplectic integrators work with Hamiltonian systems of the form:

dq/dt = ∂H/∂p dp/dt = -∂H/∂q

For separable Hamiltonians H(q,p) = T(p) + V(q):

dq/dt = ∂T/∂p = p/m (for standard kinetic energy) dp/dt = -∂V/∂q = F(q) (generalized force)

abstract property order: int

Order of accuracy of the integrator.

abstract property name: str

Human-readable name of the integrator.

abstract step(t: float, q: ndarray, p: ndarray, h: float, grad_T: Callable[[ndarray], ndarray], grad_V: Callable[[ndarray], ndarray]) Tuple[ndarray, ndarray][source]

Perform one integration step.

Parameters:
  • t – Current time

  • q – Position vector

  • p – Momentum vector

  • h – Step size

  • grad_T – Gradient of kinetic energy w.r.t. momentum (∂T/∂p)

  • grad_V – Gradient of potential energy w.r.t. position (∂V/∂q)

Returns:

Tuple of (new_q, new_p) after one step

integrate(t_span: Tuple[float, float], q0: ndarray, p0: ndarray, h: float, grad_T: Callable[[ndarray], ndarray], grad_V: Callable[[ndarray], ndarray], t_eval: ndarray | None = None, max_steps: int = 100000) Dict[str, ndarray][source]

Integrate the system from t_span[0] to t_span[1].

Parameters:
  • t_span – (t_start, t_end)

  • q0 – Initial positions

  • p0 – Initial momenta

  • h – Fixed step size

  • grad_T – Gradient of kinetic energy

  • grad_V – Gradient of potential energy

  • t_eval – Optional times at which to evaluate solution

  • max_steps – Maximum integration steps

Returns:

  • ‘t’: Time array

  • ’q’: Position array (shape: n_coords x n_times)

  • ’p’: Momentum array (shape: n_coords x n_times)

  • ’success’: Boolean indicating success

  • ’message’: Status message

Return type:

Dictionary with keys

class mechanics_dsl.solver.StormerVerlet[source]

Bases: SymplecticIntegrator

Störmer-Verlet integrator (2nd order, explicit symplectic).

The velocity Verlet formulation:

p_half = p_n - (h/2) * ∇V(q_n) q_{n+1} = q_n + h * ∇T(p_half) p_{n+1} = p_half - (h/2) * ∇V(q_{n+1})

Properties: - 2nd order accurate - Symplectic - Time-reversible - Explicit (no implicit solves needed for separable H) - Energy oscillates around true value, bounded error

property order: int

Order of accuracy of the integrator.

property name: str

Human-readable name of the integrator.

step(t, q, p, h, grad_T, grad_V)[source]

Perform one integration step.

Parameters:
  • t – Current time

  • q – Position vector

  • p – Momentum vector

  • h – Step size

  • grad_T – Gradient of kinetic energy w.r.t. momentum (∂T/∂p)

  • grad_V – Gradient of potential energy w.r.t. position (∂V/∂q)

Returns:

Tuple of (new_q, new_p) after one step

class mechanics_dsl.solver.Leapfrog[source]

Bases: SymplecticIntegrator

Leapfrog integrator (2nd order, explicit symplectic).

Mathematically equivalent to Störmer-Verlet but with staggered storage pattern. Often preferred for N-body simulations.

Algorithm:

q_{n+1} = q_n + h * ∇T(p_{n+1/2}) p_{n+3/2} = p_{n+1/2} - h * ∇V(q_{n+1})

property order: int

Order of accuracy of the integrator.

property name: str

Human-readable name of the integrator.

step(t, q, p, h, grad_T, grad_V)[source]

Perform one integration step.

Parameters:
  • t – Current time

  • q – Position vector

  • p – Momentum vector

  • h – Step size

  • grad_T – Gradient of kinetic energy w.r.t. momentum (∂T/∂p)

  • grad_V – Gradient of potential energy w.r.t. position (∂V/∂q)

Returns:

Tuple of (new_q, new_p) after one step

class mechanics_dsl.solver.Yoshida4[source]

Bases: SymplecticIntegrator

Yoshida 4th order symplectic integrator.

Composition method using triple-jump technique:

S_h = S_{c_1 h} ∘ S_{c_2 h} ∘ S_{c_1 h}

where S is the 2nd order Störmer-Verlet step.

Coefficients:

c_1 = 1/(2 - 2^(1/3)) c_2 = -2^(1/3)/(2 - 2^(1/3))

Properties: - 4th order accurate - Symplectic - 3 stages (force evaluations per step) - Time-reversible

Reference:

Yoshida, “Construction of higher order symplectic integrators” Physics Letters A, 150 (1990)

property order: int

Order of accuracy of the integrator.

property name: str

Human-readable name of the integrator.

step(t, q, p, h, grad_T, grad_V)[source]

Perform one integration step.

Parameters:
  • t – Current time

  • q – Position vector

  • p – Momentum vector

  • h – Step size

  • grad_T – Gradient of kinetic energy w.r.t. momentum (∂T/∂p)

  • grad_V – Gradient of potential energy w.r.t. position (∂V/∂q)

Returns:

Tuple of (new_q, new_p) after one step

class mechanics_dsl.solver.Ruth3[source]

Bases: SymplecticIntegrator

Ruth 3rd order symplectic integrator.

Minimal-stage 3rd order method using composition:

S_h = A_{c_1 h} ∘ B_{d_1 h} ∘ A_{c_2 h} ∘ B_{d_2 h} ∘ A_{c_3 h} ∘ B_{d_3 h}

where A is the momentum kick and B is the position drift.

Coefficients (Ruth):

c1 = 7/24, c2 = 3/4, c3 = -1/24 d1 = 2/3, d2 = -2/3, d3 = 1

Properties: - 3rd order accurate - Symplectic - 3 stages

Reference:

Ruth, “A canonical integration technique” (1983)

property order: int

Order of accuracy of the integrator.

property name: str

Human-readable name of the integrator.

step(t, q, p, h, grad_T, grad_V)[source]

Perform one integration step.

Parameters:
  • t – Current time

  • q – Position vector

  • p – Momentum vector

  • h – Step size

  • grad_T – Gradient of kinetic energy w.r.t. momentum (∂T/∂p)

  • grad_V – Gradient of potential energy w.r.t. position (∂V/∂q)

Returns:

Tuple of (new_q, new_p) after one step

class mechanics_dsl.solver.McLachlan4[source]

Bases: SymplecticIntegrator

McLachlan 4th order symplectic integrator with optimal coefficients.

This method minimizes the error constant while maintaining 4th order. Uses a 5-stage composition with optimized coefficients.

Properties: - 4th order accurate - Symplectic - 5 stages - Smaller error constant than Yoshida-4

Reference:

McLachlan, “On the numerical integration of ODEs by symmetric composition methods” (1995)

property order: int

Order of accuracy of the integrator.

property name: str

Human-readable name of the integrator.

step(t, q, p, h, grad_T, grad_V)[source]

Perform one integration step.

Parameters:
  • t – Current time

  • q – Position vector

  • p – Momentum vector

  • h – Step size

  • grad_T – Gradient of kinetic energy w.r.t. momentum (∂T/∂p)

  • grad_V – Gradient of potential energy w.r.t. position (∂V/∂q)

Returns:

Tuple of (new_q, new_p) after one step

mechanics_dsl.solver.get_symplectic_integrator(name: str) SymplecticIntegrator[source]

Get a symplectic integrator by name.

Parameters:

name – One of ‘verlet’, ‘leapfrog’, ‘yoshida4’, ‘yoshida6’, ‘yoshida8’, ‘ruth3’, ‘mclachlan4’, ‘pefrl’

Returns:

SymplecticIntegrator instance

class mechanics_dsl.solver.VariationalIntegrator(config: VariationalConfig | None = None)[source]

Bases: ABC

Base class for variational integrators.

Variational integrators discretize the action integral and derive the discrete Euler-Lagrange equations:

D_2 L_d(q_{k-1}, q_k) + D_1 L_d(q_k, q_{k+1}) = 0

The discrete Lagrangian L_d(q_k, q_{k+1}, h) approximates: ∫_{t_k}^{t_{k+1}} L(q, q̇) dt

abstract property order: int

Order of accuracy.

abstract property name: str

Human-readable name.

abstract discrete_lagrangian(q0: ndarray, q1: ndarray, h: float, lagrangian: Callable[[ndarray, ndarray], float]) float[source]

Compute discrete Lagrangian L_d(q0, q1, h).

Parameters:
  • q0 – Configuration at t_k

  • q1 – Configuration at t_{k+1}

  • h – Time step

  • lagrangian – Continuous Lagrangian L(q, q_dot) -> float

Returns:

Approximation to ∫_{t_k}^{t_{k+1}} L(q, q̇) dt

discrete_equations(q_prev: ndarray, q_curr: ndarray, q_next: ndarray, h: float, lagrangian: Callable) ndarray[source]

Evaluate discrete Euler-Lagrange equations: D_2 L_d(q_{k-1}, q_k) + D_1 L_d(q_k, q_{k+1}) = 0

Returns:

Residual of the discrete EL equations

step(q_prev: ndarray, q_curr: ndarray, h: float, lagrangian: Callable) ndarray[source]

Compute q_{k+1} given q_{k-1} and q_k using Newton iteration.

Solves: D_2 L_d(q_{k-1}, q_k) + D_1 L_d(q_k, q_{k+1}) = 0

integrate(t_span: Tuple[float, float], q0: ndarray, q_dot0: ndarray, h: float, lagrangian: Callable[[ndarray, ndarray], float], max_steps: int = 100000) Dict[str, ndarray][source]

Integrate using the variational method.

Parameters:
  • t_span – (t_start, t_end)

  • q0 – Initial configuration

  • q_dot0 – Initial velocity

  • h – Time step

  • lagrangian – L(q, q_dot) -> float

  • max_steps – Maximum steps

Returns:

Dictionary with ‘t’, ‘q’, ‘q_dot’, ‘success’, ‘message’

class mechanics_dsl.solver.MidpointVariational(config: VariationalConfig | None = None)[source]

Bases: VariationalIntegrator

Midpoint rule variational integrator.

Discrete Lagrangian:

L_d(q0, q1, h) = h * L((q0 + q1)/2, (q1 - q0)/h)

This is equivalent to the implicit midpoint rule, which is symplectic and 2nd order accurate.

property order: int

Order of accuracy.

property name: str

Human-readable name.

discrete_lagrangian(q0, q1, h, lagrangian)[source]

Compute discrete Lagrangian L_d(q0, q1, h).

Parameters:
  • q0 – Configuration at t_k

  • q1 – Configuration at t_{k+1}

  • h – Time step

  • lagrangian – Continuous Lagrangian L(q, q_dot) -> float

Returns:

Approximation to ∫_{t_k}^{t_{k+1}} L(q, q̇) dt

class mechanics_dsl.solver.TrapezoidalVariational(config: VariationalConfig | None = None)[source]

Bases: VariationalIntegrator

Trapezoidal rule variational integrator.

Discrete Lagrangian:

L_d(q0, q1, h) = (h/2) * [L(q0, (q1-q0)/h) + L(q1, (q1-q0)/h)]

This is 2nd order accurate and symmetric.

property order: int

Order of accuracy.

property name: str

Human-readable name.

discrete_lagrangian(q0, q1, h, lagrangian)[source]

Compute discrete Lagrangian L_d(q0, q1, h).

Parameters:
  • q0 – Configuration at t_k

  • q1 – Configuration at t_{k+1}

  • h – Time step

  • lagrangian – Continuous Lagrangian L(q, q_dot) -> float

Returns:

Approximation to ∫_{t_k}^{t_{k+1}} L(q, q̇) dt

class mechanics_dsl.solver.GalerkinVariational(num_points: int = 2, config: VariationalConfig | None = None)[source]

Bases: VariationalIntegrator

Galerkin variational integrator using polynomial approximation.

Uses Gauss-Legendre quadrature for higher-order accuracy. This method achieves 2s order accuracy with s Gauss points.

Default: 2 Gauss points → 4th order accuracy

property order: int

Order of accuracy.

property name: str

Human-readable name.

discrete_lagrangian(q0, q1, h, lagrangian)[source]

Use Gauss-Legendre quadrature on [0, h].

mechanics_dsl.solver.get_variational_integrator(name: str) VariationalIntegrator[source]

Get a variational integrator by name.

mechanics_dsl.symbolic module

Symbolic computation engine for MechanicsDSL

class mechanics_dsl.symbolic.SymbolicEngine(use_weak_refs: bool = False)[source]

Bases: object

Enhanced symbolic mathematics engine with advanced caching and performance monitoring

get_symbol(name: str, **assumptions) Symbol[source]

Get or create a SymPy symbol with assumptions (cached)

clear_cache() int[source]

Clear all caches to free memory.

Useful for long-running applications that process many different mechanical systems. Clears: - LRU expression cache - Symbol map (keeps time_symbol) - Function map

Returns:

Number of cached items cleared

Example

>>> engine = SymbolicEngine()
>>> # ... do lots of computation ...
>>> cleared = engine.clear_cache()
>>> print(f"Freed {cleared} cached items")
memory_stats() Dict[str, int][source]

Get memory usage statistics.

Returns:

Dictionary with counts of cached items by category

get_function(name: str) Function[source]

Get or create a SymPy function (cached)

ast_to_sympy(expr: Expression) Expr[source]

Convert AST expression to SymPy with comprehensive support and caching

Parameters:

expr – AST expression node

Returns:

SymPy expression

derive_equations_of_motion(lagrangian: Expr, coordinates: List[str]) List[Expr][source]

Derive Euler-Lagrange equations from Lagrangian

Parameters:
  • lagrangian – Lagrangian expression

  • coordinates – List of generalized coordinates

Returns:

List of equations of motion

Note

The Euler-Lagrange equations are: d/dt(∂L/∂q̇ᵢ) - ∂L/∂qᵢ = 0

For coupled systems (e.g., double pendulum), ALL coordinates must be treated as functions of time simultaneously to correctly compute cross-coupling terms like ∂²θ₂/∂t² appearing in the θ₁ equation.

derive_equations_with_constraints(lagrangian: Expr, coordinates: List[str], constraints: List[Expr]) Tuple[List[Expr], List[str]][source]

Derive equations with holonomic constraints using Lagrange multipliers

Parameters:
  • lagrangian – Lagrangian expression

  • coordinates – List of generalized coordinates

  • constraints – List of constraint expressions

Returns:

Tuple of (augmented equations, extended coordinates including lambdas)

derive_hamiltonian_equations(hamiltonian: Expr, coordinates: List[str]) Tuple[List[Expr], List[Expr]][source]

Derive Hamilton’s equations from Hamiltonian

Hamilton’s equations: dq/dt = ∂H/∂p dp/dt = -∂H/∂q

Parameters:
  • hamiltonian – Hamiltonian expression

  • coordinates – List of generalized coordinates

Returns:

Tuple of (q_dot equations, p_dot equations)

lagrangian_to_hamiltonian(lagrangian: Expr, coordinates: List[str]) Expr[source]

Convert Lagrangian to Hamiltonian via Legendre transform

H = Σ(p_i * q̇_i) - L where p_i = ∂L/∂q̇_i

Parameters:
  • lagrangian – Lagrangian expression

  • coordinates – List of generalized coordinates

Returns:

Hamiltonian expression

solve_for_accelerations(equations: List[Expr], coordinates: List[str]) Dict[str, Expr][source]

Solve equations of motion for accelerations SIMULTANEOUSLY.

For coupled systems like double pendulum, accelerations are interdependent: M * [q1_ddot, q2_ddot, …]^T = F

This function: 1. Substitutes all derivative notations with symbols 2. Extracts the mass matrix M and force vector F 3. Solves the linear system M*a = F simultaneously 4. Returns simplified acceleration expressions

This is CRITICAL for coupled systems where accelerations appear in each other’s equations.

mechanics_dsl.parser module

MechanicsDSL Parser Package

This package provides the parsing infrastructure for converting MechanicsDSL source code into an Abstract Syntax Tree (AST) for compilation.

Modules:

tokens: Token definitions and tokenization. ast_nodes: AST node dataclass definitions. core: MechanicsParser class implementation.

Quick Start:
>>> from mechanics_dsl.parser import tokenize, MechanicsParser
>>> tokens = tokenize(r"\system{pendulum} \lagrangian{T - V}")
>>> parser = MechanicsParser(tokens)
>>> ast = parser.parse()

The parser uses a recursive descent approach with operator precedence parsing for expressions. It handles: - System definitions and variables - Lagrangian and Hamiltonian mechanics - Constraints (holonomic and non-holonomic) - Forces and damping - Initial conditions - Coordinate transformations - SPH fluid definitions

class mechanics_dsl.parser.Token(type: str, value: str, position: int = 0, line: int = 1, column: int = 1)[source]

Bases: object

Token with position tracking for better error messages.

type

The token type (e.g., ‘IDENT’, ‘NUMBER’, ‘LAGRANGIAN’).

Type:

str

value

The raw string value matched from source.

Type:

str

position

Character position in source (0-indexed).

Type:

int

line

Line number (1-indexed).

Type:

int

column

Column number (1-indexed).

Type:

int

Example

>>> token = Token('IDENT', 'theta', position=10, line=2, column=5)
>>> print(token)
IDENT:theta@2:5
type: str
value: str
position: int = 0
line: int = 1
column: int = 1
mechanics_dsl.parser.tokenize(source: str) List[Token][source]

Tokenize DSL source code with position tracking.

Converts a string of MechanicsDSL code into a list of tokens, excluding whitespace and comments. Unrecognized characters are reported as a single error rather than silently dropped.

Parameters:

source – DSL source code string.

Returns:

List of Token objects (excluding whitespace and comments).

Raises:

ValueError – If the source contains characters that do not match any token pattern (e.g. @, $, &).

Example

>>> tokens = tokenize(r"\lagrangian{T - V}")
>>> [t.type for t in tokens]
['LAGRANGIAN', 'LBRACE', 'IDENT', 'MINUS', 'IDENT', 'RBRACE']
class mechanics_dsl.parser.MechanicsParser(tokens: List[Token])[source]

Bases: object

Recursive descent parser for MechanicsDSL.

Converts a list of tokens into an Abstract Syntax Tree (AST) that can be compiled into equations of motion.

tokens

List of Token objects to parse.

pos

Current position in token stream.

current_system

Name of current system being parsed.

errors

List of parsing errors encountered.

max_errors

Maximum errors before giving up (from config).

parse()[source]

Parse complete token stream into AST.

peek(offset)[source]

Look ahead at tokens.

match(*types)[source]

Match and consume token if type matches.

expect(type)[source]

Require specific token type.

Example

>>> tokens = tokenize(r"\lagrangian{T - V}")
>>> parser = MechanicsParser(tokens)
>>> ast = parser.parse()
>>> print(ast[0])
Lagrangian(...)
peek(offset: int = 0) Token | None[source]

Look ahead at token without consuming it.

Parameters:

offset – Number of tokens to look ahead (default 0).

Returns:

Token at position pos+offset, or None if past end.

match(*expected_types: str) Token | None[source]

Match and consume token if type matches.

Parameters:

*expected_types – One or more acceptable token types.

Returns:

Matched token if successful, None otherwise.

expect(expected_type: str) Token[source]

Expect a specific token type, raise error if not found.

Parameters:

expected_type – Required token type.

Returns:

The matched token.

Raises:

ParserError – If token doesn’t match expected type.

parse() List[ASTNode][source]

Parse the complete DSL with comprehensive error recovery.

Returns:

List of ASTNode objects representing the parsed program.

Note

The parser attempts error recovery to parse as much as possible even when errors are encountered.

parse_statement() ASTNode | None[source]

Parse a top-level statement.

parse_region() RegionDef[source]

Parse region{shape}{constraints}.

parse_fluid() FluidDef[source]

Parse fluid{name} with properties.

parse_boundary() BoundaryDef[source]

Parse boundary{name} region{…}.

parse_system() SystemDef[source]

Parse system{name}.

parse_defvar() VarDef[source]

Parse defvar{name}{type}{unit}.

parse_parameter() ParameterDef[source]

Parse parameter{name}{value}{unit}.

parse_define() DefineDef[source]

Parse define{op{name}(args) = expression}.

parse_lagrangian() LagrangianDef[source]

Parse lagrangian{expression}.

parse_hamiltonian() HamiltonianDef[source]

Parse hamiltonian{expression}.

parse_transform() TransformDef[source]

Parse transform{type}{var = expr}.

parse_constraint() ConstraintDef[source]

Parse constraint{expression}.

parse_nonholonomic() NonHolonomicConstraintDef[source]

Parse nonholonomic{expression}.

parse_force() ForceDef[source]

Parse a non-conservative force.

Two forms are supported:

force{expr} - applied positionally (legacy) force{coord}{expr} - applied to the named generalized coordinate

parse_damping() DampingDef[source]

Parse damping{expression}.

parse_rayleigh()[source]

Parse rayleigh{expression}.

The Rayleigh dissipation function F represents velocity-dependent dissipative forces. The generalized dissipative forces are: Q_i = -∂F/∂q̇_i

For linear damping: F = ½ Σ bᵢⱼ q̇ᵢ q̇ⱼ

Example

rayleigh{frac{1}{2} * b * dot{x}^2}

parse_initial() InitialCondition[source]

Parse initial{var1=val1, var2=val2, …}.

parse_solve() SolveDef[source]

Parse solve{method}.

parse_animate() AnimateDef[source]

Parse animate{target}.

parse_export() ExportDef[source]

Parse export{filename}.

parse_import() ImportDef[source]

Parse import{filename}.

parse_expression() Expression[source]

Parse expressions with full operator precedence.

parse_additive() Expression[source]

Addition and subtraction (lowest precedence).

parse_multiplicative() Expression[source]

Multiplication, division, and vector operations.

parse_power() Expression[source]

Exponentiation (right associative).

parse_unary() Expression[source]

Unary operators (+, -).

parse_postfix() Expression[source]

Function calls, subscripts, etc.

parse_primary() Expression[source]

Primary expressions: literals, identifiers, parentheses, vectors, commands.

parse_command(cmd: str) Expression[source]

Parse LaTeX-style commands.

at_end_of_expression() bool[source]

Check if we’re at the end of an expression.

expression_to_string(expr: Expression) str[source]

Convert expression back to string for unit parsing.

exception mechanics_dsl.parser.ParserError(message: str, token: Token | None = None)[source]

Bases: Exception

Custom exception for parser errors with position tracking.

Provides detailed error messages including line and column information when available from the token.

message

Error description.

token

Optional token where the error occurred.

Example

>>> try:
...     parser.expect("RBRACE")
... except ParserError as e:
...     print(e)
Expected RBRACE but got EOF at line 5, column 10
format_message() str[source]

Format error message with position information.

class mechanics_dsl.parser.ASTNode[source]

Bases: object

Base class for all AST nodes.

All AST nodes inherit from this class, providing a common interface for tree traversal and manipulation.

class mechanics_dsl.parser.Expression[source]

Bases: ASTNode

Base class for all expressions.

Expressions are AST nodes that evaluate to a value, as opposed to statements which perform actions.

class mechanics_dsl.parser.NumberExpr(value: float)[source]

Bases: Expression

Numeric literal expression.

value

The numeric value (float).

Type:

float

Example

>>> expr = NumberExpr(3.14159)
>>> print(expr)
Num(3.14159)
value: float
class mechanics_dsl.parser.IdentExpr(name: str)[source]

Bases: Expression

Identifier expression (variable name).

name

The identifier string.

Type:

str

Example

>>> expr = IdentExpr('theta')
>>> print(expr)
Id(theta)
name: str
class mechanics_dsl.parser.GreekLetterExpr(letter: str)[source]

Bases: Expression

Greek letter expression (e.g., alpha, omega).

letter

The Greek letter name (without backslash).

Type:

str

Example

>>> expr = GreekLetterExpr('omega')
>>> print(expr)
Greek(omega)
letter: str
class mechanics_dsl.parser.DerivativeVarExpr(var: str, order: int = 1)[source]

Bases: Expression

Derivative notation expression (dot{x} or ddot{x}).

Represents time derivatives using Newton’s dot notation.

var

The variable name being differentiated.

Type:

str

order

Order of derivative (1 for dot, 2 for ddot).

Type:

int

Example

>>> expr = DerivativeVarExpr('x', order=2)
>>> print(expr)
DerivativeVar(x, order=2)
var: str
order: int = 1
class mechanics_dsl.parser.BinaryOpExpr(left: Expression, operator: Literal['+', '-', '*', '/', '^'], right: Expression)[source]

Bases: Expression

Binary operation expression.

Represents operations with two operands: +, -, *, /, ^.

left

Left operand expression.

Type:

mechanics_dsl.parser.ast_nodes.Expression

operator

Operator symbol (+, -, *, /, ^).

Type:

Literal[‘+’, ‘-’, ‘*’, ‘/’, ‘^’]

right

Right operand expression.

Type:

mechanics_dsl.parser.ast_nodes.Expression

Example

>>> expr = BinaryOpExpr(IdentExpr('x'), '+', NumberExpr(1))
>>> print(expr)
BinOp(Id(x) + Num(1))
left: Expression
operator: Literal['+', '-', '*', '/', '^']
right: Expression
class mechanics_dsl.parser.UnaryOpExpr(operator: Literal['+', '-'], operand: Expression)[source]

Bases: Expression

Unary operation expression.

Represents unary + and - operators.

operator

Operator symbol (+ or -).

Type:

Literal[‘+’, ‘-’]

operand

The expression being operated on.

Type:

mechanics_dsl.parser.ast_nodes.Expression

Example

>>> expr = UnaryOpExpr('-', NumberExpr(5))
>>> print(expr)
UnaryOp(-Num(5))
operator: Literal['+', '-']
operand: Expression
class mechanics_dsl.parser.VectorExpr(components: List[Expression])[source]

Bases: Expression

Vector literal expression.

Represents a vector with multiple components.

components

List of component expressions.

Type:

List[mechanics_dsl.parser.ast_nodes.Expression]

Example

>>> expr = VectorExpr([IdentExpr('x'), IdentExpr('y'), IdentExpr('z')])
>>> print(expr)
Vector([Id(x), Id(y), Id(z)])
components: List[Expression]
class mechanics_dsl.parser.VectorOpExpr(operation: str, left: Expression, right: Expression | None = None)[source]

Bases: Expression

Vector operation expression.

Represents vector operations like dot product, cross product, gradient, divergence, and curl.

operation

Operation name (e.g., ‘dot’, ‘cross’, ‘grad’).

Type:

str

left

First operand expression.

Type:

mechanics_dsl.parser.ast_nodes.Expression

right

Optional second operand (for binary operations).

Type:

mechanics_dsl.parser.ast_nodes.Expression | None

Example

>>> expr = VectorOpExpr('cross', IdentExpr('A'), IdentExpr('B'))
>>> print(expr)
VectorOp(cross, Id(A), Id(B))
operation: str
left: Expression
right: Expression | None = None
class mechanics_dsl.parser.DerivativeExpr(expr: Expression, var: str, order: int = 1, partial: bool = False)[source]

Bases: Expression

Derivative expression.

Represents total or partial derivatives of expressions.

expr

The expression being differentiated.

Type:

mechanics_dsl.parser.ast_nodes.Expression

var

The variable of differentiation.

Type:

str

order

Order of the derivative (default 1).

Type:

int

partial

True for partial derivative, False for total.

Type:

bool

Example

>>> expr = DerivativeExpr(IdentExpr('f'), 'x', order=2, partial=True)
>>> print(expr)
PartialDeriv(Id(f), x, order=2)
expr: Expression
var: str
order: int = 1
partial: bool = False
class mechanics_dsl.parser.IntegralExpr(expr: Expression, var: str, lower: Expression | None = None, upper: Expression | None = None, line_integral: bool = False)[source]

Bases: Expression

Integral expression.

Represents definite and indefinite integrals, including line integrals.

expr

The integrand expression.

Type:

mechanics_dsl.parser.ast_nodes.Expression

var

The variable of integration.

Type:

str

lower

Optional lower bound expression.

Type:

mechanics_dsl.parser.ast_nodes.Expression | None

upper

Optional upper bound expression.

Type:

mechanics_dsl.parser.ast_nodes.Expression | None

line_integral

True for line integrals (oint).

Type:

bool

Example

>>> expr = IntegralExpr(IdentExpr('f'), 'x', NumberExpr(0), NumberExpr(1))
>>> print(expr)
Integral(Id(f), x, Num(0), Num(1))
expr: Expression
var: str
lower: Expression | None = None
upper: Expression | None = None
line_integral: bool = False
class mechanics_dsl.parser.FunctionCallExpr(name: str, args: List[Expression])[source]

Bases: Expression

Function call expression.

Represents calls to built-in or user-defined functions.

name

Function name.

Type:

str

args

List of argument expressions.

Type:

List[mechanics_dsl.parser.ast_nodes.Expression]

Example

>>> expr = FunctionCallExpr('sin', [IdentExpr('theta')])
>>> print(expr)
Call(sin, [Id(theta)])
name: str
args: List[Expression]
class mechanics_dsl.parser.FractionExpr(numerator: Expression, denominator: Expression)[source]

Bases: Expression

Fraction expression (frac{num}{denom}).

Represents fractions in LaTeX-style notation.

numerator

Numerator expression.

Type:

mechanics_dsl.parser.ast_nodes.Expression

denominator

Denominator expression.

Type:

mechanics_dsl.parser.ast_nodes.Expression

Example

>>> expr = FractionExpr(NumberExpr(1), NumberExpr(2))
>>> print(expr)
Frac(Num(1)/Num(2))
numerator: Expression
denominator: Expression
class mechanics_dsl.parser.SystemDef(name: str)[source]

Bases: ASTNode

System definition statement (system{name}).

Declares a new physics system by name.

name

The system name.

Type:

str

Example

>>> stmt = SystemDef('double_pendulum')
>>> print(stmt)
System(double_pendulum)
name: str
class mechanics_dsl.parser.VarDef(name: str, vartype: str, unit: str, vector: bool = False)[source]

Bases: ASTNode

Variable definition statement (defvar{name}{type}{unit}).

Defines a generalized coordinate or other variable.

name

Variable name.

Type:

str

vartype

Variable type (e.g., ‘Angle’, ‘Length’, ‘Vector’).

Type:

str

unit

Unit specification (e.g., ‘rad’, ‘m’).

Type:

str

vector

True if this is a vector variable.

Type:

bool

Example

>>> stmt = VarDef('theta', 'Angle', 'rad')
>>> print(stmt)
VarDef(theta: Angle[rad])
name: str
vartype: str
unit: str
vector: bool = False
class mechanics_dsl.parser.ParameterDef(name: str, value: float, unit: str)[source]

Bases: ASTNode

Parameter definition statement (parameter{name}{value}{unit}).

Defines a constant parameter with a value.

name

Parameter name.

Type:

str

value

Numeric value.

Type:

float

unit

Unit specification.

Type:

str

Example

>>> stmt = ParameterDef('g', 9.81, 'm/s^2')
>>> print(stmt)
Parameter(g = 9.81 [m/s^2])
name: str
value: float
unit: str
class mechanics_dsl.parser.DefineDef(name: str, args: List[str], body: Expression)[source]

Bases: ASTNode

Function definition statement (define{…}).

Defines a custom function or macro.

name

Function name.

Type:

str

args

List of argument names.

Type:

List[str]

body

Body expression.

Type:

mechanics_dsl.parser.ast_nodes.Expression

Example

>>> stmt = DefineDef('KE', ['m', 'v'], BinaryOpExpr(...))
>>> print(stmt)
Define(KE(m, v) = ...)
name: str
args: List[str]
body: Expression
class mechanics_dsl.parser.LagrangianDef(expr: Expression)[source]

Bases: ASTNode

Lagrangian definition statement (lagrangian{expr}).

Defines the system Lagrangian L = T - V.

expr

The Lagrangian expression.

Type:

mechanics_dsl.parser.ast_nodes.Expression

Example

>>> stmt = LagrangianDef(BinaryOpExpr(T, '-', V))
>>> print(stmt)
Lagrangian(...)
expr: Expression
class mechanics_dsl.parser.HamiltonianDef(expr: Expression)[source]

Bases: ASTNode

Hamiltonian definition statement (hamiltonian{expr}).

Defines the system Hamiltonian H = T + V.

expr

The Hamiltonian expression.

Type:

mechanics_dsl.parser.ast_nodes.Expression

expr: Expression
class mechanics_dsl.parser.TransformDef(coord_type: str, var: str, expr: Expression)[source]

Bases: ASTNode

Coordinate transform definition (transform{type}{var = expr}).

Defines a coordinate transformation.

coord_type

Type of coordinates (e.g., ‘polar’, ‘spherical’).

Type:

str

var

Variable being defined.

Type:

str

expr

Transformation expression.

Type:

mechanics_dsl.parser.ast_nodes.Expression

coord_type: str
var: str
expr: Expression
class mechanics_dsl.parser.ConstraintDef(expr: Expression, constraint_type: str = 'holonomic')[source]

Bases: ASTNode

Holonomic constraint definition (constraint{expr}).

Defines a position-dependent constraint.

expr

The constraint expression (should equal zero).

Type:

mechanics_dsl.parser.ast_nodes.Expression

constraint_type

Type of constraint (default ‘holonomic’).

Type:

str

expr: Expression
constraint_type: str = 'holonomic'
class mechanics_dsl.parser.NonHolonomicConstraintDef(expr: Expression)[source]

Bases: ASTNode

Non-holonomic constraint definition (nonholonomic{expr}).

Defines a velocity-dependent constraint that cannot be integrated.

expr

The constraint expression.

Type:

mechanics_dsl.parser.ast_nodes.Expression

expr: Expression
class mechanics_dsl.parser.ForceDef(expr: Expression, force_type: str = 'general', coordinate: str | None = None)[source]

Bases: ASTNode

Non-conservative force definition (force{expr}).

Defines a generalized force (non-conservative).

expr

The force expression.

Type:

mechanics_dsl.parser.ast_nodes.Expression

force_type

Type of force (‘friction’, ‘damping’, ‘drag’, ‘general’).

Type:

str

coordinate

Optional name of the generalized coordinate this force acts on. When None the force is applied positionally (legacy behavior).

Type:

str | None

expr: Expression
force_type: str = 'general'
coordinate: str | None = None
class mechanics_dsl.parser.DampingDef(expr: Expression, damping_coefficient: float | None = None)[source]

Bases: ASTNode

Damping force definition (damping{expr}).

Defines a velocity-dependent damping force.

expr

The damping expression.

Type:

mechanics_dsl.parser.ast_nodes.Expression

damping_coefficient

Optional damping coefficient.

Type:

float | None

expr: Expression
damping_coefficient: float | None = None
class mechanics_dsl.parser.RayleighDef(expr: Expression)[source]

Bases: ASTNode

Rayleigh dissipation function definition (rayleigh{expr}).

Defines the Rayleigh dissipation function F where the generalized dissipative forces are Q_i = -∂F/∂q̇_i.

For velocity-dependent damping: F = ½Σ bᵢⱼ q̇ᵢ q̇ⱼ

expr

The dissipation function expression.

Type:

mechanics_dsl.parser.ast_nodes.Expression

Example

rayleigh{frac{1}{2} * b * dot{x}^2}

expr: Expression
class mechanics_dsl.parser.InitialCondition(conditions: Dict[str, float])[source]

Bases: ASTNode

Initial conditions statement (initial{var1=val1, …}).

Specifies initial values for simulation.

conditions

Dictionary mapping variable names to initial values.

Type:

Dict[str, float]

conditions: Dict[str, float]
class mechanics_dsl.parser.SolveDef(method: str, options: ~typing.Dict[str, ~typing.Any] = <factory>)[source]

Bases: ASTNode

Solve statement (solve{method}).

Specifies the solution method.

method

Solution method name.

Type:

str

options

Additional solver options.

Type:

Dict[str, Any]

method: str
options: Dict[str, Any]
class mechanics_dsl.parser.AnimateDef(target: str, options: ~typing.Dict[str, ~typing.Any] = <factory>)[source]

Bases: ASTNode

Animate statement (animate{target}).

Specifies animation configuration.

target

Animation target.

Type:

str

options

Animation options.

Type:

Dict[str, Any]

target: str
options: Dict[str, Any]
class mechanics_dsl.parser.ExportDef(filename: str, format: str = 'json')[source]

Bases: ASTNode

Export statement (export{filename}).

Exports the system to a file.

filename

Output filename.

Type:

str

format

Export format (default ‘json’).

Type:

str

filename: str
format: str = 'json'
class mechanics_dsl.parser.ImportDef(filename: str)[source]

Bases: ASTNode

Import statement (import{filename}).

Imports a system from a file.

filename

Input filename.

Type:

str

filename: str
class mechanics_dsl.parser.RegionDef(shape: str, constraints: Dict[str, Tuple[float, float]])[source]

Bases: ASTNode

Region definition for SPH fluids.

Defines a geometric region with constraints.

shape

Region shape (‘rectangle’, ‘circle’, ‘line’).

Type:

str

constraints

Coordinate constraints as (min, max) tuples.

Type:

Dict[str, Tuple[float, float]]

shape: str
constraints: Dict[str, Tuple[float, float]]
class mechanics_dsl.parser.FluidDef(name: str, region: RegionDef, mass: float, eos: str)[source]

Bases: ASTNode

Fluid definition for SPH simulation.

Defines a fluid region with properties.

name

Fluid name.

Type:

str

region

Region definition.

Type:

mechanics_dsl.parser.ast_nodes.RegionDef

mass

Particle mass.

Type:

float

eos

Equation of state (e.g., ‘tait’).

Type:

str

name: str
region: RegionDef
mass: float
eos: str
class mechanics_dsl.parser.BoundaryDef(name: str, region: RegionDef)[source]

Bases: ASTNode

Boundary definition for SPH simulation.

Defines a solid boundary.

name

Boundary name.

Type:

str

region

Region definition.

Type:

mechanics_dsl.parser.ast_nodes.RegionDef

name: str
region: RegionDef

mechanics_dsl.visualization module

MechanicsDSL Visualization Package

Modular visualization tools for animations, plots, and phase space analysis.

The MechanicsVisualizer class is the legacy all-in-one visualizer preserved for backward compatibility. New code should prefer the focused Animator, Plotter, and PhaseSpaceVisualizer classes.

class mechanics_dsl.visualization.Animator(trail_length: int | None = None, fps: int | None = None)[source]

Bases: object

Animation handler for mechanical system simulations.

Supports: - Pendulum animations (single, double, multi-body) - Particle trajectory animations - Fluid particle visualizations

setup_figure(xlim: Tuple[float, float] = (-2, 2), ylim: Tuple[float, float] = (-2, 2), title: str = 'Animation') Tuple[Figure, Axes][source]

Create and configure figure for animation.

animate_pendulum(solution: dict, length: float = 1.0, title: str = 'Pendulum') FuncAnimation[source]

Create pendulum animation from simulation solution.

Parameters:
  • solution – Simulation result with ‘t’ and ‘y’ arrays

  • length – Pendulum length for visualization

  • title – Animation title

Returns:

matplotlib FuncAnimation object

animate(solution: dict, parameters: dict | None = None, system_name: str = 'system')[source]

Generic animation dispatcher (backward compatibility with MechanicsVisualizer).

Parameters:
  • solution – Simulation result dictionary

  • parameters – Physical parameters (optional)

  • system_name – Name of the system

Returns:

matplotlib FuncAnimation object

animate_particles(positions: List[Tuple[ndarray, ndarray]], title: str = 'Particles') FuncAnimation[source]

Animate particle positions over time.

Parameters:
  • positions – List of (x_array, y_array) for each frame

  • title – Animation title

Returns:

matplotlib FuncAnimation object

save(filename: str, dpi: int = 100) bool[source]

Save animation to file.

Parameters:
  • filename – Output filename (mp4, gif, etc.)

  • dpi – Resolution

Returns:

True if successful

class mechanics_dsl.visualization.MechanicsVisualizer(trail_length: int | None = None, fps: int | None = None)[source]

Bases: object

Enhanced visualization with circular buffers and configurable options

has_ffmpeg() bool[source]

Check if ffmpeg is available

save_animation_to_file(anim: FuncAnimation, filename: str, fps: int | None = None, dpi: int = 100) bool[source]

Save animation to file with validation.

Parameters:
  • anim – Animation object to save

  • filename – Output filename (validated)

  • fps – Frames per second (optional)

  • dpi – Dots per inch (default: 100)

Returns:

True if successful, False otherwise

Raises:
  • TypeError – If inputs have wrong types

  • ValueError – If filename is invalid or parameters out of range

setup_3d_plot(title: str = 'Classical Mechanics Simulation')[source]

Setup 3D plotting environment

animate_pendulum(solution: dict, parameters: dict, system_name: str = 'pendulum')[source]

Create animated pendulum visualization with validation.

Parameters:
  • solution – Solution dictionary (validated)

  • parameters – System parameters dictionary

  • system_name – Name of the system

Returns:

Animation object or None if failed

Raises:
  • TypeError – If inputs have wrong types

  • ValueError – If solution is invalid

animate_fluid_from_csv(csv_filename: str, title: str = 'Fluid Simulation')[source]

Animate SPH particle data from CSV. Expected CSV Format: t, id, x, y, rho

animate_oscillator(solution: dict, parameters: dict, system_name: str = 'oscillator')[source]

Animate harmonic oscillator

animate(solution: dict, parameters: dict, system_name: str = 'system')[source]

Generic animation dispatcher

plot_energy(solution: dict, parameters: dict, system_name: str = '', lagrangian: Expr | None = None)[source]

Plot energy conservation analysis with proper offset correction

plot_phase_space(solution: dict, coordinate_index: int = 0)[source]

Plot phase space trajectory with validation.

Parameters:
  • solution – Solution dictionary (validated)

  • coordinate_index – Index of coordinate to plot (default: 0)

Raises:
  • TypeError – If inputs have wrong types

  • ValueError – If solution is invalid or coordinate_index out of range

class mechanics_dsl.visualization.PhaseSpaceVisualizer[source]

Bases: object

Phase space and Poincaré section visualization.

Provides tools for analyzing dynamical systems through phase portraits and stroboscopic maps.

plot_phase_portrait(solution: dict, coordinate_index: int = 0, title: str = 'Phase Portrait') Figure[source]

Plot phase space trajectory (q vs q_dot).

Parameters:
  • solution – Simulation result

  • coordinate_index – Which coordinate to plot

  • title – Plot title

Returns:

matplotlib Figure

plot_phase_portrait_3d(solution: dict, coords: Tuple[int, int, int] = (0, 0, 1), title: str = '3D Phase Space') Figure[source]

Plot 3D phase space trajectory.

Parameters:
  • solution – Simulation result

  • coords – Tuple of (coord1_idx, coord1_type, coord2_idx) where type 0=position, 1=velocity

  • title – Plot title

Returns:

matplotlib Figure

plot_poincare_section(solution: dict, section_var: int = 0, section_value: float = 0.0, plot_vars: Tuple[int, int] = (1, 2), title: str = 'Poincaré Section') Figure[source]

Plot Poincaré section (stroboscopic map).

Parameters:
  • solution – Simulation result

  • section_var – State variable index for section condition

  • section_value – Value where section is taken

  • plot_vars – Which variables to plot (indices)

  • title – Plot title

Returns:

matplotlib Figure

class mechanics_dsl.visualization.Plotter[source]

Bases: object

Plotting utilities for simulation analysis.

Provides methods for: - Time series plots - Trajectory plots - Energy plots - Multi-panel figures

plot_time_series(solution: dict, variables: List[str] | None = None, title: str = 'Time Series') Figure[source]

Plot state variables vs time.

Parameters:
  • solution – Simulation result

  • variables – List of variables to plot (default: all coordinates)

  • title – Plot title

Returns:

matplotlib Figure

plot_trajectory_2d(solution: dict, x_var: str = 'x', y_var: str = 'y', title: str = 'Trajectory') Figure[source]

Plot 2D trajectory from solution.

Parameters:
  • solution – Simulation result

  • x_var – Variable names for x and y axes

  • y_var – Variable names for x and y axes

  • title – Plot title

Returns:

matplotlib Figure

plot_energy(solution: dict, kinetic: ndarray, potential: ndarray, title: str = 'Energy Conservation') Figure[source]

Plot energy components over time.

Parameters:
  • solution – Simulation result

  • kinetic – Kinetic energy array

  • potential – Potential energy array

  • title – Plot title

Returns:

matplotlib Figure

static show()[source]

Display all figures.

static save_figure(fig: Figure, filename: str, dpi: int = 150) None[source]

Save figure to file.

mechanics_dsl.utils module

MechanicsDSL Utils Package

Modular utilities for configuration, logging, caching, profiling, and validation.

mechanics_dsl.utils.setup_logging(level: int = 20, log_file: str | None = None) Logger[source]

Setup logging configuration

Parameters:
  • level – Logging level

  • log_file – Optional file to write logs to

Returns:

Logger instance

class mechanics_dsl.utils.Config[source]

Bases: object

Global configuration for MechanicsDSL with validation.

All configuration values are validated on assignment to ensure they are within reasonable bounds and of correct types.

property enable_profiling: bool

Whether to enable performance profiling.

property enable_debug_logging: bool

Whether to enable debug-level logging.

property simplification_timeout: float

Timeout for symbolic simplification operations in seconds.

property max_parser_errors: int

Maximum parser errors before giving up.

property default_rtol: float

Default relative tolerance for numerical integration.

property default_atol: float

Default absolute tolerance for numerical integration.

property trail_length: int

Maximum length of animation trails.

property animation_fps: int

Animation frames per second.

property save_intermediate_results: bool

Whether to save intermediate computation results.

property cache_symbolic_results: bool

Whether to cache symbolic computation results.

property enable_performance_monitoring: bool

Whether to enable performance monitoring.

property enable_memory_monitoring: bool

Whether to enable additional memory monitoring.

property cache_max_size: int

Maximum cache size.

property cache_max_memory_mb: float

Maximum cache memory in MB.

property enable_adaptive_solver: bool

Whether to enable adaptive solver selection.

property error_recovery_enabled: bool

Whether error recovery is enabled.

to_dict() Dict[str, Any][source]

Convert configuration to dictionary.

Returns:

Dictionary containing all configuration values

from_dict(data: Dict[str, Any]) None[source]

Load configuration from dictionary with validation.

Uses property setters to ensure all values are validated.

Parameters:

data – Dictionary containing configuration values

Raises:
  • TypeError – If data is not a dictionary

  • ValueError – If any value is invalid

class mechanics_dsl.utils.LRUCache(maxsize: int = 128, max_memory_mb: float = 100.0)[source]

Bases: object

Advanced LRU cache with size limits and memory awareness

get(key: str) Any | None[source]

Get item from cache with validation

set(key: str, value: Any) None[source]

Set item in cache with eviction if needed and validation

clear() None[source]

Clear cache

get_stats() Dict[str, Any][source]

Get cache statistics

class mechanics_dsl.utils.PerformanceMonitor[source]

Bases: object

Advanced performance monitoring with memory and timing tracking

start_timer(name: str) None[source]

Start timing an operation with validation

stop_timer(name: str) float[source]

Stop timing and record duration with validation

get_memory_usage() Dict[str, float][source]

Get current memory usage in MB

snapshot_memory(label: str = '') None[source]

Take a memory snapshot

get_stats(name: str) Dict[str, float][source]

Get statistics for a metric with validation

reset() None[source]

Reset all metrics

mechanics_dsl.utils.profile_function(func: Callable) Callable[source]

Decorator to profile function execution

mechanics_dsl.utils.timeout(seconds: float)[source]

Cross-platform timeout context manager for timing out operations.

Uses signal.SIGALRM on Unix systems and threading.Timer on Windows. Note: Threading-based timeout on Windows cannot interrupt CPU-bound operations.

Parameters:

seconds – Maximum time allowed (must be positive)

Raises:
  • TimeoutError – If operation exceeds time limit

  • ValueError – If seconds is not positive

exception mechanics_dsl.utils.TimeoutError[source]

Bases: Exception

Raised when an operation times out

mechanics_dsl.utils.safe_float_conversion(value: Any) float[source]

Safely convert any value to Python float with comprehensive error handling.

Parameters:

value – Value to convert to float

Returns:

Converted float value (0.0 on failure)

mechanics_dsl.utils.validate_array_safe(arr: Any, name: str = 'array', min_size: int = 0, max_size: int | None = None, check_finite: bool = True) bool[source]

Comprehensive array validation with extensive checks.

Parameters:
  • arr – Array to validate

  • name – Name for error messages

  • min_size – Minimum array size

  • max_size – Maximum array size (None for no limit)

  • check_finite – Whether to check for finite values

Returns:

True if valid, False otherwise

mechanics_dsl.utils.safe_array_access(arr: ndarray, index: int, default: float = 0.0) float[source]

Safely access array element with bounds checking.

Parameters:
  • arr – Array to access

  • index – Index to access

  • default – Default value if access fails

Returns:

Array element or default value

mechanics_dsl.utils.runtime_type_check(value: Any, expected_type: type, name: str = 'value') bool[source]

Runtime type checking with detailed error messages and validation

mechanics_dsl.utils.validate_finite(arr: ndarray, name: str = 'array') bool[source]

Validate that array contains only finite values.

Parameters:
  • arr – NumPy array to validate

  • name – Name for error messages

Returns:

True if all finite, False otherwise

Raises:

TypeError – If arr is not a numpy array

mechanics_dsl.utils.validate_positive(value: int | float, name: str = 'value') None[source]

Validate that a value is positive.

Parameters:
  • value – Value to validate

  • name – Name for error messages

Raises:
  • TypeError – If value is not numeric

  • ValueError – If value is not positive

mechanics_dsl.utils.validate_non_negative(value: int | float, name: str = 'value') None[source]

Validate that a value is non-negative.

Parameters:
  • value – Value to validate

  • name – Name for error messages

Raises:
  • TypeError – If value is not numeric

  • ValueError – If value is negative

mechanics_dsl.utils.validate_time_span(t_span: Tuple[float, float]) None[source]

Validate time span tuple.

Parameters:

t_span – Tuple of (t_start, t_end)

Raises:
  • TypeError – If t_span is not a tuple or values are not numeric

  • ValueError – If t_start >= t_end or values are negative

mechanics_dsl.utils.validate_solution_dict(solution: dict) None[source]

Validate solution dictionary structure and content.

Parameters:

solution – Solution dictionary from simulation

Raises:
  • TypeError – If solution is not a dict

  • ValueError – If required keys are missing or values are invalid

mechanics_dsl.utils.validate_file_path(filename: str, must_exist: bool = False, allow_symlinks: bool = False) None[source]

Validate file path with comprehensive security checks.

Parameters:
  • filename – File path to validate

  • must_exist – Whether file must exist

  • allow_symlinks – Whether to allow symlinks (default: False for security)

Raises:
  • TypeError – If filename is not a string

  • ValueError – If filename is empty, contains unsafe characters, or is invalid

  • FileNotFoundError – If must_exist=True and file doesn’t exist

Security checks performed:
  • Null byte injection prevention

  • Path traversal (..) prevention

  • Special character detection

  • Symlink detection (when allow_symlinks=False)

  • Excessive path length check

mechanics_dsl.utils.resource_manager(*resources)[source]

Context manager for multiple resources with validation

class mechanics_dsl.utils.AdvancedErrorHandler[source]

Bases: object

Advanced error handling with retry and recovery mechanisms

static retry_on_failure(max_retries: int = 3, delay: float = 0.1, backoff: float = 2.0, exceptions: ~typing.Tuple = (<class 'Exception'>, ))[source]

Decorator for retrying operations on failure

static safe_execute(func: Callable, default: Any | None = None, log_errors: bool = True) Any[source]

Safely execute a function with error handling

class mechanics_dsl.utils.VariableCategory(value)[source]

Bases: Enum

Categories of variables in the physics system.

COORDINATE = 1
VELOCITY = 2
CONSTANT = 3
PARAMETER = 4
EXTERNAL_FIELD = 5
mechanics_dsl.utils.is_coordinate_type(var_type: str) bool[source]

Check if a variable type represents a dynamic coordinate.

Parameters:

var_type – The type string from VarDef

Returns:

True if this type represents a coordinate, False otherwise

mechanics_dsl.utils.is_constant_type(var_type: str) bool[source]

Check if a variable type represents a constant/parameter.

Parameters:

var_type – The type string from VarDef

Returns:

True if this type represents a constant, False otherwise

mechanics_dsl.utils.is_likely_coordinate(var_name: str, var_type: str) bool[source]

Determine if a variable is likely a dynamic coordinate.

Uses both type information and naming conventions to determine if a variable represents a generalized coordinate.

Priority: 1. Explicit COORDINATE types (Angle, Position, Coordinate) -> IS coordinate 2. Explicit CONSTANT types (Parameter, Constant, Mass) -> NOT coordinate 3. Name-based fallback for ambiguous types (like ‘Length’) -> use common names

Parameters:
  • var_name – The variable name

  • var_type – The variable type string

Returns:

True if this is likely a coordinate, False otherwise

mechanics_dsl.utils.classify_variable(var_name: str, var_type: str) VariableCategory[source]

Classify a variable into its category.

Parameters:
  • var_name – The variable name

  • var_type – The variable type string

Returns:

VariableCategory enum value

class mechanics_dsl.utils.RateLimiter(requests_per_minute: float = 60.0, burst_limit: float = 10.0, cleanup_interval: float = 300.0)[source]

Bases: object

Thread-safe rate limiter using token bucket algorithm.

Supports per-client rate limiting with configurable limits.

Parameters:
  • requests_per_minute – Maximum sustained requests per minute

  • burst_limit – Maximum burst size (peak requests)

  • cleanup_interval – Seconds between cleanup of stale buckets

Example

>>> limiter = RateLimiter(requests_per_minute=60, burst_limit=10)
>>> if limiter.allow("user_123"):
...     # Process request
...     pass
>>> else:
...     # Return 429 Too Many Requests
...     pass
allow(key: str, cost: float = 1.0) bool[source]

Check if a request is allowed under the rate limit.

Parameters:
  • key – Identifier for the client (e.g., IP address, user ID)

  • cost – Cost of this request in tokens (default 1.0)

Returns:

True if request is allowed, False if rate limited

allow_or_raise(key: str, cost: float = 1.0) None[source]

Check if request is allowed, raise RateLimitExceeded if not.

Parameters:
  • key – Identifier for the client

  • cost – Cost of this request in tokens

Raises:

RateLimitExceeded – If rate limit is exceeded

get_remaining(key: str) float[source]

Get remaining tokens for a client.

Parameters:

key – Client identifier

Returns:

Number of remaining tokens

reset(key: str) None[source]

Reset rate limit for a specific client.

reset_all() None[source]

Reset all rate limits.

class mechanics_dsl.utils.SimulationRateLimiter(simulations_per_minute: float = 30.0, burst_limit: float = 5.0, max_points_free: int = 1000, points_per_token: int = 1000)[source]

Bases: RateLimiter

Specialized rate limiter for physics simulations.

Applies higher costs for expensive operations like long simulations or high-resolution outputs.

Parameters:
  • simulations_per_minute – Base simulation rate

  • max_points_free – Maximum points without extra cost

  • points_per_token – Points that cost 1 token each

calculate_cost(num_points: int = 1000, time_span: float = 10.0, method: str = 'RK45') float[source]

Calculate token cost for a simulation.

Parameters:
  • num_points – Number of output points

  • time_span – Simulation time span

  • method – Integration method

Returns:

Cost in tokens

allow_simulation(key: str, num_points: int = 1000, time_span: float = 10.0, method: str = 'RK45') bool[source]

Check if a simulation is allowed.

Parameters:
  • key – Client identifier

  • num_points – Number of output points

  • time_span – Simulation time span

  • method – Integration method

Returns:

True if simulation is allowed

exception mechanics_dsl.utils.RateLimitExceeded(key: str, retry_after: float)[source]

Bases: Exception

Raised when rate limit is exceeded.

class mechanics_dsl.utils.TokenBucket(capacity: float, refill_rate: float, tokens: float = 0.0, last_refill: float = <factory>)[source]

Bases: object

Token bucket algorithm implementation for rate limiting.

capacity: float
refill_rate: float
tokens: float = 0.0
last_refill: float
consume(tokens: float = 1.0) bool[source]

Try to consume tokens from the bucket.

Parameters:

tokens – Number of tokens to consume

Returns:

True if tokens were consumed, False if insufficient tokens

time_until_available(tokens: float = 1.0) float[source]

Calculate time until the requested tokens will be available.

Parameters:

tokens – Number of tokens needed

Returns:

Seconds until tokens are available (0 if already available)

exception mechanics_dsl.utils.PathValidationError[source]

Bases: ValueError

Raised when a path fails validation.

mechanics_dsl.utils.is_safe_filename(filename: str) bool[source]

Check if a filename is safe (no path components).

Parameters:

filename – The filename to validate

Returns:

True if the filename is safe

mechanics_dsl.utils.secure_filename(filename: str) str[source]

Sanitize a filename by removing unsafe characters.

Similar to werkzeug.utils.secure_filename.

Parameters:

filename – The original filename

Returns:

A safe version of the filename

mechanics_dsl.utils.validate_path_within_base(user_path: str, base_path: str, must_exist: bool = False) str[source]

Validate that a user-provided path stays within a base directory.

This is the recommended approach for path traversal prevention.

Parameters:
  • user_path – The user-provided path (potentially malicious)

  • base_path – The base directory paths must stay within

  • must_exist – If True, verify the path exists

Returns:

The validated absolute path

Raises:

PathValidationError – If the path escapes the base directory

mechanics_dsl.utils.safe_open(file_path: str, mode: str = 'r', base_path: str | None = None, allowed_extensions: List[str] | None = None, **kwargs)[source]

Safely open a file with path validation.

Parameters:
  • file_path – Path to the file

  • mode – File open mode

  • base_path – If provided, validate path is within this directory

  • allowed_extensions – If provided, restrict to these extensions

  • **kwargs – Additional arguments for open()

Returns:

File handle

Raises:

PathValidationError – If path validation fails

mechanics_dsl.utils.safe_path_join(base: str, *parts: str) str[source]

Safely join path parts, preventing traversal.

Parameters:
  • base – The base directory

  • *parts – Additional path components

Returns:

The validated joined path

Raises:

PathValidationError – If result escapes base

Module contents

MechanicsDSL: A Domain-Specific Language for Classical Mechanics

A comprehensive framework for symbolic and numerical analysis of classical mechanical systems using LaTeX-inspired notation.

class mechanics_dsl.PhysicsCompiler[source]

Bases: object

Main compiler class.

Production-ready physics DSL compiler with comprehensive validation, cross-platform support, and security hardening.

Features: - Cross-platform timeout support (Windows/Unix) - Safe AST-based parsing (no eval()) - Comprehensive input validation - Specific exception handling - Extensive type hints - Production-ready error recovery

Example

>>> compiler = PhysicsCompiler()
>>> result = compiler.compile_dsl("\system{pendulum}\lagrangian{x^2}")
>>> if result['success']:
...     solution = compiler.simulate((0, 10))
...     compiler.animate(solution)
cleanup() None[source]

Cleanup resources and trigger garbage collection.

compile_dsl(dsl_source: str, use_hamiltonian: bool = False, use_constraints: bool = True) dict[source]

Complete compilation pipeline with comprehensive validation.

Parameters:
  • dsl_source – DSL source code (must be non-empty string)

  • use_hamiltonian – Force Hamiltonian formulation

  • use_constraints – Apply constraint handling

Returns:

Compilation result dictionary with ‘success’ key

Raises:
  • TypeError – If dsl_source is not a string

  • ValueError – If dsl_source is empty or invalid

Example

>>> compiler = PhysicsCompiler()
>>> result = compiler.compile_dsl(r"\system{test}\lagrangian{x^2}")
>>> assert result['success']
analyze_semantics()[source]

Extract system information from AST

get_coordinates() List[str][source]

Extract generalized coordinates (exclude constants).

Uses the registry module’s is_likely_coordinate() function to determine which variables are dynamic coordinates vs. constants/parameters.

Returns:

List of coordinate variable names

process_fluids()[source]

Generate particles for all fluid and boundary definitions

derive_equations() Dict[str, Expr][source]

Derive equations using Lagrangian formulation (Patched for Forces)

derive_constrained_equations() Dict[str, Expr][source]

Derive equations with constraints using Lagrange multipliers

derive_hamiltonian_equations() Tuple[List[Expr], List[Expr]][source]

Derive equations using Hamiltonian formulation

setup_simulation(equations)[source]

Configure numerical simulator

simulate(t_span: Tuple[float, float] = (0, 10), num_points: int = 1000, **kwargs) dict[source]

Run numerical simulation

animate(solution: dict, show: bool = True)[source]

Create animation from solution

export_animation(solution: dict, filename: str, fps: int = 30, dpi: int = 100) str[source]

Export animation to file

plot_energy(solution: dict)[source]

Plot energy analysis

plot_phase_space(solution: dict, coordinate_index: int = 0)[source]

Plot phase space

print_equations()[source]

Print derived equations

get_info() dict[source]

Get comprehensive system information

export_system(filename: str, format: str = 'json') bool[source]

Export system state to file

export(target: str, filename: str) str[source]

Generate standalone simulation code for a target language.

Parameters:
  • target – Target language identifier (see _GENERATOR_REGISTRY for the list, e.g. ‘cpp’, ‘python’, ‘rust’, ‘julia’, ‘cuda’, …).

  • filename – Output file path for the generated source.

Returns:

Path to the generated file.

Raises:
  • ValueError – If target is not supported or the compiler has no equations yet.

  • IOError – If the file cannot be written.

static import_system(filename: str, allow_pickle: bool = False) PhysicsCompiler | None[source]

Import system state from file.

See SystemSerializer.import_system for the semantics of allow_pickle; pickle loading is refused by default.

compile_to_cpp(filename: str = 'simulation.cpp', target: str = 'standard', compile_binary: bool = True) bool[source]

Generate C++ code for multiple targets.

Parameters:
  • filename – Output filename

  • target – ‘standard’, ‘raylib’, ‘arduino’, ‘wasm’, ‘openmp’, ‘python’

  • compile_binary – Whether to run the compiler (g++, emcc, etc.)

class mechanics_dsl.MechanicsParser(tokens: List[Token])[source]

Bases: object

Recursive descent parser for MechanicsDSL.

Converts a list of tokens into an Abstract Syntax Tree (AST) that can be compiled into equations of motion.

tokens

List of Token objects to parse.

pos

Current position in token stream.

current_system

Name of current system being parsed.

errors

List of parsing errors encountered.

max_errors

Maximum errors before giving up (from config).

parse()[source]

Parse complete token stream into AST.

peek(offset)[source]

Look ahead at tokens.

match(*types)[source]

Match and consume token if type matches.

expect(type)[source]

Require specific token type.

Example

>>> tokens = tokenize(r"\lagrangian{T - V}")
>>> parser = MechanicsParser(tokens)
>>> ast = parser.parse()
>>> print(ast[0])
Lagrangian(...)
peek(offset: int = 0) Token | None[source]

Look ahead at token without consuming it.

Parameters:

offset – Number of tokens to look ahead (default 0).

Returns:

Token at position pos+offset, or None if past end.

match(*expected_types: str) Token | None[source]

Match and consume token if type matches.

Parameters:

*expected_types – One or more acceptable token types.

Returns:

Matched token if successful, None otherwise.

expect(expected_type: str) Token[source]

Expect a specific token type, raise error if not found.

Parameters:

expected_type – Required token type.

Returns:

The matched token.

Raises:

ParserError – If token doesn’t match expected type.

parse() List[ASTNode][source]

Parse the complete DSL with comprehensive error recovery.

Returns:

List of ASTNode objects representing the parsed program.

Note

The parser attempts error recovery to parse as much as possible even when errors are encountered.

parse_statement() ASTNode | None[source]

Parse a top-level statement.

parse_region() RegionDef[source]

Parse region{shape}{constraints}.

parse_fluid() FluidDef[source]

Parse fluid{name} with properties.

parse_boundary() BoundaryDef[source]

Parse boundary{name} region{…}.

parse_system() SystemDef[source]

Parse system{name}.

parse_defvar() VarDef[source]

Parse defvar{name}{type}{unit}.

parse_parameter() ParameterDef[source]

Parse parameter{name}{value}{unit}.

parse_define() DefineDef[source]

Parse define{op{name}(args) = expression}.

parse_lagrangian() LagrangianDef[source]

Parse lagrangian{expression}.

parse_hamiltonian() HamiltonianDef[source]

Parse hamiltonian{expression}.

parse_transform() TransformDef[source]

Parse transform{type}{var = expr}.

parse_constraint() ConstraintDef[source]

Parse constraint{expression}.

parse_nonholonomic() NonHolonomicConstraintDef[source]

Parse nonholonomic{expression}.

parse_force() ForceDef[source]

Parse a non-conservative force.

Two forms are supported:

force{expr} - applied positionally (legacy) force{coord}{expr} - applied to the named generalized coordinate

parse_damping() DampingDef[source]

Parse damping{expression}.

parse_rayleigh()[source]

Parse rayleigh{expression}.

The Rayleigh dissipation function F represents velocity-dependent dissipative forces. The generalized dissipative forces are: Q_i = -∂F/∂q̇_i

For linear damping: F = ½ Σ bᵢⱼ q̇ᵢ q̇ⱼ

Example

rayleigh{frac{1}{2} * b * dot{x}^2}

parse_initial() InitialCondition[source]

Parse initial{var1=val1, var2=val2, …}.

parse_solve() SolveDef[source]

Parse solve{method}.

parse_animate() AnimateDef[source]

Parse animate{target}.

parse_export() ExportDef[source]

Parse export{filename}.

parse_import() ImportDef[source]

Parse import{filename}.

parse_expression() Expression[source]

Parse expressions with full operator precedence.

parse_additive() Expression[source]

Addition and subtraction (lowest precedence).

parse_multiplicative() Expression[source]

Multiplication, division, and vector operations.

parse_power() Expression[source]

Exponentiation (right associative).

parse_unary() Expression[source]

Unary operators (+, -).

parse_postfix() Expression[source]

Function calls, subscripts, etc.

parse_primary() Expression[source]

Primary expressions: literals, identifiers, parentheses, vectors, commands.

parse_command(cmd: str) Expression[source]

Parse LaTeX-style commands.

at_end_of_expression() bool[source]

Check if we’re at the end of an expression.

expression_to_string(expr: Expression) str[source]

Convert expression back to string for unit parsing.

class mechanics_dsl.SymbolicEngine(use_weak_refs: bool = False)[source]

Bases: object

Enhanced symbolic mathematics engine with advanced caching and performance monitoring

get_symbol(name: str, **assumptions) Symbol[source]

Get or create a SymPy symbol with assumptions (cached)

clear_cache() int[source]

Clear all caches to free memory.

Useful for long-running applications that process many different mechanical systems. Clears: - LRU expression cache - Symbol map (keeps time_symbol) - Function map

Returns:

Number of cached items cleared

Example

>>> engine = SymbolicEngine()
>>> # ... do lots of computation ...
>>> cleared = engine.clear_cache()
>>> print(f"Freed {cleared} cached items")
memory_stats() Dict[str, int][source]

Get memory usage statistics.

Returns:

Dictionary with counts of cached items by category

get_function(name: str) Function[source]

Get or create a SymPy function (cached)

ast_to_sympy(expr: Expression) Expr[source]

Convert AST expression to SymPy with comprehensive support and caching

Parameters:

expr – AST expression node

Returns:

SymPy expression

derive_equations_of_motion(lagrangian: Expr, coordinates: List[str]) List[Expr][source]

Derive Euler-Lagrange equations from Lagrangian

Parameters:
  • lagrangian – Lagrangian expression

  • coordinates – List of generalized coordinates

Returns:

List of equations of motion

Note

The Euler-Lagrange equations are: d/dt(∂L/∂q̇ᵢ) - ∂L/∂qᵢ = 0

For coupled systems (e.g., double pendulum), ALL coordinates must be treated as functions of time simultaneously to correctly compute cross-coupling terms like ∂²θ₂/∂t² appearing in the θ₁ equation.

derive_equations_with_constraints(lagrangian: Expr, coordinates: List[str], constraints: List[Expr]) Tuple[List[Expr], List[str]][source]

Derive equations with holonomic constraints using Lagrange multipliers

Parameters:
  • lagrangian – Lagrangian expression

  • coordinates – List of generalized coordinates

  • constraints – List of constraint expressions

Returns:

Tuple of (augmented equations, extended coordinates including lambdas)

derive_hamiltonian_equations(hamiltonian: Expr, coordinates: List[str]) Tuple[List[Expr], List[Expr]][source]

Derive Hamilton’s equations from Hamiltonian

Hamilton’s equations: dq/dt = ∂H/∂p dp/dt = -∂H/∂q

Parameters:
  • hamiltonian – Hamiltonian expression

  • coordinates – List of generalized coordinates

Returns:

Tuple of (q_dot equations, p_dot equations)

lagrangian_to_hamiltonian(lagrangian: Expr, coordinates: List[str]) Expr[source]

Convert Lagrangian to Hamiltonian via Legendre transform

H = Σ(p_i * q̇_i) - L where p_i = ∂L/∂q̇_i

Parameters:
  • lagrangian – Lagrangian expression

  • coordinates – List of generalized coordinates

Returns:

Hamiltonian expression

solve_for_accelerations(equations: List[Expr], coordinates: List[str]) Dict[str, Expr][source]

Solve equations of motion for accelerations SIMULTANEOUSLY.

For coupled systems like double pendulum, accelerations are interdependent: M * [q1_ddot, q2_ddot, …]^T = F

This function: 1. Substitutes all derivative notations with symbols 2. Extracts the mass matrix M and force vector F 3. Solves the linear system M*a = F simultaneously 4. Returns simplified acceleration expressions

This is CRITICAL for coupled systems where accelerations appear in each other’s equations.

class mechanics_dsl.NumericalSimulator(symbolic_engine: SymbolicEngine)[source]

Bases: object

Enhanced numerical simulator with better stability and diagnostics

set_parameters(params: Dict[str, float])[source]

Set physical parameters

set_initial_conditions(conditions: Dict[str, float])[source]

Set initial conditions

add_constraint(constraint_expr: Expr)[source]

Add a constraint equation

compile_equations(accelerations: Dict[str, Expr], coordinates: List[str])[source]

Compile symbolic equations to numerical functions

compile_hamiltonian_equations(q_dots: List[Expr], p_dots: List[Expr], coordinates: List[str])[source]

Compile Hamiltonian equations

equations_of_motion(t: float, y: ndarray) ndarray[source]

ODE system for numerical integration with comprehensive bounds checking and validation.

Parameters:
  • t – Current time

  • y – State vector

Returns:

Derivative vector dydt

simulate(t_span: Tuple[float, float], num_points: int = 1000, method: str = None, rtol: float = None, atol: float = None, detect_stiff: bool = True) dict[source]

Run numerical simulation with adaptive integration and diagnostics.

Parameters:
  • t_span – Time span (t_start, t_end) where t_start < t_end

  • num_points – Number of output points (must be >= 2)

  • method – Integration method (‘RK45’, ‘LSODA’, ‘Radau’, etc.)

  • rtol – Relative tolerance (must be in (0, 1))

  • atol – Absolute tolerance (must be positive)

  • detect_stiff – Whether to detect stiff systems

Returns:

Dictionary with solution data and metadata, always contains ‘success’ key

Raises:
  • TypeError – If arguments have wrong types

  • ValueError – If arguments are out of valid ranges

Example

>>> solution = simulator.simulate((0, 10), num_points=1000)
>>> if solution['success']:
...     t = solution['t']
...     y = solution['y']
async simulate_async(t_span: Tuple[float, float], num_points: int = 1000, method: str | None = None, rtol: float | None = None, atol: float | None = None, detect_stiff: bool = True, executor: Executor | None = None) Dict[str, Any][source]

Run numerical simulation asynchronously.

This method runs the simulation in a thread pool executor to avoid blocking the event loop. Useful for: - Jupyter notebooks (keeps the kernel responsive) - Async web backends (FastAPI, aiohttp) - GUI applications with async event loops

Parameters:
  • t_span – Time span (t_start, t_end)

  • num_points – Number of output points

  • method – Integration method (‘RK45’, ‘LSODA’, ‘Radau’, etc.)

  • rtol – Relative tolerance

  • atol – Absolute tolerance

  • detect_stiff – Whether to detect stiff systems

  • executor – Optional custom executor (defaults to ThreadPoolExecutor)

Returns:

Dictionary with solution data and metadata

Example

>>> import asyncio
>>> async def main():
...     result = await simulator.simulate_async((0, 10), num_points=1000)
...     print(f"Success: {result['success']}")
>>> asyncio.run(main())

Note

For CPU-bound simulations, consider using ProcessPoolExecutor for true parallelism (requires picklable equations).

async simulate_batch_async(simulations: List[Dict[str, Any]], max_concurrent: int = 4) List[Dict[str, Any]][source]

Run multiple simulations concurrently.

Useful for parameter sweeps, sensitivity analysis, or ensemble simulations where many similar systems need to be simulated.

Parameters:
  • simulations – List of simulation parameter dicts, each containing: - t_span: Tuple[float, float] (required) - num_points: int (optional, default 1000) - method: str (optional) - rtol: float (optional) - atol: float (optional)

  • max_concurrent – Maximum concurrent simulations

Returns:

List of simulation results in the same order as input

Example

>>> simulations = [
...     {'t_span': (0, 10), 'num_points': 500},
...     {'t_span': (0, 20), 'num_points': 1000},
... ]
>>> results = await simulator.simulate_batch_async(simulations)
class mechanics_dsl.NumbaSimulator(symbolic_engine=None)[source]

Bases: object

Numba-accelerated numerical simulator for MechanicsDSL.

Provides significant speedups over SciPy’s solve_ivp for simple to moderately complex systems.

Example

>>> from mechanics_dsl.solver_numba import NumbaSimulator
>>> sim = NumbaSimulator(symbolic_engine)
>>> sim.compile_equations(accelerations, coordinates)
>>> solution = sim.simulate_numba(t_span=(0, 10), num_points=1000)
set_parameters(params: Dict[str, float]) None[source]

Set physical parameters.

set_initial_conditions(conditions: Dict[str, float]) None[source]

Set initial conditions.

compile_equations(accelerations: Dict[str, Expr], coordinates: List[str]) None[source]

Compile symbolic equations to Numba-compatible functions.

Parameters:
  • accelerations – Dictionary of {coord_ddot: symbolic_expression}

  • coordinates – List of coordinate names

simulate_numba(t_span: Tuple[float, float], num_points: int = 1000, method: str = 'rk4', rtol: float = 1e-06, atol: float = 1e-09) Dict[source]

Run simulation using Numba-accelerated integrator.

Parameters:
  • t_span – (t_start, t_end) time interval

  • num_points – Number of output points

  • method – Integration method (‘euler’, ‘rk4’, ‘rk45’)

  • rtol – Relative tolerance (for adaptive methods)

  • atol – Absolute tolerance (for adaptive methods)

Returns:

Dictionary with ‘t’ and ‘y’ arrays

mechanics_dsl.is_numba_available() bool[source]

Check if Numba is available for JIT compilation.

mechanics_dsl.tokenize(source: str) List[Token][source]

Tokenize DSL source code with position tracking.

Converts a string of MechanicsDSL code into a list of tokens, excluding whitespace and comments. Unrecognized characters are reported as a single error rather than silently dropped.

Parameters:

source – DSL source code string.

Returns:

List of Token objects (excluding whitespace and comments).

Raises:

ValueError – If the source contains characters that do not match any token pattern (e.g. @, $, &).

Example

>>> tokens = tokenize(r"\lagrangian{T - V}")
>>> [t.type for t in tokens]
['LAGRANGIAN', 'LBRACE', 'IDENT', 'MINUS', 'IDENT', 'RBRACE']
mechanics_dsl.setup_logging(level: int = 20, log_file: str | None = None) Logger[source]

Setup logging configuration

Parameters:
  • level – Logging level

  • log_file – Optional file to write logs to

Returns:

Logger instance

class mechanics_dsl.PotentialEnergyCalculator[source]

Bases: object

Compute potential energy with proper offset for different systems

static compute_pe_offset(system_type: str, parameters: Dict[str, float]) float[source]

Compute PE offset to set minimum PE = 0

Parameters:
  • system_type – Type of mechanical system

  • parameters – System parameters

Returns:

PE offset value

static compute_kinetic_energy(solution: dict, parameters: Dict[str, float]) ndarray[source]

Compute kinetic energy from solution with validation.

Parameters:
  • solution – Solution dictionary (validated)

  • parameters – System parameters dictionary

Returns:

Array of kinetic energy values

Raises:
  • TypeError – If inputs have wrong types

  • ValueError – If solution is invalid

static compute_potential_energy(solution: dict, parameters: Dict[str, float], system_type: str = '') ndarray[source]

Compute potential energy from solution with proper offset

class mechanics_dsl.EnergyAnalyzer[source]

Bases: object

Energy analysis for mechanical systems.

Computes kinetic energy, potential energy, and validates conservation.

compute_kinetic_energy(solution: dict, masses: Dict[str, float], velocities: List[str] | None = None) ndarray[source]

Compute kinetic energy T = 0.5 * m * v^2 for each timestep.

Parameters:
  • solution – Simulation result

  • masses – Dict mapping coordinate names to masses

  • velocities – List of velocity variable names

Returns:

Kinetic energy array

compute_potential_energy(solution: dict, potential_func: Callable) ndarray[source]

Compute potential energy at each timestep.

Parameters:
  • solution – Simulation result

  • potential_func – Function V(state) -> float

Returns:

Potential energy array

check_conservation(solution: dict, kinetic: ndarray, potential: ndarray, tolerance: float = 0.001) Dict[source]

Check energy conservation.

Parameters:
  • solution – Simulation result

  • kinetic – Kinetic energy array

  • potential – Potential energy array

  • tolerance – Relative tolerance for conservation check

Returns:

Dict with conservation analysis results

compute_pendulum_energy(solution: dict, m: float, length: float, g: float) Dict[source]

Compute energy for simple pendulum.

Parameters:
  • solution – Simulation result

  • m – Mass

  • length – Pendulum length

  • g – Gravitational acceleration

Returns:

Dict with kinetic, potential, and total energy

class mechanics_dsl.StabilityAnalyzer[source]

Bases: object

Stability analysis for dynamical systems.

Provides: - Fixed point finding - Linearization and Jacobian computation - Eigenvalue analysis - Lyapunov exponent estimation

find_fixed_points(equations: Dict[str, Expr], variables: List[Symbol]) List[Dict][source]

Find fixed points where all derivatives are zero.

Parameters:
  • equations – Dict mapping derivative names to expressions

  • variables – List of state variable symbols

Returns:

List of fixed point dictionaries

compute_jacobian(equations: Dict[str, Expr], variables: List[Symbol]) MutableDenseMatrix[source]

Compute the Jacobian matrix of the system.

Parameters:
  • equations – Dict mapping output names to expressions

  • variables – List of input variable symbols

Returns:

SymPy Matrix (Jacobian)

analyze_stability(jacobian: MutableDenseMatrix, fixed_point: Dict) Dict[source]

Analyze stability at a fixed point via eigenvalues.

Parameters:
  • jacobian – Jacobian matrix

  • fixed_point – Dict of variable values at fixed point

Returns:

Stability analysis result

estimate_lyapunov_exponent(trajectory: ndarray, dt: float, n_renorm: int = 100) float[source]

Estimate largest Lyapunov exponent from trajectory data.

Uses Wolf’s algorithm with periodic renormalization.

Parameters:
  • trajectory – State trajectory array (n_vars x n_points)

  • dt – Time step

  • n_renorm – Number of renormalization steps

Returns:

Estimated Lyapunov exponent

mechanics_dsl.get_preset(name)[source]

Get a built-in preset by name. See list_presets() for available options.

mechanics_dsl.list_presets()[source]

List available built-in presets.

exception mechanics_dsl.MechanicsDSLError(message: str, suggestion: str | None = None, docs_url: str | None = None)[source]

Bases: Exception

Base exception for all MechanicsDSL errors.

exception mechanics_dsl.ParseError(message: str, line: int | None = None, column: int | None = None, source_snippet: str | None = None)[source]

Bases: MechanicsDSLError

Raised when the DSL source code cannot be parsed.

exception mechanics_dsl.TokenizationError(message: str, position: int | None = None)[source]

Bases: MechanicsDSLError

Raised when source code cannot be tokenized.

exception mechanics_dsl.SemanticError(message: str, suggestion: str | None = None, docs_url: str | None = None)[source]

Bases: MechanicsDSLError

Raised when DSL has semantic errors (valid syntax but invalid meaning).

exception mechanics_dsl.NoLagrangianError(system_name: str = 'system')[source]

Bases: SemanticError

Raised when Lagrangian is required but not defined.

exception mechanics_dsl.NoCoordinatesError[source]

Bases: SemanticError

Raised when no generalized coordinates are found.

exception mechanics_dsl.SimulationError(message: str, suggestion: str | None = None, docs_url: str | None = None)[source]

Bases: MechanicsDSLError

Base class for simulation-related errors.

exception mechanics_dsl.IntegrationError(message: str, t_failed: float | None = None, is_stiff: bool = False)[source]

Bases: SimulationError

Raised when numerical integration fails.

exception mechanics_dsl.InitialConditionError(message: str, missing_vars: List[str] | None = None)[source]

Bases: SimulationError

Raised when initial conditions are invalid or inconsistent.

exception mechanics_dsl.ParameterError(message: str, param_name: str | None = None)[source]

Bases: MechanicsDSLError

Raised when there are issues with physical parameters.