GNU Octave  3.8.0
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-2013 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 #ifdef 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 "gripes.h"
38 #include "pager.h"
39 #include "oct-obj.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 
65  octave_value_list args;
66  args(0) = x;
67 
68  if (quad_fcn)
69  {
70  octave_value_list tmp = quad_fcn->do_multi_index_op (1, args);
71 
72  if (error_state)
73  {
74  quad_integration_error = 1; // FIXME
75  gripe_user_supplied_eval ("quad");
76  return retval;
77  }
78 
79  if (tmp.length () && tmp(0).is_defined ())
80  {
81  if (! warned_imaginary && tmp(0).is_complex_type ())
82  {
83  warning ("quad: ignoring imaginary part returned from user-supplied function");
84  warned_imaginary = true;
85  }
86 
87  retval = tmp(0).double_value ();
88 
89  if (error_state)
90  {
91  quad_integration_error = 1; // FIXME
92  gripe_user_supplied_eval ("quad");
93  }
94  }
95  else
96  {
97  quad_integration_error = 1; // FIXME
98  gripe_user_supplied_eval ("quad");
99  }
100  }
101 
102  return retval;
103 }
104 
105 float
107 {
108  float retval = 0.0;
109 
110  octave_value_list args;
111  args(0) = x;
112 
113  if (quad_fcn)
114  {
115  octave_value_list tmp = quad_fcn->do_multi_index_op (1, args);
116 
117  if (error_state)
118  {
119  quad_integration_error = 1; // FIXME
120  gripe_user_supplied_eval ("quad");
121  return retval;
122  }
123 
124  if (tmp.length () && tmp(0).is_defined ())
125  {
126  if (! warned_imaginary && tmp(0).is_complex_type ())
127  {
128  warning ("quad: ignoring imaginary part returned from user-supplied function");
129  warned_imaginary = true;
130  }
131 
132  retval = tmp(0).float_value ();
133 
134  if (error_state)
135  {
136  quad_integration_error = 1; // FIXME
137  gripe_user_supplied_eval ("quad");
138  }
139  }
140  else
141  {
142  quad_integration_error = 1; // FIXME
143  gripe_user_supplied_eval ("quad");
144  }
145  }
146 
147  return retval;
148 }
149 
150 #define QUAD_ABORT() \
151  do \
152  { \
153  if (fcn_name.length ()) \
154  clear_function (fcn_name); \
155  return retval; \
156  } \
157  while (0)
158 
159 #define QUAD_ABORT1(msg) \
160  do \
161  { \
162  ::error ("quad: " msg); \
163  QUAD_ABORT (); \
164  } \
165  while (0)
166 
167 #define QUAD_ABORT2(fmt, arg) \
168  do \
169  { \
170  ::error ("quad: " fmt, arg); \
171  QUAD_ABORT (); \
172  } \
173  while (0)
174 
175 DEFUN (quad, args, nargout,
176  "-*- texinfo -*-\n\
177 @deftypefn {Built-in Function} {@var{q} =} quad (@var{f}, @var{a}, @var{b})\n\
178 @deftypefnx {Built-in Function} {@var{q} =} quad (@var{f}, @var{a}, @var{b}, @var{tol})\n\
179 @deftypefnx {Built-in Function} {@var{q} =} quad (@var{f}, @var{a}, @var{b}, @var{tol}, @var{sing})\n\
180 @deftypefnx {Built-in Function} {[@var{q}, @var{ier}, @var{nfun}, @var{err}] =} quad (@dots{})\n\
181 Numerically evaluate the integral of @var{f} from @var{a} to @var{b} using\n\
182 Fortran routines from @w{@sc{quadpack}}. @var{f} is a function handle,\n\
183 inline function, or a string containing the name of the function to\n\
184 evaluate. The function must have the form @code{y = f (x)} where @var{y} and\n\
185 @var{x} are scalars.\n\
186 \n\
187 @var{a} and @var{b} are the lower and upper limits of integration. Either\n\
188 or both may be infinite.\n\
189 \n\
190 The optional argument @var{tol} is a vector that specifies the desired\n\
191 accuracy of the result. The first element of the vector is the desired\n\
192 absolute tolerance, and the second element is the desired relative\n\
193 tolerance. To choose a relative test only, set the absolute\n\
194 tolerance to zero. To choose an absolute test only, set the relative\n\
195 tolerance to zero. Both tolerances default to @code{sqrt (eps)} or\n\
196 approximately @math{1.5e^{-8}}.\n\
197 \n\
198 The optional argument @var{sing} is a vector of values at which the\n\
199 integrand is known to be singular.\n\
200 \n\
201 The result of the integration is returned in @var{q}. @var{ier}\n\
202 contains an integer error code (0 indicates a successful integration).\n\
203 @var{nfun} indicates the number of function evaluations that were\n\
204 made, and @var{err} contains an estimate of the error in the\n\
205 solution.\n\
206 \n\
207 The function @code{quad_options} can set other optional\n\
208 parameters for @code{quad}.\n\
209 \n\
210 Note: because @code{quad} is written in Fortran it cannot be called\n\
211 recursively. This prevents its use in integrating over more than one\n\
212 variable by routines @code{dblquad} and @code{triplequad}.\n\
213 @seealso{quad_options, quadv, quadl, quadgk, quadcc, trapz, dblquad, triplequad}\n\
214 @end deftypefn")
215 {
216  octave_value_list retval;
217 
218  std::string fcn_name;
219 
220  warned_imaginary = false;
221 
222  unwind_protect frame;
223 
224  frame.protect_var (call_depth);
225  call_depth++;
226 
227  if (call_depth > 1)
228  QUAD_ABORT1 ("invalid recursive call");
229 
230  int nargin = args.length ();
231 
232  if (nargin > 2 && nargin < 6 && nargout < 5)
233  {
234  if (args(0).is_function_handle () || args(0).is_inline_function ())
235  quad_fcn = args(0).function_value ();
236  else
237  {
238  fcn_name = unique_symbol_name ("__quad_fcn_");
239  std::string fname = "function y = ";
240  fname.append (fcn_name);
241  fname.append ("(x) y = ");
242  quad_fcn = extract_function (args(0), "quad", fcn_name, fname,
243  "; endfunction");
244  }
245 
246  if (! quad_fcn)
247  QUAD_ABORT ();
248 
249  if (args(1).is_single_type () || args(2).is_single_type ())
250  {
251  float a = args(1).float_value ();
252 
253  if (error_state)
254  QUAD_ABORT1 ("expecting second argument to be a scalar");
255 
256  float b = args(2).float_value ();
257 
258  if (error_state)
259  QUAD_ABORT1 ("expecting third argument to be a scalar");
260 
261  int indefinite = 0;
264  float bound = 0.0;
265  if (xisinf (a) && xisinf (b))
266  {
267  indefinite = 1;
268  indef_type = FloatIndefQuad::doubly_infinite;
269  }
270  else if (xisinf (a))
271  {
272  indefinite = 1;
273  bound = b;
275  }
276  else if (xisinf (b))
277  {
278  indefinite = 1;
279  bound = a;
280  indef_type = FloatIndefQuad::bound_to_inf;
281  }
282 
283  octave_idx_type ier = 0;
284  octave_idx_type nfun = 0;
285  float abserr = 0.0;
286  float val = 0.0;
287  bool have_sing = false;
288  FloatColumnVector sing;
289  FloatColumnVector tol;
290 
291  switch (nargin)
292  {
293  case 5:
294  if (indefinite)
295  QUAD_ABORT1 ("singularities not allowed on infinite intervals");
296 
297  have_sing = true;
298 
299  sing = FloatColumnVector (args(4).float_vector_value ());
300 
301  if (error_state)
302  QUAD_ABORT1 ("expecting vector of singularities as fourth argument");
303 
304  case 4:
305  tol = FloatColumnVector (args(3).float_vector_value ());
306 
307  if (error_state)
308  QUAD_ABORT1 ("expecting vector of tolerances as fifth argument");
309 
310  switch (tol.capacity ())
311  {
312  case 2:
314 
315  case 1:
317  break;
318 
319  default:
320  QUAD_ABORT1 ("expecting tol to contain no more than two values");
321  }
322 
323  case 3:
324  if (indefinite)
325  {
327  indef_type);
328  iq.set_options (quad_opts);
329  val = iq.float_integrate (ier, nfun, abserr);
330  }
331  else
332  {
333  if (have_sing)
334  {
335  FloatDefQuad dq (quad_float_user_function, a, b, sing);
336  dq.set_options (quad_opts);
337  val = dq.float_integrate (ier, nfun, abserr);
338  }
339  else
340  {
342  dq.set_options (quad_opts);
343  val = dq.float_integrate (ier, nfun, abserr);
344  }
345  }
346  break;
347 
348  default:
349  panic_impossible ();
350  break;
351  }
352 
353  retval(3) = abserr;
354  retval(2) = nfun;
355  retval(1) = ier;
356  retval(0) = val;
357 
358  }
359  else
360  {
361  double a = args(1).double_value ();
362 
363  if (error_state)
364  QUAD_ABORT1 ("expecting second argument to be a scalar");
365 
366  double b = args(2).double_value ();
367 
368  if (error_state)
369  QUAD_ABORT1 ("expecting third argument to be a scalar");
370 
371  int indefinite = 0;
373  double bound = 0.0;
374  if (xisinf (a) && xisinf (b))
375  {
376  indefinite = 1;
377  indef_type = IndefQuad::doubly_infinite;
378  }
379  else if (xisinf (a))
380  {
381  indefinite = 1;
382  bound = b;
383  indef_type = IndefQuad::neg_inf_to_bound;
384  }
385  else if (xisinf (b))
386  {
387  indefinite = 1;
388  bound = a;
389  indef_type = IndefQuad::bound_to_inf;
390  }
391 
392  octave_idx_type ier = 0;
393  octave_idx_type nfun = 0;
394  double abserr = 0.0;
395  double val = 0.0;
396  bool have_sing = false;
397  ColumnVector sing;
398  ColumnVector tol;
399 
400  switch (nargin)
401  {
402  case 5:
403  if (indefinite)
404  QUAD_ABORT1 ("singularities not allowed on infinite intervals");
405 
406  have_sing = true;
407 
408  sing = ColumnVector (args(4).vector_value ());
409 
410  if (error_state)
411  QUAD_ABORT1 ("expecting vector of singularities as fourth argument");
412 
413  case 4:
414  tol = ColumnVector (args(3).vector_value ());
415 
416  if (error_state)
417  QUAD_ABORT1 ("expecting vector of tolerances as fifth argument");
418 
419  switch (tol.capacity ())
420  {
421  case 2:
423 
424  case 1:
426  break;
427 
428  default:
429  QUAD_ABORT1 ("expecting tol to contain no more than two values");
430  }
431 
432  case 3:
433  if (indefinite)
434  {
435  IndefQuad iq (quad_user_function, bound, indef_type);
436  iq.set_options (quad_opts);
437  val = iq.integrate (ier, nfun, abserr);
438  }
439  else
440  {
441  if (have_sing)
442  {
443  DefQuad dq (quad_user_function, a, b, sing);
444  dq.set_options (quad_opts);
445  val = dq.integrate (ier, nfun, abserr);
446  }
447  else
448  {
449  DefQuad dq (quad_user_function, a, b);
450  dq.set_options (quad_opts);
451  val = dq.integrate (ier, nfun, abserr);
452  }
453  }
454  break;
455 
456  default:
457  panic_impossible ();
458  break;
459  }
460 
461  retval(3) = abserr;
462  retval(2) = nfun;
463  retval(1) = ier;
464  retval(0) = val;
465  }
466 
467  if (fcn_name.length ())
468  clear_function (fcn_name);
469  }
470  else
471  print_usage ();
472 
473  return retval;
474 }
475 
476 /*
477 %!function y = __f (x)
478 %! y = x + 1;
479 %!endfunction
480 
481 %!test
482 %! [v, ier, nfun, err] = quad ("__f", 0, 5);
483 %! assert (ier, 0);
484 %! assert (v, 17.5, sqrt (eps));
485 %! assert (nfun > 0);
486 %! assert (err < sqrt (eps));
487 
488 %!test
489 %! [v, ier, nfun, err] = quad ("__f", single (0), single (5));
490 %! assert (ier, 0);
491 %! assert (v, 17.5, sqrt (eps ("single")));
492 %! assert (nfun > 0);
493 %! assert (err < sqrt (eps ("single")));
494 
495 %!function y = __f (x)
496 %! y = x .* sin (1 ./ x) .* sqrt (abs (1 - x));
497 %!endfunction
498 
499 %!test
500 %! [v, ier, nfun, err] = quad ("__f", 0.001, 3);
501 %! assert (ier == 0 || ier == 1);
502 %! assert (v, 1.98194120273598, sqrt (eps));
503 %! assert (nfun > 0);
504 
505 %!test
506 %! [v, ier, nfun, err] = quad ("__f", single (0.001), single (3));
507 %! assert (ier == 0 || ier == 1);
508 %! assert (v, 1.98194120273598, sqrt (eps ("single")));
509 %! assert (nfun > 0);
510 
511 %!error quad ()
512 %!error quad ("__f", 1, 2, 3, 4, 5)
513 
514 %!test
515 %! quad_options ("absolute tolerance", eps);
516 %! assert (quad_options ("absolute tolerance") == eps);
517 
518 %!error quad_options (1, 2, 3)
519 */