Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions docs/control/api/checks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# gds_control.verification.checks

Control system verification checks (CS-001..CS-006).

::: gds_control.verification.checks.check_cs001_undriven_states

::: gds_control.verification.checks.check_cs002_unobserved_states

::: gds_control.verification.checks.check_cs003_unused_inputs

::: gds_control.verification.checks.check_cs004_controller_read_validity

::: gds_control.verification.checks.check_cs005_controller_drive_validity

::: gds_control.verification.checks.check_cs006_sensor_observe_validity
27 changes: 27 additions & 0 deletions docs/control/api/compile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# gds_control.dsl.compile

Compiler: ControlModel -> GDSSpec / SystemIR.

## Semantic Types

::: gds_control.dsl.compile.StateType

::: gds_control.dsl.compile.StateSpace

::: gds_control.dsl.compile.ReferenceType

::: gds_control.dsl.compile.ReferenceSpace

::: gds_control.dsl.compile.MeasurementType

::: gds_control.dsl.compile.MeasurementSpace

::: gds_control.dsl.compile.ControlType

::: gds_control.dsl.compile.ControlSpace

## Public Functions

::: gds_control.dsl.compile.compile_model

::: gds_control.dsl.compile.compile_to_system
11 changes: 11 additions & 0 deletions docs/control/api/elements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# gds_control.dsl.elements

Control system element declarations -- frozen Pydantic models for user-facing declarations.

::: gds_control.dsl.elements.State

::: gds_control.dsl.elements.Input

::: gds_control.dsl.elements.Sensor

::: gds_control.dsl.elements.Controller
8 changes: 8 additions & 0 deletions docs/control/api/init.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# gds_control

Public API -- top-level exports.

::: gds_control
options:
show_submodules: false
members: false
5 changes: 5 additions & 0 deletions docs/control/api/model.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# gds_control.dsl.model

ControlModel -- declarative container for control system specifications.

::: gds_control.dsl.model.ControlModel
5 changes: 5 additions & 0 deletions docs/control/api/verification.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# gds_control.verification

Verification engine -- runs domain checks with optional GDS structural checks.

::: gds_control.verification.engine.verify
105 changes: 105 additions & 0 deletions docs/control/getting-started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Getting Started

## Installation

```bash
uv add gds-control
# or: pip install gds-control
```

For development (monorepo):

```bash
git clone https://github.com/BlockScience/gds-core.git
cd gds-core
uv sync --all-packages
```

## Your First Control Model

A control model describes a feedback control system: states represent the plant, inputs provide reference signals, sensors observe state, and controllers compute control actions.

```python
from gds_control import (
State, Input, Sensor, Controller,
ControlModel, compile_model, compile_to_system, verify,
)

# Declare a thermostat control system
model = ControlModel(
name="Thermostat",
states=[State(name="temperature", initial=20.0)],
inputs=[Input(name="setpoint")],
sensors=[Sensor(name="thermometer", observes=["temperature"])],
controllers=[
Controller(
name="PID",
reads=["thermometer", "setpoint"],
drives=["temperature"],
)
],
)

# Compile to GDS
spec = compile_model(model)
print(f"Blocks: {len(spec.blocks)}") # 4 blocks
print(f"Entities: {len(spec.entities)}") # 1 (temperature state)

# Compile to SystemIR for verification
ir = compile_to_system(model)
print(f"{len(ir.blocks)} blocks, {len(ir.wirings)} wirings")

# Verify — domain checks + GDS structural checks
report = verify(model, include_gds_checks=True)
print(f"{report.checks_passed}/{report.checks_total} checks passed")
```

## A Multi-State Model

Control models support multiple states with multiple sensors and controllers:

```python
from gds_control import (
State, Input, Sensor, Controller,
ControlModel, verify,
)

model = ControlModel(
name="HVAC System",
states=[
State(name="temperature", initial=22.0),
State(name="humidity", initial=45.0),
],
inputs=[
Input(name="temp_setpoint"),
Input(name="humidity_setpoint"),
],
sensors=[
Sensor(name="temp_sensor", observes=["temperature"]),
Sensor(name="humidity_sensor", observes=["humidity"]),
],
controllers=[
Controller(
name="heater",
reads=["temp_sensor", "temp_setpoint"],
drives=["temperature"],
),
Controller(
name="humidifier",
reads=["humidity_sensor", "humidity_setpoint"],
drives=["humidity"],
),
],
)

# Verify
report = verify(model, include_gds_checks=False)
for f in report.findings:
print(f" [{f.check_id}] {'PASS' if f.passed else 'FAIL'} {f.message}")
```

## Next Steps

- [Elements & GDS Mapping](guide/elements.md) -- detailed element reference and how each maps to GDS
- [Verification Guide](guide/verification.md) -- all 6 domain checks explained
- [API Reference](api/init.md) -- complete auto-generated API docs
120 changes: 120 additions & 0 deletions docs/control/guide/elements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Elements & GDS Mapping

`gds-control` provides four element types, each mapping to a specific GDS role and corresponding to the standard state-space representation.

## State

A state variable in the plant. Each state becomes a GDS entity with a `value` state variable, and a dynamics block that applies incoming control signals.

```python
State(name="temperature", initial=20.0)
```

**GDS mapping:** `Mechanism` (state update *f*) + `Entity` (state *X*)

**State-space:** x (state vector)

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `name` | str | required | State name (becomes entity name) |
| `initial` | float \| None | None | Initial value |

### Port Convention

- Output: `"{Name} State"` (temporal feedback to sensors)
- Input: `"{ControllerName} Control"` (incoming control signals)

---

## Input

An exogenous reference signal or disturbance entering the system from outside. Inputs have no internal sources -- they represent the boundary between the system and its environment.

```python
Input(name="setpoint")
```

**GDS mapping:** `BoundaryAction` (exogenous input *U*)

**State-space:** r (reference signal)

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `name` | str | required | Input name |

### Port Convention

- Output: `"{Name} Reference"`

---

## Sensor

A sensor reads state variables and emits a measurement signal. The `observes` list declares which states the sensor can read -- validated at model construction time.

```python
Sensor(name="thermometer", observes=["temperature"])
```

**GDS mapping:** `Policy` (observation *g*)

**State-space:** y = Cx + Du (sensor output)

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `name` | str | required | Sensor name |
| `observes` | list[str] | [] | Names of states this sensor reads |

### Port Convention

- Input: `"{StateName} State"`
- Output: `"{Name} Measurement"`

---

## Controller

A controller reads sensor measurements and/or reference inputs, then emits control signals to drive state variables.

```python
Controller(name="PID", reads=["thermometer", "setpoint"], drives=["temperature"])
```

**GDS mapping:** `Policy` (decision logic *g*)

**State-space:** u = K(y, r) (control law)

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `name` | str | required | Controller name |
| `reads` | list[str] | [] | Names of sensors/inputs this controller reads |
| `drives` | list[str] | [] | Names of states this controller drives |

### Port Convention

- Input: `"{ReadName} Measurement"` or `"{ReadName} Reference"`
- Output: `"{Name} Control"`

---

## Semantic Type System

Four distinct semantic spaces, all `float`-backed but structurally separate -- this prevents accidentally wiring a measurement where a control signal is expected:

| Type | Space | Used By | Description |
|------|-------|---------|-------------|
| `StateType` | `StateSpace` | States | Plant state variables |
| `ReferenceType` | `ReferenceSpace` | Inputs | Exogenous reference/disturbance signals |
| `MeasurementType` | `MeasurementSpace` | Sensors | Sensor output measurements |
| `ControlType` | `ControlSpace` | Controllers | Controller output signals |

## Composition Structure

The compiler builds a tiered composition tree:

```
(inputs | sensors) >> (controllers) >> (state dynamics)
.loop([state dynamics forward_out -> sensor forward_in])
```

This maps to the GDS canonical form `h = f . g` where states carry state (X), dynamics provide f, and sensors + controllers contribute to g.
Loading