BEM++  2.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Groups Pages
modified_aca.hpp
1 // Copyright (C) 2011-2013 by the BEM++ Authors
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to deal
5 // in the Software without restriction, including without limitation the rights
6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 // copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
9 //
10 // The above copyright notice and this permission notice shall be included in
11 // all copies or substantial portions of the Software.
12 //
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 // THE SOFTWARE.
20 
21 #ifndef bempp_modified_aca_hpp
22 #define bempp_modified_aca_hpp
23 
24 #include "../common/common.hpp"
25 #include "bempp/common/config_ahmed.hpp"
26 
27 #ifdef WITH_AHMED
28 
29 #ifdef __INTEL_COMPILER
30 #pragma warning(disable:381)
31 #endif
32 
33 #include <apprx.h>
34 
35 #ifdef __INTEL_COMPILER
36 #pragma warning(default:381)
37 #endif
38 
39 #include <boost/scoped_array.hpp>
40 #include <limits>
41 
42 namespace Bempp
43 {
44 
45 // returns true if a pivot could be found (there were any nonapproximated
46 // rows or columns), false otherwise
47 template <class abs_T>
48 bool select_pivot_with_min_norm2(unsigned n, const abs_T* norm2,
49  const int* apprx_times /* S or Z */,
50  unsigned& pivot)
51 {
52  pivot = n; // invalid value
53  abs_T min_norm2 = std::numeric_limits<abs_T>::max();
54  for (unsigned i = 0; i < n; ++i)
55  if (apprx_times[i] >= 0 && norm2[i] < min_norm2) {
56  min_norm2 = norm2[i];
57  pivot = i;
58  }
59  return (pivot != n);
60 }
61 
62 template<class T, class MATGEN_T>
63 bool ACAs(MATGEN_T& MatGen, unsigned b1, unsigned n1, unsigned b2, unsigned n2,
64  double eps, unsigned kmax, unsigned i0, unsigned& k, T* &U, T* &V,
65  const cluster* c1, const cluster* c2)
66 {
67  typedef typename num_traits<T>::abs_type abs_T;
68  unsigned no = 0; // number of crosses calculated so far
69  unsigned klast; // unused
70  const unsigned maxit = std::min(n1, n2);
71 
72  abs_T scale = MatGen.scale(b1, n1, b2, n2, c1, c2); // set initial scale
73 
74  U = new T[(kmax+1)*n1]; // these arrays are expected to be
75  V = new T[(kmax+1)*n2]; // deallocated by the caller
76  assert(U != NULL && V != NULL);
77 
78  // arrays storing number of successful approximations of rows and columns
79  boost::scoped_array<int> Z(new int[n1]), S(new int[n2]);
80  for (unsigned l=0; l<n1; ++l)
81  Z[l] = 0;
82  for (unsigned l=0; l<n2; ++l)
83  S[l] = 0;
84 
85  boost::scoped_array<T> orig_row(new T[n2]);
86  boost::scoped_array<T> orig_col(new T[n1]);
87 
88  boost::scoped_array<abs_T> orig_row_norm2(new abs_T[n2]);
89  boost::scoped_array<abs_T> orig_col_norm2(new abs_T[n1]);
90 
91  abs_T nrms2 = 0.; // squared Frobenius norm of U V^H
92 
93  const unsigned ROW = 0, COL = 1;
94  const unsigned NORMAL = 0, FIRST_SHOT = 1, SECOND_SHOT = 2;
95  unsigned mode = ROW;
96  unsigned stage = NORMAL;
97 
98  k = 0;
99  unsigned next_pivot = i0;
100 
101  // The relativeScale() function is expected to return an estimate of the
102  // magnitude of the largest element in the block, relative to the magnitude
103  // of the largest element in the whole matrix.
104  // If the result is deemed small enough relative to eps, the block is taken to
105  // be zero and its elements are not evaluate.
106  // This can be useful in the approximation of strongly decaying kernels.
107  // abs_T relscale = MatGen.relativeScale(b1, n1, b2, n2, c1, c2);
108  // if (relscale < 1e-2 * eps)
109  // return true;
110 
111  do {
112  ACA_status status;
113  abs_T nrmlsk2; // product of squared norms of new columns of U and V
114  bool retry_if_zero = (stage == NORMAL); // don't retry if shooting
115  // compute a cross
116  if (mode == ROW)
117  status = ACA_row_step(
118  MatGen, b1, n1, b2, n2, klast, next_pivot, k, no,
119  Z.get(), S.get(), U, V, nrmlsk2, scale, c1, c2,
120  retry_if_zero, orig_row.get(), orig_col.get());
121  else
122  status = ACA_col_step(
123  MatGen, b1, n1, b2, n2, next_pivot, k, no,
124  Z.get(), S.get(), U, V, nrmlsk2, scale, c1, c2,
125  retry_if_zero, orig_row.get(), orig_col.get());
126  // std::cout << "status = " << status << std::endl;
127 
128  bool stpcrit = false;
129  if (status == ACA_STATUS_SUCCESS) {
130  // check stopping criterion
131  T sum = 0.; // update nrms2
132  for (unsigned l=0; l<k; ++l)
133  sum += blas::scpr(n1, U+l*n1, U+k*n1) * blas::scpr(n2, V+k*n2, V+l*n2);
134  nrms2 += 2. * Re(sum) + nrmlsk2;
135 
136  stpcrit = (nrmlsk2 < eps * eps * nrms2);
137  // adjust scale (estimated entry size of the next remainder)
138  scale = sqrt(nrmlsk2/(n1*n2));
139  // std::cout << "nrmlsk2: " << nrmlsk2 << ", nrms2: " << nrms2 << ", scale = " << scale
140  // << std::endl;
141 
142  ++k;
143  } else if (status == ACA_STATUS_EARLY_EXIT)
144  stpcrit = true;
145  else {
146  // in the last step no non-zero row/column could be found
147  assert(status == ACA_STATUS_REMAINDER_IS_ZERO);
148  return true;
149  }
150 
151  if (stpcrit) {
152  if (stage == SECOND_SHOT)
153  return true;
154  else if (stage == FIRST_SHOT) {
155  if (mode == ROW) {
156  // select column pivot
157  bool found = select_pivot_with_min_norm2(
158  n2, orig_row_norm2.get(), S.get(), next_pivot);
159  if (!found) // no nonapproximated column could be found
160  return true;
161  mode = COL;
162  } else {
163  // select row pivot
164  bool found = select_pivot_with_min_norm2(
165  n1, orig_col_norm2.get(), Z.get(), next_pivot);
166  if (!found) // no nonapproximated row could be found
167  return true;
168  mode = ROW;
169  }
170  stage = SECOND_SHOT;
171  } else {
172  assert(stage == NORMAL);
173  for (unsigned i = 0; i < n2; ++i)
174  orig_row_norm2[i] = abs2(orig_row[i]);
175  for (unsigned i = 0; i < n1; ++i)
176  orig_col_norm2[i] = abs2(orig_col[i]);
177  if (mode == ROW) {
178  // select row pivot
179  bool found = select_pivot_with_min_norm2(
180  n1, orig_col_norm2.get(), Z.get(), next_pivot);
181  if (!found) // no nonapproximated row could be found
182  return true;
183  }
184  else {
185  // select column pivot
186  bool found = select_pivot_with_min_norm2(
187  n2, orig_row_norm2.get(), S.get(), next_pivot);
188  if (!found) // no nonapproximated column could be found
189  return true;
190  }
191  stage = FIRST_SHOT;
192  // mode stays the same
193  }
194  } else
195  stage = NORMAL;
196  // mode stays the same
197 
198  // std::cout << "Stage: " << stage << ", mode: " << mode << "\n";
199  } while (no < maxit && k < kmax);
200 
201  // std::cout << "Giving up" << std::endl;
202  return false;
203 }
204 
205 template<class T,class T1,class T2, class MATGEN_T>
206 void apprx_unsym_shooting(
207  MATGEN_T& MatGen, mblock<T>* &mbl, bbxbemblcluster<T1,T2>* bl,
208  double eps, unsigned rankmax)
209 {
210  apprx_unsym_generic(&ACAs<T, MATGEN_T>, MatGen, mbl, bl, eps, rankmax);
211 }
212 
213 } // namespace Bempp
214 
215 #endif // WITH_AHMED
216 
217 #endif