GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/candidate_rewrite_filter.cpp Lines: 115 126 91.3 %
Date: 2021-11-07 Branches: 255 596 42.8 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Mathias Preiner, 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
 * Implements techniques for candidate rewrite rule filtering, which
14
 * filters the output of --sygus-rr-synth. The classes in this file implement
15
 * filtering based on congruence, variable ordering, and matching.
16
 */
17
18
#include "theory/quantifiers/candidate_rewrite_filter.h"
19
20
#include "options/base_options.h"
21
#include "options/quantifiers_options.h"
22
#include "printer/printer.h"
23
24
using namespace cvc5::kind;
25
26
namespace cvc5 {
27
namespace theory {
28
namespace quantifiers {
29
30
// the number of d_drewrite objects we have allocated (to avoid name conflicts)
31
static unsigned drewrite_counter = 0;
32
33
71
CandidateRewriteFilter::CandidateRewriteFilter(Env& env)
34
    : EnvObj(env),
35
      d_ss(nullptr),
36
      d_tds(nullptr),
37
      d_use_sygus_type(false),
38
      d_drewrite(nullptr),
39
71
      d_ssenm(*this)
40
{
41
71
}
42
43
8
void CandidateRewriteFilter::initialize(SygusSampler* ss,
44
                                        TermDbSygus* tds,
45
                                        bool useSygusType)
46
{
47
8
  d_ss = ss;
48
8
  d_use_sygus_type = useSygusType;
49
8
  d_tds = tds;
50
  // initialize members of this class
51
8
  d_match_trie.clear();
52
8
  d_pairs.clear();
53
  // (re)initialize the dynamic rewriter
54
16
  std::stringstream ssn;
55
8
  ssn << "_dyn_rewriter_" << drewrite_counter;
56
8
  drewrite_counter++;
57
8
  d_drewrite =
58
16
      std::make_unique<DynamicRewriter>(d_env, &d_fakeContext, ssn.str());
59
8
}
60
61
310
bool CandidateRewriteFilter::filterPair(Node n, Node eq_n)
62
{
63
620
  Node bn = n;
64
620
  Node beq_n = eq_n;
65
310
  if (d_use_sygus_type)
66
  {
67
310
    bn = d_tds->sygusToBuiltin(n);
68
310
    beq_n = d_tds->sygusToBuiltin(eq_n);
69
  }
70
620
  Trace("cr-filter") << "crewriteFilter : " << bn << "..." << beq_n
71
310
                     << std::endl;
72
  // whether we will keep this pair
73
310
  bool keep = true;
74
75
  // ----- check redundancy based on variables
76
620
  if (options().quantifiers.sygusRewSynthFilterOrder
77
310
      || options().quantifiers.sygusRewSynthFilterNonLinear)
78
  {
79
1240
    bool nor = d_ss->checkVariables(
80
        bn,
81
310
        options().quantifiers.sygusRewSynthFilterOrder,
82
620
        options().quantifiers.sygusRewSynthFilterNonLinear);
83
1240
    bool eqor = d_ss->checkVariables(
84
        beq_n,
85
310
        options().quantifiers.sygusRewSynthFilterOrder,
86
620
        options().quantifiers.sygusRewSynthFilterNonLinear);
87
620
    Trace("cr-filter-debug")
88
310
        << "Variables ok? : " << nor << " " << eqor << std::endl;
89
310
    if (eqor || nor)
90
    {
91
      // if only one is ordered, then we require that the ordered one's
92
      // variables cannot be a strict subset of the variables of the other.
93
478
      if (!eqor)
94
      {
95
4
        if (d_ss->containsFreeVariables(beq_n, bn, true))
96
        {
97
1
          keep = false;
98
        }
99
        else
100
        {
101
          // if the previous value stored was unordered, but n is
102
          // ordered, we prefer n. Thus, we force its addition to the
103
          // sampler database.
104
3
          d_ss->registerTerm(n, true);
105
        }
106
      }
107
235
      else if (!nor)
108
      {
109
80
        keep = !d_ss->containsFreeVariables(bn, beq_n, true);
110
      }
111
    }
112
    else
113
    {
114
71
      keep = false;
115
    }
116
310
    if (!keep)
117
    {
118
142
      Trace("cr-filter") << "...redundant (unordered)" << std::endl;
119
    }
120
  }
121
122
  // ----- check rewriting redundancy
123
310
  if (keep && options().quantifiers.sygusRewSynthFilterCong)
124
  {
125
    // When using sygus types, this filtering applies to the builtin versions
126
    // of n and eq_n. This means that we may filter out a rewrite rule for one
127
    // sygus type based on another, e.g. we won't report x=x+0 for both A and B
128
    // in:
129
    //   A -> x | 0 | A+A
130
    //   B -> x | 0 | B+B
131
168
    Trace("cr-filter-debug") << "Check equal rewrite pair..." << std::endl;
132
168
    if (d_drewrite->areEqual(bn, beq_n))
133
    {
134
      // must be unique according to the dynamic rewriter
135
3
      Trace("cr-filter") << "...redundant (rewritable)" << std::endl;
136
3
      keep = false;
137
    }
138
  }
139
140
310
  if (keep && options().quantifiers.sygusRewSynthFilterMatch)
141
  {
142
    // ----- check matchable
143
    // check whether the pair is matchable with a previous one
144
165
    d_curr_pair_rhs = beq_n;
145
330
    Trace("crf-match") << "CRF check matches : " << bn << " [rhs = " << beq_n
146
165
                       << "]..." << std::endl;
147
330
    Node bni = d_drewrite->toInternal(bn);
148
165
    if (!bni.isNull())
149
    {
150
      // as with congruence filtering, we cache based on the builtin type
151
330
      TypeNode tn = bn.getType();
152
165
      if (!d_match_trie[tn].getMatches(bni, &d_ssenm))
153
      {
154
3
        keep = false;
155
3
        Trace("cr-filter") << "...redundant (matchable)" << std::endl;
156
        // regardless, would help to remember it
157
3
        registerRelevantPair(n, eq_n);
158
      }
159
    }
160
    // if bni is null, it may involve non-first-class types that we cannot
161
    // reason about
162
  }
163
164
310
  if (keep)
165
  {
166
162
    return false;
167
  }
168
148
  if (Trace.isOn("sygus-rr-filter"))
169
  {
170
    std::stringstream ss;
171
    ss << "(redundant-rewrite ";
172
    TermDbSygus::toStreamSygus(ss, n);
173
    ss << " ";
174
    TermDbSygus::toStreamSygus(ss, eq_n);
175
    ss << ")";
176
    Trace("sygus-rr-filter") << ss.str() << std::endl;
177
  }
178
148
  return true;
179
}
180
181
149
void CandidateRewriteFilter::registerRelevantPair(Node n, Node eq_n)
182
{
183
298
  Node bn = n;
184
298
  Node beq_n = eq_n;
185
149
  if (d_use_sygus_type)
186
  {
187
149
    bn = d_tds->sygusToBuiltin(n);
188
149
    beq_n = d_tds->sygusToBuiltin(eq_n);
189
  }
190
  // ----- check rewriting redundancy
191
149
  if (options().quantifiers.sygusRewSynthFilterCong)
192
  {
193
149
    Trace("cr-filter-debug") << "Add rewrite pair..." << std::endl;
194
149
    Assert(!d_drewrite->areEqual(bn, beq_n));
195
149
    d_drewrite->addRewrite(bn, beq_n);
196
  }
197
149
  if (options().quantifiers.sygusRewSynthFilterMatch)
198
  {
199
    // cache based on the builtin type
200
298
    TypeNode tn = bn.getType();
201
    // add to match information
202
447
    for (unsigned r = 0; r < 2; r++)
203
    {
204
596
      Node t = r == 0 ? bn : beq_n;
205
596
      Node to = r == 0 ? beq_n : bn;
206
      // insert in match trie if first time
207
298
      if (d_pairs.find(t) == d_pairs.end())
208
      {
209
210
        Trace("crf-match") << "CRF add term : " << t << std::endl;
210
420
        Node ti = d_drewrite->toInternal(t);
211
210
        if (!ti.isNull())
212
        {
213
210
          d_match_trie[tn].addTerm(ti);
214
        }
215
      }
216
298
      d_pairs[t].insert(to);
217
    }
218
  }
219
149
}
220
221
120
bool CandidateRewriteFilter::notify(Node s,
222
                                    Node n,
223
                                    std::vector<Node>& vars,
224
                                    std::vector<Node>& subs)
225
{
226
120
  Trace("crf-match-debug") << "Got : " << s << " matches " << n << std::endl;
227
120
  Assert(!d_curr_pair_rhs.isNull());
228
  // convert back to original forms
229
120
  s = d_drewrite->toExternal(s);
230
120
  Assert(!s.isNull());
231
120
  n = d_drewrite->toExternal(n);
232
120
  Assert(!n.isNull());
233
120
  std::map<Node, std::unordered_set<Node> >::iterator it = d_pairs.find(n);
234
120
  if (Trace.isOn("crf-match"))
235
  {
236
    Trace("crf-match") << "  " << s << " matches " << n
237
                       << " under:" << std::endl;
238
    for (unsigned i = 0, size = vars.size(); i < size; i++)
239
    {
240
      Trace("crf-match") << "    " << vars[i] << " -> " << subs[i] << std::endl;
241
    }
242
  }
243
#ifdef CVC5_ASSERTIONS
244
246
  for (unsigned i = 0, size = vars.size(); i < size; i++)
245
  {
246
    // By using internal representation of terms, we ensure polymorphism is
247
    // handled correctly.
248
126
    Assert(vars[i].getType().isComparableTo(subs[i].getType()));
249
  }
250
#endif
251
  // must convert the inferred substitution to original form
252
240
  std::vector<Node> esubs;
253
246
  for (const Node& sb : subs)
254
  {
255
126
    esubs.push_back(d_drewrite->toExternal(sb));
256
  }
257
120
  Assert(it != d_pairs.end());
258
984
  for (const Node& nr : it->second)
259
  {
260
    Node nrs =
261
1731
        nr.substitute(vars.begin(), vars.end(), esubs.begin(), esubs.end());
262
867
    bool areEqual = (nrs == d_curr_pair_rhs);
263
867
    if (!areEqual && options().quantifiers.sygusRewSynthFilterCong)
264
    {
265
      // if dynamic rewriter is available, consult it
266
864
      areEqual = d_drewrite->areEqual(nrs, d_curr_pair_rhs);
267
    }
268
867
    if (areEqual)
269
    {
270
3
      Trace("crf-match") << "*** Match, current pair: " << std::endl;
271
6
      Trace("crf-match") << "  (" << s << ", " << d_curr_pair_rhs << ")"
272
3
                         << std::endl;
273
3
      Trace("crf-match") << "is an instance of previous pair:" << std::endl;
274
3
      Trace("crf-match") << "  (" << n << ", " << nr << ")" << std::endl;
275
3
      return false;
276
    }
277
  }
278
117
  return true;
279
}
280
281
}  // namespace quantifiers
282
}  // namespace theory
283
31137
}  // namespace cvc5