-
Notifications
You must be signed in to change notification settings - Fork 2
/
SubstituteOperations.fs
307 lines (261 loc) · 13.2 KB
/
SubstituteOperations.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
module RInGen.SubstituteOperations
open SMTLIB2
open SMTLIB2.Operations
open RInGen.Operations
type private termArgumentFolding = LeftAssoc | RightAssoc
type private atomArgumentFolding = Chainable | Pairwise
let private termOperations =
[
"+", LeftAssoc
"-", LeftAssoc
"*", LeftAssoc
"and", LeftAssoc
"or", LeftAssoc
"=>", RightAssoc
] |> List.map (fun (name, assoc) -> Map.find name elementaryOperations, assoc) |> Map.ofList
let private atomOperations =
[
"<=", Chainable
"<", Chainable
">=", Chainable
">", Chainable
] |> List.map (fun (name, assoc) -> Map.find name elementaryOperations, assoc) |> Map.ofList
type FormulaTraverser () =
abstract TraverseSort : sort -> sort
default x.TraverseSort (sort : sort) = sort
abstract TraverseReturnSort : sort -> sort
default x.TraverseReturnSort (sort : sort) = x.TraverseSort sort
member x.TraverseSorts sorts = List.map x.TraverseSort sorts
member x.TraverseSortedVar (name, sort) =
let sort = x.TraverseSort sort
(name, sort)
member x.TraverseSortedVars vars = List.map x.TraverseSortedVar vars
member x.TraverseOp op =
let mapOp constr name args ret =
let args = x.TraverseSorts args
let ret = x.TraverseReturnSort ret
constr(name, args, ret)
match op with
| UserDefinedOperation(name, args, ret) -> mapOp UserDefinedOperation name args ret
| ElementaryOperation(name, args, ret) -> mapOp ElementaryOperation name args ret
member x.TraverseTerm = function
| TConst _ as c -> c
| TIdent(name, sort) ->
let sort = x.TraverseSort sort
TIdent(name, sort)
| TApply(op, ts) ->
let op = x.TraverseOp op
let ts = x.TraverseTerms ts
TApply(op, ts)
member x.TraverseTerms terms = List.map x.TraverseTerm terms
member x.TraverseAtom = function
| Bot | Top as a -> a
| Equal(t1, t2) ->
let t1 = x.TraverseTerm t1
let t2 = x.TraverseTerm t2
Equal(t1, t2)
| Distinct(t1, t2) ->
let t1 = x.TraverseTerm t1
let t2 = x.TraverseTerm t2
Distinct(t1, t2)
| AApply(op, ts) ->
let op = x.TraverseOp op
let ts = x.TraverseTerms ts
AApply(op, ts)
member x.TraverseAtoms atoms = List.map x.TraverseAtom atoms
member x.TraverseDatatype (name, constrs) =
let mapConstrEntry (c, t, ss) =
let c' = x.TraverseOp c
let t' = x.TraverseOp c
let ss' = List.map x.TraverseOp ss
(c', t', ss')
let constrs = List.map mapConstrEntry constrs
(name, constrs)
member x.TraverseQuantifiers = Quantifiers.map (Quantifier.map x.TraverseSortedVars)
member x.TraverseFOLFormula = FOL.map x.TraverseAtom
member x.TraverseLemma (qs, (premises, lemma)) =
let qs = x.TraverseQuantifiers qs
let premises = x.TraverseAtoms premises
let lemma = x.TraverseFOLFormula lemma
(qs, (premises, lemma))
type FormulaMapper () =
inherit FormulaTraverser ()
member x.TraverseRule (Rule(qs, premises, conclusion)) =
let qs = x.TraverseQuantifiers qs
let premises = x.TraverseAtoms premises
let conclusion = x.TraverseAtom conclusion
Rule(qs, premises, conclusion)
member x.TraverseCommand = function
| command.DeclareFun(name, q, argSorts, retSort) ->
let argSorts = x.TraverseSorts argSorts
let retSort = x.TraverseReturnSort retSort
command.DeclareFun(name, q, argSorts, retSort)
| DeclareDatatype(name, constrs) ->
let (name, constrs) = x.TraverseDatatype (name, constrs)
command.DeclareDatatype(name, constrs)
| DeclareDatatypes dts ->
let dts = List.map x.TraverseDatatype dts
command.DeclareDatatypes dts
| DeclareConst(name, sort) ->
let retSort = x.TraverseSort sort
DeclareConst(name, retSort)
| c -> c
member x.TraverseTransformedCommand command =
match command with
| OriginalCommand c -> OriginalCommand(x.TraverseCommand c)
| TransformedCommand r -> TransformedCommand(x.TraverseRule r)
| LemmaCommand(pred, vars, bodyLemma, headCube) ->
let vars = x.TraverseSortedVars vars
let bodyLemma = x.TraverseLemma bodyLemma
let headCube = x.TraverseLemma headCube
LemmaCommand(pred, vars, bodyLemma, headCube)
type SubstituteOperations(relativizations, eqSubstitutor, diseqSubstitutor, constantMap) =
let mutable wasSubstituted = false
let searchInRelativizations op =
match Map.tryFind op relativizations with
| Some _ as r -> wasSubstituted <- true; r
| None -> None
let relativizationsSubstitutor op ts justSubstOp defaultResult =
let generateReturnArgument op =
let retType = Operation.returnType op
let retArg = SortedVar.freshFromSort retType
let retVar = TIdent retArg
retArg, retVar
match searchInRelativizations op with
| Some (op', true) ->
let newVar, newVarIdent = generateReturnArgument op
([newVar], [Relativization.relapply op' ts newVarIdent]), newVarIdent
| Some (op', false) -> ([], []), justSubstOp op'
| None -> ([], []), defaultResult
let substituteOperationsWithRelationsInTermApplication op ts =
relativizationsSubstitutor op ts (fun op' -> TApply(op', ts)) (TApply(op, ts))
let rec substituteOperationsWithRelationsInTerm = function
| TIdent _ as t -> [], [], t
| TConst(c, _) as t ->
match constantMap c with
| Some c' -> wasSubstituted <- true; [], [], c'
| None -> [], [], t
| TApply(op, ts) ->
let vars, conds, ts = substituteOperationsWithRelationsInTermList ts
let top = termOperations
match Map.tryFind op termOperations with
| Some assoc when List.length ts >= 2 ->
let folder =
match assoc with
| LeftAssoc -> List.mapReduce
| RightAssoc -> List.mapReduceBack
let vcs, t = folder (fun x y -> substituteOperationsWithRelationsInTermApplication op [x; y]) ts
let vss, css = List.unzip vcs
vars @ List.concat vss, conds @ List.concat css, t
| _ ->
let (appVars, appConds), app = substituteOperationsWithRelationsInTermApplication op ts
vars @ appVars, conds @ appConds, app
and substituteOperationsWithRelationsInTermList ts =
let varss, condss, ts = ts |> List.map substituteOperationsWithRelationsInTerm |> List.unzip3
List.concat varss, List.concat condss, ts
let substituteOperationsWithRelationsInAtomApplication op ts =
match searchInRelativizations op with
| Some(op', _) -> wasSubstituted <- true; AApply(op', ts)
| None -> AApply(op, ts)
let substituteOperationsWithRelationsInAtomWithPositivity posK k (oldVars, oldConds) a =
let a', (newVars, newConds) =
match a with
| Top | Bot as a -> k a, ([], [])
| Equal(a, b) ->
let avars, aconds, a = substituteOperationsWithRelationsInTerm a
let bvars, bconds, b = substituteOperationsWithRelationsInTerm b
let d = posK diseqSubstitutor eqSubstitutor a b
d, (avars @ bvars, aconds @ bconds)
| Distinct(a, b) ->
let avars, aconds, a = substituteOperationsWithRelationsInTerm a
let bvars, bconds, b = substituteOperationsWithRelationsInTerm b
let d = posK eqSubstitutor diseqSubstitutor a b
d, (avars @ bvars, aconds @ bconds)
| AApply(op, ts) ->
let vars, conds, ts = substituteOperationsWithRelationsInTermList ts
opt {
if List.length ts <= 1 then return! None else
let! assoc, makeApp =
match Map.tryFind op atomOperations, op with
| Some assoc, _ -> Some (assoc, fun (x, y) -> substituteOperationsWithRelationsInAtomApplication op [x; y])
| _, Equality -> Some(Chainable, (<||) eqSubstitutor)
| _, Disequality -> Some(Pairwise, (<||) diseqSubstitutor)
| _ -> None
let pairs =
match assoc with
| Chainable -> List.pairwise
| Pairwise -> List.triangle
match ts |> pairs |> List.map makeApp with
| at::ats -> return k at, (vars, ats @ conds)
| _ -> __unreachable__()
} |> Option.defaultWith (fun () -> k <| substituteOperationsWithRelationsInAtomApplication op ts, (vars, conds))
a', (newVars @ oldVars, newConds @ oldConds)
let substituteOperationsWithRelationsInAtom = substituteOperationsWithRelationsInAtomWithPositivity (fun _ -> id) id
let substituteOperationsWithRelationsInAtoms = List.mapFold substituteOperationsWithRelationsInAtom ([], [])
let rec substInRule qs premises consequence =
let ps, vcs = substituteOperationsWithRelationsInAtoms premises
let c, (vars, conds) = substituteOperationsWithRelationsInAtom vcs consequence
Rule(Quantifiers.combine qs (Quantifiers.forall vars), ps @ conds, c)
let substituteOperationsWithRelationsInFOL =
let posK pos dualSubst subst a b = if pos then subst a b |> FOLAtom else dualSubst a b |> FOLAtom |> FOLNot
FOL.mapFoldPositivity (fun pos -> substituteOperationsWithRelationsInAtomWithPositivity (posK pos) FOLAtom)
let substInLemma pos (qs, (premises, lemma)) =
let ps, vcs = substituteOperationsWithRelationsInAtoms premises
let c, (newVars, newConds) = substituteOperationsWithRelationsInFOL pos vcs lemma
Quantifiers.combine qs (Quantifiers.forall newVars), (ps @ newConds, c)
new (relativizations) = SubstituteOperations(relativizations, emptyEqSubstitutor, smartDiseqSubstitutor, fun _ -> None)
new (relativizations, constantMap) = SubstituteOperations(relativizations, emptyEqSubstitutor, smartDiseqSubstitutor, constantMap)
new (relativizations, eqSubst, diseqSubst) =
SubstituteOperations(relativizations, opSubstitutor emptyEqSubstitutor eqSubst, opSubstitutor smartDiseqSubstitutor diseqSubst, fun _ -> None)
member x.WasSubstituted () = wasSubstituted
member x.SubstituteOperationsWithRelations = function
| TransformedCommand(Rule(qs, body, head)) -> substInRule qs body head |> TransformedCommand
| LemmaCommand(pred, vars, bodyLemma, headCube) ->
let bodyLemma = substInLemma true bodyLemma
let headCube = substInLemma false headCube
LemmaCommand(pred, vars, bodyLemma, headCube)
| c -> c
type MapSorts<'acc>(mapSort : 'acc -> sort -> sort * 'acc, mapReturnSorts : bool) =
inherit FormulaMapper ()
let mutable acc = Unchecked.defaultof<'acc>
override x.TraverseSort sort =
let sort', acc' = mapSort acc sort
acc <- acc'
sort'
override x.TraverseReturnSort sort = if mapReturnSorts then x.TraverseSort sort else sort
member x.FoldCommand acc' command =
acc <- acc'
let command' = x.TraverseTransformedCommand command
command', acc
new (mapSort) = MapSorts(mapSort, true)
[<AbstractClass>]
type TheorySubstitutor () =
inherit FormulaMapper ()
let mutable wasMapped = false
member x.SubstInCommand (relativizer : SubstituteOperations) command =
let command = relativizer.SubstituteOperationsWithRelations(command)
let command = x.TraverseTransformedCommand(command)
command
override x.TraverseSort s =
let rec mapSort s =
match x.TryMapSort s with
| Some s' -> wasMapped <- true; s'
| None ->
match s with
| ArraySort(s1, s2) -> ArraySort(mapSort s1, mapSort s2)
| s -> s
mapSort s
override x.TraverseReturnSort sort = if x.MapReturnSortsFlag then x.TraverseSort sort else sort
abstract member MapReturnSortsFlag : bool
default x.MapReturnSortsFlag = true
abstract member TryMapSort : sort -> sort option
abstract member GenerateDeclarations : unit -> transformedCommand list * sort * Map<operation,operation * bool> * (symbol -> term option)
member x.SubstituteTheoryDelayed commands =
let preamble, newSort, newOps, newConstMap = x.GenerateDeclarations ()
let relativizer = SubstituteOperations(newOps, newConstMap)
let commands = List.map (x.SubstInCommand relativizer) commands
let wasSubstituted = relativizer.WasSubstituted ()
let shouldAddPreamble = wasMapped || wasSubstituted
let returnedCommands = if shouldAddPreamble then preamble @ commands else commands
shouldAddPreamble, preamble, returnedCommands, newSort
member x.SubstituteTheory commands = let _, _, commands, _ = x.SubstituteTheoryDelayed commands in commands