Dane Sabo cebf8c167a Initial umbrella repo: thesis + FRET pipeline + plant model with first controllers
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>
2026-04-16 16:24:11 -04:00

4.7 KiB

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 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

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.