LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/proof/lfsc - lfsc_printer.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 534 618 86.4 %
Date: 2026-02-16 11:40:47 Functions: 15 16 93.8 %
Branches: 227 322 70.5 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * Top contributors (to current version):
       3                 :            :  *   Andrew Reynolds, Hans-Joerg Schurr, Abdalrhman Mohamed
       4                 :            :  *
       5                 :            :  * This file is part of the cvc5 project.
       6                 :            :  *
       7                 :            :  * Copyright (c) 2009-2025 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 "options/proof_options.h"
      26                 :            : #include "proof/lfsc/lfsc_list_sc_node_converter.h"
      27                 :            : #include "proof/lfsc/lfsc_print_channel.h"
      28                 :            : 
      29                 :            : using namespace cvc5::internal::kind;
      30                 :            : using namespace cvc5::internal::rewriter;
      31                 :            : 
      32                 :            : namespace cvc5::internal {
      33                 :            : namespace proof {
      34                 :            : 
      35                 :       1696 : LfscPrinter::LfscPrinter(Env& env,
      36                 :            :                          LfscNodeConverter& ltp,
      37                 :       1696 :                          rewriter::RewriteDb* rdb)
      38                 :            :     : EnvObj(env),
      39                 :            :       d_tproc(ltp),
      40                 :            :       d_assumpCounter(0),
      41                 :            :       d_trustChildPletCounter(0),
      42                 :            :       d_termLetPrefix("t"),
      43                 :            :       d_assumpPrefix("a"),
      44                 :            :       d_pletPrefix("p"),
      45                 :            :       d_pletTrustChildPrefix("q"),
      46                 :       1696 :       d_rdb(rdb)
      47                 :            : {
      48                 :       1696 :   NodeManager* nm = nodeManager();
      49                 :       1696 :   d_boolType = nm->booleanType();
      50                 :            :   // used for the `flag` type in LFSC
      51                 :       1696 :   d_tt = d_tproc.mkInternalSymbol("tt", d_boolType);
      52                 :       1696 :   d_ff = d_tproc.mkInternalSymbol("ff", d_boolType);
      53                 :       1696 : }
      54                 :            : 
      55                 :       1696 : void LfscPrinter::print(std::ostream& out, const ProofNode* pn)
      56                 :            : {
      57         [ +  - ]:       1696 :   Trace("lfsc-print-debug") << "; ORIGINAL PROOF: " << *pn << std::endl;
      58 [ -  + ][ -  + ]:       1696 :   Assert (!pn->getChildren().empty());
                 [ -  - ]
      59                 :            :   // closing parentheses
      60                 :       3392 :   std::stringstream cparen;
      61                 :       1696 :   const std::vector<Node>& definitions = pn->getArguments();
      62                 :       3392 :   std::unordered_set<Node> definedSymbols;
      63         [ +  + ]:       2253 :   for (const Node& n : definitions)
      64                 :            :   {
      65                 :        557 :     definedSymbols.insert(n[0]);
      66                 :            :     // Note that we don't have to convert it via the term processor (for the
      67                 :            :     // sake of inferring declared symbols), since this is already done in the
      68                 :            :     // lfsc post processor update method for the outermost SCOPE.
      69                 :            :   }
      70                 :       1696 :   const std::vector<Node>& assertions = pn->getChildren()[0]->getArguments();
      71                 :       1696 :   const ProofNode* pnBody = pn->getChildren()[0]->getChildren()[0].get();
      72                 :            : 
      73                 :            :   // clear the rules we have warned about
      74                 :       1696 :   d_trustWarned.clear();
      75                 :            : 
      76                 :            :   // [1] convert assertions to internal and set up assumption map
      77         [ +  - ]:       1696 :   Trace("lfsc-print-debug") << "; print declarations" << std::endl;
      78                 :       3392 :   std::vector<Node> iasserts;
      79                 :       3392 :   std::map<Node, size_t> passumeMap;
      80         [ +  + ]:      17662 :   for (size_t i = 0, nasserts = assertions.size(); i < nasserts; i++)
      81                 :            :   {
      82                 :      15966 :     Node a = assertions[i];
      83                 :      15966 :     iasserts.push_back(d_tproc.convert(a));
      84                 :            :     // remember the assumption name
      85                 :      15966 :     passumeMap[a] = i;
      86                 :            :   }
      87                 :       1696 :   d_assumpCounter = assertions.size();
      88                 :            : 
      89                 :            :   // [2] compute the proof letification
      90         [ +  - ]:       1696 :   Trace("lfsc-print-debug") << "; compute proof letification" << std::endl;
      91                 :       3392 :   std::vector<const ProofNode*> pletList;
      92                 :       3392 :   std::map<const ProofNode*, size_t> pletMap;
      93                 :       1696 :   computeProofLetification(pnBody, pletList, pletMap);
      94                 :            : 
      95                 :            :   // [3] compute the global term letification and declared symbols and types
      96         [ +  - ]:       3392 :   Trace("lfsc-print-debug")
      97                 :       1696 :       << "; compute global term letification and declared symbols" << std::endl;
      98                 :       3392 :   LetBinding lbind(d_termLetPrefix);
      99         [ +  + ]:      17662 :   for (const Node& ia : iasserts)
     100                 :            :   {
     101                 :      15966 :     lbind.process(ia);
     102                 :            :   }
     103                 :            :   // We do a "dry-run" of proof printing here, using the LetBinding print
     104                 :            :   // channel. This pass traverses the proof but does not print it, but instead
     105                 :            :   // updates the let binding data structure for all nodes that appear anywhere
     106                 :            :   // in the proof. It is also important for the term processor for collecting
     107                 :            :   // symbols and types that are used in the proof.
     108                 :       3392 :   LfscPrintChannelPre lpcp(lbind);
     109                 :       3392 :   LetBinding emptyLetBind(d_termLetPrefix);
     110                 :       1696 :   std::map<const ProofNode*, size_t>::iterator itp;
     111         [ +  + ]:     142867 :   for (const ProofNode* p : pletList)
     112                 :            :   {
     113                 :     141171 :     itp = pletMap.find(p);
     114 [ -  + ][ -  + ]:     141171 :     Assert(itp != pletMap.end());
                 [ -  - ]
     115                 :     141171 :     size_t pid = itp->second;
     116                 :     141171 :     pletMap.erase(p);
     117                 :     141171 :     printProofInternal(&lpcp, p, emptyLetBind, pletMap, passumeMap);
     118                 :     141171 :     pletMap[p] = pid;
     119                 :     141171 :     Node resType = p->getResult();
     120                 :     141171 :     lbind.process(d_tproc.convert(resType));
     121                 :            :   }
     122                 :            :   // Print the body of the outermost scope
     123                 :       1696 :   printProofInternal(&lpcp, pnBody, emptyLetBind, pletMap, passumeMap);
     124                 :            : 
     125                 :            :   // [4] print declared sorts and symbols
     126                 :            :   // [4a] user declare function symbols
     127                 :            :   // Note that this is buffered into an output stream preambleSymDecl and then
     128                 :            :   // printed after types. We require printing the declared symbols here so that
     129                 :            :   // the set of collected declared types is complete at [4b].
     130         [ +  - ]:       1696 :   Trace("lfsc-print-debug") << "; print user symbols" << std::endl;
     131                 :       3392 :   std::stringstream preambleSymDecl;
     132                 :       1696 :   const std::unordered_set<Node>& syms = d_tproc.getDeclaredSymbols();
     133         [ +  + ]:      17859 :   for (const Node& s : syms)
     134                 :            :   {
     135                 :      16163 :     TypeNode st = s.getType();
     136         [ +  - ]:      32326 :     if (st.isDatatypeConstructor() || st.isDatatypeSelector()
     137 [ +  - ][ +  - ]:      16163 :         || st.isDatatypeTester() || st.isDatatypeUpdater()
     138 [ +  - ][ +  + ]:      32326 :         || definedSymbols.find(s) != definedSymbols.cend())
                 [ +  + ]
     139                 :            :     {
     140                 :            :       // Constructors, selector, testers, updaters are defined by the datatype.
     141                 :            :       // Some definitions depend on declarations and other definitions. So, we
     142                 :            :       // print them in order after declarations.
     143                 :        557 :       continue;
     144                 :            :     }
     145                 :      31212 :     Node si = d_tproc.convert(s);
     146                 :      15606 :     preambleSymDecl << "(define " << si << " (var "
     147                 :      15606 :                     << d_tproc.getOrAssignIndexForFVar(s) << " ";
     148                 :      15606 :     printType(preambleSymDecl, st);
     149                 :      15606 :     preambleSymDecl << "))" << std::endl;
     150                 :            :   }
     151                 :            :   // Note that definitions always use their own internal letification, since
     152                 :            :   // their bodies are not part of the main proof. It is possible to share term
     153                 :            :   // letification via global definitions, however, this requires further
     154                 :            :   // analysis to ensure symbols are printed in the correct order. This is
     155                 :            :   // not done for simplicity.
     156         [ +  + ]:       2253 :   for (const Node& def : definitions)
     157                 :            :   {
     158                 :       1114 :     Node si = d_tproc.convert(def[0]);
     159                 :        557 :     preambleSymDecl << "(define " << si << ' ';
     160                 :        557 :     print(preambleSymDecl, def[1]);
     161                 :        557 :     preambleSymDecl << ')' << std::endl;
     162                 :            :   }
     163                 :            :   // [4b] user declared sorts
     164         [ +  - ]:       1696 :   Trace("lfsc-print-debug") << "; print user sorts" << std::endl;
     165                 :       3392 :   std::stringstream preamble;
     166                 :       3392 :   std::unordered_set<TypeNode> sts;
     167                 :       3392 :   std::unordered_set<size_t> tupleArity;
     168                 :            :   // get the types from the term processor, which has seen all terms occurring
     169                 :            :   // in the proof at this point
     170                 :            :   // The for loop below may add elements to the set of declared types, so we
     171                 :            :   // copy the set to ensure that the for loop iterators do not become outdated.
     172                 :       3392 :   const std::unordered_set<TypeNode> types = d_tproc.getDeclaredTypes();
     173         [ +  + ]:       4862 :   for (const TypeNode& st : types)
     174                 :            :   {
     175                 :            :     // note that we must get all "component types" of a type, so that
     176                 :            :     // e.g. U is printed as a sort declaration when we have type (Array U Int).
     177                 :       3166 :     ensureTypeDefinitionPrinted(preamble, st, sts, tupleArity);
     178                 :            :   }
     179                 :            :   // print datatype definitions for the above sorts
     180         [ +  + ]:       4940 :   for (const TypeNode& stc : sts)
     181                 :            :   {
     182 [ +  + ][ +  + ]:       3244 :     if (!stc.isDatatype() || stc.getKind() == Kind::PARAMETRIC_DATATYPE)
                 [ +  + ]
     183                 :            :     {
     184                 :            :       // skip the instance of a parametric datatype
     185                 :       2811 :       continue;
     186                 :            :     }
     187                 :        433 :     const DType& dt = stc.getDType();
     188                 :        433 :     preamble << "; DATATYPE " << dt.getName() << std::endl;
     189         [ +  + ]:       1145 :     for (size_t i = 0, ncons = dt.getNumConstructors(); i < ncons; i++)
     190                 :            :     {
     191                 :        712 :       const DTypeConstructor& cons = dt[i];
     192                 :       1424 :       std::string cname = d_tproc.getNameForUserNameOf(cons.getConstructor());
     193                 :       1424 :       Node cc = NodeManager::mkRawSymbol(cname, stc);
     194                 :            :       // print constructor/tester
     195                 :        712 :       preamble << "(declare " << cc << " term)" << std::endl;
     196         [ +  + ]:       1489 :       for (size_t j = 0, nargs = cons.getNumArgs(); j < nargs; j++)
     197                 :            :       {
     198                 :        777 :         const DTypeSelector& arg = cons[j];
     199                 :            :         // print selector
     200                 :       1554 :         std::string sname = d_tproc.getNameForUserNameOf(arg.getSelector());
     201                 :        777 :         Node sc = NodeManager::mkRawSymbol(sname, stc);
     202                 :        777 :         preamble << "(declare " << sc << " term)" << std::endl;
     203                 :            :       }
     204                 :            :     }
     205                 :            :     // testers and updaters are instances of parametric symbols
     206                 :            :     // shared selectors are instance of parametric symbol "sel"
     207                 :        433 :     preamble << "; END DATATYPE " << std::endl;
     208                 :            :   }
     209                 :            :   // [4c] user declared function symbols
     210                 :       1696 :   preamble << preambleSymDecl.str();
     211                 :            : 
     212                 :            :   // [5] print warnings
     213         [ +  + ]:       5292 :   for (ProofRule r : d_trustWarned)
     214                 :            :   {
     215                 :       3596 :     out << "; WARNING: adding trust step for " << r << std::endl;
     216                 :            :   }
     217                 :            : 
     218                 :            :   // [6] print the DSL rewrite rule declarations
     219                 :       1696 :   const std::unordered_set<ProofRewriteRule>& dslrs = lpcp.getDslRewrites();
     220         [ +  + ]:       1698 :   for (ProofRewriteRule dslr : dslrs)
     221                 :            :   {
     222                 :            :     // also computes the format for the rule
     223                 :          2 :     printDslRule(out, dslr, d_dslFormat[dslr]);
     224                 :            :   }
     225                 :            : 
     226                 :            :   // [7] print the check command and term lets
     227                 :       1696 :   out << preamble.str();
     228         [ +  + ]:       1696 :   if (options().proof.lfscFlatten)
     229                 :            :   {
     230                 :            :     // print term lets as definitions
     231                 :          2 :     std::stringstream cparenTmp;
     232                 :          1 :     printLetList(out, cparenTmp, lbind, true);
     233                 :            :   }
     234                 :            :   else
     235                 :            :   {
     236                 :            :     // the outer check statement for the main proof
     237                 :       1695 :     out << "(check" << std::endl;
     238                 :       1695 :     cparen << ")";
     239                 :            :     // print the term let list wrapped around the body of the final proof
     240                 :       1695 :     printLetList(out, cparen, lbind, false);
     241                 :            :   }
     242                 :            : 
     243         [ +  - ]:       1696 :   Trace("lfsc-print-debug") << "; print asserts" << std::endl;
     244                 :            :   // [8] print the assertions, with letification
     245                 :            :   // the assumption identifier mapping
     246         [ +  + ]:      17662 :   for (size_t i = 0, nasserts = iasserts.size(); i < nasserts; i++)
     247                 :            :   {
     248                 :      31932 :     Node ia = iasserts[i];
     249         [ +  + ]:      15966 :     if (options().proof.lfscFlatten)
     250                 :            :     {
     251                 :          1 :       out << "(declare ";
     252                 :          1 :       LfscPrintChannelOut::printId(out, i, d_assumpPrefix);
     253                 :          1 :       out << " (holds ";
     254                 :          1 :       printInternal(out, ia, lbind);
     255                 :          1 :       out << "))" << std::endl;
     256                 :            :     }
     257                 :            :     else
     258                 :            :     {
     259                 :      15965 :       out << "(# ";
     260                 :      15965 :       LfscPrintChannelOut::printId(out, i, d_assumpPrefix);
     261                 :      15965 :       out << " (holds ";
     262                 :      15965 :       printInternal(out, ia, lbind);
     263                 :      15965 :       out << ")" << std::endl;
     264                 :      15965 :       cparen << ")";
     265                 :            :     }
     266                 :            :   }
     267                 :            : 
     268         [ +  - ]:       1696 :   Trace("lfsc-print-debug") << "; print annotation" << std::endl;
     269                 :            :   // [9] print the annotation
     270         [ +  + ]:       1696 :   if (!options().proof.lfscFlatten)
     271                 :            :   {
     272                 :       1695 :     out << "(: (holds false)" << std::endl;
     273                 :       1695 :     cparen << ")";
     274                 :            :   }
     275                 :            : 
     276         [ +  - ]:       1696 :   Trace("lfsc-print-debug") << "; print proof body" << std::endl;
     277                 :            :   // [10] print the proof body
     278 [ -  + ][ -  + ]:       1696 :   Assert(pn->getRule() == ProofRule::SCOPE);
                 [ -  - ]
     279                 :            :   // the outermost scope can be ignored (it is the scope of the assertions,
     280                 :            :   // which are already printed above).
     281                 :       1696 :   LfscPrintChannelOut lout(out);
     282                 :            : 
     283         [ +  + ]:       1696 :   if (options().proof.lfscFlatten)
     284                 :            :   {
     285                 :            :     // print the proof letification as separate check statements, followed
     286                 :            :     // by the main proof.
     287         [ +  + ]:          7 :     for (size_t i = 0; i <= pletList.size(); i++)
     288                 :            :     {
     289                 :          6 :       bool isFinal = (i == pletList.size());
     290         [ +  + ]:          6 :       const ProofNode* p = isFinal ? pnBody : pletList[i];
     291                 :         12 :       Node res = p->getResult();
     292                 :         12 :       std::stringstream resType;
     293                 :          6 :       printInternal(resType, d_tproc.convert(res), lbind);
     294                 :          6 :       out << "(check (: (holds " << resType.str() << ")" << std::endl;
     295                 :            :       // print the letified proof
     296         [ +  + ]:          6 :       if (isFinal)
     297                 :            :       {
     298                 :          1 :         printProofInternal(&lout, p, lbind, pletMap, passumeMap);
     299                 :          1 :         out << "))" << std::endl;
     300                 :            :       }
     301                 :            :       else
     302                 :            :       {
     303                 :          5 :         itp = pletMap.find(p);
     304 [ -  + ][ -  + ]:          5 :         Assert(itp != pletMap.end());
                 [ -  - ]
     305                 :          5 :         size_t pid = itp->second;
     306                 :          5 :         pletMap.erase(p);
     307                 :          5 :         printProofInternal(&lout, p, lbind, pletMap, passumeMap);
     308                 :          5 :         pletMap[p] = pid;
     309                 :          5 :         out << "))" << std::endl;
     310                 :          5 :         out << "(declare ";
     311                 :          5 :         LfscPrintChannelOut::printId(out, pid, d_pletPrefix);
     312                 :          5 :         out << " (holds " << resType.str() << "))" << std::endl;
     313                 :            :       }
     314                 :            :     }
     315                 :            :   }
     316                 :            :   else
     317                 :            :   {
     318                 :       1695 :     printProofLetify(&lout, pnBody, lbind, pletList, pletMap, passumeMap);
     319                 :            :   }
     320                 :            :   // [11] print closing parantheses
     321                 :       1696 :   out << cparen.str() << std::endl;
     322                 :       1696 : }
     323                 :            : 
     324                 :       3729 : void LfscPrinter::ensureTypeDefinitionPrinted(
     325                 :            :     std::ostream& os,
     326                 :            :     TypeNode tn,
     327                 :            :     std::unordered_set<TypeNode>& processed,
     328                 :            :     std::unordered_set<size_t>& tupleArityProcessed)
     329                 :            : {
     330                 :            :   // note that we must get all "component types" of a type, so that
     331                 :            :   // e.g. U is printed as a sort declaration when we have type (Array U Int).
     332                 :       7458 :   std::unordered_set<TypeNode> ctypes;
     333                 :       3729 :   expr::getComponentTypes(tn, ctypes);
     334                 :            : 
     335         [ +  + ]:       7611 :   for (const TypeNode& stc : ctypes)
     336                 :            :   {
     337                 :       3882 :     printTypeDefinition(os, stc, processed, tupleArityProcessed);
     338                 :            :   }
     339                 :       3729 : }
     340                 :            : 
     341                 :       3882 : void LfscPrinter::printTypeDefinition(
     342                 :            :     std::ostream& os,
     343                 :            :     TypeNode tn,
     344                 :            :     std::unordered_set<TypeNode>& processed,
     345                 :            :     std::unordered_set<size_t>& tupleArityProcessed)
     346                 :            : {
     347         [ +  + ]:       3882 :   if (processed.find(tn) != processed.end())
     348                 :            :   {
     349                 :        638 :     return;
     350                 :            :   }
     351                 :       3244 :   processed.insert(tn);
     352                 :            :   // print uninterpreted sorts and uninterpreted sort constructors here
     353         [ +  + ]:       3244 :   if (tn.getKind() == Kind::SORT_TYPE)
     354                 :            :   {
     355                 :       1210 :     os << "(declare ";
     356                 :       1210 :     printType(os, tn);
     357                 :       1210 :     uint64_t arity = 0;
     358         [ +  + ]:       1210 :     if (tn.isUninterpretedSortConstructor())
     359                 :            :     {
     360                 :         11 :       arity = tn.getUninterpretedSortConstructorArity();
     361                 :            :     }
     362                 :       1210 :     std::stringstream tcparen;
     363         [ +  + ]:       1222 :     for (uint64_t i = 0; i < arity; i++)
     364                 :            :     {
     365                 :         12 :       os << " (! s" << i << " sort";
     366                 :         12 :       tcparen << ")";
     367                 :            :     }
     368                 :       1210 :     os << " sort" << tcparen.str() << ")" << std::endl;
     369                 :            :   }
     370         [ +  + ]:       2034 :   else if (tn.isDatatype())
     371                 :            :   {
     372                 :        442 :     const DType& dt = tn.getDType();
     373 [ +  + ][ +  + ]:        442 :     if (tn.getKind() == Kind::PARAMETRIC_DATATYPE || dt.isNullable())
                 [ +  + ]
     374                 :            :     {
     375                 :            :       // skip the instance of a parametric datatype
     376                 :            :       // nullables don't need printing
     377                 :         12 :       return;
     378                 :            :     }
     379         [ +  + ]:        430 :     if (dt.isTuple())
     380                 :            :     {
     381                 :         88 :       const DTypeConstructor& cons = dt[0];
     382                 :         88 :       size_t arity = cons.getNumArgs();
     383         [ +  + ]:         88 :       if (tupleArityProcessed.find(arity) == tupleArityProcessed.end())
     384                 :            :       {
     385                 :         84 :         tupleArityProcessed.insert(arity);
     386         [ +  + ]:         84 :         if (arity>0)
     387                 :            :         {
     388                 :         83 :           os << "(declare Tuple";
     389                 :         83 :           os << "_" << arity;
     390                 :            :         }
     391                 :            :         else
     392                 :            :         {
     393                 :          1 :           os << "(declare UnitTuple";
     394                 :            :         }
     395                 :         84 :         os << " ";
     396                 :         84 :         std::stringstream tcparen;
     397         [ +  + ]:        270 :         for (size_t j = 0, nargs = cons.getNumArgs(); j < nargs; j++)
     398                 :            :         {
     399                 :        186 :           os << "(! s" << j << " sort ";
     400                 :        186 :           tcparen << ")";
     401                 :            :         }
     402                 :         84 :         os << "sort" << tcparen.str() << ")";
     403                 :            :       }
     404                 :         88 :       os << std::endl;
     405                 :            :     }
     406                 :            :     else
     407                 :            :     {
     408                 :        342 :       os << "(declare ";
     409                 :        342 :       printType(os, tn);
     410                 :        342 :       std::stringstream cdttparens;
     411         [ +  + ]:        342 :       if (dt.isParametric())
     412                 :            :       {
     413                 :         18 :         std::vector<TypeNode> params = dt.getParameters();
     414         [ +  + ]:         20 :         for (const TypeNode& p : params)
     415                 :            :         {
     416                 :         11 :           os << " (! " << p << " sort";
     417                 :         11 :           cdttparens << ")";
     418                 :            :         }
     419                 :            :       }
     420                 :        342 :       os << " sort)" << cdttparens.str() << std::endl;
     421                 :            :     }
     422                 :            :     // must also ensure the subfield types of the datatype are printed
     423                 :        860 :     std::unordered_set<TypeNode> sftypes = dt.getSubfieldTypes();
     424         [ +  + ]:        993 :     for (const TypeNode& sft : sftypes)
     425                 :            :     {
     426                 :        563 :       ensureTypeDefinitionPrinted(os, sft, processed, tupleArityProcessed);
     427                 :            :     }
     428                 :            :   }
     429                 :            :   // all other sorts are builtin into the LFSC signature
     430                 :            : }
     431                 :            : 
     432                 :     411707 : void LfscPrinter::printProofLetify(
     433                 :            :     LfscPrintChannel* out,
     434                 :            :     const ProofNode* pn,
     435                 :            :     const LetBinding& lbind,
     436                 :            :     const std::vector<const ProofNode*>& pletList,
     437                 :            :     std::map<const ProofNode*, size_t>& pletMap,
     438                 :            :     std::map<Node, size_t>& passumeMap)
     439                 :            : {
     440                 :            :   // closing parentheses
     441                 :     411707 :   size_t cparen = 0;
     442                 :            : 
     443                 :            :   // define the let proofs
     444         [ +  + ]:     411707 :   if (!pletList.empty())
     445                 :            :   {
     446                 :      45913 :     std::map<const ProofNode*, size_t>::iterator itp;
     447         [ +  + ]:    1401950 :     for (const ProofNode* p : pletList)
     448                 :            :     {
     449                 :    1356040 :       itp = pletMap.find(p);
     450 [ -  + ][ -  + ]:    1356040 :       Assert(itp != pletMap.end());
                 [ -  - ]
     451                 :    1356040 :       size_t pid = itp->second;
     452                 :    1356040 :       pletMap.erase(p);
     453                 :    1356040 :       printPLet(out, p, pid, d_pletPrefix, lbind, pletMap, passumeMap);
     454                 :    1356040 :       pletMap[p] = pid;
     455                 :            :       // printPLet opens two parentheses
     456                 :    1356040 :       cparen = cparen + 2;
     457                 :            :     }
     458                 :      45913 :     out->printEndLine();
     459                 :            :   }
     460                 :            : 
     461                 :            :   // [2] print the proof body
     462                 :     411707 :   printProofInternal(out, pn, lbind, pletMap, passumeMap);
     463                 :            : 
     464                 :            :   // print the closing parenthesis
     465                 :     411707 :   out->printCloseRule(cparen);
     466                 :     411707 : }
     467                 :            : 
     468                 :    1356040 : void LfscPrinter::printPLet(LfscPrintChannel* out,
     469                 :            :                             const ProofNode* p,
     470                 :            :                             size_t pid,
     471                 :            :                             const std::string& prefix,
     472                 :            :                             const LetBinding& lbind,
     473                 :            :                             const std::map<const ProofNode*, size_t>& pletMap,
     474                 :            :                             std::map<Node, size_t>& passumeMap)
     475                 :            : {
     476                 :            :   // print (plet _ _
     477                 :    1356040 :   out->printOpenLfscRule(LfscRule::PLET);
     478                 :    1356040 :   out->printHole();
     479                 :    1356040 :   out->printHole();
     480                 :    1356040 :   out->printEndLine();
     481                 :            :   // print the letified proof
     482                 :    1356040 :   printProofInternal(out, p, lbind, pletMap, passumeMap);
     483                 :            :   // print the lambda (\ __pX
     484                 :    1356040 :   out->printOpenLfscRule(LfscRule::LAMBDA);
     485                 :    1356040 :   out->printId(pid, prefix);
     486                 :    1356040 :   out->printEndLine();
     487                 :    1356040 : }
     488                 :            : 
     489                 :    1910620 : void LfscPrinter::printProofInternal(
     490                 :            :     LfscPrintChannel* out,
     491                 :            :     const ProofNode* pn,
     492                 :            :     const LetBinding& lbind,
     493                 :            :     const std::map<const ProofNode*, size_t>& pletMap,
     494                 :            :     std::map<Node, size_t>& passumeMap)
     495                 :            : {
     496                 :            :   // the stack
     497                 :    3821240 :   std::vector<PExpr> visit;
     498                 :            :   // whether we have to process children
     499                 :    3821240 :   std::unordered_set<const ProofNode*> processingChildren;
     500                 :            :   // helper iterators
     501                 :    1910620 :   std::unordered_set<const ProofNode*>::iterator pit;
     502                 :    1910620 :   std::map<const ProofNode*, size_t>::const_iterator pletIt;
     503                 :    1910620 :   std::map<Node, size_t>::iterator passumeIt;
     504                 :    3821240 :   Node curn;
     505                 :    3821240 :   TypeNode curtn;
     506                 :            :   const ProofNode* cur;
     507                 :    1910620 :   visit.push_back(PExpr(pn));
     508                 :   76668800 :   do
     509                 :            :   {
     510                 :   78579500 :     curn = visit.back().d_node;
     511                 :   78579500 :     curtn = visit.back().d_typeNode;
     512                 :   78579500 :     cur = visit.back().d_pnode;
     513                 :   78579500 :     visit.pop_back();
     514                 :            :     // case 1: printing a proof
     515         [ +  + ]:   78579500 :     if (cur != nullptr)
     516                 :            :     {
     517                 :   35981100 :       ProofRule r = cur->getRule();
     518                 :            :       // maybe it is letified
     519                 :   35981100 :       pletIt = pletMap.find(cur);
     520         [ +  + ]:   35981100 :       if (pletIt != pletMap.end())
     521                 :            :       {
     522                 :            :         // a letified proof
     523                 :    4985310 :         out->printId(pletIt->second, d_pletPrefix);
     524                 :    4985310 :         continue;
     525                 :            :       }
     526                 :   30995800 :       pit = processingChildren.find(cur);
     527         [ +  + ]:   30995800 :       if (pit == processingChildren.end())
     528                 :            :       {
     529                 :   16573300 :         bool isLambda = false;
     530         [ +  + ]:   16573300 :         if (r == ProofRule::LFSC_RULE)
     531                 :            :         {
     532 [ -  + ][ -  + ]:    8093190 :           Assert(!cur->getArguments().empty());
                 [ -  - ]
     533                 :    8093190 :           LfscRule lr = getLfscRule(cur->getArguments()[0]);
     534                 :    8093190 :           isLambda = (lr == LfscRule::LAMBDA);
     535                 :            :         }
     536         [ +  + ]:   16573300 :         if (r == ProofRule::ASSUME)
     537                 :            :         {
     538                 :            :           // an assumption, must have a name
     539                 :     573000 :           passumeIt = passumeMap.find(cur->getResult());
     540 [ -  + ][ -  + ]:     573000 :           Assert(passumeIt != passumeMap.end());
                 [ -  - ]
     541                 :     573000 :           out->printId(passumeIt->second, d_assumpPrefix);
     542                 :            :         }
     543         [ +  + ]:   16000300 :         else if (isLambda)
     544                 :            :         {
     545 [ -  + ][ -  + ]:     410012 :           Assert(cur->getArguments().size() == 3);
                 [ -  - ]
     546                 :            :           // lambdas are handled specially. We print in a self contained way
     547                 :            :           // here.
     548                 :            :           // allocate an assumption, if necessary
     549                 :            :           size_t pid;
     550                 :     820024 :           Node assumption = cur->getArguments()[2];
     551                 :     410012 :           passumeIt = passumeMap.find(assumption);
     552         [ +  + ]:     410012 :           if (passumeIt == passumeMap.end())
     553                 :            :           {
     554                 :      23551 :             pid = d_assumpCounter;
     555                 :      23551 :             d_assumpCounter++;
     556                 :      23551 :             passumeMap[assumption] = pid;
     557                 :            :           }
     558                 :            :           else
     559                 :            :           {
     560                 :     386461 :             pid = passumeIt->second;
     561                 :            :           }
     562                 :            :           // make the node whose name is the assumption id, where notice that
     563                 :            :           // the type of this node does not matter
     564                 :     820024 :           std::stringstream pidNodeName;
     565                 :     410012 :           LfscPrintChannelOut::printId(pidNodeName, pid, d_assumpPrefix);
     566                 :            :           // must be an internal symbol so that it is not turned into (bvar ...)
     567                 :            :           Node pidNode =
     568                 :    1230040 :               d_tproc.mkInternalSymbol(pidNodeName.str(), d_boolType);
     569                 :            :           // print "(\ "
     570                 :     410012 :           out->printOpenRule(cur);
     571                 :            :           // print the identifier
     572                 :     410012 :           out->printNode(pidNode);
     573                 :            :           // Print the body of the proof with a fresh proof letification. We can
     574                 :            :           // keep the assumption map and the let binding (for terms).
     575                 :     820024 :           std::vector<const ProofNode*> pletListNested;
     576                 :     820024 :           std::map<const ProofNode*, size_t> pletMapNested;
     577                 :     410012 :           const ProofNode* curBody = cur->getChildren()[0].get();
     578                 :     410012 :           computeProofLetification(curBody, pletListNested, pletMapNested);
     579                 :     410012 :           printProofLetify(
     580                 :            :               out, curBody, lbind, pletListNested, pletMapNested, passumeMap);
     581                 :            :           // print ")"
     582                 :     410012 :           out->printCloseRule();
     583                 :            :         }
     584                 :            :         else
     585                 :            :         {
     586                 :            :           // assert that we should traverse cur when letifying
     587 [ -  + ][ -  + ]:   15590300 :           Assert(d_lpltc.shouldTraverse(cur));
                 [ -  - ]
     588                 :            :           // a normal rule application, compute the proof arguments, which
     589                 :            :           // notice in the case of PI also may modify our passumeMap.
     590                 :   31180600 :           std::vector<PExpr> args;
     591         [ +  + ]:   15590300 :           if (computeProofArgs(cur, args))
     592                 :            :           {
     593                 :   14422500 :             processingChildren.insert(cur);
     594                 :            :             // will revisit this proof node to close parentheses
     595                 :   14422500 :             visit.push_back(PExpr(cur));
     596                 :   14422500 :             std::reverse(args.begin(), args.end());
     597                 :   14422500 :             visit.insert(visit.end(), args.begin(), args.end());
     598                 :            :             // print the rule name
     599                 :   14422500 :             out->printOpenRule(cur);
     600                 :            :           }
     601                 :            :           else
     602                 :            :           {
     603                 :            :             // Could not print the rule, trust for now.
     604                 :            :             // If we are expanding trusted steps, its children are printed as
     605                 :            :             // plet applications that wrap this term, so that all subproofs are
     606                 :            :             // recorded in the proof.
     607                 :    1167820 :             size_t cparenTrustChild = 0;
     608         [ +  + ]:    1167820 :             if (options().proof.lfscExpandTrust)
     609                 :            :             {
     610                 :            :               const std::vector<std::shared_ptr<ProofNode>>& children =
     611                 :         22 :                   cur->getChildren();
     612         [ -  + ]:         22 :               for (const std::shared_ptr<ProofNode>& c : children)
     613                 :            :               {
     614                 :          0 :                 size_t pid = d_trustChildPletCounter;
     615                 :          0 :                 d_trustChildPletCounter++;
     616                 :          0 :                 printPLet(out,
     617                 :          0 :                           c.get(),
     618                 :            :                           pid,
     619                 :          0 :                           d_pletTrustChildPrefix,
     620                 :            :                           lbind,
     621                 :            :                           pletMap,
     622                 :            :                           passumeMap);
     623                 :          0 :                 cparenTrustChild = cparenTrustChild + 2;
     624                 :            :               }
     625                 :            :             }
     626                 :    2335640 :             Node res = d_tproc.convert(cur->getResult());
     627                 :    1167820 :             res = lbind.convert(res, true);
     628                 :    1167820 :             out->printTrust(res, r);
     629                 :    1167820 :             d_trustWarned.insert(r);
     630                 :    1167820 :             out->printCloseRule(cparenTrustChild);
     631                 :            :           }
     632                 :            :         }
     633                 :            :       }
     634                 :            :       else
     635                 :            :       {
     636                 :   14422500 :         processingChildren.erase(cur);
     637                 :   14422500 :         out->printCloseRule();
     638                 :            :       }
     639                 :            :     }
     640                 :            :     // case 2: printing a node
     641         [ +  + ]:   42598300 :     else if (!curn.isNull())
     642                 :            :     {
     643                 :            :       // it has already been converted to internal form, we letify it here
     644                 :    6420690 :       Node curni = lbind.convert(curn, true);
     645                 :    6420690 :       out->printNode(curni);
     646                 :            :     }
     647                 :            :     // case 3: printing a type node
     648         [ +  + ]:   36177600 :     else if (!curtn.isNull())
     649                 :            :     {
     650                 :      40192 :       out->printTypeNode(curtn);
     651                 :            :     }
     652                 :            :     // case 4: a hole
     653                 :            :     else
     654                 :            :     {
     655                 :   36137400 :       out->printHole();
     656                 :            :     }
     657         [ +  + ]:   78579500 :   } while (!visit.empty());
     658                 :    1910620 : }
     659                 :            : 
     660                 :   15590300 : bool LfscPrinter::computeProofArgs(const ProofNode* pn,
     661                 :            :                                    std::vector<PExpr>& pargs)
     662                 :            : {
     663                 :   15590300 :   const std::vector<std::shared_ptr<ProofNode>>& children = pn->getChildren();
     664                 :   31180600 :   std::vector<const ProofNode*> cs;
     665         [ +  + ]:   35252700 :   for (const std::shared_ptr<ProofNode>& c : children)
     666                 :            :   {
     667                 :   19662300 :     cs.push_back(c.get());
     668                 :            :   }
     669                 :   15590300 :   ProofRule r = pn->getRule();
     670                 :   15590300 :   const std::vector<Node>& args = pn->getArguments();
     671                 :   31180600 :   std::vector<Node> as;
     672         [ +  + ]:   40751900 :   for (const Node& a : args)
     673                 :            :   {
     674                 :   50323100 :     Node ac = d_tproc.convert(a);
     675                 :   25161600 :     Assert(!ac.isNull()) << "Could not convert " << a << " in " << r;
     676                 :   25161600 :     as.push_back(ac);
     677                 :            :   }
     678                 :            :   // The proof expression stream, which packs the next expressions (proofs,
     679                 :            :   // terms, sorts, LFSC datatypes) into a print-expression vector pargs. This
     680                 :            :   // stream can be used via "pf << e" which appends an expression to the
     681                 :            :   // vector maintained by this stream.
     682                 :   46771000 :   PExprStream pf(pargs, d_tt, d_ff);
     683                 :            :   // hole
     684                 :   31180600 :   PExpr h;
     685         [ +  - ]:   31180600 :   Trace("lfsc-print-debug2")
     686                 :          0 :       << "Compute proof args " << r << " #children= " << cs.size()
     687                 :   15590300 :       << " #args=" << as.size() << std::endl;
     688 [ +  + ][ +  + ]:   15590300 :   switch (r)
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
     689                 :            :   {
     690                 :            :     // SAT
     691                 :     792490 :     case ProofRule::RESOLUTION:
     692                 :     792490 :       pf << h << h << h << cs[0] << cs[1] << args[0].getConst<bool>() << as[1];
     693                 :     792490 :       break;
     694                 :     120224 :     case ProofRule::REORDERING: pf << h << as[0] << cs[0]; break;
     695                 :     139732 :     case ProofRule::FACTORING: pf << h << h << cs[0]; break;
     696                 :            :     // Boolean
     697                 :         34 :     case ProofRule::SPLIT: pf << as[0]; break;
     698                 :       1694 :     case ProofRule::NOT_NOT_ELIM: pf << h << cs[0]; break;
     699                 :       5144 :     case ProofRule::CONTRA: pf << h << cs[0] << cs[1]; break;
     700                 :     260622 :     case ProofRule::MODUS_PONENS:
     701                 :     260622 :     case ProofRule::EQ_RESOLVE: pf << h << h << cs[0] << cs[1]; break;
     702                 :      14650 :     case ProofRule::NOT_AND: pf << h << h << cs[0]; break;
     703                 :     235142 :     case ProofRule::NOT_OR_ELIM:
     704                 :     235142 :     case ProofRule::AND_ELIM: pf << h << h << args[0] << cs[0]; break;
     705                 :      45708 :     case ProofRule::IMPLIES_ELIM:
     706                 :            :     case ProofRule::NOT_IMPLIES_ELIM1:
     707                 :            :     case ProofRule::NOT_IMPLIES_ELIM2:
     708                 :            :     case ProofRule::EQUIV_ELIM1:
     709                 :            :     case ProofRule::EQUIV_ELIM2:
     710                 :            :     case ProofRule::NOT_EQUIV_ELIM1:
     711                 :            :     case ProofRule::NOT_EQUIV_ELIM2:
     712                 :            :     case ProofRule::XOR_ELIM1:
     713                 :            :     case ProofRule::XOR_ELIM2:
     714                 :            :     case ProofRule::NOT_XOR_ELIM1:
     715                 :      45708 :     case ProofRule::NOT_XOR_ELIM2: pf << h << h << cs[0]; break;
     716                 :       5180 :     case ProofRule::ITE_ELIM1:
     717                 :            :     case ProofRule::ITE_ELIM2:
     718                 :            :     case ProofRule::NOT_ITE_ELIM1:
     719                 :       5180 :     case ProofRule::NOT_ITE_ELIM2: pf << h << h << h << cs[0]; break;
     720                 :            :     // CNF
     721                 :      27354 :     case ProofRule::CNF_AND_POS:
     722                 :            :     case ProofRule::CNF_OR_NEG:
     723                 :            :       // print second argument as a raw integer (mpz)
     724                 :      27354 :       pf << h << as[0] << args[1];
     725                 :      27354 :       break;
     726                 :      22222 :     case ProofRule::CNF_AND_NEG: pf << h << as[0]; break;
     727                 :       5078 :     case ProofRule::CNF_OR_POS:
     728                 :       5078 :       pf << as[0];
     729                 :       5078 :       break;
     730                 :            :       break;
     731                 :      10458 :     case ProofRule::CNF_IMPLIES_POS:
     732                 :            :     case ProofRule::CNF_IMPLIES_NEG1:
     733                 :            :     case ProofRule::CNF_IMPLIES_NEG2:
     734                 :            :     case ProofRule::CNF_EQUIV_POS1:
     735                 :            :     case ProofRule::CNF_EQUIV_POS2:
     736                 :            :     case ProofRule::CNF_EQUIV_NEG1:
     737                 :            :     case ProofRule::CNF_EQUIV_NEG2:
     738                 :            :     case ProofRule::CNF_XOR_POS1:
     739                 :            :     case ProofRule::CNF_XOR_POS2:
     740                 :            :     case ProofRule::CNF_XOR_NEG1:
     741                 :      10458 :     case ProofRule::CNF_XOR_NEG2: pf << as[0][0] << as[0][1]; break;
     742                 :       2878 :     case ProofRule::CNF_ITE_POS1:
     743                 :            :     case ProofRule::CNF_ITE_POS2:
     744                 :            :     case ProofRule::CNF_ITE_POS3:
     745                 :            :     case ProofRule::CNF_ITE_NEG1:
     746                 :            :     case ProofRule::CNF_ITE_NEG2:
     747                 :       2878 :     case ProofRule::CNF_ITE_NEG3: pf << as[0][0] << as[0][1] << as[0][2]; break;
     748                 :            :     // equality
     749                 :    3725870 :     case ProofRule::REFL: pf << as[0]; break;
     750                 :     184408 :     case ProofRule::SYMM: pf << h << h << cs[0]; break;
     751                 :     968750 :     case ProofRule::TRANS: pf << h << h << h << cs[0] << cs[1]; break;
     752                 :      54234 :     case ProofRule::TRUE_INTRO:
     753                 :            :     case ProofRule::FALSE_INTRO:
     754                 :            :     case ProofRule::TRUE_ELIM:
     755                 :      54234 :     case ProofRule::FALSE_ELIM: pf << h << cs[0]; break;
     756                 :            :     // arithmetic
     757                 :      32506 :     case ProofRule::ARITH_MULT_POS:
     758                 :            :     case ProofRule::ARITH_MULT_NEG:
     759                 :            :     {
     760                 :      32506 :       pf << h << as[0] << as[1] << d_tproc.convertType(as[0].getType());
     761                 :            :     }
     762                 :      32506 :     break;
     763                 :       2756 :     case ProofRule::ARITH_TRICHOTOMY:
     764                 :            :     {
     765                 :            :       // should be robust to different orderings
     766                 :       2756 :       pf << h << h << h << cs[0] << cs[1];
     767                 :            :     }
     768                 :       2756 :     break;
     769                 :       4550 :     case ProofRule::INT_TIGHT_UB:
     770                 :            :     case ProofRule::INT_TIGHT_LB:
     771                 :            :     {
     772                 :       4550 :       Node res = pn->getResult();
     773 [ -  + ][ -  + ]:       4550 :       Assert(res.getNumChildren() == 2);
                 [ -  - ]
     774 [ -  + ][ -  + ]:       4550 :       Assert(res[1].isConst());
                 [ -  - ]
     775                 :       4550 :       pf << h << h << d_tproc.convert(res[1]) << cs[0];
     776                 :            :     }
     777                 :       4550 :     break;
     778                 :            :     // strings
     779                 :        972 :     case ProofRule::STRING_LENGTH_POS:
     780                 :        972 :       pf << as[0] << d_tproc.convertType(as[0].getType()) << h;
     781                 :        972 :       break;
     782                 :        204 :     case ProofRule::STRING_LENGTH_NON_EMPTY: pf << h << h << cs[0]; break;
     783                 :         14 :     case ProofRule::RE_INTER: pf << h << h << h << cs[0] << cs[1]; break;
     784                 :        764 :     case ProofRule::CONCAT_EQ:
     785                 :       1528 :       pf << h << h << h << args[0].getConst<bool>()
     786                 :        764 :          << d_tproc.convertType(children[0]->getResult()[0].getType()) << cs[0];
     787                 :        764 :       break;
     788                 :        664 :     case ProofRule::CONCAT_UNIFY:
     789                 :       1328 :       pf << h << h << h << h << args[0].getConst<bool>()
     790                 :       1328 :          << d_tproc.convertType(children[0]->getResult()[0].getType()) << cs[0]
     791                 :        664 :          << cs[1];
     792                 :        664 :       break;
     793                 :        300 :     case ProofRule::CONCAT_CSPLIT:
     794                 :        600 :       pf << h << h << h << h << args[0].getConst<bool>()
     795                 :        600 :          << d_tproc.convertType(children[0]->getResult()[0].getType()) << cs[0]
     796                 :        300 :          << cs[1];
     797                 :        300 :       break;
     798                 :        864 :     case ProofRule::RE_UNFOLD_POS:
     799         [ +  + ]:        864 :       if (children[0]->getResult()[1].getKind() != Kind::REGEXP_CONCAT)
     800                 :            :       {
     801                 :         48 :         return false;
     802                 :            :       }
     803                 :        816 :       pf << h << h << h << cs[0];
     804                 :        816 :       break;
     805                 :        808 :     case ProofRule::STRING_EAGER_REDUCTION:
     806                 :            :     {
     807                 :        808 :       Kind k = as[0].getKind();
     808 [ +  + ][ +  + ]:        808 :       if (k == Kind::STRING_TO_CODE || k == Kind::STRING_CONTAINS
     809         [ +  + ]:        150 :           || k == Kind::STRING_INDEXOF)
     810                 :            :       {
     811                 :        768 :         pf << h << as[0] << as[0][0].getType();
     812                 :            :       }
     813                 :            :       else
     814                 :            :       {
     815                 :            :         // not yet defined for other kinds
     816                 :         40 :         return false;
     817                 :            :       }
     818                 :            :     }
     819                 :        768 :     break;
     820                 :       6820 :     case ProofRule::STRING_REDUCTION:
     821                 :            :     {
     822                 :       6820 :       Kind k = as[0].getKind();
     823 [ +  + ][ +  + ]:       6820 :       if (k == Kind::STRING_SUBSTR || k == Kind::STRING_INDEXOF)
     824                 :            :       {
     825                 :       4218 :         pf << h << as[0] << d_tproc.convertType(as[0][0].getType());
     826                 :            :       }
     827                 :            :       else
     828                 :            :       {
     829                 :            :         // not yet defined for other kinds
     830                 :       2602 :         return false;
     831                 :            :       }
     832                 :            :     }
     833                 :       4218 :     break;
     834                 :            :     // quantifiers
     835                 :      68906 :     case ProofRule::SKOLEM_INTRO:
     836                 :            :     {
     837                 :      68906 :       pf << d_tproc.convert(SkolemManager::getUnpurifiedForm(args[0]));
     838                 :            :     }
     839                 :      68906 :     break;
     840                 :            :     // ---------- arguments of non-translated rules go here
     841                 :    7683180 :     case ProofRule::LFSC_RULE:
     842                 :            :     {
     843                 :    7683180 :       LfscRule lr = getLfscRule(args[0]);
     844                 :            :       // lambda should be processed elsewhere
     845                 :    7683180 :       Assert(lr != LfscRule::LAMBDA);
     846                 :            :       // Note that `args` has 2 builtin arguments, thus the first real argument
     847                 :            :       // begins at index 2
     848                 :            :       switch (lr)
     849                 :            :       {
     850                 :       4798 :         case LfscRule::DEFINITION: pf << as[1][0]; break;
     851                 :     410012 :         case LfscRule::SCOPE: pf << h << as[2] << cs[0]; break;
     852                 :        684 :         case LfscRule::NEG_SYMM: pf << h << h << cs[0]; break;
     853                 :    6913330 :         case LfscRule::CONG: pf << h << h << h << h << cs[0] << cs[1]; break;
     854                 :      67524 :         case LfscRule::AND_INTRO1: pf << h << cs[0]; break;
     855                 :      17402 :         case LfscRule::NOT_AND_REV: pf << h << h << cs[0]; break;
     856                 :      70056 :         case LfscRule::PROCESS_SCOPE: pf << h << h << as[2] << cs[0]; break;
     857                 :     135210 :         case LfscRule::AND_INTRO2: pf << h << h << cs[0] << cs[1]; break;
     858                 :      52310 :         case LfscRule::ARITH_SUM_UB: pf << h << h << h << cs[0] << cs[1]; break;
     859                 :      11850 :         case LfscRule::INSTANTIATE:
     860                 :      11850 :           pf << h << h << h << h << as[2] << cs[0];
     861                 :      11850 :           break;
     862                 :          0 :         case LfscRule::BETA_REDUCE: pf << h << as[2]; break;
     863                 :          0 :         default: return false; break;
     864                 :            :       }
     865                 :            :     }
     866                 :    7683180 :     break;
     867                 :          8 :     case ProofRule::DSL_REWRITE:
     868                 :            :     {
     869                 :          8 :       ProofRewriteRule di = ProofRewriteRule::NONE;
     870         [ -  + ]:          8 :       if (!rewriter::getRewriteRule(args[0], di))
     871                 :            :       {
     872                 :          0 :         DebugUnhandled();
     873                 :            :       }
     874         [ +  - ]:          8 :       Trace("lfsc-print-debug2") << "Printing dsl rule " << di << std::endl;
     875                 :          8 :       const rewriter::RewriteProofRule& rpr = d_rdb->getRule(di);
     876                 :          8 :       const std::vector<Node>& varList = rpr.getVarList();
     877 [ -  + ][ -  + ]:          8 :       Assert(as.size() == varList.size() + 1);
                 [ -  - ]
     878                 :            :       // print holes/terms based on whether variables are explicit
     879         [ +  + ]:         20 :       for (size_t i = 1, nargs = as.size(); i < nargs; i++)
     880                 :            :       {
     881                 :         24 :         Node v = varList[i - 1];
     882         [ +  - ]:         12 :         if (rpr.isExplicitVar(v))
     883                 :            :         {
     884                 :            :           // If the variable is a list variable, we must convert its value to
     885                 :            :           // the proper term. This is based on its context.
     886         [ -  + ]:         12 :           if (as[i].getKind() == Kind::SEXPR)
     887                 :            :           {
     888                 :          0 :             Assert(args[i].getKind() == Kind::SEXPR);
     889                 :          0 :             NodeManager* nm = nodeManager();
     890                 :          0 :             Kind k = rpr.getListContext(v);
     891                 :            :             // notice we use d_tproc.getNullTerminator and not
     892                 :            :             // expr::getNullTerminator here, which has subtle differences
     893                 :            :             // e.g. re.empty vs (str.to_re "").
     894                 :          0 :             Node null = d_tproc.getNullTerminator(nm, k, v.getType());
     895                 :          0 :             Node t;
     896         [ -  - ]:          0 :             if (as[i].getNumChildren() == 1)
     897                 :            :             {
     898                 :            :               // Singleton list uses null terminator. We first construct an
     899                 :            :               // original term and convert it.
     900                 :          0 :               Node tt = nm->mkNode(k, args[i][0], null);
     901                 :          0 :               tt = d_tproc.convert(tt);
     902                 :            :               // Since conversion adds a null terminator, we have that
     903                 :            :               // tt is of the form (f t (f null null)). We reconstruct
     904                 :            :               // the proper term (f t null) below.
     905                 :          0 :               Assert(tt.getNumChildren() == 2);
     906                 :          0 :               Assert(tt[1].getNumChildren() == 2);
     907                 :          0 :               std::vector<Node> tchildren;
     908         [ -  - ]:          0 :               if (tt.getMetaKind() == metakind::PARAMETERIZED)
     909                 :            :               {
     910                 :          0 :                 tchildren.push_back(tt.getOperator());
     911                 :            :               }
     912                 :          0 :               tchildren.push_back(tt[0]);
     913                 :          0 :               tchildren.push_back(tt[1][0]);
     914                 :          0 :               t = nm->mkNode(tt.getKind(), tchildren);
     915                 :            :             }
     916                 :            :             else
     917                 :            :             {
     918         [ -  - ]:          0 :               if (k == Kind::UNDEFINED_KIND)
     919                 :            :               {
     920                 :          0 :                 Unhandled() << "Unknown context for list variable " << v
     921                 :          0 :                             << " in rule " << di;
     922                 :            :               }
     923         [ -  - ]:          0 :               if (as[i].getNumChildren() == 0)
     924                 :            :               {
     925                 :          0 :                 t = null;
     926                 :            :               }
     927                 :            :               else
     928                 :            :               {
     929                 :            :                 // re-convert it
     930                 :          0 :                 std::vector<Node> vec(args[i].begin(), args[i].end());
     931                 :          0 :                 t = nm->mkNode(k, vec);
     932                 :            :               }
     933                 :          0 :               t = d_tproc.convert(t);
     934                 :            :             }
     935                 :          0 :             pf << t;
     936                 :            :           }
     937                 :            :           else
     938                 :            :           {
     939                 :         12 :             pf << as[i];
     940                 :            :           }
     941                 :            :         }
     942                 :            :         else
     943                 :            :         {
     944                 :          0 :           pf << h;
     945                 :            :         }
     946                 :            :       }
     947                 :            :       // print child proofs, which is based on the format computed for the rule
     948                 :          8 :       size_t ccounter = 0;
     949                 :            :       std::map<ProofRewriteRule, std::vector<Node>>::iterator itf =
     950                 :          8 :           d_dslFormat.find(di);
     951         [ +  + ]:          8 :       if (itf == d_dslFormat.end())
     952                 :            :       {
     953                 :            :         // We may not have computed the format yet, e.g. if we are printing
     954                 :            :         // via the pre print channel. In this case, just print all the children.
     955         [ -  + ]:          4 :         for (const ProofNode* c : cs)
     956                 :            :         {
     957                 :          0 :           pf << c;
     958                 :            :         }
     959                 :            :       }
     960                 :            :       else
     961                 :            :       {
     962         [ -  + ]:          4 :         for (const Node& f : itf->second)
     963                 :            :         {
     964         [ -  - ]:          0 :           if (f.isNull())
     965                 :            :           {
     966                 :            :             // this position is a hole
     967                 :          0 :             pf << h;
     968                 :          0 :             continue;
     969                 :            :           }
     970                 :          0 :           Assert(ccounter < cs.size());
     971                 :          0 :           pf << cs[ccounter];
     972                 :          0 :           ccounter++;
     973                 :            :         }
     974 [ -  + ][ -  + ]:          4 :         Assert(ccounter == cs.size());
                 [ -  - ]
     975                 :            :       }
     976                 :            :     }
     977                 :          8 :     break;
     978                 :    1165130 :     default:
     979                 :            :     {
     980                 :    1165130 :       return false;
     981                 :            :       break;
     982                 :            :     }
     983                 :            :   }
     984                 :   14422500 :   return true;
     985                 :            : }
     986                 :            : 
     987                 :     411708 : void LfscPrinter::computeProofLetification(
     988                 :            :     const ProofNode* pn,
     989                 :            :     std::vector<const ProofNode*>& pletList,
     990                 :            :     std::map<const ProofNode*, size_t>& pletMap)
     991                 :            : {
     992                 :            :   // use callback to specify to stop at LAMBDA
     993                 :     411708 :   ProofLetify::computeProofLet(pn, pletList, pletMap, 2, &d_lpltc);
     994                 :     411708 : }
     995                 :            : 
     996                 :        559 : void LfscPrinter::print(std::ostream& out, Node n)
     997                 :            : {
     998                 :        559 :   Node ni = d_tproc.convert(n);
     999                 :        559 :   printLetify(out, ni);
    1000                 :        559 : }
    1001                 :            : 
    1002                 :        559 : void LfscPrinter::printLetify(std::ostream& out, Node n)
    1003                 :            : {
    1004                 :            :   // closing parentheses
    1005                 :       1118 :   std::stringstream cparen;
    1006                 :            : 
    1007                 :        559 :   LetBinding lbind(d_termLetPrefix);
    1008                 :        559 :   lbind.process(n);
    1009                 :            : 
    1010                 :            :   // [1] print the letification
    1011                 :        559 :   printLetList(out, cparen, lbind);
    1012                 :            : 
    1013                 :            :   // [2] print the body
    1014                 :        559 :   printInternal(out, n, lbind);
    1015                 :            : 
    1016                 :        559 :   out << cparen.str();
    1017                 :        559 : }
    1018                 :            : 
    1019                 :       2255 : void LfscPrinter::printLetList(std::ostream& out,
    1020                 :            :                                std::ostream& cparen,
    1021                 :            :                                LetBinding& lbind,
    1022                 :            :                                bool asDefs)
    1023                 :            : {
    1024                 :       4510 :   std::vector<Node> letList;
    1025                 :       2255 :   lbind.letify(letList);
    1026                 :       2255 :   std::map<Node, size_t>::const_iterator it;
    1027         [ +  + ]:     398387 :   for (size_t i = 0, nlets = letList.size(); i < nlets; i++)
    1028                 :            :   {
    1029                 :     792264 :     Node nl = letList[i];
    1030                 :     396132 :     size_t id = lbind.getId(nl);
    1031 [ -  + ][ -  + ]:     396132 :     Assert(id != 0);
                 [ -  - ]
    1032         [ +  + ]:     396132 :     if (asDefs)
    1033                 :            :     {
    1034                 :         28 :       out << "(define ";
    1035                 :         28 :       LfscPrintChannelOut::printId(out, id, d_termLetPrefix);
    1036                 :         28 :       out << " ";
    1037                 :            :       // do not letify the top term
    1038                 :         28 :       printInternal(out, nl, lbind, false);
    1039                 :         28 :       out << ")" << std::endl;
    1040                 :            :     }
    1041                 :            :     else
    1042                 :            :     {
    1043                 :     396104 :       out << "(@ ";
    1044                 :     396104 :       LfscPrintChannelOut::printId(out, id, d_termLetPrefix);
    1045                 :     396104 :       out << " ";
    1046                 :            :       // do not letify the top term
    1047                 :     396104 :       printInternal(out, nl, lbind, false);
    1048                 :     396104 :       out << std::endl;
    1049                 :     396104 :       cparen << ")";
    1050                 :            :     }
    1051                 :            :   }
    1052                 :       2255 : }
    1053                 :            : 
    1054                 :          0 : void LfscPrinter::printInternal(std::ostream& out, Node n)
    1055                 :            : {
    1056                 :          0 :   LetBinding lbind(d_termLetPrefix);
    1057                 :          0 :   printInternal(out, n, lbind);
    1058                 :          0 : }
    1059                 :     412663 : void LfscPrinter::printInternal(std::ostream& out,
    1060                 :            :                                 Node n,
    1061                 :            :                                 LetBinding& lbind,
    1062                 :            :                                 bool letTop)
    1063                 :            : {
    1064                 :     412663 :   Node nc = lbind.convert(n, letTop);
    1065                 :     412663 :   LfscPrintChannelOut::printNodeInternal(out, nc);
    1066                 :     412663 : }
    1067                 :            : 
    1068                 :      17158 : void LfscPrinter::printType(std::ostream& out, TypeNode tn)
    1069                 :            : {
    1070                 :      17158 :   TypeNode tni = d_tproc.convertType(tn);
    1071                 :      17158 :   LfscPrintChannelOut::printTypeNodeInternal(out, tni);
    1072                 :      17158 : }
    1073                 :            : 
    1074                 :          2 : void LfscPrinter::printDslRule(std::ostream& out,
    1075                 :            :                                ProofRewriteRule id,
    1076                 :            :                                std::vector<Node>& format)
    1077                 :            : {
    1078                 :          2 :   const rewriter::RewriteProofRule& rpr = d_rdb->getRule(id);
    1079                 :          2 :   const std::vector<Node>& varList = rpr.getVarList();
    1080                 :          2 :   const std::vector<Node>& uvarList = rpr.getUserVarList();
    1081                 :          2 :   const std::vector<Node>& conds = rpr.getConditions();
    1082                 :          4 :   Node conc = rpr.getConclusion();
    1083                 :            : 
    1084                 :          4 :   std::stringstream oscs;
    1085                 :          4 :   std::stringstream odecl;
    1086                 :            : 
    1087                 :          4 :   std::stringstream rparen;
    1088                 :          2 :   odecl << "(declare ";
    1089                 :          2 :   LfscPrintChannelOut::printProofRewriteRule(odecl, id);
    1090                 :          4 :   std::vector<Node> vlsubs;
    1091                 :            :   // streams for printing the computation of term in side conditions or
    1092                 :            :   // list semantics substitutions
    1093                 :          4 :   std::stringstream argList;
    1094                 :          4 :   std::stringstream argListTerms;
    1095                 :            :   // the list variables
    1096                 :          2 :   std::unordered_set<Node> listVars;
    1097                 :          2 :   argList << "(";
    1098                 :            :   // use the names from the user variable list (uvarList)
    1099         [ +  + ]:          5 :   for (const Node& v : uvarList)
    1100                 :            :   {
    1101                 :          6 :     std::stringstream sss;
    1102                 :          3 :     sss << v;
    1103                 :          9 :     Node s = d_tproc.mkInternalSymbol(sss.str(), v.getType());
    1104                 :          3 :     odecl << " (! " << sss.str() << " term";
    1105                 :          3 :     argList << "(" << sss.str() << " term)";
    1106                 :          3 :     argListTerms << " " << sss.str();
    1107                 :          3 :     rparen << ")";
    1108                 :          3 :     vlsubs.push_back(s);
    1109                 :            :     // remember if v was a list variable, we must convert these in side
    1110                 :            :     // condition printing below
    1111         [ -  + ]:          3 :     if (expr::isListVar(v))
    1112                 :            :     {
    1113                 :          0 :       listVars.insert(s);
    1114                 :            :     }
    1115                 :            :   }
    1116                 :          2 :   argList << ")";
    1117                 :            :   // print conditions
    1118                 :          2 :   size_t termCount = 0;
    1119                 :          2 :   size_t scCount = 0;
    1120                 :            :   // print conditions, then conclusion
    1121         [ +  + ]:          4 :   for (size_t i = 0, nconds = conds.size(); i <= nconds; i++)
    1122                 :            :   {
    1123                 :          2 :     bool isConclusion = i == nconds;
    1124         [ +  - ]:          2 :     Node term = isConclusion ? conc : conds[i];
    1125                 :            :     Node sterm = term.substitute(
    1126                 :          2 :         varList.begin(), varList.end(), vlsubs.begin(), vlsubs.end());
    1127         [ -  + ]:          2 :     if (expr::hasListVar(term))
    1128                 :            :     {
    1129                 :          0 :       Assert(!listVars.empty());
    1130                 :          0 :       scCount++;
    1131                 :          0 :       std::stringstream scName;
    1132                 :          0 :       scName << "dsl.sc." << scCount << "." << id;
    1133                 :            :       // generate the side condition
    1134                 :          0 :       oscs << "(function " << scName.str() << " " << argList.str() << " term"
    1135                 :          0 :            << std::endl;
    1136                 :            :       // body must be converted to incorporate list semantics for substitutions
    1137                 :            :       // first traversal applies nary_elim to required n-ary applications
    1138                 :          0 :       LfscListScNodeConverter llsncp(nodeManager(), d_tproc, listVars, true);
    1139                 :          0 :       Node tscp;
    1140         [ -  - ]:          0 :       if (isConclusion)
    1141                 :            :       {
    1142                 :          0 :         Assert(sterm.getKind() == Kind::EQUAL);
    1143                 :            :         // optimization: don't need nary_elim for heads
    1144                 :          0 :         tscp = llsncp.convert(sterm[1]);
    1145                 :          0 :         tscp = sterm[0].eqNode(tscp);
    1146                 :            :       }
    1147                 :            :       else
    1148                 :            :       {
    1149                 :          0 :         tscp = llsncp.convert(sterm);
    1150                 :            :       }
    1151                 :            :       // second traversal converts to LFSC form
    1152                 :          0 :       Node t = d_tproc.convert(tscp);
    1153                 :            :       // third traversal applies nary_concat where list variables are used
    1154                 :          0 :       LfscListScNodeConverter llsnc(nodeManager(), d_tproc, listVars, false);
    1155                 :          0 :       Node tsc = llsnc.convert(t);
    1156                 :          0 :       oscs << "  ";
    1157                 :          0 :       print(oscs, tsc);
    1158                 :          0 :       oscs << ")" << std::endl;
    1159                 :          0 :       termCount++;
    1160                 :            :       // introduce a term computed by side condition
    1161                 :          0 :       odecl << " (! _t" << termCount << " term";
    1162                 :          0 :       rparen << ")";
    1163                 :          0 :       format.push_back(Node::null());
    1164                 :            :       // side condition, which is an implicit argument
    1165                 :          0 :       odecl << " (! _s" << scCount << " (^ (" << scName.str();
    1166                 :          0 :       rparen << ")";
    1167                 :            :       // arguments to side condition
    1168                 :          0 :       odecl << argListTerms.str() << ") ";
    1169                 :            :       // matches condition
    1170                 :          0 :       odecl << "_t" << termCount << ")";
    1171         [ -  - ]:          0 :       if (!isConclusion)
    1172                 :            :       {
    1173                 :            :         // the child proof
    1174                 :          0 :         odecl << " (! _u" << i;
    1175                 :          0 :         rparen << ")";
    1176                 :          0 :         format.push_back(term);
    1177                 :            :       }
    1178                 :          0 :       odecl << " (holds _t" << termCount << ")";
    1179                 :          0 :       continue;
    1180                 :            :     }
    1181                 :            :     // ordinary condition/conclusion, print the term directly
    1182         [ -  + ]:          2 :     if (!isConclusion)
    1183                 :            :     {
    1184                 :          0 :       odecl << " (! _u" << i;
    1185                 :          0 :       rparen << ")";
    1186                 :          0 :       format.push_back(term);
    1187                 :            :     }
    1188                 :          2 :     odecl << " (holds ";
    1189                 :          4 :     Node t = d_tproc.convert(sterm);
    1190                 :          2 :     print(odecl, t);
    1191                 :          2 :     odecl << ")";
    1192                 :            :   }
    1193                 :          2 :   odecl << rparen.str() << ")" << std::endl;
    1194                 :            :   // print the side conditions
    1195                 :          2 :   out << oscs.str();
    1196                 :            :   // print the rule declaration
    1197                 :          2 :   out << odecl.str();
    1198                 :          2 : }
    1199                 :            : 
    1200                 :            : }  // namespace proof
    1201                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14