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