00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
00052 static octave_function *quad_fcn;
00053
00054
00055 static bool warned_imaginary = false;
00056
00057
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;
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;
00092 gripe_user_supplied_eval ("quad");
00093 }
00094 }
00095 else
00096 {
00097 quad_integration_error = 1;
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;
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;
00137 gripe_user_supplied_eval ("quad");
00138 }
00139 }
00140 else
00141 {
00142 quad_integration_error = 1;
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
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511