diff --git a/k-files/imp-simple-spec.k b/k-files/imp-simple-spec.k
index 6e0dd4ccd7d..3a5cd90fdcd 100644
--- a/k-files/imp-simple-spec.k
+++ b/k-files/imp-simple-spec.k
@@ -9,8 +9,11 @@ module IMP-SIMPLE-SPEC
claim [addition-var]: 3 + N => 7 ... requires N ==Int 4
+ claim [pre-branch-proved]: $n = 7 ; if (B:Bool) { $n = 6 ; } else { $n = 5 ; } ~> #FINISH => if (B:Bool) { $n = 6 ; } else { $n = 5 ; } ~> #FINISH
+ $n |-> (0 => 7)
+
claim [sum-10]: int $s, $n, .Ids ; $n = 10 ; while (0 <= $n) { $s = $s + $n ; $n = $n + -1 ; } ~> #FINISH => . ...
- .Map => $s |-> 55 $n |-> -1
+ .Map => $s |-> 55 $n |-> -1
claim [sum-100]: int $s, $n, .Ids ; $n = 100 ; while (0 <= $n) { $s = $s + $n ; $n = $n + -1 ; } ~> #FINISH => . ...
.Map => $s |-> 5050 $n |-> -1
diff --git a/package/version b/package/version
index 5eb8803f31e..b1453c3a10c 100644
--- a/package/version
+++ b/package/version
@@ -1 +1 @@
-0.1.225
+0.1.226
diff --git a/pyproject.toml b/pyproject.toml
index fe68e510e05..145666211bf 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
[tool.poetry]
name = "pyk"
-version = "0.1.225"
+version = "0.1.226"
description = ""
authors = [
"Runtime Verification, Inc. ",
diff --git a/src/pyk/cterm.py b/src/pyk/cterm.py
index f0cfd055171..a73440fbc51 100644
--- a/src/pyk/cterm.py
+++ b/src/pyk/cterm.py
@@ -17,6 +17,7 @@
remove_generated_cells,
simplify_bool,
split_config_and_constraints,
+ split_config_from,
)
from .kast.outer import KClaim, KRule
from .prelude.k import GENERATED_TOP_CELL
@@ -94,6 +95,14 @@ def kast(self) -> KInner:
def hash(self) -> str:
return self.kast.hash
+ @cached_property
+ def cells(self) -> Subst:
+ _, subst = split_config_from(self.config)
+ return Subst(subst)
+
+ def cell(self, cell: str) -> KInner:
+ return self.cells[cell]
+
def match(self, cterm: CTerm) -> Subst | None:
csubst = self.match_with_constraint(cterm)
diff --git a/src/pyk/proof/reachability.py b/src/pyk/proof/reachability.py
index ad2c11e1cc7..7f638dcab06 100644
--- a/src/pyk/proof/reachability.py
+++ b/src/pyk/proof/reachability.py
@@ -70,6 +70,27 @@ class AGProver:
def __init__(self, proof: AGProof) -> None:
self.proof = proof
+ def _check_subsumption(
+ self,
+ kcfg_explore: KCFGExplore,
+ curr_node: KCFG.Node,
+ is_terminal: Callable[[CTerm], bool] | None = None,
+ implication_every_block: bool = True,
+ ) -> bool:
+ if implication_every_block or (is_terminal is not None and is_terminal(curr_node.cterm)):
+ target_node = self.proof.kcfg.get_unique_target()
+ _LOGGER.info(
+ f'Checking subsumption into target state {self.proof.id}: {shorten_hashes((curr_node.id, target_node.id))}'
+ )
+ csubst = kcfg_explore.cterm_implies(curr_node.cterm, target_node.cterm)
+ if csubst is not None:
+ self.proof.kcfg.create_cover(curr_node.id, target_node.id, csubst=csubst)
+ _LOGGER.info(
+ f'Subsumed into target node {self.proof.id}: {shorten_hashes((curr_node.id, target_node.id))}'
+ )
+ return True
+ return False
+
def advance_proof(
self,
kcfg_explore: KCFGExplore,
@@ -79,10 +100,8 @@ def advance_proof(
execute_depth: int | None = None,
cut_point_rules: Iterable[str] = (),
terminal_rules: Iterable[str] = (),
- simplify_init: bool = True,
implication_every_block: bool = True,
) -> KCFG:
- target_node = self.proof.kcfg.get_unique_target()
iterations = 0
while self.proof.kcfg.frontier:
@@ -94,17 +113,10 @@ def advance_proof(
iterations += 1
curr_node = self.proof.kcfg.frontier[0]
- if implication_every_block or (is_terminal is not None and is_terminal(curr_node.cterm)):
- _LOGGER.info(
- f'Checking subsumption into target state {self.proof.id}: {shorten_hashes((curr_node.id, target_node.id))}'
- )
- csubst = kcfg_explore.cterm_implies(curr_node.cterm, target_node.cterm)
- if csubst is not None:
- self.proof.kcfg.create_cover(curr_node.id, target_node.id, csubst=csubst)
- _LOGGER.info(
- f'Subsumed into target node {self.proof.id}: {shorten_hashes((curr_node.id, target_node.id))}'
- )
- continue
+ if self._check_subsumption(
+ kcfg_explore, curr_node, is_terminal=is_terminal, implication_every_block=implication_every_block
+ ):
+ continue
if is_terminal is not None:
_LOGGER.info(f'Checking terminal {self.proof.id}: {shorten_hashes(curr_node.id)}')
@@ -132,6 +144,11 @@ def advance_proof(
)
curr_node = next_node
+ if self._check_subsumption(
+ kcfg_explore, curr_node, is_terminal=is_terminal, implication_every_block=implication_every_block
+ ):
+ continue
+
if len(next_cterms) == 0:
_LOGGER.info(f'Found stuck node {self.proof.id}: {shorten_hashes(curr_node.id)}')
diff --git a/src/tests/integration/kcfg/test_cell_map.py b/src/tests/integration/kcfg/test_cell_map.py
index 0bb3976b114..77b3948999e 100644
--- a/src/tests/integration/kcfg/test_cell_map.py
+++ b/src/tests/integration/kcfg/test_cell_map.py
@@ -7,7 +7,6 @@
from pyk.cterm import CTerm
from pyk.kast.inner import KApply, KSequence, KToken, KVariable, build_assoc
-from pyk.kast.manip import get_cell
from pyk.kcfg import KCFG
from pyk.proof import AGProof, AGProver
@@ -103,7 +102,7 @@ def test_execute(
actual_depth, actual_post_term, _ = kcfg_explore.cterm_execute(
self.config(kcfg_explore.kprint, k, aacounts, accounts), depth=depth
)
- actual_k = kcfg_explore.kprint.pretty_print(get_cell(actual_post_term.kast, 'K_CELL'))
+ actual_k = kcfg_explore.kprint.pretty_print(actual_post_term.cell('K_CELL'))
# Then
assert actual_depth == expected_depth
diff --git a/src/tests/integration/kcfg/test_imp.py b/src/tests/integration/kcfg/test_imp.py
index 2c68526d64f..ee6f7c22c84 100644
--- a/src/tests/integration/kcfg/test_imp.py
+++ b/src/tests/integration/kcfg/test_imp.py
@@ -7,7 +7,6 @@
from pyk.cterm import CSubst, CTerm
from pyk.kast.inner import KApply, KSequence, KSort, KToken, KVariable, Subst
-from pyk.kast.manip import get_cell
from pyk.kcfg import KCFG
from pyk.prelude.kint import intToken
from pyk.prelude.ml import mlAnd, mlBottom, mlEqualsFalse, mlEqualsTrue
@@ -111,6 +110,7 @@
('imp-simple-addition-1', 'k-files/imp-simple-spec.k', 'IMP-SIMPLE-SPEC', 'addition-1', 2, 1, []),
('imp-simple-addition-2', 'k-files/imp-simple-spec.k', 'IMP-SIMPLE-SPEC', 'addition-2', 2, 7, []),
('imp-simple-addition-var', 'k-files/imp-simple-spec.k', 'IMP-SIMPLE-SPEC', 'addition-var', 2, 1, []),
+ ('pre-branch-proved', 'k-files/imp-simple-spec.k', 'IMP-SIMPLE-SPEC', 'pre-branch-proved', 1, 100, []),
(
'imp-simple-sum-10',
'k-files/imp-simple-spec.k',
@@ -193,13 +193,13 @@ def test_execute(
actual_depth, actual_post_term, actual_next_terms = kcfg_explore.cterm_execute(
self.config(kcfg_explore.kprint, k, state), depth=depth
)
- actual_k = kcfg_explore.kprint.pretty_print(get_cell(actual_post_term.kast, 'K_CELL'))
- actual_state = kcfg_explore.kprint.pretty_print(get_cell(actual_post_term.kast, 'STATE_CELL'))
+ actual_k = kcfg_explore.kprint.pretty_print(actual_post_term.cell('K_CELL'))
+ actual_state = kcfg_explore.kprint.pretty_print(actual_post_term.cell('STATE_CELL'))
actual_next_states = [
(
- kcfg_explore.kprint.pretty_print(get_cell(s.kast, 'K_CELL')),
- kcfg_explore.kprint.pretty_print(get_cell(s.kast, 'STATE_CELL')),
+ kcfg_explore.kprint.pretty_print(s.cell('K_CELL')),
+ kcfg_explore.kprint.pretty_print(s.cell('STATE_CELL')),
)
for s in actual_next_terms
]
diff --git a/src/tests/integration/kcfg/test_simple.py b/src/tests/integration/kcfg/test_simple.py
index 6312454d5f8..fb7fcbd481d 100644
--- a/src/tests/integration/kcfg/test_simple.py
+++ b/src/tests/integration/kcfg/test_simple.py
@@ -81,12 +81,12 @@ def test_execute(
actual_depth, actual_post_term, actual_next_terms = kcfg_explore.cterm_execute(
self.config(kcfg_explore.kprint, *pre), depth=depth
)
- actual_k = kcfg_explore.kprint.pretty_print(get_cell(actual_post_term.kast, 'K_CELL'))
- actual_state = kcfg_explore.kprint.pretty_print(get_cell(actual_post_term.kast, 'STATE_CELL'))
+ actual_k = kcfg_explore.kprint.pretty_print(actual_post_term.cell('K_CELL'))
+ actual_state = kcfg_explore.kprint.pretty_print(actual_post_term.cell('STATE_CELL'))
actual_next_states = [
(
- kcfg_explore.kprint.pretty_print(get_cell(s.kast, 'K_CELL')),
- kcfg_explore.kprint.pretty_print(get_cell(s.kast, 'STATE_CELL')),
+ kcfg_explore.kprint.pretty_print(s.cell('K_CELL')),
+ kcfg_explore.kprint.pretty_print(s.cell('STATE_CELL')),
)
for s in actual_next_terms
]
diff --git a/src/tests/integration/test_krun.py b/src/tests/integration/test_krun.py
index 3c0a799e946..d6c6081e983 100644
--- a/src/tests/integration/test_krun.py
+++ b/src/tests/integration/test_krun.py
@@ -5,7 +5,7 @@
import pytest
from pyk.kast.inner import KApply, KSequence, KSort, KToken, Subst
-from pyk.kast.manip import flatten_label, get_cell
+from pyk.kast.manip import flatten_label
from pyk.kore.prelude import int_dv
from pyk.kore.syntax import App
from pyk.prelude.kint import intToken
@@ -34,8 +34,8 @@ def test_run(self, krun: KRun) -> None:
]
# When
- actual_k = get_cell(final_cterm.config, 'K_CELL')
- actual_map_items = flatten_label('_Map_', get_cell(final_cterm.config, 'STATE_CELL'))
+ actual_k = final_cterm.cell('K_CELL')
+ actual_map_items = flatten_label('_Map_', final_cterm.cell('STATE_CELL'))
assert actual_k == expected_k
assert set(actual_map_items) == set(expected_map_items)