PageRenderTime 26ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/src/util/mpzzp.h

http://z3.codeplex.com
C Header | 285 lines | 221 code | 33 blank | 31 comment | 32 complexity | 31186fbcf6b65d9eeb28a6aabf9354a7 MD5 | raw file
  1. /*++
  2. Copyright (c) 2012 Microsoft Corporation
  3. Module Name:
  4. mpzzp.h
  5. Abstract:
  6. Combines Z ring, GF(p) finite field, and Z_p ring (when p is not a prime)
  7. in a single manager;
  8. That is, the manager may be dynamically configured
  9. to be Z Ring, GF(p), etc.
  10. Author:
  11. Leonardo 2012-01-17.
  12. Revision History:
  13. This code is based on mpzp.h.
  14. In the future, it will replace it.
  15. --*/
  16. #ifndef _MPZZP_H_
  17. #define _MPZZP_H_
  18. #include "mpz.h"
  19. class mpzzp_manager {
  20. typedef unsynch_mpz_manager numeral_manager;
  21. numeral_manager & m_manager;
  22. bool m_z;
  23. // instead the usual [0..p) we will keep the numbers in [lower, upper]
  24. mpz m_p, m_lower, m_upper;
  25. bool m_p_prime;
  26. mpz m_inv_tmp1, m_inv_tmp2, m_inv_tmp3;
  27. mpz m_div_tmp;
  28. bool is_p_normalized_core(mpz const & x) const {
  29. return m().ge(x, m_lower) && m().le(x, m_upper);
  30. }
  31. void setup_p() {
  32. SASSERT(m().is_pos(m_p) && !m().is_one(m_p));
  33. bool even = m().is_even(m_p);
  34. m().div(m_p, 2, m_upper);
  35. m().set(m_lower, m_upper);
  36. m().neg(m_lower);
  37. if (even) {
  38. m().inc(m_lower);
  39. }
  40. TRACE("mpzzp", tout << "lower: " << m_manager.to_string(m_lower) << ", upper: " << m_manager.to_string(m_upper) << "\n";);
  41. }
  42. void p_normalize_core(mpz & x) {
  43. SASSERT(!m_z);
  44. m().rem(x, m_p, x);
  45. if (m().gt(x, m_upper)) {
  46. m().sub(x, m_p, x);
  47. } else {
  48. if (m().lt(x, m_lower)) {
  49. m().add(x, m_p, x);
  50. }
  51. }
  52. SASSERT(is_p_normalized(x));
  53. }
  54. public:
  55. typedef mpz numeral;
  56. static bool precise() { return true; }
  57. bool field() { return !m_z && m_p_prime; }
  58. bool finite() const { return !m_z; }
  59. bool modular() const { return !m_z; }
  60. mpzzp_manager(numeral_manager & _m):
  61. m_manager(_m),
  62. m_z(true) {
  63. }
  64. mpzzp_manager(numeral_manager & _m, mpz const & p, bool prime = true):
  65. m_manager(_m),
  66. m_z(false) {
  67. m().set(m_p, p);
  68. setup_p();
  69. }
  70. mpzzp_manager(numeral_manager & _m, uint64 p, bool prime = true):
  71. m_manager(_m),
  72. m_z(false) {
  73. m().set(m_p, p);
  74. setup_p();
  75. }
  76. ~mpzzp_manager() {
  77. m().del(m_p);
  78. m().del(m_lower);
  79. m().del(m_upper);
  80. m().del(m_inv_tmp1);
  81. m().del(m_inv_tmp2);
  82. m().del(m_inv_tmp3);
  83. m().del(m_div_tmp);
  84. }
  85. bool is_p_normalized(mpz const & x) const {
  86. return m_z || is_p_normalized_core(x);
  87. }
  88. void p_normalize(mpz & x) {
  89. if (!m_z)
  90. p_normalize_core(x);
  91. SASSERT(is_p_normalized(x));
  92. }
  93. numeral_manager & m() const { return m_manager; }
  94. mpz const & p() const { return m_p; }
  95. void set_z() { m_z = true; }
  96. void set_zp(mpz const & new_p) { m_z = false; m_p_prime = true; m().set(m_p, new_p); setup_p(); }
  97. void set_zp(uint64 new_p) { m_z = false; m_p_prime = true; m().set(m_p, new_p); setup_p(); }
  98. // p = p^2
  99. void set_p_sq() { SASSERT(!m_z); m_p_prime = false; m().mul(m_p, m_p, m_p); setup_p(); }
  100. void set_zp_swap(mpz & new_p) { SASSERT(!m_z); m().swap(m_p, new_p); setup_p(); }
  101. void reset(mpz & a) { m().reset(a); }
  102. bool is_small(mpz const & a) { return m().is_small(a); }
  103. void del(mpz & a) { m().del(a); }
  104. void neg(mpz & a) { m().neg(a); p_normalize(a); }
  105. void abs(mpz & a) { m().abs(a); p_normalize(a); }
  106. bool is_zero(mpz const & a) { SASSERT(is_p_normalized(a)); return numeral_manager::is_zero(a); }
  107. bool is_one(mpz const & a) { SASSERT(is_p_normalized(a)); return numeral_manager::is_one(a); }
  108. bool is_pos(mpz const & a) { SASSERT(is_p_normalized(a)); return numeral_manager::is_pos(a); }
  109. bool is_neg(mpz const & a) { SASSERT(is_p_normalized(a)); return numeral_manager::is_neg(a); }
  110. bool is_nonpos(mpz const & a) { SASSERT(is_p_normalized(a)); return numeral_manager::is_nonpos(a); }
  111. bool is_nonneg(mpz const & a) { SASSERT(is_p_normalized(a)); return numeral_manager::is_nonneg(a); }
  112. bool is_minus_one(mpz const & a) { SASSERT(is_p_normalized(a)); return numeral_manager::is_minus_one(a); }
  113. bool eq(mpz const & a, mpz const & b) { SASSERT(is_p_normalized(a) && is_p_normalized(b)); return m().eq(a, b); }
  114. bool lt(mpz const & a, mpz const & b) { SASSERT(is_p_normalized(a) && is_p_normalized(b)); return m().lt(a, b); }
  115. bool le(mpz const & a, mpz const & b) { SASSERT(is_p_normalized(a) && is_p_normalized(b)); return m().le(a, b); }
  116. bool gt(mpz const & a, mpz const & b) { SASSERT(is_p_normalized(a) && is_p_normalized(b)); return m().gt(a, b); }
  117. bool ge(mpz const & a, mpz const & b) { SASSERT(is_p_normalized(a) && is_p_normalized(b)); return m().ge(a, b); }
  118. std::string to_string(mpz const & a) const {
  119. SASSERT(is_p_normalized(a));
  120. return m().to_string(a);
  121. }
  122. void display(std::ostream & out, mpz const & a) const { m().display(out, a); }
  123. void add(mpz const & a, mpz const & b, mpz & c) { SASSERT(is_p_normalized(a) && is_p_normalized(b)); m().add(a, b, c); p_normalize(c); }
  124. void sub(mpz const & a, mpz const & b, mpz & c) { SASSERT(is_p_normalized(a) && is_p_normalized(b)); m().sub(a, b, c); p_normalize(c); }
  125. void inc(mpz & a) { SASSERT(is_p_normalized(a)); m().inc(a); p_normalize(a); }
  126. void dec(mpz & a) { SASSERT(is_p_normalized(a)); m().dec(a); p_normalize(a); }
  127. void mul(mpz const & a, mpz const & b, mpz & c) { SASSERT(is_p_normalized(a) && is_p_normalized(b)); m().mul(a, b, c); p_normalize(c); }
  128. void addmul(mpz const & a, mpz const & b, mpz const & c, mpz & d) {
  129. SASSERT(is_p_normalized(a) && is_p_normalized(b) && is_p_normalized(c)); m().addmul(a, b, c, d); p_normalize(d);
  130. }
  131. // d <- a - b*c
  132. void submul(mpz const & a, mpz const & b, mpz const & c, mpz & d) {
  133. SASSERT(is_p_normalized(a));
  134. SASSERT(is_p_normalized(b));
  135. SASSERT(is_p_normalized(c));
  136. m().submul(a, b, c, d);
  137. p_normalize(d);
  138. }
  139. void inv(mpz & a) {
  140. if (m_z) {
  141. UNREACHABLE();
  142. }
  143. else {
  144. SASSERT(!is_zero(a));
  145. // eulers theorem a^(p - 2), but gcd could be more efficient
  146. // a*t1 + p*t2 = 1 => a*t1 = 1 (mod p) => t1 is the inverse (t3 == 1)
  147. TRACE("mpzp_inv_bug", tout << "a: " << m().to_string(a) << ", p: " << m().to_string(m_p) << "\n";);
  148. p_normalize(a);
  149. TRACE("mpzp_inv_bug", tout << "after normalization a: " << m().to_string(a) << "\n";);
  150. m().gcd(a, m_p, m_inv_tmp1, m_inv_tmp2, m_inv_tmp3);
  151. TRACE("mpzp_inv_bug", tout << "tmp1: " << m().to_string(m_inv_tmp1) << "\ntmp2: " << m().to_string(m_inv_tmp2)
  152. << "\ntmp3: " << m().to_string(m_inv_tmp3) << "\n";);
  153. p_normalize(m_inv_tmp1);
  154. m().swap(a, m_inv_tmp1);
  155. SASSERT(m().is_one(m_inv_tmp3)); // otherwise p is not prime and inverse is not defined
  156. }
  157. }
  158. void swap(mpz & a, mpz & b) {
  159. SASSERT(is_p_normalized(a) && is_p_normalized(b));
  160. m().swap(a, b);
  161. }
  162. bool divides(mpz const & a, mpz const & b) { return (field() && !is_zero(a)) || m().divides(a, b); }
  163. // a/b = a*inv(b)
  164. void div(mpz const & a, mpz const & b, mpz & c) {
  165. if (m_z) {
  166. return m().div(a, b, c);
  167. }
  168. else {
  169. SASSERT(m_p_prime);
  170. SASSERT(is_p_normalized(a));
  171. m().set(m_div_tmp, b);
  172. inv(m_div_tmp);
  173. mul(a, m_div_tmp, c);
  174. SASSERT(is_p_normalized(c));
  175. }
  176. }
  177. static unsigned hash(mpz const & a) { return numeral_manager::hash(a); }
  178. void gcd(mpz const & a, mpz const & b, mpz & c) {
  179. SASSERT(is_p_normalized(a) && is_p_normalized(b));
  180. m().gcd(a, b, c);
  181. SASSERT(is_p_normalized(c));
  182. }
  183. void gcd(unsigned sz, mpz const * as, mpz & g) {
  184. m().gcd(sz, as, g);
  185. SASSERT(is_p_normalized(g));
  186. }
  187. void gcd(mpz const & r1, mpz const & r2, mpz & a, mpz & b, mpz & g) {
  188. SASSERT(is_p_normalized(r1) && is_p_normalized(r2));
  189. m().gcd(r1, r2, a, b, g);
  190. p_normalize(a);
  191. p_normalize(b);
  192. }
  193. void set(mpz & a, mpz & val) { m().set(a, val); p_normalize(a); }
  194. void set(mpz & a, int val) { m().set(a, val); p_normalize(a); }
  195. void set(mpz & a, unsigned val) { m().set(a, val); p_normalize(a); }
  196. void set(mpz & a, char const * val) { m().set(a, val); p_normalize(a); }
  197. void set(mpz & a, int64 val) { m().set(a, val); p_normalize(a); }
  198. void set(mpz & a, uint64 val) { m().set(a, val); p_normalize(a); }
  199. void set(mpz & a, mpz const & val) { m().set(a, val); p_normalize(a); }
  200. bool is_uint64(mpz & a) const { const_cast<mpzzp_manager*>(this)->p_normalize(a); return m().is_uint64(a); }
  201. bool is_int64(mpz & a) const { const_cast<mpzzp_manager*>(this)->p_normalize(a); return m().is_int64(a); }
  202. uint64 get_uint64(mpz & a) const { const_cast<mpzzp_manager*>(this)->p_normalize(a); return m().get_uint64(a); }
  203. int64 get_int64(mpz & a) const { const_cast<mpzzp_manager*>(this)->p_normalize(a); return m().get_int64(a); }
  204. double get_double(mpz & a) const { const_cast<mpzzp_manager*>(this)->p_normalize(a); return m().get_double(a); }
  205. void power(mpz const & a, unsigned k, mpz & b) {
  206. SASSERT(is_p_normalized(a));
  207. unsigned mask = 1;
  208. mpz power;
  209. set(power, a);
  210. set(b, 1);
  211. while (mask <= k) {
  212. if (mask & k)
  213. mul(b, power, b);
  214. mul(power, power, power);
  215. mask = mask << 1;
  216. }
  217. del(power);
  218. }
  219. bool is_perfect_square(mpz const & a, mpz & root) {
  220. if (m_z) {
  221. return m().is_perfect_square(a, root);
  222. }
  223. else {
  224. NOT_IMPLEMENTED_YET();
  225. return false;
  226. }
  227. }
  228. bool is_uint64(mpz const & a) const { return m().is_uint64(a); }
  229. bool is_int64(mpz const & a) const { return m().is_int64(a); }
  230. uint64 get_uint64(mpz const & a) const { return m().get_uint64(a); }
  231. int64 get_int64(mpz const & a) const { return m().get_int64(a); }
  232. void mul2k(mpz & a, unsigned k) { m().mul2k(a, k); p_normalize(a); }
  233. void mul2k(mpz const & a, unsigned k, mpz & r) { m().mul2k(a, k, r); p_normalize(r); }
  234. unsigned power_of_two_multiple(mpz const & n) { return m().power_of_two_multiple(n); }
  235. unsigned log2(mpz const & n) { return m().log2(n); }
  236. unsigned mlog2(mpz const & n) { return m().mlog2(n); }
  237. void machine_div2k(mpz & a, unsigned k) { m().machine_div2k(a, k); SASSERT(is_p_normalized(a)); }
  238. void machine_div2k(mpz const & a, unsigned k, mpz & r) { m().machine_div2k(a, k, r); SASSERT(is_p_normalized(r)); }
  239. bool root(mpz & a, unsigned n) { SASSERT(!modular()); return m().root(a, n); }
  240. bool root(mpz const & a, unsigned n, mpz & r) { SASSERT(!modular()); return m().root(a, n, r); }
  241. };
  242. #endif