GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/proof/lfsc/lfsc_node_converter.cpp Lines: 221 594 37.2 %
Date: 2021-11-05 Branches: 436 2536 17.2 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds
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 LFSC node conversion
14
 */
15
16
#include "proof/lfsc/lfsc_node_converter.h"
17
18
#include <sstream>
19
20
#include "expr/array_store_all.h"
21
#include "expr/dtype.h"
22
#include "expr/dtype_cons.h"
23
#include "expr/nary_term_util.h"
24
#include "expr/node_manager_attributes.h"
25
#include "expr/sequence.h"
26
#include "expr/skolem_manager.h"
27
#include "printer/smt2/smt2_printer.h"
28
#include "theory/bv/theory_bv_utils.h"
29
#include "theory/strings/word.h"
30
#include "theory/uf/theory_uf_rewriter.h"
31
#include "util/bitvector.h"
32
#include "util/iand.h"
33
#include "util/rational.h"
34
#include "util/regexp.h"
35
#include "util/string.h"
36
37
using namespace cvc5::kind;
38
39
namespace cvc5 {
40
namespace proof {
41
42
1
LfscNodeConverter::LfscNodeConverter()
43
{
44
1
  NodeManager* nm = NodeManager::currentNM();
45
1
  d_arrow = nm->mkSortConstructor("arrow", 2);
46
47
1
  d_sortType = nm->mkSort("sortType");
48
  // the embedding of arrow into Node, which is binary constructor over sorts
49
2
  TypeNode anfType = nm->mkFunctionType({d_sortType, d_sortType}, d_sortType);
50
1
  d_typeAsNode[d_arrow] = getSymbolInternal(FUNCTION_TYPE, anfType, "arrow");
51
52
2
  TypeNode intType = nm->integerType();
53
2
  TypeNode arrType = nm->mkFunctionType({d_sortType, d_sortType}, d_sortType);
54
1
  d_typeKindToNodeCons[ARRAY_TYPE] =
55
2
      getSymbolInternal(FUNCTION_TYPE, arrType, "Array");
56
2
  TypeNode bvType = nm->mkFunctionType(intType, d_sortType);
57
1
  d_typeKindToNodeCons[BITVECTOR_TYPE] =
58
2
      getSymbolInternal(FUNCTION_TYPE, bvType, "BitVec");
59
2
  TypeNode fpType = nm->mkFunctionType({intType, intType}, d_sortType);
60
1
  d_typeKindToNodeCons[FLOATINGPOINT_TYPE] =
61
2
      getSymbolInternal(FUNCTION_TYPE, fpType, "FloatingPoint");
62
2
  TypeNode setType = nm->mkFunctionType(d_sortType, d_sortType);
63
1
  d_typeKindToNodeCons[SET_TYPE] =
64
2
      getSymbolInternal(FUNCTION_TYPE, setType, "Set");
65
1
  d_typeKindToNodeCons[BAG_TYPE] =
66
2
      getSymbolInternal(FUNCTION_TYPE, setType, "Bag");
67
1
  d_typeKindToNodeCons[SEQUENCE_TYPE] =
68
2
      getSymbolInternal(FUNCTION_TYPE, setType, "Seq");
69
1
}
70
71
80
Node LfscNodeConverter::postConvert(Node n)
72
{
73
80
  NodeManager* nm = NodeManager::currentNM();
74
80
  Kind k = n.getKind();
75
80
  if (k == ASCRIPTION_TYPE)
76
  {
77
    // dummy node, return it
78
    return n;
79
  }
80
160
  TypeNode tn = n.getType();
81
160
  Trace("lfsc-term-process-debug")
82
80
      << "postConvert " << n << " " << k << std::endl;
83
80
  if (k == BOUND_VARIABLE)
84
  {
85
    // ignore internally generated symbols
86
3
    if (d_symbols.find(n) != d_symbols.end())
87
    {
88
3
      return n;
89
    }
90
    // bound variable v is (bvar x T)
91
    TypeNode intType = nm->integerType();
92
    Node x = nm->mkConst(Rational(getOrAssignIndexForVar(n)));
93
    Node tc = typeAsNode(convertType(tn));
94
    TypeNode ftype = nm->mkFunctionType({intType, d_sortType}, tn);
95
    Node bvarOp = getSymbolInternal(k, ftype, "bvar");
96
    return nm->mkNode(APPLY_UF, bvarOp, x, tc);
97
  }
98
77
  else if (k == SKOLEM || k == BOOLEAN_TERM_VARIABLE)
99
  {
100
    // constructors/selectors are represented by skolems, which are defined
101
    // symbols
102
    if (tn.isConstructor() || tn.isSelector() || tn.isTester()
103
        || tn.isUpdater())
104
    {
105
      // note these are not converted to their user named (cvc.) symbols here,
106
      // to avoid type errors when constructing terms for postConvert
107
      return n;
108
    }
109
    // skolems v print as their witness forms
110
    // v is (skolem W) where W is the original or witness form of v
111
    Node wi = SkolemManager::getOriginalForm(n);
112
    if (wi == n)
113
    {
114
      // if it is not a purification skolem, maybe it is a witness skolem
115
      wi = SkolemManager::getWitnessForm(n);
116
    }
117
    if (!wi.isNull() && wi != n)
118
    {
119
      Trace("lfsc-term-process-debug") << "...witness form " << wi << std::endl;
120
      wi = convert(wi);
121
      Trace("lfsc-term-process-debug")
122
          << "...converted witness for " << wi << std::endl;
123
      TypeNode ftype = nm->mkFunctionType(tn, tn);
124
      Node skolemOp = getSymbolInternal(k, ftype, "skolem");
125
      return nm->mkNode(APPLY_UF, skolemOp, wi);
126
    }
127
    // might be a skolem function
128
    Node ns = maybeMkSkolemFun(n);
129
    if (!ns.isNull())
130
    {
131
      return ns;
132
    }
133
    // Otherwise, it is an uncategorized skolem, must use a fresh variable.
134
    // This case will only apply for terms originating from places with no
135
    // proof support.
136
    TypeNode intType = nm->integerType();
137
    TypeNode varType = nm->mkFunctionType({intType, d_sortType}, tn);
138
    Node var = mkInternalSymbol("var", varType);
139
    Node index = nm->mkConst(Rational(getOrAssignIndexForVar(n)));
140
    Node tc = typeAsNode(convertType(tn));
141
    return nm->mkNode(APPLY_UF, var, index, tc);
142
  }
143
77
  else if (n.isVar())
144
  {
145
10
    std::stringstream ss;
146
5
    ss << n;
147
10
    Node nn = mkInternalSymbol(getNameForUserName(ss.str()), tn);
148
5
    return nn;
149
  }
150
72
  else if (k == APPLY_UF)
151
  {
152
2
    return convert(theory::uf::TheoryUfRewriter::getHoApplyForApplyUf(n));
153
  }
154
70
  else if (k == APPLY_CONSTRUCTOR || k == APPLY_SELECTOR || k == APPLY_TESTER
155
70
           || k == APPLY_SELECTOR_TOTAL || k == APPLY_UPDATER)
156
  {
157
    // must convert other kinds of apply to functions, since we convert to
158
    // HO_APPLY
159
    Node opc = getOperatorOfTerm(n, true);
160
    if (n.getNumChildren() == 0)
161
    {
162
      return opc;
163
    }
164
    std::vector<Node> children;
165
    children.push_back(opc);
166
    children.insert(children.end(), n.begin(), n.end());
167
    return postConvert(nm->mkNode(APPLY_UF, children));
168
  }
169
70
  else if (k == HO_APPLY)
170
  {
171
46
    std::vector<TypeNode> argTypes;
172
23
    argTypes.push_back(n[0].getType());
173
23
    argTypes.push_back(n[1].getType());
174
46
    TypeNode tnh = nm->mkFunctionType(argTypes, tn);
175
46
    Node hconstf = getSymbolInternal(k, tnh, "apply");
176
23
    return nm->mkNode(APPLY_UF, hconstf, n[0], n[1]);
177
  }
178
47
  else if (k == CONST_RATIONAL || k == CAST_TO_REAL)
179
  {
180
5
    if (k == CAST_TO_REAL)
181
    {
182
      // already converted
183
      do
184
      {
185
        n = n[0];
186
        Assert(n.getKind() == APPLY_UF || n.getKind() == CONST_RATIONAL);
187
      } while (n.getKind() != CONST_RATIONAL);
188
    }
189
10
    TypeNode tnv = nm->mkFunctionType(tn, tn);
190
10
    Node rconstf;
191
10
    Node arg;
192
10
    Rational r = n.getConst<Rational>();
193
5
    if (tn.isInteger())
194
    {
195
5
      rconstf = getSymbolInternal(k, tnv, "int");
196
5
      if (r.sgn() == -1)
197
      {
198
        // use LFSC syntax for mpz negation
199
        Node mpzn = getSymbolInternal(k, nm->mkFunctionType(tn, tn), "~");
200
        arg = nm->mkNode(APPLY_UF, mpzn, nm->mkConst(r.abs()));
201
      }
202
      else
203
      {
204
5
        arg = n;
205
      }
206
    }
207
    else
208
    {
209
      rconstf = getSymbolInternal(k, tnv, "real");
210
      // ensure rationals are printed properly here using mpq syntax
211
      // Note that inconvieniently, LFSC uses (non-sexpr) syntax n/m for
212
      // constant rationals, hence we must use a string
213
      std::stringstream ss;
214
      ss << "__LFSC_TMP" << r.getNumerator().abs() << "/" << r.getDenominator();
215
      arg = mkInternalSymbol(ss.str(), tn);
216
      // negative (~ n/m)
217
      if (r.sgn() == -1)
218
      {
219
        Node mpzn = getSymbolInternal(k, nm->mkFunctionType(tn, tn), "~");
220
        arg = nm->mkNode(APPLY_UF, mpzn, arg);
221
      }
222
    }
223
5
    return nm->mkNode(APPLY_UF, rconstf, arg);
224
  }
225
42
  else if (k == CONST_BITVECTOR)
226
  {
227
    TypeNode btn = nm->booleanType();
228
    TypeNode tnv = nm->mkFunctionType(btn, tn);
229
    TypeNode btnv = nm->mkFunctionType({btn, btn}, btn);
230
    BitVector bv = n.getConst<BitVector>();
231
    size_t w = bv.getSize();
232
    Node ret = getSymbolInternal(k, btn, "bvn");
233
    Node b0 = getSymbolInternal(k, btn, "b0");
234
    Node b1 = getSymbolInternal(k, btn, "b1");
235
    Node bvc = getSymbolInternal(k, btnv, "bvc");
236
    for (size_t i = 0; i < w; i++)
237
    {
238
      Node arg = bv.isBitSet((w - 1) - i) ? b1 : b0;
239
      ret = nm->mkNode(APPLY_UF, bvc, arg, ret);
240
    }
241
    Node bconstf = getSymbolInternal(k, tnv, "bv");
242
    return nm->mkNode(APPLY_UF, bconstf, ret);
243
  }
244
42
  else if (k == CONST_STRING)
245
  {
246
    //"" is emptystr
247
    //"A" is (char 65)
248
    //"ABC" is (str.++ (char 65) (str.++ (char 66) (str.++ (char 67) emptystr)))
249
    std::vector<Node> charVec;
250
    getCharVectorInternal(n, charVec);
251
    Assert(!charVec.empty());
252
    if (charVec.size() == 1)
253
    {
254
      // handles empty string and singleton character
255
      return charVec[0];
256
    }
257
    std::reverse(charVec.begin(), charVec.end());
258
    Node ret = postConvert(getNullTerminator(STRING_CONCAT, tn));
259
    for (size_t i = 0, size = charVec.size(); i < size; i++)
260
    {
261
      ret = nm->mkNode(STRING_CONCAT, charVec[i], ret);
262
    }
263
    return ret;
264
  }
265
42
  else if (k == CONST_SEQUENCE)
266
  {
267
    const std::vector<Node>& charVec = n.getConst<Sequence>().getVec();
268
    TypeNode etype = nm->mkFunctionType(d_sortType, tn);
269
    Node ret = getSymbolInternal(k, etype, "seq.empty");
270
    ret = nm->mkNode(APPLY_UF, ret, typeAsNode(convertType(tn)));
271
    std::vector<Node> vecu;
272
    for (size_t i = 0, size = charVec.size(); i < size; i++)
273
    {
274
      Node u = nm->mkNode(SEQ_UNIT, postConvert(charVec[size - (i + 1)]));
275
      if (size == 1)
276
      {
277
        // singleton case
278
        return u;
279
      }
280
      ret = nm->mkNode(STRING_CONCAT, u, ret);
281
    }
282
    return ret;
283
  }
284
42
  else if (k == STORE_ALL)
285
  {
286
    Node t = typeAsNode(convertType(tn));
287
    TypeNode caRetType = nm->mkFunctionType(tn.getArrayConstituentType(), tn);
288
    TypeNode catype = nm->mkFunctionType(d_sortType, caRetType);
289
    Node bconstf = getSymbolInternal(k, catype, "array_const");
290
    Node f = nm->mkNode(APPLY_UF, bconstf, t);
291
    ArrayStoreAll storeAll = n.getConst<ArrayStoreAll>();
292
    return nm->mkNode(APPLY_UF, f, convert(storeAll.getValue()));
293
  }
294
126
  else if (k == GEQ || k == GT || k == LEQ || k == LT || k == MINUS
295
42
           || k == DIVISION || k == DIVISION_TOTAL || k == INTS_DIVISION
296
42
           || k == INTS_DIVISION_TOTAL || k == INTS_MODULUS
297
42
           || k == INTS_MODULUS_TOTAL || k == UMINUS || k == POW
298
84
           || isIndexedOperatorKind(k))
299
  {
300
    // must give special names to SMT-LIB operators with arithmetic subtyping
301
    // note that MINUS is not n-ary
302
    // get the macro-apply version of the operator
303
    Node opc = getOperatorOfTerm(n, true);
304
    std::vector<Node> children;
305
    children.push_back(opc);
306
    children.insert(children.end(), n.begin(), n.end());
307
    return nm->mkNode(APPLY_UF, children);
308
  }
309
42
  else if (k == EMPTYSET || k == UNIVERSE_SET || k == EMPTYBAG)
310
  {
311
    Node t = typeAsNode(convertType(tn));
312
    TypeNode etype = nm->mkFunctionType(d_sortType, tn);
313
    Node ef = getSymbolInternal(
314
        k,
315
        etype,
316
        k == EMPTYSET ? "emptyset"
317
                      : (k == UNIVERSE_SET ? "univset" : "emptybag"));
318
    return nm->mkNode(APPLY_UF, ef, t);
319
  }
320
42
  else if (n.isClosure())
321
  {
322
    // (forall ((x1 T1) ... (xn Tk)) P) is
323
    // ((forall x1 T1) ((forall x2 T2) ... ((forall xk Tk) P))). We use
324
    // SEXPR to do this, which avoids the need for indexed operators.
325
    Node ret = n[1];
326
    Node cop = getOperatorOfClosure(n, true);
327
    for (size_t i = 0, nchild = n[0].getNumChildren(); i < nchild; i++)
328
    {
329
      size_t ii = (nchild - 1) - i;
330
      Node v = n[0][ii];
331
      Node vop = getOperatorOfBoundVar(cop, v);
332
      ret = nm->mkNode(APPLY_UF, vop, ret);
333
    }
334
    // notice that intentionally we drop annotations here
335
    return ret;
336
  }
337
42
  else if (k == REGEXP_LOOP)
338
  {
339
    // ((_ re.loop n1 n2) t) is ((re.loop n1 n2) t)
340
    TypeNode intType = nm->integerType();
341
    TypeNode relType =
342
        nm->mkFunctionType({intType, intType}, nm->mkFunctionType(tn, tn));
343
    Node rop = getSymbolInternal(
344
        k, relType, printer::smt2::Smt2Printer::smtKindString(k));
345
    RegExpLoop op = n.getOperator().getConst<RegExpLoop>();
346
    Node n1 = nm->mkConst(Rational(op.d_loopMinOcc));
347
    Node n2 = nm->mkConst(Rational(op.d_loopMaxOcc));
348
    return nm->mkNode(APPLY_UF, nm->mkNode(APPLY_UF, rop, n1, n2), n[0]);
349
  }
350
42
  else if (k == MATCH)
351
  {
352
    // currently unsupported
353
    return n;
354
  }
355
42
  else if (k == BITVECTOR_BB_TERM)
356
  {
357
    TypeNode btn = nm->booleanType();
358
    // (bbT t1 ... tn) is (bbT t1 (bbT t2 ... (bbT tn emptybv)))
359
    // where notice that each bbT has a different type
360
    Node curr = getNullTerminator(BITVECTOR_CONCAT, tn);
361
    for (size_t i = 0, nchild = n.getNumChildren(); i < nchild; ++i)
362
    {
363
      TypeNode bvt = nm->mkBitVectorType(i + 1);
364
      TypeNode ftype = nm->mkFunctionType({btn, curr.getType()}, bvt);
365
      Node bbt = getSymbolInternal(k, ftype, "bbT");
366
      curr = nm->mkNode(APPLY_UF, bbt, n[nchild - (i + 1)], curr);
367
    }
368
    return curr;
369
  }
370
42
  else if (k == SEP_NIL)
371
  {
372
    Node tnn = typeAsNode(convertType(tn));
373
    TypeNode ftype = nm->mkFunctionType(d_sortType, tn);
374
    Node s = getSymbolInternal(k, ftype, "sep.nil");
375
    return nm->mkNode(APPLY_UF, s, tnn);
376
  }
377
42
  else if (NodeManager::isNAryKind(k) && n.getNumChildren() >= 2)
378
  {
379
7
    size_t nchild = n.getNumChildren();
380
7
    Assert(n.getMetaKind() != metakind::PARAMETERIZED);
381
    // convert all n-ary applications to binary
382
14
    std::vector<Node> children(n.begin(), n.end());
383
    // distinct is special case
384
7
    if (k == DISTINCT)
385
    {
386
      // DISTINCT(x1,...,xn) --->
387
      // AND(DISTINCT(x1,x2), AND(,..., AND(,..,DISTINCT(x_{n-1},x_n))))
388
2
      Node ret = nm->mkNode(k, children[0], children[1]);
389
4
      for (unsigned i = 0; i < nchild; i++)
390
6
        for (unsigned j = i + 1; j < nchild; j++)
391
        {
392
3
          if (i != 0 && j != 1)
393
          {
394
1
            ret = nm->mkNode(AND, ret, nm->mkNode(k, children[i], children[j]));
395
          }
396
        }
397
2
      Trace("lfsc-term-process-debug") << "n: " << n << std::endl
398
1
                                       << "ret: " << ret << std::endl;
399
1
      return ret;
400
    }
401
6
    std::reverse(children.begin(), children.end());
402
    // Add the null-terminator. This is done to disambiguate the number
403
    // of children for term with n-ary operators. In particular note that
404
    // (or A B C (or D E)) has representation:
405
    //   (or A (or B (or C (or (or D E) false))))
406
    // This makes the AST above distinguishable from (or A B C D E),
407
    // which otherwise would both have representation:
408
    //   (or A (or B (or C (or D E))))
409
12
    Node nullTerm = getNullTerminator(k, tn);
410
    // Most operators simply get binarized
411
12
    Node ret;
412
6
    size_t istart = 0;
413
6
    if (nullTerm.isNull())
414
    {
415
      ret = children[0];
416
      istart = 1;
417
    }
418
    else
419
    {
420
      // must convert recursively, since nullTerm may have subterms.
421
6
      ret = convert(nullTerm);
422
    }
423
    // the kind to chain
424
6
    Kind ck = k;
425
    // check whether we are also changing the operator name, in which case
426
    // we build a binary uninterpreted function opc
427
12
    Node opc;
428
6
    if (k == PLUS || k == MULT || k == NONLINEAR_MULT)
429
    {
430
      std::stringstream opName;
431
      // currently allow subtyping
432
      opName << "a.";
433
      opName << printer::smt2::Smt2Printer::smtKindString(k);
434
      TypeNode ftype = nm->mkFunctionType({tn, tn}, tn);
435
      opc = getSymbolInternal(k, ftype, opName.str());
436
      ck = APPLY_UF;
437
    }
438
    // now, iterate over children and make binary conversion
439
22
    for (size_t i = istart, npchild = children.size(); i < npchild; i++)
440
    {
441
16
      if (!opc.isNull())
442
      {
443
        ret = nm->mkNode(ck, opc, children[i], ret);
444
      }
445
      else
446
      {
447
16
        ret = nm->mkNode(ck, children[i], ret);
448
      }
449
    }
450
6
    return ret;
451
  }
452
35
  return n;
453
}
454
455
3
TypeNode LfscNodeConverter::postConvertType(TypeNode tn)
456
{
457
3
  NodeManager* nm = NodeManager::currentNM();
458
3
  TypeNode cur = tn;
459
6
  Node tnn;
460
3
  Kind k = tn.getKind();
461
6
  Trace("lfsc-term-process-debug")
462
6
      << "postConvertType " << tn << " " << tn.getNumChildren() << " " << k
463
3
      << std::endl;
464
3
  if (k == FUNCTION_TYPE)
465
  {
466
    // (-> T1 ... Tn T) is (arrow T1 .... (arrow Tn T))
467
2
    std::vector<TypeNode> argTypes = tn.getArgTypes();
468
    // also make the node embedding of the type
469
2
    Node arrown = d_typeAsNode[d_arrow];
470
1
    Assert(!arrown.isNull());
471
1
    cur = tn.getRangeType();
472
1
    tnn = typeAsNode(cur);
473
2
    for (std::vector<TypeNode>::reverse_iterator it = argTypes.rbegin();
474
2
         it != argTypes.rend();
475
         ++it)
476
    {
477
2
      std::vector<TypeNode> aargs;
478
1
      aargs.push_back(*it);
479
1
      aargs.push_back(cur);
480
1
      cur = nm->mkSort(d_arrow, aargs);
481
1
      tnn = nm->mkNode(APPLY_UF, arrown, typeAsNode(*it), tnn);
482
    }
483
  }
484
2
  else if (k == BITVECTOR_TYPE)
485
  {
486
    tnn = d_typeKindToNodeCons[k];
487
    Node w = nm->mkConst(Rational(tn.getBitVectorSize()));
488
    tnn = nm->mkNode(APPLY_UF, tnn, w);
489
  }
490
2
  else if (k == FLOATINGPOINT_TYPE)
491
  {
492
    tnn = d_typeKindToNodeCons[k];
493
    Node e = nm->mkConst(Rational(tn.getFloatingPointExponentSize()));
494
    Node s = nm->mkConst(Rational(tn.getFloatingPointSignificandSize()));
495
    tnn = nm->mkNode(APPLY_UF, tnn, e, s);
496
  }
497
2
  else if (tn.getNumChildren() == 0)
498
  {
499
    // special case: tuples must be distinguished by their arity
500
2
    if (tn.isTuple())
501
    {
502
      const DType& dt = tn.getDType();
503
      unsigned int nargs = dt[0].getNumArgs();
504
      if (nargs > 0)
505
      {
506
        std::vector<TypeNode> types;
507
        std::vector<TypeNode> convTypes;
508
        std::vector<Node> targs;
509
        for (unsigned int i = 0; i < nargs; i++)
510
        {
511
          // it is not converted yet, convert here
512
          TypeNode tnc = convertType(dt[0][i].getRangeType());
513
          types.push_back(d_sortType);
514
          convTypes.push_back(tnc);
515
          targs.push_back(typeAsNode(tnc));
516
        }
517
        TypeNode ftype = nm->mkFunctionType(types, d_sortType);
518
        // must distinguish by arity
519
        std::stringstream ss;
520
        ss << "Tuple_" << nargs;
521
        targs.insert(targs.begin(), getSymbolInternal(k, ftype, ss.str()));
522
        tnn = nm->mkNode(APPLY_UF, targs);
523
        // we are changing its name, we must make a sort constructor
524
        cur = nm->mkSortConstructor(ss.str(), nargs);
525
        cur = nm->mkSort(cur, convTypes);
526
      }
527
    }
528
2
    if (tnn.isNull())
529
    {
530
4
      std::stringstream ss;
531
2
      tn.toStream(ss, Language::LANG_SMTLIB_V2_6);
532
2
      if (tn.isSort() || (tn.isDatatype() && !tn.isTuple()))
533
      {
534
2
        std::stringstream sss;
535
1
        sss << LfscNodeConverter::getNameForUserName(ss.str());
536
1
        tnn = getSymbolInternal(k, d_sortType, sss.str());
537
1
        cur = nm->mkSort(sss.str());
538
      }
539
      else
540
      {
541
1
        tnn = getSymbolInternal(k, d_sortType, ss.str());
542
      }
543
    }
544
  }
545
  else
546
  {
547
    // to build the type-as-node, must convert the component types
548
    std::vector<Node> targs;
549
    std::vector<TypeNode> types;
550
    for (const TypeNode& tnc : tn)
551
    {
552
      targs.push_back(typeAsNode(tnc));
553
      types.push_back(d_sortType);
554
    }
555
    Node op;
556
    if (k == PARAMETRIC_DATATYPE)
557
    {
558
      // erase first child, which repeats the datatype
559
      targs.erase(targs.begin(), targs.begin() + 1);
560
      types.erase(types.begin(), types.begin() + 1);
561
      TypeNode ftype = nm->mkFunctionType(types, d_sortType);
562
      // the operator has been converted; it is no longer a datatype, thus
563
      // we must print to get its name.
564
      std::stringstream ss;
565
      ss << tn[0];
566
      op = getSymbolInternal(k, ftype, ss.str());
567
    }
568
    else if (k == SORT_TYPE)
569
    {
570
      TypeNode ftype = nm->mkFunctionType(types, d_sortType);
571
      std::string name;
572
      tn.getAttribute(expr::VarNameAttr(), name);
573
      op = getSymbolInternal(k, ftype, name);
574
    }
575
    else
576
    {
577
      std::map<Kind, Node>::iterator it = d_typeKindToNodeCons.find(k);
578
      if (it != d_typeKindToNodeCons.end())
579
      {
580
        op = it->second;
581
      }
582
    }
583
    if (!op.isNull())
584
    {
585
      targs.insert(targs.begin(), op);
586
      tnn = nm->mkNode(APPLY_UF, targs);
587
    }
588
    else
589
    {
590
      AlwaysAssert(false);
591
    }
592
  }
593
3
  Assert(!tnn.isNull());
594
3
  Trace("lfsc-term-process-debug") << "...type as node: " << tnn << std::endl;
595
3
  d_typeAsNode[cur] = tnn;
596
6
  return cur;
597
}
598
599
6
std::string LfscNodeConverter::getNameForUserName(const std::string& name)
600
{
601
12
  std::stringstream ss;
602
6
  ss << "cvc." << name;
603
12
  return ss.str();
604
}
605
606
80
bool LfscNodeConverter::shouldTraverse(Node n)
607
{
608
80
  Kind k = n.getKind();
609
  // don't convert bound variable or instantiation pattern list directly
610
80
  if (k == BOUND_VAR_LIST || k == INST_PATTERN_LIST)
611
  {
612
    return false;
613
  }
614
  // should not traverse internal applications
615
80
  if (k == APPLY_UF)
616
  {
617
2
    if (d_symbols.find(n.getOperator()) != d_symbols.end())
618
    {
619
      return false;
620
    }
621
  }
622
80
  return true;
623
}
624
625
Node LfscNodeConverter::maybeMkSkolemFun(Node k, bool macroApply)
626
{
627
  NodeManager* nm = NodeManager::currentNM();
628
  SkolemManager* sm = nm->getSkolemManager();
629
  SkolemFunId sfi = SkolemFunId::NONE;
630
  Node cacheVal;
631
  TypeNode tn = k.getType();
632
  if (sm->isSkolemFunction(k, sfi, cacheVal))
633
  {
634
    if (sfi == SkolemFunId::SHARED_SELECTOR)
635
    {
636
      // a skolem corresponding to shared selector should print in
637
      // LFSC as (sel T n) where T is the type and n is the index of the
638
      // shared selector.
639
      TypeNode fselt = nm->mkFunctionType(tn.getSelectorDomainType(),
640
                                          tn.getSelectorRangeType());
641
      TypeNode intType = nm->integerType();
642
      TypeNode selt = nm->mkFunctionType({d_sortType, intType}, fselt);
643
      Node sel = getSymbolInternal(k.getKind(), selt, "sel");
644
      Node kn = typeAsNode(convertType(tn.getSelectorRangeType()));
645
      Assert(!cacheVal.isNull() && cacheVal.getKind() == CONST_RATIONAL);
646
      return nm->mkNode(APPLY_UF, sel, kn, cacheVal);
647
    }
648
    else if (sfi == SkolemFunId::RE_UNFOLD_POS_COMPONENT)
649
    {
650
      // a skolem corresponding to a regular expression unfolding component
651
      // should print as (skolem_re_unfold_pos t R n) where the skolem is the
652
      // n^th component for the unfolding of (str.in_re t R).
653
      TypeNode strType = nm->stringType();
654
      TypeNode reType = nm->regExpType();
655
      TypeNode intType = nm->integerType();
656
      TypeNode reut = nm->mkFunctionType({strType, reType, intType}, strType);
657
      Node sk = getSymbolInternal(k.getKind(), reut, "skolem_re_unfold_pos");
658
      Assert(!cacheVal.isNull() && cacheVal.getKind() == SEXPR
659
             && cacheVal.getNumChildren() == 3);
660
      // third value is mpz, which is not converted
661
      return nm->mkNode(
662
          APPLY_UF,
663
          {sk, convert(cacheVal[0]), convert(cacheVal[1]), cacheVal[2]});
664
    }
665
  }
666
  return Node::null();
667
}
668
669
2
Node LfscNodeConverter::typeAsNode(TypeNode tni) const
670
{
671
  // should always exist in the cache, as we always run types through
672
  // postConvertType before calling this method.
673
2
  std::map<TypeNode, Node>::const_iterator it = d_typeAsNode.find(tni);
674
2
  AlwaysAssert(it != d_typeAsNode.end()) << "Missing typeAsNode " << tni;
675
2
  return it->second;
676
}
677
678
23
Node LfscNodeConverter::mkInternalSymbol(const std::string& name, TypeNode tn)
679
{
680
23
  Node sym = NodeManager::currentNM()->mkBoundVar(name, tn);
681
23
  d_symbols.insert(sym);
682
23
  return sym;
683
}
684
685
Node LfscNodeConverter::getSymbolInternalFor(Node n, const std::string& name)
686
{
687
  return getSymbolInternal(n.getKind(), n.getType(), name);
688
}
689
690
42
Node LfscNodeConverter::getSymbolInternal(Kind k,
691
                                          TypeNode tn,
692
                                          const std::string& name)
693
{
694
84
  std::tuple<Kind, TypeNode, std::string> key(k, tn, name);
695
  std::map<std::tuple<Kind, TypeNode, std::string>, Node>::iterator it =
696
42
      d_symbolsMap.find(key);
697
42
  if (it != d_symbolsMap.end())
698
  {
699
26
    return it->second;
700
  }
701
32
  Node sym = mkInternalSymbol(name, tn);
702
16
  d_symbolToBuiltinKind[sym] = k;
703
16
  d_symbolsMap[key] = sym;
704
16
  return sym;
705
}
706
707
void LfscNodeConverter::getCharVectorInternal(Node c, std::vector<Node>& chars)
708
{
709
  Assert(c.getKind() == CONST_STRING);
710
  NodeManager* nm = NodeManager::currentNM();
711
  const std::vector<unsigned>& vec = c.getConst<String>().getVec();
712
  if (vec.size() == 0)
713
  {
714
    Node ec = getSymbolInternalFor(c, "emptystr");
715
    chars.push_back(ec);
716
    return;
717
  }
718
  TypeNode tnc = nm->mkFunctionType(nm->integerType(), c.getType());
719
  Node aconstf = getSymbolInternal(CONST_STRING, tnc, "char");
720
  for (unsigned i = 0, size = vec.size(); i < size; i++)
721
  {
722
    Node cc = nm->mkNode(APPLY_UF, aconstf, nm->mkConst(Rational(vec[i])));
723
    chars.push_back(cc);
724
  }
725
}
726
727
47
bool LfscNodeConverter::isIndexedOperatorKind(Kind k)
728
{
729
47
  return k == BITVECTOR_EXTRACT || k == BITVECTOR_REPEAT
730
47
         || k == BITVECTOR_ZERO_EXTEND || k == BITVECTOR_SIGN_EXTEND
731
47
         || k == BITVECTOR_ROTATE_LEFT || k == BITVECTOR_ROTATE_RIGHT
732
47
         || k == INT_TO_BITVECTOR || k == IAND || k == APPLY_UPDATER
733
94
         || k == APPLY_TESTER;
734
}
735
736
std::vector<Node> LfscNodeConverter::getOperatorIndices(Kind k, Node n)
737
{
738
  NodeManager* nm = NodeManager::currentNM();
739
  std::vector<Node> indices;
740
  switch (k)
741
  {
742
    case BITVECTOR_EXTRACT:
743
    {
744
      BitVectorExtract p = n.getConst<BitVectorExtract>();
745
      indices.push_back(nm->mkConst(Rational(p.d_high)));
746
      indices.push_back(nm->mkConst(Rational(p.d_low)));
747
      break;
748
    }
749
    case BITVECTOR_REPEAT:
750
      indices.push_back(
751
          nm->mkConst(Rational(n.getConst<BitVectorRepeat>().d_repeatAmount)));
752
      break;
753
    case BITVECTOR_ZERO_EXTEND:
754
      indices.push_back(nm->mkConst(
755
          Rational(n.getConst<BitVectorZeroExtend>().d_zeroExtendAmount)));
756
      break;
757
    case BITVECTOR_SIGN_EXTEND:
758
      indices.push_back(nm->mkConst(
759
          Rational(n.getConst<BitVectorSignExtend>().d_signExtendAmount)));
760
      break;
761
    case BITVECTOR_ROTATE_LEFT:
762
      indices.push_back(nm->mkConst(
763
          Rational(n.getConst<BitVectorRotateLeft>().d_rotateLeftAmount)));
764
      break;
765
    case BITVECTOR_ROTATE_RIGHT:
766
      indices.push_back(nm->mkConst(
767
          Rational(n.getConst<BitVectorRotateRight>().d_rotateRightAmount)));
768
      break;
769
    case INT_TO_BITVECTOR:
770
      indices.push_back(
771
          nm->mkConst(Rational(n.getConst<IntToBitVector>().d_size)));
772
      break;
773
    case IAND:
774
      indices.push_back(nm->mkConst(Rational(n.getConst<IntAnd>().d_size)));
775
      break;
776
    case APPLY_TESTER:
777
    {
778
      unsigned index = DType::indexOf(n);
779
      const DType& dt = DType::datatypeOf(n);
780
      indices.push_back(dt[index].getConstructor());
781
    }
782
    break;
783
    case APPLY_UPDATER:
784
    {
785
      unsigned index = DType::indexOf(n);
786
      const DType& dt = DType::datatypeOf(n);
787
      unsigned cindex = DType::cindexOf(n);
788
      indices.push_back(dt[cindex][index].getSelector());
789
    }
790
    break;
791
    default: Assert(false); break;
792
  }
793
  return indices;
794
}
795
796
11
Node LfscNodeConverter::getNullTerminator(Kind k, TypeNode tn)
797
{
798
11
  NodeManager* nm = NodeManager::currentNM();
799
22
  Node nullTerm;
800
11
  switch (k)
801
  {
802
    case REGEXP_CONCAT:
803
      // the language containing only the empty string, which has special
804
      // syntax in LFSC
805
      nullTerm = getSymbolInternal(k, tn, "re.empty");
806
      break;
807
    case BITVECTOR_CONCAT:
808
    {
809
      // the null terminator of bitvector concat is a dummy variable of
810
      // bit-vector type with zero width, regardless of the type of the overall
811
      // concat.
812
      TypeNode bvz = nm->mkBitVectorType(0);
813
      nullTerm = getSymbolInternal(k, bvz, "emptybv");
814
    }
815
    break;
816
11
    default:
817
      // no special handling, or not null terminated
818
11
      break;
819
  }
820
11
  if (!nullTerm.isNull())
821
  {
822
    return nullTerm;
823
  }
824
  // otherwise, fall back to standard utility
825
11
  return expr::getNullTerminator(k, tn);
826
}
827
828
Kind LfscNodeConverter::getBuiltinKindForInternalSymbol(Node op) const
829
{
830
  std::map<Node, Kind>::const_iterator it = d_symbolToBuiltinKind.find(op);
831
  if (it != d_symbolToBuiltinKind.end())
832
  {
833
    return it->second;
834
  }
835
  return UNDEFINED_KIND;
836
}
837
838
5
Node LfscNodeConverter::getOperatorOfTerm(Node n, bool macroApply)
839
{
840
5
  Assert(n.hasOperator());
841
5
  Assert(!n.isClosure());
842
5
  NodeManager* nm = NodeManager::currentNM();
843
5
  Kind k = n.getKind();
844
10
  std::stringstream opName;
845
10
  Trace("lfsc-term-process-debug2")
846
5
      << "getOperatorOfTerm " << n << " " << k << " "
847
10
      << (n.getMetaKind() == metakind::PARAMETERIZED) << " "
848
5
      << isIndexedOperatorKind(k) << std::endl;
849
5
  if (n.getMetaKind() == metakind::PARAMETERIZED)
850
  {
851
    Node op = n.getOperator();
852
    std::vector<Node> indices;
853
    if (isIndexedOperatorKind(k))
854
    {
855
      indices = getOperatorIndices(k, n.getOperator());
856
      // we must convert the name of indices on updaters and testers
857
      if (k == APPLY_UPDATER || k == APPLY_TESTER)
858
      {
859
        Assert(indices.size() == 1);
860
        // must convert to user name
861
        std::stringstream sss;
862
        sss << indices[0];
863
        TypeNode intType = nm->integerType();
864
        indices[0] =
865
            getSymbolInternal(k, intType, getNameForUserName(sss.str()));
866
      }
867
    }
868
    else if (op.getType().isFunction())
869
    {
870
      return op;
871
    }
872
    // note other kinds of functions (e.g. selectors and testers)
873
    std::vector<TypeNode> argTypes;
874
    for (const Node& nc : n)
875
    {
876
      argTypes.push_back(nc.getType());
877
    }
878
    TypeNode ftype = n.getType();
879
    if (!argTypes.empty())
880
    {
881
      ftype = nm->mkFunctionType(argTypes, ftype);
882
    }
883
    Node ret;
884
    if (isIndexedOperatorKind(k))
885
    {
886
      std::vector<TypeNode> itypes;
887
      for (const Node& i : indices)
888
      {
889
        itypes.push_back(i.getType());
890
      }
891
      if (!itypes.empty())
892
      {
893
        ftype = nm->mkFunctionType(itypes, ftype);
894
      }
895
      if (!macroApply)
896
      {
897
        if (k != APPLY_UPDATER && k != APPLY_TESTER)
898
        {
899
          opName << "f_";
900
        }
901
      }
902
      opName << printer::smt2::Smt2Printer::smtKindString(k);
903
    }
904
    else if (k == APPLY_CONSTRUCTOR)
905
    {
906
      unsigned index = DType::indexOf(op);
907
      const DType& dt = DType::datatypeOf(op);
908
      std::stringstream ssc;
909
      ssc << dt[index].getConstructor();
910
      opName << getNameForUserName(ssc.str());
911
    }
912
    else if (k == APPLY_SELECTOR)
913
    {
914
      unsigned index = DType::indexOf(op);
915
      const DType& dt = DType::datatypeOf(op);
916
      unsigned cindex = DType::cindexOf(op);
917
      std::stringstream sss;
918
      sss << dt[cindex][index].getSelector();
919
      opName << getNameForUserName(sss.str());
920
    }
921
    else if (k == APPLY_SELECTOR_TOTAL)
922
    {
923
      ret = maybeMkSkolemFun(op, macroApply);
924
      Assert(!ret.isNull());
925
    }
926
    else if (k == SINGLETON || k == MK_BAG)
927
    {
928
      if (!macroApply)
929
      {
930
        opName << "f_";
931
      }
932
      opName << printer::smt2::Smt2Printer::smtKindString(k);
933
    }
934
    else
935
    {
936
      opName << op;
937
    }
938
    if (ret.isNull())
939
    {
940
      ret = getSymbolInternal(k, ftype, opName.str());
941
    }
942
    // if indexed, apply to index
943
    if (!indices.empty())
944
    {
945
      std::vector<Node> ichildren;
946
      ichildren.push_back(ret);
947
      ichildren.insert(ichildren.end(), indices.begin(), indices.end());
948
      ret = nm->mkNode(APPLY_UF, ichildren);
949
    }
950
    Trace("lfsc-term-process-debug2") << "...return " << ret << std::endl;
951
    return ret;
952
  }
953
10
  std::vector<TypeNode> argTypes;
954
15
  for (const Node& nc : n)
955
  {
956
10
    argTypes.push_back(nc.getType());
957
  }
958
  // we only use binary operators
959
5
  if (NodeManager::isNAryKind(k))
960
  {
961
3
    argTypes.resize(2);
962
  }
963
10
  TypeNode tn = n.getType();
964
10
  TypeNode ftype = nm->mkFunctionType(argTypes, tn);
965
  // most functions are called f_X where X is the SMT-LIB name, if we are
966
  // getting the macroApply variant, then we don't prefix with `f_`.
967
5
  if (!macroApply)
968
  {
969
5
    opName << "f_";
970
  }
971
  // all arithmetic kinds must explicitly deal with real vs int subtyping
972
5
  if (k == PLUS || k == MULT || k == NONLINEAR_MULT || k == GEQ || k == GT
973
5
      || k == LEQ || k == LT || k == MINUS || k == DIVISION
974
5
      || k == DIVISION_TOTAL || k == INTS_DIVISION || k == INTS_DIVISION_TOTAL
975
5
      || k == INTS_MODULUS || k == INTS_MODULUS_TOTAL || k == UMINUS
976
5
      || k == POW)
977
  {
978
    // currently allow subtyping
979
    opName << "a.";
980
  }
981
5
  if (k == UMINUS)
982
  {
983
    opName << "u";
984
  }
985
5
  opName << printer::smt2::Smt2Printer::smtKindString(k);
986
5
  if (k == DIVISION_TOTAL || k == INTS_DIVISION_TOTAL
987
5
      || k == INTS_MODULUS_TOTAL)
988
  {
989
    opName << "_total";
990
  }
991
5
  return getSymbolInternal(k, ftype, opName.str());
992
}
993
994
Node LfscNodeConverter::getOperatorOfClosure(Node q, bool macroApply)
995
{
996
  NodeManager* nm = NodeManager::currentNM();
997
  TypeNode bodyType = nm->mkFunctionType(q[1].getType(), q.getType());
998
  // We permit non-flat function types here
999
  // intType is used here for variable indices
1000
  TypeNode intType = nm->integerType();
1001
  TypeNode ftype = nm->mkFunctionType({intType, d_sortType}, bodyType);
1002
  Kind k = q.getKind();
1003
  std::stringstream opName;
1004
  if (!macroApply)
1005
  {
1006
    opName << "f_";
1007
  }
1008
  opName << printer::smt2::Smt2Printer::smtKindString(k);
1009
  return getSymbolInternal(k, ftype, opName.str());
1010
}
1011
1012
Node LfscNodeConverter::getOperatorOfBoundVar(Node cop, Node v)
1013
{
1014
  NodeManager* nm = NodeManager::currentNM();
1015
  Node x = nm->mkConst(Rational(getOrAssignIndexForVar(v)));
1016
  Node tc = typeAsNode(convertType(v.getType()));
1017
  return nm->mkNode(APPLY_UF, cop, x, tc);
1018
}
1019
1020
5
size_t LfscNodeConverter::getOrAssignIndexForVar(Node v)
1021
{
1022
5
  Assert(v.isVar());
1023
5
  std::map<Node, size_t>::iterator it = d_varIndex.find(v);
1024
5
  if (it != d_varIndex.end())
1025
  {
1026
    return it->second;
1027
  }
1028
5
  size_t id = d_varIndex.size();
1029
5
  d_varIndex[v] = id;
1030
5
  return id;
1031
}
1032
1033
}  // namespace proof
1034
31125
}  // namespace cvc5