Skip to main content

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 examples
  • examples/prisoners_dilemma/visualize.py — custom architecture-aware diagram
  • examples/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) | C for 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

Theoretical Foundation

This codebase is a direct implementation of the research and mathematical frameworks developed by:

Architectural Inspiration

The design patterns and structural approach of this library are heavily influenced by the prior work of Sean McOwen (@SeanMcOwen), specifically:

  • MSML: For system specification logic.
  • bdp-lib: For block-data processing architecture.

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gds_examples-0.1.0.tar.gz (62.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gds_examples-0.1.0-py3-none-any.whl (74.9 kB view details)

Uploaded Python 3

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

Hashes for gds_examples-0.1.0.tar.gz
Algorithm Hash digest
SHA256 59738a4f141667493d79278039076ab0237f27b60d74cd70d5062510460ddab1
MD5 0c70593e18ce0aad7034aeb33ae16c51
BLAKE2b-256 8d2f0b15e9437d4feec66a2698cc54c9221932fe86aed995c63fa36d1ab4b4ae

See more details on using hashes here.

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

Hashes for gds_examples-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ee89329aa6b7ec786fff9a5b5039a79a15f07f58f8d4b432eeacb45b555ed3de
MD5 2b46c0b7136250ee14fec49d314dd955
BLAKE2b-256 9f9b592a6b9d6f4e92ce28e2530e6ea5f2b0364bcbf85ca7e1cfb683e2e911be

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page