GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/proof/lfsc/lfsc_node_converter.cpp Lines: 1 585 0.2 %
Date: 2021-09-07 Branches: 2 2478 0.1 %

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
LfscNodeConverter::LfscNodeConverter()
43
{
44
  NodeManager* nm = NodeManager::currentNM();
45
  d_arrow = nm->mkSortConstructor("arrow", 2);
46
47
  d_sortType = nm->mkSort("sortType");
48
  // the embedding of arrow into Node, which is binary constructor over sorts
49
  TypeNode anfType = nm->mkFunctionType({d_sortType, d_sortType}, d_sortType);
50
  d_typeAsNode[d_arrow] = getSymbolInternal(FUNCTION_TYPE, anfType, "arrow");
51
52
  TypeNode intType = nm->integerType();
53
  TypeNode arrType = nm->mkFunctionType({d_sortType, d_sortType}, d_sortType);
54
  d_typeKindToNodeCons[ARRAY_TYPE] =
55
      getSymbolInternal(FUNCTION_TYPE, arrType, "Array");
56
  TypeNode bvType = nm->mkFunctionType(intType, d_sortType);
57
  d_typeKindToNodeCons[BITVECTOR_TYPE] =
58
      getSymbolInternal(FUNCTION_TYPE, bvType, "BitVec");
59
  TypeNode fpType = nm->mkFunctionType({intType, intType}, d_sortType);
60
  d_typeKindToNodeCons[FLOATINGPOINT_TYPE] =
61
      getSymbolInternal(FUNCTION_TYPE, fpType, "FloatingPoint");
62
  TypeNode setType = nm->mkFunctionType(d_sortType, d_sortType);
63
  d_typeKindToNodeCons[SET_TYPE] =
64
      getSymbolInternal(FUNCTION_TYPE, setType, "Set");
65
  d_typeKindToNodeCons[BAG_TYPE] =
66
      getSymbolInternal(FUNCTION_TYPE, setType, "Bag");
67
  d_typeKindToNodeCons[SEQUENCE_TYPE] =
68
      getSymbolInternal(FUNCTION_TYPE, setType, "Seq");
69
}
70
71
Node LfscNodeConverter::postConvert(Node n)
72
{
73
  NodeManager* nm = NodeManager::currentNM();
74
  Kind k = n.getKind();
75
  if (k == ASCRIPTION_TYPE)
76
  {
77
    // dummy node, return it
78
    return n;
79
  }
80
  TypeNode tn = n.getType();
81
  Trace("lfsc-term-process-debug")
82
      << "postConvert " << n << " " << k << std::endl;
83
  if (k == BOUND_VARIABLE)
84
  {
85
    // ignore internally generated symbols
86
    if (d_symbols.find(n) != d_symbols.end())
87
    {
88
      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
  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
  else if (n.isVar())
144
  {
145
    std::stringstream ss;
146
    ss << n;
147
    Node nn = mkInternalSymbol(getNameForUserName(ss.str()), tn);
148
    return nn;
149
  }
150
  else if (k == APPLY_UF)
151
  {
152
    return convert(theory::uf::TheoryUfRewriter::getHoApplyForApplyUf(n));
153
  }
154
  else if (k == APPLY_CONSTRUCTOR || k == APPLY_SELECTOR || k == APPLY_TESTER
155
           || 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
  else if (k == HO_APPLY)
170
  {
171
    std::vector<TypeNode> argTypes;
172
    argTypes.push_back(n[0].getType());
173
    argTypes.push_back(n[1].getType());
174
    TypeNode tnh = nm->mkFunctionType(argTypes, tn);
175
    Node hconstf = getSymbolInternal(k, tnh, "apply");
176
    return nm->mkNode(APPLY_UF, hconstf, n[0], n[1]);
177
  }
178
  else if (k == CONST_RATIONAL || k == CAST_TO_REAL)
179
  {
180
    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
    TypeNode tnv = nm->mkFunctionType(tn, tn);
190
    Node rconstf;
191
    Node arg;
192
    Rational r = n.getConst<Rational>();
193
    if (tn.isInteger())
194
    {
195
      rconstf = getSymbolInternal(k, tnv, "int");
196
      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
        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
    return nm->mkNode(APPLY_UF, rconstf, arg);
224
  }
225
  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);
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
  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
  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
  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
  else if (k == GEQ || k == GT || k == LEQ || k == LT || k == MINUS
295
           || k == DIVISION || k == DIVISION_TOTAL || k == INTS_DIVISION
296
           || k == INTS_DIVISION_TOTAL || k == INTS_MODULUS
297
           || k == INTS_MODULUS_TOTAL || k == UMINUS || k == POW
298
           || 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
  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
  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
  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
  else if (k == MATCH)
351
  {
352
    // currently unsupported
353
    return n;
354
  }
355
  else if (k == SEP_NIL)
356
  {
357
    Node tnn = typeAsNode(convertType(tn));
358
    TypeNode ftype = nm->mkFunctionType(d_sortType, tn);
359
    Node s = getSymbolInternal(k, ftype, "sep.nil");
360
    return nm->mkNode(APPLY_UF, s, tnn);
361
  }
362
  else if (NodeManager::isNAryKind(k) && n.getNumChildren() >= 2)
363
  {
364
    size_t nchild = n.getNumChildren();
365
    Assert(n.getMetaKind() != metakind::PARAMETERIZED);
366
    // convert all n-ary applications to binary
367
    std::vector<Node> children(n.begin(), n.end());
368
    // distinct is special case
369
    if (k == DISTINCT)
370
    {
371
      // DISTINCT(x1,...,xn) --->
372
      // AND(DISTINCT(x1,x2), AND(,..., AND(,..,DISTINCT(x_{n-1},x_n))))
373
      Node ret = nm->mkNode(k, children[0], children[1]);
374
      for (unsigned i = 0; i < nchild; i++)
375
        for (unsigned j = i + 1; j < nchild; j++)
376
        {
377
          if (i != 0 && j != 1)
378
          {
379
            ret = nm->mkNode(AND, ret, nm->mkNode(k, children[i], children[j]));
380
          }
381
        }
382
      Trace("lfsc-term-process-debug") << "n: " << n << std::endl
383
                                       << "ret: " << ret << std::endl;
384
      return ret;
385
    }
386
    std::reverse(children.begin(), children.end());
387
    // Add the null-terminator. This is done to disambiguate the number
388
    // of children for term with n-ary operators. In particular note that
389
    // (or A B C (or D E)) has representation:
390
    //   (or A (or B (or C (or (or D E) false))))
391
    // This makes the AST above distinguishable from (or A B C D E),
392
    // which otherwise would both have representation:
393
    //   (or A (or B (or C (or D E))))
394
    Node nullTerm = getNullTerminator(k, tn);
395
    // Most operators simply get binarized
396
    Node ret;
397
    size_t istart = 0;
398
    if (nullTerm.isNull())
399
    {
400
      ret = children[0];
401
      istart = 1;
402
    }
403
    else
404
    {
405
      // must convert recursively, since nullTerm may have subterms.
406
      ret = convert(nullTerm);
407
    }
408
    // the kind to chain
409
    Kind ck = k;
410
    // check whether we are also changing the operator name, in which case
411
    // we build a binary uninterpreted function opc
412
    Node opc;
413
    if (k == PLUS || k == MULT || k == NONLINEAR_MULT)
414
    {
415
      std::stringstream opName;
416
      // currently allow subtyping
417
      opName << "a.";
418
      opName << printer::smt2::Smt2Printer::smtKindString(k);
419
      TypeNode ftype = nm->mkFunctionType({tn, tn}, tn);
420
      opc = getSymbolInternal(k, ftype, opName.str());
421
      ck = APPLY_UF;
422
    }
423
    // now, iterate over children and make binary conversion
424
    for (size_t i = istart, npchild = children.size(); i < npchild; i++)
425
    {
426
      if (!opc.isNull())
427
      {
428
        ret = nm->mkNode(ck, opc, children[i], ret);
429
      }
430
      else
431
      {
432
        ret = nm->mkNode(ck, children[i], ret);
433
      }
434
    }
435
    return ret;
436
  }
437
  return n;
438
}
439
440
TypeNode LfscNodeConverter::postConvertType(TypeNode tn)
441
{
442
  NodeManager* nm = NodeManager::currentNM();
443
  TypeNode cur = tn;
444
  Node tnn;
445
  Kind k = tn.getKind();
446
  Trace("lfsc-term-process-debug")
447
      << "postConvertType " << tn << " " << tn.getNumChildren() << " " << k
448
      << std::endl;
449
  if (k == FUNCTION_TYPE)
450
  {
451
    // (-> T1 ... Tn T) is (arrow T1 .... (arrow Tn T))
452
    std::vector<TypeNode> argTypes = tn.getArgTypes();
453
    // also make the node embedding of the type
454
    Node arrown = d_typeAsNode[d_arrow];
455
    Assert(!arrown.isNull());
456
    cur = tn.getRangeType();
457
    tnn = typeAsNode(cur);
458
    for (std::vector<TypeNode>::reverse_iterator it = argTypes.rbegin();
459
         it != argTypes.rend();
460
         ++it)
461
    {
462
      std::vector<TypeNode> aargs;
463
      aargs.push_back(*it);
464
      aargs.push_back(cur);
465
      cur = nm->mkSort(d_arrow, aargs);
466
      tnn = nm->mkNode(APPLY_UF, arrown, typeAsNode(*it), tnn);
467
    }
468
  }
469
  else if (k == BITVECTOR_TYPE)
470
  {
471
    tnn = d_typeKindToNodeCons[k];
472
    Node w = nm->mkConst(Rational(tn.getBitVectorSize()));
473
    tnn = nm->mkNode(APPLY_UF, tnn, w);
474
  }
475
  else if (k == FLOATINGPOINT_TYPE)
476
  {
477
    tnn = d_typeKindToNodeCons[k];
478
    Node e = nm->mkConst(Rational(tn.getFloatingPointExponentSize()));
479
    Node s = nm->mkConst(Rational(tn.getFloatingPointSignificandSize()));
480
    tnn = nm->mkNode(APPLY_UF, tnn, e, s);
481
  }
482
  else if (tn.getNumChildren() == 0)
483
  {
484
    // special case: tuples must be distinguished by their arity
485
    if (tn.isTuple())
486
    {
487
      const DType& dt = tn.getDType();
488
      unsigned int nargs = dt[0].getNumArgs();
489
      if (nargs > 0)
490
      {
491
        std::vector<TypeNode> types;
492
        std::vector<TypeNode> convTypes;
493
        std::vector<Node> targs;
494
        for (unsigned int i = 0; i < nargs; i++)
495
        {
496
          // it is not converted yet, convert here
497
          TypeNode tnc = convertType(dt[0][i].getRangeType());
498
          types.push_back(d_sortType);
499
          convTypes.push_back(tnc);
500
          targs.push_back(typeAsNode(tnc));
501
        }
502
        TypeNode ftype = nm->mkFunctionType(types, d_sortType);
503
        // must distinguish by arity
504
        std::stringstream ss;
505
        ss << "Tuple_" << nargs;
506
        targs.insert(targs.begin(), getSymbolInternal(k, ftype, ss.str()));
507
        tnn = nm->mkNode(APPLY_UF, targs);
508
        // we are changing its name, we must make a sort constructor
509
        cur = nm->mkSortConstructor(ss.str(), nargs);
510
        cur = nm->mkSort(cur, convTypes);
511
      }
512
    }
513
    if (tnn.isNull())
514
    {
515
      std::stringstream ss;
516
      tn.toStream(ss, Language::LANG_SMTLIB_V2_6);
517
      if (tn.isSort() || (tn.isDatatype() && !tn.isTuple()))
518
      {
519
        std::stringstream sss;
520
        sss << LfscNodeConverter::getNameForUserName(ss.str());
521
        tnn = getSymbolInternal(k, d_sortType, sss.str());
522
        cur = nm->mkSort(sss.str());
523
      }
524
      else
525
      {
526
        tnn = getSymbolInternal(k, d_sortType, ss.str());
527
      }
528
    }
529
  }
530
  else
531
  {
532
    // to build the type-as-node, must convert the component types
533
    std::vector<Node> targs;
534
    std::vector<TypeNode> types;
535
    for (const TypeNode& tnc : tn)
536
    {
537
      targs.push_back(typeAsNode(tnc));
538
      types.push_back(d_sortType);
539
    }
540
    Node op;
541
    if (k == PARAMETRIC_DATATYPE)
542
    {
543
      // erase first child, which repeats the datatype
544
      targs.erase(targs.begin(), targs.begin() + 1);
545
      types.erase(types.begin(), types.begin() + 1);
546
      TypeNode ftype = nm->mkFunctionType(types, d_sortType);
547
      // the operator has been converted; it is no longer a datatype, thus
548
      // we must print to get its name.
549
      std::stringstream ss;
550
      ss << tn[0];
551
      op = getSymbolInternal(k, ftype, ss.str());
552
    }
553
    else if (k == SORT_TYPE)
554
    {
555
      TypeNode ftype = nm->mkFunctionType(types, d_sortType);
556
      std::string name;
557
      tn.getAttribute(expr::VarNameAttr(), name);
558
      op = getSymbolInternal(k, ftype, name);
559
    }
560
    else
561
    {
562
      std::map<Kind, Node>::iterator it = d_typeKindToNodeCons.find(k);
563
      if (it != d_typeKindToNodeCons.end())
564
      {
565
        op = it->second;
566
      }
567
    }
568
    if (!op.isNull())
569
    {
570
      targs.insert(targs.begin(), op);
571
      tnn = nm->mkNode(APPLY_UF, targs);
572
    }
573
    else
574
    {
575
      AlwaysAssert(false);
576
    }
577
  }
578
  Assert(!tnn.isNull());
579
  Trace("lfsc-term-process-debug") << "...type as node: " << tnn << std::endl;
580
  d_typeAsNode[cur] = tnn;
581
  return cur;
582
}
583
584
std::string LfscNodeConverter::getNameForUserName(const std::string& name)
585
{
586
  std::stringstream ss;
587
  ss << "cvc." << name;
588
  return ss.str();
589
}
590
591
bool LfscNodeConverter::shouldTraverse(Node n)
592
{
593
  Kind k = n.getKind();
594
  // don't convert bound variable list directly
595
  if (k == BOUND_VAR_LIST)
596
  {
597
    return false;
598
  }
599
  // should not traverse internal applications
600
  if (k == APPLY_UF)
601
  {
602
    if (d_symbols.find(n.getOperator()) != d_symbols.end())
603
    {
604
      return false;
605
    }
606
  }
607
  return true;
608
}
609
610
Node LfscNodeConverter::maybeMkSkolemFun(Node k, bool macroApply)
611
{
612
  NodeManager* nm = NodeManager::currentNM();
613
  SkolemManager* sm = nm->getSkolemManager();
614
  SkolemFunId sfi = SkolemFunId::NONE;
615
  Node cacheVal;
616
  TypeNode tn = k.getType();
617
  if (sm->isSkolemFunction(k, sfi, cacheVal))
618
  {
619
    if (sfi == SkolemFunId::SHARED_SELECTOR)
620
    {
621
      // a skolem corresponding to shared selector should print in
622
      // LFSC as (sel T n) where T is the type and n is the index of the
623
      // shared selector.
624
      TypeNode fselt = nm->mkFunctionType(tn.getSelectorDomainType(),
625
                                          tn.getSelectorRangeType());
626
      TypeNode intType = nm->integerType();
627
      TypeNode selt = nm->mkFunctionType({d_sortType, intType}, fselt);
628
      Node sel = getSymbolInternal(k.getKind(), selt, "sel");
629
      Node kn = typeAsNode(convertType(tn.getSelectorRangeType()));
630
      Assert(!cacheVal.isNull() && cacheVal.getKind() == CONST_RATIONAL);
631
      return nm->mkNode(APPLY_UF, sel, kn, cacheVal);
632
    }
633
    else if (sfi == SkolemFunId::RE_UNFOLD_POS_COMPONENT)
634
    {
635
      // a skolem corresponding to a regular expression unfolding component
636
      // should print as (skolem_re_unfold_pos t R n) where the skolem is the
637
      // n^th component for the unfolding of (str.in_re t R).
638
      TypeNode strType = nm->stringType();
639
      TypeNode reType = nm->regExpType();
640
      TypeNode intType = nm->integerType();
641
      TypeNode reut = nm->mkFunctionType({strType, reType, intType}, strType);
642
      Node sk = getSymbolInternal(k.getKind(), reut, "skolem_re_unfold_pos");
643
      Assert(!cacheVal.isNull() && cacheVal.getKind() == SEXPR
644
             && cacheVal.getNumChildren() == 3);
645
      // third value is mpz, which is not converted
646
      return nm->mkNode(
647
          APPLY_UF,
648
          {sk, convert(cacheVal[0]), convert(cacheVal[1]), cacheVal[2]});
649
    }
650
  }
651
  return Node::null();
652
}
653
654
Node LfscNodeConverter::typeAsNode(TypeNode tni) const
655
{
656
  // should always exist in the cache, as we always run types through
657
  // postConvertType before calling this method.
658
  std::map<TypeNode, Node>::const_iterator it = d_typeAsNode.find(tni);
659
  AlwaysAssert(it != d_typeAsNode.end()) << "Missing typeAsNode " << tni;
660
  return it->second;
661
}
662
663
Node LfscNodeConverter::mkInternalSymbol(const std::string& name, TypeNode tn)
664
{
665
  Node sym = NodeManager::currentNM()->mkBoundVar(name, tn);
666
  d_symbols.insert(sym);
667
  return sym;
668
}
669
670
Node LfscNodeConverter::getSymbolInternalFor(Node n, const std::string& name)
671
{
672
  return getSymbolInternal(n.getKind(), n.getType(), name);
673
}
674
675
Node LfscNodeConverter::getSymbolInternal(Kind k,
676
                                          TypeNode tn,
677
                                          const std::string& name)
678
{
679
  std::tuple<Kind, TypeNode, std::string> key(k, tn, name);
680
  std::map<std::tuple<Kind, TypeNode, std::string>, Node>::iterator it =
681
      d_symbolsMap.find(key);
682
  if (it != d_symbolsMap.end())
683
  {
684
    return it->second;
685
  }
686
  Node sym = mkInternalSymbol(name, tn);
687
  d_symbolToBuiltinKind[sym] = k;
688
  d_symbolsMap[key] = sym;
689
  return sym;
690
}
691
692
void LfscNodeConverter::getCharVectorInternal(Node c, std::vector<Node>& chars)
693
{
694
  Assert(c.getKind() == CONST_STRING);
695
  NodeManager* nm = NodeManager::currentNM();
696
  const std::vector<unsigned>& vec = c.getConst<String>().getVec();
697
  if (vec.size() == 0)
698
  {
699
    Node ec = getSymbolInternalFor(c, "emptystr");
700
    chars.push_back(ec);
701
    return;
702
  }
703
  TypeNode tnc = nm->mkFunctionType(nm->integerType(), c.getType());
704
  Node aconstf = getSymbolInternal(CONST_STRING, tnc, "char");
705
  for (unsigned i = 0, size = vec.size(); i < size; i++)
706
  {
707
    Node cc = nm->mkNode(APPLY_UF, aconstf, nm->mkConst(Rational(vec[i])));
708
    chars.push_back(cc);
709
  }
710
}
711
712
bool LfscNodeConverter::isIndexedOperatorKind(Kind k)
713
{
714
  return k == BITVECTOR_EXTRACT || k == BITVECTOR_REPEAT
715
         || k == BITVECTOR_ZERO_EXTEND || k == BITVECTOR_SIGN_EXTEND
716
         || k == BITVECTOR_ROTATE_LEFT || k == BITVECTOR_ROTATE_RIGHT
717
         || k == INT_TO_BITVECTOR || k == IAND || k == APPLY_UPDATER
718
         || k == APPLY_TESTER;
719
}
720
721
std::vector<Node> LfscNodeConverter::getOperatorIndices(Kind k, Node n)
722
{
723
  NodeManager* nm = NodeManager::currentNM();
724
  std::vector<Node> indices;
725
  switch (k)
726
  {
727
    case BITVECTOR_EXTRACT:
728
    {
729
      BitVectorExtract p = n.getConst<BitVectorExtract>();
730
      indices.push_back(nm->mkConst(Rational(p.d_high)));
731
      indices.push_back(nm->mkConst(Rational(p.d_low)));
732
      break;
733
    }
734
    case BITVECTOR_REPEAT:
735
      indices.push_back(
736
          nm->mkConst(Rational(n.getConst<BitVectorRepeat>().d_repeatAmount)));
737
      break;
738
    case BITVECTOR_ZERO_EXTEND:
739
      indices.push_back(nm->mkConst(
740
          Rational(n.getConst<BitVectorZeroExtend>().d_zeroExtendAmount)));
741
      break;
742
    case BITVECTOR_SIGN_EXTEND:
743
      indices.push_back(nm->mkConst(
744
          Rational(n.getConst<BitVectorSignExtend>().d_signExtendAmount)));
745
      break;
746
    case BITVECTOR_ROTATE_LEFT:
747
      indices.push_back(nm->mkConst(
748
          Rational(n.getConst<BitVectorRotateLeft>().d_rotateLeftAmount)));
749
      break;
750
    case BITVECTOR_ROTATE_RIGHT:
751
      indices.push_back(nm->mkConst(
752
          Rational(n.getConst<BitVectorRotateRight>().d_rotateRightAmount)));
753
      break;
754
    case INT_TO_BITVECTOR:
755
      indices.push_back(
756
          nm->mkConst(Rational(n.getConst<IntToBitVector>().d_size)));
757
      break;
758
    case IAND:
759
      indices.push_back(nm->mkConst(Rational(n.getConst<IntAnd>().d_size)));
760
      break;
761
    case APPLY_TESTER:
762
    {
763
      unsigned index = DType::indexOf(n);
764
      const DType& dt = DType::datatypeOf(n);
765
      indices.push_back(dt[index].getConstructor());
766
    }
767
    break;
768
    case APPLY_UPDATER:
769
    {
770
      unsigned index = DType::indexOf(n);
771
      const DType& dt = DType::datatypeOf(n);
772
      unsigned cindex = DType::cindexOf(n);
773
      indices.push_back(dt[cindex][index].getSelector());
774
    }
775
    break;
776
    default: Assert(false); break;
777
  }
778
  return indices;
779
}
780
781
Node LfscNodeConverter::getNullTerminator(Kind k, TypeNode tn)
782
{
783
  NodeManager* nm = NodeManager::currentNM();
784
  Node nullTerm;
785
  switch (k)
786
  {
787
    case REGEXP_CONCAT:
788
      // the language containing only the empty string, which has special
789
      // syntax in LFSC
790
      nullTerm = getSymbolInternal(k, tn, "re.empty");
791
      break;
792
    case BITVECTOR_CONCAT:
793
    {
794
      // the null terminator of bitvector concat is a dummy variable of
795
      // bit-vector type with zero width, regardless of the type of the overall
796
      // concat.
797
      TypeNode bvz = nm->mkBitVectorType(0);
798
      nullTerm = getSymbolInternal(k, bvz, "emptybv");
799
    }
800
    break;
801
    default:
802
      // no special handling, or not null terminated
803
      break;
804
  }
805
  if (!nullTerm.isNull())
806
  {
807
    return nullTerm;
808
  }
809
  // otherwise, fall back to standard utility
810
  return expr::getNullTerminator(k, tn);
811
}
812
813
Kind LfscNodeConverter::getBuiltinKindForInternalSymbol(Node op) const
814
{
815
  std::map<Node, Kind>::const_iterator it = d_symbolToBuiltinKind.find(op);
816
  if (it != d_symbolToBuiltinKind.end())
817
  {
818
    return it->second;
819
  }
820
  return UNDEFINED_KIND;
821
}
822
823
Node LfscNodeConverter::getOperatorOfTerm(Node n, bool macroApply)
824
{
825
  Assert(n.hasOperator());
826
  Assert(!n.isClosure());
827
  NodeManager* nm = NodeManager::currentNM();
828
  Kind k = n.getKind();
829
  std::stringstream opName;
830
  Trace("lfsc-term-process-debug2")
831
      << "getOperatorOfTerm " << n << " " << k << " "
832
      << (n.getMetaKind() == metakind::PARAMETERIZED) << " "
833
      << isIndexedOperatorKind(k) << std::endl;
834
  if (n.getMetaKind() == metakind::PARAMETERIZED)
835
  {
836
    Node op = n.getOperator();
837
    std::vector<Node> indices;
838
    if (isIndexedOperatorKind(k))
839
    {
840
      indices = getOperatorIndices(k, n.getOperator());
841
      // we must convert the name of indices on updaters and testers
842
      if (k == APPLY_UPDATER || k == APPLY_TESTER)
843
      {
844
        Assert(indices.size() == 1);
845
        // must convert to user name
846
        std::stringstream sss;
847
        sss << indices[0];
848
        TypeNode intType = nm->integerType();
849
        indices[0] =
850
            getSymbolInternal(k, intType, getNameForUserName(sss.str()));
851
      }
852
    }
853
    else if (op.getType().isFunction())
854
    {
855
      return op;
856
    }
857
    // note other kinds of functions (e.g. selectors and testers)
858
    std::vector<TypeNode> argTypes;
859
    for (const Node& nc : n)
860
    {
861
      argTypes.push_back(nc.getType());
862
    }
863
    TypeNode ftype = n.getType();
864
    if (!argTypes.empty())
865
    {
866
      ftype = nm->mkFunctionType(argTypes, ftype);
867
    }
868
    Node ret;
869
    if (isIndexedOperatorKind(k))
870
    {
871
      std::vector<TypeNode> itypes;
872
      for (const Node& i : indices)
873
      {
874
        itypes.push_back(i.getType());
875
      }
876
      if (!itypes.empty())
877
      {
878
        ftype = nm->mkFunctionType(itypes, ftype);
879
      }
880
      if (!macroApply)
881
      {
882
        if (k != APPLY_UPDATER && k != APPLY_TESTER)
883
        {
884
          opName << "f_";
885
        }
886
      }
887
      opName << printer::smt2::Smt2Printer::smtKindString(k);
888
    }
889
    else if (k == APPLY_CONSTRUCTOR)
890
    {
891
      unsigned index = DType::indexOf(op);
892
      const DType& dt = DType::datatypeOf(op);
893
      std::stringstream ssc;
894
      ssc << dt[index].getConstructor();
895
      opName << getNameForUserName(ssc.str());
896
    }
897
    else if (k == APPLY_SELECTOR)
898
    {
899
      unsigned index = DType::indexOf(op);
900
      const DType& dt = DType::datatypeOf(op);
901
      unsigned cindex = DType::cindexOf(op);
902
      std::stringstream sss;
903
      sss << dt[cindex][index].getSelector();
904
      opName << getNameForUserName(sss.str());
905
    }
906
    else if (k == APPLY_SELECTOR_TOTAL)
907
    {
908
      ret = maybeMkSkolemFun(op, macroApply);
909
      Assert(!ret.isNull());
910
    }
911
    else if (k == SINGLETON || k == MK_BAG)
912
    {
913
      if (!macroApply)
914
      {
915
        opName << "f_";
916
      }
917
      opName << printer::smt2::Smt2Printer::smtKindString(k);
918
    }
919
    else
920
    {
921
      opName << op;
922
    }
923
    if (ret.isNull())
924
    {
925
      ret = getSymbolInternal(k, ftype, opName.str());
926
    }
927
    // if indexed, apply to index
928
    if (!indices.empty())
929
    {
930
      std::vector<Node> ichildren;
931
      ichildren.push_back(ret);
932
      ichildren.insert(ichildren.end(), indices.begin(), indices.end());
933
      ret = nm->mkNode(APPLY_UF, ichildren);
934
    }
935
    Trace("lfsc-term-process-debug2") << "...return " << ret << std::endl;
936
    return ret;
937
  }
938
  std::vector<TypeNode> argTypes;
939
  for (const Node& nc : n)
940
  {
941
    argTypes.push_back(nc.getType());
942
  }
943
  // we only use binary operators
944
  if (NodeManager::isNAryKind(k))
945
  {
946
    argTypes.resize(2);
947
  }
948
  TypeNode tn = n.getType();
949
  TypeNode ftype = nm->mkFunctionType(argTypes, tn);
950
  // most functions are called f_X where X is the SMT-LIB name, if we are
951
  // getting the macroApply variant, then we don't prefix with `f_`.
952
  if (!macroApply)
953
  {
954
    opName << "f_";
955
  }
956
  // all arithmetic kinds must explicitly deal with real vs int subtyping
957
  if (k == PLUS || k == MULT || k == NONLINEAR_MULT || k == GEQ || k == GT
958
      || k == LEQ || k == LT || k == MINUS || k == DIVISION
959
      || k == DIVISION_TOTAL || k == INTS_DIVISION || k == INTS_DIVISION_TOTAL
960
      || k == INTS_MODULUS || k == INTS_MODULUS_TOTAL || k == UMINUS
961
      || k == POW)
962
  {
963
    // currently allow subtyping
964
    opName << "a.";
965
  }
966
  if (k == UMINUS)
967
  {
968
    opName << "u";
969
  }
970
  opName << printer::smt2::Smt2Printer::smtKindString(k);
971
  if (k == DIVISION_TOTAL || k == INTS_DIVISION_TOTAL
972
      || k == INTS_MODULUS_TOTAL)
973
  {
974
    opName << "_total";
975
  }
976
  return getSymbolInternal(k, ftype, opName.str());
977
}
978
979
Node LfscNodeConverter::getOperatorOfClosure(Node q, bool macroApply)
980
{
981
  NodeManager* nm = NodeManager::currentNM();
982
  TypeNode bodyType = nm->mkFunctionType(q[1].getType(), q.getType());
983
  // We permit non-flat function types here
984
  // intType is used here for variable indices
985
  TypeNode intType = nm->integerType();
986
  TypeNode ftype = nm->mkFunctionType({intType, d_sortType}, bodyType);
987
  Kind k = q.getKind();
988
  std::stringstream opName;
989
  if (!macroApply)
990
  {
991
    opName << "f_";
992
  }
993
  opName << printer::smt2::Smt2Printer::smtKindString(k);
994
  return getSymbolInternal(k, ftype, opName.str());
995
}
996
997
Node LfscNodeConverter::getOperatorOfBoundVar(Node cop, Node v)
998
{
999
  NodeManager* nm = NodeManager::currentNM();
1000
  Node x = nm->mkConst(Rational(getOrAssignIndexForVar(v)));
1001
  Node tc = typeAsNode(convertType(v.getType()));
1002
  return nm->mkNode(APPLY_UF, cop, x, tc);
1003
}
1004
1005
size_t LfscNodeConverter::getOrAssignIndexForVar(Node v)
1006
{
1007
  Assert(v.isVar());
1008
  std::map<Node, size_t>::iterator it = d_varIndex.find(v);
1009
  if (it != d_varIndex.end())
1010
  {
1011
    return it->second;
1012
  }
1013
  size_t id = d_varIndex.size();
1014
  d_varIndex[v] = id;
1015
  return id;
1016
}
1017
1018
}  // namespace proof
1019
29502
}  // namespace cvc5