GiNaC  1.6.2
inifcns_trans.cpp
Go to the documentation of this file.
00001 
00006 /*
00007  *  GiNaC Copyright (C) 1999-2011 Johannes Gutenberg University Mainz, Germany
00008  *
00009  *  This program is free software; you can redistribute it and/or modify
00010  *  it under the terms of the GNU General Public License as published by
00011  *  the Free Software Foundation; either version 2 of the License, or
00012  *  (at your option) any later version.
00013  *
00014  *  This program is distributed in the hope that it will be useful,
00015  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  *  GNU General Public License for more details.
00018  *
00019  *  You should have received a copy of the GNU General Public License
00020  *  along with this program; if not, write to the Free Software
00021  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00022  */
00023 
00024 #include "inifcns.h"
00025 #include "ex.h"
00026 #include "constant.h"
00027 #include "numeric.h"
00028 #include "power.h"
00029 #include "operators.h"
00030 #include "relational.h"
00031 #include "symbol.h"
00032 #include "pseries.h"
00033 #include "utils.h"
00034 
00035 #include <stdexcept>
00036 #include <vector>
00037 
00038 namespace GiNaC {
00039 
00041 // exponential function
00043 
00044 static ex exp_evalf(const ex & x)
00045 {
00046     if (is_exactly_a<numeric>(x))
00047         return exp(ex_to<numeric>(x));
00048     
00049     return exp(x).hold();
00050 }
00051 
00052 static ex exp_eval(const ex & x)
00053 {
00054     // exp(0) -> 1
00055     if (x.is_zero()) {
00056         return _ex1;
00057     }
00058 
00059     // exp(n*Pi*I/2) -> {+1|+I|-1|-I}
00060     const ex TwoExOverPiI=(_ex2*x)/(Pi*I);
00061     if (TwoExOverPiI.info(info_flags::integer)) {
00062         const numeric z = mod(ex_to<numeric>(TwoExOverPiI),*_num4_p);
00063         if (z.is_equal(*_num0_p))
00064             return _ex1;
00065         if (z.is_equal(*_num1_p))
00066             return ex(I);
00067         if (z.is_equal(*_num2_p))
00068             return _ex_1;
00069         if (z.is_equal(*_num3_p))
00070             return ex(-I);
00071     }
00072 
00073     // exp(log(x)) -> x
00074     if (is_ex_the_function(x, log))
00075         return x.op(0);
00076     
00077     // exp(float) -> float
00078     if (x.info(info_flags::numeric) && !x.info(info_flags::crational))
00079         return exp(ex_to<numeric>(x));
00080     
00081     return exp(x).hold();
00082 }
00083 
00084 static ex exp_deriv(const ex & x, unsigned deriv_param)
00085 {
00086     GINAC_ASSERT(deriv_param==0);
00087 
00088     // d/dx exp(x) -> exp(x)
00089     return exp(x);
00090 }
00091 
00092 static ex exp_real_part(const ex & x)
00093 {
00094     return exp(GiNaC::real_part(x))*cos(GiNaC::imag_part(x));
00095 }
00096 
00097 static ex exp_imag_part(const ex & x)
00098 {
00099     return exp(GiNaC::real_part(x))*sin(GiNaC::imag_part(x));
00100 }
00101 
00102 static ex exp_conjugate(const ex & x)
00103 {
00104     // conjugate(exp(x))==exp(conjugate(x))
00105     return exp(x.conjugate());
00106 }
00107 
00108 REGISTER_FUNCTION(exp, eval_func(exp_eval).
00109                        evalf_func(exp_evalf).
00110                        derivative_func(exp_deriv).
00111                        real_part_func(exp_real_part).
00112                        imag_part_func(exp_imag_part).
00113                        conjugate_func(exp_conjugate).
00114                        latex_name("\\exp"));
00115 
00117 // natural logarithm
00119 
00120 static ex log_evalf(const ex & x)
00121 {
00122     if (is_exactly_a<numeric>(x))
00123         return log(ex_to<numeric>(x));
00124     
00125     return log(x).hold();
00126 }
00127 
00128 static ex log_eval(const ex & x)
00129 {
00130     if (x.info(info_flags::numeric)) {
00131         if (x.is_zero())         // log(0) -> infinity
00132             throw(pole_error("log_eval(): log(0)",0));
00133         if (x.info(info_flags::rational) && x.info(info_flags::negative))
00134             return (log(-x)+I*Pi);
00135         if (x.is_equal(_ex1))  // log(1) -> 0
00136             return _ex0;
00137         if (x.is_equal(I))       // log(I) -> Pi*I/2
00138             return (Pi*I*_ex1_2);
00139         if (x.is_equal(-I))      // log(-I) -> -Pi*I/2
00140             return (Pi*I*_ex_1_2);
00141 
00142         // log(float) -> float
00143         if (!x.info(info_flags::crational))
00144             return log(ex_to<numeric>(x));
00145     }
00146 
00147     // log(exp(t)) -> t (if -Pi < t.imag() <= Pi):
00148     if (is_ex_the_function(x, exp)) {
00149         const ex &t = x.op(0);
00150         if (t.info(info_flags::real))
00151             return t;
00152     }
00153     
00154     return log(x).hold();
00155 }
00156 
00157 static ex log_deriv(const ex & x, unsigned deriv_param)
00158 {
00159     GINAC_ASSERT(deriv_param==0);
00160     
00161     // d/dx log(x) -> 1/x
00162     return power(x, _ex_1);
00163 }
00164 
00165 static ex log_series(const ex &arg,
00166                      const relational &rel,
00167                      int order,
00168                      unsigned options)
00169 {
00170     GINAC_ASSERT(is_a<symbol>(rel.lhs()));
00171     ex arg_pt;
00172     bool must_expand_arg = false;
00173     // maybe substitution of rel into arg fails because of a pole
00174     try {
00175         arg_pt = arg.subs(rel, subs_options::no_pattern);
00176     } catch (pole_error) {
00177         must_expand_arg = true;
00178     }
00179     // or we are at the branch point anyways
00180     if (arg_pt.is_zero())
00181         must_expand_arg = true;
00182     
00183     if (must_expand_arg) {
00184         // method:
00185         // This is the branch point: Series expand the argument first, then
00186         // trivially factorize it to isolate that part which has constant
00187         // leading coefficient in this fashion:
00188         //   x^n + x^(n+1) +...+ Order(x^(n+m))  ->  x^n * (1 + x +...+ Order(x^m)).
00189         // Return a plain n*log(x) for the x^n part and series expand the
00190         // other part.  Add them together and reexpand again in order to have
00191         // one unnested pseries object.  All this also works for negative n.
00192         pseries argser;          // series expansion of log's argument
00193         unsigned extra_ord = 0;  // extra expansion order
00194         do {
00195             // oops, the argument expanded to a pure Order(x^something)...
00196             argser = ex_to<pseries>(arg.series(rel, order+extra_ord, options));
00197             ++extra_ord;
00198         } while (!argser.is_terminating() && argser.nops()==1);
00199 
00200         const symbol &s = ex_to<symbol>(rel.lhs());
00201         const ex &point = rel.rhs();
00202         const int n = argser.ldegree(s);
00203         epvector seq;
00204         // construct what we carelessly called the n*log(x) term above
00205         const ex coeff = argser.coeff(s, n);
00206         // expand the log, but only if coeff is real and > 0, since otherwise
00207         // it would make the branch cut run into the wrong direction
00208         if (coeff.info(info_flags::positive))
00209             seq.push_back(expair(n*log(s-point)+log(coeff), _ex0));
00210         else
00211             seq.push_back(expair(log(coeff*pow(s-point, n)), _ex0));
00212 
00213         if (!argser.is_terminating() || argser.nops()!=1) {
00214             // in this case n more (or less) terms are needed
00215             // (sadly, to generate them, we have to start from the beginning)
00216             if (n == 0 && coeff == 1) {
00217                 epvector epv;
00218                 ex acc = (new pseries(rel, epv))->setflag(status_flags::dynallocated);
00219                 epv.reserve(2);
00220                 epv.push_back(expair(-1, _ex0));
00221                 epv.push_back(expair(Order(_ex1), order));
00222                 ex rest = pseries(rel, epv).add_series(argser);
00223                 for (int i = order-1; i>0; --i) {
00224                     epvector cterm;
00225                     cterm.reserve(1);
00226                     cterm.push_back(expair(i%2 ? _ex1/i : _ex_1/i, _ex0));
00227                     acc = pseries(rel, cterm).add_series(ex_to<pseries>(acc));
00228                     acc = (ex_to<pseries>(rest)).mul_series(ex_to<pseries>(acc));
00229                 }
00230                 return acc;
00231             }
00232             const ex newarg = ex_to<pseries>((arg/coeff).series(rel, order+n, options)).shift_exponents(-n).convert_to_poly(true);
00233             return pseries(rel, seq).add_series(ex_to<pseries>(log(newarg).series(rel, order, options)));
00234         } else  // it was a monomial
00235             return pseries(rel, seq);
00236     }
00237     if (!(options & series_options::suppress_branchcut) &&
00238          arg_pt.info(info_flags::negative)) {
00239         // method:
00240         // This is the branch cut: assemble the primitive series manually and
00241         // then add the corresponding complex step function.
00242         const symbol &s = ex_to<symbol>(rel.lhs());
00243         const ex &point = rel.rhs();
00244         const symbol foo;
00245         const ex replarg = series(log(arg), s==foo, order).subs(foo==point, subs_options::no_pattern);
00246         epvector seq;
00247         seq.push_back(expair(-I*csgn(arg*I)*Pi, _ex0));
00248         seq.push_back(expair(Order(_ex1), order));
00249         return series(replarg - I*Pi + pseries(rel, seq), rel, order);
00250     }
00251     throw do_taylor();  // caught by function::series()
00252 }
00253 
00254 static ex log_real_part(const ex & x)
00255 {
00256     if (x.info(info_flags::nonnegative))
00257         return log(x).hold();
00258     return log(abs(x));
00259 }
00260 
00261 static ex log_imag_part(const ex & x)
00262 {
00263     if (x.info(info_flags::nonnegative))
00264         return 0;
00265     return atan2(GiNaC::imag_part(x), GiNaC::real_part(x));
00266 }
00267 
00268 static ex log_conjugate(const ex & x)
00269 {
00270     // conjugate(log(x))==log(conjugate(x)) unless on the branch cut which
00271     // runs along the negative real axis.
00272     if (x.info(info_flags::positive)) {
00273         return log(x);
00274     }
00275     if (is_exactly_a<numeric>(x) &&
00276         !x.imag_part().is_zero()) {
00277         return log(x.conjugate());
00278     }
00279     return conjugate_function(log(x)).hold();
00280 }
00281 
00282 REGISTER_FUNCTION(log, eval_func(log_eval).
00283                        evalf_func(log_evalf).
00284                        derivative_func(log_deriv).
00285                        series_func(log_series).
00286                        real_part_func(log_real_part).
00287                        imag_part_func(log_imag_part).
00288                        conjugate_func(log_conjugate).
00289                        latex_name("\\ln"));
00290 
00292 // sine (trigonometric function)
00294 
00295 static ex sin_evalf(const ex & x)
00296 {
00297     if (is_exactly_a<numeric>(x))
00298         return sin(ex_to<numeric>(x));
00299     
00300     return sin(x).hold();
00301 }
00302 
00303 static ex sin_eval(const ex & x)
00304 {
00305     // sin(n/d*Pi) -> { all known non-nested radicals }
00306     const ex SixtyExOverPi = _ex60*x/Pi;
00307     ex sign = _ex1;
00308     if (SixtyExOverPi.info(info_flags::integer)) {
00309         numeric z = mod(ex_to<numeric>(SixtyExOverPi),*_num120_p);
00310         if (z>=*_num60_p) {
00311             // wrap to interval [0, Pi)
00312             z -= *_num60_p;
00313             sign = _ex_1;
00314         }
00315         if (z>*_num30_p) {
00316             // wrap to interval [0, Pi/2)
00317             z = *_num60_p-z;
00318         }
00319         if (z.is_equal(*_num0_p))  // sin(0)       -> 0
00320             return _ex0;
00321         if (z.is_equal(*_num5_p))  // sin(Pi/12)   -> sqrt(6)/4*(1-sqrt(3)/3)
00322             return sign*_ex1_4*sqrt(_ex6)*(_ex1+_ex_1_3*sqrt(_ex3));
00323         if (z.is_equal(*_num6_p))  // sin(Pi/10)   -> sqrt(5)/4-1/4
00324             return sign*(_ex1_4*sqrt(_ex5)+_ex_1_4);
00325         if (z.is_equal(*_num10_p)) // sin(Pi/6)    -> 1/2
00326             return sign*_ex1_2;
00327         if (z.is_equal(*_num15_p)) // sin(Pi/4)    -> sqrt(2)/2
00328             return sign*_ex1_2*sqrt(_ex2);
00329         if (z.is_equal(*_num18_p)) // sin(3/10*Pi) -> sqrt(5)/4+1/4
00330             return sign*(_ex1_4*sqrt(_ex5)+_ex1_4);
00331         if (z.is_equal(*_num20_p)) // sin(Pi/3)    -> sqrt(3)/2
00332             return sign*_ex1_2*sqrt(_ex3);
00333         if (z.is_equal(*_num25_p)) // sin(5/12*Pi) -> sqrt(6)/4*(1+sqrt(3)/3)
00334             return sign*_ex1_4*sqrt(_ex6)*(_ex1+_ex1_3*sqrt(_ex3));
00335         if (z.is_equal(*_num30_p)) // sin(Pi/2)    -> 1
00336             return sign;
00337     }
00338 
00339     if (is_exactly_a<function>(x)) {
00340         const ex &t = x.op(0);
00341 
00342         // sin(asin(x)) -> x
00343         if (is_ex_the_function(x, asin))
00344             return t;
00345 
00346         // sin(acos(x)) -> sqrt(1-x^2)
00347         if (is_ex_the_function(x, acos))
00348             return sqrt(_ex1-power(t,_ex2));
00349 
00350         // sin(atan(x)) -> x/sqrt(1+x^2)
00351         if (is_ex_the_function(x, atan))
00352             return t*power(_ex1+power(t,_ex2),_ex_1_2);
00353     }
00354     
00355     // sin(float) -> float
00356     if (x.info(info_flags::numeric) && !x.info(info_flags::crational))
00357         return sin(ex_to<numeric>(x));
00358 
00359     // sin() is odd
00360     if (x.info(info_flags::negative))
00361         return -sin(-x);
00362     
00363     return sin(x).hold();
00364 }
00365 
00366 static ex sin_deriv(const ex & x, unsigned deriv_param)
00367 {
00368     GINAC_ASSERT(deriv_param==0);
00369     
00370     // d/dx sin(x) -> cos(x)
00371     return cos(x);
00372 }
00373 
00374 static ex sin_real_part(const ex & x)
00375 {
00376     return cosh(GiNaC::imag_part(x))*sin(GiNaC::real_part(x));
00377 }
00378 
00379 static ex sin_imag_part(const ex & x)
00380 {
00381     return sinh(GiNaC::imag_part(x))*cos(GiNaC::real_part(x));
00382 }
00383 
00384 static ex sin_conjugate(const ex & x)
00385 {
00386     // conjugate(sin(x))==sin(conjugate(x))
00387     return sin(x.conjugate());
00388 }
00389 
00390 REGISTER_FUNCTION(sin, eval_func(sin_eval).
00391                        evalf_func(sin_evalf).
00392                        derivative_func(sin_deriv).
00393                        real_part_func(sin_real_part).
00394                        imag_part_func(sin_imag_part).
00395                        conjugate_func(sin_conjugate).
00396                        latex_name("\\sin"));
00397 
00399 // cosine (trigonometric function)
00401 
00402 static ex cos_evalf(const ex & x)
00403 {
00404     if (is_exactly_a<numeric>(x))
00405         return cos(ex_to<numeric>(x));
00406     
00407     return cos(x).hold();
00408 }
00409 
00410 static ex cos_eval(const ex & x)
00411 {
00412     // cos(n/d*Pi) -> { all known non-nested radicals }
00413     const ex SixtyExOverPi = _ex60*x/Pi;
00414     ex sign = _ex1;
00415     if (SixtyExOverPi.info(info_flags::integer)) {
00416         numeric z = mod(ex_to<numeric>(SixtyExOverPi),*_num120_p);
00417         if (z>=*_num60_p) {
00418             // wrap to interval [0, Pi)
00419             z = *_num120_p-z;
00420         }
00421         if (z>=*_num30_p) {
00422             // wrap to interval [0, Pi/2)
00423             z = *_num60_p-z;
00424             sign = _ex_1;
00425         }
00426         if (z.is_equal(*_num0_p))  // cos(0)       -> 1
00427             return sign;
00428         if (z.is_equal(*_num5_p))  // cos(Pi/12)   -> sqrt(6)/4*(1+sqrt(3)/3)
00429             return sign*_ex1_4*sqrt(_ex6)*(_ex1+_ex1_3*sqrt(_ex3));
00430         if (z.is_equal(*_num10_p)) // cos(Pi/6)    -> sqrt(3)/2
00431             return sign*_ex1_2*sqrt(_ex3);
00432         if (z.is_equal(*_num12_p)) // cos(Pi/5)    -> sqrt(5)/4+1/4
00433             return sign*(_ex1_4*sqrt(_ex5)+_ex1_4);
00434         if (z.is_equal(*_num15_p)) // cos(Pi/4)    -> sqrt(2)/2
00435             return sign*_ex1_2*sqrt(_ex2);
00436         if (z.is_equal(*_num20_p)) // cos(Pi/3)    -> 1/2
00437             return sign*_ex1_2;
00438         if (z.is_equal(*_num24_p)) // cos(2/5*Pi)  -> sqrt(5)/4-1/4x
00439             return sign*(_ex1_4*sqrt(_ex5)+_ex_1_4);
00440         if (z.is_equal(*_num25_p)) // cos(5/12*Pi) -> sqrt(6)/4*(1-sqrt(3)/3)
00441             return sign*_ex1_4*sqrt(_ex6)*(_ex1+_ex_1_3*sqrt(_ex3));
00442         if (z.is_equal(*_num30_p)) // cos(Pi/2)    -> 0
00443             return _ex0;
00444     }
00445 
00446     if (is_exactly_a<function>(x)) {
00447         const ex &t = x.op(0);
00448 
00449         // cos(acos(x)) -> x
00450         if (is_ex_the_function(x, acos))
00451             return t;
00452 
00453         // cos(asin(x)) -> sqrt(1-x^2)
00454         if (is_ex_the_function(x, asin))
00455             return sqrt(_ex1-power(t,_ex2));
00456 
00457         // cos(atan(x)) -> 1/sqrt(1+x^2)
00458         if (is_ex_the_function(x, atan))
00459             return power(_ex1+power(t,_ex2),_ex_1_2);
00460     }
00461     
00462     // cos(float) -> float
00463     if (x.info(info_flags::numeric) && !x.info(info_flags::crational))
00464         return cos(ex_to<numeric>(x));
00465     
00466     // cos() is even
00467     if (x.info(info_flags::negative))
00468         return cos(-x);
00469     
00470     return cos(x).hold();
00471 }
00472 
00473 static ex cos_deriv(const ex & x, unsigned deriv_param)
00474 {
00475     GINAC_ASSERT(deriv_param==0);
00476 
00477     // d/dx cos(x) -> -sin(x)
00478     return -sin(x);
00479 }
00480 
00481 static ex cos_real_part(const ex & x)
00482 {
00483     return cosh(GiNaC::imag_part(x))*cos(GiNaC::real_part(x));
00484 }
00485 
00486 static ex cos_imag_part(const ex & x)
00487 {
00488     return -sinh(GiNaC::imag_part(x))*sin(GiNaC::real_part(x));
00489 }
00490 
00491 static ex cos_conjugate(const ex & x)
00492 {
00493     // conjugate(cos(x))==cos(conjugate(x))
00494     return cos(x.conjugate());
00495 }
00496 
00497 REGISTER_FUNCTION(cos, eval_func(cos_eval).
00498                        evalf_func(cos_evalf).
00499                        derivative_func(cos_deriv).
00500                        real_part_func(cos_real_part).
00501                        imag_part_func(cos_imag_part).
00502                        conjugate_func(cos_conjugate).
00503                        latex_name("\\cos"));
00504 
00506 // tangent (trigonometric function)
00508 
00509 static ex tan_evalf(const ex & x)
00510 {
00511     if (is_exactly_a<numeric>(x))
00512         return tan(ex_to<numeric>(x));
00513     
00514     return tan(x).hold();
00515 }
00516 
00517 static ex tan_eval(const ex & x)
00518 {
00519     // tan(n/d*Pi) -> { all known non-nested radicals }
00520     const ex SixtyExOverPi = _ex60*x/Pi;
00521     ex sign = _ex1;
00522     if (SixtyExOverPi.info(info_flags::integer)) {
00523         numeric z = mod(ex_to<numeric>(SixtyExOverPi),*_num60_p);
00524         if (z>=*_num60_p) {
00525             // wrap to interval [0, Pi)
00526             z -= *_num60_p;
00527         }
00528         if (z>=*_num30_p) {
00529             // wrap to interval [0, Pi/2)
00530             z = *_num60_p-z;
00531             sign = _ex_1;
00532         }
00533         if (z.is_equal(*_num0_p))  // tan(0)       -> 0
00534             return _ex0;
00535         if (z.is_equal(*_num5_p))  // tan(Pi/12)   -> 2-sqrt(3)
00536             return sign*(_ex2-sqrt(_ex3));
00537         if (z.is_equal(*_num10_p)) // tan(Pi/6)    -> sqrt(3)/3
00538             return sign*_ex1_3*sqrt(_ex3);
00539         if (z.is_equal(*_num15_p)) // tan(Pi/4)    -> 1
00540             return sign;
00541         if (z.is_equal(*_num20_p)) // tan(Pi/3)    -> sqrt(3)
00542             return sign*sqrt(_ex3);
00543         if (z.is_equal(*_num25_p)) // tan(5/12*Pi) -> 2+sqrt(3)
00544             return sign*(sqrt(_ex3)+_ex2);
00545         if (z.is_equal(*_num30_p)) // tan(Pi/2)    -> infinity
00546             throw (pole_error("tan_eval(): simple pole",1));
00547     }
00548 
00549     if (is_exactly_a<function>(x)) {
00550         const ex &t = x.op(0);
00551 
00552         // tan(atan(x)) -> x
00553         if (is_ex_the_function(x, atan))
00554             return t;
00555 
00556         // tan(asin(x)) -> x/sqrt(1+x^2)
00557         if (is_ex_the_function(x, asin))
00558             return t*power(_ex1-power(t,_ex2),_ex_1_2);
00559 
00560         // tan(acos(x)) -> sqrt(1-x^2)/x
00561         if (is_ex_the_function(x, acos))
00562             return power(t,_ex_1)*sqrt(_ex1-power(t,_ex2));
00563     }
00564     
00565     // tan(float) -> float
00566     if (x.info(info_flags::numeric) && !x.info(info_flags::crational)) {
00567         return tan(ex_to<numeric>(x));
00568     }
00569     
00570     // tan() is odd
00571     if (x.info(info_flags::negative))
00572         return -tan(-x);
00573     
00574     return tan(x).hold();
00575 }
00576 
00577 static ex tan_deriv(const ex & x, unsigned deriv_param)
00578 {
00579     GINAC_ASSERT(deriv_param==0);
00580     
00581     // d/dx tan(x) -> 1+tan(x)^2;
00582     return (_ex1+power(tan(x),_ex2));
00583 }
00584 
00585 static ex tan_real_part(const ex & x)
00586 {
00587     ex a = GiNaC::real_part(x);
00588     ex b = GiNaC::imag_part(x);
00589     return tan(a)/(1+power(tan(a),2)*power(tan(b),2));
00590 }
00591 
00592 static ex tan_imag_part(const ex & x)
00593 {
00594     ex a = GiNaC::real_part(x);
00595     ex b = GiNaC::imag_part(x);
00596     return tanh(b)/(1+power(tan(a),2)*power(tan(b),2));
00597 }
00598 
00599 static ex tan_series(const ex &x,
00600                      const relational &rel,
00601                      int order,
00602                      unsigned options)
00603 {
00604     GINAC_ASSERT(is_a<symbol>(rel.lhs()));
00605     // method:
00606     // Taylor series where there is no pole falls back to tan_deriv.
00607     // On a pole simply expand sin(x)/cos(x).
00608     const ex x_pt = x.subs(rel, subs_options::no_pattern);
00609     if (!(2*x_pt/Pi).info(info_flags::odd))
00610         throw do_taylor();  // caught by function::series()
00611     // if we got here we have to care for a simple pole
00612     return (sin(x)/cos(x)).series(rel, order, options);
00613 }
00614 
00615 static ex tan_conjugate(const ex & x)
00616 {
00617     // conjugate(tan(x))==tan(conjugate(x))
00618     return tan(x.conjugate());
00619 }
00620 
00621 REGISTER_FUNCTION(tan, eval_func(tan_eval).
00622                        evalf_func(tan_evalf).
00623                        derivative_func(tan_deriv).
00624                        series_func(tan_series).
00625                        real_part_func(tan_real_part).
00626                        imag_part_func(tan_imag_part).
00627                        conjugate_func(tan_conjugate).
00628                        latex_name("\\tan"));
00629 
00631 // inverse sine (arc sine)
00633 
00634 static ex asin_evalf(const ex & x)
00635 {
00636     if (is_exactly_a<numeric>(x))
00637         return asin(ex_to<numeric>(x));
00638     
00639     return asin(x).hold();
00640 }
00641 
00642 static ex asin_eval(const ex & x)
00643 {
00644     if (x.info(info_flags::numeric)) {
00645 
00646         // asin(0) -> 0
00647         if (x.is_zero())
00648             return x;
00649 
00650         // asin(1/2) -> Pi/6
00651         if (x.is_equal(_ex1_2))
00652             return numeric(1,6)*Pi;
00653 
00654         // asin(1) -> Pi/2
00655         if (x.is_equal(_ex1))
00656             return _ex1_2*Pi;
00657 
00658         // asin(-1/2) -> -Pi/6
00659         if (x.is_equal(_ex_1_2))
00660             return numeric(-1,6)*Pi;
00661 
00662         // asin(-1) -> -Pi/2
00663         if (x.is_equal(_ex_1))
00664             return _ex_1_2*Pi;
00665 
00666         // asin(float) -> float
00667         if (!x.info(info_flags::crational))
00668             return asin(ex_to<numeric>(x));
00669 
00670         // asin() is odd
00671         if (x.info(info_flags::negative))
00672             return -asin(-x);
00673     }
00674     
00675     return asin(x).hold();
00676 }
00677 
00678 static ex asin_deriv(const ex & x, unsigned deriv_param)
00679 {
00680     GINAC_ASSERT(deriv_param==0);
00681     
00682     // d/dx asin(x) -> 1/sqrt(1-x^2)
00683     return power(1-power(x,_ex2),_ex_1_2);
00684 }
00685 
00686 static ex asin_conjugate(const ex & x)
00687 {
00688     // conjugate(asin(x))==asin(conjugate(x)) unless on the branch cuts which
00689     // run along the real axis outside the interval [-1, +1].
00690     if (is_exactly_a<numeric>(x) &&
00691         (!x.imag_part().is_zero() || (x > *_num_1_p && x < *_num1_p))) {
00692         return asin(x.conjugate());
00693     }
00694     return conjugate_function(asin(x)).hold();
00695 }
00696 
00697 REGISTER_FUNCTION(asin, eval_func(asin_eval).
00698                         evalf_func(asin_evalf).
00699                         derivative_func(asin_deriv).
00700                         conjugate_func(asin_conjugate).
00701                         latex_name("\\arcsin"));
00702 
00704 // inverse cosine (arc cosine)
00706 
00707 static ex acos_evalf(const ex & x)
00708 {
00709     if (is_exactly_a<numeric>(x))
00710         return acos(ex_to<numeric>(x));
00711     
00712     return acos(x).hold();
00713 }
00714 
00715 static ex acos_eval(const ex & x)
00716 {
00717     if (x.info(info_flags::numeric)) {
00718 
00719         // acos(1) -> 0
00720         if (x.is_equal(_ex1))
00721             return _ex0;
00722 
00723         // acos(1/2) -> Pi/3
00724         if (x.is_equal(_ex1_2))
00725             return _ex1_3*Pi;
00726 
00727         // acos(0) -> Pi/2
00728         if (x.is_zero())
00729             return _ex1_2*Pi;
00730 
00731         // acos(-1/2) -> 2/3*Pi
00732         if (x.is_equal(_ex_1_2))
00733             return numeric(2,3)*Pi;
00734 
00735         // acos(-1) -> Pi
00736         if (x.is_equal(_ex_1))
00737             return Pi;
00738 
00739         // acos(float) -> float
00740         if (!x.info(info_flags::crational))
00741             return acos(ex_to<numeric>(x));
00742 
00743         // acos(-x) -> Pi-acos(x)
00744         if (x.info(info_flags::negative))
00745             return Pi-acos(-x);
00746     }
00747     
00748     return acos(x).hold();
00749 }
00750 
00751 static ex acos_deriv(const ex & x, unsigned deriv_param)
00752 {
00753     GINAC_ASSERT(deriv_param==0);
00754     
00755     // d/dx acos(x) -> -1/sqrt(1-x^2)
00756     return -power(1-power(x,_ex2),_ex_1_2);
00757 }
00758 
00759 static ex acos_conjugate(const ex & x)
00760 {
00761     // conjugate(acos(x))==acos(conjugate(x)) unless on the branch cuts which
00762     // run along the real axis outside the interval [-1, +1].
00763     if (is_exactly_a<numeric>(x) &&
00764         (!x.imag_part().is_zero() || (x > *_num_1_p && x < *_num1_p))) {
00765         return acos(x.conjugate());
00766     }
00767     return conjugate_function(acos(x)).hold();
00768 }
00769 
00770 REGISTER_FUNCTION(acos, eval_func(acos_eval).
00771                         evalf_func(acos_evalf).
00772                         derivative_func(acos_deriv).
00773                         conjugate_func(acos_conjugate).
00774                         latex_name("\\arccos"));
00775 
00777 // inverse tangent (arc tangent)
00779 
00780 static ex atan_evalf(const ex & x)
00781 {
00782     if (is_exactly_a<numeric>(x))
00783         return atan(ex_to<numeric>(x));
00784     
00785     return atan(x).hold();
00786 }
00787 
00788 static ex atan_eval(const ex & x)
00789 {
00790     if (x.info(info_flags::numeric)) {
00791 
00792         // atan(0) -> 0
00793         if (x.is_zero())
00794             return _ex0;
00795 
00796         // atan(1) -> Pi/4
00797         if (x.is_equal(_ex1))
00798             return _ex1_4*Pi;
00799 
00800         // atan(-1) -> -Pi/4
00801         if (x.is_equal(_ex_1))
00802             return _ex_1_4*Pi;
00803 
00804         if (x.is_equal(I) || x.is_equal(-I))
00805             throw (pole_error("atan_eval(): logarithmic pole",0));
00806 
00807         // atan(float) -> float
00808         if (!x.info(info_flags::crational))
00809             return atan(ex_to<numeric>(x));
00810 
00811         // atan() is odd
00812         if (x.info(info_flags::negative))
00813             return -atan(-x);
00814     }
00815     
00816     return atan(x).hold();
00817 }
00818 
00819 static ex atan_deriv(const ex & x, unsigned deriv_param)
00820 {
00821     GINAC_ASSERT(deriv_param==0);
00822 
00823     // d/dx atan(x) -> 1/(1+x^2)
00824     return power(_ex1+power(x,_ex2), _ex_1);
00825 }
00826 
00827 static ex atan_series(const ex &arg,
00828                       const relational &rel,
00829                       int order,
00830                       unsigned options)
00831 {
00832     GINAC_ASSERT(is_a<symbol>(rel.lhs()));
00833     // method:
00834     // Taylor series where there is no pole or cut falls back to atan_deriv.
00835     // There are two branch cuts, one runnig from I up the imaginary axis and
00836     // one running from -I down the imaginary axis.  The points I and -I are
00837     // poles.
00838     // On the branch cuts and the poles series expand
00839     //     (log(1+I*x)-log(1-I*x))/(2*I)
00840     // instead.
00841     const ex arg_pt = arg.subs(rel, subs_options::no_pattern);
00842     if (!(I*arg_pt).info(info_flags::real))
00843         throw do_taylor();     // Re(x) != 0
00844     if ((I*arg_pt).info(info_flags::real) && abs(I*arg_pt)<_ex1)
00845         throw do_taylor();     // Re(x) == 0, but abs(x)<1
00846     // care for the poles, using the defining formula for atan()...
00847     if (arg_pt.is_equal(I) || arg_pt.is_equal(-I))
00848         return ((log(1+I*arg)-log(1-I*arg))/(2*I)).series(rel, order, options);
00849     if (!(options & series_options::suppress_branchcut)) {
00850         // method:
00851         // This is the branch cut: assemble the primitive series manually and
00852         // then add the corresponding complex step function.
00853         const symbol &s = ex_to<symbol>(rel.lhs());
00854         const ex &point = rel.rhs();
00855         const symbol foo;
00856         const ex replarg = series(atan(arg), s==foo, order).subs(foo==point, subs_options::no_pattern);
00857         ex Order0correction = replarg.op(0)+csgn(arg)*Pi*_ex_1_2;
00858         if ((I*arg_pt)<_ex0)
00859             Order0correction += log((I*arg_pt+_ex_1)/(I*arg_pt+_ex1))*I*_ex_1_2;
00860         else
00861             Order0correction += log((I*arg_pt+_ex1)/(I*arg_pt+_ex_1))*I*_ex1_2;
00862         epvector seq;
00863         seq.push_back(expair(Order0correction, _ex0));
00864         seq.push_back(expair(Order(_ex1), order));
00865         return series(replarg - pseries(rel, seq), rel, order);
00866     }
00867     throw do_taylor();
00868 }
00869 
00870 static ex atan_conjugate(const ex & x)
00871 {
00872     // conjugate(atan(x))==atan(conjugate(x)) unless on the branch cuts which
00873     // run along the imaginary axis outside the interval [-I, +I].
00874     if (x.info(info_flags::real))
00875         return atan(x);
00876     if (is_exactly_a<numeric>(x)) {
00877         const numeric x_re = ex_to<numeric>(x.real_part());
00878         const numeric x_im = ex_to<numeric>(x.imag_part());
00879         if (!x_re.is_zero() ||
00880             (x_im > *_num_1_p && x_im < *_num1_p))
00881             return atan(x.conjugate());
00882     }
00883     return conjugate_function(atan(x)).hold();
00884 }
00885 
00886 REGISTER_FUNCTION(atan, eval_func(atan_eval).
00887                         evalf_func(atan_evalf).
00888                         derivative_func(atan_deriv).
00889                         series_func(atan_series).
00890                         conjugate_func(atan_conjugate).
00891                         latex_name("\\arctan"));
00892 
00894 // inverse tangent (atan2(y,x))
00896 
00897 static ex atan2_evalf(const ex &y, const ex &x)
00898 {
00899     if (is_exactly_a<numeric>(y) && is_exactly_a<numeric>(x))
00900         return atan(ex_to<numeric>(y), ex_to<numeric>(x));
00901     
00902     return atan2(y, x).hold();
00903 }
00904 
00905 static ex atan2_eval(const ex & y, const ex & x)
00906 {
00907     if (y.is_zero()) {
00908 
00909         // atan2(0, 0) -> 0
00910         if (x.is_zero())
00911             return _ex0;
00912 
00913         // atan2(0, x), x real and positive -> 0
00914         if (x.info(info_flags::positive))
00915             return _ex0;
00916 
00917         // atan2(0, x), x real and negative -> Pi
00918         if (x.info(info_flags::negative))
00919             return Pi;
00920     }
00921 
00922     if (x.is_zero()) {
00923 
00924         // atan2(y, 0), y real and positive -> Pi/2
00925         if (y.info(info_flags::positive))
00926             return _ex1_2*Pi;
00927 
00928         // atan2(y, 0), y real and negative -> -Pi/2
00929         if (y.info(info_flags::negative))
00930             return _ex_1_2*Pi;
00931     }
00932 
00933     if (y.is_equal(x)) {
00934 
00935         // atan2(y, y), y real and positive -> Pi/4
00936         if (y.info(info_flags::positive))
00937             return _ex1_4*Pi;
00938 
00939         // atan2(y, y), y real and negative -> -3/4*Pi
00940         if (y.info(info_flags::negative))
00941             return numeric(-3, 4)*Pi;
00942     }
00943 
00944     if (y.is_equal(-x)) {
00945 
00946         // atan2(y, -y), y real and positive -> 3*Pi/4
00947         if (y.info(info_flags::positive))
00948             return numeric(3, 4)*Pi;
00949 
00950         // atan2(y, -y), y real and negative -> -Pi/4
00951         if (y.info(info_flags::negative))
00952             return _ex_1_4*Pi;
00953     }
00954 
00955     // atan2(float, float) -> float
00956     if (is_a<numeric>(y) && !y.info(info_flags::crational) &&
00957         is_a<numeric>(x) && !x.info(info_flags::crational))
00958         return atan(ex_to<numeric>(y), ex_to<numeric>(x));
00959 
00960     // atan2(real, real) -> atan(y/x) +/- Pi
00961     if (y.info(info_flags::real) && x.info(info_flags::real)) {
00962         if (x.info(info_flags::positive))
00963             return atan(y/x);
00964 
00965         if (x.info(info_flags::negative)) {
00966             if (y.info(info_flags::positive))
00967                 return atan(y/x)+Pi;
00968             if (y.info(info_flags::negative))
00969                 return atan(y/x)-Pi;
00970         }
00971     }
00972 
00973     return atan2(y, x).hold();
00974 }    
00975 
00976 static ex atan2_deriv(const ex & y, const ex & x, unsigned deriv_param)
00977 {
00978     GINAC_ASSERT(deriv_param<2);
00979     
00980     if (deriv_param==0) {
00981         // d/dy atan2(y,x)
00982         return x*power(power(x,_ex2)+power(y,_ex2),_ex_1);
00983     }
00984     // d/dx atan2(y,x)
00985     return -y*power(power(x,_ex2)+power(y,_ex2),_ex_1);
00986 }
00987 
00988 REGISTER_FUNCTION(atan2, eval_func(atan2_eval).
00989                          evalf_func(atan2_evalf).
00990                          derivative_func(atan2_deriv));
00991 
00993 // hyperbolic sine (trigonometric function)
00995 
00996 static ex sinh_evalf(const ex & x)
00997 {
00998     if (is_exactly_a<numeric>(x))
00999         return sinh(ex_to<numeric>(x));
01000     
01001     return sinh(x).hold();
01002 }
01003 
01004 static ex sinh_eval(const ex & x)
01005 {
01006     if (x.info(info_flags::numeric)) {
01007 
01008         // sinh(0) -> 0
01009         if (x.is_zero())
01010             return _ex0;        
01011 
01012         // sinh(float) -> float
01013         if (!x.info(info_flags::crational))
01014             return sinh(ex_to<numeric>(x));
01015 
01016         // sinh() is odd
01017         if (x.info(info_flags::negative))
01018             return -sinh(-x);
01019     }
01020     
01021     if ((x/Pi).info(info_flags::numeric) &&
01022         ex_to<numeric>(x/Pi).real().is_zero())  // sinh(I*x) -> I*sin(x)
01023         return I*sin(x/I);
01024     
01025     if (is_exactly_a<function>(x)) {
01026         const ex &t = x.op(0);
01027 
01028         // sinh(asinh(x)) -> x
01029         if (is_ex_the_function(x, asinh))
01030             return t;
01031 
01032         // sinh(acosh(x)) -> sqrt(x-1) * sqrt(x+1)
01033         if (is_ex_the_function(x, acosh))
01034             return sqrt(t-_ex1)*sqrt(t+_ex1);
01035 
01036         // sinh(atanh(x)) -> x/sqrt(1-x^2)
01037         if (is_ex_the_function(x, atanh))
01038             return t*power(_ex1-power(t,_ex2),_ex_1_2);
01039     }
01040     
01041     return sinh(x).hold();
01042 }
01043 
01044 static ex sinh_deriv(const ex & x, unsigned deriv_param)
01045 {
01046     GINAC_ASSERT(deriv_param==0);
01047     
01048     // d/dx sinh(x) -> cosh(x)
01049     return cosh(x);
01050 }
01051 
01052 static ex sinh_real_part(const ex & x)
01053 {
01054     return sinh(GiNaC::real_part(x))*cos(GiNaC::imag_part(x));
01055 }
01056 
01057 static ex sinh_imag_part(const ex & x)
01058 {
01059     return cosh(GiNaC::real_part(x))*sin(GiNaC::imag_part(x));
01060 }
01061 
01062 static ex sinh_conjugate(const ex & x)
01063 {
01064     // conjugate(sinh(x))==sinh(conjugate(x))
01065     return sinh(x.conjugate());
01066 }
01067 
01068 REGISTER_FUNCTION(sinh, eval_func(sinh_eval).
01069                         evalf_func(sinh_evalf).
01070                         derivative_func(sinh_deriv).
01071                         real_part_func(sinh_real_part).
01072                         imag_part_func(sinh_imag_part).
01073                         conjugate_func(sinh_conjugate).
01074                         latex_name("\\sinh"));
01075 
01077 // hyperbolic cosine (trigonometric function)
01079 
01080 static ex cosh_evalf(const ex & x)
01081 {
01082     if (is_exactly_a<numeric>(x))
01083         return cosh(ex_to<numeric>(x));
01084     
01085     return cosh(x).hold();
01086 }
01087 
01088 static ex cosh_eval(const ex & x)
01089 {
01090     if (x.info(info_flags::numeric)) {
01091 
01092         // cosh(0) -> 1
01093         if (x.is_zero())
01094             return _ex1;
01095 
01096         // cosh(float) -> float
01097         if (!x.info(info_flags::crational))
01098             return cosh(ex_to<numeric>(x));
01099 
01100         // cosh() is even
01101         if (x.info(info_flags::negative))
01102             return cosh(-x);
01103     }
01104     
01105     if ((x/Pi).info(info_flags::numeric) &&
01106         ex_to<numeric>(x/Pi).real().is_zero())  // cosh(I*x) -> cos(x)
01107         return cos(x/I);
01108     
01109     if (is_exactly_a<function>(x)) {
01110         const ex &t = x.op(0);
01111 
01112         // cosh(acosh(x)) -> x
01113         if (is_ex_the_function(x, acosh))
01114             return t;
01115 
01116         // cosh(asinh(x)) -> sqrt(1+x^2)
01117         if (is_ex_the_function(x, asinh))
01118             return sqrt(_ex1+power(t,_ex2));
01119 
01120         // cosh(atanh(x)) -> 1/sqrt(1-x^2)
01121         if (is_ex_the_function(x, atanh))
01122             return power(_ex1-power(t,_ex2),_ex_1_2);
01123     }
01124     
01125     return cosh(x).hold();
01126 }
01127 
01128 static ex cosh_deriv(const ex & x, unsigned deriv_param)
01129 {
01130     GINAC_ASSERT(deriv_param==0);
01131     
01132     // d/dx cosh(x) -> sinh(x)
01133     return sinh(x);
01134 }
01135 
01136 static ex cosh_real_part(const ex & x)
01137 {
01138     return cosh(GiNaC::real_part(x))*cos(GiNaC::imag_part(x));
01139 }
01140 
01141 static ex cosh_imag_part(const ex & x)
01142 {
01143     return sinh(GiNaC::real_part(x))*sin(GiNaC::imag_part(x));
01144 }
01145 
01146 static ex cosh_conjugate(const ex & x)
01147 {
01148     // conjugate(cosh(x))==cosh(conjugate(x))
01149     return cosh(x.conjugate());
01150 }
01151 
01152 REGISTER_FUNCTION(cosh, eval_func(cosh_eval).
01153                         evalf_func(cosh_evalf).
01154                         derivative_func(cosh_deriv).
01155                         real_part_func(cosh_real_part).
01156                         imag_part_func(cosh_imag_part).
01157                         conjugate_func(cosh_conjugate).
01158                         latex_name("\\cosh"));
01159 
01161 // hyperbolic tangent (trigonometric function)
01163 
01164 static ex tanh_evalf(const ex & x)
01165 {
01166     if (is_exactly_a<numeric>(x))
01167         return tanh(ex_to<numeric>(x));
01168     
01169     return tanh(x).hold();
01170 }
01171 
01172 static ex tanh_eval(const ex & x)
01173 {
01174     if (x.info(info_flags::numeric)) {
01175 
01176         // tanh(0) -> 0
01177         if (x.is_zero())
01178             return _ex0;
01179 
01180         // tanh(float) -> float
01181         if (!x.info(info_flags::crational))
01182             return tanh(ex_to<numeric>(x));
01183 
01184         // tanh() is odd
01185         if (x.info(info_flags::negative))
01186             return -tanh(-x);
01187     }
01188     
01189     if ((x/Pi).info(info_flags::numeric) &&
01190         ex_to<numeric>(x/Pi).real().is_zero())  // tanh(I*x) -> I*tan(x);
01191         return I*tan(x/I);
01192     
01193     if (is_exactly_a<function>(x)) {
01194         const ex &t = x.op(0);
01195 
01196         // tanh(atanh(x)) -> x
01197         if (is_ex_the_function(x, atanh))
01198             return t;
01199 
01200         // tanh(asinh(x)) -> x/sqrt(1+x^2)
01201         if (is_ex_the_function(x, asinh))
01202             return t*power(_ex1+power(t,_ex2),_ex_1_2);
01203 
01204         // tanh(acosh(x)) -> sqrt(x-1)*sqrt(x+1)/x
01205         if (is_ex_the_function(x, acosh))
01206             return sqrt(t-_ex1)*sqrt(t+_ex1)*power(t,_ex_1);
01207     }
01208     
01209     return tanh(x).hold();
01210 }
01211 
01212 static ex tanh_deriv(const ex & x, unsigned deriv_param)
01213 {
01214     GINAC_ASSERT(deriv_param==0);
01215     
01216     // d/dx tanh(x) -> 1-tanh(x)^2
01217     return _ex1-power(tanh(x),_ex2);
01218 }
01219 
01220 static ex tanh_series(const ex &x,
01221                       const relational &rel,
01222                       int order,
01223                       unsigned options)
01224 {
01225     GINAC_ASSERT(is_a<symbol>(rel.lhs()));
01226     // method:
01227     // Taylor series where there is no pole falls back to tanh_deriv.
01228     // On a pole simply expand sinh(x)/cosh(x).
01229     const ex x_pt = x.subs(rel, subs_options::no_pattern);
01230     if (!(2*I*x_pt/Pi).info(info_flags::odd))
01231         throw do_taylor();  // caught by function::series()
01232     // if we got here we have to care for a simple pole
01233     return (sinh(x)/cosh(x)).series(rel, order, options);
01234 }
01235 
01236 static ex tanh_real_part(const ex & x)
01237 {
01238     ex a = GiNaC::real_part(x);
01239     ex b = GiNaC::imag_part(x);
01240     return tanh(a)/(1+power(tanh(a),2)*power(tan(b),2));
01241 }
01242 
01243 static ex tanh_imag_part(const ex & x)
01244 {
01245     ex a = GiNaC::real_part(x);
01246     ex b = GiNaC::imag_part(x);
01247     return tan(b)/(1+power(tanh(a),2)*power(tan(b),2));
01248 }
01249 
01250 static ex tanh_conjugate(const ex & x)
01251 {
01252     // conjugate(tanh(x))==tanh(conjugate(x))
01253     return tanh(x.conjugate());
01254 }
01255 
01256 REGISTER_FUNCTION(tanh, eval_func(tanh_eval).
01257                         evalf_func(tanh_evalf).
01258                         derivative_func(tanh_deriv).
01259                         series_func(tanh_series).
01260                         real_part_func(tanh_real_part).
01261                         imag_part_func(tanh_imag_part).
01262                         conjugate_func(tanh_conjugate).
01263                         latex_name("\\tanh"));
01264 
01266 // inverse hyperbolic sine (trigonometric function)
01268 
01269 static ex asinh_evalf(const ex & x)
01270 {
01271     if (is_exactly_a<numeric>(x))
01272         return asinh(ex_to<numeric>(x));
01273     
01274     return asinh(x).hold();
01275 }
01276 
01277 static ex asinh_eval(const ex & x)
01278 {
01279     if (x.info(info_flags::numeric)) {
01280 
01281         // asinh(0) -> 0
01282         if (x.is_zero())
01283             return _ex0;
01284 
01285         // asinh(float) -> float
01286         if (!x.info(info_flags::crational))
01287             return asinh(ex_to<numeric>(x));
01288 
01289         // asinh() is odd
01290         if (x.info(info_flags::negative))
01291             return -asinh(-x);
01292     }
01293     
01294     return asinh(x).hold();
01295 }
01296 
01297 static ex asinh_deriv(const ex & x, unsigned deriv_param)
01298 {
01299     GINAC_ASSERT(deriv_param==0);
01300     
01301     // d/dx asinh(x) -> 1/sqrt(1+x^2)
01302     return power(_ex1+power(x,_ex2),_ex_1_2);
01303 }
01304 
01305 static ex asinh_conjugate(const ex & x)
01306 {
01307     // conjugate(asinh(x))==asinh(conjugate(x)) unless on the branch cuts which
01308     // run along the imaginary axis outside the interval [-I, +I].
01309     if (x.info(info_flags::real))
01310         return asinh(x);
01311     if (is_exactly_a<numeric>(x)) {
01312         const numeric x_re = ex_to<numeric>(x.real_part());
01313         const numeric x_im = ex_to<numeric>(x.imag_part());
01314         if (!x_re.is_zero() ||
01315             (x_im > *_num_1_p && x_im < *_num1_p))
01316             return asinh(x.conjugate());
01317     }
01318     return conjugate_function(asinh(x)).hold();
01319 }
01320 
01321 REGISTER_FUNCTION(asinh, eval_func(asinh_eval).
01322                          evalf_func(asinh_evalf).
01323                          derivative_func(asinh_deriv).
01324                          conjugate_func(asinh_conjugate));
01325 
01327 // inverse hyperbolic cosine (trigonometric function)
01329 
01330 static ex acosh_evalf(const ex & x)
01331 {
01332     if (is_exactly_a<numeric>(x))
01333         return acosh(ex_to<numeric>(x));
01334     
01335     return acosh(x).hold();
01336 }
01337 
01338 static ex acosh_eval(const ex & x)
01339 {
01340     if (x.info(info_flags::numeric)) {
01341 
01342         // acosh(0) -> Pi*I/2
01343         if (x.is_zero())
01344             return Pi*I*numeric(1,2);
01345 
01346         // acosh(1) -> 0
01347         if (x.is_equal(_ex1))
01348             return _ex0;
01349 
01350         // acosh(-1) -> Pi*I
01351         if (x.is_equal(_ex_1))
01352             return Pi*I;
01353 
01354         // acosh(float) -> float
01355         if (!x.info(info_flags::crational))
01356             return acosh(ex_to<numeric>(x));
01357 
01358         // acosh(-x) -> Pi*I-acosh(x)
01359         if (x.info(info_flags::negative))
01360             return Pi*I-acosh(-x);
01361     }
01362     
01363     return acosh(x).hold();
01364 }
01365 
01366 static ex acosh_deriv(const ex & x, unsigned deriv_param)
01367 {
01368     GINAC_ASSERT(deriv_param==0);
01369     
01370     // d/dx acosh(x) -> 1/(sqrt(x-1)*sqrt(x+1))
01371     return power(x+_ex_1,_ex_1_2)*power(x+_ex1,_ex_1_2);
01372 }
01373 
01374 static ex acosh_conjugate(const ex & x)
01375 {
01376     // conjugate(acosh(x))==acosh(conjugate(x)) unless on the branch cut
01377     // which runs along the real axis from +1 to -inf.
01378     if (is_exactly_a<numeric>(x) &&
01379         (!x.imag_part().is_zero() || x > *_num1_p)) {
01380         return acosh(x.conjugate());
01381     }
01382     return conjugate_function(acosh(x)).hold();
01383 }
01384 
01385 REGISTER_FUNCTION(acosh, eval_func(acosh_eval).
01386                          evalf_func(acosh_evalf).
01387                          derivative_func(acosh_deriv).
01388                          conjugate_func(acosh_conjugate));
01389 
01391 // inverse hyperbolic tangent (trigonometric function)
01393 
01394 static ex atanh_evalf(const ex & x)
01395 {
01396     if (is_exactly_a<numeric>(x))
01397         return atanh(ex_to<numeric>(x));
01398     
01399     return atanh(x).hold();
01400 }
01401 
01402 static ex atanh_eval(const ex & x)
01403 {
01404     if (x.info(info_flags::numeric)) {
01405 
01406         // atanh(0) -> 0
01407         if (x.is_zero())
01408             return _ex0;
01409 
01410         // atanh({+|-}1) -> throw
01411         if (x.is_equal(_ex1) || x.is_equal(_ex_1))
01412             throw (pole_error("atanh_eval(): logarithmic pole",0));
01413 
01414         // atanh(float) -> float
01415         if (!x.info(info_flags::crational))
01416             return atanh(ex_to<numeric>(x));
01417 
01418         // atanh() is odd
01419         if (x.info(info_flags::negative))
01420             return -atanh(-x);
01421     }
01422     
01423     return atanh(x).hold();
01424 }
01425 
01426 static ex atanh_deriv(const ex & x, unsigned deriv_param)
01427 {
01428     GINAC_ASSERT(deriv_param==0);
01429     
01430     // d/dx atanh(x) -> 1/(1-x^2)
01431     return power(_ex1-power(x,_ex2),_ex_1);
01432 }
01433 
01434 static ex atanh_series(const ex &arg,
01435                        const relational &rel,
01436                        int order,
01437                        unsigned options)
01438 {
01439     GINAC_ASSERT(is_a<symbol>(rel.lhs()));
01440     // method:
01441     // Taylor series where there is no pole or cut falls back to atanh_deriv.
01442     // There are two branch cuts, one runnig from 1 up the real axis and one
01443     // one running from -1 down the real axis.  The points 1 and -1 are poles
01444     // On the branch cuts and the poles series expand
01445     //     (log(1+x)-log(1-x))/2
01446     // instead.
01447     const ex arg_pt = arg.subs(rel, subs_options::no_pattern);
01448     if (!(arg_pt).info(info_flags::real))
01449         throw do_taylor();     // Im(x) != 0
01450     if ((arg_pt).info(info_flags::real) && abs(arg_pt)<_ex1)
01451         throw do_taylor();     // Im(x) == 0, but abs(x)<1
01452     // care for the poles, using the defining formula for atanh()...
01453     if (arg_pt.is_equal(_ex1) || arg_pt.is_equal(_ex_1))
01454         return ((log(_ex1+arg)-log(_ex1-arg))*_ex1_2).series(rel, order, options);
01455     // ...and the branch cuts (the discontinuity at the cut being just I*Pi)
01456     if (!(options & series_options::suppress_branchcut)) {
01457         // method:
01458         // This is the branch cut: assemble the primitive series manually and
01459         // then add the corresponding complex step function.
01460         const symbol &s = ex_to<symbol>(rel.lhs());
01461         const ex &point = rel.rhs();
01462         const symbol foo;
01463         const ex replarg = series(atanh(arg), s==foo, order).subs(foo==point, subs_options::no_pattern);
01464         ex Order0correction = replarg.op(0)+csgn(I*arg)*Pi*I*_ex1_2;
01465         if (arg_pt<_ex0)
01466             Order0correction += log((arg_pt+_ex_1)/(arg_pt+_ex1))*_ex1_2;
01467         else
01468             Order0correction += log((arg_pt+_ex1)/(arg_pt+_ex_1))*_ex_1_2;
01469         epvector seq;
01470         seq.push_back(expair(Order0correction, _ex0));
01471         seq.push_back(expair(Order(_ex1), order));
01472         return series(replarg - pseries(rel, seq), rel, order);
01473     }
01474     throw do_taylor();
01475 }
01476 
01477 static ex atanh_conjugate(const ex & x)
01478 {
01479     // conjugate(atanh(x))==atanh(conjugate(x)) unless on the branch cuts which
01480     // run along the real axis outside the interval [-1, +1].
01481     if (is_exactly_a<numeric>(x) &&
01482         (!x.imag_part().is_zero() || (x > *_num_1_p && x < *_num1_p))) {
01483         return atanh(x.conjugate());
01484     }
01485     return conjugate_function(atanh(x)).hold();
01486 }
01487 
01488 REGISTER_FUNCTION(atanh, eval_func(atanh_eval).
01489                          evalf_func(atanh_evalf).
01490                          derivative_func(atanh_deriv).
01491                          series_func(atanh_series).
01492                          conjugate_func(atanh_conjugate));
01493 
01494 
01495 } // namespace GiNaC

This page is part of the GiNaC developer's reference. It was generated automatically by doxygen. For an introduction, see the tutorial.