SkillAgentSearch skills...

RadCAD

A Python framework for designing, testing, and validating complex systems through modelling and simulation.

Install / Use

/learn @CADLabs/RadCAD
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

radCAD

PyPI Build Status Coverage Status Maintainability

Gosper Glider Gun

A Python framework for modelling and simulating dynamical systems. A dynamical system is a system whose state evolves over time according to a fixed set of rules, often expressed as mathematical equations, that depend on its current state and, optionally, external inputs.

Models are structured using state transitions for encoding differential equations, or any other logic, as an example. Simulations are configured using methods such as parameter sweeps, Monte Carlo runs, and A/B testing. See cadCAD.education for the most comprehensive cadCAD beginner course.

Goals:

  • simple API for ease of use
  • performance driven (more speed = more experiments, larger parameter sweeps, in less time)
  • cadCAD compatible (standard functions, data structures, and simulation results)
  • maintainable, testable codebase

Have a question not answered in this README or the cadCAD Edu courses? Post a comment in the issues or check out the cadCAD Discord community.

Table of Contents

Open-source Models Using radCAD

  • Ethereum Economic Model by CADLabs: A modular dynamical-systems model of Ethereum's validator economics
  • Beacon Runner by Ethereum RIG: An agent-based model of Ethereum's Proof-of-Stake consensus layer
  • GEB Controller Simulations by BlockScience: A Proportional-Integral-Derivative (PID) controller based upon a reference document approach for the Maker DAI market that was never implemented
  • Fei Protocol Model by CADLabs: A modular dynamical-systems model of Fei Protocol

Example Models

Iterable Models

Using Models as live in-the-loop digital twins, creating your own model pipelines, and streaming simulation results to update a visualization. That's what an iterable Model class enables.

Iterable Models

Game of Life

Live radCAD demo model on Streamlit

A simple game where at each timestep, the following transitions occur:

  1. Any live cell with fewer than two live neighbours dies, as if by underpopulation.
  2. Any live cell with two or three live neighbours lives on to the next generation.
  3. Any live cell with more than three live neighbours dies, as if by overpopulation.
  4. Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.

See examples/game_of_life/game-of-life.ipynb

Game of Life

Predator-Prey

A simple model that applies the two Lotka-Volterra differential equations, frequently used to describe the dynamics of biological systems in which two species interact:

Original models thanks to Danilo @danlessa!

Features

  • [x] Parameter sweeps
params = {
    'a': [1, 2, 3],
    'b': [1, 2],
    'c': [1]
}
# Creates a parameter sweep of:
# [{'a': 1, 'b': 1, 'c': 1}, {'a': 2, 'b': 2, 'c': 1}, {'a': 3, 'b': 2, 'c': 1}]
  • [x] Monte Carlo runs
RUNS = 100 # Set to the number of Monte Carlo Runs
Simulation(model=model, timesteps=TIMESTEPS, runs=RUNS)
  • [x] A/B tests
model_a = Model(initial_state=states_a, state_update_blocks=state_update_blocks_a, params=params_a)
model_b = Model(initial_state=states_b, state_update_blocks=state_update_blocks_b, params=params_b)

simulation_1 = Simulation(model=model_a, timesteps=TIMESTEPS, runs=RUNS)
simulation_2 = Simulation(model=model_b, timesteps=TIMESTEPS, runs=RUNS)

# Simulate any number of models in parallel
experiment = Experiment([simulation_1, simulation_2])
result = experiment.run()
  • [x] cadCAD compatibility and familiar data structure
               a          b  simulation  subset  run  substep  timestep
0       1.000000        2.0           0       0    1        0         0
1       0.540302        2.0           0       0    1        1         1
2       0.540302        7.0           0       0    1        2         1
3       0.463338        7.0           0       0    1        1         2
4       0.463338       12.0           0       0    1        2         2
...          ...        ...         ...     ...  ...      ...       ...
799999  0.003162   999982.0           1       1    1        2     99998
800000  0.003162   999982.0           1       1    1        1     99999
800001  0.003162   999992.0           1       1    1        2     99999
800002  0.003162   999992.0           1       1    1        1    100000
800003  0.003162  1000002.0           1       1    1        2    100000
  • [x] Tested against Python 3.8 to 3.12 using Ubuntu, MacOS, and Windows

Advanced Features

  • [x] Disable deepcopy option for improved performance (at cost of mutability)
  • [x] Robust exception handling with partial results, and tracebacks
  • [x] Parallel processing with multiple backend options: multiprocessing, pathos, ray
  • [x] Distributed computing and remote execution in a cluster (AWS, GCP, Kubernetes, ...) using Ray - Fast and Simple Distributed Computing
  • [x] Hooks to easily extend the functionality - e.g. save results to HDF5 file format after completion
  • [x] Model classes are iterable, so you can iterate over them step-by-step from one state to the next (useful for gradient descent, live digital twins)
  • [x] Parameters can be configured using nested dataclasses! This enables typing and dot notation for accessing parameters, and the creation of parameter namespaces.

Installation

pip install radcad

Documentation

radCAD provides the following classes:

  1. A system is represented in some form as a Model
  2. A Model can be simulated using a Simulation
  3. An Experiment consists of one or more Simulations
  4. An Experiment or a Simulation is run by the Engine

So, the hierarchy is as follows Model > Simulation > Experiment > Engine.

from radcad import Model, Simulation, Experiment

model = Model(initial_state=initial_state, state_update_blocks=state_update_blocks, params=params)
simulation = Simulation(model=model, timesteps=100_000, runs=1)

result = simulation.run()
# Or, multiple simulations:
# experiment = Experiment([simulation_1, simulation_2, simulation_3])
# result = experiment.run()

df = pd.DataFrame(result)

Model Parameters

A unique feature of radCAD is being able to use nested dataclasses to configure the model's parameters. This enables typing and dot notation for accessing parameters, and the creation of parameter namespaces, demonstrated below.

from dataclasses import dataclass
from radcad.utils import default
from radcad.types import StateVariables, PolicySignal

...

@dataclass
class LiquidityPoolParameters:
    initial_liquidity: int = 100_000


@dataclass
class ProtocolParameters:
    liquidity_pool: LiquidityPoolParameters = default(LiquidityPoolParameters())
    ...


@dataclass
class Parameters:
    protocol: ProtocolParameters = default(ProtocolParameters())
    agents: AgentParameters = default(AgentParameters())
    ...


models.params = Parameters()

...

def update_liquidity(
        params: Parameters,
        substep: int,
        state_history: List[List[StateVariables]],
        previous_state: StateVariables,
        policy_input: PolicySignal
) -> Tuple[str, int]:
    if not previous_state["liquidity"]:
        updated_liquidity = params.protocol.liquidity_pool.initial_liquidity
    else:
        updated_liquidity = ...
    return "liquidity", updated_liquidity

cadCAD Compatibility

Migrating from cadCAD to radCAD

cadCAD
# cadCAD configuration modules
from cadCAD.configuration.utils import config_sim
from cadCAD.configuration import Experiment

# cadCAD simulation engine modules
from cadCAD.engine import ExecutionMode, ExecutionContext
from cadCAD.engine import Executor

# cadCAD global simulation configuration list
from cadCAD import configs

# Clears any prior configs
del configs[:]

sim_config = config_sim({
    'N': 1, # Number of Monte Carlo Runs
    'T': range(100), # Number of timesteps
    'M': system_params # System Parameters
})

experiment.append_configs(
    # Model initial

Related Skills

View on GitHub
GitHub Stars113
CategoryDevelopment
Updated13d ago
Forks25

Languages

Python

Security Score

100/100

Audited on Mar 26, 2026

No findings