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>
4.4 KiB
CLAUDE.md
Guidance for Claude Code (claude.ai/code) working in this subdirectory.
What this is
A deterministic pipeline that converts FRET natural-language requirements into
a reactive controller and a state-machine diagram. Implements Thrust 1 + 2 of
the HAHACS methodology (../thesis/3-research-approach/approach.tex).
The pipeline is four stages:
FRET JSON --> fret_to_synth.py --> synthesis config JSON
synthesis config --> synthesize.sh --> AIGER circuit (.aag)
AIGER circuit --> trace_aiger.py --> DOT + PNG + SVG state machine
AIGER circuit --> aag2dot.py --> gate-level circuit diagram
Running
python3 scripts/fret_to_synth.py pwr_hybrid_3.json specs/synthesis_config_v3.json
bash scripts/synthesize.sh specs/synthesis_config_v3.json circuits
python3 scripts/trace_aiger.py circuits/PWR_HYBRID_3_DRC.aag diagrams
dot -Tpng diagrams/PWR_HYBRID_3_DRC_states.dot -o diagrams/PWR_HYBRID_3_DRC_states.png
All scripts are pure Python 3 stdlib + bash. External binaries required:
ltlsynt(Spot) —brew install spotdot(Graphviz) —brew install graphviz
Architecture
scripts/fret_to_synth.py — Auto-discovers mode groups by regex-scanning
LTL formulas for (control_X = q_Y) patterns. Decomposes multi-valued mode
variables into independent booleans and generates mutual-exclusion constraints
so the synthesizer can't assert two modes simultaneously. Classifies every
other variable as an environment input. See docs/fret_to_synth.md.
scripts/synthesize.sh — Thin wrapper around ltlsynt that reads the
synthesis config, extracts inputs/outputs/formula, and calls ltlsynt with
AIGER output. Strips the REALIZABLE header line from the output. See
docs/synthesize.md.
scripts/trace_aiger.py — Exhaustive circuit evaluation: enumerates all
reachable latch states, extracts guard conditions on transitions via boolean
function simplification, emits DOT. See docs/trace_aiger.md.
scripts/aag2dot.py — Gate-level diagram of the AIGER circuit (wires,
AND gates, latches). Useful for debugging unexpectedly large circuits. See
docs/aag2dot.md.
Key design decisions
- Mode decomposition with mutex constraint. FRET's
control_mode = q_Xis a single integer variable that inherently holds one value. ltlsynt works over independent booleans. So we decompose intoin_mode_shutdown,in_mode_heatup, etc., and add a "G(exactly one active)" constraint. The mutex is a synthesis encoding artifact, not a missing FRET requirement. - Prefer
ftInfAUExpandedoverft. FRET emits multiple LTL forms; we use the expanded infinite-horizon form because ltlsynt works over infinite traces. Theftform can contain LAST operators that bias toward finite traces. - Regex-based mode discovery. Fully automatic — no hardcoded variable lists. Add a new mode in FRET and re-export; the script picks it up.
- Strict sanity check. If any
control_orq_token survives the boolean encoding, the script errors out rather than producing silent bugs.
FRET naming conventions
Enforced by fret_to_synth.py. See README.md for the full rules.
- Mode variables:
control_<group>with valuesq_<value>. Decomposed toin_<group_suffix>_<value_suffix>. - Environment inputs: anything else. Assumed boolean; continuous quantities
should be abstracted to predicates at the FRET level
(e.g.,
t_avg_above_min).
Extending
- New requirement. Add it in FRET, re-export JSON, re-run the pipeline. No code changes needed as long as the new variables follow the naming rule.
- New mode group. Same as above —
fret_to_synth.pyauto-discovers. - Unrealizable spec. Use FRET's realizability checking first to isolate
the conflicting requirement.
synthesize.shwill printUNREALIZABLEif the full spec is inconsistent. - Output format. Current targets are DOT and AIGER. Translating AIGER to
Stateflow is the next planned extension (see parent
CLAUDE.md— this is flagged as the known pain point in the thesis workflow).
Conventions in this subtree
- Scripts are self-contained and take explicit I/O paths as args — no global config file, no env vars.
- Generated artifacts live in
circuits/,diagrams/, andspecs/. Treat them as derived; regenerate rather than hand-edit. pwr_hybrid_3.jsonis the source of truth. Never hand-edit the generatedsynthesis_config_v3.json.