1 /********************* */
2 /*! \file assertion_pipeline.cpp
4 ** Top contributors (to current version):
5 ** Andrew Reynolds, Andres Noetzli, Haniel Barbosa
6 ** This file is part of the CVC4 project.
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.\endverbatim
12 ** \brief AssertionPipeline stores a list of assertions modified by
13 ** preprocessing passes
16 #include "preprocessing/assertion_pipeline.h"
18 #include "expr/node_manager.h"
19 #include "options/smt_options.h"
20 #include "expr/lazy_proof.h"
21 #include "proof/proof_manager.h"
22 #include "smt/preprocess_proof_generator.h"
23 #include "theory/builtin/proof_checker.h"
24 #include "theory/rewriter.h"
27 namespace preprocessing
{
29 AssertionPipeline::AssertionPipeline()
30 : d_realAssertionsEnd(0),
31 d_storeSubstsInAsserts(false),
33 d_assumptionsStart(0),
39 void AssertionPipeline::clear()
42 d_realAssertionsEnd
= 0;
43 d_assumptionsStart
= 0;
47 void AssertionPipeline::push_back(Node n
,
55 Assert(pgen
== nullptr);
56 if (d_numAssumptions
== 0)
58 d_assumptionsStart
= d_nodes
.size() - 1;
60 // Currently, we assume that assumptions are all added one after another
61 // and that we store them in the same vector as the assertions. Once we
62 // split the assertions up into multiple vectors (see issue #2473), we will
63 // not have this limitation anymore.
64 Assert(d_assumptionsStart
+ d_numAssumptions
== d_nodes
.size() - 1);
67 Trace("assert-pipeline") << "Assertions: ...new assertion " << n
68 << ", isInput=" << isInput
<< std::endl
;
73 // notice this is always called, regardless of whether pgen is nullptr
74 d_pppg
->notifyNewAssert(n
, pgen
);
78 Assert(pgen
== nullptr);
79 // n is an input assertion, whose proof should be ASSUME.
80 d_pppg
->notifyInput(n
);
85 void AssertionPipeline::pushBackTrusted(theory::TrustNode trn
)
87 Assert(trn
.getKind() == theory::TrustNodeKind::LEMMA
);
88 // push back what was proven
89 push_back(trn
.getProven(), false, false, trn
.getGenerator());
92 void AssertionPipeline::replace(size_t i
, Node n
, ProofGenerator
* pgen
)
99 Trace("assert-pipeline") << "Assertions: Replace " << d_nodes
[i
] << " with "
101 if (isProofEnabled())
103 d_pppg
->notifyPreprocessed(d_nodes
[i
], n
, pgen
);
105 else if (options::unsatCores())
107 ProofManager::currentPM()->addDependence(n
, d_nodes
[i
]);
112 void AssertionPipeline::replaceTrusted(size_t i
, theory::TrustNode trn
)
116 // null trust node denotes no change, nothing to do
119 Assert(trn
.getKind() == theory::TrustNodeKind::REWRITE
);
120 Assert(trn
.getProven()[0] == d_nodes
[i
]);
121 replace(i
, trn
.getNode(), trn
.getGenerator());
124 void AssertionPipeline::setProofGenerator(smt::PreprocessProofGenerator
* pppg
)
129 bool AssertionPipeline::isProofEnabled() const { return d_pppg
!= nullptr; }
131 void AssertionPipeline::enableStoreSubstsInAsserts()
133 d_storeSubstsInAsserts
= true;
134 d_substsIndex
= d_nodes
.size();
135 d_nodes
.push_back(NodeManager::currentNM()->mkConst
<bool>(true));
138 void AssertionPipeline::disableStoreSubstsInAsserts()
140 d_storeSubstsInAsserts
= false;
143 void AssertionPipeline::addSubstitutionNode(Node n
, ProofGenerator
* pg
)
145 Assert(d_storeSubstsInAsserts
);
146 Assert(n
.getKind() == kind::EQUAL
);
147 conjoin(d_substsIndex
, n
, pg
);
150 void AssertionPipeline::conjoin(size_t i
, Node n
, ProofGenerator
* pg
)
152 NodeManager
* nm
= NodeManager::currentNM();
153 Node newConj
= nm
->mkNode(kind::AND
, d_nodes
[i
], n
);
154 Node newConjr
= theory::Rewriter::rewrite(newConj
);
155 Trace("assert-pipeline") << "Assertions: conjoin " << n
<< " to "
156 << d_nodes
[i
] << std::endl
;
157 Trace("assert-pipeline-debug") << "conjoin " << n
<< " to " << d_nodes
[i
]
158 << ", got " << newConjr
<< std::endl
;
159 if (newConjr
== d_nodes
[i
])
164 if (isProofEnabled())
168 // don't care about the previous proof and can simply plug in the
169 // proof from pg if the resulting assertion is the same as n.
170 d_pppg
->notifyNewAssert(newConjr
, pg
);
174 // ---------- from pppg --------- from pg
176 // -------------------------------- AND_INTRO
178 // -------------------------------- MACRO_SR_PRED_TRANSFORM
179 // rewrite( d_nodes[i] ^ n )
180 // allocate a fresh proof which will act as the proof generator
181 LazyCDProof
* lcp
= d_pppg
->allocateHelperProof();
182 lcp
->addLazyStep(n
, pg
, PfRule::PREPROCESS
);
183 if (d_nodes
[i
].isConst() && d_nodes
[i
].getConst
<bool>())
185 // skip the AND_INTRO if the previous d_nodes[i] was true
190 lcp
->addLazyStep(d_nodes
[i
], d_pppg
);
191 lcp
->addStep(newConj
, PfRule::AND_INTRO
, {d_nodes
[i
], n
}, {});
193 if (newConjr
!= newConj
)
196 newConjr
, PfRule::MACRO_SR_PRED_TRANSFORM
, {newConj
}, {newConjr
});
198 // Notice we have constructed a proof of a new assertion, where d_pppg
199 // is referenced in the lazy proof above. If alternatively we had
200 // constructed a proof of d_nodes[i] = rewrite( d_nodes[i] ^ n ), we would
201 // have used notifyPreprocessed. However, it is simpler to make the
203 d_pppg
->notifyNewAssert(newConjr
, lcp
);
206 if (options::unsatCores() && !isProofEnabled())
208 ProofManager::currentPM()->addDependence(newConjr
, d_nodes
[i
]);
210 d_nodes
[i
] = newConjr
;
211 Assert(theory::Rewriter::rewrite(newConjr
) == newConjr
);
214 } // namespace preprocessing