GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/sygus/sygus_process_conj.cpp Lines: 351 387 90.7 %
Date: 2021-11-07 Branches: 621 1406 44.2 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, 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
 * Implementation of techniqures for static preprocessing and analysis
14
 * of sygus conjectures.
15
 */
16
#include "theory/quantifiers/sygus/sygus_process_conj.h"
17
18
#include <sstream>
19
#include <stack>
20
21
#include "options/quantifiers_options.h"
22
#include "theory/quantifiers/sygus/term_database_sygus.h"
23
#include "theory/quantifiers/term_util.h"
24
#include "theory/rewriter.h"
25
26
using namespace cvc5::kind;
27
using namespace std;
28
29
namespace cvc5 {
30
namespace theory {
31
namespace quantifiers {
32
33
8
void SynthConjectureProcessFun::init(Node f)
34
{
35
8
  d_synth_fun = f;
36
8
  Assert(f.getType().isFunction());
37
38
  // initialize the arguments
39
16
  std::unordered_map<TypeNode, unsigned> type_to_init_deq_id;
40
16
  std::vector<TypeNode> argTypes = f.getType().getArgTypes();
41
88
  for (unsigned j = 0; j < argTypes.size(); j++)
42
  {
43
160
    TypeNode atn = argTypes[j];
44
160
    std::stringstream ss;
45
80
    ss << "a" << j;
46
160
    Node k = NodeManager::currentNM()->mkBoundVar(ss.str(), atn);
47
80
    d_arg_vars.push_back(k);
48
80
    d_arg_var_num[k] = j;
49
80
    d_arg_props.push_back(SynthConjectureProcessArg());
50
  }
51
8
}
52
53
18
bool SynthConjectureProcessFun::checkMatch(
54
    Node cn, Node n, std::unordered_map<unsigned, Node>& n_arg_map)
55
{
56
36
  std::vector<Node> vars;
57
36
  std::vector<Node> subs;
58
198
  for (std::unordered_map<unsigned, Node>::iterator it = n_arg_map.begin();
59
198
       it != n_arg_map.end();
60
       ++it)
61
  {
62
180
    Assert(it->first < d_arg_vars.size());
63
180
    Assert(
64
        it->second.getType().isComparableTo(d_arg_vars[it->first].getType()));
65
180
    vars.push_back(d_arg_vars[it->first]);
66
180
    subs.push_back(it->second);
67
  }
68
  Node cn_subs =
69
36
      cn.substitute(vars.begin(), vars.end(), subs.begin(), subs.end());
70
18
  cn_subs = Rewriter::rewrite(cn_subs);
71
18
  n = Rewriter::rewrite(n);
72
36
  return cn_subs == n;
73
}
74
75
bool SynthConjectureProcessFun::isArgVar(Node n, unsigned& arg_index)
76
{
77
  if (n.isVar())
78
  {
79
    std::unordered_map<Node, unsigned>::iterator ita = d_arg_var_num.find(n);
80
    if (ita != d_arg_var_num.end())
81
    {
82
      arg_index = ita->second;
83
      return true;
84
    }
85
  }
86
  return false;
87
}
88
89
24
Node SynthConjectureProcessFun::inferDefinition(
90
    Node n,
91
    std::unordered_map<Node, unsigned>& term_to_arg_carry,
92
    std::unordered_map<Node, std::unordered_set<Node>>& free_vars)
93
{
94
48
  std::unordered_map<TNode, Node> visited;
95
24
  std::unordered_map<TNode, Node>::iterator it;
96
48
  std::stack<TNode> visit;
97
48
  TNode cur;
98
24
  visit.push(n);
99
18
  do
100
  {
101
42
    cur = visit.top();
102
42
    visit.pop();
103
42
    it = visited.find(cur);
104
42
    if (it == visited.end())
105
    {
106
      // if it is ground, we can use it
107
38
      if (free_vars[cur].empty())
108
      {
109
6
        visited[cur] = cur;
110
      }
111
      else
112
      {
113
        // if it is term used by another argument, use it
114
        std::unordered_map<Node, unsigned>::iterator itt =
115
32
            term_to_arg_carry.find(cur);
116
32
        if (itt != term_to_arg_carry.end())
117
        {
118
6
          visited[cur] = d_arg_vars[itt->second];
119
        }
120
26
        else if (cur.getNumChildren() > 0)
121
        {
122
          // try constructing children
123
10
          visited[cur] = Node::null();
124
10
          visit.push(cur);
125
30
          for (unsigned i = 0; i < cur.getNumChildren(); i++)
126
          {
127
20
            visit.push(cur[i]);
128
          }
129
        }
130
        else
131
        {
132
16
          return Node::null();
133
        }
134
      }
135
    }
136
4
    else if (it->second.isNull())
137
    {
138
8
      Node ret = cur;
139
4
      bool childChanged = false;
140
8
      std::vector<Node> children;
141
4
      if (cur.getMetaKind() == kind::metakind::PARAMETERIZED)
142
      {
143
        children.push_back(cur.getOperator());
144
      }
145
12
      for (unsigned i = 0; i < cur.getNumChildren(); i++)
146
      {
147
8
        it = visited.find(cur[i]);
148
8
        Assert(it != visited.end());
149
8
        Assert(!it->second.isNull());
150
8
        childChanged = childChanged || cur[i] != it->second;
151
8
        children.push_back(it->second);
152
      }
153
4
      if (childChanged)
154
      {
155
4
        ret = NodeManager::currentNM()->mkNode(cur.getKind(), children);
156
      }
157
4
      visited[cur] = ret;
158
    }
159
26
  } while (!visit.empty());
160
8
  Assert(visited.find(n) != visited.end());
161
8
  Assert(!visited.find(n)->second.isNull());
162
8
  return visited[n];
163
}
164
165
16
unsigned SynthConjectureProcessFun::assignRelevantDef(
166
    Node def, std::vector<unsigned>& args)
167
{
168
16
  unsigned id = 0;
169
16
  if (def.isNull())
170
  {
171
    // prefer one that already has a definition, if one exists
172
24
    for (unsigned j = 0; j < args.size(); j++)
173
    {
174
16
      unsigned i = args[j];
175
16
      if (!d_arg_props[i].d_template.isNull())
176
      {
177
        id = j;
178
        break;
179
      }
180
    }
181
  }
182
16
  unsigned rid = args[id];
183
  // for merging previously equivalent definitions
184
32
  std::unordered_map<Node, unsigned> prev_defs;
185
50
  for (unsigned j = 0; j < args.size(); j++)
186
  {
187
34
    unsigned i = args[j];
188
34
    Trace("sygus-process-arg-deps") << "    ...processed arg #" << i;
189
34
    if (!d_arg_props[i].d_template.isNull())
190
    {
191
8
      if (d_arg_props[i].d_template == def)
192
      {
193
        // definition was consistent
194
      }
195
      else
196
      {
197
16
        Node t = d_arg_props[i].d_template;
198
8
        std::unordered_map<Node, unsigned>::iterator itt = prev_defs.find(t);
199
8
        if (itt != prev_defs.end())
200
        {
201
          // merge previously equivalent definitions
202
4
          d_arg_props[i].d_template = d_arg_vars[itt->second];
203
8
          Trace("sygus-process-arg-deps")
204
4
              << " (merged equivalent def from argument ";
205
4
          Trace("sygus-process-arg-deps") << itt->second << ")." << std::endl;
206
        }
207
        else
208
        {
209
          // store this as previous
210
4
          prev_defs[t] = i;
211
          // now must be relevant
212
4
          d_arg_props[i].d_relevant = true;
213
8
          Trace("sygus-process-arg-deps")
214
4
              << " (marked relevant, overwrite definition)." << std::endl;
215
        }
216
      }
217
    }
218
    else
219
    {
220
26
      if (def.isNull())
221
      {
222
16
        if (i != rid)
223
        {
224
          // marked as relevant, but template can be set equal to master
225
8
          d_arg_props[i].d_template = d_arg_vars[rid];
226
16
          Trace("sygus-process-arg-deps") << " (new definition, map to master "
227
8
                                          << d_arg_vars[rid] << ")."
228
8
                                          << std::endl;
229
        }
230
        else
231
        {
232
8
          d_arg_props[i].d_relevant = true;
233
8
          Trace("sygus-process-arg-deps") << " (marked relevant)." << std::endl;
234
        }
235
      }
236
      else
237
      {
238
        // has new definition
239
10
        d_arg_props[i].d_template = def;
240
20
        Trace("sygus-process-arg-deps") << " (new definition " << def << ")."
241
10
                                        << std::endl;
242
      }
243
    }
244
  }
245
32
  return rid;
246
}
247
248
10
void SynthConjectureProcessFun::processTerms(
249
    std::vector<Node>& ns,
250
    std::vector<Node>& ks,
251
    Node nf,
252
    std::unordered_set<Node>& synth_fv,
253
    std::unordered_map<Node, std::unordered_set<Node>>& free_vars)
254
{
255
10
  Assert(ns.size() == ks.size());
256
20
  Trace("sygus-process-arg-deps") << "Process " << ns.size()
257
10
                                  << " applications of " << d_synth_fun << "..."
258
10
                                  << std::endl;
259
260
  // get the relevant variables
261
  // relevant variables are those that appear in the body of the conjunction
262
20
  std::unordered_set<Node> rlv_vars;
263
10
  Assert(free_vars.find(nf) != free_vars.end());
264
10
  rlv_vars = free_vars[nf];
265
266
  // get the single occurrence variables
267
  // single occurrence variables are those that appear in only one position,
268
  // as an argument to the function-to-synthesize.
269
20
  std::unordered_map<Node, bool> single_occ_variables;
270
20
  for (unsigned index = 0; index < ns.size(); index++)
271
  {
272
20
    Node n = ns[index];
273
110
    for (unsigned i = 0; i < n.getNumChildren(); i++)
274
    {
275
200
      Node nn = n[i];
276
100
      if (nn.isVar())
277
      {
278
        std::unordered_map<Node, bool>::iterator its =
279
88
            single_occ_variables.find(nn);
280
88
        if (its == single_occ_variables.end())
281
        {
282
          // only irrelevant variables
283
62
          single_occ_variables[nn] = rlv_vars.find(nn) == rlv_vars.end();
284
        }
285
        else
286
        {
287
26
          single_occ_variables[nn] = false;
288
        }
289
      }
290
      else
291
      {
292
        std::unordered_map<Node, std::unordered_set<Node>>::iterator itf =
293
12
            free_vars.find(nn);
294
12
        Assert(itf != free_vars.end());
295
20
        for (std::unordered_set<Node>::iterator itfv = itf->second.begin();
296
20
             itfv != itf->second.end();
297
             ++itfv)
298
        {
299
8
          single_occ_variables[*itfv] = false;
300
        }
301
      }
302
    }
303
  }
304
305
  // update constant argument information
306
20
  for (unsigned index = 0; index < ns.size(); index++)
307
  {
308
20
    Node n = ns[index];
309
20
    Trace("sygus-process-arg-deps")
310
10
        << "  Analyze argument information for application #" << index << ": "
311
10
        << n << std::endl;
312
313
    // in the following, we say an argument a "carries" a term t if
314
    // the function to synthesize would use argument a to construct
315
    // the term t in its definition.
316
317
    // map that assumes all arguments carry their respective term
318
20
    std::unordered_map<unsigned, Node> n_arg_map;
319
    // terms to the argument that is carrying it.
320
    // the arguments in the range of this map must be marked as relevant.
321
20
    std::unordered_map<Node, unsigned> term_to_arg_carry;
322
    // map of terms to (unprocessed) arguments where it occurs
323
20
    std::unordered_map<Node, std::vector<unsigned>> term_to_args;
324
325
    // initialize
326
110
    for (unsigned a = 0; a < n.getNumChildren(); a++)
327
    {
328
100
      n_arg_map[a] = n[a];
329
    }
330
331
110
    for (unsigned a = 0; a < n.getNumChildren(); a++)
332
    {
333
100
      bool processed = false;
334
100
      if (d_arg_props[a].d_relevant)
335
      {
336
        // we can assume all relevant arguments carry their terms
337
2
        processed = true;
338
4
        Trace("sygus-process-arg-deps") << "    ...processed arg #" << a
339
2
                                        << " (already relevant)." << std::endl;
340
2
        if (term_to_arg_carry.find(n[a]) == term_to_arg_carry.end())
341
        {
342
4
          Trace("sygus-process-arg-deps") << "    carry " << n[a]
343
2
                                          << " by argument #" << a << std::endl;
344
2
          term_to_arg_carry[n[a]] = a;
345
        }
346
      }
347
      else
348
      {
349
        // first, check if single occurrence variable
350
        // check if an irrelevant variable
351
98
        if (n[a].isVar() && synth_fv.find(n[a]) != synth_fv.end())
352
        {
353
86
          Assert(single_occ_variables.find(n[a]) != single_occ_variables.end());
354
          // may be able to make this more precise?
355
          // check if a single-occurrence variable
356
86
          if (single_occ_variables[n[a]])
357
          {
358
            // if we do not already have a template definition, or the
359
            // template is a single occurrence variable
360
108
            if (d_arg_props[a].d_template.isNull()
361
54
                || d_arg_props[a].d_var_single_occ)
362
            {
363
54
              processed = true;
364
54
              Trace("sygus-process-arg-deps") << "    ...processed arg #" << a;
365
108
              Trace("sygus-process-arg-deps")
366
54
                  << " (single occurrence variable ";
367
54
              Trace("sygus-process-arg-deps") << n[a] << ")." << std::endl;
368
54
              d_arg_props[a].d_var_single_occ = true;
369
54
              d_arg_props[a].d_template = n[a];
370
            }
371
          }
372
        }
373
240
        if (!processed && !d_arg_props[a].d_template.isNull()
374
116
            && !d_arg_props[a].d_var_single_occ)
375
        {
376
          // argument already has a definition, see if it is maintained
377
18
          if (checkMatch(d_arg_props[a].d_template, n[a], n_arg_map))
378
          {
379
10
            processed = true;
380
10
            Trace("sygus-process-arg-deps") << "    ...processed arg #" << a;
381
20
            Trace("sygus-process-arg-deps") << " (consistent definition "
382
10
                                            << n[a];
383
20
            Trace("sygus-process-arg-deps")
384
10
                << " with " << d_arg_props[a].d_template << ")." << std::endl;
385
          }
386
        }
387
      }
388
100
      if (!processed)
389
      {
390
        // otherwise, add it to the list of arguments for this term
391
34
        term_to_args[n[a]].push_back(a);
392
      }
393
    }
394
395
20
    Trace("sygus-process-arg-deps") << "  Look at argument terms..."
396
10
                                    << std::endl;
397
398
    // list of all arguments
399
20
    std::vector<Node> arg_list;
400
    // now look at the terms for unprocessed arguments
401
16
    for (std::unordered_map<Node, std::vector<unsigned>>::iterator it =
402
10
             term_to_args.begin();
403
26
         it != term_to_args.end();
404
         ++it)
405
    {
406
32
      Node nn = it->first;
407
16
      arg_list.push_back(nn);
408
16
      if (Trace.isOn("sygus-process-arg-deps"))
409
      {
410
        Trace("sygus-process-arg-deps") << "    argument " << nn;
411
        Trace("sygus-process-arg-deps") << " (" << it->second.size()
412
                                        << " positions)";
413
        // check the status of this term
414
        if (nn.isVar() && synth_fv.find(nn) != synth_fv.end())
415
        {
416
          // is it relevant?
417
          if (rlv_vars.find(nn) != rlv_vars.end())
418
          {
419
            Trace("sygus-process-arg-deps") << " is a relevant variable."
420
                                            << std::endl;
421
          }
422
          else
423
          {
424
            Trace("sygus-process-arg-deps") << " is an irrelevant variable."
425
                                            << std::endl;
426
          }
427
        }
428
        else
429
        {
430
          // this can be more precise
431
          Trace("sygus-process-arg-deps") << " is a relevant term."
432
                                          << std::endl;
433
        }
434
      }
435
    }
436
437
10
    unsigned arg_list_counter = 0;
438
    // sort arg_list by term size?
439
440
34
    while (arg_list_counter < arg_list.size())
441
    {
442
24
      Node infer_def_t;
443
8
      do
444
      {
445
20
        infer_def_t = Node::null();
446
        // see if we can infer a definition
447
16
        for (std::unordered_map<Node, std::vector<unsigned>>::iterator it =
448
20
                 term_to_args.begin();
449
36
             it != term_to_args.end();
450
             ++it)
451
        {
452
40
          Node def = inferDefinition(it->first, term_to_arg_carry, free_vars);
453
24
          if (!def.isNull())
454
          {
455
16
            Trace("sygus-process-arg-deps") << "  *** Inferred definition "
456
8
                                            << def << " for " << it->first
457
8
                                            << std::endl;
458
            // assign to each argument
459
8
            assignRelevantDef(def, it->second);
460
            // term_to_arg_carry[it->first] = rid;
461
8
            infer_def_t = it->first;
462
8
            break;
463
          }
464
        }
465
20
        if (!infer_def_t.isNull())
466
        {
467
8
          term_to_args.erase(infer_def_t);
468
        }
469
20
      } while (!infer_def_t.isNull());
470
471
      // decide to make an argument relevant
472
12
      bool success = false;
473
44
      while (arg_list_counter < arg_list.size() && !success)
474
      {
475
32
        Node curr = arg_list[arg_list_counter];
476
        std::unordered_map<Node, std::vector<unsigned>>::iterator it =
477
16
            term_to_args.find(curr);
478
16
        if (it != term_to_args.end())
479
        {
480
16
          Trace("sygus-process-arg-deps") << "  *** Decide relevant " << curr
481
8
                                          << std::endl;
482
          // assign relevant to each
483
16
          Node null_def;
484
8
          unsigned rid = assignRelevantDef(null_def, it->second);
485
8
          term_to_arg_carry[curr] = rid;
486
16
          Trace("sygus-process-arg-deps")
487
8
              << "    carry " << curr << " by argument #" << rid << std::endl;
488
8
          term_to_args.erase(curr);
489
8
          success = true;
490
        }
491
16
        arg_list_counter++;
492
      }
493
    }
494
  }
495
10
}
496
497
bool SynthConjectureProcessFun::isArgRelevant(unsigned i)
498
{
499
  return d_arg_props[i].d_relevant;
500
}
501
502
8
void SynthConjectureProcessFun::getIrrelevantArgs(
503
    std::unordered_set<unsigned>& args)
504
{
505
88
  for (unsigned i = 0; i < d_arg_vars.size(); i++)
506
  {
507
80
    if (!d_arg_props[i].d_relevant)
508
    {
509
68
      args.insert(i);
510
    }
511
  }
512
8
}
513
514
1900
SynthConjectureProcess::SynthConjectureProcess() {}
515
1896
SynthConjectureProcess::~SynthConjectureProcess() {}
516
542
Node SynthConjectureProcess::preSimplify(Node q)
517
{
518
542
  Trace("sygus-process") << "Pre-simplify conjecture : " << q << std::endl;
519
542
  return q;
520
}
521
522
542
Node SynthConjectureProcess::postSimplify(Node q)
523
{
524
542
  Trace("sygus-process") << "Post-simplify conjecture : " << q << std::endl;
525
542
  Assert(q.getKind() == FORALL);
526
527
542
  if (options::sygusArgRelevant())
528
  {
529
    // initialize the information about each function to synthesize
530
14
    for (unsigned i = 0, size = q[0].getNumChildren(); i < size; i++)
531
    {
532
16
      Node f = q[0][i];
533
8
      if (f.getType().isFunction())
534
      {
535
8
        d_sf_info[f].init(f);
536
      }
537
    }
538
539
    // get the base on the conjecture
540
12
    Node base = q[1];
541
12
    std::unordered_set<Node> synth_fv;
542
6
    if (base.getKind() == NOT && base[0].getKind() == FORALL)
543
    {
544
48
      for (unsigned j = 0, size = base[0][0].getNumChildren(); j < size; j++)
545
      {
546
42
        synth_fv.insert(base[0][0][j]);
547
      }
548
6
      base = base[0][1];
549
    }
550
12
    std::vector<Node> conjuncts;
551
6
    getComponentVector(AND, base, conjuncts);
552
553
    // process the conjunctions
554
8
    for (std::map<Node, SynthConjectureProcessFun>::iterator it =
555
6
             d_sf_info.begin();
556
14
         it != d_sf_info.end();
557
         ++it)
558
    {
559
16
      Node f = it->first;
560
22
      for (const Node& conj : conjuncts)
561
      {
562
14
        processConjunct(conj, f, synth_fv);
563
      }
564
    }
565
  }
566
567
542
  return q;
568
}
569
570
409
void SynthConjectureProcess::initialize(Node n, std::vector<Node>& candidates)
571
{
572
409
  if (Trace.isOn("sygus-process"))
573
  {
574
    Trace("sygus-process") << "Process conjecture : " << n
575
                           << " with candidates: " << std::endl;
576
    for (unsigned i = 0; i < candidates.size(); i++)
577
    {
578
      Trace("sygus-process") << "  " << candidates[i] << std::endl;
579
    }
580
  }
581
409
}
582
583
bool SynthConjectureProcess::isArgRelevant(Node f, unsigned i)
584
{
585
  if (!options::sygusArgRelevant())
586
  {
587
    return true;
588
  }
589
  std::map<Node, SynthConjectureProcessFun>::iterator its = d_sf_info.find(f);
590
  if (its != d_sf_info.end())
591
  {
592
    return its->second.isArgRelevant(i);
593
  }
594
  Assert(false);
595
  return true;
596
}
597
598
583
bool SynthConjectureProcess::getIrrelevantArgs(
599
    Node f, std::unordered_set<unsigned>& args)
600
{
601
583
  std::map<Node, SynthConjectureProcessFun>::iterator its = d_sf_info.find(f);
602
583
  if (its != d_sf_info.end())
603
  {
604
8
    its->second.getIrrelevantArgs(args);
605
8
    return true;
606
  }
607
575
  return false;
608
}
609
610
14
void SynthConjectureProcess::processConjunct(Node n,
611
                                             Node f,
612
                                             std::unordered_set<Node>& synth_fv)
613
{
614
14
  Trace("sygus-process-arg-deps") << "Process conjunct: " << std::endl;
615
28
  Trace("sygus-process-arg-deps") << "  " << n << " for synth fun " << f
616
14
                                  << "..." << std::endl;
617
618
  // first, flatten the conjunct
619
  // make a copy of free variables since we may add new ones
620
28
  std::unordered_set<Node> synth_fv_n = synth_fv;
621
28
  std::unordered_map<Node, Node> defs;
622
28
  Node nf = flatten(n, f, synth_fv_n, defs);
623
624
14
  Trace("sygus-process-arg-deps") << "Flattened to: " << std::endl;
625
14
  Trace("sygus-process-arg-deps") << "  " << nf << std::endl;
626
627
  // get free variables in nf
628
28
  std::unordered_map<Node, std::unordered_set<Node>> free_vars;
629
14
  getFreeVariables(nf, synth_fv_n, free_vars);
630
  // get free variables in each application
631
28
  std::vector<Node> ns;
632
28
  std::vector<Node> ks;
633
24
  for (std::unordered_map<Node, Node>::iterator it = defs.begin();
634
24
       it != defs.end();
635
       ++it)
636
  {
637
10
    getFreeVariables(it->second, synth_fv_n, free_vars);
638
10
    ns.push_back(it->second);
639
10
    ks.push_back(it->first);
640
  }
641
642
  // process the applications of synthesis functions
643
14
  if (!ns.empty())
644
  {
645
10
    std::map<Node, SynthConjectureProcessFun>::iterator its = d_sf_info.find(f);
646
10
    if (its != d_sf_info.end())
647
    {
648
10
      its->second.processTerms(ns, ks, nf, synth_fv_n, free_vars);
649
    }
650
  }
651
14
}
652
653
14
Node SynthConjectureProcess::SynthConjectureProcess::flatten(
654
    Node n,
655
    Node f,
656
    std::unordered_set<Node>& synth_fv,
657
    std::unordered_map<Node, Node>& defs)
658
{
659
28
  std::unordered_map<Node, Node> visited;
660
14
  std::unordered_map<Node, Node>::iterator it;
661
28
  std::stack<Node> visit;
662
28
  Node cur;
663
14
  visit.push(n);
664
508
  do
665
  {
666
522
    cur = visit.top();
667
522
    visit.pop();
668
522
    it = visited.find(cur);
669
670
522
    if (it == visited.end())
671
    {
672
236
      visited[cur] = Node::null();
673
236
      visit.push(cur);
674
508
      for (unsigned i = 0; i < cur.getNumChildren(); i++)
675
      {
676
272
        visit.push(cur[i]);
677
      }
678
    }
679
286
    else if (it->second.isNull())
680
    {
681
472
      Node ret = cur;
682
236
      bool childChanged = false;
683
472
      std::vector<Node> children;
684
236
      if (cur.getMetaKind() == kind::metakind::PARAMETERIZED)
685
      {
686
14
        children.push_back(cur.getOperator());
687
      }
688
508
      for (unsigned i = 0; i < cur.getNumChildren(); i++)
689
      {
690
272
        it = visited.find(cur[i]);
691
272
        Assert(it != visited.end());
692
272
        Assert(!it->second.isNull());
693
272
        childChanged = childChanged || cur[i] != it->second;
694
272
        children.push_back(it->second);
695
      }
696
236
      if (childChanged)
697
      {
698
38
        ret = NodeManager::currentNM()->mkNode(cur.getKind(), children);
699
      }
700
      // is it the function to synthesize?
701
236
      if (cur.getKind() == APPLY_UF && cur.getOperator() == f)
702
      {
703
        // if so, flatten
704
20
        Node k = NodeManager::currentNM()->mkBoundVar("vf", cur.getType());
705
10
        defs[k] = ret;
706
10
        ret = k;
707
10
        synth_fv.insert(k);
708
      }
709
      // post-rewrite
710
236
      visited[cur] = ret;
711
    }
712
522
  } while (!visit.empty());
713
14
  Assert(visited.find(n) != visited.end());
714
14
  Assert(!visited.find(n)->second.isNull());
715
28
  return visited[n];
716
}
717
718
24
void SynthConjectureProcess::getFreeVariables(
719
    Node n,
720
    std::unordered_set<Node>& synth_fv,
721
    std::unordered_map<Node, std::unordered_set<Node>>& free_vars)
722
{
723
  // first must compute free variables in each subterm of n,
724
  // as well as contains_synth_fun
725
48
  std::unordered_map<Node, bool> visited;
726
24
  std::unordered_map<Node, bool>::iterator it;
727
48
  std::stack<Node> visit;
728
48
  Node cur;
729
24
  visit.push(n);
730
532
  do
731
  {
732
556
    cur = visit.top();
733
556
    visit.pop();
734
556
    it = visited.find(cur);
735
736
556
    if (it == visited.end())
737
    {
738
260
      visited[cur] = false;
739
260
      visit.push(cur);
740
532
      for (unsigned i = 0; i < cur.getNumChildren(); i++)
741
      {
742
272
        visit.push(cur[i]);
743
      }
744
    }
745
296
    else if (!it->second)
746
    {
747
260
      free_vars[cur].clear();
748
260
      if (synth_fv.find(cur) != synth_fv.end())
749
      {
750
        // it is a free variable
751
124
        free_vars[cur].insert(cur);
752
      }
753
      else
754
      {
755
        // otherwise, carry the free variables from the children
756
408
        for (unsigned i = 0; i < cur.getNumChildren(); i++)
757
        {
758
544
          free_vars[cur].insert(free_vars[cur[i]].begin(),
759
544
                                free_vars[cur[i]].end());
760
        }
761
      }
762
260
      visited[cur] = true;
763
    }
764
556
  } while (!visit.empty());
765
24
}
766
767
16796
Node SynthConjectureProcess::getSymmetryBreakingPredicate(
768
    Node x, Node e, TypeNode tn, unsigned tindex, unsigned depth)
769
{
770
16796
  return Node::null();
771
}
772
773
void SynthConjectureProcess::debugPrint(const char* c) {}
774
6
void SynthConjectureProcess::getComponentVector(Kind k,
775
                                                Node n,
776
                                                std::vector<Node>& args)
777
{
778
6
  if (n.getKind() == k)
779
  {
780
12
    for (unsigned i = 0; i < n.getNumChildren(); i++)
781
    {
782
8
      args.push_back(n[i]);
783
    }
784
  }
785
  else
786
  {
787
2
    args.push_back(n);
788
  }
789
6
}
790
791
}  // namespace quantifiers
792
}  // namespace theory
793
31137
}  // namespace cvc5