1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Andres Noetzli |
4 |
|
* |
5 |
|
* This file is part of the cvc5 project. |
6 |
|
* |
7 |
|
* Copyright (c) 2009-2021 by the authors listed in the file AUTHORS |
8 |
|
* in the top-level source directory and their institutional affiliations. |
9 |
|
* All rights reserved. See the file COPYING in the top-level source |
10 |
|
* directory for licensing information. |
11 |
|
* **************************************************************************** |
12 |
|
* |
13 |
|
* The HoElim preprocessing pass. |
14 |
|
* |
15 |
|
* Eliminates higher-order constraints. |
16 |
|
*/ |
17 |
|
|
18 |
|
#include "cvc5_private.h" |
19 |
|
|
20 |
|
#ifndef __CVC5__PREPROCESSING__PASSES__HO_ELIM_PASS_H |
21 |
|
#define __CVC5__PREPROCESSING__PASSES__HO_ELIM_PASS_H |
22 |
|
|
23 |
|
#include <map> |
24 |
|
#include <unordered_map> |
25 |
|
#include <unordered_set> |
26 |
|
|
27 |
|
#include "expr/node.h" |
28 |
|
#include "preprocessing/preprocessing_pass.h" |
29 |
|
|
30 |
|
namespace cvc5 { |
31 |
|
namespace preprocessing { |
32 |
|
namespace passes { |
33 |
|
|
34 |
|
/** Higher-order elimination. |
35 |
|
* |
36 |
|
* This preprocessing pass eliminates all occurrences of higher-order |
37 |
|
* constraints in the input, and replaces the entire input problem with |
38 |
|
* an equisatisfiable one. This is based on the following steps. |
39 |
|
* |
40 |
|
* [1] Eliminate all occurrences of lambdas via lambda lifting. This includes |
41 |
|
* lambdas with free variables that occur in quantifier bodies (see |
42 |
|
* documentation for eliminateLambdaComplete). |
43 |
|
* |
44 |
|
* [2] Eliminate all occurrences of partial applications and constraints |
45 |
|
* involving functions as first-class members. This is done by first |
46 |
|
* turning all function applications into an applicative encoding involving the |
47 |
|
* parametric binary operator @ (of kind HO_APPLY). Then we introduce: |
48 |
|
* - An uninterpreted sort U(T) for each function type T, |
49 |
|
* - A function H(f) of sort U(T1) x .. x U(Tn) -> U(T) for each function f |
50 |
|
* of sort T1 x ... x Tn -> T. |
51 |
|
* - A function App_{T1 x T2 ... x Tn -> T} of type |
52 |
|
* U(T1 x T2 ... x Tn -> T) x U(T1) -> U(T2 ... x Tn -> T) |
53 |
|
* for each occurrence of @ applied to arguments of types T1 x T2 ... x Tn -> T |
54 |
|
* and T1. |
55 |
|
* |
56 |
|
* [3] Add additional axioms to ensure the correct interpretation of |
57 |
|
* the sorts U(...), and functions App_{...}. This includes: |
58 |
|
* |
59 |
|
* - The "extensionality" axiom for App_{...} terms, stating that functions |
60 |
|
* that behave the same according to App for all inputs must be equal: |
61 |
|
* forall x : U(T1->T2), y : U(T1->T2). |
62 |
|
* ( forall z : T1. App_{T1->T2}( x, z ) = App_{T1->T2}( y, z ) ) => |
63 |
|
* x = y |
64 |
|
* |
65 |
|
* - The "store" axiom, which effectively states that for all (encoded) |
66 |
|
* functions f, there exists a function g that behaves identically to f, except |
67 |
|
* that g for argument i is e: |
68 |
|
* forall x : U(T1->T2), i : U(T1), e : U(T2). |
69 |
|
* exists g : U(T1->T2). |
70 |
|
* forall z: T1. |
71 |
|
* App_{T1->T2}( g, z ) = ite( z = i, e, App_{T1->T2}( f, z ) ). |
72 |
|
* |
73 |
|
* |
74 |
|
* Based on options, this preprocessing pass may apply a subset o the above |
75 |
|
* steps. In particular: |
76 |
|
* * If options::hoElim() is true, then step [2] is taken and extensionality |
77 |
|
* axioms are added in step [3]. |
78 |
|
* * If options::hoElimStoreAx() is true, then store axioms are added in step 3. |
79 |
|
* The form of these axioms depends on whether options::hoElim() is true. If it |
80 |
|
* is true, the axiom is given in terms of the uninterpreted functions that |
81 |
|
* encode function sorts. If it is false, then the store axiom is given in terms |
82 |
|
* of the original function sorts. |
83 |
|
*/ |
84 |
19708 |
class HoElim : public PreprocessingPass |
85 |
|
{ |
86 |
|
public: |
87 |
|
HoElim(PreprocessingPassContext* preprocContext); |
88 |
|
|
89 |
|
protected: |
90 |
|
PreprocessingPassResult applyInternal( |
91 |
|
AssertionPipeline* assertionsToPreprocess) override; |
92 |
|
/** |
93 |
|
* Eliminate all occurrences of lambdas in term n, return the result. This |
94 |
|
* is step [1] mentioned at the header of this class. |
95 |
|
* |
96 |
|
* The map newLambda maps newly introduced function skolems with their |
97 |
|
* (lambda) definition, which is a closed term. |
98 |
|
* |
99 |
|
* Notice that to ensure that all lambda definitions are closed, we |
100 |
|
* introduce extra bound arguments to the lambda, for example: |
101 |
|
* forall x. (lambda y. x+y) != f |
102 |
|
* becomes |
103 |
|
* forall x. g(x) != f |
104 |
|
* where g is mapped to the (closed) term ( lambda xy. x+y ). |
105 |
|
* |
106 |
|
* Notice that the definitions in newLambda may themselves contain lambdas, |
107 |
|
* hence, this method is run until a fix point is reached. |
108 |
|
*/ |
109 |
|
Node eliminateLambdaComplete(Node n, std::map<Node, Node>& newLambda); |
110 |
|
|
111 |
|
/** |
112 |
|
* Eliminate all higher-order constraints in n, return the result. This is |
113 |
|
* step [2] mentioned at the header of this class. |
114 |
|
*/ |
115 |
|
Node eliminateHo(Node n); |
116 |
|
/** |
117 |
|
* Stores the set of nodes we have current visited and their results |
118 |
|
* in steps [1] and [2] of this pass. |
119 |
|
*/ |
120 |
|
std::unordered_map<Node, Node> d_visited; |
121 |
|
/** |
122 |
|
* Stores the mapping from functions f to their corresponding function H(f) |
123 |
|
* in the encoding for step [2] of this pass. |
124 |
|
*/ |
125 |
|
std::unordered_map<TNode, Node> d_visited_op; |
126 |
|
/** The set of all function types encountered in assertions. */ |
127 |
|
std::unordered_set<TypeNode> d_funTypes; |
128 |
|
|
129 |
|
/** |
130 |
|
* Get ho apply uf, this returns App_{@_{T1 x T2 ... x Tn -> T}} |
131 |
|
*/ |
132 |
|
Node getHoApplyUf(TypeNode tn); |
133 |
|
/** |
134 |
|
* Get ho apply uf, where: |
135 |
|
* tn is T1 x T2 ... x Tn -> T, |
136 |
|
* tna is T1, |
137 |
|
* tnr is T2 ... x Tn -> T |
138 |
|
* This returns App_{@_{T1 x T2 ... x Tn -> T}}. |
139 |
|
*/ |
140 |
|
Node getHoApplyUf(TypeNode tn, TypeNode tna, TypeNode tnr); |
141 |
|
/** cache of getHoApplyUf */ |
142 |
|
std::map<TypeNode, Node> d_hoApplyUf; |
143 |
|
/** |
144 |
|
* Get uninterpreted sort for function sort. This returns U(T) for function |
145 |
|
* type T for step [2] of this pass. |
146 |
|
*/ |
147 |
|
TypeNode getUSort(TypeNode tn); |
148 |
|
/** cache of the above function */ |
149 |
|
std::map<TypeNode, TypeNode> d_ftypeMap; |
150 |
|
}; |
151 |
|
|
152 |
|
} // namespace passes |
153 |
|
} // namespace preprocessing |
154 |
|
} // namespace cvc5 |
155 |
|
|
156 |
|
#endif /* __CVC5__PREPROCESSING__PASSES__HO_ELIM_PASS_H */ |