Skip to content

Commit da71a9b

Browse files
authored
Interpretation of function rules (#1789)
1 parent 05014d2 commit da71a9b

File tree

1 file changed

+261
-0
lines changed

1 file changed

+261
-0
lines changed
Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
# Interpretation of function rules
2+
3+
## Purpose
4+
5+
This document
6+
7+
1. describes how function rules are currently interpreted in Kore,
8+
1. exposes some problems with the current approach, and
9+
1. explains how function rules will be interpreted in Kore in the future to solve these problems.
10+
11+
## Notation
12+
13+
`Xᵢ` and `Yᵢ` refer to element variables.
14+
`{X}` and `{Y}` refer to all variables in the respective family of element variables.
15+
`fun(...)` is a function symbol.
16+
`φ` are arbitrary patterns appearing as the arguments of a function rule.
17+
`ψ` are arbitrary patterns appearing on the right-hand side of function rules.
18+
`Pre` and `Post` are respectively pre- and post-condition patterns.
19+
20+
## Background
21+
22+
This section will briefly describe how function rules are interpreted in Kore,
23+
before we continue in the next section to expose some problems with this interpretation.
24+
Consider a K function `fun` described by a family of rules,
25+
26+
```.k
27+
rule fun(φ₁ᵢ({Y}), φ₂ᵢ({Y}), ...) => ψᵢ({Y}) requires Preᵢ({Y}) ensures Postᵢ({Y})
28+
```
29+
30+
Each rule is interpreted in Kore as an axiom,
31+
32+
```.kore
33+
axiom \implies(Preᵢ({Y}), (fun(φ₁ᵢ({Y}), φ₂ᵢ({Y}), ...) = ψᵢ({Y})) ∧ Postᵢ({Y})).
34+
```
35+
36+
## Problems
37+
38+
### Partial heads
39+
40+
See also: [kframework/kore#1146](https://github.com/kframework/kore/issues/1146)
41+
42+
Rules with partial heads are potentially unsound.
43+
Consider the family of rules
44+
45+
```.k
46+
rule sizeMap(_ |-> _ M:Map) = 1 +Int sizeMap(M)
47+
rule sizeMap(_ |-> _) = 1
48+
rule sizeMap(.Map) = 0
49+
```
50+
51+
producing axioms
52+
53+
```.kore
54+
axiom sizeMap(concatMap(elementMap(_1, _2), M:Map)) = +Int(1, sizeMap(M))
55+
axiom sizeMap(elementMap(_, _)) = 1
56+
axiom sizeMap(.Map) = 0.
57+
```
58+
59+
Note that the first rule has a partial head;
60+
we can instantiate it at `M = elementMap(_1, _2)` to prove
61+
62+
```.kore
63+
sizeMap(concatMap(elementMap(_1, _2), elementMap(_1, _2))) = +Int(1, sizeMap(elementMap(_1, _2)))
64+
sizeMap(\bottom) = +Int(1, sizeMap(elementMap(_1, _2)))
65+
sizeMap(\bottom) = +Int(1, 1)
66+
\bottom = 2.
67+
```
68+
69+
### Or patterns
70+
71+
See also: [kframework/kore#1245](https://github.com/kframework/kore/issues/1245)
72+
73+
Consider this family of rules defining function `fun`,
74+
75+
```.k
76+
rule fun(A) => C
77+
rule fun(B) => C
78+
```
79+
80+
which is interpreted in Kore as two axioms,
81+
82+
```.kore
83+
axiom \implies(\top, (fun(A) = C) ∧ \top)
84+
axiom \implies(\top, (fun(B) = C) ∧ \top).
85+
```
86+
87+
The K language offers a shorthand notation,
88+
89+
```.k
90+
rule fun(A #Or B) => C
91+
```
92+
93+
which is intended to be equivalent to the pair of rules above.
94+
Under the current interpretation, this rule produces an axiom,
95+
96+
```.kore
97+
axiom \implies(\top, (fun(A ∨ B) = C) ∧ \top)
98+
```
99+
100+
which is **not** equivalent to the first interpretation.
101+
Specifically, the first interpretation is satisfied if and only if
102+
`fun(A) = C ∧ fun(B) = C`,
103+
but the second interpretation can be satisfied if
104+
`fun(A) = C ∧ fun(B) = \bottom`
105+
or if
106+
`fun(A) = \bottom ∧ fun(B) = C`.
107+
Therefore, the current interpretation of function rules is not faithful to the user's intent.
108+
109+
### Priority
110+
111+
The `priority` attribute is not properly supported.
112+
The `owise` attribute is supported, but its implementation is inefficient:
113+
work is duplicated by re-checking that the other rules in the family do not apply.
114+
115+
## Solution
116+
117+
The interpretation of simplification rules will not change,
118+
but the family of K rules defining `fun`,
119+
120+
```.k
121+
rule fun(φ₁ᵢ({Y}), φ₂ᵢ({Y}), ...) => ψᵢ({Y}) requires Preᵢ({Y}) ensures Postᵢ({Y})
122+
```
123+
124+
will be interpreted in Kore as
125+
126+
```.kore
127+
axiom \implies(Preᵢ({Y}) ∧ Argsᵢ({X}, {Y}) ∧ Prioᵢ({X}), (fun(X₁, X₂, ...) = ψᵢ({Y})) ∧ Postᵢ({Y}))
128+
```
129+
130+
where
131+
132+
```.kore
133+
Argsᵢ({X}, {Y}) = (X₁ ∈ φ₁ᵢ({Y})) ∧ (X₂ ∈ φ₂ᵢ({Y})) ∧ ...
134+
Prioᵢ({X}) = ∧ⱼ ¬ ∃ {Y}. Preⱼ({Y}) ∧ Argsⱼ({X}, {Y})
135+
for all j that priority(rule j) < priority(rule i).
136+
```
137+
138+
The predicate `Argsᵢ` interprets the argument patterns `φ₁ᵢ` element-wise,
139+
matching the user's intent and (as we will see below) avoiding the problems described above.
140+
The predicate `Prioᵢ` encodes the `priority` attribute in the pre-condition of the rule,
141+
which is now possible only because we have moved argument matching into the `Argsᵢ` pre-condition.
142+
143+
### Partial heads
144+
145+
The troublesome example,
146+
147+
```.k
148+
rule sizeMap(_ |-> _ M:Map) = 1 +Int sizeMap(M)
149+
```
150+
151+
is interpreted in Kore as
152+
153+
```.kore
154+
axiom \implies(X ∈ concatMap(elementMap(_1, _2), M:Map), sizeMap(X) = +Int(1, sizeMap(M))).
155+
```
156+
157+
If `concatMap(_, _)` is undefined,
158+
then the pre-condition `X ∈ concatMap(_, _)` is not satisfied;
159+
therefore, the rule is sound.
160+
161+
### Or patterns
162+
163+
The example or-pattern rule,
164+
165+
```.k
166+
rule fun(A #Or B) => C
167+
```
168+
169+
will be interpreted as
170+
171+
```.kore
172+
axiom \implies(X ∈ (A ∨ B), fun(X) = C).
173+
```
174+
175+
The disjunction distributes over `_ ∈ _`
176+
177+
```.kore
178+
X ∈ (A ∨ B)
179+
= (X ∈ A) ∨ (X ∈ B)
180+
```
181+
182+
and over `\implies`
183+
184+
```.kore
185+
\implies(X ∈ (A ∨ B), fun(X) = C)
186+
= \implies(X ∈ A, fun(X) = C) ∧ \implies(X ∈ B, fun(X) = C)
187+
```
188+
189+
so that the original axiom is equivalent to two axioms, as intended:
190+
191+
```.kore
192+
axiom \implies(X ∈ A, fun(X) = C)
193+
axiom \implies(X ∈ B, fun(X) = C).
194+
```
195+
196+
### Priority
197+
198+
The `priority` and `owise` attributes are now encoded explicitly in the
199+
pre-condition of the axiom.
200+
Consider a function,
201+
202+
```.k
203+
rule L:Int <= X:Int < _ => false requires notBool L <=Int X
204+
rule _ <= X:Int < U:Int => false requires notBool X <Int U [priority(51)]
205+
rule _ <= _ < _ => true [owise]
206+
```
207+
208+
which will be interpreted in Kore as axioms
209+
210+
```.kore
211+
axiom
212+
\implies(
213+
\and(
214+
true = notBool(<=Int(L, X)),
215+
(X₁ ∈ L) ∧ (X₂ ∈ X)
216+
),
217+
\and(
218+
_<=_<_(X₁, X₂, X₃) = false,
219+
\top
220+
)
221+
)
222+
axiom
223+
\implies(
224+
\and(
225+
true = notBool(<Int(X, U)),
226+
(X₂ ∈ X) ∧ (X₃ ∈ U),
227+
\not \exists L X.
228+
\and(
229+
true = notBool(<=Int(L, X)),
230+
(X₁ ∈ L) ∧ (X₂ ∈ X)
231+
)
232+
),
233+
\and(
234+
_<=_<_(X₁, X₂, X₃) = false,
235+
\top
236+
)
237+
)
238+
axiom
239+
\implies(
240+
\and(
241+
\top,
242+
\top,
243+
\and(
244+
\not \exists L X.
245+
\and(
246+
true = notBool(<=Int(L, X)),
247+
(X₁ ∈ L) ∧ (X₂ ∈ X)
248+
),
249+
\not \exists X U.
250+
\and(
251+
true = notBool(<Int(X, U)),
252+
(X₂ ∈ X) ∧ (X₃ ∈ U)
253+
)
254+
)
255+
),
256+
\and(
257+
_<=_<_(X₁, X₂, X₃) = true,
258+
\top
259+
)
260+
)
261+
```

0 commit comments

Comments
 (0)