|
GiNaC
1.6.2
|
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