f9e50c0f4aa3f1ac5d199eebf9466f3cf81b77c0
1 /********************* */
4 ** Top contributors (to current version):
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2019 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 Implementation of proof
15 #include "expr/proof.h"
17 using namespace CVC4::kind
;
21 std::ostream
& operator<<(std::ostream
& out
, CDPOverwrite opol
)
25 case CDPOverwrite::ALWAYS
: out
<< "ALWAYS"; break;
26 case CDPOverwrite::ASSUME_ONLY
: out
<< "ASSUME_ONLY"; break;
27 case CDPOverwrite::NEVER
: out
<< "NEVER"; break;
28 default: out
<< "CDPOverwrite:unknown"; break;
33 CDProof::CDProof(ProofNodeManager
* pnm
, context::Context
* c
)
34 : d_manager(pnm
), d_context(), d_nodes(c
? c
: &d_context
)
38 CDProof::~CDProof() {}
40 std::shared_ptr
<ProofNode
> CDProof::mkProof(Node fact
)
42 std::shared_ptr
<ProofNode
> pf
= getProofSymm(fact
);
48 std::vector
<Node
> pargs
= {fact
};
49 std::vector
<std::shared_ptr
<ProofNode
>> passume
;
50 std::shared_ptr
<ProofNode
> pfa
=
51 d_manager
->mkNode(PfRule::ASSUME
, passume
, pargs
, fact
);
52 d_nodes
.insert(fact
, pfa
);
56 std::shared_ptr
<ProofNode
> CDProof::getProof(Node fact
) const
58 NodeProofNodeMap::iterator it
= d_nodes
.find(fact
);
59 if (it
!= d_nodes
.end())
66 std::shared_ptr
<ProofNode
> CDProof::getProofSymm(Node fact
)
68 Trace("cdproof") << "CDProof::getProofSymm: " << fact
<< std::endl
;
69 std::shared_ptr
<ProofNode
> pf
= getProof(fact
);
70 if (pf
!= nullptr && !isAssumption(pf
.get()))
72 Trace("cdproof") << "...existing non-assume " << pf
->getRule() << std::endl
;
75 Node symFact
= getSymmFact(fact
);
78 Trace("cdproof") << "...no possible symm" << std::endl
;
79 // no symmetry possible, return original proof (possibly assumption)
82 // See if a proof exists for the opposite direction, if so, add the step.
83 // Notice that SYMM is also disallowed.
84 std::shared_ptr
<ProofNode
> pfs
= getProof(symFact
);
87 // The symmetric fact exists, and the current one either does not, or is
88 // an assumption. We make a new proof that applies SYMM to pfs.
89 std::vector
<std::shared_ptr
<ProofNode
>> pschild
;
90 pschild
.push_back(pfs
);
91 std::vector
<Node
> args
;
94 Trace("cdproof") << "...fresh make symm" << std::endl
;
95 std::shared_ptr
<ProofNode
> psym
=
96 d_manager
->mkNode(PfRule::SYMM
, pschild
, args
, fact
);
97 Assert(psym
!= nullptr);
98 d_nodes
.insert(fact
, psym
);
101 else if (!isAssumption(pfs
.get()))
103 // if its not an assumption, make the connection
104 Trace("cdproof") << "...update symm" << std::endl
;
106 bool sret
= d_manager
->updateNode(pf
.get(), PfRule::SYMM
, pschild
, args
);
112 Trace("cdproof") << "...no symm, return "
113 << (pf
== nullptr ? "null" : "non-null") << std::endl
;
115 // return original proof (possibly assumption)
119 bool CDProof::addStep(Node expected
,
121 const std::vector
<Node
>& children
,
122 const std::vector
<Node
>& args
,
124 CDPOverwrite opolicy
)
126 Trace("cdproof") << "CDProof::addStep: " << id
<< " " << expected
127 << ", ensureChildren = " << ensureChildren
128 << ", overwrite policy = " << opolicy
<< std::endl
;
129 // We must always provide expected to this method
130 Assert(!expected
.isNull());
132 std::shared_ptr
<ProofNode
> pprev
= getProofSymm(expected
);
133 if (pprev
!= nullptr)
135 if (!shouldOverwrite(pprev
.get(), id
, opolicy
))
137 // we should not overwrite the current step
138 Trace("cdproof") << "...success, no overwrite" << std::endl
;
141 Trace("cdproof") << "existing proof " << pprev
->getRule()
142 << ", overwrite..." << std::endl
;
143 // we will overwrite the existing proof node by updating its contents below
145 // collect the child proofs, for each premise
146 std::vector
<std::shared_ptr
<ProofNode
>> pchildren
;
147 for (const Node
& c
: children
)
149 Trace("cdproof") << "- get child " << c
<< std::endl
;
150 std::shared_ptr
<ProofNode
> pc
= getProofSymm(c
);
155 // failed to get a proof for a child, fail
156 Trace("cdproof") << "...fail, no child" << std::endl
;
159 Trace("cdproof") << "--- add assume" << std::endl
;
160 // otherwise, we initialize it as an assumption
161 std::vector
<Node
> pcargs
= {c
};
162 std::vector
<std::shared_ptr
<ProofNode
>> pcassume
;
163 pc
= d_manager
->mkNode(PfRule::ASSUME
, pcassume
, pcargs
, c
);
164 // assumptions never fail to check
165 Assert(pc
!= nullptr);
166 d_nodes
.insert(c
, pc
);
168 pchildren
.push_back(pc
);
171 // the user may have provided SYMM of an assumption
172 if (id
== PfRule::SYMM
)
174 Assert(pchildren
.size() == 1);
175 if (isAssumption(pchildren
[0].get()))
177 // the step we are constructing is a (symmetric fact of an) assumption, so
178 // there is no use adding it to the proof.
184 // create or update it
185 std::shared_ptr
<ProofNode
> pthis
;
186 if (pprev
== nullptr)
188 Trace("cdproof") << " new node " << expected
<< "..." << std::endl
;
189 pthis
= d_manager
->mkNode(id
, pchildren
, args
, expected
);
190 if (pthis
== nullptr)
192 // failed to construct the node, perhaps due to a proof checking failure
193 Trace("cdproof") << "...fail, proof checking" << std::endl
;
196 d_nodes
.insert(expected
, pthis
);
200 Trace("cdproof") << " update node " << expected
<< "..." << std::endl
;
203 // We return the value of updateNode here. This means this method may return
204 // false if this call failed, regardless of whether we already have a proof
205 // step for expected.
206 ret
= d_manager
->updateNode(pthis
.get(), id
, pchildren
, args
);
210 // the result of the proof node should be expected
211 Assert(pthis
->getResult() == expected
);
214 notifyNewProof(expected
);
217 Trace("cdproof") << "...return " << ret
<< std::endl
;
221 void CDProof::notifyNewProof(Node expected
)
223 // ensure SYMM proof is also linked to an existing proof, if it is an
225 Node symExpected
= getSymmFact(expected
);
226 if (!symExpected
.isNull())
228 Trace("cdproof") << " check connect symmetry " << symExpected
<< std::endl
;
229 // if it exists, we may need to update it
230 std::shared_ptr
<ProofNode
> pfs
= getProof(symExpected
);
233 Trace("cdproof") << " connect via getProofSymm method..." << std::endl
;
234 // call the get function with symmetry, which will do the update
235 std::shared_ptr
<ProofNode
> pfss
= getProofSymm(symExpected
);
239 Trace("cdproof") << " no connect" << std::endl
;
244 bool CDProof::addStep(Node expected
,
245 const ProofStep
& step
,
247 CDPOverwrite opolicy
)
249 return addStep(expected
,
257 bool CDProof::addSteps(const ProofStepBuffer
& psb
,
259 CDPOverwrite opolicy
)
261 const std::vector
<std::pair
<Node
, ProofStep
>>& steps
= psb
.getSteps();
262 for (const std::pair
<Node
, ProofStep
>& ps
: steps
)
264 if (!addStep(ps
.first
, ps
.second
, ensureChildren
, opolicy
))
272 bool CDProof::addProof(std::shared_ptr
<ProofNode
> pn
,
273 CDPOverwrite opolicy
,
278 // If we aren't doing a deep copy, we either store pn or link its top
279 // node into the existing pointer
280 Node curFact
= pn
->getResult();
281 std::shared_ptr
<ProofNode
> cur
= getProofSymm(curFact
);
284 // Assert that the checker of this class agrees with (the externally
285 // provided) pn. This ensures that if pn was checked by a different
286 // checker than the one of the manager in this class, then it is double
287 // checked here, so that this class maintains the invariant that all of
288 // its nodes in d_nodes have been checked by the underlying checker.
289 Assert(d_manager
->getChecker() == nullptr
290 || d_manager
->getChecker()->check(pn
.get(), curFact
) == curFact
);
291 // just store the proof for fact
292 d_nodes
.insert(curFact
, pn
);
294 else if (shouldOverwrite(cur
.get(), pn
->getRule(), opolicy
))
296 // We update cur to have the structure of the top node of pn. Notice that
297 // the interface to update this node will ensure that the proof apf is a
298 // proof of the assumption. If it does not, then pn was wrong.
299 if (!d_manager
->updateNode(
300 cur
.get(), pn
->getRule(), pn
->getChildren(), pn
->getArguments()))
305 // also need to connect via SYMM if necessary
306 notifyNewProof(curFact
);
309 std::unordered_map
<ProofNode
*, bool> visited
;
310 std::unordered_map
<ProofNode
*, bool>::iterator it
;
311 std::vector
<ProofNode
*> visit
;
314 visit
.push_back(pn
.get());
315 bool retValue
= true;
319 curFact
= cur
->getResult();
321 it
= visited
.find(cur
);
322 if (it
== visited
.end())
324 // visit the children
325 visited
[cur
] = false;
326 visit
.push_back(cur
);
327 const std::vector
<std::shared_ptr
<ProofNode
>>& cs
= cur
->getChildren();
328 for (const std::shared_ptr
<ProofNode
>& c
: cs
)
330 visit
.push_back(c
.get());
333 else if (!it
->second
)
335 // we always call addStep, which may or may not overwrite the
337 std::vector
<Node
> pexp
;
338 const std::vector
<std::shared_ptr
<ProofNode
>>& cs
= cur
->getChildren();
339 for (const std::shared_ptr
<ProofNode
>& c
: cs
)
341 Assert(!c
->getResult().isNull());
342 pexp
.push_back(c
->getResult());
344 // can ensure children at this point
346 curFact
, cur
->getRule(), pexp
, cur
->getArguments(), true, opolicy
);
347 // should always succeed
349 retValue
= retValue
&& res
;
352 } while (!visit
.empty());
357 bool CDProof::hasStep(Node fact
)
359 std::shared_ptr
<ProofNode
> pf
= getProof(fact
);
360 if (pf
!= nullptr && !isAssumption(pf
.get()))
364 Node symFact
= getSymmFact(fact
);
365 if (symFact
.isNull())
369 pf
= getProof(symFact
);
370 if (pf
!= nullptr && !isAssumption(pf
.get()))
377 ProofNodeManager
* CDProof::getManager() const { return d_manager
; }
379 bool CDProof::shouldOverwrite(ProofNode
* pn
, PfRule newId
, CDPOverwrite opol
)
381 Assert(pn
!= nullptr);
382 // we overwrite only if opol is CDPOverwrite::ALWAYS, or if
383 // opol is CDPOverwrite::ASSUME_ONLY and the previously
384 // provided proof pn was an assumption and the currently provided step is not
385 return opol
== CDPOverwrite::ALWAYS
386 || (opol
== CDPOverwrite::ASSUME_ONLY
&& isAssumption(pn
)
387 && newId
!= PfRule::ASSUME
);
390 bool CDProof::isAssumption(ProofNode
* pn
)
392 PfRule rule
= pn
->getRule();
393 if (rule
== PfRule::ASSUME
)
397 else if (rule
== PfRule::SYMM
)
399 const std::vector
<std::shared_ptr
<ProofNode
>>& pc
= pn
->getChildren();
400 Assert(pc
.size() == 1);
401 return pc
[0]->getRule() == PfRule::ASSUME
;
406 bool CDProof::isSame(TNode f
, TNode g
)
412 Kind fk
= f
.getKind();
413 Kind gk
= g
.getKind();
414 if (fk
== EQUAL
&& gk
== EQUAL
&& f
[0] == g
[1] && f
[1] == g
[0])
416 // symmetric equality
419 if (fk
== NOT
&& gk
== NOT
&& f
[0][0] == g
[0][1] && f
[0][1] == g
[0][0])
421 // symmetric disequality
427 Node
CDProof::getSymmFact(TNode f
)
429 bool polarity
= f
.getKind() != NOT
;
430 TNode fatom
= polarity
? f
: f
[0];
431 if (fatom
.getKind() != EQUAL
|| fatom
[0] == fatom
[1])
435 Node symFact
= fatom
[1].eqNode(fatom
[0]);
436 return polarity
? symFact
: symFact
.notNode();