1 /*********************                                                        */
2 /*! \file uf_proof.cpp
3  ** \verbatim
4  ** Top contributors (to current version):
5  **   Liana Hadarean, Guy Katz, Yoni Zohar
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
11  **
12  ** [[ Add lengthier description here ]]
13 
14  ** \todo document this file
15 
16 **/
17 #include "proof/uf_proof.h"
18 
19 #include <stack>
20 
21 #include "proof/proof_manager.h"
22 #include "proof/simplify_boolean_node.h"
23 #include "theory/uf/theory_uf.h"
24 
25 namespace CVC4 {
26 
toStream(std::ostream & out) const27 void ProofUF::toStream(std::ostream& out) const
28 {
29   ProofLetMap map;
30   toStream(out, map);
31 }
32 
toStream(std::ostream & out,const ProofLetMap & map) const33 void ProofUF::toStream(std::ostream& out, const ProofLetMap& map) const
34 {
35   Trace("theory-proof-debug") << "; Print UF proof..." << std::endl;
36   //AJR : carry this further?
37   toStreamLFSC(out, ProofManager::getUfProof(), *d_proof, map);
38 }
39 
toStreamLFSC(std::ostream & out,TheoryProof * tp,const theory::eq::EqProof & pf,const ProofLetMap & map)40 void ProofUF::toStreamLFSC(std::ostream& out,
41                            TheoryProof* tp,
42                            const theory::eq::EqProof& pf,
43                            const ProofLetMap& map)
44 {
45   Debug("pf::uf") << "ProofUF::toStreamLFSC starting" << std::endl;
46   Debug("lfsc-uf") << "Printing uf proof in LFSC : " << std::endl;
47   pf.debug_print("lfsc-uf");
48   Debug("lfsc-uf") << std::endl;
49   toStreamRecLFSC( out, tp, pf, 0, map );
50 }
51 
toStreamRecLFSC(std::ostream & out,TheoryProof * tp,const theory::eq::EqProof & pf,unsigned tb,const ProofLetMap & map)52 Node ProofUF::toStreamRecLFSC(std::ostream& out,
53                               TheoryProof* tp,
54                               const theory::eq::EqProof& pf,
55                               unsigned tb,
56                               const ProofLetMap& map)
57 {
58   Debug("pf::uf") << std::endl
59                   << std::endl
60                   << "toStreamRecLFSC called. tb = " << tb
61                   << " . proof:" << std::endl;
62   if (tb == 0)
63   {
64     // Special case: false was an input, so the proof is just "false".
65     if (pf.d_id == theory::eq::MERGED_THROUGH_EQUALITY &&
66         pf.d_node == NodeManager::currentNM()->mkConst(false)) {
67       out << "(clausify_false ";
68       out << ProofManager::getLitName(NodeManager::currentNM()->mkConst(false).notNode());
69       out << ")" << std::endl;
70       return Node();
71     }
72 
73     std::shared_ptr<theory::eq::EqProof> subTrans =
74         std::make_shared<theory::eq::EqProof>();
75 
76     int neg = tp->assertAndPrint(pf, map, subTrans);
77 
78     Node n1;
79     std::stringstream ss, ss2;
80     Debug("pf::uf") << "\nsubtrans has " << subTrans->d_children.size() << " children\n";
81     bool disequalityFound = (neg >= 0);
82 
83     if(!disequalityFound || subTrans->d_children.size() >= 2) {
84       n1 = toStreamRecLFSC(ss, tp, *subTrans, 1, map);
85     } else {
86       n1 = toStreamRecLFSC(ss, tp, *(subTrans->d_children[0]), 1, map);
87       Debug("pf::uf") << "\nsubTrans unique child "
88                       << subTrans->d_children[0]->d_id
89                       << " was proven\ngot: " << n1 << std::endl;
90     }
91 
92     Debug("pf::uf") << "\nhave proven: " << n1 << std::endl;
93 
94     out << "(clausify_false (contra _ ";
95     if (disequalityFound) {
96       Node n2 = pf.d_children[neg]->d_node;
97       Assert(n2.getKind() == kind::NOT);
98 
99       Debug("pf::uf") << "n2 is " << n2[0] << std::endl;
100 
101       if (n2[0].getNumChildren() > 0)
102       {
103         Debug("pf::uf") << "\nn2[0]: " << n2[0][0] << std::endl;
104       }
105       if (n1.getNumChildren() > 1) { Debug("pf::uf") << "n1[1]: " << n1[1] << std::endl; }
106 
107       if(n2[0].getKind() == kind::APPLY_UF) {
108         out << "(trans _ _ _ _ ";
109 
110         if (n1[0] == n2[0]) {
111           out << "(symm _ _ _ ";
112           out << ss.str();
113           out << ") ";
114         } else {
115           Assert(n1[1] == n2[0]);
116           out << ss.str();
117         }
118         out << "(pred_eq_f _ " << ProofManager::getLitName(n2[0]) << ")) t_t_neq_f))" << std::endl;
119       } else if (n2[0].getKind() == kind::BOOLEAN_TERM_VARIABLE) {
120         out << ss.str() << " " << ProofManager::getLitName(n2[0]) << "))";
121       } else {
122         Assert((n1[0] == n2[0][0] && n1[1] == n2[0][1]) || (n1[1] == n2[0][0] && n1[0] == n2[0][1]));
123         if(n1[1] == n2[0][0]) {
124           out << "(symm _ _ _ " << ss.str() << ")";
125         } else {
126           out << ss.str();
127         }
128         out << " " << ProofManager::getLitName(n2[0]) << "))" << std::endl;
129       }
130     } else {
131       Node n2 = pf.d_node;
132       Assert(n2.getKind() == kind::EQUAL);
133       Assert((n1[0] == n2[0] && n1[1] == n2[1]) || (n1[1] == n2[0] && n1[0] == n2[1]));
134 
135       out << ss.str();
136       out << " ";
137       ProofManager::getTheoryProofEngine()->printConstantDisequalityProof(
138           out, n1[0].toExpr(), n1[1].toExpr(), map);
139       out << "))" << std::endl;
140     }
141 
142     return Node();
143   }
144 
145   switch(pf.d_id) {
146   case theory::eq::MERGED_THROUGH_CONGRUENCE: {
147     Debug("pf::uf") << "\nok, looking at congruence:\n";
148     pf.debug_print("pf::uf");
149     std::stack<const theory::eq::EqProof*> stk;
150     for (const theory::eq::EqProof* pf2 = &pf;
151          pf2->d_id == theory::eq::MERGED_THROUGH_CONGRUENCE;
152          pf2 = pf2->d_children[0].get()) {
153       Assert(!pf2->d_node.isNull());
154       Assert(pf2->d_node.getKind() == kind::PARTIAL_APPLY_UF
155              || pf2->d_node.getKind() == kind::BUILTIN
156              || pf2->d_node.getKind() == kind::APPLY_UF
157              || pf2->d_node.getKind() == kind::SELECT
158              || pf2->d_node.getKind() == kind::STORE);
159       Assert(pf2->d_children.size() == 2);
160       out << "(cong _ _ _ _ _ _ ";
161       stk.push(pf2);
162     }
163     Assert(stk.top()->d_children[0]->d_id != theory::eq::MERGED_THROUGH_CONGRUENCE);
164     NodeBuilder<> b1(kind::PARTIAL_APPLY_UF), b2(kind::PARTIAL_APPLY_UF);
165     const theory::eq::EqProof* pf2 = stk.top();
166     stk.pop();
167     Assert(pf2->d_id == theory::eq::MERGED_THROUGH_CONGRUENCE);
168     Node n1 = toStreamRecLFSC(out, tp, *(pf2->d_children[0]), tb + 1, map);
169     out << " ";
170     std::stringstream ss;
171     Node n2 = toStreamRecLFSC(ss, tp, *(pf2->d_children[1]), tb + 1, map);
172     Debug("pf::uf") << "\nok, in FIRST cong[" << stk.size() << "]" << "\n";
173     pf2->debug_print("pf::uf");
174     Debug("pf::uf") << "looking at " << pf2->d_node << "\n";
175     Debug("pf::uf") << "           " << n1 << "\n";
176     Debug("pf::uf") << "           " << n2 << "\n";
177     int side = 0;
178     if (tp->match(pf2->d_node, n1[0]))
179     {
180       //if(tb == 1) {
181       Debug("pf::uf") << "SIDE IS 0\n";
182       //}
183       side = 0;
184     } else {
185       //if(tb == 1) {
186       Debug("pf::uf") << "SIDE IS 1\n";
187       //}
188       if (!tp->match(pf2->d_node, n1[1]))
189       {
190         Debug("pf::uf") << "IN BAD CASE, our first subproof is\n";
191         pf2->d_children[0]->debug_print("pf::uf");
192       }
193       Assert(tp->match(pf2->d_node, n1[1]));
194       side = 1;
195     }
196     if (n1[side].getKind() == kind::APPLY_UF
197         || n1[side].getKind() == kind::PARTIAL_APPLY_UF
198         || n1[side].getKind() == kind::SELECT
199         || n1[side].getKind() == kind::STORE)
200     {
201       if (n1[side].getKind() == kind::APPLY_UF
202           || n1[side].getKind() == kind::PARTIAL_APPLY_UF)
203       {
204         b1 << n1[side].getOperator();
205       } else {
206         b1 << ProofManager::currentPM()->mkOp(n1[side].getOperator());
207       }
208       b1.append(n1[side].begin(), n1[side].end());
209     } else {
210       b1 << n1[side];
211     }
212     if(n1[1-side].getKind() == kind::PARTIAL_APPLY_UF || n1[1-side].getKind() == kind::APPLY_UF || n1[side].getKind() == kind::SELECT || n1[side].getKind() == kind::STORE) {
213       if (n1[1 - side].getKind() == kind::PARTIAL_APPLY_UF
214           || n1[1 - side].getKind() == kind::APPLY_UF)
215       {
216         b2 << n1[1-side].getOperator();
217       } else {
218         b2 << ProofManager::currentPM()->mkOp(n1[1-side].getOperator());
219       }
220       b2.append(n1[1-side].begin(), n1[1-side].end());
221     } else {
222       b2 << n1[1-side];
223     }
224     Debug("pf::uf") << "pf2->d_node " << pf2->d_node << std::endl;
225     Debug("pf::uf") << "b1.getNumChildren() " << b1.getNumChildren() << std::endl;
226     Debug("pf::uf") << "n1 " << n1 << std::endl;
227     Debug("pf::uf") << "n2 " << n2 << std::endl;
228     Debug("pf::uf") << "side " << side << std::endl;
229     if(pf2->d_node[b1.getNumChildren() - (pf2->d_node.getMetaKind() == kind::metakind::PARAMETERIZED ? 0 : 1)] == n2[side]) {
230       b1 << n2[side];
231       b2 << n2[1-side];
232       out << ss.str();
233     } else {
234       Assert(pf2->d_node[b1.getNumChildren() - (pf2->d_node.getMetaKind() == kind::metakind::PARAMETERIZED ? 0 : 1)] == n2[1-side]);
235       b1 << n2[1-side];
236       b2 << n2[side];
237       out << "(symm _ _ _ " << ss.str() << ")";
238     }
239     out << ")";
240     while(!stk.empty()) {
241       if(tb == 1) {
242         Debug("pf::uf") << "\nMORE TO DO\n";
243       }
244       pf2 = stk.top();
245       stk.pop();
246       Assert(pf2->d_id == theory::eq::MERGED_THROUGH_CONGRUENCE);
247       out << " ";
248       ss.str("");
249       n2 = toStreamRecLFSC(ss, tp, *(pf2->d_children[1]), tb + 1, map);
250       Debug("pf::uf") << "\nok, in cong[" << stk.size() << "]" << "\n";
251       Debug("pf::uf") << "looking at " << pf2->d_node << "\n";
252       Debug("pf::uf") << "           " << n1 << "\n";
253       Debug("pf::uf") << "           " << n2 << "\n";
254       Debug("pf::uf") << "           " << b1 << "\n";
255       Debug("pf::uf") << "           " << b2 << "\n";
256       if(pf2->d_node[b1.getNumChildren()] == n2[side]) {
257         b1 << n2[side];
258         b2 << n2[1-side];
259         out << ss.str();
260       } else {
261         Assert(pf2->d_node[b1.getNumChildren()] == n2[1-side]);
262         b1 << n2[1-side];
263         b2 << n2[side];
264         out << "(symm _ _ _ " << ss.str() << ")";
265       }
266       out << ")";
267     }
268     n1 = b1;
269     n2 = b2;
270     Debug("pf::uf") << "at end assert, got " << pf2->d_node << "  and  " << n1 << std::endl;
271     if(pf2->d_node.getKind() == kind::PARTIAL_APPLY_UF) {
272       Assert(n1 == pf2->d_node);
273     }
274     if(n1.getOperator().getType().getNumChildren() == n1.getNumChildren() + 1) {
275       if(ProofManager::currentPM()->hasOp(n1.getOperator())) {
276         b1.clear(ProofManager::currentPM()->lookupOp(n2.getOperator()).getConst<Kind>());
277       } else {
278         b1.clear(kind::APPLY_UF);
279         b1 << n1.getOperator();
280       }
281       b1.append(n1.begin(), n1.end());
282       n1 = b1;
283       Debug("pf::uf") << "at[2] end assert, got " << pf2->d_node << "  and  " << n1 << std::endl;
284       if(pf2->d_node.getKind() == kind::APPLY_UF) {
285         Assert(n1 == pf2->d_node);
286       }
287     }
288     if(n2.getOperator().getType().getNumChildren() == n2.getNumChildren() + 1) {
289       if(ProofManager::currentPM()->hasOp(n2.getOperator())) {
290         b2.clear(ProofManager::currentPM()->lookupOp(n2.getOperator()).getConst<Kind>());
291       } else {
292         b2.clear(kind::APPLY_UF);
293         b2 << n2.getOperator();
294       }
295       b2.append(n2.begin(), n2.end());
296       n2 = b2;
297     }
298     Node n = (side == 0 ? n1.eqNode(n2) : n2.eqNode(n1));
299     if(tb == 1) {
300       Debug("pf::uf") << "\ncong proved: " << n << "\n";
301     }
302     return n;
303   }
304 
305   case theory::eq::MERGED_THROUGH_REFLEXIVITY:
306   {
307     Assert(!pf.d_node.isNull());
308     Assert(pf.d_children.empty());
309     out << "(refl _ ";
310     tp->printTerm(NodeManager::currentNM()->toExpr(pf.d_node), out, map);
311     out << ")";
312     return pf.d_node.eqNode(pf.d_node);
313   }
314   case theory::eq::MERGED_THROUGH_EQUALITY:
315     Assert(!pf.d_node.isNull());
316     Assert(pf.d_children.empty());
317     out << ProofManager::getLitName(pf.d_node.negate());
318     return pf.d_node;
319 
320   case theory::eq::MERGED_THROUGH_TRANS: {
321     Assert(!pf.d_node.isNull());
322     Assert(pf.d_children.size() >= 2);
323     std::stringstream ss;
324     Debug("pf::uf") << "\ndoing trans proof[[\n";
325     pf.debug_print("pf::uf");
326     Debug("pf::uf") << "\n";
327 
328     pf.d_children[0]->d_node = simplifyBooleanNode(pf.d_children[0]->d_node);
329 
330     Node n1 = toStreamRecLFSC(ss, tp, *(pf.d_children[0]), tb + 1, map);
331     Debug("pf::uf") << "\ndoing trans proof, got n1 " << n1 << "\n";
332     Node n2;
333     if(tb == 1) {
334       Debug("pf::uf") << "\ntrans proof[0], got n1 " << n1 << "\n";
335     }
336 
337     bool identicalEqualities = false;
338     bool evenLengthSequence;
339     std::stringstream dontCare;
340     Node nodeAfterEqualitySequence =
341         toStreamRecLFSC(dontCare, tp, *(pf.d_children[0]), tb + 1, map);
342 
343     std::map<size_t, Node> childToStream;
344     std::stringstream ss1(ss.str()), ss2;
345     std::pair<Node, Node> nodePair;
346     for(size_t i = 1; i < pf.d_children.size(); ++i) {
347       std::stringstream ss1(ss.str()), ss2;
348       ss.str("");
349 
350       pf.d_children[i]->d_node = simplifyBooleanNode(pf.d_children[i]->d_node);
351 
352       // It is possible that we've already converted the i'th child to stream.
353       // If so,
354       // use previously stored result. Otherwise, convert and store.
355       Node n2;
356       if (childToStream.find(i) != childToStream.end())
357         n2 = childToStream[i];
358       else
359       {
360         n2 = toStreamRecLFSC(ss2, tp, *(pf.d_children[i]), tb + 1, map);
361         childToStream[i] = n2;
362       }
363 
364       // The following branch is dedicated to handling sequences of identical
365       // equalities,
366       // i.e. trans[ a=b, a=b, a=b ].
367       //
368       // There are two cases:
369       //    1. The number of equalities is odd. Then, the sequence can be
370       //    collapsed to just one equality,
371       //       i.e. a=b.
372       //    2. The number of equalities is even. Now, we have two options: a=a
373       //    or b=b. To determine this,
374       //       we look at the node after the equality sequence. If it needs a,
375       //       we go for a=a; and if it needs
376       //       b, we go for b=b. If there is no following node, we look at the
377       //       goal of the transitivity proof,
378       //       and use it to determine which option we need.
379       if (n2.getKind() == kind::EQUAL)
380       {
381         if (((n1[0] == n2[0]) && (n1[1] == n2[1]))
382             || ((n1[0] == n2[1]) && (n1[1] == n2[0])))
383         {
384           // We are in a sequence of identical equalities
385 
386           Debug("pf::uf") << "Detected identical equalities: " << std::endl
387                           << "\t" << n1 << std::endl;
388 
389           if (!identicalEqualities)
390           {
391             // The sequence of identical equalities has started just now
392             identicalEqualities = true;
393 
394             Debug("pf::uf")
395                 << "The sequence is just beginning. Determining length..."
396                 << std::endl;
397 
398             // Determine whether the length of this sequence is odd or even.
399             evenLengthSequence = true;
400             bool sequenceOver = false;
401             size_t j = i + 1;
402 
403             while (j < pf.d_children.size() && !sequenceOver)
404             {
405               std::stringstream dontCare;
406               nodeAfterEqualitySequence = toStreamRecLFSC(
407                   dontCare, tp, *(pf.d_children[j]), tb + 1, map);
408 
409               if (((nodeAfterEqualitySequence[0] == n1[0])
410                    && (nodeAfterEqualitySequence[1] == n1[1]))
411                   || ((nodeAfterEqualitySequence[0] == n1[1])
412                       && (nodeAfterEqualitySequence[1] == n1[0])))
413               {
414                 evenLengthSequence = !evenLengthSequence;
415               }
416               else
417               {
418                 sequenceOver = true;
419               }
420 
421               ++j;
422             }
423 
424             nodePair =
425                 tp->identicalEqualitiesPrinterHelper(evenLengthSequence,
426                                                      sequenceOver,
427                                                      pf,
428                                                      map,
429                                                      ss1.str(),
430                                                      &ss,
431                                                      n1,
432                                                      nodeAfterEqualitySequence);
433             n1 = nodePair.first;
434             nodeAfterEqualitySequence = nodePair.second;
435           } else {
436             ss.str(ss1.str());
437           }
438 
439           // Ignore the redundancy.
440           continue;
441         }
442       }
443 
444       if (identicalEqualities) {
445         // We were in a sequence of identical equalities, but it has now ended. Resume normal operation.
446         identicalEqualities = false;
447       }
448 
449       Debug("pf::uf") << "\ndoing trans proof, got n2 " << n2 << "\n";
450       if(tb == 1) {
451         Debug("pf::uf") << "\ntrans proof[" << i << "], got n2 " << n2 << "\n";
452         Debug("pf::uf") << (n2.getKind() == kind::EQUAL) << "\n";
453 
454         if ((n1.getNumChildren() >= 2) && (n2.getNumChildren() >= 2)) {
455           Debug("pf::uf") << n1[0].getId() << " " << n1[1].getId() << " / " << n2[0].getId() << " " << n2[1].getId() << "\n";
456           Debug("pf::uf") << n1[0].getId() << " " << n1[0] << "\n";
457           Debug("pf::uf") << n1[1].getId() << " " << n1[1] << "\n";
458           Debug("pf::uf") << n2[0].getId() << " " << n2[0] << "\n";
459           Debug("pf::uf") << n2[1].getId() << " " << n2[1] << "\n";
460           Debug("pf::uf") << (n1[0] == n2[0]) << "\n";
461           Debug("pf::uf") << (n1[1] == n2[1]) << "\n";
462           Debug("pf::uf") << (n1[0] == n2[1]) << "\n";
463           Debug("pf::uf") << (n1[1] == n2[0]) << "\n";
464         }
465       }
466 
467       ss << "(trans _ _ _ _ ";
468 
469       if(n2.getKind() == kind::EQUAL && n1.getKind() == kind::EQUAL)
470         // Both elements of the transitivity rule are equalities/iffs
471       {
472         if(n1[0] == n2[0]) {
473           if(tb == 1) { Debug("pf::uf") << "case 1\n"; }
474           n1 = n1[1].eqNode(n2[1]);
475           ss << "(symm _ _ _ " << ss1.str() << ") " << ss2.str();
476         } else if(n1[1] == n2[1]) {
477           if(tb == 1) { Debug("pf::uf") << "case 2\n"; }
478           n1 = n1[0].eqNode(n2[0]);
479           ss << ss1.str() << " (symm _ _ _ " << ss2.str() << ")";
480         } else if(n1[0] == n2[1]) {
481           if(tb == 1) { Debug("pf::uf") << "case 3\n"; }
482           n1 = n2[0].eqNode(n1[1]);
483           ss << ss2.str() << " " << ss1.str();
484           if(tb == 1) { Debug("pf::uf") << "++ proved " << n1 << "\n"; }
485         } else if(n1[1] == n2[0]) {
486           if(tb == 1) { Debug("pf::uf") << "case 4\n"; }
487           n1 = n1[0].eqNode(n2[1]);
488           ss << ss1.str() << " " << ss2.str();
489         } else {
490           Warning() << "\n\ntrans proof failure at step " << i << "\n\n";
491           Warning() << "0 proves " << n1 << "\n";
492           Warning() << "1 proves " << n2 << "\n\n";
493           pf.debug_print("pf::uf",0);
494           //toStreamRec(Warning.getStream(), pf, 0);
495           Warning() << "\n\n";
496           Unreachable();
497         }
498         Debug("pf::uf") << "++ trans proof[" << i << "], now have " << n1 << std::endl;
499       } else if(n1.getKind() == kind::EQUAL) {
500         // n1 is an equality/iff, but n2 is a predicate
501         if(n1[0] == n2) {
502           n1 = n1[1].eqNode(NodeManager::currentNM()->mkConst(true));
503           ss << "(symm _ _ _ " << ss1.str() << ") (pred_eq_t _ " << ss2.str() << ")";
504         } else if(n1[1] == n2) {
505           n1 = n1[0].eqNode(NodeManager::currentNM()->mkConst(true));
506           ss << ss1.str() << " (pred_eq_t _ " << ss2.str() << ")";
507         } else {
508           Unreachable();
509         }
510       } else if(n2.getKind() == kind::EQUAL) {
511         // n2 is an equality/iff, but n1 is a predicate
512         if(n2[0] == n1) {
513           n1 = n2[1].eqNode(NodeManager::currentNM()->mkConst(true));
514           ss << "(symm _ _ _ " << ss2.str() << ") (pred_eq_t _ " << ss1.str() << ")";
515         } else if(n2[1] == n1) {
516           n1 = n2[0].eqNode(NodeManager::currentNM()->mkConst(true));
517           ss << ss2.str() << " (pred_eq_t _ " << ss1.str() << ")";
518         } else {
519           Unreachable();
520         }
521       } else {
522         // Both n1 and n2 are predicates.
523         // We want to prove b1 = b2, and we know that ((b1), (b2)) or ((not b1), (not b2))
524         if (n1.getKind() == kind::NOT) {
525           Assert(n2.getKind() == kind::NOT);
526           Assert(pf.d_node[0] == n1[0] || pf.d_node[0] == n2[0]);
527           Assert(pf.d_node[1] == n1[0] || pf.d_node[1] == n2[0]);
528           Assert(n1[0].getKind() == kind::BOOLEAN_TERM_VARIABLE);
529           Assert(n2[0].getKind() == kind::BOOLEAN_TERM_VARIABLE);
530 
531           if (pf.d_node[0] == n1[0]) {
532             ss << "(false_preds_equal _ _ " << ss1.str() << " " << ss2.str() << ") ";
533             ss << "(pred_refl_neg _ " << ss2.str() << ")";
534           } else {
535             ss << "(false_preds_equal _ _ " << ss2.str() << " " << ss1.str() << ") ";
536             ss << "(pred_refl_neg _ " << ss1.str() << ")";
537           }
538           n1 = pf.d_node;
539 
540         } else if (n1.getKind() == kind::BOOLEAN_TERM_VARIABLE) {
541           Assert(n2.getKind() == kind::BOOLEAN_TERM_VARIABLE);
542           Assert(pf.d_node[0] == n1 || pf.d_node[0] == n2);
543           Assert(pf.d_node[1] == n1 || pf.d_node[2] == n2);
544 
545           if (pf.d_node[0] == n1) {
546             ss << "(true_preds_equal _ _ " << ss1.str() << " " << ss2.str() << ") ";
547             ss << "(pred_refl_pos _ " << ss2.str() << ")";
548           } else {
549             ss << "(true_preds_equal _ _ " << ss2.str() << " " << ss1.str() << ") ";
550             ss << "(pred_refl_pos _ " << ss1.str() << ")";
551           }
552           n1 = pf.d_node;
553 
554         } else {
555 
556           Unreachable();
557         }
558       }
559 
560       ss << ")";
561     }
562     out << ss.str();
563     Debug("pf::uf") << "\n++ trans proof done, have proven " << n1 << std::endl;
564     return n1;
565   }
566 
567   default:
568     Assert(!pf.d_node.isNull());
569     Assert(pf.d_children.empty());
570     Debug("pf::uf") << "theory proof: " << pf.d_node << " by rule " << int(pf.d_id) << std::endl;
571     AlwaysAssert(false);
572     return pf.d_node;
573   }
574 }
575 
UFProof(theory::uf::TheoryUF * uf,TheoryProofEngine * pe)576 UFProof::UFProof(theory::uf::TheoryUF* uf, TheoryProofEngine* pe)
577   : TheoryProof(uf, pe)
578 {}
579 
getTheoryId()580 theory::TheoryId UFProof::getTheoryId() { return theory::THEORY_UF; }
registerTerm(Expr term)581 void UFProof::registerTerm(Expr term) {
582   // already registered
583   if (d_declarations.find(term) != d_declarations.end())
584     return;
585 
586   Type type = term.getType();
587   if (type.isSort()) {
588     // declare uninterpreted sorts
589     d_sorts.insert(type);
590   }
591 
592   if (term.getKind() == kind::APPLY_UF) {
593     Expr function = term.getOperator();
594     d_declarations.insert(function);
595   }
596 
597   if (term.isVariable()) {
598     d_declarations.insert(term);
599 
600 
601     if (term.getKind() == kind::BOOLEAN_TERM_VARIABLE) {
602       // Ensure cnf literals
603       Node asNode(term);
604       ProofManager::currentPM()->ensureLiteral(
605           asNode.eqNode(NodeManager::currentNM()->mkConst(true)));
606       ProofManager::currentPM()->ensureLiteral(
607           asNode.eqNode(NodeManager::currentNM()->mkConst(false)));
608     }
609   }
610 
611   // recursively declare all other terms
612   for (unsigned i = 0; i < term.getNumChildren(); ++i) {
613     // could belong to other theories
614     d_proofEngine->registerTerm(term[i]);
615   }
616 }
617 
printOwnedTerm(Expr term,std::ostream & os,const ProofLetMap & map)618 void LFSCUFProof::printOwnedTerm(Expr term, std::ostream& os, const ProofLetMap& map) {
619   Debug("pf::uf") << std::endl << "(pf::uf) LFSCUfProof::printOwnedTerm: term = " << term << std::endl;
620 
621   Assert (theory::Theory::theoryOf(term) == theory::THEORY_UF);
622 
623   if (term.getKind() == kind::VARIABLE ||
624       term.getKind() == kind::SKOLEM ||
625       term.getKind() == kind::BOOLEAN_TERM_VARIABLE) {
626     os << term;
627     return;
628   }
629 
630   Assert (term.getKind() == kind::APPLY_UF);
631 
632   if(term.getType().isBoolean()) {
633     os << "(p_app ";
634   }
635   Expr func = term.getOperator();
636   for (unsigned i = 0; i < term.getNumChildren(); ++i) {
637     os << "(apply _ _ ";
638   }
639   os << func << " ";
640   for (unsigned i = 0; i < term.getNumChildren(); ++i) {
641 
642     bool convertToBool = (term[i].getType().isBoolean() && !d_proofEngine->printsAsBool(term[i]));
643     if (convertToBool) os << "(f_to_b ";
644     d_proofEngine->printBoundTerm(term[i], os, map);
645     if (convertToBool) os << ")";
646     os << ")";
647   }
648   if(term.getType().isBoolean()) {
649     os << ")";
650   }
651 }
652 
printOwnedSort(Type type,std::ostream & os)653 void LFSCUFProof::printOwnedSort(Type type, std::ostream& os) {
654   Debug("pf::uf") << std::endl << "(pf::uf) LFSCArrayProof::printOwnedSort: type is: " << type << std::endl;
655 
656   Assert (type.isSort());
657   os << type;
658 }
659 
printTheoryLemmaProof(std::vector<Expr> & lemma,std::ostream & os,std::ostream & paren,const ProofLetMap & map)660 void LFSCUFProof::printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren, const ProofLetMap& map) {
661   os << " ;; UF Theory Lemma \n;;";
662   for (unsigned i = 0; i < lemma.size(); ++i) {
663     os << lemma[i] <<" ";
664   }
665   os <<"\n";
666   //os << " (clausify_false trust)";
667   UFProof::printTheoryLemmaProof(lemma, os, paren, map);
668 }
669 
printSortDeclarations(std::ostream & os,std::ostream & paren)670 void LFSCUFProof::printSortDeclarations(std::ostream& os, std::ostream& paren) {
671   for (TypeSet::const_iterator it = d_sorts.begin(); it != d_sorts.end(); ++it) {
672     if (!ProofManager::currentPM()->wasPrinted(*it)) {
673       os << "(% " << *it << " sort\n";
674       paren << ")";
675       ProofManager::currentPM()->markPrinted(*it);
676     }
677   }
678 }
679 
printTermDeclarations(std::ostream & os,std::ostream & paren)680 void LFSCUFProof::printTermDeclarations(std::ostream& os, std::ostream& paren) {
681   // declaring the terms
682   Debug("pf::uf") << "LFSCUFProof::printTermDeclarations called" << std::endl;
683 
684   for (ExprSet::const_iterator it = d_declarations.begin(); it != d_declarations.end(); ++it) {
685     Expr term = *it;
686 
687     os << "(% " << ProofManager::sanitize(term) << " ";
688     os << "(term ";
689 
690     Type type = term.getType();
691     if (type.isFunction()) {
692       std::ostringstream fparen;
693       FunctionType ftype = (FunctionType)type;
694       std::vector<Type> args = ftype.getArgTypes();
695       args.push_back(ftype.getRangeType());
696       os << "(arrow";
697       for (unsigned i = 0; i < args.size(); i++) {
698         Type arg_type = args[i];
699         os << " ";
700         d_proofEngine->printSort(arg_type, os);
701         if (i < args.size() - 2) {
702           os << " (arrow";
703           fparen << ")";
704         }
705       }
706       os << fparen.str() << "))\n";
707     } else {
708       Assert (term.isVariable());
709       os << type << ")\n";
710     }
711     paren << ")";
712   }
713 
714   Debug("pf::uf") << "LFSCUFProof::printTermDeclarations done" << std::endl;
715 }
716 
printDeferredDeclarations(std::ostream & os,std::ostream & paren)717 void LFSCUFProof::printDeferredDeclarations(std::ostream& os, std::ostream& paren) {
718   // Nothing to do here at this point.
719 }
720 
printAliasingDeclarations(std::ostream & os,std::ostream & paren,const ProofLetMap & globalLetMap)721 void LFSCUFProof::printAliasingDeclarations(std::ostream& os, std::ostream& paren, const ProofLetMap &globalLetMap) {
722   // Nothing to do here at this point.
723 }
724 
printsAsBool(const Node & n)725 bool LFSCUFProof::printsAsBool(const Node &n) {
726   if (n.getKind() == kind::BOOLEAN_TERM_VARIABLE)
727     return true;
728 
729   return false;
730 }
731 
printConstantDisequalityProof(std::ostream & os,Expr c1,Expr c2,const ProofLetMap & globalLetMap)732 void LFSCUFProof::printConstantDisequalityProof(std::ostream& os, Expr c1, Expr c2, const ProofLetMap &globalLetMap) {
733   Node falseNode = NodeManager::currentNM()->mkConst(false);
734   Node trueNode = NodeManager::currentNM()->mkConst(true);
735 
736   Assert(c1 == falseNode.toExpr() || c1 == trueNode.toExpr());
737   Assert(c2 == falseNode.toExpr() || c2 == trueNode.toExpr());
738   Assert(c1 != c2);
739 
740   if (c1 == trueNode.toExpr())
741     os << "t_t_neq_f";
742   else
743     os << "(symm _ _ _ t_t_neq_f)";
744 }
745 
746 } /* namespace CVC4 */
747