Architecture
Understanding ControlDESymulation’s Internal Design
Introduction
ControlDESymulation is built on a type-driven, composition-based architecture that achieves mathematical rigor, software engineering excellence, and multi-backend performance simultaneously. This section provides comprehensive documentation of the framework’s internal design for developers and advanced users.
Most users do NOT need to read architecture documentation. If you’re:
- Using built-in systems from
cdesym.systems.builtin.* - Defining custom systems by subclassing
ContinuousSymbolicSystemorDiscreteSymbolicSystem - Following tutorials and examples
Then you can skip this section entirely. The architecture documentation is intended for:
- Framework contributors and maintainers
- Advanced users implementing custom integrators or utilities
- Researchers studying the framework’s design
- Developers extending the framework with new capabilities
Architecture Documents
The framework consists of 7 architectural layers, each documented separately:
1. Design Philosophy
Start here to understand the core principles that guide the framework’s design.
Topics covered:
- Type-driven design philosophy
- Composition over inheritance
- Backend agnosticism
- Zero code duplication
- Progressive disclosure of complexity
- Design patterns and trade-offs
Read this if: You want to understand why the framework is built the way it is, or you’re contributing new features.
2. Type System Architecture
The foundational Layer 0 that provides semantic types, structured results, and type-safe interfaces.
Topics covered:
- Multi-backend array types (NumPy, PyTorch, JAX)
- Semantic vector/matrix types (StateVector, GainMatrix, etc.)
- TypedDict structured results (IntegrationResult, LQRResult, etc.)
- Protocol-based interfaces for duck typing with type safety
- 200+ type definitions across 8 modules
Read this if: You’re implementing custom components, need to understand type conventions, or want to leverage IDE support.
3. UI Framework Architecture
The user-facing Layer 3 for defining and working with dynamical systems.
Components documented:
- Layer 0:
SymbolicSystemBase- Time-domain agnostic foundation - Layer 1:
ContinuousSystemBase,DiscreteSystemBase- Time-domain interfaces - Layer 2:
ContinuousSymbolicSystem,DiscreteSymbolicSystem- Concrete implementations - Layer 3:
ContinuousStochasticSystem,DiscreteStochasticSystem- Stochastic extensions
Read this if: You’re defining custom systems, extending the framework, or need to understand the class hierarchy.
4. Delegation Layer
The internal service layer that provides specialized utilities through composition.
Components documented:
- Core Utilities:
BackendManager,CodeGenerator,EquilibriumHandler,SymbolicValidator - Deterministic Evaluation:
DynamicsEvaluator,LinearizationEngine,ObservationEngine - Stochastic Support:
DiffusionHandler,NoiseCharacterizer,SDEValidator - Low-Level Utilities:
codegen_utils
Read this if: You’re implementing custom system types or need to understand how symbolic-to-numerical compilation works.
5. Integration Framework
Multi-backend numerical integration for ODEs and SDEs.
Topics covered:
- Integrator architecture and factories
- Deterministic integrators (Scipy, TorchDiffEq, Diffrax, DiffEqPy, Fixed-step)
- Stochastic integrators (TorchSDE, Diffrax SDE, DiffEqPy SDE)
- 40+ integration methods across 4 backends
- Integration result types and performance tracking
Read this if: You’re implementing custom integrators, need to understand method selection, or want to optimize integration performance.
6. Control Framework Architecture
Classical control theory algorithms for analysis and synthesis.
Topics covered:
- Control Design: LQR, Kalman filter, LQG controller design
- System Analysis: Stability, controllability, observability analysis
- Pure functional architecture with thin composition wrappers
- Unified continuous/discrete interface
- TypedDict results (LQRResult, KalmanFilterResult, StabilityInfo, etc.)
Read this if: You’re using control design methods, need to understand the control API, or want to extend control capabilities.
7. Visualization Framework
Interactive, publication-ready plotting for dynamical systems analysis.
Components documented:
- Theming layer (colors, styles, themes)
TrajectoryPlotter- Time-domain visualizationPhasePortraitPlotter- State-space visualizationControlPlotter- Control analysis plots
Read this if: You’re extending visualization capabilities or need to understand the plotting system architecture.
Architecture Statistics
The framework consists of:
- 50+ core files organized into 7 architectural layers
- 200+ types for semantic clarity and IDE support
- 55+ integration methods across NumPy, PyTorch, JAX, and Julia backends
- 11 delegation layer utilities providing specialized services
- Classical control algorithms (LQR, Kalman, LQG, stability, controllability, observability)
- 8 core UI framework classes for system definition
- 16+ plot types for comprehensive visualization
- Zero code duplication through strategic abstraction
Design Principles Summary
- Type-Driven Design - Types are not just annotations—they are the architecture
- Composition Over Inheritance - Build systems from specialized utilities
- Backend Agnosticism - Write once, run on NumPy/PyTorch/JAX
- Zero Code Duplication - Every line exists in exactly one place
- Structured Results - TypedDict for all outputs with IDE support
- Protocol-Based Interfaces - Duck typing with type safety
- Factory Pattern - Hide complexity behind simple creation methods
- Semantic Naming - Names convey mathematical meaning
- Progressive Disclosure - Simple things simple, complex things possible
Common Architectural Questions
Why composition instead of inheritance?
Short answer: Single responsibility, testability, and flexibility.
Long answer: See Design Philosophy
Why support multiple backends?
Short answer: Different backends excel at different tasks—NumPy for CPU, PyTorch for GPUs/neural networks, JAX for optimization.
Long answer: See Design Philosophy
Where does symbolic-to-numerical compilation happen?
Short answer: In the CodeGenerator utility, with per-backend caching.
Long answer: See Delegation Layer
How are integrators selected automatically?
Short answer: Through the IntegratorFactory which chooses based on system properties and backend.
Long answer: See Integration Framework
How does the framework avoid code duplication?
Short answer: Through SymbolicSystemBase providing shared functionality to both continuous and discrete systems.
Long answer: See UI Framework Architecture and Design Philosophy
What types should I use for my custom components?
Short answer: Use semantic types like StateVector, ControlVector, and TypedDict results like IntegrationResult.
Long answer: See Type System Architecture
How do I design an LQR controller?
Short answer: Use system.control.design_lqr(A, B, Q, R) after linearizing your system.
Long answer: See Control Framework Architecture
How do I define a custom dynamical system?
Short answer: Subclass ContinuousSymbolicSystem or DiscreteSymbolicSystem and implement define_system().
Long answer: See UI Framework Architecture
Contributing to the Framework
If you’re interested in contributing:
- Start with Design Philosophy to understand core principles
- Review Type System Architecture to understand type conventions
- Study the relevant layer docs for your contribution area:
- System definition → UI Framework Architecture
- Internal utilities → Delegation Layer
- Numerical integration → Integration Framework
- Control algorithms → Control Framework
- Visualization → Visualization Framework
- Follow the established patterns (composition, type-driven design, etc.)
- Write comprehensive tests for each component in isolation
- Document your additions with clear examples and type annotations
See Contributing Guidelines for more details.
Getting Help
- Questions about architecture? Open a discussion on GitHub
- Found a design issue? File an issue with the “architecture” label
- Want to propose an enhancement? Start with a discussion to align with design principles
Remember: Most users don’t need to read architecture documentation. The framework is designed so you can be productive without understanding its internals. These documents are here when you need them.