Skip to content
This repository was archived by the owner on Apr 25, 2024. It is now read-only.

Commit 6c7eb22

Browse files
committed
Add separate get proof steps and execute proof step phase
1 parent 7ee5e70 commit 6c7eb22

File tree

3 files changed

+71
-44
lines changed

3 files changed

+71
-44
lines changed

src/pyk/proof/implies.py

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from ..prelude.kbool import BOOL, FALSE, TRUE
1313
from ..prelude.ml import is_bottom, is_top, mlAnd, mlEquals, mlEqualsFalse, mlEqualsTrue
1414
from ..utils import ensure_dir_path
15-
from .proof import FailureInfo, Proof, ProofStatus, ProofSummary, Prover, StepResult
15+
from .proof import FailureInfo, Proof, ProofStatus, ProofStep, ProofSummary, Prover, StepResult
1616

1717
if TYPE_CHECKING:
1818
from collections.abc import Iterable, Mapping
@@ -26,6 +26,11 @@
2626
_LOGGER: Final = logging.getLogger(__name__)
2727

2828

29+
@dataclass
30+
class ImpliesProofStep(ProofStep):
31+
proof: ImpliesProof
32+
33+
2934
class ImpliesProof(Proof):
3035
antecedent: KInner
3136
consequent: KInner
@@ -55,6 +60,9 @@ def __init__(
5560
self.simplified_consequent = simplified_consequent
5661
self.csubst = csubst
5762

63+
def get_steps(self) -> Iterable[ProofStep]:
64+
return [ImpliesProofStep(self)]
65+
5866
def commit(self, result: StepResult) -> None:
5967
proof_type = type(self).__name__
6068
if isinstance(result, ImpliesProofResult):
@@ -404,29 +412,31 @@ def __init__(self, proof: ImpliesProof, kcfg_explore: KCFGExplore):
404412
super().__init__(kcfg_explore)
405413
self.proof = proof
406414

407-
def step_proof(self) -> Iterable[StepResult]:
408-
proof_type = type(self.proof).__name__
409-
_LOGGER.info(f'Attempting {proof_type} {self.proof.id}')
415+
def step_proof(self, step: ProofStep) -> Iterable[StepResult]:
416+
assert isinstance(step, ImpliesProofStep)
417+
418+
proof_type = type(step.proof).__name__
419+
_LOGGER.info(f'Attempting {proof_type} {step.proof.id}')
410420

411-
if self.proof.status is not ProofStatus.PENDING:
412-
_LOGGER.info(f'{proof_type} finished {self.proof.id}: {self.proof.status}')
421+
if step.proof.status is not ProofStatus.PENDING:
422+
_LOGGER.info(f'{proof_type} finished {step.proof.id}: {step.proof.status}')
413423
return []
414424

415425
# to prove the equality, we check the implication of the form `constraints #Implies LHS #Equals RHS`, i.e.
416426
# "LHS equals RHS under these constraints"
417-
simplified_antecedent, _ = self.kcfg_explore.cterm_symbolic.kast_simplify(self.proof.antecedent)
418-
simplified_consequent, _ = self.kcfg_explore.cterm_symbolic.kast_simplify(self.proof.consequent)
427+
simplified_antecedent, _ = self.kcfg_explore.cterm_symbolic.kast_simplify(step.proof.antecedent)
428+
simplified_consequent, _ = self.kcfg_explore.cterm_symbolic.kast_simplify(step.proof.consequent)
419429
_LOGGER.info(f'Simplified antecedent: {self.kcfg_explore.pretty_print(simplified_antecedent)}')
420430
_LOGGER.info(f'Simplified consequent: {self.kcfg_explore.pretty_print(simplified_consequent)}')
421431

422432
csubst: CSubst | None = None
423433

424434
if is_bottom(simplified_antecedent):
425-
_LOGGER.warning(f'Antecedent of implication (proof constraints) simplifies to #Bottom {self.proof.id}')
435+
_LOGGER.warning(f'Antecedent of implication (proof constraints) simplifies to #Bottom {step.proof.id}')
426436
csubst = CSubst(Subst({}), ())
427437

428438
elif is_top(simplified_consequent):
429-
_LOGGER.warning(f'Consequent of implication (proof equality) simplifies to #Top {self.proof.id}')
439+
_LOGGER.warning(f'Consequent of implication (proof equality) simplifies to #Top {step.proof.id}')
430440
csubst = CSubst(Subst({}), ())
431441

432442
else:
@@ -435,13 +445,13 @@ def step_proof(self) -> Iterable[StepResult]:
435445
_result = self.kcfg_explore.cterm_symbolic.implies(
436446
antecedent=CTerm(config=dummy_config, constraints=[simplified_antecedent]),
437447
consequent=CTerm(config=dummy_config, constraints=[simplified_consequent]),
438-
bind_universally=self.proof.bind_universally,
448+
bind_universally=step.proof.bind_universally,
439449
)
440450
result = _result.csubst
441451
if result is not None:
442452
csubst = result
443453

444-
_LOGGER.info(f'{proof_type} finished {self.proof.id}: {self.proof.status}')
454+
_LOGGER.info(f'{proof_type} finished {step.proof.id}: {step.proof.status}')
445455
return [
446456
ImpliesProofResult(
447457
csubst=csubst, simplified_antecedent=simplified_antecedent, simplified_consequent=simplified_consequent

src/pyk/proof/proof.py

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,9 @@ def lines(self) -> list[str]:
268268
subproofs_summaries = [subproof.summary for subproof in self.subproofs]
269269
return CompositeSummary([BaseSummary(self.id, self.status), *subproofs_summaries])
270270

271+
@abstractmethod
272+
def get_steps(self) -> Iterable[ProofStep]: ...
273+
271274

272275
class ProofSummary(ABC):
273276
id: str
@@ -296,6 +299,9 @@ def lines(self) -> list[str]:
296299
return [line for lines in (summary.lines for summary in self.summaries) for line in lines]
297300

298301

302+
class ProofStep: ...
303+
304+
299305
class StepResult: ...
300306

301307

@@ -313,21 +319,23 @@ def __init__(self, kcfg_explore: KCFGExplore):
313319
def failure_info(self) -> FailureInfo: ...
314320

315321
@abstractmethod
316-
def step_proof(self) -> Iterable[StepResult]: ...
322+
def step_proof(self, step: ProofStep) -> Iterable[StepResult]: ...
317323

318324
def advance_proof(self, max_iterations: int | None = None, fail_fast: bool = False) -> None:
319325
iterations = 0
320-
while self.proof.can_progress:
321-
if fail_fast and self.proof.failed:
322-
_LOGGER.warning(f'Terminating proof early because fail_fast is set: {self.proof.id}')
323-
self.proof.failure_info = self.failure_info()
324-
return
325-
if max_iterations is not None and max_iterations <= iterations:
326-
return
327-
iterations += 1
328-
results = self.step_proof()
329-
for result in results:
330-
self.proof.commit(result)
331-
self.proof.write_proof_data()
326+
while True:
327+
steps = self.proof.get_steps()
328+
for step in steps:
329+
if fail_fast and self.proof.failed:
330+
_LOGGER.warning(f'Terminating proof early because fail_fast is set: {self.proof.id}')
331+
self.proof.failure_info = self.failure_info()
332+
return
333+
if max_iterations is not None and max_iterations <= iterations:
334+
return
335+
iterations += 1
336+
results = self.step_proof(step)
337+
for result in results:
338+
self.proof.commit(result)
339+
self.proof.write_proof_data()
332340
if self.proof.failed:
333341
self.proof.failure_info = self.failure_info()

src/pyk/proof/reachability.py

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from ..prelude.ml import mlAnd, mlTop
2020
from ..utils import FrozenDict, ensure_dir_path, hash_str, shorten_hashes, single
2121
from .implies import ProofSummary, Prover, RefutationProof
22-
from .proof import CompositeSummary, FailureInfo, Proof, ProofStatus, StepResult
22+
from .proof import CompositeSummary, FailureInfo, Proof, ProofStatus, ProofStep, StepResult
2323

2424
if TYPE_CHECKING:
2525
from collections.abc import Iterable, Mapping
@@ -59,6 +59,12 @@ class APRProofTerminalResult(APRProofResult): ...
5959
class APRProofBoundedResult(APRProofResult): ...
6060

6161

62+
@dataclass
63+
class APRProofStep(ProofStep):
64+
proof: APRProof
65+
node_id: int
66+
67+
6268
class APRProof(Proof, KCFGExploration):
6369
"""APRProof and APRProver implement all-path reachability logic,
6470
as introduced by A. Stefanescu and others in their paper 'All-Path Reachability Logic':
@@ -132,6 +138,9 @@ def __init__(
132138
assert type(subproof) is RefutationProof
133139
self.node_refutations[node_id] = subproof
134140

141+
def get_steps(self) -> Iterable[APRProofStep]:
142+
return [APRProofStep(self, node.id) for node in self.pending]
143+
135144
def commit(self, result: StepResult) -> None:
136145
if isinstance(result, APRProofExtendResult):
137146
self.kcfg.extend(result.extend_result, self.kcfg.node(result.node_id), logs=self.logs)
@@ -720,37 +729,37 @@ def _check_subsume(self, node: KCFG.Node) -> CSubst | None:
720729
_LOGGER.info(f'Subsumed into target node {self.proof.id}: {shorten_hashes((node.id, self.proof.target))}')
721730
return csubst
722731

723-
def step_proof(self) -> Iterable[StepResult]:
724-
if not self.proof.pending:
725-
return []
726-
curr_node = self.proof.pending[0]
732+
def step_proof(self, step: ProofStep) -> Iterable[StepResult]:
733+
assert isinstance(step, APRProofStep)
734+
735+
curr_node = step.proof.kcfg.node(step.node_id)
727736

728-
if self.proof.bmc_depth is not None and curr_node.id not in self._checked_for_bounded:
729-
_LOGGER.info(f'Checking bmc depth for node {self.proof.id}: {curr_node.id}')
737+
if step.proof.bmc_depth is not None and curr_node.id not in self._checked_for_bounded:
738+
_LOGGER.info(f'Checking bmc depth for node {step.proof.id}: {curr_node.id}')
730739
self._checked_for_bounded.add(curr_node.id)
731740

732741
prior_loops = []
733-
for succ in reversed(self.proof.shortest_path_to(curr_node.id)):
742+
for succ in reversed(step.proof.shortest_path_to(curr_node.id)):
734743
if self.kcfg_explore.kcfg_semantics.same_loop(succ.source.cterm, curr_node.cterm):
735-
if succ.source.id in self.proof.prior_loops_cache:
736-
if self.proof.kcfg.zero_depth_between(succ.source.id, curr_node.id):
737-
prior_loops = self.proof.prior_loops_cache[succ.source.id]
744+
if succ.source.id in step.proof.prior_loops_cache:
745+
if step.proof.kcfg.zero_depth_between(succ.source.id, curr_node.id):
746+
prior_loops = step.proof.prior_loops_cache[succ.source.id]
738747
else:
739-
prior_loops = self.proof.prior_loops_cache[succ.source.id] + [succ.source.id]
748+
prior_loops = step.proof.prior_loops_cache[succ.source.id] + [succ.source.id]
740749
break
741750
else:
742-
self.proof.prior_loops_cache[succ.source.id] = []
751+
step.proof.prior_loops_cache[succ.source.id] = []
743752

744-
self.proof.prior_loops_cache[curr_node.id] = prior_loops
753+
step.proof.prior_loops_cache[curr_node.id] = prior_loops
745754

746-
_LOGGER.info(f'Prior loop heads for node {self.proof.id}: {(curr_node.id, prior_loops)}')
747-
if len(prior_loops) > self.proof.bmc_depth:
748-
_LOGGER.warning(f'Bounded node {self.proof.id}: {curr_node.id} at bmc depth {self.proof.bmc_depth}')
755+
_LOGGER.info(f'Prior loop heads for node {step.proof.id}: {(curr_node.id, prior_loops)}')
756+
if len(prior_loops) > step.proof.bmc_depth:
757+
_LOGGER.warning(f'Bounded node {step.proof.id}: {curr_node.id} at bmc depth {step.proof.bmc_depth}')
749758
return [APRProofBoundedResult(curr_node.id)]
750759

751760
# Terminal checks for current node and target node
752761
is_terminal = self.kcfg_explore.kcfg_semantics.is_terminal(curr_node.cterm)
753-
target_is_terminal = self.proof.is_terminal(self.proof.target)
762+
target_is_terminal = step.proof.is_terminal(step.proof.target)
754763

755764
terminal_result = [APRProofTerminalResult(node_id=curr_node.id)] if is_terminal else []
756765

@@ -768,7 +777,7 @@ def step_proof(self) -> Iterable[StepResult]:
768777

769778
module_name = self.circularities_module_name if self.nonzero_depth(curr_node) else self.dependencies_module_name
770779

771-
self.kcfg_explore.check_extendable(self.proof, curr_node)
780+
self.kcfg_explore.check_extendable(step.proof, curr_node)
772781
extend_result = self.kcfg_explore.extend_cterm(
773782
curr_node.cterm,
774783
execute_depth=self.execute_depth,

0 commit comments

Comments
 (0)