Mercurial > forge
changeset 86:b5a37718a50d octave-forge
(for Leopoldo Cerbaro) handle complex inputs
author | pkienzle |
---|---|
date | Fri, 21 Dec 2001 16:44:30 +0000 |
parents | e26254f9e5dc |
children | ce5400ea9ba1 |
files | main/specfun/ellipj.m |
diffstat | 1 files changed, 97 insertions(+), 78 deletions(-) [+] |
line wrap: on
line diff
--- a/main/specfun/ellipj.m Fri Dec 21 16:42:46 2001 +0000 +++ b/main/specfun/ellipj.m Fri Dec 21 16:44:30 2001 +0000 @@ -14,15 +14,12 @@ ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -## Compute the Jacobi elliptic functions sn(u|m), cn(u|m) and dn(u|m) -## for argument u and parameter m. -## ## usage: [sn,cn,dn] = ellipj(u,m[,tol]) ## -## u and m must be real arrays of same size. Either or both can be -## scalars. m is restricted to 0 <= m <= 1. +## Compute the Jacobi elliptic functions sn(u|m), cn(u|m) and dn(u|m) +## for complex argument u and parameter 0 <= m <= 1. ## -## WARNING: the approximation blows up for abs(U)>20 near m=1. +## WARNING: the approximation blows up for abs(u)>20 near m=1. ## ## tol is accepted for compatibility, but ignored ## @@ -32,104 +29,126 @@ ## ## Example ## m = linspace(0,1,200); u=linspace(-10,10,200); -## M = ones(length(u),1) * m; U = u' * ones(1,length(m)); +## [U,M] = meshgrid(u,m); ## [sn, cn, dn] = ellipj(U,M); ## imagesc(sn); ## ## See also: ellipke ## Author: David Billinghurst <David.Billinghurst@riotinto.com> -## Created: 31 January 2001 -## 2001-02-01 Paul Kienzle +## 2001-01-31 David Billinghurst <David.Billinghusrt@riotinto.com> +## * initial revision +## 2001-02-01 Paul Kienzle <pkienzle@users.sf.net> ## * vectorized ## * added demos ## * included function name in error messages +## 2001-12-15 Leopoldo Cerbaro <redbliss@libero.it> +## * support for complex u function [sn, cn, dn] = ellipj (u, m) if nargin < 2 || nargin > 3 usage("[sn, cn, dn] = ellipj (u, m)"); endif - if size(u,1) != size(m,1) || size(u,2) != size(m,2), - error("ellipj must have same shape for u and m"); + [err, u, m] = common_size(u,m); + if any(size(m) != size(u)) + error("ellipj m and u must have the same shape"); + endif + if is_complex(m) || any(m(:) < 0.0 | m(:) > 1.0) + error("ellipj must have m in the range [0,1]"); endif - sn=cn=dn=phi=zeros(size(u)); - m = m(:); u=u(:); + sn=cn=dn=zeros(size(u)); + if (is_complex(u)) + m1 = 1.0-m; - if !all(isreal(m) & isreal(u)) - error("ellipj must have real u and m"); - endif - if any(m < 0.0 | m > 1.0), - error("ellipj must have m in the range [0,1]"); + ## u is pure imaginary: Jacoby imag. transf. + idx = (real(u) == 0. & imag(u) != 0.); + [ss1,cc1,dd1] = ellipj( imag(u(idx)), m1(idx)); + sn(idx) = 1i * ss1./cc1; + cn(idx) = 1./cc1; + dn(idx) = dd1./cc1; + + ## u is pure real + idx = (imag(u) == 0.); + [ss,cc,dd] = ellipj( real(u(idx)), m(idx)); + sn(idx) = ss; + cn(idx) = cc; + dn(idx) = dd; + + ## u is generic complex + idx = (real(u) != 0. & imag(u) != 0.); + [ss1,cc1,dd1] = ellipj( imag(u(idx)), m1(idx)); + [ss,cc,dd] = ellipj( real(u(idx)), m(idx)); + ddd = cc1.^2 + m(idx).*(ss.^2).*(ss1.^2); + sn(idx) = (ss.*dd1 + 1i*cc.*dd.*ss1.*cc1)./ddd; + cn(idx) = (cc.*cc1 - 1i*ss.*dd.*ss1.*dd1)./ddd; + dn(idx) = (dd.*cc1.*dd1 - 1i*m(idx).*ss.*cc.*ss1)./ddd; + return endif lo = sqrt(eps); hi = 1-sqrt(eps); - dfi = do_fortran_indexing; - unwind_protect - do_fortran_indexing = 1; - - ## For small m, ( Abramowitz and Stegun, Section 16.13 ) - idx = find(m < lo); - if !isempty(idx) - uidx = u(idx); - midx = m(idx); - sin_u = sin(uidx); - cos_u = cos(uidx); - t = 0.25 * midx .* (uidx - sin_u.*cos_u); - sn(idx) = sin_u - t.*cos_u; - cn(idx) = cos_u + t.*sin_u; - dn(idx) = 1.0 - 0.5*midx.*sin_u.*sin_u; - endif + ## For small m, ( Abramowitz and Stegun, Section 16.13 ) + idx = ( m < lo ); + if any(idx(:)) + uidx = u(idx)(:); + midx = m(idx)(:); + sin_u = sin(uidx); + cos_u = cos(uidx); + t = 0.25 * midx .* (uidx - sin_u.*cos_u); + sn(idx) = sin_u - t.*cos_u; + cn(idx) = cos_u + t.*sin_u; + dn(idx) = 1.0 - 0.5*midx.*sin_u.*sin_u; + endif - ## For m1 = (1-m) small ( Abramowitz and Stegun, Section 16.15 ) - idx = find( m >= hi ); - if !isempty(idx) - uidx = u(idx); - sinh_u = sinh(uidx); - cosh_u = cosh(uidx); - tanh_u = tanh(uidx); - sech_u = 1.0./cosh_u; - sechm1over4 = 0.25 * (1.0 - m(idx)) ./ cosh_u; - sinhcosh = sinh_u.*cosh_u; - sn(idx) = tanh_u + sechm1over4 .* (sinhcosh-uidx) .* sech_u; - cn(idx) = sech_u - sechm1over4 .* (sinhcosh-uidx) .* tanh_u; - dn(idx) = sech_u + sechm1over4 .* (sinhcosh+uidx) .* tanh_u; - endif + ## For m1 = (1-m) small ( Abramowitz and Stegun, Section 16.15 ) + idx = ( m > hi ); + if any(idx(:)) + uidx = u(idx)(:); + midx = m(idx)(:); + sinh_u = sinh(uidx); + cosh_u = cosh(uidx); + tanh_u = tanh(uidx); + sech_u = 1.0./cosh_u; + sechm1over4 = 0.25 * (1.0 - midx) ./ cosh_u; + sinhcosh = sinh_u.*cosh_u; + sn(idx) = tanh_u + sechm1over4 .* (sinhcosh-uidx) .* sech_u; + cn(idx) = sech_u - sechm1over4 .* (sinhcosh-uidx) .* tanh_u; + dn(idx) = sech_u + sechm1over4 .* (sinhcosh+uidx) .* tanh_u; + endif - ## Arithmetic-Geometric Mean (AGM) algorithm - ## ( Abramowitz and Stegun, Section 16.4 ) - idx = find ( lo <= m & m < hi ); - if !isempty(idx) - Nmax = 16; - c = a = zeros(length(idx),Nmax); - a(:,1) = ones(length(idx),1); - b = sqrt(1.0 - m(idx)); - c(:,1) = sqrt(m(idx)); - for n = 2:Nmax - a(:,n) = (a(:,n-1) + b) / 2.0; - c(:,n) = (a(:,n-1) - b) / 2.0; - b = sqrt ( a(:,n-1) .* b); - if all (c(:,n)./a(:,n) < eps), break; endif - endfor - if n >= Nmax - error("ellipj: Not enough workspace"); - endif - phi = 2.^(n-1) * a(:,n) .* u(idx); - for j=n:-1:2 - t = phi; - phi = ( asin ( (c(:,j)./a(:,j)) .* sin(phi)) + phi ) / 2; - endfor + ## Arithmetic-Geometric Mean (AGM) algorithm + ## ( Abramowitz and Stegun, Section 16.4 ) + idx = ( lo <= m & m <= hi ); + if any(idx(:)) + uidx = u(idx)(:); + midx = m(idx)(:); + Nmax = 16; + c = a = zeros(sum(idx(:)),Nmax); + a(:,1) = ones(sum(idx(:)),1); + b = sqrt(1.0 - midx); + c(:,1) = sqrt(midx); + for n = 2:Nmax + a(:,n) = (a(:,n-1) + b) / 2.0; + c(:,n) = (a(:,n-1) - b) / 2.0; + b = sqrt ( a(:,n-1) .* b); + if all (c(:,n)./a(:,n) < eps), break; endif + endfor + if n >= Nmax + error("ellipj: Not enough workspace"); + endif + phi = 2.^(n-1) * a(:,n) .* uidx; + for j=n:-1:2 + t = phi; + phi = ( asin ( (c(:,j)./a(:,j)) .* sin(phi)) + phi ) / 2; + endfor - sn(idx) = sin(phi); - cn(idx) = cos(phi); - dn(idx) = cos(phi)./cos(t-phi); - endif - unwind_protect_cleanup - do_fortran_indexing = dfi; - end_unwind_protect + sn(idx) = sin(phi); + cn(idx) = cos(phi); + dn(idx) = cos(phi)./cos(t-phi); + endif endfunction %!demo