GNU Octave  4.2.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
quad.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2017 John W. Eaton
4 
5 This file is part of Octave.
6 
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 #if defined (HAVE_CONFIG_H)
24 # include "config.h"
25 #endif
26 
27 #include <string>
28 
29 #include <iomanip>
30 #include <iostream>
31 
32 #include "Quad.h"
33 #include "lo-mappers.h"
34 
35 #include "defun.h"
36 #include "error.h"
37 #include "errwarn.h"
38 #include "pager.h"
39 #include "ovl.h"
40 #include "ov-fcn.h"
41 #include "unwind-prot.h"
42 #include "utils.h"
43 #include "variables.h"
44 
45 #include "Quad-opts.cc"
46 
47 #if defined (quad)
48 # undef quad
49 #endif
50 
51 // Global pointer for user defined function required by quadrature functions.
53 
54 // Have we warned about imaginary values returned from user function?
55 static bool warned_imaginary = false;
56 
57 // Is this a recursive call?
58 static int call_depth = 0;
59 
60 double
62 {
63  double retval = 0.0;
64 
66  args(0) = x;
67 
68  if (quad_fcn)
69  {
71 
72  try
73  {
74  tmp = quad_fcn->do_multi_index_op (1, args);
75  }
76  catch (octave::execution_exception& e)
77  {
78  err_user_supplied_eval (e, "quad");
79  }
80 
81  if (! tmp.length () || ! tmp(0).is_defined ())
82  err_user_supplied_eval ("quad");
83 
84  if (! warned_imaginary && tmp(0).is_complex_type ())
85  {
86  warning ("quad: ignoring imaginary part returned from user-supplied function");
87  warned_imaginary = true;
88  }
89 
90  retval = tmp(0).xdouble_value ("quad: expecting user supplied function to return numeric value");
91  }
92 
93  return retval;
94 }
95 
96 float
98 {
99  float retval = 0.0;
100 
102  args(0) = x;
103 
104  if (quad_fcn)
105  {
107 
108  try
109  {
110  tmp = quad_fcn->do_multi_index_op (1, args);
111  }
112  catch (octave::execution_exception& e)
113  {
114  err_user_supplied_eval (e, "quad");
115  }
116 
117  if (! tmp.length () || ! tmp(0).is_defined ())
118  err_user_supplied_eval ("quad");
119 
120  if (! warned_imaginary && tmp(0).is_complex_type ())
121  {
122  warning ("quad: ignoring imaginary part returned from user-supplied function");
123  warned_imaginary = true;
124  }
125 
126  retval = tmp(0).xfloat_value ("quad: expecting user supplied function to return numeric value");
127  }
128 
129  return retval;
130 }
131 
132 DEFUN (quad, args, ,
133  doc: /* -*- texinfo -*-
134 @deftypefn {} {@var{q} =} quad (@var{f}, @var{a}, @var{b})
135 @deftypefnx {} {@var{q} =} quad (@var{f}, @var{a}, @var{b}, @var{tol})
136 @deftypefnx {} {@var{q} =} quad (@var{f}, @var{a}, @var{b}, @var{tol}, @var{sing})
137 @deftypefnx {} {[@var{q}, @var{ier}, @var{nfun}, @var{err}] =} quad (@dots{})
138 Numerically evaluate the integral of @var{f} from @var{a} to @var{b} using
139 Fortran routines from @w{@sc{quadpack}}.
140 
141 @var{f} is a function handle, inline function, or a string containing the
142 name of the function to evaluate. The function must have the form @code{y =
143 f (x)} where @var{y} and @var{x} are scalars.
144 
145 @var{a} and @var{b} are the lower and upper limits of integration. Either
146 or both may be infinite.
147 
148 The optional argument @var{tol} is a vector that specifies the desired
149 accuracy of the result. The first element of the vector is the desired
150 absolute tolerance, and the second element is the desired relative
151 tolerance. To choose a relative test only, set the absolute
152 tolerance to zero. To choose an absolute test only, set the relative
153 tolerance to zero. Both tolerances default to @code{sqrt (eps)} or
154 approximately @math{1.5e^{-8}}.
155 
156 The optional argument @var{sing} is a vector of values at which the
157 integrand is known to be singular.
158 
159 The result of the integration is returned in @var{q}.
160 
161 @var{ier} contains an integer error code (0 indicates a successful
162 integration).
163 
164 @var{nfun} indicates the number of function evaluations that were
165 made.
166 
167 @var{err} contains an estimate of the error in the solution.
168 
169 The function @code{quad_options} can set other optional parameters for
170 @code{quad}.
171 
172 Note: because @code{quad} is written in Fortran it cannot be called
173 recursively. This prevents its use in integrating over more than one
174 variable by routines @code{dblquad} and @code{triplequad}.
175 @seealso{quad_options, quadv, quadl, quadgk, quadcc, trapz, dblquad, triplequad}
176 @end deftypefn */)
177 {
178  int nargin = args.length ();
179 
180  if (nargin < 3 || nargin > 5)
181  print_usage ();
182 
183  warned_imaginary = false;
184 
186 
187  frame.protect_var (call_depth);
188  call_depth++;
189 
190  if (call_depth > 1)
191  error ("quad: invalid recursive call");
192 
193  std::string fcn_name;
194 
195  if (args(0).is_function_handle () || args(0).is_inline_function ())
196  quad_fcn = args(0).function_value ();
197  else
198  {
199  fcn_name = unique_symbol_name ("__quad_fcn__");
200  std::string fname = "function y = ";
201  fname.append (fcn_name);
202  fname.append ("(x) y = ");
203  quad_fcn = extract_function (args(0), "quad", fcn_name, fname,
204  "; endfunction");
205  frame.add_fcn (clear_function, fcn_name);
206  }
207 
208  if (! quad_fcn)
209  error ("quad: FCN argument is not a valid function name or handle");
210 
212 
213  if (args(1).is_single_type () || args(2).is_single_type ())
214  {
215  float a = args(1).xfloat_value ("quad: lower limit of integration A must be a scalar");
216  float b = args(2).xfloat_value ("quad: upper limit of integration B must be a scalar");
217 
218  int indefinite = 0;
221  float bound = 0.0;
223  {
224  indefinite = 1;
225  indef_type = FloatIndefQuad::doubly_infinite;
226  }
227  else if (octave::math::isinf (a))
228  {
229  indefinite = 1;
230  bound = b;
232  }
233  else if (octave::math::isinf (b))
234  {
235  indefinite = 1;
236  bound = a;
237  indef_type = FloatIndefQuad::bound_to_inf;
238  }
239 
240  octave_idx_type ier = 0;
241  octave_idx_type nfun = 0;
242  float abserr = 0.0;
243  float val = 0.0;
244  bool have_sing = false;
245  FloatColumnVector sing;
246  FloatColumnVector tol;
247 
248  switch (nargin)
249  {
250  case 5:
251  if (indefinite)
252  error ("quad: singularities not allowed on infinite intervals");
253 
254  have_sing = true;
255 
256  sing = args(4).xfloat_vector_value ("quad: fifth argument SING must be a vector of singularities");
257 
258  case 4:
259  tol = args(3).xfloat_vector_value ("quad: TOL must be a 1 or 2-element vector");
260 
261  switch (tol.numel ())
262  {
263  case 2:
265 
266  case 1:
268  break;
269 
270  default:
271  error ("quad: TOL must be a 1 or 2-element vector");
272  }
273 
274  case 3:
275  if (indefinite)
276  {
278  indef_type);
279  iq.set_options (quad_opts);
280  val = iq.float_integrate (ier, nfun, abserr);
281  }
282  else
283  {
284  if (have_sing)
285  {
286  FloatDefQuad dq (quad_float_user_function, a, b, sing);
287  dq.set_options (quad_opts);
288  val = dq.float_integrate (ier, nfun, abserr);
289  }
290  else
291  {
293  dq.set_options (quad_opts);
294  val = dq.float_integrate (ier, nfun, abserr);
295  }
296  }
297  break;
298 
299  default:
300  panic_impossible ();
301  break;
302  }
303 
304  retval = ovl (val, ier, nfun, abserr);
305 
306  }
307  else
308  {
309  double a = args(1).xdouble_value ("quad: lower limit of integration A must be a scalar");
310  double b = args(2).xdouble_value ("quad: upper limit of integration B must be a scalar");
311 
312  int indefinite = 0;
314  double bound = 0.0;
316  {
317  indefinite = 1;
318  indef_type = IndefQuad::doubly_infinite;
319  }
320  else if (octave::math::isinf (a))
321  {
322  indefinite = 1;
323  bound = b;
324  indef_type = IndefQuad::neg_inf_to_bound;
325  }
326  else if (octave::math::isinf (b))
327  {
328  indefinite = 1;
329  bound = a;
330  indef_type = IndefQuad::bound_to_inf;
331  }
332 
333  octave_idx_type ier = 0;
334  octave_idx_type nfun = 0;
335  double abserr = 0.0;
336  double val = 0.0;
337  bool have_sing = false;
338  ColumnVector sing;
339  ColumnVector tol;
340 
341  switch (nargin)
342  {
343  case 5:
344  if (indefinite)
345  error ("quad: singularities not allowed on infinite intervals");
346 
347  have_sing = true;
348 
349  sing = args(4).vector_value ("quad: fifth argument SING must be a vector of singularities");
350 
351  case 4:
352  tol = args(3).xvector_value ("quad: TOL must be a 1 or 2-element vector");
353 
354  switch (tol.numel ())
355  {
356  case 2:
358 
359  case 1:
361  break;
362 
363  default:
364  error ("quad: TOL must be a 1 or 2-element vector");
365  }
366 
367  case 3:
368  if (indefinite)
369  {
370  IndefQuad iq (quad_user_function, bound, indef_type);
371  iq.set_options (quad_opts);
372  val = iq.integrate (ier, nfun, abserr);
373  }
374  else
375  {
376  if (have_sing)
377  {
378  DefQuad dq (quad_user_function, a, b, sing);
379  dq.set_options (quad_opts);
380  val = dq.integrate (ier, nfun, abserr);
381  }
382  else
383  {
384  DefQuad dq (quad_user_function, a, b);
385  dq.set_options (quad_opts);
386  val = dq.integrate (ier, nfun, abserr);
387  }
388  }
389  break;
390 
391  default:
392  panic_impossible ();
393  break;
394  }
395 
396  retval = ovl (val, ier, nfun, abserr);
397  }
398 
399  if (fcn_name.length ())
400  clear_function (fcn_name);
401 
402  return retval;
403 }
404 
405 /*
406 %!function y = __f (x)
407 %! y = x + 1;
408 %!endfunction
409 
410 %!test
411 %! [v, ier, nfun, err] = quad ("__f", 0, 5);
412 %! assert (ier, 0);
413 %! assert (v, 17.5, sqrt (eps));
414 %! assert (nfun > 0);
415 %! assert (err < sqrt (eps));
416 
417 %!test
418 %! [v, ier, nfun, err] = quad ("__f", single (0), single (5));
419 %! assert (ier, 0);
420 %! assert (v, 17.5, sqrt (eps ("single")));
421 %! assert (nfun > 0);
422 %! assert (err < sqrt (eps ("single")));
423 
424 %!function y = __f (x)
425 %! y = x .* sin (1 ./ x) .* sqrt (abs (1 - x));
426 %!endfunction
427 
428 %!test
429 %! [v, ier, nfun, err] = quad ("__f", 0.001, 3);
430 %! assert (ier == 0 || ier == 1);
431 %! assert (v, 1.98194120273598, sqrt (eps));
432 %! assert (nfun > 0);
433 
434 %!test
435 %! [v, ier, nfun, err] = quad ("__f", single (0.001), single (3));
436 %! assert (ier == 0 || ier == 1);
437 %! assert (v, 1.98194120273598, sqrt (eps ("single")));
438 %! assert (nfun > 0);
439 
440 %!error quad ()
441 %!error quad ("__f", 1, 2, 3, 4, 5)
442 
443 %!test
444 %! quad_options ("absolute tolerance", eps);
445 %! assert (quad_options ("absolute tolerance") == eps);
446 
447 %!error quad_options (1, 2, 3)
448 */
void set_single_precision_relative_tolerance(float val)
Definition: Quad-opts.h:80
virtual double integrate(void)
Definition: Quad.h:57
fname
Definition: load-save.cc:754
virtual octave_value_list do_multi_index_op(int nargout, const octave_value_list &idx)
Definition: ov-base.cc:259
virtual float float_integrate(void)
Definition: Quad.h:64
OCTAVE_EXPORT octave_value_list isa nd deftypefn *return ovl(args(0).is_integer_type())
OCTINTERP_API void print_usage(void)
Definition: defun.cc:52
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:363
void set_relative_tolerance(double val)
Definition: Quad-opts.h:74
identity matrix If supplied two scalar respectively For allows like xample val
Definition: data.cc:5068
octave_idx_type length(void) const
Definition: ovl.h:96
double quad_user_function(double x)
Definition: quad.cc:61
void protect_var(T &var)
void error(const char *fmt,...)
Definition: error.cc:570
DEFUN(quad, args,, doc:)
Definition: quad.cc:132
IntegralType
Definition: Quad.h:164
static Quad_options quad_opts
Definition: Quad-opts.cc:20
i e
Definition: data.cc:2724
std::string unique_symbol_name(const std::string &basename)
Definition: variables.cc:491
calling an anonymous function involves an overhead quite comparable to the overhead of an m file function Passing a handle to a built in function is because the interpreter is not involved in the internal loop For a
Definition: cellfun.cc:398
void clear_function(const std::string &nm)
Definition: variables.cc:79
JNIEnv void * args
Definition: ov-java.cc:67
void add_fcn(void(*fcn)(void))
void set_single_precision_absolute_tolerance(float val)
Definition: Quad-opts.h:77
float quad_float_user_function(float x)
Definition: quad.cc:97
int nargin
Definition: graphics.cc:10115
double tmp
Definition: data.cc:6300
octave_value retval
Definition: data.cc:6294
#define panic_impossible()
Definition: error.h:40
Definition: Quad.h:121
bool isinf(double x)
Definition: lo-mappers.cc:387
static bool warned_imaginary
Definition: quad.cc:55
void set_options(const Quad_options &opt)
Definition: Quad-opts.h:60
static octave_function * quad_fcn
Definition: quad.cc:52
void warning(const char *fmt,...)
Definition: error.cc:788
octave::unwind_protect frame
Definition: graphics.cc:11584
void err_user_supplied_eval(const char *name)
Definition: errwarn.cc:142
void set_absolute_tolerance(double val)
Definition: Quad-opts.h:71
octave_function * extract_function(const octave_value &arg, const std::string &warn_for, const std::string &fname, const std::string &header, const std::string &trailer)
Definition: variables.cc:145
static int call_depth
Definition: quad.cc:58
b
Definition: cellfun.cc:398
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:854
F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T F77_REAL F77_REAL &F77_RET_T F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE * x