quad.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 1996-2012 John W. Eaton
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, see
00019 <http://www.gnu.org/licenses/>.
00020 
00021 */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026 
00027 #include <string>
00028 
00029 #include <iomanip>
00030 #include <iostream>
00031 
00032 #include "Quad.h"
00033 #include "lo-mappers.h"
00034 
00035 #include "defun-dld.h"
00036 #include "error.h"
00037 #include "gripes.h"
00038 #include "pager.h"
00039 #include "oct-obj.h"
00040 #include "ov-fcn.h"
00041 #include "unwind-prot.h"
00042 #include "utils.h"
00043 #include "variables.h"
00044 
00045 #include "Quad-opts.cc"
00046 
00047 #if defined (quad)
00048 #undef quad
00049 #endif
00050 
00051 // Global pointer for user defined function required by quadrature functions.
00052 static octave_function *quad_fcn;
00053 
00054 // Have we warned about imaginary values returned from user function?
00055 static bool warned_imaginary = false;
00056 
00057 // Is this a recursive call?
00058 static int call_depth = 0;
00059 
00060 double
00061 quad_user_function (double x)
00062 {
00063   double retval = 0.0;
00064 
00065   octave_value_list args;
00066   args(0) = x;
00067 
00068   if (quad_fcn)
00069     {
00070       octave_value_list tmp = quad_fcn->do_multi_index_op (1, args);
00071 
00072       if (error_state)
00073         {
00074           quad_integration_error = 1;  // FIXME
00075           gripe_user_supplied_eval ("quad");
00076           return retval;
00077         }
00078 
00079       if (tmp.length () && tmp(0).is_defined ())
00080         {
00081           if (! warned_imaginary && tmp(0).is_complex_type ())
00082             {
00083               warning ("quad: ignoring imaginary part returned from user-supplied function");
00084               warned_imaginary = true;
00085             }
00086 
00087           retval = tmp(0).double_value ();
00088 
00089           if (error_state)
00090             {
00091               quad_integration_error = 1;  // FIXME
00092               gripe_user_supplied_eval ("quad");
00093             }
00094         }
00095       else
00096         {
00097           quad_integration_error = 1;  // FIXME
00098           gripe_user_supplied_eval ("quad");
00099         }
00100     }
00101 
00102   return retval;
00103 }
00104 
00105 float
00106 quad_float_user_function (float x)
00107 {
00108   float retval = 0.0;
00109 
00110   octave_value_list args;
00111   args(0) = x;
00112 
00113   if (quad_fcn)
00114     {
00115       octave_value_list tmp = quad_fcn->do_multi_index_op (1, args);
00116 
00117       if (error_state)
00118         {
00119           quad_integration_error = 1;  // FIXME
00120           gripe_user_supplied_eval ("quad");
00121           return retval;
00122         }
00123 
00124       if (tmp.length () && tmp(0).is_defined ())
00125         {
00126           if (! warned_imaginary && tmp(0).is_complex_type ())
00127             {
00128               warning ("quad: ignoring imaginary part returned from user-supplied function");
00129               warned_imaginary = true;
00130             }
00131 
00132           retval = tmp(0).float_value ();
00133 
00134           if (error_state)
00135             {
00136               quad_integration_error = 1;  // FIXME
00137               gripe_user_supplied_eval ("quad");
00138             }
00139         }
00140       else
00141         {
00142           quad_integration_error = 1;  // FIXME
00143           gripe_user_supplied_eval ("quad");
00144         }
00145     }
00146 
00147   return retval;
00148 }
00149 
00150 #define QUAD_ABORT() \
00151   do \
00152     { \
00153       if (fcn_name.length()) \
00154         clear_function (fcn_name); \
00155       return retval; \
00156     } \
00157   while (0)
00158 
00159 #define QUAD_ABORT1(msg) \
00160   do \
00161     { \
00162       ::error ("quad: " msg); \
00163       QUAD_ABORT (); \
00164     } \
00165   while (0)
00166 
00167 #define QUAD_ABORT2(fmt, arg) \
00168   do \
00169     { \
00170       ::error ("quad: " fmt, arg); \
00171       QUAD_ABORT (); \
00172     } \
00173   while (0)
00174 
00175 DEFUN_DLD (quad, args, nargout,
00176   "-*- texinfo -*-\n\
00177 @deftypefn  {Loadable Function} {@var{q} =} quad (@var{f}, @var{a}, @var{b})\n\
00178 @deftypefnx {Loadable Function} {@var{q} =} quad (@var{f}, @var{a}, @var{b}, @var{tol})\n\
00179 @deftypefnx {Loadable Function} {@var{q} =} quad (@var{f}, @var{a}, @var{b}, @var{tol}, @var{sing})\n\
00180 @deftypefnx {Loadable Function} {[@var{q}, @var{ier}, @var{nfun}, @var{err}] =} quad (@dots{})\n\
00181 Numerically evaluate the integral of @var{f} from @var{a} to @var{b} using\n\
00182 Fortran routines from @w{@sc{quadpack}}.  @var{f} is a function handle,\n\
00183 inline function, or a string containing the name of the function to\n\
00184 evaluate.  The function must have the form @code{y = f (x)} where @var{y} and\n\
00185 @var{x} are scalars.\n\
00186 \n\
00187 @var{a} and @var{b} are the lower and upper limits of integration.  Either\n\
00188 or both may be infinite.\n\
00189 \n\
00190 The optional argument @var{tol} is a vector that specifies the desired\n\
00191 accuracy of the result.  The first element of the vector is the desired\n\
00192 absolute tolerance, and the second element is the desired relative\n\
00193 tolerance.  To choose a relative test only, set the absolute\n\
00194 tolerance to zero.  To choose an absolute test only, set the relative\n\
00195 tolerance to zero.  Both tolerances default to @code{sqrt(eps)} or\n\
00196 approximately @math{1.5e^{-8}}.\n\
00197 \n\
00198 The optional argument @var{sing} is a vector of values at which the\n\
00199 integrand is known to be singular.\n\
00200 \n\
00201 The result of the integration is returned in @var{q}.  @var{ier}\n\
00202 contains an integer error code (0 indicates a successful integration).\n\
00203 @var{nfun} indicates the number of function evaluations that were\n\
00204 made, and @var{err} contains an estimate of the error in the\n\
00205 solution.\n\
00206 \n\
00207 The function @code{quad_options} can set other optional\n\
00208 parameters for @code{quad}.\n\
00209 \n\
00210 Note: because @code{quad} is written in Fortran it cannot be called\n\
00211 recursively.  This prevents its use in integrating over more than one\n\
00212 variable by routines @code{dblquad} and @code{triplequad}.\n\
00213 @seealso{quad_options, quadv, quadl, quadgk, quadcc, trapz, dblquad, triplequad}\n\
00214 @end deftypefn")
00215 {
00216   octave_value_list retval;
00217 
00218   std::string fcn_name;
00219 
00220   warned_imaginary = false;
00221 
00222   unwind_protect frame;
00223 
00224   frame.protect_var (call_depth);
00225   call_depth++;
00226 
00227   if (call_depth > 1)
00228     QUAD_ABORT1 ("invalid recursive call");
00229 
00230   int nargin = args.length ();
00231 
00232   if (nargin > 2 && nargin < 6 && nargout < 5)
00233     {
00234       if (args(0).is_function_handle () || args(0).is_inline_function ())
00235         quad_fcn = args(0).function_value ();
00236       else
00237         {
00238           fcn_name = unique_symbol_name ("__quad_fcn_");
00239           std::string fname = "function y = ";
00240           fname.append (fcn_name);
00241           fname.append ("(x) y = ");
00242           quad_fcn = extract_function (args(0), "quad", fcn_name, fname,
00243                                        "; endfunction");
00244         }
00245 
00246       if (! quad_fcn)
00247         QUAD_ABORT ();
00248 
00249       if (args(1).is_single_type () || args(2).is_single_type ())
00250         {
00251           float a = args(1).float_value ();
00252 
00253           if (error_state)
00254             QUAD_ABORT1 ("expecting second argument to be a scalar");
00255 
00256           float b = args(2).float_value ();
00257 
00258           if (error_state)
00259             QUAD_ABORT1 ("expecting third argument to be a scalar");
00260 
00261           int indefinite = 0;
00262           FloatIndefQuad::IntegralType indef_type = FloatIndefQuad::doubly_infinite;
00263           float bound = 0.0;
00264           if (xisinf (a) && xisinf (b))
00265             {
00266               indefinite = 1;
00267               indef_type = FloatIndefQuad::doubly_infinite;
00268             }
00269           else if (xisinf (a))
00270             {
00271               indefinite = 1;
00272               bound = b;
00273               indef_type = FloatIndefQuad::neg_inf_to_bound;
00274             }
00275           else if (xisinf (b))
00276             {
00277               indefinite = 1;
00278               bound = a;
00279               indef_type = FloatIndefQuad::bound_to_inf;
00280             }
00281 
00282           octave_idx_type ier = 0;
00283           octave_idx_type nfun = 0;
00284           float abserr = 0.0;
00285           float val = 0.0;
00286           bool have_sing = false;
00287           FloatColumnVector sing;
00288           FloatColumnVector tol;
00289 
00290           switch (nargin)
00291             {
00292             case 5:
00293               if (indefinite)
00294                 QUAD_ABORT1 ("singularities not allowed on infinite intervals");
00295 
00296               have_sing = true;
00297 
00298               sing = FloatColumnVector (args(4).float_vector_value ());
00299 
00300               if (error_state)
00301                 QUAD_ABORT1 ("expecting vector of singularities as fourth argument");
00302 
00303             case 4:
00304               tol = FloatColumnVector (args(3).float_vector_value ());
00305 
00306               if (error_state)
00307                 QUAD_ABORT1 ("expecting vector of tolerances as fifth argument");
00308 
00309               switch (tol.capacity ())
00310                 {
00311                 case 2:
00312                   quad_opts.set_single_precision_relative_tolerance (tol (1));
00313 
00314                 case 1:
00315                   quad_opts.set_single_precision_absolute_tolerance (tol (0));
00316                   break;
00317 
00318                 default:
00319                   QUAD_ABORT1 ("expecting tol to contain no more than two values");
00320                 }
00321 
00322             case 3:
00323               if (indefinite)
00324                 {
00325                   FloatIndefQuad iq (quad_float_user_function, bound,
00326                                      indef_type);
00327                   iq.set_options (quad_opts);
00328                   val = iq.float_integrate (ier, nfun, abserr);
00329                 }
00330               else
00331                 {
00332                   if (have_sing)
00333                     {
00334                       FloatDefQuad dq (quad_float_user_function, a, b, sing);
00335                       dq.set_options (quad_opts);
00336                       val = dq.float_integrate (ier, nfun, abserr);
00337                     }
00338                   else
00339                     {
00340                       FloatDefQuad dq (quad_float_user_function, a, b);
00341                       dq.set_options (quad_opts);
00342                       val = dq.float_integrate (ier, nfun, abserr);
00343                     }
00344                 }
00345               break;
00346 
00347             default:
00348               panic_impossible ();
00349               break;
00350             }
00351 
00352           retval(3) = abserr;
00353           retval(2) = nfun;
00354           retval(1) = ier;
00355           retval(0) = val;
00356 
00357         }
00358       else
00359         {
00360           double a = args(1).double_value ();
00361 
00362           if (error_state)
00363             QUAD_ABORT1 ("expecting second argument to be a scalar");
00364 
00365           double b = args(2).double_value ();
00366 
00367           if (error_state)
00368             QUAD_ABORT1 ("expecting third argument to be a scalar");
00369 
00370           int indefinite = 0;
00371           IndefQuad::IntegralType indef_type = IndefQuad::doubly_infinite;
00372           double bound = 0.0;
00373           if (xisinf (a) && xisinf (b))
00374             {
00375               indefinite = 1;
00376               indef_type = IndefQuad::doubly_infinite;
00377             }
00378           else if (xisinf (a))
00379             {
00380               indefinite = 1;
00381               bound = b;
00382               indef_type = IndefQuad::neg_inf_to_bound;
00383             }
00384           else if (xisinf (b))
00385             {
00386               indefinite = 1;
00387               bound = a;
00388               indef_type = IndefQuad::bound_to_inf;
00389             }
00390 
00391           octave_idx_type ier = 0;
00392           octave_idx_type nfun = 0;
00393           double abserr = 0.0;
00394           double val = 0.0;
00395           bool have_sing = false;
00396           ColumnVector sing;
00397           ColumnVector tol;
00398 
00399           switch (nargin)
00400             {
00401             case 5:
00402               if (indefinite)
00403                 QUAD_ABORT1 ("singularities not allowed on infinite intervals");
00404 
00405               have_sing = true;
00406 
00407               sing = ColumnVector (args(4).vector_value ());
00408 
00409               if (error_state)
00410                 QUAD_ABORT1 ("expecting vector of singularities as fourth argument");
00411 
00412             case 4:
00413               tol = ColumnVector (args(3).vector_value ());
00414 
00415               if (error_state)
00416                 QUAD_ABORT1 ("expecting vector of tolerances as fifth argument");
00417 
00418               switch (tol.capacity ())
00419                 {
00420                 case 2:
00421                   quad_opts.set_relative_tolerance (tol (1));
00422 
00423                 case 1:
00424                   quad_opts.set_absolute_tolerance (tol (0));
00425                   break;
00426 
00427                 default:
00428                   QUAD_ABORT1 ("expecting tol to contain no more than two values");
00429                 }
00430 
00431             case 3:
00432               if (indefinite)
00433                 {
00434                   IndefQuad iq (quad_user_function, bound, indef_type);
00435                   iq.set_options (quad_opts);
00436                   val = iq.integrate (ier, nfun, abserr);
00437                 }
00438               else
00439                 {
00440                   if (have_sing)
00441                     {
00442                       DefQuad dq (quad_user_function, a, b, sing);
00443                       dq.set_options (quad_opts);
00444                       val = dq.integrate (ier, nfun, abserr);
00445                     }
00446                   else
00447                     {
00448                       DefQuad dq (quad_user_function, a, b);
00449                       dq.set_options (quad_opts);
00450                       val = dq.integrate (ier, nfun, abserr);
00451                     }
00452                 }
00453               break;
00454 
00455             default:
00456               panic_impossible ();
00457               break;
00458             }
00459 
00460           retval(3) = abserr;
00461           retval(2) = nfun;
00462           retval(1) = ier;
00463           retval(0) = val;
00464         }
00465 
00466       if (fcn_name.length())
00467         clear_function (fcn_name);
00468     }
00469   else
00470     print_usage ();
00471 
00472   return retval;
00473 }
00474 
00475 /*
00476 
00477 %!function y = __f (x)
00478 %! y = x + 1;
00479 %!endfunction
00480 
00481 %!test
00482 %! [v, ier, nfun, err] = quad ("__f", 0, 5);
00483 %! assert(ier == 0 && abs (v - 17.5) < sqrt (eps) && nfun > 0 &&
00484 %!        err < sqrt (eps))
00485 %!test
00486 %! [v, ier, nfun, err] = quad ("__f", single(0), single(5));
00487 %! assert(ier == 0 && abs (v - 17.5) < sqrt (eps ("single")) && nfun > 0 &&
00488 %!        err < sqrt (eps ("single")))
00489 
00490 %!function y = __f (x)
00491 %!  y = x .* sin (1 ./ x) .* sqrt (abs (1 - x));
00492 %!endfunction
00493 
00494 %!test
00495 %!  [v, ier, nfun, err] = quad ("__f", 0.001, 3);
00496 %! assert((ier == 0 || ier == 1) && abs (v - 1.98194120273598) < sqrt (eps) && nfun > 0);
00497 %!test
00498 %!  [v, ier, nfun, err] = quad ("__f", single(0.001), single(3));
00499 %! assert((ier == 0 || ier == 1) && abs (v - 1.98194120273598) < sqrt (eps ("single")) && nfun > 0);
00500 
00501 %!error <Invalid call to quad> quad ();
00502 
00503 %!error <Invalid call to quad> quad ("__f", 1, 2, 3, 4, 5);
00504 
00505 %!test
00506 %! quad_options ("absolute tolerance", eps);
00507 %! assert(quad_options ("absolute tolerance") == eps);
00508 
00509 %!error <Invalid call to quad_options> quad_options (1, 2, 3);
00510 
00511 */
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines