gsl_miser.h

00001 /*
00002   -------------------------------------------------------------------
00003   
00004   Copyright (C) 2006, 2007, 2008, Andrew W. Steiner
00005   
00006   This file is part of O2scl.
00007   
00008   O2scl is free software; you can redistribute it and/or modify
00009   it under the terms of the GNU General Public License as published by
00010   the Free Software Foundation; either version 3 of the License, or
00011   (at your option) any later version.
00012   
00013   O2scl is distributed in the hope that it will be useful,
00014   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016   GNU General Public License for more details.
00017   
00018   You should have received a copy of the GNU General Public License
00019   along with O2scl. If not, see <http://www.gnu.org/licenses/>.
00020 
00021   -------------------------------------------------------------------
00022 */
00023 #ifndef O2SCL_GSL_MISER_H
00024 #define O2SCL_GSL_MISER_H
00025 
00026 #include <iostream>
00027 #include <o2scl/collection.h>
00028 #include <o2scl/mcarlo_inte.h>
00029 #include <o2scl/gsl_rnga.h>
00030 #include <gsl/gsl_math.h>
00031 #include <gsl/gsl_monte.h>
00032 #include <gsl/gsl_machine.h>
00033 #include <gsl/gsl_monte_miser.h>
00034 
00035 #ifndef DOXYGENP
00036 namespace o2scl {
00037 #endif
00038   
00039   /** 
00040       \brief Multidimensional integration using Miser Miser Carlo (GSL)
00041 
00042       \todo Document the fact that min_calls and min_calls_per_bi
00043       need to be set beforehand
00044   */
00045   template<class param_t, class func_t=multi_funct<param_t>, 
00046     class rng_t=gsl_rnga, class vec_t=ovector_view, class alloc_vec_t=ovector,
00047     class alloc_t=ovector_alloc> class gsl_miser : 
00048   public mcarlo_inte<param_t,func_t,rng_t,vec_t> {
00049 
00050     public:
00051 
00052     /** 
00053         \brief Introduce random variation into bisection (default 0.0)
00054 
00055         From GSL documentation:
00056         \verbatim
00057         This parameter introduces a random fractional variation of size
00058         DITHER into each bisection, which can be used to break the
00059         symmetry of integrands which are concentrated near the exact
00060         center of the hypercubic integration region.  The default value of
00061         dither is zero, so no variation is introduced. If needed, a
00062         typical value of DITHER is 0.1.
00063         \endverbatim
00064     */
00065     double dither;
00066 
00067     /** 
00068         \brief Specify fraction of function calls for estimating variance
00069         
00070         From GSL documentation:
00071         \verbatim
00072         This parameter specifies the fraction of the currently available
00073         number of function calls which are allocated to estimating the
00074         variance at each recursive step. The default value is 0.1.
00075         \endverbatim
00076     */
00077     double estimate_frac;
00078 
00079     /** 
00080         \brief How estimated variances for two sub-regions are combined
00081 
00082         From GSL documentation:
00083         \verbatim
00084         This parameter controls how the estimated variances for the two
00085         sub-regions of a bisection are combined when allocating points.
00086         With recursive sampling the overall variance should scale better
00087         than 1/N, since the values from the sub-regions will be obtained
00088         using a procedure which explicitly minimizes their variance.  To
00089         accommodate this behavior the MISER algorithm allows the total
00090         variance to depend on a scaling parameter \alpha,
00091         
00092         \Var(f) = {\sigma_a \over N_a^\alpha} + {\sigma_b \over N_b^\alpha}.
00093         
00094         The authors of the original paper describing MISER recommend the
00095         value \alpha = 2 as a good choice, obtained from numerical
00096         experiments, and this is used as the default value in this
00097         implementation.
00098         \endverbatim
00099     */
00100     double alpha;
00101 
00102     /** 
00103         \brief Minimum number of calls to estimate the variance
00104         (default 100)
00105 
00106         From GSL documentation:
00107         \verbatim
00108         This parameter specifies the minimum number of function calls
00109         required for each estimate of the variance. If the number of
00110         function calls allocated to the estimate using ESTIMATE_FRAC falls
00111         below MIN_CALLS then MIN_CALLS are used instead.  This ensures
00112         that each estimate maintains a reasonable level of accuracy.  The
00113         default value of MIN_CALLS is `16 * dim'.
00114         \endverbatim
00115     */
00116     size_t min_calls;
00117 
00118     /** 
00119         \brief Minimum number of calls required to proceed with bisection
00120         (default 4000)
00121 
00122         From GSL documentation:
00123         \verbatim
00124         This parameter specifies the minimum number of function calls
00125         required to proceed with a bisection step.  When a recursive step
00126         has fewer calls available than MIN_CALLS_PER_BISECTION it performs
00127         a plain Monte Carlo estimate of the current sub-region and
00128         terminates its branch of the recursion.  The default value of this
00129         parameter is `32 * min_calls'.
00130         \endverbatim
00131     */
00132     size_t min_calls_per_bisection;
00133 
00134 #ifndef DOXYGEN_INTERNAL
00135 
00136     protected:
00137 
00138     /// Desc
00139     size_t dim;
00140     /// Desc
00141     int estimate_style;
00142     /// Desc
00143     int depth;
00144     /// Desc
00145     int verbose;
00146     /// Desc
00147     double *xmid;
00148     /// Desc
00149     double *sigma_l;
00150     /// Desc
00151     double *sigma_r;
00152     /// Desc
00153     double *fmax_l;
00154     /// Desc
00155     double *fmax_r;
00156     /// Desc
00157     double *fmin_l;
00158     /// Desc
00159     double *fmin_r;
00160     /// Desc
00161     double *fsum_l;
00162     /// Desc
00163     double *fsum_r;
00164     /// Desc
00165     double *fsum2_l;
00166     /// Desc
00167     double *fsum2_r;
00168     /// Desc
00169     size_t *hits_l;
00170     /// Desc
00171     size_t *hits_r;
00172     
00173     /// Desc
00174     virtual int estimate_corrmc(func_t &func, size_t ndim,
00175                                 const vec_t &xl, const vec_t &xu,
00176                                 param_t &pa, size_t calls, double &res,
00177                                 double &err, const double lxmid[],
00178                                 double lsigma_l[], double lsigma_r[]) {
00179       size_t i, n;
00180       
00181       double m = 0.0, q = 0.0;
00182       double vol = 1.0;
00183 
00184       for (i = 0; i < dim; i++) {
00185         vol *= xu[i] - xl[i];
00186         hits_l[i] = hits_r[i] = 0;
00187         fsum_l[i] = fsum_r[i] = 0.0;
00188         fsum2_l[i] = fsum2_r[i] = 0.0;
00189         lsigma_l[i] = lsigma_r[i] = -1;
00190       }
00191 
00192       for (n = 0; n < calls; n++) {
00193         double fval;
00194 
00195         unsigned int j = (n/2) % dim;
00196         unsigned int side = (n % 2);
00197 
00198         for (i = 0; i < dim; i++) {
00199 
00200           // The equivalent of gsl_rng_uniform_pos()
00201           double z;
00202           do { z=this->def_rng.random(); } while (z==0);
00203           
00204           if (i != j) {
00205             x[i] = xl[i] + z * (xu[i] - xl[i]);
00206           } else {
00207             if (side == 0) {
00208               x[i] = lxmid[i] + z * (xu[i] - lxmid[i]);
00209             } else {
00210               x[i] = xl[i] + z * (lxmid[i] - xl[i]);
00211             }
00212           }
00213         }
00214         
00215         //fval = GSL_MONTE_FN_EVAL (f, x);
00216         func(ndim,x,fval,pa);
00217         
00218         /* recurrence for mean and variance */
00219         {
00220           double d = fval - m;
00221           m += d / (n + 1.0);
00222           q += d * d * (n / (n + 1.0));
00223         }
00224 
00225         /* compute the variances on each side of the bisection */
00226         for (i = 0; i < dim; i++) {
00227           if (x[i] <= lxmid[i]) {
00228             fsum_l[i] += fval;
00229             fsum2_l[i] += fval * fval;
00230             hits_l[i]++;
00231           } else {
00232             fsum_r[i] += fval;
00233             fsum2_r[i] += fval * fval;
00234             hits_r[i]++;
00235           }
00236         }
00237       }
00238 
00239       for (i = 0; i < dim; i++) {
00240         double fraction_l = (lxmid[i] - xl[i]) / (xu[i] - xl[i]);
00241 
00242         if (hits_l[i] > 0) {
00243           fsum_l[i] /= hits_l[i];
00244           lsigma_l[i] = sqrt (fsum2_l[i] - fsum_l[i] * fsum_l[i] / hits_l[i]);
00245           lsigma_l[i] *= fraction_l * vol / hits_l[i];
00246         }
00247         
00248         if (hits_r[i] > 0) {
00249           fsum_r[i] /= hits_r[i];
00250           lsigma_r[i] = sqrt (fsum2_r[i] - fsum_r[i] * fsum_r[i] / hits_r[i]);
00251           lsigma_r[i] *= (1 - fraction_l) * vol / hits_r[i];
00252         }
00253       }
00254       
00255       res = vol * m;
00256       
00257       if (calls < 2) {
00258         err = GSL_POSINF;
00259       } else {
00260         err = vol * sqrt (q / (calls * (calls - 1.0)));
00261       }
00262       
00263       return GSL_SUCCESS;
00264     }
00265 
00266     /// Desc
00267     alloc_t ao;
00268 
00269     /// Desc
00270     alloc_vec_t x;
00271 
00272 #endif
00273     
00274     public:
00275     
00276     gsl_miser() {
00277       estimate_frac=0.1;
00278       alpha=2.0;
00279       dither=0.0;
00280       min_calls=100;
00281       min_calls_per_bisection=4000;
00282     }
00283     
00284     /// Allocate memory
00285     virtual int allocate(size_t ldim) {
00286 
00287       ao.allocate(x,ldim);
00288        
00289       xmid = (double *) malloc (ldim * sizeof (double));
00290       if (xmid == 0) {
00291         ao.free(x);
00292         GSL_ERROR_VAL ("failed to allocate space for xmid", GSL_ENOMEM, 0);
00293       }
00294 
00295       sigma_l = (double *) malloc (ldim * sizeof (double));
00296       if (sigma_l == 0) {
00297         std::free(xmid);
00298         ao.free(x);
00299         GSL_ERROR_VAL ("failed to allocate space for sigma_l", 
00300                        GSL_ENOMEM, 0);
00301       }
00302 
00303       sigma_r = (double *) malloc (ldim * sizeof (double));
00304       if (sigma_r == 0) {
00305         std::free(sigma_l);
00306         std::free(xmid);
00307         ao.free(x);
00308         GSL_ERROR_VAL ("failed to allocate space for sigma_r", 
00309                        GSL_ENOMEM, 0);
00310       }
00311 
00312       fmax_l = (double *) malloc (ldim * sizeof (double));
00313       if (fmax_l == 0) {
00314         std::free(sigma_r);
00315         std::free(sigma_l);
00316         std::free(xmid);
00317         ao.free(x);
00318         GSL_ERROR_VAL ("failed to allocate space for fmax_l", GSL_ENOMEM, 0);
00319       }
00320 
00321       fmax_r = (double *) malloc (ldim * sizeof (double));
00322       if (fmax_r == 0) {
00323         std::free(fmax_l);
00324         std::free(sigma_r);
00325         std::free(sigma_l);
00326         std::free(xmid);
00327         ao.free(x);
00328         GSL_ERROR_VAL ("failed to allocate space for fmax_r", GSL_ENOMEM, 0);
00329       }
00330 
00331       fmin_l = (double *) malloc (ldim * sizeof (double));
00332       if (fmin_l == 0) {
00333         std::free(fmax_r);
00334         std::free(fmax_l);
00335         std::free(sigma_r);
00336         std::free(sigma_l);
00337         std::free(xmid);
00338         ao.free(x);
00339         GSL_ERROR_VAL ("failed to allocate space for fmin_l", GSL_ENOMEM, 0);
00340       }
00341 
00342       fmin_r = (double *) malloc (ldim * sizeof (double));
00343       if (fmin_r == 0) {
00344         std::free(fmin_l);
00345         std::free(fmax_r);
00346         std::free(fmax_l);
00347         std::free(sigma_r);
00348         std::free(sigma_l);
00349         std::free(xmid);
00350         ao.free(x);
00351         GSL_ERROR_VAL ("failed to allocate space for fmin_r", GSL_ENOMEM, 0);
00352       }
00353 
00354       fsum_l = (double *) malloc (ldim * sizeof (double));
00355       if (fsum_l == 0) {
00356         std::free(fmin_r);
00357         std::free(fmin_l);
00358         std::free(fmax_r);
00359         std::free(fmax_l);
00360         std::free(sigma_r);
00361         std::free(sigma_l);
00362         std::free(xmid);
00363         ao.free(x);
00364         GSL_ERROR_VAL ("failed to allocate space for fsum_l", GSL_ENOMEM, 0);
00365       }
00366 
00367       fsum_r = (double *) malloc (ldim * sizeof (double));
00368       if (fsum_r == 0) {
00369         std::free(fsum_l);
00370         std::free(fmin_r);
00371         std::free(fmin_l);
00372         std::free(fmax_r);
00373         std::free(fmax_l);
00374         std::free(sigma_r);
00375         std::free(sigma_l);
00376         std::free(xmid);
00377         ao.free(x);
00378         GSL_ERROR_VAL ("failed to allocate space for fsum_r", GSL_ENOMEM, 0);
00379       }
00380 
00381       fsum2_l = (double *) malloc (ldim * sizeof (double));
00382       if (fsum2_l == 0) {
00383         std::free(fsum_r);
00384         std::free(fsum_l);
00385         std::free(fmin_r);
00386         std::free(fmin_l);
00387         std::free(fmax_r);
00388         std::free(fmax_l);
00389         std::free(sigma_r);
00390         std::free(sigma_l);
00391         std::free(xmid);
00392         ao.free(x);
00393         GSL_ERROR_VAL ("failed to allocate space for fsum2_l", 
00394                        GSL_ENOMEM, 0);
00395       }
00396 
00397       fsum2_r = (double *) malloc (ldim * sizeof (double));
00398       if (fsum2_r == 0) {
00399         std::free(fsum2_l);
00400         std::free(fsum_r);
00401         std::free(fsum_l);
00402         std::free(fmin_r);
00403         std::free(fmin_l);
00404         std::free(fmax_r);
00405         std::free(fmax_l);
00406         std::free(sigma_r);
00407         std::free(sigma_l);
00408         std::free(xmid);
00409         ao.free(x);
00410         GSL_ERROR_VAL ("failed to allocate space for fsum2_r", 
00411                        GSL_ENOMEM, 0);
00412       }
00413 
00414 
00415       hits_r = (size_t *) malloc (ldim * sizeof (size_t));
00416       if (hits_r == 0) {
00417         std::free(fsum2_r);
00418         std::free(fsum2_l);
00419         std::free(fsum_r);
00420         std::free(fsum_l);
00421         std::free(fmin_r);
00422         std::free(fmin_l);
00423         std::free(fmax_r);
00424         std::free(fmax_l);
00425         std::free(sigma_r);
00426         std::free(sigma_l);
00427         std::free(xmid);
00428         ao.free(x);
00429         GSL_ERROR_VAL ("failed to allocate space for fsum2_r", 
00430                        GSL_ENOMEM, 0);
00431       }
00432 
00433       hits_l = (size_t *) malloc (ldim * sizeof (size_t));
00434       if (hits_l == 0) {
00435         std::free(hits_r);
00436         std::free(fsum2_r);
00437         std::free(fsum2_l);
00438         std::free(fsum_r);
00439         std::free(fsum_l);
00440         std::free(fmin_r);
00441         std::free(fmin_l);
00442         std::free(fmax_r);
00443         std::free(fmax_l);
00444         std::free(sigma_r);
00445         std::free(sigma_l);
00446         std::free(xmid);
00447         ao.free(x);
00448         GSL_ERROR_VAL ("failed to allocate space for fsum2_r", 
00449                        GSL_ENOMEM, 0);
00450       }
00451 
00452       dim = ldim;
00453 
00454       return 0;
00455     }
00456 
00457     /// Free allocated memory
00458     virtual int free() {
00459       std::free(hits_r);
00460       std::free(hits_l);
00461       std::free(fsum2_r);
00462       std::free(fsum2_l);
00463       std::free(fsum_r);
00464       std::free(fsum_l);
00465       std::free(fmin_r);
00466       std::free(fmin_l);
00467       std::free(fmax_r);
00468       std::free(fmax_l);
00469       std::free(sigma_r);
00470       std::free(sigma_l);
00471       std::free(xmid);
00472       ao.free(x);
00473       return 0;
00474     }
00475 
00476     /** 
00477         \brief Integrate function \c func from x=a to x=b.
00478     */
00479     virtual int miser_minteg_err(func_t &func, size_t ndim, const vec_t &xl, 
00480                                  const vec_t &xu, size_t calls, param_t &pa,
00481                                  double &res, double &err) {
00482       
00483       size_t n, estimate_calls, calls_l, calls_r;
00484       size_t i;
00485       size_t i_bisect;
00486       int found_best;
00487 
00488       double res_est = 0, err_est = 0;
00489       double res_r = 0, err_r = 0, res_l = 0, err_l = 0;
00490       double xbi_l, xbi_m, xbi_r, s;
00491 
00492       double vol;
00493       double weight_l, weight_r;
00494 
00495       for (i = 0; i < dim; i++) {
00496         if (xu[i] <= xl[i])         {
00497           GSL_ERROR ("xu must be greater than xl", GSL_EINVAL);
00498         }
00499 
00500         if (xu[i] - xl[i] > GSL_DBL_MAX)            {
00501           GSL_ERROR ("Range of integration is too large, please rescale",
00502                      GSL_EINVAL);
00503         }
00504       }
00505 
00506       if (alpha < 0)    {
00507         GSL_ERROR ("alpha must be non-negative", GSL_EINVAL);
00508       }
00509 
00510       /* Compute volume */
00511 
00512       vol = 1;
00513 
00514       for (i = 0; i < dim; i++) {
00515         vol *= xu[i] - xl[i];
00516       }
00517 
00518       if (calls < min_calls_per_bisection) {
00519         double m = 0.0, q = 0.0;
00520 
00521         if (calls < 2) {
00522           GSL_ERROR ("insufficient calls for subvolume", GSL_EFAILED);
00523         }
00524 
00525         for (n = 0; n < calls; n++) {
00526           /* Choose a random point in the integration region */
00527 
00528           for (i = 0; i < dim; i++) {
00529             
00530             // The equivalent of gsl_rng_uniform_pos()
00531             double rdn;
00532             do { rdn=this->def_rng.random(); } while (rdn==0);
00533 
00534             x[i] = xl[i] + rdn * (xu[i] - xl[i]);
00535           }
00536 
00537           {
00538             double fval;
00539             func(ndim,x,fval,pa);
00540             
00541             /* recurrence for mean and variance */
00542 
00543             double d = fval - m;
00544             m += d / (n + 1.0);
00545             q += d * d * (n / (n + 1.0));
00546           }
00547         }
00548 
00549         res = vol * m;
00550 
00551         err = vol * sqrt (q / (calls * (calls - 1.0)));
00552 
00553         return GSL_SUCCESS;
00554       }
00555       
00556       // We explicitly make the typecast here
00557       estimate_calls=((size_t)GSL_MAX(min_calls,calls*(estimate_frac)));
00558       
00559       if (estimate_calls < 4 * dim) {
00560         GSL_ERROR ("insufficient calls to sample all halfspaces", GSL_ESANITY);
00561       }
00562 
00563       /* Flip coins to bisect the integration region with some fuzz */
00564 
00565       for (i = 0; i < dim; i++) {
00566         s=(this->def_rng.random()-0.5) >= 0.0 ? dither : -dither;
00567         xmid[i] = (0.5 + s) * xl[i] + (0.5 - s) * xu[i];
00568       }
00569 
00570       /* 
00571          The idea is to chose the direction to bisect based on which will
00572          give the smallest total variance.  We could (and may do so later)
00573          use MC to compute these variances.  But the NR guys simply estimate
00574          the variances by finding the min and max function values
00575          for each half-region for each bisection. 
00576       */
00577       
00578       estimate_corrmc(func,dim,xl,xu,pa,estimate_calls,
00579                       res_est,err_est,xmid,sigma_l,sigma_r);
00580 
00581       /* We have now used up some calls for the estimation */
00582 
00583       calls -= estimate_calls;
00584 
00585       /* Now find direction with the smallest total "variance" */
00586 
00587       {
00588         double best_var = GSL_DBL_MAX;
00589         double beta = 2.0 / (1.0 + alpha);
00590         found_best = 0;
00591         i_bisect = 0;
00592         weight_l = weight_r = 1.0;
00593 
00594         for (i = 0; i < dim; i++) {
00595           if (sigma_l[i] >= 0 && sigma_r[i] >= 0) {
00596             /* estimates are okay */
00597             double var = pow (sigma_l[i], beta) + pow (sigma_r[i], beta);
00598             
00599             if (var <= best_var) {
00600               found_best = 1;
00601               best_var = var;
00602               i_bisect = i;
00603               weight_l = pow (sigma_l[i], beta);
00604               weight_r = pow (sigma_r[i], beta);
00605             }
00606           } else {
00607             if (sigma_l[i] < 0) {
00608               GSL_ERROR ("no points in left-half space!", GSL_ESANITY);
00609             }
00610             if (sigma_r[i] < 0) {
00611               GSL_ERROR ("no points in right-half space!", GSL_ESANITY);
00612             }
00613           }
00614         }
00615       }
00616       
00617       if (!found_best)  {
00618         /* All estimates were the same, so chose a direction at random */
00619         
00620         i_bisect = this->def_rng.random_int(dim);
00621       }
00622 
00623       xbi_l = xl[i_bisect];
00624       xbi_m = xmid[i_bisect];
00625       xbi_r = xu[i_bisect];
00626 
00627       /* Get the actual fractional sizes of the two "halves", and
00628          distribute the remaining calls among them */
00629 
00630       {
00631         double fraction_l = fabs ((xbi_m - xbi_l) / (xbi_r - xbi_l));
00632         double fraction_r = 1 - fraction_l;
00633 
00634         double a = fraction_l * weight_l;
00635         double b = fraction_r * weight_r;
00636 
00637         calls_l = (size_t)(min_calls + (calls - 2 * min_calls) * a / (a + b));
00638         calls_r = (size_t)(min_calls + (calls - 2 * min_calls) * b / (a + b));
00639       }
00640 
00641       /* Compute the integral for the left hand side of the bisection */
00642 
00643       /* Due to the recursive nature of the algorithm we must allocate
00644          some new memory for the integration limits for each recursive call */
00645 
00646       {
00647         int status;
00648         
00649         alloc_vec_t xu_tmp;
00650         ao.allocate(xu_tmp,dim);
00651         
00652         for (i = 0; i < dim; i++) {
00653           xu_tmp[i] = xu[i];
00654         }
00655         
00656         xu_tmp[i_bisect] = xbi_m;
00657         
00658         status=miser_minteg_err(func,dim,xl,xu_tmp,calls_l,pa,res_l,err_l);
00659 
00660         ao.free(xu_tmp);
00661 
00662         if (status != GSL_SUCCESS) {
00663           return status;
00664         }
00665       }
00666 
00667       /* Compute the integral for the right hand side of the bisection */
00668 
00669       {
00670         int status;
00671 
00672         alloc_vec_t xl_tmp;
00673         ao.allocate(xl_tmp,dim);
00674 
00675         for (i = 0; i < dim; i++) {
00676           xl_tmp[i] = xl[i];
00677         }
00678 
00679         xl_tmp[i_bisect] = xbi_m;
00680 
00681         status=miser_minteg_err(func,dim,xl_tmp,xu,calls_r,pa,res_r,err_r);
00682         
00683         ao.free(xl_tmp);
00684 
00685         if (status != GSL_SUCCESS) {
00686           return status;
00687         }
00688       }
00689 
00690       res=res_l+res_r;
00691       err=sqrt(err_l*err_l+err_r*err_r);
00692       
00693       return 0;
00694     }
00695     
00696     virtual ~gsl_miser() {}
00697     
00698     /// Integrate function \c func from x=a to x=b.
00699     virtual int minteg_err(func_t &func, size_t ndim, const vec_t &a, 
00700                            const vec_t &b, param_t &pa, double &res, 
00701                            double &err) {
00702       allocate(ndim);
00703       min_calls=16*ndim;
00704       min_calls_per_bisection=32*min_calls;
00705       int ret=miser_minteg_err(func,ndim,a,b,this->n_points,pa,res,err);
00706       free();
00707       return ret;
00708     }
00709     
00710     /// Return string denoting type ("gsl_miser")
00711     virtual const char *type() { return "gsl_miser"; }
00712     
00713   };
00714   
00715 #ifndef DOXYGENP
00716 }
00717 #endif
00718 
00719 #endif
00720 

Documentation generated with Doxygen and provided under the GNU Free Documentation License. See License Information for details.

Project hosting provided by SourceForge.net Logo, O2scl Sourceforge Project Page