Skip to content

Commit 2c8e7c8

Browse files
Implementing saving and resuming proofs with prove-rs command (#551)
This PR updates the `prove-rs` command. In particular: - `prove-rs` takes optional arg `--proof-dir <DIR>` that it will save proof objects in to disc - `prove-rs` will resume a proof from disc if it exists, unless optional arg `--reload` is added Now it is possible to use `prove view` and `prove prune` after using `prove-rs`. Since `ProveRunOpts` and `ProveRSOpts` now have `--proof-dir` and `--reload` in common I refactored the logic into `ProveOpts`. --------- Co-authored-by: devops <devops@runtimeverification.com>
1 parent c81b40e commit 2c8e7c8

7 files changed

Lines changed: 32 additions & 11 deletions

File tree

kmir/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "kmir"
7-
version = "0.3.135"
7+
version = "0.3.136"
88
description = ""
99
requires-python = "~=3.10"
1010
dependencies = [

kmir/src/kmir/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
from typing import Final
22

3-
VERSION: Final = '0.3.135'
3+
VERSION: Final = '0.3.136'

kmir/src/kmir/__main__.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,11 +172,13 @@ def _arg_parser() -> ArgumentParser:
172172
)
173173

174174
prove_args = ArgumentParser(add_help=False)
175+
prove_args.add_argument('--proof-dir', metavar='DIR', help='Proof directory')
175176
prove_args.add_argument('--bug-report', metavar='PATH', help='path to optional bug report')
176177
prove_args.add_argument('--max-depth', metavar='DEPTH', type=int, help='max steps to take between nodes in kcfg')
177178
prove_args.add_argument(
178179
'--max-iterations', metavar='ITERATIONS', type=int, help='max number of proof iterations to take'
179180
)
181+
prove_args.add_argument('--reload', action='store_true', help='Force restarting proof')
180182

181183
prove_parser = command_parser.add_parser(
182184
'prove', help='Utilities for working with proofs over SMIR', parents=[kcli_args.logging_args]
@@ -185,14 +187,12 @@ def _arg_parser() -> ArgumentParser:
185187

186188
prove_run_parser = prove_command_parser.add_parser('run', help='Run the prover on a spec', parents=[prove_args])
187189
prove_run_parser.add_argument('input_file', metavar='FILE', help='K File with the spec module')
188-
prove_run_parser.add_argument('--proof-dir', metavar='DIR', help='Proof directory')
189190
prove_run_parser.add_argument(
190191
'--include-labels', metavar='LABELS', help='Comma separated list of claim labels to include'
191192
)
192193
prove_run_parser.add_argument(
193194
'--exclude-labels', metavar='LABELS', help='Comma separated list of claim labels to exclude'
194195
)
195-
prove_run_parser.add_argument('--reload', action='store_true', help='Force restarting proof')
196196

197197
prove_view_parser = prove_command_parser.add_parser('view', help='View a saved proof')
198198
prove_view_parser.add_argument('id', metavar='PROOF_ID', help='The id of the proof to view')
@@ -253,9 +253,11 @@ def _parse_args(ns: Namespace) -> KMirOpts:
253253
case 'prove-rs':
254254
return ProveRSOpts(
255255
rs_file=Path(ns.rs_file).resolve(),
256+
proof_dir=ns.proof_dir,
256257
bug_report=ns.bug_report,
257258
max_depth=ns.max_depth,
258259
max_iterations=ns.max_iterations,
260+
reload=ns.reload,
259261
)
260262
case _:
261263
raise AssertionError()

kmir/src/kmir/kmir.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
import logging
34
from contextlib import contextmanager
45
from typing import TYPE_CHECKING
56

@@ -29,6 +30,8 @@
2930

3031
from .options import ProveRSOpts
3132

33+
_LOGGER: Final = logging.getLogger(__name__)
34+
3235

3336
class KMIR(KProve, KRun):
3437
llvm_library_dir: Path | None
@@ -56,7 +59,9 @@ def kcfg_explore(self, label: str | None = None) -> Iterator[KCFGExplore]:
5659
) as cts:
5760
yield KCFGExplore(cts, kcfg_semantics=KMIRSemantics())
5861

59-
def apr_proof_from_kast(self, id: str, kmir_kast: KInner, sort: str = 'GeneratedTopCell') -> APRProof:
62+
def apr_proof_from_kast(
63+
self, id: str, kmir_kast: KInner, sort: str = 'GeneratedTopCell', proof_dir: Path | None = None
64+
) -> APRProof:
6065
tools = Tools(self.definition_dir)
6166
config = tools.make_init_config(kmir_kast, 'main', sort=sort)
6267
config_with_cell_vars, _ = split_config_from(config)
@@ -68,7 +73,7 @@ def apr_proof_from_kast(self, id: str, kmir_kast: KInner, sort: str = 'Generated
6873
kcfg = KCFG()
6974
init_node = kcfg.create_node(lhs)
7075
target_node = kcfg.create_node(rhs)
71-
return APRProof(id, kcfg, [], init_node.id, target_node.id, {})
76+
return APRProof(id, kcfg, [], init_node.id, target_node.id, {}, proof_dir=proof_dir)
7277

7378
def prove_rs(self, opts: ProveRSOpts) -> APRProof:
7479
if not opts.rs_file.is_file():
@@ -81,7 +86,13 @@ def prove_rs(self, opts: ProveRSOpts) -> APRProof:
8186
kmir_kast, _ = parse_result
8287
assert isinstance(kmir_kast, KInner)
8388

84-
apr_proof = self.apr_proof_from_kast(str(opts.rs_file.stem), kmir_kast)
89+
label = str(opts.rs_file.stem)
90+
if not opts.reload and opts.proof_dir is not None and APRProof.proof_data_exists(label, opts.proof_dir):
91+
_LOGGER.info(f'Reading proof from disc: {opts.proof_dir}, {label}')
92+
apr_proof = APRProof.read_proof_data(opts.proof_dir, label)
93+
else:
94+
_LOGGER.info(f'Initialising proof: {label}')
95+
apr_proof = self.apr_proof_from_kast(label, kmir_kast, proof_dir=opts.proof_dir)
8596
with self.kcfg_explore('PROOF-TEST') as kcfg_explore:
8697
prover = APRProver(kcfg_explore, execute_depth=opts.max_depth)
8798
prover.advance_proof(apr_proof, max_iterations=opts.max_iterations)

kmir/src/kmir/options.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,25 @@ class RunOpts(KMirOpts):
2929

3030
@dataclass
3131
class ProveOpts(KMirOpts):
32+
proof_dir: Path | None
3233
bug_report: Path | None
3334
max_depth: int | None
3435
max_iterations: int | None
36+
reload: bool
3537

3638
def __init__(
3739
self,
40+
proof_dir: Path | str | None,
3841
bug_report: Path | None = None,
3942
max_depth: int | None = None,
4043
max_iterations: int | None = None,
44+
reload: bool = False,
4145
) -> None:
46+
self.proof_dir = Path(proof_dir).resolve() if proof_dir is not None else None
4247
self.bug_report = bug_report
4348
self.max_depth = max_depth
4449
self.max_iterations = max_iterations
50+
self.reload = reload
4551

4652

4753
@dataclass
@@ -66,23 +72,25 @@ class ProveRSOpts(ProveOpts):
6672
def __init__(
6773
self,
6874
rs_file: Path,
75+
proof_dir: Path | str | None = None,
6976
bug_report: Path | None = None,
7077
max_depth: int | None = None,
7178
max_iterations: int | None = None,
79+
reload: bool = False,
7280
) -> None:
7381
self.rs_file = rs_file
82+
self.proof_dir = Path(proof_dir).resolve() if proof_dir is not None else None
7483
self.bug_report = bug_report
7584
self.max_depth = max_depth
7685
self.max_iterations = max_iterations
86+
self.reload = reload
7787

7888

7989
@dataclass
8090
class ProveRunOpts(ProveOpts):
8191
spec_file: Path
82-
proof_dir: Path | None
8392
include_labels: tuple[str, ...] | None
8493
exclude_labels: tuple[str, ...] | None
85-
reload: bool
8694

8795
def __init__(
8896
self,

kmir/uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package/version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.3.135
1+
0.3.136

0 commit comments

Comments
 (0)