Tutorial examples for gds-framework — five complete domain models demonstrating every framework feature
Project description
GDS Framework Examples
Five complete domain models demonstrating every framework feature. Each model.py is written as a tutorial chapter with inline GDS theory commentary — read them in order.
Learning Path
Start with SIR Epidemic and work down. Each example introduces one new concept.
| # | Example | New Concept | Composition | Roles |
|---|---|---|---|---|
| 1 | SIR Epidemic | Fundamentals — TypeDef, Entity, Space, blocks | >> | |
BA, P, M |
| 2 | Thermostat PID | .feedback(), CONTRAVARIANT backward flow |
>> .feedback() |
BA, P, CA, M |
| 3 | Lotka-Volterra | .loop(), COVARIANT temporal iteration |
>> | .loop() |
BA, P, M |
| 4 | Prisoner's Dilemma | Nested |, multi-entity X, complex trees |
| >> .loop() |
BA, P, M |
| 5 | Insurance Contract | ControlAction role, complete 4-role taxonomy | >> |
BA, P, CA, M |
Roles: BA = BoundaryAction, P = Policy, CA = ControlAction, M = Mechanism
Quick Start
# Run all example tests (140 tests)
uv run pytest examples/ -v
# Run a specific example
uv run pytest examples/sir_epidemic/ -v
# Generate all structural diagrams
uv run python examples/visualize_examples.py
# Generate all 6 views for one example
uv run python examples/sir_epidemic/generate_views.py # print to stdout
uv run python examples/sir_epidemic/generate_views.py --save # write VIEWS.md
File Structure
Each example follows the same layout:
examples/sir_epidemic/
├── __init__.py # empty
├── model.py # types, entities, spaces, blocks, build_spec(), build_system()
├── test_model.py # comprehensive tests for every layer
├── generate_views.py # generates all 6 visualization views with commentary
└── VIEWS.md # generated output — 6 Mermaid diagrams with explanations
Additional files:
examples/visualize_examples.py— generates structural diagrams for all examplesexamples/prisoners_dilemma/visualize.py— custom architecture-aware diagramexamples/CLAUDE.md— detailed guide for building new models from scratch
SIR Epidemic
Start here. The most thoroughly documented example — every definition has inline commentary explaining the GDS concept it represents.
Model: 3 compartments (Susceptible, Infected, Recovered) with contact-driven infection dynamics.
GDS Decomposition:
X = (S, I, R) — state: population counts
U = contact_rate — exogenous input
g = infection_policy — policy: computes deltas
f = (update_s, update_i, update_r) — mechanisms: apply deltas
Θ = {beta, gamma, contact_rate}
Composition:
contact >> infection_policy >> (update_s | update_i | update_r)
What you'll learn:
- TypeDef with runtime constraints (non-negative counts, positive rates)
- Entity and StateVariable for defining state space X
- Space for typed inter-block communication channels
- BoundaryAction (exogenous input), Policy (decision logic), Mechanism (state update)
>>sequential composition with token-based auto-wiring|parallel composition for independent mechanisms- GDSSpec registration and SpecWiring
- compile_system() to produce SystemIR
Files: model.py · tests · views
Thermostat PID
Adds feedback — backward information flow within a single timestep.
Model: PID controller maintaining room temperature with energy cost feedback from the plant.
GDS Decomposition:
X = (T, E) — state: temperature, cumulative energy
U = measured_temp — exogenous sensor reading
g = pid_controller — policy with backward_in for cost feedback
f = update_room — mechanism: applies changes to X
Θ = {setpoint, Kp, Ki, Kd}
Composition:
(sensor >> controller >> plant >> update).feedback(
[Energy Cost: plant -> controller CONTRAVARIANT]
)
What you'll learn:
.feedback()composition for within-timestep backward flow- CONTRAVARIANT flow direction (backward_out → backward_in)
- ControlAction role — reads state and emits control signals (vs Mechanism which writes state)
- backward_in / backward_out ports on block interfaces
- Multi-variable Entity (Room has both temperature and energy_consumed)
Key distinction: Room Plant is ControlAction (not Mechanism) because it has backward_out. Mechanisms cannot have backward ports — that constraint is enforced at construction time.
Files: model.py · tests · views
Lotka-Volterra
Adds temporal loops — forward iteration across timesteps.
Model: Predator-prey population dynamics where updated populations feed back into rate computation at the next timestep.
GDS Decomposition:
X = (x, y) — state: prey and predator populations
U = population_signal — exogenous seed observation
g = compute_rates — policy: Lotka-Volterra rate equations
f = (update_prey, update_predator) — mechanisms with forward_out
Θ = {prey_birth_rate, predation_rate, predator_death_rate, predator_efficiency}
Composition:
(observe >> compute >> (update_prey | update_pred)).loop(
[Population Signal -> Compute Rates COVARIANT]
)
What you'll learn:
.loop()composition for cross-timestep temporal feedback- COVARIANT flow direction — mandatory for
.loop()(CONTRAVARIANT raises GDSTypeError) - Mechanism with forward_out — emitting signals after state update
- exit_condition parameter for loop termination
- Contrast with
.feedback(): within-timestep (thermostat) vs across-timestep (here)
Key distinction: Temporal wirings must be COVARIANT — .loop() enforces this at construction time. The mechanisms here have forward_out ports, unlike SIR's terminal mechanisms.
Files: model.py · tests · views
Prisoner's Dilemma
Most complex composition — nested parallel + sequential + temporal loop.
Model: Iterated game with two adaptive agents (Alice, Bob) learning from payoff outcomes.
GDS Decomposition:
X = (s_A, U_A, s_B, U_B, t) — state: strategies, scores, round
U = game_config — exogenous payoff matrix (R, T, S, P)
g = (alice_decision, bob_decision) — independent policies
f = (payoff_realization, alice_world_model, bob_world_model)
Θ = {} (payoff matrix is exogenous, not a parameter)
Composition:
input_phase = payoff_setting | (alice_decision | bob_decision)
world_updates = alice_world_model | bob_world_model
pipeline = input_phase >> payoff_realization >> world_updates
system = pipeline.loop([world models -> decisions])
What you'll learn:
- Nested parallel composition:
(A | B) | Cfor logical grouping - Multi-entity state space X with 3 entities (5 state variables total)
- Mechanism with forward_out for temporal feedback (same pattern as lotka_volterra)
- Complex composition tree combining all operators except
.feedback() - Design choice: parameter vs exogenous input (payoff matrix is U, not Θ)
Files: model.py · tests · views · architecture viz
Insurance Contract
Completes the role taxonomy — the only example using all 4 block roles.
Model: Claim processing pipeline with risk-based premium calculation and reserve management.
GDS Decomposition:
X = (R, P, C, H) — state: reserve, premium pool, coverage, claims history
U = claim_event — exogenous claim arrival
g = risk_assessment — policy: scores risk from claim data
d = premium_calculation — control action: admissibility decision
f = (claim_payout, reserve_update) — mechanisms: state transitions
Θ = {base_premium_rate, deductible, coverage_limit}
Composition:
claim >> risk >> premium >> payout >> reserve_update
What you'll learn:
- ControlAction role — the 4th block role, for admissibility/control decisions
- Complete 4-role taxonomy: BoundaryAction → Policy → ControlAction → Mechanism
- ControlAction vs Policy: Policy is core decision logic (g), ControlAction constrains the action space (d)
- params_used on ControlAction — parameterized admissibility rules
- Mechanism with forward_out for chaining within a timestep (Claim Payout → Reserve Update)
Key distinction: Premium Calculation is ControlAction because it enforces admissibility constraints (deductible, coverage limit) — it decides what's allowed, not what to do.
Files: model.py · tests · views
Visualization Views
Each example includes a generate_views.py script that produces 6 complementary views:
| View | Input | What It Shows |
|---|---|---|
| 1. Structural | SystemIR | Compiled block graph — role shapes, wiring arrows |
| 2. Canonical GDS | CanonicalGDS | Mathematical decomposition: X_t → U → g → f → X_{t+1} |
| 3. Architecture by Role | GDSSpec | Blocks grouped by GDS role (boundary/policy/mechanism/control) |
| 4. Architecture by Domain | GDSSpec | Blocks grouped by domain tag (organizational view) |
| 5. Parameter Influence | GDSSpec | Θ → blocks → entities causal map |
| 6. Traceability | GDSSpec | Backwards trace from one state variable to all influencing blocks |
Here's the architecture by domain view for the Thermostat PID — blocks grouped by domain tag (Sensor, Controller, Plant), revealing the physical subsystem decomposition:
%%{init:{"theme":"neutral"}}%%
flowchart TD
classDef boundary fill:#93c5fd,stroke:#2563eb,stroke-width:2px,color:#1e3a5f
classDef policy fill:#fcd34d,stroke:#d97706,stroke-width:2px,color:#78350f
classDef mechanism fill:#86efac,stroke:#16a34a,stroke-width:2px,color:#14532d
classDef control fill:#d8b4fe,stroke:#9333ea,stroke-width:2px,color:#3b0764
classDef generic fill:#cbd5e1,stroke:#64748b,stroke-width:1px,color:#1e293b
classDef entity fill:#e2e8f0,stroke:#475569,stroke-width:2px,color:#0f172a
classDef param fill:#fdba74,stroke:#ea580c,stroke-width:2px,color:#7c2d12
classDef state fill:#5eead4,stroke:#0d9488,stroke-width:2px,color:#134e4a
classDef target fill:#fca5a5,stroke:#dc2626,stroke-width:2px,color:#7f1d1d
classDef empty fill:#e2e8f0,stroke:#94a3b8,stroke-width:1px,color:#475569
subgraph Sensor ["Sensor"]
Temperature_Sensor([Temperature Sensor]):::boundary
end
subgraph Controller ["Controller"]
PID_Controller[PID Controller]:::policy
end
subgraph Plant ["Plant"]
Room_Plant[Room Plant]:::control
Update_Room[[Update Room]]:::mechanism
end
entity_Room[("Room<br/>temperature: T, energy_consumed: E")]:::entity
Update_Room -.-> entity_Room
Temperature_Sensor --TemperatureSpace--> PID_Controller
PID_Controller --CommandSpace--> Room_Plant
Room_Plant --EnergyCostSpace--> PID_Controller
Room_Plant --RoomStateSpace--> Update_Room
And the structural view for the Thermostat PID — note the thick feedback arrow (==>) from Room Plant back to PID Controller, showing CONTRAVARIANT within-timestep flow:
%%{init:{"theme":"neutral"}}%%
flowchart TD
classDef boundary fill:#93c5fd,stroke:#2563eb,stroke-width:2px,color:#1e3a5f
classDef policy fill:#fcd34d,stroke:#d97706,stroke-width:2px,color:#78350f
classDef mechanism fill:#86efac,stroke:#16a34a,stroke-width:2px,color:#14532d
classDef control fill:#d8b4fe,stroke:#9333ea,stroke-width:2px,color:#3b0764
classDef generic fill:#cbd5e1,stroke:#64748b,stroke-width:1px,color:#1e293b
Temperature_Sensor([Temperature Sensor]):::boundary
PID_Controller[PID Controller]:::generic
Room_Plant[Room Plant]:::generic
Update_Room[[Update Room]]:::mechanism
Temperature_Sensor --Measured Temperature--> PID_Controller
PID_Controller --Heater Command--> Room_Plant
Room_Plant --Room State--> Update_Room
Room_Plant ==Energy Cost==> PID_Controller
Here's the parameter influence view for the SIR Epidemic — Θ → blocks → entities causal map showing which parameters affect which state variables:
%%{init:{"theme":"neutral"}}%%
flowchart LR
classDef boundary fill:#93c5fd,stroke:#2563eb,stroke-width:2px,color:#1e3a5f
classDef policy fill:#fcd34d,stroke:#d97706,stroke-width:2px,color:#78350f
classDef mechanism fill:#86efac,stroke:#16a34a,stroke-width:2px,color:#14532d
classDef control fill:#d8b4fe,stroke:#9333ea,stroke-width:2px,color:#3b0764
classDef generic fill:#cbd5e1,stroke:#64748b,stroke-width:1px,color:#1e293b
classDef entity fill:#e2e8f0,stroke:#475569,stroke-width:2px,color:#0f172a
classDef param fill:#fdba74,stroke:#ea580c,stroke-width:2px,color:#7c2d12
classDef state fill:#5eead4,stroke:#0d9488,stroke-width:2px,color:#134e4a
classDef target fill:#fca5a5,stroke:#dc2626,stroke-width:2px,color:#7f1d1d
classDef empty fill:#e2e8f0,stroke:#94a3b8,stroke-width:1px,color:#475569
param_beta{{"beta"}}:::param
param_contact_rate{{"contact_rate"}}:::param
param_gamma{{"gamma"}}:::param
Contact_Process[Contact Process]
Infection_Policy[Infection Policy]
entity_Infected[("Infected<br/>I")]:::entity
entity_Recovered[("Recovered<br/>R")]:::entity
entity_Susceptible[("Susceptible<br/>S")]:::entity
param_beta -.-> Infection_Policy
param_contact_rate -.-> Contact_Process
param_gamma -.-> Infection_Policy
Update_Recovered -.-> entity_Recovered
Update_Susceptible -.-> entity_Susceptible
Update_Infected -.-> entity_Infected
Contact_Process --> Infection_Policy
Infection_Policy --> Update_Infected
Infection_Policy --> Update_Recovered
Infection_Policy --> Update_Susceptible
Each example's VIEWS.md contains all 6 views with commentary explaining what each reveals for that specific model.
# Generate views for one example
uv run python examples/sir_epidemic/generate_views.py --save
# Generate views for all examples
for d in sir_epidemic thermostat lotka_volterra prisoners_dilemma insurance; do
uv run python examples/$d/generate_views.py --save
done
Output is Mermaid markdown — renders in GitHub, GitLab, VS Code, Obsidian, and mermaid.live.
Test Coverage
All examples include tests covering every layer:
- Types — TypeDef.check_value() for valid/invalid/boundary values
- Entities — Entity.validate_state() with good/bad/missing data
- Blocks — Role isinstance checks, interface port counts, Mechanism.updates
- Composition — Operators build without error, flatten() yields expected block count
- GDSSpec — validate_spec() returns no errors, entity/block/parameter counts
- SystemIR — compile_system() succeeds, block/wiring counts correct
- Verification — Generic checks (G-001/003/004/005/006), semantic checks (completeness, determinism, type safety, reachability)
- SpecQuery — Dependency graphs, update maps, parameter tracking, causal chains
Total: 140 example tests. Run with uv run pytest examples/ -v.
Feature Coverage Matrix
| Feature | SIR | Thermostat | Lotka-V | Prisoner's D | Insurance |
|---|---|---|---|---|---|
| BoundaryAction | ✓ | ✓ | ✓ | ✓ | ✓ |
| Policy | ✓ | ✓ | ✓ | ✓ | ✓ |
| Mechanism | ✓ | ✓ | ✓ | ✓ | ✓ |
| ControlAction | ✓ | ✓ | |||
>> (sequential) |
✓ | ✓ | ✓ | ✓ | ✓ |
| (parallel) |
✓ | ✓ | ✓ | ||
.feedback() |
✓ | ||||
.loop() |
✓ | ✓ | |||
| CONTRAVARIANT wiring | ✓ | ||||
| Temporal wiring | ✓ | ✓ | |||
| Multi-variable Entity | ✓ | ✓ | ✓ | ||
| Multiple entities | ✓ | ✓ | ✓ | ✓ | |
| Parameters (Θ) | ✓ | ✓ | ✓ | ✓ |
Building New Examples
See CLAUDE.md for a detailed guide covering:
- Step-by-step model creation (types → entities → spaces → blocks → spec → system)
- Role constraint rules (what each role enforces on its interface)
- Composition operator reference with pitfalls
- Common mistakes at construction, registration, and validation time
- Test patterns to follow
- Design decisions (state vs signal, parameter vs exogenous input, ControlAction vs Policy)
License
Apache-2.0
Credits & Attribution
Development & Implementation
- Primary Author: Rohan Mehta
- Organization: BlockScience
Theoretical Foundation
This codebase is a direct implementation of the research and mathematical frameworks developed by:
- Dr. Jamsheed Shorish (@jshorish) and Dr. Michael Zargham (@mzargham).
- Key Reference: Generalized Dynamical Systems, Part I: Foundations (BlockScience, 2021).
Architectural Inspiration
The design patterns and structural approach of this library are heavily influenced by the prior work of Sean McOwen (@SeanMcOwen), specifically:
Contributors
- Peter Hacker (@phacker3) — Code auditing and review (BlockScience).
Intellectual Lineage
This project exists within the broader ecosystem of:
- cadCAD: For foundational philosophy in Complex Adaptive Dynamics.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gds_examples-0.1.0.tar.gz.
File metadata
- Download URL: gds_examples-0.1.0.tar.gz
- Upload date:
- Size: 62.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
59738a4f141667493d79278039076ab0237f27b60d74cd70d5062510460ddab1
|
|
| MD5 |
0c70593e18ce0aad7034aeb33ae16c51
|
|
| BLAKE2b-256 |
8d2f0b15e9437d4feec66a2698cc54c9221932fe86aed995c63fa36d1ab4b4ae
|
File details
Details for the file gds_examples-0.1.0-py3-none-any.whl.
File metadata
- Download URL: gds_examples-0.1.0-py3-none-any.whl
- Upload date:
- Size: 74.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ee89329aa6b7ec786fff9a5b5039a79a15f07f58f8d4b432eeacb45b555ed3de
|
|
| MD5 |
2b46c0b7136250ee14fec49d314dd955
|
|
| BLAKE2b-256 |
9f9b592a6b9d6f4e92ce28e2530e6ea5f2b0364bcbf85ca7e1cfb683e2e911be
|