/* -*- mode:C++ ; compile-command: "g++-3.4 -I.. -I../include -g -c threaded.cc -DHAVE_CONFIG_H -DIN_GIAC -D_I386_" -*- */
#include "giacPCH.h"
/* Copyright (C) 2000,2007 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 "threaded.h"
#include "sym2poly.h"
#include "gausspol.h"
#include "usual.h"
#include "monomial.h"
#include "modpoly.h"
#include "giacintl.h"
#include "input_parser.h"
#ifndef NO_NAMESPACE_GIAC
namespace giac {
#endif // ndef NO_NAMESPACE_GIAC
#ifdef HAVE_GMPXX_H
mpz_class invmod(const mpz_class & a,int reduce){
mpz_class z=(a%reduce);
int tmp=z.get_si();
tmp=giac::invmod(tmp,reduce);
return tmp;
}
mpz_class smod(const mpz_class & a,int reduce){
mpz_class z=(a%reduce);
int tmp=z.get_si();
tmp=giac::smod(tmp,reduce);
return tmp;
}
#endif
double heap_mult=20000;
gen _heap_mult(const gen & g0,GIAC_CONTEXT){
if ( g0.type==_STRNG && g0.subtype==-1) return g0;
gen g=evalf_double(g0,1,contextptr);
if (g.type!=_DOUBLE_)
return heap_mult;
return heap_mult=g._DOUBLE_val;
}
static const char _heap_mult_s []="heap_mult";
static define_unary_function_eval (__heap_mult,&_heap_mult,_heap_mult_s);
define_unary_function_ptr5( at_heap_mult ,alias_at_heap_mult,&__heap_mult,0,true);
double modgcd_cachesize=6291456;
gen _modgcd_cachesize(const gen & g0,GIAC_CONTEXT){
if ( g0.type==_STRNG && g0.subtype==-1) return g0;
gen g=evalf_double(g0,1,contextptr);
if (g.type!=_DOUBLE_)
return modgcd_cachesize;
return modgcd_cachesize=g._DOUBLE_val;
}
static const char _modgcd_cachesize_s []="modgcd_cachesize";
static define_unary_function_eval (__modgcd_cachesize,&_modgcd_cachesize,_modgcd_cachesize_s);
define_unary_function_ptr5( at_modgcd_cachesize ,alias_at_modgcd_cachesize,&__modgcd_cachesize,0,true);
gen _debug_infolevel(const gen & g0,GIAC_CONTEXT){
if ( g0.type==_STRNG && g0.subtype==-1) return g0;
gen g=evalf_double(g0,1,contextptr);
if (g.type!=_DOUBLE_)
return debug_infolevel;
return debug_infolevel=int(g._DOUBLE_val);
}
static const char _debug_infolevel_s []="debug_infolevel";
static define_unary_function_eval (__debug_infolevel,&_debug_infolevel,_debug_infolevel_s);
define_unary_function_ptr5( at_debug_infolevel ,alias_at_debug_infolevel,&__debug_infolevel,0,T_DIGITS);
gen _step_infolevel(const gen & g0,GIAC_CONTEXT){
if ( g0.type==_STRNG && g0.subtype==-1) return g0;
gen g=evalf_double(g0,1,contextptr);
if (g.type!=_DOUBLE_)
return step_infolevel(contextptr);
return step_infolevel(contextptr)=int(g._DOUBLE_val);
}
static const char _step_infolevel_s []="step_infolevel";
static define_unary_function_eval (__step_infolevel,&_step_infolevel,_step_infolevel_s);
define_unary_function_ptr5( at_step_infolevel ,alias_at_step_infolevel,&__step_infolevel,0,true);
my_mpz operator % (const my_mpz & a,const my_mpz & b){
my_mpz tmp;
mpz_fdiv_r(tmp.ptr,a.ptr,b.ptr);
return tmp;
}
my_mpz operator %= (my_mpz & a,const my_mpz & b){
mpz_fdiv_r(a.ptr,a.ptr,b.ptr);
return a;
}
my_mpz operator += (my_mpz & a,const my_mpz & b){
mpz_add(a.ptr,a.ptr,b.ptr);
return a;
}
my_mpz operator -= (my_mpz & a,const my_mpz & b){
mpz_sub(a.ptr,a.ptr,b.ptr);
return a;
}
my_mpz operator + (const my_mpz & a,const my_mpz & b){
my_mpz tmp;
mpz_add(tmp.ptr,a.ptr,b.ptr);
return tmp;
}
my_mpz operator - (const my_mpz & a,const my_mpz & b){
my_mpz tmp;
mpz_sub(tmp.ptr,a.ptr,b.ptr);
return tmp;
}
my_mpz operator * (const my_mpz & a,const my_mpz & b){
my_mpz tmp;
mpz_mul(tmp.ptr,a.ptr,b.ptr);
return tmp;
}
my_mpz operator / (const my_mpz & a,const my_mpz & b){
my_mpz tmp;
mpz_fdiv_q(tmp.ptr,a.ptr,b.ptr);
return tmp;
}
my_mpz invmod(const my_mpz & a,int reduce){
my_mpz z=(a%reduce);
int tmp=mpz_get_si(z.ptr);
tmp=invmod(tmp,reduce);
return tmp;
}
my_mpz smod(const my_mpz & a,int reduce){
my_mpz z=(a%reduce);
int tmp=mpz_get_si(z.ptr);
tmp=smod(tmp,reduce);
return tmp;
}
void wait_1ms(context * contextptr){
#ifdef NSPIRE
sleep(1);
#else
usleep(1000);
#endif
}
void background_callback(const gen & g,void * newcontextptr){
if (g.type==_VECT && g._VECTptr->size()==2){
context * cptr=(giac::context *)newcontextptr;
if (cptr){
#ifdef HAVE_LIBPTHREAD
pthread_mutex_lock(cptr->globalptr->_mutex_eval_status_ptr);
sto(g._VECTptr->back(),g._VECTptr->front(),cptr);
pthread_mutex_unlock(cptr->globalptr->_mutex_eval_status_ptr);
#endif
}
}
}
gen _background(const gen & g,GIAC_CONTEXT){
if ( g.type==_STRNG && g.subtype==-1) return g;
#ifdef HAVE_LIBPTHREAD
if (g.type!=_VECT || g._VECTptr->size()<2)
return gensizeerr(contextptr);
vecteur v(*g._VECTptr);
gen target=v[0];
gen toeval=v[1];
int s=v.size();
double maxsize=1e9; // in bytes
double maxtime=1e9; // in microseconds
int level=eval_level(contextptr);
if (s>2){
gen tmp=evalf_double(v[2],level,contextptr);
if (tmp.type!=_DOUBLE_)
return gentypeerr(contextptr);
maxsize=tmp._DOUBLE_val;
}
if (s>3){
gen tmp=evalf_double(v[3],level,contextptr);
if (tmp.type!=_DOUBLE_)
return gentypeerr(contextptr);
maxtime=tmp._DOUBLE_val;
}
if (s>4 && v[4].type==_INT_)
level=v[4].val;
gen tmp;
context * newcontextptr=clone_context(contextptr);
newcontextptr->parent=contextptr;
tmp=gen(newcontextptr,_THREAD_POINTER);
sto(tmp,target,contextptr);
if (!make_thread(makevecteur(symbolic(at_quote,target),toeval),level,background_callback,(void *)newcontextptr,newcontextptr)){
sto(undef,target,contextptr);
return gensizeerr(gettext("Unable to make thread"));
}
return tmp;
#else
return undef;
#endif
}
static const char _background_s []="background";
static define_unary_function_eval_quoted (__background,&_background,_background_s);
define_unary_function_ptr5( at_background ,alias_at_background,&__background,_QUOTE_ARGUMENTS,true);
// check if var is a power of 2
static int find_shift(const hashgcd_U & var){
hashgcd_U u(var);
int shift=-1;
for (;u;u = u>> 1){
++shift;
}
return (int(var) == (1< & vars,index_t & shift){
shift.clear();
std::vector::const_iterator it=vars.begin(),itend=vars.end();
shift.reserve(itend-it);
for (;it!=itend;++it){
shift.push_back(find_shift(*it));
if (shift.back()==-1)
return false;
}
return true;
}
static bool gcdsmallmodpoly(const vector & a,const vector & b,const vector * pminptr,int modulo,vector & d){
gcdsmallmodpoly(a,b,modulo,d);
return true;
}
static bool DivRem(const vector & a,const vector & b,const vector * pminptr,int modulo,vector & q,vector & r){
DivRem(a,b,modulo,q,r);
return true;
}
static bool divrem_(vector< vector > & a,vector< vector > & b,const vector & pmin, int modulo, vector< vector > * qptr,bool set_q_orig_b,vector & b0,vector & b0inv,vector & tmp,vector & tmp1,vector & tmp2,vector & tmp3,vector & tmp4,vector & tmp5);
static bool DivRem(const vector< vector > & a,const vector< vector > & b,const vector * pminptr,int modulo,vector< vector > & q,vector< vector > & r){
r=a;
vector< vector > b0(b);
vector B0,B0inv,tmp,tmp1,tmp2,tmp3,tmp4,tmp5;
return divrem_(r,b0,*pminptr,modulo,&q,true,B0,B0inv,tmp,tmp1,tmp2,tmp3,tmp4,tmp5);
}
static bool gcdsmallmodpoly_ext(const vector< vector > & p,const vector< vector > & q,const vector & pmin,int modulo,vector< vector > & d);
static bool gcdsmallmodpoly(const vector< vector > & a,const vector< vector > & b,const vector * pminptr,int modulo,vector< vector > & d){
return gcdsmallmodpoly_ext(a,b,*pminptr,modulo,d);
}
bool is_zero(const vector & v){
vector::const_iterator it=v.begin(),itend=v.end();
for (;it!=itend;++it){
if (*it)
return false;
}
return true;
}
inline int make_unit(int ){
return 1;
}
inline vector make_unit(const vector){
vector v(1,1);
return v;
}
// extract modular content of p wrt to the last variable
template
static bool pp_mod(vector< T_unsigned > & p,const vector * pminptr,int modulo,hashgcd_U var,hashgcd_U var2,vector & pcontxn){
typename vector< T_unsigned >::const_iterator it=p.begin(),itend=p.end();
pcontxn.clear();
if (it==itend) return true;
hashgcd_U u=(p.front().u/var)*var,curu,newu=0;
if (u==p.front().u){
pcontxn.push_back(make_unit(p.front().g));
return true;
}
vector current,tmp,reste;
for (;it!=itend;){
current.clear();
current.push_back(it->g);
curu=it->u;
++it;
for (;it!=itend;++it){
newu=it->u;
if ( newu < u ){
break;
}
if (curu>newu+var2)
current.insert(current.end(),(curu-newu)/var2-1,T(0));
current.push_back(it->g);
curu=newu;
}
if (curu>u)
current.insert(current.end(),(curu-u)/var2,T(0));
#ifdef TIMEOUT
control_c();
#endif
if (ctrl_c || interrupted || !gcdsmallmodpoly(pcontxn,current,pminptr,modulo,tmp))
return false;
pcontxn=tmp;
if (tmp.size()==1)
return true;
u=(newu/var)*var;
}
vector< T_unsigned > res;
it=p.begin();
u=(p.front().u/var)*var;
for (;it!=itend;){
current.clear();
current.push_back(it->g);
curu=it->u;
++it;
for (;it!=itend;++it){
newu=it->u;
if ( newu < u ){
break;
}
if (curu>newu+var2)
current.insert(current.end(),(curu-newu)/var2-1,T(0));
current.push_back(it->g);
curu=newu;
}
if (curu>u)
current.insert(current.end(),(curu-u)/var2,T(0));
#ifdef TIMEOUT
control_c();
#endif
if (ctrl_c || interrupted || !DivRem(current,pcontxn,pminptr,modulo,tmp,reste))
return false;
typename vector::const_iterator jt=tmp.begin(),jtend=tmp.end();
for (int s=int(jtend-jt)-1;jt!=jtend;++jt,--s){
if (!is_zero(*jt))
res.push_back(T_unsigned(*jt,u+s*var2));
}
u=(newu/var)*var;
}
p=res;
return true;
}
template
static bool operator < (const vector< T_unsigned > & v1,const vector< T_unsigned > & v2){
return v1.size() > & p,hashgcd_U var,hashgcd_U var2){
vector< T_unsigned >::const_iterator it=p.begin(),itend=p.end();
hashgcd_U degxn=0;
hashgcd_U u;
for (;it!=itend;++it){
u=it->u%var;
if (degxn
static unsigned degree_xn(const vector< T_unsigned > & p,short int shift_var,short int shift_var2){
typename vector< T_unsigned >::const_iterator it=p.begin(),itend=p.end(),it1;
unsigned degxn=0;
unsigned u,uend;
for (;it!=itend;++it){
uend = ((it->u >> shift_var) << shift_var);
u = (it->u - uend) >> shift_var2 ;
if (!u)
continue;
if (degxn=itend-it)
continue;
it1 = it+u;
if (it1->u==uend)
it = it1;
}
return degxn ;
}
/*
template
int degree(const vector< T_unsigned > & p,
const std::vector & vars,
index_t & res){
typename vector< T_unsigned >::const_iterator it=p.begin(),itend=p.end();
std::vector::const_iterator jtbeg=vars.begin(),jtend=vars.end(),jt;
hashgcd_U u,ur;
res=index_t(jtend-jtbeg);
index_t::iterator ktbeg=res.begin(),ktend=res.end(),kt;
int totaldeg=0,current;
for (;it!=itend;++it){
u=it->u;
current=0;
for (jt=jtbeg,kt=ktbeg;jt!=jtend;++jt,++kt){
ur=u%(*jt);
u=u/(*jt);
if (u>*kt)
*kt=u;
current += u;
u=ur;
}
if (current>totaldeg)
totaldeg=current;
}
return totaldeg;
}
*/
template
static int degree(const vector< T_unsigned > & p,
const index_t & shift_vars,
index_t & res){
typename vector< T_unsigned >::const_iterator it=p.begin(),itend=p.end();
index_t::const_iterator jtbeg=shift_vars.begin(),jtend=shift_vars.end(),jt;
int dim=int(jtend-jtbeg);
if (dim==1){
int deg=it->u >> *jtbeg;
res.clear();
res.push_back(deg);
return deg;
}
hashgcd_U u,uq,uend,skip;
short int lastvar=shift_vars[shift_vars.size()-2],shift_var2=shift_vars.back();
res=index_t(jtend-jtbeg);
index_t::iterator ktbeg=res.begin(),ktend=res.end(),kt;
int totaldeg=0,current;
for (;it!=itend;){
u=it->u;
// find degree for *it and skip monomials having x1..xn-1 in common
uend = (u >> lastvar) << lastvar;
skip = (u-uend) >> shift_var2;
current=0;
// find partial and total degree
for (jt=jtbeg,kt=ktbeg;jt!=jtend;++jt,++kt){
uq = u >> *jt;
u -= uq << *jt;
if ((int)uq>*kt)
*kt = uq;
current += uq;
}
if (current>totaldeg)
totaldeg=current;
if ((int)skipu==uend){
it += skip;
++it;
continue;
}
for (++it;it!=itend;++it){
if (it->u,hashgcd_U> > & p_orig,const vector< T_unsigned,hashgcd_U> > & q_orig,const std::vector & vars,const vector & pmin,int modulo,
vector< T_unsigned,hashgcd_U> > & d,
vector< T_unsigned,hashgcd_U> > & pcof,vector< T_unsigned,hashgcd_U> > & qcof,bool compute_pcof,bool compute_qcof,
int nthreads);
bool mod_gcd(const vector< T_unsigned,hashgcd_U> > & p_orig,const vector< T_unsigned,hashgcd_U> > & q_orig,const vector * pminptr,int modulo,const std::vector & vars,
vector< T_unsigned,hashgcd_U> > & d,
vector< T_unsigned,hashgcd_U> > & pcof,vector< T_unsigned,hashgcd_U> > & qcof,bool compute_cof,
int nthreads){
return mod_gcd_ext(p_orig,q_orig,vars,*pminptr,modulo,d,pcof,qcof,compute_cof,compute_cof,nthreads)!=0;
}
bool mod_gcd(const vector< T_unsigned > & p_orig,const vector< T_unsigned > & q_orig,const vector * pminptr,int modulo,const std::vector & vars, vector< T_unsigned > & d, vector< T_unsigned > & pcofactor, vector< T_unsigned > & qcofactor,bool compute_cofactor,int nthreads){
return mod_gcd(p_orig,q_orig,modulo,d,pcofactor,qcofactor,vars,compute_cofactor,nthreads);
}
struct modred {
int modulo;
vector pmin;
modred(int m,const vector & p):modulo(m),pmin(p) {}
modred():modulo(0),pmin(0) {}
};
static bool is_zero(const modred & r){
return r.modulo==0;
}
static int make_modulo(const vector * pminptr,int modulo,int){
return modulo;
}
static modred make_modulo(const vector * pminptr,int modulo,vector){
return modred(modulo,*pminptr);
}
struct Modred {
int modulo;
vecteur pmin;
Modred(int m,const vecteur & p):modulo(m),pmin(p) {}
Modred():modulo(0),pmin(0) {}
};
static bool is_zero(const Modred & r){
return r.modulo==0;
}
// extract modular content of p wrt to all but the last variable
template
static bool pp_mod(vector< T_unsigned > & p,const vector * pminptr,int modulo,const std::vector & vars,vector< T_unsigned > & pcont,int nthreads){
#ifdef NO_TEMPLATE_MULTGCD
return false;
#else
typename vector< T_unsigned >::const_iterator it=p.begin(),itend=p.end();
pcont.clear();
pcont.push_back(T_unsigned(make_unit(T(0)),0));
if (it==itend || vars.empty()) return true;
std::vector varsn(vars);
varsn.pop_back();
// hashgcd_U degxnu=0;
hashgcd_U u,u0,var=varsn.back(),var2=vars.back();
short int shiftvar=find_shift(var),shiftvar2=find_shift(var2);
unsigned degxn = degree_xn(p,shiftvar,shiftvar2);
vector nterms(degxn+1);
vector nonzero(degxn+1,false); // number of non constant terms
int pos;
for (it=p.begin();it!=itend;++it){
u = it->u;
pos = (u%var) >> shiftvar2;
nonzero[pos]=true;
if (u>>shiftvar)
++nterms[pos];
}
vector< vector< T_unsigned > > vp(degxn+1);
for (int i=degxn;i>=0;--i){
if (!nterms[i] && nonzero[i]) // all terms would be constant in vp[i]
return true;
vp[i].reserve(nterms[i]+1);
}
for (it=p.begin();it!=itend;++it){
u = it->u;
u0 = (u >> shiftvar) << shiftvar;
vp[(u-u0)>>shiftvar2].push_back(T_unsigned(it->g, u0));
}
// sort vp by size
sort(vp.begin(),vp.end());
// compute gcd
unsigned int i=0;
for (;i<=degxn;++i){
if (!vp[i].empty()){
pcont=vp[i];
break;
}
}
if (pcont.empty())
CERR << "empty" << endl;
vector< T_unsigned > res,rem,pcof,qcof;
for (++i;i<=degxn;++i){
if (pcont.size()==1 && pcont.front().u==0)
return true;
#ifdef TIMEOUT
control_c();
#endif
if (ctrl_c || interrupted || !mod_gcd(pcont,vp[i],pminptr,modulo,varsn,pcont,pcof,qcof,false,nthreads))
return false;
}
if (pcont.size()==1 && pcont.front().u==0)
return true;
hashdivrem(p,pcont,res,rem,vars,make_modulo(pminptr,modulo,T(0)),0,false);
swap(p,res);
return true;
#endif // NO_TEMPLATE_MULTGCD
}
// fast check if p is primitive with respect to the main var
// p main var is y, inner var is x
static bool is_front_primitive(vector< vector > & p,int modulo){
vector< vector >::iterator it=p.begin(),itend=p.end();
int degy=int(itend-it)-1;
vector degrees;
int degs=0,d;
for (it=p.begin();it!=itend;++it,--degy){
d=int(it->size());
// there is a x^d*y^degy term -> set degree of x^0 to x^d to degy at least
if (d>degs){
degrees.insert(degrees.end(),d-degs,degy);
degs=d;
}
}
vector::iterator jt=degrees.begin(),jtend=degrees.end();
for (;jt!=jtend;++jt){
if (!*jt)
return true;
}
return false;
}
// eval p at x with respect to the last variable
// keep only terms of degree <= maxdeg with respect to the main variable
static bool horner(const vector< T_unsigned > & p,int x,const std::vector & vars,vector< T_unsigned > & px,int modulo,int maxdeg){
hashgcd_U var=vars[vars.size()-2];
hashgcd_U var2=vars.back();
vector< T_unsigned >::const_iterator it=p.begin(),itend=p.end(),it1,it2;
vector::const_iterator jtend=vars.end()-1;
hashgcd_U ucur,uend;
if (maxdeg>=0){
uend=(maxdeg+1)*vars.front();
// dichotomy to find start position
int pos1=0,pos2=int(itend-it),pos;
for (;pos2-pos1>1;){
pos=(pos1+pos2)/2;
if ((it+pos)->uu>=uend)
++it;
}
if (x==0){
px.clear();
for (;it!=itend;){
ucur=it->u;
uend=(ucur/var)*var;
if (ucur==uend){
register int g=smod(it->g,modulo);
if (g!=0)
px.push_back(T_unsigned(g,uend));
++it;
continue;
}
register int nterms = (ucur-uend)/var2;
if (ntermsu==uend){
it += nterms;
register int g=smod(it->g,modulo);
if (g!=0)
px.push_back(T_unsigned(g,uend));
++it;
continue;
}
for (++it;it!=itend;++it){
if (it->u<=uend){
if (it->u==uend){
register int g=smod(it->g,modulo);
if (g!=0)
px.push_back(T_unsigned(g,uend));
++it;
}
break;
}
}
}
return true;
}
vector< T_unsigned >::iterator kt=px.begin(),ktend=px.end();
for (;it!=itend;){
ucur=it->u;
uend=(ucur/var)*var;
if (ucur==uend){
if (kt!=ktend){
*kt=*it;
++kt;
}
else
px.push_back(*it);
++it;
continue;
}
int g=0;
int nterms=(ucur-uend)/var2+1;
if (x==1 && nterms < RAND_MAX/modulo ){
for (;it!=itend;++it){
if (it->u(g,uend);
++kt;
}
else
px.push_back(T_unsigned(g,uend));
}
break;
}
else
g += it->g;
}
if (it==itend){
g=smod(g,modulo);
if (g!=0){
if (kt!=ktend){
*kt=T_unsigned(g,uend);
++kt;
}
else
px.push_back(T_unsigned(g,uend));
}
}
continue;
}
else {
// Check if the next group of monomials is dense wrt to xn
it1=it+nterms;
if (//false &&
ntermsu==uend
){
if (modulo<=46340){
if (x>=-14 && x<=14){
if (x>=-8 && x<=8){
it2=it+5*((it1-it)/5);
for (;it!=it2;){
g *= x;
g += it->g;
++it;
g *= x;
g += it->g;
++it;
g *= x;
g += it->g;
++it;
g *= x;
g += it->g;
++it;
g *= x;
g += it->g;
g %= modulo;
++it;
}
}
else {
it2=it+4*((it1-it)/4);
for (;it!=it2;){
g *= x;
g += it->g;
++it;
g *= x;
g += it->g;
++it;
g *= x;
g += it->g;
++it;
g *= x;
g += it->g;
g %= modulo;
++it;
}
}
}
else {
if (x>=-35 && x<=35){
it2=it+3*((it1-it)/3);
for (;it!=it2;){
g *= x;
g += it->g;
++it;
g *= x;
g += it->g;
++it;
g *= x;
g += it->g;
g %= modulo;
++it;
}
}
}
for (;it!=it1;++it){
g = (g*x+it->g)%modulo;
}
} // end if (modulo<46430)
else { // modulo>=46430, using longlong
if (x>=-84 && x<=84){
longlong G=g;
it2=it+5*((it1-it)/5);
for (;it!=it2;){
G *= x;
G += it->g;
++it;
G *= x;
G += it->g;
++it;
G *= x;
G += it->g;
++it;
G *= x;
G += it->g;
++it;
G *= x;
G += it->g;
G %= modulo;
++it;
}
for (;it!=it1;++it){
G *=x;
G += it->g;
}
g=G%modulo;
}
else {
for (;it!=it1;++it){
g = (g*longlong(x)+it->g)%modulo;
}
}
}
g=smod(g,modulo);
if (g!=0){
if (kt!=ktend){
*kt=T_unsigned(g,uend);
++kt;
}
else
px.push_back(T_unsigned(g,uend));
}
continue;
}
if (modulo>=46340){
for (;it!=itend;++it){
const hashgcd_U & u=it->u;
if (u(g,uend);
++kt;
}
else
px.push_back(T_unsigned(g,uend));
}
}
break;
}
if (ucur-u==var2)
g = (g*longlong(x)+ it->g)%modulo;
else
g = (g*longlong(powmod(x,(ucur-u)/var2,modulo))+ it->g)%modulo;
ucur=u;
} // end for
} // end if modulo>=46340
else {
for (;it!=itend;++it){
const hashgcd_U & u=it->u;
if (u(g,uend);
++kt;
}
else
px.push_back(T_unsigned(g,uend));
}
}
break;
}
if (ucur-u==var2)
g = (g*x+ it->g)%modulo;
else
g = (g*powmod(x,(ucur-u)/var2,modulo)+ it->g)%modulo;
ucur=u;
} // end for
}
} // end else x=1
if (it==itend){
if (g!=0){
g = smod(g*longlong(powmod(x,(ucur-uend)/var2,modulo)),modulo);
if (g!=0){
if (kt!=ktend){
*kt=T_unsigned(g,uend);
++kt;
}
else
px.push_back(T_unsigned(g,uend));
}
}
}
}
if (kt!=ktend)
px.erase(kt,ktend);
return true;
}
// v <- v*k % m
void mulmod(vector & v,int k,int m){
if (k==1)
return;
vector::iterator it=v.begin(),itend=v.end();
for (;it!=itend;++it){
type_operator_times_reduce(*it,k,*it,m);
// *it = ((*it)*k)%m;
}
}
// v <- v*k % m
static void mulmod(vector< vector > & v,int k,int m){
if (k==1)
return;
vector< vector >::iterator it=v.begin(),itend=v.end();
for (;it!=itend;++it){
mulmod(*it,k,m);
}
}
inline void mulmod(int k,vector & v,int m){
mulmod(v,k,m);
}
// v <- v+w % m
static void addmod(vector & v,const vector & w,int m){
vector::const_iterator jt=w.begin(),jtend=w.end();
vector::iterator it=v.begin(),itend=v.end();
int ws=int(jtend-jt),vs=int(v.size());
if (ws>vs){
if ((int)v.capacity() tmp(ws);
copy(v.begin(),v.end(),tmp.begin()+ws-vs);
swap(v,tmp);
}
else {
v.insert(v.begin(),ws-vs,0);
}
it=v.begin();
itend=v.end();
}
for (it=itend-ws;it!=itend;++jt,++it){
*it = (*it+*jt)%m;
}
// trim resulting polynomial
for (it=v.begin();it!=itend;++it){
if (*it)
break;
}
if (it!=v.begin())
v.erase(v.begin(),it);
}
// v <- v+w % m
static void addmod(vector< vector > & v,const vector< vector > & w,int m){
vector< vector >::iterator it=v.begin(),itend=v.end();
vector< vector >::const_iterator jt=w.begin(),jtend=w.end();
int addv=int(jtend-jt)-int(itend-it);
if (addv>0){
v.insert(v.begin(),addv,vector(0));
it=v.begin();
itend=v.end();
}
for (it=itend-(jtend-jt);it!=itend;++jt,++it){
addmod(*it,*jt,m);
}
}
// v <- v+w % m
static void addmod(vecteur & v,const vecteur & w,int m){
vecteur::const_iterator jt=w.begin(),jtend=w.end();
vecteur::iterator it=v.begin(),itend=v.end();
int ws=int(jtend-jt),vs=int(v.size());
if (ws>vs){
if ((int)v.capacity() & v,const vector & w,int m){
vector::iterator it=v.begin(),itend=v.end();
vector::const_iterator jt=w.begin(),jtend=w.end();
int addv=int(jtend-jt)-int(itend-it);
if (addv>0){
v.insert(v.begin(),addv,0);
it=v.begin();
itend=v.end();
}
for (it=itend-(jtend-jt);it!=itend;++jt,++it){
*it = (*it-*jt)%m;
}
for (it=v.begin();it!=itend;++it){
if (*it)
break;
}
if (it!=v.begin())
v.erase(v.begin(),it);
}
// v <- k*(v-w) % m
static void mulsubmod(int k,vector & v,const vector & w,int m){
vector::iterator it=v.begin(),itend=v.end();
vector::const_iterator jt=w.begin(),jtend=w.end();
int addv=int(jtend-jt)-int(itend-it);
if (addv>0){
v.insert(v.begin(),addv,0);
it=v.begin();
itend=v.end();
}
itend -= (jtend-jt);
if (m<=46340){
if (2*k>m)
k -= m;
for (;it!=itend;++it){
*it = ((*it)*k)%m;
}
for (itend=v.end();it!=itend;++jt,++it){
*it = ((*it-*jt)*k)%m;
}
}
else {
for (;it!=itend;++it){
type_operator_times_reduce(*it,k,*it,m);
// *it = ((*it)*k)%m;
}
for (itend=v.end();it!=itend;++jt,++it){
*it -= *jt;
type_operator_times_reduce(*it,k,*it,m);
// *it = ((*it)*k)%m;
}
}
for (it=v.begin();it!=itend;++it){
if (*it)
break;
}
if (it!=v.begin())
v.erase(v.begin(),it);
}
// eval p at x with respect to all but the last variable
template
static bool horner(const std::vector< T_unsigned > & p,const std::vector & x,const std::vector & vars,std::vector & px,int modulo){
int s=int(x.size());
// int xback=x.back();
int vs=int(vars.size());
if (s+1!=vs || vs<2)
return false; // setdimerr();
hashgcd_U var=vars[vs-2],var2=vars.back();
int shift_var=find_shift(var),shift_var2=find_shift(var2);
typename vector< T_unsigned >::const_iterator it=p.begin(),itend=p.end();
if (is_zero(x)){
int pos1=0,pos2=int(itend-it),pos;
for (;pos2-pos1>1;){
pos=(pos1+pos2)/2;
if ((it+pos)->uu>=var)
++it;
if (it==itend)
px.clear();
else {
int pxdeg = it->u >> shift_var2;
px=vector(pxdeg+1);
for (;it!=itend;++it){
px[pxdeg - (it->u >> shift_var2)]=it->g;
}
}
}
else {
int pxdeg=degree_xn(p,shift_var,shift_var2);
px=vector(pxdeg+1);
vector::const_iterator jtbeg=vars.begin(),jtend=vars.end(),jt;
--jtend;
vector::const_iterator ktbeg=x.begin(),kt;
hashgcd_U u,oldu=0;
int oldfact=0;
int inverse=x.back()?invmod(x.back(),modulo):0;
for (;it!=itend;){
// group next monomials with same powers in x1..xn-1
u=(it->u/var)*var;
int tmpdeg=(it->u-u)/var2;
vector tmp(tmpdeg+1);
for (;;++it){
if (it==itend || it->uu-u)/var2]=it->g;
}
}
} // end else is_zero(x)
// trim px
typename vector::iterator lt=px.begin(),ltend=px.end();
for (;lt!=ltend;++lt){
if (!is_zero(*lt))
break;
}
if (lt!=px.begin())
px.erase(px.begin(),lt);
return true;
}
template
static void convert_back(const vector & v,hashgcd_U var,vector< T_unsigned > & p){
p.clear();
typename vector::const_iterator it=v.begin(),itend=v.end();
unsigned s=unsigned(itend-it);
p.reserve(s);
hashgcd_U u=var*(s-1);
for (;it!=itend;u-=var,++it){
if (!is_zero(*it))
p.push_back(T_unsigned(*it,u));
}
}
static void convert_back(const vector< vector > & v,hashgcd_U varxn,hashgcd_U var2,vector< T_unsigned > & p){
vector< vector >::const_iterator jt=v.begin(),jtend=v.end();
vector< T_unsigned >::iterator kt=p.begin(),ktend=p.end();
for (;jt!=jtend;++jt){
vector::const_iterator it=jt->begin(),itend=jt->end();
unsigned s=unsigned(itend-it);
hashgcd_U u=var2*(s-1)+varxn*(unsigned(jtend-jt)-1);
for (;it!=itend;u-=var2,++it){
if (*it!=0){
if (kt!=ktend){
*kt=T_unsigned(*it,u);
++kt;
}
else
p.push_back(T_unsigned(*it,u));
}
}
}
if (kt!=ktend)
p.erase(kt,ktend);
}
static void convert(const vector< T_unsigned > & p,hashgcd_U var,vector & v,int modulo){
v.clear();
vector< T_unsigned >::const_iterator it=p.begin(),itend=p.end();
if (it==itend)
return;
hashgcd_U u=it->u;
unsigned s=u/var;
v=vector(s+1);
for (;it!=itend;++it){
v[s-it->u/var]=it->g<0?it->g+modulo:it->g;
}
}
#if 0
static void convert(const vector< T_unsigned > & p,short int var,vector & v,int modulo){
vector< T_unsigned >::const_iterator it=p.begin(),itend=p.end();
if (it==itend){
v.clear();
return;
}
hashgcd_U u=it->u;
unsigned s=u >> var;
if (v.size()==s+1)
fill(v.begin(),v.end(),0);
else
v=vector(s+1);
for (;it!=itend;++it){
v[s-(it->u >> var)]=it->g<0?it->g+modulo:it->g;
}
}
#endif
/*
void convert(const vector< T_unsigned > & p,hashgcd_U var,vector & v){
v.clear();
vector< T_unsigned >::const_iterator it=p.begin(),itend=p.end();
if (it==itend)
return;
hashgcd_U u=it->u,prevu=u;
unsigned s=u/var;
v.reserve(s+1);
v.push_back(it->g);
for (++it;it!=itend;++it){
u=it->u;
prevu -= var;
if (u==prevu)
v.push_back(it->g);
else {
v.insert(v.end(),(prevu-u)/var,0);
v.push_back(it->g);
prevu=u;
}
}
}
*/
// Find non zeros coeffs of p
template
static int find_nonzero(const vector & p,index_t & res){
res.clear();
typename vector::const_iterator it=p.begin(),itend=p.end();
if (it==itend)
return 0;
int nzeros=0;
for (;it!=itend;++it){
bool test=is_zero(*it);
res.push_back(test?0:1);
if (test)
++nzeros;
}
return nzeros;
}
template
static hashgcd_U lcoeff(const vector< T_unsigned > & p,hashgcd_U var,hashgcd_U var2,vector & lp){
lp.clear();
typename vector< T_unsigned >::const_iterator it=p.begin(),itend=p.end();
if (it==itend)
return 0;
hashgcd_U u=it->u;
int deg=(u%var)/var2;
lp=vector(deg+1);
u=(u/var)*var;
for (;it!=itend;++it){
if (it->uu%var)/var2]=it->g;
}
return u;
}
static std::vector smod(const std::vector & v,int modulo){
std::vector res(v);
std::vector::iterator it=res.begin(),itend=res.end();
for (;it!=itend;++it){
*it = smod(*it,modulo);
}
if (res.empty() || res.front())
return res;
for (it=res.begin();it!=itend;++it){
if (*it)
break;
}
return std::vector(it,itend);
}
static int hornermod(const vector & v,int alpha,int modulo,bool unsig=false){
vector::const_iterator it=v.begin(),itend=v.end(),it0;
if (!alpha)
return it==itend?0:v.back();
int res=0;
if (alpha==1 && (itend-it)=-8 && alpha<=8){
it0=it+5*((itend-it)/5);
for (;it!=it0;){
res *= alpha;
res += *it;
++it;
res *= alpha;
res += *it;
++it;
res *= alpha;
res += *it;
++it;
res *= alpha;
res += *it;
++it;
res *= alpha;
res += *it;
res %= modulo;
++it;
}
for (;it!=itend;++it){
res *= alpha;
res += *it;
}
return smod(res,modulo);
}
if (alpha>=-14 && alpha<=14){
it0=it+4*((itend-it)/4);
for (;it!=it0;){
res *= alpha;
res += *it;
++it;
res *= alpha;
res += *it;
++it;
res *= alpha;
res += *it;
++it;
res *= alpha;
res += *it;
res %= modulo;
++it;
}
for (;it!=itend;++it){
res *= alpha;
res += *it;
}
return smod(res,modulo);
}
if (alpha>=-35 && alpha<=35){
it0=it+3*((itend-it)/3);
for (;it!=it0;){
res *= alpha;
res += *it;
++it;
res *= alpha;
res += *it;
++it;
res *= alpha;
res += *it;
res %= modulo;
++it;
}
for (;it!=itend;++it){
res *= alpha;
res += *it;
}
return smod(res,modulo);
}
if (alpha>=-214 && alpha<=214){
it0=it+2*((itend-it)/2);
for (;it!=it0;){
res *= alpha;
res += *it;
++it;
res *= alpha;
res += *it;
res %= modulo;
++it;
}
for (;it!=itend;++it){
res *= alpha;
res += *it;
}
return smod(res,modulo);
}
} // if (modulo<46430)
else {
longlong Res=res;
if (alpha>=-8 && alpha<=8){
it0=it+5*((itend-it)/5);
for (;it!=it0;){
Res *= alpha;
Res += *it;
++it;
Res *= alpha;
Res += *it;
++it;
Res *= alpha;
Res += *it;
++it;
Res *= alpha;
Res += *it;
++it;
Res *= alpha;
Res += *it;
Res %= modulo;
++it;
}
for (;it!=itend;++it){
Res *= alpha;
Res += *it;
}
return smod(Res,modulo);
} // end if alpha>=-84 and alpha<=84
} // end else (modulo>46430)
#if defined _I386_ && !defined x86_64
if (unsig){
if (alpha<0)
alpha += modulo;
// it va dans ecx, itend dans ebx, modulo dans edi, alpha dans esi
// eax::edx produit et division, eax contient res,
asm volatile("movl $0x0,%%eax;\n\t"
"cmpl %%ecx,%%ebx;\n\t"
"je .Lend%=\n"
".Lloop%=:\t"
"imul %%esi;\n\t" /* res<-res*alpha */
"addl (%%ecx),%%eax;\n\t"
"adcl $0x0,%%edx; \n\t" /* res += *it */
"idivl %%edi; \n\t" /* res %= modulo */
"movl %%edx,%%eax; \n\t"
"addl $4,%%ecx; \n\t" /* ++ *it */
"cmpl %%ecx,%%ebx;\n\t" /* it==itend */
"jne .Lloop%=\n"
".Lend%=:\t"
:"=a"(res)
:"c"(it),"b"(itend),"D"(modulo),"S"(alpha)
:"%edx"
);
if (res>modulo)
return res-modulo;
return res;
}
#endif
if (modulo<46340){
if (unsig){
unsigned Alpha=alpha<0?alpha+modulo:alpha;
unsigned res=0;
for (;it!=itend;++it){
res = (res*Alpha+unsigned(*it))%modulo;
}
if (res>(unsigned)(modulo/2))
return int(res)-modulo;
else
return int(res);
}
for (;it!=itend;++it){
res = (res*alpha+*it)%modulo;
}
}
else {
for (;it!=itend;++it){
res = (res*longlong(alpha)+*it)%modulo;
}
}
register int tmp=res+res;
if (tmp>modulo)
return res-modulo;
if (tmp<=-modulo)
return res+modulo;
return res;
}
// distribute multiplication
static void distmult(const vector< T_unsigned > & p,const vector & v,vector< T_unsigned > & pv,hashgcd_U var,int modulo){
if (&pv==&p){
vector< T_unsigned > tmp;
distmult(p,v,tmp,var,modulo);
swap(pv,tmp);
return;
}
pv.clear();
vector< T_unsigned >::const_iterator it=p.begin(),itend=p.end();
vector::const_iterator jtbeg=v.begin(),jtend=v.end(),jt;
int vs=int(jtend-jtbeg),j;
pv.reserve((itend-it)*vs);
if (modulo>=46340){
for (;it!=itend;++it){
for (jt=jtbeg,j=1;jt!=jtend;++j,++jt){
if (*jt)
pv.push_back(T_unsigned((it->g*longlong(*jt))%modulo,it->u+(vs-j)*var));
}
}
}
else {
for (;it!=itend;++it){
for (jt=jtbeg,j=1;jt!=jtend;++j,++jt){
if (*jt)
pv.push_back(T_unsigned((it->g*(*jt))%modulo,it->u+(vs-j)*var));
}
}
}
}
// distribute multiplication
static void distmult(const vector< T_unsigned,hashgcd_U> > & p,const vector & v,vector< T_unsigned,hashgcd_U> > & pv,hashgcd_U var,int modulo){
if (&pv==&p){
vector< T_unsigned,hashgcd_U> > tmp;
distmult(p,v,tmp,var,modulo);
swap(pv,tmp);
return;
}
pv.clear();
vector< T_unsigned,hashgcd_U> >::const_iterator it=p.begin(),itend=p.end();
vector tmp;
vector::const_iterator jtbeg=v.begin(),jtend=v.end(),jt;
int vs=int(jtend-jtbeg),j;
pv.reserve((itend-it)*vs);
for (;it!=itend;++it){
for (jt=jtbeg,j=1;jt!=jtend;++j,++jt){
if (*jt){
tmp=it->g;
mulmod(*jt,tmp,modulo);
pv.push_back( T_unsigned,hashgcd_U>(tmp,it->u+(vs-j)*var));
}
}
}
}
#if 0
static void distmult(const vector & p,const vector & v,vector< vector > & pv,int modulo){
vector::const_iterator it=p.begin(),itend=p.end(),jt=v.begin(),jtend=v.end();
pv.clear();
pv.insert(pv.end(),(itend-it),vector(0));
if (modulo<=46340){
for (int i=0;it!=itend;++it,++i){
vector & w = pv[i];
const int & fact = *it;
if (fact){
w.reserve(v.size());
for (jt=v.begin();jt!=jtend;++jt)
w.push_back(fact*(*jt) % modulo);
}
}
}
else {
for (int i=0;it!=itend;++it,++i){
vector & w = pv[i];
const int & fact = *it;
if (fact){
w.reserve(v.size());
for (jt=v.begin();jt!=jtend;++jt)
w.push_back( (longlong(fact)*(*jt)) % modulo);
}
}
}
}
static void mulmod(const vector & v,int m,vector & w,int modulo){
if (&v==&w){
mulmod(w,m,modulo);
return;
}
vector::const_iterator jt=v.begin(),jtend=v.end();
w.clear();
w.reserve(jtend-jt);
if (modulo>=46340){
for (;jt!=jtend;++jt)
w.push_back(smod(*jt * longlong(m),modulo));
}
else {
for (;jt!=jtend;++jt)
w.push_back(smod(*jt * m,modulo));
}
}
#endif
// if all indices are == return -2
// if all indices corr. to u1 are <= to u2 return 1,
// if all are >= to u2 return 0
// otherwise return -1
int compare(hashgcd_U u1,hashgcd_U u2,const vector & vars){
if (u1==u2)
return -2;
std::vector::const_iterator it=vars.begin(),itend=vars.end();
hashgcd_U r1,r2;
int res=-2;
for (;it!=itend;++it){
r1=u1%(*it);
r2=u2%(*it);
if (r1==r2)
continue;
if (res==-2){
res=r1= to u2 return 0
// otherwise return -1
static int compare(const index_t & u1,const index_t & u2){
if (u1==u2)
return -2;
index_t::const_iterator it=u1.begin(),itend=u1.end(),jt=u2.begin();
int res=-2;
for (;it!=itend;++it,++jt){
if (*it==*jt)
continue;
if (res==-2){
res=*it<*jt;
continue;
}
if (*it<*jt){
if (res)
continue;
return -1;
}
else {
if (!res)
continue;
return -1;
}
}
return res;
}
inline bool is_one(const vector< T_unsigned > & p){
return p.size()==1 && p.front().g==1 && p.front().u==0;
}
// Note that smallmult may fail if the degree of a and b * modulo^2
// overflows in a longlong, so keep modulo not too large
static void smallmult(const vector::const_iterator & ita0,const vector::const_iterator & ita_end,const vector::const_iterator & itb0,const vector::const_iterator & itb_end,vector & new_coord,int modulo){
longlong test=longlong(modulo)*std::min(ita_end-ita0,itb_end-itb0);
bool large=test/RAND_MAX>RAND_MAX/modulo;
new_coord.clear();
vector::const_iterator ita_begin=ita0,ita=ita0,itb=itb0;
for ( ; ita!=ita_end; ++ita ){
vector::const_iterator ita_cur=ita,itb_cur=itb;
if (large){
int res=0;
for (;itb_cur!=itb_end;--ita_cur,++itb_cur) {
res = (res + *ita_cur * longlong(*itb_cur))%modulo ;
if (ita_cur==ita_begin)
break;
}
new_coord.push_back(smod(res,modulo));
}
else {
longlong res=0;
for (;itb_cur!=itb_end;--ita_cur,++itb_cur) {
res += *ita_cur * longlong(*itb_cur) ;
if (ita_cur==ita_begin)
break;
}
new_coord.push_back(smod(res,modulo));
}
}
--ita;
++itb;
for ( ; itb!=itb_end;++itb){
vector::const_iterator ita_cur=ita,itb_cur=itb;
if (large){
int res=0;
for (;;) {
res = (res + *ita_cur * longlong(*itb_cur))%modulo ;
if (ita_cur==ita_begin)
break;
--ita_cur;
++itb_cur;
if (itb_cur==itb_end)
break;
}
new_coord.push_back(smod(res,modulo));
}
else {
longlong res= 0;
for (;;) {
res += *ita_cur * longlong(*itb_cur) ;
if (ita_cur==ita_begin)
break;
--ita_cur;
++itb_cur;
if (itb_cur==itb_end)
break;
}
new_coord.push_back(smod(res,modulo));
}
}
}
#if 0
static void smallmult1(const vector< T_unsigned > & p,const vector< T_unsigned > & q,vector< T_unsigned