GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/sygus_sampler.cpp Lines: 369 456 80.9 %
Date: 2021-09-29 Branches: 591 1508 39.2 %

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