GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/ho_term_database.cpp Lines: 106 121 87.6 %
Date: 2021-09-29 Branches: 202 430 47.0 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds
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 higher-order term database class.
14
 */
15
16
#include "theory/quantifiers/ho_term_database.h"
17
18
#include "expr/skolem_manager.h"
19
#include "options/quantifiers_options.h"
20
#include "theory/quantifiers/quantifiers_inference_manager.h"
21
#include "theory/quantifiers/quantifiers_state.h"
22
#include "theory/rewriter.h"
23
#include "theory/uf/equality_engine.h"
24
25
using namespace cvc5::kind;
26
27
namespace cvc5 {
28
namespace theory {
29
namespace quantifiers {
30
31
120
HoTermDb::HoTermDb(Env& env, QuantifiersState& qs, QuantifiersRegistry& qr)
32
120
    : TermDb(env, qs, qr)
33
{
34
120
}
35
36
238
HoTermDb::~HoTermDb() {}
37
38
38566
void HoTermDb::addTermInternal(Node n)
39
{
40
38566
  if (n.getType().isFunction())
41
  {
42
    // nothing special to do with functions
43
285
    return;
44
  }
45
38281
  NodeManager* nm = NodeManager::currentNM();
46
38281
  SkolemManager* sm = nm->getSkolemManager();
47
76562
  Node curr = n;
48
76562
  std::vector<Node> args;
49
86703
  while (curr.getKind() == HO_APPLY)
50
  {
51
24211
    args.insert(args.begin(), curr[1]);
52
24211
    curr = curr[0];
53
24211
    if (!curr.isVar())
54
    {
55
      // purify the term
56
12086
      std::map<Node, Node>::iterator itp = d_hoFunOpPurify.find(curr);
57
24172
      Node psk;
58
12086
      if (itp == d_hoFunOpPurify.end())
59
      {
60
126
        psk = sm->mkPurifySkolem(
61
            curr, "pfun", "purify for function operator term indexing");
62
126
        d_hoFunOpPurify[curr] = psk;
63
        // we do not add it to d_ops since it is an internal operator
64
      }
65
      else
66
      {
67
11960
        psk = itp->second;
68
      }
69
24172
      std::vector<Node> children;
70
12086
      children.push_back(psk);
71
12086
      children.insert(children.end(), args.begin(), args.end());
72
24172
      Node p_n = nm->mkNode(APPLY_UF, children);
73
24172
      Trace("term-db") << "register term in db (via purify) " << p_n
74
12086
                       << std::endl;
75
      // also add this one internally
76
12086
      DbList* dblp = getOrMkDbListForOp(psk);
77
12086
      dblp->d_list.push_back(p_n);
78
      // maintain backwards mapping
79
12086
      d_hoPurifyToTerm[p_n] = n;
80
    }
81
  }
82
38281
  if (!args.empty() && curr.isVar())
83
  {
84
    // also add standard application version
85
12125
    args.insert(args.begin(), curr);
86
24250
    Node uf_n = nm->mkNode(APPLY_UF, args);
87
12125
    addTerm(uf_n);
88
  }
89
}
90
91
2114
void HoTermDb::getOperatorsFor(TNode f, std::vector<TNode>& ops)
92
{
93
2114
  ops.push_back(f);
94
2114
  ops.insert(ops.end(), d_hoOpSlaves[f].begin(), d_hoOpSlaves[f].end());
95
2114
}
96
97
189580
Node HoTermDb::getOperatorRepresentative(TNode op) const
98
{
99
189580
  std::map<TNode, TNode>::const_iterator it = d_hoOpRep.find(op);
100
189580
  if (it != d_hoOpRep.end())
101
  {
102
175517
    return it->second;
103
  }
104
14063
  return op;
105
}
106
107
691
bool HoTermDb::resetInternal(Theory::Effort effort)
108
{
109
1382
  Trace("quant-ho")
110
691
      << "HoTermDb::reset : assert higher-order purify equalities..."
111
691
      << std::endl;
112
691
  eq::EqualityEngine* ee = d_qstate.getEqualityEngine();
113
11672
  for (std::pair<const Node, Node>& pp : d_hoPurifyToTerm)
114
  {
115
32943
    if (ee->hasTerm(pp.second)
116
32943
        && (!ee->hasTerm(pp.first) || !ee->areEqual(pp.second, pp.first)))
117
    {
118
14558
      Node eq;
119
7279
      std::map<Node, Node>::iterator itpe = d_hoPurifyToEq.find(pp.first);
120
7279
      if (itpe == d_hoPurifyToEq.end())
121
      {
122
441
        eq = Rewriter::rewrite(pp.first.eqNode(pp.second));
123
441
        d_hoPurifyToEq[pp.first] = eq;
124
      }
125
      else
126
      {
127
6838
        eq = itpe->second;
128
      }
129
7279
      Trace("quant-ho") << "- assert purify equality : " << eq << std::endl;
130
      // Note that ee may be the central equality engine, in which case this
131
      // equality is explained trivially with "true", since both sides of
132
      // eq are HOL and FOL encodings of the same thing.
133
7279
      ee->assertEquality(eq, true, d_true);
134
7279
      if (!ee->consistent())
135
      {
136
        // In some rare cases, purification functions (in the domain of
137
        // d_hoPurifyToTerm) may escape the term database. For example,
138
        // matching algorithms may construct instantiations involving these
139
        // functions. As a result, asserting these equalities internally may
140
        // cause a conflict. In this case, we insist that the purification
141
        // equality is sent out as a lemma here.
142
        Trace("term-db-lemma") << "Purify equality lemma: " << eq << std::endl;
143
        d_qim->addPendingLemma(eq, InferenceId::QUANTIFIERS_HO_PURIFY);
144
        d_qstate.notifyInConflict();
145
        d_consistent_ee = false;
146
        return false;
147
      }
148
    }
149
  }
150
691
  return true;
151
}
152
153
691
bool HoTermDb::finishResetInternal(Theory::Effort effort)
154
{
155
691
  if (!options().quantifiers.hoMergeTermDb)
156
  {
157
    return true;
158
  }
159
1382
  Trace("quant-ho") << "HoTermDb::reset : compute equal functions..."
160
691
                    << std::endl;
161
  // build operator representative map
162
691
  d_hoOpRep.clear();
163
691
  d_hoOpSlaves.clear();
164
691
  eq::EqualityEngine* ee = d_qstate.getEqualityEngine();
165
691
  eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(ee);
166
74635
  while (!eqcs_i.isFinished())
167
  {
168
73944
    TNode r = (*eqcs_i);
169
36972
    if (r.getType().isFunction())
170
    {
171
2388
      Trace("quant-ho") << "  process function eqc " << r << std::endl;
172
4776
      Node first;
173
2388
      eq::EqClassIterator eqc_i = eq::EqClassIterator(r, ee);
174
10374
      while (!eqc_i.isFinished())
175
      {
176
7986
        TNode n = (*eqc_i);
177
7986
        Node n_use;
178
3993
        if (n.isVar())
179
        {
180
2651
          n_use = n;
181
        }
182
        else
183
        {
184
          // use its purified variable, if it exists
185
1342
          std::map<Node, Node>::iterator itp = d_hoFunOpPurify.find(n);
186
1342
          if (itp != d_hoFunOpPurify.end())
187
          {
188
1299
            n_use = itp->second;
189
          }
190
        }
191
7986
        Trace("quant-ho") << "  - process " << n_use << ", from " << n
192
3993
                          << std::endl;
193
3993
        if (!n_use.isNull() && d_opMap.find(n_use) != d_opMap.end())
194
        {
195
3310
          if (first.isNull())
196
          {
197
2038
            first = n_use;
198
2038
            d_hoOpRep[n_use] = n_use;
199
          }
200
          else
201
          {
202
2544
            Trace("quant-ho") << "  have : " << n_use << " == " << first
203
1272
                              << ", type = " << n_use.getType() << std::endl;
204
1272
            d_hoOpRep[n_use] = first;
205
1272
            d_hoOpSlaves[first].push_back(n_use);
206
          }
207
        }
208
3993
        ++eqc_i;
209
      }
210
    }
211
36972
    ++eqcs_i;
212
  }
213
691
  Trace("quant-ho") << "...finished compute equal functions." << std::endl;
214
215
691
  return true;
216
}
217
3477
bool HoTermDb::checkCongruentDisequal(TNode a, TNode b, std::vector<Node>& exp)
218
{
219
3477
  if (!d_qstate.areDisequal(a, b))
220
  {
221
3477
    return false;
222
  }
223
  exp.push_back(a.eqNode(b));
224
  // operators might be disequal
225
  Node af = getMatchOperator(a);
226
  Node bf = getMatchOperator(b);
227
  if (af != bf)
228
  {
229
    if (a.getKind() == APPLY_UF && b.getKind() == APPLY_UF)
230
    {
231
      exp.push_back(af.eqNode(bf).negate());
232
    }
233
    else
234
    {
235
      Assert(false);
236
      return false;
237
    }
238
  }
239
  return true;
240
}
241
242
43
Node HoTermDb::getHoTypeMatchPredicate(TypeNode tn)
243
{
244
43
  NodeManager* nm = NodeManager::currentNM();
245
43
  SkolemManager* sm = nm->getSkolemManager();
246
86
  TypeNode ptn = nm->mkFunctionType(tn, nm->booleanType());
247
86
  return sm->mkSkolemFunction(SkolemFunId::HO_TYPE_MATCH_PRED, ptn);
248
}
249
250
}  // namespace quantifiers
251
}  // namespace theory
252
22746
}  // namespace cvc5