LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory/arith/nl/ext - monomial.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 168 176 95.5 %
Date: 2026-03-15 10:41:23 Functions: 19 19 100.0 %
Branches: 89 138 64.5 %

           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                 :            :  * Implementation of utilities for monomials.
      11                 :            :  */
      12                 :            : 
      13                 :            : #include "theory/arith/nl/ext/monomial.h"
      14                 :            : 
      15                 :            : #include "theory/arith/arith_utilities.h"
      16                 :            : #include "theory/arith/nl/nl_lemma_utils.h"
      17                 :            : #include "theory/rewriter.h"
      18                 :            : 
      19                 :            : using namespace cvc5::internal::kind;
      20                 :            : 
      21                 :            : namespace cvc5::internal {
      22                 :            : namespace theory {
      23                 :            : namespace arith {
      24                 :            : namespace nl {
      25                 :            : 
      26                 :            : // Returns a[key] if key is in a or value otherwise.
      27                 :     238267 : unsigned getCountWithDefault(const NodeMultiset& a, Node key, unsigned value)
      28                 :            : {
      29                 :     238267 :   NodeMultiset::const_iterator it = a.find(key);
      30         [ +  + ]:     238267 :   return (it == a.end()) ? value : it->second;
      31                 :            : }
      32                 :            : // Given two multisets return the multiset difference a \ b.
      33                 :      22974 : NodeMultiset diffMultiset(const NodeMultiset& a, const NodeMultiset& b)
      34                 :            : {
      35                 :      22974 :   NodeMultiset difference;
      36         [ +  + ]:      62116 :   for (NodeMultiset::const_iterator it_a = a.begin(); it_a != a.end(); ++it_a)
      37                 :            :   {
      38                 :      39142 :     Node key = it_a->first;
      39                 :      39142 :     const unsigned a_value = it_a->second;
      40                 :      39142 :     const unsigned b_value = getCountWithDefault(b, key, 0);
      41         [ +  + ]:      39142 :     if (a_value > b_value)
      42                 :            :     {
      43                 :      29867 :       difference[key] = a_value - b_value;
      44                 :            :     }
      45                 :      39142 :   }
      46                 :      22974 :   return difference;
      47                 :          0 : }
      48                 :            : 
      49                 :            : // Return a vector containing a[key] repetitions of key in a multiset a.
      50                 :      22974 : std::vector<Node> ExpandMultiset(const NodeMultiset& a)
      51                 :            : {
      52                 :      22974 :   std::vector<Node> expansion;
      53         [ +  + ]:      52841 :   for (NodeMultiset::const_iterator it_a = a.begin(); it_a != a.end(); ++it_a)
      54                 :            :   {
      55                 :      29867 :     expansion.insert(expansion.end(), it_a->second, it_a->first);
      56                 :            :   }
      57                 :      22974 :   return expansion;
      58                 :          0 : }
      59                 :            : 
      60                 :            : // status 0 : n equal, -1 : n superset, 1 : n subset
      61                 :     141863 : void MonomialIndex::addTerm(Node n,
      62                 :            :                             const std::vector<Node>& reps,
      63                 :            :                             MonomialDb* nla,
      64                 :            :                             int status,
      65                 :            :                             unsigned argIndex)
      66                 :            : {
      67         [ +  + ]:     141863 :   if (status == 0)
      68                 :            :   {
      69         [ +  + ]:      29391 :     if (argIndex == reps.size())
      70                 :            :     {
      71                 :      13583 :       d_monos.push_back(n);
      72                 :            :     }
      73                 :            :     else
      74                 :            :     {
      75                 :      15808 :       d_data[reps[argIndex]].addTerm(n, reps, nla, status, argIndex + 1);
      76                 :            :     }
      77                 :            :   }
      78                 :     141863 :   for (std::map<Node, MonomialIndex>::iterator it = d_data.begin();
      79         [ +  + ]:     270859 :        it != d_data.end();
      80                 :     128996 :        ++it)
      81                 :            :   {
      82 [ +  + ][ +  + ]:     128996 :     if (status != 0 || argIndex == reps.size() || it->first != reps[argIndex])
         [ +  + ][ +  + ]
      83                 :            :     {
      84                 :            :       // if we do not contain this variable, then if we were a superset,
      85                 :            :       // fail (-2), otherwise we are subset.  if we do contain this
      86                 :            :       // variable, then if we were equal, we are superset since variables
      87                 :            :       // are ordered, otherwise we remain the same.
      88                 :            :       int new_status =
      89                 :     113188 :           std::find(reps.begin(), reps.end(), it->first) == reps.end()
      90 [ +  + ][ +  + ]:     120772 :               ? (status >= 0 ? 1 : -2)
      91         [ +  + ]:       7584 :               : (status == 0 ? -1 : status);
      92         [ +  + ]:     113188 :       if (new_status != -2)
      93                 :            :       {
      94                 :     112472 :         it->second.addTerm(n, reps, nla, new_status, argIndex);
      95                 :            :       }
      96                 :            :     }
      97                 :            :   }
      98                 :            :   // compare for subsets
      99         [ +  + ]:     294411 :   for (unsigned i = 0; i < d_monos.size(); i++)
     100                 :            :   {
     101                 :     152548 :     Node m = d_monos[i];
     102         [ +  + ]:     152548 :     if (m != n)
     103                 :            :     {
     104                 :            :       // we are superset if we are equal and haven't traversed all variables
     105 [ +  + ][ +  + ]:     138965 :       int cstatus = status == 0 ? (argIndex == reps.size() ? 0 : -1) : status;
     106         [ +  - ]:     277930 :       Trace("nl-ext-mindex-debug") << "  compare " << n << " and " << m
     107                 :     138965 :                                    << ", status = " << cstatus << std::endl;
     108                 :     138965 :       if (cstatus <= 0 && nla->isMonomialSubset(m, n))
     109                 :            :       {
     110                 :      14159 :         nla->registerMonomialSubset(m, n);
     111         [ +  - ]:      14159 :         Trace("nl-ext-mindex-debug") << "...success" << std::endl;
     112                 :            :       }
     113                 :     124806 :       else if (cstatus >= 0 && nla->isMonomialSubset(n, m))
     114                 :            :       {
     115                 :       8815 :         nla->registerMonomialSubset(n, m);
     116         [ +  - ]:       8815 :         Trace("nl-ext-mindex-debug") << "...success (rev)" << std::endl;
     117                 :            :       }
     118                 :            :     }
     119                 :     152548 :   }
     120                 :     141863 : }
     121                 :            : 
     122                 :      33012 : MonomialDb::MonomialDb()
     123                 :            : {
     124                 :      33012 : }
     125                 :            : 
     126                 :     200032 : void MonomialDb::registerMonomial(Node n)
     127                 :            : {
     128         [ +  + ]:     200032 :   if (std::find(d_monomials.begin(), d_monomials.end(), n) != d_monomials.end())
     129                 :            :   {
     130                 :     186449 :     return;
     131                 :            :   }
     132                 :      13583 :   d_monomials.push_back(n);
     133         [ +  - ]:      13583 :   Trace("nl-ext-debug") << "Register monomial : " << n << std::endl;
     134                 :      13583 :   Kind k = n.getKind();
     135         [ +  + ]:      13583 :   if (k == Kind::NONLINEAR_MULT)
     136                 :            :   {
     137                 :            :     // get exponent count
     138                 :       4605 :     unsigned nchild = n.getNumChildren();
     139         [ +  + ]:      15289 :     for (unsigned i = 0; i < nchild; i++)
     140                 :            :     {
     141                 :      10684 :       d_m_exp[n][n[i]]++;
     142                 :      10684 :       if (i == 0 || n[i] != n[i - 1])
     143                 :            :       {
     144                 :       8505 :         d_m_vlist[n].push_back(n[i]);
     145                 :            :       }
     146                 :            :     }
     147                 :       4605 :     d_m_degree[n] = nchild;
     148                 :            :   }
     149         [ +  + ]:       8978 :   else if (n.isConst())
     150                 :            :   {
     151 [ -  + ][ -  + ]:       1675 :     Assert(n.getConst<Rational>().isOne());
                 [ -  - ]
     152                 :       1675 :     d_m_exp[n].clear();
     153                 :       1675 :     d_m_vlist[n].clear();
     154                 :       1675 :     d_m_degree[n] = 0;
     155                 :            :   }
     156                 :            :   else
     157                 :            :   {
     158 [ +  - ][ +  - ]:       7303 :     Assert(k != Kind::ADD && k != Kind::MULT);
         [ -  + ][ -  + ]
                 [ -  - ]
     159                 :       7303 :     d_m_exp[n][n] = 1;
     160                 :       7303 :     d_m_vlist[n].push_back(n);
     161                 :       7303 :     d_m_degree[n] = 1;
     162                 :            :   }
     163                 :      13583 :   std::sort(d_m_vlist[n].begin(), d_m_vlist[n].end());
     164         [ +  - ]:      13583 :   Trace("nl-ext-mindex") << "Add monomial to index : " << n << std::endl;
     165                 :      13583 :   d_m_index.addTerm(n, d_m_vlist[n], this);
     166                 :            : }
     167                 :            : 
     168                 :      22974 : void MonomialDb::registerMonomialSubset(Node a, Node b)
     169                 :            : {
     170 [ -  + ][ -  + ]:      22974 :   Assert(isMonomialSubset(a, b));
                 [ -  - ]
     171                 :            : 
     172                 :      22974 :   const NodeMultiset& a_exponent_map = getMonomialExponentMap(a);
     173                 :      22974 :   const NodeMultiset& b_exponent_map = getMonomialExponentMap(b);
     174                 :            : 
     175                 :            :   std::vector<Node> diff_children =
     176                 :      22974 :       ExpandMultiset(diffMultiset(b_exponent_map, a_exponent_map));
     177 [ -  + ][ -  + ]:      22974 :   Assert(!diff_children.empty());
                 [ -  - ]
     178                 :            : 
     179                 :      22974 :   d_m_contain_parent[a].push_back(b);
     180                 :      22974 :   d_m_contain_children[b].push_back(a);
     181                 :            : 
     182                 :            :   // currently use real type here
     183                 :      22974 :   TypeNode tn = a.getNodeManager()->realType();
     184                 :      22974 :   Node mult_term = safeConstructNaryType(tn, Kind::MULT, diff_children);
     185                 :            :   Node nlmult_term =
     186                 :      22974 :       safeConstructNaryType(tn, Kind::NONLINEAR_MULT, diff_children);
     187                 :      22974 :   d_m_contain_mult[a][b] = mult_term;
     188                 :      22974 :   d_m_contain_umult[a][b] = nlmult_term;
     189         [ +  - ]:      45948 :   Trace("nl-ext-mindex") << "..." << a << " is a subset of " << b
     190                 :      22974 :                          << ", difference is " << mult_term << std::endl;
     191                 :      22974 : }
     192                 :            : 
     193                 :     163891 : bool MonomialDb::isMonomialSubset(Node am, Node bm) const
     194                 :            : {
     195                 :     163891 :   const NodeMultiset& a = getMonomialExponentMap(am);
     196                 :     163891 :   const NodeMultiset& b = getMonomialExponentMap(bm);
     197         [ +  + ]:     199900 :   for (NodeMultiset::const_iterator it_a = a.begin(); it_a != a.end(); ++it_a)
     198                 :            :   {
     199                 :     153952 :     Node key = it_a->first;
     200                 :     153952 :     const unsigned a_value = it_a->second;
     201                 :     153952 :     const unsigned b_value = getCountWithDefault(b, key, 0);
     202         [ +  + ]:     153952 :     if (a_value > b_value)
     203                 :            :     {
     204                 :     117943 :       return false;
     205                 :            :     }
     206         [ +  + ]:     153952 :   }
     207                 :      45948 :   return true;
     208                 :            : }
     209                 :            : 
     210                 :     562319 : const NodeMultiset& MonomialDb::getMonomialExponentMap(Node monomial) const
     211                 :            : {
     212                 :     562319 :   MonomialExponentMap::const_iterator it = d_m_exp.find(monomial);
     213 [ -  + ][ -  + ]:     562319 :   Assert(it != d_m_exp.end());
                 [ -  - ]
     214                 :     562319 :   return it->second;
     215                 :            : }
     216                 :            : 
     217                 :    1355886 : unsigned MonomialDb::getExponent(Node monomial, Node v) const
     218                 :            : {
     219                 :    1355886 :   MonomialExponentMap::const_iterator it = d_m_exp.find(monomial);
     220         [ -  + ]:    1355886 :   if (it == d_m_exp.end())
     221                 :            :   {
     222                 :          0 :     return 0;
     223                 :            :   }
     224                 :    1355886 :   std::map<Node, unsigned>::const_iterator itv = it->second.find(v);
     225         [ -  + ]:    1355886 :   if (itv == it->second.end())
     226                 :            :   {
     227                 :          0 :     return 0;
     228                 :            :   }
     229                 :    1355886 :   return itv->second;
     230                 :            : }
     231                 :            : 
     232                 :    2381514 : const std::vector<Node>& MonomialDb::getVariableList(Node monomial) const
     233                 :            : {
     234                 :            :   std::map<Node, std::vector<Node> >::const_iterator itvl =
     235                 :    2381514 :       d_m_vlist.find(monomial);
     236 [ -  + ][ -  + ]:    2381514 :   Assert(itvl != d_m_vlist.end());
                 [ -  - ]
     237                 :    2381514 :   return itvl->second;
     238                 :            : }
     239                 :            : 
     240                 :      81768 : unsigned MonomialDb::getDegree(Node monomial) const
     241                 :            : {
     242                 :      81768 :   std::map<Node, unsigned>::const_iterator it = d_m_degree.find(monomial);
     243 [ -  + ][ -  + ]:      81768 :   Assert(it != d_m_degree.end());
                 [ -  - ]
     244                 :      81768 :   return it->second;
     245                 :            : }
     246                 :            : 
     247                 :       2765 : void MonomialDb::sortByDegree(std::vector<Node>& ms) const
     248                 :            : {
     249                 :       2765 :   SortNonlinearDegree snlad(d_m_degree);
     250                 :       2765 :   std::sort(ms.begin(), ms.end(), snlad);
     251                 :       2765 : }
     252                 :            : 
     253                 :       7165 : void MonomialDb::sortVariablesByModel(std::vector<Node>& ms, NlModel& m)
     254                 :            : {
     255                 :       7165 :   SortNlModel smv;
     256                 :       7165 :   smv.d_nlm = &m;
     257                 :       7165 :   smv.d_isConcrete = false;
     258                 :       7165 :   smv.d_isAbsolute = true;
     259                 :       7165 :   smv.d_reverse_order = true;
     260         [ +  + ]:      45208 :   for (const Node& msc : ms)
     261                 :            :   {
     262                 :      38043 :     std::sort(d_m_vlist[msc].begin(), d_m_vlist[msc].end(), smv);
     263                 :            :   }
     264                 :       7165 : }
     265                 :            : 
     266                 :        814 : const std::map<Node, std::vector<Node> >& MonomialDb::getContainsChildrenMap()
     267                 :            : {
     268                 :        814 :   return d_m_contain_children;
     269                 :            : }
     270                 :            : 
     271                 :       2765 : const std::map<Node, std::vector<Node> >& MonomialDb::getContainsParentMap()
     272                 :            : {
     273                 :       2765 :   return d_m_contain_parent;
     274                 :            : }
     275                 :            : 
     276                 :     367068 : Node MonomialDb::getContainsDiff(Node a, Node b) const
     277                 :            : {
     278                 :            :   std::map<Node, std::map<Node, Node> >::const_iterator it =
     279                 :     367068 :       d_m_contain_mult.find(a);
     280         [ -  + ]:     367068 :   if (it == d_m_contain_mult.end())
     281                 :            :   {
     282                 :          0 :     return Node::null();
     283                 :            :   }
     284                 :     367068 :   std::map<Node, Node>::const_iterator it2 = it->second.find(b);
     285         [ -  + ]:     367068 :   if (it2 == it->second.end())
     286                 :            :   {
     287                 :          0 :     return Node::null();
     288                 :            :   }
     289                 :     367068 :   return it2->second;
     290                 :            : }
     291                 :            : 
     292                 :        874 : Node MonomialDb::getContainsDiffNl(Node a, Node b) const
     293                 :            : {
     294                 :            :   std::map<Node, std::map<Node, Node> >::const_iterator it =
     295                 :        874 :       d_m_contain_umult.find(a);
     296         [ -  + ]:        874 :   if (it == d_m_contain_umult.end())
     297                 :            :   {
     298                 :          0 :     return Node::null();
     299                 :            :   }
     300                 :        874 :   std::map<Node, Node>::const_iterator it2 = it->second.find(b);
     301         [ -  + ]:        874 :   if (it2 == it->second.end())
     302                 :            :   {
     303                 :          0 :     return Node::null();
     304                 :            :   }
     305                 :        874 :   return it2->second;
     306                 :            : }
     307                 :            : 
     308                 :      25840 : Node MonomialDb::mkMonomialRemFactor(Node n,
     309                 :            :                                      const NodeMultiset& n_exp_rem) const
     310                 :            : {
     311                 :      25840 :   std::vector<Node> children;
     312                 :      25840 :   const NodeMultiset& exponent_map = getMonomialExponentMap(n);
     313                 :      25840 :   for (NodeMultiset::const_iterator itme2 = exponent_map.begin();
     314         [ +  + ]:      71013 :        itme2 != exponent_map.end();
     315                 :      45173 :        ++itme2)
     316                 :            :   {
     317                 :      45173 :     Node v = itme2->first;
     318                 :      45173 :     unsigned inc = itme2->second;
     319         [ +  - ]:      90346 :     Trace("nl-ext-mono-factor")
     320                 :      45173 :         << "..." << inc << " factors of " << v << std::endl;
     321                 :      45173 :     unsigned count_in_n_exp_rem = getCountWithDefault(n_exp_rem, v, 0);
     322 [ -  + ][ -  + ]:      45173 :     Assert(count_in_n_exp_rem <= inc);
                 [ -  - ]
     323                 :      45173 :     inc -= count_in_n_exp_rem;
     324         [ +  - ]:      90346 :     Trace("nl-ext-mono-factor")
     325                 :      45173 :         << "......rem, now " << inc << " factors of " << v << std::endl;
     326                 :      45173 :     children.insert(children.end(), inc, v);
     327                 :      45173 :   }
     328                 :      25840 :   Node ret = safeConstructNaryType(n.getType(), Kind::MULT, children);
     329         [ +  - ]:      25840 :   Trace("nl-ext-mono-factor") << "...return : " << ret << std::endl;
     330                 :      51680 :   return ret;
     331                 :      25840 : }
     332                 :            : 
     333                 :            : }  // namespace nl
     334                 :            : }  // namespace arith
     335                 :            : }  // namespace theory
     336                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14