LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/smt - print_benchmark.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 143 167 85.6 %
Date: 2024-10-06 11:37:27 Functions: 8 9 88.9 %
Branches: 97 132 73.5 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * Top contributors (to current version):
       3                 :            :  *   Andrew Reynolds, Aina Niemetz, Mathias Preiner
       4                 :            :  *
       5                 :            :  * This file is part of the cvc5 project.
       6                 :            :  *
       7                 :            :  * Copyright (c) 2009-2024 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                 :            :  * Print benchmark utility.
      14                 :            :  */
      15                 :            : 
      16                 :            : #include "smt/print_benchmark.h"
      17                 :            : 
      18                 :            : #include "expr/attribute.h"
      19                 :            : #include "expr/dtype.h"
      20                 :            : #include "expr/node_algorithm.h"
      21                 :            : #include "expr/node_converter.h"
      22                 :            : #include "printer/printer.h"
      23                 :            : #include "expr/skolem_manager.h"
      24                 :            : 
      25                 :            : using namespace cvc5::internal::kind;
      26                 :            : 
      27                 :            : namespace cvc5::internal {
      28                 :            : namespace smt {
      29                 :            : 
      30                 :            : /**
      31                 :            :  * Attribute true for symbols that should be excluded from the output of this
      32                 :            :  * utility.
      33                 :            :  */
      34                 :            : struct BenchmarkNoPrintAttributeId
      35                 :            : {
      36                 :            : };
      37                 :            : using BenchmarkNoPrintAttribute =
      38                 :            :     expr::Attribute<BenchmarkNoPrintAttributeId, bool>;
      39                 :            : 
      40                 :       1628 : void PrintBenchmark::printDeclarationsFrom(std::ostream& outDecl,
      41                 :            :                                            std::ostream& outDef,
      42                 :            :                                            const std::vector<Node>& defs,
      43                 :            :                                            const std::vector<Node>& terms)
      44                 :            : {
      45                 :       3256 :   std::unordered_set<TypeNode> unorderedTypes;
      46                 :       3256 :   std::unordered_set<TNode> typeVisited;
      47         [ +  + ]:       2033 :   for (const Node& a : defs)
      48                 :            :   {
      49                 :        405 :     expr::getTypes(a, unorderedTypes, typeVisited);
      50                 :            :   }
      51         [ +  + ]:      17631 :   for (const Node& a : terms)
      52                 :            :   {
      53                 :      16003 :     expr::getTypes(a, unorderedTypes, typeVisited);
      54                 :            :   }
      55                 :       3256 :   std::vector<TypeNode> types{unorderedTypes.begin(), unorderedTypes.end()};
      56         [ +  + ]:       1628 :   if (d_sorted)
      57                 :            :   {
      58                 :            :     // We want to print declarations in a deterministic order, independent of
      59                 :            :     // the implementation of data structures. Hence, we insert into a vector
      60                 :            :     // and reorder. Note that collecting the types in an std::unordered_map,
      61                 :            :     // then inserting them into a vector and sorting the vector is faster than
      62                 :            :     // immediately using an std::set instead.
      63                 :         15 :     std::sort(types.begin(), types.end());
      64                 :            :   }
      65                 :            :   // print the declared types first
      66                 :       3256 :   std::unordered_set<TypeNode> alreadyPrintedDeclSorts;
      67         [ +  + ]:       8114 :   for (const TypeNode& st : types)
      68                 :            :   {
      69                 :            :     // note that we must get all "component types" of a type, so that
      70                 :            :     // e.g. U is printed as a sort declaration when we have type (Array U Int).
      71                 :            :     // get all connected datatypes to this one
      72                 :      12972 :     std::vector<TypeNode> connectedTypes;
      73                 :       6486 :     getConnectedSubfieldTypes(st, connectedTypes, alreadyPrintedDeclSorts);
      74                 :            :     // now, separate into sorts and datatypes
      75                 :      12972 :     std::vector<TypeNode> datatypeBlock;
      76         [ +  + ]:      13028 :     for (const TypeNode& ctn : connectedTypes)
      77                 :            :     {
      78         [ +  + ]:       7819 :       if ((ctn.isUninterpretedSort() && ctn.getNumChildren() == 0)
      79 [ +  + ][ +  + ]:       7819 :           || ctn.isUninterpretedSortConstructor())
                 [ +  + ]
      80                 :            :       {
      81                 :       2554 :         TypeNode ctnp = ctn;
      82         [ +  - ]:       1277 :         if (d_converter != nullptr)
      83                 :            :         {
      84                 :       1277 :           ctnp = d_converter->convertType(ctnp);
      85                 :            :         }
      86                 :       1277 :         d_printer->toStreamCmdDeclareType(outDecl, ctn);
      87                 :       1277 :         outDecl << std::endl;
      88                 :            :       }
      89 [ +  + ][ +  + ]:       5265 :       else if (ctn.isDatatype() && !ctn.isTuple() && !ctn.isNullable())
         [ +  + ][ +  + ]
      90                 :            :       {
      91                 :        236 :         datatypeBlock.push_back(ctn);
      92                 :            :       }
      93                 :            :     }
      94                 :            :     // print the mutually recursive datatype block if necessary
      95         [ +  + ]:       6486 :     if (!datatypeBlock.empty())
      96                 :            :     {
      97                 :        184 :       d_printer->toStreamCmdDatatypeDeclaration(outDecl, datatypeBlock);
      98                 :        184 :       outDecl << std::endl;
      99                 :            :     }
     100                 :            :   }
     101                 :            : 
     102                 :            :   // global visited cache for expr::getSymbols calls
     103                 :       3256 :   std::unordered_set<TNode> visited;
     104                 :            : 
     105                 :            :   // print the definitions
     106                 :       3256 :   std::unordered_map<Node, std::pair<bool, Node>> defMap;
     107                 :       3256 :   std::vector<Node> defSyms;
     108                 :            :   // first, record all the defined symbols
     109         [ +  + ]:       2033 :   for (const Node& a : defs)
     110                 :            :   {
     111                 :        405 :     bool isRec = false;
     112                 :        405 :     Node defSym;
     113                 :        405 :     Node defBody;
     114         [ -  + ]:        405 :     if (!decomposeDefinition(a, isRec, defSym, defBody))
     115                 :            :     {
     116                 :          0 :       continue;
     117                 :            :     }
     118         [ +  - ]:        405 :     if (!defSym.isNull())
     119                 :            :     {
     120 [ -  + ][ -  + ]:        405 :       Assert(defMap.find(defSym) == defMap.end());
                 [ -  - ]
     121                 :        405 :       defMap[defSym] = std::pair<bool, Node>(isRec, defBody);
     122                 :        405 :       defSyms.push_back(defSym);
     123                 :            :     }
     124                 :            :   }
     125                 :            :   // go back and print the definitions
     126                 :       3256 :   std::unordered_set<Node> alreadyPrintedDecl;
     127                 :       3256 :   std::unordered_set<Node> alreadyPrintedDef;
     128                 :            : 
     129                 :       1628 :   std::unordered_map<Node, std::pair<bool, Node>>::const_iterator itd;
     130         [ +  + ]:       2033 :   for (const Node& s : defSyms)
     131                 :            :   {
     132                 :        810 :     std::vector<Node> recDefs;
     133                 :        810 :     std::vector<Node> ordinaryDefs;
     134                 :        810 :     std::unordered_set<Node> unorderedSyms;
     135                 :        405 :     getConnectedDefinitions(s,
     136                 :            :                             recDefs,
     137                 :            :                             ordinaryDefs,
     138                 :            :                             unorderedSyms,
     139                 :            :                             defMap,
     140                 :            :                             alreadyPrintedDef,
     141                 :            :                             visited);
     142                 :        810 :     std::vector<Node> syms{unorderedSyms.begin(), unorderedSyms.end()};
     143         [ +  + ]:        405 :     if (d_sorted)
     144                 :            :     {
     145                 :            :       // We want to print declarations in a deterministic order, independent of
     146                 :            :       // the implementation of data structures. Hence, we insert into a vector
     147                 :            :       // and reorder. Note that collecting `syms` in an std::unordered_map,
     148                 :            :       // then inserting them into a vector and sorting the vector is faster than
     149                 :            :       // immediately using an std::set instead.
     150                 :          6 :       std::sort(syms.begin(), syms.end());
     151                 :            :     }
     152                 :            :     // print the declarations that are encountered for the first time in this
     153                 :            :     // block
     154                 :        405 :     printDeclaredFuns(outDecl, syms, alreadyPrintedDecl);
     155         [ +  + ]:        405 :     if (d_sorted)
     156                 :            :     {
     157                 :            :       // Sort recursive definitions for deterministic order.
     158                 :          6 :       std::sort(recDefs.begin(), recDefs.end());
     159                 :            :       // In general, we cannot sort the ordinary definitions since they were
     160                 :            :       // added to the vector in an order which ensures the functions they
     161                 :            :       // depend on are defined first.
     162                 :            :     }
     163                 :            :     // print the ordinary definitions
     164         [ +  + ]:        810 :     for (const Node& f : ordinaryDefs)
     165                 :            :     {
     166                 :        405 :       itd = defMap.find(f);
     167 [ -  + ][ -  + ]:        405 :       Assert(itd != defMap.end());
                 [ -  - ]
     168 [ -  + ][ -  + ]:        405 :       Assert(!itd->second.first);
                 [ -  - ]
     169                 :        810 :       Node def = itd->second.second;
     170         [ +  + ]:        405 :       if (d_converter != nullptr)
     171                 :            :       {
     172                 :        399 :         def = d_converter->convert(def);
     173                 :            :       }
     174                 :        405 :       d_printer->toStreamCmdDefineFunction(outDef, f, def);
     175                 :        405 :       outDef << std::endl;
     176                 :            :       // a definition is also a declaration
     177                 :        405 :       alreadyPrintedDecl.insert(f);
     178                 :            :     }
     179                 :            :     // print a recursive function definition block
     180         [ -  + ]:        405 :     if (!recDefs.empty())
     181                 :            :     {
     182                 :          0 :       std::vector<Node> lambdas;
     183         [ -  - ]:          0 :       for (const Node& f : recDefs)
     184                 :            :       {
     185                 :          0 :         Node lam = defMap[f].second;
     186         [ -  - ]:          0 :         if (d_converter != nullptr)
     187                 :            :         {
     188                 :          0 :           lam = d_converter->convert(lam);
     189                 :            :         }
     190                 :          0 :         lambdas.push_back(lam);
     191                 :            :         // a recursive definition is also a declaration
     192                 :          0 :         alreadyPrintedDecl.insert(f);
     193                 :            :       }
     194                 :          0 :       d_printer->toStreamCmdDefineFunctionRec(outDef, recDefs, lambdas);
     195                 :          0 :       outDef << std::endl;
     196                 :            :     }
     197                 :            :   }
     198                 :            : 
     199                 :            :   // print the remaining declared symbols
     200                 :       3256 :   std::unordered_set<Node> unorderedSyms;
     201         [ +  + ]:      17631 :   for (const Node& a : terms)
     202                 :            :   {
     203                 :      16003 :     expr::getSymbols(a, unorderedSyms, visited);
     204                 :            :   }
     205                 :       3256 :   std::vector<Node> syms{unorderedSyms.begin(), unorderedSyms.end()};
     206         [ +  + ]:       1628 :   if (d_sorted)
     207                 :            :   {
     208                 :            :     // We want to print declarations in a deterministic order, independent of
     209                 :            :     // the implementation of data structures. Hence, we insert into a vector
     210                 :            :     // and reorder. Note that collecting `syms` in an std::unordered_map,
     211                 :            :     // then inserting them into a vector and sorting the vector is faster than
     212                 :            :     // immediately using an std::set instead.
     213                 :         15 :     std::sort(syms.begin(), syms.end());
     214                 :            :   }
     215                 :       1628 :   printDeclaredFuns(outDecl, syms, alreadyPrintedDecl);
     216                 :       1628 : }
     217                 :            : 
     218                 :         15 : void PrintBenchmark::printAssertions(std::ostream& out,
     219                 :            :                                      const std::vector<Node>& defs,
     220                 :            :                                      const std::vector<Node>& assertions)
     221                 :            : {
     222                 :         15 :   printDeclarationsFrom(out, out, defs, assertions);
     223                 :            :   // print the assertions
     224         [ +  + ]:         38 :   for (const Node& a : assertions)
     225                 :            :   {
     226                 :         46 :     Node ap = a;
     227         [ -  + ]:         23 :     if (d_converter != nullptr)
     228                 :            :     {
     229                 :          0 :       ap = d_converter->convert(ap);
     230                 :            :     }
     231                 :         23 :     d_printer->toStreamCmdAssert(out, ap);
     232                 :         23 :     out << std::endl;
     233                 :            :   }
     234                 :         15 : }
     235                 :            : 
     236                 :          0 : void PrintBenchmark::printAssertions(std::ostream& out,
     237                 :            :                                      const std::vector<Node>& assertions)
     238                 :            : {
     239                 :          0 :   std::vector<Node> defs;
     240                 :          0 :   printAssertions(out, defs, assertions);
     241                 :          0 : }
     242                 :            : 
     243                 :       2033 : void PrintBenchmark::printDeclaredFuns(std::ostream& out,
     244                 :            :                                        const std::vector<Node>& funs,
     245                 :            :                                        std::unordered_set<Node>& alreadyPrinted)
     246                 :            : {
     247                 :       2033 :   bool printSkolemDefs = options::ioutils::getPrintSkolemDefinitions(out);
     248                 :       2033 :   SkolemManager* sm = d_nm->getSkolemManager();
     249                 :            :   BenchmarkNoPrintAttribute bnpa;
     250         [ +  + ]:      18274 :   for (const Node& f : funs)
     251                 :            :   {
     252 [ -  + ][ -  + ]:      16241 :     Assert(f.isVar());
                 [ -  - ]
     253                 :            :     // do not print selectors, constructors
     254         [ +  + ]:      16241 :     if (!f.getType().isFirstClass())
     255                 :            :     {
     256                 :        541 :       continue;
     257                 :            :     }
     258                 :            :     // don't print symbols that have been marked
     259         [ +  + ]:      15700 :     if (f.getAttribute(bnpa))
     260                 :            :     {
     261                 :         12 :       continue;
     262                 :            :     }
     263                 :            :     // if print skolem definitions is true, we shouldn't print declarations for
     264                 :            :     // (exported) skolems, as they are printed as parsable terms.
     265 [ +  + ][ +  + ]:      15688 :     if (printSkolemDefs && f.getKind() == Kind::SKOLEM)
                 [ +  + ]
     266                 :            :     {
     267         [ +  - ]:          1 :       if (sm->getId(f)!= SkolemId::INTERNAL)
     268                 :            :       {
     269                 :          1 :         continue;
     270                 :            :       }
     271                 :            :     }
     272         [ +  + ]:      15687 :     if (alreadyPrinted.find(f) == alreadyPrinted.end())
     273                 :            :     {
     274                 :      15596 :       d_printer->toStreamCmdDeclareFunction(out, f);
     275                 :      15596 :       out << std::endl;
     276                 :            :     }
     277                 :            :   }
     278                 :       2033 :   alreadyPrinted.insert(funs.begin(), funs.end());
     279                 :       2033 : }
     280                 :            : 
     281                 :       8821 : void PrintBenchmark::getConnectedSubfieldTypes(
     282                 :            :     TypeNode tn,
     283                 :            :     std::vector<TypeNode>& connectedTypes,
     284                 :            :     std::unordered_set<TypeNode>& processed)
     285                 :            : {
     286         [ +  + ]:       8821 :   if (processed.find(tn) != processed.end())
     287                 :            :   {
     288                 :       2272 :     return;
     289                 :            :   }
     290                 :       6549 :   processed.insert(tn);
     291         [ +  + ]:       6549 :   if (tn.isParametricDatatype())
     292                 :            :   {
     293                 :          7 :     const DType& dt = tn.getDType();
     294                 :            :     // ignore its parameters
     295         [ +  + ]:         16 :     for (size_t i = 0, nparams = dt.getNumParameters(); i < nparams; i++)
     296                 :            :     {
     297                 :          9 :       processed.insert(dt.getParameter(i));
     298                 :            :     }
     299                 :            :     // we do not process the datatype here, instead we will traverse to the
     300                 :            :     // head of the parameteric datatype (tn[0]), which will subsequently
     301                 :            :     // process its subfield types.
     302                 :            :   }
     303                 :            :   else
     304                 :            :   {
     305                 :       6542 :     connectedTypes.push_back(tn);
     306         [ +  + ]:       6542 :     if (tn.isDatatype())
     307                 :            :     {
     308                 :            :       std::unordered_set<TypeNode> subfieldTypes =
     309                 :        656 :           tn.getDType().getSubfieldTypes();
     310         [ +  + ]:        742 :       for (const TypeNode& ctn : subfieldTypes)
     311                 :            :       {
     312                 :        414 :         getConnectedSubfieldTypes(ctn, connectedTypes, processed);
     313                 :            :       }
     314                 :            :     }
     315                 :            :   }
     316         [ +  + ]:       8470 :   for (unsigned i = 0, nchild = tn.getNumChildren(); i < nchild; i++)
     317                 :            :   {
     318                 :       1921 :     getConnectedSubfieldTypes(tn[i], connectedTypes, processed);
     319                 :            :   }
     320                 :            : }
     321                 :            : 
     322                 :        792 : void PrintBenchmark::getConnectedDefinitions(
     323                 :            :     Node n,
     324                 :            :     std::vector<Node>& recDefs,
     325                 :            :     std::vector<Node>& ordinaryDefs,
     326                 :            :     std::unordered_set<Node>& syms,
     327                 :            :     const std::unordered_map<Node, std::pair<bool, Node>>& defMap,
     328                 :            :     std::unordered_set<Node>& processedDefs,
     329                 :            :     std::unordered_set<TNode>& visited)
     330                 :            : {
     331                 :            :   // does it have a definition?
     332                 :            :   std::unordered_map<Node, std::pair<bool, Node>>::const_iterator it =
     333                 :        792 :       defMap.find(n);
     334         [ +  + ]:        792 :   if (it == defMap.end())
     335                 :            :   {
     336                 :            :     // an ordinary declared symbol
     337                 :        238 :     syms.insert(n);
     338                 :        387 :     return;
     339                 :            :   }
     340         [ +  + ]:        554 :   if (processedDefs.find(n) != processedDefs.end())
     341                 :            :   {
     342                 :        149 :     return;
     343                 :            :   }
     344                 :        405 :   processedDefs.insert(n);
     345                 :            :   // get the symbols in the body
     346                 :        810 :   std::unordered_set<Node> symsBody;
     347                 :        405 :   expr::getSymbols(it->second.second, symsBody, visited);
     348         [ +  + ]:        792 :   for (const Node& s : symsBody)
     349                 :            :   {
     350                 :        387 :     getConnectedDefinitions(
     351                 :            :         s, recDefs, ordinaryDefs, syms, defMap, processedDefs, visited);
     352                 :            :   }
     353                 :            :   // add the symbol after we add the definitions
     354         [ +  - ]:        405 :   if (!it->second.first)
     355                 :            :   {
     356                 :            :     // an ordinary define-fun symbol
     357                 :        405 :     ordinaryDefs.push_back(n);
     358                 :            :   }
     359                 :            :   else
     360                 :            :   {
     361                 :            :     // a recursively defined symbol
     362                 :          0 :     recDefs.push_back(n);
     363                 :            :   }
     364                 :            : }
     365                 :            : 
     366                 :        405 : bool PrintBenchmark::decomposeDefinition(Node a,
     367                 :            :                                          bool& isRecDef,
     368                 :            :                                          Node& sym,
     369                 :            :                                          Node& body)
     370                 :            : {
     371 [ +  - ][ +  - ]:        405 :   if (a.getKind() == Kind::EQUAL && a[0].isVar())
         [ +  - ][ +  - ]
                 [ -  - ]
     372                 :            :   {
     373                 :            :     // an ordinary define-fun
     374                 :        405 :     isRecDef = false;
     375                 :        405 :     sym = a[0];
     376                 :        405 :     body = a[1];
     377                 :        405 :     return true;
     378                 :            :   }
     379                 :          0 :   else if (a.getKind() == Kind::FORALL && a[1].getKind() == Kind::EQUAL
     380                 :          0 :            && a[1][0].getKind() == Kind::APPLY_UF)
     381                 :            :   {
     382                 :          0 :     isRecDef = true;
     383                 :          0 :     sym = a[1][0].getOperator();
     384                 :          0 :     body = NodeManager::currentNM()->mkNode(Kind::LAMBDA, a[0], a[1][1]);
     385                 :          0 :     return true;
     386                 :            :   }
     387                 :            :   else
     388                 :            :   {
     389         [ -  - ]:          0 :     Warning() << "Unhandled definition: " << a << std::endl;
     390                 :            :   }
     391                 :          0 :   return false;
     392                 :            : }
     393                 :            : 
     394                 :         15 : void PrintBenchmark::printBenchmark(std::ostream& out,
     395                 :            :                                     const std::string& logic,
     396                 :            :                                     const std::vector<Node>& defs,
     397                 :            :                                     const std::vector<Node>& assertions)
     398                 :            : {
     399                 :         15 :   d_printer->toStreamCmdSetBenchmarkLogic(out, logic);
     400                 :         15 :   out << std::endl;
     401                 :         15 :   printAssertions(out, defs, assertions);
     402                 :         15 :   d_printer->toStreamCmdCheckSat(out);
     403                 :         15 :   out << std::endl;
     404                 :         15 : }
     405                 :            : 
     406                 :       2575 : void PrintBenchmark::markNoPrint(Node& sym)
     407                 :            : {
     408                 :            :   BenchmarkNoPrintAttribute bnpa;
     409                 :       2575 :   sym.setAttribute(bnpa, true);
     410                 :       2575 : }
     411                 :            : 
     412                 :            : }  // namespace smt
     413                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14