carl  24.04
Computer ARithmetic Library
DiophantineEquation.tpp
Go to the documentation of this file.
1 /**
2  * @file DiophantineEquation.tpp
3  * @author Tobias Winkler
4  *
5  */
6 
7 #pragma once
8 
9 #include "DiophantineEquation.h"
10 
11 namespace carl {
12 
13 template<typename T>
14 std::vector<T> solveDiophantine(MultivariatePolynomial<T>& p) {
15  static_assert(carl::is_integer_type<T>::value, "Diophantine equations are build from integral coefficients only!");
16  std::vector<T> res;
17  res = std::vector<T>();
18 
19  // use an algorithm for linear equations only
20  if(p.is_linear()) {
21  res = solveLinearDiophantine(p);
22  }
23  else {
24  CARL_LOG_NOTIMPLEMENTED();
25  }
26 
27  return res;
28 }
29 
30 // Finds a single solution of a linear diophantine Equation
31 template<typename T>
32 std::vector<T> solveLinearDiophantine(MultivariatePolynomial<T>& equation) {
33  assert(equation.is_linear());
34  //assert(!equation.is_constant());
35  //assert(equation.hatConstantTerm()); // change this later
36 
37  std::vector<T> res;
38 
39  // if there is no constant part return the trivial solution
40  if(!equation.has_constant_term()){
41  res = std::vector<T>(carl::variables(equation).size(), 0);
42  return res;
43  }
44 
45  T const_part = equation.constant_part();
46 
47  // initialize coefficient vector
48  std::vector<carl::Term<T>> terms = equation.terms();
49  std::vector<T> coeffs = std::vector<T>();
50  for(std::size_t i = 1; i < terms.size(); i++ ) { // terms[0] is the constant part
51  coeffs.push_back(terms[i].coeff());
52  }
53 
54 
55  std::vector<T> fromExtendedGcd = std::vector<T>(1, 1);
56  T currGcd = coeffs[0];
57 
58  if(carl::mod(const_part, coeffs[0]) == 0) {
59  res = std::vector<T>(coeffs.size(), 0);
60  res[0] = -carl::div(const_part, coeffs[0]);
61  return res;
62  }
63  for(std::size_t i = 1; i < coeffs.size(); i++) {
64  T s;
65  T t;
66  currGcd = extended_gcd_integer(currGcd, coeffs[i], s, t);
67  for(auto& r : fromExtendedGcd) {
68  r *= s;
69  }
70  fromExtendedGcd.push_back(t);
71  if(carl::mod(const_part, currGcd) == 0) {
72  T factor = -carl::div(const_part, currGcd);
73  for(auto& r : fromExtendedGcd) {
74  r *= factor;
75  }
76  std::size_t diff = coeffs.size() - fromExtendedGcd.size();
77  for(std::size_t j = 0; j < diff; j++) {
78  fromExtendedGcd.push_back(0);
79  }
80  assert(fromExtendedGcd.size() == coeffs.size());
81  return fromExtendedGcd;
82  }
83  }
84  // no solution exists
85  CARL_LOG_NOTIMPLEMENTED();
86  return std::vector<T>(coeffs.size(), 0);
87 
88 }
89 
90 // implementation of extended euklid for integers
91 template<typename T>
92 T extended_gcd_integer(T a, T b, T& s, T& t) {
93  static_assert(carl::is_integer_type<T>::value, "extended gcd algorithmn is for integral types only!");
94 
95  // gcd(0, 0) := 0
96  if(a == 0 && b == 0) {
97  s = 0; t = 0;
98  return 0;
99  }
100 
101  s = 0;
102  T old_s = 1;
103  t = 1;
104  T old_t = 0;
105  T r = b;
106  T old_r = a;
107  T quotient;
108 
109  T temp;
110 
111  while(r != 0) {
112  quotient = carl::quotient(old_r, r);
113 
114  temp = r;
115  r = old_r - quotient * r;
116  old_r = temp;
117 
118  temp = s;
119  s = old_s - quotient * s;
120  old_s = temp;
121 
122  temp = t;
123  t = old_t - quotient * t;
124  old_t = temp;
125  }
126  // normalize so that the gcd is always positive
127  if(old_r < 0) {
128  old_s = -old_s;
129  old_t = -old_t;
130  old_r = -old_r;
131  }
132  s = old_s;
133  t = old_t;
134  return old_r;
135 }
136 
137 }