Mercurial > octave
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 */ |