LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory/quantifiers - single_inv_partition.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 300 337 89.0 %
Date: 2026-05-08 10:22:53 Functions: 15 18 83.3 %
Branches: 202 308 65.6 %

           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                 :            :  * Utility for processing single invocation synthesis conjectures.
      11                 :            :  */
      12                 :            : #include "theory/quantifiers/single_inv_partition.h"
      13                 :            : 
      14                 :            : #include <sstream>
      15                 :            : 
      16                 :            : #include "expr/node_algorithm.h"
      17                 :            : #include "expr/skolem_manager.h"
      18                 :            : #include "theory/quantifiers/term_util.h"
      19                 :            : 
      20                 :            : using namespace cvc5::internal;
      21                 :            : using namespace cvc5::internal::kind;
      22                 :            : using namespace std;
      23                 :            : 
      24                 :            : namespace cvc5::internal {
      25                 :            : namespace theory {
      26                 :            : namespace quantifiers {
      27                 :            : 
      28                 :       6329 : SingleInvocationPartition::SingleInvocationPartition(Env& env)
      29         [ +  + ]:      31645 :     : EnvObj(env), d_has_input_funcs(false)
      30                 :            : {
      31                 :       6329 : }
      32                 :            : 
      33                 :          0 : bool SingleInvocationPartition::init(Node n)
      34                 :            : {
      35                 :            :   // first, get types of arguments for functions
      36                 :          0 :   std::vector<TypeNode> typs;
      37                 :          0 :   std::map<Node, bool> visited;
      38                 :          0 :   std::vector<Node> funcs;
      39         [ -  - ]:          0 :   if (inferArgTypes(n, typs, visited))
      40                 :            :   {
      41                 :          0 :     return init(funcs, typs, n, false);
      42                 :            :   }
      43                 :            :   else
      44                 :            :   {
      45         [ -  - ]:          0 :     Trace("si-prt") << "Could not infer argument types." << std::endl;
      46                 :          0 :     return false;
      47                 :            :   }
      48                 :          0 : }
      49                 :            : 
      50                 :        126 : Node SingleInvocationPartition::getFirstOrderVariableForFunction(Node f) const
      51                 :            : {
      52                 :        126 :   std::map<Node, Node>::const_iterator it = d_func_fo_var.find(f);
      53         [ +  - ]:        126 :   if (it != d_func_fo_var.end())
      54                 :            :   {
      55                 :        126 :     return it->second;
      56                 :            :   }
      57                 :          0 :   return Node::null();
      58                 :            : }
      59                 :            : 
      60                 :          0 : Node SingleInvocationPartition::getFunctionForFirstOrderVariable(Node v) const
      61                 :            : {
      62                 :          0 :   std::map<Node, Node>::const_iterator it = d_fo_var_to_func.find(v);
      63         [ -  - ]:          0 :   if (it != d_fo_var_to_func.end())
      64                 :            :   {
      65                 :          0 :     return it->second;
      66                 :            :   }
      67                 :          0 :   return Node::null();
      68                 :            : }
      69                 :            : 
      70                 :        126 : Node SingleInvocationPartition::getFunctionInvocationFor(Node f) const
      71                 :            : {
      72                 :        126 :   std::map<Node, Node>::const_iterator it = d_func_inv.find(f);
      73         [ +  - ]:        126 :   if (it != d_func_inv.end())
      74                 :            :   {
      75                 :        126 :     return it->second;
      76                 :            :   }
      77                 :          0 :   return Node::null();
      78                 :            : }
      79                 :            : 
      80                 :        157 : void SingleInvocationPartition::getFunctionVariables(
      81                 :            :     std::vector<Node>& fvars) const
      82                 :            : {
      83                 :        157 :   fvars.insert(fvars.end(), d_func_vars.begin(), d_func_vars.end());
      84                 :        157 : }
      85                 :            : 
      86                 :        946 : void SingleInvocationPartition::getFunctions(std::vector<Node>& fs) const
      87                 :            : {
      88                 :        946 :   fs.insert(fs.end(), d_all_funcs.begin(), d_all_funcs.end());
      89                 :        946 : }
      90                 :            : 
      91                 :        162 : void SingleInvocationPartition::getSingleInvocationVariables(
      92                 :            :     std::vector<Node>& sivars) const
      93                 :            : {
      94                 :        162 :   sivars.insert(sivars.end(), d_si_vars.begin(), d_si_vars.end());
      95                 :        162 : }
      96                 :            : 
      97                 :          5 : void SingleInvocationPartition::getAllVariables(std::vector<Node>& vars) const
      98                 :            : {
      99                 :          5 :   vars.insert(vars.end(), d_all_vars.begin(), d_all_vars.end());
     100                 :          5 : }
     101                 :            : 
     102                 :            : // gets the argument type list for the first APPLY_UF we see
     103                 :          0 : bool SingleInvocationPartition::inferArgTypes(Node n,
     104                 :            :                                               std::vector<TypeNode>& typs,
     105                 :            :                                               std::map<Node, bool>& visited)
     106                 :            : {
     107         [ -  - ]:          0 :   if (visited.find(n) == visited.end())
     108                 :            :   {
     109                 :          0 :     visited[n] = true;
     110         [ -  - ]:          0 :     if (n.getKind() != Kind::FORALL)
     111                 :            :     {
     112         [ -  - ]:          0 :       if (n.getKind() == Kind::APPLY_UF)
     113                 :            :       {
     114         [ -  - ]:          0 :         for (unsigned i = 0; i < n.getNumChildren(); i++)
     115                 :            :         {
     116                 :          0 :           typs.push_back(n[i].getType());
     117                 :            :         }
     118                 :          0 :         return true;
     119                 :            :       }
     120                 :            :       else
     121                 :            :       {
     122         [ -  - ]:          0 :         for (unsigned i = 0; i < n.getNumChildren(); i++)
     123                 :            :         {
     124         [ -  - ]:          0 :           if (inferArgTypes(n[i], typs, visited))
     125                 :            :           {
     126                 :          0 :             return true;
     127                 :            :           }
     128                 :            :         }
     129                 :            :       }
     130                 :            :     }
     131                 :            :   }
     132                 :          0 :   return false;
     133                 :            : }
     134                 :            : 
     135                 :        977 : bool SingleInvocationPartition::init(std::vector<Node>& funcs, Node n)
     136                 :            : {
     137         [ +  - ]:       1954 :   Trace("si-prt") << "Initialize with " << funcs.size() << " input functions ("
     138                 :        977 :                   << funcs << ")..." << std::endl;
     139                 :        977 :   std::vector<TypeNode> typs;
     140         [ +  - ]:        977 :   if (!funcs.empty())
     141                 :            :   {
     142                 :        977 :     TypeNode tn0 = funcs[0].getType();
     143         [ +  + ]:        977 :     if (tn0.isFunction())
     144                 :            :     {
     145         [ +  + ]:       2138 :       for (unsigned i = 0, nargs = tn0.getNumChildren() - 1; i < nargs; i++)
     146                 :            :       {
     147                 :       1399 :         typs.push_back(tn0[i]);
     148                 :            :       }
     149                 :            :     }
     150         [ +  + ]:       1397 :     for (unsigned i = 1, size = funcs.size(); i < size; i++)
     151                 :            :     {
     152                 :        447 :       TypeNode tni = funcs[i].getType();
     153         [ +  + ]:        447 :       if (tni.getNumChildren() != tn0.getNumChildren())
     154                 :            :       {
     155                 :            :         // can't anti-skolemize functions of different sort
     156         [ +  - ]:         27 :         Trace("si-prt") << "...type mismatch" << std::endl;
     157                 :         27 :         return false;
     158                 :            :       }
     159         [ +  + ]:        420 :       else if (tni.isFunction())
     160                 :            :       {
     161         [ +  + ]:       1414 :         for (unsigned j = 0, nargs = tni.getNumChildren() - 1; j < nargs; j++)
     162                 :            :         {
     163         [ -  + ]:       1050 :           if (tni[j] != typs[j])
     164                 :            :           {
     165         [ -  - ]:          0 :             Trace("si-prt") << "...argument type mismatch" << std::endl;
     166                 :          0 :             return false;
     167                 :            :           }
     168                 :            :         }
     169                 :            :       }
     170         [ +  + ]:        447 :     }
     171         [ +  + ]:        977 :   }
     172         [ +  - ]:        950 :   Trace("si-prt") << "#types = " << typs.size() << std::endl;
     173                 :        950 :   return init(funcs, typs, n, true);
     174                 :        977 : }
     175                 :            : 
     176                 :        950 : bool SingleInvocationPartition::init(std::vector<Node>& funcs,
     177                 :            :                                      std::vector<TypeNode>& typs,
     178                 :            :                                      Node n,
     179                 :            :                                      bool has_funcs)
     180                 :            : {
     181 [ -  + ][ -  + ]:        950 :   Assert(d_arg_types.empty());
                 [ -  - ]
     182 [ -  + ][ -  + ]:        950 :   Assert(d_input_funcs.empty());
                 [ -  - ]
     183 [ -  + ][ -  + ]:        950 :   Assert(d_si_vars.empty());
                 [ -  - ]
     184                 :        950 :   NodeManager* nm = nodeManager();
     185                 :        950 :   d_has_input_funcs = has_funcs;
     186                 :        950 :   d_arg_types.insert(d_arg_types.end(), typs.begin(), typs.end());
     187                 :        950 :   d_input_funcs.insert(d_input_funcs.end(), funcs.begin(), funcs.end());
     188         [ +  - ]:        950 :   Trace("si-prt") << "Initialize..." << std::endl;
     189         [ +  + ]:       2337 :   for (unsigned j = 0; j < d_arg_types.size(); j++)
     190                 :            :   {
     191                 :       1387 :     std::stringstream ss;
     192                 :       1387 :     ss << "s_" << j;
     193                 :       1387 :     Node si_v = NodeManager::mkBoundVar(ss.str(), d_arg_types[j]);
     194                 :       1387 :     d_si_vars.push_back(si_v);
     195                 :       1387 :   }
     196 [ -  + ][ -  + ]:        950 :   Assert(d_si_vars.size() == d_arg_types.size());
                 [ -  - ]
     197         [ +  + ]:       2308 :   for (const Node& inf : d_input_funcs)
     198                 :            :   {
     199                 :       2716 :     Node sk = NodeManager::mkDummySkolem("_sik", inf.getType());
     200                 :       1358 :     d_input_func_sks.push_back(sk);
     201                 :       1358 :   }
     202         [ +  - ]:        950 :   Trace("si-prt") << "SingleInvocationPartition::process " << n << std::endl;
     203         [ +  - ]:        950 :   Trace("si-prt") << "Get conjuncts..." << std::endl;
     204                 :        950 :   std::vector<Node> conj;
     205         [ +  + ]:        950 :   if (collectConjuncts(n, true, conj))
     206                 :            :   {
     207         [ +  - ]:        946 :     Trace("si-prt") << "...success." << std::endl;
     208         [ +  + ]:       3083 :     for (unsigned i = 0; i < conj.size(); i++)
     209                 :            :     {
     210                 :       2137 :       std::vector<Node> si_terms;
     211                 :       2137 :       std::vector<Node> si_subs;
     212         [ +  - ]:       2137 :       Trace("si-prt") << "Process conjunct : " << conj[i] << std::endl;
     213                 :            :       // do DER on conjunct
     214                 :            :       // Must avoid eliminating the first-order input functions in the
     215                 :            :       // getQuantSimplify step below. We use a substitution to avoid this.
     216                 :            :       // This makes it so that e.g. the synthesis conjecture:
     217                 :            :       //   exists f. f!=0 ^ P
     218                 :            :       // is not rewritten to exists f. (f=0 => false) ^ P and subsquently
     219                 :            :       // rewritten to exists f. false ^ P by the elimination f -> 0.
     220                 :       2137 :       Node cr = conj[i].substitute(d_input_funcs.begin(),
     221                 :            :                                    d_input_funcs.end(),
     222                 :            :                                    d_input_func_sks.begin(),
     223                 :       2137 :                                    d_input_func_sks.end());
     224                 :       2137 :       cr = getQuantSimplify(cr);
     225                 :       4274 :       cr = cr.substitute(d_input_func_sks.begin(),
     226                 :            :                          d_input_func_sks.end(),
     227                 :            :                          d_input_funcs.begin(),
     228                 :       2137 :                          d_input_funcs.end());
     229         [ +  + ]:       2137 :       if (cr != conj[i])
     230                 :            :       {
     231         [ +  - ]:        625 :         Trace("si-prt-debug") << "...rewritten to " << cr << std::endl;
     232                 :            :       }
     233                 :       2137 :       std::map<Node, bool> visited;
     234                 :            :       // functions to arguments
     235                 :       2137 :       std::vector<Node> args;
     236                 :       2137 :       Subs sb;
     237                 :       2137 :       bool singleInvocation = true;
     238                 :       2137 :       bool ngroundSingleInvocation = false;
     239         [ +  + ]:       2137 :       if (processConjunct(cr, visited, args, sb))
     240                 :            :       {
     241         [ +  + ]:       4414 :         for (size_t j = 0, vsize = sb.d_vars.size(); j < vsize; j++)
     242                 :            :         {
     243                 :       2372 :           Node s = sb.d_subs[j];
     244                 :       2372 :           si_terms.push_back(s);
     245         [ +  + ]:       2372 :           Node op = s.hasOperator() ? s.getOperator() : s;
     246 [ -  + ][ -  + ]:       2372 :           Assert(d_func_fo_var.find(op) != d_func_fo_var.end());
                 [ -  - ]
     247                 :       2372 :           si_subs.push_back(d_func_fo_var[op]);
     248                 :       2372 :         }
     249                 :       2042 :         std::map<Node, Node> subs_map;
     250                 :       2042 :         std::map<Node, Node> subs_map_rev;
     251                 :            :         // normalize the invocations
     252         [ +  + ]:       2042 :         if (!sb.empty())
     253                 :            :         {
     254                 :       1971 :           cr = sb.apply(cr);
     255                 :            :         }
     256                 :       2042 :         std::vector<Node> children;
     257                 :       2042 :         children.push_back(cr);
     258                 :       2042 :         sb.clear();
     259         [ +  - ]:       4084 :         Trace("si-prt") << "...single invocation, with arguments: "
     260                 :       2042 :                         << std::endl;
     261         [ +  + ]:       5329 :         for (unsigned j = 0; j < args.size(); j++)
     262                 :            :         {
     263         [ +  - ]:       3287 :           Trace("si-prt") << args[j] << " ";
     264                 :       3287 :           if (args[j].getKind() == Kind::BOUND_VARIABLE
     265 [ +  + ][ +  + ]:       6574 :               && !sb.contains(args[j]))
         [ +  + ][ +  + ]
                 [ -  - ]
     266                 :            :           {
     267                 :       1717 :             sb.add(args[j], d_si_vars[j]);
     268                 :            :           }
     269                 :            :           else
     270                 :            :           {
     271                 :       1570 :             children.push_back(d_si_vars[j].eqNode(args[j]).negate());
     272                 :            :           }
     273                 :            :         }
     274         [ +  - ]:       2042 :         Trace("si-prt") << std::endl;
     275                 :       2042 :         cr = nm->mkOr(children);
     276                 :       2042 :         cr = sb.apply(cr);
     277         [ +  - ]:       4084 :         Trace("si-prt-debug")
     278                 :       2042 :             << "...normalized invocations to " << cr << std::endl;
     279                 :            :         // now must check if it has other bound variables
     280                 :       2042 :         std::unordered_set<Node> fvs;
     281                 :       2042 :         expr::getFreeVariables(cr, fvs);
     282                 :            :         // bound variables must be contained in the single invocation variables
     283         [ +  + ]:       8156 :         for (const Node& bv : fvs)
     284                 :            :         {
     285                 :       6114 :           if (std::find(d_si_vars.begin(), d_si_vars.end(), bv)
     286         [ +  + ]:      12228 :               == d_si_vars.end())
     287                 :            :           {
     288                 :            :             // getFreeVariables also collects functions in the rare case that
     289                 :            :             // we are synthesizing a function with 0 arguments, take this into
     290                 :            :             // account here.
     291                 :       2827 :             if (std::find(d_input_funcs.begin(), d_input_funcs.end(), bv)
     292         [ +  + ]:       5654 :                 == d_input_funcs.end())
     293                 :            :             {
     294         [ +  - ]:        910 :               Trace("si-prt")
     295                 :        455 :                   << "...not ground single invocation." << std::endl;
     296                 :        455 :               ngroundSingleInvocation = true;
     297                 :        455 :               singleInvocation = false;
     298                 :            :             }
     299                 :            :           }
     300                 :            :         }
     301         [ +  + ]:       2042 :         if (singleInvocation)
     302                 :            :         {
     303         [ +  - ]:       1616 :           Trace("si-prt") << "...ground single invocation" << std::endl;
     304                 :            :         }
     305                 :       2042 :       }
     306                 :            :       else
     307                 :            :       {
     308         [ +  - ]:         95 :         Trace("si-prt") << "...not single invocation." << std::endl;
     309                 :         95 :         singleInvocation = false;
     310                 :            :         // rename bound variables with maximal overlap with si_vars
     311                 :         95 :         std::unordered_set<Node> fvs;
     312                 :         95 :         expr::getFreeVariables(cr, fvs);
     313                 :         95 :         std::vector<Node> termsNs;
     314                 :         95 :         std::vector<Node> subsNs;
     315         [ +  + ]:        616 :         for (const Node& v : fvs)
     316                 :            :         {
     317                 :        521 :           TypeNode tn = v.getType();
     318         [ +  - ]:       1042 :           Trace("si-prt-debug")
     319                 :        521 :               << "Fit bound var: " << v << " with si." << std::endl;
     320         [ +  + ]:       3533 :           for (unsigned k = 0; k < d_si_vars.size(); k++)
     321                 :            :           {
     322         [ +  + ]:       3303 :             if (tn == d_arg_types[k])
     323                 :            :             {
     324                 :       2066 :               if (std::find(subsNs.begin(), subsNs.end(), d_si_vars[k])
     325         [ +  + ]:       4132 :                   == subsNs.end())
     326                 :            :               {
     327                 :        291 :                 termsNs.push_back(v);
     328                 :        291 :                 subsNs.push_back(d_si_vars[k]);
     329         [ +  - ]:        582 :                 Trace("si-prt-debug")
     330                 :        291 :                     << "  ...use " << d_si_vars[k] << std::endl;
     331                 :        291 :                 break;
     332                 :            :               }
     333                 :            :             }
     334                 :            :           }
     335                 :        521 :         }
     336 [ -  + ][ -  + ]:         95 :         Assert(termsNs.size() == subsNs.size());
                 [ -  - ]
     337                 :        190 :         cr = cr.substitute(
     338                 :         95 :             termsNs.begin(), termsNs.end(), subsNs.begin(), subsNs.end());
     339                 :         95 :       }
     340         [ +  - ]:       4274 :       Trace("si-prt") << ".....got si=" << singleInvocation
     341                 :       2137 :                       << ", result : " << cr << std::endl;
     342                 :       2137 :       d_conjuncts[2].push_back(cr);
     343                 :       2137 :       std::unordered_set<Node> fvs;
     344                 :       2137 :       expr::getFreeVariables(cr, fvs);
     345                 :       2137 :       d_all_vars.insert(fvs.begin(), fvs.end());
     346         [ +  + ]:       2137 :       if (singleInvocation)
     347                 :            :       {
     348                 :            :         // replace with single invocation formulation
     349 [ -  + ][ -  + ]:       1616 :         Assert(si_terms.size() == si_subs.size());
                 [ -  - ]
     350                 :       3232 :         cr = cr.substitute(
     351                 :       1616 :             si_terms.begin(), si_terms.end(), si_subs.begin(), si_subs.end());
     352         [ +  - ]:       1616 :         Trace("si-prt") << ".....si version=" << cr << std::endl;
     353                 :       1616 :         d_conjuncts[0].push_back(cr);
     354                 :            :       }
     355                 :            :       else
     356                 :            :       {
     357                 :        521 :         d_conjuncts[1].push_back(cr);
     358         [ +  + ]:        521 :         if (ngroundSingleInvocation)
     359                 :            :         {
     360                 :        426 :           d_conjuncts[3].push_back(cr);
     361                 :            :         }
     362                 :            :       }
     363                 :       2137 :     }
     364                 :            :   }
     365                 :            :   else
     366                 :            :   {
     367         [ +  - ]:          4 :     Trace("si-prt") << "...failed." << std::endl;
     368                 :          4 :     return false;
     369                 :            :   }
     370                 :        946 :   return true;
     371                 :        950 : }
     372                 :            : 
     373                 :       2714 : bool SingleInvocationPartition::collectConjuncts(Node n,
     374                 :            :                                                  bool pol,
     375                 :            :                                                  std::vector<Node>& conj)
     376                 :            : {
     377 [ +  + ][ +  - ]:       2714 :   if ((!pol && n.getKind() == Kind::OR) || (pol && n.getKind() == Kind::AND))
         [ +  + ][ +  + ]
                 [ +  + ]
     378                 :            :   {
     379         [ +  + ]:       2088 :     for (unsigned i = 0; i < n.getNumChildren(); i++)
     380                 :            :     {
     381         [ +  + ]:       1641 :       if (!collectConjuncts(n[i], pol, conj))
     382                 :            :       {
     383                 :          3 :         return false;
     384                 :            :       }
     385                 :            :     }
     386                 :            :   }
     387         [ +  + ]:       2264 :   else if (n.getKind() == Kind::NOT)
     388                 :            :   {
     389                 :        123 :     return collectConjuncts(n[0], !pol, conj);
     390                 :            :   }
     391         [ +  + ]:       2141 :   else if (n.getKind() == Kind::FORALL)
     392                 :            :   {
     393                 :          4 :     return false;
     394                 :            :   }
     395                 :            :   else
     396                 :            :   {
     397         [ +  + ]:       2137 :     if (!pol)
     398                 :            :     {
     399                 :        120 :       n = TermUtil::simpleNegate(n);
     400                 :            :     }
     401         [ +  - ]:       2137 :     Trace("si-prt") << "Conjunct : " << n << std::endl;
     402                 :       2137 :     conj.push_back(n);
     403                 :            :   }
     404                 :       2584 :   return true;
     405                 :            : }
     406                 :            : 
     407                 :      30873 : bool SingleInvocationPartition::processConjunct(Node n,
     408                 :            :                                                 std::map<Node, bool>& visited,
     409                 :            :                                                 std::vector<Node>& args,
     410                 :            :                                                 Subs& sb)
     411                 :            : {
     412                 :      30873 :   std::map<Node, bool>::iterator it = visited.find(n);
     413         [ +  + ]:      30873 :   if (it != visited.end())
     414                 :            :   {
     415                 :      10345 :     return true;
     416                 :            :   }
     417                 :            :   else
     418                 :            :   {
     419                 :      20528 :     bool ret = true;
     420         [ +  + ]:      49264 :     for (unsigned i = 0; i < n.getNumChildren(); i++)
     421                 :            :     {
     422         [ +  + ]:      28736 :       if (!processConjunct(n[i], visited, args, sb))
     423                 :            :       {
     424                 :        215 :         ret = false;
     425                 :            :       }
     426                 :            :     }
     427         [ +  + ]:      20528 :     if (ret)
     428                 :            :     {
     429                 :      20327 :       Node f;
     430                 :      20327 :       bool success = false;
     431         [ +  - ]:      20327 :       if (d_has_input_funcs)
     432                 :            :       {
     433         [ +  + ]:      20327 :         f = n.hasOperator() ? n.getOperator() : n;
     434                 :      20327 :         if (std::find(d_input_funcs.begin(), d_input_funcs.end(), f)
     435         [ +  + ]:      40654 :             != d_input_funcs.end())
     436                 :            :         {
     437                 :            :           // If n is an application of a function-to-synthesize f, or is
     438                 :            :           // itself a function-to-synthesize, then n must be fully applied.
     439                 :            :           // This catches cases where n is a function-to-synthesize that occurs
     440                 :            :           // in a higher-order context.
     441                 :            :           // If the type of n is functional, then it is not fully applied.
     442         [ +  + ]:       2572 :           if (n.getType().isFunction())
     443                 :            :           {
     444                 :          4 :             ret = false;
     445                 :          4 :             success = false;
     446                 :            :           }
     447                 :            :           else
     448                 :            :           {
     449                 :       2568 :             success = true;
     450                 :            :           }
     451                 :            :         }
     452                 :            :       }
     453                 :            :       else
     454                 :            :       {
     455         [ -  - ]:          0 :         if (n.getKind() == Kind::APPLY_UF)
     456                 :            :         {
     457                 :          0 :           f = n.getOperator();
     458                 :          0 :           success = true;
     459                 :            :         }
     460                 :            :       }
     461         [ +  + ]:      20327 :       if (success)
     462                 :            :       {
     463         [ +  - ]:       2568 :         Trace("si-prt-debug") << "Process " << n << std::endl;
     464         [ +  - ]:       2568 :         if (!sb.contains(n))
     465                 :            :         {
     466                 :            :           // check if it matches the type requirement
     467         [ +  + ]:       2568 :           if (isAntiSkolemizableType(f))
     468                 :            :           {
     469         [ +  + ]:       2556 :             if (args.empty())
     470                 :            :             {
     471                 :            :               // record arguments
     472         [ +  + ]:       5689 :               for (unsigned i = 0; i < n.getNumChildren(); i++)
     473                 :            :               {
     474                 :       3590 :                 args.push_back(n[i]);
     475                 :            :               }
     476                 :            :             }
     477                 :            :             else
     478                 :            :             {
     479                 :            :               // arguments must be the same as those already recorded
     480         [ +  + ]:       1523 :               for (unsigned i = 0; i < n.getNumChildren(); i++)
     481                 :            :               {
     482         [ +  + ]:       1159 :                 if (args[i] != n[i])
     483                 :            :                 {
     484         [ +  - ]:        186 :                   Trace("si-prt-debug") << "...bad invocation : " << n
     485                 :         93 :                                         << " at arg " << i << "." << std::endl;
     486                 :         93 :                   ret = false;
     487                 :         93 :                   break;
     488                 :            :                 }
     489                 :            :               }
     490                 :            :             }
     491         [ +  + ]:       2556 :             if (ret)
     492                 :            :             {
     493                 :       2463 :               sb.add(n, d_func_inv[f]);
     494                 :            :             }
     495                 :            :           }
     496                 :            :           else
     497                 :            :           {
     498         [ +  - ]:         24 :             Trace("si-prt-debug")
     499                 :         12 :                 << "... " << f << " is a bad operator." << std::endl;
     500                 :         12 :             ret = false;
     501                 :            :           }
     502                 :            :         }
     503                 :            :       }
     504                 :      20327 :     }
     505                 :      20528 :     visited[n] = ret;
     506                 :      20528 :     return ret;
     507                 :            :   }
     508                 :            : }
     509                 :            : 
     510                 :       2568 : bool SingleInvocationPartition::isAntiSkolemizableType(Node f)
     511                 :            : {
     512                 :       2568 :   std::map<Node, bool>::iterator it = d_funcs.find(f);
     513         [ +  + ]:       2568 :   if (it != d_funcs.end())
     514                 :            :   {
     515                 :       1288 :     return it->second;
     516                 :            :   }
     517                 :            :   else
     518                 :            :   {
     519                 :       1280 :     TypeNode tn = f.getType();
     520                 :       1280 :     bool ret = false;
     521         [ -  + ]:       2350 :     if (((tn.isFunction() && tn.getNumChildren() == d_arg_types.size() + 1)
     522 [ +  + ][ +  - ]:       2350 :          || (d_arg_types.empty() && tn.getNumChildren() == 0)))
         [ +  + ][ +  + ]
     523                 :            :     {
     524                 :       1268 :       ret = true;
     525                 :       1268 :       std::vector<Node> children;
     526                 :       1268 :       children.push_back(f);
     527                 :            :       // TODO: permutations of arguments
     528         [ +  + ]:       3676 :       for (unsigned i = 0; i < d_arg_types.size(); i++)
     529                 :            :       {
     530                 :       2408 :         children.push_back(d_si_vars[i]);
     531         [ -  + ]:       2408 :         if (tn[i] != d_arg_types[i])
     532                 :            :         {
     533                 :          0 :           ret = false;
     534                 :          0 :           break;
     535                 :            :         }
     536                 :            :       }
     537         [ +  - ]:       1268 :       if (ret)
     538                 :            :       {
     539                 :       1268 :         Node t;
     540         [ +  + ]:       1268 :         if (children.size() > 1)
     541                 :            :         {
     542                 :       1070 :           t = nodeManager()->mkNode(Kind::APPLY_UF, children);
     543                 :            :         }
     544                 :            :         else
     545                 :            :         {
     546                 :        198 :           t = children[0];
     547                 :            :         }
     548                 :       1268 :         d_func_inv[f] = t;
     549                 :       1268 :         std::stringstream ss;
     550                 :       1268 :         ss << "F_" << f;
     551                 :       1268 :         TypeNode rt;
     552         [ +  + ]:       1268 :         if (d_arg_types.empty())
     553                 :            :         {
     554                 :        198 :           rt = tn;
     555                 :            :         }
     556                 :            :         else
     557                 :            :         {
     558                 :       1070 :           rt = tn.getRangeType();
     559                 :            :         }
     560                 :       1268 :         Node v = nodeManager()->mkBoundVar(ss.str(), rt);
     561                 :       1268 :         d_func_fo_var[f] = v;
     562                 :       1268 :         d_fo_var_to_func[v] = f;
     563                 :       1268 :         d_func_vars.push_back(v);
     564                 :       1268 :         d_all_funcs.push_back(f);
     565                 :       1268 :       }
     566                 :       1268 :     }
     567                 :       1280 :     d_funcs[f] = ret;
     568                 :       1280 :     return ret;
     569                 :       1280 :   }
     570                 :            : }
     571                 :            : 
     572                 :        162 : Node SingleInvocationPartition::getConjunct(int index)
     573                 :            : {
     574                 :        162 :   return d_conjuncts[index].empty()
     575                 :        162 :              ? nodeManager()->mkConst(true)
     576                 :        162 :              : (d_conjuncts[index].size() == 1
     577                 :        103 :                     ? d_conjuncts[index][0]
     578 [ -  + ][ +  + ]:        589 :                     : nodeManager()->mkNode(Kind::AND, d_conjuncts[index]));
     579                 :            : }
     580                 :            : 
     581                 :        946 : void SingleInvocationPartition::debugPrint(CVC5_UNUSED const char* c)
     582                 :            : {
     583         [ +  - ]:        946 :   Trace(c) << "Single invocation variables : ";
     584         [ +  + ]:       2328 :   for (unsigned i = 0; i < d_si_vars.size(); i++)
     585                 :            :   {
     586         [ +  - ]:       1382 :     Trace(c) << d_si_vars[i] << " ";
     587                 :            :   }
     588         [ +  - ]:        946 :   Trace(c) << std::endl;
     589         [ +  - ]:        946 :   Trace(c) << "Functions : " << std::endl;
     590         [ +  + ]:       2226 :   for (std::map<Node, bool>::iterator it = d_funcs.begin(); it != d_funcs.end();
     591                 :       1280 :        ++it)
     592                 :            :   {
     593         [ +  - ]:       1280 :     Trace(c) << "  " << it->first << " : ";
     594         [ +  + ]:       1280 :     if (it->second)
     595                 :            :     {
     596         [ +  - ]:       2536 :       Trace(c) << d_func_inv[it->first] << " " << d_func_fo_var[it->first]
     597                 :       1268 :                << std::endl;
     598                 :            :     }
     599                 :            :     else
     600                 :            :     {
     601         [ +  - ]:         12 :       Trace(c) << "not incorporated." << std::endl;
     602                 :            :     }
     603                 :            :   }
     604         [ +  + ]:       4730 :   for (unsigned i = 0; i < 4; i++)
     605                 :            :   {
     606 [ +  - ][ -  - ]:       7568 :     Trace(c) << (i == 0 ? "Single invocation"
     607         [ -  - ]:          0 :                         : (i == 1 ? "Non-single invocation"
     608         [ -  - ]:          0 :                                   : (i == 2 ? "All"
     609                 :       3784 :                                             : "Non-ground single invocation")));
     610         [ +  - ]:       3784 :     Trace(c) << " conjuncts: " << std::endl;
     611         [ +  + ]:       8484 :     for (unsigned j = 0; j < d_conjuncts[i].size(); j++)
     612                 :            :     {
     613         [ +  - ]:       4700 :       Trace(c) << "  " << (j + 1) << " : " << d_conjuncts[i][j] << std::endl;
     614                 :            :     }
     615                 :            :   }
     616         [ +  - ]:        946 :   Trace(c) << std::endl;
     617                 :        946 : }
     618                 :            : 
     619                 :       2137 : Node SingleInvocationPartition::getQuantSimplify(TNode n) const
     620                 :            : {
     621                 :       2137 :   std::unordered_set<Node> fvs;
     622                 :       2137 :   expr::getFreeVariables(n, fvs);
     623         [ +  + ]:       2137 :   if (fvs.empty())
     624                 :            :   {
     625                 :       1065 :     return rewrite(n);
     626                 :            :   }
     627                 :       1072 :   std::vector<Node> bvs(fvs.begin(), fvs.end());
     628                 :       1072 :   NodeManager* nm = nodeManager();
     629                 :       2144 :   Node q = nm->mkNode(Kind::FORALL, nm->mkNode(Kind::BOUND_VAR_LIST, bvs), n);
     630                 :       1072 :   q = rewrite(q);
     631                 :       1072 :   return TermUtil::getRemoveQuantifiers(q);
     632                 :       2137 : }
     633                 :            : 
     634                 :            : }  // namespace quantifiers
     635                 :            : }  // namespace theory
     636                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14