LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/util - real_algebraic_number_poly_imp.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 121 155 78.1 %
Date: 2026-04-25 10:46:27 Functions: 26 32 81.2 %
Branches: 58 94 61.7 %

           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 RealAlgebraicNumber based on libpoly.
      11                 :            :  */
      12                 :            : 
      13                 :            : #include "base/cvc5config.h"
      14                 :            : #include "util/real_algebraic_number.h"
      15                 :            : 
      16                 :            : #ifdef CVC5_POLY_IMP
      17                 :            : #include <poly/polyxx.h>
      18                 :            : #endif
      19                 :            : 
      20                 :            : #include <limits>
      21                 :            : #include <sstream>
      22                 :            : 
      23                 :            : #include "base/check.h"
      24                 :            : #include "util/poly_util.h"
      25                 :            : 
      26                 :            : #define RAN_UNREACHABLE \
      27                 :            :   Unreachable() << "RealAlgebraicNumber is not available without libpoly."
      28                 :            : 
      29                 :            : namespace cvc5::internal {
      30                 :            : 
      31                 :    2428970 : RealAlgebraicNumber::RealAlgebraicNumber()
      32                 :            :     :
      33                 :            : #ifdef CVC5_POLY_IMP
      34                 :    2428970 :       d_isRational(true),
      35                 :            : #endif
      36                 :    2428970 :       d_rat()
      37                 :            : {
      38                 :    2428970 : }
      39                 :            : 
      40                 :            : #ifdef CVC5_POLY_IMP
      41                 :        166 : RealAlgebraicNumber::RealAlgebraicNumber(poly::AlgebraicNumber&& an)
      42                 :        166 :     : d_isRational(false), d_value(std::move(an))
      43                 :            : {
      44                 :        166 : }
      45                 :            : #endif
      46                 :            : 
      47                 :   23603615 : RealAlgebraicNumber::RealAlgebraicNumber(const Integer& i)
      48                 :            :     :
      49                 :            : #ifdef CVC5_POLY_IMP
      50                 :   23603615 :       d_isRational(true),
      51                 :            : #endif
      52                 :   23603615 :       d_rat(i)
      53                 :            : {
      54                 :   23603615 : }
      55                 :            : 
      56                 :   28525362 : RealAlgebraicNumber::RealAlgebraicNumber(const Rational& r)
      57                 :            :     :
      58                 :            : #ifdef CVC5_POLY_IMP
      59                 :   28525362 :       d_isRational(true),
      60                 :            : #endif
      61                 :   28525362 :       d_rat(r)
      62                 :            : {
      63                 :   28525362 : }
      64                 :            : 
      65                 :         21 : RealAlgebraicNumber::RealAlgebraicNumber(
      66                 :            :     CVC5_UNUSED const std::vector<long>& coefficients,
      67                 :            :     CVC5_UNUSED long lower,
      68                 :         21 :     CVC5_UNUSED long upper)
      69                 :            : {
      70                 :            : #ifdef CVC5_ASSERTIONS
      71         [ +  + ]:         84 :   for (long c : coefficients)
      72                 :            :   {
      73 [ +  - ][ +  - ]:         63 :     Assert(std::numeric_limits<int32_t>::min() <= c
         [ -  + ][ -  + ]
                 [ -  - ]
      74                 :            :            && c <= std::numeric_limits<int32_t>::max())
      75                 :            :         << "Coefficients need to fit within 32 bit integers. Please use the "
      76                 :          0 :            "constructor based on Integer instead.";
      77                 :            :   }
      78                 :            : #endif
      79                 :            : #ifdef CVC5_POLY_IMP
      80                 :         21 :   d_isRational = false;
      81                 :         42 :   d_value = poly::AlgebraicNumber(poly::UPolynomial(coefficients),
      82                 :         63 :                                   poly::DyadicInterval(lower, upper));
      83                 :            : #else
      84                 :            :   RAN_UNREACHABLE;
      85                 :            : #endif
      86                 :         21 : }
      87                 :            : 
      88                 :          0 : RealAlgebraicNumber::RealAlgebraicNumber(
      89                 :            :     CVC5_UNUSED const std::vector<Integer>& coefficients,
      90                 :            :     CVC5_UNUSED const Rational& lower,
      91                 :          0 :     CVC5_UNUSED const Rational& upper)
      92                 :            : {
      93                 :            : #ifdef CVC5_POLY_IMP
      94                 :          0 :   d_isRational = false;
      95                 :          0 :   *this = poly_utils::toRanWithRefinement(
      96                 :          0 :       poly::UPolynomial(poly_utils::toInteger(coefficients)), lower, upper);
      97                 :            : #else
      98                 :            :   RAN_UNREACHABLE;
      99                 :            : #endif
     100                 :          0 : }
     101                 :          1 : RealAlgebraicNumber::RealAlgebraicNumber(
     102                 :            :     CVC5_UNUSED const std::vector<Rational>& coefficients,
     103                 :            :     CVC5_UNUSED const Rational& lower,
     104                 :          1 :     CVC5_UNUSED const Rational& upper)
     105                 :            : {
     106                 :            : #ifdef CVC5_POLY_IMP
     107                 :          1 :   d_isRational = false;
     108                 :          1 :   Integer factor = Integer(1);
     109         [ +  + ]:          4 :   for (const auto& c : coefficients)
     110                 :            :   {
     111                 :          3 :     factor = factor.lcm(c.getDenominator());
     112                 :            :   }
     113                 :          1 :   std::vector<poly::Integer> coeffs;
     114         [ +  + ]:          4 :   for (const auto& c : coefficients)
     115                 :            :   {
     116 [ -  + ][ -  + ]:          3 :     Assert((c * factor).getDenominator() == Integer(1));
                 [ -  - ]
     117                 :          3 :     coeffs.emplace_back(poly_utils::toInteger((c * factor).getNumerator()));
     118                 :            :   }
     119                 :          2 :   *this = poly_utils::toRanWithRefinement(
     120                 :          3 :       poly::UPolynomial(std::move(coeffs)), lower, upper);
     121                 :            : #else
     122                 :            :   RAN_UNREACHABLE;
     123                 :            : #endif
     124                 :          1 : }
     125                 :            : 
     126                 :   37031567 : bool RealAlgebraicNumber::isRational() const
     127                 :            : {
     128                 :            : #ifdef CVC5_POLY_IMP
     129         [ +  + ]:   37031567 :   if (!d_isRational)
     130                 :            :   {
     131                 :       1400 :     return poly::is_rational(getValue());
     132                 :            :   }
     133                 :            : #endif
     134                 :   37030167 :   return true;
     135                 :            : }
     136                 :   35260018 : Rational RealAlgebraicNumber::toRational() const
     137                 :            : {
     138                 :            : #ifdef CVC5_POLY_IMP
     139         [ +  + ]:   35260018 :   if (!d_isRational)
     140                 :            :   {
     141                 :         88 :     return poly_utils::toRational(poly::to_rational_approximation(getValue()));
     142                 :            :   }
     143                 :            : #endif
     144                 :   35259974 :   return getRationalValue();
     145                 :            : }
     146                 :            : 
     147                 :          4 : std::string RealAlgebraicNumber::toString() const
     148                 :            : {
     149                 :          4 :   std::stringstream ss;
     150                 :            : #ifdef CVC5_POLY_IMP
     151         [ +  - ]:          4 :   if (!d_isRational)
     152                 :            :   {
     153                 :          4 :     ss << getValue();
     154                 :          4 :     return ss.str();
     155                 :            :   }
     156                 :            : #endif
     157                 :          0 :   ss << getRationalValue();
     158                 :          0 :   return ss.str();
     159                 :          4 : }
     160                 :            : 
     161                 :            : #ifdef CVC5_POLY_IMP
     162                 :       4656 : poly::AlgebraicNumber RealAlgebraicNumber::convertToPoly(
     163                 :            :     const RealAlgebraicNumber& r)
     164                 :            : {
     165                 :            :   // if we are already poly, just return the value
     166         [ +  + ]:       4656 :   if (!r.d_isRational)
     167                 :            :   {
     168                 :       4018 :     return r.d_value;
     169                 :            :   }
     170                 :            :   // otherwise, this converts the rational value of r to poly
     171                 :        638 :   const Rational& rr = r.getRationalValue();
     172                 :        638 :   poly::Rational pr = poly_utils::toRational(rr);
     173                 :        638 :   auto dr = poly_utils::toDyadicRational(rr);
     174         [ +  + ]:        638 :   if (dr)
     175                 :            :   {
     176                 :        611 :     return poly::AlgebraicNumber(dr.value());
     177                 :            :   }
     178                 :            :   return poly::AlgebraicNumber(
     179 [ +  + ][ -  - ]:        108 :       poly::UPolynomial({-numerator(pr), denominator(pr)}),
     180                 :         81 :       poly::DyadicInterval(floor(pr), ceil(pr)));
     181                 :        638 : }
     182                 :            : #endif
     183                 :            : 
     184                 :       1700 : bool RealAlgebraicNumber::operator==(const RealAlgebraicNumber& rhs) const
     185                 :            : {
     186                 :            : #ifdef CVC5_POLY_IMP
     187 [ +  + ][ +  - ]:       1700 :   if (!d_isRational || !rhs.d_isRational)
     188                 :            :   {
     189                 :       1700 :     return convertToPoly(*this) == convertToPoly(rhs);
     190                 :            :   }
     191                 :            : #endif
     192                 :          0 :   return getRationalValue() == rhs.getRationalValue();
     193                 :            : }
     194                 :          0 : bool RealAlgebraicNumber::operator!=(const RealAlgebraicNumber& rhs) const
     195                 :            : {
     196                 :          0 :   return !(*this == rhs);
     197                 :            : }
     198                 :         12 : bool RealAlgebraicNumber::operator<(const RealAlgebraicNumber& rhs) const
     199                 :            : {
     200                 :            : #ifdef CVC5_POLY_IMP
     201 [ +  + ][ +  - ]:         12 :   if (!d_isRational || !rhs.d_isRational)
     202                 :            :   {
     203                 :         12 :     return convertToPoly(*this) < convertToPoly(rhs);
     204                 :            :   }
     205                 :            : #endif
     206                 :          0 :   return getRationalValue() < rhs.getRationalValue();
     207                 :            : }
     208                 :        152 : bool RealAlgebraicNumber::operator<=(const RealAlgebraicNumber& rhs) const
     209                 :            : {
     210                 :            : #ifdef CVC5_POLY_IMP
     211 [ +  - ][ +  - ]:        152 :   if (!d_isRational || !rhs.d_isRational)
     212                 :            :   {
     213                 :        152 :     return convertToPoly(*this) <= convertToPoly(rhs);
     214                 :            :   }
     215                 :            : #endif
     216                 :          0 :   return getRationalValue() <= rhs.getRationalValue();
     217                 :            : }
     218                 :          0 : bool RealAlgebraicNumber::operator>(const RealAlgebraicNumber& rhs) const
     219                 :            : {
     220                 :          0 :   return rhs < *this;
     221                 :            : }
     222                 :        152 : bool RealAlgebraicNumber::operator>=(const RealAlgebraicNumber& rhs) const
     223                 :            : {
     224                 :        152 :   return rhs <= *this;
     225                 :            :   ;
     226                 :            : }
     227                 :            : 
     228                 :          3 : RealAlgebraicNumber RealAlgebraicNumber::operator+(
     229                 :            :     const RealAlgebraicNumber& rhs) const
     230                 :            : {
     231                 :            : #ifdef CVC5_POLY_IMP
     232                 :            :   // if either is poly, we convert both and return the result
     233 [ -  + ][ -  - ]:          3 :   if (!d_isRational || !rhs.d_isRational)
     234                 :            :   {
     235                 :          6 :     return convertToPoly(*this) + convertToPoly(rhs);
     236                 :            :   }
     237                 :            : #endif
     238                 :          0 :   return getRationalValue() + rhs.getRationalValue();
     239                 :            : }
     240                 :          0 : RealAlgebraicNumber RealAlgebraicNumber::operator-(
     241                 :            :     const RealAlgebraicNumber& rhs) const
     242                 :            : {
     243                 :            : #ifdef CVC5_POLY_IMP
     244 [ -  - ][ -  - ]:          0 :   if (!d_isRational || !rhs.d_isRational)
     245                 :            :   {
     246                 :          0 :     return convertToPoly(*this) - convertToPoly(rhs);
     247                 :            :   }
     248                 :            : #endif
     249                 :          0 :   return getRationalValue() - rhs.getRationalValue();
     250                 :            : }
     251                 :    3558670 : RealAlgebraicNumber RealAlgebraicNumber::operator-() const
     252                 :            : {
     253                 :            : #ifdef CVC5_POLY_IMP
     254         [ +  + ]:    3558670 :   if (!d_isRational)
     255                 :            :   {
     256                 :         20 :     return -getValue();
     257                 :            :   }
     258                 :            : #endif
     259                 :    7117320 :   return -getRationalValue();
     260                 :            : }
     261                 :     147806 : RealAlgebraicNumber RealAlgebraicNumber::operator*(
     262                 :            :     const RealAlgebraicNumber& rhs) const
     263                 :            : {
     264                 :            : #ifdef CVC5_POLY_IMP
     265 [ +  + ][ -  + ]:     147806 :   if (!d_isRational || !rhs.d_isRational)
     266                 :            :   {
     267                 :        142 :     return convertToPoly(*this) * convertToPoly(rhs);
     268                 :            :   }
     269                 :            : #endif
     270                 :     295470 :   return getRationalValue() * rhs.getRationalValue();
     271                 :            : }
     272                 :     432435 : RealAlgebraicNumber RealAlgebraicNumber::operator/(
     273                 :            :     const RealAlgebraicNumber& rhs) const
     274                 :            : {
     275 [ -  + ][ -  + ]:     432435 :   Assert(!rhs.isZero()) << "Can not divide by zero";
                 [ -  - ]
     276                 :            : #ifdef CVC5_POLY_IMP
     277 [ +  + ][ +  + ]:     432435 :   if (!d_isRational || !rhs.d_isRational)
     278                 :            :   {
     279                 :         22 :     return convertToPoly(*this) / convertToPoly(rhs);
     280                 :            :   }
     281                 :            : #endif
     282                 :     864848 :   return getRationalValue() / rhs.getRationalValue();
     283                 :            : }
     284                 :            : 
     285                 :     726888 : RealAlgebraicNumber& RealAlgebraicNumber::operator+=(
     286                 :            :     const RealAlgebraicNumber& rhs)
     287                 :            : {
     288                 :            : #ifdef CVC5_POLY_IMP
     289 [ +  + ][ +  + ]:     726888 :   if (!d_isRational || !rhs.d_isRational)
     290                 :            :   {
     291                 :         78 :     getValue() = convertToPoly(*this) + convertToPoly(rhs);
     292                 :            :     // ensure it is no longer marked as rational
     293                 :         78 :     d_isRational = false;
     294                 :         78 :     return *this;
     295                 :            :   }
     296                 :            : #endif
     297                 :     726810 :   getRationalValue() = getRationalValue() + rhs.getRationalValue();
     298                 :     726810 :   return *this;
     299                 :            : }
     300                 :          0 : RealAlgebraicNumber& RealAlgebraicNumber::operator-=(
     301                 :            :     const RealAlgebraicNumber& rhs)
     302                 :            : {
     303                 :            : #ifdef CVC5_POLY_IMP
     304 [ -  - ][ -  - ]:          0 :   if (!d_isRational || !rhs.d_isRational)
     305                 :            :   {
     306                 :          0 :     getValue() = convertToPoly(*this) - convertToPoly(rhs);
     307                 :            :     // ensure it is no longer marked as rational
     308                 :          0 :     d_isRational = false;
     309                 :          0 :     return *this;
     310                 :            :   }
     311                 :            : #endif
     312                 :          0 :   getRationalValue() = getRationalValue() - rhs.getRationalValue();
     313                 :          0 :   return *this;
     314                 :            : }
     315                 :   17493058 : RealAlgebraicNumber& RealAlgebraicNumber::operator*=(
     316                 :            :     const RealAlgebraicNumber& rhs)
     317                 :            : {
     318                 :            : #ifdef CVC5_POLY_IMP
     319 [ +  + ][ +  + ]:   17493058 :   if (!d_isRational || !rhs.d_isRational)
     320                 :            :   {
     321                 :        301 :     getValue() = convertToPoly(*this) * convertToPoly(rhs);
     322                 :            :     // ensure it is no longer marked as rational
     323                 :        301 :     d_isRational = false;
     324                 :        301 :     return *this;
     325                 :            :   }
     326                 :            : #endif
     327                 :   17492757 :   getRationalValue() = getRationalValue() * rhs.getRationalValue();
     328                 :   17492757 :   return *this;
     329                 :            : }
     330                 :            : 
     331                 :    4205181 : int RealAlgebraicNumber::sgn() const
     332                 :            : {
     333                 :            : #ifdef CVC5_POLY_IMP
     334         [ +  + ]:    4205181 :   if (!d_isRational)
     335                 :            :   {
     336                 :          2 :     return poly::sgn(getValue());
     337                 :            :   }
     338                 :            : #endif
     339                 :    4205179 :   return getRationalValue().sgn();
     340                 :            : }
     341                 :   18826718 : bool RealAlgebraicNumber::isZero() const
     342                 :            : {
     343                 :            : #ifdef CVC5_POLY_IMP
     344         [ +  + ]:   18826718 :   if (!d_isRational)
     345                 :            :   {
     346                 :        210 :     return poly::is_zero(getValue());
     347                 :            :   }
     348                 :            : #endif
     349                 :   18826508 :   return getRationalValue().isZero();
     350                 :            : }
     351                 :     761881 : bool RealAlgebraicNumber::isOne() const
     352                 :            : {
     353                 :            : #ifdef CVC5_POLY_IMP
     354         [ +  + ]:     761881 :   if (!d_isRational)
     355                 :            :   {
     356                 :          1 :     return poly::is_one(getValue());
     357                 :            :   }
     358                 :            : #endif
     359                 :     761880 :   return getRationalValue().isOne();
     360                 :            : }
     361                 :          0 : RealAlgebraicNumber RealAlgebraicNumber::inverse() const
     362                 :            : {
     363                 :          0 :   Assert(!isZero()) << "Can not invert zero";
     364                 :            : #ifdef CVC5_POLY_IMP
     365         [ -  - ]:          0 :   if (!d_isRational)
     366                 :            :   {
     367                 :          0 :     return poly::inverse(getValue());
     368                 :            :   }
     369                 :            : #endif
     370                 :          0 :   return getRationalValue().inverse();
     371                 :            : }
     372                 :            : 
     373                 :       1030 : size_t RealAlgebraicNumber::hash() const
     374                 :            : {
     375                 :            : #ifdef CVC5_POLY_IMP
     376         [ +  - ]:       1030 :   if (!d_isRational)
     377                 :            :   {
     378                 :       1030 :     return lp_algebraic_number_hash_approx(getValue().get_internal(), 2);
     379                 :            :   }
     380                 :            : #endif
     381                 :          0 :   return getRationalValue().hash();
     382                 :            : }
     383                 :            : 
     384                 :          4 : std::ostream& operator<<(std::ostream& os, const RealAlgebraicNumber& ran)
     385                 :            : {
     386                 :          4 :   return os << ran.toString();
     387                 :            : }
     388                 :            : 
     389                 :            : }  // namespace cvc5::internal
     390                 :            : 
     391                 :            : namespace std {
     392                 :       1030 : size_t hash<cvc5::internal::RealAlgebraicNumber>::operator()(
     393                 :            :     const cvc5::internal::RealAlgebraicNumber& ran) const
     394                 :            : {
     395                 :       1030 :   return ran.hash();
     396                 :            : }
     397                 :            : 
     398                 :            : }  // namespace std

Generated by: LCOV version 1.14