comparison src/DLD-FUNCTIONS/quadcc.cc @ 12614:4e11a87d86e6

quadcc.cc: Recode input validation and add tests.
author Rik <octave@nomad.inbox5.com>
date Mon, 18 Apr 2011 07:22:31 -0700
parents 16cca721117b
children 25d4e163ee38
comparison
equal deleted inserted replaced
12613:0e79664b969c 12614:4e11a87d86e6
48 double fx[33]; 48 double fx[33];
49 double igral, err; 49 double igral, err;
50 int depth, rdepth, ndiv; 50 int depth, rdepth, ndiv;
51 } cquad_ival; 51 } cquad_ival;
52 52
53 /* Some constants and matrices that we'll need. 53 /* Some constants and matrices that we'll need. */
54 */
55 54
56 static const double xi[33] = { 55 static const double xi[33] = {
57 -1., -0.99518472667219688624, -0.98078528040323044912, 56 -1., -0.99518472667219688624, -0.98078528040323044912,
58 -0.95694033573220886493, -0.92387953251128675612, 57 -0.95694033573220886493, -0.92387953251128675612,
59 -0.88192126434835502970, -0.83146961230254523708, 58 -0.88192126434835502970, -0.83146961230254523708,
1471 } 1470 }
1472 1471
1473 } 1472 }
1474 1473
1475 1474
1476 1475 /* The actual integration routine. */
1477 /* The actual integration routine.
1478 */
1479 1476
1480 DEFUN_DLD (quadcc, args, nargout, 1477 DEFUN_DLD (quadcc, args, nargout,
1481 "-*- texinfo -*-\n\ 1478 "-*- texinfo -*-\n\
1482 @deftypefn {Function File} {@var{q} =} quadcc (@var{f}, @var{a}, @var{b})\n\ 1479 @deftypefn {Function File} {@var{q} =} quadcc (@var{f}, @var{a}, @var{b})\n\
1483 @deftypefnx {Function File} {@var{q} =} quadcc (@var{f}, @var{a}, @var{b}, @var{tol})\n\ 1480 @deftypefnx {Function File} {@var{q} =} quadcc (@var{f}, @var{a}, @var{b}, @var{tol})\n\
1543 Quadrature Using Explicit Interpolants}, ACM Transactions on\n\ 1540 Quadrature Using Explicit Interpolants}, ACM Transactions on\n\
1544 Mathematical Software, Vol. 37, Issue 3, Article No. 3, 2010.\n\ 1541 Mathematical Software, Vol. 37, Issue 3, Article No. 3, 2010.\n\
1545 @seealso{quad, quadv, quadl, quadgk, trapz, dblquad, triplequad}\n\ 1542 @seealso{quad, quadv, quadl, quadgk, trapz, dblquad, triplequad}\n\
1546 @end deftypefn") 1543 @end deftypefn")
1547 { 1544 {
1545 octave_value_list retval;
1548 1546
1549 /* Some constants that we will need. */ 1547 /* Some constants that we will need. */
1550 static const int n[4] = { 4, 8, 16, 32 }; 1548 static const int n[4] = { 4, 8, 16, 32 };
1551 static const int skip[4] = { 8, 4, 2, 1 }; 1549 static const int skip[4] = { 8, 4, 2, 1 };
1552 static const int idx[4] = { 0, 5, 14, 31 }; 1550 static const int idx[4] = { 0, 5, 14, 31 };
1561 int nargin = args.length (); 1559 int nargin = args.length ();
1562 octave_function *fcn; 1560 octave_function *fcn;
1563 double a, b, tol, iivals[cquad_heapsize], *sing; 1561 double a, b, tol, iivals[cquad_heapsize], *sing;
1564 1562
1565 /* Variables needed for transforming the integrand. */ 1563 /* Variables needed for transforming the integrand. */
1566 int wrap = 0; 1564 bool wrap = false;
1567 double xw; 1565 double xw;
1568 1566
1569 /* Stuff we will need to call the integrand. */ 1567 /* Stuff we will need to call the integrand. */
1570 octave_value_list fargs, retval; 1568 octave_value_list fargs, fvals;
1571 1569
1572 /* Actual variables (as opposed to constants above). */ 1570 /* Actual variables (as opposed to constants above). */
1573 double m, h, ml, hl, mr, hr, temp; 1571 double m, h, ml, hl, mr, hr, temp;
1574 double igral, err, igral_final, err_final, err_excess; 1572 double igral, err, igral_final, err_final, err_excess;
1575 int nivals, neval = 0; 1573 int nivals, neval = 0;
1578 cquad_ival *iv, *ivl, *ivr; 1576 cquad_ival *iv, *ivl, *ivr;
1579 double nc, ncdiff; 1577 double nc, ncdiff;
1580 1578
1581 1579
1582 /* Parse the input arguments. */ 1580 /* Parse the input arguments. */
1583 if (nargin < 1) 1581 if (nargin < 3)
1584 { 1582 {
1585 error 1583 print_usage ();
1586 ("quadcc: first argument (integrand) of type function handle required"); 1584 return retval;
1587 return octave_value_list (); 1585 }
1586
1587 if (args(0).is_function_handle () || args(0).is_inline_function ())
1588 fcn = args(0).function_value ();
1589 else
1590 {
1591 std::string fcn_name = unique_symbol_name ("__quadcc_fcn_");
1592 std::string fname = "function y = ";
1593 fname.append (fcn_name);
1594 fname.append ("(x) y = ");
1595 fcn = extract_function (args(0), "quadcc", fcn_name, fname,
1596 "; endfunction");
1597 }
1598
1599 if (!args(1).is_real_scalar ())
1600 {
1601 error ("quadcc: lower limit of integration (A) must be a single real scalar");
1602 return retval;
1588 } 1603 }
1589 else 1604 else
1605 a = args(1).double_value ();
1606
1607 if (!args(2).is_real_scalar ())
1590 { 1608 {
1591 if (args (0).is_function_handle () || args (0).is_inline_function ()) 1609 error ("quadcc: upper limit of integration (B) must be a single real scalar");
1592 fcn = args (0).function_value (); 1610 return retval;
1593 else
1594 {
1595 error ("quadcc: first argument (integrand) must be a function handle or an inline function");
1596 return octave_value_list();
1597 }
1598 }
1599
1600 if (nargin < 2 || !args (1).is_real_scalar ())
1601 {
1602 error ("quadcc: second argument (left interval edge) must be a single real scalar");
1603 return octave_value_list ();
1604 } 1611 }
1605 else 1612 else
1606 a = args (1).double_value (); 1613 b = args(2).double_value ();
1607 1614
1608 if (nargin < 3 || !args (2).is_real_scalar ()) 1615 if (nargin < 4 || args(3).is_empty ())
1616 tol = 1.0e-6;
1617 else if (!args(3).is_real_scalar () || args(3).double_value () <= 0)
1609 { 1618 {
1610 error ("quadcc: third argument (right interval edge) must be a single real scalar"); 1619 error ("quadcc: tolerance (TOL) must be a single real scalar > 0");
1611 return octave_value_list (); 1620 return retval;
1612 } 1621 }
1613 else 1622 else
1614 b = args (2).double_value (); 1623 tol = args(3).double_value ();
1615
1616 if (nargin < 4)
1617 tol = 1.0e-6;
1618 else if (!args (3).is_real_scalar ())
1619 {
1620 error ("quadcc: fourth argument (tolerance) must be a single real scalar");
1621 return octave_value_list ();
1622 }
1623 else
1624 tol = args (3).double_value ();
1625 1624
1626 if (nargin < 5) 1625 if (nargin < 5)
1627 { 1626 {
1628 nivals = 1; 1627 nivals = 1;
1629 iivals[0] = a; 1628 iivals[0] = a;
1630 iivals[1] = b; 1629 iivals[1] = b;
1631 } 1630 }
1632 else if (!(args (4).is_real_scalar () || args (4).is_real_matrix ())) 1631 else if (!(args(4).is_real_scalar () || args(4).is_real_matrix ()))
1633 { 1632 {
1634 error ("quadcc: fifth argument (singularities) must be a vector of real values"); 1633 error ("quadcc: list of singularities (SING) must be a vector of real values");
1635 return octave_value_list (); 1634 return retval;
1636 } 1635 }
1637 else 1636 else
1638 { 1637 {
1639 nivals = 1 + args (4).length (); 1638 nivals = 1 + args(4).length ();
1640 if ( nivals > cquad_heapsize ) { 1639 if (nivals > cquad_heapsize)
1641 error ("quadcc: maximum number of singular points is limited to %i", 1640 {
1642 cquad_heapsize-1); 1641 error ("quadcc: maximum number of singular points is limited to %i",
1643 return octave_value_list(); 1642 cquad_heapsize-1);
1643 return retval;
1644 } 1644 }
1645 sing = args (4).array_value ().fortran_vec (); 1645 sing = args(4).array_value ().fortran_vec ();
1646 iivals[0] = a; 1646 iivals[0] = a;
1647 for (i = 0; i < nivals - 2; i++) 1647 for (i = 0; i < nivals - 2; i++)
1648 iivals[i + 1] = sing[i]; 1648 iivals[i + 1] = sing[i];
1649 iivals[nivals] = b; 1649 iivals[nivals] = b;
1650 } 1650 }
1651 1651
1652 /* If a or b are +/-Inf, transform the integral. */ 1652 /* If a or b are +/-Inf, transform the integral. */
1653 if (xisinf (a) || xisinf (b)) 1653 if (xisinf (a) || xisinf (b))
1654 { 1654 {
1655 wrap = 1; 1655 wrap = true;
1656 for (i = 0; i <= nivals; i++) 1656 for (i = 0; i <= nivals; i++)
1657 if (xisinf (iivals[i])) 1657 if (xisinf (iivals[i]))
1658 iivals[i] = copysign (1.0, iivals[i]); 1658 iivals[i] = copysign (1.0, iivals[i]);
1659 else 1659 else
1660 iivals[i] = 2.0 * atan (iivals[i]) / M_PI; 1660 iivals[i] = 2.0 * atan (iivals[i]) / M_PI;
1686 else 1686 else
1687 { 1687 {
1688 for (i = 0; i <= n[3]; i++) 1688 for (i = 0; i <= n[3]; i++)
1689 ex (i) = m + xi[i] * h; 1689 ex (i) = m + xi[i] * h;
1690 } 1690 }
1691 fargs (0) = ex; 1691 fargs(0) = ex;
1692 retval = feval (fcn, fargs, 1); 1692 fvals = feval (fcn, fargs, 1);
1693 if (retval.length () != 1 || !retval (0).is_real_matrix ()) 1693 if (fvals.length () != 1 || !fvals(0).is_real_matrix ())
1694 { 1694 {
1695 error 1695 error ("quadcc: integrand F must return a single, real-valued vector");
1696 ("quadcc: integrand must return a single, real-valued vector"); 1696 return retval;
1697 return octave_value_list ();
1698 } 1697 }
1699 Matrix effex = retval (0).matrix_value (); 1698 Matrix effex = fvals(0).matrix_value ();
1700 if (effex.length () != ex.length ()) 1699 if (effex.length () != ex.length ())
1701 { 1700 {
1702 error ("quadcc: integrand must return a single, real-valued vector of the same size as the input"); 1701 error ("quadcc: integrand F must return a single, real-valued vector of the same size as the input");
1703 return octave_value_list (); 1702 return retval;
1704 } 1703 }
1705 for (i = 0; i <= n[3]; i++) 1704 for (i = 0; i <= n[3]; i++)
1706 { 1705 {
1707 iv->fx[i] = effex (i); 1706 iv->fx[i] = effex (i);
1708 if (wrap) 1707 if (wrap)
1807 else 1806 else
1808 { 1807 {
1809 for (i = 0; i < n[d] / 2; i++) 1808 for (i = 0; i < n[d] / 2; i++)
1810 ex (i) = m + xi[(2 * i + 1) * skip[d]] * h; 1809 ex (i) = m + xi[(2 * i + 1) * skip[d]] * h;
1811 } 1810 }
1812 fargs (0) = ex; 1811 fargs(0) = ex;
1813 retval = feval (fcn, fargs, 1); 1812 fvals = feval (fcn, fargs, 1);
1814 if (retval.length () != 1 || !retval (0).is_real_matrix ()) 1813 if (fvals.length () != 1 || !fvals(0).is_real_matrix ())
1815 { 1814 {
1816 error ("quadcc: integrand must return a single, real-valued vector"); 1815 error ("quadcc: integrand F must return a single, real-valued vector");
1817 return octave_value_list (); 1816 return retval;
1818 } 1817 }
1819 Matrix effex = retval (0).matrix_value (); 1818 Matrix effex = fvals(0).matrix_value ();
1820 if (effex.length () != ex.length ()) 1819 if (effex.length () != ex.length ())
1821 { 1820 {
1822 error ("quadcc: integrand must return a single, real-valued vector of the same size as the input"); 1821 error ("quadcc: integrand F must return a single, real-valued vector of the same size as the input");
1823 return octave_value_list (); 1822 return retval;
1824 } 1823 }
1825 neval += effex.length (); 1824 neval += effex.length ();
1826 for (i = 0; i < n[d] / 2; i++) 1825 for (i = 0; i < n[d] / 2; i++)
1827 { 1826 {
1828 j = (2 * i + 1) * skip[d]; 1827 j = (2 * i + 1) * skip[d];
1955 else 1954 else
1956 { 1955 {
1957 for (i = 0; i < n[0] - 1; i++) 1956 for (i = 0; i < n[0] - 1; i++)
1958 ex (i) = ml + xi[(i + 1) * skip[0]] * hl; 1957 ex (i) = ml + xi[(i + 1) * skip[0]] * hl;
1959 } 1958 }
1960 fargs (0) = ex; 1959 fargs(0) = ex;
1961 retval = feval (fcn, fargs, 1); 1960 fvals = feval (fcn, fargs, 1);
1962 if (retval.length () != 1 || !retval (0).is_real_matrix ()) 1961 if (fvals.length () != 1 || !fvals(0).is_real_matrix ())
1963 { 1962 {
1964 error ("quadcc: integrand must return a single, real-valued vector"); 1963 error ("quadcc: integrand F must return a single, real-valued vector");
1965 return octave_value_list (); 1964 return retval;
1966 } 1965 }
1967 Matrix effex = retval (0).matrix_value (); 1966 Matrix effex = fvals(0).matrix_value ();
1968 if (effex.length () != ex.length ()) 1967 if (effex.length () != ex.length ())
1969 { 1968 {
1970 error ("quadcc: integrand must return a single, real-valued vector of the same size as the input"); 1969 error ("quadcc: integrand F must return a single, real-valued vector of the same size as the input");
1971 return octave_value_list (); 1970 return retval;
1972 } 1971 }
1973 neval += effex.length (); 1972 neval += effex.length ();
1974 for (i = 0; i < n[0] - 1; i++) 1973 for (i = 0; i < n[0] - 1; i++)
1975 { 1974 {
1976 j = (i + 1) * skip[0]; 1975 j = (i + 1) * skip[0];
2051 else 2050 else
2052 { 2051 {
2053 for (i = 0; i < n[0] - 1; i++) 2052 for (i = 0; i < n[0] - 1; i++)
2054 ex (i) = mr + xi[(i + 1) * skip[0]] * hr; 2053 ex (i) = mr + xi[(i + 1) * skip[0]] * hr;
2055 } 2054 }
2056 fargs (0) = ex; 2055 fargs(0) = ex;
2057 retval = feval (fcn, fargs, 1); 2056 fvals = feval (fcn, fargs, 1);
2058 if (retval.length () != 1 || !retval (0).is_real_matrix ()) 2057 if (fvals.length () != 1 || !fvals(0).is_real_matrix ())
2059 { 2058 {
2060 error ("quadcc: integrand must return a single, real-valued vector"); 2059 error ("quadcc: integrand F must return a single, real-valued vector");
2061 return octave_value_list (); 2060 return retval;
2062 } 2061 }
2063 Matrix effex = retval (0).matrix_value (); 2062 Matrix effex = fvals(0).matrix_value ();
2064 if (effex.length () != ex.length ()) 2063 if (effex.length () != ex.length ())
2065 { 2064 {
2066 error ("quadcc: integrand must return a single, real-valued vector of the same size as the input"); 2065 error ("quadcc: integrand F must return a single, real-valued vector of the same size as the input");
2067 return octave_value_list (); 2066 return retval;
2068 } 2067 }
2069 neval += effex.length (); 2068 neval += effex.length ();
2070 for (i = 0; i < n[0] - 1; i++) 2069 for (i = 0; i < n[0] - 1; i++)
2071 { 2070 {
2072 j = (i + 1) * skip[0]; 2071 j = (i + 1) * skip[0];
2232 i, heap[i], iv->a, iv->b, iv->igral, iv->err, iv->depth, 2231 i, heap[i], iv->a, iv->b, iv->igral, iv->err, iv->depth,
2233 iv->rdepth, iv->ndiv); 2232 iv->rdepth, iv->ndiv);
2234 } 2233 }
2235 */ 2234 */
2236 /* Clean up and present the results. */ 2235 /* Clean up and present the results. */
2237 retval (0) = igral; 2236 if (nargout > 2)
2237 retval(2) = neval;
2238 if (nargout > 1) 2238 if (nargout > 1)
2239 retval (1) = err; 2239 retval(1) = err;
2240 if (nargout > 2) 2240 retval(0) = igral;
2241 retval (2) = neval;
2242 /* All is well that ends well. */ 2241 /* All is well that ends well. */
2243 return retval; 2242 return retval;
2244 } 2243 }
2244
2245
2246 /*
2247
2248 %!assert (quadcc(@sin,-pi,pi), 0, 1e-6)
2249 %!assert (quadcc(inline('sin'),-pi,pi), 0, 1e-6)
2250 %!assert (quadcc('sin',-pi,pi), 0, 1e-6)
2251
2252 %!assert (quadcc(@sin,-pi,0), -2, 1e-6)
2253 %!assert (quadcc(@sin,0,pi), 2, 1e-6)
2254 %!assert (quadcc(@(x) 1./sqrt(x), 0, 1), 2, 1e-6)
2255 %!assert (quadcc(@(x) 1./(sqrt(x).*(x+1)), 0, Inf), pi, 1e-6)
2256
2257 %!assert (quadcc (@(x) exp(-x .^ 2), -Inf, Inf), sqrt(pi), 1e-6)
2258 %!assert (quadcc (@(x) exp(-x .^ 2), -Inf, 0), sqrt(pi)/2, 1e-6)
2259
2260 %% Test input validation
2261 %!error (quadcc ())
2262 %!error (quadcc (@sin))
2263 %!error (quadcc (@sin, 0))
2264 %!error (quadcc (@sin, ones(2), pi))
2265 %!error (quadcc (@sin, -i, pi))
2266 %!error (quadcc (@sin, 0, ones(2)))
2267 %!error (quadcc (@sin, 0, i))
2268 %!error (quadcc (@sin, 0, pi, 0))
2269 %!error (quadcc (@sin, 0, pi, 1e-6, [ i ]))
2270
2271 */