]> www.ginac.de Git - ginac.git/blobdiff - ginac/factor.cpp
[BUGFIX] Fix crash in parser.
[ginac.git] / ginac / factor.cpp
index 987ba16847bbd314283942c9873f8df464832b30..efe438eae8c59e658cd7553d2867aa42c71556b3 100644 (file)
@@ -33,7 +33,7 @@
  */
 
 /*
- *  GiNaC Copyright (C) 1999-2022 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2024 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -158,6 +158,11 @@ template<typename T> static typename T::value_type lcoeff(const T& p)
        return p[p.size() - 1];
 }
 
+/** Make the polynomial unit normal (having unit normal leading coefficient).
+ *
+ *  @param[in, out] a  polynomial to make unit normal
+ *  @return            true if polynomial a was already unit normal, false otherwise
+ */
 static bool normalize_in_field(umodpoly& a)
 {
        if (a.size() == 0)
@@ -172,55 +177,23 @@ static bool normalize_in_field(umodpoly& a)
        return false;
 }
 
+/** Remove leading zero coefficients from polynomial.
+ *
+ *  @param[in, out] p     polynomial from which the zero leading coefficients will be removed
+ *  @param[in]      hint  assume all coefficients of order ≥ hint are zero
+ */
 template<typename T> static void
 canonicalize(T& p, const typename T::size_type hint = std::numeric_limits<typename T::size_type>::max())
 {
-       if (p.empty())
-               return;
+       std::size_t i = min(p.size(), hint);
 
-       std::size_t i = p.size() - 1;
-       // Be fast if the polynomial is already canonicalized
-       if (!zerop(p[i]))
-               return;
-
-       if (hint < p.size())
-               i = hint;
+       while ( i-- && zerop(p[i]) ) { }
 
-       bool is_zero = false;
-       do {
-               if (!zerop(p[i])) {
-                       ++i;
-                       break;
-               }
-               if (i == 0) {
-                       is_zero = true;
-                       break;
-               }
-               --i;
-       } while (true);
-
-       if (is_zero) {
-               p.clear();
-               return;
-       }
-
-       p.erase(p.begin() + i, p.end());
+       p.erase(p.begin() + i + 1, p.end());
 }
 
 // END COPY FROM UPOLY.H
 
-static void expt_pos(umodpoly& a, unsigned int q)
-{
-       if ( a.empty() ) return;
-       cl_MI zero = a[0].ring()->zero(); 
-       int deg = degree(a);
-       a.resize(degree(a)*q+1, zero);
-       for ( int i=deg; i>0; --i ) {
-               a[i*q] = a[i];
-               a[i] = zero;
-       }
-}
-
 template<typename T> struct uvar_poly_p
 {
        static const bool value = false;
@@ -482,12 +455,12 @@ static umodpoly umodpoly_to_umodpoly(const umodpoly& a, const cl_modint_ring& R,
        return e;
 }
 
-/** Divides all coefficients of the polynomial a by the integer x.
+/** Divides all coefficients of the polynomial a by the positive integer x.
  *  All coefficients are supposed to be divisible by x. If they are not, the
- *  the<cl_I> cast will raise an exception.
+ *  division will raise an exception.
  *
  *  @param[in,out] a  polynomial of which the coefficients will be reduced by x
- *  @param[in]     x  integer that divides the coefficients
+ *  @param[in]     x  positive integer that divides the coefficients
  */
 static void reduce_coeff(umodpoly& a, const cl_I& x)
 {
@@ -497,7 +470,7 @@ static void reduce_coeff(umodpoly& a, const cl_I& x)
        for (auto & i : a) {
                // cln cannot perform this division in the modular field
                cl_I c = R->retract(i);
-               i = cl_MI(R, the<cl_I>(c / x));
+               i = cl_MI(R, exquopos(c, x));
        }
 }
 
@@ -527,7 +500,7 @@ static void rem(const umodpoly& a, const umodpoly& b, umodpoly& r)
        } while ( k-- );
 
        fill(r.begin()+n, r.end(), a[0].ring()->zero());
-       canonicalize(r);
+       canonicalize(r, n);
 }
 
 /** Calculates quotient of a/b.
@@ -638,7 +611,6 @@ static void deriv(const umodpoly& a, umodpoly& d)
 
 static bool unequal_one(const umodpoly& a)
 {
-       if ( a.empty() ) return true;
        return ( a.size() != 1 || a[0] != a[0].ring()->one() );
 }
 
@@ -664,6 +636,26 @@ static bool squarefree(const umodpoly& a)
        return equal_one(c);
 }
 
+/** Computes w^q mod a.
+ *  Uses theorem 2.1 from A.K.Lenstra's PhD thesis; see exercise 8.13 in [GCL].
+ *
+ *  @param[in]  w  polynomial
+ *  @param[in]  a  modulus polynomial
+ *  @param[in]  q  common modulus of w and a
+ *  @param[out] r  result
+ */
+static void expt_pos_Q(const umodpoly& w, const umodpoly& a, unsigned int q, umodpoly& r)
+{
+       if ( w.empty() ) return;
+       cl_MI zero = w[0].ring()->zero();
+       int deg = degree(w);
+       umodpoly buf(deg*q+1, zero);
+       for ( size_t i=0; i<=deg; ++i ) {
+               buf[i*q] = w[i];
+       }
+       rem(buf, a, r);
+}
+
 // END modular univariate polynomial code
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -962,9 +954,9 @@ static void berlekamp(const umodpoly& a, upvec& upv)
 
 /** Calculates a^(1/prime).
  *  
- *  @param[in] a      polynomial
- *  @param[in] prime  prime number -> exponent 1/prime
- *  @param[in] ap     resulting polynomial
+ *  @param[in]  a      polynomial
+ *  @param[in]  prime  prime number -> exponent 1/prime
+ *  @param[out] ap     resulting polynomial
  */
 static void expt_1_over_p(const umodpoly& a, unsigned int prime, umodpoly& ap)
 {
@@ -1047,23 +1039,17 @@ static void distinct_degree_factor(const umodpoly& a_, vector<int>& degrees, upv
        int nhalf = degree(a)/2;
 
        int i = 1;
-       umodpoly w(2);
-       w[0] = R->zero();
-       w[1] = R->one();
+       umodpoly w = {R->zero(), R->one()};
        umodpoly x = w;
 
        while ( i <= nhalf ) {
-               expt_pos(w, q);
                umodpoly buf;
-               rem(w, a, buf);
+               expt_pos_Q(w, a, q, buf);
                w = buf;
-               umodpoly wx = w - x;
-               gcd(a, wx, buf);
+               gcd(a, w - x, buf);
                if ( unequal_one(buf) ) {
                        degrees.push_back(i);
                        ddfactors.push_back(buf);
-               }
-               if ( unequal_one(buf) ) {
                        umodpoly buf2;
                        div(a, buf, buf2);
                        a = buf2;
@@ -1235,7 +1221,7 @@ static void hensel_univar(const upoly& a_, unsigned int p, const umodpoly& u1_,
 
        // calc bound B
        int maxdeg = (degree(u1_) > degree(w1_)) ? degree(u1_) : degree(w1_);
-       cl_I maxmodulus = calc_bound(a) * ash(cl_I(1), maxdeg+1);  // 2 * calc_bound(a) * 2^maxdeg
+       cl_I maxmodulus = ash(calc_bound(a), maxdeg+1);  // = 2 * calc_bound(a) * 2^maxdeg
 
        // step 1
        cl_I alpha = lcoeff(a);
@@ -1303,35 +1289,29 @@ static void hensel_univar(const upoly& a_, unsigned int p, const umodpoly& u1_,
        }
 }
 
-/** Returns a new prime number.
+/** Returns a new small prime number.
  *
- *  @param[in] p  prime number
- *  @return       next prime number after p
+ *  @param[in] n  an integer
+ *  @return       smallest prime greater than n
  */
-static unsigned int next_prime(unsigned int p)
-{
-       static vector<unsigned int> primes;
-       if (primes.empty()) {
-               primes = {3, 5, 7};
-       }
-       if ( p >= primes.back() ) {
-               unsigned int candidate = primes.back() + 2;
-               while ( true ) {
-                       size_t n = primes.size()/2;
-                       for ( size_t i=0; i<n; ++i ) {
-                               if (candidate % primes[i])
-                                       continue;
-                               candidate += 2;
-                               i=-1;
-                       }
-                       primes.push_back(candidate);
-                       if (candidate > p)
+static unsigned int next_prime(unsigned int n)
+{
+       static vector<unsigned int> primes = {2, 3, 5, 7};
+       unsigned int candidate = primes.back();
+       while (primes.back() <= n) {
+               candidate += 2;
+               bool is_prime = true;
+               for (size_t i=1; primes[i]*primes[i]<=candidate; ++i) {
+                       if (candidate % primes[i] == 0) {
+                               is_prime = false;
                                break;
+                       }
                }
-               return candidate;
+               if (is_prime)
+                       primes.push_back(candidate);
        }
        for (auto & it : primes) {
-               if ( it > p ) {
+               if ( it > n ) {
                        return it;
                }
        }
@@ -2285,8 +2265,9 @@ struct factorization_ctx {
                                        numeric prefac = ex_to<numeric>(ufaclst[i+1].lcoeff(x));
                                        for ( int j=ftilde.size()-1; j>=0; --j ) {
                                                int count = 0;
-                                               while ( irem(prefac, ftilde[j]) == 0 ) {
-                                                       prefac = iquo(prefac, ftilde[j]);
+                                               numeric q;
+                                               while ( irem(prefac, ftilde[j], q) == 0 ) {
+                                                       prefac = q;
                                                        ++count;
                                                }
                                                if ( count ) {
@@ -2301,8 +2282,9 @@ struct factorization_ctx {
                                        numeric prefac = ex_to<numeric>(ufaclst[i+1].lcoeff(x));
                                        for ( int j=ftilde.size()-1; j>=0; --j ) {
                                                int count = 0;
-                                               while ( irem(prefac, ftilde[j]) == 0 ) {
-                                                       prefac = iquo(prefac, ftilde[j]);
+                                               numeric q;
+                                               while ( irem(prefac, ftilde[j], q) == 0 ) {
+                                                       prefac = q;
                                                        ++count;
                                                }
                                                while ( irem(ex_to<numeric>(delta)*prefac, ftilde[j]) == 0 ) {
@@ -2341,13 +2323,10 @@ struct factorization_ctx {
                }
 
                // set up evaluation points
-               EvalPoint ep;
                vector<EvalPoint> epv;
                auto s = syms_wox.begin();
                for ( size_t i=0; i<a.size(); ++i ) {
-                       ep.x = *s++;
-                       ep.evalpoint = a[i].to_int();
-                       epv.push_back(ep);
+                       epv.emplace_back(EvalPoint{*s++, a[i].to_int()});
                }
 
                // calc bound p^l
@@ -2357,7 +2336,7 @@ struct factorization_ctx {
                                maxdeg = ufaclst[i].degree(x);
                        }
                }
-               cl_I B = calc_bound(u, x) * ash(cl_I(1), maxdeg+1);  // 2 * calc_bound(u,x) * 2^maxdeg
+               cl_I B = ash(calc_bound(u, x), maxdeg+1);  // = 2 * calc_bound(u,x) * 2^maxdeg
                cl_I l = 1;
                cl_I pl = prime;
                while ( pl < B ) {
@@ -2401,8 +2380,7 @@ static ex factor_multivariate(const ex& poly, const exset& syms)
                copy_if(syms.begin(), syms.end(),
                        inserter(syms_wox, syms_wox.end()), [x](const ex& y){ return y != x; });
 
-               factorization_ctx ctx = {.poly = poly, .x = x,
-                                        .syms_wox = syms_wox};
+               factorization_ctx ctx{poly, x, syms_wox};
 
                // make polynomial primitive
                poly.unitcontprim(x, ctx.unit, ctx.cont, ctx.pp);
@@ -2415,7 +2393,7 @@ static ex factor_multivariate(const ex& poly, const exset& syms)
                ctx.vn = ctx.pp.collect(x).lcoeff(x);
                ctx.vnlst = put_factors_into_vec(factor(ctx.vn));
 
-               ctx.modulus = (ctx.vnlst.size() > 3) ? ctx.vnlst.size() : 3;
+               ctx.modulus = (ctx.vnlst.size() > 3) ? ctx.vnlst.size() : numeric(3);
 
                ctx_in_x.push_back(ctx);
        }