GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/datatypes/infer_proof_cons.cpp Lines: 110 143 76.9 %
Date: 2021-08-19 Branches: 296 891 33.2 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Gereon Kremer, Aina Niemetz
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
 * Implementation of inference to proof conversion  for datatypes.
14
 */
15
16
#include "theory/datatypes/infer_proof_cons.h"
17
18
#include "proof/proof.h"
19
#include "proof/proof_checker.h"
20
#include "theory/datatypes/theory_datatypes_utils.h"
21
#include "theory/model_manager.h"
22
#include "theory/rewriter.h"
23
#include "util/rational.h"
24
25
using namespace cvc5::kind;
26
27
namespace cvc5 {
28
namespace theory {
29
namespace datatypes {
30
31
2209
InferProofCons::InferProofCons(context::Context* c, ProofNodeManager* pnm)
32
2209
    : d_pnm(pnm), d_lazyFactMap(c == nullptr ? &d_context : c)
33
{
34
2209
  Assert(d_pnm != nullptr);
35
2209
}
36
37
11263
void InferProofCons::notifyFact(const std::shared_ptr<DatatypesInference>& di)
38
{
39
22475
  TNode fact = di->d_conc;
40
11263
  if (d_lazyFactMap.find(fact) != d_lazyFactMap.end())
41
  {
42
48
    return;
43
  }
44
22427
  Node symFact = CDProof::getSymmFact(fact);
45
11215
  if (!symFact.isNull() && d_lazyFactMap.find(symFact) != d_lazyFactMap.end())
46
  {
47
3
    return;
48
  }
49
11212
  d_lazyFactMap.insert(fact, di);
50
}
51
52
6307
void InferProofCons::convert(InferenceId infer, TNode conc, TNode exp, CDProof* cdp)
53
{
54
12614
  Trace("dt-ipc") << "convert: " << infer << ": " << conc << " by " << exp
55
6307
                  << std::endl;
56
  // split into vector
57
12614
  std::vector<Node> expv;
58
6307
  if (!exp.isNull() && !exp.isConst())
59
  {
60
4967
    if (exp.getKind() == AND)
61
    {
62
331
      for (const Node& ec : exp)
63
      {
64
242
        expv.push_back(ec);
65
      }
66
    }
67
    else
68
    {
69
4878
      expv.push_back(exp);
70
    }
71
  }
72
6307
  NodeManager* nm = NodeManager::currentNM();
73
6307
  bool success = false;
74
6307
  switch (infer)
75
  {
76
781
    case InferenceId::DATATYPES_UNIF:
77
    {
78
781
      Assert(expv.size() == 1);
79
781
      Assert(exp.getKind() == EQUAL && exp[0].getKind() == APPLY_CONSTRUCTOR
80
             && exp[1].getKind() == APPLY_CONSTRUCTOR
81
             && exp[0].getOperator() == exp[1].getOperator());
82
1562
      Node narg;
83
      // we may be asked for a proof of (not P) coming from (= P false) or
84
      // (= false P), or similarly P from (= P true) or (= true P).
85
781
      bool concPol = conc.getKind() != NOT;
86
1562
      Node concAtom = concPol ? conc : conc[0];
87
1562
      Node unifConc = conc;
88
1285
      for (size_t i = 0, nchild = exp[0].getNumChildren(); i < nchild; i++)
89
      {
90
1284
        bool argSuccess = false;
91
1284
        if (conc.getKind() == EQUAL)
92
        {
93
1284
          argSuccess = (exp[0][i] == conc[0] && exp[1][i] == conc[1]);
94
        }
95
        else
96
        {
97
          for (size_t j = 0; j < 2; j++)
98
          {
99
            if (exp[j][i] == concAtom && exp[1 - j][i].isConst()
100
                && exp[1 - j][i].getConst<bool>() == concPol)
101
            {
102
              argSuccess = true;
103
              unifConc = exp[0][i].eqNode(exp[1][i]);
104
              break;
105
            }
106
          }
107
        }
108
1284
        if (argSuccess)
109
        {
110
780
          narg = nm->mkConst(Rational(i));
111
780
          break;
112
        }
113
      }
114
781
      if (!narg.isNull())
115
      {
116
780
        if (conc.getKind() == EQUAL)
117
        {
118
          // normal case where we conclude an equality
119
780
          cdp->addStep(conc, PfRule::DT_UNIF, {exp}, {narg});
120
        }
121
        else
122
        {
123
          // must use true or false elim to prove the final
124
          cdp->addStep(unifConc, PfRule::DT_UNIF, {exp}, {narg});
125
          // may use symmetry
126
          Node eq = concAtom.eqNode(nm->mkConst(concPol));
127
          cdp->addStep(
128
              conc, concPol ? PfRule::TRUE_ELIM : PfRule::FALSE_ELIM, {eq}, {});
129
        }
130
780
        success = true;
131
781
      }
132
    }
133
781
    break;
134
2950
    case InferenceId::DATATYPES_INST:
135
    {
136
2950
      if (expv.size() == 1)
137
      {
138
2673
        Assert(conc.getKind() == EQUAL);
139
2673
        int n = utils::isTester(exp);
140
2673
        if (n >= 0)
141
        {
142
5346
          Node t = exp[0];
143
5346
          Node nn = nm->mkConst(Rational(n));
144
5346
          Node eq = exp.eqNode(conc);
145
2673
          cdp->addStep(eq, PfRule::DT_INST, {}, {t, nn});
146
2673
          cdp->addStep(conc, PfRule::EQ_RESOLVE, {exp, eq}, {});
147
2673
          success = true;
148
        }
149
      }
150
    }
151
2950
    break;
152
1063
    case InferenceId::DATATYPES_SPLIT:
153
    {
154
1063
      Assert(expv.empty());
155
2126
      Node t = conc.getKind() == OR ? conc[0][0] : conc[0];
156
1063
      cdp->addStep(conc, PfRule::DT_SPLIT, {}, {t});
157
2126
      success = true;
158
    }
159
1063
    break;
160
1202
    case InferenceId::DATATYPES_COLLAPSE_SEL:
161
    {
162
1202
      Assert(exp.getKind() == EQUAL);
163
2404
      Node concEq = conc;
164
      // might be a Boolean conclusion
165
1202
      if (conc.getKind() != EQUAL)
166
      {
167
        bool concPol = conc.getKind() != NOT;
168
        Node concAtom = concPol ? conc : conc[0];
169
        concEq = concAtom.eqNode(nm->mkConst(concPol));
170
      }
171
1202
      Assert(concEq.getKind() == EQUAL
172
             && concEq[0].getKind() == APPLY_SELECTOR_TOTAL);
173
1202
      Assert(exp[0].getType().isDatatype());
174
2404
      Node sop = concEq[0].getOperator();
175
2404
      Node sl = nm->mkNode(APPLY_SELECTOR_TOTAL, sop, exp[0]);
176
2404
      Node sr = nm->mkNode(APPLY_SELECTOR_TOTAL, sop, exp[1]);
177
      // exp[0] = exp[1]
178
      // --------------------- CONG        ----------------- DT_COLLAPSE
179
      // s(exp[0]) = s(exp[1])             s(exp[1]) = r
180
      // --------------------------------------------------- TRANS
181
      // s(exp[0]) = r
182
2404
      Node asn = ProofRuleChecker::mkKindNode(APPLY_SELECTOR_TOTAL);
183
2404
      Node seq = sl.eqNode(sr);
184
1202
      cdp->addStep(seq, PfRule::CONG, {exp}, {asn, sop});
185
2404
      Node sceq = sr.eqNode(concEq[1]);
186
1202
      cdp->addStep(sceq, PfRule::DT_COLLAPSE, {}, {sr});
187
1202
      cdp->addStep(sl.eqNode(concEq[1]), PfRule::TRANS, {seq, sceq}, {});
188
1202
      if (conc.getKind() != EQUAL)
189
      {
190
        PfRule eid =
191
            conc.getKind() == NOT ? PfRule::FALSE_ELIM : PfRule::TRUE_ELIM;
192
        cdp->addStep(conc, eid, {concEq}, {});
193
      }
194
2404
      success = true;
195
    }
196
1202
    break;
197
100
    case InferenceId::DATATYPES_CLASH_CONFLICT:
198
    {
199
100
      cdp->addStep(conc, PfRule::MACRO_SR_PRED_ELIM, {exp}, {});
200
100
      success = true;
201
    }
202
100
    break;
203
66
    case InferenceId::DATATYPES_TESTER_CONFLICT:
204
    {
205
      // rewrites to false under substitution
206
132
      Node fn = nm->mkConst(false);
207
66
      cdp->addStep(fn, PfRule::MACRO_SR_PRED_ELIM, expv, {});
208
132
      success = true;
209
    }
210
66
    break;
211
    case InferenceId::DATATYPES_TESTER_MERGE_CONFLICT:
212
    {
213
      Assert(expv.size() == 3);
214
      Node tester1 = expv[0];
215
      Node tester1c =
216
          nm->mkNode(APPLY_TESTER, expv[1].getOperator(), expv[0][0]);
217
      cdp->addStep(tester1c,
218
                   PfRule::MACRO_SR_PRED_TRANSFORM,
219
                   {expv[1], expv[2]},
220
                   {tester1c});
221
      Node fn = nm->mkConst(false);
222
      cdp->addStep(fn, PfRule::DT_CLASH, {tester1, tester1c}, {});
223
      success = true;
224
    }
225
    break;
226
    case InferenceId::DATATYPES_PURIFY:
227
    {
228
      cdp->addStep(conc, PfRule::MACRO_SR_PRED_INTRO, {}, {});
229
      success = true;
230
    }
231
    break;
232
    // inferences currently not supported
233
145
    case InferenceId::DATATYPES_LABEL_EXH:
234
    case InferenceId::DATATYPES_BISIMILAR:
235
    case InferenceId::DATATYPES_CYCLE:
236
    default:
237
290
      Trace("dt-ipc") << "...no conversion for inference " << infer
238
145
                      << std::endl;
239
145
      break;
240
  }
241
242
6307
  if (!success)
243
  {
244
    // failed to reconstruct, add trust
245
423
    Trace("dt-ipc") << "...failed " << infer << std::endl;
246
423
    cdp->addStep(conc, PfRule::DT_TRUST, expv, {conc});
247
  }
248
  else
249
  {
250
5884
    Trace("dt-ipc") << "...success" << std::endl;
251
  }
252
6307
}
253
254
6307
std::shared_ptr<ProofNode> InferProofCons::getProofFor(Node fact)
255
{
256
6307
  Trace("dt-ipc") << "dt-ipc: Ask proof for " << fact << std::endl;
257
  // temporary proof
258
12614
  CDProof pf(d_pnm);
259
  // get the inference
260
6307
  NodeDatatypesInferenceMap::iterator it = d_lazyFactMap.find(fact);
261
6307
  if (it == d_lazyFactMap.end())
262
  {
263
    Node factSym = CDProof::getSymmFact(fact);
264
    if (!factSym.isNull())
265
    {
266
      // Use the symmetric fact. There is no need to explictly make a
267
      // SYMM proof, as this is handled by CDProof::getProofFor below.
268
      it = d_lazyFactMap.find(factSym);
269
    }
270
  }
271
6307
  AlwaysAssert(it != d_lazyFactMap.end());
272
  // now go back and convert it to proof steps and add to proof
273
12614
  std::shared_ptr<DatatypesInference> di = (*it).second;
274
  // run the conversion
275
6307
  convert(di->getId(), di->d_conc, di->d_exp, &pf);
276
12614
  return pf.getProofFor(fact);
277
}
278
279
14818
std::string InferProofCons::identify() const
280
{
281
14818
  return "datatypes::InferProofCons";
282
}
283
284
}  // namespace datatypes
285
}  // namespace theory
286
29349
}  // namespace cvc5