SMT-RAT  24.02
Toolbox for Strategic and Parallel Satisfiability-Modulo-Theories Solving
RNSEncoder.cpp
Go to the documentation of this file.
1 #include "RNSEncoder.h"
2 
3 #include <carl-arith/numbers/PrimeFactory.h>
4 
5 namespace smtrat {
6 
7  std::optional<FormulaT> RNSEncoder::doEncode(const ConstraintT& constraint) {
8  std::vector<Integer> base = calculateRNSBase(constraint);
9  if(base.size() != 0 && isNonRedundant(base, constraint)){
10  std::vector<FormulaT> subformulas;
11  for(auto i : base){
12  subformulas.push_back(rnsTransformation(constraint, i));
13  }
14  auto res = FormulaT(carl::FormulaType::AND, std::move(subformulas));
15  SMTRAT_LOG_INFO("smtrat.pbc", constraint << " -> " << res);
16  return res;
17  }
18 
19  return {};
20  }
21 
22  bool RNSEncoder::isNonRedundant(const std::vector<Integer>& base, const ConstraintT& formula) {
23  const auto& cLHS = formula.lhs();
24  Rational max = INT_MIN;
25  Rational sum = 0;
26  Rational product = 1;
27  carl::PrimeFactory<Integer> pFactory;
28 
29 
30  for(auto it : cLHS){
31  if(it.coeff() > max){
32  max = it.coeff();
33  }
34  sum += it.coeff();
35  }
36 
37  for(auto it : base){
38  if(it >= max){
39  return false;
40  }
41  }
42 
43  for(Rational i = 0; i < max; i++){
44  product *= pFactory.next_prime();
45  }
46 
47  if(sum > product){
48  return false;
49  }
50 
51  return true;
52  }
53 
55  const auto& cLHS = formula.lhs();
56  assert(carl::is_integer(formula.lhs().constant_part()));
57  Integer cRHS = carl::get_num(formula.lhs().constant_part());
58  Poly newLHS;
59  Rational newRHS = carl::mod(cRHS, prime);
60 
61 
62  for(const auto& it : cLHS){
63  // TODO actually, we only modify the coefficient. Is it enough to modify the coefficient?
64  assert(carl::is_integer(it.coeff()));
65  Integer newCoeff = carl::mod(carl::get_num(it.coeff()), prime);
66  if(newCoeff != 0){
67  newLHS += TermT(newCoeff, it.single_variable(), 1);
68  }
69  }
70 
71  if(newLHS.size() == 0 && newRHS > 0){
72  return FormulaT(carl::FormulaType::FALSE);
73  }else if(newLHS.size() == 0 && newRHS == 0){
74  return FormulaT(carl::FormulaType::TRUE);
75  }
76 
77  Rational t = 0;
78  for(const auto& it : newLHS){
79  t += it.coeff();
80  }
81  t = carl::floor((t - newRHS) / prime );
82 
83  for(int i = 0; i < t; i++){
84  // newLHS.push_back(std::pair<Rational, carl::Variable>(-t, carl::fresh_variable(carl::VariableType::VT_BOOL)));
85  newLHS += TermT(-t, carl::fresh_boolean_variable(), 1);
86  }
87 
88  ConstraintT newConstraint(newLHS - newRHS, carl::Relation::EQ);
89  // TODO checkFormulaType is not our job, here
90  // return checkFormulaType(FormulaT(newConstraint));
91  return FormulaT(newConstraint);
92  }
93 
94  std::vector<Integer> RNSEncoder::calculateRNSBase(const ConstraintT& formula) {
95  const auto& cLHS = formula.lhs();
96  std::vector<std::pair<int, Integer>> freq;
97  Rational sum = 0;
98  Rational product = 1;
99  std::vector<Integer> base;
100 
101  for(auto it : cLHS){
102  assert(carl::is_integer(it.coeff()));
103  sum += carl::get_num(it.coeff());
104  }
105 
106  for(auto it : cLHS){
107  assert(carl::is_integer(it.coeff()));
108  std::vector<Integer> v = integerFactorization(carl::get_num(it.coeff()));
109  std::sort(v.begin(), v.end());
110  v.erase( unique( v.begin(), v.end() ), v.end() );
111 
112  for(auto i : v){
113  auto elem = std::find_if(freq.begin(), freq.end(),
114  [&] (const std::pair<int, Integer>& elem){
115  return elem.second == i;
116  });
117  if(elem != freq.end()){
118  auto distance = std::distance(freq.begin(), elem);
119  freq[(unsigned long) distance].first = freq[(unsigned long) distance].first + 1;
120  }else{
121  freq.push_back(std::pair<int, Integer>(1, i));
122  }
123  }
124  }
125 
126  std::sort(freq.begin(), freq.end(),
127  [&](const std::pair<int, Integer> &p1, const std::pair<int, Integer> &p2)
128  {
129  if(p1.first == p2.first){
130  return (p1.second < p2.second);
131  }else{
132  return(p1.first > p2.first);
133  }
134  });
135 
136 
137  for(auto it : freq){
138  if(it.second != 0){
139  product *= it.second;
140  if(product <= sum){
141  base.push_back(it.second);
142  }else{
143  base.push_back(it.second);
144  break;
145  }
146  }
147 
148  }
149 
150  for(std::size_t i = 0; i < base.size(); i++){
151  if(base[i] == 1 || base[i] == 0){
152  base.erase(base.begin() + (long) i);
153  }
154  }
155  return base;
156  }
157 
158  std::vector<Integer> RNSEncoder::integerFactorization(const Integer& coeff) {
159  if(coeff <= 100){
160  return mPrimesTable[carl::to_int<carl::uint>(coeff)];
161  }
162 
163  std::vector<Integer> primes;
164  Integer x = carl::ceil(carl::sqrt(coeff));
165  Integer y = (x * x) - coeff;
166  Integer r = carl::floor(carl::sqrt(y));
167 
168  if(coeff % 2 == 0){
169  primes.emplace_back(2);
170  if(coeff / 2 > 2){
171  std::vector<Integer> v = integerFactorization(coeff / 2);
172  primes.insert(primes.end(), v.begin(), v.end());
173  }
174  }else{
175  while(y > r * r){
176  x++;
177  y = (x * x) - coeff;
178  r = carl::floor(carl::sqrt(y));
179  }
180 
181  Integer first = x + r;
182  Integer second = x - r;
183 
184  if(first > 1){
185  if(first <= 100){
186  std::vector<Integer> v = mPrimesTable[carl::to_int<carl::uint>(first)];
187  primes.insert(primes.end(), v.begin(), v.end());
188 
189  }else{
190  carl::PrimeFactory<Integer> pFactory;
191  Integer prime = pFactory[24];
192  while(prime < first){
193  prime = pFactory.next_prime();
194  }
195  if(prime == first){
196  //first is a big prime number
197  primes.push_back(first);
198  }else{
199  //first is not a prime number
200  std::vector<Integer> v = integerFactorization(first);
201  primes.insert(primes.end(), v.begin(), v.end());
202  }
203  }
204  }
205 
206  if(second > 1){
207  if(second <= 100){
208  std::vector<Integer> v = mPrimesTable[carl::to_int<carl::uint>(second)];
209  primes.insert(primes.end(), v.begin(), v.end());
210  }else{
211  carl::PrimeFactory<Integer> pFactory;
212  Integer prime = pFactory[24];
213  while(prime < second){
214  prime = pFactory.next_prime();
215  }
216  if(prime == second){
217  //second is a big prime number
218  primes.push_back(second);
219  }else{
220  //second is not a prime number
221  std::vector<Integer> v = integerFactorization(second);
222  primes.insert(primes.end(), v.begin(), v.end());
223  }
224  }
225  }
226  }
227  return primes;
228  }
229 
230  bool RNSEncoder::canEncode(const ConstraintT&) {
231  return false;
232  }
233 
234  std::vector<std::vector<Integer>> RNSEncoder::primesTable() {
235  //The 0 and 1 MUST be here in order to pick the right factorization!
236  return {{0}, {1}, {2}, {3}, {2, 2}, {5}, {2, 3}, {7}, {2, 2, 2}, {3, 3}, {2, 5}, {11}, {2, 2, 3},
237  {13}, {2, 7}, {3, 5}, {2, 2, 2, 2}, {17}, {2, 3, 3}, {19}, {2, 2, 5}, {3, 7}, {2, 11},
238  {23}, {2, 2, 2, 3}, {5, 5}, {2, 13}, {3, 3, 3}, {2, 2, 7}, {29}, {2, 3, 5}, {31},
239  {2, 2, 2, 2, 2}, {3, 11}, {2, 17}, {5, 7}, {2, 2, 3, 3}, {37}, {2, 19}, {3, 13}, {2, 2, 2, 5},
240  {41}, {2, 3, 7}, {43}, {2, 2, 11}, {3, 3, 5}, {2, 23}, {47}, {2, 2, 2, 2, 3}, {7 ,7}, {2, 5, 5},
241  {3, 17}, {2, 2, 13}, {53}, {2, 3, 3, 3}, {5, 11}, {2, 2, 2, 7}, {3, 19}, {2, 29}, {59},
242  {2, 2, 3, 5}, {61}, {2, 31}, {3, 3, 7}, {2, 2, 2, 2, 2, 2}, {5, 13}, {2, 3, 11}, {67},
243  {2, 2, 17}, {3, 23}, {2, 5, 7}, {71}, {2, 2, 2, 3, 3}, {73}, {2, 37}, {3, 5, 5}, {2, 2, 19},
244  {7, 11}, {2, 3, 13}, {79}, {2, 2, 2, 2, 5}, {3, 3, 3, 3}, {2, 41}, {83}, {2, 2, 3, 7}, {5, 17},
245  {2, 43}, {3, 29}, {2, 2, 2, 11}, {89}, {2, 3, 3, 5}, {7, 13}, {2, 2, 23}, {3, 31}, {2, 47},
246  {5, 19}, {2, 2, 2, 2, 2, 3}, {97}, {2, 7, 7}, {3, 3, 11}, {2, 2, 5, 5}};
247  }
248 }
std::vector< Integer > integerFactorization(const Integer &coeff)
Definition: RNSEncoder.cpp:158
std::optional< FormulaT > doEncode(const ConstraintT &constraint)
Definition: RNSEncoder.cpp:7
std::vector< Integer > calculateRNSBase(const ConstraintT &formula)
Definition: RNSEncoder.cpp:94
FormulaT rnsTransformation(const ConstraintT &formula, const Integer &prime)
Definition: RNSEncoder.cpp:54
bool isNonRedundant(const std::vector< Integer > &base, const ConstraintT &formula)
Definition: RNSEncoder.cpp:22
static const int primes[nprimes]
Definition: Map.h:50
void sort(T *array, int size, LessThan lt)
Definition: Sort.h:67
Numeric mod(const Numeric &_valueA, const Numeric &_valueB)
Calculates the result of the first argument modulo the second argument.
Definition: Numeric.cpp:288
Class to create the formulas for axioms.
carl::Term< Rational > TermT
Definition: types.h:23
carl::Formula< Poly > FormulaT
Definition: types.h:37
carl::MultivariatePolynomial< Rational > Poly
Definition: types.h:25
carl::Constraint< Poly > ConstraintT
Definition: types.h:29
mpq_class Rational
Definition: types.h:19
carl::IntegralType< Rational >::type Integer
Definition: types.h:21
#define SMTRAT_LOG_INFO(channel, msg)
Definition: logging.h:34