Skip to content

[Strata] Better isolation of non-determinism in Core#617

Draft
MikaelMayer wants to merge 6 commits intomainfrom
issue-612-better-isolation-of-non-determinism-in-c
Draft

[Strata] Better isolation of non-determinism in Core#617
MikaelMayer wants to merge 6 commits intomainfrom
issue-612-better-isolation-of-non-determinism-in-c

Conversation

@MikaelMayer
Copy link
Contributor

@MikaelMayer MikaelMayer commented Mar 19, 2026

Summary

Completes the isolation of non-determinism in the Strata Core dialect by extending ExprOrNondet from commands (init/set) to statement-level constructs (ite/loop).

Problem

The previous commits on this branch replaced Option/havoc with ExprOrNondet in Cmd, but Stmt.ite and Stmt.loop still used P.Expr for their conditions/guards. This meant non-deterministic branching and looping could only be expressed indirectly.

Solution

Changed Stmt.ite and Stmt.loop to use ExprOrNondet P for their condition/guard fields. When the condition is .nondet, the branch or loop iteration is chosen arbitrarily.

Key changes:

  • Stmt.ite condition and Stmt.loop guard now accept ExprOrNondet P
  • Big-step semantics: added ite_nondet_true_sem/ite_nondet_false_sem constructors
  • Small-step semantics: added nondet variants for ite and loop steps
  • DetToNondet transform handles nondet conditions (no assume needed)
  • LoopElim transform handles nondet guards (no guard negation needed)
  • All frontends wrap deterministic conditions with .det
  • All backends handle ExprOrNondet in condition positions
  • Correctness proofs updated for new semantic cases

Testing

All existing tests pass (except a pre-existing failure in StrataTest/DDM/Integration/Java/TestGen.lean due to a sorry in StatementWF.lean on main).

Fixes #612

Introduce ExprOrNondet type to unify deterministic and non-deterministic
expressions in Imperative commands. Merge Cmd.havoc into Cmd.set with
ExprOrNondet.nondet, and change Cmd.init to use ExprOrNondet instead of
Option. Update all downstream consumers including backends, transforms,
languages, and tests.
Add ExprOrNondet.map helper function and use it in places that
manually match on .det/.nondet to transform the inner expression.
| .cover _ _ md =>
throw s!"{Imperative.MetaData.formatFileRangeD md}\
cover unimplemented"
| .havoc _ md =>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make sure we keep .havoc as a definition accepting the name and metadata so that the .set ... .nondet can be built and deconstructed with .havoc .... for better hypothetical compatibility, but everything rewritten in this PR should prefer .set so don't undo your changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The .havoc abbreviation is preserved at both the Cmd level (via the HasHavoc class which builds .set name .nondet md) and the Statement level (via Statement.havoc which is a @[match_pattern] abbreviation). All rewritten code in this PR uses .set ... .nondet directly, but .havoc remains available for construction and pattern matching.

-- variable name mapping.
IdMap.updateVars map [(n1.name,n2.name)]
| .cmd (.set n1 e1 _), .cmd (.set n2 e2 _) =>
| .cmd (.set n1 (.det e1) _), .cmd (.set n2 (.det e2) _) =>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I looked at the entire PR it's good. I would also like to see in Stmt that the condition of an if as well as the condition of the while loop also use ExprOrNondet.
And since these two are new, we need a syntax in Core to parse them, I suggest using a single star in the DDM to indicate nondeterminism like if * { } else { } and while * { ... }
And I want to see tests that make sure that these last two constructs are tested until verification. In the partial evaluator, for the if * we would introduce a fresh boolean. For the loop elimination phase, we would introduce a fresh boolean with a nondet RHS and set it at the end of the loop with a nondet RHS for now, until we have better.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed all three points:

  1. ExprOrNondet in Stmt.ite/Stmt.loop: Done - both ite and loop conditions in Stmt now use ExprOrNondet P instead of P.Expr. All downstream code (semantics, transforms, backends, tests) updated.

  2. DDM syntax if (*) and while (*): Added bstar expression (*) to the Core grammar. The DDM translator recognizes if (*) { } else { } and while (*) { ... } and produces ExprOrNondet.nondet. The ASTtoCST round-trips using bstar as well. Added Examples/NondetCond.core.st demonstrating the syntax.

  3. Fresh boolean in partial evaluator: Updated processIteBranchesNondet to introduce a fresh boolean variable ($__nondet_cond_N) with a nondet RHS (init ... .nondet), then use it as the condition for the ite in the output. Path conditions are set up using this fresh variable for proper path splitting.

Extend the non-determinism isolation from Cmd (init/set) to Stmt
(ite/loop) by changing their condition/guard fields from P.Expr to
ExprOrNondet P.

This allows if-then-else and while-loop constructs to have
non-deterministic conditions, where the branch or loop iteration
is chosen arbitrarily.

Changes:
- Stmt.ite condition: P.Expr → ExprOrNondet P
- Stmt.loop guard: P.Expr → ExprOrNondet P
- Added ite_nondet_true_sem/ite_nondet_false_sem to big-step semantics
- Added step_ite_nondet_true/false and step_loop_nondet_enter/exit
  to small-step semantics
- Updated DetToNondet transform to handle nondet conditions
- Updated LoopElim transform to handle nondet guards
- Updated all language frontends (Core, C_Simp, Boole, Laurel, Python)
  to wrap deterministic conditions with .det
- Updated all backends (CBMC, GOTO) to handle ExprOrNondet
- Updated correctness proofs (DetToNondetCorrect, StatementSemanticsProps)
- Updated all affected tests

Closes #612
[
.init "x" t[int] (.det eb[#0]) .empty,
.ite eb[x == #3]
.ite (.det eb[x == #3])
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see no test with .ite (.nondet) and .loop(.nondet). Also, where is the concrete syntax represented for nondet if and nondet loop ? I couldn't find where the new syntax was defined.

Add 'bstar' (*) expression to Core grammar for non-deterministic
conditions in if/while statements. The DDM translator recognizes
if (*) and while (*) and produces ExprOrNondet.nondet.

Update the partial evaluator to introduce a fresh boolean variable
for non-deterministic if conditions, enabling proper path splitting
with path conditions.

Add NondetCond.core.st example demonstrating the syntax.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Better isolation of non-determinism in Core

1 participant