// -*- mode:C++ ; compile-command: "g++ -I.. -I../include -DHAVE_CONFIG_H -DIN_GIAC -DGIAC_GENERIC_CONSTANTS -fno-strict-aliasing -g -c alg_ext.cc -Wall" -*- #include "giacPCH.h" /* * Copyright (C) 2000,14 B. Parisse, Institut Fourier, 38402 St Martin d'Heres * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ using namespace std; #include #include #include #include #include #include "gen.h" #include "gausspol.h" #include "identificateur.h" #include "poly.h" #include "usual.h" #include "sym2poly.h" #include "vecteur.h" #include "modpoly.h" #include "alg_ext.h" #include "vecteur.h" #include "solve.h" #include "subst.h" #include "plot.h" #include "derive.h" #include "ezgcd.h" #include "prog.h" #include "intg.h" #include "csturm.h" #include "lin.h" #include "ti89.h" #include "giacintl.h" #ifndef NO_NAMESPACE_GIAC namespace giac { #endif // ndef NO_NAMESPACE_GIAC bool islesscomplex(const gen & a,const gen & b){ if (a==b) return false; return a.islesscomplexthan(b); } // symbolic_rootof_list() protected with a mutex in multi-thread environment bool comparegen::operator ()(const gen & a,const gen & b) const { if (a.type==_INT_ && b.type==_INT_) return a.valsize()==2 && (A1=a._VECTptr->front()).type==_INT_ && (A2=a._VECTptr->back()).type==_INT_ && b.type==_VECT && b._VECTptr->size()==2 && (B1=b._VECTptr->front()).type==_INT_ && (B2=b._VECTptr->back()).type==_INT_){ return (A1.val!=B1.val)?A1.valsecond.type==_VECT) res=*rit->second._VECTptr; rootof_unlock(); return !res.empty(); } // cache list of Galois conjugates bool galoisconj_cache(const vecteur & v,const vecteur & res){ if (rootof_trylock()) return false; rootmap::iterator ritend=galoisconj_list().end(),rit=galoisconj_list().find(v); if (rit==ritend) galoisconj_list()[v]=res; rootof_unlock(); return true; } vecteur galoisconj(const vecteur & v,GIAC_CONTEXT){ vecteur res; if (galoisconj_cached(v,res)) return res; gen g=symb_horner(v,vx_var); if (pari_galoisconj(g,res,contextptr)) return res; if (int(v.size())>MAX_COMMON_ALG_EXT_ORDER_SIZE) return res; // factor v over rootof(v) if degree is small g=_factors(makesequence(g,rootof(g,contextptr)),contextptr); if (g.type!=_VECT) return res; vecteur w=*g._VECTptr; for (int i=0;isecond.type==_VECT){ res=*rit->second._VECTptr; if (res.size()==2 && res.front().type==_VECT && res.back().type==_DOUBLE_){ oldeps=res.back()._DOUBLE_val; res=*res.front()._VECTptr; } else res.clear(); } rootof_unlock(); return !res.empty() && oldeps<=eps; } bool proot_cache(const vecteur & v,double eps,const vecteur & res){ if (rootof_trylock()) return false; rootmap::iterator ritend=proot_list().end(),rit=proot_list().find(v); if (rit!=ritend){ if (rit->second.type!=_VECT || rit->second._VECTptr->size()!=2 || rit->second._VECTptr->front().type!=_VECT || rit->second._VECTptr->back().type!=_DOUBLE_ || rit->second._VECTptr->back()._DOUBLE_val>eps) rit->second=makevecteur(res,eps); } else proot_list()[v]=makevecteur(res,eps); rootof_unlock(); return true; } gen algebraic_EXTension(const gen & a_,const gen & v){ gen a(a_); if (a.type==_VECT && !a._VECTptr->empty() && is_zero(a._VECTptr->front())){ a=trim(*a._VECTptr,0); } if (is_zero(a) ) return 0; if (a.type==_VECT){ if (a._VECTptr->empty()) return zero; if (a._VECTptr->size()==1) return a._VECTptr->front(); } gen res; #ifdef SMARTPTR64 * ((ulonglong * ) &res) = ulonglong(new ref_algext) << 16; #else res.__EXTptr=new ref_algext; #endif res.type=_EXT; *(res._EXTptr+1) = v; if (a.type==_FRAC){ *res._EXTptr = a._FRACptr->num; return fraction(res,a._FRACptr->den); } *res._EXTptr = a; return res; } gen in_select_root(const vecteur & a,bool reel,GIAC_CONTEXT,double eps){ if (a.empty() || is_undef(a)) return undef; gen current(a.front()); double max_re(re(current,contextptr).evalf_double(1,contextptr)._DOUBLE_val),max_im(im(current,contextptr).evalf_double(1,contextptr)._DOUBLE_val); const_iterateur it=a.begin(),itend=a.end(); for (;it!=itend;++it){ double cur_re(re(*it,contextptr).evalf_double(1,contextptr)._DOUBLE_val),cur_im(im(*it,contextptr).evalf_double(1,contextptr)._DOUBLE_val); if (cur_re > (1+eps)*max_re ){ current=*it; max_re=cur_re; max_im=cur_im; } else { // same argument if ( std::abs(cur_re-max_re)max_im) ){ current=*it; max_im=cur_im; } } } if (reel && is_strictly_positive(-im(current,contextptr),contextptr)) current=conj(current,contextptr); return current; } gen select_root(const vecteur & v,GIAC_CONTEXT){ int n=decimal_digits(contextptr); if (n<12) n=12; double eps=std::pow(0.1,n); int rprec=int(n*3.3); vecteur a=proot(v,eps,rprec); gen r=in_select_root(a,is_real(v,contextptr),contextptr); return r; } gen alg_evalf(const gen & a,const gen &b,GIAC_CONTEXT){ if (a.type==_FRAC) return rdiv(alg_evalf(a._FRACptr->num,b,contextptr),alg_evalf(a._FRACptr->den,b,contextptr),contextptr); gen a1=a.evalf(1,contextptr),b1=b.evalf(1,contextptr); if (a1.type!=_VECT) return a1; if (b1.type!=_VECT) return algebraic_EXTension(a1,b1); gen r(select_root(*b1._VECTptr,contextptr)); if (is_undef(r)) return algebraic_EXTension(a1,b1); return horner(*a1._VECTptr,r); } gen ext_reduce(const gen & a, const gen & v){ if (a.type==_FRAC) return fraction(ext_reduce(a._FRACptr->num,v),ext_reduce(a._FRACptr->den,v)); if (a.type!=_VECT) return a;// algebraic_EXTension(a,v); if (a._VECTptr->empty()) return zero; if (a._VECTptr->size()==1) return a._VECTptr->front(); if (v.type==_VECT){ if (a._VECTptr->size()size()) return algebraic_EXTension(a,v); #if 1 // special code for quadratic extension, if v=[1,0,-a] if (v._VECTptr->size()==3 && v[0]==1 && v[1]==0){ gen x=-v[2],r1,r0; if (a._VECTptr->size()==3){ r0=a._VECTptr->front()*x+a._VECTptr->back(); r1=(*a._VECTptr)[1]; } else { const_iterateur it=a._VECTptr->begin(),itend=a._VECTptr->end()-1; for (;itfront()=r1; c._VECTptr->back()=r0; return algebraic_EXTension(c,v); } gen c=new ref_vecteur; vecteur & rem=*c._VECTptr; modpoly quo; environment env; DivRem(*a._VECTptr,*v._VECTptr,0,quo,rem); if (rem.empty()) return 0; if (rem.size()==1) return rem.front(); return algebraic_EXTension(c,v); #endif return algebraic_EXTension((*a._VECTptr) % (*v._VECTptr),v); } if (v.type==_FRAC) return horner(*a._VECTptr,*v._FRACptr,true); if (v.type!=_EXT) return gentypeerr(gettext("ext_reduce")); gen va=*v._EXTptr,vb=*(v._EXTptr+1); if (va.type==_FRAC) return ext_reduce(horner(*a._VECTptr,*va._FRACptr,true),vb); if (va.type!=_VECT){ if (vb.type!=_VECT) return gensizeerr(gettext("alg_ext.cc/ext_reduce")); return algebraic_EXTension( (*a._VECTptr) % (*vb._VECTptr),v); } return ext_reduce(horner(*a._VECTptr,gen(*va._VECTptr,_POLY1__VECT)),vb); } gen ext_reduce(const gen & e){ #ifdef DEBUG_SUPPORT if (e.type!=_EXT){ gensizeerr(gettext("alg_ext.cc/ext_reduce")); CERR << gettext("alg_ext.cc/ext_reduce"); return e; } #endif if ( (e._EXTptr->type==_VECT) && ((e._EXTptr+1)->type==_VECT) && (e._EXTptr->_VECTptr->size()<(e._EXTptr+1)->_VECTptr->size()) ) return e; return ext_reduce(*(e._EXTptr),*(e._EXTptr+1)); } static bool polynome2vecteur(const polynome & p,int na,int nb,vecteur & v){ v=vecteur(na*nb,zero); int i,j; if (p.dim!=2){ #ifdef NO_STDEXCEPT return false; #else setsizeerr(gettext("alg_ext.cc/polynome2vecteur")); return false; #endif } vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end(); for (;it!=itend;++it){ i=it->index.front(); j=it->index.back(); // cerr << nb*(na-i-1)+nb-j-1 << " " << na*nb << endl; v[nb*(na-i-1)+nb-j-1]=it->value; } return true; } bool is_known_rootof(const vecteur & v,gen & symroot,GIAC_CONTEXT){ const_iterateur it=v.begin(),itend=v.end(); for (;it!=itend;++it){ if (it->type!=_INT_) return false; } if (rootof_trylock()) return false; rootmap::iterator ritend=symbolic_rootof_list().end(),rit=symbolic_rootof_list().find(v); if (rit!=ritend) symroot=rit->second; rootof_unlock(); if (rit!=ritend) return true; if (v.size()==3){ vecteur w; identificateur x(" x"); in_solve(symb_horner(v,x),x,w,0,contextptr); if (w.empty()) return false; symroot=w.front(); return true; } return false; } // replace _EXT == to ext by g in v static vecteur replace_ext(const vecteur & v,const vecteur &ext,const gen & g,GIAC_CONTEXT){ vecteur res; const_iterateur it=v.begin(),itend=v.end(); res.reserve(int(itend-it)); for (;it!=itend;++it){ gen numtmp=*it,dentmp=1; if (it->type==_FRAC){ numtmp=it->_FRACptr->num; dentmp=it->_FRACptr->den; } // if numtmp is an ext, it must be the same ext as a if (numtmp.type==_EXT){ if (*(numtmp._EXTptr+1)!=ext) return vecteur(1,gensizeerr(gettext("Invalid _EXT in replace_ext"))); res.push_back(horner(*numtmp._EXTptr,g)/dentmp); } else res.push_back(evalf_double(*it,1,contextptr)); } return res; } // given theta1 and theta2 with minimal poly va and vb (inside gen ga and gb) // find k / Q[theta1+ k*theta2 ] contains theta1 and theta2 // return the minimal poly of theta=theta1+k*theta2 // and return in a and b theta1 and theta2 as ext (in terms of theta) gen common_minimal_POLY(const gen & ga,const gen & gb, gen & a,gen & b,int & k,GIAC_CONTEXT){ const vecteur & va=*ga._VECTptr; const vecteur & vb=*gb._VECTptr; int na=int(va.size()-1),nb=int(vb.size()-1); if (nb==1){ k=0; vecteur un(2,zero); un[0]=plus_one; gen vag(va); a=algebraic_EXTension(un,vag); gen tmp=-vb[1]; if (tmp.type!=_POLY) b=tmp; else { if (tmp._POLYptr->coord.empty()) b=zero; else b=tmp._POLYptr->coord.front().value; } return vag; } // create minimal polynomial of theta1/theta2 as 2-d polynomials // with main variable respectively a and b // (since pb is used for reduction after var reordering of p) polynome pa(2),pb(2); const_iterateur it=va.begin(),itend=va.end(); for (int d=na;it!=itend;++it,--d){ if (!is_zero(*it)) pa.coord.push_back(monomial(*it,d,1,2)); // deg=d, var=1, dim=2 } it=vb.begin(),itend=vb.end(); int k_init=0; for (int d=nb;it!=itend;++it,--d){ if (!is_zero(*it)){ gen numtmp=*it,dentmp=1; if (it->type==_FRAC){ numtmp=it->_FRACptr->num; dentmp=it->_FRACptr->den; } polynome pbadd(pb.dim); // if numtmp is an ext, it must be the same ext as a if (numtmp.type==_EXT){ pbadd=poly12polynome(*(numtmp._EXTptr->_VECTptr),1,1).untrunc1(d); k_init=1; } else pbadd.coord.push_back(monomial(numtmp,d,1,2)); pb = pb + pbadd/dentmp; } } if (k_init){ vecteur v1=*evalf_double(va,1,contextptr)._VECTptr; if (is_fully_numeric(v1)){ // when theta2 depends on theta1, theta1+k*theta2 is not necessarily // the largest root, because the numeric value of v2 depends // on the selected root of v1 // // we should compute k*theta1+theta2 for a sufficiently large // value of k to insure largest root, e.g. // this implies computing approx value of theta1 and theta2 // vecteur rac=real_proot(v1,1e-12,contextptr); if (rac.empty()){ vecteur rac1=proot(v1,1e-12); gen theta1=in_select_root(rac1,is_real(v1,contextptr),contextptr); // replace _EXT in vb by r1 and evaluate numerically vecteur v2=replace_ext(vb,va,theta1,contextptr); if (!v2.empty() && is_undef(v2)) return v2.front(); // find theta2 if (is_fully_numeric(v2)){ vecteur rac2=proot(v2,1e-12); if (!rac2.empty() && !is_undef(rac2)){ gen theta2=in_select_root(rac2,is_real(v2,contextptr),contextptr); int racs=int(rac1.size()); for (int i=0;i(1,2)); polynome q(2),tmpq(2),tmpr(2); q.coord.push_back(monomial(k,1,1,2)); // k*a: deg=1, var=1, dim=2 q.coord.push_back(monomial(1,1,2,2)); // b: deg=1, var=2 // create the matrix // lines are 1, k*a+b, ..., (k*a+b)^(na*nb) // in terms of (columns) // a^(na-1)*b^(nb-1) ... a^(na-1) ... ab^(nb-1) ... ab a b^(nb-1) ... b 1 m.clear(); vecteur ligne; for (int j=0;j<=na*nb;++j){ if (!polynome2vecteur(p,na,nb,ligne)) return gensizeerr(gettext("alg_ext.cc/polynome2vecteur")); // ligne.push_back(pow(theta,j)); m.push_back(ligne); p=p*q; // permutation of indices order before making division by pb p.reorder(transposition(0,1,2)); p.TDivRem(pb,tmpq,tmpr,true); p.coord.swap(tmpr.coord); // p=p%pb; // p.reorder(transposition(0,1,2)); // division by a after because b might depend on a p.TDivRem(pa,tmpq,tmpr,true); p.coord.swap(tmpr.coord); // p=p%pa; // } // Add the lines corresponding to b and a (i.e. theta2, theta1) ligne=vecteur(na*nb); ligne[na*nb-2]=plus_one; m.push_back(ligne); ligne=vecteur(na*nb); ligne[na*nb-nb-1]=plus_one; m.push_back(ligne); // Transpose matrix // then we have the na*nb+3 columns 1, theta, ..., theta^(na*nb), b, a // in terms of a basis (with na*nb coordinates) m=mtran(m); // reduce the matrix m to echelon form and test rank=na*nb // if ok break, else try another value of k matrice m_red; vecteur pivots; gen det; int st=step_infolevel(contextptr); step_infolevel(contextptr)=0; if (!mrref(m,m_red,pivots,det,0,na*nb,0,na*nb+3, /* fullreduction */1,0,true,1,0, contextptr)){ step_infolevel(contextptr)=st; return gensizeerr(contextptr); } step_infolevel(contextptr)=st; m=m_red; // the reduced matrix m should have the form // * 0 ... 0 * * * // 0 * ... 0 * * * // ... // 0 0 ... 0 * * * // 0 0 ... 0 * * * // 0 0 ... ? * * * // with ? != 0, we check ?, if it is zero we try another value k vecteur v(m[na*nb-1]._VECTptr->begin(),m[na*nb-1]._VECTptr->end()-1); if (!is_zero__VECT(v,contextptr)) break; } mdividebypivot(m); // add a -1 at the end of column na*nb (C convention, index starting at 0) // to get the min poly vecteur v(na*nb+1); for (int i=0;itype!=_VECT) ) return vecteur(1,gensizeerr(gettext("alg_ext.cc/min_pol"))); return *((a._EXTptr+1)->_VECTptr); } } // Find an evaluation point for p at b where pb=p[b] is squarefree bool find_good_eval(const polynome & F,polynome & Fb,vecteur & b){ int Fdeg=F.lexsorted_degree(),nvars=int(b.size()); gen Fg; int essai=0; for (;;++essai){ Fb=peval_1(F,b,0); if (Fb.lexsorted_degree()==Fdeg && gcd(Fb,Fb.derivative()).lexsorted_degree()==0 ){ return true; } b=vranm(nvars,0,0); // find another random point } } static void clean(gen & g); static void clean(polynome & p){ vector< monomial >::iterator it=p.coord.begin(),itend=p.coord.end(); for (;it!=itend;++it) clean(it->value); } static void clean(gen & g){ if (g.is_symb_of_sommet(at_neg) && is_integer(g._SYMBptr->feuille)) g=-g._SYMBptr->feuille; if (g.type==_POLY){ clean(*g._POLYptr); return; } if (g.type==_VECT){ iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end(); for (;it!=itend;++it) clean(*it); return; } if (g.type==_EXT){ clean(*g._EXTptr); clean(*(g._EXTptr+1)); } } // in-place reduction of algebraic extensions void clean_ext_reduce(vecteur & v){ iterateur it=v.begin(),itend=v.end(); for (;it!=itend;++it) clean_ext_reduce(*it); } void clean_ext_reduce(gen & g){ if (g.type==_EXT){ g=ext_reduce(g); return; } if (g.type==_VECT){ clean_ext_reduce(*g._VECTptr); return; } if (g.type==_POLY){ vector< monomial >::iterator it=g._POLYptr->coord.begin(),itend=g._POLYptr->coord.end(); for (;it!=itend;++it) clean_ext_reduce(it->value); return; } if (g.type==_FRAC) clean_ext_reduce(g._FRACptr->num); } // a and b are supposed to be *(_EXTptr+1) of some algebraic extension // common_EXT will return a new algebraic extension // (suitable to be an extptr+1) // and will modify a and b to be ext of the returned common_EXT gen common_EXT(gen & a,gen & b,const vecteur * l,GIAC_CONTEXT){ if (a==b) return a; if (a.type==_FRAC) return common_EXT(a._FRACptr->num,b,l,contextptr); if (b.type==_FRAC) return common_EXT(a,b._FRACptr->num,l,contextptr); // extract minimal polynomials gen a_orig(a),b_orig(b); gen a__VECT,b__VECT; if (a.type==_VECT) a__VECT=a; else { if ( (a.type!=_EXT) || ((a._EXTptr+1)->type!=_VECT) ) return gensizeerr(gettext("alg_ext.cc/common_EXT")); a__VECT=*(a._EXTptr+1); } if (b.type==_VECT) b__VECT=b; else { if ( (b.type!=_EXT) || ((b._EXTptr+1)->type!=_VECT) ) return gensizeerr(gettext("alg_ext.cc/common_EXT")); b__VECT=*(b._EXTptr+1); } int as=int(a__VECT._VECTptr->size()),bs=int(b__VECT._VECTptr->size()); if (bs>as) return common_EXT(b,a,l,contextptr); if (as==3 && bs==3 && is_one(a[0]) && is_one(b[0]) && is_zero(a[1]) && is_zero(b[1]) && a[2]==-b[2]){ // sqrt(X) and sqrt(-X) b=algebraic_EXTension(makevecteur(cst_i,0),a); gen tmp=a; a=algebraic_EXTension(makevecteur(1,0),a); return tmp; } // special handling if both extensions are cyclotomic int ac=is_cyclotomic(*a__VECT._VECTptr,epsilon(contextptr)),bc; if (ac && (bc=is_cyclotomic(*b__VECT._VECTptr,epsilon(contextptr))) ){ int cc=ac*bc/gcd(ac,bc); gen res=gen(cyclotomic(cc),_POLY1__VECT); a__VECT=gen(vecteur(cc/ac+1),_POLY1__VECT); a__VECT._VECTptr->front()=1; a=algebraic_EXTension(a__VECT,res); b__VECT=gen(vecteur(cc/bc+1),_POLY1__VECT); b__VECT._VECTptr->front()=1; b=algebraic_EXTension(b__VECT,res); return res; } // reduce extension degree by factorizing b__VECT over Q[a] polynome p(poly12polynome(*b__VECT._VECTptr)); polynome p_content(p.dim); factorization f; gen an,extra_div; ext_factor(p,algebraic_EXTension(a__VECT,a__VECT),an,p_content,f,false,extra_div); // now choose in the factorization which factor is relevant for b // this is done by approximation if possible // or by choosing the factor of lowest degree // this way we update b__VECT int min_deg=int(b__VECT._VECTptr->size()); factorization::const_iterator f_it=f.begin(),f_itend=f.end(); bool trouve=false; if (f_itend-f_it==1) trouve=true; vecteur racines; vector real_racines; int innerdim=0; const_iterateur b_it=b__VECT._VECTptr->begin(),b_itend=b__VECT._VECTptr->end(); for (;b_it!=b_itend;++b_it){ if (b_it->type==_POLY) innerdim=b_it->_POLYptr->dim; } vecteur vb(innerdim); gen racine_max=undef; if (!trouve){ // Change for multivariate polynomials p, added evaluation if (innerdim){ gen params; *logptr(contextptr) << gettext("Warning, need to choose a branch for the root of a polynomial with parameters. This might be wrong.") << endl; if (l && l->size()>=2){ for (int i=1;isize();++i){ params=(*l)[i]; if (params.type==_VECT && !params._VECTptr->empty()) break; } // IMPROVE: using context and *l look for assumptions if (params.type==_VECT){ vecteur paramv=*params._VECTptr; for (unsigned j=0;jeval(1,g,contextptr); if ((g2.type==_VECT) && (g2.subtype==_ASSUME__VECT)){ vecteur V=*g2._VECTptr; if ( V.size()==3 && V[1].type==_VECT && V[2].type==_VECT){ for (unsigned i=0;isize();++i){ gen tmp=(*V[1]._VECTptr)[i]; if (tmp.type==_VECT && tmp._VECTptr->size()==2){ gen a=tmp._VECTptr->front(),b=tmp._VECTptr->back(); if (a==minus_inf) vb[j]=b-1; else { if (b==plus_inf) vb[j]=a+1; else { if (a+b==0) vb[j]=b/2; else vb[j]=(a+b)/2; } } } } } // end if V.size()==3 } // end g2 assume_vect } // end for j } // end params.type==_VECT } vecteur vb0=vb; polynome pb(1),px(unsplitmultivarpoly(p,innerdim)); find_good_eval(px,pb,vb); // need to modify find_good_eval for assumptions... if (vb==vb0) *logptr(contextptr) << gettext("The choice was done assuming ") << params << "=" << vb << endl; else *logptr(contextptr) << gettext("Non regular value ") << vb0 << gettext(" was discarded and replaced randomly by ") << params << "=" << vb << endl; racines=proot(polynome2poly1(pb)); } else racines=proot(*b__VECT._VECTptr); if (is_undef(racines)) return gensizeerr(contextptr); // racines= list of approx roots if b__VECT is numeric // empty if not numeric racine_max=in_select_root(racines,is_real(b__VECT,contextptr),contextptr); } if (!trouve && !is_undef(racine_max)){ // select root for b // now eval each factor over racine_max and choose the one with // minimal absolute value double min_abs=0; for (;f_it!=f_itend;++f_it){ vecteur vtmp(polynome2poly1(f_it->fact)); gen tmp; lcmdeno_converted(vtmp,tmp,contextptr); int maxsave=max_sum_sqrt(contextptr); max_sum_sqrt(0,contextptr); if (innerdim) tmp=r2sym(vtmp,vecteur(1,vb),contextptr); else tmp=r2sym(vtmp,vecteur(1,vecteur(0)),contextptr); max_sum_sqrt(maxsave,contextptr); tmp=evalf(tmp,1,contextptr); if (tmp.type==_VECT && !tmp._VECTptr->empty()) tmp=tmp/tmp._VECTptr->front(); gen f_racine_max(evalf_double(abs(horner(tmp,racine_max),contextptr),1,contextptr)); if (f_racine_max.type!=_DOUBLE_) continue; double current_evaluation=fabs(f_racine_max._DOUBLE_val); if (!trouve){ trouve=true; min_abs=current_evaluation; p=f_it->fact; } else { if (min_abs>current_evaluation){ min_abs=current_evaluation; p=f_it->fact; } } } } if (!trouve) { for (;f_it!=f_itend;++f_it){ if ( (b.type==_EXT) && is_zero(horner(polynome2poly1(f_it->fact,1),*b._EXTptr)) ){ p=f_it->fact; break; } int d=f_it->fact.lexsorted_degree(); if (d && (d<=min_deg)){ p=f_it->fact; min_deg=d; } } } // end choose by degree clean(p); b__VECT=polynome2poly1(p/p.coord.front().value); // p must be monic (?) // compute new minimal polynomial int k; gen res1=common_minimal_POLY(a__VECT,b__VECT,a,b,k,contextptr); if ((a_orig.type==_EXT) && (b_orig.type==_EXT) && !is_undef(res1)) return algebraic_EXTension(a_orig+gen(k)*b_orig,res1); else return res1; } gen ext_add(const gen & aa,const gen & bb,GIAC_CONTEXT){ gen a(ext_reduce(aa)),b(ext_reduce(bb)); if ( (a.type!=_EXT) || (b.type!=_EXT) ) return a+b; if (*(a._EXTptr+1)==*(b._EXTptr+1)){ if ( (a._EXTptr->type==_VECT) && (b._EXTptr->type==_VECT)){ gen c=new ref_vecteur; addmodpoly(*a._EXTptr->_VECTptr,*b._EXTptr->_VECTptr,*c._VECTptr); return ext_reduce(c,*(a._EXTptr+1)); return ext_reduce(*(a._EXTptr->_VECTptr)+ *(b._EXTptr->_VECTptr),*(a._EXTptr+1)); } else return ext_reduce(*a._EXTptr+*b._EXTptr,*(a._EXTptr+1)); } gen c=common_EXT(*(a._EXTptr+1),*(b._EXTptr+1),0,contextptr); if (is_undef(c)) return c; // if c.type==_INT_/_ZINT, call ichinrem on a.extptr,b.extptr,... return ext_reduce(a)+ext_reduce(b); } gen ext_sub(const gen & a,const gen & b,GIAC_CONTEXT){ if (*(a._EXTptr+1)==*(b._EXTptr+1)){ if ( (a._EXTptr->type==_VECT) && (b._EXTptr->type==_VECT)){ #if 1 gen c=new ref_vecteur; submodpoly(*a._EXTptr->_VECTptr,*b._EXTptr->_VECTptr,*c._VECTptr); return ext_reduce(c,*(a._EXTptr+1)); #endif return ext_reduce(*(a._EXTptr->_VECTptr)- *(b._EXTptr->_VECTptr),*(a._EXTptr+1)); } else return ext_reduce(*a._EXTptr-*b._EXTptr,*(a._EXTptr+1)); } return ext_add(a,-b,contextptr); } gen ext_mul(const gen & aa,const gen & bb,GIAC_CONTEXT){ gen a(ext_reduce(aa)),b(ext_reduce(bb)); if ( (a.type!=_EXT) || (b.type!=_EXT) ) return a*b; if (*(a._EXTptr+1)==*(b._EXTptr+1)){ if ((a._EXTptr->type==_VECT) && (b._EXTptr->type==_VECT)){ #if 1 gen c=new ref_vecteur; operator_times(*a._EXTptr->_VECTptr,*b._EXTptr->_VECTptr,0,*c._VECTptr); return ext_reduce(c,*(a._EXTptr+1)); #endif return ext_reduce( *(a._EXTptr->_VECTptr) * *(b._EXTptr->_VECTptr),*(a._EXTptr+1)); } else return ext_reduce((*a._EXTptr)*(*b._EXTptr),*(a._EXTptr+1)); } gen c=common_EXT(*(a._EXTptr+1),*(b._EXTptr+1),0,contextptr); if (is_undef(c)) return c; // if c.type==_INT_/_ZINT, call ichinrem on a._EXTptr,b._EXTptr,... return ext_reduce(a)*ext_reduce(b); } gen inv_EXT(const gen & aa){ if (aa.type!=_EXT) return inv(aa,context0); gen a(ext_reduce(aa)); if (a.type==_FRAC){ return a._FRACptr->den*inv_EXT(a._FRACptr->num); } if (a.type!=_EXT) return inv(a,context0); if (a._EXTptr->type==_VECT){ vecteur u,v,d; egcd(*(a._EXTptr->_VECTptr),*((a._EXTptr+1)->_VECTptr),0,u,v,d); if (d.size()!=1) return gensizeerr(gettext("inv_EXT")); gen de=d.front(),du=u; simplify(du,de); return fraction(algebraic_EXTension(du,*(a._EXTptr+1)),de); } return gentypeerr(gettext("inv_EXT")); } gen horner_rootof(const vecteur & p,const gen & g,GIAC_CONTEXT){ if (g.type==_SYMB && g._SYMBptr->feuille.type==_VECT && // false int(g._SYMBptr->feuille._VECTptr->size())>max_sum_sqrt(contextptr) ) return symb_horner(p,g); const_iterateur it=p.begin(),itend=p.end(); gen res; for (;it!=itend;++it){ res=ratnormal(res*g+*it,contextptr); } return ratnormal(res,contextptr); } bool has_rootof_value(const gen & Pmin,gen & value,GIAC_CONTEXT){ value=undef; if (contextptr && contextptr->globalcontextptr->rootofs){ const vecteur & r=*contextptr->globalcontextptr->rootofs; for (unsigned i=0;isize()==2 && Pmin.type==_VECT && ri._VECTptr->front().type==_VECT && *Pmin._VECTptr==*ri._VECTptr->front()._VECTptr){ value=ri._VECTptr->back(); return true; } } } return !is_undef(value); } static string printasrootof(const gen & g,const char * s,GIAC_CONTEXT){ if (contextptr && g.type==_VECT && g._VECTptr->size()==2){ gen value; if (g._VECTptr->front().type==_VECT && has_rootof_value(g._VECTptr->back(),value,contextptr)){ value=horner_rootof(*g._VECTptr->front()._VECTptr,value,contextptr); string res=value.print(contextptr); if (need_parenthesis(value)) res=("("+res)+')'; return res; } } string res(s); res+='('; res+=g.print(contextptr); res+=')'; return res; } // rootof has 2 args: P(theta) and Pmin(theta) gen symb_rootof(const gen & p,const gen &pmin,GIAC_CONTEXT){ if (p.type!=_VECT) return p; // first check that pmin is in the list of known rootof gen value(undef); if (!rootof_trylock()){ rootmap::iterator it=symbolic_rootof_list().find(pmin),itend=symbolic_rootof_list().end(); if (it!=itend) value=it->second; rootof_unlock(); } if (is_undef(value)) return symbolic(at_rootof,makevecteur(p,pmin)); return horner_rootof(*p._VECTptr,value,contextptr); // return ratnormal(ratnormal(symb_horner(*p._VECTptr,it->second))); } gen rootof(const gen & e,GIAC_CONTEXT){ if (e.type!=_VECT){ vecteur v=lidnt(e); if (v.size()==1) return rootof(_symb2poly(makesequence(e,v.front()),contextptr),contextptr); return gentypeerr(gettext("rootof")); } if (e.type==_VECT && *e._VECTptr==makevecteur(1,0,1)){ *logptr(contextptr) << "rootof([1,0,1]) was converted to i" << endl; return cst_i; } if (e._VECTptr->size()==2 && e._VECTptr->front().type!=_VECT){ vecteur v=lidnt(e); if (v.size()!=1) return gentypeerr(gettext("rootof")); return rootof(makesequence(_symb2poly(makesequence(e._VECTptr->front(),v.front()),contextptr),_symb2poly(makesequence(e._VECTptr->back(),v.front()),contextptr)),contextptr); } if (e._VECTptr->size()!=2 || e._VECTptr->back().type!=_VECT) return rootof(makesequence(makevecteur(1,0),e),contextptr); if (has_num_coeff(e)) return approx_rootof(e,contextptr); if (!lop(lvar(e),at_pow).empty()){ *logptr(contextptr) << gettext("Algebraic extensions not allowed in a rootof")<size()==2 && e._VECTptr->back().type==_VECT){ vecteur v2=*e._VECTptr->back()._VECTptr; gen g(1); lcmdeno(v2,g,contextptr); return symbolic(at_rootof,gen(makevecteur(e._VECTptr->front(),gen(v2,e._VECTptr->back().subtype)),e.subtype)); } return symbolic(at_rootof,e); } gen approx_rootof(const gen & e,GIAC_CONTEXT){ if ( (e.type!=_VECT) || (e._VECTptr->size()!=2) ) return gensizeerr(contextptr); if (!lidnt(e).empty()) return symbolic(at_rootof,e); gen a=e._VECTptr->front(),b=e._VECTptr->back(); return alg_evalf(a,b,contextptr); } /* statically in derive.cc static gen d1_rootof(const gen & args,GIAC_CONTEXT){ return gentypeerr(contextptr); return zero; } static gen d2_rootof(const gen & args,GIAC_CONTEXT){ return gentypeerr(contextptr); return zero; } define_unary_function_ptr( D1_rootof,alias_D1_rootof,new unary_function_eval(0,&d1_rootof,"")); define_unary_function_ptr( D2_rootof,alias_D2_rootof,new unary_function_eval(0,&d2_rootof,"")); static unary_function_ptr d_rootof(int i){ if (i==1) return D1_rootof; if (i==2) return D2_rootof; return gensizeerr(contextptr); return 0; } partial_derivative_multiargs D_rootof(&d_rootof); */ static const char _rootof_s []="rootof"; static define_unary_function_eval2 (__rootof,&giac::rootof,_rootof_s,&printasrootof); define_unary_function_ptr5( at_rootof ,alias_at_rootof,&__rootof,0,true); gen max_algext(const gen & args,GIAC_CONTEXT){ gen g=args; if (!is_integral(g) || g.type!=_INT_ || g.val<3) return gensizeerr(contextptr); return MAX_ALG_EXT_ORDER_SIZE=MAX_COMMON_ALG_EXT_ORDER_SIZE=g.val; } static const char _max_algext_s []="max_algext"; static define_unary_function_eval (__max_algext,&giac::max_algext,_max_algext_s); define_unary_function_ptr5( at_max_algext ,alias_at_max_algext,&__max_algext,0,true); static vecteur sturm(const gen & g){ if (g.type!=_POLY) return vecteur(1,g); polynome p(*g._POLYptr); polynome pl(lgcd(p)); polynome pp=p/pl; polynome cont(p.dim); factorization f(sqff(pp)); factorization::const_iterator it=f.begin(),itend=f.end(); gen a=p.coord.front().value; for (;it!=itend;++it){ if (it->mult %2) a=a/it->fact.coord.front().value; } vecteur v(1,pl.coord.empty()?a:a/pl.coord.front().value*pl); for (it=f.begin();it!=itend;++it){ if (it->mult %2) v.push_back(sturm_seq(it->fact,cont)); } return v; } vecteur sturm(const gen &g,const gen & x,GIAC_CONTEXT){ if (g.type==_VECT) return vecteur(1,gensizeerr(contextptr)); vecteur l; if (!is_zero(x)) l.push_back(x); lvar(g,l); fraction fa(e2r(g,l,contextptr)); gen n,d; fxnd(fa,n,d); vecteur v=mergevecteur(sturm(n),sturm(d)); vecteur res,tmp,ll=cdr_VECT(l); const_iterateur it=v.begin(),itend=v.end(); for (;it!=itend;++it){ if (it->type==_VECT){ const_iterateur jt=it->_VECTptr->begin(),jtend=it->_VECTptr->end(); vecteur tmpres; tmpres.reserve(int(jtend-jt)); for (;jt!=jtend;++jt){ if (jt->type==_POLY){ tmp=polynome2poly1(*(jt->_POLYptr),1); tmpres.push_back(r2e(tmp,ll,contextptr)); } else tmpres.push_back(*jt); } res.push_back(tmpres); } else { // it->type != _VECT but we must convert anyway the cst coeff! if (it->type==_POLY){ gen tmpg=polynome2poly1(*(it->_POLYptr),1).front(); res.push_back(r2e(tmpg,ll,contextptr)); } else res.push_back(*it); } } return res; } // v is a sequence of dense polynomials // each poly is evaluated at a, then we count # of sign changes // ignoring zeros // The function modifies a sign variable according to the sign first // non-zero element of v static int number_of_sign_changes(const vecteur & v,const gen & a0,int & global_sign,GIAC_CONTEXT){ gen a=exact(a0,contextptr); gen w=normal(apply1st(v,a,horner),contextptr); int previous_sign=0,current_sign,res=0; const_iterateur it=w._VECTptr->begin(),itend=w._VECTptr->end(); for (;it!=itend;++it){ if (is_exactly_zero(*it)) continue; if (ck_is_strictly_positive(*it,contextptr)) current_sign=1; else current_sign=-1; if (!previous_sign) {// assign first non-zero sign previous_sign=current_sign; global_sign = global_sign *current_sign; } if (previous_sign==current_sign) continue; ++res; previous_sign=current_sign; } return res; } static int sturmab(const gen & g,const gen & x,const gen & a,const gen & b,bool remove_b_root,GIAC_CONTEXT){ if (g.type==_VECT){ #ifdef NO_STDEXCEPT return -2; #else setsizeerr(contextptr); #endif } if (ck_is_strictly_greater(a,b,contextptr)) return sturmab(g,x,b,a,contextptr); if (a==b){ gen tmp; if (is_inf(a) && x.type==_IDNT) tmp=limit(g,*x._IDNTptr,a,0,contextptr); else tmp=subst(g,x,a,false,contextptr); int s=fastsign(tmp,contextptr); if (s==1 || s==-1) return (s-1)/2; } #ifdef NO_STDEXCEPT vecteur lvarg(lvar(g)); if (!lvarg.empty() && lvarg!=vecteur(1,x)) return -2; #endif int res=0,dontcare,global_sign=1; vecteur v=sturm(g,x,contextptr); if (is_undef(v)) return -2; const_iterateur it=v.begin(),itend=v.end(); for (;it!=itend;++it){ if (it->type==_VECT){ res += number_of_sign_changes(*it->_VECTptr,a,global_sign,contextptr)-number_of_sign_changes(*it->_VECTptr,b,dontcare,contextptr); if (remove_b_root && is_zero(horner(it->_VECTptr->front(),b))) --res; } else { if (!ck_is_positive(*it,contextptr)) global_sign = -global_sign; } } if (res) return res; return (global_sign-1)/2; } int sturmab(const gen & g,const gen & x,const gen & a,const gen & b,GIAC_CONTEXT){ return sturmab(g,x,a,b,false,contextptr); } gen _sturmab(const gen & g_orig,GIAC_CONTEXT){ if ( g_orig.type==_STRNG && g_orig.subtype==-1) return g_orig; if ( g_orig.type!=_VECT || g_orig._VECTptr->size()<3 ) return gensizeerr(contextptr); vecteur v(*g_orig._VECTptr); int s=int(v.size()); gen P(v[0]),x(vx_var),a,b; if (s==3){ a=v[1]; b=v[2]; } else { x=v[1]; a=v[2]; b=v[3]; if (P.type==_VECT) *logptr(contextptr) << gettext("Warning: variable name ignored: ") << x << endl; } gen ai=im(a,contextptr); gen bi=im(b,contextptr); if (!is_zero(ai) || !is_zero(bi)){ gen p=_e2r(gen(makevecteur(P,vecteur(1,x)),_SEQ__VECT),contextptr),n,d,g1,g2; if (is_undef(p)) return p; fxnd(p,n,d); vecteur nr; int n1; #if 0 // replace by 1 if you want to count complex rational root on the edges if (n.type==_POLY && n._POLYptr->dim==1){ polynome nrp=*n._POLYptr; nr=crationalroot(nrp,true); n1=csturm_square(nrp,a,b,g1,contextptr); } else n1=csturm_square(n,a,b,g1,contextptr); #else n1=csturm_square(n,a,b,g1,contextptr); #endif int d1=csturm_square(d,a,b,g2,contextptr); if (n1==-1 || d1==-1) return gensizeerr(contextptr); return int(nr.size())+gen(n1)/2+cst_i*gen(d1)/2; } if (s==5 && v[4].type==_INT_) return sturmab(P,x,a,b,v[4].val!=0,contextptr); return sturmab(P,x,a,b,contextptr); } static const char _sturmab_s []="sturmab"; static define_unary_function_eval (__sturmab,&giac::_sturmab,_sturmab_s); define_unary_function_ptr5( at_sturmab ,alias_at_sturmab,&__sturmab,0,true); gen _sturm(const gen & g,GIAC_CONTEXT){ if ( g.type==_STRNG && g.subtype==-1) return g; if (g.type!=_VECT || (g.type==_VECT && g.subtype!=_SEQ__VECT) ) return sturm(g,zero,contextptr); vecteur & v = *g._VECTptr; int s=int(v.size()); if (s==2) return sturm(v.front(),v.back(),contextptr); if (s==4) return _sturmab(g,contextptr); if (s==3){ if (v[2].type!=_IDNT) return gensizeerr(contextptr); gen S=_e2r(gen(makevecteur(v[0],v[2]),_SEQ__VECT),contextptr); if (is_undef(S)) return S; gen R=_e2r(gen(makevecteur(v[1],v[2]),_SEQ__VECT),contextptr); if (is_undef(R)) return R; if (S.type==_FRAC) S=S._FRACptr->num; if (R.type==_FRAC) R=R._FRACptr->num; modpoly r0(gen2vecteur(S)),r1(gen2vecteur(R)); vecteur listquo,coeffP,coeffR; gen pgcd=csturm_seq(r0,r1,listquo,coeffP,coeffR,contextptr); return makevecteur(r0,r1,pgcd,listquo,coeffP,coeffR); } return gendimerr(contextptr); } static const char _sturm_s []="sturm"; static define_unary_function_eval (__sturm,&giac::_sturm,_sturm_s); define_unary_function_ptr5( at_sturm ,alias_at_sturm,&__sturm,0,true); gen _sturmseq(const gen & g,GIAC_CONTEXT){ if ( g.type==_STRNG && g.subtype==-1) return g; // should return in the same format as maple return _sturm(g,contextptr); } static const char _sturmseq_s []="sturmseq"; static define_unary_function_eval (__sturmseq,&giac::_sturmseq,_sturmseq_s); define_unary_function_ptr5( at_sturmseq ,alias_at_sturmseq,&__sturmseq,0,true); void recompute_minmax(const vecteur & w,const vecteur & range,const gen & expr,const gen & var,gen & resmin,gen & resmax,vecteur & xmin,vecteur & xmax,int direction,GIAC_CONTEXT){ const_iterateur it=w.begin(),itend=w.end(); for (;it!=itend;++it){ if (ck_is_strictly_greater(*it,range[1],contextptr) || ck_is_strictly_greater(range[0],*it,contextptr)) continue; #ifdef NO_STDEXCEPT gen tmp=limit(expr,*var._IDNTptr,*it,direction,contextptr); #else gen tmp; try { tmp=limit(expr,*var._IDNTptr,*it,direction,contextptr); } catch (std::runtime_error & err){ tmp=undef; } #endif if (is_undef(tmp) || tmp==unsigned_inf) continue; if (tmp==resmax && !equalposcomp(xmax,*it)) xmax.push_back(*it); else { if (ck_is_strictly_greater(tmp,resmax,contextptr)){ resmax=tmp; xmax=vecteur(1,*it); } } if (tmp==resmin && !equalposcomp(xmin,*it)) xmin.push_back(*it); else { if (ck_is_strictly_greater(resmin,tmp,contextptr)){ resmin=tmp; xmin=vecteur(1,*it); } } } } // minmax=0 both 1 min, 2 max, /3 =1 if return x instead of f(x) gen fminmax(const gen & g,int minmax,GIAC_CONTEXT){ gen expr,var; vecteur v(gen2vecteur(g)); if (v.size()==1) v.push_back(vx_var); if (v.size()!=2) return gensizeerr(contextptr); expr=v[0]; var=v[1]; // avoid inf recursion like g0(x):=ln(abs(ln(x))); // g1(x,xp):=x/(ln(x))^(xp);g0(g1(x,.3)); gen varev=eval(var,1,contextptr); if (varev!=var && contains(varev,var)) return undef; if (expr.type==_SYMB){ unary_function_ptr & u=expr._SYMBptr->sommet; if (u==at_exp || u==at_ln || u==at_atan || u==at_abs){ gen tmp=fminmax(makevecteur(expr._SYMBptr->feuille,var),minmax,contextptr); if (is_undef(tmp)) return tmp; if (u==at_abs && tmp.type==_VECT && tmp._VECTptr->size()==2 ){ gen t1=tmp._VECTptr->front(); gen t2=tmp._VECTptr->back(); if (is_positive(t1,contextptr)) return tmp; if (is_positive(-t2,contextptr)){ return gen(makevecteur(-t2,-t1),_LINE__VECT); } // t1<=0 t2>=0 if (is_greater(-t1,t2,contextptr)) return gen(makevecteur(0,-t1),_LINE__VECT); else return gen(makevecteur(0,t2),_LINE__VECT); } if (u==at_ln && tmp.type==_VECT && tmp._VECTptr->size()==2 && is_positive(-tmp._VECTptr->front(),contextptr) ) tmp._VECTptr->front()=zero; if (minmax/3) return tmp; else return u(tmp,contextptr); } } bool do_find_range=true; vecteur range; if (is_equal(var)){ gen tmp=var._SYMBptr->feuille; if (tmp.type==_VECT && tmp._VECTptr->size()==2){ gen varminmax=tmp._VECTptr->back(); var=tmp._VECTptr->front(); if (varminmax.is_symb_of_sommet(at_interval) && varminmax._SYMBptr->feuille.type==_VECT){ range=*varminmax._SYMBptr->feuille._VECTptr; do_find_range=false; } } } // gensizeerr replaced by undef because otherwise abs(sin(exp(x))) fails on emcc if (var.type!=_IDNT) return undef; // gensizeerr(contextptr); if (do_find_range){ find_range(var,range,contextptr); if (range.size()!=1 || range.front().type!=_VECT) return gensizeerr(gettext("Or condition not implemented")); range=*range.front()._VECTptr; } if (range.size()!=2) return gensizeerr(gettext("fminmax, range ")+gen(range).print(contextptr)); if (range[0]==minus_inf || range[1]==plus_inf){ // periodic function? vecteur w=lvarx(trig2exp(expr,contextptr),var); gen period=0; for (unsigned i=0;ifeuille,a,b; if (!is_linear_wrt(tmp,var,a,b,contextptr) || !is_zero(re(a,contextptr))){ period=0; break; } if (is_zero(a)) continue; a=ratnormal(cst_two_pi/im(a,contextptr),contextptr); // current period if (is_zero(period)) period=a; else { // find common period (if it exists) b=ratnormal(period/a,contextptr); if (b.type!=_INT_ && b.type!=_FRAC){ period=0; break; } if (b.type==_FRAC) period=period*b._FRACptr->den; } } if (!is_zero(period)){ if (w.size()>1) expr=simplify(expr,contextptr); if (range[0]==minus_inf){ if (range[1]==plus_inf){ range[1]=period/2; range[0]=-range[1]; } else range[0]=range[1]-period; } else range[1]=range[0]+period; } } gen df(derive(expr,var,contextptr)); if (is_undef(df)) return df; vecteur w; if (range==makevecteur(minus_inf,plus_inf)) w=solve(df,var,2,contextptr); else { // FIXME: check if var is quoted, otherwise it will be erased gen savevar=var; var._IDNTptr->in_eval(1,var,savevar,contextptr); // if (var._IDNTptr->in_eval(1,var,savevar,contextptr)) 1; giac_assume(symbolic(at_and,makevecteur(symb_superieur_egal(var,range[0]),symb_inferieur_egal(var,range[1]))),contextptr); w=solve(df,var,2,contextptr); if (savevar==var) purgenoassume(var,contextptr); else sto(savevar,var,contextptr); } if (w.empty() && debug_infolevel) *logptr(contextptr) << gettext("Warning: ") << df << gettext("=0: no solution found") << endl; vecteur wvar=makevecteur(cst_pi); lidnt(w,wvar,false); if (wvar.size()>1) return undef; gen resmin=plus_inf; gen resmax=minus_inf; vecteur xmin,xmax; // Extrema recompute_minmax(w,range,expr,var,resmin,resmax,xmin,xmax,0,contextptr); // Limits at begin and end of range recompute_minmax(vecteur(1,range[0]),range,expr,var,resmin,resmax,xmin,xmax,1,contextptr); recompute_minmax(vecteur(1,range[1]),range,expr,var,resmin,resmax,xmin,xmax,-1,contextptr); // Singularities vecteur ws=find_singularities(expr,*var._IDNTptr,0,contextptr); int wss=int(ws.size()); w.clear(); for (int i=0;i prog.h // find extremals values of g // should be improved (currently return -1..1 for sin and cos int find_range(const gen & g,vecteur & a,GIAC_CONTEXT){ if (g.type==_IDNT){ gen g2=g._IDNTptr->eval(1,g,contextptr); if ((g2.type==_VECT) && (g2.subtype==_ASSUME__VECT)){ vecteur v=*g2._VECTptr; if ( (v.size()==3) && (v.front()==vecteur(0) || v.front()==_DOUBLE_ || v.front()==_ZINT || v.front()==_SYMB || v.front()==0) && (v[1].type==_VECT)){ a=*v[1]._VECTptr; return 1; } if (v.size()==1 && v.front()==_ZINT) return 2; } } if (g.type==_SYMB){ #ifndef NO_STDEXCEPT try { #endif if (g._SYMBptr->feuille.type==_SPOL1) return 0; vecteur lv0(lvar(g._SYMBptr->feuille)),lv; // remove cst idnt for (unsigned i=0;isommet); if ( (s==at_sin) || (s==at_cos) ){ a=vecteur(1,gen(makevecteur(minus_one,plus_one),_LINE__VECT)); return 1; } } a=vecteur(1,gen(makevecteur(minus_inf,plus_inf),_LINE__VECT)); return 1; } bool is_sqrt(const gen & a,gen & arg){ if (a.is_symb_of_sommet(at_sqrt)){ arg=a._SYMBptr->feuille; return true; } if (!a.is_symb_of_sommet(at_pow)) return false; gen & f = a._SYMBptr->feuille; if (f.type!=_VECT || f._VECTptr->size()!=2) return false; arg = f._VECTptr->front(); gen & expo = f._VECTptr->back(); if (expo.type!=_FRAC || !is_one(expo._FRACptr->num)) return false; gen & d =expo._FRACptr->den; if (d.type!=_INT_ || d.val!=2) return false; return true; } static int insturmsign1(const gen & g0,bool strict,GIAC_CONTEXT){ gen g=recursive_normal(exact(g0,contextptr),contextptr); if (has_i(g)) return 0; vecteur v(lvar(g)); // search for a sqrt inside v: sign(a+b*sqrt(c))= // = sign(a) if a^2-c*b^2 > 0, // = sign(b) if a^2-c*b^2 < 0 int s=int(v.size()); if (!s #ifdef EMCC || s>1 #endif ) return fastsign(g,contextptr); gen v0(v[0]); for (int i=0;ieval(1,v[i],contextptr).type!=_IDNT){ v0=v[i]; } gen a,b,c; if (is_sqrt(v[i],c)){ identificateur x(" x"); gen g1=subst(g,v[i],x,false,contextptr); if (is_linear_wrt(g1,x,b,a,contextptr)){ gen s=sign(a*b,contextptr); if (is_one(s) && (s=sign(a,contextptr)).type==_INT_) return s.val; s=sign(a*a-c*b*b,contextptr); if (s.type!=_INT_ || is_zero(s.val)) return 0; s=(is_one(s))?sign(a,contextptr):sign(b,contextptr); if (is_one(s)) return 1; if (is_minus_one(s)) return -1; return 0; } } } vecteur a; if (!find_range(v0,a,contextptr)) return -2; int previous_sign=2,current_sign=0; #ifndef NO_STDEXCEPT try { #endif const_iterateur ita=a.begin(),itaend=a.end(); for (;ita!=itaend;++ita){ if ( (ita->type!=_VECT) || (ita->subtype!=_LINE__VECT) || (ita->_VECTptr->size()!=2) ) return 0; gen last(ita->_VECTptr->back()); gen gg(g); identificateur idnttmp("t"); gen testg(subst(g,v0,idnttmp,false,contextptr)); if (is_zero(limit(testg,idnttmp,last,-1,contextptr))){ if (strict && (v0.is_symb_of_sommet(at_sin) || v0.is_symb_of_sommet(at_cos))) return 0; gen tmp=_fxnd(gg,contextptr); if (tmp.type!=_VECT || tmp._VECTptr->size()!=2){ #ifdef NO_STDEXCEPT return -2; #else setsizeerr(contextptr); #endif } gen num=tmp._VECTptr->front(),den=tmp._VECTptr->back(),tmpden; tmp=_e2r(makevecteur(num,v0),contextptr); tmpden=_e2r(makevecteur(den,v0),contextptr); if (is_undef(tmp) || is_undef(tmpden)) return -2; if (is_inf(last) && tmpden.type==_VECT) den=den/pow(v0,2*int(tmpden._VECTptr->size()/2)); tmp=gen2vecteur(tmp); modpoly p(*tmp._VECTptr),q; if (!is_inf(last)) { while (is_zero(horner(p,last,0,q))) p=-q; } gg=_r2e(gen(makevecteur(p,v0),_SEQ__VECT),contextptr)/den; } current_sign=sturmab(gg,v0,ita->_VECTptr->front(),last,true,contextptr); if (current_sign>0 || current_sign==-2) return 0; if (previous_sign==2) previous_sign=current_sign; if (previous_sign!=current_sign) return 0; } #ifndef NO_STDEXCEPT } catch (std::runtime_error & ){ return 0; } #endif return 2*current_sign+1; } static int insturmsign(const gen & g0,bool strict,GIAC_CONTEXT){ //bool absb=eval_abs(contextptr); //eval_abs(false,contextptr); int res=insturmsign1(g0,strict,contextptr); return res; //eval_abs(absb,contextptr); } int sturmsign(const gen & g0,bool strict,GIAC_CONTEXT){ int fs=fastsign(g0,contextptr); if (fs) return fs; gen g=simplifier(g0,contextptr); // first check some operators inv, *, exp, sqrt int tmp; if (g.is_symb_of_sommet(at_neg)){ tmp=sturmsign(g._SYMBptr->feuille,strict,contextptr); return tmp==-2?tmp:-tmp; } if (g.is_symb_of_sommet(at_inv)){ tmp=sturmsign(g._SYMBptr->feuille,strict,contextptr); return tmp; } if (g.is_symb_of_sommet(at_exp)) return 1; /* if (g.is_symb_of_sommet(at_pow) && g._SYMBptr->feuille[1]==plus_one_half) return 1; */ if (g.is_symb_of_sommet(at_prod)){ gen &f=g._SYMBptr->feuille; vecteur v(gen2vecteur(f)); int s=int(v.size()); vecteur w; int res=1,currentsign; // remove cst coeffs and exp/ for (int i=0;ifeuille,strict,contextptr)==1) continue; if ( (currentsign=fastsign(v[i],contextptr)) ) res *= currentsign; else w.push_back(v[i]); } switch (w.size()){ case 0: return res; case 1: tmp=insturmsign(w.front(),strict,contextptr); return tmp==-2?-2:res*tmp; default: tmp=insturmsign(symbolic(at_prod,w),strict,contextptr); return tmp==-2?-2:res*tmp; } } return insturmsign(g,strict,contextptr); } #ifndef NO_NAMESPACE_GIAC } // namespace giac #endif // ndef NO_NAMESPACE_GIAC