kernel_aux.h

Go to the documentation of this file.
00001 /* MLPACK 0.2
00002  *
00003  * Copyright (c) 2008, 2009 Alexander Gray,
00004  *                          Garry Boyer,
00005  *                          Ryan Riegel,
00006  *                          Nikolaos Vasiloglou,
00007  *                          Dongryeol Lee,
00008  *                          Chip Mappus, 
00009  *                          Nishant Mehta,
00010  *                          Hua Ouyang,
00011  *                          Parikshit Ram,
00012  *                          Long Tran,
00013  *                          Wee Chin Wong
00014  *
00015  * Copyright (c) 2008, 2009 Georgia Institute of Technology
00016  *
00017  * This program is free software; you can redistribute it and/or
00018  * modify it under the terms of the GNU General Public License as
00019  * published by the Free Software Foundation; either version 2 of the
00020  * License, or (at your option) any later version.
00021  *
00022  * This program is distributed in the hope that it will be useful, but
00023  * WITHOUT ANY WARRANTY; without even the implied warranty of
00024  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00025  * General Public License for more details.
00026  *
00027  * You should have received a copy of the GNU General Public License
00028  * along with this program; if not, write to the Free Software
00029  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00030  * 02110-1301, USA.
00031  */
00042 #ifndef KERNEL_AUX
00043 #define KERNEL_AUX
00044 
00045 #include "fastlib/fastlib.h"
00046 
00047 #include "bounds_aux.h"
00048 #include "farfield_expansion.h"
00049 #include "local_expansion.h"
00050 #include "inverse_pow_dist_kernel_aux.h"
00051 #include "mult_farfield_expansion.h"
00052 #include "mult_local_expansion.h"
00053 
00054 
00059 class GaussianKernelMultAux {
00060 
00061  public:
00062 
00063   typedef GaussianKernel TKernel;
00064 
00065   typedef MultSeriesExpansionAux TSeriesExpansionAux;
00066   
00067   typedef MultFarFieldExpansion<GaussianKernelMultAux> TFarFieldExpansion;
00068   
00069   typedef MultLocalExpansion<GaussianKernelMultAux> TLocalExpansion;
00070 
00072   TKernel kernel_;
00073 
00075   TSeriesExpansionAux sea_;
00076 
00077   OT_DEF_BASIC(GaussianKernelMultAux) {
00078     OT_MY_OBJECT(kernel_);
00079     OT_MY_OBJECT(sea_);
00080   }
00081 
00082  public:
00083 
00084   void Init(double bandwidth, int max_order, int dim) {
00085     kernel_.Init(bandwidth);
00086     sea_.Init(max_order, dim);
00087   }
00088 
00089   double BandwidthFactor(double bandwidth_sq) const {
00090     return sqrt(2 * bandwidth_sq);
00091   }
00092 
00093   void AllocateDerivativeMap(int dim, int order, 
00094                              Matrix *derivative_map) const {
00095     derivative_map->Init(dim, order + 1);
00096   }
00097 
00098   void ComputeDirectionalDerivatives(const Vector &x, 
00099                                      Matrix *derivative_map, int order) const {
00100 
00101     int dim = x.length();
00102     
00103     // precompute necessary Hermite polynomials based on coordinate difference
00104     for(index_t d = 0; d < dim; d++) {
00105       
00106       double coord_div_band = x[d];
00107       double d2 = 2 * coord_div_band;
00108       double facj = exp(-coord_div_band * coord_div_band);
00109       
00110       derivative_map->set(d, 0, facj);
00111       
00112       if(order > 0) {
00113         
00114         derivative_map->set(d, 1, d2 * facj);
00115         
00116         if(order > 1) {
00117           for(index_t k = 1; k < order; k++) {
00118             int k2 = k * 2;
00119             derivative_map->set(d, k + 1, d2 * derivative_map->get(d, k) -
00120                                 k2 * derivative_map->get(d, k - 1));
00121           }
00122         }
00123       }
00124     } // end of looping over each dimension
00125   }
00126 
00127   double ComputePartialDerivative(const Matrix &derivative_map,
00128                                   const ArrayList<int> &mapping) const {
00129     
00130     double partial_derivative = 1.0;
00131     
00132     for(index_t d = 0; d < mapping.size(); d++) {
00133       partial_derivative *= derivative_map.get(d, mapping[d]);
00134     }
00135     return partial_derivative;
00136   }
00137 
00138   template<typename TBound>
00139   int OrderForEvaluatingFarField
00140     (const TBound &far_field_region, const TBound &local_field_region, 
00141      double min_dist_sqd_regions, double max_dist_sqd_regions, 
00142      double max_error, double *actual_error) const {
00143     
00144     // Find out the maximum side length of the bounding box of the
00145     // far-field region.
00146     double max_far_field_length =
00147       bounds_aux::MaxSideLengthOfBoundingBox(far_field_region);
00148 
00149     double two_times_bandwidth = sqrt(kernel_.bandwidth_sq()) * 2;
00150     double r = max_far_field_length / two_times_bandwidth;
00151 
00152     int dim = sea_.get_dimension();
00153     double r_raised_to_p_alpha = 1.0;
00154     double ret, ret2;
00155     int p_alpha = 0;
00156     double factorialvalue = 1.0;
00157     double first_factor, second_factor;
00158     double one_minus_r;
00159 
00160     // In this case, it is "impossible" to prune for the Gaussian kernel.
00161     if(r >= 1.0) {
00162       return -1;
00163     }
00164     one_minus_r = 1.0 - r;
00165     ret = 1.0 / pow(one_minus_r, dim);
00166   
00167     do {
00168       factorialvalue *= (p_alpha + 1);
00169 
00170       if(factorialvalue < 0.0 || p_alpha > sea_.get_max_order()) {
00171         return -1;
00172       }
00173 
00174       r_raised_to_p_alpha *= r;
00175       first_factor = 1.0 - r_raised_to_p_alpha;
00176       second_factor = r_raised_to_p_alpha / sqrt(factorialvalue);
00177 
00178       ret2 = ret * (pow((first_factor + second_factor), dim) -
00179                     pow(first_factor, dim));
00180 
00181       if(ret2 <= max_error) {
00182         break;
00183       }
00184       
00185       p_alpha++;
00186 
00187     } while(1);
00188 
00189     *actual_error = ret2;
00190     return p_alpha;
00191   }
00192 
00193   template<typename TBound>
00194   int OrderForConvertingFromFarFieldToLocal
00195   (const TBound &far_field_region,
00196    const TBound &local_field_region, double min_dist_sqd_regions, 
00197    double max_dist_sqd_regions, double max_error, 
00198    double *actual_error) const {
00199 
00200     // Find out the maximum side length of the bounding box of the
00201     // far-field region and the local-field regions.
00202     double max_far_field_length =
00203       bounds_aux::MaxSideLengthOfBoundingBox(far_field_region);
00204     double max_local_field_length =
00205       bounds_aux::MaxSideLengthOfBoundingBox(local_field_region);
00206 
00207     double two_times_bandwidth = sqrt(kernel_.bandwidth_sq()) * 2;
00208     double r = max_far_field_length / two_times_bandwidth;
00209     double r2 = max_local_field_length / two_times_bandwidth;
00210 
00211     int dim = sea_.get_dimension();
00212     double r_raised_to_p_alpha = 1.0;
00213     double ret, ret2;
00214     int p_alpha = 0;
00215     double factorialvalue = 1.0;
00216     double first_factor, second_factor;
00217     double one_minus_two_r, two_r;
00218 
00219     // In this case, it is "impossible" to prune for the Gaussian kernel.
00220     if(r >= 0.5 || r2 >= 0.5) {
00221       return -1;
00222     }
00223 
00224     r = max(r, r2);
00225     two_r = 2.0 * r;
00226     one_minus_two_r = 1.0 - two_r;
00227     ret = 1.0 / pow(one_minus_two_r * one_minus_two_r, dim);
00228   
00229     do {
00230       factorialvalue *= (p_alpha + 1);
00231 
00232       if(factorialvalue < 0.0 || p_alpha > sea_.get_max_order()) {
00233         return -1;
00234       }
00235 
00236       r_raised_to_p_alpha *= two_r;
00237       first_factor = 1.0 - r_raised_to_p_alpha;
00238       first_factor *= first_factor;
00239       second_factor = r_raised_to_p_alpha * (2.0 - r_raised_to_p_alpha)
00240         / sqrt(factorialvalue);
00241 
00242       ret2 = ret * (pow((first_factor + second_factor), dim) -
00243                     pow(first_factor, dim));
00244 
00245       if(ret2 <= max_error) {
00246         break;
00247       }
00248       
00249       p_alpha++;
00250 
00251     } while(1);
00252 
00253     *actual_error = ret2;
00254     return p_alpha;
00255   }
00256   
00257   template<typename TBound>
00258   int OrderForEvaluatingLocal(const TBound &far_field_region, 
00259                               const TBound &local_field_region, 
00260                               double min_dist_sqd_regions,
00261                               double max_dist_sqd_regions, double max_error, 
00262                               double *actual_error) const {
00263     
00264     // Find out the maximum side length of the local field region.
00265     double max_local_field_length =
00266       bounds_aux::MaxSideLengthOfBoundingBox(local_field_region);
00267 
00268     double two_times_bandwidth = sqrt(kernel_.bandwidth_sq()) * 2;
00269     double r = max_local_field_length / two_times_bandwidth;
00270 
00271     int dim = sea_.get_dimension();
00272     double r_raised_to_p_alpha = 1.0;
00273     double ret, ret2;
00274     int p_alpha = 0;
00275     double factorialvalue = 1.0;
00276     double first_factor, second_factor;
00277     double one_minus_r;
00278 
00279     // In this case, it is "impossible" to prune for the Gaussian kernel.
00280     if(r >= 1.0) {
00281       return -1;
00282     }
00283     one_minus_r = 1.0 - r;
00284     ret = 1.0 / pow(one_minus_r, dim);
00285   
00286     do {
00287       factorialvalue *= (p_alpha + 1);
00288 
00289       if(factorialvalue < 0.0 || p_alpha > sea_.get_max_order()) {
00290         return -1;
00291       }
00292 
00293       r_raised_to_p_alpha *= r;
00294       first_factor = 1.0 - r_raised_to_p_alpha;
00295       second_factor = r_raised_to_p_alpha / sqrt(factorialvalue);
00296 
00297       ret2 = ret * (pow((first_factor + second_factor), dim) -
00298                     pow(first_factor, dim));
00299 
00300       if(ret2 <= max_error) {
00301         break;
00302       }
00303       
00304       p_alpha++;
00305 
00306     } while(1);
00307 
00308     *actual_error = ret2;
00309     return p_alpha;
00310   }
00311 };
00312 
00315 class GaussianKernelAux {
00316 
00317  public:
00318 
00319   typedef GaussianKernel TKernel;
00320 
00321   typedef SeriesExpansionAux TSeriesExpansionAux;
00322 
00323   typedef FarFieldExpansion<GaussianKernelAux> TFarFieldExpansion;
00324   
00325   typedef LocalExpansion<GaussianKernelAux> TLocalExpansion;
00326 
00328   TKernel kernel_;
00329 
00331   TSeriesExpansionAux sea_;
00332 
00333   OT_DEF_BASIC(GaussianKernelAux) {
00334     OT_MY_OBJECT(kernel_);
00335     OT_MY_OBJECT(sea_);
00336   }
00337 
00338  public:
00339 
00340   void Init(double bandwidth, int max_order, int dim) {
00341     kernel_.Init(bandwidth);
00342     sea_.Init(max_order, dim);
00343   }
00344 
00345   double BandwidthFactor(double bandwidth_sq) const {
00346     return sqrt(2 * bandwidth_sq);
00347   }
00348 
00349   void AllocateDerivativeMap(int dim, int order, 
00350                              Matrix *derivative_map) const {
00351     derivative_map->Init(dim, order + 1);
00352   }
00353 
00354   void ComputeDirectionalDerivatives(const Vector &x, 
00355                                      Matrix *derivative_map, int order) const {
00356     
00357     int dim = x.length();
00358     
00359     // precompute necessary Hermite polynomials based on coordinate difference
00360     for(index_t d = 0; d < dim; d++) {
00361       
00362       double coord_div_band = x[d];
00363       double d2 = 2 * coord_div_band;
00364       double facj = exp(-coord_div_band * coord_div_band);
00365       
00366       derivative_map->set(d, 0, facj);
00367       
00368       if(order > 0) {
00369         
00370         derivative_map->set(d, 1, d2 * facj);
00371         
00372         if(order > 1) {
00373           for(index_t k = 1; k < order; k++) {
00374             int k2 = k * 2;
00375             derivative_map->set(d, k + 1, d2 * derivative_map->get(d, k) -
00376                                 k2 * derivative_map->get(d, k - 1));
00377           }
00378         }
00379       }
00380     } // end of looping over each dimension
00381   }
00382 
00383   double ComputePartialDerivative(const Matrix &derivative_map,
00384                                   const ArrayList<int> &mapping) const {
00385     
00386     double partial_derivative = 1.0;
00387     
00388     for(index_t d = 0; d < mapping.size(); d++) {
00389       partial_derivative *= derivative_map.get(d, mapping[d]);
00390     }
00391     return partial_derivative;
00392   }
00393 
00394   template<typename TBound>
00395   int OrderForConvolvingFarField(const TBound &far_field_region, 
00396                                  const Vector &far_field_region_centroid,
00397                                  const TBound &local_field_region, 
00398                                  const Vector &local_field_region_centroid,
00399                                  double min_dist_sqd_regions,
00400                                  double max_dist_sqd_regions, 
00401                                  double max_error, 
00402                                  double *actual_error) const {
00403     
00404     double squared_distance_between_two_centroids =
00405       la::DistanceSqEuclidean(far_field_region_centroid.length(),
00406                               far_field_region_centroid.ptr(),
00407                               local_field_region_centroid.ptr());
00408     double frontfactor = 
00409       exp(-squared_distance_between_two_centroids / 
00410           (4 * kernel_.bandwidth_sq()));
00411     int max_order = sea_.get_max_order();
00412     
00413     // Find out the widest dimension of the far-field region and its
00414     // length.
00415     double far_field_widest_width = 
00416       bounds_aux::MaxSideLengthOfBoundingBox(far_field_region);
00417     double local_field_widest_width =
00418       bounds_aux::MaxSideLengthOfBoundingBox(local_field_region);
00419     
00420     double two_bandwidth = 2 * sqrt(kernel_.bandwidth_sq());
00421     double r = (far_field_widest_width + local_field_widest_width) / 
00422       two_bandwidth;
00423     
00424     double r_raised_to_p_alpha = 1.0;
00425     double ret;
00426     int p_alpha = 0;
00427     
00428     do {
00429       
00430       if(p_alpha > max_order - 1) {
00431         return -1;
00432       }
00433 
00434       r_raised_to_p_alpha *= r;
00435       frontfactor /= sqrt(p_alpha + 1);
00436       
00437       ret = frontfactor * r_raised_to_p_alpha;
00438     
00439       if(ret > max_error) {
00440         p_alpha++;
00441       }
00442       else {
00443         break;
00444       }
00445     } while(1);
00446 
00447     *actual_error = ret;
00448     return p_alpha;
00449   }
00450 
00451   template<typename TBound>
00452   int OrderForEvaluatingFarField(const TBound &far_field_region, 
00453                                  const TBound &local_field_region, 
00454                                  double min_dist_sqd_regions,
00455                                  double max_dist_sqd_regions, 
00456                                  double max_error, 
00457                                  double *actual_error) const {
00458 
00459     double frontfactor = 
00460       exp(-min_dist_sqd_regions / (4 * kernel_.bandwidth_sq()));
00461     int max_order = sea_.get_max_order();
00462 
00463     // Find out the widest dimension of the far-field region and its
00464     // length.
00465     double widest_width = 
00466       bounds_aux::MaxSideLengthOfBoundingBox(far_field_region);
00467   
00468     double two_bandwidth = 2 * sqrt(kernel_.bandwidth_sq());
00469     double r = widest_width / two_bandwidth;
00470 
00471     double r_raised_to_p_alpha = 1.0;
00472     double ret;
00473     int p_alpha = 0;
00474 
00475     do {
00476 
00477       if(p_alpha > max_order - 1) {
00478         return -1;
00479       }
00480 
00481       r_raised_to_p_alpha *= r;
00482       frontfactor /= sqrt(p_alpha + 1);
00483       
00484       ret = frontfactor * r_raised_to_p_alpha;
00485     
00486       if(ret > max_error) {
00487         p_alpha++;
00488       }
00489       else {
00490         break;
00491       }
00492     } while(1);
00493 
00494     *actual_error = ret;
00495     return p_alpha;
00496   }
00497 
00498   template<typename TBound>
00499   int OrderForConvertingFromFarFieldToLocal
00500   (const TBound &far_field_region, const TBound &local_field_region, 
00501    double min_dist_sqd_regions, double max_dist_sqd_regions, double max_error, 
00502    double *actual_error) const {
00503     
00504     // Find out the maximum side length of the reference and the query
00505     // regions.
00506     double max_ref_length = 
00507       bounds_aux::MaxSideLengthOfBoundingBox(far_field_region);
00508     double max_query_length =
00509       bounds_aux::MaxSideLengthOfBoundingBox(local_field_region);
00510   
00511     double two_times_bandwidth = sqrt(kernel_.bandwidth_sq()) * 2;
00512     double r_R = max_ref_length / two_times_bandwidth;
00513     double r_Q = max_query_length / two_times_bandwidth;
00514 
00515     int p_alpha = -1;
00516     double r_Q_raised_to_p = 1.0;
00517     double r_R_raised_to_p = 1.0;
00518     double ret2;
00519     double frontfactor =
00520       exp(-min_dist_sqd_regions / (4.0 * kernel_.bandwidth_sq()));
00521     double first_factorial = 1.0;
00522     double second_factorial = 1.0;
00523     double r_Q_raised_to_p_cumulative = 1;
00524 
00525     do {
00526       p_alpha++;
00527 
00528       if(p_alpha > sea_.get_max_order() - 1) {
00529         return -1;
00530       }
00531 
00532       first_factorial *= (p_alpha + 1);
00533       if(p_alpha > 0) {
00534         second_factorial *= sqrt(2 * p_alpha * (2 * p_alpha + 1));
00535       }
00536       r_Q_raised_to_p *= r_Q;
00537       r_R_raised_to_p *= r_R;
00538       
00539       ret2 = frontfactor * 
00540         (1.0 / first_factorial * r_R_raised_to_p * second_factorial * 
00541          r_Q_raised_to_p_cumulative +
00542          1.0 / sqrt(first_factorial) * r_Q_raised_to_p);
00543 
00544       r_Q_raised_to_p_cumulative += r_Q_raised_to_p / 
00545         ((p_alpha > 0) ? (first_factorial / (p_alpha + 1)):first_factorial);
00546 
00547     } while(ret2 >= max_error);
00548 
00549     *actual_error = ret2;
00550     return p_alpha;
00551   }
00552 
00553   template<typename TBound>
00554   int OrderForEvaluatingLocal
00555   (const TBound &far_field_region, const TBound &local_field_region, 
00556    double min_dist_sqd_regions, double max_dist_sqd_regions, double max_error, 
00557    double *actual_error) const {
00558     
00559     double frontfactor =
00560       exp(-min_dist_sqd_regions / (4 * kernel_.bandwidth_sq()));
00561     int max_order = sea_.get_max_order();
00562   
00563     // Find out the widest dimension of the local field region and its
00564     // length.
00565     double widest_width =
00566       bounds_aux::MaxSideLengthOfBoundingBox(local_field_region);
00567   
00568     double two_bandwidth = 2 * sqrt(kernel_.bandwidth_sq());
00569     double r = widest_width / two_bandwidth;
00570 
00571     double r_raised_to_p_alpha = 1.0;
00572     double ret;
00573     int p_alpha = 0;
00574   
00575     do {
00576     
00577       if(p_alpha > max_order - 1) {
00578         return -1;
00579       }
00580     
00581       r_raised_to_p_alpha *= r;
00582       frontfactor /= sqrt(p_alpha + 1);
00583     
00584       ret = frontfactor * r_raised_to_p_alpha;
00585     
00586       if(ret > max_error) {
00587         p_alpha++;
00588       }
00589       else {
00590         break;
00591       }
00592     } while(1);
00593   
00594     *actual_error = ret;
00595     return p_alpha;
00596   }
00597 };
00598 
00602 class EpanKernelAux {
00603   
00604  public:
00605 
00606   typedef EpanKernel TKernel;
00607 
00608   typedef SeriesExpansionAux TSeriesExpansionAux;
00609 
00610   typedef FarFieldExpansion<EpanKernelAux> TFarFieldExpansion;
00611   
00612   typedef LocalExpansion<EpanKernelAux> TLocalExpansion;
00613 
00614   TKernel kernel_;
00615   
00616   TSeriesExpansionAux sea_;
00617 
00618   InversePowDistKernelAux squared_component_;
00619 
00620   OT_DEF_BASIC(EpanKernelAux) {
00621     OT_MY_OBJECT(kernel_);
00622     OT_MY_OBJECT(sea_);
00623     OT_MY_OBJECT(squared_component_);
00624   }
00625 
00626  public:
00627 
00628   void Init(double bandwidth, int max_order, int dim) {
00629     kernel_.Init(bandwidth);
00630     sea_.Init(max_order, dim);
00631 
00632     // This is for doing an expansion on $||x||^2$ part.
00633     squared_component_.Init(-2, max_order, dim);
00634   }
00635 
00636   double BandwidthFactor(double bandwidth_sq) const {
00637     return sqrt(bandwidth_sq);
00638   }
00639 
00640   void AllocateDerivativeMap(int dim, int order, 
00641                              Matrix *derivative_map) const {
00642     derivative_map->Init(sea_.get_total_num_coeffs(order), 1);
00643   }
00644 
00645   void ComputeDirectionalDerivatives(const Vector &x, 
00646                                      Matrix *derivative_map, int order) const {
00647     
00648     // Compute the derivatives for $||x||^2$ and negate it. Then, add
00649     // $(1, 0, 0, ... 0)$ to it.
00650     squared_component_.ComputeDirectionalDerivatives(x, derivative_map, order);
00651     
00652     la::Scale(derivative_map->n_rows(), -1, derivative_map->GetColumnPtr(0));
00653 
00654     (derivative_map->GetColumnPtr(0))[0] += 1.0;
00655   }
00656 
00657   double ComputePartialDerivative(const Matrix &derivative_map,
00658                                   const ArrayList<int> &mapping) const {
00659 
00660     return derivative_map.get(sea_.ComputeMultiindexPosition(mapping), 0);
00661   }
00662 
00663   template<typename TBound>
00664   int OrderForEvaluatingFarField
00665   (const TBound &far_field_region, const TBound &local_field_region, 
00666    double min_dist_sqd_regions, double max_dist_sqd_regions, 
00667    double max_error, double *actual_error) const {
00668 
00669     // first check that the maximum distances between the two regions are
00670     // within the bandwidth, otherwise the expansion is not valid
00671     if(max_dist_sqd_regions > kernel_.bandwidth_sq()) {
00672       return -1;
00673     }
00674 
00675     // Find out the widest dimension and its length of the far-field
00676     // region.
00677     double widest_width =
00678       bounds_aux::MaxSideLengthOfBoundingBox(far_field_region);
00679   
00680     // Find out the max distance between query and reference region in L1
00681     // sense
00682     int dim;
00683     double farthest_distance_manhattan =
00684       bounds_aux::MaxL1Distance(far_field_region, local_field_region, &dim);
00685 
00686     // divide by the two times the bandwidth to find out how wide it is
00687     // in terms of the bandwidth
00688     double two_bandwidth = 2 * sqrt(kernel_.bandwidth_sq());
00689     double r = widest_width / two_bandwidth;
00690     farthest_distance_manhattan /= sqrt(kernel_.bandwidth_sq());
00691 
00692     // try the 0-th order approximation first
00693     double error = 2 * dim * farthest_distance_manhattan * r;
00694     if(error < max_error) {
00695       *actual_error = error;
00696       return 0;
00697     }
00698 
00699     // try the 1st order approximation later
00700     error = dim * r * r;
00701     if(error < max_error) {
00702       *actual_error = error;
00703       return 1;
00704     }
00705 
00706     // failing all above, take up to 2nd terms
00707     *actual_error = 0;
00708     return 2;
00709   }
00710 
00711   template<typename TBound>
00712   int OrderForConvertingFromFarFieldToLocal
00713   (const TBound &far_field_region, const TBound &local_field_region, 
00714    double min_dist_sqd_regions, double max_dist_sqd_regions, double max_error, 
00715    double *actual_error) const {
00716         
00717     // first check that the maximum distances between the two regions are
00718     // within the bandwidth, otherwise the expansion is not valid
00719     if(max_dist_sqd_regions > kernel_.bandwidth_sq() ||
00720        min_dist_sqd_regions == 0) {
00721       return -1;
00722     }
00723     else {
00724       *actual_error = 0;
00725       return 2;
00726     }
00727   }
00728   
00729   template<typename TBound>
00730   int OrderForEvaluatingLocal
00731   (const TBound &far_field_region, 
00732    const TBound &local_field_region, 
00733    double min_dist_sqd_regions, double max_dist_sqd_regions, 
00734    double max_error, double *actual_error) const {
00735     
00736     // first check that the maximum distances between the two regions are
00737     // within the bandwidth, otherwise the expansion is not valid
00738     if(max_dist_sqd_regions > kernel_.bandwidth_sq()) {
00739       return -1;
00740     }
00741 
00742     // Find out the widest dimension and its length of the local
00743     // region.
00744     double widest_width =
00745       bounds_aux::MaxSideLengthOfBoundingBox(local_field_region);
00746   
00747     // Find out the max distance between query and reference region in L1
00748     // sense
00749     int dim;
00750     double farthest_distance_manhattan =
00751       bounds_aux::MaxL1Distance(far_field_region, local_field_region, &dim);
00752 
00753     // divide by the two times the bandwidth to find out how wide it is
00754     // in terms of the bandwidth
00755     double two_bandwidth = 2 * sqrt(kernel_.bandwidth_sq());
00756     double r = widest_width / two_bandwidth;
00757     farthest_distance_manhattan /= sqrt(kernel_.bandwidth_sq());
00758 
00759     // try the 0-th order approximation first
00760     double error = 2 * dim * farthest_distance_manhattan * r;
00761     if(error < max_error) {
00762       *actual_error = error;
00763       return 0;
00764     }
00765 
00766     // try the 1st order approximation later
00767     error = dim * math::Sqr(farthest_distance_manhattan);
00768     if(error < max_error) {
00769       *actual_error = error;
00770       return 1;
00771     }
00772 
00773     // failing all above, take up to 2nd terms
00774     *actual_error = 0;
00775     return 2;
00776   }
00777 };
00778 
00779 #endif
Generated on Mon Jan 24 12:04:38 2011 for FASTlib by  doxygen 1.6.3