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: 565 653 86.5 %
Date: 2026-03-11 10:41:32 Functions: 15 16 93.8 %
Branches: 231 328 70.4 %

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

Generated by: LCOV version 1.14