Folds three previously-separate pieces into one preliminary-example repo for the HAHACS thesis: - thesis/ (submodule) → gitea Thesis.git — the PhD proposal - fret-pipeline/ — FRET requirements to AIGER controller (was ~/Documents/fret_processing/; prior single-commit history abandoned per user decision) - plant-model/ — 10-state PKE + lumped T/H PWR model (was ~/Documents/PKE_Playground/; never version-controlled before) - presentations/2026DICE/ (submodule) → gitea 2026DICE.git - reachability/, hardware/ — empty placeholders for Thrust 3 and HIL - docs/architecture.md — how the discrete and continuous layers compose - claude_memory/ — session notes and scratch knowledge pattern Plant model refactored to thesis naming (x, plant, u, ref); pke_th_rhs now takes u as an explicit arg instead of reading rho_ext from the params struct. First two controllers built to the contract u = ctrl_<mode>(t, x, plant, ref): ctrl_null (baseline) and ctrl_operation (stabilizing, proportional on T_avg). Validated under a 100% -> 80% Q_sg step: ctrl_operation reduces steady-state T_avg drift ~47% vs. the unforced plant. Root CLAUDE.md emphasizes that CLAUDE.md files are living documents and that any knowledge not captured before a session ends is lost forever; claude_memory/ holds the session-level notes that haven't stabilized enough to graduate into a CLAUDE.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
124 lines
4.7 KiB
Markdown
124 lines
4.7 KiB
Markdown
# synthesize.sh -- ltlsynt Reactive Synthesis Wrapper
|
|
|
|
## Purpose
|
|
|
|
Reads a synthesis configuration JSON and invokes `ltlsynt` (from the Spot
|
|
library) to produce a reactive controller as an AIGER circuit. This is the
|
|
step where temporal logic specifications become a concrete implementation.
|
|
|
|
## Usage
|
|
|
|
```bash
|
|
bash scripts/synthesize.sh <synthesis_config.json> [output_dir]
|
|
```
|
|
|
|
- `synthesis_config.json`: output of `fret_to_synth.py`
|
|
- `output_dir`: where to write the `.aag` file (default: `circuits/`)
|
|
|
|
## How It Works
|
|
|
|
### Parameter Extraction
|
|
|
|
A small inline Python script reads the JSON config and extracts:
|
|
|
|
- `INPUTS`: comma-separated list of environment variables (uncontrollable)
|
|
- `OUTPUTS`: comma-separated list of system variables (controllable)
|
|
- `LTL_FORMULA`: the conjoined LTL specification
|
|
- `SPEC_NAME`: used for the output filename
|
|
|
|
### The ltlsynt Call
|
|
|
|
```bash
|
|
ltlsynt -f "$LTL_FORMULA" \
|
|
--ins="$INPUTS" \
|
|
--outs="$OUTPUTS" \
|
|
--aiger=both+ud+dc \
|
|
--simplify=bwoa-sat
|
|
```
|
|
|
|
**Flags explained:**
|
|
|
|
| Flag | Meaning |
|
|
|---|---|
|
|
| `-f` | LTL formula (the specification) |
|
|
| `--ins` | Input (environment/uncontrollable) propositions |
|
|
| `--outs` | Output (system/controllable) propositions |
|
|
| `--aiger=both+ud+dc` | Output as ASCII AIGER with both latches and gates, using unit delays and don't-cares for optimization |
|
|
| `--simplify=bwoa-sat` | Best simplification: bounded width with SAT-based optimization. Produces the smallest circuit |
|
|
|
|
### The Two-Player Game
|
|
|
|
Reactive synthesis frames controller design as a two-player game:
|
|
|
|
- **Player 1 (Environment)**: controls the `--ins` variables. Assumed to be
|
|
adversarial -- the synthesizer must find a strategy that wins against ALL
|
|
possible environment behaviors, including worst-case.
|
|
|
|
- **Player 2 (Controller)**: controls the `--outs` variables. The synthesizer
|
|
searches for a strategy (a Mealy machine) such that no matter what Player 1
|
|
does, the LTL specification is satisfied.
|
|
|
|
**Why adversarial?** Because we need a controller that works in ALL operating
|
|
conditions, not just typical ones. If the environment CAN violate a safety
|
|
invariant, the synthesizer assumes it WILL, and the controller must handle it.
|
|
|
|
This is why the old PWR_Hybrid specs produced a degenerate controller: the
|
|
environment could force `t_max_exceeded` every step, triggering irrecoverable
|
|
SCRAM. The only winning strategy was to SCRAM immediately. The new specs
|
|
have proper guard conditions that give the controller legal responses to every
|
|
environment move.
|
|
|
|
### Realizability
|
|
|
|
ltlsynt outputs one of two results:
|
|
|
|
- **REALIZABLE**: A winning strategy exists. The AIGER circuit is printed
|
|
after the `REALIZABLE` line. The script strips this line and writes the
|
|
circuit to `{output_dir}/{spec_name}.aag`.
|
|
|
|
- **UNREALIZABLE**: No controller can satisfy the specification against all
|
|
possible environment behaviors. This means the specs have a fundamental
|
|
conflict. Use FRET's realizability checking and counterexample traces to
|
|
diagnose which requirements conflict.
|
|
|
|
### Output: AIGER Format
|
|
|
|
The `.aag` (ASCII AIGER) file is a text-based hardware description:
|
|
|
|
```
|
|
aag M I L O A Header: Max-var, Inputs, Latches, Outputs, ANDs
|
|
<input literals> One per line, even numbers (2, 4, 6, ...)
|
|
<latch definitions> current_lit next_lit (state registers)
|
|
<output literals> Which literals are outputs
|
|
<AND gates> lhs rhs0 rhs1 (lhs = rhs0 AND rhs1)
|
|
<symbol table> i0 name, o0 name, etc.
|
|
```
|
|
|
|
**Literal encoding:** Variable `n` has literal `2n` (positive) and `2n+1`
|
|
(negated). Literal `0` = constant FALSE, literal `1` = constant TRUE.
|
|
XOR-ing a literal with 1 flips its polarity.
|
|
|
|
**Latches** are 1-bit registers that initialize to 0. With `L` latches,
|
|
the controller has up to `2^L` internal states. The circuit is a Mealy
|
|
machine: outputs depend on both current state (latches) and current inputs.
|
|
|
|
## Future Improvements
|
|
|
|
- **Environment assumptions**: ltlsynt supports `--from-ltlf` for finite
|
|
traces and can separate assumptions from guarantees. Adding support for
|
|
environment assumptions (e.g., fairness constraints like "the environment
|
|
won't hold t_max_exceeded forever") would expand the class of realizable
|
|
specifications.
|
|
|
|
- **Decomposed synthesis**: For large specs, monolithic synthesis can be
|
|
expensive. Compositional synthesis (synthesizing each mode's controller
|
|
separately and composing them) could improve scalability.
|
|
|
|
- **Alternative output formats**: The AIGER circuit could be translated to
|
|
Verilog, VHDL, or Simulink/Stateflow for integration with existing
|
|
control system toolchains.
|
|
|
|
- **Timeout handling**: Currently no timeout on the ltlsynt call. Very
|
|
complex specifications can take hours. Adding a configurable timeout
|
|
with a clear error message would improve usability.
|