LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory/quantifiers - quantifiers_preprocess.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 114 135 84.4 %
Date: 2025-01-07 12:38:26 Functions: 4 4 100.0 %
Branches: 69 122 56.6 %

           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                 :            :  * Preprocessor for the theory of quantifiers.
      14                 :            :  */
      15                 :            : 
      16                 :            : #include "theory/quantifiers/quantifiers_preprocess.h"
      17                 :            : 
      18                 :            : #include "expr/node_algorithm.h"
      19                 :            : #include "options/quantifiers_options.h"
      20                 :            : #include "theory/quantifiers/quant_util.h"
      21                 :            : #include "theory/quantifiers/skolemize.h"
      22                 :            : 
      23                 :            : using namespace cvc5::internal::kind;
      24                 :            : 
      25                 :            : namespace cvc5::internal {
      26                 :            : namespace theory {
      27                 :            : namespace quantifiers {
      28                 :            : 
      29                 :      81768 : QuantifiersPreprocess::QuantifiersPreprocess(Env& env)
      30                 :      81768 :     : EnvObj(env), d_qrew(nodeManager(), env.getRewriter(), options())
      31                 :            : {
      32                 :      81768 : }
      33                 :            : 
      34                 :          9 : Node QuantifiersPreprocess::computePrenexAgg(
      35                 :            :     Node n, std::map<Node, Node>& visited) const
      36                 :            : {
      37                 :          9 :   std::map<Node, Node>::iterator itv = visited.find(n);
      38         [ -  + ]:          9 :   if (itv != visited.end())
      39                 :            :   {
      40                 :          0 :     return itv->second;
      41                 :            :   }
      42         [ +  + ]:          9 :   if (!expr::hasClosure(n))
      43                 :            :   {
      44                 :            :     // trivial
      45                 :          4 :     return n;
      46                 :            :   }
      47                 :          5 :   NodeManager* nm = nodeManager();
      48                 :         10 :   Node ret = n;
      49         [ +  + ]:          5 :   if (n.getKind() == Kind::NOT)
      50                 :            :   {
      51                 :          1 :     ret = computePrenexAgg(n[0], visited).negate();
      52                 :            :   }
      53         [ +  + ]:          4 :   else if (n.getKind() == Kind::FORALL)
      54                 :            :   {
      55                 :          6 :     std::vector<Node> children;
      56                 :          3 :     children.push_back(computePrenexAgg(n[1], visited));
      57                 :          6 :     std::vector<Node> args;
      58                 :          3 :     args.insert(args.end(), n[0].begin(), n[0].end());
      59                 :            :     // only combine if standard
      60         [ +  + ]:          3 :     if (d_qrew.isStandard(n, options()))
      61                 :            :     {
      62                 :            :       // for each child, strip top level quant
      63         [ +  + ]:          4 :       for (unsigned i = 0; i < children.size(); i++)
      64                 :            :       {
      65         [ -  + ]:          2 :         if (children[i].getKind() == Kind::FORALL)
      66                 :            :         {
      67                 :          0 :           args.insert(args.end(), children[i][0].begin(), children[i][0].end());
      68                 :          0 :           children[i] = children[i][1];
      69                 :            :         }
      70                 :            :       }
      71                 :            :     }
      72                 :            :     // keep the pattern
      73                 :          6 :     std::vector<Node> iplc;
      74         [ +  - ]:          3 :     if (n.getNumChildren() == 3)
      75                 :            :     {
      76                 :          3 :       iplc.insert(iplc.end(), n[2].begin(), n[2].end());
      77                 :            :     }
      78                 :          3 :     Node nb = nm->mkOr(children);
      79                 :          3 :     ret = d_qrew.mkForall(args, nb, iplc, true);
      80                 :            :   }
      81                 :            :   else
      82                 :            :   {
      83                 :          2 :     Node q;
      84                 :          2 :     std::vector<Node> args, nargs;
      85                 :          3 :     Node nn = d_qrew.computePrenex(q, n, args, nargs, true, true);
      86                 :          2 :     std::unordered_set<Node> argsSet(args.begin(), args.end());
      87                 :          2 :     std::unordered_set<Node> nargsSet(args.begin(), args.end());
      88 [ -  + ][ -  - ]:          1 :     Assert(n != nn || argsSet.empty());
         [ -  + ][ -  - ]
      89 [ -  + ][ -  - ]:          1 :     Assert(n != nn || nargsSet.empty());
         [ -  + ][ -  - ]
      90         [ +  - ]:          1 :     if (n != nn)
      91                 :            :     {
      92                 :          2 :       Node nnn = computePrenexAgg(nn, visited);
      93                 :            :       // merge prenex
      94         [ -  + ]:          1 :       if (nnn.getKind() == Kind::FORALL)
      95                 :            :       {
      96                 :          0 :         argsSet.insert(nnn[0].begin(), nnn[0].end());
      97                 :          0 :         nnn = nnn[1];
      98                 :            :         // pos polarity variables are inner
      99         [ -  - ]:          0 :         if (!argsSet.empty())
     100                 :            :         {
     101                 :          0 :           nnn = d_qrew.mkForall({argsSet.begin(), argsSet.end()}, nnn, true);
     102                 :            :         }
     103                 :          0 :         argsSet.clear();
     104                 :            :       }
     105 [ -  + ][ -  - ]:          1 :       else if (nnn.getKind() == Kind::NOT && nnn[0].getKind() == Kind::FORALL)
         [ -  + ][ -  + ]
                 [ -  - ]
     106                 :            :       {
     107                 :          0 :         nargsSet.insert(nnn[0][0].begin(), nnn[0][0].end());
     108                 :          0 :         nnn = nnn[0][1].negate();
     109                 :            :       }
     110         [ +  - ]:          1 :       if (!nargsSet.empty())
     111                 :            :       {
     112                 :            :         nnn = d_qrew
     113                 :          2 :                   .mkForall(
     114                 :          2 :                       {nargsSet.begin(), nargsSet.end()}, nnn.negate(), true)
     115                 :          1 :                   .negate();
     116                 :            :       }
     117         [ +  - ]:          1 :       if (!argsSet.empty())
     118                 :            :       {
     119                 :          1 :         nnn = d_qrew.mkForall({argsSet.begin(), argsSet.end()}, nnn, true);
     120                 :            :       }
     121                 :          1 :       ret = nnn;
     122                 :            :     }
     123                 :            :   }
     124                 :          5 :   visited[n] = ret;
     125                 :          5 :   return ret;
     126                 :            : }
     127                 :            : 
     128                 :        683 : Node QuantifiersPreprocess::preSkolemizeQuantifiers(
     129                 :            :     Node n,
     130                 :            :     bool polarity,
     131                 :            :     std::vector<TNode>& fvs,
     132                 :            :     std::unordered_map<std::pair<Node, bool>, Node, NodePolPairHashFunction>&
     133                 :            :         visited) const
     134                 :            : {
     135 [ -  + ][ -  + ]:        683 :   Assert(options().quantifiers.preSkolemQuant
                 [ -  - ]
     136                 :            :          != options::PreSkolemQuantMode::OFF);
     137                 :       1366 :   std::pair<Node, bool> key(n, polarity);
     138                 :            :   std::unordered_map<std::pair<Node, bool>, Node, NodePolPairHashFunction>::
     139                 :        683 :       iterator it = visited.find(key);
     140         [ -  + ]:        683 :   if (it != visited.end())
     141                 :            :   {
     142                 :          0 :     return it->second;
     143                 :            :   }
     144                 :        683 :   NodeManager* nm = nodeManager();
     145         [ +  - ]:       1366 :   Trace("pre-sk") << "Pre-skolem " << n << " " << polarity << " " << fvs.size()
     146                 :        683 :                   << std::endl;
     147         [ +  + ]:        683 :   if (n.getKind() == Kind::FORALL)
     148                 :            :   {
     149                 :        380 :     Node ret = n;
     150         [ +  + ]:        190 :     if (n.getNumChildren() == 3)
     151                 :            :     {
     152                 :            :       // Do not pre-skolemize quantified formulas with three children.
     153                 :            :       // This includes non-standard quantified formulas
     154                 :            :       // like recursive function definitions, or sygus conjectures, and
     155                 :            :       // quantified formulas with triggers.
     156                 :            :     }
     157         [ +  + ]:         78 :     else if (polarity)
     158                 :            :     {
     159         [ +  + ]:         62 :       if (options().quantifiers.preSkolemQuantNested)
     160                 :            :       {
     161                 :         80 :         std::vector<Node> children;
     162                 :         40 :         children.push_back(n[0]);
     163                 :            :         // add children to current scope
     164                 :         80 :         std::vector<TNode> fvss;
     165                 :         40 :         fvss.insert(fvss.end(), fvs.begin(), fvs.end());
     166                 :         40 :         fvss.insert(fvss.end(), n[0].begin(), n[0].end());
     167                 :            :         // process body in a new context
     168                 :            :         std::unordered_map<std::pair<Node, bool>, Node, NodePolPairHashFunction>
     169                 :         80 :             visitedSub;
     170                 :         40 :         Node pbody = preSkolemizeQuantifiers(n[1], polarity, fvss, visitedSub);
     171                 :         40 :         children.push_back(pbody);
     172                 :            :         // return processed quantifier
     173                 :         40 :         ret = nm->mkNode(Kind::FORALL, children);
     174                 :            :       }
     175                 :            :     }
     176                 :            :     else
     177                 :            :     {
     178                 :            :       // will skolemize current, process body
     179                 :         32 :       Node nn = preSkolemizeQuantifiers(n[1], polarity, fvs, visited);
     180                 :         32 :       std::vector<Node> sk;
     181                 :         32 :       Node sub;
     182                 :         16 :       std::vector<unsigned> sub_vars;
     183                 :            :       // return skolemized body
     184                 :         32 :       ret = Skolemize::mkSkolemizedBodyInduction(
     185                 :         16 :           options(), n, nn, fvs, sk, sub, sub_vars);
     186                 :            :     }
     187                 :        190 :     visited[key] = ret;
     188                 :        190 :     return ret;
     189                 :            :   }
     190                 :            :   // check if it contains a quantifier as a subterm
     191                 :            :   // if so, we may preprocess this node
     192         [ +  + ]:        493 :   if (!expr::hasClosure(n))
     193                 :            :   {
     194                 :        453 :     visited[key] = n;
     195                 :        453 :     return n;
     196                 :            :   }
     197                 :         40 :   Kind k = n.getKind();
     198                 :         80 :   Node ret = n;
     199 [ -  + ][ -  + ]:         40 :   Assert(n.getType().isBoolean());
                 [ -  - ]
     200                 :         40 :   if (k == Kind::ITE || (k == Kind::EQUAL && n[0].getType().isBoolean()))
     201                 :            :   {
     202                 :          6 :     if (options().quantifiers.preSkolemQuant
     203         [ -  + ]:          6 :         == options::PreSkolemQuantMode::AGG)
     204                 :            :     {
     205                 :          0 :       Node nn;
     206                 :            :       // must remove structure
     207         [ -  - ]:          0 :       if (k == Kind::ITE)
     208                 :            :       {
     209                 :          0 :         nn = nm->mkNode(Kind::AND,
     210                 :          0 :                         nm->mkNode(Kind::OR, n[0].notNode(), n[1]),
     211                 :          0 :                         nm->mkNode(Kind::OR, n[0], n[2]));
     212                 :            :       }
     213         [ -  - ]:          0 :       else if (k == Kind::EQUAL)
     214                 :            :       {
     215                 :          0 :         nn = nm->mkNode(Kind::AND,
     216                 :          0 :                         nm->mkNode(Kind::OR, n[0].notNode(), n[1]),
     217                 :          0 :                         nm->mkNode(Kind::OR, n[0], n[1].notNode()));
     218                 :            :       }
     219                 :          0 :       ret = preSkolemizeQuantifiers(nn, polarity, fvs, visited);
     220                 :            :     }
     221                 :            :   }
     222 [ +  + ][ +  + ]:         34 :   else if (k == Kind::AND || k == Kind::OR || k == Kind::NOT
                 [ +  + ]
     223         [ -  + ]:          2 :            || k == Kind::IMPLIES)
     224                 :            :   {
     225                 :         32 :     std::vector<Node> children;
     226         [ +  + ]:         76 :     for (size_t i = 0, nchild = n.getNumChildren(); i < nchild; i++)
     227                 :            :     {
     228                 :            :       bool newHasPol;
     229                 :            :       bool newPol;
     230                 :         44 :       QuantPhaseReq::getPolarity(n, i, true, polarity, newHasPol, newPol);
     231 [ -  + ][ -  + ]:         44 :       Assert(newHasPol);
                 [ -  - ]
     232                 :         44 :       children.push_back(preSkolemizeQuantifiers(n[i], newPol, fvs, visited));
     233                 :            :     }
     234                 :         32 :     ret = nm->mkNode(k, children);
     235                 :            :   }
     236                 :         40 :   visited[key] = ret;
     237                 :         40 :   return ret;
     238                 :            : }
     239                 :            : 
     240                 :     323243 : TrustNode QuantifiersPreprocess::preprocess(Node n, bool isInst) const
     241                 :            : {
     242                 :     646486 :   Node prev = n;
     243         [ +  + ]:     323243 :   if (options().quantifiers.preSkolemQuant != options::PreSkolemQuantMode::OFF)
     244                 :            :   {
     245 [ +  + ][ +  + ]:        644 :     if (!isInst || !options().quantifiers.preSkolemQuantNested)
                 [ +  + ]
     246                 :            :     {
     247         [ +  - ]:       1166 :       Trace("quantifiers-preprocess-debug")
     248                 :        583 :           << "Pre-skolemize " << n << "..." << std::endl;
     249                 :            :       // apply pre-skolemization to existential quantifiers
     250                 :       1166 :       std::vector<TNode> fvs;
     251                 :            :       std::unordered_map<std::pair<Node, bool>, Node, NodePolPairHashFunction>
     252                 :        583 :           visited;
     253                 :        583 :       n = preSkolemizeQuantifiers(prev, true, fvs, visited);
     254                 :            :     }
     255                 :            :   }
     256                 :            :   // pull all quantifiers globally
     257         [ +  + ]:     323243 :   if (options().quantifiers.prenexQuant == options::PrenexQuantMode::NORMAL)
     258                 :            :   {
     259         [ +  - ]:          4 :     Trace("quantifiers-prenex") << "Prenexing : " << n << std::endl;
     260                 :          4 :     std::map<Node, Node> visited;
     261                 :          4 :     n = computePrenexAgg(n, visited);
     262                 :          4 :     n = rewrite(n);
     263         [ +  - ]:          4 :     Trace("quantifiers-prenex") << "Prenexing returned : " << n << std::endl;
     264                 :            :   }
     265         [ +  + ]:     323243 :   if (n != prev)
     266                 :            :   {
     267         [ +  - ]:         17 :     Trace("quantifiers-preprocess") << "Preprocess " << prev << std::endl;
     268         [ +  - ]:         17 :     Trace("quantifiers-preprocess") << "..returned " << n << std::endl;
     269                 :         17 :     return TrustNode::mkTrustRewrite(prev, n, nullptr);
     270                 :            :   }
     271                 :     323226 :   return TrustNode::null();
     272                 :            : }
     273                 :            : 
     274                 :            : }  // namespace quantifiers
     275                 :            : }  // namespace theory
     276                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14