carl  24.04
Computer ARithmetic Library
MultivariateHensel.h
Go to the documentation of this file.
1 /**
2  * @file: MultivariateHensel.h
3  * @author: Sebastian Junges
4  *
5  * @since October 14, 2013
6  */
7 
8 #pragma once
10 #include "../UnivariatePolynomial.h"
12 #include <list>
13 
14 
15 namespace carl
16 {
17 
18 /**
19  * Includes the algorithms 6.2 and 6.3 from the book
20  * Algorithms for Computer Algebra by Geddes, Czaper, Labahn.
21  *
22  * The Algorithms are used to computer the Multivariate GCD.
23  */
24 template<typename Integer>
26 {
31 
32  public:
33  DiophantineEquations(unsigned p, unsigned k) :
34  mGf_pk(GaloisFieldManager<Integer>::getInstance().field(p,k)),
35  mGf_p(GaloisFieldManager<Integer>::getInstance().field(p))
36  {
37 
38  }
39  /**
40  * Solve in the domain Z_(p^k)[x_!,...,x_v] the multivariate polynomial
41  * diophantine equation
42  * sigma_1 * b_1 + ... sigma_r * b_r = c (mod <I^(d+1), p^k>)
43  * where, in terms of the given list of polynomials a_1,...,a_r
44  * the polynomials b_i, i = 1,...,r, are defined by:
45  * b_i = a_1 * ... * a_(i-1) * a_(i+1) * ... * a_r.
46  * The unique solution sigma_i, i = 1,...,r, will be computed such that
47  * degree(sigma_i,x_i) < degree(a_i,x_1).
48  *
49  * Conditions:
50  * (1) p must not divide lcoeff(a_i mod I), i = 1,...,r;
51  * (2) A_i mod <I,p>, i = 1,...,r, must be pairwise relatively prime
52  * in Z_p[x_1];
53  * (3) degree(c,x_1) < sum(degree(a_i,x_1), i = 1,...,r)
54  *
55  * The prime integer p and the positive integer k must bei specified in
56  * the constructor.
57  *
58  * @param a A list a of r > 1 polynomials in the domain Z_(p^k)[x_1,...,x_v].
59  * @param c A polynomial c from Z_(p^k)[x_1,...,x_v].
60  * @param I A list of equations [x_2 = alpha_2,...,x_v = alpha_v].
61  * @param d A nonnegative integer d specifying the maximum total degree
62  * with respect to x_2,...,x_v of the desired result.
63  * @return The list sigma = [sigma_1,...,sigma_r].
64  */
65  std::vector<Polynomial> solveMultivariateDiophantine(
66  const std::vector<Polynomial>& a, // must be of type MultiPoly??
67  const MultiPoly& c,
68  const std::map<Variable, GFNumber<Integer>>& I, // should be Integer instead of GFNumber<Integer> ??
69  unsigned d) const
70  {
71  // TODO: check the conditions
72  assert(a.size() > (unsigned)1);
73  size_t r = a.size();
74  size_t v = I.size() + 1;
75  Variable x_v = I.rend()->first;
76  Integer alpha_v = I.rend()->second;
77  if(v > 1) {
78  // Multivariate case
80  // A = product(a_i, i = 1,...,r)
81  MultiPoly A;
82  A = MultiPoly(1);
83  for(unsigned i = 1; i <= r; i++) {
84  A = A * a[i];
85  }
86  // b_j = A / a_j
87  std::vector<MultiPoly> b;
88  for(unsigned j = 1; j <= r; j++) {
89  b[j] = A / Multipoly(a[j]);
90  }
91  // a_new = substitute(x_v = alpha_v, a)
92  std::vector<Polynomial> a_new;
93  for(unsigned i = 1; i <= r; i++) {
94  a_new.pushBack(substitute(a[i], x_v, alpha_v));
95  }
96  // c_new = substitute(x_v = alpha_v, c);
97  Polynomial c_new = substitute(c,x_v, alpha_v);
98  // I_new = updated list I with x_v = alpha_v deleted
99  std::map<Variable, GFNumber<Integer>> I_new(I);
100  I_new.erase(x_v);
101  // sigma = MultivariateDiohant(a_new,c_new,I_new,d,p,k)
102  std::vector<Polynomial> sigma = MultivariateDiophant(a_new, c_new, I_new, d);
103  // e = (c - sum(sigma_i * b_i, i = 1,...,r))) mod p^k
104  // note that the mod p^k operation is performed automatically
105  MultiPoly e(c);
106  for(unsigned i = 1; i <= r; i++) {
107  c -= sigma[i] * b[i];
108  }
109  // monomial = 1
110  for(unsigned m = 1; m <= d; m++) {
111  if(e == 0) break;
112 
113 
114  }
115  }
116  else {
117  // Univariate Case
118  /// @todo implement
119  // the list of equations is empty, a contains univarate polnomials
120  //Variable x_1 = a[0].main_var();
121  // sigma = zero lost of length r
122  std::vector<Polynomial> sigma(r, Polynomial(0));
123  for(auto& z : c.terms()) {
124 
125  }
126  }
127  //Prvent warning
128  return {};
129  }
130 
131  /**
132  * Solve in Z_(p^k)[x] the univariate polynomial Diophantine equation:
133  * s_1 x b_1 + ... s_r x b_r === x^m (mod p^k)
134  * where in terms of the given list a: [a_1, ... a_r] the polynomials b_i
135  * for i = 1...r are defined by:
136  * b_i = a_1 x ... x a_{i-1} x a_{i+1} x ... x a_r
137  * The unique solution s_1,... s_r, will be computed such that deg(s_i) < deg(a_i).
138  */
139  std::vector<Polynomial> univariateDiophantine(const std::vector<Polynomial>& a, Variable::Arg x, unsigned m) const
140  {
141  assert(a.size() > 1);
142  Polynomial xm(x,GFNumber<Integer>(1, mGf_pk),m);
143  if(a.size() == 2)
144  {
145  std::vector<Polynomial> s = EEAlift(a.back(), a.front());
146  DivisionResult<Polynomial> d = (xm * s.front()).divideBy(a.front());
147  Polynomial q = d.quotient.normalizeCoefficients();
148  return { d.remainder.normalizeCoefficients(), (xm * s.back() + q * a.back()).normalizeCoefficients() };
149  }
150  else
151  {
152  assert(a.size() > 2);
153  std::vector<Polynomial> s = MultiTermEEAlift(a);
154  assert(a.size() == s.size());
155  std::vector<Polynomial> res;
156  for(unsigned j = 0; j < s.size(); ++j)
157  {
158  res.push_back( (xm * s.at(j)).remainder(a.at(j)).normalizeCoefficients());
159  }
160  return res;
161  }
162  }
163  private:
164  std::vector<Polynomial> MultiTermEEAlift(const std::vector<Polynomial>& a) const
165  {
166  assert(a.size() > 2);
167  const Variable& x = a.front().main_var();
168  size_t r = a.size();
169 
170  std::vector<Polynomial> q(r,Polynomial(x));
171  q[r-1] = a.back();
172  // TODO this folding should be more elegant..
173  for(size_t j = r - 2; j < r-1; --j)
174  {
175  q[j] = a[j+1] * q[j+1];
176  }
177  std::vector<Polynomial> s;
178  Polynomial beta(x,GFNumber<Integer>(1,mGf_pk),0);
179  for(unsigned j = 0; j < r-1; ++j)
180  {
181  std::vector<Polynomial> sigma = solveMultivariateDiophantine({q.at(j), a.at(j)}, beta, std::map<Variable, Integer>(), (unsigned)0);
182  assert(sigma.size() == 2);
183  beta = sigma.front();
184  s.push_back(sigma.back());
185  }
186  s.push_back(beta);
187 
188  assert(s.size() == a.size());
189  return s;
190  }
191 
192  /**
193  * EEAlift computes s,t such that s*a + tb == 1 (mod p^k)
194  * with deg(s) < deg(b) and deg(t) < deg(a).
195  * Assumption GCD(a mod p, b mod p) = 1 in Z_p[x]
196  * @param a Polynomial in Z_p^k[x]
197  * @param b Polynomial in Z_p^k[x]
198  * @return
199  */
200  std::vector<Polynomial> EEAlift(Polynomial a, Polynomial b) const
201  {
202  assert(a.main_var() == b.main_var());
203  CARL_LOG_DEBUG("carl.core.hensel", "EEALIFT: a=" << a << ", b=" << b );
204  const Variable& x = a.main_var();
205  Polynomial amodp = a.toFiniteDomain(mGf_p);
206  Polynomial bmodp = b.toFiniteDomain(mGf_p);
207  CARL_LOG_DEBUG("carl.core.hensel", "EEALIFT: a mod p=" << amodp << ", b mod p=" << bmodp );
208  Polynomial s(x);
209  Polynomial t(x);
210  Polynomial g(x);
211  g = Polynomial::extended_gcd(amodp,bmodp,s,t);
212  CARL_LOG_DEBUG("carl.core.hensel", "EEALIFT: g=" << g << ", s=" << s << ", t=" << t );
213  CARL_LOG_ASSERT("carl.core.hensel", g.is_one(), "g expected to be one");
214  Polynomial smodp = s;
215  Polynomial tmodp = t;
216  assert( mGf_p->p() == mGf_pk->p());
217  Integer p = mGf_p->p();
218  Integer modulus = p;
219  Polynomial c(x);
220  for(unsigned j=1; j<mGf_pk->k(); ++j)
221  {
222  // TODO check moduli.
223  // e = 1 - s*a - t*b. // c = (e/modulus) mod p.
224  GFNumber<Integer> one(1,mGf_pk);
225  c = -s*a-t*b+one;
227  cf /= modulus;
228  c = cf.toFiniteDomain(mGf_p);
229  Polynomial sigmaprime = smodp * c;
230  Polynomial tauprime = tmodp * c;
231  DivisionResult<Polynomial> d = sigmaprime.divideBy(bmodp);
232  Polynomial q = d.quotient.normalizeCoefficients();
233  Polynomial sigma = d.remainder.normalizeCoefficients();
234  Polynomial tau = (tauprime + q * amodp).normalizeCoefficients();
235  s += sigma*modulus;
236  t += tau*modulus;
237  modulus *= p;
238  }
239  assert((s.toFiniteDomain(mGf_pk)*a + t.toFiniteDomain(mGf_pk)*b).is_one());
240  return {s,t};
241  }
242 };
243 
244 template<typename Coeff, typename Ordering, typename Policies>
246 {
247  typedef Coeff Integer;
249 
250 
251  static std::list<UnivReprPol> calculate(const UnivReprPol& , const std::map<Variable, Coeff>& , Integer )
252  {
253 
254  }
255  //{}
256 };
257 }
A small wrapper that configures logging for carl.
#define CARL_LOG_ASSERT(channel, condition, msg)
Definition: carl-logging.h:47
#define CARL_LOG_DEBUG(channel, msg)
Definition: carl-logging.h:43
#define CARL_LOG_NOTIMPLEMENTED()
Definition: carl-logging.h:48
mpz_class Integer
carl is the main namespace for the library.
UnivariatePolynomial< Coeff > extended_gcd(const UnivariatePolynomial< Coeff > &a, const UnivariatePolynomial< Coeff > &b, UnivariatePolynomial< Coeff > &s, UnivariatePolynomial< Coeff > &t)
Calculates the extended greatest common divisor g of two polynomials.
typename UnderlyingNumberType< P >::type Coeff
Coeff substitute(const Monomial &m, const std::map< Variable, Coeff > &substitutions)
Applies the given substitutions to a monomial.
Definition: Substitution.h:19
A Variable represents an algebraic variable that can be used throughout carl.
Definition: Variable.h:85
BaseIntType p() const noexcept
Returns the p from Z_{p^k}.
Definition: GaloisField.h:61
BaseIntType k() const noexcept
Returns the k from Z_{p^k}.
Definition: GaloisField.h:69
Galois Field numbers, i.e.
Definition: GFNumber.h:21
This class represents a univariate polynomial with coefficients of an arbitrary type.
Variable main_var() const
Retrieves the main variable of this polynomial.
bool is_one() const
Checks if the polynomial is equal to one.
UnivariatePolynomial< typename IntegralType< Coefficient >::type > to_integer_domain() const
Works only from rationals, if the numbers are already integers.
UnivariatePolynomial< GFNumber< typename IntegralType< Coefficient >::type > > toFiniteDomain(const GaloisField< typename IntegralType< Coefficient >::type > *galoisField) const
The general-purpose multivariate polynomial class.
const TermsType & terms() const
A strongly typed pair encoding the result of a division, being a quotient and a remainder.
Definition: Division.h:16
Includes the algorithms 6.2 and 6.3 from the book Algorithms for Computer Algebra by Geddes,...
const GaloisField< Integer > * mGf_p
std::vector< Polynomial > MultiTermEEAlift(const std::vector< Polynomial > &a) const
DiophantineEquations(unsigned p, unsigned k)
std::vector< Polynomial > EEAlift(Polynomial a, Polynomial b) const
EEAlift computes s,t such that s*a + tb == 1 (mod p^k) with deg(s) < deg(b) and deg(t) < deg(a).
const GaloisField< Integer > * mGf_pk
MultivariatePolynomial< GFNumber< Integer > > MultiPoly
std::vector< Polynomial > solveMultivariateDiophantine(const std::vector< Polynomial > &a, const MultiPoly &c, const std::map< Variable, GFNumber< Integer >> &I, unsigned d) const
Solve in the domain Z_(p^k)[x_!,...,x_v] the multivariate polynomial diophantine equation sigma_1 * b...
std::vector< Polynomial > univariateDiophantine(const std::vector< Polynomial > &a, Variable::Arg x, unsigned m) const
Solve in Z_(p^k)[x] the univariate polynomial Diophantine equation: s_1 x b_1 + .....
UnivariatePolynomial< GFNumber< Integer > > Polynomial
UnivariatePolynomial< MultivariatePolynomial< Coeff, Ordering, Policies > > UnivReprPol
static std::list< UnivReprPol > calculate(const UnivReprPol &, const std::map< Variable, Coeff > &, Integer)