GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/proof/lfsc/lfsc_printer.cpp Lines: 237 383 61.9 %
Date: 2021-11-07 Branches: 367 1469 25.0 %

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
 * The printer for LFSC proofs
14
 */
15
16
#include "proof/lfsc/lfsc_printer.h"
17
18
#include <sstream>
19
20
#include "expr/dtype.h"
21
#include "expr/dtype_cons.h"
22
#include "expr/dtype_selector.h"
23
#include "expr/node_algorithm.h"
24
#include "expr/skolem_manager.h"
25
#include "proof/lfsc/lfsc_list_sc_node_converter.h"
26
#include "proof/lfsc/lfsc_print_channel.h"
27
28
using namespace cvc5::kind;
29
30
namespace cvc5 {
31
namespace proof {
32
33
1
LfscPrinter::LfscPrinter(LfscNodeConverter& ltp)
34
1
    : d_tproc(ltp), d_assumpCounter(0)
35
{
36
1
  NodeManager* nm = NodeManager::currentNM();
37
1
  d_boolType = nm->booleanType();
38
  // used for the `flag` type in LFSC
39
1
  d_tt = d_tproc.mkInternalSymbol("tt", d_boolType);
40
1
  d_ff = d_tproc.mkInternalSymbol("ff", d_boolType);
41
1
}
42
43
1
void LfscPrinter::print(std::ostream& out,
44
                        const std::vector<Node>& assertions,
45
                        const ProofNode* pn)
46
{
47
1
  Trace("lfsc-print-debug") << "; ORIGINAL PROOF: " << *pn << std::endl;
48
1
  Assert (!pn->getChildren().empty());
49
  // closing parentheses
50
2
  std::stringstream cparen;
51
1
  const ProofNode* pnBody = pn->getChildren()[0].get();
52
53
  // clear the rules we have warned about
54
1
  d_trustWarned.clear();
55
56
1
  Trace("lfsc-print-debug") << "; print declarations" << std::endl;
57
  // [1] compute and print the declarations
58
2
  std::unordered_set<Node> syms;
59
2
  std::unordered_set<TNode> visited;
60
2
  std::vector<Node> iasserts;
61
2
  std::map<Node, size_t> passumeMap;
62
2
  std::unordered_set<TypeNode> types;
63
2
  std::unordered_set<TNode> typeVisited;
64
4
  for (size_t i = 0, nasserts = assertions.size(); i < nasserts; i++)
65
  {
66
6
    Node a = assertions[i];
67
3
    expr::getSymbols(a, syms, visited);
68
3
    expr::getTypes(a, types, typeVisited);
69
3
    iasserts.push_back(d_tproc.convert(a));
70
    // remember the assumption name
71
3
    passumeMap[a] = i;
72
  }
73
1
  d_assumpCounter = assertions.size();
74
1
  Trace("lfsc-print-debug") << "; print sorts" << std::endl;
75
  // [1a] user declared sorts
76
2
  std::stringstream preamble;
77
2
  std::unordered_set<TypeNode> sts;
78
2
  std::unordered_set<size_t> tupleArity;
79
3
  for (const TypeNode& st : types)
80
  {
81
    // note that we must get all "component types" of a type, so that
82
    // e.g. U is printed as a sort declaration when we have type (Array U Int).
83
4
    std::unordered_set<TypeNode> ctypes;
84
2
    expr::getComponentTypes(st, ctypes);
85
4
    for (const TypeNode& stc : ctypes)
86
    {
87
2
      if (sts.find(stc) != sts.end())
88
      {
89
        continue;
90
      }
91
2
      sts.insert(stc);
92
2
      if (stc.isSort())
93
      {
94
1
        preamble << "(declare ";
95
1
        printType(preamble, stc);
96
1
        preamble << " sort)" << std::endl;
97
      }
98
1
      else if (stc.isDatatype())
99
      {
100
        const DType& dt = stc.getDType();
101
        if (stc.getKind() == PARAMETRIC_DATATYPE)
102
        {
103
          // skip the instance of a parametric datatype
104
          continue;
105
        }
106
        preamble << "; DATATYPE " << dt.getName() << std::endl;
107
        if (dt.isTuple())
108
        {
109
          const DTypeConstructor& cons = dt[0];
110
          size_t arity = cons.getNumArgs();
111
          if (tupleArity.find(arity) == tupleArity.end())
112
          {
113
            tupleArity.insert(arity);
114
            preamble << "(declare Tuple_" << arity << " ";
115
            std::stringstream tcparen;
116
            for (size_t j = 0, nargs = cons.getNumArgs(); j < nargs; j++)
117
            {
118
              preamble << "(! s" << j << " sort ";
119
              tcparen << ")";
120
            }
121
            preamble << "sort" << tcparen.str() << ")";
122
          }
123
          preamble << std::endl;
124
        }
125
        else
126
        {
127
          preamble << "(declare ";
128
          printType(preamble, stc);
129
          std::stringstream cdttparens;
130
          if (dt.isParametric())
131
          {
132
            std::vector<TypeNode> params = dt.getParameters();
133
            for (const TypeNode& tn : params)
134
            {
135
              preamble << " (! " << tn << " sort";
136
              cdttparens << ")";
137
            }
138
          }
139
          preamble << " sort)" << cdttparens.str() << std::endl;
140
        }
141
        for (size_t i = 0, ncons = dt.getNumConstructors(); i < ncons; i++)
142
        {
143
          const DTypeConstructor& cons = dt[i];
144
          std::stringstream sscons;
145
          sscons << d_tproc.convert(cons.getConstructor());
146
          std::string cname =
147
              LfscNodeConverter::getNameForUserName(sscons.str());
148
          // print construct/tester
149
          preamble << "(declare " << cname << " term)" << std::endl;
150
          for (size_t j = 0, nargs = cons.getNumArgs(); j < nargs; j++)
151
          {
152
            const DTypeSelector& arg = cons[j];
153
            // print selector
154
            Node si = d_tproc.convert(arg.getSelector());
155
            std::stringstream sns;
156
            sns << si;
157
            std::string sname =
158
                LfscNodeConverter::getNameForUserName(sns.str());
159
            preamble << "(declare " << sname << " term)" << std::endl;
160
          }
161
        }
162
        // testers and updaters are instances of parametric symbols
163
        // shared selectors are instance of parametric symbol "sel"
164
        preamble << "; END DATATYPE " << std::endl;
165
      }
166
      // all other sorts are builtin into the LFSC signature
167
    }
168
  }
169
1
  Trace("lfsc-print-debug") << "; print user symbols" << std::endl;
170
  // [1b] user declare function symbols
171
6
  for (const Node& s : syms)
172
  {
173
10
    TypeNode st = s.getType();
174
15
    if (st.isConstructor() || st.isSelector() || st.isTester()
175
10
        || st.isUpdater())
176
    {
177
      // constructors, selector, testers, updaters are defined by the datatype
178
      continue;
179
    }
180
10
    Node si = d_tproc.convert(s);
181
10
    preamble << "(define " << si << " (var "
182
5
             << d_tproc.getOrAssignIndexForVar(s) << " ";
183
5
    printType(preamble, st);
184
5
    preamble << "))" << std::endl;
185
  }
186
187
1
  Trace("lfsc-print-debug") << "; compute proof letification" << std::endl;
188
  // [2] compute the proof letification
189
2
  std::vector<const ProofNode*> pletList;
190
2
  std::map<const ProofNode*, size_t> pletMap;
191
1
  computeProofLetification(pnBody, pletList, pletMap);
192
193
1
  Trace("lfsc-print-debug") << "; compute term lets" << std::endl;
194
  // compute the term lets
195
2
  LetBinding lbind;
196
4
  for (const Node& ia : iasserts)
197
  {
198
3
    lbind.process(ia);
199
  }
200
  // We do a "dry-run" of proof printing here, using the LetBinding print
201
  // channel. This pass traverses the proof but does not print it, but instead
202
  // updates the let binding data structure for all nodes that appear anywhere
203
  // in the proof.
204
2
  LfscPrintChannelPre lpcp(lbind);
205
2
  LetBinding emptyLetBind;
206
1
  std::map<const ProofNode*, size_t>::iterator itp;
207
4
  for (const ProofNode* p : pletList)
208
  {
209
3
    itp = pletMap.find(p);
210
3
    Assert(itp != pletMap.end());
211
3
    size_t pid = itp->second;
212
3
    pletMap.erase(p);
213
3
    printProofInternal(&lpcp, p, emptyLetBind, pletMap, passumeMap);
214
3
    pletMap[p] = pid;
215
  }
216
  // Print the body of the outermost scope
217
1
  printProofInternal(&lpcp, pnBody, emptyLetBind, pletMap, passumeMap);
218
219
  // [3] print warnings
220
2
  for (PfRule r : d_trustWarned)
221
  {
222
1
    out << "; WARNING: adding trust step for " << r << std::endl;
223
  }
224
225
  // [4] print the DSL rewrite rule declarations
226
  // TODO cvc5-projects #285.
227
228
  // [5] print the check command and term lets
229
1
  out << preamble.str();
230
1
  out << "(check" << std::endl;
231
1
  cparen << ")";
232
  // print the term let list
233
1
  printLetList(out, cparen, lbind);
234
235
1
  Trace("lfsc-print-debug") << "; print asserts" << std::endl;
236
  // [6] print the assertions, with letification
237
  // the assumption identifier mapping
238
4
  for (size_t i = 0, nasserts = iasserts.size(); i < nasserts; i++)
239
  {
240
6
    Node ia = iasserts[i];
241
3
    out << "(% ";
242
3
    LfscPrintChannelOut::printAssumeId(out, i);
243
3
    out << " (holds ";
244
3
    printInternal(out, ia, lbind);
245
3
    out << ")" << std::endl;
246
3
    cparen << ")";
247
  }
248
249
1
  Trace("lfsc-print-debug") << "; print annotation" << std::endl;
250
  // [7] print the annotation
251
1
  out << "(: (holds false)" << std::endl;
252
1
  cparen << ")";
253
254
1
  Trace("lfsc-print-debug") << "; print proof body" << std::endl;
255
  // [8] print the proof body
256
1
  Assert(pn->getRule() == PfRule::SCOPE);
257
  // the outermost scope can be ignored (it is the scope of the assertions,
258
  // which are already printed above).
259
2
  LfscPrintChannelOut lout(out);
260
1
  printProofLetify(&lout, pnBody, lbind, pletList, pletMap, passumeMap);
261
262
1
  out << cparen.str() << std::endl;
263
1
}
264
265
1
void LfscPrinter::printProofLetify(
266
    LfscPrintChannel* out,
267
    const ProofNode* pn,
268
    const LetBinding& lbind,
269
    const std::vector<const ProofNode*>& pletList,
270
    std::map<const ProofNode*, size_t>& pletMap,
271
    std::map<Node, size_t>& passumeMap)
272
{
273
  // closing parentheses
274
1
  size_t cparen = 0;
275
276
  // define the let proofs
277
1
  if (!pletList.empty())
278
  {
279
1
    std::map<const ProofNode*, size_t>::iterator itp;
280
4
    for (const ProofNode* p : pletList)
281
    {
282
3
      itp = pletMap.find(p);
283
3
      Assert(itp != pletMap.end());
284
3
      size_t pid = itp->second;
285
      // print (plet _ _
286
3
      out->printOpenLfscRule(LfscRule::PLET);
287
3
      cparen++;
288
3
      out->printHole();
289
3
      out->printHole();
290
3
      out->printEndLine();
291
      // print the letified proof
292
3
      pletMap.erase(p);
293
3
      printProofInternal(out, p, lbind, pletMap, passumeMap);
294
3
      pletMap[p] = pid;
295
      // print the lambda (\ __pX
296
3
      out->printOpenLfscRule(LfscRule::LAMBDA);
297
3
      cparen++;
298
3
      out->printProofId(pid);
299
3
      out->printEndLine();
300
    }
301
1
    out->printEndLine();
302
  }
303
304
  // [2] print the proof body
305
1
  printProofInternal(out, pn, lbind, pletMap, passumeMap);
306
307
  // print the closing parenthesis
308
1
  out->printCloseRule(cparen);
309
1
}
310
311
8
void LfscPrinter::printProofInternal(
312
    LfscPrintChannel* out,
313
    const ProofNode* pn,
314
    const LetBinding& lbind,
315
    const std::map<const ProofNode*, size_t>& pletMap,
316
    std::map<Node, size_t>& passumeMap)
317
{
318
  // the stack
319
16
  std::vector<PExpr> visit;
320
  // whether we have to process children
321
16
  std::unordered_set<const ProofNode*> processingChildren;
322
  // helper iterators
323
8
  std::unordered_set<const ProofNode*>::iterator pit;
324
8
  std::map<const ProofNode*, size_t>::const_iterator pletIt;
325
8
  std::map<Node, size_t>::iterator passumeIt;
326
16
  Node curn;
327
16
  TypeNode curtn;
328
  const ProofNode* cur;
329
8
  visit.push_back(PExpr(pn));
330
366
  do
331
  {
332
374
    curn = visit.back().d_node;
333
374
    curtn = visit.back().d_typeNode;
334
374
    cur = visit.back().d_pnode;
335
374
    visit.pop_back();
336
    // case 1: printing a proof
337
374
    if (cur != nullptr)
338
    {
339
172
      PfRule r = cur->getRule();
340
      // maybe it is letified
341
172
      pletIt = pletMap.find(cur);
342
188
      if (pletIt != pletMap.end())
343
      {
344
        // a letified proof
345
16
        out->printProofId(pletIt->second);
346
16
        continue;
347
      }
348
156
      pit = processingChildren.find(cur);
349
156
      if (pit == processingChildren.end())
350
      {
351
84
        bool isLambda = false;
352
84
        if (r == PfRule::LFSC_RULE)
353
        {
354
36
          Assert(!cur->getArguments().empty());
355
36
          LfscRule lr = getLfscRule(cur->getArguments()[0]);
356
36
          isLambda = (lr == LfscRule::LAMBDA);
357
        }
358
84
        if (r == PfRule::ASSUME)
359
        {
360
          // an assumption, must have a name
361
6
          passumeIt = passumeMap.find(cur->getResult());
362
6
          Assert(passumeIt != passumeMap.end());
363
6
          out->printAssumeId(passumeIt->second);
364
        }
365
78
        else if (isLambda)
366
        {
367
          Assert(cur->getArguments().size() == 3);
368
          // lambdas are handled specially. We print in a self contained way
369
          // here.
370
          // allocate an assumption, if necessary
371
          size_t pid;
372
          Node assumption = cur->getArguments()[2];
373
          passumeIt = passumeMap.find(assumption);
374
          if (passumeIt == passumeMap.end())
375
          {
376
            pid = d_assumpCounter;
377
            d_assumpCounter++;
378
            passumeMap[assumption] = pid;
379
          }
380
          else
381
          {
382
            pid = passumeIt->second;
383
          }
384
          // make the node whose name is the assumption id, where notice that
385
          // the type of this node does not matter
386
          std::stringstream pidNodeName;
387
          LfscPrintChannelOut::printAssumeId(pidNodeName, pid);
388
          // must be an internal symbol so that it is not turned into (bvar ...)
389
          Node pidNode =
390
              d_tproc.mkInternalSymbol(pidNodeName.str(), d_boolType);
391
          // print "(\ "
392
          out->printOpenRule(cur);
393
          // print the identifier
394
          out->printNode(pidNode);
395
          // Print the body of the proof with a fresh proof letification. We can
396
          // keep the assumption map and the let binding (for terms).
397
          std::vector<const ProofNode*> pletListNested;
398
          std::map<const ProofNode*, size_t> pletMapNested;
399
          const ProofNode* curBody = cur->getChildren()[0].get();
400
          computeProofLetification(curBody, pletListNested, pletMapNested);
401
          printProofLetify(
402
              out, curBody, lbind, pletListNested, pletMapNested, passumeMap);
403
          // print ")"
404
          out->printCloseRule();
405
        }
406
        else
407
        {
408
          // assert that we should traverse cur when letifying
409
78
          Assert(d_lpltc.shouldTraverse(cur));
410
          // a normal rule application, compute the proof arguments, which
411
          // notice in the case of PI also may modify our passumeMap.
412
156
          std::vector<PExpr> args;
413
78
          if (computeProofArgs(cur, args))
414
          {
415
72
            processingChildren.insert(cur);
416
            // will revisit this proof node to close parentheses
417
72
            visit.push_back(PExpr(cur));
418
72
            std::reverse(args.begin(), args.end());
419
72
            visit.insert(visit.end(), args.begin(), args.end());
420
            // print the rule name
421
72
            out->printOpenRule(cur);
422
          }
423
          else
424
          {
425
            // could not print the rule, trust for now
426
12
            Node res = d_tproc.convert(cur->getResult());
427
6
            res = lbind.convert(res, "__t", true);
428
6
            out->printTrust(res, r);
429
6
            if (d_trustWarned.find(r) == d_trustWarned.end())
430
            {
431
1
              d_trustWarned.insert(r);
432
            }
433
          }
434
        }
435
      }
436
      else
437
      {
438
72
        processingChildren.erase(cur);
439
72
        out->printCloseRule();
440
      }
441
    }
442
    // case 2: printing a node
443
202
    else if (!curn.isNull())
444
    {
445
      // it has already been converted to internal form, we letify it here
446
64
      Node curni = lbind.convert(curn, "__t", true);
447
32
      out->printNode(curni);
448
    }
449
    // case 3: printing a type node
450
170
    else if (!curtn.isNull())
451
    {
452
      out->printTypeNode(curtn);
453
    }
454
    // case 4: a hole
455
    else
456
    {
457
170
      out->printHole();
458
    }
459
374
  } while (!visit.empty());
460
8
}
461
462
78
bool LfscPrinter::computeProofArgs(const ProofNode* pn,
463
                                   std::vector<PExpr>& pargs)
464
{
465
78
  const std::vector<std::shared_ptr<ProofNode>>& children = pn->getChildren();
466
156
  std::vector<const ProofNode*> cs;
467
170
  for (const std::shared_ptr<ProofNode>& c : children)
468
  {
469
92
    cs.push_back(c.get());
470
  }
471
78
  PfRule r = pn->getRule();
472
78
  const std::vector<Node>& args = pn->getArguments();
473
156
  std::vector<Node> as;
474
200
  for (const Node& a : args)
475
  {
476
244
    Node ac = d_tproc.convert(a);
477
122
    Assert(!ac.isNull());
478
122
    as.push_back(ac);
479
  }
480
  // The proof expression stream, which packs the next expressions (proofs,
481
  // terms, sorts, LFSC datatypes) into a print-expression vector pargs. This
482
  // stream can be used via "pf << e" which appends an expression to the
483
  // vector maintained by this stream.
484
156
  PExprStream pf(pargs, d_tt, d_ff);
485
  // hole
486
156
  PExpr h;
487
156
  Trace("lfsc-print-debug2")
488
156
      << "Compute proof args " << r << " #children= " << cs.size()
489
78
      << " #args=" << as.size() << std::endl;
490
78
  switch (r)
491
  {
492
    // SAT
493
2
    case PfRule::RESOLUTION:
494
2
      pf << h << h << h << cs[0] << cs[1] << args[0].getConst<bool>() << as[1];
495
2
      break;
496
    case PfRule::REORDERING: pf << h << as[0] << cs[0]; break;
497
    case PfRule::FACTORING: pf << h << h << cs[0]; break;
498
    // Boolean
499
    case PfRule::SPLIT: pf << as[0]; break;
500
    case PfRule::NOT_NOT_ELIM: pf << h << cs[0]; break;
501
2
    case PfRule::CONTRA: pf << h << cs[0] << cs[1]; break;
502
2
    case PfRule::MODUS_PONENS:
503
2
    case PfRule::EQ_RESOLVE: pf << h << h << cs[0] << cs[1]; break;
504
    case PfRule::NOT_AND: pf << h << h << cs[0]; break;
505
4
    case PfRule::NOT_OR_ELIM:
506
4
    case PfRule::AND_ELIM: pf << h << h << args[0] << cs[0]; break;
507
    case PfRule::IMPLIES_ELIM:
508
    case PfRule::NOT_IMPLIES_ELIM1:
509
    case PfRule::NOT_IMPLIES_ELIM2:
510
    case PfRule::EQUIV_ELIM1:
511
    case PfRule::EQUIV_ELIM2:
512
    case PfRule::NOT_EQUIV_ELIM1:
513
    case PfRule::NOT_EQUIV_ELIM2:
514
    case PfRule::XOR_ELIM1:
515
    case PfRule::XOR_ELIM2:
516
    case PfRule::NOT_XOR_ELIM1:
517
    case PfRule::NOT_XOR_ELIM2: pf << h << h << cs[0]; break;
518
    case PfRule::ITE_ELIM1:
519
    case PfRule::ITE_ELIM2:
520
    case PfRule::NOT_ITE_ELIM1:
521
    case PfRule::NOT_ITE_ELIM2: pf << h << h << h << cs[0]; break;
522
    // CNF
523
    case PfRule::CNF_AND_POS:
524
    case PfRule::CNF_OR_NEG:
525
      // print second argument as a raw integer (mpz)
526
      pf << h << as[0] << args[1];
527
      break;
528
    case PfRule::CNF_AND_NEG: pf << h << as[0]; break;
529
    case PfRule::CNF_OR_POS:
530
      pf << as[0];
531
      break;
532
      break;
533
    case PfRule::CNF_IMPLIES_POS:
534
    case PfRule::CNF_IMPLIES_NEG1:
535
    case PfRule::CNF_IMPLIES_NEG2:
536
    case PfRule::CNF_EQUIV_POS1:
537
    case PfRule::CNF_EQUIV_POS2:
538
    case PfRule::CNF_EQUIV_NEG1:
539
    case PfRule::CNF_EQUIV_NEG2:
540
    case PfRule::CNF_XOR_POS1:
541
    case PfRule::CNF_XOR_POS2:
542
    case PfRule::CNF_XOR_NEG1:
543
    case PfRule::CNF_XOR_NEG2: pf << as[0][0] << as[0][1]; break;
544
    case PfRule::CNF_ITE_POS1:
545
    case PfRule::CNF_ITE_POS2:
546
    case PfRule::CNF_ITE_POS3:
547
    case PfRule::CNF_ITE_NEG1:
548
    case PfRule::CNF_ITE_NEG2:
549
    case PfRule::CNF_ITE_NEG3: pf << as[0][0] << as[0][1] << as[0][2]; break;
550
    // equality
551
24
    case PfRule::REFL: pf << as[0]; break;
552
    case PfRule::SYMM: pf << h << h << cs[0]; break;
553
2
    case PfRule::TRANS: pf << h << h << h << cs[0] << cs[1]; break;
554
    case PfRule::TRUE_INTRO:
555
    case PfRule::FALSE_INTRO:
556
    case PfRule::TRUE_ELIM:
557
    case PfRule::FALSE_ELIM: pf << h << cs[0]; break;
558
    // arithmetic
559
    case PfRule::ARITH_MULT_POS:
560
    case PfRule::ARITH_MULT_NEG:
561
    {
562
      pf << h << as[0] << as[1];
563
    }
564
    break;
565
    case PfRule::ARITH_TRICHOTOMY:
566
    {
567
      // should be robust to different orderings
568
      pf << h << h << h << cs[0] << cs[1];
569
    }
570
    break;
571
    // strings
572
    case PfRule::STRING_LENGTH_POS: pf << as[0]; break;
573
    case PfRule::STRING_LENGTH_NON_EMPTY: pf << h << cs[0]; break;
574
    case PfRule::RE_INTER: pf << h << h << h << cs[0] << cs[1]; break;
575
    case PfRule::CONCAT_EQ:
576
      pf << h << h << h << args[0].getConst<bool>() << cs[0];
577
      break;
578
    case PfRule::CONCAT_UNIFY:
579
      pf << h << h << h << h << args[0].getConst<bool>() << cs[0] << cs[1];
580
      break;
581
    case PfRule::CONCAT_CSPLIT:
582
      pf << h << h << h << h << args[0].getConst<bool>() << cs[0] << cs[1];
583
      break;
584
      break;
585
    case PfRule::RE_UNFOLD_POS:
586
      if (children[0]->getResult()[1].getKind() != REGEXP_CONCAT)
587
      {
588
        return false;
589
      }
590
      pf << h << h << h << cs[0];
591
      break;
592
    case PfRule::STRING_EAGER_REDUCTION:
593
    {
594
      Kind k = as[0].getKind();
595
      if (k == STRING_TO_CODE || k == STRING_CONTAINS || k == STRING_INDEXOF)
596
      {
597
        pf << h << as[0] << as[0][0].getType();
598
      }
599
      else
600
      {
601
        // not yet defined for other kinds
602
        return false;
603
      }
604
    }
605
    break;
606
    case PfRule::STRING_REDUCTION:
607
    {
608
      Kind k = as[0].getKind();
609
      if (k == STRING_SUBSTR || k == STRING_INDEXOF)
610
      {
611
        pf << h << as[0] << as[0][0].getType();
612
      }
613
      else
614
      {
615
        // not yet defined for other kinds
616
        return false;
617
      }
618
    }
619
    break;
620
    // quantifiers
621
    case PfRule::SKOLEM_INTRO:
622
    {
623
      pf << h << d_tproc.convert(SkolemManager::getOriginalForm(args[0]));
624
    }
625
    break;
626
    // ---------- arguments of non-translated rules go here
627
36
    case PfRule::LFSC_RULE:
628
    {
629
36
      LfscRule lr = getLfscRule(args[0]);
630
      // lambda should be processed elsewhere
631
36
      Assert(lr != LfscRule::LAMBDA);
632
      // Note that `args` has 2 builtin arguments, thus the first real argument
633
      // begins at index 2
634
36
      switch (lr)
635
      {
636
        case LfscRule::SCOPE: pf << h << as[2] << cs[0]; break;
637
        case LfscRule::NEG_SYMM: pf << h << h << cs[0]; break;
638
36
        case LfscRule::CONG: pf << h << h << h << h << cs[0] << cs[1]; break;
639
        case LfscRule::AND_INTRO1: pf << h << cs[0]; break;
640
        case LfscRule::NOT_AND_REV: pf << h << h << cs[0]; break;
641
        case LfscRule::PROCESS_SCOPE: pf << h << h << as[2] << cs[0]; break;
642
        case LfscRule::AND_INTRO2: pf << h << h << cs[0] << cs[1]; break;
643
        case LfscRule::ARITH_SUM_UB: pf << h << h << h << cs[0] << cs[1]; break;
644
        default: return false; break;
645
      }
646
    }
647
36
    break;
648
6
    default:
649
    {
650
6
      return false;
651
      break;
652
    }
653
  }
654
72
  return true;
655
}
656
657
1
void LfscPrinter::computeProofLetification(
658
    const ProofNode* pn,
659
    std::vector<const ProofNode*>& pletList,
660
    std::map<const ProofNode*, size_t>& pletMap)
661
{
662
  // use callback to specify to stop at LAMBDA
663
1
  ProofLetify::computeProofLet(pn, pletList, pletMap, 2, &d_lpltc);
664
1
}
665
666
void LfscPrinter::print(std::ostream& out, Node n)
667
{
668
  Node ni = d_tproc.convert(n);
669
  printLetify(out, ni);
670
}
671
672
void LfscPrinter::printLetify(std::ostream& out, Node n)
673
{
674
  // closing parentheses
675
  std::stringstream cparen;
676
677
  LetBinding lbind;
678
  lbind.process(n);
679
680
  // [1] print the letification
681
  printLetList(out, cparen, lbind);
682
683
  // [2] print the body
684
  printInternal(out, n, lbind);
685
686
  out << cparen.str();
687
}
688
689
1
void LfscPrinter::printLetList(std::ostream& out,
690
                               std::ostream& cparen,
691
                               LetBinding& lbind)
692
{
693
2
  std::vector<Node> letList;
694
1
  lbind.letify(letList);
695
1
  std::map<Node, size_t>::const_iterator it;
696
9
  for (size_t i = 0, nlets = letList.size(); i < nlets; i++)
697
  {
698
16
    Node nl = letList[i];
699
8
    out << "(@ ";
700
8
    size_t id = lbind.getId(nl);
701
8
    Assert(id != 0);
702
8
    LfscPrintChannelOut::printId(out, id);
703
8
    out << " ";
704
    // remove, print, insert again
705
8
    printInternal(out, nl, lbind, false);
706
8
    out << std::endl;
707
8
    cparen << ")";
708
  }
709
1
}
710
711
void LfscPrinter::printInternal(std::ostream& out, Node n)
712
{
713
  LetBinding lbind;
714
  printInternal(out, n, lbind);
715
}
716
11
void LfscPrinter::printInternal(std::ostream& out,
717
                                Node n,
718
                                LetBinding& lbind,
719
                                bool letTop)
720
{
721
22
  Node nc = lbind.convert(n, "__t", letTop);
722
11
  LfscPrintChannelOut::printNodeInternal(out, nc);
723
11
}
724
725
6
void LfscPrinter::printType(std::ostream& out, TypeNode tn)
726
{
727
12
  TypeNode tni = d_tproc.convertType(tn);
728
6
  LfscPrintChannelOut::printTypeNodeInternal(out, tni);
729
6
}
730
731
}  // namespace proof
732
31137
}  // namespace cvc5