filter.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /* Boost example/filter.cpp
  2. * two examples of filters for computing the sign of a determinant
  3. * the second filter is based on an idea presented in
  4. * "Interval arithmetic yields efficient dynamic filters for computational
  5. * geometry" by Brönnimann, Burnikel and Pion, 2001
  6. *
  7. * Copyright 2003 Guillaume Melquiond
  8. *
  9. * Distributed under the Boost Software License, Version 1.0.
  10. * (See accompanying file LICENSE_1_0.txt or
  11. * copy at http://www.boost.org/LICENSE_1_0.txt)
  12. */
  13. #include <boost/numeric/interval.hpp>
  14. #include <cstring>
  15. #include <iostream>
  16. namespace dummy {
  17. using namespace boost;
  18. using namespace numeric;
  19. using namespace interval_lib;
  20. typedef save_state<rounded_arith_opp<double> > R;
  21. typedef checking_no_nan<double, checking_no_empty<double> > P;
  22. typedef interval<double, policies<R, P> > I;
  23. }
  24. template<class T>
  25. class vector {
  26. T* ptr;
  27. public:
  28. vector(int d) { ptr = (T*)malloc(sizeof(T) * d); }
  29. ~vector() { free(ptr); }
  30. const T& operator[](int i) const { return ptr[i]; }
  31. T& operator[](int i) { return ptr[i]; }
  32. };
  33. template<class T>
  34. class matrix {
  35. int dim;
  36. T* ptr;
  37. public:
  38. matrix(int d): dim(d) { ptr = (T*)malloc(sizeof(T) * dim * dim); }
  39. ~matrix() { free(ptr); }
  40. int get_dim() const { return dim; }
  41. void assign(const matrix<T> &a) { memcpy(ptr, a.ptr, sizeof(T) * dim * dim); }
  42. const T* operator[](int i) const { return &(ptr[i * dim]); }
  43. T* operator[](int i) { return &(ptr[i * dim]); }
  44. };
  45. typedef dummy::I I_dbl;
  46. /* compute the sign of a determinant using an interval LU-decomposition; the
  47. function answers 1 or -1 if the determinant is positive or negative (and
  48. more importantly, the result must be provable), or 0 if the algorithm was
  49. unable to get a correct sign */
  50. int det_sign_algo1(const matrix<double> &a) {
  51. int dim = a.get_dim();
  52. vector<int> p(dim);
  53. for(int i = 0; i < dim; i++) p[i] = i;
  54. int sig = 1;
  55. I_dbl::traits_type::rounding rnd;
  56. typedef boost::numeric::interval_lib::unprotect<I_dbl>::type I;
  57. matrix<I> u(dim);
  58. for(int i = 0; i < dim; i++) {
  59. const double* line1 = a[i];
  60. I* line2 = u[i];
  61. for(int j = 0; j < dim; j++)
  62. line2[j] = line1[j];
  63. }
  64. // computation of L and U
  65. for(int i = 0; i < dim; i++) {
  66. // partial pivoting
  67. {
  68. int pivot = i;
  69. double max = 0;
  70. for(int j = i; j < dim; j++) {
  71. const I &v = u[p[j]][i];
  72. if (zero_in(v)) continue;
  73. double m = norm(v);
  74. if (m > max) { max = m; pivot = j; }
  75. }
  76. if (max == 0) return 0;
  77. if (pivot != i) {
  78. sig = -sig;
  79. int tmp = p[i];
  80. p[i] = p[pivot];
  81. p[pivot] = tmp;
  82. }
  83. }
  84. // U[i,?]
  85. {
  86. I *line1 = u[p[i]];
  87. const I &pivot = line1[i];
  88. if (boost::numeric::interval_lib::cerlt(pivot, 0.)) sig = -sig;
  89. for(int k = i + 1; k < dim; k++) {
  90. I *line2 = u[p[k]];
  91. I fact = line2[i] / pivot;
  92. for(int j = i + 1; j < dim; j++) line2[j] -= fact * line1[j];
  93. }
  94. }
  95. }
  96. return sig;
  97. }
  98. /* compute the sign of a determinant using a floating-point LU-decomposition
  99. and an a posteriori interval validation; the meaning of the answer is the
  100. same as previously */
  101. int det_sign_algo2(const matrix<double> &a) {
  102. int dim = a.get_dim();
  103. vector<int> p(dim);
  104. for(int i = 0; i < dim; i++) p[i] = i;
  105. int sig = 1;
  106. matrix<double> lui(dim);
  107. {
  108. // computation of L and U
  109. matrix<double> lu(dim);
  110. lu.assign(a);
  111. for(int i = 0; i < dim; i++) {
  112. // partial pivoting
  113. {
  114. int pivot = i;
  115. double max = std::abs(lu[p[i]][i]);
  116. for(int j = i + 1; j < dim; j++) {
  117. double m = std::abs(lu[p[j]][i]);
  118. if (m > max) { max = m; pivot = j; }
  119. }
  120. if (max == 0) return 0;
  121. if (pivot != i) {
  122. sig = -sig;
  123. int tmp = p[i];
  124. p[i] = p[pivot];
  125. p[pivot] = tmp;
  126. }
  127. }
  128. // L[?,i] and U[i,?]
  129. {
  130. double *line1 = lu[p[i]];
  131. double pivot = line1[i];
  132. if (pivot < 0) sig = -sig;
  133. for(int k = i + 1; k < dim; k++) {
  134. double *line2 = lu[p[k]];
  135. double fact = line2[i] / pivot;
  136. line2[i] = fact;
  137. for(int j = i + 1; j < dim; j++) line2[j] -= line1[j] * fact;
  138. }
  139. }
  140. }
  141. // computation of approximate inverses: Li and Ui
  142. for(int j = 0; j < dim; j++) {
  143. for(int i = j + 1; i < dim; i++) {
  144. double *line = lu[p[i]];
  145. double s = - line[j];
  146. for(int k = j + 1; k < i; k++) s -= line[k] * lui[k][j];
  147. lui[i][j] = s;
  148. }
  149. lui[j][j] = 1 / lu[p[j]][j];
  150. for(int i = j - 1; i >= 0; i--) {
  151. double *line = lu[p[i]];
  152. double s = 0;
  153. for(int k = i + 1; k <= j; k++) s -= line[k] * lui[k][j];
  154. lui[i][j] = s / line[i];
  155. }
  156. }
  157. }
  158. // norm of PAUiLi-I computed with intervals
  159. {
  160. I_dbl::traits_type::rounding rnd;
  161. typedef boost::numeric::interval_lib::unprotect<I_dbl>::type I;
  162. vector<I> m1(dim);
  163. vector<I> m2(dim);
  164. for(int i = 0; i < dim; i++) {
  165. for(int j = 0; j < dim; j++) m1[j] = 0;
  166. const double *l1 = a[p[i]];
  167. for(int j = 0; j < dim; j++) {
  168. double v = l1[j]; // PA[i,j]
  169. double *l2 = lui[j]; // Ui[j,?]
  170. for(int k = j; k < dim; k++) {
  171. using boost::numeric::interval_lib::mul;
  172. m1[k] += mul<I>(v, l2[k]); // PAUi[i,k]
  173. }
  174. }
  175. for(int j = 0; j < dim; j++) m2[j] = m1[j]; // PAUi[i,j] * Li[j,j]
  176. for(int j = 1; j < dim; j++) {
  177. const I &v = m1[j]; // PAUi[i,j]
  178. double *l2 = lui[j]; // Li[j,?]
  179. for(int k = 0; k < j; k++)
  180. m2[k] += v * l2[k]; // PAUiLi[i,k]
  181. }
  182. m2[i] -= 1; // PAUiLi-I
  183. double ss = 0;
  184. for(int i = 0; i < dim; i++) ss = rnd.add_up(ss, norm(m2[i]));
  185. if (ss >= 1) return 0;
  186. }
  187. }
  188. return sig;
  189. }
  190. int main() {
  191. int dim = 20;
  192. matrix<double> m(dim);
  193. for(int i = 0; i < dim; i++) for(int j = 0; j < dim; j++)
  194. m[i][j] = /*1 / (i-j-0.001)*/ cos(1+i*sin(1 + j)) /*1./(1+i+j)*/;
  195. // compute the sign of the determinant of a "strange" matrix with the two
  196. // algorithms, the first should fail and the second succeed
  197. std::cout << det_sign_algo1(m) << " " << det_sign_algo2(m) << std::endl;
  198. }