1 /********************* */
2 /*! \file trust_substitutions.cpp
4 ** Top contributors (to current version):
5 ** Andrew Reynolds, Gereon Kremer
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2020 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.\endverbatim
12 ** \brief Trust substitutions
15 #include "theory/trust_substitutions.h"
17 #include "theory/rewriter.h"
22 TrustSubstitutionMap::TrustSubstitutionMap(context::Context
* c
,
23 ProofNodeManager
* pnm
,
31 d_tspb(pnm
? new TheoryProofStepBuffer(pnm
->getChecker()) : nullptr),
33 pnm
? new LazyCDProof(pnm
, nullptr, c
, "TrustSubstitutionMap::subsPg")
35 d_applyPg(pnm
? new LazyCDProof(
36 pnm
, nullptr, c
, "TrustSubstitutionMap::applyPg")
46 void TrustSubstitutionMap::addSubstitution(TNode x
, TNode t
, ProofGenerator
* pg
)
48 Trace("trust-subs") << "TrustSubstitutionMap::addSubstitution: add " << x
49 << " -> " << t
<< std::endl
;
50 d_subs
.addSubstitution(x
, t
);
53 TrustNode tnl
= TrustNode::mkTrustRewrite(x
, t
, pg
);
54 d_tsubs
.push_back(tnl
);
55 // current substitution node is no longer valid.
56 d_currentSubs
= Node::null();
58 d_subsPg
->addLazyStep(tnl
.getProven(), pg
, d_trustId
);
62 void TrustSubstitutionMap::addSubstitution(TNode x
,
65 const std::vector
<Node
>& args
)
67 if (!isProofEnabled())
69 addSubstitution(x
, t
, nullptr);
72 LazyCDProof
* stepPg
= d_helperPf
.allocateProof(nullptr, d_ctx
);
73 Node eq
= x
.eqNode(t
);
74 stepPg
->addStep(eq
, id
, {}, args
);
75 addSubstitution(x
, t
, stepPg
);
78 ProofGenerator
* TrustSubstitutionMap::addSubstitutionSolved(TNode x
,
82 Trace("trust-subs") << "TrustSubstitutionMap::addSubstitutionSolved: add "
83 << x
<< " -> " << t
<< " from " << tn
.getProven()
85 if (!isProofEnabled() || tn
.getGenerator() == nullptr)
87 // no generator or not proof enabled, nothing to do
88 addSubstitution(x
, t
, nullptr);
89 Trace("trust-subs") << "...no proof" << std::endl
;
92 Node eq
= x
.eqNode(t
);
93 Node proven
= tn
.getProven();
94 // notice that this checks syntactic equality, not CDProof::isSame since
95 // tn.getGenerator() is not necessarily robust to symmetry.
98 // no rewrite required, just use the generator
99 addSubstitution(x
, t
, tn
.getGenerator());
100 Trace("trust-subs") << "...use generator directly" << std::endl
;
101 return tn
.getGenerator();
103 LazyCDProof
* solvePg
= d_helperPf
.allocateProof(nullptr, d_ctx
);
104 // Try to transform tn.getProven() to (= x t) here, if necessary
105 if (!d_tspb
->applyPredTransform(proven
, eq
, {}))
108 addSubstitution(x
, t
, nullptr);
109 Trace("trust-subs") << "...failed to rewrite" << std::endl
;
112 Trace("trust-subs") << "...successful rewrite" << std::endl
;
113 solvePg
->addSteps(*d_tspb
.get());
115 // link the given generator
116 solvePg
->addLazyStep(proven
, tn
.getGenerator());
117 addSubstitution(x
, t
, solvePg
);
121 void TrustSubstitutionMap::addSubstitutions(TrustSubstitutionMap
& t
)
123 if (!isProofEnabled())
125 // just use the basic utility
126 d_subs
.addSubstitutions(t
.get());
129 // call addSubstitution above in sequence
130 for (const TrustNode
& tns
: t
.d_tsubs
)
132 Node proven
= tns
.getProven();
133 addSubstitution(proven
[0], proven
[1], tns
.getGenerator());
137 TrustNode
TrustSubstitutionMap::apply(Node n
, bool doRewrite
)
139 Trace("trust-subs") << "TrustSubstitutionMap::addSubstitution: apply " << n
141 Node ns
= d_subs
.apply(n
);
142 Trace("trust-subs") << "...subs " << ns
<< std::endl
;
143 // rewrite if indicated
146 ns
= Rewriter::rewrite(ns
);
147 Trace("trust-subs") << "...rewrite " << ns
<< std::endl
;
152 return TrustNode::null();
154 if (!isProofEnabled())
156 // no proofs, use null generator
157 return TrustNode::mkTrustRewrite(n
, ns
, nullptr);
159 Node cs
= getCurrentSubstitution();
161 << "TrustSubstitutionMap::addSubstitution: current substitution is " << cs
163 // Easy case: if n is in the domain of the substitution, maybe it is already
164 // a proof in the substitution proof generator. This is moreover required
165 // to avoid cyclic proofs below. For example, if { x -> 5 } is a substitution,
166 // and we are asked to transform x, resulting in 5, we hence must provide
167 // a proof of (= x 5) based on the substitution. However, it must be the
168 // case that (= x 5) is a proven fact of the substitution generator. Hence
169 // we avoid a proof that looks like:
170 // ---------- from d_subsPg
172 // ---------- MACRO_SR_EQ_INTRO{x}
174 // by taking the premise proof directly.
175 Node eq
= n
.eqNode(ns
);
176 if (d_subsPg
->hasStep(eq
) || d_subsPg
->hasGenerator(eq
))
178 return TrustNode::mkTrustRewrite(n
, ns
, d_subsPg
.get());
181 std::vector
<Node
> pfChildren
;
184 // note we will get more proof reuse if we do not special case AND here.
185 if (cs
.getKind() == kind::AND
)
187 for (const Node
& csc
: cs
)
189 pfChildren
.push_back(csc
);
190 // connect substitution generator into apply generator
191 d_applyPg
->addLazyStep(csc
, d_subsPg
.get());
196 pfChildren
.push_back(cs
);
197 // connect substitution generator into apply generator
198 d_applyPg
->addLazyStep(cs
, d_subsPg
.get());
201 if (!d_tspb
->applyEqIntro(n
, ns
, pfChildren
, d_ids
))
203 // if we fail for any reason, we must use a trusted step instead
204 d_tspb
->addStep(PfRule::TRUST_SUBS_MAP
, pfChildren
, {eq
}, eq
);
206 // ------- ------- from external proof generators
207 // x1 = t1 ... xn = tn
208 // ----------------------- AND_INTRO
210 // --------- MACRO_SR_EQ_INTRO (or TRUST_SUBS_MAP if we failed above)
212 // add it to the apply proof generator.
214 // Notice that we use a single child to MACRO_SR_EQ_INTRO here. This is an
215 // optimization motivated by the fact that n may be large and reused many
216 // time. For instance, if this class is being used to track substitutions
217 // derived during non-clausal simplification during preprocessing, it is
218 // a fixed (possibly) large substitution applied to many terms. Having
219 // a single child saves us from creating many proofs with n children, where
220 // notice this proof is reused.
221 d_applyPg
->addSteps(*d_tspb
.get());
223 return TrustNode::mkTrustRewrite(n
, ns
, d_applyPg
.get());
226 SubstitutionMap
& TrustSubstitutionMap::get() { return d_subs
; }
228 bool TrustSubstitutionMap::isProofEnabled() const
230 return d_subsPg
!= nullptr;
233 Node
TrustSubstitutionMap::getCurrentSubstitution()
235 Assert(isProofEnabled());
236 if (!d_currentSubs
.get().isNull())
238 return d_currentSubs
;
240 std::vector
<Node
> csubsChildren
;
241 for (const TrustNode
& tns
: d_tsubs
)
243 csubsChildren
.push_back(tns
.getProven());
245 std::reverse(csubsChildren
.begin(),csubsChildren
.end());
246 d_currentSubs
= NodeManager::currentNM()->mkAnd(csubsChildren
);
247 if (d_currentSubs
.get().getKind() == kind::AND
)
249 d_subsPg
->addStep(d_currentSubs
, PfRule::AND_INTRO
, csubsChildren
, {});
251 return d_currentSubs
;
254 } // namespace theory