Better isolation of non-determinism in Core#617
Conversation
Replace Option/havoc with ExprOrNondet in Cmd, and extend ExprOrNondet to Stmt.ite and Stmt.loop conditions. This unifies non-determinism handling across commands and control flow. Changes: - Add ExprOrNondet type for deterministic-or-nondet expressions - Merge set/havoc into single set command with ExprOrNondet RHS - Use ExprOrNondet for ite/loop conditions in Stmt - Add DDM syntax: if (*) and while (*) for nondet conditions - Introduce fresh nondet booleans in PE and StructuredToUnstructured - Update all downstream code, semantics, transforms, backends, tests - Add boolTy to HasNot for declaring fresh boolean variables
c79a486 to
3ce8e92
Compare
Update test file to use ExprOrNondet (.det/.nondet) instead of Option (some/none) for Cmd and ExprOrNondet for Stmt conditions. Add boolTy to HasNot instance.
MikaelMayer
left a comment
There was a problem hiding this comment.
Thorough and well-structured PR that extends ExprOrNondet from commands to statement-level constructs (ite/loop). The design is clean: the ExprOrNondet type, its .map helper, and the HasNot.boolTy field are good abstractions. Semantics (big-step and small-step), correctness proofs, and all frontends/backends are updated consistently. New tests cover type-checking and evaluation of nondet conditions.
A few observations below, mostly about minor code duplication and one design question about the nondet loop elimination ignoring the measure parameter.
- Extract isBstarArg helper in Translate.lean to reduce duplication - Use ExprOrNondet.map in StatementType.lean and C_Simp/Verify.lean - Add comment explaining why measure is ignored for nondet loops
…m-in-c Resolve conflicts between ExprOrNondet changes (PR #612) and Hoare triple / DetToNondet correctness with loops (PR #660). Key merge decisions: - Keep ExprOrNondet (.det/.nondet) from our branch - Adopt main's Env record (ρ) style and Bool failure flag in EvalCmd - Add nondet ite/loop cases to all new proofs from main - Add loop_sim_nondet for nondet loop correctness proof
Add a .nondet guard branch mirroring LoopElim.lean: havoc assigned vars, assert/assume entry invariants, run body with invariant maintenance, and use .ite .nondet. The catch-all now only matches .det guards without a measure, with a more specific error message.
Introduce a CondBool category with condDet (parenthesized bool) and
condNondet (*) variants, so nondet conditions parse as 'if * { ... }'
and 'while * { ... }' without parentheses. Deterministic conditions
retain their parenthesized form 'if (expr) { ... }'.
Remove the bstar bool function, now superseded by condNondet.
Fix none -> .nondet in LaurelToCoreTranslator for init statements introduced by main merge.
| .assume s!"invariant_{i}" (translate_expr inv) {} | ||
|
|
||
| .ite (.det (translate_expr guard_expr)) ([first_iter_facts, arbitrary_iter_facts, havocd, not_guard] ++ invariant_assumes) [] {} | ||
| | .det guard_expr, .none, _ => |
There was a problem hiding this comment.
This is super nice but that case was not supported in main, was it? If so I would like to see a test that demonstrates this rewriting of core to core, and that the test be human readable.
There was a problem hiding this comment.
Added StrataTest/Languages/C_Simp/Examples/LoopElimTests.lean with human-readable #guard_msgs tests for the two new loop elimination cases:
-
Deterministic guard without measure (
.det guard_expr, .none, _): Uses a C_Simp program parsed via#stratawith awhileloop that has an invariant but nodecreasesclause. Theto_coreoutput shows the loop elimination without any measure-related obligations. -
Nondet guard (
.nondet, _, _): Constructs aC_Simp.Programprogrammatically (since C_Simp's parser always produces deterministic guards) and passes it throughto_core. The output shows the nondet loop elimination withif * { ... }and the entry invariant assert/assume pattern.
The existing LoopTrivial.lean and LoopSimple.lean already cover the .det guard_expr, .some measure, _ case.
Summary
Completes the isolation of non-determinism in the Strata Core dialect by extending
ExprOrNondetfrom commands (init/set) to statement-level constructs (ite/loop).Problem
The previous commits on this branch replaced
Option/havocwithExprOrNondetinCmd, butStmt.iteandStmt.loopstill usedP.Exprfor their conditions/guards. This meant non-deterministic branching and looping could only be expressed indirectly.Solution
Changed
Stmt.iteandStmt.loopto useExprOrNondet Pfor their condition/guard fields. When the condition is.nondet, the branch or loop iteration is chosen arbitrarily.Key changes:
Stmt.itecondition andStmt.loopguard now acceptExprOrNondet Pite_nondet_true_sem/ite_nondet_false_semconstructorsDetToNondettransform handles nondet conditions (no assume needed)LoopElimtransform handles nondet guards (no guard negation needed).detExprOrNondetin condition positionsTesting
All existing tests pass (except a pre-existing failure in
StrataTest/DDM/Integration/Java/TestGen.leandue to asorryinStatementWF.leanon main).Fixes #612