diff src/DLD-FUNCTIONS/quad.cc @ 2928:295f037b4b3e

[project @ 1997-05-05 05:32:33 by jwe]
author jwe
date Mon, 05 May 1997 05:33:54 +0000
parents
children e330cb788508
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/DLD-FUNCTIONS/quad.cc	Mon May 05 05:33:54 1997 +0000
@@ -0,0 +1,406 @@
+/*
+
+Copyright (C) 1996, 1997 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string>
+
+#include <iostream.h>
+
+#include "Quad.h"
+#include "lo-mappers.h"
+
+#include "defun-dld.h"
+#include "error.h"
+#include "gripes.h"
+#include "help.h"
+#include "oct-sym.h"
+#include "pager.h"
+#include "oct-obj.h"
+#include "utils.h"
+#include "variables.h"
+
+#if defined (quad)
+#undef quad
+#endif
+
+// Global pointer for user defined function required by quadrature functions.
+static octave_symbol *quad_fcn;
+
+static Quad_options quad_opts;
+
+double
+quad_user_function (double x)
+{
+  double retval = 0.0;
+
+  octave_value_list args;
+  args(0) = x;
+
+  if (quad_fcn)
+    {
+      octave_value_list tmp = quad_fcn->eval (1, args);
+
+      if (error_state)
+	{
+	  quad_integration_error = 1;  // XXX FIXME XXX
+	  gripe_user_supplied_eval ("quad");
+	  return retval;
+	}
+
+      if (tmp.length () && tmp(0).is_defined ())
+	{
+	  retval = tmp(0).double_value ();
+
+	  if (error_state)
+	    {
+	      quad_integration_error = 1;  // XXX FIXME XXX
+	      gripe_user_supplied_eval ("quad");
+	    }
+	}
+      else
+	{
+	  quad_integration_error = 1;  // XXX FIXME XXX
+	  gripe_user_supplied_eval ("quad");
+	}
+    }
+
+  return retval;
+}
+
+DEFUN_DLD (quad, args, nargout,
+  "[V, IER, NFUN] = quad (F, A, B [, TOL] [, SING])\n\
+\n\
+Where the first argument is the name of the  function to call to\n\
+compute the value of the integrand.  It must have the form\n\
+\n\
+  y = f (x)\n\
+\n\
+where y and x are scalars.\n\
+\n\
+The second and third arguments are limits of integration.  Either or\n\
+both may be infinite.\n\
+\n\
+The optional argument tol is a vector that specifies the desired\n\
+accuracy of the result.  The first element of the vector is the desired\n\
+absolute tolerance, and the second element is the desired relative\n\
+tolerance.\n\
+\n\
+The optional argument @var{sing} is a vector of values at which the\n\
+integrand is singular.")
+{
+  octave_value_list retval;
+
+  int nargin = args.length ();
+
+  if (nargin < 3 || nargin > 5 || nargout > 4)
+    {
+      print_usage ("quad");
+      return retval;
+    }
+
+  quad_fcn = extract_function (args(0), "quad", "__quad_fcn__",
+			       "function y = __quad_fcn__ (x) y = ",
+			       "; endfunction");
+  if (! quad_fcn)
+    return retval;
+
+  double a = args(1).double_value ();
+
+  if (error_state)
+    {
+      error ("quad: expecting second argument to be a scalar");
+      return retval;
+    }
+
+  double b = args(2).double_value ();
+
+  if (error_state)
+    {
+      error ("quad: expecting third argument to be a scalar");
+      return retval;
+    }
+
+  int indefinite = 0;
+  IndefQuad::IntegralType indef_type = IndefQuad::doubly_infinite;
+  double bound = 0.0;
+  if (xisinf (a) && xisinf (b))
+    {
+      indefinite = 1;
+      indef_type = IndefQuad::doubly_infinite;
+    }
+  else if (xisinf (a))
+    {
+      indefinite = 1;
+      bound = b;
+      indef_type = IndefQuad::neg_inf_to_bound;
+    }
+  else if (xisinf (b))
+    {
+      indefinite = 1;
+      bound = a;
+      indef_type = IndefQuad::bound_to_inf;
+    }
+
+  int ier = 0;
+  int nfun = 0;
+  double abserr = 0.0;
+  double val = 0.0;
+  double abstol = 1e-6;
+  double reltol = 1e-6;
+  ColumnVector tol (2);
+  ColumnVector sing;
+  int have_sing = 0;
+  switch (nargin)
+    {
+    case 5:
+      if (indefinite)
+	{
+	  error("quad: singularities not allowed on infinite intervals");
+	  return retval;
+	}
+
+      have_sing = 1;
+
+      sing = args(4).vector_value ();
+
+      if (error_state)
+	{
+	  error ("quad: expecting vector of singularities as fourth argument");
+	  return retval;
+	}
+
+    case 4:
+      tol = args(3).vector_value ();
+
+      if (error_state)
+	{
+	  error ("quad: expecting vector of tolerances as fifth argument");
+	  return retval;
+	}
+
+      switch (tol.capacity ())
+	{
+	case 2:
+	  reltol = tol (1);
+
+	case 1:
+	  abstol = tol (0);
+	  break;
+
+	default:
+	  error ("quad: expecting tol to contain no more than two values");
+	  return retval;
+	}
+
+    case 3:
+      if (indefinite)
+	{
+	  IndefQuad iq (quad_user_function, bound, indef_type, abstol, reltol);
+	  iq.set_options (quad_opts);
+	  val = iq.integrate (ier, nfun, abserr);
+	}
+      else
+	{
+	  if (have_sing)
+	    {
+	      DefQuad dq (quad_user_function, a, b, sing, abstol, reltol);
+	      dq.set_options (quad_opts);
+	      val = dq.integrate (ier, nfun, abserr);
+	    }
+	  else
+	    {
+	      DefQuad dq (quad_user_function, a, b, abstol, reltol);
+	      dq.set_options (quad_opts);
+	      val = dq.integrate (ier, nfun, abserr);
+	    }
+	}
+      break;
+
+    default:
+      panic_impossible ();
+      break;
+    }
+
+  retval(3) = abserr;
+  retval(2) = static_cast<double> (nfun);
+  retval(1) = static_cast<double> (ier);
+  retval(0) = val;
+
+  return retval;
+}
+
+typedef void (Quad_options::*d_set_opt_mf) (double);
+typedef double (Quad_options::*d_get_opt_mf) (void);
+
+#define MAX_TOKENS 2
+
+struct QUAD_OPTIONS
+{
+  const char *keyword;
+  const char *kw_tok[MAX_TOKENS + 1];
+  int min_len[MAX_TOKENS + 1];
+  int min_toks_to_match;
+  d_set_opt_mf d_set_fcn;
+  d_get_opt_mf d_get_fcn;
+};
+
+static QUAD_OPTIONS quad_option_table [] =
+{
+  { "absolute tolerance",
+    { "absolute", "tolerance", 0, },
+    { 1, 0, 0, }, 1,
+    Quad_options::set_absolute_tolerance,
+    Quad_options::absolute_tolerance, },
+
+  { "relative tolerance",
+    { "relative", "tolerance", 0, },
+    { 1, 0, 0, }, 1,
+    Quad_options::set_relative_tolerance,
+    Quad_options::relative_tolerance, },
+
+  { 0,
+    { 0, 0, 0, },
+    { 0, 0, 0, }, 0,
+    0, 0, },
+};
+
+static void
+print_quad_option_list (ostream& os)
+{
+  print_usage ("quad_options", 1);
+
+  os << "\n"
+     << "Options for quad include:\n\n"
+     << "  keyword                                  value\n"
+     << "  -------                                  -----\n\n";
+
+  QUAD_OPTIONS *list = quad_option_table;
+
+  const char *keyword;
+  while ((keyword = list->keyword) != 0)
+    {
+      os.form ("  %-40s ", keyword);
+
+      double val = (quad_opts.*list->d_get_fcn) ();
+      if (val < 0.0)
+	os << "computed automatically";
+      else
+	os << val;
+
+      os << "\n";
+      list++;
+    }
+
+  os << "\n";
+}
+
+static void
+set_quad_option (const string& keyword, double val)
+{
+  QUAD_OPTIONS *list = quad_option_table;
+
+  while (list->keyword != 0)
+    {
+      if (keyword_almost_match (list->kw_tok, list->min_len, keyword,
+				list->min_toks_to_match, MAX_TOKENS))
+	{
+	  (quad_opts.*list->d_set_fcn) (val);
+
+	  return;
+	}
+      list++;
+    }
+
+  warning ("quad_options: no match for `%s'", keyword.c_str ());
+}
+
+static octave_value_list
+show_quad_option (const string& keyword)
+{
+  octave_value retval;
+
+  QUAD_OPTIONS *list = quad_option_table;
+
+  while (list->keyword != 0)
+    {
+      if (keyword_almost_match (list->kw_tok, list->min_len, keyword,
+				list->min_toks_to_match, MAX_TOKENS))
+	{
+	  return (quad_opts.*list->d_get_fcn) ();
+	}
+      list++;
+    }
+
+  warning ("quad_options: no match for `%s'", keyword.c_str ());
+
+  return retval;
+}
+
+DEFUN_DLD (quad_options, args, ,
+  "quad_options (KEYWORD, VALUE)\n\
+\n\
+Set or show options for quad.  Keywords may be abbreviated\n\
+to the shortest match.")
+{
+  octave_value_list retval;
+
+  int nargin = args.length ();
+
+  if (nargin == 0)
+    {
+      print_quad_option_list (octave_stdout);
+      return retval;
+    }
+  else if (nargin == 1 || nargin == 2)
+    {
+      string keyword = args(0).string_value ();
+
+      if (! error_state)
+	{
+	  if (nargin == 1)
+	    return show_quad_option (keyword);
+	  else
+	    {
+	      double val = args(1).double_value ();
+
+	      if (! error_state)
+		{
+		  set_quad_option (keyword, val);
+		  return retval;
+		}
+	    }
+	}
+    }
+
+  print_usage ("quad_options");
+
+  return retval;
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; End: ***
+*/