1 // -*- mode:C++ ; compile-command: "g++ -I.. -g -c intg.cc -fno-strict-aliasing -DGIAC_GENERIC_CONSTANTS -DHAVE_CONFIG_H -DIN_GIAC " -*- 2 #include "giacPCH.h" 3 // #define LOGINT 4 5 /* 6 * Copyright (C) 2000,2014 B. Parisse, Institut Fourier, 38402 St Martin d'Heres 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 3 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program. If not, see <http://www.gnu.org/licenses/>. 20 */ 21 using namespace std; 22 #include <stdexcept> 23 #include "vector.h" 24 #include <cmath> 25 #include <cstdlib> 26 #include <limits> 27 #include "sym2poly.h" 28 #include "usual.h" 29 #include "intg.h" 30 #include "subst.h" 31 #include "derive.h" 32 #include "lin.h" 33 #include "vecteur.h" 34 #include "gausspol.h" 35 #include "plot.h" 36 #include "prog.h" 37 #include "modpoly.h" 38 #include "series.h" 39 #include "tex.h" 40 #include "ifactor.h" 41 #include "risch.h" 42 #include "solve.h" 43 #include "intgab.h" 44 #include "moyal.h" 45 #include "maple.h" 46 #include "rpn.h" 47 #include "modpoly.h" 48 #include "giacintl.h" 49 #ifdef HAVE_CONFIG_H 50 #include "config.h" 51 #endif 52 #ifdef HAVE_LIBGSL 53 #include <gsl/gsl_math.h> 54 #include <gsl/gsl_sf_gamma.h> 55 #include <gsl/gsl_sf_psi.h> 56 #include <gsl/gsl_sf_zeta.h> 57 #include <gsl/gsl_odeiv.h> 58 #include <gsl/gsl_errno.h> 59 #endif 60 61 #ifndef NO_NAMESPACE_GIAC 62 namespace giac { 63 #endif // ndef NO_NAMESPACE_GIAC 64 65 // Left redimension p to degree n, i.e. size n+1 lrdm(modpoly & p,int n)66 void lrdm(modpoly & p,int n){ 67 int s=int(p.size()); 68 if (n+1>s) 69 p=mergevecteur(vecteur(n+1-s),p); 70 } 71 72 struct pf1 { 73 vecteur num; 74 vecteur den; 75 vecteur fact; 76 int mult; // den=cste*fact^mult pf1giac::pf177 pf1():num(0),den(makevecteur(1)),fact(makevecteur(1)),mult(1) {} pf1giac::pf178 pf1(const pf1 & a) : num(a.num), den(a.den), fact(a.fact),mult(a.mult) {} pf1giac::pf179 pf1(const vecteur &n, const vecteur & d, const vecteur & f,int m) : num(n), den(d), fact(f), mult(m) {}; pf1giac::pf180 pf1(const polynome & n,const polynome & d,const polynome & f,int m): num(polynome2poly1(n,1)),den(polynome2poly1(d,1)),fact(polynome2poly1(f,1)),mult(m) {} 81 }; 82 complex_subst(const gen & e,const vecteur & substin,const vecteur & substout,GIAC_CONTEXT)83 gen complex_subst(const gen & e,const vecteur & substin,const vecteur & substout,GIAC_CONTEXT){ 84 bool save_complex_mode=complex_mode(contextptr); 85 complex_mode(true,contextptr); 86 bool save_eval_abs=eval_abs(contextptr); 87 eval_abs(false,contextptr); 88 gen res=simplifier(eval(subst(e,substin,substout,false,contextptr),1,contextptr),contextptr); 89 // eval is used since after subst * are not flattened 90 complex_mode(save_complex_mode,contextptr); 91 eval_abs(save_eval_abs,contextptr); 92 return res; 93 } 94 complex_subst(const gen & e,const gen & x,const gen & newx,GIAC_CONTEXT)95 gen complex_subst(const gen & e,const gen & x,const gen & newx,GIAC_CONTEXT){ 96 bool save_complex_mode=complex_mode(contextptr); 97 complex_mode(true,contextptr); 98 gen res=subst(e,x,newx,false,contextptr); 99 // avoid rewrite of fractional powers 100 vecteur v=lop(newx,at_pow); 101 int i=0; 102 for (;i<v.size();++i){ 103 gen tmp=v[i]; 104 if (tmp.is_symb_of_sommet(at_pow)){ 105 tmp=tmp._SYMBptr->feuille; 106 if (tmp.type==_VECT && tmp._VECTptr->size()==2){ 107 tmp=tmp._VECTptr->back(); 108 if (tmp.type==_FRAC && tmp._FRACptr->den.type==_INT_ ){ 109 tmp=tmp._FRACptr->den; 110 if (tmp.val % 2==1) 111 break; 112 } 113 } 114 } 115 } 116 if (i==v.size()) 117 res=eval(res,1,contextptr); 118 complex_mode(save_complex_mode,contextptr); 119 return res; 120 } 121 has_nop_var(const vecteur & v)122 static bool has_nop_var(const vecteur & v){ 123 const_iterateur it=v.begin(),itend=v.end(); 124 for (;it!=itend;++it){ 125 if (contains(*it,at_nop)) 126 return true; 127 } 128 return false; 129 } 130 nop_inv(const gen & e,GIAC_CONTEXT)131 static gen nop_inv(const gen & e,GIAC_CONTEXT){ 132 return symbolic(at_nop,gen(symbolic(at_inv,e))); 133 } nop_pow(const gen & e,GIAC_CONTEXT)134 static gen nop_pow(const gen & e,GIAC_CONTEXT){ 135 if ( (e.type!=_VECT) || (e._VECTptr->size()!=2)) 136 return symbolic(at_pow,e); 137 if ( (e._VECTptr->back().type!=_INT_) || (e._VECTptr->back().val>=0) || ( (e._VECTptr->front().type==_SYMB) && (e._VECTptr->front()._SYMBptr->sommet==at_exp) ) ) 138 return symbolic(at_pow,change_subtype(e,_SEQ__VECT)); 139 return nop_inv(symbolic(at_pow,gen(makevecteur(e._VECTptr->front(),-e._VECTptr->back()),_SEQ__VECT)),contextptr); 140 } 141 sin_over_cos(const gen & e,GIAC_CONTEXT)142 static gen sin_over_cos(const gen & e,GIAC_CONTEXT){ 143 return rdiv(symb_sin(e),symb_cos(e),contextptr); 144 } 145 const gen_op_context invpowtan2_tab[]={nop_inv,nop_pow,sin_over_cos,0}; 146 // remove nop if nop() does not contain x remove_nop(const gen & g,const gen & x,GIAC_CONTEXT)147 gen remove_nop(const gen & g,const gen & x,GIAC_CONTEXT){ 148 if (g.type==_VECT){ 149 vecteur res(*g._VECTptr); 150 iterateur it=res.begin(),itend=res.end(); 151 for (;it!=itend;++it){ 152 *it=remove_nop(*it,x,contextptr); 153 } 154 return gen(res,g.subtype); 155 } 156 if (g.type!=_SYMB) 157 return g; 158 if (g._SYMBptr->sommet!=at_nop) 159 return symbolic(g._SYMBptr->sommet,remove_nop(g._SYMBptr->feuille,x,contextptr)); 160 if (is_zero(derive(g._SYMBptr->feuille,x,contextptr))) 161 return g._SYMBptr->feuille; 162 else 163 return g; 164 } lvarxwithinv(const gen & e,const gen & x,GIAC_CONTEXT)165 vecteur lvarxwithinv(const gen &e,const gen & x,GIAC_CONTEXT){ 166 gen ee=subst(e,invpowtan_tab,invpowtan2_tab,false,contextptr); 167 ee=remove_nop(ee,x,contextptr); 168 vecteur v(lvarx(ee,x)); 169 return v; // to remove nop do a return *(eval(v)._VECTptr); 170 } 171 is_constant_wrt(const gen & e,const gen & x,GIAC_CONTEXT)172 bool is_constant_wrt(const gen & e,const gen & x,GIAC_CONTEXT){ 173 if (e.type==_VECT){ 174 const_iterateur it=e._VECTptr->begin(),itend=e._VECTptr->end(); 175 for (;it!=itend;++it){ 176 if (!is_constant_wrt(*it,x,contextptr)) 177 return false; 178 } 179 return true; 180 } 181 if (e==x) 182 return false; 183 if (e.type!=_SYMB) 184 return true; 185 return is_exactly_zero(derive(e,x,contextptr)); 186 } 187 188 // return true if e=a*x+b is_linear_wrt(const gen & e,const gen & x,gen & a,gen & b,GIAC_CONTEXT)189 bool is_linear_wrt(const gen & e,const gen &x,gen & a,gen & b,GIAC_CONTEXT){ 190 a=derive(e,x,contextptr); 191 if (is_undef(a) || !is_constant_wrt(a,x,contextptr)) 192 return false; 193 if (x*a==e) 194 b=0; 195 else 196 b=ratnormal(e-a*x,contextptr); 197 return lvarx(b,x).empty(); 198 } 199 200 // return true if e=a*x+b is_quadratic_wrt(const gen & e,const gen & x,gen & a,gen & b,gen & c,GIAC_CONTEXT)201 bool is_quadratic_wrt(const gen & e,const gen &x,gen & a,gen & b,gen & c,GIAC_CONTEXT){ 202 gen tmp=derive(e,x,contextptr); 203 if (is_undef(tmp) || !is_linear_wrt(tmp,x,a,b,contextptr)) 204 return false; 205 a=ratnormal(rdiv(a,plus_two,contextptr),contextptr); 206 c=ratnormal(e-a*x*x-b*x,contextptr); 207 return true; 208 } 209 decompose_plus(const vecteur & arg,const gen & x,vecteur & non_constant,gen & plus_constant,GIAC_CONTEXT)210 void decompose_plus(const vecteur & arg,const gen & x,vecteur & non_constant,gen & plus_constant,GIAC_CONTEXT){ 211 non_constant.clear(); 212 plus_constant=zero; 213 const_iterateur it=arg.begin(),itend=arg.end(); 214 for (;it!=itend;++it){ 215 if (is_constant_wrt(*it,x,contextptr)) 216 plus_constant=plus_constant+(*it); 217 else 218 non_constant.push_back(*it); 219 } 220 // if (contains(plus_constant,x)) plus_constant=ratnormal(plus_constant,contextptr); 221 } 222 decompose_prod(const vecteur & arg,const gen & x,vecteur & non_constant,gen & prod_constant,bool signcst,GIAC_CONTEXT)223 void decompose_prod(const vecteur & arg,const gen & x,vecteur & non_constant,gen & prod_constant,bool signcst,GIAC_CONTEXT){ 224 non_constant.clear(); 225 prod_constant=plus_one; 226 const_iterateur it=arg.begin(),itend=arg.end(); 227 for (;it!=itend;++it){ 228 gen tst=*it; 229 if (!signcst && it->is_symb_of_sommet(at_sign)) 230 tst=it->_SYMBptr->feuille; 231 if (is_constant_wrt(tst,x,contextptr)) 232 prod_constant=prod_constant*(*it); 233 else 234 non_constant.push_back(*it); 235 } 236 // if (contains(prod_constant,x)) prod_constant=ratnormal(prod_constant,contextptr); 237 } 238 extract_cst(gen & u,const gen & x,GIAC_CONTEXT)239 gen extract_cst(gen & u,const gen & x,GIAC_CONTEXT){ 240 if (!u.is_symb_of_sommet(at_prod) || u._SYMBptr->feuille.type!=_VECT) 241 return 1; 242 vecteur non_constant; gen prod_constant=1; 243 decompose_prod(*u._SYMBptr->feuille._VECTptr,x,non_constant,prod_constant,false,contextptr); 244 if (non_constant.size()==0) 245 u=1; 246 if (non_constant.size()==1) 247 u=non_constant.front(); 248 if (non_constant.size()>1) 249 u=symbolic(at_prod,gen(non_constant,_SEQ__VECT)); 250 return prod_constant; 251 } 252 253 // applies linearity of f. + & neg are distributed as well as * with respect 254 // to terms that are constant w.r.t. x 255 // e is assumed to be a scalar linear_apply(const gen & e,const gen & x,gen & remains,GIAC_CONTEXT,gen (* f)(const gen &,const gen &,gen &,const context *))256 gen linear_apply(const gen & e,const gen & x,gen & remains, GIAC_CONTEXT, gen (* f)(const gen &,const gen &,gen &,const context *)){ 257 if (is_constant_wrt(e,x,contextptr) || (e==x) ) 258 return f(e,x,remains,contextptr); 259 // e must be of type _SYMB 260 if (e.type==_VECT){ 261 vecteur v(*e._VECTptr); 262 vecteur r(v.size()); 263 for (unsigned i=0;i<v.size();++i){ 264 v[i]=linear_apply(v[i],x,r[i],contextptr,f); 265 } 266 remains=r; 267 return gen(v,e.subtype); 268 } 269 if (e.type!=_SYMB) return gensizeerr(gettext("in linear_apply")); 270 unary_function_ptr u(e._SYMBptr->sommet); 271 gen arg(e._SYMBptr->feuille); 272 gen res; 273 if (u==at_neg){ 274 res=-linear_apply(arg,x,remains,contextptr,f); 275 remains=-remains; 276 return res; 277 } // end at_neg 278 if (u==at_plus){ 279 if (arg.type!=_VECT) 280 return linear_apply(arg,x,remains,contextptr,f); 281 const_iterateur it=arg._VECTptr->begin(),itend=arg._VECTptr->end(); 282 for (gen tmp;it!=itend;++it){ 283 res = res + linear_apply(*it,x,tmp,contextptr,f); 284 remains =remains + tmp; 285 } 286 return res; 287 } // end at_plus 288 if (u==at_prod){ 289 if (arg.type!=_VECT) 290 return linear_apply(arg,x,remains,contextptr,f); 291 // find all constant terms in the product 292 vecteur non_constant; 293 gen prod_constant; 294 decompose_prod(*arg._VECTptr,x,non_constant,prod_constant,false,contextptr); 295 if (non_constant.empty()) return gensizeerr(gettext("in linear_apply 2")); // otherwise the product would be constant 296 if (non_constant.size()==1) 297 res = linear_apply(non_constant.front(),x,remains,contextptr,f); 298 else 299 res = f(symbolic(at_prod,gen(non_constant,_SEQ__VECT)),x,remains,contextptr); 300 remains = prod_constant * remains; 301 return prod_constant * res; 302 } // end at_prod 303 return f(e,x,remains,contextptr); 304 } 305 lnabs(const gen & x,GIAC_CONTEXT)306 gen lnabs(const gen & x,GIAC_CONTEXT){ 307 bool _lnabs=do_lnabs(contextptr); 308 if (!complex_mode(contextptr) && _lnabs && !has_i(x)) 309 return ln(abs(x,contextptr),contextptr); 310 else 311 return ln(x,contextptr); 312 } 313 lnabs2(const gen & x,const gen & xvar,GIAC_CONTEXT)314 gen lnabs2(const gen & x,const gen & xvar,GIAC_CONTEXT){ 315 if (xvar.type!=_IDNT) 316 return lnabs(x,contextptr); 317 bool _lnabs=do_lnabs(contextptr); 318 if (!complex_mode(contextptr) && _lnabs && !has_i(x)){ 319 return symbolic(at_ln,symbolic(at_abs,x)); 320 } 321 else { 322 if (is_positive(-x,contextptr)) 323 return symbolic(at_ln,-x); 324 return symbolic(at_ln,x); 325 } 326 } 327 normal_norootof(const gen & g,GIAC_CONTEXT)328 static gen normal_norootof(const gen & g,GIAC_CONTEXT){ 329 gen res=normal(g,contextptr); 330 if (!lop(res,at_rootof).empty()) 331 res=ratnormal(normalize_sqrt(g,contextptr),contextptr); 332 return res; 333 } 334 335 // eval N at X=e with e=x*exp(i*dephasage*pi/n)/(X-e)+conj and integrate substconj_(const gen & N,const gen & X,const gen & x,const gen & dephasage_,bool residue_only,GIAC_CONTEXT)336 static gen substconj_(const gen & N,const gen & X,const gen & x,const gen & dephasage_,bool residue_only,GIAC_CONTEXT){ 337 int mode=angle_mode(contextptr); 338 gen pi=cst_pi; 339 gen dephasage(dephasage_); 340 if (mode==1){ 341 dephasage=ratnormal(gen(180)/cst_pi*dephasage,contextptr); 342 pi=180; 343 } 344 if (mode==2){ 345 dephasage=ratnormal(gen(200)/cst_pi*dephasage,contextptr); 346 pi=200; 347 } 348 gen c=cos(dephasage,contextptr); 349 gen s=sin(dephasage,contextptr); 350 gen e=x*(c+cst_i*s); 351 gen b=subst(N,X,e,false,contextptr),rb,ib; 352 reim(b,rb,ib,contextptr); 353 gen N2=normal_norootof(-2*ib,contextptr); // same 354 if (residue_only) 355 return N2*sign(s*x,contextptr); 356 gen res=normal_norootof(rb,contextptr)*symbolic(at_ln,pow(X,2)+ratnormal(-2*c*x,contextptr)*X+x.squarenorm(contextptr)); 357 gen atanterm=pi/cst_pi*symbolic(at_atan,(X-c*x)/(s*x)); 358 if (X.is_symb_of_sommet(at_tan)) 359 atanterm += pi*sign(s*x,contextptr)*symbolic(at_floor,X._SYMBptr->feuille/pi+plus_one_half); 360 res=res+N2*atanterm; 361 return res; 362 } 363 substconj(const gen & N,const gen & X,const gen & x,const gen & dephasage,bool residue_only,GIAC_CONTEXT)364 static gen substconj(const gen & N,const gen & X,const gen & x,const gen & dephasage,bool residue_only,GIAC_CONTEXT){ 365 if (has_i(N)){ 366 gen Nr,Ni; 367 reim(N,Nr,Ni,contextptr); 368 return substconj_(Nr,X,x,dephasage,residue_only,contextptr)+cst_i*substconj_(Ni,X,x,dephasage,residue_only,contextptr); 369 } 370 return substconj_(N,X,x,dephasage,residue_only,contextptr); 371 } 372 surd(const gen & c,int n,GIAC_CONTEXT)373 gen surd(const gen & c,int n,GIAC_CONTEXT){ 374 if (is_exactly_zero(c)) 375 return c; 376 if (n%2 && is_positive(-c,contextptr)){ 377 if (c.type==_FLOAT_) 378 return -exp(ln(-c,contextptr)/n,contextptr); 379 return -pow(-c,inv(n,contextptr),contextptr); 380 } 381 else { 382 if (c.type==_FLOAT_) 383 return exp(ln(c,contextptr)/n,contextptr); 384 return pow(c,inv(n,contextptr),contextptr); 385 } 386 } 387 _surd(const gen & args,GIAC_CONTEXT)388 gen _surd(const gen & args,GIAC_CONTEXT){ 389 if ( args.type==_STRNG && args.subtype==-1) return args; 390 if (args.type!=_VECT || args._VECTptr->size()!=2) 391 return gensizeerr(contextptr); 392 gen a=args._VECTptr->front(),aa,b=args._VECTptr->back(),c; 393 if (a.is_symb_of_sommet(at_abs) || a.is_symb_of_sommet(at_exp)) 394 return pow(a,inv(b,contextptr),contextptr); 395 if (is_equal(a)){ 396 gen a0=a._SYMBptr->feuille[0],a1=a._SYMBptr->feuille[1]; 397 return symbolic(at_equal,makesequence(_surd(makesequence(a0,b),contextptr),_surd(makesequence(a1,b),contextptr))); 398 } 399 if (is_undef(a)) return a; 400 if (is_undef(b)) return b; 401 if (is_inf(b)){ 402 if (is_inf(a) || is_zero(a)) 403 return undef; 404 return 1; 405 } 406 if (is_zero(b)) 407 return undef; 408 if (is_inf(a)) 409 return pow(a,inv(b,contextptr),contextptr); 410 c=_floor(b,contextptr); 411 if (c.type==_FLOAT_) 412 c=get_int(c._FLOAT_val); 413 if (!has_evalf(a,aa,1,contextptr)){ 414 if (c.type==_INT_ && c==b && (c.val %2 ==0 || (a.is_symb_of_sommet(at_pow) && a._SYMBptr->feuille[1].type==_INT_ && a._SYMBptr->feuille[1].val % c.val==0)) ) 415 return pow(a,inv(c,contextptr),contextptr); 416 return symbolic(at_NTHROOT,gen(makevecteur(b,a),_SEQ__VECT)); 417 } 418 if (c.type==_INT_ && c==b) 419 return surd(a,c.val,contextptr); 420 else 421 return pow(a,inv(b,contextptr),contextptr); 422 } 423 static const char _surd_s []="surd"; 424 static define_unary_function_eval (__surd,&_surd,_surd_s); 425 define_unary_function_ptr5( at_surd ,alias_at_surd,&__surd,0,true); 426 makelnatan(const gen & N,const gen & X,const gen & c0,int n,bool residue_only,GIAC_CONTEXT)427 static gen makelnatan(const gen & N,const gen & X,const gen & c0,int n,bool residue_only,GIAC_CONTEXT){ 428 gen c(c0),res(0); 429 if (n%2){ 430 if (is_positive(-c,contextptr)) 431 c=-pow(-c,inv(n,contextptr),contextptr); 432 else 433 c=pow(c,inv(n,contextptr),contextptr); 434 if (!residue_only) 435 res += subst(N,X,c,false,contextptr)*lnabs(X-c,contextptr); 436 for (int i=1;i<=n/2;++i) 437 res += substconj(N,X,c,gen(2*i)/n*cst_pi,residue_only,contextptr); 438 return res; 439 } 440 if (is_positive(c,contextptr) ){ 441 if (n==2) 442 c=sqrt(c,contextptr); 443 else 444 c=pow(c,inv(n,contextptr),contextptr); 445 if (!residue_only) 446 res += normal_norootof(subst(N,X,c,false,contextptr),contextptr)*lnabs2(X-c,X,contextptr)+normal_norootof(subst(N,X,-c,false,contextptr),contextptr)*lnabs2(X+c,X,contextptr); 447 for (int i=1;i<n/2;++i) 448 res += substconj(N,X,c,gen(2*i)/n*cst_pi,residue_only,contextptr); 449 } 450 else { 451 if (n==2) 452 c=sqrt(-c,contextptr); 453 else 454 c=pow(-c,inv(n,contextptr),contextptr); 455 for (int i=0;i<n/2;++i) 456 res += substconj(N,X,c,gen(2*i+1)/n*cst_pi,residue_only,contextptr); 457 } 458 return res; 459 } 460 symb_atan(const polynome & d_,const polynome & a_,const vecteur & l,GIAC_CONTEXT)461 gen symb_atan(const polynome & d_,const polynome & a_,const vecteur & l,GIAC_CONTEXT){ 462 polynome d(d_),a(a_); 463 simplify(d,a); 464 if (a.coord.empty()) 465 return 0; 466 gen D=r2e(d,l,contextptr); 467 if (is_positive(-D*a.coord.front().value,contextptr)) 468 return -symb_atan(r2e(-a,l,contextptr)/D); 469 return symb_atan(r2e(a,l,contextptr)/D); 470 } 471 472 // im(ln(a+i*b)), a and b polynomials rewritten as sum of atan without denominators 473 // im(ln(a+i*b)+ln(u-i*v))=im(ln(a*u+b*v)+i(b*u-a*v)) ln2sumatan(const polynome & a,const polynome & b,const vecteur & l,GIAC_CONTEXT)474 gen ln2sumatan(const polynome & a,const polynome & b,const vecteur & l,GIAC_CONTEXT){ 475 if (a.lexsorted_degree()>b.lexsorted_degree()) 476 return -ln2sumatan(b,a,l,contextptr); 477 polynome u,v,d; 478 egcd(a,b,u,v,d); 479 if (v.coord.empty()){ // a divides b 480 return symb_atan(a,b,l,contextptr); 481 } 482 gen tmp=-ln2sumatan(v,u,l,contextptr); 483 tmp += symb_atan(d,b*u-a*v,l,contextptr); 484 return tmp; 485 } ln2sumatan(const gen & a,const gen & b,const vecteur & l,GIAC_CONTEXT)486 gen ln2sumatan(const gen & a,const gen & b,const vecteur & l,GIAC_CONTEXT){ 487 //return symb_atan(b/a); 488 gen A=e2r(a,l,contextptr),An,Ad; 489 gen B=e2r(b,l,contextptr),Bn,Bd; 490 fxnd(A,An,Ad); 491 fxnd(B,Bn,Bd); 492 An=Bd*An; 493 Bn=Ad*Bn; 494 if (An.type==_POLY && Bn.type==_POLY) 495 return ln2sumatan(*An._POLYptr,*Bn._POLYptr,l,contextptr); 496 if (Bn.type!=_POLY) 497 return -symb_atan(a/b); 498 return symb_atan(b/a); 499 } 500 integrate_rothstein_trager(const polynome & num,const vecteur & v,const vecteur & l,const gen & X,gen & res,int intmode,GIAC_CONTEXT)501 static bool integrate_rothstein_trager(const polynome & num,const vecteur & v,const vecteur & l,const gen & X,gen & res,int intmode,GIAC_CONTEXT){ 502 // Improve: csolve for resultant(num-t*v',v) 503 // Example a:=diff(atan((x^2-2x)/(x-1))); b:=int(a); 504 // v=[1,-4,5,-2,1], roots for resultant +/-i/2 505 // sum t*ln(gcd(n-t*d',d)) 506 // if t is complex and v real 507 // t*ln()+conjugate=re(t)*ln(|gcd|^2)-im(t)*atan(im(gcd)/re(gcd)) 508 gen N=r2e(num,l,contextptr); 509 vecteur Nv(lvar(N)); 510 if (1 || Nv==vecteur(1,X)){ // do it for univariate only 511 gen D=r2e(poly12polynome(v,1),l,contextptr); 512 gen Dprime=r2e(poly12polynome(derivative(v),1),l,contextptr); 513 gen tres(identificateur("tresultant")); 514 gen R=_resultant(makesequence(N-tres*Dprime,D,X),contextptr); 515 gen Rprime=derive(R,tres,contextptr); 516 R=_quo(makesequence(R,gcd(R,Rprime,contextptr),tres),contextptr); 517 gen Rdeg=_degree(makesequence(R,tres),contextptr); 518 gen Rt=solve(R,tres,1,contextptr); // _cSolve(makesequence(R,tres),contextptr); 519 if (Rdeg.type==_INT_ && Rt.type==_VECT && Rt._VECTptr->size()==Rdeg.val){ 520 vecteur w=*Rt._VECTptr; 521 bool reel=vect_is_real(v,contextptr); 522 if (!has_num_coeff(w)){ 523 for (size_t wi=0;wi<w.size();++wi){ 524 gen racine=w[wi]; 525 if (has_op(normal(racine,contextptr),*at_rootof)) 526 return false; 527 gen G=gcd(N-racine*Dprime,D,contextptr); 528 if (reel){ 529 gen racr,raci; 530 reim(racine,racr,raci,contextptr); 531 if (is_zero(raci,contextptr)) 532 res += racine*symb_ln(symb_abs(G)); 533 else { 534 if (wi<w.size()-1 && w[wi]==conj(w[wi+1],contextptr)){ 535 gen gcdr,gcdi; 536 reim(G,gcdr,gcdi,contextptr); 537 res += racr*symb_ln(gcdr*gcdr+gcdi*gcdi)-2*raci*ln2sumatan(gcdr,gcdi,l,contextptr); 538 ++wi; 539 } 540 else 541 res += racine*symb_ln(G); 542 } 543 } 544 else { 545 res += racine*symb_ln(G); 546 } 547 } 548 return true; 549 } 550 } 551 } 552 return false; 553 } 554 555 // integration of cyclotomic-type denominators integrate_deno_length_2(const polynome & num,const vecteur & v,const vecteur & l,const vecteur & lprime,gen & res,bool residue_only,int intmode,GIAC_CONTEXT)556 static bool integrate_deno_length_2(const polynome & num,const vecteur & v,const vecteur & l,const vecteur & lprime,gen & res,bool residue_only,int intmode,GIAC_CONTEXT){ 557 if (v.size()<2) 558 return false; 559 const_iterateur it=v.begin()+1,itend=v.end()-1; 560 for (;it!=itend;++it){ 561 if (!is_zero(*it)) 562 break; 563 } 564 int n=int(v.size())-1,d=int(it-v.begin()),deg; 565 gen X=l.front(); 566 if (X.type==_VECT) 567 X=X._VECTptr->front(); 568 gen a=r2e(v.front(),lprime,contextptr); 569 gen b=r2e(v.back(),lprime,contextptr); 570 // check for deno of type a*x^2n + A*x^n + b 571 // FIXME: improve some simplifications of sin/cos(asin()/k) and remove test d==2 572 if (d==2 && 2*d==n){ 573 ++it; 574 for (;it!=itend;++it){ 575 if (!is_zero(*it)) 576 break; 577 } 578 if (it==itend){ // ok! 579 gen c=b; 580 b=r2e(v[d],lprime,contextptr); 581 gen delta=b*b-4*a*c; 582 if (is_positive(-delta,contextptr)) // FIXME was if (is_zero(delta)) 583 return false; 584 if ( (intmode &2)==0) 585 gprintf(step_ratfrac,gettext("Integration of a rational fraction with denominator %gen\nroots are obtained by solving the 2nd order equation %gen=0 then extracting nth-roots"),makevecteur(a*symb_pow(vx_var,2*n)+b*symb_pow(vx_var,n)+c,a*symb_pow(vx_var,2)+b*vx_var+c),contextptr); 586 // int(num/(a*X^2n+b*X^n+c),X) = 587 // sum(x=rootof(deno),num*x/(+/-n*sqrt(delta))*ln(X-x)) 588 gen sqrtdelta=sqrt(delta,contextptr); 589 gen c1=(-b-sqrtdelta)/2/a; 590 gen c2=(-b+sqrtdelta)/2/a; 591 gen N=r2e(num,l,contextptr)*X/d/sqrtdelta; 592 if (is_zero(im(a,contextptr)) && is_zero(im(b,contextptr)) && is_zero(im(c,contextptr))){ 593 if (!is_positive(-delta,contextptr)){ 594 res += makelnatan(N/c2,X,c2,d,residue_only,contextptr); 595 res -= makelnatan(N/c1,X,c1,d,residue_only,contextptr); 596 return true; 597 } 598 else { 599 gen module=sqrt(c/a,contextptr); 600 gen argument=acos(normal(-b/a/2/module,contextptr),contextptr); 601 // roots are module^(1/d)*exp(i*argument/d)*exp(2*i*pi*k/d) 602 // for k=0..d-1and conjugates 603 gen moduled=pow(c/a,inv(n,contextptr),contextptr); 604 for (int i=0;i<d;++i) 605 res += substconj(N/c2,X,moduled,(argument+2*i*cst_pi)/d,residue_only,contextptr); 606 } 607 return true; 608 } 609 if (residue_only) 610 return true; 611 gen c1s=surd(c1,d,contextptr); 612 gen c2s=surd(c2,d,contextptr); 613 for (int i=0;i<d;++i){ 614 gen x=c1s*exp((2*i*cst_i*cst_pi)/d,contextptr); 615 res -= normal(subst(N,X,x,false,contextptr)/c1,contextptr)*ln(X-x,contextptr); 616 x=c2s*exp((2*i*cst_i*cst_pi)/d,contextptr); 617 res += normal(subst(N,X,x,false,contextptr)/c2,contextptr)*ln(X-x,contextptr); 618 } 619 return true; 620 } 621 } // end if d==2 and n==2d 622 gen c=normal(-b/a,contextptr); 623 if (n%d) 624 return residue_only?false:integrate_rothstein_trager(num,v,l,X,res,intmode,contextptr); 625 if (d!=n){ 626 // rescale and check cyclotomic 627 gen tw=v.back()/pow(*it/v.front(),n/d); 628 if (tw.type!=_INT_ && tw.type!=_POLY) 629 return residue_only?false:integrate_rothstein_trager(num,v,l,X,res,intmode,contextptr); 630 tw=r2e(v/v.front(),lprime,contextptr); 631 if (tw.type!=_VECT) 632 return residue_only?false:integrate_rothstein_trager(num,v,l,X,res,intmode,contextptr); 633 vecteur w=*tw._VECTptr; 634 vecteur w_copy=w; 635 c=pow(r2e(*it/v.front(),lprime,contextptr),inv(d,contextptr),contextptr); 636 iterateur jt=w.begin()+1,jtend=w.end(); 637 for (int k=1;jt!=jtend;++jt,++k){ 638 *jt=normal(*jt * pow(c,-k),contextptr); 639 if (jt->type!=_INT_ && jt->type!=_POLY) 640 break; 641 } 642 deg=is_cyclotomic(w,epsilon(contextptr)); 643 if (!deg){ 644 w=w_copy; 645 c=pow(r2e(-*it/v.front(),lprime,contextptr),inv(d,contextptr),contextptr); 646 jt=w.begin()+1,jtend=w.end(); 647 for (int k=1;jt!=jtend;++jt,++k){ 648 *jt=normal(*jt * pow(c,-k),contextptr); 649 if (jt->type!=_INT_ && jt->type!=_POLY) 650 break; 651 } 652 deg=is_cyclotomic(w,epsilon(contextptr)); 653 } 654 if (!deg) 655 return residue_only?false:integrate_rothstein_trager(num,v,l,X,res,intmode,contextptr); 656 if ( (intmode &2)==0) 657 gprintf(step_cyclotomic,gettext("Integrate rational fraction with denominator a cyclotomic polynomial, roots are primitive roots of %gen=0"),makevecteur(a*symb_pow(vx_var,deg)+b),contextptr); 658 // int(num/(a*X^n+b),X)=sum(x=rootof(-b/a),num*x/(-n*b)*ln(X-x)) 659 vecteur vprime=derivative(v),V,Vprime,d; 660 egcd(v,vprime,0,V,Vprime,d); 661 if (d.size()!=1) 662 return residue_only?false:integrate_rothstein_trager(num,v,l,X,res,intmode,contextptr); 663 gen dd=d.front(); 664 // 1/vprime=Vprime/d 665 gen N=normal(_quorem(makesequence(r2e(num,l,contextptr)*horner(r2e(Vprime,lprime,contextptr),X),horner(r2e(v,lprime,contextptr),X),X),contextptr)[1]/r2e(dd,lprime,contextptr),contextptr); 666 if (complex_mode(contextptr) && !residue_only){ 667 for (int i=1;i<deg;++i){ 668 if (gcd(i,deg)!=1) 669 continue; 670 gen x=c*exp((2*i*cst_i*cst_pi)/deg,contextptr); 671 res += normal(subst(N,X,x,false,contextptr),contextptr)*ln(X-x,contextptr); 672 } 673 } 674 else { 675 for (int i=1;i<=deg/2;++i){ 676 if (gcd(i,deg)!=1) 677 continue; 678 res += substconj(N,X,c,2*i*cst_pi/deg,residue_only,contextptr); 679 } 680 } 681 return true; 682 } // if (d!=n) 683 else { 684 if ( (intmode &2)==0) 685 gprintf(step_nthroot,gettext("Integrate rational fraction with denominator %gen=0\nroots are deduced from nth-roots of unity"),makevecteur(a*symb_pow(vx_var,n)+b),contextptr); 686 // int(num/(a*X^n+b),X)=sum(x=rootof(-b/a),num*x/(-n*b)*ln(X-x)) 687 gen N=r2e(num,l,contextptr)*X/(r2e(-n*b,l,contextptr)); 688 if (complex_mode(contextptr) && !residue_only){ 689 c=pow(c,inv(n,contextptr),contextptr); 690 for (int i=0;i<n;++i){ 691 gen x=c*exp((2*i*cst_i*cst_pi)/n,contextptr); 692 res += normal(subst(N,X,x,false,contextptr),contextptr)*ln(X-x,contextptr); 693 } 694 return true; 695 } 696 res += makelnatan(N,X,c,n,residue_only,contextptr); 697 return true; 698 } 699 } 700 701 // tests if v is symmetric or antisymmetric 702 // if it is, compute res such that res[t+-1/t]=v/t^[deg(v)/2] is_symmetric(const vecteur & v,vecteur & res,bool sym)703 static int is_symmetric(const vecteur & v,vecteur & res,bool sym){ 704 if (v.empty()) 705 return 0; 706 int n=int(v.size()); 707 vecteur w; 708 if (n%2) 709 w=v; 710 else { 711 if (!is_zero(v[n-1])) 712 return 0; 713 w=vecteur(v.begin(),v.end()-1); 714 --n; 715 } 716 vecteur w1(w); 717 reverse(w1.begin(),w1.end()); 718 if (!sym){ 719 for (int i=1;i<n;i+=2){ 720 w1[i] = -w1[i]; 721 } 722 } 723 int rescoeff=0; 724 if (w==w1) 725 rescoeff=1; 726 if (w==-w1) 727 rescoeff=-1; 728 if (!rescoeff) 729 return 0; 730 // if antisym, n/2 is the number of power of (t^2-1), check if it is odd 731 if (!sym && (n/2)%2) 732 rescoeff = -rescoeff; 733 vecteur test(makevecteur(1,0,sym?1:-1)),q,r; 734 res.clear(); 735 for (n/=2;n>0;n--){ 736 DivRem(w,powmod(test,n,0,0),0,q,r); 737 if (q.size()>1) 738 return 0; 739 w=r.empty()?r:vecteur(r.begin(),r.end()-1); 740 res.push_back(q.empty()?0:q.front()); 741 } 742 if (w.empty()) 743 res.push_back(0); // was return 0; 744 else 745 res.push_back(w.front()); 746 return rescoeff; 747 } 748 749 // n/d(x) -> newn/newd(t) with x=a/t, 750 // if dx is true multiplies by dx/dt=-a/t^2 xtoinvx(const gen & a,const modpoly & n,const modpoly & d,modpoly & newn,modpoly & newd,bool dx)751 static void xtoinvx(const gen & a,const modpoly & n,const modpoly & d,modpoly & newn, modpoly & newd,bool dx){ 752 int ns=int(n.size()); int nd=int(d.size()); 753 newn=vecteur(ns); newd=vecteur(nd); 754 gen ad(1); 755 for (int i=ns-1;i>=0;--i){ 756 newn[ns-1-i]=ad*n[i]; 757 ad = ad*a; 758 } 759 ad=1; 760 for (int i=nd-1;i>=0;--i){ 761 newd[nd-1-i]=ad*d[i]; 762 ad = ad*a; 763 } 764 if (dx){ 765 newn=operator_times(-a,newn,0); 766 ns+=2; 767 } 768 trim(newn,0); 769 trim(newd,0); 770 for (;ns>nd;--ns){ 771 newd.push_back(0); 772 } 773 for (;nd>ns;--nd){ 774 newn.push_back(0); 775 } 776 } 777 778 static gen integrate_rational(const gen & e, const gen & x, gen & remains_to_integrate,gen & xvar,int intmode,GIAC_CONTEXT); 779 solve_aPprime_plus_P(const gen & anum,const gen & aden,const vecteur & Q,vecteur & R,gen & Pden)780 static void solve_aPprime_plus_P(const gen & anum,const gen & aden,const vecteur & Q,vecteur & R,gen & Pden){ 781 // a P+P'=Q, a=anum/aden, on cherche P sous la forme R/Pden 782 // On a (k+1)p_(k+1)+ anum/aden*p_k=q_k 783 // Donc p_k=aden/anum*(q_k-(k+1)p_(k+1)) 784 // n=deg[Q], on a donc Pden=anum^(n+1), puis on cherche R=P*anum^(n+1) 785 // on multiplie donc Q par anum^(n+1) S=Q*anum^(n+1)/a 786 // on a aR+R'=aS 787 // on a donc par ordre decr. r_(n+1)=0 788 // r_k= s_k - (k+1)*r_(k+1)/a 789 // avec des divisions sans creation de denominateurs 790 // par ex. P'+3P=x^2+5x+7 -> r_2=9, r_1=39, r_0=50, a=3, n=2, a^n=9 791 R.clear(); 792 if (Q.empty()){ 793 Pden=plus_one; 794 return; 795 } 796 int n=int(Q.size())-1; 797 R.reserve(n+1); 798 Pden=pow(anum,n); 799 vecteur S; 800 multvecteur(Pden*aden,Q,S); 801 Pden=Pden*anum; 802 const_iterateur it=S.begin(),itend=S.end(); 803 R.push_back(*it); 804 ++it; 805 for (int k=n-1;it!=itend;++it,--k){ 806 R.push_back(*it-rdiv(gen(k+1)*R.back()*aden,anum,context0)); 807 } 808 // should simplify R with Pden 809 } 810 integrate_linearizable(const gen & e,const gen & gen_x,gen & remains_to_integrate,int intmode,GIAC_CONTEXT)811 static gen integrate_linearizable(const gen & e,const gen & gen_x,gen & remains_to_integrate,int intmode,GIAC_CONTEXT){ 812 // exp linearization 813 vecteur vexp; 814 gen res; 815 const identificateur & id_x=*gen_x._IDNTptr; 816 lin(e,vexp,contextptr); // vexp = coeff, arg of exponential 817 if ( (intmode &2)==0 ){ 818 gen tmp=unlin(vexp,contextptr); 819 if (vexp.size()>2 || !is_zero(ratnormal(tmp-e,contextptr))) 820 gprintf(step_linearizable,gettext("Integrate linearizable expression %gen -> %gen"),makevecteur(e,tmp),contextptr); 821 } 822 const_iterateur it=vexp.begin(),itend=vexp.end(); 823 for (;it!=itend;){ 824 // trig linearization 825 vecteur vtrig; 826 gen coeff=*it; 827 ++it; // it -> on the arg of the exp that must be linear 828 gen rex2,rea,reb,reaxb=*it; 829 ++it; 830 if (!is_quadratic_wrt(reaxb,gen_x,rex2,rea,reb,contextptr)){ 831 // IMPROVE using int(exp(-x^a))=1/a*igamma(1/a,x^a) 832 vecteur lv=lvarxwithinv(makevecteur(reaxb,coeff),gen_x,contextptr); 833 if (lv.size()==1){ 834 gen C=_coeff(makesequence(reaxb,gen_x),contextptr); 835 if (C.type==_VECT && C._VECTptr->size()>2){ 836 vecteur Cv=*C._VECTptr; 837 int n=int(Cv.size())-1; 838 gen c=Cv[0]; 839 gen a=-Cv[1]/(n*c); 840 // must be c*(x-a)^n 841 if (C==_coeff(makesequence(c*pow(gen_x-a,n,contextptr),gen_x),contextptr) && ((n%2) || is_positive(-c,contextptr))){ 842 // c=surd(c,n,contextptr); 843 C=_coeff(makesequence(coeff,gen_x),contextptr); 844 C=_ptayl(makesequence(C,a,gen_x),contextptr); 845 if (C.type==_VECT){ 846 c=-c; 847 gen ca=surd(c,n,contextptr); 848 Cv=*C._VECTptr; 849 int m=int(Cv.size())-1; 850 gen ires=0; 851 // 1/n*igamma(1/n+b/n,c*x^n)'=x^b*exp(-c*x^n)*c^(b+1)/n 852 for (int b=0;b<=m;++b){ 853 ires += Cv[m-b]*_lower_incomplete_gamma(makesequence(gen(b+1)/gen(n),c*pow(gen_x-a,n)),contextptr)/pow(ca,b+1,contextptr); 854 } 855 if (n%2==0){ 856 ires=ires*abs(gen_x,contextptr)/gen_x; // sign(gen_x,contextptr); 857 } 858 ires=ires/n; 859 res += ires; 860 continue; 861 } 862 } 863 } 864 } 865 remains_to_integrate = remains_to_integrate + coeff*exp(reaxb,contextptr); 866 continue; 867 } 868 if (!is_zero(rex2)){ 869 if (1 870 //&&is_zero(im(rex2,contextptr)) 871 //&& is_positive(-rex2,contextptr) 872 ){ 873 const vecteur & vx2=lvarxpow(coeff,gen_x); 874 if ( vx2.size()>1 || (!vx2.empty() && vx2.front()!=gen_x) ){ 875 remains_to_integrate = remains_to_integrate + coeff*exp(reaxb,contextptr); 876 continue; 877 } 878 // int(exp(rex2*x^2+rea*x+reb)*P(x),x) 879 gen decal=rea/rex2/2; 880 gen cst=normal(reb-rex2*decal*decal,contextptr); 881 // exp(cst)*int(exp(rex2*(x+decal)^2)*P(x),x) 882 coeff=quotesubst(coeff,gen_x,gen_x-decal,contextptr); 883 // exp(cst)*subst(int(exp(rex2*x^2)*coeff(x),x),x,x+decal) 884 vecteur les_var(1,gen_x); // insure x is the main var 885 lvar(makevecteur(coeff,rex2),les_var); 886 int les_vars=int(les_var.size()); 887 gen in_coeff,in_coeffnum,in_coeffden,ina; 888 in_coeff=e2r(coeff,les_var,contextptr); 889 ina=e2r(rex2,vecteur(les_var.begin()+1,les_var.end()),contextptr); 890 fxnd(in_coeff,in_coeffnum,in_coeffden); 891 vecteur in_coeffnumv; 892 if (in_coeffnum.type==_POLY) 893 in_coeffnumv=polynome2poly1(*in_coeffnum._POLYptr,1); 894 else 895 in_coeffnumv.push_back(in_coeffnum); 896 // now find int(exp(ina*x^2)*P(x)), coeffs of P are in in_coeffnumv 897 int vs=int(in_coeffnumv.size())-1; 898 vecteur vres(vs+1); 899 // integration by part to decrease vs 900 for (int i=vs;i>=1;--i){ 901 // i is the degree of the term to integrate 902 gen tmp=in_coeffnumv[vs-i]/ina/2; 903 vres[vs-(i-1)]=tmp; 904 if (i>1) 905 in_coeffnumv[vs-(i-2)] -= (i-1)*tmp; 906 } 907 gen vresden; 908 lcmdeno(vres,vresden,contextptr); // lcmdeno_converted? 909 gen ppart=subst(r2e(poly12polynome(vres,1,les_vars),les_var,contextptr),gen_x,gen_x+decal,false,contextptr)/r2e(vresden,vecteur(les_var.begin()+1,les_var.end()),contextptr)*exp(reaxb,contextptr); 910 // add erf part from the last coeff vres[vs] 911 gen a=-rex2; // r2e(-ina,les_var,contextptr); 912 gen sqrta=sqrt_noabs(a,contextptr); 913 gen erfpart=r2e(in_coeffnumv[vs],cdr_VECT(les_var),contextptr)*symbolic(at_sqrt,cst_pi)/sqrta*exp(cst,contextptr)/2*_erf(sqrta*(gen_x+decal),contextptr); 914 res += (ppart + erfpart)/r2e(in_coeffden,les_var,contextptr); 915 continue; 916 } 917 remains_to_integrate = remains_to_integrate + coeff*exp(reaxb,contextptr); 918 continue; 919 } 920 gen reai=im(rea,contextptr),rebi=im(reb,contextptr); 921 if (!is_zero(reai) || !is_zero(rebi)){ 922 gen reaxbi=reai*gen_x+rebi; 923 coeff=coeff*(cos(reaxbi,contextptr)+cst_i*sin(reaxbi,contextptr)); 924 rea=re(rea,contextptr); 925 reb=re(reb,contextptr); 926 reaxb=rea*gen_x+reb; 927 } 928 tlin(coeff,vtrig,contextptr); // vtrig = coeff , sin/cos(arg)/1 929 if ( (intmode &2)==0 ){ 930 gen tmp=tunlin(vtrig,contextptr); 931 if (vtrig.size()>2 || !is_zero(ratnormal(tmp-coeff,contextptr))) 932 gprintf(step_triglinearizable,gettext("Integrate trigonometric linearizable expression %gen -> %gen"),makevecteur(coeff,tmp),contextptr); 933 } 934 const_iterateur jt=vtrig.begin(),jtend=vtrig.end(); 935 for (;jt!=jtend;){ 936 // now check that each arg is linear and coeff polynomial 937 coeff=*jt; 938 ++jt; 939 gen ima,imb,imaxb=*jt; 940 ++jt; 941 if (is_constant_wrt(imaxb,gen_x,contextptr)){ 942 coeff = coeff*imaxb; 943 imaxb=1; 944 } 945 int trig_type=0; // 0 for 1, 1 for sin, 2 for cos 946 if (imaxb.type==_SYMB){ 947 if (imaxb._SYMBptr->sommet==at_sin) 948 trig_type=1; 949 if (imaxb._SYMBptr->sommet==at_cos) 950 trig_type=2; 951 } 952 else 953 imaxb=0; 954 // check polynomial 955 const vecteur vx2=lvarxpow(coeff,gen_x); 956 bool coeffnotpoly=(vx2.size()>1) || ( (!vx2.empty()) && (vx2.front()!=gen_x)); 957 gen imc; 958 bool quad=imaxb.type==_SYMB && is_quadratic_wrt(imaxb._SYMBptr->feuille,gen_x,ima,imb,imc,contextptr); 959 if (!coeffnotpoly && quad && !is_zero(ima) && angle_radian(contextptr)){ 960 imc=_trig2exp(coeff*exp(reaxb,contextptr)*imaxb,contextptr); 961 res += integrate_linearizable(imc,gen_x,remains_to_integrate,intmode,contextptr); 962 continue; 963 } 964 if ( coeffnotpoly || ( imaxb.type==_SYMB && !is_linear_wrt(imaxb._SYMBptr->feuille,gen_x,ima,imb,contextptr)) ) { 965 if (trig_type) imaxb=imaxb._SYMBptr->feuille; 966 gen tmp(plus_one); 967 if (trig_type==1) 968 tmp=sin(imaxb,contextptr); 969 if (trig_type==2) 970 tmp=cos(imaxb,contextptr); 971 remains_to_integrate = remains_to_integrate + coeff * exp(reaxb,contextptr) * tmp; 972 continue; 973 } 974 // everything OK coeff*exp(rea*x+reb)* 1/cos/sin(ima*x+imb) 975 if (trig_type) 976 imaxb=imaxb._SYMBptr->feuille; 977 else { 978 if (is_zero(rea)){ 979 gen tmprem,xvar(gen_x); 980 res= res + exp(reb,contextptr)*integrate_rational(coeff,gen_x,tmprem,xvar,intmode,contextptr); 981 remains_to_integrate = remains_to_integrate+exp(reb,contextptr)*tmprem; 982 continue; 983 } 984 } 985 bool coeff_is_real=false; 986 if (trig_type){ 987 gen imcoeff=im(coeff,contextptr); 988 rewrite_with_t_real(imcoeff,gen_x,contextptr); 989 if (is_zero(imcoeff) && is_zero(im(rea,contextptr)) && is_zero(im(ima,contextptr))) 990 coeff_is_real=true; 991 } 992 // find vars of coeff,rea,reb,ima,imb 993 vecteur les_var(1,gen_x); // insure x is the main var 994 lvar(makevecteur(coeff,rea,ima),les_var); 995 int les_vars=int(les_var.size()); 996 gen in_coeff,in_coeffnum,in_coeffden,in_rea,in_ima,in_anum,in_aden; 997 in_coeff=e2r(coeff,les_var,contextptr); 998 fxnd(in_coeff,in_coeffnum,in_coeffden); 999 vecteur in_coeffnumv; 1000 if (in_coeffnum.type==_POLY) 1001 in_coeffnumv=polynome2poly1(*in_coeffnum._POLYptr,1); 1002 else 1003 in_coeffnumv.push_back(in_coeffnum); 1004 in_coeffden=firstcoefftrunc(in_coeffden); 1005 in_rea=firstcoefftrunc(e2r(rea,les_var,contextptr)); 1006 in_ima=firstcoefftrunc(e2r(ima,les_var,contextptr)); 1007 vecteur resnum; 1008 gen resden,resplus; 1009 fxnd(in_rea+cst_i*in_ima,in_anum,in_aden); 1010 solve_aPprime_plus_P(in_anum,in_aden,in_coeffnumv,resnum,resden); 1011 resplus=rdiv(r2e(poly12polynome(resnum,1,les_vars),les_var,contextptr),r2e(poly12polynome(vecteur(1,resden*in_coeffden),1,les_vars),les_var,contextptr),contextptr); 1012 if (step_infolevel(contextptr)){ 1013 gprintf(step_polyexp,gettext("Primitive of %gen is polynomial of same degree*same exponential %gen"),makevecteur(coeff*symb_exp(reaxb+cst_i*imaxb),resplus*symb_exp(reaxb+cst_i*imaxb)),contextptr); 1014 } 1015 if (!trig_type){ 1016 res = res + resplus*exp(reaxb,contextptr); 1017 continue; 1018 } 1019 if (coeff_is_real){ 1020 gen resre=re(resplus,contextptr); 1021 rewrite_with_t_real(resre,gen_x,contextptr); 1022 gen resim=im(resplus,contextptr); 1023 rewrite_with_t_real(resim,gen_x,contextptr); 1024 if (trig_type==1) 1025 res = res + exp(reaxb,contextptr)*(resim*cos(imaxb,contextptr)+resre*sin(imaxb,contextptr)); 1026 else 1027 res = res + exp(reaxb,contextptr)*(resre*cos(imaxb,contextptr)-resim*sin(imaxb,contextptr)); 1028 continue; 1029 } 1030 fxnd(in_rea-cst_i*in_ima,in_anum,in_aden); 1031 solve_aPprime_plus_P(in_anum,in_aden,in_coeffnumv,resnum,resden); 1032 gen resmoins=rdiv(r2e(poly12polynome(resnum,1,les_vars),les_var,contextptr),r2e(poly12polynome(vecteur(1,resden*in_coeffden),1,les_vars),les_var,contextptr),contextptr); 1033 if (trig_type==1) 1034 res = res + exp(reaxb,contextptr)*rdiv(resplus*exp(cst_i*imaxb,contextptr)-resmoins*exp(-cst_i*imaxb,contextptr),plus_two*cst_i,contextptr); 1035 else 1036 res = res + exp(reaxb,contextptr)*rdiv(resplus*exp(cst_i*imaxb,contextptr)+resmoins*exp(-cst_i*imaxb,contextptr),plus_two,contextptr); 1037 } // end for (jt) 1038 } // end for (it) 1039 gen tmp=remains_to_integrate; 1040 remains_to_integrate=0; 1041 res=res+risch(tmp,id_x,remains_to_integrate,contextptr); 1042 if (is_undef(res)){ 1043 remains_to_integrate=e; 1044 return 0; 1045 } 1046 if (is_zero(im(e,contextptr)) &&has_i(res) && lop(res,at_erf).empty()){ 1047 remains_to_integrate=re(remains_to_integrate,contextptr); 1048 res=ratnormal(re(res,contextptr),contextptr); 1049 } 1050 return res; 1051 } // end linearizable 1052 1053 gen linear_integrate_nostep(const gen & e,const gen & x,gen & remains_to_integrate,int intmode,GIAC_CONTEXT); 1054 integrate_sqrt(gen & e,const gen & gen_x,const vecteur & rvar,gen & res,gen & remains_to_integrate,int intmode,GIAC_CONTEXT)1055 static bool integrate_sqrt(gen & e,const gen & gen_x,const vecteur & rvar,gen & res,gen & remains_to_integrate,int intmode,GIAC_CONTEXT){ // x and a power 1056 // subcase 1: power is a fraction of int 1057 // find rational parametrization if possible 1058 // subcase 2: 1st argument of power is linear, 2nd is constant && no inv 1059 gen argument=rvar.back()._SYMBptr->feuille._VECTptr->front(); 1060 gen exposant=rvar.back()._SYMBptr->feuille._VECTptr->back(); 1061 if ( (exposant.type==_FRAC) && (exposant._FRACptr->num.type==_INT_) && (exposant._FRACptr->den.type==_INT_) ){ 1062 int d=exposant._FRACptr->den.val; // n=exposant._FRACptr->num.val, 1063 gen a,b,c,tmprem,tmpres,tmpe; 1064 if (is_linear_wrt(argument,gen_x,a,b,contextptr)){ 1065 // argument=(ax+b)=t^d -> x=(t^d-a)/b and dx=d/a*t^(d-1)*dt 1066 vecteur substin(makevecteur(argument,gen_x)); 1067 vecteur substout(makevecteur(pow(gen_x,d),rdiv(pow(gen_x,d)-b,a,contextptr))); 1068 tmpe=complex_subst(e,substin,substout,contextptr)*pow(gen_x,d-1); 1069 tmpres=linear_integrate_nostep(tmpe,gen_x,tmprem,intmode,contextptr); 1070 gen fnc_inverse=pow(a*gen_x+b,fraction(1,d),contextptr); 1071 remains_to_integrate=rdiv(d,a,contextptr)*complex_subst(tmprem,gen_x,fnc_inverse,contextptr); 1072 res=rdiv(d,a,contextptr)*complex_subst(tmpres,gen_x,fnc_inverse,contextptr); 1073 return true; 1074 } 1075 vecteur tmpv(1,gen_x); 1076 lvar(argument,tmpv); 1077 gen fr,fr_n,fr_d,ap,bp; 1078 fr=e2r(argument,tmpv,contextptr); 1079 fxnd(fr,fr_n,fr_d); 1080 fr_n=r2e(fr_n,tmpv,contextptr); 1081 fr_d=r2e(fr_d,tmpv,contextptr); 1082 if (is_linear_wrt(fr_n,gen_x,a,b,contextptr) && is_linear_wrt(fr_d,gen_x,ap,bp,contextptr) ){ 1083 // argument=(a*x+b)/(ap*x+bp)=t^d 1084 // -> x=(bp*t^d-b)/(a-ap*t^d) 1085 // -> dx= d*(b*ap-a*bp)*t^(d-1)/(a-ap*t^d)^2 1086 vecteur substin(makevecteur(argument,gen_x)); 1087 vecteur substout(makevecteur(pow(gen_x,d),rdiv(bp*pow(gen_x,d)-b,a-ap*pow(gen_x,d),contextptr))); 1088 tmpe=complex_subst(e,substin,substout,contextptr)*rdiv(pow(gen_x,d-1),pow(a-ap*pow(gen_x,d),2),contextptr); 1089 tmpres=linear_integrate_nostep(tmpe,gen_x,tmprem,intmode,contextptr); 1090 gen fnc_inverse=pow(rdiv(a*gen_x+b,ap*gen_x+bp,contextptr),fraction(1,d),contextptr); 1091 gen tmp=gen(d)*(a*bp-b*ap); 1092 remains_to_integrate=tmp*complex_subst(tmprem,gen_x,fnc_inverse,contextptr); 1093 res=tmp*complex_subst(tmpres,gen_x,fnc_inverse,contextptr); 1094 return true; 1095 } 1096 /* ( * 2nd order: dispatch for y=ax^2+bx+c * ) 1097 ( * a>0 -> x=[m^2-c]/[b-2*sqrt[a]*m] * ) 1098 ( * m=sqrt[y]-sqrt[a]*x * ) 1099 ( * dx/sqrt[y]=2*dm/[b-2*sqrt[a]*m] * ) 1100 */ 1101 if (d==2 && is_constant_wrt(fr_d,gen_x,contextptr)){ 1102 // write e as alpha+beta*sqrt(argument) 1103 identificateur tmpx(" x"); 1104 gen e1=complex_subst(e,sqrt(argument,contextptr),tmpx,contextptr); 1105 vecteur lv(1,tmpx); 1106 lvar(e1,lv); 1107 gen e2=e2r(e1,lv,contextptr),num,den; 1108 fxnd(e2,num,den); 1109 den=r2e(den,lv,contextptr); 1110 num=r2e(num,lv,contextptr); 1111 // multiply denominator of e2 by conjugate 1112 gen pmini=tmpx*tmpx-argument; 1113 gen C=_egcd(makesequence(den,pmini,tmpx),contextptr); 1114 if (is_undef(C)){ 1115 res=C; 1116 return true; 1117 } 1118 num=_rem(makesequence(num*C[0],pmini,tmpx),contextptr); 1119 if (is_undef(num)){ 1120 res= num; 1121 return true; 1122 } 1123 den=C[2]; 1124 gen alpha,beta,xvar(gen_x); 1125 if (!is_linear_wrt(num,tmpx,beta,alpha,contextptr)){ 1126 res=gensizeerr(contextptr); 1127 return true; 1128 } 1129 alpha=integrate_rational(alpha/den,gen_x,remains_to_integrate,xvar,intmode,contextptr); 1130 if (is_undef(alpha)){ 1131 res=alpha; 1132 return true; 1133 } 1134 /* Instead we should factor argument in den 1135 FIXME in usual.cc diff of ln should expand * and / and rm abs 1136 write y=argument, P=beta 1137 we want to integrate P*sqrt(y)/den=(P*y)/den* y^(-1/2) 1138 *IF* den=y^l*D where D is prime with y (not always true...) 1139 P/Dy^l = P_y/y^l + P_D/D <--> P = P_y*D + P_D*y^l, 1140 find P_D and P_y by Bezout, find 1141 g = Q*D+R*y^l then Pg = P*Q*D + P*R*y^l hence 1142 P_D = P*R mod D/g and P_y = P*Q /g + [P*R div D] *y^l /g 1143 */ 1144 gen y=argument,P=beta,D=den; // P*y/den 1145 C=_quorem(makesequence(D,y,gen_x),contextptr); 1146 if (is_undef(C)){ 1147 res= C; 1148 return true; 1149 } 1150 int l=0; 1151 if (is_zero(C[1])){ // P/(den/y) 1152 D=C[0]; 1153 for (;;++l){ 1154 C=_quorem(makesequence(D,y,gen_x),contextptr); 1155 if (is_undef(C)){ 1156 res=C; 1157 return true; 1158 } 1159 if (!is_zero(C[1])) 1160 break; 1161 D=C[0]; 1162 } 1163 } 1164 else 1165 P=P*y; 1166 gen yl=pow(y,l); 1167 C=_egcd(makesequence(D,yl,gen_x),contextptr); 1168 if (is_undef(C)){ 1169 res= C; 1170 return true; 1171 } 1172 gen g=C[2],Q=C[0],R=C[1]; 1173 C=_quorem(makesequence(P*R,D,gen_x),contextptr); 1174 if (is_undef(C)){ 1175 res=C; 1176 return true; 1177 } 1178 gen PD=C[1]/g; 1179 // changed made for int(1/(sin(x)*sqrt(sin(2*x)^3))); 1180 C=_quorem(makesequence(P*Q+C[0]*yl,g,gen_x),contextptr); 1181 if (!is_zero(C[1])) 1182 return false; 1183 gen Py=C[0]; 1184 // gen Py=(P*Q+C[0]*yl)/g; 1185 C=_quorem(makesequence(Py,y,gen_x),contextptr); 1186 if (is_undef(C)){ 1187 res= C; 1188 return true; 1189 } 1190 /* 1191 int[ Py/y^l*y^-1/2 ] = Q*y^[1/2-l] + int[ C*y^-1/2 ] 1192 degre[Py]=n, degre[y]=k, find Q degre[Q]=n+1-k and C degre[C]=k-2 1193 so that Py = Q'*y + Q*y'*[1/2-l] + C y^l 1194 to do this we represent Q by a n+2-k-vector, C by a k-1-vector 1195 gluing Q and C we get a n+1-vector that must be solution of a 1196 n+1*n+1 linear system. Now we build the matrix of this system 1197 The n+2-k first columns are 1198 y'[1/2-l] ... x^alpha*y'*[1/2-l]+alpha*x^[alpha-1]*y ... 1199 The k-1 last columns are 1200 y^l ... x^beta*y^l 1201 Note 1: to avoid rational input in the matrix we multiply by 2 1202 coef of Q and C are found in the reverse order 1203 for l!=0 n is more precisely max[deg[Py],k[l+1]-2] 1204 Note 2: at the end we integrate only (C+PD/D)*y^(-1/2) 1205 */ 1206 gen tmpv=_e2r(makesequence(Py,gen_x),contextptr); 1207 if (tmpv.type!=_VECT){ 1208 if (tmpv.type==_FRAC){ 1209 if (tmpv._FRACptr->den.type==_VECT){ 1210 if (tmpv._FRACptr->den._VECTptr->size()!=1){ 1211 *logptr(contextptr) << "Internal error integrating sqrt" << '\n'; 1212 return false; 1213 } 1214 tmpv._FRACptr->den=tmpv._FRACptr->den._VECTptr->front(); 1215 } 1216 if (tmpv._FRACptr->num.type==_VECT) 1217 tmpv=multvecteur(inv(tmpv._FRACptr->den,contextptr),*tmpv._FRACptr->num._VECTptr); 1218 } 1219 if (tmpv.type!=_VECT) 1220 tmpv=vecteur(1,tmpv); // change 3/1/2013 for int(sqrt(1+x^2)/(-2*x^2)) 1221 // res= gensizeerr(contextptr); 1222 // return true; 1223 } 1224 vecteur colP=*tmpv._VECTptr; 1225 int n=int(colP.size())-1; 1226 tmpv=_e2r(makesequence(y,gen_x),contextptr); 1227 if (tmpv.type!=_VECT){ 1228 res= gensizeerr(contextptr); 1229 return true; 1230 } 1231 int k=int(tmpv._VECTptr->size())-1; 1232 n=giacmax(n,k*(l+1)-2); 1233 n=giacmax(n,k-1); 1234 if (n){ 1235 lrdm(colP,n); 1236 gen yprime=(1-2*l)*derive(y,gen_x,contextptr); 1237 if (is_undef(yprime)){ 1238 res= yprime; 1239 return true; 1240 } 1241 matrice sys; 1242 tmpv=_e2r(makesequence(yprime,gen_x),contextptr); 1243 if (tmpv.type!=_VECT){ 1244 res=gensizeerr(contextptr); 1245 return true; 1246 } 1247 vecteur col0(*tmpv._VECTptr); 1248 vecteur col(col0); 1249 lrdm(col,n); 1250 sys.push_back(col); 1251 col0.push_back(zero); 1252 tmpv=_e2r(makesequence(2*y,gen_x),contextptr); 1253 if (tmpv.type!=_VECT){ 1254 res=gensizeerr(contextptr); 1255 return true; 1256 } 1257 vecteur col1(*tmpv._VECTptr); 1258 for (int i=1;i<n+2-k;++i){ 1259 col=col0+gen(i)*col1; 1260 lrdm(col,n); 1261 col0.push_back(zero); 1262 col1.push_back(zero); 1263 sys.push_back(col); 1264 } 1265 tmpv=_e2r(makesequence(2*yl,gen_x),contextptr); 1266 if (tmpv.type!=_VECT){ 1267 res= gensizeerr(contextptr); 1268 return true; 1269 } 1270 col0=*tmpv._VECTptr; 1271 for (int i=0;i<k-1;++i){ 1272 col=col0; 1273 lrdm(col,n); 1274 sys.push_back(col); 1275 col0.push_back(zero); 1276 } 1277 sys=mtran(sys); 1278 int st=step_infolevel(contextptr); 1279 step_infolevel(contextptr)=0; 1280 col0=linsolve(sys,colP,contextptr); 1281 step_infolevel(contextptr)=st; 1282 if (!col0.empty() && is_undef(col0.front())){ 1283 res= col0.front(); 1284 return true; 1285 } 1286 reverse(col0.begin(),col0.end()); // C at the beginning, Q at the end 1287 C=2*horner(vecteur(col0.begin(),col0.begin()+k-1),gen_x); 1288 Q=2*horner(vecteur(col0.begin()+k-1,col0.end()),gen_x); 1289 alpha=alpha+Q*sqrt(y,contextptr)/yl; 1290 } 1291 else 1292 C=Py; 1293 e=(C+PD/D)/sqrt(argument,contextptr); 1294 if (is_quadratic_wrt(argument,gen_x,a,b,c,contextptr)){ 1295 if (!is_positive(-a,contextptr)){ 1296 gen sqrta(sqrt(a,contextptr)); 1297 identificateur id_m(" m"); 1298 gen m(id_m); 1299 tmpe=eval(rdiv(complex_subst(e*sqrt(argument,contextptr),argument,pow(m+sqrta*gen_x,2),contextptr),b-plus_two*sqrta*m,contextptr),1,contextptr); 1300 tmpe=ratnormal(complex_subst(tmpe,gen_x,rdiv(m*m-c,b-plus_two*sqrta*m,contextptr),contextptr),contextptr); 1301 tmpres=linear_integrate_nostep(tmpe,m,tmprem,intmode | 2,contextptr); 1302 remains_to_integrate=remains_to_integrate+complex_subst(plus_two*tmprem,m,sqrt(argument,contextptr)-sqrta*gen_x,contextptr); 1303 res= alpha+complex_subst(plus_two*tmpres,m,sqrt(argument,contextptr)-sqrta*gen_x,contextptr); 1304 return true; 1305 } 1306 else { 1307 gen D=sqrt_noabs(b*b-gen(4)*a*c,contextptr); 1308 gen sD=sign(D,contextptr); 1309 if (is_minus_one(sD)){ 1310 D=-D; 1311 sD=1; 1312 } 1313 /* 1314 ( * D=sqrt(b^2-4ac) * ) 1315 ( * a<0 and D>0 -> x=[D*2u/[1+u^2]-b]/2a * ) 1316 ( * u=[D-2*sqrt[-a]*sqrt[y]]/[2ax+b] * ) 1317 ( * dx/sqrt[y]=-2*du/[sqrt[-a]*[1+u^2]] * ) 1318 */ 1319 gen sqrta(sqrt(-a,contextptr)); 1320 identificateur id_u(" u"); 1321 gen u(id_u),uu(u); 1322 gen uasx=rdiv(D-plus_two*sqrta*sqrt(argument,contextptr),plus_two*a*gen_x+b,contextptr); 1323 tmpe=ratnormal(e*sqrt(argument,contextptr),contextptr); 1324 tmpe=complex_subst(tmpe,gen_x,rdiv(rdiv(plus_two*u*D,1+u*u,contextptr)-b,plus_two*a,contextptr),contextptr); 1325 tmpe=-rdiv(plus_two,sqrta,contextptr)*tmpe/(1+u*u); 1326 tmpres=integrate_rational(tmpe,u,tmprem,uu,intmode,contextptr); 1327 // sqrt(a*x^2+b*x+c) -> a*[(x+b/2/a)^2-(D/a)^2] 1328 // -> asin(a*x+b/2) 1329 vecteur vin(makevecteur(u,symbolic(at_atan,u))),vout(makevecteur(uasx,inv(-2,contextptr)*sD*asin(ratnormal((-2*a*gen_x-b)/D,contextptr),contextptr))); 1330 remains_to_integrate=remains_to_integrate+complex_subst(tmprem,vin,vout,contextptr); 1331 res=alpha+complex_subst(tmpres,vin,vout,contextptr); 1332 return true; 1333 } 1334 } // end sqrt of quadratic 1335 else { 1336 remains_to_integrate=e; 1337 res=alpha; 1338 return true; 1339 } 1340 } // end if d==2 1341 } // end exposant=fraction of integers 1342 return false; 1343 } // end recusive var size==2 i.e. of integrate_sqrt 1344 integrate_piecewise(gen & e,const gen & piece,const gen & gen_x,gen & remains_to_integrate,GIAC_CONTEXT,int intmode)1345 static gen integrate_piecewise(gen& e,const gen & piece,const gen & gen_x,gen & remains_to_integrate,GIAC_CONTEXT,int intmode){ 1346 gen & piecef=piece._SYMBptr->feuille; 1347 if (piecef.type!=_VECT){ 1348 e=subst(e,piece,piecef,false,contextptr); 1349 return integrate_id_rem(e,gen_x,remains_to_integrate,contextptr,intmode); 1350 } 1351 vecteur piecev=*piecef._VECTptr,remainsv(piecev); 1352 int nargs=int(piecev.size()); 1353 bool addremains=false; 1354 for (int i=0;i<nargs/2;++i){ 1355 remainsv[2*i+1]=0; 1356 gen tmp=subst(e,piece,piecev[2*i+1],false,contextptr); 1357 piecev[2*i+1]=integrate_id_rem(tmp,gen_x,remainsv[2*i+1],contextptr,intmode); 1358 addremains = addremains || !is_zero(remainsv[2*i+1]); 1359 } 1360 if (nargs%2){ 1361 remainsv[nargs-1]=0; 1362 gen tmp=subst(e,piece,piecev[nargs-1],false,contextptr); 1363 piecev[nargs-1]=integrate_id_rem(tmp,gen_x,remainsv[nargs-1],contextptr,intmode); 1364 addremains = addremains || !is_zero(remainsv[nargs-1]); 1365 } 1366 if (addremains) 1367 remains_to_integrate=symbolic(at_piecewise,gen(remainsv,_SEQ__VECT)); 1368 return symbolic(at_piecewise,gen(piecev,_SEQ__VECT)); 1369 // FIXME: make the antiderivative continuous 1370 } 1371 integrate_trig_fraction(gen & e,const gen & gen_x,vecteur & var,const gen & coeff_trig,int trig_fraction,gen & remains_to_integrate,int intmode,GIAC_CONTEXT)1372 static gen integrate_trig_fraction(gen & e,const gen & gen_x,vecteur & var,const gen & coeff_trig,int trig_fraction,gen& remains_to_integrate,int intmode,GIAC_CONTEXT){ 1373 const_iterateur vart=var.begin(),vartend=var.end(); 1374 vecteur substout; 1375 gen a,b,coeff_cst; 1376 is_linear_wrt(vart->_SYMBptr->feuille,gen_x,a,b,contextptr); 1377 coeff_cst=ratnormal(rdiv(a,coeff_trig,contextptr),contextptr)*b; 1378 // express all angles in vart as n*(coeff_trig*x+coeff_cst)+angle=a*x+b, 1379 // t=coeff_trig*x+coeff_cst 1380 for (;vart!=vartend;++vart){ 1381 is_linear_wrt(vart->_SYMBptr->feuille,gen_x,a,b,contextptr); 1382 gen n=ratnormal(rdiv(a,coeff_trig,contextptr),contextptr); 1383 if (n.type!=_INT_) return gensizeerr(gettext("trig_fraction")); 1384 gen angle=ratnormal(b-n*coeff_cst,contextptr); 1385 substout.push_back(symbolic(vart->_SYMBptr->sommet,n*gen_x+angle)); 1386 } 1387 gen f=complex_subst(e,var,substout,contextptr); // should be divided by coeff_trig 1388 f=_texpand(f,contextptr); 1389 gen tmprem,tmpres; 1390 if (trig_fraction==4){ // everything depends on exp(x) 1391 f=complex_subst(f,exp(gen_x,contextptr),gen_x,contextptr)*inv(gen_x,contextptr); 1392 if ( (intmode &2)==0) 1393 gprintf(step_ratfracexp,gettext("Integrate rational fraction of exponential %gen by %gen change of variable, leading to integral of %gen"),makevecteur(e,exp(gen_x,contextptr),f),contextptr); 1394 tmpres=linear_integrate_nostep(f,gen_x,tmprem,intmode,contextptr); 1395 gen expx=exp(coeff_trig*gen_x+coeff_cst,contextptr); 1396 if ( (intmode & 2)==0) 1397 gprintf(step_backsubst,gettext("Back substitution %gen->%gen in %gen"),makevecteur(gen_x,expx,tmprem),contextptr); 1398 remains_to_integrate = inv(coeff_trig,contextptr)*complex_subst(tmprem,gen_x,expx,contextptr); 1399 return inv(coeff_trig,contextptr)*complex_subst(tmpres,gen_x,expx,contextptr); 1400 } 1401 f=halftan(f,contextptr); // now everything depends on tan(x/2) 1402 // t=tan(x/2), dt=1/2(1+t^2)*dx 1403 gen xsur2=rdiv(coeff_trig*gen_x+coeff_cst,plus_two,contextptr); 1404 gen tanxsur2=tan(xsur2,contextptr); 1405 f=complex_subst(f,tan(rdiv(gen_x,plus_two,contextptr),contextptr),gen_x,contextptr)*inv(plus_one+pow(gen_x,2),contextptr); 1406 if ( (intmode &2)==0) 1407 gprintf(step_ratfractrig,gettext("Integrate rational fraction of trigonometric %gen by %gen change of variable, leading to integral of %gen"),makevecteur(e,tanxsur2,f),contextptr); 1408 vecteur vf(1,gen_x); 1409 rlvarx(f,gen_x,vf); 1410 if (vf.size()<=1) 1411 tmpres=integrate_rational(f,gen_x,tmprem,tanxsur2,intmode,contextptr); 1412 else { 1413 tmpres=linear_integrate_nostep(f,gen_x,tmprem,intmode,contextptr); 1414 if ( (intmode & 2)==0) 1415 gprintf(step_backsubst,gettext("Back substitution %gen->%gen in %gen"),makevecteur(gen_x,tanxsur2,tmpres),contextptr); 1416 tmpres=complex_subst(tmpres,gen_x,tanxsur2,contextptr); 1417 // tmprem=complex_subst(tmprem,gen_x,tanxsur2,contextptr); 1418 } 1419 if (tmpres==0) 1420 remains_to_integrate = e; 1421 else 1422 remains_to_integrate = rdiv(plus_two,coeff_trig,contextptr)*tmprem*(1+pow(tanxsur2,2)); 1423 return rdiv(plus_two,coeff_trig,contextptr)*tmpres; 1424 } 1425 1426 // reduce g, a rational fraction wrt to x, to a sqff lnpart 1427 // and adds the non sqff integrated part to ratpart intgab_ratfrac(const gen & e,const gen & x,gen & value,GIAC_CONTEXT)1428 bool intgab_ratfrac(const gen & e,const gen & x,gen & value,GIAC_CONTEXT){ 1429 vecteur l; 1430 l.push_back(x); // insure x is the main var 1431 l=vecteur(1,l); 1432 alg_lvar(e,l); 1433 int s=int(l.front()._VECTptr->size()); 1434 if (!s){ 1435 l.erase(l.begin()); 1436 s=int(l.front()._VECTptr->size()); 1437 } 1438 if (!s) 1439 return false; 1440 gen r=e2r(e,l,contextptr); 1441 gen r_num,r_den; 1442 fxnd(r,r_num,r_den); 1443 if (r_num.type==_EXT) 1444 return false; 1445 polynome num(s); 1446 if (r_num.type==_POLY) 1447 num=*r_num._POLYptr; 1448 else 1449 num=polynome(r_num,s); 1450 if (r_den.type!=_POLY){ // not convergent 1451 if (num.lexsorted_degree()%2) 1452 value=undef; 1453 else 1454 value=subst(r2e(r_num,l,contextptr),x,1,false,contextptr)/r2e(r_den,l,contextptr)*plus_inf; 1455 return true; 1456 } 1457 polynome den(*r_den._POLYptr); 1458 if (num.lexsorted_degree()>den.lexsorted_degree()-2){ // not convergent 1459 if ( (num.lexsorted_degree()-den.lexsorted_degree())%2 ) 1460 value=undef; 1461 else 1462 value=subst(r2e(r_num,l,contextptr)/r2e(r_den,l,contextptr),x,1,false,contextptr)*plus_inf; 1463 return true; 1464 } 1465 l.front()._VECTptr->front()=x; 1466 vecteur lprime(l); 1467 if (lprime.front().type!=_VECT){ 1468 value=gensizeerr(gettext("in intgab_rational")); 1469 return false; 1470 } 1471 lprime.front()=cdr_VECT(*(lprime.front()._VECTptr)); 1472 // quick check for length 2 deno 1473 vecteur vtmp; 1474 polynome2poly1(den,1,vtmp); 1475 if (integrate_deno_length_2(num,vtmp,l,lprime,value,true,2/* no step info*/,contextptr)){ 1476 value=ratnormal(value,contextptr)*cst_pi; 1477 return true; 1478 } 1479 polynome p_content(lgcd(den)); 1480 factorization vden(sqff(den/p_content)); // first square-free factorization 1481 vector< pf<gen> > pfde_VECT; 1482 polynome ipnum(s),ipden(s),temp(s),tmp(s); 1483 partfrac(num,den,vden,pfde_VECT,ipnum,ipden); 1484 vector< pf<gen> >::iterator it=pfde_VECT.begin(); 1485 vector< pf<gen> >::const_iterator itend=pfde_VECT.end(); 1486 vector< pf<gen> > intdecomp,finaldecomp; 1487 for (;it!=itend;++it){ 1488 pf<gen> single(intreduce_pf(*it,intdecomp,true)); 1489 // Now final factorization for single.den, 1490 // then compute single.num/single.den'(root) for roots with im>0 1491 // this is the residue 1492 // Example 1/(x^4+1) roots in C^+: exp(i*pi/4), exp(3*i*pi/4), 1493 // num/den'=1/4/x^3=-x/4 -> -1/4*exp(i*pi/4)-1/4*exp(3*i*pi/4) 1494 // -> -1/2*sin(pi/4)*i [*2*i*pi -> sqrt(2)/2*pi] 1495 vden.clear(); 1496 gen extra_div=1; 1497 factor(single.den,p_content,vden,false,false,false,1,extra_div); 1498 partfrac(single.num,single.den,vden,finaldecomp,temp,tmp); 1499 } 1500 it=finaldecomp.begin(); 1501 itend=finaldecomp.end(); 1502 gen lnpart(0),deuxaxplusb,sqrtdelta; 1503 polynome a(s),b(s),c(s); 1504 polynome d(s),E(s),lnpartden(s); 1505 polynome delta(s),atannum(s),alpha(s); 1506 for (;it!=itend;++it){ 1507 int deg=it->fact.lexsorted_degree(); 1508 // polynome & itnum=it->num; 1509 // polynome & itden=it->den; 1510 gen Delta; 1511 switch (deg) { 1512 case 1: // 1st order 1513 value=undef; 1514 return true; 1515 case 2: // 2nd order 1516 findabcdelta(it->fact,a,b,c,delta); 1517 Delta=r2e(delta,lprime,contextptr); 1518 if (is_positive(Delta,contextptr)){ 1519 value=undef; 1520 return true; 1521 } 1522 alpha=(it->den/it->fact).trunc1()*a*gen(2); 1523 findde(it->num,d,E); 1524 atannum=a*E*gen(2)-b*d; 1525 atannum=atannum*gen(2); 1526 simplify(atannum,alpha); 1527 sqrtdelta=normalize_sqrt(sqrt(-Delta,contextptr),contextptr); 1528 value += rdiv(r2e(atannum,lprime,contextptr),(r2e(alpha,lprime,contextptr))*sqrtdelta,contextptr); 1529 break; 1530 default: // divide a*it->num =b*it->den.derivative()+c 1531 it->num.TPseudoDivRem(it->den.derivative(),b,c,a); 1532 // remaining pf 1533 if (!c.coord.empty()){ 1534 vtmp=polynome2poly1(a*it->den,1); 1535 if (!integrate_deno_length_2(c,vtmp,l,lprime,value,true,2/* no step info*/,contextptr)) 1536 return false; 1537 } 1538 break ; 1539 } 1540 } 1541 value=ratnormal(value,contextptr)*cst_pi; 1542 return true; 1543 } 1544 integrate_rational_end(vector<pf<gen>>::iterator & it,vector<pf<gen>>::const_iterator & itend,const gen & x,const gen & xvar,const vecteur & l,const vecteur & lprime,const polynome & ipnum,const polynome & ipden,const gen & ratpart,gen & remains_to_integrate,int intmode,GIAC_CONTEXT)1545 static gen integrate_rational_end(vector< pf<gen> >::iterator & it,vector< pf<gen> >::const_iterator & itend,const gen & x,const gen & xvar,const vecteur & l,const vecteur & lprime,const polynome & ipnum,const polynome & ipden,const gen & ratpart,gen & remains_to_integrate,int intmode,GIAC_CONTEXT){ 1546 gen lnpart(0),deuxaxplusb,sqrtdelta; 1547 int s=ipnum.dim; 1548 polynome a(s),b(s),c(s); 1549 polynome d(s),E(s),lnpartden(s); 1550 polynome delta(s),atannum(s),alpha(s); 1551 bool uselog; 1552 remains_to_integrate=0; 1553 for (;it!=itend;++it){ 1554 int deg=it->fact.lexsorted_degree(); 1555 // polynome & itnum=it->num; 1556 // polynome & itden=it->den; 1557 gen Delta; 1558 switch (deg) { 1559 case 1: // 1st order 1560 lnpart=lnpart+rdiv(r2e(it->num,l,contextptr),r2e(firstcoeff(it->den),l,contextptr),contextptr)*lnabs2(r2e(it->fact,l,contextptr),xvar,contextptr); 1561 break; 1562 case 2: // 2nd order 1563 findabcdelta(it->fact,a,b,c,delta); 1564 Delta=r2e(delta,lprime,contextptr); 1565 uselog=is_positive(Delta,contextptr); 1566 alpha=(it->den/it->fact).trunc1()*a*gen(2); 1567 findde(it->num,d,E); 1568 atannum=a*E*gen(2)-b*d; 1569 // ln part d/alpha*ln(fact) 1570 lnpartden=alpha; 1571 simplify(d,lnpartden); 1572 lnpart=lnpart+rdiv(r2e(d,lprime,contextptr),r2e(lnpartden,lprime,contextptr),contextptr)*gen(uselog?lnabs2(r2e(it->fact,l,contextptr),xvar,contextptr):symbolic(at_ln,r2e(it->fact,l,contextptr))); 1573 // atan or _FUNCnd ln part 1574 deuxaxplusb=r2e(it->fact.derivative(),l,contextptr); 1575 if (uselog){ 1576 sqrtdelta=normalize_sqrt(sqrt(Delta,contextptr),contextptr); 1577 simplify(atannum,alpha); 1578 lnpart=lnpart+rdiv(r2e(atannum,lprime,contextptr),(r2e(alpha,lprime,contextptr))*sqrtdelta,contextptr)*lnabs2(rdiv(deuxaxplusb-sqrtdelta,deuxaxplusb+sqrtdelta,contextptr),xvar,contextptr); 1579 } 1580 else { 1581 vecteur v=solve(x*x+Delta,x,0,contextptr); 1582 if (v.size()==2 && !is_undef(v[0]) && !is_undef(v[1])){ 1583 if (is_positive(-v[0],contextptr)) 1584 sqrtdelta=v[1]; 1585 else 1586 sqrtdelta=v[0]; 1587 } 1588 else 1589 sqrtdelta=normalize_sqrt(sqrt(-Delta,contextptr),contextptr); 1590 atannum=atannum*gen(2); 1591 simplify(atannum,alpha); 1592 gen tmpatan=ratnormal(rdiv(deuxaxplusb,sqrtdelta,contextptr),contextptr); 1593 gen residue; 1594 if (tmpatan.is_symb_of_sommet(at_tan)) 1595 tmpatan=tmpatan._SYMBptr->feuille; 1596 else { 1597 // avoid floor if possible 1598 // atan(beta*tan(theta)+gamma)+floor() for beta>0 and gamma>-1 1599 // -> atan( cos(theta)*((beta-1)*sin(theta)+gamma*cos(theta))/ 1600 // (cos(theta)^2+beta*sin(theta)^2+gamma*sin(theta)*cos()) ) 1601 gen beta,gamma; 1602 if ( //0 && 1603 xvar.is_symb_of_sommet(at_tan) && is_linear_wrt(tmpatan,xvar,beta,gamma,contextptr) && is_strictly_greater(4*beta,gamma*gamma,contextptr) ){ 1604 gen argtan=ratnormal(2*xvar._SYMBptr->feuille,contextptr); 1605 gen si=symbolic(at_sin,argtan),ci=symbolic(at_cos,argtan); 1606 tmpatan=symbolic(at_atan,ratnormal(((beta-1)*si+gamma*(1+ci))/(1+beta+gamma*si+(1-beta)*ci),contextptr)); 1607 residue=xvar._SYMBptr->feuille; 1608 } 1609 else { 1610 tmpatan=atan(tmpatan,contextptr); 1611 if (xvar.is_symb_of_sommet(at_tan)){ 1612 if (do_lnabs(contextptr)){ 1613 // add residue 1614 residue=r2e(it->fact.derivative().derivative(),l,contextptr); 1615 residue=cst_pi*sign(residue,contextptr)*_floor((xvar._SYMBptr->feuille/cst_pi+plus_one_half),contextptr); 1616 } 1617 } 1618 else { 1619 // if xvar has a singularity at 0 e.g. xvar =x+1/x or x-1/x, 1620 // add the residue at 0 1621 if (xvar.type!=_IDNT){ 1622 // replacing tmpatan by atan(inv(tmpatan)) would avoid residue for int((x^2+1)/(x^4+3x^2+1)); but then it would not be continuous at 1 and -1 1623 residue=ratnormal(limit(tmpatan,*x._IDNTptr,0,-1,contextptr)-limit(tmpatan,*x._IDNTptr,0,1,contextptr),contextptr); 1624 residue=residue*sign(x,contextptr)/2; 1625 } 1626 } 1627 } 1628 } 1629 if (!angle_radian(contextptr)){ 1630 if (angle_degree(contextptr)) 1631 tmpatan=tmpatan*deg2rad_e; 1632 //grad 1633 else 1634 tmpatan = tmpatan*grad2rad_e; 1635 } 1636 tmpatan += residue; 1637 lnpart=lnpart+rdiv(r2e(atannum,lprime,contextptr),(r2e(alpha,lprime,contextptr))*sqrtdelta,contextptr)*tmpatan; 1638 } // end else uselof 1639 break; 1640 default: // divide a*it->num =b*it->den.derivative()+c 1641 it->num.TPseudoDivRem(it->den.derivative(),b,c,a); 1642 // remaining pf 1643 if (!c.coord.empty()){ 1644 vecteur vtmp=polynome2poly1(a*it->den,1); 1645 if (!integrate_deno_length_2(c,vtmp,l,lprime,lnpart,false,intmode,contextptr)) 1646 remains_to_integrate += r2sym(vector< pf<gen> >(1,pf<gen>(c,a*it->den,it->fact,1)),l,contextptr); 1647 } 1648 // extract log part b/a*ln[fact] 1649 simplify(b,a); 1650 if (!is_zero(b)) 1651 lnpart=lnpart+rdiv(r2e(b,l,contextptr),r2e(a,l,contextptr),contextptr)*lnabs(r2e(it->fact,l,contextptr),contextptr); 1652 break ; 1653 } 1654 } 1655 return rdiv(r2e(ipnum.integrate(),l,contextptr),r2e(ipden,l,contextptr),contextptr)+ratpart+lnpart; 1656 } 1657 1658 // integration of a rational fraction integrate_rational(const gen & e,const gen & x,gen & remains_to_integrate,gen & xvar,int intmode,GIAC_CONTEXT)1659 static gen integrate_rational(const gen & e, const gen & x, gen & remains_to_integrate,gen & xvar,int intmode,GIAC_CONTEXT){ 1660 if (x.type!=_IDNT) return gensizeerr(contextptr); // see limit 1661 if (has_num_coeff(e)){ 1662 gen ee=exact(e,contextptr); 1663 if (!has_num_coeff(ee)){ 1664 ee=integrate_rational(ee,x,remains_to_integrate,xvar,intmode,contextptr); 1665 ee=evalf(ee,1,contextptr); 1666 remains_to_integrate=evalf(remains_to_integrate,1,contextptr); 1667 return ee; 1668 } 1669 } 1670 const vecteur & varx=lvarx(e,x); 1671 int varxs=int(varx.size()); 1672 if (!varxs){ 1673 remains_to_integrate=zero; 1674 return e*xvar; 1675 } 1676 if ( (varxs>1) || (varx.front()!=x) ) { 1677 remains_to_integrate = e; 1678 return zero; 1679 } 1680 vecteur l; 1681 l.push_back(x); // insure x is the main var 1682 l=vecteur(1,l); 1683 alg_lvar(e,l); 1684 vecteur l_orig=l; 1685 int s=int(l.front()._VECTptr->size()); 1686 if (!s){ 1687 l.erase(l.begin()); 1688 s=int(l.front()._VECTptr->size()); 1689 } 1690 if (!s) 1691 return gensizeerr(contextptr); 1692 vecteur lprime(l); 1693 if (lprime.front().type!=_VECT) return gensizeerr(gettext("in integrate_rational")); 1694 lprime.front()=cdr_VECT(*(lprime.front()._VECTptr)); 1695 gen r=e2r(e,l,contextptr); 1696 // cout << "Int " << r << '\n'; 1697 gen r_num,r_den; 1698 fxnd(r,r_num,r_den); 1699 if (r_num.type==_EXT){ 1700 remains_to_integrate=e; 1701 return zero; 1702 } 1703 if (r_den.type!=_POLY){ 1704 l.front()._VECTptr->front()=xvar; 1705 if (r_num.type==_POLY) 1706 return rdiv(r2e(r_num._POLYptr->integrate(),l,contextptr),r2sym(r_den,l,contextptr),contextptr); 1707 else 1708 return e*xvar; 1709 } 1710 polynome den(*r_den._POLYptr),num(s); 1711 if (r_num.type==_POLY) 1712 num=*r_num._POLYptr; 1713 else 1714 num=polynome(r_num,s); 1715 // cyclotomic-like polys 1716 vecteur vtmp; 1717 if (den.coord.size()==2 && den.lexsorted_degree()!=1 && num.lexsorted_degree() < den.lexsorted_degree() && den.coord.back().index.is_zero() && xvar.type==_IDNT){ 1718 polynome2poly1(den,1,vtmp); 1719 r=0; 1720 if (!integrate_deno_length_2(num,vtmp,l,lprime,r,false,intmode,contextptr)) 1721 remains_to_integrate=e; 1722 return r; 1723 } 1724 // check for a t=x^aa change of variable: a divides deg(num)+1-deg(den) 1725 // as well as all differences of degrees in the poly num and den 1726 int den_deg=den.lexsorted_degree(),num_deg=num.lexsorted_degree(); 1727 int aa=num_deg+1-den_deg,precedent,actuel; 1728 vector< monomial<gen> > ::const_iterator num_it=num.coord.begin(),num_itend=num.coord.end(); 1729 if (num_itend-num_it>1){ 1730 precedent=num_it->index.front(); 1731 ++num_it; 1732 for (;num_it!=num_itend;++num_it){ 1733 actuel=num_it->index.front(); 1734 aa=gcd(aa,actuel-precedent); 1735 precedent=actuel; 1736 } 1737 } 1738 num_it=den.coord.begin(),num_itend=den.coord.end(); 1739 if (num_itend-num_it>1){ 1740 precedent=num_it->index.front(); 1741 ++num_it; 1742 for (;num_it!=num_itend;++num_it){ 1743 actuel=num_it->index.front(); 1744 aa=gcd(aa,actuel-precedent); 1745 precedent=actuel; 1746 } 1747 } 1748 if (!aa) 1749 aa=den_deg; 1750 if (aa>1){ // Apply 1751 if ( (intmode & 2)==0) 1752 gprintf(step_ratfracpow,gettext("Integrate rational fraction %gen, change of variable %gen"),makevecteur(e,symb_equal(x,symb_pow(x,aa))),contextptr); 1753 int k=0; 1754 k=den_deg % aa; 1755 // shift num and den by x^k 1756 index_t k1(num.dim); 1757 k1.front()=k+1; 1758 num=(num.shift(k1)).dividedegrees(aa); 1759 index_t ka(num.dim); 1760 ka.front()=k+aa; 1761 den=gen(aa)*(den.shift(ka)).dividedegrees(aa); 1762 if (!(aa%2) && xvar.is_symb_of_sommet(at_tan)){ 1763 // t=tan(x)^2: c=cos(2x)=(1-t^2)/(1+t^2) -> t^2=(1-c)/(1+c) 1764 xvar=symbolic(at_cos,ratnormal(2*xvar._SYMBptr->feuille,contextptr)); 1765 xvar=(1-xvar)/(1+xvar); 1766 aa/=2; 1767 } 1768 xvar=pow(xvar,aa); 1769 return integrate_rational(r2e(fraction(num,den),l,contextptr),x,remains_to_integrate,xvar,intmode,contextptr); 1770 } 1771 int den_val=den.valuation(0),num_val=num.valuation(0); 1772 if (den_deg+den_val==num_deg+num_val+2){ 1773 // now detect pattern that simplifies trig fraction integration 1774 /* cos is already detected by x^aa above with aa=2 1775 * 1776 * sin: if the fraction, including dt, is invariant by t->v=1/t 1777 * e.g (1-t^2)/(1+t^2)^2 dt = v^2(v^2-1)/(v^2+1)^2*( -1/v^2) dv 1778 * or [equivalent] tF(t) must change sign 1779 * let u=t+1/t, du=(1-1/t^2)dt, F(t)dt= F(t) * t^2/(t^2-1) du 1780 * e.g. t^2/(1+t^2)^2 du 1781 * N/(t^2-1) and D must be symm 1782 * 1783 * tan: if the fraction, including dt, is invariant by t->-1/t 1784 * u=t-1/t, du=(1+1/t^2)dt, F(t)dt= F(t) * t^2/(t^2+1) du 1785 * N/(t^2+1) and D must be antism. 1786 */ 1787 vecteur Nsave,Dsave,N,D,test(makevecteur(1,0,-1)),q,r; 1788 polynome2poly1(num,1,N); 1789 if (num_val && num_val<signed(N.size())) 1790 N=vecteur(N.begin(),N.begin()+N.size()-num_val); 1791 polynome2poly1(den,1,D); 1792 if (den_val && den_val<signed(D.size())) 1793 D=vecteur(D.begin(),D.begin()+D.size()-den_val); 1794 Nsave=N; Dsave=D; 1795 bool type=false; 1796 if (N.size()>=test.size() && DivRem(N,test,0,q,r) && r.empty()){ 1797 r=D; 1798 if (is_symmetric(q,N,true)*is_symmetric(r,D,true)==1){ 1799 // yes! 1800 type = (xvar.type==_SYMB) || D.size()>1; 1801 } 1802 } 1803 if (!type) { 1804 N=Nsave; D=Dsave; 1805 } 1806 if (!type && D.size()>=test.size() && DivRem(D,test,0,q,r) && r.empty()){ 1807 r=N; 1808 if (is_symmetric(r,N,true)*is_symmetric(q,D,true)==1){ 1809 // yes! 1810 type = (xvar.type==_SYMB) || D.size()>1; 1811 if (type) 1812 D=operator_times(D,makevecteur(1,0,-4),0); 1813 } 1814 } 1815 if (type){ 1816 if (xvar.is_symb_of_sommet(at_tan)){ 1817 q=N; r=D; 1818 xtoinvx(2,q,r,N,D,true); 1819 xvar=symbolic(at_sin,ratnormal(2*xvar._SYMBptr->feuille,contextptr)); 1820 } 1821 else { 1822 xvar=xvar+inv(xvar,contextptr); 1823 } 1824 num=poly12polynome(N,1,num.dim); 1825 den=poly12polynome(D,1,den.dim); 1826 return integrate_rational(r2e(fraction(num,den),l,contextptr),x,remains_to_integrate,xvar,intmode,contextptr); 1827 } 1828 test[2]=1; 1829 N=Nsave; D=Dsave; 1830 if (N.size()>=test.size() && DivRem(N,test,0,q,r) && r.empty()){ 1831 r=D; 1832 if (is_symmetric(q,N,false)*is_symmetric(r,D,false)==1){ 1833 // yes! 1834 type = (xvar.type==_SYMB) || D.size()>1; 1835 } 1836 } 1837 if (!type){ 1838 N=Nsave; D=Dsave; 1839 } 1840 if (!type && D.size()>=test.size() && DivRem(D,test,0,q,r) && r.empty()){ 1841 r=N; 1842 if (is_symmetric(r,N,false)*is_symmetric(q,D,false)==1){ 1843 // yes! 1844 type = (xvar.type==_SYMB && xvar._SYMBptr->sommet!=at_tan) || D.size()>1; 1845 if (type) 1846 D=operator_times(D,makevecteur(1,0,4),0); 1847 } 1848 } 1849 if (type){ 1850 if (xvar.is_symb_of_sommet(at_tan)){ 1851 q=N; r=D; 1852 xtoinvx(-2,q,r,N,D,true); 1853 xvar=symbolic(at_tan,ratnormal(2*xvar._SYMBptr->feuille,contextptr)); 1854 } 1855 else 1856 xvar=xvar-inv(xvar,contextptr); 1857 num=poly12polynome(N,1); 1858 den=poly12polynome(D,1); 1859 for (;den.dim!=num.dim;){ 1860 vector< monomial<gen> >::iterator dt,dtend; 1861 if (den.dim<num.dim){ 1862 dt=den.coord.begin(); 1863 dtend=den.coord.end(); 1864 ++den.dim; 1865 } 1866 else { 1867 dt=num.coord.begin(); 1868 dtend=num.coord.end(); 1869 ++num.dim; 1870 } 1871 for (;dt!=dtend;++dt){ 1872 index_t::const_iterator it=dt->index.begin(),itend=dt->index.end(); 1873 index_m new_i(itend-it+1); 1874 index_t::iterator newit=new_i.begin(); 1875 for (;it!=itend;++newit,++it) 1876 *newit=*it; 1877 *newit=0; 1878 dt->index=new_i; 1879 } 1880 } 1881 simplify(num,den); 1882 return integrate_rational(r2e(fraction(num,den),l,contextptr),x,remains_to_integrate,xvar,intmode,contextptr); 1883 } 1884 } 1885 if ( (intmode & 2)==0) 1886 gprintf(step_ratfracsqrfree,gettext("Integrate rational fraction %gen"),makevecteur(_sqrfree(e,contextptr)),contextptr); 1887 vecteur lf=*l.front()._VECTptr; 1888 lf.front()=xvar; 1889 l.front()=lf; 1890 // l.front()._VECTptr->front()=xvar; 1891 polynome p_content(lgcd(den)); 1892 factorization vden(sqff(den/p_content)); // first square-free factorization 1893 vector< pf<gen> > pfdecomp; 1894 polynome ipnum(s),ipden(s),temp(s),tmp(s); 1895 partfrac(num,den,vden,pfdecomp,ipnum,ipden); 1896 vector< pf<gen> >::iterator it=pfdecomp.begin(); 1897 vector< pf<gen> >::const_iterator itend=pfdecomp.end(); 1898 vector< pf<gen> > intdecomp,finaldecomp; 1899 for (;it!=itend;++it){ 1900 if (it->den.lexsorted_degree()==0) 1901 continue; 1902 const pf<gen> & single =intreduce_pf(*it,intdecomp); 1903 if ( (it->mult>1) && (intmode & 2)==0){ 1904 gen fact1=pow(r2e(it->fact,l,contextptr),it->mult,contextptr); 1905 gen fact2=it->den/pow(it->fact,it->mult); 1906 gprintf(step_ratfrachermite,gettext("Partial fraction %gen -> Hermite reduction -> integrate squarefree part %gen"),makevecteur(inv(r2sym(fact2,l,contextptr),contextptr)*r2e(it->num,l,contextptr)/fact1,r2e(single.num,l,contextptr)/r2e(single.den,l,contextptr)),contextptr); 1907 } 1908 // factor(single.den,p_content,vden,false,withsqrt(contextptr),complex_mode(contextptr)); 1909 gen extra_div=1; 1910 factor(single.den,p_content,vden,false,false,false,1,extra_div); 1911 partfrac(single.num,single.den,vden,finaldecomp,temp,tmp); 1912 } 1913 if ( (intmode & 2)==0) 1914 gprintf(step_ratfracfinal,gettext("Partial fraction integration of %gen"),makevecteur(r2sym(finaldecomp,l_orig,contextptr)),contextptr); 1915 it=finaldecomp.begin(); 1916 itend=finaldecomp.end(); 1917 gen ratpart=r2sym(intdecomp,l,contextptr); 1918 // should remove constants in ratpart 1919 gen tmp1=_fxnd(ratpart,contextptr); 1920 if (xvar.type==_IDNT && tmp1.type==_VECT && tmp1._VECTptr->size()==2){ 1921 gen tmp2=_quorem(makesequence(tmp1._VECTptr->front(),tmp1._VECTptr->back(),xvar),contextptr); 1922 if (tmp2.type==_VECT && tmp2._VECTptr->size()==2){ 1923 gen q=tmp2._VECTptr->front(),r=tmp2._VECTptr->back(); 1924 gen C=subst(q,xvar,0,false,contextptr); 1925 if (!is_zero(C)){ 1926 q=ratnormal(q-C,contextptr); 1927 tmp1=tmp1._VECTptr->back(); 1928 tmp1=_collect(tmp1,contextptr); 1929 tmp1=r*inv(tmp1,contextptr); 1930 ratpart=q+tmp1; 1931 } 1932 } 1933 } 1934 return integrate_rational_end(it,itend,x,xvar,l,lprime,ipnum,ipden,ratpart,remains_to_integrate,intmode,contextptr); 1935 } 1936 1937 // integration of e when linear operations have been applied xln_x(const gen & x,GIAC_CONTEXT)1938 static gen xln_x(const gen & x,GIAC_CONTEXT){ 1939 return x*ln(x,contextptr)-x; 1940 } 1941 int_exp(const gen & x,GIAC_CONTEXT)1942 static gen int_exp(const gen & x,GIAC_CONTEXT){ 1943 return exp(x,contextptr); 1944 } 1945 int_sinh(const gen & x,GIAC_CONTEXT)1946 static gen int_sinh(const gen & x,GIAC_CONTEXT){ 1947 return cosh(x,contextptr); 1948 } 1949 int_cosh(const gen & x,GIAC_CONTEXT)1950 static gen int_cosh(const gen & x,GIAC_CONTEXT){ 1951 return sinh(x,contextptr); 1952 } 1953 int_sin(const gen & x,GIAC_CONTEXT)1954 static gen int_sin(const gen & x,GIAC_CONTEXT){ 1955 if (angle_radian(contextptr)) 1956 return -cos(x,contextptr); 1957 else if(angle_degree(contextptr)) 1958 return -cos(x,contextptr)*gen(180)/cst_pi; 1959 //grad 1960 else 1961 return -cos(x, contextptr)*gen(200) / cst_pi; 1962 } 1963 int_cos(const gen & x,GIAC_CONTEXT)1964 static gen int_cos(const gen & x,GIAC_CONTEXT){ 1965 if (angle_radian(contextptr)) 1966 return sin(x,contextptr); 1967 else if(angle_degree(contextptr)) 1968 return sin(x,contextptr)*gen(180)/cst_pi; 1969 //grad 1970 else 1971 return sin(x, contextptr)*gen(200) / cst_pi; 1972 } 1973 int_tan(const gen & x,GIAC_CONTEXT)1974 static gen int_tan(const gen & x,GIAC_CONTEXT){ 1975 gen g=-lnabs(cos(x,contextptr),contextptr); 1976 if (angle_radian(contextptr)) 1977 return g; 1978 else if(angle_degree(contextptr)) 1979 return g*gen(180)/cst_pi; 1980 //grad 1981 else 1982 return g*gen(200) / cst_pi; 1983 } 1984 int_tanh(const gen & x,GIAC_CONTEXT)1985 static gen int_tanh(const gen & x,GIAC_CONTEXT){ 1986 return -ln(cosh(x,contextptr),contextptr); 1987 } 1988 int_asin(const gen & x,GIAC_CONTEXT)1989 static gen int_asin(const gen & x,GIAC_CONTEXT){ 1990 if (angle_radian(contextptr)) 1991 return x*asin(x,contextptr)+sqrt(1-pow(x,2),contextptr); 1992 else if(angle_degree(contextptr)) 1993 return x*asin(x,contextptr)*deg2rad_e+sqrt(1-pow(x,2),contextptr); 1994 //grad 1995 else 1996 return x*asin(x, contextptr)*grad2rad_e + sqrt(1 - pow(x, 2), contextptr); 1997 } 1998 int_acos(const gen & x,GIAC_CONTEXT)1999 static gen int_acos(const gen & x,GIAC_CONTEXT){ 2000 if (angle_radian(contextptr)) 2001 return x*acos(x,contextptr)-sqrt(1-pow(x,2),contextptr); 2002 else if(angle_degree(contextptr)) 2003 return x*acos(x,contextptr)*deg2rad_e-sqrt(1-pow(x,2),contextptr); 2004 //grad 2005 else 2006 return x*acos(x, contextptr)*grad2rad_e - sqrt(1 - pow(x, 2), contextptr); 2007 } 2008 int_atan(const gen & x,GIAC_CONTEXT)2009 static gen int_atan(const gen & x,GIAC_CONTEXT){ 2010 if (angle_radian(contextptr)) 2011 return x*atan(x,contextptr)-rdiv(ln(pow(x,2)+1,contextptr),plus_two,contextptr); 2012 else if(angle_degree(contextptr)) 2013 return x*atan(x,contextptr)*deg2rad_e-rdiv(ln(pow(x,2)+1,contextptr),plus_two,contextptr); 2014 //grad 2015 else 2016 return x*atan(x, contextptr)*grad2rad_e - rdiv(ln(pow(x, 2) + 1, contextptr), plus_two, contextptr); 2017 } 2018 int_asinh(const gen & x,GIAC_CONTEXT)2019 static gen int_asinh(const gen & x,GIAC_CONTEXT){ 2020 return x*asinh(x,contextptr)-sqrt(pow(x,2)+1,contextptr); 2021 } 2022 int_acosh(const gen & x,GIAC_CONTEXT)2023 static gen int_acosh(const gen & x,GIAC_CONTEXT){ 2024 return x*acosh(x,contextptr)-sqrt(pow(x,2)-1,contextptr); 2025 } 2026 int_atanh(const gen & x,GIAC_CONTEXT)2027 static gen int_atanh(const gen & x,GIAC_CONTEXT){ 2028 return x*atan(x,contextptr)-rdiv(ln(abs(pow(x,2)-1,contextptr),contextptr),plus_two,contextptr); 2029 } 2030 2031 static const gen_op_context primitive_tab_primitive[]={int_sin,int_cos,int_tan,int_exp,int_sinh,int_cosh,int_tanh,int_asin,int_acos,int_atan,xln_x,int_asinh,int_acosh,int_atanh}; 2032 2033 #if 0 2034 static void insure_real_deno(gen & n,gen & d,GIAC_CONTEXT){ 2035 gen i=im(d,contextptr),c=conj(d,contextptr); 2036 if (!is_zero(i)){ 2037 n=n*c; 2038 d=d*c; 2039 } 2040 } 2041 #endif 2042 in_is_rewritable_as_f_of(const gen & fu,const gen & u,gen & fx,const gen & gen_x,GIAC_CONTEXT)2043 static bool in_is_rewritable_as_f_of(const gen & fu,const gen & u,gen & fx,const gen & gen_x,GIAC_CONTEXT){ 2044 if (fu.type==_VECT){ 2045 vecteur res; 2046 const_iterateur it=fu._VECTptr->begin(),itend=fu._VECTptr->end(); 2047 gen tmp; 2048 for (;it!=itend;++it){ 2049 if (!is_rewritable_as_f_of(*it,u,tmp,gen_x,contextptr)) 2050 return false; 2051 res.push_back(tmp); 2052 } 2053 fx=gen(res,fu.subtype); 2054 return true; 2055 } 2056 if (fu.type==_IDNT){ 2057 if (fu!=gen_x){ 2058 fx=fu; 2059 return true; 2060 } 2061 return false; 2062 } 2063 if (fu.type!=_SYMB){ 2064 fx=fu; 2065 return true; 2066 } 2067 // symbolic 2068 if (fu==u){ 2069 fx=gen_x; 2070 return true; 2071 } 2072 // decompose 2073 unary_function_ptr s=fu._SYMBptr->sommet; 2074 gen f=fu._SYMBptr->feuille,tmpfx; 2075 if (in_is_rewritable_as_f_of(f,u,tmpfx,gen_x,contextptr)){ 2076 fx=symbolic(s,tmpfx); 2077 return true; 2078 } 2079 // try special treatment for integral powers 2080 int fexp,uexp; 2081 if ( (u.type!=_SYMB) || (s!=at_pow) || (f._VECTptr->back().type!=_INT_) ) 2082 return false; 2083 fexp=f._VECTptr->back().val; 2084 if ( (u._SYMBptr->sommet==at_pow) && (u._SYMBptr->feuille._VECTptr->back().type==_INT_) && (u._SYMBptr->feuille._VECTptr->front()==f._VECTptr->front()) ){ 2085 uexp=u._SYMBptr->feuille._VECTptr->back().val; 2086 if (fexp%uexp) 2087 return false; 2088 fx=pow(gen_x,fexp/uexp); 2089 return true; 2090 } 2091 // trigonometric fcns to an even power 2092 f=f._VECTptr->front(); 2093 if ( (fexp %2) || (f.type!=_SYMB) ) 2094 return false; 2095 fexp=fexp/2; 2096 int ftrig=equalposcomp(primitive_tab_op,f._SYMBptr->sommet); 2097 if (!ftrig) 2098 return false; 2099 int utrig=equalposcomp(primitive_tab_op,u._SYMBptr->sommet); 2100 if (utrig==2 && u._SYMBptr->feuille==2*f._SYMBptr->feuille){ 2101 // sin^2/cos^2/tan^2 in terms of cos(2x) 2102 switch (ftrig){ 2103 case 1: // sin 2104 fx=(1-gen_x)/2; 2105 return true; 2106 case 2: // cos 2107 fx=(1+gen_x)/2; 2108 return true; 2109 case 3: 2110 fx=(1-gen_x)/(1+gen_x); 2111 return true; 2112 } 2113 } 2114 if (!utrig || f._SYMBptr->feuille!=u._SYMBptr->feuille) 2115 return false; 2116 switch (ftrig){ 2117 case 1: // sin 2118 switch (utrig){ 2119 case 2: // sin^2=1-cos^2 2120 fx=pow(1-pow(gen_x,2),fexp); 2121 return true; 2122 case 3: // sin^2=1-1/(tan^2+1) 2123 fx=pow(1-inv(pow(gen_x,2)+1,contextptr),fexp); 2124 return true; 2125 default: 2126 return false; 2127 } 2128 case 2: // cos 2129 switch (utrig){ 2130 case 1: // cos^2=1-sin^2 2131 fx=pow(1-pow(gen_x,2),fexp); 2132 return true; 2133 case 3: // cos^2=1/(tan^2+1) 2134 fx=pow(pow(gen_x,2)+1,-fexp); 2135 return true; 2136 default: 2137 return false; 2138 } 2139 case 3: // tan 2140 switch (utrig){ 2141 case 1: // tan^2=1/(1-sin^2)-1 2142 fx=pow(inv(1-pow(gen_x,2),contextptr)-1,fexp); 2143 return true; 2144 case 2: // tan^2=1/cos^2-1 2145 fx=pow(pow(gen_x,-2)-1,fexp); 2146 return true; 2147 default: 2148 return false; 2149 } 2150 } 2151 return false; 2152 } 2153 2154 // try to rewrite fu(x), function of x as a fonction of u(x), if possible 2155 // return fx(x) such that fu(x)=fx(u(x)) 2156 // FIXME: should detect u=pow(.,inv(n)) with n integer is_rewritable_as_f_of(const gen & fu,const gen & u,gen & fx,const gen & gen_x,GIAC_CONTEXT)2157 bool is_rewritable_as_f_of(const gen & fu,const gen & u,gen & fx,const gen & gen_x,GIAC_CONTEXT){ 2158 gen a,b; 2159 if (is_linear_wrt(u,gen_x,a,b,contextptr)){ 2160 fx=complex_subst(fu,gen_x,rdiv(gen_x-b,a,contextptr),contextptr); 2161 return false;// true? 2162 } 2163 // try first if u is a linear expression of something else 2164 if (u.type==_SYMB){ 2165 if (u._SYMBptr->sommet==at_neg){ 2166 gen tmpu=u._SYMBptr->feuille,tmpfx; 2167 if (!is_rewritable_as_f_of(fu,tmpu,tmpfx,gen_x,contextptr)) 2168 return false; 2169 fx=complex_subst(tmpfx,gen_x,-gen_x,contextptr); 2170 return true; 2171 } 2172 if (u._SYMBptr->sommet==at_pow){ 2173 gen tmpu=u._SYMBptr->feuille,tmpfx; 2174 if (tmpu.type==_VECT && tmpu._VECTptr->size()==2){ 2175 gen expo=inv(tmpu._VECTptr->back(),contextptr); 2176 tmpu=tmpu._VECTptr->front(); 2177 if (expo.type==_INT_){ 2178 if (is_linear_wrt(tmpu,gen_x,a,b,contextptr)){ 2179 fx=complex_subst(fu,gen_x,rdiv(pow(gen_x,expo,contextptr)-b,a,contextptr),contextptr); 2180 return true; 2181 } 2182 } 2183 } 2184 } 2185 gen alpha; 2186 vecteur non_constant; 2187 if (u._SYMBptr->sommet==at_prod ){ 2188 if (u._SYMBptr->feuille.type!=_VECT) 2189 return is_rewritable_as_f_of(fu,u._SYMBptr->feuille,fx,gen_x,contextptr); 2190 decompose_prod(*u._SYMBptr->feuille._VECTptr,gen_x,non_constant,alpha,true,contextptr); 2191 if (non_constant.empty()) return false; // setsizeerr(gettext("in is_rewritable_as_f_of_f")); 2192 if (!is_one(alpha)){ 2193 gen tmpu,tmpfx; 2194 tmpu=_prod(non_constant,contextptr); 2195 if (!is_rewritable_as_f_of(fu,tmpu,tmpfx,gen_x,contextptr)) 2196 return false; 2197 fx=complex_subst(tmpfx,gen_x,rdiv(gen_x,alpha,contextptr),contextptr); 2198 return true; 2199 } 2200 } 2201 if (u._SYMBptr->sommet==at_plus){ 2202 if (u._SYMBptr->feuille.type!=_VECT) 2203 return is_rewritable_as_f_of(fu,u._SYMBptr->feuille,fx,gen_x,contextptr); 2204 if (_is_polynomial(makesequence(fu,gen_x),contextptr)==1 && _is_polynomial(makesequence(u,gen_x),contextptr)==1){ 2205 gen FU=_symb2poly(makesequence(fu,gen_x),contextptr); 2206 gen U=_symb2poly(makesequence(u,gen_x),contextptr); 2207 if (FU.type==_VECT && U.type==_VECT){ 2208 vecteur vfu=*FU._VECTptr; 2209 vecteur vu=*U._VECTptr; 2210 int N=vfu.size()-1,M=vu.size()-1; 2211 vecteur vfx(N/M+1); 2212 for (;!vfu.empty();){ 2213 int n=vfu.size()-1,m=vu.size()-1; 2214 if (n % m) 2215 break; 2216 gen c=vfu[0]/pow(vu[0],n/m,contextptr); 2217 vfx[N/M-n/m]=c; 2218 vecteur vtmp; 2219 submodpoly(vfu,*_symb2poly(makesequence(c*pow(u,n/m),gen_x),contextptr)._VECTptr,vtmp); 2220 vfu=*normal(vtmp,contextptr)._VECTptr; 2221 trim(vfu,0); 2222 } 2223 if (vfu.empty()){ 2224 fx=_poly2symb(makesequence(vfx,gen_x),contextptr); 2225 return true; 2226 } 2227 } 2228 } 2229 decompose_plus(*u._SYMBptr->feuille._VECTptr,gen_x,non_constant,alpha,contextptr); 2230 if (non_constant.empty()) return false; // setsizeerr(gettext("in is_rewritable_as_f_of_f 2")); 2231 if (!is_zero(alpha)){ 2232 gen tmpu,tmpfx; 2233 tmpu=_plus(non_constant,contextptr); 2234 if (!is_rewritable_as_f_of(fu,tmpu,tmpfx,gen_x,contextptr)) 2235 return in_is_rewritable_as_f_of(fu,u,fx,gen_x,contextptr);; 2236 fx=complex_subst(tmpfx,gen_x,gen_x-alpha,contextptr); 2237 if (!has_i(fx)) // FIX for int(x^3/sqrt(1-x^2),x,-1,0); 2238 return true; 2239 } 2240 } 2241 } 2242 return in_is_rewritable_as_f_of(fu,u,fx,gen_x,contextptr); 2243 } 2244 firstcoefftrunc(const gen & e)2245 gen firstcoefftrunc(const gen & e){ 2246 if (e.type==_FRAC) 2247 return fraction(firstcoefftrunc(e._FRACptr->num),firstcoefftrunc(e._FRACptr->den)); 2248 if (e.type==_POLY) 2249 return firstcoeff(*e._POLYptr).trunc1(); 2250 return e; 2251 } 2252 2253 // special version of lvarx that does not remove cst powers lvarxpow(const gen & e,const gen & x)2254 vecteur lvarxpow(const gen &e,const gen & x){ 2255 const vecteur & v=lvar(e); 2256 vecteur res; 2257 vecteur::const_iterator it=v.begin(),itend=v.end(); 2258 for (;it!=itend;++it){ 2259 if (contains(*it,x)) 2260 res.push_back(*it); 2261 } 2262 // do lvar again to comprim the first arg of ^ 2263 return lvar(res); 2264 } 2265 invexptoexpneg(const gen & g,GIAC_CONTEXT)2266 gen invexptoexpneg(const gen& g,GIAC_CONTEXT){ 2267 if (g.type==_SYMB && g._SYMBptr->sommet==at_exp) 2268 return exp(-g._SYMBptr->feuille,contextptr); 2269 else 2270 return symb_inv(g); 2271 } 2272 integrate_gen_rem(const gen & e_orig,const gen & x_orig,gen & remains_to_integrate,GIAC_CONTEXT)2273 gen integrate_gen_rem(const gen & e_orig,const gen & x_orig,gen & remains_to_integrate,GIAC_CONTEXT){ 2274 if (x_orig.type!=_IDNT){ 2275 identificateur x(" x"); 2276 gen e=subst(e_orig,x_orig,x,false,contextptr); 2277 e=integrate_id_rem(e,x,remains_to_integrate,contextptr,0); 2278 remains_to_integrate=quotesubst(remains_to_integrate,x,x_orig,contextptr); 2279 return quotesubst(e,x,x_orig,contextptr); 2280 } 2281 return integrate_id_rem(e_orig,x_orig,remains_to_integrate,contextptr,0); 2282 } 2283 integrate_step0(gen & e,const gen & gen_x,vecteur & l1,vecteur & m1,gen & res,gen & remains_to_integrate,GIAC_CONTEXT,int intmode)2284 static bool integrate_step0(gen & e,const gen & gen_x,vecteur & l1,vecteur & m1,gen & res,gen & remains_to_integrate,GIAC_CONTEXT,int intmode){ 2285 const identificateur & id_x=*gen_x._IDNTptr; 2286 vecteur l2,m2,l3,l4; 2287 const_iterateur it=l1.begin(),itend=l1.end(); 2288 int i=0; 2289 for (;it!=itend;++it,++i){ 2290 gen tmp=it->_SYMBptr->feuille; 2291 identificateur tmpi(" s"+print_INT_(i)); 2292 l2.push_back(tmpi*tmp); 2293 l3.push_back(tmpi); 2294 l4.push_back(symbolic(at_sign,tmp)); 2295 } 2296 it=m1.begin(),itend=m1.end(); 2297 for (;it!=itend;++it,++i){ 2298 l1.push_back(*it); 2299 gen tmp=it->_SYMBptr->feuille; 2300 identificateur tmpi(" s"+print_INT_(i)); 2301 l2.push_back(tmpi); 2302 l3.push_back(tmpi); 2303 l4.push_back(*it); 2304 } 2305 *logptr(contextptr) << gettext("Warning, integration of abs or sign assumes constant sign by intervals (correct if the argument is real):\nCheck ") << l1 << '\n'; 2306 e=complex_subst(e,l1,l2,contextptr); 2307 res=integrate_id_rem(e,gen_x,remains_to_integrate,contextptr,intmode); 2308 gen resadd; 2309 if (is_undef(res)) return true; 2310 // check what happens when si==0 2311 for (int j=0;j<i;++j){ 2312 gen val=l4[j],a,b,r; 2313 if (val.is_symb_of_sommet(at_sign)){ 2314 gen val2=val._SYMBptr->feuille; 2315 if (val2.is_symb_of_sommet(at_sin) || val2.is_symb_of_sommet(at_tan)) 2316 val2=val2._SYMBptr->feuille; 2317 bool warn=true; 2318 if (is_linear_wrt(val2,gen_x,a,b,contextptr) && ((has_evalf(a,r,1,contextptr) && has_evalf(b,r,1,contextptr)) || lvar(res)==lidnt(res))){ 2319 warn=val._SYMBptr->feuille!=val2; 2320 r=-b/a; 2321 vecteur l5(l4); 2322 #if 1 2323 l5[j]=1; 2324 gen limsup=subst(res,l3,l5,false,contextptr); 2325 l5[j]=-1; 2326 gen liminf=subst(res,l3,l5,false,contextptr); 2327 #else 2328 l5[j]=1; 2329 bool dolim=l3.size()==1 && l5.size()==1 && l3.front().type==_IDNT; 2330 gen limsup=dolim?limit(res,*l3.front()._IDNTptr,l5.front(),0,contextptr):subst(res,l3,l5,false,contextptr); 2331 l5[j]=-1; 2332 gen liminf=dolim?limit(res,*l3.front()._IDNTptr,l5.front(),0,contextptr):subst(res,l3,l5,false,contextptr); 2333 #endif 2334 gen tmp=ratnormal((limit(liminf,id_x,r,-1,contextptr)-limit(limsup,id_x,r,1,contextptr))/2,contextptr)*val; 2335 if (is_undef(tmp) || is_inf(tmp)) 2336 *logptr(contextptr) << gettext("Unable to cancel step at ")+r.print(contextptr) + " of " << limsup << "-" << liminf << '\n'; 2337 else 2338 resadd += tmp; 2339 } 2340 if (warn) 2341 *logptr(contextptr) << gettext("Discontinuities at zeroes of ") << val._SYMBptr->feuille << " were not checked" << '\n'; 2342 } 2343 } 2344 remains_to_integrate=complex_subst(remains_to_integrate,l3,l4,contextptr); 2345 res=resadd+complex_subst(res,l3,l4,contextptr); 2346 return true; 2347 } 2348 detect_inv_trigln(gen & e,vecteur & rvar,const gen & gen_x,gen & res,gen & remains_to_integrate,bool additional_check,int intmode,GIAC_CONTEXT)2349 static bool detect_inv_trigln(gen & e,vecteur & rvar,const gen & gen_x,gen & res,gen & remains_to_integrate,bool additional_check,int intmode,GIAC_CONTEXT){ 2350 const_iterateur rvt=rvar.begin(),rvtend=rvar.end(); 2351 for (;rvt!=rvtend;++rvt){ 2352 if (rvt->type!=_SYMB) 2353 continue; 2354 int rvtt=equalposcomp(inverse_tab_op,rvt->_SYMBptr->sommet); 2355 if (!rvtt || rvtt==3 || rvtt==7) // exclude atan and atanh 2356 continue; 2357 rvtt=equalposcomp(primitive_tab_op,rvt->_SYMBptr->sommet); 2358 if (rvtt>7){ 2359 unary_function_ptr inverse_sommet=primitive_tab_op[rvtt-8]; 2360 gen feuille=rvt->_SYMBptr->feuille,a,b; 2361 if (!is_linear_wrt(feuille,gen_x,a,b,contextptr)) 2362 continue; 2363 if (additional_check){ 2364 // Additionaly check that e is polynomial wrt x 2365 identificateur tmpidnt(" t"); 2366 gen tmpcheck=subst(e,*rvt,tmpidnt,false,contextptr); 2367 vecteur vx2(rlvarx(tmpcheck,gen_x)); 2368 if ( vx2.size()>1) 2369 continue; 2370 if (vx2.size()){ 2371 lvar(tmpcheck,vx2); 2372 fraction ftemp=sym2r(tmpcheck,vx2,contextptr); 2373 if (ftemp.den.type==_POLY && ftemp.den._POLYptr->lexsorted_degree()) 2374 continue; 2375 } 2376 } 2377 // make the change of var ln[ax+b]=t -> x=rdiv(exp(t)-b,a) 2378 gen tmprem,tmpres,tmpe,xt,dxt,sqrtxt; 2379 xt=rdiv(symbolic(inverse_sommet,gen_x)-b,a,contextptr); 2380 dxt=derive(xt,gen_x,contextptr); 2381 if (is_undef(dxt)){ 2382 res=dxt; 2383 return true; 2384 } 2385 // should add sqrt(1-.^2) 2386 vecteur substin(makevecteur(gen_x,*rvt)); 2387 vecteur substout(makevecteur(xt,gen_x)); 2388 if ((rvtt==8 || rvtt==9)){ 2389 vecteur tmpv=lop(e,at_pow); 2390 for (unsigned tmpi=0;tmpi<tmpv.size();++tmpi){ 2391 gen tmpvi=tmpv[tmpi]._SYMBptr->feuille; 2392 if (tmpvi.type==_VECT && tmpvi._VECTptr->size()==2){ 2393 gen tmpvi0=tmpvi._VECTptr->front(); 2394 if (ratnormal(tmpvi0-1+pow(a*gen_x+b,2,contextptr),contextptr)==0){ 2395 substin.push_back(tmpv[tmpi]); 2396 substout.push_back(pow(symbolic(rvtt==8?at_cos:at_sin,gen_x),2*tmpvi._VECTptr->back(),contextptr)); 2397 } 2398 } 2399 } 2400 } 2401 tmpe=ratnormal(complex_subst(e,substin,substout,contextptr)*dxt,contextptr); 2402 if ( (intmode & 2)==0) 2403 gprintf(step_ratfracchgvar,gettext("Integrate %gen, change of variable %gen->%gen, new integral %gen"),makevecteur(e,gen_x,xt,tmpe),contextptr); 2404 tmpres=linear_integrate_nostep(tmpe,gen_x,tmprem,intmode,contextptr); 2405 if ( (intmode & 2)==0) 2406 gprintf(step_backsubst,gettext("Back substitution %gen->%gen in %gen"),makevecteur(gen_x,*rvt,tmpres),contextptr); 2407 remains_to_integrate=complex_subst(rdiv(tmprem,dxt,contextptr),gen_x,*rvt,contextptr); 2408 // replace tan(asin/2) or tan(acos/2) and cos(asin) and sin(acos) 2409 if ((rvtt==8 || rvtt==9) && has_op(tmpres,*at_tan)) 2410 tmpres=tan2sincos2(tmpres,contextptr); 2411 tmpres=_texpand(tmpres,contextptr); 2412 res=complex_subst(tmpres,substout,substin,contextptr); 2413 return true; 2414 } 2415 } 2416 return false; 2417 } 2418 integrate_id_rem(const gen & e_orig,const gen & gen_x,gen & remains_to_integrate,GIAC_CONTEXT)2419 gen integrate_id_rem(const gen & e_orig,const gen & gen_x,gen & remains_to_integrate,GIAC_CONTEXT){ 2420 return integrate_id_rem(e_orig,gen_x,remains_to_integrate,contextptr,0); 2421 } 2422 add_lnabs(const gen & g,GIAC_CONTEXT)2423 gen add_lnabs(const gen & g,GIAC_CONTEXT){ 2424 return symbolic(at_ln,abs(g,contextptr)); 2425 } 2426 surd2pow(const gen & e,vecteur & subst1,vecteur & subst2,GIAC_CONTEXT)2427 void surd2pow(const gen & e,vecteur & subst1,vecteur & subst2,GIAC_CONTEXT){ 2428 vecteur l1surd(lop(e,at_surd)); 2429 vecteur l2surd(l1surd); 2430 for (unsigned i=0;i<l1surd.size();++i){ 2431 gen & g=l2surd[i]; 2432 if (g._SYMBptr->feuille.type==_VECT && g._SYMBptr->feuille._VECTptr->size()==2){ 2433 vecteur gv=*g._SYMBptr->feuille._VECTptr; 2434 gv=makevecteur(gv[0],inv(gv[1],contextptr)); 2435 g=_pow(gen(gv,_SEQ__VECT),contextptr);//symbolic(at_pow,gen(gv,_SEQ__VECT)); 2436 } 2437 } 2438 vecteur l1NTHROOT(lop(e,at_NTHROOT)); 2439 vecteur l2NTHROOT(l1NTHROOT); 2440 for (unsigned i=0;i<l1NTHROOT.size();++i){ 2441 gen & g=l2NTHROOT[i]; 2442 if (g._SYMBptr->feuille.type==_VECT && g._SYMBptr->feuille._VECTptr->size()==2){ 2443 vecteur gv=*g._SYMBptr->feuille._VECTptr; 2444 #if defined GIAC_GGB 2445 gv=makevecteur(subst(gv[1],l1NTHROOT,l2NTHROOT,false,contextptr),inv(gv[0],contextptr)); 2446 #else 2447 gv=makevecteur(gv[1],inv(gv[0],contextptr)); 2448 #endif 2449 g=_pow(gen(gv,_SEQ__VECT),contextptr);//symbolic(at_pow,gen(gv,_SEQ__VECT)); 2450 } 2451 } 2452 subst1=mergevecteur(l1surd,l1NTHROOT); 2453 subst2=mergevecteur(l2surd,l2NTHROOT); 2454 if (!subst1.empty()) 2455 *logptr(contextptr) << gettext("Temporary replacing surd/NTHROOT by fractional powers") << '\n'; 2456 } 2457 is_elementary(const vecteur & v,const gen & x)2458 bool is_elementary(const vecteur & v,const gen & x){ 2459 const_iterateur it=v.begin(),itend=v.end(); 2460 for (;it!=itend;++it){ 2461 if (*it==x) 2462 continue; 2463 if (!it->is_symb_of_sommet(at_exp) && (!it->is_symb_of_sommet(at_ln)) ) 2464 return false; 2465 } 2466 return true; 2467 } 2468 when2sign(gen & e,const gen & gen_x,GIAC_CONTEXT)2469 bool when2sign(gen &e,const gen &gen_x,GIAC_CONTEXT){ 2470 vecteur lwhen(lop(e,at_when)); 2471 if (!lwhen.empty()) lwhen=lvarx(lwhen,gen_x); 2472 if (!lwhen.empty()){ 2473 vecteur l2; 2474 const_iterateur it=lwhen.begin(),itend=lwhen.end(); 2475 int i=0; 2476 for (;it!=itend;++it,++i){ 2477 gen tmp=it->_SYMBptr->feuille,repl; 2478 if (tmp.type!=_VECT || tmp._VECTptr->size()!=3) 2479 return false; 2480 vecteur & whenargs = *tmp._VECTptr; 2481 tmp = whenargs[0]; 2482 if ( (tmp.is_symb_of_sommet(at_superieur_strict) || 2483 tmp.is_symb_of_sommet(at_superieur_egal) ) && 2484 (repl=tmp._SYMBptr->feuille).type==_VECT && repl._VECTptr->size()==2){ 2485 repl=repl._VECTptr->back()-repl._VECTptr->front(); 2486 repl=(symbolic(at_sign,repl)+1)/2; 2487 } 2488 else { 2489 repl=symbolic(at_same,gen(makevecteur(tmp,0),_SEQ__VECT)); 2490 repl=symbolic(at_sign,repl); 2491 } 2492 l2.push_back(whenargs[1]+repl*(whenargs[2]-whenargs[1])); 2493 } 2494 e=complex_subst(e,lwhen,l2,contextptr); 2495 } 2496 return true; 2497 } 2498 2499 // intmode bit 0 is used for sqrt int control, bit 1 control step/step info integrate_id_rem(const gen & e_orig,const gen & gen_x,gen & remains_to_integrate,GIAC_CONTEXT,int intmode)2500 gen integrate_id_rem(const gen & e_orig,const gen & gen_x,gen & remains_to_integrate,GIAC_CONTEXT,int intmode){ 2501 #ifdef LOGINT 2502 *logptr(contextptr) << gettext("integrate id_rem ") << e_orig << '\n'; 2503 #endif 2504 remains_to_integrate=0; 2505 gen e(e_orig); 2506 // Additional check: atan/asin in degree/grad 2507 if (angle_mode(contextptr)){ 2508 if (has_op(e,*at_asin)|| has_op(e,*at_atan) || has_op(e,*at_acos)) 2509 return undeferr("Inverse trigonometric functions are supported in radian mode only."); 2510 } 2511 // Step -3: replace when by piecewise 2512 e=when2piecewise(e,contextptr); 2513 e=Heavisidetopiecewise(e,contextptr); // e=Heavisidetosign(e,contextptr); 2514 if (is_constant_wrt(e,gen_x,contextptr) && lop(e,at_sign).empty()) 2515 return e*gen_x; 2516 if (e.type!=_SYMB) { 2517 remains_to_integrate=zero; 2518 if (e==gen_x) 2519 return rdiv(pow(e,2),plus_two,contextptr); 2520 else 2521 return e*gen_x; 2522 } 2523 // Step -2: piecewise 2524 vecteur lpiece(lop(e,at_piecewise)); 2525 if (!lpiece.empty()) lpiece=lvarx(lpiece,gen_x); 2526 if (!lpiece.empty()){ 2527 *logptr(contextptr) << gettext("Warning: piecewise indefinite integration does not return a continuous antiderivative") << '\n'; 2528 gen piece=lpiece.front(); 2529 if (piece.is_symb_of_sommet(at_piecewise)) 2530 return integrate_piecewise(e,piece,gen_x,remains_to_integrate,contextptr,intmode); 2531 } 2532 #ifdef LOGINT 2533 *logptr(contextptr) << gettext("integrate step -2 ") << e << '\n'; 2534 #endif 2535 // Step -1: replace ifte(a,b,c) by b+sign(a==0)*(c-b) 2536 // if a is A1>A2 or A1>=A2 condition, the sign(a==0) is replaced by (sign(A2-A1)+1)/2 2537 if (!when2sign(e,gen_x,contextptr)) 2538 return gensizeerr(gettext("Bad when ")+e.print(contextptr)); 2539 #ifdef LOGINT 2540 *logptr(contextptr) << gettext("integrate step 0 ") << e << '\n'; 2541 #endif 2542 // Step 0: replace abs(var_dep_x) with sign*var_dep_x 2543 // and then sign() with a constant 2544 gen res; 2545 vecteur l1(lop(e,at_abs)),m1(lop(e,at_sign)); 2546 if (!l1.empty()) l1=lvarx(l1,gen_x); 2547 if (!m1.empty()) m1=lvarx(m1,gen_x); 2548 if (!l1.empty() || !m1.empty()){ 2549 if (integrate_step0(e,gen_x,l1,m1,res,remains_to_integrate,contextptr,intmode)) 2550 return res; 2551 } 2552 // Step1: detection of some unary_op[linear fcn] 2553 if (e.is_symb_of_sommet(at_inv) && e._SYMBptr->feuille.is_symb_of_sommet(at_pow)){ 2554 gen f=e._SYMBptr->feuille._SYMBptr->feuille; 2555 if (f.type==_VECT && f._VECTptr->size()==2){ 2556 gen b=f._VECTptr->back(); 2557 if (!is_integer(b) && b.type!=_FRAC) 2558 e=symbolic(at_pow,makevecteur(f._VECTptr->front(),-b)); 2559 } 2560 } 2561 unary_function_ptr u=e._SYMBptr->sommet; 2562 gen f=e._SYMBptr->feuille,a,b; 2563 // particular case for ^, _FUNCnd arg must be constant 2564 if ( (u==at_pow) && is_constant_wrt(f._VECTptr->back(),gen_x,contextptr) && is_linear_wrt(f._VECTptr->front(),gen_x,a,b,contextptr) ){ 2565 if ( (intmode & 2)==0) 2566 gprintf(step_linear,gettext("Integrate %gen, a linear expression u=%gen to a constant power n=%gen,\nIf n=-1 then ln(u)/a else u^(n+1)/((n+1)*%gen)"),makevecteur(e,a*gen_x+b,f._VECTptr->back(),a),contextptr); 2567 b=f._VECTptr->back(); 2568 if (is_minus_one(b)) 2569 return rdiv(lnabs(f._VECTptr->front(),contextptr),a,contextptr); 2570 return rdiv(pow(f._VECTptr->front(),b+plus_one,contextptr),a*(b+plus_one),contextptr); 2571 } 2572 if ( (u==at_surd) && is_constant_wrt(f._VECTptr->back(),gen_x,contextptr) && is_linear_wrt(f._VECTptr->front(),gen_x,a,b,contextptr) ){ 2573 if ( (intmode & 2)==0) 2574 gprintf(step_linear,gettext("Integrate %gen, a linear expression u=%gen to a constant power n=1/%gen,\nIf n=-1 then ln(u)/a else u^(n+1)/((n+1)*%gen)"),makevecteur(e,a*gen_x+b,f._VECTptr->front(),a),contextptr); 2575 b=f._VECTptr->back(); 2576 if (is_minus_one(b)) 2577 return rdiv(lnabs(f._VECTptr->front(),contextptr),a,contextptr); 2578 return f._VECTptr->front()*symbolic(at_surd,f)/(a+a/b); 2579 } 2580 if ( (u==at_NTHROOT) && is_constant_wrt(f._VECTptr->front(),gen_x,contextptr) && is_linear_wrt(f._VECTptr->back(),gen_x,a,b,contextptr) ){ 2581 if ( (intmode & 2)==0) 2582 gprintf(step_linear,gettext("Integrate %gen, a linear expression u=%gen to a constant power n=1/%gen,\nIf n=-1 then ln(u)/a else u^(n+1)/((n+1)*%gen)"),makevecteur(e,a*gen_x+b,f._VECTptr->front(),a),contextptr); 2583 b=f._VECTptr->front(); 2584 if (is_minus_one(b)) 2585 return rdiv(lnabs(f._VECTptr->back(),contextptr),a,contextptr); 2586 return f._VECTptr->back()*symbolic(at_NTHROOT,f)/(a+a/b); 2587 } 2588 #if 1 // ndef EMCC // re-enabled Aug. 2015 for integrate(1/surd(x^2,3),x,-1,1) 2589 if (has_op(e,*at_surd) || has_op(e,*at_NTHROOT)){ 2590 vecteur subst1,subst2; 2591 surd2pow(e,subst1,subst2,contextptr); 2592 gen g=subst(e,subst1,subst2,false,contextptr); 2593 g=integrate_id_rem(g,gen_x,remains_to_integrate,contextptr,intmode); 2594 remains_to_integrate=subst(remains_to_integrate,subst2,subst1,false,contextptr); 2595 g=subst(g,subst2,subst1,false,contextptr); 2596 return g; 2597 } 2598 #endif 2599 #ifdef LOGINT 2600 *logptr(contextptr) << gettext("integrate step 1 ") << e << '\n'; 2601 #endif 2602 if (u==at_sum && f.type==_VECT && f._VECTptr->size()==4){ 2603 vecteur & fv=*f._VECTptr; 2604 if (!is_zero(derive(fv[1],gen_x,contextptr))) 2605 return gensizeerr("Mute variable of sum depends on integration variable"); 2606 if (!is_zero(derive(fv[2],gen_x,contextptr)) || !is_zero(derive(fv[3],gen_x,contextptr)) ) 2607 return gensizeerr("Boundaries of sum depends on integration variables"); 2608 if (is_inf(fv[2])||is_inf(fv[3])) 2609 *logptr(contextptr) << "Warning: assuming integration and sum commutes" << '\n'; 2610 gen res=integrate_id_rem(fv[0],gen_x,remains_to_integrate,contextptr,intmode); 2611 res=_sum(makesequence(res,fv[1],fv[2],fv[3]),contextptr); 2612 if (!is_zero(remains_to_integrate)) 2613 remains_to_integrate=_sum(makesequence(remains_to_integrate,fv[1],fv[2],fv[3]),contextptr); 2614 return res; 2615 } 2616 // unary op only 2617 int s=equalposcomp(primitive_tab_op,u); 2618 if (s && is_linear_wrt(f,gen_x,a,b,contextptr) ){ 2619 if ( (intmode & 2)==0) 2620 gprintf(step_funclinear,gettext("Integrate %gen: function %gen applied to a linear expression u=%gen, result %gen"),makevecteur(e,primitive_tab_op[s-1],a*gen_x+b,primitive_tab_primitive[s-1](a*gen_x+b,contextptr)/a),contextptr); 2621 return rdiv(primitive_tab_primitive[s-1](f,contextptr),a,contextptr); 2622 } 2623 // Step2: detection of f(u)*u' 2624 vecteur v(1,gen_x); 2625 rlvarx(e,gen_x,v); 2626 int rvarsize=int(v.size()); 2627 if (rvarsize>1){ 2628 gen e2=_texpand(e,contextptr); 2629 if (is_undef(e2)) 2630 e2=e; 2631 vecteur v2(1,gen_x); 2632 rlvarx(e2,gen_x,v2); 2633 if (v2.size()<rvarsize){ 2634 e=e2; 2635 v=v2; 2636 rvarsize=int(v2.size()); 2637 } 2638 if (rvarsize==2){ 2639 e2=simplifier(e,contextptr); 2640 v2.clear(); 2641 v2.push_back(gen_x); 2642 rlvarx(e2,gen_x,v2); 2643 if (v2.size()==1 || (v2.size()==2 && taille(v2[1],100)<taille(v[1],100))){ 2644 e=e2; 2645 v=v2; 2646 } 2647 } 2648 } 2649 vecteur rvar=v; 2650 gen fu,fx; 2651 if (rvarsize<=TRY_FU_UPRIME){ // otherwise no hope 2652 const_iterateur it=v.begin(),itend=v.end(); 2653 ++it; // don't try x! 2654 for (;it!=itend;++it){ 2655 if (it->is_symb_of_sommet(at_fsolve) || it->is_symb_of_sommet(at_equal)) 2656 continue; 2657 gen df=derive(*it,gen_x,contextptr); 2658 gen tmprem; 2659 fu=rdiv(e,df,contextptr); 2660 fu=recursive_ratnormal(fu,contextptr); 2661 fu=eval(fu,1,contextptr); 2662 if ((is_undef(fu) || is_inf(fu)) && is_zero(ratnormal(df,contextptr))){ 2663 // *it is constant -> find the value 2664 tmprem=subst(*it,gen_x,zero,false,contextptr); 2665 e=subst(e,*it,tmprem,false,contextptr); 2666 return integrate_id_rem(e,gen_x,remains_to_integrate,contextptr,intmode | 2); 2667 } 2668 if (is_undef(fu) || is_inf(fu)) 2669 continue; 2670 if (it->is_symb_of_sommet(at_cos)) 2671 fu=_trigcos(tan2sincos(fu,contextptr),contextptr); 2672 if (it->is_symb_of_sommet(at_sin)) 2673 fu=_trigsin(tan2sincos(fu,contextptr),contextptr); 2674 if (it->is_symb_of_sommet(at_tan)) 2675 fu=_trigtan(fu,contextptr); 2676 bool tst=is_rewritable_as_f_of(fu,*it,fx,gen_x,contextptr); 2677 if (tst){ 2678 if (taille(fx,256)>taille(e,255)){ 2679 vecteur fxv=lvarx(fx,gen_x); 2680 if (has_op(fxv,*at_ln) || has_op(fxv,*at_atan)) 2681 tst=false; 2682 } 2683 } 2684 if (tst){ 2685 if ( (intmode & 2)==0) 2686 gprintf(step_fuuprime,gettext("Integration of %gen: f(u)*u' where f=%gen->%gen and u=%gen"),makevecteur(e,gen_x,fx,*it),contextptr); 2687 #if 0 2688 // no abs, for integrate(cot(ln(x))/x,x), but has side effect... 2689 // would be better to add implicit assumptions 2690 bool save_do_lnabs=do_lnabs(contextptr); 2691 do_lnabs(false,contextptr); 2692 e=linear_integrate_nostep(fx,gen_x,tmprem,intmode,contextptr); 2693 do_lnabs(save_do_lnabs,contextptr); 2694 remains_to_integrate=remains_to_integrate+complex_subst(tmprem,gen_x,*it,contextptr)*df; 2695 e=complex_subst(e,gen_x,*it,contextptr); 2696 if (save_do_lnabs){ 2697 vector<const unary_function_ptr *> ln_tab(1,at_ln); 2698 vector<gen_op_context> lnabs_tab(1,add_lnabs); 2699 e=subst(e,ln_tab,lnabs_tab,true,contextptr); 2700 } 2701 return e; 2702 #else 2703 // ln() in integration should not be ln(abs()) if complex change of variable, example a:=-2/(2*i*exp(2*i*x)+2*i)*exp(2*i*x); b:=int(a); simplify(diff(b)-a); 2704 bool b=do_lnabs(contextptr); 2705 if (has_i(*it)) do_lnabs(false,contextptr); 2706 e=linear_integrate_nostep(fx,gen_x,tmprem,intmode,contextptr); 2707 do_lnabs(b,contextptr); 2708 remains_to_integrate=remains_to_integrate+complex_subst(tmprem,gen_x,*it,contextptr)*df; 2709 bool batan=atan_tan_no_floor(contextptr); 2710 atan_tan_no_floor(true,contextptr); 2711 e=complex_subst(e,gen_x,*it,contextptr); 2712 atan_tan_no_floor(batan,contextptr); 2713 // additional check for integrals like 2714 // int(sqrt (1+x^(-2/3)),x,-1,0) 2715 if (it->is_symb_of_sommet(at_pow)){ 2716 gen powarg=(*it)[1],powa,powb; 2717 if (is_linear_wrt(powarg,gen_x,powa,powb,contextptr) && !is_zero(powa)){ 2718 gen powx=-powb/powa; 2719 // check derivative at powx+-1 2720 gen check=ratnormal(derive(e,gen_x,contextptr)/e_orig,contextptr); 2721 gen chkplus=subst(check,gen_x,powx+1.0,false,contextptr); 2722 gen chkminus=subst(check,gen_x,powx-1.0,false,contextptr); 2723 bool tstplus=is_zero(chkplus+1,contextptr); 2724 bool tstminus=is_zero(chkminus+1,contextptr); 2725 if (tstplus){ 2726 if (tstminus) 2727 e=-e; 2728 else 2729 e=-sign(gen_x,contextptr)*e; 2730 } 2731 else { 2732 if (tstminus) 2733 e=sign(gen_x,contextptr)*e; 2734 } 2735 } 2736 } 2737 return e; 2738 #endif 2739 } 2740 if (it->is_symb_of_sommet(at_pow)){ 2741 v[it-v.begin()]=powexpand(*it,contextptr); 2742 bool tst=is_rewritable_as_f_of(powexpand(fu,contextptr),*it,fx,gen_x,contextptr); 2743 if (tst){ 2744 if (taille(fx,256)>taille(e,255)){ 2745 vecteur fxv=lvarx(fx,gen_x); 2746 if (has_op(fxv,*at_ln) || has_op(fxv,*at_atan)) 2747 tst=false; 2748 } 2749 } 2750 if (tst){ 2751 if ( (intmode & 2)==0) 2752 gprintf(step_fuuprime,gettext("Integration of %gen: f(u)*u' where f=%gen->%gen and u=%gen"),makevecteur(e,gen_x,fx,*it),contextptr); 2753 e=linear_integrate_nostep(fx,gen_x,tmprem,intmode,contextptr); 2754 remains_to_integrate=remains_to_integrate+complex_subst(tmprem,gen_x,*it,contextptr)*df; 2755 return complex_subst(e,gen_x,*it,contextptr); 2756 } 2757 } 2758 if (it->type!=_SYMB) 2759 continue; 2760 f=ratnormal(it->_SYMBptr->feuille,contextptr); 2761 // ratnormal added otherwise infinite recursion for int(1/sin(x^-1)) 2762 if ( (f.type==_VECT) && (!f._VECTptr->empty()) ) 2763 f=f._VECTptr->front(); 2764 if (f.type!=_SYMB) 2765 continue; 2766 if (is_linear_wrt(f,gen_x,a,b,contextptr)) 2767 continue; 2768 df=derive(f,gen_x,contextptr); 2769 fu=ratnormal(rdiv(e,df,contextptr),contextptr); 2770 if (is_rewritable_as_f_of(fu,f,fx,gen_x,contextptr)){ 2771 if ( (intmode & 2)==0) 2772 gprintf(step_fuuprime,gettext("Integration of %gen: f(u)*u' where f=%gen->%gen and u=%gen"),makevecteur(e,gen_x,fx,f),contextptr); 2773 e=linear_integrate_nostep(fx,gen_x,tmprem,intmode,contextptr); 2774 remains_to_integrate=remains_to_integrate+complex_subst(tmprem,gen_x,f,contextptr)*df; 2775 return complex_subst(e,gen_x,f,contextptr); 2776 } 2777 } 2778 } 2779 #ifdef LOGINT 2780 *logptr(contextptr) << gettext("integrate step 2 ") << e << '\n'; 2781 #endif 2782 if (e.type!=_SYMB){ 2783 if (e==gen_x) 2784 return pow(gen_x,2,contextptr)/2; 2785 else 2786 return e*gen_x; 2787 } 2788 // try with argument of the product or of a power 2789 v.clear(); 2790 bool est_puissance; 2791 if (e._SYMBptr->sommet==at_pow){ 2792 v=vecteur(1,e._SYMBptr->feuille._VECTptr->front()); 2793 fu=pow(e._SYMBptr->feuille._VECTptr->front(),e._SYMBptr->feuille._VECTptr->back()-plus_one,contextptr); 2794 est_puissance=true; 2795 } 2796 else { 2797 if ( (e._SYMBptr->sommet==at_prod) && (e._SYMBptr->feuille.type==_VECT)) 2798 v=*e._SYMBptr->feuille._VECTptr; 2799 est_puissance=false; 2800 } 2801 const_iterateur vt=v.begin(),vtend=v.end(); 2802 for (int i=0;(i<TRY_FU_UPRIME) && (vt!=vtend);++vt,++i){ 2803 gen tmprem,u=linear_integrate_nostep(*vt,gen_x,tmprem,intmode|2,contextptr); 2804 if (is_undef(u) || !is_zero(tmprem)){ 2805 gen tst=*vt; 2806 if (tst.is_symb_of_sommet(at_pow)){ 2807 gen vtbase=tst._SYMBptr->feuille[0],vtexpo=inv(tst._SYMBptr->feuille[1],contextptr); 2808 if (vtexpo.type==_INT_ && vtexpo.val==4){ 2809 if (is_even_odd(e,gen_x,contextptr)==1){ 2810 gen tmp=complex_subst(e,gen_x,inv(gen_x,contextptr),contextptr); 2811 gen root=complex_subst(tst,gen_x,inv(gen_x,contextptr),contextptr); 2812 gen sroot=simplify(root,contextptr); 2813 if (is_even_odd(sroot,gen_x,contextptr)){ 2814 tmp=complex_subst(tmp,root,sroot,contextptr); 2815 tmp=-linear_integrate_nostep(tmp*pow(gen_x,-2,contextptr),gen_x,tmprem,intmode|2,contextptr); 2816 if (!is_undef(tmp) && is_zero(tmprem)){ 2817 tmp=simplifier(tmp,contextptr); 2818 tmp=complex_subst(tmp,gen_x,inv(gen_x,contextptr),contextptr); 2819 vecteur v=lop(tmp,at_pow); 2820 vecteur w=gen2vecteur(simplify(v,contextptr)); 2821 tmp=complex_subst(tmp,v,w,contextptr); 2822 return tmp; 2823 } 2824 } 2825 } 2826 } 2827 } 2828 continue; 2829 } 2830 if (!est_puissance){ 2831 vecteur vv(v); 2832 vv.erase(vv.begin()+i,vv.begin()+i+1); 2833 fu=symbolic(at_prod,gen(vv,_SEQ__VECT)); 2834 } 2835 gen cst=extract_cst(u,gen_x,contextptr); 2836 bool recur=rvarsize>2 && gen_x.type==_IDNT && strcmp(gen_x._IDNTptr->id_name,"t_nostep")==0 && u.is_symb_of_sommet(at_pow); // workaround for some stupid integrals like integrate(sin((d*x + c)^(2/3)*b + a)/(f*x + E),x); 2837 if (!recur && 2838 is_rewritable_as_f_of(fu,u,fx,gen_x,contextptr)){ 2839 fx=cst*fx; 2840 if ( (intmode & 2)==0) 2841 gprintf(step_fuuprime,gettext("Integration of %gen: f(u)*u' where f=%gen->%gen and u=%gen"),makevecteur(e,gen_x,fx,u),contextptr); 2842 e=linear_integrate_nostep(fx,gen_x,tmprem,intmode,contextptr); 2843 remains_to_integrate=remains_to_integrate+complex_subst(tmprem,gen_x,u,contextptr)*derive(u,gen_x,contextptr); 2844 return complex_subst(e,gen_x,u,contextptr); 2845 } 2846 if (vt->is_symb_of_sommet(at_pow)){ 2847 gen vtbase=vt->_SYMBptr->feuille[0],vtexpo=vt->_SYMBptr->feuille[1]; 2848 if (vtexpo.type==_INT_ && vtexpo.val %2){ 2849 // for example *vt=x^9, retry with *vt=x^4 2850 u=linear_integrate_nostep(pow(vtbase,vtexpo.val/2,contextptr),gen_x,tmprem,intmode|2,contextptr); 2851 if (is_undef(u) || !is_zero(tmprem)) 2852 continue; 2853 if (!est_puissance){ 2854 vecteur vv(v); 2855 vv.erase(vv.begin()+i,vv.begin()+i+1); 2856 fu=symbolic(at_prod,gen(vv,_SEQ__VECT)); 2857 } 2858 cst=extract_cst(u,gen_x,contextptr); 2859 fu=fu*pow(vtbase,vtexpo.val-vtexpo.val/2,contextptr); 2860 if (is_rewritable_as_f_of(fu,u,fx,gen_x,contextptr)){ 2861 fx=cst*fx; 2862 if ( (intmode & 2)==0) 2863 gprintf(step_fuuprime,gettext("Integration of %gen: f(u)*u' where f=%gen->%gen and u=%gen"),makevecteur(e,gen_x,fx,u),contextptr); 2864 e=linear_integrate_nostep(fx,gen_x,tmprem,intmode,contextptr); 2865 remains_to_integrate=remains_to_integrate+complex_subst(tmprem,gen_x,u,contextptr)*derive(u,gen_x,contextptr); 2866 return complex_subst(e,gen_x,u,contextptr); 2867 } 2868 } 2869 } 2870 } 2871 #ifdef LOGINT 2872 *logptr(contextptr) << gettext("integrate step 3 ") << e << '\n'; 2873 #endif 2874 // Step3: rational fraction? 2875 if (rvarsize==1){ 2876 gen xvar(gen_x); 2877 return integrate_rational(e,gen_x,remains_to_integrate,xvar,intmode,contextptr); 2878 } 2879 bool do_risch=true; 2880 for (size_t i=0;i<rvar.size();++i){ 2881 if (rvar[i].is_symb_of_sommet(at_pow)){ 2882 do_risch=false; 2883 break; 2884 } 2885 } 2886 // minimal support for LambertW 2887 if (has_op(rvar,*at_LambertW)){ 2888 vecteur vw(lop(rvar,at_LambertW)); 2889 gen a,b; 2890 if (vw.size()==1 && is_linear_wrt(vw[0]._SYMBptr->feuille,gen_x,a,b,contextptr)){ 2891 // W(ax+b) inside, change of variables ax+b=z*exp(z) 2892 // W(ax+b)=z, dx=(z+1)*exp(z)*dz/a 2893 vecteur substin(makevecteur(vw[0],gen_x)); 2894 vecteur substout(makevecteur(gen_x,(gen_x*symbolic(at_exp,gen_x)))); 2895 gen tmpe=complex_subst(e,substin,substout,contextptr)*(gen_x+1)*symbolic(at_exp,gen_x)/a,tmprem; 2896 gen tmpres=linear_integrate_nostep(tmpe,gen_x,tmprem,intmode,contextptr); 2897 substout[1]=symbolic(at_exp,gen_x); substin[1]=(a*gen_x+b)/vw[0]; 2898 remains_to_integrate=complex_subst(tmprem,substout,substin,contextptr); 2899 res=complex_subst(tmpres,substout,substin,contextptr); 2900 return res; 2901 } 2902 } 2903 // square roots 2904 if ( (rvarsize==2) && (rvar.back().type==_SYMB) && (rvar.back()._SYMBptr->sommet==at_pow) ){ 2905 if (integrate_sqrt(e,gen_x,rvar,res,remains_to_integrate,intmode,contextptr)){ 2906 if ( (intmode & 1)==0 && is_zero(res)){ 2907 // try again with x->1/x? 2908 gen e2=normal(-complex_subst(e,gen_x,inv(gen_x,contextptr),contextptr)/gen_x/gen_x,contextptr); 2909 gen remains_to_integrate2,res2=integrate_id_rem(e2,gen_x,remains_to_integrate2,contextptr,1); 2910 if (!is_zero(res2)){ 2911 res=complex_subst(res2,gen_x,inv(gen_x,contextptr),contextptr); 2912 remains_to_integrate=-complex_subst(remains_to_integrate2,gen_x,inv(gen_x,contextptr),contextptr)/gen_x/gen_x; 2913 return res; 2914 } 2915 } 2916 return res; 2917 } 2918 } 2919 // detection of inv of trig or ln of a linear expression 2920 if (detect_inv_trigln(e,rvar,gen_x,res,remains_to_integrate,true,intmode,contextptr)) 2921 return res; 2922 2923 // integration by part? 2924 if ( (e._SYMBptr->sommet==at_prod) && (e._SYMBptr->feuille.type==_VECT)){ 2925 const_iterateur ibp=e._SYMBptr->feuille._VECTptr->begin(),ibpend=e._SYMBptr->feuille._VECTptr->end(); 2926 for (int j=0;ibp!=ibpend;++ibp,++j){ 2927 int test; 2928 if (ibp->type!=_SYMB) 2929 continue; 2930 if ( (ibp->_SYMBptr->sommet==at_pow) && 2931 (ibp->_SYMBptr->feuille._VECTptr->front().type==_SYMB) && 2932 (ibp->_SYMBptr->feuille._VECTptr->back().type==_INT_) && 2933 (ibp->_SYMBptr->feuille._VECTptr->back().val>0) ) 2934 test=equalposcomp(inverse_tab_op,ibp->_SYMBptr->feuille._VECTptr->front()._SYMBptr->sommet); 2935 else 2936 test=equalposcomp(inverse_tab_op,ibp->_SYMBptr->sommet); 2937 if (!test) 2938 continue; 2939 vecteur ibpv(*e._SYMBptr->feuille._VECTptr); 2940 ibpv.erase(ibpv.begin()+j); 2941 gen ibpe=_prod(ibpv,contextptr); 2942 #if 1 2943 gen tmpres,tmprem,tmpprimitive,tmp; 2944 tmpprimitive=linear_integrate_nostep(ibpe,gen_x,tmp,intmode|2,contextptr); 2945 if (is_zero(tmp)){ 2946 vecteur tmpv=rlvarx(tmpprimitive,gen_x); 2947 unsigned tmpi=0; 2948 for (;tmpi<tmpv.size();++tmpi){ 2949 if (tmpv[tmpi].type==_SYMB && equalposcomp(inverse_tab_op,tmpv[tmpi]._SYMBptr->sommet)) 2950 break; 2951 } 2952 if (tmpi==tmpv.size()){ 2953 if ( (intmode & 2)==0) 2954 gprintf(step_bypart,gettext("Integration of %gen: by part, u*v'=%gen*(%gen)'"),makevecteur(e,*ibp,tmpprimitive),contextptr); 2955 tmpres=tmpprimitive*derive(*ibp,gen_x,contextptr); 2956 tmpres=recursive_normal(tmpres,true,contextptr); 2957 tmpres=linear_integrate_nostep(tmpres,gen_x,tmprem,intmode,contextptr); 2958 remains_to_integrate=-tmprem; 2959 return tmpprimitive*(*ibp)-tmpres; 2960 } 2961 } 2962 #else 2963 vecteur tmpv(1,gen_x); 2964 lvar(ibpe,tmpv); 2965 tmpv.erase(tmpv.begin()); 2966 if (lvarx(tmpv,gen_x).empty()){ 2967 gen tmpres,tmprem,tmpprimitive,tmp,xvar(gen_x); 2968 tmpprimitive=integrate_rational(ibpe,gen_x,tmp,xvar,intmode,contextptr); 2969 if (is_zero(tmp) && lvarx(tmpprimitive,gen_x)==vecteur(1,gen_x)){ 2970 tmpres=tmpprimitive*derive(*ibp,gen_x,contextptr); 2971 tmpres=recursive_normal(tmpres,true,contextptr); 2972 tmpres=linear_integrate_nostep(tmpres,gen_x,tmprem,intmode,contextptr); 2973 remains_to_integrate=-tmprem; 2974 return tmpprimitive*(*ibp)-tmpres; 2975 } 2976 } 2977 #endif 2978 } 2979 } 2980 else { // check for u'=1 2981 int test; 2982 if ( (e._SYMBptr->sommet==at_pow) && (e._SYMBptr->feuille._VECTptr->front().type==_SYMB) && (e._SYMBptr->feuille._VECTptr->back().type==_INT_) && (e._SYMBptr->feuille._VECTptr->back().val>0) ) 2983 test=equalposcomp(inverse_tab_op,e._SYMBptr->feuille._VECTptr->front()._SYMBptr->sommet); 2984 else 2985 test=equalposcomp(inverse_tab_op,e._SYMBptr->sommet); 2986 if (test){ 2987 if ( (intmode & 2)==0) 2988 gprintf(step_bypart1,gettext("Integration of %gen by part of u*v' where u=1 and v=%gen'"),makevecteur(e,e),contextptr); 2989 gen tmpres,tmprem; 2990 tmpres=normal(derive(e,gen_x,contextptr),contextptr); 2991 tmpres=linear_integrate_nostep(gen_x*tmpres,gen_x,tmprem,intmode,contextptr); 2992 if (!has_i(e) && has_i(tmpres)){ 2993 remains_to_integrate=e; 2994 return 0; 2995 } 2996 remains_to_integrate=-tmprem; 2997 return gen_x*e-tmpres; 2998 } 2999 } 3000 // additional check on e for f:= x*(x + 1)*(2*x*(x - (2*x**3 + 2*x**2 + x + 1)*log(x + 1))*exp(3*x**2) + (x**2*exp(2*x**2) - log(x + 1)**2)**2)/((x + 1)*log(x + 1)**2 - (x**3 + x**2)*exp(2*x**2))**2 3001 if (!is_elementary(rvar,gen_x) && detect_inv_trigln(e,rvar,gen_x,res,remains_to_integrate,false,intmode,contextptr)) 3002 return res; 3003 3004 // rewrite inv(exp) 3005 vector<const unary_function_ptr *> vsubstin(1,at_inv); 3006 vector<gen_op_context> vsubstout(1,invexptoexpneg); 3007 e=subst(e,vsubstin,vsubstout,true,contextptr); // changed to true for numint of programs (otherwise e becomes undef) 3008 // detection of denominator=independent of x 3009 v=lvarxwithinv(e,gen_x,contextptr); 3010 // search for nop (for nop[inv]) 3011 if (!has_nop_var(v)){ 3012 // additional check for non integer powers 3013 v=lop(lvar(e),at_pow); 3014 vecteur vx=lvarx(v,gen_x); 3015 if (vx.empty() || vx==vecteur(1,gen_x)) 3016 return integrate_linearizable(e,gen_x,remains_to_integrate,intmode,contextptr); 3017 // second try with ^ rewritten as exp(ln) 3018 gen etmp=pow2expln(e,contextptr); 3019 v=lvarxwithinv(etmp,gen_x,contextptr); 3020 // search for nop (for nop[inv]) 3021 if (!has_nop_var(v)){ 3022 // additional check for non integer powers 3023 v=lop(lvar(etmp),at_pow); 3024 vecteur vx=lvarx(v,gen_x); 3025 if (vx.empty() || vx==vecteur(1,gen_x)) 3026 return integrate_linearizable(etmp,gen_x,remains_to_integrate,intmode,contextptr); 3027 } 3028 } 3029 // trigonometric fraction (or exp _FRAC), rewrite all elemnts of rvar as 3030 // tan of the common half angle, i.e. tan([coeff_trig*x+b]/2) 3031 int trig_fraction=-1; 3032 gen coeff_trig; 3033 vecteur var(lvarx(e,gen_x)); 3034 const_iterateur vart=var.begin(),vartend=var.end(); 3035 for (;vart!=vartend;++vart){ 3036 if (vart->type!=_SYMB){ 3037 trig_fraction=false; 3038 continue; 3039 } 3040 int vartt=equalposcomp(primitive_tab_op,vart->_SYMBptr->sommet); 3041 if ( (!vartt) || (vartt>4) ) 3042 trig_fraction=0; 3043 if (trig_fraction==-1){ 3044 trig_fraction=vartt; 3045 } 3046 else { 3047 if (trig_fraction==4){ 3048 if (vartt!=4) 3049 trig_fraction=0; 3050 } 3051 else { 3052 if (vartt==4) 3053 trig_fraction=0; 3054 } 3055 } 3056 if (trig_fraction ){ // trig of linear? 3057 gen a,b; 3058 if (!is_linear_wrt(vart->_SYMBptr->feuille,gen_x,a,b,contextptr)){ 3059 trig_fraction=false; 3060 continue; 3061 } 3062 if (is_zero(coeff_trig)) 3063 coeff_trig=a; 3064 else { 3065 gen quotient=ratnormal(rdiv(a,coeff_trig,contextptr),contextptr); 3066 if (quotient.type==_INT_) 3067 continue; 3068 if ( (quotient.type==_FRAC) && (quotient._FRACptr->num.type==_INT_) && (quotient._FRACptr->den.type==_INT_) ){ 3069 coeff_trig=ratnormal(rdiv(coeff_trig,quotient._FRACptr->den,contextptr),contextptr); 3070 continue; 3071 } 3072 if ( (quotient.type==_SYMB) && (quotient._SYMBptr->sommet==at_inv) && (quotient._SYMBptr->feuille.type==_INT_)){ 3073 coeff_trig=ratnormal(rdiv(coeff_trig,quotient._SYMBptr->feuille,contextptr),contextptr); 3074 continue; 3075 } 3076 trig_fraction=false; 3077 } 3078 } // end if (trig_fraction) 3079 } 3080 if (trig_fraction) 3081 return integrate_trig_fraction(e,gen_x,var,coeff_trig,trig_fraction,remains_to_integrate,intmode,contextptr); 3082 if (!do_risch){ 3083 remains_to_integrate=e; 3084 return 0; 3085 } 3086 // finish by calling the Risch algorithm 3087 if ( (intmode & 2)==0) 3088 gprintf(step_risch,gettext("Integrate %gen, no heuristic found, running Risch algorithm"),makevecteur(e),contextptr); 3089 return risch(e,*gen_x._IDNTptr,remains_to_integrate,contextptr); 3090 } 3091 linear_integrate(const gen & e,const gen & x,gen & remains_to_integrate,GIAC_CONTEXT)3092 gen linear_integrate(const gen & e,const gen & x,gen & remains_to_integrate,GIAC_CONTEXT){ 3093 gen ee(normalize_sqrt(e,contextptr)); 3094 return linear_apply(ee,x,remains_to_integrate,contextptr,integrate_gen_rem); 3095 } 3096 linear_integrate_nostep(const gen & e,const gen & x,gen & remains_to_integrate,int intmode,GIAC_CONTEXT)3097 gen linear_integrate_nostep(const gen & e,const gen & x,gen & remains_to_integrate,int intmode,GIAC_CONTEXT){ 3098 int step_infolevelsave=step_infolevel(contextptr); 3099 if ((intmode & 2)==2) 3100 step_infolevel(contextptr)=0; 3101 // temporarily remove assumptions by changing integration variable 3102 identificateur t("t_nostep"); 3103 gen tt(t); 3104 gen ee=quotesubst(e,x,tt,contextptr); 3105 ee=normalize_sqrt(ee,contextptr); 3106 gen res=linear_apply(ee,tt,remains_to_integrate,contextptr,integrate_gen_rem); 3107 step_infolevel(contextptr)=step_infolevelsave; 3108 res=quotesubst(res,tt,x,contextptr); 3109 remains_to_integrate=quotesubst(remains_to_integrate,tt,x,contextptr); 3110 return res; 3111 } 3112 min2abs(const gen & g,GIAC_CONTEXT)3113 gen min2abs(const gen & g,GIAC_CONTEXT){ 3114 if (g.type!=_VECT || g._VECTptr->size()!=2) 3115 return symbolic(at_min,g); 3116 gen a=g._VECTptr->front(),b=g._VECTptr->back(); 3117 return (a+b-abs(a-b,contextptr))/2; 3118 } 3119 max2abs(const gen & g,GIAC_CONTEXT)3120 gen max2abs(const gen & g,GIAC_CONTEXT){ 3121 if (g.type!=_VECT || g._VECTptr->size()!=2) 3122 return symbolic(at_min,g); 3123 gen a=g._VECTptr->front(),b=g._VECTptr->back(); 3124 return (a+b+abs(a-b,contextptr))/2; 3125 } 3126 rewrite_minmax(const gen & e,bool quotesubst,GIAC_CONTEXT)3127 gen rewrite_minmax(const gen & e,bool quotesubst,GIAC_CONTEXT){ 3128 vector<const unary_function_ptr *> vu; 3129 vu.push_back(at_min); 3130 vu.push_back(at_max); 3131 vector <gen_op_context> vv; 3132 vv.push_back(min2abs); 3133 vv.push_back(max2abs); 3134 return subst(e,vu,vv,quotesubst,contextptr); 3135 } 3136 integrate_id(const gen & e,const identificateur & x,GIAC_CONTEXT)3137 gen integrate_id(const gen & e,const identificateur & x,GIAC_CONTEXT){ 3138 if (e.type==_VECT){ 3139 vecteur w; 3140 vecteur::const_iterator it=e._VECTptr->begin(),itend=e._VECTptr->end(); 3141 for (;it!=itend;++it) 3142 w.push_back(integrate_id(*it,x,contextptr)); 3143 return w; 3144 } 3145 gen remains_to_integrate; 3146 gen ee=rewrite_hyper(e,contextptr); 3147 ee=rewrite_minmax(ee,true,contextptr); 3148 gen res=_simplifier(linear_integrate(ee,x,remains_to_integrate,contextptr),contextptr); 3149 if (is_zero(remains_to_integrate)) 3150 return res; 3151 else 3152 return res+symbolic(at_integrate,gen(makevecteur(remains_to_integrate,x),_SEQ__VECT)); 3153 } 3154 integrate0_(const gen & e,const identificateur & x,gen & remains_to_integrate,GIAC_CONTEXT)3155 static gen integrate0_(const gen & e,const identificateur & x,gen & remains_to_integrate,GIAC_CONTEXT){ 3156 if (step_infolevel(contextptr)) 3157 gprintf(step_integrate_header,gettext("===== Step/step primitive of %gen with respect to %gen ====="),makevecteur(e,x),contextptr); 3158 if (e.type==_VECT){ 3159 vecteur w; 3160 vecteur::const_iterator it=e._VECTptr->begin(),itend=e._VECTptr->end(); 3161 for (;it!=itend;++it) 3162 w.push_back(integrate_id(*it,x,contextptr)); 3163 return w; 3164 } 3165 gen ee=rewrite_hyper(e,contextptr),tmprem; 3166 ee=rewrite_minmax(ee,true,contextptr); 3167 gen res=linear_integrate(ee,x,tmprem,contextptr); 3168 if (!is_zero(tmprem)){ 3169 ee = tmprem; 3170 gen k=extract_cst(ee,x,contextptr); 3171 if (ee.is_symb_of_sommet(at_plus)){ 3172 res += k*integrate_gen_rem(ee,x,tmprem,contextptr); 3173 tmprem = k*tmprem; 3174 } 3175 } 3176 remains_to_integrate=remains_to_integrate+tmprem; 3177 if (step_infolevel(contextptr) && is_zero(remains_to_integrate)) 3178 gprintf(gettext("Hence primitive of %gen with respect to %gen is %gen"),makevecteur(e,x,res),contextptr); 3179 return res; 3180 } 3181 integrate0(const gen & e,const identificateur & x,gen & remains_to_integrate,GIAC_CONTEXT)3182 static gen integrate0(const gen & e,const identificateur & x,gen & remains_to_integrate,GIAC_CONTEXT){ 3183 bool b_acosh=keep_acosh_asinh(contextptr); 3184 keep_acosh_asinh(true,contextptr); 3185 gen res=integrate0_(e,x,remains_to_integrate,contextptr); 3186 keep_acosh_asinh(b_acosh,contextptr); 3187 return res; 3188 } 3189 integrate_gen(const gen & e,const gen & f,GIAC_CONTEXT)3190 gen integrate_gen(const gen & e,const gen & f,GIAC_CONTEXT){ 3191 if (f.type!=_IDNT){ 3192 identificateur x(" x"); 3193 gen e1=subst(e,f,x,false,contextptr); 3194 return quotesubst(integrate_id(e1,x,contextptr),x,f,contextptr); 3195 } 3196 return integrate_id(e,*f._IDNTptr,contextptr); 3197 } 3198 adjust_int_sum_arg(vecteur & v,int & s)3199 bool adjust_int_sum_arg(vecteur & v,int & s){ 3200 if (s<2) 3201 return false; // setsizeerr(contextptr); 3202 if ( (s==2) && (v[1].type==_SYMB) && (v[1]._SYMBptr->sommet==at_equal || v[1]._SYMBptr->sommet==at_equal2 || v[1]._SYMBptr->sommet==at_same)){ 3203 v.push_back(v[1]._SYMBptr->feuille._VECTptr->back()); 3204 v[1]=v[1]._SYMBptr->feuille._VECTptr->front(); 3205 if ( (v[2].type!=_SYMB) || (v[2]._SYMBptr->sommet!=at_interval) ) 3206 return false; // settypeerr(contextptr); 3207 v.push_back(v[2]._SYMBptr->feuille._VECTptr->back()); 3208 v[2]=v[2]._SYMBptr->feuille._VECTptr->front(); 3209 s=4; 3210 } 3211 return true; 3212 } 3213 3214 static int ggb_intcounter=0; 3215 ck_int_numerically(const gen & f,const gen & x,const gen & a,const gen & b,const gen & exactvalue,GIAC_CONTEXT)3216 gen ck_int_numerically(const gen & f,const gen & x,const gen & a,const gen &b,const gen & exactvalue,GIAC_CONTEXT){ 3217 if (is_inf(a) || is_inf(b)) 3218 return exactvalue; 3219 gen tmp=evalf_double(exactvalue,1,contextptr); 3220 #if defined HAVE_LIBMPFR && !defined NO_STDEXCEPT 3221 if ( (tmp.type==_DOUBLE_ || tmp.type==_CPLX) 3222 && !has_i(lop(exactvalue,at_erf)) // otherwise it's slow 3223 ){ 3224 try { 3225 tmp=evalf_double(accurate_evalf(exactvalue,256),1,contextptr); 3226 } catch (std::runtime_error & err){ 3227 last_evaled_argptr(contextptr)=NULL; 3228 } 3229 } 3230 #endif 3231 if (tmp.type!=_DOUBLE_ && tmp.type!=_CPLX) 3232 return exactvalue; 3233 if (debug_infolevel) 3234 *logptr(contextptr) << gettext("Checking exact value of integral with numeric approximation")<<'\n'; 3235 gen tmp2; 3236 if (!tegral(f,x,a,b,1e-6,(1<<10),tmp2,true,contextptr)) 3237 return exactvalue; 3238 tmp2=evalf_double(tmp2,1,contextptr); 3239 if ( (tmp2.type!=_DOUBLE_ && tmp2.type!=_CPLX) || 3240 (abs(tmp,contextptr)._DOUBLE_val<1e-8 && abs(tmp2,contextptr)._DOUBLE_val<1e-8) || 3241 abs(tmp-tmp2,contextptr)._DOUBLE_val<=1e-3*abs(tmp2,contextptr)._DOUBLE_val 3242 ) 3243 return simplifier(exactvalue,contextptr); 3244 *logptr(contextptr) << gettext("Error while checking exact value with approximate value, returning both!") << '\n'; 3245 return makevecteur(exactvalue,tmp2); 3246 } 3247 comprim(vecteur & v)3248 void comprim(vecteur & v){ 3249 vecteur w; 3250 for (unsigned i=0;i<v.size();++i){ 3251 if (!equalposcomp(w,v[i])) 3252 w.push_back(v[i]); 3253 } 3254 v=w; 3255 } 3256 assumeeval(const gen & x,GIAC_CONTEXT)3257 gen assumeeval(const gen & x,GIAC_CONTEXT){ 3258 if (x.type!=_IDNT) 3259 return x.eval(1,contextptr); 3260 gen evaled; 3261 if (x._IDNTptr->in_eval(1,x,evaled,contextptr)) 3262 return evaled; 3263 return x; 3264 } 3265 restorepurge(const gen & xval,const gen & x,GIAC_CONTEXT)3266 void restorepurge(const gen & xval,const gen & x,GIAC_CONTEXT){ 3267 if (xval==x 3268 // || (xval.type==_VECT && xval.subtype==_ASSUME__VECT && xval._VECTptr->size()==1 && xval._VECTptr->front().val==_SYMB) 3269 ) 3270 purgenoassume(x,contextptr); 3271 else 3272 sto(xval,x,contextptr); 3273 } 3274 3275 #ifndef USE_GMP_REPLACEMENTS 3276 // small utility for ggb floats looking like fractions ggb_num_coeff(gen & g)3277 void ggb_num_coeff(gen & g){ 3278 if (g.type!=_FRAC || g._FRACptr->den.type!=_ZINT) 3279 return; 3280 mpz_t t; mpz_init_set(t,*g._FRACptr->den._ZINTptr); 3281 while (mpz_divisible_ui_p(t,2)){ 3282 mpz_divexact_ui(t,t,2); 3283 continue; 3284 } 3285 while (mpz_divisible_ui_p(t,5)){ 3286 mpz_divexact_ui(t,t,5); 3287 continue; 3288 } 3289 if (mpz_cmp_ui(t,1)==0) 3290 g=evalf(g,1,context0); 3291 mpz_clear(t); 3292 } 3293 #endif 3294 3295 #ifdef NO_STDEXCEPT protect_integrate(const gen & args,GIAC_CONTEXT)3296 inline gen protect_integrate(const gen & args,GIAC_CONTEXT){ 3297 return _integrate(args,contextptr); 3298 } 3299 #else protect_integrate(const gen & args,GIAC_CONTEXT)3300 gen protect_integrate(const gen & args,GIAC_CONTEXT){ 3301 gen res; 3302 try { 3303 res=_integrate(args,contextptr); 3304 } catch (std::runtime_error & err){ 3305 last_evaled_argptr(contextptr)=NULL; 3306 res=string2gen(err.what(),false); 3307 res.subtype=-1; 3308 } 3309 return res; 3310 } 3311 #endif 3312 // "unary" version _integrate(const gen & args,GIAC_CONTEXT)3313 gen _integrate(const gen & args,GIAC_CONTEXT){ 3314 if (complex_variables(contextptr)) 3315 *logptr(contextptr) << gettext("Warning, complex variables is set, this can lead to fairly complex answers. It is recommended to switch off complex variables in the settings or by complex_variables:=0; and declare individual variables to be complex by e.g. assume(a,complex).") << '\n'; 3316 #ifdef LOGINT 3317 *logptr(contextptr) << gettext("integrate begin") << '\n'; 3318 #endif 3319 if ( args.type==_STRNG && args.subtype==-1) return args; 3320 vecteur v(gen2vecteur(args)); 3321 if (v.size()==1){ 3322 gen a,b,c=eval(args,1,contextptr); 3323 if (c.type==_SPOL1){ 3324 sparse_poly1 res=*c._SPOL1ptr; 3325 sparse_poly1::iterator it=res.begin(),itend=res.end(); 3326 for (;it!=itend;++it){ 3327 gen e=it->exponent+1; 3328 if (e==0) 3329 return sparse_poly1(1,monome(undef,undef)); 3330 it->coeff=it->coeff/e; 3331 it->exponent=e; 3332 } 3333 return res; 3334 } 3335 if (c.type==_VECT && c.subtype==_POLY1__VECT){ 3336 vecteur v=*c._VECTptr; 3337 reverse(v.begin(),v.end()); 3338 v=integrate(v,1); 3339 reverse(v.begin(),v.end()); 3340 v.push_back(0); 3341 return gen(v,_POLY1__VECT); 3342 } 3343 if (is_algebraic_program(c,a,b) && a.type!=_VECT) 3344 return symbolic(at_program,makesequence(a,0,_integrate(gen(makevecteur(b,a),_SEQ__VECT),contextptr))); 3345 if (calc_mode(contextptr)==1) 3346 v.push_back(ggb_var(v.front())); 3347 else 3348 v.push_back(vx_var); 3349 } 3350 int s=int(v.size()); 3351 if (!adjust_int_sum_arg(v,s)) 3352 return gensizeerr(contextptr); 3353 if (s>=4 && complex_mode(contextptr)){ 3354 complex_mode(false,contextptr); 3355 gen res=_integrate(args,contextptr); 3356 complex_mode(true,contextptr); 3357 return res; 3358 } 3359 if (s==1) 3360 return gentoofewargs("integrate"); 3361 if (s==3){ 3362 if (calc_mode(contextptr)!=1) 3363 // indefinite integration with constant of integration 3364 return _integrate(gen(makevecteur(v[0],v[1]),_SEQ__VECT),contextptr)+v[2]; 3365 v.insert(v.begin()+1,ggb_var(eval(v.front(),1,contextptr))); 3366 ++s; 3367 } 3368 if (s>6) 3369 return gentoomanyargs("integrate"); 3370 gen x=v[1]; 3371 if (x.is_symb_of_sommet(at_unquote)) 3372 x=eval(x,1,contextptr); 3373 if (storcl_38 && x.type==_IDNT && storcl_38(x,0,x._IDNTptr->id_name,undef,false,contextptr,NULL,false)){ 3374 identificateur t("t_"); 3375 x=v[1]; 3376 v[0]=quotesubst(v[0],x,t,contextptr); 3377 v[1]=t; 3378 gen res=_integrate(gen(v,_SEQ__VECT),contextptr); 3379 return quotesubst(res,t,x,contextptr); 3380 } 3381 if (x.type!=_IDNT){ 3382 if (x.type<_IDNT) 3383 return gensizeerr(contextptr); 3384 if (abs_calc_mode(contextptr)==38 && x.type!=_SYMB) 3385 return gensizeerr(contextptr); 3386 if (x.type==_SYMB && x._SYMBptr->sommet!=at_of && x._SYMBptr->sommet!=at_at) 3387 return gensizeerr(contextptr); 3388 identificateur t(" t"); 3389 v[0]=quotesubst(v[0],x,t,contextptr); 3390 v[1]=t; 3391 gen res=_integrate(gen(v,_SEQ__VECT),contextptr); 3392 return quotesubst(res,t,x,contextptr); 3393 } 3394 int quoted=0; 3395 if (x._IDNTptr->quoted){ 3396 quoted=*x._IDNTptr->quoted; 3397 *x._IDNTptr->quoted=1; 3398 } 3399 for (int i=2;i<s;++i){ 3400 v[i]=eval(v[i],eval_level(contextptr),contextptr); 3401 if (v[i].is_symb_of_sommet(at_pnt)) 3402 return gensizeerr(contextptr); 3403 } 3404 #if 0 // ndef USE_GMP_REPLACEMENTS 3405 if (calc_mode(contextptr)==1){ 3406 if (s>2) 3407 ggb_num_coeff(v[2]); 3408 if (s>3) 3409 ggb_num_coeff(v[3]); 3410 } 3411 #endif 3412 if (s>=4){ // take care of boundaries when evaluating 3413 if (v.back()==at_assume){ 3414 --s; 3415 v.pop_back(); 3416 } 3417 else { 3418 gen xval=assumeeval(x,contextptr); 3419 gen a(v[2]),b(v[3]); 3420 if (evalf_double(a,1,contextptr).type==_DOUBLE_ && evalf_double(b,1,contextptr).type==_DOUBLE_){ 3421 bool neg=false; 3422 if (is_greater(v[2],v[3],contextptr)){ 3423 a=v[3]; b=v[2]; 3424 neg=true; 3425 v[2]=a; v[3]=b; 3426 } 3427 vecteur lv=lop(lvarx(v[0],v[1]),at_pow); 3428 lv=mergevecteur(lv,lop(lvarx(v[0],v[1]),at_surd)); 3429 lv=mergevecteur(lv,lop(lvarx(v[0],v[1]),at_NTHROOT)); 3430 if (lv.size()==1 && v[1].type==_IDNT){ 3431 gen powarg=lv[0][1]; 3432 if (lv[0][0]==at_NTHROOT) 3433 powarg=lv[0][2]; 3434 lv=protect_solve(powarg,*v[1]._IDNTptr,0,contextptr); 3435 for (int i=0;i<int(lv.size());++i){ 3436 if (is_strictly_greater(lv[i],a,contextptr) && is_strictly_greater(b,lv[i],contextptr)){ 3437 v[3]=lv[i]; 3438 gen res1=_integrate(v,contextptr); 3439 v[3]=b; 3440 v[2]=lv[i]; 3441 gen res2=_integrate(v,contextptr); 3442 res2=res1+res2; 3443 return neg?-res2:res2; 3444 } 3445 } 3446 } 3447 giac_assume(symb_and(symb_superieur_egal(x,a),symb_inferieur_egal(x,b)),contextptr); 3448 v.push_back(at_assume); 3449 gen res=protect_integrate(gen(v,_SEQ__VECT),contextptr); 3450 restorepurge(xval,x,contextptr); 3451 return neg?-res:res; 3452 } 3453 if (is_greater(b,a,contextptr)){ 3454 giac_assume(symb_and(symb_superieur_egal(x,a),symb_inferieur_egal(x,b)),contextptr); 3455 v.push_back(at_assume); 3456 gen res=protect_integrate(gen(v,_SEQ__VECT),contextptr); 3457 restorepurge(xval,x,contextptr); 3458 return res; 3459 } 3460 else { 3461 if (is_greater(a,b,contextptr)){ 3462 giac_assume(symb_and(symb_superieur_egal(x,b),symb_inferieur_egal(x,a)),contextptr); 3463 v.push_back(at_assume); 3464 gen res=protect_integrate(gen(v,_SEQ__VECT),contextptr); 3465 restorepurge(xval,x,contextptr); 3466 return res; 3467 } 3468 } 3469 } 3470 } 3471 bool b_acosh=keep_acosh_asinh(contextptr); 3472 keep_acosh_asinh(true,contextptr); 3473 #ifdef NO_STDEXCEPT 3474 if (contextptr && contextptr->quoted_global_vars && !is_assumed_real(x,contextptr)){ 3475 contextptr->quoted_global_vars->push_back(x); 3476 gen tmp=eval(v[0],eval_level(contextptr),contextptr); 3477 tmp=Heavisidetopiecewise(tmp,contextptr); 3478 if (!is_undef(tmp)) v[0]=tmp; 3479 contextptr->quoted_global_vars->pop_back(); 3480 } 3481 else { 3482 gen tmp=eval(v[0],eval_level(contextptr),contextptr); 3483 tmp=Heavisidetopiecewise(tmp,contextptr); 3484 if (!is_undef(tmp)) v[0]=tmp; 3485 } 3486 #else 3487 try { 3488 if (contextptr && contextptr->quoted_global_vars && !is_assumed_real(x,contextptr)){ 3489 contextptr->quoted_global_vars->push_back(x); 3490 gen tmp=eval(v[0],eval_level(contextptr),contextptr); 3491 tmp=Heavisidetopiecewise(tmp,contextptr); 3492 if (!is_undef(tmp)) v[0]=tmp; 3493 contextptr->quoted_global_vars->pop_back(); 3494 } 3495 else { 3496 gen tmp=eval(v[0],eval_level(contextptr),contextptr); 3497 tmp=Heavisidetopiecewise(tmp,contextptr); 3498 if (!is_undef(tmp)) v[0]=tmp; 3499 } 3500 } catch (std::runtime_error & err){ 3501 last_evaled_argptr(contextptr)=NULL; 3502 CERR << "Unable to eval " << v[0] << ": " << err.what() << '\n'; 3503 } 3504 #endif 3505 keep_acosh_asinh(b_acosh,contextptr); 3506 if (x._IDNTptr->quoted) 3507 *x._IDNTptr->quoted=quoted; 3508 if (s>4 || (approx_mode(contextptr) && (s==4)) ){ 3509 v[1]=x; 3510 return intnum(gen(v,_SEQ__VECT),false,contextptr,true); 3511 } 3512 gen rem,borne_inf,borne_sup,res,v0orig,aorig,borig; 3513 if (s==4){ 3514 #ifndef POCKETCAS 3515 if ( (has_num_coeff(v[0]) || 3516 v[2].type==_FLOAT_ || v[2].type==_DOUBLE_ || v[2].type==_REAL || 3517 v[3].type==_FLOAT_ || v[3].type==_DOUBLE_ || v[3].type==_REAL)){ 3518 vecteur ld=makevecteur(unsigned_inf,cst_pi); 3519 // should first remove mute variables inside embedded sum/int/fsolve 3520 lidnt(makevecteur(true_lidnt(v[0]),evalf_double(v[2],1,contextptr),evalf_double(v[3],1,contextptr)),ld,false); 3521 ld.erase(ld.begin()); 3522 ld.erase(ld.begin()); 3523 if (ld==vecteur(1,v[1]) || ld.empty()) 3524 return intnum(gen(makevecteur(v[0],v[1],v[2],v[3]),_SEQ__VECT),false,contextptr,true); 3525 } 3526 #endif 3527 v0orig=v[0]; 3528 aorig=borne_inf=v[2]; 3529 borig=borne_sup=v[3]; 3530 if (borne_inf==borne_sup) 3531 return 0; 3532 v[0]=ceil2floor(v[0],contextptr,true); 3533 vecteur lfloor(lop(v[0],at_floor)); 3534 lfloor=lvarx(lfloor,x); 3535 if (!lfloor.empty()){ 3536 gen a,b,l,cond=lfloor.front()._SYMBptr->feuille,tmp; 3537 if (lvarx(cond,x).size()>1 || !is_linear_wrt(cond,x,a,b,contextptr) ){ 3538 *logptr(contextptr) << gettext("Floor definite integration: can only handle linear < or > condition") << '\n'; 3539 if (!tegral(v0orig,x,aorig,borig,1e-12,(1<<10),res,true,contextptr)) 3540 return undef; 3541 return res; 3542 } 3543 if (is_inf(borne_inf) || is_inf(borne_sup)){ 3544 *logptr(contextptr) << gettext("Floor definite integration: unable to handle infinite boundaries") << '\n'; 3545 } 3546 else { 3547 // find integers of the form a*x+b in [borne_inf,borne_sup] 3548 gen n1=_floor(a*borne_inf+b,contextptr); 3549 // n1=a*x+b -> x=(n1-b)/a 3550 gen stepx,stepn; 3551 if (is_positive(a,contextptr)){ 3552 stepx=inv(a,contextptr); 3553 stepn=1; 3554 } 3555 else { 3556 stepx=-inv(a,contextptr); 3557 stepn=-1; 3558 } 3559 gen cur=borne_inf,next=(n1+stepn-b)/a,res=0; 3560 if (stepn==-1 && n1==a*borne_inf+b) 3561 n1 -= 1; 3562 for (;is_greater(borne_sup,next,contextptr); cur=next,next+=stepx,n1+=stepn){ 3563 tmp=quotesubst(v[0],lfloor.front(),n1,contextptr); 3564 res += _integrate(makesequence(tmp,x,cur,next),contextptr); 3565 #ifdef TIMEOUT 3566 control_c(); 3567 #endif 3568 if (ctrl_c || interrupted) { 3569 interrupted = true; ctrl_c=false; 3570 gensizeerr(gettext("Stopped by user interruption."),res); 3571 return res; 3572 } 3573 if (is_undef(res)) 3574 return res; 3575 } 3576 tmp=quotesubst(v[0],lfloor.front(),n1,contextptr); 3577 res += _integrate(makesequence(tmp,x,cur,borne_sup),contextptr); 3578 return ck_int_numerically(v0orig,x,aorig,borig,res,contextptr); 3579 } 3580 } 3581 v[0]=when2piecewise(v[0],contextptr); 3582 vecteur lpiece(lop(v[0],at_piecewise)); 3583 lpiece=lvarx(lpiece,x); 3584 if (!lpiece.empty()){ 3585 bool chsign=is_strictly_greater(borne_inf,borne_sup,contextptr); 3586 if (chsign) 3587 swapgen(borne_inf,borne_sup); 3588 res=0; 3589 gen piece=lpiece.front(); 3590 if (!piece.is_symb_of_sommet(at_piecewise)) 3591 return gensizeerr(contextptr); 3592 gen piecef=piece._SYMBptr->feuille; 3593 if (piecef.type!=_VECT || piecef._VECTptr->size()<2) 3594 return gensizeerr(contextptr); 3595 vecteur & piecev = *piecef._VECTptr; 3596 // check conditions: they must be linear wrt x 3597 int vs=int(piecev.size()); 3598 for (int i=0;i<vs/2;++i){ 3599 bool unable=true; 3600 gen cond=piecev[2*i]; 3601 if (is_zero(cond)) 3602 continue; 3603 if (is_one(cond)){ 3604 gen tmp=quotesubst(v[0],piece,piecev[2*i+1],contextptr); 3605 res += _integrate(gen(makevecteur(tmp,x,borne_inf,borne_sup),_SEQ__VECT),contextptr); 3606 return ck_int_numerically(v0orig,x,aorig,borig,(chsign?-res:res),contextptr); 3607 } 3608 if (is_equal(cond) || cond.is_symb_of_sommet(at_same)){ 3609 *logptr(contextptr) << gettext("Assuming false condition ") << cond << '\n'; 3610 continue; 3611 } 3612 if (cond.is_symb_of_sommet(at_different)){ 3613 *logptr(contextptr) << gettext("Assuming true condition ") << cond << '\n'; 3614 v[0]=quotesubst(v[0],piece,piecev[2*i+1],contextptr); 3615 res += _integrate(gen(makevecteur(v[0],x,borne_inf,borne_sup),_SEQ__VECT),contextptr); 3616 return ck_int_numerically(v0orig,x,aorig,borig,(chsign?-res:res),contextptr); 3617 } 3618 if (cond.is_symb_of_sommet(at_superieur_strict) || cond.is_symb_of_sommet(at_superieur_egal)){ 3619 cond=cond._SYMBptr->feuille[0]-cond._SYMBptr->feuille[1]; 3620 unable=false; 3621 } 3622 if (cond.is_symb_of_sommet(at_inferieur_strict) || cond.is_symb_of_sommet(at_inferieur_egal)){ 3623 cond=cond._SYMBptr->feuille[1]-cond._SYMBptr->feuille[0]; 3624 unable=false; 3625 } 3626 gen a,b,l; 3627 if (unable || !is_linear_wrt(cond,x,a,b,contextptr)){ 3628 *logptr(contextptr) << gettext("Piecewise definite integration: can only handle linear < or > condition") << '\n'; 3629 if (!tegral(v0orig,x,aorig,borig,1e-12,(1<<10),res,true,contextptr)) 3630 return undef; 3631 return res; 3632 } 3633 // check if a*x+b>0 on [borne_inf,borne_sup] 3634 l=-b/a; 3635 bool positif=ck_is_greater(a,0,contextptr); 3636 gen tmp=quotesubst(v[0],piece,piecev[2*i+1],contextptr); 3637 if (ck_is_greater(l,borne_sup,contextptr)){ 3638 // borne_inf < borne_sup <= l 3639 if (positif) // test is false, continue 3640 continue; 3641 // test is true we can compute the integral 3642 res += _integrate(gen(makevecteur(tmp,x,borne_inf,borne_sup),_SEQ__VECT),contextptr); 3643 return ck_int_numerically(v0orig,x,aorig,borig,(chsign?-res:res),contextptr); 3644 } 3645 if (ck_is_greater(borne_inf,l,contextptr)){ 3646 // l <= borne_inf < borne_sup 3647 if (!positif) // test is false, continue 3648 continue; 3649 // test is true we can compute the integral 3650 res += _integrate(gen(makevecteur(tmp,x,borne_inf,borne_sup),_SEQ__VECT),contextptr); 3651 return ck_int_numerically(v0orig,x,aorig,borig,(chsign?-res:res),contextptr); 3652 } 3653 // borne_inf<l<borne_sup 3654 if (positif){ 3655 // compute integral between l and borne_sup 3656 res += _integrate(gen(makevecteur(tmp,x,l,borne_sup),_SEQ__VECT),contextptr); 3657 borne_sup=l; // continue with integral from borne_inf to l 3658 continue; 3659 } 3660 // compute integral between borne_inf and l 3661 res += _integrate(gen(makevecteur(tmp,x,borne_inf,l),_SEQ__VECT),contextptr); 3662 borne_inf=l; // continue with integral from l to borne_sup 3663 } 3664 if (vs%2){ 3665 v[0]=quotesubst(v[0],piece,piecev[vs-1],contextptr); 3666 res += _integrate(gen(makevecteur(v[0],x,borne_inf,borne_sup),_SEQ__VECT),contextptr); 3667 } 3668 return ck_int_numerically(v0orig,x,aorig,borig,(chsign?-res:res),contextptr); // return chsign?-res:res; 3669 } // end piecewise 3670 if (intgab(v[0],x,borne_inf,borne_sup,res,contextptr)){ 3671 // additional check for singularities in ggb mode 3672 if (calc_mode(contextptr)==1 || abs_calc_mode(contextptr)==38){ 3673 bool ordonne=is_greater(borne_sup,borne_inf,contextptr); 3674 vecteur sp=protect_find_singularities(v[0],*x._IDNTptr,false,contextptr); 3675 int sps=int(sp.size()); 3676 for (int i=0;i<sps;i++){ 3677 if ( (ordonne && is_strictly_greater(sp[i],borne_inf,contextptr) && is_strictly_greater(borne_sup,sp[i],contextptr) ) || 3678 (!ordonne && is_strictly_greater(sp[i],borne_sup,contextptr) && is_strictly_greater(borne_inf,sp[i],contextptr) ) 3679 ){ 3680 if (!is_zero(limit(v[0]*(sp[i]-x),*x._IDNTptr,sp[i],0,contextptr))) 3681 return undef; 3682 } 3683 } 3684 } 3685 return res; 3686 } 3687 } 3688 gen primitive; 3689 // fast check if we are integrating over a period 3690 // if so we can shift integration to 3691 // simplify one of the functions 3692 if (s==4 && !is_inf(borne_sup) && !is_inf(borne_inf)){ 3693 gen v0ab=subst(v[0],x,x+borne_sup-borne_inf,false,contextptr)-v[0]; 3694 gen tmpv0ab=recursive_ratnormal(v0ab,contextptr); 3695 if (!contains(tmpv0ab,undef)) 3696 v0ab=tmpv0ab; 3697 if (is_zero(v0ab)){ 3698 vecteur l(rlvarx(v[0],x)); 3699 unsigned i=0; gen a,b; 3700 for (;i<l.size();++i){ 3701 if (l[i].type==_SYMB && is_linear_wrt(l[i]._SYMBptr->feuille,x,a,b,contextptr) && !is_zero(a) && !is_zero(b)) 3702 break; 3703 } 3704 if (i<l.size()){ 3705 vecteur vin=makevecteur(x,l[i]),vout=makevecteur(x-b/a,l[i]._SYMBptr->sommet(a*x,contextptr)); 3706 v[0]=subst(v[0],vin,vout,false,contextptr); 3707 } 3708 } 3709 } 3710 if (has_num_coeff(v[0])){ 3711 primitive=integrate0(exact(v[0],contextptr),*x._IDNTptr,rem,contextptr); 3712 primitive=evalf(primitive,1,contextptr); 3713 rem=evalf(rem,1,contextptr); 3714 } 3715 else 3716 primitive=integrate0(v[0],*x._IDNTptr,rem,contextptr); 3717 if (s==2 && calc_mode(contextptr)==1){ 3718 ++ggb_intcounter; 3719 primitive += diffeq_constante(ggb_intcounter,contextptr); 3720 } 3721 if (s==2){ 3722 if (is_zero(rem)) 3723 return primitive; 3724 return primitive + symbolic(at_integrate,gen(makevecteur(rem,x),_SEQ__VECT)); 3725 } 3726 // here s==4 3727 bool ordonne=is_greater(borne_sup,borne_inf,contextptr); 3728 bool desordonne=false; 3729 #ifdef NO_STDEXCEPT 3730 if (ordonne){ 3731 gen xval=assumeeval(x,contextptr); 3732 giac_assume(symb_and(symb_superieur_egal(x,borne_inf),symb_inferieur_egal(x,borne_sup)),contextptr); 3733 primitive=eval(primitive,1,contextptr); 3734 restorepurge(xval,x,contextptr); 3735 res=limit(primitive,*x._IDNTptr,borne_sup,-1,contextptr)-limit(primitive,*x._IDNTptr,borne_inf,1,contextptr); 3736 } 3737 else { 3738 if ( (desordonne=is_greater(borne_inf,borne_sup,contextptr) )){ 3739 gen xval=assumeeval(x,contextptr); 3740 giac_assume(symb_and(symb_superieur_egal(x,borne_sup),symb_inferieur_egal(x,borne_inf)),contextptr); 3741 restorepurge(xval,x,contextptr); 3742 res=limit(primitive,*x._IDNTptr,borne_sup,1,contextptr)-limit(primitive,*x._IDNTptr,borne_inf,-1,contextptr) ; 3743 } 3744 else 3745 res=limit(primitive,*x._IDNTptr,borne_sup,0,contextptr)-limit(primitive,*x._IDNTptr,borne_inf,0,contextptr); 3746 } 3747 #else 3748 try { 3749 if (ordonne){ 3750 gen xval=assumeeval(x,contextptr); 3751 giac_assume(symb_and(symb_superieur_egal(x,borne_inf),symb_inferieur_egal(x,borne_sup)),contextptr); 3752 primitive=eval(primitive,1,contextptr); 3753 restorepurge(xval,x,contextptr); 3754 gen rs=limit(primitive,*x._IDNTptr,borne_sup,-1,contextptr); 3755 gen ri=limit(primitive,*x._IDNTptr,borne_inf,1,contextptr); 3756 res=rs-ri; 3757 } 3758 else { 3759 if ( (desordonne=is_greater(borne_inf,borne_sup,contextptr) )){ 3760 gen xval=assumeeval(x,contextptr); 3761 giac_assume(symb_and(symb_superieur_egal(x,borne_sup),symb_inferieur_egal(x,borne_inf)),contextptr); 3762 restorepurge(xval,x,contextptr); 3763 res=limit(primitive,*x._IDNTptr,borne_sup,1,contextptr)-limit(primitive,*x._IDNTptr,borne_inf,-1,contextptr) ; 3764 } 3765 else 3766 res=limit(primitive,*x._IDNTptr,borne_sup,0,contextptr)-limit(primitive,*x._IDNTptr,borne_inf,0,contextptr); 3767 } 3768 } catch (std::runtime_error & e){ 3769 last_evaled_argptr(contextptr)=NULL; 3770 *logptr(contextptr) << "Error trying to find limit of " << primitive << '\n'; 3771 return symbolic(at_integrate,makesequence(v[0],x,borne_inf,borne_sup)); 3772 } 3773 #endif 3774 if (!lop(res,at_bounded_function).empty()) 3775 res=undef; 3776 if (is_undef(res)){ 3777 if (res.type==_STRNG && abs_calc_mode(contextptr)==38) 3778 return res; 3779 res=subst(primitive,*x._IDNTptr,borne_sup,false,contextptr)-subst(primitive,*x._IDNTptr,borne_inf,false,contextptr); 3780 } 3781 vecteur sp; 3782 gen prim2(primitive); 3783 // remove multiplicative constants to compute sp 3784 if (prim2.is_symb_of_sommet(at_prod)){ 3785 gen primf=prim2._SYMBptr->feuille; 3786 if (primf.type==_VECT){ 3787 vecteur primv=*primf._VECTptr,primv2; 3788 for (int i=0;i<primv.size();++i){ 3789 if (contains(lidnt(primv[i]),x)) 3790 primv2.push_back(primv[i]); 3791 } 3792 prim2=symbolic(at_prod,gen(primv2,_SEQ__VECT)); 3793 } 3794 } 3795 sp=lidnt(evalf(makevecteur(prim2,borne_inf,borne_sup),1,contextptr)); 3796 if (sp.size()>1){ 3797 *logptr(contextptr) << gettext("No checks were made for singular points of antiderivative ")+primitive.print(contextptr)+gettext(" for definite integration in [")+borne_inf.print(contextptr)+","+borne_sup.print(contextptr)+"]" << '\n' ; 3798 sp.clear(); 3799 } 3800 else { 3801 if ((is_inf(borne_inf) || evalf_double(borne_inf,1,contextptr).type==_DOUBLE_) 3802 && (is_inf(borne_sup) || evalf_double(borne_sup,1,contextptr).type==_DOUBLE_)){ 3803 gen xval=assumeeval(x,contextptr); 3804 if (is_greater(borne_sup,borne_inf,contextptr)) 3805 giac_assume(symb_and(symb_superieur_egal(x,borne_inf),symb_inferieur_egal(x,borne_sup)),contextptr); 3806 else 3807 giac_assume(symb_and(symb_superieur_egal(x,borne_sup),symb_inferieur_egal(x,borne_inf)),contextptr); 3808 sp=protect_find_singularities(primitive,*x._IDNTptr,2,contextptr); 3809 restorepurge(xval,x,contextptr); 3810 if (!lidnt(evalf_double(sp,1,contextptr)).empty()) 3811 return gensizeerr("Unable to handle singularities of "+ primitive.print(contextptr)+" at "+gen(sp).print(contextptr)); 3812 } 3813 else 3814 sp=protect_find_singularities(primitive,*x._IDNTptr,0,contextptr); 3815 if (is_undef(sp)){ 3816 *logptr(contextptr) << gettext("Unable to find singular points of antiderivative") << '\n' ; 3817 if (!tegral(v0orig,x,aorig,borig,1e-12,(1<<10),res,true,contextptr)) 3818 return undef; 3819 return res; 3820 } 3821 } 3822 // FIXME if v depends on an integer parameter, find values in inf,sup 3823 comprim(sp); 3824 int sps=int(sp.size()); 3825 for (int i=0;i<sps;i++){ 3826 if (sp[i].type==_DOUBLE_ || sp[i].type==_REAL || has_op(sp[i],*at_rootof)){ 3827 *logptr(contextptr) << gettext("Unable to handle approx. or algebraic extension singular point ")+sp[i].print(contextptr)+gettext(" of antiderivative"); 3828 if (!tegral(v0orig,x,aorig,borig,1e-12,(1<<10),res,true,contextptr)) 3829 return undef; 3830 return res; 3831 } 3832 if ( (ordonne && is_strictly_greater(sp[i],borne_inf,contextptr) && is_strictly_greater(borne_sup,sp[i],contextptr) ) || 3833 (desordonne && is_strictly_greater(sp[i],borne_sup,contextptr) && is_strictly_greater(borne_inf,sp[i],contextptr) ) 3834 ) 3835 res += limit(primitive,*x._IDNTptr,sp[i],-1,contextptr)-limit(primitive,*x._IDNTptr,sp[i],1,contextptr); 3836 } 3837 if (!is_zero(rem)){ 3838 if (is_inf(res)) 3839 return symbolic(at_integrate,gen(makevecteur(v[0],x,v[2],v[3]),_SEQ__VECT)); 3840 if (ordonne || !desordonne) 3841 res = res + symbolic(at_integrate,gen(makevecteur(rem,x,v[2],v[3]),_SEQ__VECT)); 3842 else 3843 res = res - symbolic(at_integrate,gen(makevecteur(rem,x,v[3],v[2]),_SEQ__VECT)); 3844 return res; 3845 } 3846 return ck_int_numerically(v0orig,x,aorig,borig,res,contextptr); 3847 } 3848 static const char _integrate_s []="integrate"; texprintasintegrate(const gen & g,const char * s_orig,GIAC_CONTEXT)3849 static string texprintasintegrate(const gen & g,const char * s_orig,GIAC_CONTEXT){ 3850 string s("\\int "); 3851 if (g.type!=_VECT) 3852 return s+gen2tex(g,contextptr); 3853 vecteur v(*g._VECTptr); 3854 int l(int(v.size())); 3855 if (!l) 3856 return s; 3857 if (l==1) 3858 return s+gen2tex(v.front(),contextptr); 3859 if (l==2) 3860 return s+gen2tex(v.front(),contextptr)+"\\, d"+gen2tex(v.back(),contextptr); 3861 if (l==4) 3862 return s+"_{"+gen2tex(v[2],contextptr)+"}^{"+gen2tex(v[3],contextptr)+"}"+gen2tex(v.front(),contextptr)+"\\, d"+gen2tex(v[1],contextptr); 3863 return s; 3864 } 3865 static define_unary_function_eval4_quoted (__integrate,&_integrate,_integrate_s,0,&texprintasintegrate); 3866 define_unary_function_ptr5( at_integrate ,alias_at_integrate,&__integrate,_QUOTE_ARGUMENTS,true); 3867 3868 // called by approx_area rombergo(const gen & f0,const gen & x,const gen & a_orig,const gen & b_orig,int n,GIAC_CONTEXT)3869 double rombergo(const gen & f0,const gen & x, const gen & a_orig, const gen & b_orig, int n,GIAC_CONTEXT){ 3870 //f est l'expression a integrer, x le nom de la variable, a et b les bornes 3871 // n si on veut faire 2^n subdivisions 3872 gen f=eval(f0,1,context0); // otherwise int(1/sqrt(x),x,0,1) fails on 38 3873 vector<double> T(n+1); 3874 //ligne du triangle de romberg avec T(n)=aire avec "pts du milieu" 3875 //avec 2^n subdivisions 3876 double h; 3877 gen at; 3878 //at sert a faire les substitutions c'est un gen = au debut a f((a+b)/2) 3879 //et en cours de prog egal a f(am) 3880 gen a=a_orig,b=b_orig; 3881 a=a.evalf(1,contextptr).evalf_double(1,contextptr); 3882 b=b.evalf(1,contextptr).evalf_double(1,contextptr); 3883 h=b._DOUBLE_val-a._DOUBLE_val; 3884 if (h==0) 3885 return 0; 3886 //h est la longueur de la subdivision 3887 //T[0] est l'aire du premier rectangle "pt milieu" f((a+b)/2)*(b-a) 3888 //puis T[j] = aire des rectangles "pt milieu" pour 2^j subdivisions 3889 double pui4; 3890 for (int j=0;j<=n;j++){ 3891 //chaque fois que j augmente de 1 on double le nombre de subdivisions 3892 3893 double ss; 3894 //ss est la somme provenant des valeurs de f aux points am ainsi rajoutes 3895 ss=0; 3896 gen am; 3897 3898 am=a+gen(h/2); 3899 if (is_exactly_zero(am-a)){ 3900 n=j-1; 3901 break; 3902 } 3903 while (is_greater(b,am,contextptr)){ 3904 at=subst(f,x,am,false,contextptr).evalf(1,contextptr); 3905 ss=ss+at._DOUBLE_val; 3906 am=am+gen(h); 3907 } 3908 //T[j] est la nouvelle valeur de l'aire calculee avec les "pts milieu" 3909 T[j]=ss*h; 3910 3911 h=h/2; 3912 } 3913 //pui4 est la valeur de 4^k 3914 pui4=1; 3915 for (int j=1;j<=n;j++){ 3916 pui4=pui4*4; 3917 for (int k=0;k<=n-j;k++){ 3918 //on calcule T[k] en appliquant la formule de rec. de romberg 3919 //avec T[j] qui contient a chaque etape l'integrale par les pts milieu 3920 T[k]=(pui4*T[k+1]-T[k])/(pui4-1); 3921 3922 } 3923 //on vient de remplir la kieme ligne on recommence avec j=j+1 3924 //on doit calculer les "pts du milieu" pour le nouv. j et le mettre ds T[j] 3925 } 3926 3927 3928 //c'est donc T[0] la meilleur approx de l'integrale 3929 return(T[0]); 3930 } 3931 3932 // Not linked currently rombergt(const gen & f,const gen & x,const gen & a,const gen & b,int n,GIAC_CONTEXT)3933 double rombergt(const gen & f,const gen & x, const gen & a, const gen & b, int n,GIAC_CONTEXT){ 3934 //f est l'expression a integrer, x le nom de la variable, a et b les bornes 3935 // n si on veut faire 2^n subdivisions 3936 vector<double> T(n+1); 3937 //ligne du triangle de romberg avec T(n)=trapezes avec 2^n subdivisions 3938 double h; 3939 gen at; 3940 //at sert a faire les substitutions c'est un gen egal au debut a f(a)+f(b) 3941 //et en cours de prog egal a f(am) 3942 h=b.evalf(1,contextptr)._DOUBLE_val-a.evalf(1,contextptr)._DOUBLE_val; 3943 if (h==0) 3944 return 0; 3945 //h est la longueur de la subdivision 3946 at=subst(f,x,b,false,contextptr).evalf(1,contextptr)+subst(f,x,a,false,contextptr).evalf(1,contextptr); 3947 T[0]=at._DOUBLE_val*h/2; 3948 //T[0] est l'aire du premier trapeze (f(a)+f(b))*(b-a)/2 3949 //puis T[j] = aire des trapezes pour 2^j subdivisions 3950 double pui4; 3951 for (int j=1;j<=n;j++){ 3952 //chaque fois que j augmente de 1 on double le nombre de subdivisions 3953 h=h/2; 3954 double ss; 3955 //ss est la somme provenant des valeurs de f aux points am ainsi rajoutes 3956 ss=0; 3957 gen am; 3958 am=a+gen(h); 3959 if (is_exactly_zero(am-a)){ 3960 n=j-1; 3961 break; 3962 } 3963 while (is_greater(b,am,contextptr)){ 3964 at=subst(f,x,am,false,contextptr).evalf(1,contextptr); 3965 ss=ss+at._DOUBLE_val; 3966 am=am+gen(2*h); 3967 } 3968 //T[j] est la nouvelle valeur de l'aire des trapezes 3969 T[j]=T[j-1]/2+ss*h; 3970 //pui4 est la valeur de 4^k 3971 pui4=1; 3972 for (int k=j-1;k>=0;k--){ 3973 pui4=pui4*4; 3974 //on calcule T[k] en appliquant la formule de rec. de romberg 3975 //avec T[j] qui contient a chaque etape l'integrale par les trapezes 3976 T[k]=(pui4*T[k+1]-T[k])/(pui4-1); 3977 } 3978 //on vient de remplir la kieme ligne on recommence avec j=j+1 3979 //on doit calculer les trapezes pour le nouveau j et le mettre ds T[j] 3980 } 3981 //c'est donc T[0] la meilleur approx de l'integrale 3982 return(T[0]); 3983 } 3984 3985 // find approx value of int(f) using Gauss quadrature with s=15 (order 30) 3986 // returns approx value of int(f), of int(abs(f)) and error estimate 3987 // error estimated using embedded order 14 and 6 method as 3988 // err1=abs(i30-i14); err2=abs(i30-i6); err1*(err1/err2)^2 3989 #if 0 3990 static bool tegral_util(const gen & f,const gen &x, const gen &a,const gen &b,gen & i30,gen & i30abs, gen &err,GIAC_CONTEXT){ 3991 gen h=evalf_double(b-a,1,contextptr),i14,i6; 3992 int s30=15,s14=14,s6=6; 3993 long_double c30[]={0.60037409897572857552e-2,0.31363303799647047846e-1,0.75896708294786391900e-1,0.13779113431991497629,0.21451391369573057623,0.30292432646121831505,0.39940295300128273885,0.50000000000000000000,0.60059704699871726115,0.69707567353878168495,0.78548608630426942377,0.86220886568008502371,0.92410329170521360810,0.96863669620035295215,0.99399625901024271424}; 3994 long_double b30[]={0.15376620998058634177e-1,0.35183023744054062355e-1,0.53579610233585967506e-1,0.69785338963077157224e-1,0.83134602908496966777e-1,0.93080500007781105513e-1,0.99215742663555788228e-1,0.10128912096278063644,0.99215742663555788228e-1,0.93080500007781105514e-1,0.83134602908496966777e-1,0.69785338963077157224e-1,0.53579610233585967507e-1,0.35183023744054062355e-1,0.15376620998058634177e-1}; 3995 long_double b14[]={0.21474028217339757006e-1,0.14373155100418764102e-1,0.92599218105237092609e-1,0.11827741709315709983e-1,0.15847003639679458478,0.38429189419875016111e-2,0.19741290152890658991,0.19741290152890658991,0.38429189419875016111e-2,0.15847003639679458478,0.11827741709315709983e-1,0.92599218105237092608e-1,0.14373155100418764102e-1,0.21474028217339757006e-1}; 3996 long_double b6[]={0.10715760948621577132,0.31130901929813818033e-1,0.36171148858397041065,0,0.36171148858397041065,0.31130901929813818033e-1,0.10715760948621577132}; 3997 vecteur v30(15),v30abs(15); 3998 for (int i=0;i<15;i++){ 3999 v30[i]=evalf_double(subst(f,x,a+double(c30[i])*h,false,contextptr),1,contextptr); 4000 v30abs[i]=_l2norm(v30[i],contextptr); 4001 if (v30abs[i].type!=_DOUBLE_) 4002 return false; 4003 } 4004 i30abs=i30=i14=i6=0; 4005 for (int i=0;i<15;i++){ 4006 i30 += double(b30[i])*v30[i]; 4007 i30abs += double(b30[i])*v30abs[i]; 4008 } 4009 for (int i=0;i<=6;i++){ 4010 i14 += double(b14[i])*v30[i]; 4011 } 4012 for (int i=8;i<=14;i++){ 4013 i14 += double(b14[i-1])*v30[i]; 4014 } 4015 for (int i=1;i<15;i+=2){ 4016 if (i==7) 4017 continue; 4018 i6 += double(b6[(i-1)/2])*v30[i]; 4019 } 4020 i30 = i30*h; 4021 i30abs = i30abs*h; 4022 i14 = i14*h; 4023 i6 = i6*h; 4024 gen err1=_l2norm(i30-i14,contextptr); 4025 gen err2=_l2norm(i30-i6,contextptr); 4026 // check if err1 and err2 corresponds to errors in h^14 and h^6 4027 if (is_greater(abs(14./6.-ln(err1,contextptr)/ln(err2,contextptr)),.1,contextptr)) 4028 err=err1; 4029 else { 4030 err=err1/err2; 4031 err=err1*(err*err); 4032 } 4033 return true; 4034 } 4035 #else // using -1..1 scaling instead of 0..1 tegral_util(const gen & f,const gen & x,const gen & a,const gen & b,gen & i30,gen & i30abs,gen & err,GIAC_CONTEXT)4036 static bool tegral_util(const gen & f,const gen &x, const gen &a,const gen &b,gen & i30,gen & i30abs, gen &err,GIAC_CONTEXT){ 4037 gen h=evalf_double(b-a,1,contextptr),i14,i6; 4038 //int s30=15,s14=14,s6=6; 4039 long_double c30[]={-0.98799251802048542849,-0.93727339240070590430,-0.84820658341042721620,-0.72441773136017004742,-0.57097217260853884754,-0.39415134707756336990,-0.20119409399743452230,0.00000000000000000000,0.20119409399743452230,0.39415134707756336990,0.57097217260853884754,0.72441773136017004742,0.84820658341042721620,0.93727339240070590430,0.98799251802048542849}; 4040 long_double b30[]={0.15376620998058634177e-1,0.35183023744054062355e-1,0.53579610233585967506e-1,0.69785338963077157224e-1,0.83134602908496966777e-1,0.93080500007781105513e-1,0.99215742663555788228e-1,0.10128912096278063644,0.99215742663555788228e-1,0.93080500007781105514e-1,0.83134602908496966777e-1,0.69785338963077157224e-1,0.53579610233585967507e-1,0.35183023744054062355e-1,0.15376620998058634177e-1}; 4041 long_double b14[]={0.21474028217339757006e-1,0.14373155100418764102e-1,0.92599218105237092609e-1,0.11827741709315709983e-1,0.15847003639679458478,0.38429189419875016111e-2,0.19741290152890658991,0.19741290152890658991,0.38429189419875016111e-2,0.15847003639679458478,0.11827741709315709983e-1,0.92599218105237092608e-1,0.14373155100418764102e-1,0.21474028217339757006e-1}; 4042 long_double b6[]={0.10715760948621577132,0.31130901929813818033e-1,0.36171148858397041065,0,0.36171148858397041065,0.31130901929813818033e-1,0.10715760948621577132}; 4043 vecteur v30(15),v30abs(15); 4044 for (int i=0;i<15;i++){ 4045 v30[i]=evalf_double(eval(subst(f,x,((a+b)+double(c30[i])*h)/2,false,contextptr),1,contextptr),1,contextptr); 4046 v30abs[i]=_l2norm(v30[i],contextptr); 4047 if (v30abs[i].type!=_DOUBLE_) 4048 return false; 4049 } 4050 i30abs=i30=i14=i6=0; 4051 for (int i=0;i<=7;i++){ 4052 i30 += double(b30[i])*v30[i]; 4053 if (i<7) 4054 i30 += double(b30[14-i])*v30[14-i]; 4055 i30abs += double(b30[i])*v30abs[i]; 4056 if (i<7) 4057 i30abs += double(b30[14-i])*v30abs[14-i]; 4058 } 4059 for (int i=0;i<=6;i++){ 4060 i14 += double(b14[i])*v30[i]; 4061 } 4062 for (int i=8;i<=14;i++){ 4063 i14 += double(b14[i-1])*v30[i]; 4064 } 4065 for (int i=1;i<15;i+=2){ 4066 if (i==7) 4067 continue; 4068 i6 += double(b6[(i-1)/2])*v30[i]; 4069 } 4070 i30 = i30*h; 4071 i30abs = i30abs*h; 4072 i14 = i14*h; 4073 i6 = i6*h; 4074 gen err1=_l2norm(i30-i14,contextptr); 4075 gen err2=_l2norm(i30-i6,contextptr); 4076 if (is_exactly_zero(err1) || is_exactly_zero(err2)) 4077 err=0; 4078 else { 4079 // check if err1 and err2 corresponds to errors in h^14 and h^6 4080 if (is_greater(abs(14./6.-ln(err1,contextptr)/ln(err2,contextptr)),.1,contextptr)) 4081 err=err1; 4082 else { 4083 err=err1/err2; 4084 err=err1*(err*err); 4085 } 4086 } 4087 return true; 4088 } 4089 #endif 4090 approxint_exact(const gen & f,const gen & x,GIAC_CONTEXT)4091 bool approxint_exact(const gen &f,const gen &x,GIAC_CONTEXT){ 4092 if (!lop(f,at_when).empty() || !lop(f,at_piecewise).empty()) 4093 return false; 4094 if (!loptab(Heavisidetosign(f,contextptr),sign_floor_ceil_round_tab).empty() ) 4095 return false; 4096 if (f.type!=_SYMB || is_constant_wrt(f,x,contextptr)) 4097 return true; 4098 unary_function_ptr & u=f._SYMBptr->sommet; 4099 gen g=f._SYMBptr->feuille,a,b,c; 4100 if (u==at_exp) 4101 return is_quadratic_wrt(g,x,a,b,c,contextptr); 4102 if (u==at_sin || u==at_cos) 4103 return is_linear_wrt(g,x,a,b,contextptr); 4104 if (g.type!=_VECT) return false; 4105 const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end(); 4106 if (u==at_plus){ 4107 for (;it!=itend;++it){ 4108 if (!approxint_exact(*it,x,contextptr)) 4109 return false; 4110 } 4111 return true; 4112 } 4113 if (u==at_prod){ 4114 for (;it!=itend;++it){ 4115 if (is_constant_wrt(*it,x,contextptr)) 4116 continue; 4117 if (!is_zero(a)) 4118 return false; 4119 a=*it; 4120 } 4121 return approxint_exact(a,x,contextptr); 4122 } 4123 return false; 4124 } 4125 4126 // nmax=max number of subdivisions (may be 1000 or more...) tegral(const gen & f,const gen & x,const gen & a_,const gen & b_,const gen & eps,int nmax,gen & value,bool exactcheck,GIAC_CONTEXT)4127 bool tegral(const gen & f,const gen & x,const gen & a_,const gen &b_,const gen & eps,int nmax,gen & value,bool exactcheck,GIAC_CONTEXT){ 4128 gen a=evalf(a_,1,contextptr),b=evalf(b_,1,contextptr); 4129 if (a==b){ 4130 value=0.0; 4131 return true; 4132 } 4133 if (exactcheck){ 4134 vecteur vf(1,x); 4135 rlvarx(f,x,vf); 4136 if (0 && vf.size()<=1){ // dangerous 4137 gen r,F=linear_integrate(exact(f,contextptr),x,r,contextptr); 4138 value=_limit(makesequence(F,x,exact(b,contextptr),-1),contextptr)-_limit(makesequence(F,x,exact(a,contextptr),1),contextptr); 4139 value=evalf(value,1,contextptr); 4140 return true; 4141 } 4142 if (approxint_exact(f,x,contextptr)){ 4143 gen r,F=linear_integrate(f,x,r,contextptr); 4144 if (is_zero(r)){ 4145 value=subst(F,x,b,false,contextptr)-subst(F,x,a,false,contextptr); 4146 return true; 4147 } 4148 } 4149 } 4150 // adaptive integration, cf. Hairer 4151 gen i30,i30abs,err,maxerr,ERR,I30ABS; 4152 int maxerrpos; 4153 if (!tegral_util(f,x,a,b,i30,i30abs,err,contextptr)) 4154 return false; 4155 vecteur v(1,makevecteur(a,b,i30,i30abs,err)); 4156 for (;int(v.size())<nmax;){ 4157 // sum of errors, check for end 4158 i30=I30ABS=ERR=maxerr=0; 4159 maxerrpos=0; 4160 for (unsigned i=0;i<v.size();++i){ 4161 if (v[i].type!=_VECT || v[i]._VECTptr->size()<5) 4162 return false; 4163 vecteur w=*v[i]._VECTptr; 4164 i30 = i30+w[2]; // += does not work in emscripten 4165 I30ABS = I30ABS+w[3]; 4166 ERR = ERR+w[4]; 4167 if (is_strictly_greater(w[4],maxerr,contextptr)){ 4168 maxerrpos=i; 4169 maxerr=w[4]; 4170 } 4171 } 4172 value=i30; 4173 // could add a minimal number of intervals for integrals like 4174 // integrate(when(x > 2, 1,2),x,0,2.01) or int(frac(x),x,0,6.01) 4175 // but one will always find intervals where this would fail 4176 if (!is_undef(ERR) && is_greater(eps,ERR/I30ABS,contextptr)) 4177 return true; 4178 // cut interval at maxerrpos in 2 parts 4179 vecteur & w = *v[maxerrpos]._VECTptr; 4180 gen A=w[0],B=w[1],C=(A+B)/2; 4181 if (A==C || B==C){ 4182 // can not subdivise anymore 4183 if (is_greater(1e-4,ERR/I30ABS,contextptr)){ 4184 *logptr(contextptr) << "Low accuracy, error estimate " << ERR/I30ABS << "\nError might be underestimated if initial boundary was +/-infinity" << '\n'; 4185 return true; 4186 } 4187 return false; 4188 } 4189 if (!tegral_util(f,x,A,C,i30,i30abs,err,contextptr)){ 4190 if (is_greater(1e-4,ERR/I30ABS,contextptr)){ 4191 *logptr(contextptr) << "Low accuracy, error estimate " << ERR/I30ABS << "\nError might be underestimated if initial boundary was +/-infinity" << '\n'; 4192 return true; 4193 } 4194 return false; 4195 } 4196 v[maxerrpos]=makevecteur(A,C,i30,i30abs,err); 4197 if (!tegral_util(f,x,C,B,i30,i30abs,err,contextptr)){ 4198 if (is_greater(1e-4,ERR/I30ABS,contextptr)){ 4199 *logptr(contextptr) << "Low accuracy, error estimate " << ERR/I30ABS << "\nError might be underestimated if initial boundary was +/-infinity" << '\n'; 4200 return true; 4201 } 4202 return false; 4203 } 4204 v.push_back(makevecteur(C,B,i30,i30abs,err)); 4205 } 4206 return false; // too many iterations 4207 } 4208 romberg(const gen & f0,const gen & x0,const gen & a,const gen & b,const gen & eps,int nmax,GIAC_CONTEXT)4209 gen romberg(const gen & f0,const gen & x0,const gen & a,const gen &b,const gen & eps,int nmax,GIAC_CONTEXT){ 4210 return evalf_int(f0,x0,a,b,eps,nmax,true,contextptr,false); 4211 } evalf_int(const gen & f0,const gen & x0,const gen & a,const gen & b,const gen & eps,int nmax,bool romberg_method,GIAC_CONTEXT,bool exactcheck)4212 gen evalf_int(const gen & f0,const gen & x0,const gen & a,const gen &b,const gen & eps,int nmax,bool romberg_method,GIAC_CONTEXT,bool exactcheck){ 4213 gen x(x0),f(f0); 4214 if (x.type!=_IDNT){ 4215 x=identificateur(" x"); 4216 f=subst(f,x0,x,false,contextptr); 4217 } 4218 gen value=undef; 4219 if (!romberg_method && tegral(f,x,a,b,eps,(1 << nmax),value,exactcheck,contextptr)) 4220 return value; 4221 if (!romberg_method) 4222 *logptr(contextptr) << "Adaptive method failure, will try with Romberg, last approximation was " << value << '\n'; 4223 // a, b and eps should be evalf-ed, and eps>0 4224 gen h=b-a; 4225 vecteur old_line,cur_line; 4226 #ifdef NO_STDEXCEPT 4227 old_line.push_back(evalf(h*(limit(f,*x._IDNTptr,a,1,contextptr)+limit(f,*x._IDNTptr,b,-1,contextptr))/2,eval_level(contextptr),contextptr)); 4228 #else 4229 try { 4230 old_line.push_back(evalf(h*(limit(f,*x._IDNTptr,a,1,contextptr)+limit(f,*x._IDNTptr,b,-1,contextptr))/2,eval_level(contextptr),contextptr)); 4231 } catch (std::runtime_error & ){ 4232 last_evaled_argptr(contextptr)=NULL; 4233 old_line=vecteur(1,undef); 4234 } 4235 #endif 4236 if (is_inf(old_line[0])|| is_undef(old_line[0]) || !lop(old_line[0],at_bounded_function).empty()){ 4237 // FIXME middle point in arbitrary precision 4238 *logptr(contextptr) << gettext("Infinity or undefined limit at bounds.\nUsing middle point Romberg method") << '\n'; 4239 gen y=(a+b)/2; 4240 gen fy=subst(f,x,y,false,contextptr); 4241 // Workaround for undefined middle point 4242 if (is_undef(fy) || is_inf(fy)){ 4243 fy=limit(f,*x._IDNTptr,y,0,contextptr); 4244 if (is_undef(fy) || is_inf(fy)) 4245 return undef; 4246 } 4247 old_line=vecteur(1,fy*h); 4248 // At the i-th step of the loop compute the middle approx of the integral 4249 // and use old_line to compute cur_line 4250 nmax=int(2.*nmax/3.+0.5); 4251 int n=3; 4252 h=(b-a)/3; 4253 for (int i=0;i<nmax;++i){ 4254 cur_line.clear(); 4255 // compute trapeze 4256 gen y=a+h/2,sum; 4257 if (is_exactly_zero(y-a)) 4258 return old_line; 4259 for (int j=0;j<n;++j){ 4260 if (j%3==1){ 4261 y=y+h; // skip, already computed 4262 continue; 4263 } 4264 gen fy=subst(f,x,y,false,contextptr); 4265 // Workaround if fy undefined 4266 if (is_undef(fy) || is_inf(fy)){ 4267 fy=limit(f,*x._IDNTptr,y,0,contextptr); 4268 if (is_undef(fy) || is_inf(fy)) 4269 return undef; 4270 } 4271 sum=sum+evalf(fy,eval_level(contextptr),contextptr); 4272 y=y+h; 4273 } 4274 cur_line.push_back(old_line[0]/3+sum*h); 4275 h=h/3; 4276 n = 3*n ; 4277 gen pui9=1; 4278 for (int j=0;j<=i;++j){ 4279 pui9=9*pui9; 4280 cur_line.push_back((pui9*cur_line[j]-old_line[j])/(pui9-1)); 4281 } 4282 gen err=abs(old_line[i]-cur_line[i+1],contextptr); 4283 if (i>nmax/2 && (ck_is_greater(eps,err,contextptr) 4284 || ck_is_greater(eps*abs(cur_line[i+1],contextptr),err,contextptr)) ) 4285 return (old_line[i]+cur_line[i+1])/2; 4286 if (i!=nmax-1) 4287 old_line=cur_line; 4288 } 4289 if (calc_mode(contextptr)==1) 4290 return undef; 4291 *logptr(contextptr) << gettext("Unable to find numeric integral using Romberg method, returning the last approximations") << '\n'; 4292 cur_line=is_undef(value)?makevecteur(old_line.back(),cur_line.back()):makevecteur(cur_line.back(),value); 4293 return cur_line; 4294 // return rombergo(f,x,a,b,nmax,contextptr); 4295 } 4296 int n=1; 4297 // At the i-th step of the loop compute the trapeze approx of the integral 4298 // and use old_line to compute cur_line 4299 for (int i=0;i<nmax;++i){ 4300 cur_line.clear(); 4301 // compute trapeze 4302 gen y=a+h/2,sum; 4303 if (is_exactly_zero(y-a)) 4304 return old_line; 4305 for (int j=0;j<n;++j){ 4306 gen fy=subst(f,x,y,false,contextptr); 4307 // Workaround for romberg((1-cos(x))/x^2,x,-1,1)? 4308 if (is_undef(fy) || is_inf(fy)){ 4309 fy=limit(f,*x._IDNTptr,y,0,contextptr); 4310 if (is_undef(fy) || is_inf(fy)) 4311 return undef; 4312 } 4313 sum=sum+evalf(fy,eval_level(contextptr),contextptr); 4314 y=y+h; 4315 } 4316 h=h/2; 4317 cur_line.push_back(old_line[0]/2+sum*h); 4318 n = 2*n ; 4319 gen pui4=1; 4320 for (int j=0;j<=i;++j){ 4321 pui4=4*pui4; 4322 cur_line.push_back((pui4*cur_line[j]-old_line[j])/(pui4-1)); 4323 } 4324 gen err=abs(old_line[i]-cur_line[i+1],contextptr); 4325 if (i>nmax/2 && (ck_is_greater(eps,err,contextptr) 4326 || ck_is_greater(eps*abs(cur_line[i+1],contextptr),err,contextptr)) ) 4327 return (old_line[i]+cur_line[i+1])/2; 4328 if (i!=nmax-1) 4329 old_line=cur_line; 4330 } 4331 if (calc_mode(contextptr)==1) 4332 return undef; 4333 *logptr(contextptr) << gettext("Unable to find numeric integral using Romberg method, returning the last approximations") << '\n'; 4334 cur_line=is_undef(value)?makevecteur(old_line.back(),cur_line.back()):makevecteur(cur_line.back(),value); 4335 return cur_line; 4336 } ggb_var(const gen & f)4337 gen ggb_var(const gen & f){ 4338 vecteur l=lidnt(makevecteur(cst_pi,unsigned_inf,undef,f)); 4339 l=vecteur(l.begin()+3,l.end()); 4340 if (l.empty() || equalposcomp(l,vx_var)) 4341 return vx_var; 4342 const_iterateur it=l.begin(),itend=l.end(); 4343 for (;it!=itend;++it){ 4344 string s=it->print(context0); 4345 if (s[s.size()-1]=='x') 4346 return *it; 4347 } 4348 return l.front(); 4349 } intnum(const gen & args,bool romberg_method,GIAC_CONTEXT,bool exactcheck)4350 gen intnum(const gen & args,bool romberg_method,GIAC_CONTEXT,bool exactcheck){ 4351 if ( args.type==_STRNG && args.subtype==-1) return args; 4352 if ( (args.type!=_VECT) || (args._VECTptr->size()<2) ) 4353 return gensizeerr(contextptr); 4354 const_iterateur it=args._VECTptr->begin(),itend=args._VECTptr->end(); 4355 gen f=*it; 4356 ++it; 4357 gen x=*it,a,b; 4358 if (it<itend-1){ 4359 ++it; 4360 a=*it; 4361 ++it; 4362 if (it<itend) 4363 b=*it; 4364 else { 4365 b=a; 4366 a=x; 4367 x=ggb_var(f); 4368 --it; 4369 } 4370 } 4371 else { 4372 bool ok=false; 4373 if (is_equal(x)){ 4374 a=x._SYMBptr->feuille; 4375 if (a.type==_VECT && a._VECTptr->size()==2){ 4376 x=a._VECTptr->front(); 4377 a=a._VECTptr->back(); 4378 if (a.is_symb_of_sommet(at_interval)){ 4379 a=a._SYMBptr->feuille; 4380 if (a.type==_VECT && a._VECTptr->size()==2){ 4381 b=a._VECTptr->back(); 4382 a=a._VECTptr->front(); 4383 ok=true; 4384 } 4385 } 4386 } 4387 } 4388 if (!ok) 4389 return symbolic(at_integrate,args); 4390 } 4391 if (is_inf(a) || is_inf(b)){ // change of variables x=tan(t), t=atan(x) 4392 gen tanx(tan(x,contextptr)); 4393 f=subst(f,x,tanx,false,contextptr)*(1+pow(tanx,2)); 4394 a=atan(a,contextptr); 4395 b=atan(b,contextptr); 4396 gen res=intnum(makesequence(f,x,a,b),romberg_method,contextptr,exactcheck); 4397 if (!angle_radian(contextptr)) 4398 { 4399 if(angle_degree(contextptr)) 4400 res=deg2rad_d*res; 4401 //grad 4402 else 4403 res = grad2rad_d*res; 4404 } 4405 return res; 4406 } 4407 a=a.evalf(1,contextptr); 4408 b=b.evalf(1,contextptr); 4409 if (a.type==_FLOAT_) a=evalf_double(a,1,contextptr); 4410 if (b.type==_FLOAT_) b=evalf_double(b,1,contextptr); 4411 ++it; 4412 gen eps(epsilon(contextptr)); 4413 int n=11; 4414 if (it!=itend){ 4415 eps=evalf(abs(*it,contextptr),1,contextptr); 4416 ++it; 4417 if (it!=itend && it->type==_INT_) 4418 n=it->val; 4419 } 4420 if (eps.type!=_DOUBLE_ && eps.type!=_FLOAT_ && eps.type!=_REAL) 4421 eps=epsilon(contextptr); 4422 if ( x.type!=_IDNT || 4423 (a.type!=_DOUBLE_ && a.type!=_REAL) 4424 || (b.type!=_DOUBLE_ && b.type!=_REAL) 4425 ) 4426 return symbolic(at_integrate,args); 4427 return evalf_int(f,x,a,b,eps,n,romberg_method,contextptr,exactcheck); 4428 } _romberg(const gen & args,GIAC_CONTEXT)4429 gen _romberg(const gen & args,GIAC_CONTEXT) { 4430 return intnum(args,true,contextptr,false); 4431 } 4432 static const char _romberg_s []="romberg"; 4433 static define_unary_function_eval (__romberg,&_romberg,_romberg_s); 4434 define_unary_function_ptr5( at_romberg ,alias_at_romberg,&__romberg,0,true); 4435 _gaussquad(const gen & args,GIAC_CONTEXT)4436 gen _gaussquad(const gen & args,GIAC_CONTEXT) { 4437 return intnum(args,false,contextptr,false); 4438 } 4439 static const char _gaussquad_s []="gaussquad"; 4440 static define_unary_function_eval (__gaussquad,&_gaussquad,_gaussquad_s); 4441 define_unary_function_ptr5( at_gaussquad ,alias_at_gaussquad,&__gaussquad,0,true); 4442 4443 /********************************************************************** 4444 * Desc: Solve P(x+1)-P(x)=Q(x) 4445 * Algo: degree of P=degree of Q+1, constant coeff 0 4446 * If P=Sigma a_k x^k then write linear system for a_k 4447 * Columns of the matrix of the system are lines 4448 * of the Pascal triangle without the first element 4449 * (since we must substract identity matrix to the triangle) 4450 * a_1 a_2 a_3 ... a_n+1 coeff of Q 4451 * 1 1 1 1 X^0 4452 * 0 2 3 n+1 X^1 4453 * 0 0 3 ... X^2 4454 * 0 0 0 n+1 X^n 4455 **********************************************************************/ solveP_x_plus_1_minus_P_x(const vecteur & Q)4456 static vecteur solveP_x_plus_1_minus_P_x(const vecteur & Q){ 4457 vecteur v(1,plus_one); 4458 matrice m; 4459 int n=int(Q.size()); 4460 for (int i=0;i<n;++i){ 4461 v=pascal_next_line(v); 4462 vecteur v_copy(v); 4463 if (i!=n-1){ 4464 v_copy[i+1]=zero; 4465 for (int j=0;j<n-i-2;j++) 4466 v_copy.push_back(zero); 4467 } 4468 else 4469 v_copy.pop_back(); 4470 m.push_back(v_copy); 4471 } 4472 vecteur Q_copy(Q); 4473 reverse(Q_copy.begin(),Q_copy.end()); 4474 m.push_back(Q_copy); 4475 m=mtran(m); 4476 // reduce matrix, solution P are diag coeff in reverse order 4477 m=mrref(m,context0); // ok 4478 vecteur res(n+1); 4479 for (int i=0;i<n;++i) 4480 res[n-i-1]=rdiv(m[i][n],m[i][i],context0); 4481 return res; 4482 4483 } 4484 4485 // true if v2[x]=v1[x-n], false otherwise is_shift_of(const vecteur & v1,const vecteur & v2,int & n)4486 static bool is_shift_of(const vecteur & v1,const vecteur &v2,int & n){ 4487 int s1=int(v1.size()),s2=int(v2.size()); 4488 if (s1!=s2 || v1[0]!=v2[0]) 4489 return false; 4490 if (s1<2) 4491 return false; // setsizeerr(contextptr); 4492 gen e=(v1[1]-v2[1])/v1[0]; 4493 if (e.type!=_INT_) 4494 return false; 4495 if (e.val % (s1-1)) 4496 return false; 4497 n=e.val / (s1-1); 4498 return v1==taylor(v2,n); 4499 } 4500 rational_sum(const gen & e,const gen & x,gen & res,gen & remains_to_sum,bool allow_psi,GIAC_CONTEXT)4501 bool rational_sum(const gen & e,const gen & x,gen & res,gen& remains_to_sum,bool allow_psi,GIAC_CONTEXT){ 4502 // first detect rational fraction 4503 vecteur v(lvarxpow(e,x)); 4504 if (v.empty()){ 4505 res = e*x; 4506 remains_to_sum = 0; 4507 return true; 4508 } 4509 if ( (v.size()!=1) || (v.front()!=x) ){ 4510 remains_to_sum=e; 4511 return false; 4512 } 4513 lvar(e,v); 4514 gen r=e2r(e,v,contextptr),r_num,r_den; 4515 fxnd(r,r_num,r_den); 4516 if (r_num.type==_EXT){ 4517 remains_to_sum=e; 4518 return false; 4519 } 4520 if ((r_den.type!=_POLY) || (!r_den._POLYptr->lexsorted_degree())){ // polynomial w.r.t. x 4521 vecteur Q; 4522 if (r_num.type!=_POLY){ 4523 res=r_num*v.front()/r2e(r,v,contextptr); 4524 return true; 4525 } 4526 Q=polynome2poly1(*r_num._POLYptr,1); 4527 vecteur P(solveP_x_plus_1_minus_P_x(Q)); 4528 gen den; 4529 lcmdeno(P,den,contextptr); // lcmdeno_converted? 4530 r_num=poly12polynome(P,1,r_num._POLYptr->dim); 4531 r=rdiv(r_num,r_den*den,contextptr); 4532 res=r2e(r,v,contextptr); 4533 return true; 4534 } 4535 // rational fraction wrt x 4536 int s=r_den._POLYptr->dim; 4537 polynome den(*r_den._POLYptr),num(s); 4538 if (r_num.type==_POLY) 4539 num=*r_num._POLYptr; 4540 else 4541 num=polynome(r_num,s); 4542 polynome p_content(s); 4543 // partial fraction decomposition 4544 factorization vden; 4545 gen extra_div=1; 4546 factor(den,p_content,vden,false,/* withsqrt */false,/* complex */ true,1,extra_div); 4547 vector< pf<gen> > pfdecomp; 4548 polynome ipnum(s),ipden(s); 4549 partfrac(num,den,vden,pfdecomp,ipnum,ipden); 4550 // discrete antiderivative of integral part 4551 vecteur Q(polynome2poly1(ipnum,1)); 4552 vecteur P(solveP_x_plus_1_minus_P_x(Q)); 4553 ipnum=poly12polynome(P,1,ipnum.dim); 4554 r=rdiv(ipnum,ipden,contextptr); 4555 res=r2e(r,v,contextptr); 4556 int vdim=int(v.size()); 4557 // detect integral shifted denominators 4558 vector<pf1> shiftfree_pfdecomp; 4559 vector< pf<gen> >::iterator it=pfdecomp.begin(); 4560 vector< pf<gen> >::const_iterator itend=pfdecomp.end(); 4561 for (;it!=itend;++it){ 4562 vecteur it_fact(polynome2poly1(it->fact,1)); 4563 vector<pf1>::iterator jt=shiftfree_pfdecomp.begin(); 4564 vector<pf1>::const_iterator jtend=shiftfree_pfdecomp.end(); 4565 int k; 4566 for (;jt!=jtend;++jt){ 4567 if (is_shift_of(it_fact,jt->fact,k)) 4568 break; 4569 } 4570 if (jt==jtend) 4571 shiftfree_pfdecomp.push_back(pf1(it->num,it->den,it->fact,it->mult)); 4572 else { // it_fact is the shift of jt->fact 4573 vecteur it_num(polynome2poly1(it->num,1)),it_den(polynome2poly1(it->den,1)); 4574 // check which one has the highest multiplicity 4575 if (jt->mult<it->mult){ // we must swap to keep highest mult in *jt 4576 std::swap(jt->num,it_num); 4577 std::swap(jt->den,it_den); 4578 std::swap(jt->fact,it_fact); 4579 std::swap(jt->mult,it->mult); 4580 k=-k; 4581 } 4582 // do the shift (this will modify jt->num and the result res) 4583 int decal; 4584 if (k<0){ 4585 decal=1; 4586 k=-k; 4587 } 4588 else 4589 decal=-1; 4590 for (int j=0;j<k;++j){ 4591 if (decal>0) 4592 res=res-rdiv(r2e(poly12polynome(it_num,1,vdim),v,contextptr),r2e(poly12polynome(it_den,1,vdim),v,contextptr),contextptr); 4593 it_num=taylor(it_num,decal); 4594 it_den=taylor(it_den,decal); 4595 if (decal<0) 4596 res=res+rdiv(r2e(poly12polynome(it_num,1,vdim),v,contextptr),r2e(poly12polynome(it_den,1,vdim),v,contextptr),contextptr); 4597 } 4598 modpoly constante=jt->den/it_den; 4599 gen const_den; 4600 lcmdeno(constante,const_den,contextptr); // lcmdeno_converted? 4601 // should check if constante is a fraction 4602 jt->num=constante*it_num+const_den*jt->num; 4603 jt->den=const_den*jt->den; 4604 } // end else 4605 } // end for (;it!=itend;++it) 4606 // now add psi parts for every element of the shiftfree decomposition 4607 vector<pf1>::iterator jt=shiftfree_pfdecomp.begin(); 4608 vector<pf1>::const_iterator jtend=shiftfree_pfdecomp.end(); 4609 for (;jt!=jtend;++jt){ 4610 vecteur & jtfact = jt->fact; 4611 // vecteur & jtnum = jt->num; 4612 vecteur & jtden = jt->den; 4613 if (jtfact.size()!=2){ // add to remains_to_sum 4614 remains_to_sum=remains_to_sum+rdiv(r2e(poly12polynome(jt->num,1,vdim),v,contextptr),r2e(poly12polynome(jt->den,1,vdim),v,contextptr),contextptr); 4615 } 4616 else { 4617 gen racine=-rdiv(jtfact.back(),jtfact.front(),contextptr); 4618 vecteur dec=taylor(jt->num,racine); 4619 vecteur vv=cdr_VECT(v); 4620 gen coeff(plus_one); 4621 int decal=int(jt->mult-dec.size()); 4622 for (int i=0;i<jt->mult;++i){ 4623 if (i>=decal){ 4624 if (!allow_psi) 4625 return false; 4626 res=res+r2e(rdiv(dec[i-decal],coeff*jtden.front(),contextptr),vv,contextptr)*Psi(x-r2e(racine,vv,contextptr),i,contextptr); 4627 } 4628 coeff=gen(-i-1)*coeff; 4629 } 4630 } 4631 } // end for(;jt!=jtend;++jt) 4632 return true; // end non constant denominator 4633 } // end rational fraction or polynomial 4634 taylor(const polynome & P,const gen & g)4635 polynome taylor(const polynome & P,const gen & g){ 4636 vecteur v(polynome2poly1(P,1)); 4637 v=taylor(v,g); 4638 return poly12polynome(v,1,P.dim); 4639 } 4640 4641 decalage_(const polynome & A,const polynome & B)4642 vecteur decalage_(const polynome & A,const polynome & B){ 4643 int s=A.dim; 4644 // find integer roots of resultant of A(x),B(x+t) with respect to x 4645 vecteur l(s); 4646 for (int i=0;i<s;++i) 4647 l[i]=identificateur("x"+print_INT_(i)); 4648 int adeg=A.lexsorted_degree(); 4649 int bdeg=B.lexsorted_degree(); // total degree of B(x+t) is bdeg, total degree of A is adeg 4650 // therefore total degree of resultant is <= adeg*bdeg 4651 vecteur y(adeg*bdeg+1),x(adeg*bdeg+1); 4652 vecteur bb(polynome2poly1(B,1)); 4653 for (int i=0;i<=adeg*bdeg;++i){ 4654 x[i]=i; 4655 polynome b=poly12polynome(bb,1,s); 4656 y[i]=r2e(Tresultant<gen>(A,b),l,context0); 4657 bb=taylor(bb,1); 4658 } 4659 gen resu=_lagrange(makesequence(x,y,l.front()),context0); 4660 resu=e2r(resu,l,context0); 4661 if (resu.type!=_POLY) 4662 return vecteur(0); 4663 polynome pres=*resu._POLYptr; 4664 // Make the list of the positive integer roots k in t of the resultant 4665 return iroots(pres); 4666 } 4667 // IMPROVE: eval A and B at other variables to detect possible integer roots 4668 // then try gcd(A(x),B(x+t)) decalage(const polynome & A,const polynome & B)4669 vecteur decalage(const polynome & A,const polynome & B){ 4670 int s=A.dim; 4671 if (s==1) 4672 return decalage_(A,B); 4673 vecteur l(s),L(s); 4674 for (int i=0;i<s;++i) 4675 l[i]=identificateur("x"+print_INT_(i)); 4676 gen a=r2e(A,l,context0); 4677 gen b=r2e(B,l,context0); 4678 gen t=identificateur("t"); 4679 gen r=_sylvester(makesequence(a,subst(b,l[0],l[0]+t,false,context0),l[0]),context0); 4680 L[0]=l[0]; 4681 gen r0=_det(subst(r,l,L,false,context0),context0); 4682 if (is_zero(derive(r0,t,context0))){ 4683 int essai=0; 4684 for (;essai<s;++essai){ 4685 L=vranm(s,0,0); // find random evaluation 4686 L[0]=l[0]; 4687 r0=_det(subst(r,l,L,false,context0),context0); 4688 if (!is_zero(derive(r0,t,context0))) 4689 break; 4690 } 4691 if (essai==s) 4692 return decalage_(A,B); 4693 } 4694 r0=e2r(r0,vecteur(1,t),context0); 4695 if (r0.type!=_POLY) 4696 return decalage_(A,B); 4697 vecteur v=iroots(*r0._POLYptr); 4698 vecteur res; 4699 for (int i=0;i<v.size();++i){ 4700 gen ti=v[i]; 4701 gen bti=subst(b,l[0],l[0]+ti,false,context0); 4702 gen g=gcd(a,bti,context0); 4703 if (!is_zero(derive(g,l[0],context0))) 4704 res.push_back(ti); 4705 } 4706 return res; 4707 } 4708 4709 // Write a fraction A/B as E[P]/P*Q/E[R] where E[P]=subst(P,x,x+1) 4710 // and Q and all positive shifts of R are prime together AB2PQR(const polynome & A,const polynome & B,polynome & P,polynome & Q,polynome & R)4711 void AB2PQR(const polynome & A,const polynome & B,polynome & P,polynome & Q, polynome & R){ 4712 int s=A.dim; 4713 // First find integer roots of resultant of A(x),B(x+t) with respect to x 4714 #if 1 4715 std::vector< facteur< tensor<gen> > > vA(Tsqff_char0(A)),vB(Tsqff_char0(B)); 4716 std::vector< facteur< tensor<gen> > >::const_iterator itA=vA.begin(),itAend=vA.end(),itB=vB.begin(),itBend=vB.end(); 4717 vecteur racines; 4718 for (;itA!=itAend;++itA){ 4719 for (;itB!=itBend;++itB){ 4720 racines=mergeset(racines,decalage(itA->fact,itB->fact)); 4721 } 4722 } 4723 #else 4724 polynome a(A.untrunc1()); // add the t parameter 4725 polynome b(B.untrunc1()); 4726 // exchange var 1 (parameter t) and 2 (x variable) 4727 vector<int> i=transposition(0,1,s+1); 4728 a.reorder(i); 4729 b.reorder(i); 4730 // now translate b by t 4731 vecteur bb(polynome2poly1(b,1)); 4732 polynome t(monomial<gen>(plus_one,1,1,s)); 4733 bb=taylor(bb,t); 4734 b=poly12polynome(bb,1,s+1); 4735 polynome pres=Tresultant<gen>(a,b); 4736 pres=pres.trunc1(); 4737 // Make the list of the positive integer roots k in t of the resultant 4738 vecteur racines(iroots(pres)); 4739 #endif 4740 // The algorithm begins with P0=1 Q0=A R0=B 4741 P=polynome(monomial<gen>(plus_one,s)); 4742 Q=A; 4743 R=B; 4744 int d=int(racines.size()); 4745 for (int i=0;i<d;++i){ 4746 gen k=racines[i]; 4747 if (k.type!=_INT_ || k.val<=0) 4748 continue; 4749 // Then compute Pi Qi Ri so that E[Pi]/Pi*Qi/Ri=A/B 4750 // for each positive integer root k 4751 // gcd[Qi,E^k[Ri]]=Y!=1 then Qi=Y*Q_{i+1}, Ri=E^-k[Y]*R_{i+1} 4752 // hence Qi/Ri=Q_{i+1}/R_{i+1}* Y/E^[-k]Y 4753 polynome Y=gcd(Q,taylor(R,k)); 4754 Q=Q/Y; 4755 polynome Yk=taylor(Y,-k); 4756 R=R/Yk; 4757 // therefore P_{i+1}=Pi*E^[-k]Y*...*E^[-1]Y 4758 for (int j=-k.val;j<0;++j){ 4759 P=P*Yk; 4760 Yk=taylor(Yk,plus_one); 4761 } 4762 } 4763 // At the end R=E^[-1] R_i 4764 R=taylor(R,minus_one); 4765 } 4766 4767 // Solve P = Q E[Y] - R Y for Y 4768 // return true if there is a solution Y (solution is more precisely Y/deno) gosper(const polynome & P,const polynome & Q,const polynome & R,polynome & Y,gen & deno,GIAC_CONTEXT)4769 bool gosper(const polynome & P,const polynome & Q,const polynome & R,polynome & Y,gen & deno,GIAC_CONTEXT){ 4770 // First find degree of Y 4771 // if q>r then y=p-q, if q<r then y=p-r, (if y<0 return false) 4772 // if q==r then y=p-q or p (p only if same leading coeff in Q,R) 4773 int p=P.lexsorted_degree(),q=Q.lexsorted_degree(),r=R.lexsorted_degree(),y; 4774 vecteur vP(polynome2poly1(P,1)),vQ(polynome2poly1(Q,1)),vR(polynome2poly1(R,1)); 4775 gen qq=Tfirstcoeff<gen>(Q),rr=Tfirstcoeff<gen>(R); 4776 if (q==r && qq==rr){ // cancellation 4777 ++p; 4778 y=p-giacmax(q,r); 4779 if (q>0){ 4780 vecteur vq=polynome2poly1(Q,1),vr=polynome2poly1(R,1); 4781 gen ydeg=(vr[1]-vq[1])/qq;//gen ydeg=(vr[q-1]-vq[q-1])/qq; 4782 if (ydeg.type==_INT_ && ydeg.val>y){ 4783 y=ydeg.val; 4784 p=y+q-1; 4785 } 4786 } 4787 } 4788 else 4789 y=p-giacmax(q,r); 4790 if (y<0) 4791 return false; 4792 // Then solve a linear system with p+1 equations and y+1 unknowns 4793 // (p+1 rows, y+1 columns) 4794 // built the matrix of the system column by column 4795 // the column i is (X+1)^i*Q-X^i*R 4796 vecteur v(1,plus_one); // this will contain (X+1)^i using pascal_next_line 4797 vecteur w(v); // this is X^i 4798 matrice m; 4799 for (int i=0;i<=y;++i){ 4800 vecteur current=v*vQ-w*vR; 4801 // adjust current size to p 4802 lrdm(current,p); 4803 m.push_back(current); 4804 v=pascal_next_line(v); 4805 w.push_back(zero); 4806 } 4807 reverse(m.begin(),m.end()); // higher coeff at the beginning 4808 // last column is P 4809 lrdm(vP,p); 4810 m.push_back(vP); 4811 m=mtran(m); 4812 int st=step_infolevel(contextptr); 4813 step_infolevel(contextptr)=0; 4814 m=mrref(m,contextptr); 4815 step_infolevel(contextptr)=st; 4816 vecteur res(y+1); 4817 for (int i=0;i<=y;++i){ 4818 if (is_zero(m[i][i])) 4819 return false; 4820 res[i]=m[i][y+1]/m[i][i]; 4821 } 4822 lcmdeno(res,deno,contextptr); // lcmdeno_converted? 4823 Y=poly12polynome(res,1,P.dim); 4824 return p==y || is_zero(m[y+1]); 4825 // Or alternatively do a Rothstein-Trager like method if Q non constant 4826 // Let P = Q U + R V with deg(V)<deg(Q) 4827 // then Q(E(Y)-U)=R(Y+V) 4828 // hence Q divides Y+V 4829 // If we know that deg(Y)<deg(Q) then check that Y=-V is solution 4830 // Otherwise let Y+V=Qy 4831 // Then QE(Qy-V) -R(Qy-V)=P=QU+RV 4832 // hence E(Qy-V)-Ry=U 4833 // we are reduced to solve E(Q)y-Ry=U+E(V) with deg(y)=deg(Y)-deg(Q) 4834 } 4835 4836 // Check for hypergeometric e, if true 4837 // write e(x+1)/e(x) as P(n+1)/P(n)*Q(x)/R(x+1) is_hypergeometric(const gen & e,const identificateur & x,vecteur & v,polynome & P,polynome & Q,polynome & R,GIAC_CONTEXT)4838 bool is_hypergeometric(const gen & e,const identificateur &x,vecteur &v,polynome & P,polynome & Q,polynome & R,GIAC_CONTEXT){ 4839 v=lvarx(e,x); 4840 if (!loptab(v,sincostan_tab).empty() || !loptab(v,asinacosatan_tab).empty() || !lop(v,at_Psi).empty()) 4841 return false; 4842 // if v contains a non linear exp abort 4843 int vs=int(v.size()); 4844 gen a,b; 4845 for (int i=0;i<vs;++i){ 4846 if (v[i].is_symb_of_sommet(at_exp) && !is_linear_wrt(v[i]._SYMBptr->feuille,x,a,b,contextptr)) 4847 return false; 4848 } 4849 gen ratio=simplify(subst(e,x,x+1,false,contextptr)/e,contextptr); 4850 if (is_undef(ratio)) 4851 return false; 4852 v=lvarx(makevecteur(ratio,x),x); 4853 if ( (v.size()!=1) || (v.front()!=x) ){ 4854 ratio=simplify(_texpand(ratio,contextptr),contextptr); 4855 v=lvarx(makevecteur(ratio,x),x); 4856 if ( (v.size()!=1) || (v.front()!=x) ) 4857 return false; 4858 } 4859 lvar(ratio,v); 4860 for (unsigned i=1;i<v.size();++i){ 4861 if (!is_zero(derive(v[i],x,contextptr))) 4862 return false; 4863 } 4864 int s=int(v.size()); 4865 gen f=e2r(ratio,v,contextptr); 4866 polynome A(s),B(s); 4867 if (f.type==_FRAC){ 4868 A=gen2poly(f._FRACptr->num,s); 4869 B=gen2poly(f._FRACptr->den,s); 4870 } 4871 else { 4872 A=gen2poly(f,s); 4873 B=gen2poly(plus_one,s); 4874 } 4875 AB2PQR(A,B,P,Q,R); // A/B as E[P]/P*Q/E[R] 4876 return true; 4877 } 4878 inner_sum(const gen & e,const gen & x,gen & remains_to_sum,GIAC_CONTEXT)4879 static gen inner_sum(const gen & e,const gen & x,gen & remains_to_sum,GIAC_CONTEXT){ 4880 gen res; 4881 if (rational_sum(e,x,res,remains_to_sum,true,contextptr)) 4882 return res; 4883 polynome P,Q,R; 4884 vecteur v; 4885 if (!is_hypergeometric(e,*x._IDNTptr,v,P,Q,R,contextptr)){ 4886 remains_to_sum=e; 4887 return zero; 4888 } 4889 int s=int(v.size()); 4890 gen deno; 4891 polynome Y(s); 4892 if (!gosper(P,Q,R,Y,deno,contextptr)){ 4893 remains_to_sum=e; 4894 return zero; 4895 } 4896 remains_to_sum=zero; 4897 gen facteur=r2e(Y*R,v,contextptr)/r2e(P,v,contextptr)/r2e(deno,vecteur(v.begin()+1,v.end()),contextptr); 4898 return simplify(e*facteur,contextptr); 4899 } 4900 4901 // discrete antiderivative sum(const gen & e,const gen & x,gen & remains_to_sum,GIAC_CONTEXT)4902 gen sum(const gen & e,const gen & x,gen & remains_to_sum,GIAC_CONTEXT){ 4903 if (x.type!=_IDNT) 4904 return gensizeerr(contextptr); 4905 vecteur v=lvarx(e,x); 4906 v=loptab(v,sincostan_tab); 4907 // keep only sincostan which are linear wrt x 4908 vecteur newv(v); 4909 v.clear(); 4910 int s=int(newv.size()); 4911 for (int i=0;i<s;++i){ 4912 gen a,b; 4913 if (is_linear_wrt(newv[i]._SYMBptr->feuille,x,a,b,contextptr)) 4914 v.push_back(newv[i]); 4915 } 4916 if (!v.empty()){ 4917 gen w=trig2exp(v,contextptr); 4918 gen e1=_lin(subst(e,v,*w._VECTptr,true,contextptr),contextptr); 4919 return _simplify(_evalc(linear_apply(e1,x,remains_to_sum,contextptr,inner_sum),contextptr),contextptr); 4920 } 4921 else 4922 return linear_apply(e,x,remains_to_sum,contextptr,inner_sum); 4923 } 4924 4925 // discrete antiderivative evaluated sum_loop(const gen & e,const gen & x,int i,int j,GIAC_CONTEXT)4926 gen sum_loop(const gen & e,const gen & x,int i,int j,GIAC_CONTEXT){ 4927 gen f(e),res; 4928 if (i>j){ 4929 int tmp=j; 4930 j=i-1; 4931 i=tmp+1; 4932 f=-e; 4933 } 4934 for (;i<=j;++i){ 4935 res=res+subst(f,x,i,false,contextptr).eval(eval_level(contextptr),contextptr); 4936 } 4937 return res; 4938 } 4939 sum(const gen & e,const gen & x,const gen & a,const gen & b,GIAC_CONTEXT)4940 gen sum(const gen & e,const gen & x,const gen & a,const gen &b,GIAC_CONTEXT){ 4941 if ( (a.type==_INT_) && (b.type==_INT_) && (absint(b.val-a.val)<100) ) 4942 return sum_loop(e,x,a.val,b.val,contextptr); 4943 gen res; 4944 if ( sumab(e,x,a,b,res,true,contextptr) ) 4945 return res; 4946 gen remains_to_sum; 4947 #if defined EMCC || defined GIAC_HAS_STO_38 4948 res=sum(e,x,remains_to_sum,contextptr); 4949 #else 4950 gen oldx=eval(x,1,contextptr),X(x); 4951 if (!assume_t_in_ab(X,a,b,false,false,contextptr)) 4952 return gensizeerr(contextptr); 4953 res=sum(e,x,remains_to_sum,contextptr); 4954 sto(oldx,X,contextptr); 4955 #endif 4956 gen tmp1=( (is_inf(b) && x.type==_IDNT)?limit(res,*x._IDNTptr,b,0,contextptr):subst(res,x,b+1,false,contextptr)); 4957 gen tmp2=(is_inf(a) && x.type==_IDNT)?limit(res,*x._IDNTptr,a,0,contextptr):subst(res,x,a,false,contextptr); 4958 res=tmp1-tmp2; 4959 if (is_zero(remains_to_sum)) 4960 return res; 4961 if ( (a.type==_INT_) && (b.type==_INT_) && (absint(b.val-a.val)<max_sum_add(contextptr)) ) 4962 return res+sum_loop(remains_to_sum,x,a.val,b.val,contextptr); 4963 return symbolic(at_sum,gen(makevecteur(e,x,a,b),_SEQ__VECT)); 4964 } 4965 prodsum(const gen & g,bool isprod)4966 gen prodsum(const gen & g,bool isprod){ 4967 if (g.type!=_VECT) 4968 return gensizeerr(gettext("prodsum")); 4969 vecteur v=*g._VECTptr; 4970 int s=int(v.size()); 4971 if (!s) 4972 return isprod?1:0; 4973 int debut=1,fin=s; 4974 if (v[0].type==_VECT && g.subtype==_SEQ__VECT && s>1 && v[1].type==_INT_){ 4975 debut=giacmax(1,v[1].val); 4976 if (s>2 && v[2].type==_INT_) 4977 fin=v[2].val; 4978 v=*v[0]._VECTptr; 4979 s=int(v.size()); 4980 fin=giacmin(s,fin); 4981 } 4982 gen res; 4983 if (isprod){ 4984 res=plus_one; 4985 for (--debut;debut<fin;++debut){ 4986 res=matrix_apply(res,v[debut],prod); 4987 } 4988 } 4989 else { 4990 for (--debut;debut<fin;++debut){ 4991 res=matrix_apply(res,v[debut],somme); 4992 } 4993 } 4994 return res; 4995 } 4996 4997 #if 0 4998 static void local_sto(const gen & value,const identificateur & i,GIAC_CONTEXT){ 4999 if (contextptr) 5000 (*contextptr->tabptr)[i.id_name]=value; 5001 else 5002 i.localvalue->back()=value; 5003 } 5004 5005 static void local_sto_increment(const gen & value,const identificateur & i,GIAC_CONTEXT){ 5006 if (contextptr) 5007 (*contextptr->tabptr)[i.id_name] += value; 5008 else 5009 i.localvalue->back() += value; 5010 } 5011 5012 static void local_sto_int(int value,const identificateur & i,GIAC_CONTEXT){ 5013 if (contextptr) 5014 (*contextptr->tabptr)[i.id_name].val=value; 5015 else 5016 i.localvalue->back().val=value; 5017 } 5018 5019 static void local_sto_int_increment(int value,const identificateur & i,GIAC_CONTEXT){ 5020 if (contextptr) 5021 (*contextptr->tabptr)[i.id_name].val += value; 5022 else 5023 i.localvalue->back().val += value; 5024 } 5025 #endif 5026 5027 // type=0 for seq, 1 for prod, 2 for sum seqprod(const gen & g,int type,GIAC_CONTEXT)5028 gen seqprod(const gen & g,int type,GIAC_CONTEXT){ 5029 vecteur v(gen2vecteur(g)); 5030 if (v.size()==1) 5031 v=gen2vecteur(eval(g,contextptr)); 5032 if (v.size()<4){ 5033 gen v2; 5034 if (v.size()==3) 5035 v2=eval(v[2],1,contextptr); 5036 if (type==0 && v.size()==3 && v2.type==_VECT){ 5037 // for example seq(2^k,k,[1,2,5]) 5038 gen f=_unapply(makesequence(v[0],v[1]),contextptr); 5039 return _map(makesequence(v2,f),contextptr); 5040 } 5041 if (v.size()==3 && v[1].is_symb_of_sommet(at_equal) && v[1]._SYMBptr->feuille[1].is_symb_of_sommet(at_interval)){ 5042 gen f=v[1]._SYMBptr->feuille; 5043 gen v1=f[0]; 5044 gen v2=f[1]._SYMBptr->feuille[0],v3=f[1]._SYMBptr->feuille[1]; 5045 return change_subtype(seqprod(makevecteur(v[0],v1,v2,v3,v[2]),type,contextptr),_SEQ__VECT); 5046 } 5047 if (v.size()==3 && !v[1].is_symb_of_sommet(at_equal) && g.subtype==_SEQ__VECT) 5048 return change_subtype(seqprod(gen(makevecteur(symb_interval(v[0],v[1]),v[2]),_SEQ__VECT),type,contextptr),0); 5049 if (type==0) 5050 return _dollar(g,contextptr); 5051 if (type==1) 5052 return prodsum(v,true); 5053 if (type==2) 5054 return prodsum(v,false); 5055 return gentoofewargs(""); 5056 } 5057 // v[1]=eval(v[1]); 5058 v[2]=eval(v[2],contextptr); 5059 v[3]=eval(v[3],contextptr); 5060 gen step=1; 5061 gen tmp; 5062 if (v.size()==5) 5063 step=eval(v[4],contextptr); 5064 if (is_zero(step)) 5065 return gensizeerr(contextptr); 5066 if (!is_integral(v[3]) || !is_integral(v[2])){ 5067 if (v.size()==4 && g.subtype==_SEQ__VECT) 5068 return gentypeerr(contextptr); 5069 if (type==1 && (g.subtype!=_SEQ__VECT || v.size()!=5)) 5070 return prodsum(v,true); 5071 if (type==2 && (g.subtype!=_SEQ__VECT || v.size()!=5)) 5072 return prodsum(v,false); 5073 } 5074 // This will not work if v[0] has auto-quoting functions inside 5075 // because arguments are not evaled, hence replacement of v[1] by value 5076 // is not done inside arguments. 5077 // Example Ya:=desolve([y'+x*y=0,y(0)=a]); seq(plot(Ya),a,1,3); 5078 gen debut=v[2],fin=v[3]; 5079 if (is_greater(abs(fin-debut),LIST_SIZE_LIMIT,contextptr)) 5080 return gendimerr(contextptr); 5081 vecteur res; 5082 if (is_strictly_greater(debut,fin,contextptr)){ 5083 if (is_positive(step,contextptr)) 5084 step=-step; 5085 for (;!ctrl_c && !interrupted && is_greater(debut,fin,contextptr);debut=debut+step){ 5086 #ifdef TIMEOUT 5087 control_c(); 5088 #endif 5089 tmp=quotesubst(v[0],v[1],debut,contextptr); 5090 tmp=eval(tmp,contextptr); 5091 tmp=quotesubst(tmp,v[1],debut,contextptr); 5092 #ifdef RTOS_THREADX 5093 tmp=evalf(tmp,1,contextptr); 5094 #endif 5095 res.push_back(tmp); 5096 } 5097 } 5098 else { 5099 if (!is_greater(fin,debut,contextptr)) 5100 return gensizeerr((gettext("Unable to sort boundaries ")+debut.print(contextptr))+(","+fin.print(contextptr))); 5101 if (is_positive(-step,contextptr)) 5102 step=-step; 5103 for (;!ctrl_c && !interrupted && is_greater(fin,debut,contextptr);debut=debut+step){ 5104 #ifdef TIMEOUT 5105 control_c(); 5106 #endif 5107 tmp=quotesubst(v[0],v[1],debut,contextptr); 5108 tmp=eval(tmp,contextptr); 5109 tmp=quotesubst(tmp,v[1],debut,contextptr); 5110 #ifdef RTOS_THREADX 5111 tmp=evalf(tmp,1,contextptr); 5112 #endif 5113 res.push_back(tmp); 5114 } 5115 } 5116 if (type==1) 5117 return _prod(res,contextptr); 5118 if (type==2) 5119 return _plus(res,contextptr); 5120 return res;// return gen(res,_SEQ__VECT); 5121 } 5122 5123 #if 0 5124 static identificateur independant_identificateur(const gen & g){ 5125 string xname(" x"+g.print(context0)); 5126 identificateur x(xname); 5127 return x; 5128 } 5129 5130 // type=0 for seq, 1 for prod, 2 for sum 5131 static gen seqprod2(const gen & g,int type,GIAC_CONTEXT){ 5132 vecteur v(gen2vecteur(g)); 5133 if (v.size()==1) 5134 v=gen2vecteur(eval(g,eval_level(contextptr),contextptr)); 5135 if (v.size()<4){ 5136 if (type==0) 5137 return _dollar(g,contextptr); 5138 if (type==1) 5139 return prodsum(v,true); 5140 if (type==2) 5141 return prodsum(v,false); 5142 return gentoofewargs(""); 5143 } 5144 // v[1]=eval(v[1]); 5145 v[2]=eval(v[2],eval_level(contextptr),contextptr); 5146 v[3]=eval(v[3],eval_level(contextptr),contextptr); 5147 gen step=1; 5148 gen tmp; 5149 if (v.size()==5) 5150 step=eval(v[4],eval_level(contextptr),contextptr); 5151 if (is_zero(step)) 5152 return gensizeerr(contextptr); 5153 if (v[3].type!=_INT_ || v[2].type!=_INT_){ 5154 if (type==1) 5155 return prodsum(v,true); 5156 if (type==2) 5157 return prodsum(v,false); 5158 } 5159 gen debut=v[2],fin=v[3]; 5160 vecteur res; 5161 gen nstep=evalf_double((fin-debut)/step,1,contextptr); 5162 if (nstep.type!=_DOUBLE_) 5163 return gensizeerr(gettext("Bad step")); 5164 res.reserve(int(absdouble(nstep._DOUBLE_val))+1); 5165 identificateur x=independant_identificateur(v[0]); 5166 tmp=quotesubst(v[0],v[1],x,contextptr); 5167 gen tmpev=eval(tmp,eval_level(contextptr),contextptr); 5168 gen a,b; 5169 if (is_linear_wrt(tmpev,x,a,b,contextptr)){ 5170 if (is_strictly_greater(debut,fin,contextptr)){ 5171 if (is_positive(step,contextptr)) // correct pos step to - 5172 step=-step; 5173 for (;is_greater(debut,fin,contextptr);debut+=step){ 5174 res.push_back(a*debut+b); 5175 } 5176 } 5177 else { 5178 if (is_positive(-step,contextptr)) // correct negative step to + 5179 step=-step; 5180 if (step.type==_INT_){ 5181 int D=debut.val,F=fin.val,S=step.val; 5182 for (;D<=F;D+=S){ 5183 res.push_back(D*a+b); 5184 } 5185 } 5186 else { 5187 for (;is_greater(fin,debut,contextptr);debut+=step){ 5188 res.push_back(a*debut+b); 5189 } 5190 } 5191 } 5192 } 5193 else { 5194 int level=eval_level(contextptr); 5195 context * newcontextptr= (context *) contextptr; 5196 vecteur localvar(1,x); 5197 int protect=bind(vecteur(1,debut),localvar,newcontextptr); 5198 if (is_strictly_greater(debut,fin,newcontextptr)){ 5199 if (is_positive(step,newcontextptr)) // correct pos step to - 5200 step=-step; 5201 if (step.type==_INT_){ 5202 int D=debut.val,F=fin.val,S=step.val; 5203 for (;D>=F;D+=S){ 5204 res.push_back(tmp.eval(level,newcontextptr)); 5205 local_sto_int_increment(S,x,newcontextptr); 5206 } 5207 } 5208 else { 5209 for (;is_greater(debut,fin,newcontextptr);debut+=step){ 5210 local_sto(debut,x,newcontextptr); 5211 res.push_back(tmp.eval(level,newcontextptr)); 5212 } 5213 } 5214 } 5215 else { 5216 if (is_positive(-step,newcontextptr)) // correct negative step to + 5217 step=-step; 5218 if (step.type==_INT_){ 5219 int D=debut.val,F=fin.val,S=step.val; 5220 for (;D<=F;D+=S){ 5221 res.push_back(tmp.eval(level,newcontextptr)); 5222 local_sto_int_increment(S,x,newcontextptr); 5223 } 5224 } 5225 else { 5226 for (;is_greater(fin,debut,newcontextptr);debut+=step){ 5227 local_sto(debut,x,newcontextptr); 5228 res.push_back(tmp.eval(level,newcontextptr)); 5229 } 5230 } 5231 } 5232 leave(protect,localvar,newcontextptr); 5233 } // end is_linear 5234 if (type==1) 5235 return _prod(res,contextptr); 5236 if (type==2) 5237 return _plus(res,contextptr); 5238 return res;// return gen(res,_SEQ__VECT); 5239 } 5240 #endif 5241 maple_sum_product_unquote(vecteur & v,GIAC_CONTEXT)5242 bool maple_sum_product_unquote(vecteur & v,GIAC_CONTEXT){ 5243 bool res=false; 5244 int s=int(v.size()); 5245 if (s<2) 5246 return false; // setsizeerr(contextptr); 5247 if (v[0].is_symb_of_sommet(at_quote)) 5248 v[0]=v[0]._SYMBptr->feuille; 5249 if (v[1].type!=_IDNT){ 5250 if (is_equal(v[1]) && v[1]._SYMBptr->feuille.type==_VECT){ 5251 res=true; 5252 vecteur tmp =*v[1]._SYMBptr->feuille._VECTptr; 5253 if (tmp.size()==2){ 5254 if (tmp[0].is_symb_of_sommet(at_quote)) 5255 tmp[0]=tmp[0]._SYMBptr->feuille; 5256 v[1]=symbolic(at_equal,gen(makevecteur(tmp[0],eval(tmp[1],eval_level(contextptr),contextptr)),_SEQ__VECT)); 5257 } 5258 } 5259 else 5260 v[1]=eval(v[1],eval_level(contextptr),contextptr); 5261 } 5262 for (int i=2;i<s;++i) 5263 v[i]=eval(v[i],eval_level(contextptr),contextptr); 5264 return res; 5265 } 5266 _sum(const gen & args,GIAC_CONTEXT)5267 gen _sum(const gen & args,GIAC_CONTEXT) { 5268 if ( args.type==_STRNG && args.subtype==-1) return args; 5269 if (args.type==_VECT && args.subtype!=_SEQ__VECT) 5270 return prodsum(args.eval(eval_level(contextptr),contextptr),false); 5271 if ( (args.type!=_VECT) || (args._VECTptr->size()<2) ) 5272 return prodsum(args.eval(eval_level(contextptr),contextptr),false); 5273 vecteur v(*args._VECTptr); 5274 if (v.size()>1 && v[1].is_symb_of_sommet(at_unquote)) 5275 v[1]=eval(v[1],1,contextptr); 5276 maple_sum_product_unquote(v,contextptr); 5277 int s=int(v.size()); 5278 if (is_zero(ratnormal(v[0],contextptr))) 5279 return 0; 5280 if (!adjust_int_sum_arg(v,s)) 5281 return gensizeerr(contextptr); 5282 if (v[1].type==_INT_){ 5283 v[0]=eval(v[0],eval_level(contextptr),contextptr); 5284 return prodsum(v,false); 5285 } 5286 if (s==5) 5287 return seqprod(gen(v,_SEQ__VECT),2,contextptr); 5288 if (s==4) { 5289 if (v[1]==cst_i) 5290 return gensizeerr(gettext("i=sqrt(-1), please use a valid identifier name")); 5291 gen af=evalf_double(v[2],1,contextptr),bf=evalf_double(v[3],1,contextptr); 5292 if (v[1].type==_IDNT && (is_inf(af) || af.type==_DOUBLE_) && (is_inf(bf) || bf.type==_DOUBLE_)){ 5293 vecteur w; 5294 #ifndef NSPIRE 5295 my_ostream * ptr=logptr(contextptr); 5296 logptr(0,contextptr); 5297 #endif 5298 #ifdef NO_STDEXCEPT 5299 gen v0=eval(v[0],1,contextptr); 5300 if (is_undef(v0)) 5301 v0=v[0]; 5302 if (!has_num_coeff(v0)) 5303 w=protect_find_singularities(v0,*v[1]._IDNTptr,0,contextptr); 5304 #else 5305 gen v0=v[0]; 5306 try { 5307 #ifndef EMCC 5308 v0=eval(v[0],1,contextptr); 5309 #endif 5310 if (!has_num_coeff(v0)) 5311 w=protect_find_singularities(v0,*v[1]._IDNTptr,0,contextptr); 5312 } catch (std::runtime_error & e){ 5313 last_evaled_argptr(contextptr)=NULL; 5314 v0=v[0]; 5315 } 5316 #endif 5317 #ifndef NSPIRE 5318 logptr(ptr,contextptr); 5319 #endif 5320 for (unsigned i=0;i<w.size();++i){ 5321 if (is_integer(w[i]) && is_greater((v[3]-w[i])*(w[i]-v[2]),0,contextptr)) { 5322 gen v0w=limit(v0,*v[1]._IDNTptr,w[i],0,contextptr);// gen v0w=subst(v0,v[1],w[i],false,contextptr); 5323 if (is_undef(v0w) || is_inf(v0w)) 5324 return gensizeerr("Pole at "+w[i].print(contextptr)); 5325 } 5326 } 5327 } 5328 // test must be done twice for example for sum(sin(k),k,1,0) 5329 if (is_zero(v[2]-v[3]-1)) 5330 return zero; 5331 bool numeval=(!is_integer(v[2]) && v[2].type!=_FRAC) || (!is_integer(v[3]) && v[3].type!=_FRAC) || approx_mode(contextptr); 5332 if (is_integral(v[2])){ 5333 while (is_exactly_zero(subst(v[0],v[1],v[2],false,contextptr))){ 5334 if (v[2]==v[3]) 5335 return 0; 5336 v[2]+=1; 5337 } 5338 } 5339 else { 5340 gen tmp; 5341 if (has_evalf(v[2],tmp,1,contextptr)) 5342 v[2]=_ceil(v[2],contextptr); 5343 } 5344 if (is_integral(v[3])){ 5345 while (is_exactly_zero(subst(v[0],v[1],v[3],false,contextptr))){ 5346 if (v[2]==v[3]) 5347 return 0; 5348 v[3]-=1; 5349 } 5350 } 5351 else { 5352 gen tmp; 5353 if (has_evalf(v[3],tmp,1,contextptr)) 5354 v[3]=_floor(v[3],contextptr); 5355 } 5356 if (is_zero(v[2]-v[3]-1)) 5357 return zero; 5358 if (is_positive(v[2]-v[3]-1,contextptr)) 5359 return -_sum(gen(makevecteur(v[0],v[1],v[3]+(numeval?gen(1.0):plus_one),v[2]-1),_SEQ__VECT),contextptr); 5360 if (is_strictly_positive(-v[2],contextptr) && is_positive(-v[3],contextptr)){ 5361 gen tmp=quotesubst(v[0],v[1],-v[1],contextptr); 5362 return _sum(gen(makevecteur(tmp,v[1],-v[3],(numeval?evalf_double(-v[2],1,contextptr):-v[2])),args.subtype),contextptr); 5363 } 5364 if (v[2].type==_INT_ && v[3].type==_INT_ && absint(v[3].val-v[2].val)<max_sum_add(contextptr)){ 5365 gen res=seqprod(v,2,contextptr); 5366 return (numeval || has_num_coeff(res))?evalf(res,1,contextptr):ratnormal(res,contextptr); 5367 } 5368 } // end if s==4 5369 const_iterateur it=v.begin(),itend=v.end(); 5370 gen f=*it; 5371 ++it; 5372 gen x=*it; 5373 if (x.type==_IDNT){ 5374 // quote x for evaluation of f 5375 if (contextptr && contextptr->quoted_global_vars){ 5376 contextptr->quoted_global_vars->push_back(x); 5377 f=eval(f,eval_level(contextptr),contextptr); 5378 contextptr->quoted_global_vars->pop_back(); 5379 } 5380 else { 5381 if (it->_IDNTptr->quoted){ 5382 int savequote=*it->_IDNTptr->quoted; 5383 *it->_IDNTptr->quoted=1; 5384 f=eval(f,eval_level(contextptr),contextptr); 5385 *it->_IDNTptr->quoted=savequote; 5386 } 5387 else 5388 f=eval(f,eval_level(contextptr),contextptr); 5389 } 5390 } 5391 ++it; 5392 if (it==itend){ 5393 gen rem,res; 5394 res=sum(f,x,rem,contextptr); 5395 if (is_zero(rem)) 5396 return res; 5397 else 5398 return res+symbolic(at_sum,makesequence(rem,x)); 5399 } 5400 gen a=*it; 5401 ++it; 5402 if (it==itend) 5403 return prodsum(gen(v).eval(eval_level(contextptr),contextptr),false); 5404 gen b=*it; 5405 ++it; 5406 if ( (x.type!=_IDNT) ) 5407 return prodsum(gen(v).eval(eval_level(contextptr),contextptr),false); 5408 return sum(f,x,a,b,contextptr); 5409 } 5410 5411 static const char _somme_s []="somme"; 5412 static define_unary_function_eval_quoted (__somme,&_sum,_somme_s); 5413 define_unary_function_ptr5( at_somme ,alias_at_somme,&__somme,_QUOTE_ARGUMENTS,true); 5414 5415 // innert form _Sum(const gen & args,GIAC_CONTEXT)5416 gen _Sum(const gen & args,GIAC_CONTEXT) { 5417 if ( args.type==_STRNG && args.subtype==-1) return args; 5418 return symbolic(at_sum,args); 5419 } 5420 static const char _Sum_s []="Sum"; 5421 static define_unary_function_eval_quoted (__Sum,&_Sum,_Sum_s); 5422 define_unary_function_ptr5( at_Sum ,alias_at_Sum,&__Sum,_QUOTE_ARGUMENTS,true); 5423 _wz_certificate(const gen & args,GIAC_CONTEXT)5424 gen _wz_certificate(const gen & args,GIAC_CONTEXT) { 5425 if ( args.type==_STRNG && args.subtype==-1) return args; 5426 gen F,dF,G,n(n__IDNT_e),k(k__IDNT_e); 5427 if (args.type==_VECT){ 5428 int s=args._VECTptr->size(); 5429 const vecteur & v=*args._VECTptr; 5430 if (s==0 || s>4) return gensizeerr(contextptr); 5431 if (s==1) F=v[0]; 5432 if (s==2) F=v[0]/v[1]; 5433 if (s==3){ F=v[0]; n=v[1]; k=v[2]; } 5434 if (s==4){ F=v[0]/v[1]; n=v[2]; k=v[3]; } 5435 } 5436 else 5437 F=args; 5438 dF=simplify(subst(F,n,n+1,false,contextptr)-F,contextptr); 5439 G=_sum(makesequence(dF,k),contextptr); 5440 if (lop(G,at_sum).empty()){ 5441 gen R=G/subst(F,k,k-1,false,contextptr); 5442 R=_eval(simplify(R,contextptr),contextptr); 5443 return _factor(R,contextptr); 5444 } 5445 return 0; 5446 } 5447 static const char _wz_certificate_s []="wz_certificate"; 5448 static define_unary_function_eval_quoted (__wz_certificate,&_wz_certificate,_wz_certificate_s); 5449 define_unary_function_ptr5( at_wz_certificate ,alias_at_wz_certificate,&__wz_certificate,0,true); 5450 5451 // sum does also what maple add does 5452 /* 5453 gen _add(const gen & args,GIAC_CONTEXT) { 5454 if ( args.type==_STRNG && args.subtype==-1) return args; 5455 int & elevel =eval_level(contextptr); 5456 int el=elevel; 5457 elevel=1; 5458 gen res; 5459 try { 5460 res=_sum(args,contextptr); 5461 } 5462 catch (std::runtime_error & e){ 5463 last_evaled_argptr(contextptr)=NULL; 5464 elevel=el; 5465 throw(e); 5466 } 5467 elevel=el; 5468 return res; 5469 } 5470 */ 5471 static const char _add_s []="add"; 5472 static define_unary_function_eval_quoted (__add,&_sum //&_add 5473 ,_add_s); 5474 define_unary_function_ptr5( at_add ,alias_at_add,&__add,_QUOTE_ARGUMENTS,true); 5475 bernoulli(const gen & x)5476 gen bernoulli(const gen & x){ 5477 if (x.type==_VECT && x._VECTptr->size()==2){ 5478 gen a=x._VECTptr->front(),y=x._VECTptr->back(); 5479 if (a.type!=_INT_) 5480 return gensizeerr(gettext("bernoulli")); 5481 bool all=a.val<0; 5482 int n=absint(a.val); 5483 if (n==0) 5484 return plus_one; 5485 if (n==1) 5486 return y+minus_one_half; 5487 gen bi=bernoulli(-n); 5488 if (bi.type!=_VECT) 5489 return gensizeerr(gettext("bernoulli")); 5490 vecteur biv=*bi._VECTptr; 5491 if (biv.size()<=n) 5492 biv.push_back(0); 5493 // bernoulli polynomials B_n=n*int(B_n-1)+bi[n] 5494 vecteur allv; 5495 vecteur cur(1,1); 5496 if (all) 5497 allv.push_back((y.type==_VECT?cur:plus_one)); 5498 for (int i=1;i<=n;++i){ 5499 cur=multvecteur(i,integrate(cur,1)); 5500 cur.insert(cur.begin(),biv[i]); 5501 if (all){ 5502 vecteur tmp(cur); 5503 reverse(tmp.begin(),tmp.end()); 5504 if (y.type==_VECT) 5505 allv.push_back(tmp); 5506 else 5507 allv.push_back(symb_horner(tmp,y)); 5508 } 5509 } 5510 reverse(cur.begin(),cur.end()); 5511 return all?allv:(y.type==_VECT?cur:symb_horner(cur,y)); 5512 } 5513 if (x.type!=_INT_) 5514 return gensizeerr(gettext("bernoulli")); 5515 bool all=x.val<0; 5516 int n=absint(x.val); 5517 if (!n) 5518 return plus_one; 5519 if (n==1) 5520 return all?vecteur(1,minus_one_half):minus_one_half; 5521 if (n%2){ 5522 if (!all) 5523 return zero; 5524 --n; 5525 } 5526 gen a(plus_one); 5527 gen b(rdiv(1-n,plus_two,context0)); 5528 vecteur bi(makevecteur(plus_one,minus_one_half)); 5529 int i=2; 5530 for (; i< n-1; i+=2){ 5531 // compute bernoulli(i) 5532 gen A=1; 5533 gen B=gen(1-i)/2; 5534 for (int j=2; j<i-1;j+=2){ 5535 A=iquo( A*gen(i+3-j)*gen(i+2-j),(j-1)*j); 5536 B=B+A* bi[j]; 5537 } 5538 bi.push_back(-B/gen(i+1)); 5539 bi.push_back(0); 5540 a=iquo( (a*gen(n+3-i)*gen(n+2-i)),((i-1)*i)); 5541 b=b+a* bi[i]; 5542 } 5543 if (all){ 5544 bi.push_back(rdiv(-b,n+1,context0)); 5545 return bi; 5546 } 5547 return rdiv(-b,n+1,context0); 5548 } _bernoulli(const gen & args,GIAC_CONTEXT)5549 gen _bernoulli(const gen & args,GIAC_CONTEXT) { 5550 if ( args.type==_STRNG && args.subtype==-1) return args; 5551 if (args.type==_VECT && args._VECTptr->size()==2 && args._VECTptr->back().type!=_INT_) 5552 return bernoulli(args); 5553 return apply(args,bernoulli); 5554 } 5555 static const char _bernoulli_s []="bernoulli"; 5556 static define_unary_function_eval (__bernoulli,&_bernoulli,_bernoulli_s); 5557 define_unary_function_ptr5( at_bernoulli ,alias_at_bernoulli,&__bernoulli,0,true); 5558 double2vecteur(const double * y,int dim)5559 vecteur double2vecteur(const double * y,int dim){ 5560 vecteur ye; 5561 ye.reserve(dim); 5562 for (int i=0;i<dim;++i) 5563 ye.push_back(y[i]); 5564 return ye; 5565 } 5566 5567 #ifdef HAVE_LIBGSL 5568 struct odesolve_param { 5569 gen odesolve_t; 5570 vecteur odesolve_f,odesolve_ft,odesolve_y; 5571 matrice odesolve_fy; 5572 gsl_odeiv_system odesolve_system; 5573 const context * contextptr; 5574 }; 5575 5576 double m_undef = numeric_limits<double>::infinity(); 5577 gsl_odesolve_function(double t,const double y[],double dydt[],void * params)5578 static int gsl_odesolve_function(double t, const double y[], double dydt[], void * params){ 5579 odesolve_param * par =(odesolve_param *) params; 5580 #ifndef NO_STDEXCEPT 5581 try{ 5582 #endif 5583 gen res=subst(par->odesolve_f,par->odesolve_t,t,false,par->contextptr); 5584 vecteur vtmp=double2vecteur(y,par->odesolve_system.dimension); 5585 res=subst(res,par->odesolve_y,vtmp,false,par->contextptr); 5586 res=res.evalf(1,par->contextptr); 5587 // store result 5588 if ( (res.type!=_VECT) || (res._VECTptr->size()!=par->odesolve_system.dimension)){ 5589 #ifdef NO_STDEXCEPT 5590 return 1; 5591 #else 5592 setsizeerr(par->contextptr); 5593 #endif 5594 } 5595 const_iterateur it=res._VECTptr->begin(),itend=res._VECTptr->end(); 5596 for (double * dydt_it=dydt;it!=itend;++it,++dydt_it){ 5597 if (it->type==_DOUBLE_) 5598 *dydt_it=it->_DOUBLE_val; 5599 else { 5600 #ifdef NO_STDEXCEPT 5601 return 1; 5602 #else 5603 setsizeerr(par->contextptr); 5604 #endif 5605 } 5606 } 5607 #ifndef NO_STDEXCEPT 5608 } 5609 catch (std::runtime_error & err){ 5610 CERR << err.what() << '\n'; 5611 int n=par->odesolve_system.dimension,i=0; 5612 for (double * dydt_it=dydt;i<n;++i,++dydt_it){ 5613 *dydt_it=m_undef; 5614 } 5615 } 5616 #endif 5617 return 0; 5618 } 5619 5620 gsl_odesolve_jacobian(double t,const double y[],double * dfdy,double dfdt[],void * params)5621 static int gsl_odesolve_jacobian (double t, const double y[], double * dfdy, double dfdt[], void * params){ 5622 // compute 5623 odesolve_param * par =(odesolve_param *) params; 5624 #ifndef NO_STDEXCEPT 5625 try { 5626 #endif 5627 vecteur yv(double2vecteur(y,par->odesolve_system.dimension)); 5628 gen res=subst(par->odesolve_ft,par->odesolve_t,t,false,par->contextptr); 5629 res=subst(res,par->odesolve_y,yv,false,par->contextptr).evalf(1,par->contextptr); 5630 // store result 5631 if ( (res.type!=_VECT) || (res._VECTptr->size()!=par->odesolve_system.dimension)){ 5632 #ifdef NO_STDEXCEPT 5633 return 1; 5634 #else 5635 setsizeerr(par->contextptr); 5636 #endif 5637 } 5638 const_iterateur it=res._VECTptr->begin(),itend=res._VECTptr->end(); 5639 for (double * dfdt_it=dfdt;it!=itend;++it,++dfdt_it){ 5640 if (it->type==_DOUBLE_) 5641 *dfdt_it=it->_DOUBLE_val; 5642 else { 5643 #ifdef NO_STDEXCEPT 5644 return 1; 5645 #else 5646 setsizeerr(par->contextptr); 5647 #endif 5648 } 5649 } 5650 res=subst(par->odesolve_fy,par->odesolve_t,t,false,par->contextptr); 5651 res=subst(res,par->odesolve_y,yv,false,par->contextptr).evalf(1,par->contextptr); 5652 // store result 5653 if ( (res.type!=_VECT) || (res._VECTptr->size()!=par->odesolve_system.dimension)){ 5654 #ifdef NO_STDEXCEPT 5655 return 1; 5656 #else 5657 setsizeerr(par->contextptr); 5658 #endif 5659 } 5660 it=res._VECTptr->begin(); 5661 itend=res._VECTptr->end(); 5662 for (double * dfdy_it=dfdy;it!=itend;++it){ 5663 if (it->type!=_VECT){ 5664 #ifdef NO_STDEXCEPT 5665 return 1; 5666 #else 5667 setsizeerr(par->contextptr); 5668 #endif 5669 } 5670 const_iterateur jt=it->_VECTptr->begin(),jtend=it->_VECTptr->end(); 5671 for (;jt!=jtend;++jt,++dfdy_it){ 5672 if (jt->type==_DOUBLE_) 5673 *dfdy_it=it->_DOUBLE_val; 5674 else { 5675 #ifdef NO_STDEXCEPT 5676 return 1; 5677 #else 5678 setsizeerr(par->contextptr); 5679 #endif 5680 } 5681 } 5682 } 5683 #ifndef NO_STDEXCEPT 5684 } 5685 catch (std::runtime_error & err){ 5686 CERR << err.what() << '\n'; 5687 int n=par->odesolve_system.dimension,i=0; 5688 for (double * dydt_it=dfdt;i<n;++i,++dydt_it){ 5689 *dydt_it=m_undef; 5690 } 5691 i=0; 5692 for (double * dydt_it=dfdy;i<n;++i,++dydt_it){ 5693 *dydt_it=m_undef; 5694 } 5695 } 5696 #endif 5697 return 0; 5698 } 5699 #endif // HAVE_LIBGSL 5700 rk_error(const vecteur & v,const vecteur & w_final,const vecteur & w_init,GIAC_CONTEXT)5701 double rk_error(const vecteur & v,const vecteur & w_final,const vecteur & w_init,GIAC_CONTEXT){ 5702 double err=0,derr; 5703 unsigned dim=unsigned(v.size()); 5704 for (unsigned i=0;i<dim;++i){ 5705 gen wf=w_final[i],wi=w_init[i]; 5706 double wfa=abs(wf,contextptr)._DOUBLE_val; 5707 double wia=abs(wi,contextptr)._DOUBLE_val; 5708 double sci=1+((wfa<wia)?wia:wfa); 5709 derr = abs(wf-v[i],contextptr)._DOUBLE_val/sci; 5710 derr *= derr; 5711 err += derr; 5712 } 5713 err = std::sqrt(err/dim); 5714 return err; 5715 } 5716 5717 // solve dy/dt=f(t,y) with initial value y(t0)=y0 to final value t1 5718 // returns by default y[t1] or a vector of [t,y[t]] 5719 // if return_curve is true stop as soon as y is outside ymin,ymax 5720 // f is eitheir a prog (t,y) -> f(t,y) or a _VECT [f(t,y) t y] odesolve(const gen & t0orig,const gen & t1orig,const gen & f,const gen & y0orig,double tstep,bool return_curve,double * ymin,double * ymax,int maxstep,GIAC_CONTEXT)5721 gen odesolve(const gen & t0orig,const gen & t1orig,const gen & f,const gen & y0orig,double tstep,bool return_curve,double * ymin,double * ymax,int maxstep,GIAC_CONTEXT){ 5722 bool iscomplex=false; 5723 // switch to false if GSL is installed or true to force using giac code for real ode 5724 gen t0_e=evalf_double(t0orig.evalf(1,contextptr),1,contextptr); 5725 gen t1_e=evalf_double(t1orig.evalf(1,contextptr),1,contextptr); 5726 // Now accept t0 and t1 complex! 5727 if ( (t0_e.type!=_DOUBLE_ && t0_e.type!=_CPLX)|| (t1_e.type!=_DOUBLE_ && t1_e.type!=_CPLX)) 5728 return gensizeerr(contextptr); 5729 gen y0=evalf_double(y0orig.evalf(1,contextptr),1,contextptr); 5730 if (y0.type!=_VECT) 5731 y0=vecteur(1,y0); 5732 vecteur y0v=*y0._VECTptr; 5733 int dim=int(y0v.size()); 5734 if (tstep==0){ 5735 if (dim==2) 5736 tstep=(gnuplot_xmax-gnuplot_xmin)/100; 5737 else { 5738 if (return_curve && abs(t1_e,contextptr)._DOUBLE_val>1e300) 5739 tstep=abs(t0_e,contextptr)._DOUBLE_val/100; 5740 else 5741 tstep=abs(t1_e-t0_e,contextptr)._DOUBLE_val/100; 5742 } 5743 } 5744 if (tstep>abs(t1_e-t0_e,contextptr)._DOUBLE_val) 5745 tstep=abs(t1_e-t0_e,contextptr)._DOUBLE_val; 5746 #if 1 5747 ALLOCA(double, y, dim*sizeof(double));// double * y =(double *)alloca(dim*sizeof(double)); 5748 #else 5749 double * y=new double[dim]; 5750 #endif 5751 for (int i=0;i<dim;i++){ 5752 if (y0v[i].type!=_DOUBLE_ && y0v[i].type!=_CPLX) 5753 return gensizeerr(contextptr); 5754 if (y0v[i].type==_DOUBLE_) 5755 y[i]=y0v[i]._DOUBLE_val; 5756 else 5757 iscomplex=true; 5758 } 5759 identificateur t_id(" odesolve_t"); 5760 vecteur yv; 5761 gen tmp; 5762 if (f.type==_VECT){ 5763 vecteur tmpv(*f._VECTptr); 5764 if (tmpv.size()!=3) 5765 return gensizeerr(contextptr); 5766 tmp=tmpv[0]; 5767 if (tmpv[1].type!=_IDNT) 5768 return gensizeerr(contextptr); 5769 t_id=*tmpv[1]._IDNTptr; 5770 if (tmpv[2].type!=_VECT){ 5771 yv=vecteur(1,tmpv[2]); 5772 } 5773 else 5774 yv=*tmpv[2]._VECTptr; 5775 if (signed(yv.size())!=dim) 5776 return gendimerr(contextptr); 5777 } 5778 else { 5779 for (int i=0;i<dim;++i) 5780 yv.push_back(identificateur(" y"+print_INT_(i))); 5781 tmp=f(gen(makevecteur(t_id,yv),_SEQ__VECT),contextptr); 5782 } 5783 vecteur resv; // contains the curve 5784 if (return_curve) 5785 resv.push_back(makevecteur(t0_e,y0v)); 5786 #if 0 //def HAVE_LIBGSL 5787 if (!iscomplex && t0_e.type==_DOUBLE_ && t1_e.type==_DOUBLE_ && is_zero(im(tmp,contextptr))){ 5788 double t0=t0_e._DOUBLE_val; 5789 double t1=t1_e._DOUBLE_val; 5790 bool time_reverse=(t1<t0); 5791 if (time_reverse){ 5792 t0=-t0; 5793 t1=-t1; 5794 } 5795 double t=t0; 5796 if (time_reverse) 5797 tmp=-subst(tmp,t_id,-t_id,false,contextptr); 5798 vecteur odesolve_f; 5799 if (tmp.type!=_VECT) 5800 odesolve_f=vecteur(1,tmp); 5801 else 5802 odesolve_f=*tmp._VECTptr; 5803 if (signed(odesolve_f.size())!=dim) 5804 return gendimerr(contextptr); 5805 // N.B.: GSL implementation uses Dormand-Prince method of orders 8/9 5806 // which is explicit and does not require Jacobian... 5807 gen diff1=derive(odesolve_f,yv,contextptr),diff2=derive(odesolve_f,t_id,contextptr); 5808 if (is_undef(diff1) || diff1.type!=_VECT || is_undef(diff2) || diff2.type!=_VECT) 5809 return diff1+diff2; 5810 odesolve_param * par=new odesolve_param; 5811 par->odesolve_t=t_id; 5812 par->odesolve_y=yv; 5813 par->contextptr=contextptr; 5814 par->odesolve_f=odesolve_f; 5815 par->odesolve_fy=*diff1._VECTptr; 5816 par->odesolve_ft=*diff2._VECTptr; 5817 par->odesolve_system.function=gsl_odesolve_function; 5818 par->odesolve_system.dimension=dim; 5819 par->odesolve_system.jacobian=gsl_odesolve_jacobian; 5820 par->odesolve_system.params=par; 5821 // GSL call 5822 const gsl_odeiv_step_type * T = gsl_odeiv_step_rk8pd; 5823 gsl_odeiv_step * s = gsl_odeiv_step_alloc (T, dim); 5824 gsl_odeiv_control * c = gsl_odeiv_control_y_new (1e-7, 1e-7); 5825 gsl_odeiv_evolve * e = gsl_odeiv_evolve_alloc (dim); 5826 double h; 5827 if (return_curve){ 5828 h=fabs(t); 5829 if (h<1e-4) 5830 h=1e-4; 5831 } 5832 else 5833 h=(t1-t)/1e4; 5834 double oldt=t0; 5835 bool do_while=true; 5836 for (int nstep=0;nstep<maxstep && do_while && t<t1;++nstep) { 5837 if (h>tstep) 5838 h=tstep; 5839 int status = gsl_odeiv_evolve_apply (e, c, s, 5840 &par->odesolve_system, 5841 &t, t1, &h, 5842 y); 5843 if (status != GSL_SUCCESS) 5844 return gensizeerr(gettext("RK8 evolve not successfull")); 5845 if (debug_infolevel>5) 5846 CERR << nstep << ":" << t << ",y5=" << double2vecteur(y,dim) << '\n'; 5847 if (return_curve) { 5848 if ( (t-oldt)> tstep/2 || t==t1){ 5849 oldt=t; 5850 if (time_reverse) 5851 resv.push_back(makevecteur(-t,double2vecteur(y,dim))); 5852 else 5853 resv.push_back(makevecteur(t,double2vecteur(y,dim))); 5854 } 5855 for (int i=0;i<dim;++i){ 5856 // CERR << y[i] << '\n'; 5857 if ( ymin && ymax && ( y[i]<ymin[i] || y[i]>ymax[i]) ) 5858 do_while=false; 5859 } 5860 } 5861 } 5862 gsl_odeiv_evolve_free(e); 5863 gsl_odeiv_control_free(c); 5864 gsl_odeiv_step_free(s); 5865 delete par; 5866 if (return_curve) 5867 return resv; 5868 else { 5869 if (t!=t1) 5870 return makevecteur(t,double2vecteur(y,dim)); 5871 return double2vecteur(y,dim); 5872 } 5873 } 5874 #endif // HAVE_LIBGSL 5875 vecteur odesolve_f; 5876 if (tmp.type!=_VECT) 5877 odesolve_f=vecteur(1,tmp); 5878 else 5879 odesolve_f=*tmp._VECTptr; 5880 if (signed(odesolve_f.size())!=dim) 5881 return gendimerr(contextptr); 5882 // solve vector ode y'=f(t,y) with respect to time variable t_id in t0..t1 5883 // f is stored in odesolve_f, symbolic y in yv, initial value in a double array y 5884 /* Butcher tableau for Dormand/Prince 4/5 5885 0 | 5886 1/5 | 1/5 5887 3/10 | 3/40 9/40 5888 4/5 | 44/45 −56/15 32/9 5889 8/9 | 19372/6561 −25360/2187 64448/6561 −212/729 5890 1 | 9017/3168 −355/33 46732/5247 49/176 −5103/18656 5891 1 | 35/384 0 500/1113 125/192 −2187/6784 11/84 5892 =============================================================================== 5893 RK5 | 35/384 0 500/1113 125/192 −2187/6784 11/84 0 5894 RK4 5179/57600 0 7571/16695 393/640 −92097/339200 187/2100 1/40 5895 RK4 is used for computation of the tstep variable 5896 RK4 error being estimated by |RK5-RK4| 5897 Step is determined by the following algorithm 5898 (cf. Ernst Hairer http://www.unige.ch/~hairer/poly/chap3.pdf, p.67 in French) 5899 initialization: use h=tstep 5900 compute RK5_final and RK4_final, then 5901 err=|| RK5-RK4 || = sqrt(1/dim*sum(((RK5[i]-RK4[i])/(1+max(RK5[i]_init,RK5[i]_final)))^2,i=1..dim)) 5902 and hoptimal = 0.9*h*(tolerance/||RK5-RK4||)^(1/5) 5903 if (err<=hoptimal) then time += h; y_init=RK5_final; h=min(hoptimal,t_final-t_current) 5904 else h=hoptimal 5905 */ 5906 #ifdef KHICAS 5907 gen tolerance=epsilon(contextptr)>1e-9?epsilon(contextptr):1e-9; 5908 #else 5909 gen tolerance=epsilon(contextptr)>1e-12?epsilon(contextptr):1e-12; 5910 #endif 5911 vecteur yt(dim+1),ytvar(yv); 5912 for (int i=0;i<dim;++i) 5913 yt[i]=y0v[i]; 5914 gen t_e(t0_e); 5915 yt[dim]=t_e; 5916 vecteur yt1(dim+1); 5917 ytvar.push_back(t_id); 5918 bool do_while=true; 5919 double butcher_c[]={0,0.2,0.3,4./5,8./9,1.,1.}; 5920 double butcher_a[]={1./5, 5921 3./40,9./40, 5922 44./45,-56./15,32./9, 5923 19372./6561,-25360./2187,64448./6561,-212./729, 5924 9017./3168,-355./33,46732./5247,49./176,-5103./18656, 5925 35./384,0,500./1113,125./192,-2187./6784,11./84}; 5926 // double butcher_b5[]={35./384,0,500./1113,125./192,-2187./6784,11./84,0}; 5927 double butcher_b4[]={5179./57600,0,7571./16695,393./640,-92097./339200,187./2100,1./40}; 5928 vecteur y_final5(yt.begin(),yt.begin()+dim),y_final4(dim); 5929 vecteur butcher_k(7); 5930 for (int i=0;i<7;++i) 5931 butcher_k[i]=vecteur(dim); 5932 vecteur firsteval=subst(odesolve_f,ytvar,yt,false,contextptr),lasteval; 5933 gen direction=t1_e-t0_e; 5934 double temps_total=abs(direction,contextptr)._DOUBLE_val,temps=0; 5935 direction=direction/temps_total; 5936 for (int nstep=0;do_while && nstep<maxstep && temps<temps_total;++nstep) { 5937 gen dt=tstep*direction; 5938 // compute next step 5939 vecteur & bk0=*butcher_k[0]._VECTptr; 5940 bk0=firsteval; 5941 if (is_undef(bk0)) 5942 return bk0; 5943 multvecteur(dt,bk0,bk0); 5944 int butcher_a_shift=0; 5945 for (int j=1;j<=6;j++){ 5946 // compute butcher_k[j] 5947 for (int i=0;i<dim;++i){ 5948 yt1[i]=yt[i]; 5949 } 5950 if (dim==1){ 5951 gen & yt10=yt1[0]; 5952 for (int k=0;k<j;k++){ 5953 type_operator_plus_times(butcher_a[butcher_a_shift+k],butcher_k[k]._VECTptr->front(),yt10); 5954 } 5955 } 5956 else { 5957 for (int k=0;k<j;k++){ 5958 gen bak=butcher_a[butcher_a_shift+k]; 5959 const vecteur & bkk=(*butcher_k[k]._VECTptr); 5960 for (int i=0;i<dim;++i){ 5961 type_operator_plus_times(bak,bkk[i],yt1[i]); //yt1[i] += bak*bkk[i]; 5962 } 5963 } 5964 } 5965 butcher_a_shift += j; 5966 yt1[dim]=yt[dim]; 5967 type_operator_plus_times(butcher_c[j],dt,yt1[dim]); 5968 vecteur & bkj = *butcher_k[j]._VECTptr; 5969 if (j<6) 5970 bkj=subst(odesolve_f,ytvar,yt1,false,contextptr); 5971 else 5972 bkj=lasteval=subst(odesolve_f,ytvar,yt1,false,contextptr); 5973 if (is_undef(bkj)) 5974 return bkj; 5975 multvecteur(dt,bkj,bkj); 5976 } 5977 for (int i=0;i<dim;++i){ 5978 y_final5[i]=yt1[i]; 5979 y_final4[i]=yt[i]; 5980 } 5981 for (int j=0;j<7;++j){ 5982 vecteur & bkj=*butcher_k[j]._VECTptr; 5983 // gen bb5j=butcher_b5[j]; 5984 gen bb4j=butcher_b4[j]; 5985 for (int i=0;i<dim;i++){ 5986 // y_final5[i] += bb5j*bkj[i]; 5987 type_operator_plus_times(bb4j,bkj[i],y_final4[i]);//y_final4[i] += bb4j*bkj[i]; 5988 } 5989 } 5990 // accept or reject current step and compute dt 5991 double err=rk_error(y_final4,y_final5,yt,contextptr); 5992 gen hopt=.9*tstep*pow(tolerance/err,.2,contextptr); 5993 if (err==0 || is_undef(hopt)) 5994 break; 5995 if (debug_infolevel>5) 5996 CERR << nstep << ":" << t_e << ",y5=" << y_final5 << ",y4=" << y_final4 << " " << tstep << " hopt=" << hopt << " err=" << err << '\n'; 5997 if (is_strictly_greater(err,tolerance,contextptr)){ 5998 // reject step 5999 tstep=hopt._DOUBLE_val; 6000 } 6001 else { // accept 6002 swap(firsteval,lasteval); 6003 for (int i=0;i<dim;++i) 6004 yt[i]=y_final5[i]; 6005 t_e += dt; 6006 yt[dim]=t_e; 6007 temps += tstep; 6008 tstep=abs(t1_e-t_e,contextptr)._DOUBLE_val; 6009 if (hopt._DOUBLE_val<tstep) 6010 tstep=hopt._DOUBLE_val; 6011 if (return_curve) 6012 resv.push_back(makevecteur(t_e,y_final5)); 6013 if (!iscomplex){ 6014 // check boundaries for y_final5 6015 for (int i=0;i<dim;++i){ 6016 // CERR << y[i] << '\n'; 6017 if ( ymin && ymax && ( y_final5[i]._DOUBLE_val< ymin[i] || y_final5[i]._DOUBLE_val>ymax[i]) ) 6018 do_while=false; 6019 } 6020 } 6021 } 6022 } // end integration loop 6023 if (return_curve) 6024 return resv; 6025 else { 6026 if (t_e!=t1_e) 6027 return makevecteur(t_e,y_final5); 6028 return y_final5; 6029 } 6030 } 6031 // note that params is not used 6032 6033 // standard format is expression,t=t0..t1,vars,init_values 6034 // also accepted 6035 // t0..t1,function,init_values 6036 // expression,t,vars,init_values,t=tmin..tmax 6037 // expression,[t,vars],[t0,init_values],t1 odesolve(const vecteur & w,GIAC_CONTEXT)6038 static gen odesolve(const vecteur & w,GIAC_CONTEXT){ 6039 vecteur v(w); 6040 int vs=int(v.size()); 6041 if (vs<3) 6042 return gendimerr(contextptr); 6043 // convert expression,[t,vars],[t0,init_values],t1 6044 gen t0t=v[0],t0,t1,f,t,y0; 6045 if (v[1].type==_VECT && v[2].type==_VECT && v[2]._VECTptr->size()==v[1]._VECTptr->size() && vs>3){ 6046 if (v[1]._VECTptr->size()<2) 6047 return gendimerr(contextptr); 6048 t0=v[2]._VECTptr->front(); 6049 t1=v[3]; 6050 gen newv1=symbolic(at_equal,v[1]._VECTptr->front(),symb_interval(v[2]._VECTptr->front(),v[3])); 6051 gen newv2=vecteur(v[1]._VECTptr->begin()+1,v[1]._VECTptr->end()); 6052 gen newv3=vecteur(v[2]._VECTptr->begin()+1,v[2]._VECTptr->end()); 6053 v[1]=newv1; 6054 v[2]=newv2; 6055 v[3]=newv3; 6056 } 6057 int maxstep=1000,vstart=0; 6058 double tstep=0; 6059 if ( t0t.is_symb_of_sommet(at_interval)){ // functional form 6060 t0=t0t._SYMBptr->feuille._VECTptr->front(); 6061 t1=t0t._SYMBptr->feuille._VECTptr->back(); 6062 f=v[1]; 6063 y0=v[2]; 6064 vstart=3; 6065 } 6066 else { // expression,t=tmin..tmax,y,y0 6067 if (vs<4) 6068 return gentypeerr(contextptr); 6069 y0=v[3]; 6070 gen t=readvar(v[1]); 6071 f=makevecteur(v[0],t,v[2]); 6072 bool tminmax_defined,tstep_defined; 6073 double tmin(-1e300),tmax(1e300); 6074 vstart=1; 6075 read_tmintmaxtstep(v,t,vstart,tmin,tmax,tstep,tminmax_defined,tstep_defined,contextptr); 6076 if (t0!=t1){ 6077 if (tstep==0) 6078 tstep=evalf_double(abs(t1-t0,contextptr),1,contextptr)._DOUBLE_val/30; 6079 } 6080 else { 6081 if (tmin>0 || tmax<0 || tmin>tmax || tstep<=0) 6082 *logptr(contextptr) << gettext("Warning time reversal") << '\n'; 6083 t0=tmin; 6084 t1=tmax; 6085 } 6086 // if (tminmax_defined && tstep_defined) maxstep=2*int((tmax-tmin)/tstep)+1; 6087 // commented since the real step is used is smaller than tstep most of the time! 6088 vstart=3; 6089 } 6090 double ym[2]={gnuplot_xmin,gnuplot_ymin},yM[2]={gnuplot_xmin,gnuplot_ymin}; 6091 double *ymin=0,*ymax=0; 6092 vs=int(v.size()); 6093 bool curve=false; 6094 for (int i=vstart;i<vs;++i){ 6095 if (readvar(v[i])==x__IDNT_e){ 6096 if (readrange(v[i],gnuplot_xmin,gnuplot_xmax,v[i],ym[0],ym[1],contextptr)){ 6097 ymin=ym; 6098 ymax=yM; 6099 v.erase(v.begin()+i); 6100 --vs; 6101 } 6102 } 6103 if (readvar(v[i])==y__IDNT_e){ 6104 if (readrange(v[i],gnuplot_xmin,gnuplot_xmax,v[i],yM[0],yM[1],contextptr)){ 6105 ymin=ym; 6106 ymax=yM; 6107 v.erase(v.begin()+i); 6108 --vs; 6109 } 6110 } 6111 if (v[i]==at_curve) 6112 curve=true; 6113 } 6114 return odesolve(t0,t1,f,y0,tstep,curve,ymin,ymax,maxstep,contextptr); 6115 } 6116 // odesolve(t0..t1,f,y0) or odesolve(f(t,y),t,y,t0,y0,t1) _odesolve(const gen & args,GIAC_CONTEXT)6117 gen _odesolve(const gen & args,GIAC_CONTEXT) { 6118 if ( args.type==_STRNG && args.subtype==-1) return args; 6119 if ( (args.type!=_VECT) || (args._VECTptr->size()<3 ) ) 6120 return symbolic(at_odesolve,args); 6121 vecteur v(*args._VECTptr); 6122 return odesolve(v,contextptr); 6123 } 6124 static const char _odesolve_s []="odesolve"; 6125 static define_unary_function_eval (__odesolve,&_odesolve,_odesolve_s); 6126 define_unary_function_ptr5( at_odesolve ,alias_at_odesolve,&__odesolve,0,true); 6127 preval(const gen & f,const gen & x,const gen & a,const gen & b,GIAC_CONTEXT)6128 gen preval(const gen & f,const gen & x,const gen & a,const gen & b,GIAC_CONTEXT){ 6129 if (x.type!=_IDNT) 6130 return gentypeerr(contextptr); 6131 gen res; 6132 if (is_greater(b,a,contextptr)) 6133 res=limit(f,*x._IDNTptr,b,-1,contextptr)-limit(f,*x._IDNTptr,a,1,contextptr); 6134 else { 6135 if (is_greater(a,b,contextptr)) 6136 res=limit(f,*x._IDNTptr,b,1,contextptr)-limit(f,*x._IDNTptr,a,-1,contextptr) ; 6137 else 6138 res=limit(f,*x._IDNTptr,b,0,contextptr)-limit(f,*x._IDNTptr,a,0,contextptr); 6139 } 6140 return res; 6141 } 6142 6143 // args=[u'*v,u] or [[F,u'*v],u] -> [F+u*v,-u*v'] 6144 // a third argument would be the integration var 6145 // if u=cste returns F+integrate(u'*v,x) _ibpdv(const gen & args,GIAC_CONTEXT)6146 gen _ibpdv(const gen & args,GIAC_CONTEXT) { 6147 if ( args.type==_STRNG && args.subtype==-1) return args; 6148 if ( (args.type!=_VECT) || (args._VECTptr->size()<2) ) 6149 return symbolic(at_ibpdv,args); 6150 vecteur & w=*args._VECTptr; 6151 gen X(vx_var),x(vx_var),a,b; 6152 bool bound=false; 6153 if (w.size()>=3) 6154 x=X=w[2]; 6155 if (is_equal(x)) 6156 x=x._SYMBptr->feuille[0]; 6157 if (w.size()>=5) 6158 X=symb_equal(x,symb_interval(w[3],w[4])); 6159 if (is_equal(X) && X._SYMBptr->feuille[1].is_symb_of_sommet(at_interval)){ 6160 a=X._SYMBptr->feuille[1]._SYMBptr->feuille[0]; 6161 b=X._SYMBptr->feuille[1]._SYMBptr->feuille[1]; 6162 bound=true; 6163 } 6164 gen u(w[1]),v,uprimev,F; 6165 if (w.front().type==_VECT){ 6166 vecteur & ww=*w.front()._VECTptr; 6167 if (ww.size()!=2) 6168 return gensizeerr(contextptr); 6169 F=ww.front(); 6170 uprimev=ww.back(); 6171 } 6172 else 6173 uprimev=w.front(); 6174 gen uprime(derive(u,x,contextptr)); 6175 if (is_zero(uprime)){ 6176 gen tmp=integrate_gen(uprimev,x,contextptr); 6177 if (bound) 6178 tmp=preval(tmp,x,a,b,contextptr); 6179 return tmp+F; 6180 } 6181 v=normal(rdiv(uprimev,derive(u,x,contextptr),contextptr),contextptr); 6182 if (bound) 6183 F += preval(u*v,x,a,b,contextptr); 6184 else 6185 F += u*v; 6186 return makevecteur(F,normal(-u*derive(v,x,contextptr),contextptr)); 6187 } 6188 static const char _ibpdv_s []="ibpdv"; 6189 static define_unary_function_eval (__ibpdv,&_ibpdv,_ibpdv_s); 6190 define_unary_function_ptr5( at_ibpdv ,alias_at_ibpdv,&__ibpdv,0,true); 6191 fourier_assume(const gen & n,GIAC_CONTEXT)6192 void fourier_assume(const gen &n,GIAC_CONTEXT){ 6193 if (n.type==_IDNT && eval(n,1,contextptr)==n){ 6194 *logptr(contextptr) << "Running assume(" << n << ",integer)" << '\n'; 6195 sto(gen(makevecteur(change_subtype(2,1)),_ASSUME__VECT),n,contextptr); 6196 } 6197 } 6198 fourier_an(const gen & f,const gen & x,const gen & T,const gen & n,const gen & a,GIAC_CONTEXT)6199 gen fourier_an(const gen & f,const gen & x,const gen & T,const gen & n,const gen & a,GIAC_CONTEXT){ 6200 gen primi,iT=inv(T,contextptr); 6201 gen omega=2*cst_pi*iT; 6202 fourier_assume(n,contextptr); 6203 primi=_integrate(gen(makevecteur(f*cos(omega*n*x,contextptr),x,a,ratnormal(a+T,contextptr)),_SEQ__VECT),contextptr); 6204 gen an=iT*primi; 6205 if (n!=0) 6206 an=2*an; 6207 return has_num_coeff(an)?an:recursive_normal(an,contextptr); 6208 } get_fourier(vecteur & v)6209 bool get_fourier(vecteur & v){ 6210 if (v.size()==2) 6211 v=makevecteur(v[0],vx_var,cst_two_pi,v[1],-cst_pi); 6212 if (v.size()==3) 6213 v=makevecteur(v[0],v[1],cst_two_pi,v[2],-cst_pi); 6214 if (v.size()==4) v.push_back(0); 6215 return v.size()==5; 6216 } _fourier_an(const gen & args,GIAC_CONTEXT)6217 gen _fourier_an(const gen & args,GIAC_CONTEXT){ 6218 if ( args.type==_STRNG && args.subtype==-1) return args; 6219 if (args.type!=_VECT) return gensizeerr(contextptr); 6220 vecteur v(*args._VECTptr); 6221 if (!get_fourier(v)) return gensizeerr(contextptr); 6222 return fourier_an(v[0],v[1],v[2],v[3],v[4],contextptr); 6223 //gen f=v[0],x=v[1],T=v[2],n=v[3],a=v[4]; 6224 //return fourier_an(f,x,T,n,a,contextptr); 6225 } 6226 static const char _fourier_an_s []="fourier_an"; 6227 static define_unary_function_eval (__fourier_an,&_fourier_an,_fourier_an_s); 6228 define_unary_function_ptr5( at_fourier_an ,alias_at_fourier_an,&__fourier_an,0,true); 6229 6230 fourier_bn(const gen & f,const gen & x,const gen & T,const gen & n,const gen & a,GIAC_CONTEXT)6231 gen fourier_bn(const gen & f,const gen & x,const gen & T,const gen & n,const gen & a,GIAC_CONTEXT){ 6232 fourier_assume(n,contextptr); 6233 gen primi,iT=inv(T,contextptr); 6234 gen omega=2*cst_pi*iT; 6235 primi=_integrate(gen(makevecteur(f*sin(omega*n*x,contextptr),x,a,ratnormal(a+T,contextptr)),_SEQ__VECT),contextptr); 6236 gen an=2*iT*primi; 6237 return has_num_coeff(an)?an:recursive_normal(an,contextptr); 6238 } _fourier_bn(const gen & args,GIAC_CONTEXT)6239 gen _fourier_bn(const gen & args,GIAC_CONTEXT){ 6240 if ( args.type==_STRNG && args.subtype==-1) return args; 6241 if (args.type!=_VECT) return gensizeerr(contextptr); 6242 vecteur v(*args._VECTptr); 6243 if (!get_fourier(v)) return gensizeerr(contextptr); 6244 return fourier_bn(v[0],v[1],v[2],v[3],v[4],contextptr); 6245 // gen f=v[0],x=v[1],T=v[2],n=v[3],a=v[4]; 6246 // return fourier_bn(f,x,T,n,a,contextptr); 6247 } 6248 static const char _fourier_bn_s []="fourier_bn"; 6249 static define_unary_function_eval (__fourier_bn,&_fourier_bn,_fourier_bn_s); 6250 define_unary_function_ptr5( at_fourier_bn ,alias_at_fourier_bn,&__fourier_bn,0,true); 6251 fourier_cn(const gen & f,const gen & x,const gen & T,const gen & n,const gen & a,GIAC_CONTEXT)6252 gen fourier_cn(const gen & f,const gen & x,const gen & T,const gen & n,const gen & a,GIAC_CONTEXT){ 6253 fourier_assume(n,contextptr); 6254 gen primi,iT=inv(T,contextptr); 6255 gen omega=2*cst_pi*iT; 6256 primi=_integrate(gen(makevecteur(f*exp(-cst_i*omega*n*x,contextptr),x,a,ratnormal(a+T,contextptr)),_SEQ__VECT),contextptr); 6257 gen cn=iT*primi; 6258 return has_num_coeff(cn)?cn:recursive_normal(cn,contextptr); 6259 } _fourier_cn(const gen & args,GIAC_CONTEXT)6260 gen _fourier_cn(const gen & args,GIAC_CONTEXT){ 6261 if ( args.type==_STRNG && args.subtype==-1) return args; 6262 if (args.type!=_VECT) return gensizeerr(contextptr); 6263 vecteur v(*args._VECTptr); 6264 if (!get_fourier(v)) return gensizeerr(contextptr); 6265 return fourier_cn(v[0],v[1],v[2],v[3],v[4],contextptr); 6266 // gen f=v[0],x=v[1],T=v[2],n=v[3],a=v[4]; 6267 // return fourier_cn(f,x,T,n,a,contextptr); 6268 } 6269 6270 static const char _fourier_cn_s []="fourier_cn"; 6271 static define_unary_function_eval (__fourier_cn,&_fourier_cn,_fourier_cn_s); 6272 define_unary_function_ptr5( at_fourier_cn ,alias_at_fourier_cn,&__fourier_cn,0,true); 6273 6274 #if defined FXCG || !defined USE_GMP_REPLACEMENTS 6275 // periodic by Luka Marohnić 6276 // example f:=periodic(x^2,x,-1,1); plot(f,x=-5..5) _periodic(const gen & g,GIAC_CONTEXT)6277 gen _periodic(const gen & g,GIAC_CONTEXT) { 6278 if (g.type==_STRNG && g.subtype==-1) return g; 6279 if (g.type!=_VECT || g.subtype!=_SEQ__VECT) 6280 return gentypeerr(contextptr); 6281 vecteur & gv = *g._VECTptr; 6282 if (gv.size()!=4 && gv.size()!=2) 6283 return gensizeerr(contextptr); 6284 gen & e=gv[0],x,a,b; 6285 //if (e.type!=_SYMB && e.type!=_IDNT) return gentypeerr(contextptr); 6286 vecteur vars(*_lname(e,contextptr)._VECTptr); 6287 if (vars.empty()) 6288 return e; 6289 if (gv.size()==2) { 6290 if (!gv[1].is_symb_of_sommet(at_equal)) 6291 return gentypeerr(contextptr); 6292 vecteur & fl=*gv[1]._SYMBptr->feuille._VECTptr; 6293 if ((x=fl[0]).type!=_IDNT || !fl[1].is_symb_of_sommet(at_interval)) 6294 return gentypeerr(contextptr); 6295 vecteur & ab=*fl[1]._SYMBptr->feuille._VECTptr; 6296 a=ab[0]; 6297 b=ab[1]; 6298 } 6299 else { 6300 x=gv[1]; 6301 if (x.type!=_IDNT) 6302 return gentypeerr(contextptr); 6303 if (find(vars.begin(),vars.end(),x)==vars.end()) 6304 return e; 6305 a=gv[2]; 6306 b=gv[3]; 6307 } 6308 gen T(b-a); 6309 if (!is_strictly_positive(T,contextptr)) 6310 return gentypeerr(contextptr); 6311 gen p(subst(e,x,x-T*_floor((x-a)/T,contextptr),false,contextptr)); 6312 return p;// _unapply(makesequence(p,x),contextptr); 6313 } 6314 static const char _periodic_s []="periodic"; 6315 static define_unary_function_eval (__periodic,&_periodic,_periodic_s); 6316 define_unary_function_ptr5(at_periodic,alias_at_periodic,&__periodic,0,true); 6317 #endif 6318 6319 #ifndef NO_NAMESPACE_GIAC 6320 } // namespace giac 6321 #endif // ndef NO_NAMESPACE_GIAC 6322 6323