GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/sygus_sampler.cpp Lines: 369 463 79.7 %
Date: 2021-09-15 Branches: 588 1522 38.6 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Andres Noetzli, Mathias Preiner
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 sygus_sampler.
14
 */
15
16
#include "theory/quantifiers/sygus_sampler.h"
17
18
#include <sstream>
19
20
#include "expr/dtype.h"
21
#include "expr/dtype_cons.h"
22
#include "expr/node_algorithm.h"
23
#include "options/base_options.h"
24
#include "options/quantifiers_options.h"
25
#include "printer/printer.h"
26
#include "theory/quantifiers/lazy_trie.h"
27
#include "theory/rewriter.h"
28
#include "util/bitvector.h"
29
#include "util/random.h"
30
#include "util/sampler.h"
31
32
namespace cvc5 {
33
namespace theory {
34
namespace quantifiers {
35
36
3768
SygusSampler::SygusSampler()
37
3768
    : d_tds(nullptr), d_use_sygus_type(false), d_is_valid(false)
38
{
39
3768
}
40
41
58
void SygusSampler::initialize(TypeNode tn,
42
                              const std::vector<Node>& vars,
43
                              unsigned nsamples,
44
                              bool unique_type_ids)
45
{
46
58
  d_tds = nullptr;
47
58
  d_use_sygus_type = false;
48
58
  d_is_valid = true;
49
58
  d_ftn = TypeNode::null();
50
58
  d_type_vars.clear();
51
58
  d_vars.clear();
52
58
  d_rvalue_cindices.clear();
53
58
  d_rvalue_null_cindices.clear();
54
58
  d_rstring_alphabet.clear();
55
58
  d_var_sygus_types.clear();
56
58
  d_const_sygus_types.clear();
57
58
  d_vars.insert(d_vars.end(), vars.begin(), vars.end());
58
116
  std::map<TypeNode, unsigned> type_to_type_id;
59
58
  unsigned type_id_counter = 0;
60
357
  for (const Node& sv : d_vars)
61
  {
62
598
    TypeNode svt = sv.getType();
63
299
    unsigned tnid = 0;
64
299
    if (unique_type_ids)
65
    {
66
      tnid = type_id_counter;
67
      type_id_counter++;
68
    }
69
    else
70
    {
71
299
      std::map<TypeNode, unsigned>::iterator itt = type_to_type_id.find(svt);
72
299
      if (itt == type_to_type_id.end())
73
      {
74
58
        type_to_type_id[svt] = type_id_counter;
75
58
        type_id_counter++;
76
      }
77
      else
78
      {
79
241
        tnid = itt->second;
80
      }
81
    }
82
598
    Trace("sygus-sample-debug")
83
299
        << "Type id for " << sv << " is " << tnid << std::endl;
84
299
    d_var_index[sv] = d_type_vars[tnid].size();
85
299
    d_type_vars[tnid].push_back(sv);
86
299
    d_type_ids[sv] = tnid;
87
  }
88
58
  initializeSamples(nsamples);
89
58
}
90
91
16
void SygusSampler::initializeSygus(TermDbSygus* tds,
92
                                   Node f,
93
                                   unsigned nsamples,
94
                                   bool useSygusType)
95
{
96
16
  d_tds = tds;
97
16
  d_use_sygus_type = useSygusType;
98
16
  d_is_valid = true;
99
16
  d_ftn = f.getType();
100
16
  Assert(d_ftn.isDatatype());
101
16
  const DType& dt = d_ftn.getDType();
102
16
  Assert(dt.isSygus());
103
104
16
  Trace("sygus-sample") << "Register sampler for " << f << std::endl;
105
106
16
  d_vars.clear();
107
16
  d_type_vars.clear();
108
16
  d_var_index.clear();
109
16
  d_type_vars.clear();
110
16
  d_rvalue_cindices.clear();
111
16
  d_rvalue_null_cindices.clear();
112
16
  d_var_sygus_types.clear();
113
  // get the sygus variable list
114
32
  Node var_list = dt.getSygusVarList();
115
16
  if (!var_list.isNull())
116
  {
117
64
    for (const Node& sv : var_list)
118
    {
119
48
      d_vars.push_back(sv);
120
    }
121
  }
122
  // register sygus type
123
16
  registerSygusType(d_ftn);
124
  // Variables are associated with type ids based on the set of sygus types they
125
  // appear in.
126
32
  std::map<Node, unsigned> var_to_type_id;
127
16
  unsigned type_id_counter = 0;
128
64
  for (const Node& sv : d_vars)
129
  {
130
96
    TypeNode svt = sv.getType();
131
    // is it equivalent to a previous variable?
132
117
    for (const auto& v : var_to_type_id)
133
    {
134
138
      Node svc = v.first;
135
69
      if (svc.getType() == svt)
136
      {
137
57
        if (d_var_sygus_types[sv].size() == d_var_sygus_types[svc].size())
138
        {
139
53
          bool success = true;
140
86
          for (unsigned t = 0, size = d_var_sygus_types[sv].size(); t < size;
141
               t++)
142
          {
143
51
            if (d_var_sygus_types[sv][t] != d_var_sygus_types[svc][t])
144
            {
145
18
              success = false;
146
18
              break;
147
            }
148
          }
149
53
          if (success)
150
          {
151
35
            var_to_type_id[sv] = var_to_type_id[svc];
152
          }
153
        }
154
      }
155
    }
156
48
    if (var_to_type_id.find(sv) == var_to_type_id.end())
157
    {
158
32
      var_to_type_id[sv] = type_id_counter;
159
32
      type_id_counter++;
160
    }
161
48
    unsigned tnid = var_to_type_id[sv];
162
96
    Trace("sygus-sample-debug")
163
48
        << "Type id for " << sv << " is " << tnid << std::endl;
164
48
    d_var_index[sv] = d_type_vars[tnid].size();
165
48
    d_type_vars[tnid].push_back(sv);
166
48
    d_type_ids[sv] = tnid;
167
  }
168
169
16
  initializeSamples(nsamples);
170
16
}
171
172
74
void SygusSampler::initializeSamples(unsigned nsamples)
173
{
174
74
  d_samples.clear();
175
148
  std::vector<TypeNode> types;
176
421
  for (const Node& v : d_vars)
177
  {
178
694
    TypeNode vt = v.getType();
179
347
    types.push_back(vt);
180
694
    Trace("sygus-sample") << "  var #" << types.size() << " : " << v << " : "
181
347
                          << vt << std::endl;
182
  }
183
148
  std::map<unsigned, std::map<Node, std::vector<TypeNode> >::iterator> sts;
184
74
  if (options::sygusSampleGrammar())
185
  {
186
421
    for (unsigned j = 0, size = types.size(); j < size; j++)
187
    {
188
347
      sts[j] = d_var_sygus_types.find(d_vars[j]);
189
    }
190
  }
191
192
74
  unsigned nduplicates = 0;
193
88718
  for (unsigned i = 0; i < nsamples; i++)
194
  {
195
177295
    std::vector<Node> sample_pt;
196
451950
    for (unsigned j = 0, size = types.size(); j < size; j++)
197
    {
198
726598
      Node v = d_vars[j];
199
726598
      Node r;
200
363299
      if (options::sygusSampleGrammar())
201
      {
202
        // choose a random start sygus type, if possible
203
363299
        if (sts[j] != d_var_sygus_types.end())
204
        {
205
221387
          unsigned ntypes = sts[j]->second.size();
206
221387
          if(ntypes > 0)
207
          {
208
218703
            unsigned index = Random::getRandom().pick(0, ntypes - 1);
209
218703
            if (index < ntypes)
210
            {
211
              // currently hard coded to 0.0, 0.5
212
218703
              r = getSygusRandomValue(sts[j]->second[index], 0.0, 0.5);
213
            }
214
          }
215
        }
216
      }
217
363299
      if (r.isNull())
218
      {
219
144596
        r = getRandomValue(types[j]);
220
144596
        if (r.isNull())
221
        {
222
          d_is_valid = false;
223
        }
224
      }
225
363299
      sample_pt.push_back(r);
226
    }
227
88651
    if (d_samples_trie.add(sample_pt))
228
    {
229
11072
      if (Trace.isOn("sygus-sample"))
230
      {
231
        Trace("sygus-sample") << "Sample point #" << i << " : ";
232
        for (const Node& r : sample_pt)
233
        {
234
          Trace("sygus-sample") << r << " ";
235
        }
236
        Trace("sygus-sample") << std::endl;
237
      }
238
11072
      d_samples.push_back(sample_pt);
239
    }
240
    else
241
    {
242
77579
      i--;
243
77579
      nduplicates++;
244
77579
      if (nduplicates == nsamples * 10)
245
      {
246
14
        Trace("sygus-sample")
247
7
            << "...WARNING: excessive duplicates, cut off sampling at " << i
248
7
            << "/" << nsamples << " points." << std::endl;
249
7
        break;
250
      }
251
    }
252
  }
253
254
74
  d_trie.clear();
255
74
}
256
257
88651
bool SygusSampler::PtTrie::add(std::vector<Node>& pt)
258
{
259
88651
  PtTrie* curr = this;
260
451950
  for (unsigned i = 0, size = pt.size(); i < size; i++)
261
  {
262
363299
    curr = &(curr->d_children[pt[i]]);
263
  }
264
88651
  bool retVal = curr->d_children.empty();
265
88651
  curr = &(curr->d_children[Node::null()]);
266
88651
  return retVal;
267
}
268
269
1850
Node SygusSampler::registerTerm(Node n, bool forceKeep)
270
{
271
1850
  if (!d_is_valid)
272
  {
273
    // do nothing
274
    return n;
275
  }
276
3700
  Node bn = n;
277
3700
  TypeNode tn = n.getType();
278
  // If we are using sygus types, get the builtin analog of n.
279
1850
  if (d_use_sygus_type)
280
  {
281
1026
    bn = d_tds->sygusToBuiltin(n);
282
1026
    d_builtin_to_sygus[tn][bn] = n;
283
  }
284
  // cache based on the (original) type of n
285
3700
  Node res = d_trie[tn].add(bn, this, 0, d_samples.size(), forceKeep);
286
  // If we are using sygus types, map back to an original.
287
  // Notice that d_builtin_to_sygus is not necessarily bijective.
288
1850
  if (d_use_sygus_type)
289
  {
290
1026
    std::map<Node, Node>& bts = d_builtin_to_sygus[tn];
291
1026
    Assert(bts.find(res) != bts.end());
292
1026
    res = res != bn ? bts[res] : n;
293
  }
294
1850
  return res;
295
}
296
297
bool SygusSampler::isContiguous(Node n)
298
{
299
  // compute free variables in n
300
  std::vector<Node> fvs;
301
  computeFreeVariables(n, fvs);
302
  // compute contiguous condition
303
  for (const std::pair<const unsigned, std::vector<Node> >& p : d_type_vars)
304
  {
305
    bool foundNotFv = false;
306
    for (const Node& v : p.second)
307
    {
308
      bool hasFv = std::find(fvs.begin(), fvs.end(), v) != fvs.end();
309
      if (!hasFv)
310
      {
311
        foundNotFv = true;
312
      }
313
      else if (foundNotFv)
314
      {
315
        return false;
316
      }
317
    }
318
  }
319
  return true;
320
}
321
322
64
void SygusSampler::computeFreeVariables(Node n, std::vector<Node>& fvs)
323
{
324
128
  std::unordered_set<TNode> visited;
325
64
  std::unordered_set<TNode>::iterator it;
326
128
  std::vector<TNode> visit;
327
128
  TNode cur;
328
64
  visit.push_back(n);
329
201
  do
330
  {
331
265
    cur = visit.back();
332
265
    visit.pop_back();
333
265
    if (visited.find(cur) == visited.end())
334
    {
335
215
      visited.insert(cur);
336
215
      if (cur.isVar())
337
      {
338
96
        if (d_var_index.find(cur) != d_var_index.end())
339
        {
340
96
          fvs.push_back(cur);
341
        }
342
      }
343
416
      for (const Node& cn : cur)
344
      {
345
201
        visit.push_back(cn);
346
      }
347
    }
348
265
  } while (!visit.empty());
349
64
}
350
351
bool SygusSampler::isOrdered(Node n) { return checkVariables(n, true, false); }
352
353
bool SygusSampler::isLinear(Node n) { return checkVariables(n, false, true); }
354
355
458
bool SygusSampler::checkVariables(Node n, bool checkOrder, bool checkLinear)
356
{
357
  // compute free variables in n for each type
358
916
  std::map<unsigned, std::vector<Node> > fvs;
359
360
916
  std::unordered_set<TNode> visited;
361
458
  std::unordered_set<TNode>::iterator it;
362
916
  std::vector<TNode> visit;
363
916
  TNode cur;
364
458
  visit.push_back(n);
365
752
  do
366
  {
367
1210
    cur = visit.back();
368
1210
    visit.pop_back();
369
1210
    if (visited.find(cur) == visited.end())
370
    {
371
1074
      visited.insert(cur);
372
1074
      if (cur.isVar())
373
      {
374
457
        std::map<Node, unsigned>::iterator itv = d_var_index.find(cur);
375
457
        if (itv != d_var_index.end())
376
        {
377
457
          if (checkOrder)
378
          {
379
457
            unsigned tnid = d_type_ids[cur];
380
            // if this variable is out of order
381
457
            if (itv->second != fvs[tnid].size())
382
            {
383
166
              return false;
384
            }
385
291
            fvs[tnid].push_back(cur);
386
          }
387
291
          if (checkLinear)
388
          {
389
            if (expr::hasSubtermMulti(n, cur))
390
            {
391
              return false;
392
            }
393
          }
394
        }
395
      }
396
1800
      for (unsigned j = 0, nchildren = cur.getNumChildren(); j < nchildren; j++)
397
      {
398
892
        visit.push_back(cur[(nchildren - j) - 1]);
399
      }
400
    }
401
1044
  } while (!visit.empty());
402
292
  return true;
403
}
404
405
64
bool SygusSampler::containsFreeVariables(Node a, Node b, bool strict)
406
{
407
  // compute free variables in a
408
128
  std::vector<Node> fvs;
409
64
  computeFreeVariables(a, fvs);
410
128
  std::vector<Node> fv_found;
411
412
128
  std::unordered_set<TNode> visited;
413
64
  std::unordered_set<TNode>::iterator it;
414
128
  std::vector<TNode> visit;
415
128
  TNode cur;
416
64
  visit.push_back(b);
417
36
  do
418
  {
419
100
    cur = visit.back();
420
100
    visit.pop_back();
421
100
    if (visited.find(cur) == visited.end())
422
    {
423
95
      visited.insert(cur);
424
95
      if (cur.isVar())
425
      {
426
18
        if (std::find(fvs.begin(), fvs.end(), cur) == fvs.end())
427
        {
428
1
          return false;
429
        }
430
17
        else if (strict)
431
        {
432
17
          if (fv_found.size() + 1 == fvs.size())
433
          {
434
8
            return false;
435
          }
436
          // cur should only be visited once
437
9
          Assert(std::find(fv_found.begin(), fv_found.end(), cur)
438
                 == fv_found.end());
439
9
          fv_found.push_back(cur);
440
        }
441
      }
442
126
      for (const Node& cn : cur)
443
      {
444
40
        visit.push_back(cn);
445
      }
446
    }
447
91
  } while (!visit.empty());
448
55
  return true;
449
}
450
451
134
void SygusSampler::getVariables(std::vector<Node>& vars) const
452
{
453
134
  vars.insert(vars.end(), d_vars.begin(), d_vars.end());
454
134
}
455
456
6
void SygusSampler::getSamplePoint(unsigned index,
457
                                  std::vector<Node>& pt)
458
{
459
6
  Assert(index < d_samples.size());
460
6
  std::vector<Node>& spt = d_samples[index];
461
6
  pt.insert(pt.end(), spt.begin(), spt.end());
462
6
}
463
464
125
void SygusSampler::addSamplePoint(std::vector<Node>& pt)
465
{
466
125
  Assert(pt.size() == d_vars.size());
467
125
  d_samples.push_back(pt);
468
125
}
469
470
708055
Node SygusSampler::evaluate(Node n, unsigned index)
471
{
472
708055
  Assert(index < d_samples.size());
473
  // do beta-reductions in n first
474
708055
  n = Rewriter::rewrite(n);
475
  // use efficient rewrite for substitution + rewrite
476
708055
  Node ev = d_eval.eval(n, d_vars, d_samples[index]);
477
708055
  Trace("sygus-sample-ev") << "Evaluate ( " << n << ", " << index << " ) -> ";
478
708055
  if (!ev.isNull())
479
  {
480
708055
    Trace("sygus-sample-ev") << ev << std::endl;
481
708055
    return ev;
482
  }
483
  Trace("sygus-sample-ev") << "null" << std::endl;
484
  Trace("sygus-sample-ev") << "Rewrite -> ";
485
  // substitution + rewrite
486
  std::vector<Node>& pt = d_samples[index];
487
  ev = n.substitute(d_vars.begin(), d_vars.end(), pt.begin(), pt.end());
488
  ev = Rewriter::rewrite(ev);
489
  Trace("sygus-sample-ev") << ev << std::endl;
490
  return ev;
491
}
492
493
int SygusSampler::getDiffSamplePointIndex(Node a, Node b)
494
{
495
  for (unsigned i = 0, nsamp = d_samples.size(); i < nsamp; i++)
496
  {
497
    Node ae = evaluate(a, i);
498
    Node be = evaluate(b, i);
499
    if (ae != be)
500
    {
501
      return i;
502
    }
503
  }
504
  return -1;
505
}
506
507
441205
Node SygusSampler::getRandomValue(TypeNode tn)
508
{
509
441205
  NodeManager* nm = NodeManager::currentNM();
510
441205
  if (tn.isBoolean())
511
  {
512
288493
    return nm->mkConst(Random::getRandom().pickWithProb(0.5));
513
  }
514
152712
  else if (tn.isBitVector())
515
  {
516
94598
    unsigned sz = tn.getBitVectorSize();
517
94598
    return nm->mkConst(Sampler::pickBvUniform(sz));
518
  }
519
58114
  else if (tn.isFloatingPoint())
520
  {
521
    unsigned e = tn.getFloatingPointExponentSize();
522
    unsigned s = tn.getFloatingPointSignificandSize();
523
    return nm->mkConst(options::sygusSampleFpUniform()
524
                           ? Sampler::pickFpUniform(e, s)
525
                           : Sampler::pickFpBiased(e, s));
526
  }
527
58114
  else if (tn.isString() || tn.isInteger())
528
  {
529
    // if string, determine the alphabet
530
58114
    if (tn.isString() && d_rstring_alphabet.empty())
531
    {
532
4
      Trace("sygus-sample-str-alpha")
533
2
          << "Setting string alphabet..." << std::endl;
534
4
      std::unordered_set<unsigned> alphas;
535
10
      for (const std::pair<const Node, std::vector<TypeNode> >& c :
536
2
           d_const_sygus_types)
537
      {
538
10
        if (c.first.getType().isString())
539
        {
540
12
          Trace("sygus-sample-str-alpha")
541
6
              << "...have constant " << c.first << std::endl;
542
6
          Assert(c.first.isConst());
543
12
          std::vector<unsigned> svec = c.first.getConst<String>().getVec();
544
10
          for (unsigned ch : svec)
545
          {
546
4
            alphas.insert(ch);
547
          }
548
        }
549
      }
550
      // can limit to 1 extra characters beyond those in the grammar (2 if
551
      // there are none in the grammar)
552
2
      unsigned num_fresh_char = alphas.empty() ? 2 : 1;
553
2
      unsigned fresh_char = 0;
554
4
      for (unsigned i = 0; i < num_fresh_char; i++)
555
      {
556
2
        while (alphas.find(fresh_char) != alphas.end())
557
        {
558
          fresh_char++;
559
        }
560
2
        alphas.insert(fresh_char);
561
      }
562
4
      Trace("sygus-sample-str-alpha")
563
2
          << "Sygus sampler: limit strings alphabet to : " << std::endl
564
2
          << " ";
565
8
      for (unsigned ch : alphas)
566
      {
567
6
        d_rstring_alphabet.push_back(ch);
568
6
        Trace("sygus-sample-str-alpha") << " \\u" << ch;
569
      }
570
2
      Trace("sygus-sample-str-alpha") << std::endl;
571
    }
572
573
58114
    std::vector<unsigned> vec;
574
58114
    double ext_freq = .5;
575
58114
    unsigned base = tn.isString() ? d_rstring_alphabet.size() : 10;
576
173736
    while (Random::getRandom().pickWithProb(ext_freq))
577
    {
578
      // add a digit
579
57811
      unsigned digit = Random::getRandom().pick(0, base - 1);
580
57811
      if (tn.isString())
581
      {
582
6759
        digit = d_rstring_alphabet[digit];
583
      }
584
57811
      vec.push_back(digit);
585
    }
586
58114
    if (tn.isString())
587
    {
588
6858
      return nm->mkConst(String(vec));
589
    }
590
51256
    else if (tn.isInteger())
591
    {
592
102512
      Rational baser(base);
593
102512
      Rational curr(1);
594
102512
      std::vector<Node> sum;
595
102308
      for (unsigned j = 0, size = vec.size(); j < size; j++)
596
      {
597
102104
        Node digit = nm->mkConst(Rational(vec[j]) * curr);
598
51052
        sum.push_back(digit);
599
51052
        curr = curr * baser;
600
      }
601
102512
      Node ret;
602
51256
      if (sum.empty())
603
      {
604
25450
        ret = nm->mkConst(Rational(0));
605
      }
606
25806
      else if (sum.size() == 1)
607
      {
608
12982
        ret = sum[0];
609
      }
610
      else
611
      {
612
12824
        ret = nm->mkNode(kind::PLUS, sum);
613
      }
614
615
51256
      if (Random::getRandom().pickWithProb(0.5))
616
      {
617
        // negative
618
25635
        ret = nm->mkNode(kind::UMINUS, ret);
619
      }
620
51256
      ret = Rewriter::rewrite(ret);
621
51256
      Assert(ret.isConst());
622
51256
      return ret;
623
    }
624
  }
625
  else if (tn.isReal())
626
  {
627
    Node s = getRandomValue(nm->integerType());
628
    Node r = getRandomValue(nm->integerType());
629
    if (!s.isNull() && !r.isNull())
630
    {
631
      Rational sr = s.getConst<Rational>();
632
      Rational rr = r.getConst<Rational>();
633
      if (rr.sgn() == 0)
634
      {
635
        return s;
636
      }
637
      else
638
      {
639
        return nm->mkConst(sr / rr);
640
      }
641
    }
642
  }
643
  // default: use type enumerator
644
  unsigned counter = 0;
645
  while (Random::getRandom().pickWithProb(0.5))
646
  {
647
    counter++;
648
  }
649
  Node ret = d_tenum.getEnumerateTerm(tn, counter);
650
  if (ret.isNull())
651
  {
652
    // beyond bounds, return the first
653
    ret = d_tenum.getEnumerateTerm(tn, 0);
654
  }
655
  return ret;
656
}
657
658
664070
Node SygusSampler::getSygusRandomValue(TypeNode tn,
659
                                       double rchance,
660
                                       double rinc,
661
                                       unsigned depth)
662
{
663
664070
  if (!tn.isDatatype())
664
  {
665
    return getRandomValue(tn);
666
  }
667
664070
  const DType& dt = tn.getDType();
668
664070
  if (!dt.isSygus())
669
  {
670
    return getRandomValue(tn);
671
  }
672
664070
  Assert(d_rvalue_cindices.find(tn) != d_rvalue_cindices.end());
673
1328140
  Trace("sygus-sample-grammar")
674
664070
      << "Sygus random value " << tn << ", depth = " << depth
675
664070
      << ", rchance = " << rchance << std::endl;
676
  // check if we terminate on this call
677
  // we refuse to enumerate terms of 10+ depth as a hard limit
678
664070
  bool terminate = Random::getRandom().pickWithProb(rchance) || depth >= 10;
679
  // if we terminate, only nullary constructors can be chosen
680
  std::vector<unsigned>& cindices =
681
664070
      terminate ? d_rvalue_null_cindices[tn] : d_rvalue_cindices[tn];
682
664070
  unsigned ncons = cindices.size();
683
  // select a random constructor, or random value when index=ncons.
684
664070
  unsigned index = Random::getRandom().pick(0, ncons);
685
1328140
  Trace("sygus-sample-grammar")
686
664070
      << "Random index 0..." << ncons << " was : " << index << std::endl;
687
664070
  if (index < ncons)
688
  {
689
734922
    Trace("sygus-sample-grammar")
690
367461
        << "Recurse constructor index #" << index << std::endl;
691
367461
    unsigned cindex = cindices[index];
692
367461
    Assert(cindex < dt.getNumConstructors());
693
367461
    const DTypeConstructor& dtc = dt[cindex];
694
    // more likely to terminate in recursive calls
695
367461
    double rchance_new = rchance + (1.0 - rchance) * rinc;
696
367461
    std::map<int, Node> pre;
697
367461
    bool success = true;
698
    // generate random values for all arguments
699
812828
    for (unsigned i = 0, nargs = dtc.getNumArgs(); i < nargs; i++)
700
    {
701
890734
      TypeNode tnc = d_tds->getArgType(dtc, i);
702
890734
      Node c = getSygusRandomValue(tnc, rchance_new, rinc, depth + 1);
703
445367
      if (c.isNull())
704
      {
705
        success = false;
706
        Trace("sygus-sample-grammar") << "...fail." << std::endl;
707
        break;
708
      }
709
890734
      Trace("sygus-sample-grammar")
710
445367
          << "  child #" << i << " : " << c << std::endl;
711
445367
      pre[i] = c;
712
    }
713
367461
    if (success)
714
    {
715
367461
      Trace("sygus-sample-grammar") << "mkGeneric" << std::endl;
716
367461
      Node ret = d_tds->mkGeneric(dt, cindex, pre);
717
367461
      Trace("sygus-sample-grammar") << "...returned " << ret << std::endl;
718
367461
      ret = Rewriter::rewrite(ret);
719
367461
      Trace("sygus-sample-grammar") << "...after rewrite " << ret << std::endl;
720
      // A rare case where we generate a non-constant value from constant
721
      // leaves is (/ n 0).
722
367461
      if(ret.isConst())
723
      {
724
367461
        return ret;
725
      }
726
    }
727
  }
728
296609
  Trace("sygus-sample-grammar") << "...resort to random value" << std::endl;
729
  // if we did not generate based on the grammar, pick a random value
730
296609
  return getRandomValue(dt.getSygusType());
731
}
732
733
// recursion depth bounded by number of types in grammar (small)
734
311
void SygusSampler::registerSygusType(TypeNode tn)
735
{
736
311
  if (d_rvalue_cindices.find(tn) == d_rvalue_cindices.end())
737
  {
738
34
    d_rvalue_cindices[tn].clear();
739
34
    if (!tn.isDatatype())
740
    {
741
      return;
742
    }
743
34
    const DType& dt = tn.getDType();
744
34
    if (!dt.isSygus())
745
    {
746
      return;
747
    }
748
292
    for (unsigned i = 0, ncons = dt.getNumConstructors(); i < ncons; i++)
749
    {
750
258
      const DTypeConstructor& dtc = dt[i];
751
516
      Node sop = dtc.getSygusOp();
752
258
      bool isVar = std::find(d_vars.begin(), d_vars.end(), sop) != d_vars.end();
753
258
      if (isVar)
754
      {
755
        // if it is a variable, add it to the list of sygus types for that var
756
42
        d_var_sygus_types[sop].push_back(tn);
757
      }
758
      else
759
      {
760
        // otherwise, it is a constructor for sygus random value
761
216
        d_rvalue_cindices[tn].push_back(i);
762
216
        if (dtc.getNumArgs() == 0)
763
        {
764
45
          d_rvalue_null_cindices[tn].push_back(i);
765
45
          if (sop.isConst())
766
          {
767
25
            d_const_sygus_types[sop].push_back(tn);
768
          }
769
        }
770
      }
771
      // recurse on all subfields
772
553
      for (unsigned j = 0, nargs = dtc.getNumArgs(); j < nargs; j++)
773
      {
774
590
        TypeNode tnc = d_tds->getArgType(dtc, j);
775
295
        registerSygusType(tnc);
776
      }
777
    }
778
  }
779
}
780
781
1627
void SygusSampler::checkEquivalent(Node bv, Node bvr, std::ostream& out)
782
{
783
1627
  if (bv == bvr)
784
  {
785
1124
    return;
786
  }
787
2130
  Trace("sygus-rr-verify") << "Testing rewrite rule " << bv << " ---> " << bvr
788
1065
                           << std::endl;
789
790
  // see if they evaluate to same thing on all sample points
791
1065
  bool ptDisequal = false;
792
1065
  bool ptDisequalConst = false;
793
1065
  unsigned pt_index = 0;
794
2130
  Node bve, bvre;
795
314761
  for (unsigned i = 0, npoints = getNumSamplePoints(); i < npoints; i++)
796
  {
797
313696
    bve = evaluate(bv, i);
798
313696
    bvre = evaluate(bvr, i);
799
313696
    if (bve != bvre)
800
    {
801
      ptDisequal = true;
802
      pt_index = i;
803
      if (bve.isConst() && bvre.isConst())
804
      {
805
        ptDisequalConst = true;
806
        break;
807
      }
808
    }
809
  }
810
  // bv and bvr should be equivalent under examples
811
1065
  if (ptDisequal)
812
  {
813
    std::vector<Node> vars;
814
    getVariables(vars);
815
    std::vector<Node> pt;
816
    getSamplePoint(pt_index, pt);
817
    Assert(vars.size() == pt.size());
818
    std::stringstream ptOut;
819
    for (unsigned i = 0, size = pt.size(); i < size; i++)
820
    {
821
      ptOut << "  " << vars[i] << " -> " << pt[i] << std::endl;
822
    }
823
    if (!ptDisequalConst)
824
    {
825
      Notice() << "Warning: " << bv << " and " << bvr
826
               << " evaluate to different (non-constant) values on point:"
827
               << std::endl;
828
      Notice() << ptOut.str();
829
      return;
830
    }
831
    // we have detected unsoundness in the rewriter
832
    out << "(unsound-rewrite " << bv << " " << bvr << ")" << std::endl;
833
    // debugging information
834
    out << "Terms are not equivalent for : " << std::endl;
835
    out << ptOut.str();
836
    Assert(bve != bvre);
837
    out << "where they evaluate to " << bve << " and " << bvre << std::endl;
838
839
    if (options::sygusRewVerifyAbort())
840
    {
841
      AlwaysAssert(false)
842
          << "--sygus-rr-verify detected unsoundness in the rewriter!";
843
    }
844
  }
845
}
846
847
}  // namespace quantifiers
848
}  // namespace theory
849
29577
}  // namespace cvc5