// -*- mode:C++ ; compile-command: "g++-3.4 -DHAVE_CONFIG_H -I. -I.. -DIN_GIAC -g -c sym2poly.cc" -*-
#include "giacPCH.h"
/*
* This file implements several functions that work on univariate and
* multivariate polynomials and rational functions.
* These functions include polynomial quotient and remainder, GCD and LCM
* computation, factorization and rational function normalization. */
/*
* Copyright (C) 2000,2014 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 "gen.h"
#include "sym2poly.h"
#include "usual.h"
#include "unary.h"
#include "subst.h"
#include "modpoly.h"
#include "alg_ext.h"
#include "solve.h"
#include "input_parser.h"
#include "ezgcd.h"
#include "prog.h"
#include "ifactor.h"
#include "poly.h"
#include "plot.h"
#include "misc.h"
#include "giacintl.h"
#ifdef HAVE_UNISTD_H
#include
#endif
#ifndef NO_NAMESPACE_GIAC
namespace giac {
#endif // ndef NO_NAMESPACE_GIAC
// "instantiate" debugging functions
void dbgprint(const polynome &p){
p.dbgprint();
}
void dbgprint(const gen & e){
e.dbgprint();
}
vecteur cdr_VECT(const vecteur & l){
if (l.empty())
return vecteur(l);
vecteur::const_iterator it=l.begin(),itend=l.end();
vecteur res;
++it;
for (;it!=itend;++it)
res.push_back(*it);
return vecteur(res);
}
//***************************
// functions relative to lvar
//***************************
int equalposcomp(const vecteur & l,const gen & e){
int n=1;
for (vecteur::const_iterator it=l.begin();it!=l.end();++it){
if ((*it)==e)
return(n);
else
n++;
}
return(0);
}
void addtolvar(const gen & e, vecteur & l){
if (equalposcomp(l,e))
return;
l.push_back(e);
}
static void lvar_symbolic(const gen & g, vecteur &l){
const symbolic & s = *g._SYMBptr;
if ( (s.sommet==at_plus) || (s.sommet==at_prod)){
if (s.feuille.type!=_VECT){
lvar(s.feuille,l);
return;
}
vecteur::iterator it=s.feuille._VECTptr->begin(), itend=s.feuille._VECTptr->end();
for (;it!=itend;++it)
lvar(*it,l);
return;
}
if ( (s.sommet==at_neg) || (s.sommet==at_inv) ){
lvar(s.feuille,l);
return;
}
if ( (s.sommet==at_pow) && ( (*s.feuille._VECTptr)[1].type==_INT_))
lvar(s.feuille._VECTptr->front(),l);
else
addtolvar(g,l);
}
void lvar(const vecteur & v,vecteur & l){
vecteur::const_iterator it=v.begin(),itend=v.end();
for (;it!=itend;++it)
lvar(*it,l);
}
void lvar(const sparse_poly1 & p,vecteur & l){
sparse_poly1::const_iterator it=p.begin(),itend=p.end();
for (;it!=itend;++it){
lvar(it->coeff,l);
// lvar(it->exponent,l);
}
}
void lvar(const gen & e, vecteur & l) {
switch (e.type){
case _INT_: case _DOUBLE_: case _ZINT: case _CPLX: case _POLY: case _EXT: case _USER: case _REAL:
return;
case _IDNT:
if (strcmp(e._IDNTptr->id_name,string_undef))
addtolvar(e,l);
return ;
case _SYMB:
lvar_symbolic(e,l);
return ;
case _VECT:
lvar(*e._VECTptr,l);
return ;
case _FRAC:
lvar(e._FRACptr->num,l);
lvar(e._FRACptr->den,l);
return;
case _MOD:
lvar(*e._MODptr,l);
lvar(*(e._MODptr+1),l);
return;
case _SPOL1:
lvar(*e._SPOL1ptr,l);
return;
default:
return;
}
}
vecteur lvar(const gen & e){
vecteur l;
lvar(e,l);
return l;
}
gen symb_lvar(const gen & e){
return symbolic(at_lvar,e);
}
gen cklvar(const gen & e,GIAC_CONTEXT){
vecteur l;
lvar(e,l);
return l;
}
static const char _lvar_s []="lvar";
static define_unary_function_eval (__lvar,&giac::cklvar,_lvar_s);
define_unary_function_ptr5( at_lvar ,alias_at_lvar,&__lvar,0,true);
static bool is_algebraic_EXTension(const gen & e){
if (e.type==_EXT)
return true;
if (e.type!=_SYMB)
return false;
if ( (e._SYMBptr->sommet==at_sqrt) || (e._SYMBptr->sommet==at_rootof) )
return true;
if ( (e._SYMBptr->sommet==at_pow) && (e._SYMBptr->feuille._VECTptr->back().type==_FRAC) && (e._SYMBptr->feuille._VECTptr->back()._FRACptr->den.type==_INT_) &&(absint(e._SYMBptr->feuille._VECTptr->back()._FRACptr->den.val)<=MAX_ALG_EXT_ORDER_SIZE) )
return true;
return false;
}
static gen algebraic_argument(const gen & e){
if (e.type==_EXT)
return makevecteur(*e._EXTptr,*(e._EXTptr+1));
if (e.type!=_SYMB)
return gensizeerr(gettext("sym2poly.cc/algebraic_argument"));
if ((e._SYMBptr->sommet==at_sqrt) || (e._SYMBptr->sommet==at_rootof) )
return e._SYMBptr->feuille;
if ( (e._SYMBptr->sommet==at_pow) && (e._SYMBptr->feuille._VECTptr->back().type==_FRAC) && (e._SYMBptr->feuille._VECTptr->back()._FRACptr->den.type==_INT_) )
return e._SYMBptr->feuille._VECTptr->front();
return gentypeerr(gettext("algebraic_argument"));
}
static bool equalposmat(const matrice & m,const gen & e,int &i,int & j){
i=0;
const_iterateur it=m.begin(),itend=m.end(),jt,jtend;
for (;it!=itend;++it,++i){
if (*it==e){
j=-1;
return true;
}
else {
if (it->type!=_VECT){
#ifdef NO_STDEXCEPT
return false;
#else
setsizeerr(gettext("sym2poly.cc/equalposmat"));
#endif
}
for (j=0,jt=it->_VECTptr->begin(),jtend=it->_VECTptr->end();jt!=jtend;++jt,++j)
if (*jt==e)
return true;
}
}
return false;
}
static void addfirstrow(const gen & e,matrice & m){
if (m.empty()){
vecteur v(1,e);
m.push_back(v);
}
else {
if (m.front().type!=_VECT){
#ifdef NO_STDEXCEPT
return;
#else
setsizeerr(gettext("sym2poly.cc/addfirstrow"));
#endif
}
vecteur v(*m.front()._VECTptr);
v.push_back(e);
m.front()=v;
}
}
static matrice ext_glue_matrices(const matrice & a,const matrice & b){
if (a.size()>b.size())
return ext_glue_matrices(b,a);
// Algorithm should be fixed in all generality
// the loop below fixes assume(a>0); normal(-sqrt(a)*sqrt(a*pi)*sqrt(pi))
// a.size()<=b.size()
if (a.size()==b.size()){
for (int i=0;isize()size())
break;
if (a[i]._VECTptr->size()>b[i]._VECTptr->size())
return ext_glue_matrices(b,a);
}
}
}
if (b.empty() || a.empty() || (a==b))
return b;
int i,j;
matrice res(b.begin()+1,b.end()); // all alg. extensions of b
// look in a for vars that are not inside res
matrice a_not_in_res;
const_iterateur it=a.begin(),itend=a.end(),jt,jtend;
for (;it!=itend;++it){
vecteur temp;
for (jt=it->_VECTptr->begin(),jtend=it->_VECTptr->end();jt!=jtend;++jt){
if (!equalposmat(res,*jt,i,j))
temp.push_back(*jt);
}
if (it==a.begin() || (!temp.empty()) )
a_not_in_res.push_back(temp);
}
// look in the first row of b for vars that are not inside a_not_in_res
jt=b.begin()->_VECTptr->begin(),jtend=b.begin()->_VECTptr->end();
for (;jt!=jtend;++jt){
if (!equalposmat(a_not_in_res,*jt,i,j))
addfirstrow(*jt,a_not_in_res);
}
return mergevecteur(a_not_in_res,res);
}
void alg_lvar(const sparse_poly1 & p,vecteur & l){
sparse_poly1::const_iterator it=p.begin(),itend=p.end();
for (;it!=itend;++it){
alg_lvar(it->coeff,l);
// lvar(it->exponent,l);
}
}
// return true if there is at least one algebraic extension
void alg_lvar(const gen & e,matrice & m){
vecteur temp;
lvar(e,temp);
int i,j;
// For each variable of temp,
// if not alg var look if still inside m else add it to the first line
// else make a "merge"
const_iterateur it=temp.begin(),itend=temp.end();
for (;it!=itend;++it){
if ( !is_algebraic_EXTension(*it) ){
if (!equalposmat(m,*it,i,j)){
addfirstrow(*it,m);
}
}
else { // *it is an algebraic extension!
#if 1
matrice ext_mat;
vecteur v,vt;
ext_mat.push_back(v);
vt=alg_lvar(algebraic_argument(*it));
int s=int(vt.size());
if (s>1 || (s==1 && !vt.front()._VECTptr->empty()) )
ext_mat=mergevecteur(ext_mat,vt);
m=ext_glue_matrices(ext_mat,m);
#else
vecteur vt;
alg_lvar(algebraic_argument(*it),vt);
if (vt==m) return;
matrice ext_mat;
vecteur v;
ext_mat.push_back(v);
int s=int(vt.size());
if (s>1 || (s==1 && !vt.front()._VECTptr->empty()) )
ext_mat=mergevecteur(ext_mat,vt);
m=ext_glue_matrices(ext_mat,m);
#endif
}
}
}
vecteur alg_lvar(const gen & e){
vecteur l;
l.push_back(l); // insure a null line inside the matrix of alg_lvar
if (has_op(e,*at_rootof)){
vecteur w0=lvar(e),w;
for (int i=0;i vu;
vu.push_back(at_rootof);
vector vv;
vv.push_back(_nop);
// FIXME: arg of e is two vectors, if rootof is ^, this raises a warning
gen er=subst(w,vu,vv,false,context0);
if (er.type==_VECT)
er=subst(e,w,*er._VECTptr,false,context0);
else
er=e;
alg_lvar(er,l);
}
else
alg_lvar(e,l);
return l;
}
gen symb_algvar(const gen & e){
return symbolic(at_algvar,e);
}
gen ckalgvar(const gen & e,GIAC_CONTEXT){
vecteur l;
alg_lvar(e,l);
return l;
}
static const char _algvar_s []="algvar";
static define_unary_function_eval (__algvar,&giac::ckalgvar,_algvar_s);
define_unary_function_ptr5( at_algvar ,alias_at_algvar,&__algvar,0,true);
//***********************************************
// functions relative to fractions for efficiency
//***********************************************
/*
static fraction fpow(const fraction & p,const gen & n){
if (n.type!=_INT_)
setsizeerr(gettext("sym2poly.cc/fraction pow"));
return pow(p,n.val);
}
*/
gen ref_polynome2gen(ref_polynome * refptr){
if (refptr->t.coord.empty()){
delete refptr;
return 0;
}
if (refptr->t.coord.front().index.is_zero() && is_atomic(refptr->t.coord.front().value) ){
gen res=refptr->t.coord.front().value;
delete refptr;
return res;
}
return refptr;
}
gen monomial2gen(const monomial & m){
if (m.index.is_zero() && is_atomic(m.value) ){
return m.value;
}
return new ref_polynome(m);
}
gen simplify3(gen & n,gen & d){
if (is_one(n) || is_one(d))
return plus_one;
if (n.type==_EXT){
gen n_EXT=*n._EXTptr;
gen g=simplify(n_EXT,d);
if (!is_one(g)) n=algebraic_EXTension(n_EXT,*(n._EXTptr+1));
return g;
}
if ((n.type==_POLY) && (d.type==_POLY)){
ref_polynome * pptr = new ref_polynome(n._POLYptr->dim);
if (
#ifndef SMARTPTR64
n.__POLYptr->ref_count==1 && d.__POLYptr->ref_count==1
#else
((ref_polynome*)(* (ulonglong *) &n >> 16))->ref_count ==1 &&
((ref_polynome*)(* (ulonglong *) &d >> 16))->ref_count ==1
#endif
){
simplify(*n._POLYptr,*d._POLYptr,pptr->t);
return pptr;
}
polynome np(*n._POLYptr),dp(*d._POLYptr);
simplify(np,dp,pptr->t);
gen tmpmult(plus_one);
lcmdeno(pptr->t,tmpmult);
if (tmpmult.type==_POLY)
tmpmult=polynome(monomial(tmpmult,index_t(pptr->t.dim)));
gen g;
if (is_one(tmpmult))
g=pptr;
else
g=fraction(tmpmult*pptr,tmpmult); // polynome(tmpmult,np.dim));
// changed 4 nov. 2012 failure on f(x):=sqrt(x)/(x+1); F:=normal(f'(x));
// Fix 9/2/2013: np and dp may have denominators if there are _EXT coeffs
tmpmult=1;
lcmdeno(np,tmpmult);
lcmdeno(dp,tmpmult);
n=np*tmpmult;
d=dp*tmpmult;
// moved 18/3/2014 for simplify(acos2atan(acos(sqrt(1-x^2))+acos(x)))
if (tmpmult.type==_POLY) tmpmult=polynome(monomial(tmpmult,index_t(pptr->t.dim)));
if (is_one(tmpmult))
return g;
return fraction(g,tmpmult); // g*tmpmult;
}
if (n.type==_POLY) {
gen l;
vector< monomial > :: const_iterator it=n._POLYptr->coord.begin(),itend=n._POLYptr->coord.end();
if (itvalue,(itend-1)->value,context0);
++it; --itend;
}
for (;it!=itend;++it){
l=gcd(l,it->value,context0);
if (is_one(l))
return l;
}
gen g=simplify3(l,d);
if (is_one(g))
return g;
polynome np(*n._POLYptr);
np=np/g;
n=np;
if (g.type>_DOUBLE_){
// FIXME embedd g and d inside a polynomial like np was
polynome pg(np.dim);
pg.coord.push_back(monomial(g,np.dim));
g=pg;
polynome pd(np.dim);
pd.coord.push_back(monomial(d,np.dim));
d=pd;
}
return g;
}
if (d.type==_POLY){
polynome np(n,d._POLYptr->dim),dp(*d._POLYptr);
polynome g(np.dim);
g=simplify(np,dp);
n=np;
d=dp;
return g;
}
gen g=gcd(n,d,context0);
n=n/g; // iquo(n,g);
d=d/g; // iquo(d,g);
return g;
}
static bool has_EXT(const gen & g){
if (g.type==_EXT)
return true;
if (g.type!=_POLY)
return false;
polynome & p = *g._POLYptr;
vector< monomial >::const_iterator it=p.coord.begin(),itend=p.coord.end();
for (;it!=itend;++it){
if (has_EXT(it->value))
return true;
}
return false;
}
static void _FRACadd(const gen & n1, const gen & d1,const gen & n2, const gen & d2, gen & num, gen & den){
// COUT << n1 << "/" << d1 << "+" << n2 << "/" << d2 << "=";
if (is_one(d1)){
num=n1*d2+n2;
den=d2;
return;
}
if (is_one(d2)){
num=n2*d1+n1;
den=d1;
// COUT << num << "/" << den << endl;
return;
}
// n1/d1+n2/d2 with g=gcd(d1,d2), d1=d1g*g, d2=d2g*g is
// (n1*d2g+n2*d1g)/g * 1/(d1g*d2g)
gen d1g(d1),d2g(d2),coeff(1);
den=simplify3(d1g,d2g);
if (den.type==_FRAC){
coeff=den._FRACptr->den;
den=den._FRACptr->num;
}
num=(n1*d2g+n2*d1g)*coeff;
simplify3(num,den);
den=den*d1g*d2g;
}
static void _FRACmul(const gen & n1, const gen & d1,const gen & n2, const gen & d2, gen & num, gen & den){
// COUT << n1 << "/" << d1 << "*" << n2 << "/" << d2 << "=";
if (is_one(d1)){
num=n1;
den=d2;
simplify3(num,den);
num=num*n2;
// COUT << num << "/" << den << endl;
return;
}
if (is_one(d2)){
num=n2;
den=d1;
simplify3(num,den);
num=num*n1;
// COUT << num << "/" << den << endl;
return;
}
num=n1;
den=d2;
simplify3(num,den);
gen ntemp(n2),dtemp(d1);
simplify3(ntemp,dtemp);
num=num*ntemp;
den=den*dtemp;
// Further simplifications may occur with _EXT multiplications
if (has_EXT(ntemp))
simplify3(num,den);
// COUT << num << "/" << den << endl;
}
//**********************************
// symbolic to tensor
//**********************************
static bool sym2radd (vecteur::const_iterator debut,vecteur::const_iterator fin,const gen & iext,const vecteur &l,const vecteur & lv, const vecteur & lvnum,const vecteur & lvden, int l_size, gen & num, gen & den,GIAC_CONTEXT){
bool totally_converted=true;
if (fin-debut<4){
gen n1,d1,n2,d2;
num=zero;
den=plus_one;
for (;debut!=fin;++debut){
totally_converted=totally_converted && sym2r(*debut,iext,l,lv,lvnum,lvden,l_size,n1,d1,contextptr);
n2=num;
d2=den;
_FRACadd(n1,d1,n2,d2,num,den);
}
}
else {
vecteur::const_iterator milieu=debut+(fin-debut)/2;
gen n1,d1,n2,d2;
totally_converted=totally_converted && sym2radd(debut,milieu,iext,l,lv,lvnum,lvden,l_size,n1,d1,contextptr);
totally_converted=totally_converted && sym2radd(milieu,fin,iext,l,lv,lvnum,lvden,l_size,n2,d2,contextptr);
_FRACadd(n1,d1,n2,d2,num,den);
}
return totally_converted;
}
/*
static bool sym2rmulold (vecteur::const_iterator debut,vecteur::const_iterator fin,const vecteur &l, const vecteur & lv, const vecteur & lvnum,const vecteur & lvden,int l_size, gen & num, gen & den,GIAC_CONTEXT){
bool totally_converted=true;
// First check for a "normal" monomial
gen coeff=plus_one;
if (!l.empty()){
bool embedd = l.front().type==_VECT ;
vecteur l1;
if (embedd)
l1=*l.front()._VECTptr;
else
l1=l;
gen tmp;
int pui,pos;
index_t i(l_size);
for (;debut!=fin;++debut){
if (debut->type<_IDNT)
coeff=coeff*(*debut);
else {
if (debut->is_symb_of_sommet(at_pow) && debut->_SYMBptr->feuille._VECTptr->back().type==_INT_){
tmp=debut->_SYMBptr->feuille._VECTptr->front();
pui=debut->_SYMBptr->feuille._VECTptr->back().val;
}
else {
tmp=*debut;
pui=1;
}
if ( tmp.type==_IDNT && (pos=equalposcomp(l1,tmp)) && pui>=0){
i[pos-1] += pui;
}
else
break;
}
}
if (!is_zero(coeff))
coeff=monomial2gen(monomial(coeff,i));
}
if (fin-debut<4){
gen n1,d1,n2,d2;
num=coeff;
den=plus_one;
for (;debut!=fin;++debut){
totally_converted=totally_converted && sym2r(*debut,iext,l,lv,lvnum,lvden,l_size,n1,d1,contextptr);
n2=num;
d2=den;
_FRACmul(n1,d1,n2,d2,num,den);
}
}
else {
vecteur::const_iterator milieu=debut+(fin-debut)/2;
gen n1,d1,n2,d2;
totally_converted=totally_converted && sym2rmulold(debut,milieu,l,lv,lvnum,lvden,l_size,n1,d1,contextptr);
totally_converted=totally_converted && sym2rmulold(milieu,fin,l,lv,lvnum,lvden,l_size,n2,d2,contextptr);
_FRACmul(n1,d1,n2,d2,num,den);
simplify3(coeff,den);
num=num*coeff;
}
return totally_converted;
}
*/
static bool sym2rmul (vecteur::const_iterator debut,vecteur::const_iterator fin,const gen & iext,const vecteur &l, const vecteur & lv, const vecteur & lvnum,const vecteur & lvden,int l_size, gen & num, gen & den,GIAC_CONTEXT){
bool totally_converted=true;
// First check for a "normal" monomial
gen coeffnum=plus_one,coeffden=plus_one,coeffn=plus_one,coeffd=plus_one;
if (!l.empty()){
bool embedd = l.front().type==_VECT ;
const vecteur & l1 = embedd?*l.front()._VECTptr:l;
gen tmp;
int pui,pos;
index_t inum(l_size),iden(l_size);
for (;debut!=fin;++debut){
if (debut->type<_IDNT)
coeffn=coeffn*(*debut);
else {
if (debut->is_symb_of_sommet(at_inv)){
tmp=debut->_SYMBptr->feuille;
if (tmp.type<_IDNT){
coeffd=coeffd*tmp;
continue;
}
pui=-1;
}
else {
if (debut->is_symb_of_sommet(at_pow) && debut->_SYMBptr->feuille._VECTptr->back().type==_INT_){
tmp=debut->_SYMBptr->feuille._VECTptr->front();
pui=debut->_SYMBptr->feuille._VECTptr->back().val;
}
else {
tmp=*debut;
pui=1;
}
}
if (absint(pui)>=(1<<15))
coeffn=gensizeerr(gettext("Polynomial exponent overflow."));
if ( (tmp.type==_IDNT || tmp.type==_SYMB) && (pos=equalposcomp(l1,tmp)) ){
if (pui>=0)
inum[pos-1] += pui;
else
iden[pos-1] -= pui;
}
else
break;
}
}
if (!is_exactly_zero(coeffn)){
// simplify inum and iden
bool hasnum=false,hasden=false;
for (int i=0;i(coeffn,inum));
else
coeffnum=coeffn;
if (hasden)
coeffden=monomial2gen(monomial(coeffd,iden));
else
coeffden=coeffd;
}
else
coeffnum=0;
}
if (iext!=0){
gen numr,numi;
reim(coeffnum,numr,numi,contextptr);
if (!is_zero(numi)){
coeffnum=numr+iext*numi;
fxnd(coeffnum,numr,numi);
coeffnum=numr;
coeffden=coeffden*numi;
}
}
if (fin-debut<4){
num=coeffnum;
den=coeffden;
gen n1,d1,n2,d2;
for (;debut!=fin;++debut){
totally_converted=totally_converted && sym2r(*debut,iext,l,lv,lvnum,lvden,l_size,n1,d1,contextptr);
n2=num;
d2=den;
_FRACmul(n1,d1,n2,d2,num,den);
}
}
else {
vecteur::const_iterator milieu=debut+(fin-debut)/2;
gen n1,d1,n2,d2,n3,d3;
totally_converted=totally_converted && sym2rmul(debut,milieu,iext,l,lv,lvnum,lvden,l_size,n1,d1,contextptr);
totally_converted=totally_converted && sym2rmul(milieu,fin,iext,l,lv,lvnum,lvden,l_size,n2,d2,contextptr);
_FRACmul(n1,d1,n2,d2,n3,d3);
_FRACmul(coeffnum,coeffden,n3,d3,num,den);
}
return totally_converted;
}
static bool sym2rxrootnum(vecteur & v,const vecteur & lv,gen & num,gen & tmpden,GIAC_CONTEXT){
// make the polynomial X^d - num
// check for irreducibility
polynome p(poly12polynome(v));
polynome p_content(p.dim);
factorization f;
gen extra_div=1;
if (!factor(p,p_content,f,true,false,false,1,extra_div)){
#ifndef NO_STDEXCEPT
setsizeerr(gettext("Can't check irreducibility extracting rootof"));
#endif
return false;
}
// now we choose the factor of lowest degree of the factorization
int lowest_degree=int(v.size()),deg;
factorization::const_iterator f_it,f_itend=f.end();
// Rewrite num if it's an ext with i, because it is rewritten by factor
if (num.type==_EXT && has_i(num)){
gen b=1;
for (f_it=f.begin();f_it!=f_itend;++f_it){
b=b*f_it->fact.coord.back().value;
}
if (b.type==_EXT){
gen q=evalf(b,1,contextptr)/evalf(num,1,contextptr);
gen qr=_round(q,contextptr);
if (is_zero(q-qr,contextptr)){
num=b/qr;
if (num.type==_FRAC){
// commented since x^d=num is solved using irr_p, translated to b below
// tmpden=tmpden*num._FRACptr->den;
num=num._FRACptr->num;
}
}
}
}
for (f_it=f.begin();f_it!=f_itend;++f_it){
polynome irr_p(f_it->fact);
deg=irr_p.lexsorted_degree();
if (!deg)
continue;
if (deg==1){
v=polynome2poly1(irr_p);
lowest_degree=1;
num=rdiv(-v.back(),v.front(),contextptr);
// cerr << "xroot" << num << endl;
gen numlv=r2sym(num,lv,contextptr);
if (!lvar(evalf(numlv,1,contextptr)).empty())
*logptr(contextptr) << gettext("Warning, checking for positivity of a root depending of parameters might return wrong sign: ")<< numlv << endl;
if (is_positive(numlv,contextptr))
break;
}
if (deg>=lowest_degree)
continue;
v=polynome2poly1(irr_p);
lowest_degree=deg;
}
if (lowest_degree>1){
// here we must check that num is not an extension!!
if (num.type==_EXT){
gen a=*(num._EXTptr+1),b;
gen a__VECTg;
if (a.type==_VECT)
a__VECTg=a;
else {
if( a.type!=_EXT || (a._EXTptr+1)->type!=_VECT){
#ifndef NO_STDEXCEPT
setsizeerr(gettext("sym2poly.cc/sym2rxroot"));
#endif
return false;
}
a__VECTg=*(a._EXTptr+1);
}
int k;
gen new_v=common_minimal_POLY(a__VECTg,v,a,b,k,contextptr);
if (is_undef(new_v))
return false;
*(num._EXTptr+1)=a;
if (b.type==_FRAC){
num=b._FRACptr->num;
tmpden=tmpden*b._FRACptr->den;
}
else
num=b;
}
else {
vecteur w(2);
w[0]=plus_one;
num=algebraic_EXTension(w,v);
}
}
return true;
}
void fxnd(const gen & e,gen & num, gen & den){
if (e.type==_FRAC){
num=e._FRACptr->num;
den=e._FRACptr->den;
}
else {
num=e;
den=plus_one;
}
}
static factorization rsqff(const polynome & p){
polynome s(lgcd(p));
factorization f(sqff(p/s));
if (p.dim==0){
f.push_back(facteur(p,1));
return f;
}
if (p.dim==1){
// adjust const coeff
gen p1=1;
factorization::iterator it=f.begin(),itend=f.end();
for (;it!=itend;++it){
p1 = p1*pow(it->fact.coord.front().value,it->mult);
}
p1=p.coord.front().value/p1;
if (is_positive(-p1,context0)){ // ok
for (it=f.begin();it!=itend;++it){
if (it->mult%2){
it->fact=-it->fact;
p1=-p1;
break;
}
}
}
if (!is_one(p1))
f.push_back(facteur(polynome(p1,1),1));
return f;
}
factorization ff(rsqff(s.trunc1()));
factorization::const_iterator it=ff.begin(),itend=ff.end();
for (;it!=itend;++it)
f.push_back(facteur(it->fact.untrunc1(),it->mult));
return f;
}
void smaller_factor(vecteur & v){
// factor v, select smaller factor
polynome vp(1),vp_content;
vp=poly12polynome(v,1);
gen tmp(1); lcmdeno(vp,tmp); vp=tmp*vp;
factorization vf;
gen extra_div=1;
if (factor(vp,vp_content,vf,true,false,false,1,extra_div) && vf.size()>1){
polynome2poly1(vf.front().fact,1,v);
for (unsigned i=1;i i*sqrt(x-1)
commented!, should common_minimal_poly detect [1,0...0,+/-same_poly]?
if ( (d%2 || d=2) && (
(num.type==_POLY && is_positive(evalf_double(-num._POLYptr->coord.front().value,2,0),0))
) ){
num=-num;
sign_changed=true;
}
*/
// compute number of cst polynomial in num and keep track of dims
int embeddings=0;
vector embeddings_s;
if (is_atomic(num)){
const_iterateur it=l.begin(),itend=l.end();
embeddings=int(itend-it);
if (
0 && // disable for expressions with mixed rootof/fracpow?
embeddings==1 && it->type==_VECT && it->_VECTptr->empty())
embeddings=0;
else {
for (int j=0;jtype!=_VECT){
string s("sym2rxroot error num="+num.print(contextptr)+" den="+den.print(contextptr)+" l="+gen(l).print(contextptr));
CERR << s << endl;
#ifndef NO_STDEXCEPT
setsizeerr(s);
#endif
return false;
}
embeddings_s.push_back(int(it->_VECTptr->size()));
}
}
}
else {
for (;((num.type==_POLY) && (Tis_constant(*num._POLYptr)));++embeddings){
embeddings_s.push_back(num._POLYptr->dim);
num=num._POLYptr->coord.front().value;
}
}
if (num.type==_FRAC){
den=den*num._FRACptr->den;
num=num._FRACptr->num*pow(num._FRACptr->den,d-1);
}
vecteur v(d+1,zero);
gen tmpden=1;
if (num.type==_POLY){
const factorization f=rsqff(*num._POLYptr);
polynome S(plus_one,num._POLYptr->dim),D(plus_one,S.dim);
factorization::const_iterator jt=f.begin(),jtend=f.end();
for (;jt!=jtend;++jt){
if (jt->mult%d)
S=S*pow(jt->fact,jt->mult % d);
D=D*pow(jt->fact,jt->mult/d);
}
// Check sign of D
vecteur Dl(l);
if (embeddings && Dl[embeddings].type==_VECT)
Dl=*Dl[embeddings]._VECTptr;
if (is_positive(r2e(-D,Dl,contextptr),contextptr)){
D=-D;
if (d%2)
S=-S;
}
gen cont=ppz(S);
gen simpl,doubl; bool pos;
zint2simpldoublpos(cont,simpl,doubl,pos,d,contextptr);
if (!pos) simpl=-simpl;
num=simpl*S;
D=doubl*D;
v.front()=plus_one;
v.back()=-num;
sym2rxrootnum(v,vecteur(l.begin()+embeddings,l.end()),num,tmpden,contextptr);
if (num.type==_EXT && num._EXTptr->type==_VECT){
num=algebraic_EXTension(multvecteur(D,*(*num._EXTptr)._VECTptr),*(num._EXTptr+1));
}
else {
if (num.type==_POLY)
num=D**num._POLYptr;
else
num=D*num;
}
}
else {
v.front()=plus_one;
v.back()=-num;
if (is_integer(num)){
gen simpl,doubl;
bool pos;
zint2simpldoublpos(num,simpl,doubl,pos,d,contextptr);
v.back()=pos?-simpl:simpl;
smaller_factor(v);
if (is_minus_one(v.back()))
num=doubl;
else
num=algebraic_EXTension(makevecteur(doubl,0),v);
}
else {
bool neg=false;
#if 1
gen numd;
if (has_evalf(num,numd,1,contextptr) && is_positive(-numd,contextptr))
neg=true;
if (neg){
num=-num;
v.back()=-num;
}
#endif
sym2rxrootnum(v,vecteur(l.begin()+embeddings,l.end()),num,tmpden,contextptr);
if (neg)
num=cst_i*num;
}
}
// end else num integer
// and eventually we embedd num
for (;embeddings;--embeddings){
num=polynome(num,embeddings_s.back());
tmpden=polynome(tmpden,embeddings_s.back());
embeddings_s.pop_back();
}
if (sign_changed){
if (d==2)
num=cst_i*num;
else
num=-num;
}
den=den*tmpden;
return true;
}
static bool sym2r (const symbolic &s,const gen & iext,const vecteur &l, const vecteur & lv, const vecteur & lvnum,const vecteur & lvden, int l_size,gen & num,gen & den,GIAC_CONTEXT){
if (s.sommet==at_plus){
if (s.feuille.type!=_VECT){
return sym2r(s.feuille,iext,l,lv,lvnum,lvden,l_size,num,den,contextptr);
}
vecteur::iterator debut=s.feuille._VECTptr->begin();
vecteur::iterator fin=s.feuille._VECTptr->end();
return sym2radd(debut,fin,iext,l,lv,lvnum,lvden,l_size,num,den,contextptr);
}
if (s.sommet==at_prod){
vecteur::iterator debut=s.feuille._VECTptr->begin();
vecteur::iterator fin=s.feuille._VECTptr->end();
bool res=sym2rmul(debut,fin,iext,l,lv,lvnum,lvden,l_size,num,den,contextptr);
/*
gen numtmp,dentmp;
sym2rmulold(debut,fin,l,lv,lvnum,lvden,l_size,numtmp,dentmp,contextptr);
if (numtmp!=num || dentmp!=den)
return false;
*/
return res;
}
if (s.sommet==at_neg){
bool totally_converted=sym2r(s.feuille,iext,l,lv,lvnum,lvden,l_size,num,den,contextptr);
num=-num;
return totally_converted;
}
if (s.sommet==at_inv){
bool totally_converted=sym2r(s.feuille,iext,l,lv,lvnum,lvden,l_size,num,den,contextptr);
if (is_zero(num)){
num=unsigned_inf;
den=plus_one;
return true;
}
if (num.type==_EXT){
gen temp(inv_EXT(num)*den);
fxnd(temp,num,den);
}
else {
if ( (num.type==_POLY) && (num._POLYptr->dim==0) && (!num._POLYptr->coord.empty()) && (num._POLYptr->coord.front().value.type==_EXT) ){
gen temp(inv_EXT(num._POLYptr->coord.front().value));
if ( (den.type==_POLY) && (den._POLYptr->dim==0) && (!den._POLYptr->coord.empty()) )
temp=temp*den._POLYptr->coord.front().value;
else
temp=temp*den;
gen tempnum,tempden;
fxnd(temp,tempnum,tempden);
polynome tmpnum(0),tmpden(0);
tmpnum.coord.push_back(monomial(tempnum,index_t(0)));
tmpden.coord.push_back(monomial(tempden,index_t(0)));
num=tmpnum;
if (tempden.type==_POLY)
den=tmpden;
else
den=tempden;
}
else {
#if defined RTOS_THREADX || defined BESTA_OS || defined USTL
gen g=num; num=den; den=g;
#else
swap(num,den);
#endif
}
}
return totally_converted;
}
if (s.sommet==at_pow){
if ((*s.feuille._VECTptr)[1].type==_INT_) {
bool totally_converted=sym2r(s.feuille._VECTptr->front(),iext,l,lv,lvnum,lvden,l_size,num,den,contextptr);
int n=(*s.feuille._VECTptr)[1].val;
if (absint(n)>=(1<<15))
num=gensizeerr(gettext("Polynomial exponent overflow."));
if (n<0){
if (num.type==_EXT){
gen temp(inv_EXT(num)*den);
fxnd(temp,num,den);
}
else {
#if defined RTOS_THREADX || defined BESTA_OS || defined USTL
gen g=num; num=den; den=g;
#else
swap(num,den);
#endif
}
num=pow(num,-n);
den=pow(den,-n);
}
else {
num=pow(num,n);
den=pow(den,n);
}
if (num.type==_EXT)
simplify3(num,den);
// FIXME: embeddings like for rootof
return totally_converted;
}
if ((*s.feuille._VECTptr)[1].type==_FRAC) {
fraction f=*((*s.feuille._VECTptr)[1]._FRACptr);
if ( (f.num.type==_INT_) && (f.den.type==_INT_)){
bool totally_converted=sym2r(s.feuille._VECTptr->front(),iext,l,lv,lvnum,lvden,l_size,num,den,contextptr);
if (!sym2rxroot(num,den,f.num.val,f.den.val,l,contextptr))
return false;
return totally_converted;
}
}
}
if (s.sommet==at_rootof){
bool totally_converted=sym2r(s.feuille._VECTptr->front(),iext,l,lv,lvnum,lvden,l_size,num,den,contextptr);
gen pmin_num,pmin_den;
totally_converted=totally_converted && sym2r(s.feuille._VECTptr->back(),iext,l,lv,lvnum,lvden,l_size,pmin_num,pmin_den,contextptr);
if (!is_one(pmin_den)){
#ifndef NO_STDEXCEPT
setsizeerr(gettext("Minimal poly. in rootof must be fraction free"));
#endif
return false;
}
int embeddings=0;
vector embeddings_s;
// put out constant polynomials
if (num.type!=_VECT || pmin_num.type!=_VECT)
return totally_converted;
vecteur vnum=*num._VECTptr,vpmin=*pmin_num._VECTptr;
int s=int(l.size());
for (;embeddingstype==_POLY && Tis_constant(*it->_POLYptr))
continue;
exitmainloop=true;
break;
}
if (exitmainloop)
break;
if (l[embeddings].type!=_VECT){
#ifndef NO_STDEXCEPT
setsizeerr(gettext("sym2poly.cc/bool sym2r (const"));
#endif
return false;
}
embeddings_s.push_back(int(l[embeddings]._VECTptr->size()));
++embeddings;
for (it=vnum.begin(),itend=vnum.end(),i=0;;++it){
if (it==itend){
if (i==0){
++i;
it=vpmin.begin();
itend=vpmin.end();
}
else
break;
}
if (it->type==_POLY)
*it=it->_POLYptr->coord.front().value;
}
}
num=algebraic_EXTension(vnum,vpmin);
for (;embeddings;--embeddings){
num=polynome(num,embeddings_s.back());
embeddings_s.pop_back();
}
return totally_converted;
}
num=s;
den=plus_one;
return false;
}
static bool sym2r (const fraction &f,const gen &iext,const vecteur &l, const vecteur & lv, const vecteur & lvnum,const vecteur & lvden, int l_size,gen & num,gen & den,GIAC_CONTEXT){
gen dent,numt;
bool totally_converted=sym2r(f.num,iext,l,lv,lvnum,lvden,l_size,num,dent,contextptr);
totally_converted=totally_converted && sym2r(f.den,iext,l,lv,lvnum,lvden,l_size,den,numt,contextptr);
num=num*numt;
den=den*dent;
return totally_converted;
}
bool sym2r(const vecteur &v,const gen & iext,const vecteur &l, const vecteur & lv, const vecteur & lvnum,const vecteur & lvden, int l_size,gen & num,gen & den,GIAC_CONTEXT){
den=plus_one;
if (v.empty()){
num=zero;
return true;
}
bool totally_converted=true;
gen lcmdeno=plus_one;
const_iterateur it=v.begin(),itend=v.end();
vecteur res,numv;
res.reserve(2*(itend-it));
numv.reserve(itend-it);
for (;it!=itend;++it){
totally_converted=totally_converted && sym2r(*it,iext,l,lv,lvnum,lvden,l_size,num,den,contextptr);
lcmdeno = lcm(lcmdeno,den);
res.push_back(num);
res.push_back(den);
}
for (it=res.begin(),itend=res.end();it!=itend;){
num=*it;
++it;
den=*it;
++it;
numv.push_back(num*rdiv(lcmdeno,den,contextptr));
}
den=lcmdeno;
num=numv;
return totally_converted;
}
bool sym2r(const vecteur &v,const vecteur &l, const vecteur & lv, const vecteur & lvnum,const vecteur & lvden, int l_size,gen & num,gen & den,GIAC_CONTEXT){
return sym2r(v,1,l,lv,lvnum,lvden,l_size,num,den,contextptr);
}
static bool sym2rmod (const gen * gptr,const gen & iext,const vecteur &l, const vecteur & lv, const vecteur & lvnum,const vecteur & lvden, int l_size,gen & num,gen & den,GIAC_CONTEXT){
gen modnum,modden,modulo;
bool totally_converted=sym2r(*(gptr+1),iext,l,lv,lvnum,lvden,l_size,modnum,modden,contextptr);
modulo=rdiv(modnum,modden,contextptr);
totally_converted=totally_converted && sym2r(*gptr,iext,l,lv,lvnum,lvden,l_size,num,den,contextptr);
num=makemod(num,modulo);
den=makemod(den,modulo);
return totally_converted;
}
// iext is an additional parameter (added 5 sept 2014)
// value is 0 if i=sqrt(-1) is not in the algebraic number field from lvnum
// otherwise it is an extension or fraction extension/integer.
bool sym2r (const gen &e,const gen & iext,const vecteur &l, const vecteur & lv, const vecteur & lvnum,const vecteur & lvden, int l_size,gen & num,gen & den,GIAC_CONTEXT){
int n;
switch (e.type ) {
case _INT_: case _DOUBLE_: case _ZINT: case _REAL: case _FLOAT_:
num=e;
den=plus_one;
return true;
case _CPLX:
if (iext==0){
num=e;
den=plus_one;
return true;
}
if (iext.type!=_FRAC){
num=*e._CPLXptr+iext*(*(e._CPLXptr+1));
den=plus_one;
return true;
}
num=*(e._CPLXptr+1);
den=iext._FRACptr->den;
simplify3(num,den);
num=*e._CPLXptr*den+iext._FRACptr->num*num;
return true;
case _IDNT: case _SYMB:
n=equalposcomp(lv,e);
if (n && (unsigned(n)<=lvnum.size())){
num=lvnum[n-1];
den=lvden[n-1];
return true;
}
if ((!l.empty()) && (l.front().type==_VECT) ){
int i,j;
if (equalposmat(l,e,i,j)){
num=monomial2gen(monomial(gen(1),j+1,int(l[i]._VECTptr->size())));
for (int k=i-1;k>=0;--k)
num=monomial2gen(monomial(num,int(l[k]._VECTptr->size())));
den=plus_one;
return true;
}
}
else {
n=equalposcomp(l,e);
if (n){
num=monomial2gen(monomial(gen(1),n,l_size));
den=plus_one;
return true;
}
}
if (e.type!=_SYMB){
num=e;
den=plus_one;
return true;
}
return sym2r(*e._SYMBptr,iext,l,lv,lvnum,lvden,l_size,num,den,contextptr);
case _FRAC:
return sym2r(*e._FRACptr,iext,l,lv,lvnum,lvden,l_size,num,den,contextptr);
case _VECT:
return sym2r(*e._VECTptr,iext,l,lv,lvnum,lvden,l_size,num,den,contextptr);
case _POLY: case _EXT:
if ((!l.empty()) && (l.front().type==_VECT) ){
num=e;
for (int k=int(l.size())-1;k>=0;--k) // was l_size
num=monomial2gen(monomial(num,int(l[k]._VECTptr->size())));
den=plus_one;
}
else {
num=monomial2gen(monomial(e,l_size));
den=plus_one;
}
return true;
case _MOD:
return sym2rmod(e._MODptr,iext,l,lv,lvnum,lvden,l_size,num,den,contextptr);
case _USER:
num=e;
den=plus_one;
return true;
default:
#ifndef NO_STDEXCEPT
settypeerr(gettext("Unable to handle type [sym2poly.cc]")+e.print(contextptr));
#endif
num=gensizeerr(gettext("Unable to handle ")+e.print(contextptr));
den=plus_one;
return 0;
}
return 0;
}
static void extract_ext(const gen & g,gen & extracted,vector & embeddings){
if (g.type==_EXT){
extracted= ext_reduce(g);
return;
}
if (g.type==_POLY && !g._POLYptr->coord.empty() && Tis_constant(*g._POLYptr)){
embeddings.push_back(g._POLYptr->dim);
extract_ext(g._POLYptr->coord.front().value,extracted,embeddings);
}
else
extracted=0;
}
static bool check_ext(const gen & oldext,const gen & curext){
if (oldext.type!=_VECT)
return false;
if (curext.type==_EXT)
return oldext!=*(curext._EXTptr+1);
if (curext.type==_FRAC)
return check_ext(oldext,curext._FRACptr->num);
return false;
}
// rewrite extension inside a in terms of a common rootof
// extensions in a must be at the top level
// alg_extin is the current list of already translated algebraic extension
// alg_extout is the current list of corresponding values
// w.r.t the common minpoly
// return a in terms of the common ext
static vecteur common_algext(const vecteur & a,const vecteur & l,GIAC_CONTEXT){
const_iterateur it,itend=a.end();
vecteur alg_extin,alg_extoutnum,alg_extoutden;
#if 0 // ndef GIAC_HAS_STO38
// trying with rational univariate rep.
for (it=a.begin();it!=itend;++it){
if (it->type==_EXT){
gen minpoly=*(it->_EXTptr+1);
if (minpoly.type!=_VECT)
break;
unsigned i=0,s=minpoly._VECTptr->size();
for (;itype==_EXT)
break;
}
if (itend==it)
return a;
alg_extin.push_back(*(it->_EXTptr+1));
gen curext=*(it->_EXTptr+1);
gen minpoly=curext;
alg_extoutnum.push_back(makevecteur(1,0));
alg_extoutden.push_back(1);
++it;
for (;it!=itend;++it){
if (it->type!=_EXT)
continue;
curext=*(it->_EXTptr+1);
if (equalposcomp(alg_extin,curext))
continue;
// make common extension of curext and minpoly
gen oldminpoly=minpoly;
gen oldcurext=curext;
if (curext==oldminpoly){
alg_extin.push_back(oldcurext);
alg_extoutnum.push_back(makevecteur(1,0));
alg_extoutden.push_back(1);
continue;
}
else
minpoly=common_EXT(curext,oldminpoly,&l,contextptr);
if (minpoly.type!=_VECT)
return vecteur(1,gensizeerr(contextptr));
if (minpoly._VECTptr->size()>unsigned(MAX_COMMON_ALG_EXT_ORDER_SIZE))
return vecteur(1,undef);
// compute alg_extoutnum/den using newminpoly
int s=int(alg_extin.size());
for (int i=0;inum,oldminpoly._FRACptr->den,resn,resd);
alg_extoutden[i]=alg_extoutden[i]*resd;
if (resn.type!=_EXT || *(resn._EXTptr+1)!=minpoly)
return vecteur(1,gensizeerr(contextptr));
alg_extoutnum[i]=*resn._EXTptr;
}
else {
gen tmp=horner(*alg_extoutnum[i]._VECTptr,oldminpoly);
if (tmp.type!=_EXT || *(tmp._EXTptr+1)!=minpoly)
return vecteur(1,gensizeerr(contextptr));
alg_extoutnum[i]=*tmp._EXTptr;
}
}
// add oldcurext/curext to the list
alg_extin.push_back(oldcurext);
if (curext.type==_FRAC){
alg_extoutden.push_back(curext._FRACptr->den);
curext=curext._FRACptr->num;
}
else
alg_extoutden.push_back(1);
if (curext.type!=_EXT || *(curext._EXTptr+1)!=minpoly)
return vecteur(1,gensizeerr(contextptr));
alg_extoutnum.push_back(*curext._EXTptr);
}
vecteur res;
for (it=a.begin();it!=itend;++it){
if (it->type!=_EXT)
res.push_back(*it);
int n=equalposcomp(alg_extin,*(it->_EXTptr+1));
if (!n)
return vecteur(1,gensizeerr(contextptr));
--n;
gen tmp=alg_extoutnum[n];
if (tmp.type==_VECT)
tmp.subtype=_POLY1__VECT;
if (!is_one(alg_extoutden[n])){
gen resn,resd;
hornerfrac(*it->_EXTptr->_VECTptr,tmp,alg_extoutden[n],resn,resd);
if (resn.type==_VECT && minpoly.type==_VECT && resn._VECTptr->size()>=minpoly._VECTptr->size()){
resn = *resn._VECTptr % *minpoly._VECTptr;
gen tmp;
lcmdeno_converted(*resn._VECTptr,tmp,contextptr);
resd=resd*tmp;
}
res.push_back(algebraic_EXTension(resn,minpoly)/resd);
}
else {
tmp=horner(*it->_EXTptr,tmp);
if (tmp.type!=_VECT)
res.push_back(tmp);
else
res.push_back(algebraic_EXTension(tmp,minpoly));
}
}
return res;
}
static bool compute_lv_lvnum_lvden(const vecteur & l,vecteur & lv,vecteur & lvnum,vecteur & lvden,bool & totally_converted,int l_size,GIAC_CONTEXT){
gen num,den;
// sort by ascending complexity
iterateur it=lv.begin(),itend=lv.end();
lvnum.reserve(itend-it);
lvden.reserve(itend-it);
gen_sort_f(it,itend,symb_size_less);
bool algext=false;
// find num/den for each var of lv
for (;it!=itend;++it){
algext = algext || (it->type==_SYMB && (it->_SYMBptr->sommet==at_pow || it->_SYMBptr->sommet==at_rootof)) ;
totally_converted = totally_converted && sym2r(*it,0,l,lv,lvnum,lvden,l_size,num,den,contextptr);
lvnum.push_back(num);
lvden.push_back(den);
}
if (!algext || lv.size()==1 || l==lv)
return true;
it=lv.begin();
// create common extensions for rootofs
// first find extensions and embeddings levels
std::map< int,vecteur> extensions,newext;
for (int i=0;it!=itend;++it,++i){
if (it->is_symb_of_sommet(at_pow) || it->is_symb_of_sommet(at_rootof)){
gen ext;
vector emb;
extract_ext(lvnum[i],ext,emb);
if (ext.type==_FRAC){
lvnum[i]=lvnum[i]*ext._FRACptr->den;
lvden[i]=lvden[i]*ext._FRACptr->den;
ext=ext._FRACptr->num;
}
if (!is_zero(ext))
extensions[int(emb.size())].push_back(ext);
}
}
// now rewrite each element of the list at each embedding level
std::map< int,vecteur >::iterator jt=extensions.begin(),jtend=extensions.end();
for (;jt!=jtend;++jt){
if (is_undef( (newext[jt->first]=common_algext(jt->second,l,contextptr)) ))
return false;
}
//stores cur
it=lv.begin();
for (int i=0;it!=itend;++it,++i){
if (it->is_symb_of_sommet(at_pow) || it->is_symb_of_sommet(at_rootof)){
gen ext;
vector emb;
extract_ext(lvnum[i],ext,emb);
if (is_zero(ext))
continue;
int n=equalposcomp(extensions[int(emb.size())],ext);
if (!n)
return false; // setsizeerr();
gen tmp=newext[int(emb.size())],den=1;
if (tmp.type!=_VECT || int(tmp._VECTptr->size())den;
tmp=tmp._FRACptr->num;
}
for (;!emb.empty();){
tmp=polynome(tmp,emb.back());
den=polynome(den,emb.back());
emb.pop_back();
}
lvden[i]=lvden[i]*den;
lvnum[i]=tmp;
}
}
return true;
}
bool in_find_extension(const gen & extension,vecteur & already,vector & embed,gen & iext,GIAC_CONTEXT){
iext=0;
if (extension.type==_POLY && !extension._POLYptr->coord.empty()){
const polynome & p=*extension._POLYptr;
embed.push_back(p.dim);
for (unsigned i=0;isize();++i){
gen c=(*Extension._VECTptr)[i];
if (!is_integer(c)){
done=true;
// recurse
if (in_find_extension(c,already,embed,iext,contextptr))
return true;
}
}
if (done)
return false;
iext=makevecteur(1,0,1);
gen currentext=Extension;
common_EXT(iext,currentext,0,contextptr);
if (currentext.type==_EXT)
currentext=*(currentext._EXTptr+1);
if (Extension==currentext)
return true;
already.push_back(Extension);
return false;
}
// remove embedded i in n
bool clean_iext(gen & n,gen & d,const gen & iext,GIAC_CONTEXT){
if (iext==0) return true;
if (n.type==_POLY){
polynome p=*n._POLYptr;
gen iext_=iext;
if (iext.type==_FRAC){
if (iext._FRACptr->num.type==_POLY){
if (iext._FRACptr->num._POLYptr->dim!=0 || iext._FRACptr->num._POLYptr->coord.empty())
return false;
iext_=iext._FRACptr->num._POLYptr->coord.front().value/iext._FRACptr->den;
}
}
else {
if (iext.type==_POLY){
if (iext._POLYptr->dim!=0 || iext._POLYptr->coord.empty())
return false;
iext_=iext._POLYptr->coord.front().value;
}
}
unsigned i=0;
for (i=0;iden;
res=res._FRACptr->num;
}
n=res;
}
}
return true;
}
if (n.type==_CPLX){
n=(*n._CPLXptr)+(*(n._CPLXptr+1))*iext;
gen N,D;
fxnd(n,N,D);
n=N;
d=d*D;
return true;
}
return true;
}
bool clean_iext(vecteur & lvnum,vecteur & lvden,const gen & iext,GIAC_CONTEXT){
if (iext==0) return true;
for (unsigned i=0;i embed;
if (in_find_extension(extension,already,embed,iext,contextptr)){
gen iextnum,iextden;
fxnd(iext,iextnum,iextden);
for (;!embed.empty();){
iextnum=polynome(iextnum,embed.back());
iextden=polynome(iextden,embed.back());
embed.pop_back();
}
return iextnum/iextden;
}
}
}
return 0;
}
gen rootof_extract(const gen & e,GIAC_CONTEXT){
if (e.type==_VECT && e._VECTptr->size()==2)
return e._VECTptr->front()*symb_rootof(gen(makevecteur(1,0),_POLY1__VECT),e._VECTptr->back(),contextptr);
return symbolic(at_rootof,e);
}
void lvar_rootof(const gen & e,const vecteur &l,vecteur & lv,GIAC_CONTEXT){
if (!l.empty() && l.front().type==_VECT && has_op(e,*at_rootof)){
vecteur lve(lvar(e)),lvr;
for (int i=0;i vu;
vu.push_back(at_rootof);
vector vv;
vv.push_back(rootof_extract);
gen er=subst(e,vu,vv,true,contextptr);
lvar(er,lv);
}
else
lvar(e,lv);
}
else
lvar(e,lv);
}
bool sym2r (const gen &e,const vecteur &l, int l_size,gen & num,gen & den,GIAC_CONTEXT){
if (e.type<_POLY){
num=e;
den=plus_one;
return true;
}
if ( (e.type==_POLY) || (e.type==_EXT)){
if ((!l.empty()) && (l.front().type==_VECT) ){
num=e;
for (int k=int(l.size())-1;k>=0;--k) // was l.size()
num=monomial2gen(monomial(num,int(l[k]._VECTptr->size())));
den=plus_one;
}
else {
num=monomial2gen(monomial(e,l_size));
den=plus_one;
}
return true;
}
bool totally_converted=true;
vecteur lv,lvnum,lvden;
lvar_rootof(e,l,lv,context0);
if (!compute_lv_lvnum_lvden(l,lv,lvnum,lvden,totally_converted,l_size,contextptr)){
num=undef;
return false;
}
gen iext=find_iext(e,lvnum,contextptr);
clean_iext(lvnum,lvden,iext,contextptr);
totally_converted =totally_converted && sym2r(e,iext,l,lv,lvnum,lvden,l_size,num,den,contextptr);
if (is_inf(num) && !is_inf(den)) den=1;
if (is_inf(den) && !is_inf(num)) num=1;
// If den is a _POLY, multiply den by the _EXT conjugate of it's lcoeff
// FIXME this should be done recursively if the 1st coeff is a _POLY!
if (den.type==_POLY && !den._POLYptr->coord.empty() && den._POLYptr->coord.front().value.type==_EXT){
gen a = ext_reduce(den._POLYptr->coord.front().value);
if (is_undef(a)) return false;
if (a.type == _EXT && a._EXTptr->type==_VECT){
vecteur u,v,d;
egcd(*(a._EXTptr->_VECTptr),*((a._EXTptr+1)->_VECTptr),0,u,v,d);
if (d.size()==1){
gen aconj=algebraic_EXTension(u,*(a._EXTptr+1));
aconj=polynome(aconj,int(den._POLYptr->coord.front().index.size()));
num=aconj*num;
den=aconj*den;
}
}
}
return totally_converted;
}
fraction sym2r(const gen & e, const vecteur & l,GIAC_CONTEXT){
int l_size;
if (!l.empty() && l.front().type==_VECT)
l_size=int(l.front()._VECTptr->size());
else
l_size=int(l.size());
gen num,den;
bool ok=sym2r(e,l,l_size,num,den,contextptr);
if (!ok){
num=string2gen("Error in normal",false);
num.subtype=-1; //gensizeerr(contextptr);
}
if (is_positive(-den,contextptr))
return fraction(-num,-den);
else
return fraction(num,den);
}
// fraction / x -> fraction of vecteur
gen e2r(const gen & e,const gen & x,GIAC_CONTEXT){
vecteur l(1,x);
lvar(e,l);
gen r=polynome2poly1(e2r(e,l,contextptr),1);
return r2e(r,cdr_VECT(l),contextptr);
}
gen e2r(const gen & e,const vecteur & l,GIAC_CONTEXT){
if (e.type!=_VECT)
return sym2r(e,l,contextptr);
bool totally_converted=true;
int l_size;
if (!l.empty() && l.front().type==_VECT)
l_size=int(l.front()._VECTptr->size());
else
l_size=int(l.size());
gen num,den;
vecteur lv,lvnum,lvden;
lvar_rootof(e,l,lv,contextptr);
if (!compute_lv_lvnum_lvden(l,lv,lvnum,lvden,totally_converted,l_size,contextptr))
return gensizeerr(contextptr);
gen iext=find_iext(e,lvnum,contextptr);
clean_iext(lvnum,lvden,iext,contextptr);
vecteur res;
const_iterateur jt=e._VECTptr->begin(),jtend=e._VECTptr->end();
for (;jt!=jtend;++jt){
sym2r(*jt,iext,l,lv,lvnum,lvden,l_size,num,den,contextptr);
res.push_back(num/den);
}
return gen(res,e.subtype);
}
//**********************************
// tensor to symbolic
//**********************************
static gen niceprod(ref_vecteur * res,bool negatif){
gen tmp;
if (res->v.size()!=1)
tmp=symbolic(at_prod,gen(res,_SEQ__VECT));
else {
tmp=res->v.front();
delete_ref_vecteur(res);
}
return negatif?-tmp:tmp;
}
gen r2sym(const gen & e,const index_m & i,const vecteur & l,GIAC_CONTEXT){
if (is_undef(e))
return e;
if (i.size()!=l.size())
return gensizeerr(gettext("sym2poly/r2sym(const gen & e,const index_m & i,const vecteur & l)"));
vecteur::const_iterator l_it=l.begin();
index_t::const_iterator it=i.begin(),itend=i.end();
ref_vecteur * res=new_ref_vecteur(0);
res->v.reserve(itend-it+1);
bool negatif=false;
if (!is_one(e) || (e.type==_MOD) ){
if ( (e.type<=_REAL || e.type==_FRAC) && is_positive(-e,contextptr)){
negatif=true;
if (!is_minus_one(e))
res->v.push_back(-e);
}
else
res->v.push_back(e);
}
for (;it!=itend;++it,++l_it){
if ((*it))
res->v.push_back(pow(*l_it,*it));
}
if (res->v.empty()){
delete_ref_vecteur(res);
return e;
}
return niceprod(res,negatif);
}
static gen r2sym2(const polynome & p, const vecteur & l,GIAC_CONTEXT){
monomial_v::const_iterator it=p.coord.begin();
monomial_v::const_iterator itend=p.coord.end();
if (itend-it==1)
return r2sym(it->value,it->index,l,contextptr);
ref_vecteur * res=new_ref_vecteur(0);
res->v.reserve(itend-it);
for (;it!=itend;++it){
res->v.push_back(r2sym(it->value,it->index,l,contextptr)) ;
}
if (res->v.size()==1){
gen tmp=res->v.front();
delete res;
return tmp;
}
if (increasing_power(contextptr))
reverse(res->v.begin(),res->v.end());
return symbolic(at_plus,gen(res,_SEQ__VECT));
}
gen r2sym(const polynome & p, const vecteur & l,GIAC_CONTEXT){
if (p.coord.empty())
return zero;
if (p.dim==0){
return p.constant_term();
}
if (is_positive(-p.coord.front()))
return -r2sym2(-p,l,contextptr);
return r2sym2(p,l,contextptr);
}
gen r2sym(const fraction & f, const vecteur & l,GIAC_CONTEXT){
if (f.den.type==_POLY && is_positive(-f.den._POLYptr->coord.front())){
return rdiv(r2sym(-f.num,l,contextptr),r2sym(-f.den,l,contextptr),contextptr);
}
// workaround for e.g. normal(sqrt(3)*sqrt(15))
gen fn=r2sym(f.num,l,contextptr);
gen fd=r2sym(f.den,l,contextptr);
if (fn.is_symb_of_sommet(at_prod) && fn._SYMBptr->feuille.type==_VECT && fd.type==_INT_ && absint(fd.val)>1){
gen c=1;
vecteur v(*fn._SYMBptr->feuille._VECTptr);
fn=1;
for (unsigned i=0;iv.reserve(itend-it);
for (;it!=itend;++it)
res->v.push_back(r2sym(*it,l,contextptr));
return res;
}
static gen r2sym(const gen & p, const const_iterateur & lt, const const_iterateur & ltend,GIAC_CONTEXT);
static gen solve_deg2(const gen & p,const gen & pmin,const const_iterateur & lt, const const_iterateur & ltend,GIAC_CONTEXT){
if ( p.type!=_VECT || pmin.type!=_VECT)
return gensizeerr(gettext("sym2poly.cc/ckdeg2_rootof"));
vecteur & w = *pmin._VECTptr;
int s=int(w.size());
if (s!=3)// || is_greater(linfnorm(pmin,contextptr),(1<<30),contextptr))
return symb_rootof(p,r2sym(pmin,lt,ltend,contextptr),contextptr);
if (p._VECTptr->size()!=2)
return gensizeerr(gettext("sym2poly.cc/ckdeg2_rootof"));
gen b_over_2=rdiv(w[1],plus_two,contextptr);
if (is_zero(b_over_2))
return p._VECTptr->front()*sqrt(r2sym(-w.back()/w.front(),lt,ltend,contextptr),contextptr)+p._VECTptr->back();
gen x;
if (b_over_2.type!=_FRAC){
gen a=r2sym(w.front(),lt,ltend,contextptr);
gen minus_b_over_2=r2sym(-b_over_2,lt,ltend,contextptr);
gen delta_prime=r2sym(pow(b_over_2,2,contextptr)-w.front()*w.back(),lt,ltend,contextptr);
x=rdiv(minus_b_over_2+sqrt(delta_prime,contextptr),a,contextptr);
}
else {
gen two_a=r2sym(plus_two*w.front(),lt,ltend,contextptr);
gen minus_b=r2sym(-w[1],lt,ltend,contextptr);
gen delta=r2sym(w[1]*w[1]-gen(4)*w.front()*w.back(),lt,ltend,contextptr);
x=rdiv(minus_b+sqrt(delta,contextptr),two_a,contextptr);
}
return p._VECTptr->front()*x+p._VECTptr->back();
}
/*
static gen ckdeg2_rootof(const gen & p,const gen & pmin,GIAC_CONTEXT){
if ( p.type!=_VECT || pmin.type!=_VECT)
return gensizeerr(gettext("sym2poly.cc/ckdeg2_rootof"));
if (pmin._VECTptr->size()!=3)
return symb_rootof(p,pmin,contextptr);
if (p._VECTptr->size()!=2)
return gensizeerr(gettext("sym2poly.cc/ckdeg2_rootof"));
vecteur v;
identificateur x(" x");
in_solve(symb_horner(*pmin._VECTptr,x),x,v,1,contextptr);
if (v.empty())
return gensizeerr(gettext("No root found for pmin"));
return p._VECTptr->front()*v.front()+p._VECTptr->back();
}
*/
// check that an _EXT e is root of a second order poly
// return 0 if not, 2 if pmin(e) is 2nd order, 1 otherwise
// FIXME: if pmin has integer coeffs as well as e
// translate so that we just need to find the sign
// then we are reduced to find the sign of P(alpha) where alpha is the
// largest real root of a polynomial Q
// Using VAS [csturm.cc: gen complexroot(const gen & g,bool complexe,GIAC_CONTEXT)]
// find isolation interval for roots of Q, select the largest one,
// find isolation interval for roots of P, if they intersect with previous one
// improve precision by dichotomy until sign is resolved
static int is_root_of_deg2(const gen & e,vecteur & v,GIAC_CONTEXT){
// find a,b,c such that a*e*e+b*e+c=0
#ifdef DEBUG_SUPPORT
if (e.type!=_EXT || e._EXTptr->type!=_VECT)
setsizeerr(gettext("sym2poly.cc/is_root_of_deg2"));
#endif // DEBUG_SUPPORT
gen pmin=*(e._EXTptr+1),value;
if (has_rootof_value(pmin,value,contextptr))
return 0;
vecteur vpmin(min_pol(pmin));
if (!vpmin.empty() && is_undef(vpmin))
return 0;
if (vpmin.size()==3)
return 2;
v.clear();
gen e_square(e*e);
if (e_square.type!=_EXT){ // b=0, a=1, e*e=-c
v.push_back(plus_one);
v.push_back(zero);
v.push_back(-e_square);
return 1;
}
if (e_square._EXTptr->type!=_VECT)
return 0; // setsizeerr(gettext("sym2poly.cc/is_root_of_deg2"));
int s=int(e._EXTptr->_VECTptr->size());
int s2=int(e_square._EXTptr->_VECTptr->size());
if (s!=s2)
return 0;
gen b=-e_square._EXTptr->_VECTptr->front();
gen a=e._EXTptr->_VECTptr->front();
simplify(a,b);
gen c=a*e_square+b*e;
if (c.type==_EXT)
return 0;
v.push_back(a);
v.push_back(b);
v.push_back(-c);
return 1;
}
static gen randassume(const vecteur & boundaries,GIAC_CONTEXT){
if (boundaries.empty())
return 0;
if (boundaries[0].type==_VECT)
return randassume(*boundaries[0]._VECTptr,contextptr);
if (boundaries.size()<2)
return 0;
gen a=boundaries[0],b=boundaries[1];
if (a==minus_inf){
if (b==plus_inf)
return _rand(makesequence(-100,100),contextptr);
return _rand(makesequence(b-100,b-1),contextptr);
}
if (b==plus_inf)
return _rand(makesequence(a+1,a+100),contextptr);
return _rand(gen(boundaries,_SEQ__VECT),contextptr);
}
static void check_assume(vecteur & vzero,const vecteur & vassume,GIAC_CONTEXT){
for (unsigned i=0;isize()==3){
if((*assi._VECTptr)[1].type==_VECT && !(*assi._VECTptr)[1]._VECTptr->empty()){
vzero[i]=randassume(*(*assi._VECTptr)[1]._VECTptr,contextptr);
}
}
}
}
gen minimal_polynomial(const gen & pp,bool minonly,GIAC_CONTEXT){
gen f=*(pp._EXTptr+1);
if (f.type!=_VECT)
return undef;
int d=int(f._VECTptr->size());
gen r=evalf_double(pp,1,contextptr);
matrice m(d);
m[0]=vecteur(d-1);
m[0]._VECTptr->back()=1;
gen ppi(1);
for (int i=1;iback()=ppi;
}
else {
m[i]=*ppi._EXTptr;
if (m[i].type!=_VECT)
return gensizeerr(contextptr);
m[i]=*m[i]._VECTptr;
if (int(m[i]._VECTptr->size())size()),*m[i]._VECTptr);
}
} // end for i
if (!ckmatrix(m))
return gensizeerr(contextptr);
m=mtran(m); // d-1 rows, d columns
int st=step_infolevel(contextptr);
step_infolevel(contextptr)=0;
vecteur mk=mker(m,contextptr);
step_infolevel(contextptr)=st;
gen pm(mk.front()); // min poly= 1st kernel element
if (pm.type==_VECT){
mk=*pm._VECTptr;
reverse(mk.begin(),mk.end());
mk=trim(mk,0);
if (minonly){
if (is_positive(-mk.front(),contextptr))
return gen(-mk,_POLY1__VECT);
return gen(mk,_POLY1__VECT);
}
if ((d=int(mk.size()))<=5 && d!=4){
identificateur x(" x");
vecteur w;
in_solve(symb_horner(mk,x),x,w,1,contextptr);
for (unsigned k=0;knum.type==_EXT
// it might require another simplification with the denom
if (p.type==_FRAC){
gen res;
if (p._FRACptr->den.type==_CPLX)
res=rdiv(r2sym(p._FRACptr->num*conj(p._FRACptr->den,contextptr),lt,ltend,contextptr),r2sym(p._FRACptr->den*conj(p._FRACptr->den,contextptr),lt,ltend,contextptr),contextptr);
else
res=rdiv(r2sym(p._FRACptr->num,lt,ltend,contextptr),r2sym(p._FRACptr->den,lt,ltend,contextptr),contextptr);
return (p._FRACptr->num.type==_EXT)?ratnormal(res,contextptr):res;
}
if (p.type==_MOD)
return makemodquoted(r2sym(*p._MODptr,lt,ltend,contextptr),r2sym(*(p._MODptr+1),lt,ltend,contextptr));
if (p.type==_VECT){
const_iterateur it=p._VECTptr->begin(),itend=p._VECTptr->end();
vecteur res;
res.reserve(itend-it);
for (;it!=itend;++it)
res.push_back(r2sym(*it,lt,ltend,contextptr));
return res;
}
if (p.type==_EXT){
gen pp=ext_reduce(p);
if (pp.type!=_EXT){
if (is_undef(pp)) return pp;
return r2sym(pp,lt,ltend,contextptr);
}
gen f=*(pp._EXTptr+1),fvalue;
#if 1
if ( ( ltend==lt || (ltend-lt==1 && lt->type==_VECT && lt->_VECTptr->empty()) )
&& f.type==_VECT && !has_rootof_value(f,fvalue,contextptr) && !keep_algext(contextptr) ){
// univariate case
// find minimal poly of the whole _EXT if extension degree is > 2
int d=int(f._VECTptr->size());
// FIXME remove d<=10, requires better handling of rref with Gauss integers
if (d>3 && d<=10){
gen res=minimal_polynomial(pp,false,contextptr);
if (!is_undef(res))
return res;
} // end if d>3
}
#endif
if ((pp._EXTptr+1)->type!=_VECT)
f=min_pol(*(pp._EXTptr+1)); // f is a _VECT
if (is_undef(f))
return f;
if (f._VECTptr->size()==3){
gen value;
if (!has_rootof_value(f,value,contextptr))
return solve_deg2(r2sym(*(pp._EXTptr),lt,ltend,contextptr),f,lt,ltend,contextptr);
}
vecteur v;
int t=0;
fvalue=undef;
if (!has_rootof_value(f,fvalue,contextptr))
t=is_root_of_deg2(pp,v,contextptr);
// if (t==2) return solve_deg2(r2sym(*(pp._EXTptr),lt,ltend,contextptr),f,lt,ltend,contextptr);
// if (t && f==v) t=0;
if (t==1){
vecteur w;
identificateur x(" x");
in_solve(symb_horner(*(r2sym(v,lt,ltend,contextptr)._VECTptr),x),x,w,1,contextptr);
#ifndef NO_STDEXCEPT
try {
#endif
vecteur vinit(lt,ltend);
if (lt!=ltend && vinit.front().type==_VECT)
vinit=*vinit.front()._VECTptr;
vecteur vassume(vinit);
for (unsigned i=0;iin_eval(0,vinit[i],vassume[i],contextptr);
}
gen vinitd;
vecteur vzero=vecteur(vinit.size());
bool tst=has_evalf(vinit,vinitd,1,contextptr);
if (tst)
vzero=*vinitd._VECTptr;
else
check_assume(vzero,vassume,contextptr);
gen tmp0=r2sym(*pp._EXTptr,lt,ltend,contextptr);
gen tmp1=r2sym(f,lt,ltend,contextptr);
for (int ntry=0;ntry<10;++ntry,tst=false){
gen tmp00=subst(tmp0,vinit,vzero,false,contextptr);
gen tmp10=subst(tmp1,vinit,vzero,false,contextptr);
if (!lvar(makevecteur(tmp00,tmp10)).empty())
break;
if (tmp10.type==_VECT && _size(_gcd(makesequence(tmp10,derivative(*tmp10._VECTptr)),contextptr),contextptr)>1)
tmp00=cst_i; // retry
else {
tmp00=algebraic_EXTension(tmp00,tmp10);
tmp00=accurate_evalf_until(tmp00,contextptr); // tmp00.evalf_double(1,contextptr);
}
if (tmp00.type<=_CPLX){
gen tmp3=eval(subst(w.front(),vinit,vzero,false,contextptr),1,contextptr);
tmp3=accurate_evalf_until(tmp3,contextptr); // tmp3.evalf_double(1,contextptr);
gen tmp2=eval(subst(w.back(),vinit,vzero,false,contextptr),1,contextptr);
tmp2=accurate_evalf_until(tmp2,contextptr);// tmp2.evalf_double(1,contextptr);
if (tmp3.type<=_CPLX && tmp2.type<=_CPLX && tmp2!=tmp3){
if (!vzero.empty() && !tst)
*logptr(contextptr) << gettext("Warning, choosing root of ") << f << " at parameters values " << vzero << endl;
if (is_greater(abs(tmp3-tmp00,contextptr),abs(tmp2-tmp00,contextptr),contextptr))
return w.back();
else
return w.front();
}
}
// tmp2 and tmp3 are identical or tmp0 is not real, retry
vzero=vranm(int(vzero.size()),0,contextptr);
check_assume(vzero,vassume,contextptr);
}
#ifndef NO_STDEXCEPT
}
catch (std::runtime_error & e){
CERR << "sym2poly exception caught " << e.what() << endl;
}
#endif
return w.front();
/* gen tmp0=algebraic_EXTension(r2sym(*pp._EXTptr,lt,ltend),r2sym(f,lt,ltend)).evalf_double();
if (tmp0.type==_DOUBLE_){
gen tmp1=evalf_double(w.front()),tmp2=evalf_double(w.back());
if (tmp1.type==_DOUBLE_ && tmp2.type==_DOUBLE_ && fabs((tmp2-tmp0)._DOUBLE_val)size());
v=vecteur(s,zero);
v.front()=plus_one;
v.back()=f._VECTptr->back();
if (f==v){
if (is_undef(fvalue))
fvalue=pow(r2sym(-v.back(),lt,ltend,contextptr),fraction(1,s-1),contextptr);
}
else
return symb_rootof(r2sym(*(pp._EXTptr),lt,ltend,contextptr),r2sym(f,lt,ltend,contextptr),contextptr);
return symb_horner(*(r2sym(*(pp._EXTptr),lt,ltend,contextptr)._VECTptr),fvalue);
}
if (p.type==_SPOL1){
sparse_poly1 s=*p._SPOL1ptr;
sparse_poly1::iterator it=s.begin(),itend=s.end();
vecteur l(lt,ltend);
for (;it!=itend;++it){
it->coeff=r2sym(it->coeff,l,contextptr);
}
return s;
}
if ((p.type!=_POLY) || (lt==ltend))
return p;
if (p._POLYptr->coord.empty())
return zero;
if (p._POLYptr->dim==0){
return r2sym(p._POLYptr->coord.front().value,lt+1,ltend,contextptr);
}
if (is_positive(-p,contextptr) && !is_positive(p,contextptr))
return -r2sym(-p,lt,ltend,contextptr);
monomial_v::const_iterator it=p._POLYptr->coord.begin();
monomial_v::const_iterator itend=p._POLYptr->coord.end();
if (itend==it)
return zero;
vecteur res;
res.reserve(itend-it);
for (;it!=itend;++it){
res.push_back(r2sym(r2sym(it->value,lt+1,ltend,contextptr),it->index,*(lt->_VECTptr),contextptr)) ;
}
if (res.size()==1)
return res.front();
if (increasing_power(contextptr))
reverse(res.begin(),res.end());
return symbolic(at_plus,gen(res,_SEQ__VECT));
}
gen r2sym(const gen & p, const vecteur & l,GIAC_CONTEXT){
if (p.type==_VECT){
gen res=r2sym(*p._VECTptr,l,contextptr);
if (res.type==_VECT)
res.subtype=p.subtype;
return res;
}
if ( (!l.empty()) && (l.front().type==_VECT) )
return r2sym(p,l.begin(),l.end(),contextptr);
if (p.type==_FRAC)
return r2sym(*p._FRACptr,l,contextptr);
if (p.type==_MOD)
return makemodquoted(r2sym(*p._MODptr,l,contextptr),r2sym(*(p._MODptr+1),l,contextptr));
if (p.type==_EXT){
gen pp=ext_reduce(*(p._EXTptr),*(p._EXTptr+1));
if (pp.type!=_EXT){
if (is_undef(pp)) return pp;
return r2sym(pp,l,contextptr);
}
gen f=*(pp._EXTptr+1);
if ((pp._EXTptr+1)->type!=_VECT)
f=min_pol(*(pp._EXTptr+1)); // f is a _VECT
if (is_undef(f))
return f;
vecteur v;
int t=is_root_of_deg2(pp,v,contextptr);
if (f._VECTptr->size()==3){
return solve_deg2(r2sym(*(pp._EXTptr),l,contextptr),f,l.begin(),l.end(),contextptr);
}
if (t==2){
// return ckdeg2_rootof(r2sym(*(pp._EXTptr),l,contextptr),r2sym(f,l,contextptr),contextptr);
return solve_deg2(r2sym(*(pp._EXTptr),l,contextptr),f,l.begin(),l.end(),contextptr);
}
if (t==1){
vecteur w;
identificateur x(" x");
in_solve(symb_horner(*(r2sym(v,l,contextptr)._VECTptr),x),x,w,1,contextptr);
// find the nearest root from pp
gen ww,ppp,mindist,curdist;
if (has_evalf(w,ww,1,contextptr) && has_evalf(pp,ppp,1,contextptr)){
int pos=0;
vecteur & www = *ww._VECTptr;
mindist=abs(www[0]-ppp,contextptr);
for (int i=1;i<(int)www.size();++i){
curdist=abs(www[i]-ppp,contextptr);
if (is_strictly_greater(mindist,curdist,contextptr)){
pos=i;
mindist=curdist;
}
}
return w[pos];
}
return w.front();
}
int s=int(f._VECTptr->size());
v=vecteur(s,zero);
v.front()=plus_one;
v.back()=f._VECTptr->back();
gen theta;
if (f==v)
theta=pow(r2sym(-v.back(),l,contextptr),fraction(1,s-1),contextptr);
else
return symb_rootof(r2sym(*(pp._EXTptr),l,contextptr),r2sym(f,l,contextptr),contextptr);
return symb_horner(*(r2sym(*(pp._EXTptr),l,contextptr)._VECTptr),theta);
}
if (p.type==_POLY)
return r2sym(*p._POLYptr,l,contextptr);
if (p.type==_SPOL1)
return r2sym(p,l.begin(),l.end(),contextptr);
return p;
}
gen r2e(const gen & p, const vecteur & l,GIAC_CONTEXT){
return r2sym(p,l,contextptr);
}
// alias vecteur -> polynome / x
gen r2e(const gen & r,const gen & x,GIAC_CONTEXT){
if (r.type==_FRAC)
return fraction(r2e(r._FRACptr->num,x,contextptr),r2e(r._FRACptr->den,x,contextptr));
if (r.type==_VECT)
return symb_horner(*r._VECTptr,x);
else
return r;
}
// convert factorization to symbolic form
gen r2sym(const factorization & vnum,const vecteur & l,GIAC_CONTEXT){
gen resnum(1);
factorization::const_iterator it=vnum.begin(),itend=vnum.end();
for (;it!=itend;++it){
// insure no embedded sqrt inside
polynome p=it->fact;
if (l.size()==1){
vector< monomial >::iterator pt=p.coord.begin(),ptend=p.coord.end();
vecteur vtmp(1,vecteur(0));
for (;pt!=ptend;++pt){
pt->value=r2sym(pt->value,vtmp,contextptr);
}
}
gen tmp=r2sym(gen(p),l,contextptr);
resnum=resnum*pow(tmp,it->mult);
}
return resnum;
}
// convert pfde_VECT to symbolic form
gen r2sym(const vector< pf > & pfde_VECT,const vecteur & l,GIAC_CONTEXT){
gen res(0);
vector< pf >::const_iterator it=pfde_VECT.begin(),itend=pfde_VECT.end();
for (;it!=itend;++it){
res=res+rdiv(r2sym(gen(it->num),l,contextptr),(r2sym(gen(it->den/pow(it->fact,it->mult)),l,contextptr)*pow(r2sym(gen(it->fact),l,contextptr),it->mult)),contextptr);
}
return res;
}
//*****************************
/* Fonctions relatives to ex */
//*****************************
// special version of lop(.,at_pow) that removes integral powers
static vecteur lop_pow(const gen & g){
if (g.type==_SYMB) {
if (g._SYMBptr->sommet==at_pow && g._SYMBptr->feuille._VECTptr->back().type!=_INT_)
return vecteur(1,g);
else {
if (g._SYMBptr->sommet!=at_ln)
return lop_pow(g._SYMBptr->feuille);
}
}
if (g.type!=_VECT)
return vecteur(0);
vecteur res;
const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end();
for (;it!=itend;++it){
if (it->is_symb_of_sommet(at_pow) && it->_SYMBptr->feuille._VECTptr->back().type==_INT_)
continue;
res=mergeset(res,lop_pow(*it));
}
return res;
}
static gen in_normalize_sqrt(const gen & e,vecteur & L,GIAC_CONTEXT){
if (complex_mode(contextptr) || has_i(e))
return e;
// remove multiple factors inside sqrt
// vecteur l0=lop(e,at_pow),lin,lout;
vecteur l0=lop_pow(e),lin,lout;
const_iterateur it=l0.begin(),itend=l0.end();
for (;it!=itend;++it){
vecteur & arg=*it->_SYMBptr->feuille._VECTptr;
gen g=arg[1],expnum,expden;
if (g.type==_FRAC){
expnum=g._FRACptr->num;
expden=g._FRACptr->den;
}
else {
if ( (g.type!=_SYMB) || (g._SYMBptr->sommet!=at_prod) )
continue;
gen & arg1=g._SYMBptr->feuille;
if (arg1.type!=_VECT)
continue;
vecteur & v=*arg1._VECTptr;
if ( (v.size()!=2) || (v[1].type!=_SYMB) || (v[1]._SYMBptr->sommet==at_inv) )
continue;
expnum=v[0];
expden=v[1]._SYMBptr->feuille;
}
if ( (expden.type!=_INT_) || (expden.val!=2 ) )
continue;
if (is_one(expnum) && is_integer(arg[0]))
continue;
gen var=ggb_var(arg[0]),a,b,hyp;
// if var is not assigned and arg[0] depends linearly on var, add an assumption
if (complex_mode(contextptr)==false && var.type==_IDNT && var._IDNTptr->eval(1,var,contextptr)==var){
if (is_linear_wrt(arg[0],var,a,b,contextptr) && !is_zero(a)){
if (is_strictly_positive(a,contextptr))
hyp=symbolic(at_superieur_egal,makesequence(var,-b/a));
if (is_strictly_positive(-a,contextptr))
hyp=symbolic(at_inferieur_egal,makesequence(var,-b/a));
if (!is_zero(hyp))
L.push_back(hyp);
}
}
vecteur lv(alg_lvar(arg[0]));
gen num,den;
a=e2r(arg[0],lv,contextptr);
fxnd(a,num,den);
gen nd=num*den,out(1);
gen nover2=rdiv(expnum,plus_two,contextptr);
if (nd.type==_EXT && nd._EXTptr->type==_VECT){ // extract content
gen tmp=lgcd(*nd._EXTptr->_VECTptr);
out=r2e(nd/tmp,lv,contextptr);
// removed the ^ to avoid larger extensions e.g. for normal(sin(pi/5))
nd=tmp;
}
if (nd.type==_INT_ || nd.type==_ZINT){
gen simpl,doubl;
bool pos;
zint2simpldoublpos(nd,simpl,doubl,pos,2,contextptr);
if (!pos) simpl=-simpl;
lin.push_back(*it);
lout.push_back(pow(doubl/abs(r2e(den,lv,contextptr),contextptr),expnum,contextptr)*pow(simpl*out,nover2,contextptr));
continue;
}
if (nd.type!=_POLY)
continue;
lin.push_back(*it);
const factorization & f=rsqff(*nd._POLYptr);
polynome s(plus_one,nd._POLYptr->dim),d(plus_one,s.dim);
factorization::const_iterator jt=f.begin(),jtend=f.end();
for (;jt!=jtend;++jt){
if (jt->mult%2)
s=s*jt->fact;
d=d*pow(jt->fact,jt->mult/2);
}
// Extract integer content of s
gen cont=Tppz(s);
gen simpl,doubl; bool pos;
zint2simpldoublpos(cont,simpl,doubl,pos,2,contextptr);
if (!pos) simpl=-simpl;
simpl=r2e(polynome(simpl,nd._POLYptr->dim),lv,contextptr); // if simpl is not an integer
doubl=r2e(polynome(doubl,nd._POLYptr->dim),lv,contextptr); // if doubl is not an integer
lout.push_back(pow(simpl*out,nover2,contextptr)*pow(doubl,expnum,contextptr)*pow(recursive_normal(r2e(s,lv,contextptr),contextptr),nover2,contextptr)*pow(abs(r2e(d,lv,contextptr),contextptr),expnum,contextptr)*pow(abs(r2e(den,lv,contextptr),contextptr),-expnum,contextptr));
}
return subst(e,lin,lout,false,contextptr);
}
gen normalize_sqrt(const gen & e,GIAC_CONTEXT){
vecteur L;
return in_normalize_sqrt(e,L,contextptr);
}
static bool has_embedded_fractions(const gen & g){
if (g.type==_POLY){
vector< monomial >::const_iterator it=g._POLYptr->coord.begin(),itend=g._POLYptr->coord.end();
for (;it!=itend;++it){
if (has_embedded_fractions(it->value))
return true;
}
return false;
}
if (g.type==_VECT){
const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end();
for (;it!=itend;++it){
if (has_embedded_fractions(*it))
return true;
}
return false;
}
if (g.type==_FRAC){
if (is_one(g._FRACptr->den))
return has_embedded_fractions(g._FRACptr->num);
return true;
}
return false;
}
static bool sort_func(const gen & a,const gen & b){
if (a.type!=b.type)
return a.typeid_name,b._IDNTptr->id_name)<0;
if (a.type==_SYMB){
int cmp=strcmp(a._SYMBptr->sommet.ptr()->s,b._SYMBptr->sommet.ptr()->s);
if (cmp) return cmp<0;
}
return a.print(context0)type==_VECT)
*it=sort1(*it->_VECTptr);
}
}
static bool do_mult_i(const gen & g){
if (g.type==_CPLX && is_zero(*g._CPLXptr) && is_positive(*(g._CPLXptr+1),context0))
return true;
if (g.type==_POLY && do_mult_i(g._POLYptr->coord.front().value))
return true;
if (g.type!=_EXT)
return false;
if (g._EXTptr->type!=_VECT || g._EXTptr->_VECTptr->empty())
return false;
return do_mult_i(g._EXTptr->_VECTptr->front());
}
gen normal(const gen & e,bool distribute_div,GIAC_CONTEXT){
if (has_num_coeff(e))
return ratnormal(e,contextptr);
// COUT << e << endl;
if (e.type==_VECT){
vecteur res;
for (const_iterateur it=e._VECTptr->begin();it!=e._VECTptr->end();++it)
res.push_back(normal(*it,distribute_div,contextptr));
return gen(res,e.subtype);
}
if (e.type==_FRAC){
gen n=e._FRACptr->num;
gen d=e._FRACptr->den;
simplify(n,d);
if (is_one(d))
return n;
if (is_minus_one(d))
return -n;
if (is_zero(d)){
if (is_zero(n))
return undef;
else
return unsigned_inf;
}
if (is_zero(n))
return zero;
return fraction(n,d);
}
if (e.type==_MOD){
gen p=*e._MODptr;
gen m=*(e._MODptr+1);
vecteur l(lvar(m));
if (l.empty()){
l=lvar(p);
p=e2r(p,l,contextptr);
gen num,den;
fxnd(p,num,den);
num=makemod(num,m);
if (!is_one(den))
den=makemod(den,m);
p=rdiv(num,den,contextptr);
return r2e(p,l,contextptr);
}
return _quorem(makesequence(p,m),contextptr)[1];
}
if (e.type!=_SYMB)
return e;
if (is_equal(e)){
vecteur & v=*e._SYMBptr->feuille._VECTptr;
return symbolic(at_equal,makesequence(normal(v.front(),distribute_div,contextptr),normal(v.back(),distribute_div,contextptr)));
}
if (is_inf(e) || is_undef(e) )
return e;
gen ee,tmp;
matrice l;
fraction f(0);
#ifndef NO_STDEXCEPT
try {
#endif
vecteur L;
ee=in_normalize_sqrt(e,L,contextptr);
l=alg_lvar(ee);
sort0(l);
if (!L.empty() && debug_infolevel)
*logptr(contextptr) << gettext("Making implicit assumption for sqrt argument ") << L << endl;
if (contextptr && contextptr->previous)
L.clear(); // otherwise ggbsort(x):=sort(x); r:=[sqrt(a)/a,1]; ggbsort(r); VARS(); keeps implicit assumption a>=0 globally
for (unsigned k=0;knum;
f.den=tmp._FRACptr->den;
}
else
f=tmp;
if (f.den.type==_CPLX){
f.num=f.num*conj(f.den,contextptr);
f.den=f.den*conj(f.den,contextptr);
}
if (do_mult_i(f.den)){
f.num = -cst_i*f.num;
f.den = -cst_i*f.den;
}
if (do_mult_i(-f.den)){
f.num = cst_i*f.num;
f.den = cst_i*f.den;
}
// search for embedded fractions
if (has_embedded_fractions(f.num) || has_embedded_fractions(f.den))
return normal(r2sym(f,l,contextptr),distribute_div,contextptr);
if (distribute_div && f.num.type==_POLY && f.num._POLYptr->dim && f.den.type<_POLY)
return r2sym(gen(*f.num._POLYptr/f.den),l,contextptr);
if (!distribute_div){
if (f.den.type==_POLY && is_positive(-f.den._POLYptr->coord.front())){
f.num=-f.num;
f.den=-f.den;
}
if (f.num.type==_POLY && !f.num._POLYptr->coord.empty() && is_positive(-f.num._POLYptr->coord.front())){
f.num=-f.num;
return symbolic(at_neg,r2sym(f,l,contextptr));
}
}
ee=r2sym(f,l,contextptr);
if (!is_one(f.den) && is_integer(f.den)){
ee=ratnormal(ratnormal(ee,contextptr),contextptr); // first ratnormal will expand sqrt()^
// second will remove them
}
return ee; // ratnormal(ee,contextptr); // for sqrt(1-a^2)/sqrt(1-a)
}
gen normal(const gen & e,GIAC_CONTEXT){
return normal(e,true,contextptr);
}
// guess if g is a program/function: 1 func, 0 unknown, -1 not func
static int is_program(const gen & g){
#ifdef GIAC_HAS_STO_38
if (g.type==_IDNT){
const char * idname=g._IDNTptr->id_name;
if (strlen(idname)==2 && (idname[0]=='F' || idname[0]=='R' || idname[0]=='X' || idname[0]=='Y') && idname[1]>='0' && idname[1]<='9')
return 1;
else
return -1;
}
#endif
if (g.type==_FUNC)
return 1;
if (g.type==_VECT){
const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end();
for (;it!=itend;++it){
int res=is_program(*it);
if (res)
return res;
}
return 0;
}
if (g.type!=_SYMB)
return 0;
if (g.is_symb_of_sommet(at_of) && g._SYMBptr->feuille.type==_VECT){
return is_program(g._SYMBptr->feuille._VECTptr->back());
}
if (g.is_symb_of_sommet(at_program))
return 1;
vecteur v(lvar(g));
if (v.size()==1 && v.front()==g){
if (g.type!=_SYMB)
return 0;
return is_program(g._SYMBptr->feuille);
}
for (unsigned i=0;ifeuille.type!=_VECT || g._SYMBptr->feuille._VECTptr->size()!=3){
if (is_program(g)!=1)
return false;
identificateur _tmpi(" x");
f1=_tmpi;
f3=g(f1,context0);
return true;
}
f1=g._SYMBptr->feuille._VECTptr->front();
if (f1.type==_VECT && f1.subtype==_SEQ__VECT && f1._VECTptr->size()==1)
f1=f1._VECTptr->front();
f3=g._SYMBptr->feuille._VECTptr->back();
bool res= ((f3.type==_SYMB || f3.type<=_IDNT) && !f3.is_symb_of_sommet(at_bloc));
if (res)
f3=eval(f3,1,context0); // eval operators like /
return res;
}
bool has_algebraic_program(const gen & g){
if (g.type==_VECT){
vecteur & v=*g._VECTptr;
for (unsigned i=0;ifeuille.type!=_VECT || g._SYMBptr->feuille._VECTptr->size()!=3){
if (is_program(g)!=1)
return false;
return true;
}
gen f3=g._SYMBptr->feuille._VECTptr->back();
bool res= ((f3.type==_SYMB || f3.type<=_IDNT) && !f3.is_symb_of_sommet(at_bloc));
return res;
}
gen recursive_normal(const gen & e,bool distribute_div,GIAC_CONTEXT){
#ifdef TIMEOUT
control_c();
#endif
if (ctrl_c || interrupted) {
gen res;
interrupted = true; ctrl_c=false;
gensizeerr(gettext("Stopped by user interruption."),res);
return res;
}
if (e.type==_VECT)
return apply(e,contextptr,(const gen_op_context) recursive_normal);
gen e_copy(e); // was eval(e,1,contextptr));
//recursive BUG F(x):=int(1/sqrt(1+t^2),t,0,x);u(x):=exp(x); F(u(x))
if (e_copy.is_symb_of_sommet(at_pnt))
e_copy=e;
if (e_copy.type==_FRAC)
return e_copy._FRACptr->normal();
if (e_copy.type!=_SYMB && e_copy.type!=_MOD)
return e_copy;
if (is_inf(e_copy) || is_undef(e_copy) )
return e_copy;
vecteur l=lvar(e_copy);
vecteur l_subst(l);
iterateur it=l_subst.begin(),itend=l_subst.end();
for (;it!=itend;++it){
if (it->type!=_SYMB)
continue;
if (it->_SYMBptr->sommet==at_when)
continue;
if (it->_SYMBptr->sommet!=at_pow){
gen tmp=it->_SYMBptr->feuille;
if (!has_algebraic_program(tmp))
tmp=liste2symbolique(symbolique2liste(tmp,contextptr));
tmp=recursive_normal(tmp,false,contextptr);
if (is_undef(tmp)) return e;
*it=it->_SYMBptr->sommet(tmp,contextptr);
continue;
}
if (it->_SYMBptr->feuille._VECTptr->front().type==_INT_ && it->_SYMBptr->feuille._VECTptr->back()==plus_one_half)
continue;
vecteur l=lvar(it->_SYMBptr->feuille._VECTptr->back());
int l_size;
if (!l.empty() && l.front().type==_VECT)
l_size=int(l.front()._VECTptr->size());
else
l_size=int(l.size());
gen f,f_num,f_den;
f=e2r(it->_SYMBptr->feuille._VECTptr->back(),l,contextptr);
fxnd(f,f_num,f_den);
gen num=r2sym(f_num,l,contextptr),den=r2sym(f_den,l,contextptr);
gen base=recursive_normal(it->_SYMBptr->feuille._VECTptr->front(),false,contextptr);
if ( is_zero(base) || num.type!=_INT_ || den.type!=_INT_ || den.val>MAX_COMMON_ALG_EXT_ORDER_SIZE)
*it= pow(base,rdiv(num,den,contextptr),contextptr);
else {
if (den.val>1 && (is_integer(base) || base.type==_FRAC) && is_positive(base,contextptr)){
// should also handle more general base.type
vecteur vtmp(den.val+1);
vtmp[0]=1;
vtmp.back()=-pow(base,num.val % den.val,contextptr);
smaller_factor(vtmp);
gen tmp;
if (vtmp.size()>2)
tmp=r2e(algebraic_EXTension(makevecteur(1,0),vtmp),vecteur(1,vecteur(0)),contextptr);
else
tmp=-vtmp.back()/vtmp.front();
*it=pow(base,num.val/den.val,contextptr)*tmp;
}
else
*it= pow(base, num.val /den.val,contextptr) *pow(base,rdiv(num.val%den.val,den),contextptr);
}
}
if (l!=l_subst)
e_copy=subst(e_copy,l,l_subst,false,contextptr);
// return global_eval(normal(e_copy),100);
bool b=calc_mode(contextptr)==1 || abs_calc_mode(contextptr)==38;
int ca=calc_mode(contextptr);
calc_mode(0,contextptr);
calc_mode(0,context0);
int z=MPZ_MAXLOG2;
MPZ_MAXLOG2=int(8e7);
gen res=normal(e_copy,distribute_div,contextptr);
MPZ_MAXLOG2=z;
calc_mode(ca,context0);
calc_mode(ca,contextptr);
if ( b && !lop(res,at_rootof).empty())
res=simplifier(ratnormal(normalize_sqrt(e_copy,contextptr),contextptr),contextptr);
return res;
// removed eval since it eats neg(x-y)
// eval(normal(e_copy,distribute_div),contextptr);
}
gen recursive_normal(const gen & e,GIAC_CONTEXT){
gen var,res;
res=recursive_normal(e,true,contextptr);
return res;
}
gen _recursive_normal(const gen & e,GIAC_CONTEXT){
gen var,res;
if (is_equal(e))
return apply_to_equal(e,recursive_normal,contextptr); // symb_equal(_recursive_normal(equal2diff(e),contextptr),0);
if (is_algebraic_program(e,var,res))
return symbolic(at_program,makesequence(var,0,recursive_normal(res,contextptr)));
res=recursive_normal(e,true,contextptr);
return res;
}
gen ratnormal(const gen & e,GIAC_CONTEXT){
// COUT << e << endl;
if (e.type==_VECT)
return apply(e,ratnormal,contextptr);
if (e.type==_FRAC){
gen n=e._FRACptr->num;
gen d=e._FRACptr->den;
simplify(n,d);
if (is_one(d))
return n;
if (is_minus_one(d))
return -n;
if (is_zero(d)){
if (is_zero(n))
return undef;
else
return unsigned_inf;
}
if (is_zero(n))
return zero;
return fraction(n,d);
}
if (e.type!=_SYMB && e.type!=_MOD)
return e;
if (is_inf(e) || is_undef(e) )
return e;
matrice l; lvar(e,l);
if (l.size()>1) l=sort1(l);
gen fg=e2r(e,l,contextptr); // ok
if (fg.type==_FRAC && fg._FRACptr->num.type==_FRAC){
fraction f(fg._FRACptr->num._FRACptr->num,fg._FRACptr->den*fg._FRACptr->num._FRACptr->den);
f.normal();
return r2sym(f,l,contextptr); // ok
}
if (fg.type==_FRAC && fg._FRACptr->den.type==_CPLX){
gen tmp=conj(fg._FRACptr->den,contextptr);
fg._FRACptr->num = fg._FRACptr->num * tmp;
fg._FRACptr->den = fg._FRACptr->den * tmp;
}
return r2sym(fg,l,contextptr);
}
gen recursive_ratnormal(const gen & e,GIAC_CONTEXT){
// COUT << e << endl;
if (e.type==_VECT)
return apply(e,recursive_ratnormal,contextptr);
if (e.type==_FRAC){
gen n=e._FRACptr->num;
gen d=e._FRACptr->den;
simplify(n,d);
if (is_one(d))
return n;
if (is_minus_one(d))
return -n;
if (is_zero(d)){
if (is_zero(n))
return undef;
else
return unsigned_inf;
}
if (is_zero(n))
return zero;
return fraction(n,d);
}
if (e.type!=_SYMB && e.type!=_MOD)
return e;
if (is_inf(e) || is_undef(e) )
return e;
matrice l; lvar(e,l);
if (l.size()>1) l=sort1(l);
gen fg=e2r(e,l,contextptr);
for (unsigned i=0;isommet(recursive_ratnormal(l[i]._SYMBptr->feuille,contextptr),contextptr);
}
if (fg.type==_FRAC && fg._FRACptr->num.type==_FRAC){
fraction f(fg._FRACptr->num._FRACptr->num,fg._FRACptr->den*fg._FRACptr->num._FRACptr->den);
f.normal();
return r2sym(f,l,contextptr);
}
if (fg.type==_FRAC && fg._FRACptr->den.type==_CPLX){
gen tmp=conj(fg._FRACptr->den,contextptr);
fg._FRACptr->num = fg._FRACptr->num * tmp;
fg._FRACptr->den = fg._FRACptr->den * tmp;
}
return r2sym(fg,l,contextptr);
}
gen rationalgcd(const gen & a, const gen & b,GIAC_CONTEXT){
gen A,B,C,D;
if (is_algebraic_program(a,A,B) && is_algebraic_program(b,C,D)){
if (A==C)
return symbolic(at_program,makesequence(A,0,gcd(B,D,contextptr)));
D=subst(D,C,A,false,contextptr);
return symbolic(at_program,makesequence(A,0,gcd(B,D,contextptr)));
}
vecteur l(alg_lvar(a));
alg_lvar(b,l);
fraction fa(e2r(a,l,contextptr)),fb(e2r(b,l,contextptr)); // ok
if (debug_infolevel)
CERR << "rational gcd begin " << CLOCK() << endl;
if (!is_one(fa.den) || !is_one(fb.den))
CERR << "Warning gcd of fractions " << fa << " " << fb ;
if (fa.num.type==_FRAC)
fa.num=fa.num._FRACptr->num;
if (fb.num.type==_FRAC)
fb.num=fb.num._FRACptr->num;
return r2sym(gcd(fa.num,fb.num,contextptr),l,contextptr); // ok
}
static gen factor(const polynome & p,const vecteur &l,bool fixed_order,bool with_sqrt,gen divide_an_by,gen & extra_div,GIAC_CONTEXT);
static gen factor_multivar(const polynome & p,const vecteur &l,bool fixed_order,bool with_sqrt,gen divide_an_by,gen & extra_div,GIAC_CONTEXT){
polynome pp(p);
int nvars=int(l.size());
if (l.front().type==_VECT)
nvars=int(l.front()._VECTptr->size());
vector deg(nvars);
int mindeg=pp.lexsorted_degree();
int posmin=0;
for (int i=1;ibegin();
++it;
for (int i=1;ifront());
}
else
lptemp.push_back(*it);
}
lp=l;
lp[0]=lptemp;
}
else {
it=l.begin();
++it;
for (int i=1;i1)
return factor_multivar(p,l,fixed_order,with_sqrt,divide_an_by,extra_div,contextptr);
factorization v;
polynome p_content(p.dim);
if (!factor(p,p_content,v,false,with_sqrt,complex_mode(contextptr),divide_an_by,extra_div))
return gentypeerr(gettext("Not implemented, e.g. for multivariate mod/approx polynomials"));
// factor p_content
if (is_one(p_content))
return r2sym(v,l,contextptr)/r2sym(extra_div,l,contextptr);
else {
gen tmp(p_content);
simplify(tmp,extra_div);
if ( (tmp.type>_POLY || (tmp.type==_POLY && !tmp._POLYptr->coord.empty() && tmp._POLYptr->coord.front().value.type==_USER)) &&
!v.empty() && v.front().mult==1 && (v.size()==1 || v.front().fact.degree(0)==0)
){ // for GF factorization
v.front().fact = tmp.type==_POLY?(*tmp._POLYptr*v.front().fact):(tmp*v.front().fact);
return r2sym(v,l,contextptr)/r2sym(extra_div,l,contextptr);
}
polynome pp=p_content.trunc1();
vecteur ll;
if (l.front().type==_VECT){
ll=l;
ll[0]=cdr_VECT(*(ll[0]._VECTptr));
}
else
ll=cdr_VECT(l);
tmp=factor(pp,ll,false,with_sqrt,1,extra_div,contextptr); //cerr << v << endl;
return tmp*r2sym(v,l,contextptr)/r2sym(extra_div,l,contextptr);
// return r2sym(tmp,l,contextptr)*r2sym(v,l,contextptr)/r2sym(extra_div,l,contextptr);
}
}
static gen var_factor(const gen & e,const vecteur & l,bool fixed_order,bool with_sqrt,const gen & divide_an_by,GIAC_CONTEXT){
if (e.type!=_POLY)
return r2sym(e/divide_an_by,l,contextptr);
gen extra_div=1;
return factor(*e._POLYptr,l,fixed_order,with_sqrt,divide_an_by,extra_div,contextptr);
}
gen ordered_factor(const gen & ee,vecteur & l,bool with_sqrt,GIAC_CONTEXT){
gen e=normalize_sqrt(ee,contextptr);
alg_lvar(e,l);
gen f_num,f_den,f;
f=e2r(e,l,contextptr);
fxnd(f,f_num,f_den);
return rdiv(var_factor(f_num,l,true,with_sqrt,1,contextptr),var_factor(f_den,l,true,with_sqrt,1,contextptr));
}
gen factor(const gen & e,const identificateur & x,bool with_sqrt,GIAC_CONTEXT){
if (e.type==_VECT){
vecteur w;
vecteur::const_iterator it=e._VECTptr->begin(),itend=e._VECTptr->end();
for (;it!=itend;++it)
w.push_back(factor(*it,x,with_sqrt,contextptr));
return w;
}
vecteur l(1,vecteur(1,x)); // insure x is the main var
return ordered_factor(e,l,with_sqrt,contextptr);
}
static gen in_factor(const gen & e_,bool with_sqrt,const gen & divide_an_by,GIAC_CONTEXT){
gen e(normalize_sqrt(e_,contextptr));
if (e.type==_VECT){
vecteur w;
vecteur::const_iterator it=e._VECTptr->begin(),itend=e._VECTptr->end();
for (;it!=itend;++it)
w.push_back(in_factor(*it,with_sqrt,divide_an_by,contextptr));
return w;
}
vecteur l;
alg_lvar(e,l);
if (!l.empty() && l.front().type==_VECT && l.front()._VECTptr->empty())
l=lvar(e);
/* if (calc_mode(contextptr)==1 && l.size()==1 && l.front().type==_VECT){
sort(l.front()._VECTptr->begin(),l.front()._VECTptr->end(),islesscomplexthanf);
} */
gen f_num,f_den,f,dnum,dden(1);
f=e2r(e,l,contextptr);
fxnd(f,f_num,f_den);
if (has_EXT(f_num))
simplify3(f_num,f_den);
if (divide_an_by.type>=_IDNT){
gen divide=e2r(divide_an_by,l,contextptr);
fxnd(divide,dnum,dden);
if (dnum.type==_POLY){
if (!Tis_constant(*dnum._POLYptr)){
simplify3(f_num,dnum);
}
if (dnum.type==_POLY)
dnum=dnum._POLYptr->coord.front().value;
}
if (dden.type==_POLY)
dden=dden._POLYptr->coord.front().value;
}
else {
dnum=divide_an_by;
}
if (dden.type==_CPLX){
gen tmp=conj(dden,contextptr);
dnum=dnum*tmp;
dden=dden*tmp;
f_num=f_num*tmp;
f_den=f_den*tmp;
}
gen N=var_factor(f_num,l,false,with_sqrt,dnum,contextptr);
gen D=var_factor(f_den,l,false,with_sqrt,dden,contextptr);
return rdiv(N,D);
}
gen factor(const gen & ee,bool with_sqrt,const gen & divide_an_by,GIAC_CONTEXT){
if (xcas_mode(contextptr)==3 && is_integer(ee))
return _ifactor(ee,contextptr);
gen e(ee);
if (has_num_coeff(ee))
e=e.evalf(1,contextptr);
else {
vecteur L=lop_pow(e);
L=lidnt(L);
// make cfactor(-x/4*pi^2+i*sqrt(3+x)/2+x^2+3/4) work
e=in_factor(e,with_sqrt && L.empty(),divide_an_by,contextptr);
return e;
}
return in_factor(e,with_sqrt,divide_an_by,contextptr);
}
gen factor(const gen & ee,bool with_sqrt,GIAC_CONTEXT){
return factor(ee,with_sqrt,plus_one,contextptr);
}
gen ratfactor(const gen & ee,bool with_sqrt,GIAC_CONTEXT){
gen e(normalize_sqrt(ee,contextptr));
if (has_num_coeff(ee))
e=e.evalf(1,contextptr);
if (e.type==_VECT){
vecteur w;
vecteur::const_iterator it=e._VECTptr->begin(),itend=e._VECTptr->end();
for (;it!=itend;++it)
w.push_back(ratfactor(*it,with_sqrt,contextptr));
return w;
}
vecteur l;
lvar(e,l);
gen f_num,f_den,f;
f=e2r(e,l,contextptr);
fxnd(f,f_num,f_den);
if (with_sqrt)
l=vecteur(1,l);
gen tmp=rdiv(var_factor(f_num,l,false,with_sqrt,1,contextptr),var_factor(f_den,l,false,with_sqrt,1,contextptr));
return tmp;
}
gen factor(const gen & ee,const gen & f,bool with_sqrt,GIAC_CONTEXT){
if (ee.type==_VECT){
vecteur & v=*ee._VECTptr;
int s=int(v.size());
vecteur res(s);
for (int i=0;i2)
toomanyargs("factor");
if (v.back()==at_sqrt)
return factor(v.front(),true,contextptr);
if (v.back().type!=_IDNT){ // FIXME could be improved!
gen f=v.back();
if (v.back().type==_VECT)
f=symbolic(at_prod,v.back());
gen res=factor(v.front()*f,with_sqrt,f,contextptr);
return res;
}
return factor(v.front(),v.back(),with_sqrt,contextptr);
}
int s=int(v.size());
vecteur res(s);
for (int i=0;isize()==2){
ext=e._VECTptr->back();
e=e._VECTptr->front();
}
if (e.type==_VECT){
vecteur w;
vecteur::const_iterator it=e._VECTptr->begin(),itend=e._VECTptr->end();
for (;it!=itend;++it)
w.push_back(partfrac(*it,l,with_sqrt,contextptr));
return w;
}
int l_size;
gen xvar;
if (!l.empty() && l.front().type==_VECT){
l_size=int(l.front()._VECTptr->size());
xvar=l.front();
}
else {
l_size=int(l.size());
xvar=l;
}
if (!l_size)
return e;
else
xvar=xvar._VECTptr->front();
gen r=e2r(e,l,contextptr);
gen r_num,r_den;
fxnd(r,r_num,r_den);
if (r_den.type!=_POLY){
if (r_num.type==_POLY)
return rdiv(r2sym(r_num,l,contextptr),r2sym(r_den,l,contextptr));
else
return e;
}
polynome f_den(*r_den._POLYptr),f_num(l_size);
if (r_num.type==_POLY)
f_num=*r_num._POLYptr;
else
f_num=polynome(r_num,l_size);
factorization vden;
polynome p_content(l_size);
gen extra_div=1;
if (ext!=1){
ext=e2r(ext,vecteur(1,vecteur(0)),contextptr);
if (ext.type!=_EXT)
ext=1;
}
factor(ext*f_den,p_content,vden,false,with_sqrt,complex_mode(contextptr),ext,extra_div);
vector< pf > pfde_VECT;
polynome ipnum(l_size),ipden(l_size);
partfrac(f_num,f_den,vden,pfde_VECT,ipnum,ipden,!with_sqrt);
gen res=rdiv(r2sym(gen(ipnum),l,contextptr),r2sym(gen(ipden),l,contextptr));
vector< pf > ::const_iterator it=pfde_VECT.begin(),itend=pfde_VECT.end();
for (;it!=itend;++it){
const pf & current=*it;
gen reste(r2e(gen(current.num),l,contextptr)),deno(r2e(gen(current.fact),l,contextptr));
polynome p=it->mult==1?it->fact:pow(it->fact,it->mult),quo,rem;
it->den.TDivRem(p,quo,rem,true);
gen cur_deno(r2e(quo,l,contextptr));
if (current.mult==1)
res += reste/cur_deno/deno;
else {
for (int i=0;iempty())
return e_;
if (l.size()==1 && contains(l.front(),vx_var)){ // x first
l=vecteur(1,vecteur(1,vx_var));
alg_lvar(e,l);
}
return partfrac(e,l,with_sqrt,contextptr);
}
gen partfrac(const gen & e,const gen & f,bool with_sqrt,GIAC_CONTEXT){
if (f.type==_IDNT)
return partfrac(e,*f._IDNTptr,with_sqrt,contextptr);
if (f.type==_VECT){
// should check that *f._VECTptr is made only of atomic _SYMB
return partfrac(e,*f._VECTptr,with_sqrt,contextptr);
}
if (f.type==_SYMB)
return partfrac(makesequence(e,f),with_sqrt,contextptr);
return gentypeerr(contextptr);
}
/* User functions */
static gen symb2poly(const gen & fr,const gen & ba,GIAC_CONTEXT){
if (fr.type==_VECT)
return apply1st(fr,ba,contextptr,symb2poly);
if (ba.type==_VECT)
return e2r(fr,*(ba._VECTptr),contextptr);
if (ba.type!=_IDNT && ba.type!=_SYMB)
return gensizeerr(contextptr);
vecteur l(1,ba);
lvar(fr,l);
gen temp=e2r(fr,l,contextptr);
l.erase(l.begin());
gen res;
gen tmp2(polynome2poly1(temp,1));
//res=l.empty()?tmp2:r2e(tmp2,l,contextptr);
res=l.empty()?tmp2:((tmp2.type==_FRAC && tmp2._FRACptr->den.type==_VECT && tmp2._FRACptr->den._VECTptr->size()>1)?gen(fraction(r2e(tmp2._FRACptr->num,l,contextptr),r2e(tmp2._FRACptr->den,l,contextptr))):r2e(tmp2,l,contextptr));
if (res.type==_FRAC && res._FRACptr->num.type==_VECT && res._FRACptr->den.type<_POLY){
res=inv(res._FRACptr->den,contextptr)*res._FRACptr->num;
}
if (res.type==_VECT && calc_mode(contextptr)!=1)
res.subtype=_POLY1__VECT;
return res;
}
gen _e2r(const gen & args,GIAC_CONTEXT){
if ( args.type==_STRNG && args.subtype==-1) return args;
if (args.type!=_VECT)
return _e2r(makesequence(args,vx_var),contextptr);
vecteur & v=*args._VECTptr;
int s=int(v.size());
if (s<2)
return gendimerr(contextptr);
gen res=v.front();
for (int i=1;isize()==2 && is_equal(args._VECTptr->front())){
gen x=args._VECTptr->back();
gen a=_left(args._VECTptr->front(),contextptr);
gen b=_right(args._VECTptr->front(),contextptr);
return symb_equal(_factor(makesequence(a,x),contextptr),_factor(makesequence(b,x),contextptr));
}
gen var,res;
if (args.type!=_VECT && is_algebraic_program(args,var,res))
return symbolic(at_program,makesequence(var,0,_factor(res,contextptr)));
if (xcas_mode(contextptr)==3)
res=factorcollect(args,lvar(args).size()==1,contextptr);
else
res=factorcollect(args,withsqrt(contextptr),contextptr);
return res;
}
static define_unary_function_eval (__factor,&giac::_factor,_factor_s);
define_unary_function_ptr5( at_factor ,alias_at_factor,&__factor,0,true);
static const char _collect_s []="collect";
gen _collect(const gen & args,GIAC_CONTEXT){
if ( args.type==_STRNG && args.subtype==-1) return args;
gen var,res;
if (is_algebraic_program(args,var,res))
return symbolic(at_program,makesequence(var,0,_collect(res,contextptr)));
if (is_equal(args))
return apply_to_equal(args,_collect,contextptr);
if (args.type==_VECT && args.subtype==_SEQ__VECT && args._VECTptr->size()>=2&& args._VECTptr->front().type!=_VECT){
vecteur v(args._VECTptr->begin()+1,args._VECTptr->end());
res=_symb2poly(args,contextptr);
if (res.type!=_FRAC){
res=_poly2symb(gen(mergevecteur(vecteur(1,res),v),_SEQ__VECT),contextptr);
return res;
}
}
res=factorcollect(args,false,contextptr);
return res;
}
static define_unary_function_eval (__collect,&giac::_collect,_collect_s);
define_unary_function_ptr5( at_collect ,alias_at_collect,&__collect,0,true);
static const char _partfrac_s []="partfrac";
symbolic symb_partfrac(const gen & args){
return symbolic(at_partfrac,args);
}
gen _partfrac(const gen & args_,GIAC_CONTEXT){
if (args_.type==_STRNG && args_.subtype==-1) return args_;
gen args(args_),var,res;
if (is_algebraic_program(args,var,res))
return symbolic(at_program,makesequence(var,0,_partfrac(res,contextptr)));
if (is_equal(args))
return apply_to_equal(args,_partfrac,contextptr);
args=exact(args,contextptr);
if (args.type!=_VECT)
return partfrac(args,withsqrt(contextptr),contextptr);
if (args._VECTptr->size()>2)
return gentoomanyargs(_partfrac_s);
return partfrac(args._VECTptr->front(),args._VECTptr->back(),withsqrt(contextptr),contextptr);
}
static define_unary_function_eval (__partfrac,&giac::_partfrac,_partfrac_s);
define_unary_function_ptr5( at_partfrac ,alias_at_partfrac,&__partfrac,0,true);
static const char _resultant_s []="resultant";
symbolic symb_resultant(const gen & args){
return symbolic(at_resultant,args);
}
gen _resultant(const gen & args,GIAC_CONTEXT){
if ( args.type==_STRNG && args.subtype==-1) return args;
if (args.type!=_VECT)
return gentypeerr(contextptr);
vecteur v =*args._VECTptr;
int s=int(v.size());
if (s<2)
toofewargs(_resultant_s);
if (s==2){
if (v[0].type==_POLY && v[1].type==_POLY)
return resultant(*v[0]._POLYptr,*v[1]._POLYptr);
v.push_back(vx_var);
}
if (has_num_coeff(v))
return _det(_sylvester(args,contextptr),contextptr);
if (v.back()==at_sylvester || v.back()==at_det)
return _det(_sylvester(gen(vecteur(args._VECTptr->begin(),args._VECTptr->begin()+s-1),_SEQ__VECT),contextptr),contextptr);
if (v.back()==at_lagrange && s>=3){
if (debug_infolevel)
CERR << CLOCK()*1e-6 << " interp resultant begin " << endl;
gen p=v[0];
gen q=v[1];
gen x=vx_var;
if (s>3)
x=v[2];
gen dbg; // dbg=_resultant(makesequence(p,q,x),contextptr);
vecteur w(1,x);
lvar(p,w);
lvar(q,w);
int m=_degree(makesequence(p,x),contextptr).val;
int n=_degree(makesequence(q,x),contextptr).val;
if (w.size()==1 && m+n>GIAC_PADIC){
gen S=_sylvester(makesequence(p,q,x),contextptr);
return _det(S,contextptr);
}
if (w.size()>1){
gen y=w[1];
vecteur rargs(3,x);
if (s>4 && equalposcomp(w,v[3])){
y=v[3];
if (s>5){
for (int i=4;i=GIAC_PADIC)
rargs.push_back(at_lagrange);
}
}
else {
if (m+n>=GIAC_PADIC)
rargs.push_back(at_lagrange);
}
if (v[s-2]==at_det){
gen S=_sylvester(makesequence(p,q,x),contextptr);
return _det(gen(makevecteur(S,at_lagrange),_SEQ__VECT),contextptr);
}
// bound on degree of resultant with respect to y
int a=_total_degree(makesequence(p,makevecteur(x,y)),contextptr).val;
int b=_total_degree(makesequence(q,makevecteur(x,y)),contextptr).val;
// first estimate n*(a-m)+m*b
int d1=n*(a-m)+m*b;
// second estimate
a=_degree(makesequence(p,y),contextptr).val;
b=_degree(makesequence(q,y),contextptr).val;
// a*n+b*m
int d2=a*n+b*m;
int d=giacmin(d1,d2);
if (debug_infolevel)
CERR << CLOCK()*1e-6 << " interp degree " << d << endl;
vecteur X(d+1),Y(d+1);
int j=-d/2;
gen pl=_lcoeff(makesequence(p,x),contextptr);
gen ql=_lcoeff(makesequence(q,x),contextptr);
if (rargs.back()!=at_lagrange || w.size()==2){
// prepare p and q in polynomial format
vecteur l;
l.push_back(y);
l.push_back(x);
l=vecteur(1,l);
alg_lvar(p,l);
alg_lvar(q,l);
gen f1,f1_num,f1_den,f2,f2_num,f2_den;
f1=e2r(makevecteur(p,q),l,contextptr);
f2=f1[1];
f1=f1[0];
fxnd(f1,f1_num,f1_den);
fxnd(f2,f2_num,f2_den);
if ( (f1_num.type==_POLY) && (f2_num.type==_POLY)){
const polynome & pp=*f1_num._POLYptr;
const polynome & qp=*f2_num._POLYptr;
int dim=pp.dim;
vecteur vp,vq,vp0,vq0;
polynome2poly1(pp,1,vp);
polynome2poly1(qp,1,vq);
polynome pp0(pp);
pp0.reorder(transposition(0,1,dim));
pp0=firstcoeff(pp0).trunc1();
polynome qp0(qp);
qp0.reorder(transposition(0,1,dim));
qp0=firstcoeff(qp0).trunc1();
polynome2poly1(pp0,1,vp0);
polynome2poly1(qp0,1,vq0);
gen den=pow(r2sym(f1_den,l,contextptr),qp.lexsorted_degree(),contextptr)*pow(r2sym(f2_den,l,contextptr),pp.lexsorted_degree(),contextptr);
vecteur tmpv1,tmpv2,S;
for (int i=0;i<=d;++i,++j){
if (debug_infolevel)
CERR << CLOCK()*1e-6 << " interp horner " << i << endl;
for (;;++j){
// find evaluation preserving degree in x
if (0 && j==0)
CERR << "j" << endl;
gen hp=horner(vp0,j);
gen hq=horner(vq0,j);
if (!is_zero(hp) && !is_zero(hq))
break;
}
X[i]=j;
gen gp=horner(vp,j);
gen gq=horner(vq,j);
if (debug_infolevel)
CERR << CLOCK()*1e-6 << " interp resultant " << j << ", " << 100*double(i)/(d+1) << "% done" << endl;
if (gp.type==_POLY && gq.type==_POLY){
if (0 &&
m>=GIAC_PADIC/2 && n>=GIAC_PADIC/2
)
resultant_sylvester(*gp._POLYptr,*gq._POLYptr,tmpv1,tmpv2,S,Y[i]);
else
Y[i]=resultant(*gp._POLYptr,*gq._POLYptr);
continue;
}
if (gp.type==_POLY){
Y[i]=pow(gq,gp._POLYptr->lexsorted_degree(),contextptr);
continue;
}
if (gq.type==_POLY){
Y[i]=pow(gp,gq._POLYptr->lexsorted_degree(),contextptr);
continue;
}
Y[i]=1;
}
if (debug_infolevel)
CERR << CLOCK()*1e-6 << " interp dd " << endl;
vecteur R=divided_differences(X,Y);
if (debug_infolevel)
CERR << CLOCK()*1e-6 << " interp build " << endl;
modpoly resp(1,R[d]),tmp; // cst in y
for (int i=d-1;i>=0;--i){
operator_times(resp,makevecteur(1,-X[i]),0,tmp);
if (tmp.empty())
tmp=vecteur(1,R[i]);
else
tmp.back() += R[i];
tmp.swap(resp);
}
vecteur & lf=*l.front()._VECTptr;
lf.erase(lf.begin()); // remove y
if (debug_infolevel)
CERR << CLOCK()*1e-6 << " interp convert " << endl;
gen resg=r2sym(resp,l,contextptr);
if (resg.type==_VECT)
resg=symb_horner(*resg._VECTptr,y);
return resg/den;
}
}
for (int i=0;i<=d;++i,++j){
if (debug_infolevel)
CERR << CLOCK()*1e-6 << " interp resultant " << i << endl;
for (;;++j){
// find evaluation preserving degree in x
if (!is_zero(subst(pl,y,j,false,contextptr))&& !is_zero(subst(ql,y,j,false,contextptr)))
break;
}
gen py=subst(p,y,j,false,contextptr);
gen qy=subst(q,y,j,false,contextptr);
X[i]=j;
rargs[0]=py;
rargs[1]=qy;
Y[i]=_resultant(gen(rargs,_SEQ__VECT),contextptr);
if (0){
gen dbgtst=subst(dbg,y,j,false,contextptr);
if (!is_zero(ratnormal(dbgtst-Y[i],contextptr)))
CERR << "err" << endl;
}
}
if (debug_infolevel)
CERR << CLOCK()*1e-6 << " interp interpolation begin " << endl;
gen r=_lagrange(makesequence(X,Y,y),contextptr);
if (debug_infolevel)
CERR << CLOCK()*1e-6 << " interp interpolation end " << endl;
return r;
}
}
if (v.size()>3)
return gentoomanyargs(_resultant_s);
if (v.back().type==_MOD)
v.back()=*v.back()._MODptr;
if (v.back().is_symb_of_sommet(at_prod)){
const gen & f = v.back()._SYMBptr->feuille;
if (f.type==_VECT && f._VECTptr->size()==2 && f._VECTptr->front().type==_MOD)
v.back()=f._VECTptr->back();
}
gen x=v.back();
vecteur l;
l.push_back(x);
l=vecteur(1,l);
gen p1=v.front(),p2=v[1];
alg_lvar(p1,l);
alg_lvar(p2,l);
int l_size;
if (!l.empty() && l.front().type==_VECT)
l_size=int(l.front()._VECTptr->size());
else
l_size=int(l.size());
gen f1,f1_num,f1_den,f2,f2_num,f2_den;
f1=e2r(makevecteur(p1,p2),l,contextptr);
f2=f1[1];
f1=f1[0];
fxnd(f1,f1_num,f1_den);
fxnd(f2,f2_num,f2_den);
if ( (f1_num.type==_POLY) && (f2_num.type==_POLY))
return r2sym(gen(resultant(*f1_num._POLYptr,*f2_num._POLYptr)),l,contextptr)/pow(r2sym(f1_den,l,contextptr),f2_num._POLYptr->lexsorted_degree(),contextptr)/pow(r2sym(f2_den,l,contextptr),f1_num._POLYptr->lexsorted_degree(),contextptr);
if (is_zero(f1))
return f1;
if (is_zero(f2))
return f2;
return 1;
}
static define_unary_function_eval (__resultant,&giac::_resultant,_resultant_s);
define_unary_function_ptr5( at_resultant ,alias_at_resultant,&__resultant,0,true);
/* I/O on stream */
#ifdef NSPIRE
template
void readargs_from_stream(nio::ios_base & inf,vecteur & args,GIAC_CONTEXT)
#else
void readargs_from_stream(istream & inf,vecteur & args,GIAC_CONTEXT)
#endif
{
string to_parse;
char c;
for (bool notbackslash=true;;){
inf.get(c);
if (!inf
#ifdef NSPIRE
|| c==char(EOF)
#endif
)
break;
if ( notbackslash || (c!='\n') )
to_parse +=c;
else
to_parse = to_parse.substr(0,to_parse.size()-1);
notbackslash= (c!='\\');
}
gen e(to_parse,contextptr);
if (e.type==_VECT)
args=*e._VECTptr;
else
args=makevecteur(e);
}
#ifdef NSPIRE
template
gen read1arg_from_stream(nio::ios_base & inf,GIAC_CONTEXT)
#else
gen read1arg_from_stream(istream & inf,GIAC_CONTEXT)
#endif
{
string to_parse;
char c;
for (bool notbackslash=true;;){
inf.get(c);
if (!inf)
break;
if ( notbackslash || (c!='\n') )
to_parse +=c;
else
to_parse = to_parse.substr(0,to_parse.size()-1);
notbackslash= (c!='\\');
}
return gen(to_parse,contextptr);
}
void readargs(int ARGC, char *ARGV[],vecteur & args,GIAC_CONTEXT){
// first initialize random generator for factorizations
srand(0);
//srand(time(NULL));
string s;
#ifdef NSPIRE
if (ARGC==0){ // fake, just to instantiate for file
file bidon("bidon","r");
readargs_from_stream(bidon,args,contextptr);
}
#endif
if (ARGC==1)
readargs_from_stream(CIN,args,contextptr);
else {
if (ARGC==2) {
if (!secure_run
#if !defined(__MINGW_H) && !defined(NSPIRE)
&& access(ARGV[1],R_OK)==0
#endif
){
#ifndef NSPIRE
ifstream inf(ARGV[1]);
readargs_from_stream(inf,args,contextptr);
#endif
}
else {
s=string(ARGV[1]);
gen e(s,contextptr);
args.push_back(e);
}
}
else {
vecteur v;
for (int i=1;i embeddings_s;
for (;((num.type==_POLY) && (Tis_constant(*num._POLYptr)));++embeddings){
embeddings_s.push_back(num._POLYptr->dim);
num=num._POLYptr->coord.front().value;
}
if (num.type==_EXT)
num=ext_reduce(num);
if (is_undef(num)) return;
if (num.type==_FRAC){
den=num._FRACptr->den;
num=num._FRACptr->num;
}
/* else commented since ext_reduce above might reduce g
else {
num=g;
return;
} */
for (;embeddings;--embeddings){
num=polynome(num,embeddings_s.back());
den=polynome(den,embeddings_s.back());
embeddings_s.pop_back();
}
}
#endif
// check in g all ext1 ext and rewrite them with ext2
static void remove_ext_copies(gen & g,const gen & ext1,const gen & ext2){
if (g.type==_POLY){
vector >::iterator it=g._POLYptr->coord.begin(),itend=g._POLYptr->coord.end();
for (;it!=itend;++it)
remove_ext_copies(it->value,ext1,ext2);
return;
}
if (g.type==_VECT){
iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end();
for (;it!=itend;++it)
remove_ext_copies(*it,ext1,ext2);
}
if (g.type==_FRAC)
remove_ext_copies(g._FRACptr->num,ext1,ext2);
if (g.type==_EXT){
gen & ext=*(g._EXTptr+1);
if (ext==ext1)
ext=ext2;
else
remove_ext_copies(ext,ext1,ext2);
}
}
#ifndef NO_NAMESPACE_GIAC
} // namespace giac
#endif // ndef NO_NAMESPACE_GIAC