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