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

Commit 773adb3

Browse files
committed
Merge remote-tracking branch 'origin/master' into anvacaru/vacuous-2
2 parents 8461621 + a18d76d commit 773adb3

40 files changed

+1039
-409
lines changed

deps/k_release

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
6.0.58
1+
6.0.69

package/version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.1.416
1+
0.1.431

pyproject.toml

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

55
[tool.poetry]
66
name = "pyk"
7-
version = "0.1.416"
7+
version = "0.1.431"
88
description = ""
99
authors = [
1010
"Runtime Verification, Inc. <[email protected]>",

src/pyk/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@
66
from typing import Final
77

88

9-
K_VERSION: Final = '6.0.58'
9+
K_VERSION: Final = '6.0.69'

src/pyk/__main__.py

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

3+
import json
34
import logging
45
import sys
56
from argparse import ArgumentParser, FileType
@@ -99,7 +100,7 @@ def exec_prove(args: Namespace) -> None:
99100
kompiled_dir: Path = args.definition_dir
100101
kprover = KProve(kompiled_dir, args.main_file)
101102
final_state = kprover.prove(Path(args.spec_file), spec_module_name=args.spec_module, args=args.kArgs)
102-
args.output_file.write(final_state.to_json())
103+
args.output_file.write(json.dumps(mlOr([state.kast for state in final_state]).to_dict()))
103104
_LOGGER.info(f'Wrote file: {args.output_file.name}')
104105

105106

src/pyk/cli/args.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from typing import TYPE_CHECKING
66

77
from ..utils import ensure_dir_path
8-
from .utils import dir_path, file_path
8+
from .utils import bug_report_arg, dir_path, file_path
99

1010
if TYPE_CHECKING:
1111
from typing import TypeVar
@@ -27,6 +27,16 @@ def parallel_args(self) -> ArgumentParser:
2727
args.add_argument('--workers', '-j', default=1, type=int, help='Number of processes to run in parallel.')
2828
return args
2929

30+
@cached_property
31+
def bug_report_args(self) -> ArgumentParser:
32+
args = ArgumentParser(add_help=False)
33+
args.add_argument(
34+
'--bug-report',
35+
type=bug_report_arg,
36+
help='Generate bug report with given name',
37+
)
38+
return args
39+
3040
@cached_property
3141
def kompile_args(self) -> ArgumentParser:
3242
args = ArgumentParser(add_help=False)
@@ -81,6 +91,18 @@ def kompile_args(self) -> ArgumentParser:
8191
args.add_argument('-O3', dest='o3', default=False, action='store_true', help='Optimization level 3.')
8292
return args
8393

94+
@cached_property
95+
def smt_args(self) -> ArgumentParser:
96+
args = ArgumentParser(add_help=False)
97+
args.add_argument('--smt-timeout', dest='smt_timeout', type=int, help='Timeout in ms to use for SMT queries.')
98+
args.add_argument(
99+
'--smt-retry-limit',
100+
dest='smt_retry_limit',
101+
type=int,
102+
help='Number of times to retry SMT queries with scaling timeouts.',
103+
)
104+
return args
105+
84106
@cached_property
85107
def display_args(self) -> ArgumentParser:
86108
args = ArgumentParser(add_help=False)

src/pyk/cli/utils.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from pathlib import Path
55
from typing import TYPE_CHECKING
66

7-
from ..utils import check_dir_path, check_file_path, check_relative_path
7+
from ..utils import BugReport, check_dir_path, check_file_path, check_relative_path, ensure_dir_path
88

99
if TYPE_CHECKING:
1010
from argparse import Namespace
@@ -73,3 +73,9 @@ def parse(s: str) -> tuple[T1, T2]:
7373
return fst_type(elems[0]), snd_type(elems[1])
7474

7575
return parse
76+
77+
78+
def bug_report_arg(path: str | Path) -> BugReport:
79+
path = Path(path)
80+
ensure_dir_path(path.parent)
81+
return BugReport(path)

src/pyk/cterm.py

Lines changed: 103 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
from itertools import chain
66
from typing import TYPE_CHECKING
77

8-
from .kast.inner import KApply, KInner, KRewrite, KVariable, Subst
8+
from .kast.inner import KApply, KInner, KRewrite, KToken, KVariable, Subst, bottom_up
99
from .kast.kast import KAtt
1010
from .kast.manip import (
11+
abstract_term_safely,
1112
apply_existential_substitutions,
1213
count_vars,
1314
flatten_label,
@@ -22,41 +23,64 @@
2223
)
2324
from .kast.outer import KClaim, KRule
2425
from .prelude.k import GENERATED_TOP_CELL
25-
from .prelude.ml import is_top, mlAnd, mlImplies, mlTop
26-
from .utils import unique
26+
from .prelude.kbool import orBool
27+
from .prelude.ml import is_bottom, is_top, mlAnd, mlBottom, mlEqualsTrue, mlImplies, mlTop
28+
from .utils import single, unique
2729

2830
if TYPE_CHECKING:
2931
from collections.abc import Iterable, Iterator
3032
from typing import Any
3133

34+
from .kast.outer import KDefinition
35+
3236

3337
@dataclass(frozen=True, order=True)
3438
class CTerm:
3539
config: KInner # TODO Optional?
3640
constraints: tuple[KInner, ...]
3741

3842
def __init__(self, config: KInner, constraints: Iterable[KInner] = ()) -> None:
39-
self._check_config(config)
40-
constraints = self._normalize_constraints(constraints)
43+
if CTerm._is_top(config):
44+
config = mlTop()
45+
constraints = ()
46+
elif CTerm._is_bottom(config):
47+
config = mlBottom()
48+
constraints = ()
49+
else:
50+
self._check_config(config)
51+
constraints = self._normalize_constraints(constraints)
4152
object.__setattr__(self, 'config', config)
4253
object.__setattr__(self, 'constraints', constraints)
4354

4455
@staticmethod
4556
def from_kast(kast: KInner) -> CTerm:
46-
config, constraint = split_config_and_constraints(kast)
47-
constraints = flatten_label('#And', constraint)
48-
return CTerm(config, constraints)
57+
if CTerm._is_top(kast):
58+
return CTerm.top()
59+
elif CTerm._is_bottom(kast):
60+
return CTerm.bottom()
61+
else:
62+
config, constraint = split_config_and_constraints(kast)
63+
constraints = flatten_label('#And', constraint)
64+
return CTerm(config, constraints)
4965

5066
@staticmethod
5167
def from_dict(dct: dict[str, Any]) -> CTerm:
5268
config = KInner.from_dict(dct['config'])
5369
constraints = [KInner.from_dict(c) for c in dct['constraints']]
5470
return CTerm(config, constraints)
5571

72+
@staticmethod
73+
def top() -> CTerm:
74+
return CTerm(mlTop(), ())
75+
76+
@staticmethod
77+
def bottom() -> CTerm:
78+
return CTerm(mlBottom(), ())
79+
5680
@staticmethod
5781
def _check_config(config: KInner) -> None:
5882
if not isinstance(config, KApply) or not config.is_cell:
59-
raise ValueError('Expected cell label, found: {config.label.name}')
83+
raise ValueError(f'Expected cell label, found: {config}')
6084

6185
@staticmethod
6286
def _normalize_constraints(constraints: Iterable[KInner]) -> tuple[KInner, ...]:
@@ -74,6 +98,20 @@ def _is_spurious_constraint(term: KInner) -> bool:
7498
return True
7599
return False
76100

101+
@staticmethod
102+
def _is_top(kast: KInner) -> bool:
103+
flat = flatten_label('#And', kast)
104+
if len(flat) == 1:
105+
return is_top(single(flat))
106+
return all(CTerm._is_top(term) for term in flat)
107+
108+
@staticmethod
109+
def _is_bottom(kast: KInner) -> bool:
110+
flat = flatten_label('#And', kast)
111+
if len(flat) == 1:
112+
return is_bottom(single(flat))
113+
return all(CTerm._is_bottom(term) for term in flat)
114+
77115
@staticmethod
78116
def _constraint_sort_key(term: KInner) -> tuple[int, str]:
79117
term_str = str(term)
@@ -104,6 +142,9 @@ def cells(self) -> Subst:
104142
def cell(self, cell: str) -> KInner:
105143
return self.cells[cell]
106144

145+
def try_cell(self, cell: str) -> KInner | None:
146+
return self.cells.get(cell)
147+
107148
def match(self, cterm: CTerm) -> Subst | None:
108149
csubst = self.match_with_constraint(cterm)
109150

@@ -138,6 +179,59 @@ def _ml_impl(antecedents: Iterable[KInner], consequents: Iterable[KInner]) -> KI
138179
def add_constraint(self, new_constraint: KInner) -> CTerm:
139180
return CTerm(self.config, [new_constraint] + list(self.constraints))
140181

182+
def anti_unify(
183+
self, other: CTerm, keep_values: bool = False, kdef: KDefinition | None = None
184+
) -> tuple[CTerm, CSubst, CSubst]:
185+
def disjunction_from_substs(subst1: Subst, subst2: Subst) -> KInner:
186+
if KToken('true', 'Bool') in [subst1.pred, subst2.pred]:
187+
return mlTop()
188+
return mlEqualsTrue(orBool([subst1.pred, subst2.pred]))
189+
190+
new_config, self_subst, other_subst = anti_unify(self.config, other.config, kdef=kdef)
191+
common_constraints = [constraint for constraint in self.constraints if constraint in other.constraints]
192+
193+
new_cterm = CTerm(
194+
config=new_config, constraints=([disjunction_from_substs(self_subst, other_subst)] if keep_values else [])
195+
)
196+
197+
new_constraints = []
198+
fvs = free_vars(new_cterm.kast)
199+
len_fvs = 0
200+
while len_fvs < len(fvs):
201+
len_fvs = len(fvs)
202+
for constraint in common_constraints:
203+
if constraint not in new_constraints:
204+
constraint_fvs = free_vars(constraint)
205+
if any(fv in fvs for fv in constraint_fvs):
206+
new_constraints.append(constraint)
207+
fvs.extend(constraint_fvs)
208+
209+
for constraint in new_constraints:
210+
new_cterm = new_cterm.add_constraint(constraint)
211+
self_csubst = new_cterm.match_with_constraint(self)
212+
other_csubst = new_cterm.match_with_constraint(other)
213+
if self_csubst is None or other_csubst is None:
214+
raise ValueError(
215+
f'Anti-unification failed to produce a more general state: {(new_cterm, (self, self_csubst), (other, other_csubst))}'
216+
)
217+
return (new_cterm, self_csubst, other_csubst)
218+
219+
220+
def anti_unify(state1: KInner, state2: KInner, kdef: KDefinition | None = None) -> tuple[KInner, Subst, Subst]:
221+
def _rewrites_to_abstractions(_kast: KInner) -> KInner:
222+
if type(_kast) is KRewrite:
223+
sort = kdef.sort(_kast) if kdef else None
224+
return abstract_term_safely(_kast, sort=sort)
225+
return _kast
226+
227+
minimized_rewrite = push_down_rewrites(KRewrite(state1, state2))
228+
abstracted_state = bottom_up(_rewrites_to_abstractions, minimized_rewrite)
229+
subst1 = abstracted_state.match(state1)
230+
subst2 = abstracted_state.match(state2)
231+
if subst1 is None or subst2 is None:
232+
raise ValueError('Anti-unification failed to produce a more general state!')
233+
return (abstracted_state, subst1, subst2)
234+
141235

142236
@dataclass(frozen=True, order=True)
143237
class CSubst:

0 commit comments

Comments
 (0)