sqrtmod;
#endif
int bmodp=p-modulo(*b._ZINTptr,p);
if (inva){
if (p<=37000){
// sqrtm<=p/2, bmodproot1=(M+(bmodp+sqrtm)*inva) % p;
basisptr->root2=(M+(bmodp+p-sqrtm)*inva) % p;
continue;
}
#ifdef _I386_
register int q=M;
addmultmod(q,bmodp+sqrtm,inva,p);
basisptr->root1=q;
q=M;
addmultmod(q,bmodp+p-sqrtm,inva,p);
basisptr->root2=q;
#else
basisptr->root1=(M+longlong(bmodp+sqrtm)*inva) % p;
basisptr->root2=(M+longlong(bmodp+p-sqrtm)*inva) % p;
#endif
continue;
}
int cmodp=modulo(zq,p);
int q=(M+longlong(cmodp)*invmodnoerr((2*bmodp)%p,p))%p;
if (q<0)
q+=p;
basisptr->root2=q;
basisptr->root1=q;
}
#ifdef WITH_INVA
#ifdef PRIMES32
if (afact>afact0){
int * bainv2ptr=&bainv2.front();
basis_t * basisptr,*basisend=&basis.front()+bs;
for (int j=1;j::const_iterator invait=Inva.begin();
for (basisptr=&basis.front();basisptrp;
if (r<0)
r += basisptr->p;
*bainv2ptr=r;
}
}
else {
// longlong up1=up1tmp[2*j];
// longlong tmp=up1tmp[2*j+1];
// tmp is <= P^2 where P is the largest factor of a
mpz_t & bz=*bvalues[j]._ZINTptr;
vector::const_iterator invait=Inva.begin();
for (basisptr=&basis.front();basisptrp;
*bainv2ptr=((modulo(bz,p))*longlong(2*(*invait))) % p;
}
}
}
}
#endif // PRIMES32
#endif // WITH_INVA
#ifdef LP_SMALL_PRIMES // copy primes<2^16 into small_basis
copy(basis,small_basis);
#endif
}
// find relations using (a*x+b)^2=a*(a*x^2+b*x+c) mod n where
// we sieve on [-M,M] for as many polynomials as required
// a is a square, approx sqrt(2*n)/M, and n is a square modulo all primes dividing a
// b satisifies b^2=n mod a (b in [0,a[)
// c=(n-b^2)/a
bool msieve(const gen & n_orig,gen & pn,GIAC_CONTEXT){
if (n_orig.type!=_ZINT)
return false;
// find multiplier
double delta;
int multiplier=find_multiplier(n_orig,delta,contextptr);
gen N(multiplier*n_orig);
double Nd=evalf_double(N,1,contextptr)._DOUBLE_val;
#if defined RTOS_THREADX || defined NSPIRE
if (Nd>1e40) return false;
#endif
#ifdef BESTA_OS
if (Nd>1e40) return false;
#endif
#ifdef PRIMES32
if (Nd>1e76) return false;
#else
if (Nd>1e63) return false;
#endif
int Ndl=int(std::log10(Nd)-std::log10(double(multiplier))+.5); // +2*delta);
#ifdef LP_TAB_SIZE
int slicesize=(1 << LP_TAB_SIZE);
#else
int slicesize=(QS_SIZE>=65536 && Ndl<61)?32768:QS_SIZE;
#endif
double B=std::exp(std::sqrt(2.0)/4*std::sqrt(std::log(Nd)*std::log(std::log(Nd))))*0.45;
if (B<200) B=200;
int pos1=70,pos0=23,afact=2,afixed=0; // pos position in the basis, afact number of factors
// FIXME Will always include the 3 first primes of the basis
// set a larger Mtarget gives less polynomials but also use less memory
#if defined(RTOS_THREADX) || defined(RTOS_THREADX) || defined NSPIRE
double Mtarget=0.95e5;
if (Nd>1e36)
Mtarget=1.2e5;
#else
double Mtarget=0.55e5;
#ifndef USE_MORE_PRIMES // FIXME improve! in fact use more primes on Core, less on Opteron
if (Ndl>=50){
Ndl-=50;
short int Btab[]={
// 50
1900,2100,2300,2500,2700,2900,3100,3400,3700,4000,
// 60
4300,4600,4900,5300,5700,6200,6800,7500,8300,9200,
// 70
10000,11000,12000,13000,14000,15000,16000
};
if (Ndl7)
Mtarget=0.95e5;
if (Ndl>11)
Mtarget=1.3e5;
if (Ndl>15)
Mtarget=1.6e5;
if (Ndl>19)
Mtarget=1.92e5;
}
#else
if (Ndl>=50)
Mtarget=0.85e5;
if (Ndl>65)
Mtarget=1.3e5;
#endif
#endif
if (debug_infolevel)
*logptr(contextptr) << "" << CLOCK() << gettext(" sieve on ") << N << endl << gettext("Number of primes ") << B << endl;
// first compute the prime basis and sqrt(N) mod p, p in basis
vector basis;
basis.reserve(unsigned(B));
#ifdef SQRTMOD_OUTSIDE
vector sqrtmod;
sqrtmod.reserve(basis.capacity());
basis.push_back(2);
sqrtmod.push_back(1);
#else
basis.push_back(basis_t(2,1)); // I assume that N is odd... hence has sqrt 1 mod 2
#endif
N.uncoerce();
// vector N256;
int i;
mpz_t zx,zy,zq,zr;
mpz_init(zx); mpz_init(zy); mpz_init(zq); mpz_init(zr);
// fastsmod_prepare(N,zx,zy,zr,N256);
for (i=1;i6 && (i%500==99))
*logptr(contextptr) << CLOCK() << gettext(" sieve current basis size ") << basis.size() << endl;
#if 1 // def USE_GMP_REPLACEMENTS
// int n=fastsmod_compute(N256,j);
int n=modulo(*N._ZINTptr,j),s;
#else
int n=smod(N,j).val,s;
#endif
if (n<0)
n+=j;
if (n==0){
#ifdef SQRTMOD_OUTSIDE
basis.push_back(j);
sqrtmod.push_back(0);
#else
basis.push_back(basis_t(j,0));
#endif
}
else {
if (powmod(n,(unsigned long)((j-1)/2),(int)j)==1){
s=sqrt_mod(n,int(j),true,contextptr).val;
if (s<0)
s+=j;
#ifdef SQRTMOD_OUTSIDE
basis.push_back(j);
sqrtmod.push_back(s);
#else
basis.push_back(basis_t(j,s));
#endif
}
}
if (basis.size()>=B)
break;
}
vector crible;
int jp=0;
if (basis.size() 2^16 in the basis
for (;basis.size()65535){
break;
}
#endif
if (debug_infolevel>6 && (i%500==99))
*logptr(contextptr) << CLOCK() << gettext(" sieve current basis size ") << basis.size() << endl;
#if 1 // def USE_GMP_REPLACEMENTS
// int n=fastsmod_compute(N256,jp);
int n=modulo(*N._ZINTptr,jp),s;
#else
int n=smod(N,jp).val,s;
#endif
if (n<0)
n+=jp;
if (powmod(n,(unsigned long)((jp-1)/2),jp)==1){
s=sqrt_mod(n,jp,true,contextptr).val;
if (s<0)
s += jp;
#ifdef LP_TAB_SIZE
if (!lp_basis_pos && jp> (1< small_basis(lp_basis_pos); // will be filled by primes<2^16
#endif
#ifdef TIMEOUT
control_c();
#endif
if (ctrl_c || interrupted){
mpz_clear(zx); mpz_clear(zy); mpz_clear(zq); mpz_clear(zr);
return false;
}
double dtarget=1.1;
if (Mtarget>16))*basis.back().p*ps;
#else
unsigned maxadditional=3*basis.back().p*ps;
#endif
if (debug_infolevel)
*logptr(contextptr) << CLOCK() << gettext(" sieve basis OK, size ") << basis.size() << " largest prime in basis " << basis.back().p << " large prime " << maxadditional << " Mtarget " << Mtarget << endl ;
int bs=int(basis.size());
gen isqrtN=isqrt(N);
isqrtN.uncoerce();
// now compare isqrtN to a^2 for a in the basis
double seuil=1.414*evalf_double(isqrtN,1,contextptr)._DOUBLE_val/Mtarget; // should be a
seuil=std::sqrt(seuil); // should be product of primes of the basis
#ifdef OLD_AFACT
double dfactors=std::log10(seuil)/3;
// fixed primes are choosen at basis[pos0], variables are choosen around 2000
afact=int(dfactors+.5);
if (afact<=1){
afact=1;
int i=20;
for (;i<3*bs/4;++i){
if (seuil=3*bs/4){
afact=2;
for (;i<3*bs/4;++i){
if (seuil=3,
if (dfactors>5.4){
dfactors -= 3; // 3 large primes
afixed = dfactors/.8; // at least 3 fixed
afact = 3 + afixed;
}
else {
dfactors -= 2; // 2 large primes
afixed = dfactors/.8;
if (afixed==0)
afixed=1;
afact = 2 +afixed;
}
for (int i=0;iafact){
afixed=i;
afact=i+ivariable;
curseuil=seuiltest;
}
}
}
for (int i=0;i isqrtN256;
// fastsmod_prepare(isqrtN,zx,zy,zr,isqrtN256);
vector isqrtNmodp(bs);
for (int i=0;i axbmodn; // contains (sqrta,b,x)
vector additional_primes;
#ifndef ADDITIONAL_PRIMES_HASHMAP
vector additional_primes_twice;
#endif
#ifdef LP_TAB_SIZE
vector lp_map(128); // at most 128 slices in a sieve
#endif
vecteur sqrtavals,bvals;
#ifdef GIAC_ADDITIONAL_PRIMES
#ifdef ADDITIONAL_PRIMES_HASHMAP
#ifdef EMCC
additional_map_t additional_primes_map;
#else
additional_map_t additional_primes_map(8*bs);
#endif
axbmodn.reserve(bs);
#else
#if defined(RTOS_THREADX) || defined(BESTA_OS) || defined NSPIRE
additional_primes.reserve(bs);
additional_primes_twice.reserve(bs);
axbmodn.reserve(2*bs);
#else
additional_primes.reserve(4*bs);
additional_primes_twice.reserve(4*bs);
axbmodn.reserve(5*bs);
#endif
sqrtavals.reserve(bs/7);
bvals.reserve(2*bs/7);
#endif // ADDITIONAL_PRIMES_HASHMAP
#else // GIAC_ADDITIONAL_PRIMES
axbmodn.reserve(bs+1);
#endif
// now sieve
unsigned todo_rel;
unsigned marge=bs/100;
if (marge<15)
marge=15;
mpz_t alloc1,alloc2,alloc3,alloc4,alloc5;
mpz_init(alloc1); mpz_init(alloc2); mpz_init(alloc3); mpz_init(alloc4); mpz_init(alloc5);
// vector a256,b256,tmpv;
vector curpuissances,recheck,pos(afact);
#ifdef WITH_INVA
vector Inva(bs);
#endif
vecteur bvalues; // will contain values of b if afact<=afact0 or components of b if afact>afact0
// array for efficient polynomial switch (same a change b) when at least afact0 factors/a
#ifdef PRIMES32
const int afact0=3;
vector bainv2((afact-1)*bs);
vector up1tmp;
#endif
for (int i=0;i1)
end_pos1=pos1+100;
if (avar>2)
end_pos1=pos1+30;
if (int(lp_basis_pos)=end_pos1 || basis[pos.back()].p>=45000){
int i=afact-2;
for (;i>afixed;--i){
if (int(pos[i])=3, so that we can move pos[1] by thread
while (Mval>1.1*Mtarget && int(pos[afixed-1])10){
// Mval is too small, decrease one factor of a
--pos[0];
if (pos[0]<=10){
Mval=0;
break;
}
double coeff=basis[pos[0]].p/double(basis[pos[0]+1].p);
Mval=Mval/(coeff*coeff);
}
}
if ( Mval <0.7*Mtarget ){
if (pos1>pos0+afixed+5 || Mval<32768){
// CERR << pos ;
int i=afact-1;
for (;i>afixed+1;--i){
if (pos[i]>pos[i-1]+5)
break;
}
if (i<=afixed+1){
--pos1;
for (i=0;i=todo_rel)
break;
int nrelationsa=0;
// Not finished yet, construct a new value of a around ad=sqrt(2*n)/M
// using a product of afact square of primes that are in the basis
// and construct a vector of 2^(afact-1) corresponding values of b
// and compute the values of inverses of a mod p
ulonglong usqrta(basis[pos[0]].p);
for (int i=1;i6)
*logptr(contextptr) << CLOCK() << gettext(" initial value for M= ") << M << endl;
int nslices=int(std::ceil((2.*M)/slicesize));
M=(nslices*slicesize)/2;
bvalues.clear();
gen curprod=1;
for (int i=0;;){
#ifdef SQRTMOD_OUTSIDE
int s=sqrtmod[pos[i]];
#else
int s=basis[pos[i]].sqrtmod;
#endif
int p=basis[pos[i]].p;
longlong p2=p*longlong(p);
// Hensel lift s to be a sqrt of n mod p^2: (s+p*r)^2=s^2+2p*r*s=n => r=(n-s^2)/p*inv(2*s mod p)
int r=p<37000?int((modulo(*N._ZINTptr,p2)-s*s)/p):((smod(N,p2)-s*s)/p).val;
r=(r*invmod(2*s,p))%p;
// overflow should not happen because p is a factor of a hence choosen
// in the 1000 range (perhaps up to 10 000, but not much larger)
// if ((longlong(r)*p)!=r*p) CERR << "overflow" << endl;
s += p*r;
#ifdef PRIMES32
if (afact>afact0){
// store s*(inv( product(basis[pos[j]]^2,j!=i) mod p2)) in bvalues[i]
longlong up1=(usqrta/p);
longlong up=up1%p2;
up=(up*up)%p2;
//longlong tmp=(s*invmodnoerr(up,p2))%p2;
//up1tmp.push_back(up1);
//up1tmp.push_back(tmp);
gen tmp=smod(s*invmod(gen(up),gen(p2)),p2);
if (is_greater(0,tmp,contextptr)) tmp=-tmp;
gen gup1(up1);
bvalues.push_back(gup1*gup1*tmp);
bvalues.back().uncoerce();
}
else
#endif
{
if (bvalues.empty())
bvalues.push_back(s);
else {
int js=int(bvalues.size());
for (int j=0;j6)
*logptr(contextptr) << CLOCK() << gettext(" Computing inverses mod p of the basis ") << endl;
// fastsmod_prepare(a,zx,zy,zr,a256);
gen b;
for (int i=0;i< (1<<(afact-1));++i){
#ifdef TIMEOUT
control_c();
#endif
if (ctrl_c || interrupted)
break;
#ifdef ADDITIONAL_PRIMES_HASHMAP
todo_rel=bs+marge;
#else
todo_rel=bs+marge+unsigned(additional_primes.size());
#endif
if (axbmodn.size()>=todo_rel)
break;
if (debug_infolevel>6)
*logptr(contextptr) << CLOCK() << gettext(" Computing c ") << endl;
#ifdef PRIMES32
int bv=1,be=-1;
if (afact>afact0){
if (i==0){
b=0;
for (unsigned j=0;j6)
*logptr(contextptr) << CLOCK() << gettext(" Computing roots mod the basis ") << endl;
// fastsmod_prepare(b,zx,zy,zr,b256);
#ifdef PRIMES32
if (i && afact>afact0)
switch_roots(bainv2,basis,
#ifdef LP_SMALL_PRIMES
small_basis,
#endif
lp_basis_pos,nslices,slicesize,bv,be,afact,pos,b,zq,M);
else {
init_roots(basis,
#ifdef LP_SMALL_PRIMES
small_basis,
#endif
#ifdef WITH_INVA
Inva,
#endif
#ifdef SQRTMOD_OUTSIDE
sqrtmod,
#endif
bainv2,afact,afact0,
a,b,bvalues,zq,M);
#ifdef LP_TAB_TOGETHER
// init all hashtable for large primes at once
unsigned cl;
if (debug_infolevel>3){
cl=CLOCK();
*logptr(contextptr) << cl << gettext(" Init large prime hashtables ") << endl;
}
int total=(nslices << (afact-1));
if (int(lp_map.size()) < total)
lp_map.resize(total);
for (int k=0;k< total;++k)
lp_map[k].clear();
if (lp_basis_pos){
for (int k=0;;){
basis_t * bit=&basis[lp_basis_pos], * bitend=&basis[0]+bs;
unsigned endpos=nslices*slicesize;
lp_tab_t * ptr=&lp_map[0]+k*nslices;
for (;bit!=bitend;++bit){
register ushort_t p=bit->p;
register unsigned pos=bit->root1;
for (;pos> LP_TAB_SIZE))->push_back(lp_entry_t((pos & LP_MASK),p));
}
pos=bit->root2;
for (;pos> LP_TAB_SIZE))->push_back(lp_entry_t((pos & LP_MASK),p));
}
}
++k;
if (k== (1 << (afact-1))){
if (debug_infolevel>3){
unsigned cl2=CLOCK();
*logptr(contextptr) << cl2 << gettext(" End large prime hashtables ") << cl2-cl << endl;
}
break;
}
find_bv_be(k,bv,be);
// switch roots to next polynomial
int * bvpos=&bainv2[(bv-1)*bs],* bvposend=bvpos+bs;
bvpos += lp_basis_pos;
basis_t * basisptr=&basis[lp_basis_pos];
if (be>0){
for (;bvposp;
register int r=basisptr->root1-(*bvpos);
if (r<0)
r+=p;
basisptr->root1=r;
r=basisptr->root2-(*bvpos);
if (r<0)
r+=p;
basisptr->root2=r;
}
}
else {
for (;bvposp;
register int r=basisptr->root1+(*bvpos);
if (r>int(p))
r-=p;
basisptr->root1=r;
r=basisptr->root2+(*bvpos);
if (r>int(p))
r-=p;
basisptr->root2=r;
}
}
}
}
#endif // LP_TAB_TOGETHER
} // end else of if i==0
#if defined(LP_TAB_SIZE) && !defined(LP_TAB_TOGETHER)
if (int(lp_map.size()) < nslices)
lp_map.resize(nslices);
for (int k=0;k< nslices;++k)
lp_map[k].clear();
if (lp_basis_pos){
basis_t * bit=&basis[lp_basis_pos], * bitend=&basis[0]+bs;
unsigned endpos=nslices*slicesize;
for (;bit!=bitend;++bit){
register ushort_t p=bit->p;
register unsigned pos=bit->root1;
for (;pos> LP_TAB_SIZE].push_back(lp_entry_t((pos & LP_MASK),p));
}
pos=bit->root2;
for (;pos> LP_TAB_SIZE].push_back(lp_entry_t((pos & LP_MASK),p));
}
}
}
#endif // LP_TAB_SIZE && !LP_TAB_TOGETHER
#else // PRIMES32
init_roots(basis,
#ifdef WITH_INVA
Inva,
#endif
#ifdef SQRTMOD_OUTSIDE
sqrtmod,
#endif
usqrta,a,b,bvalues,zq,M);
#endif // PRIMES32
// we can now sieve in [-M,M[ by slice of size slicesize
#ifndef GIAC_HAS_STO_38
if (debug_infolevel>5){
*logptr(contextptr) << CLOCK();
*logptr(contextptr) << gettext(" Polynomial a,b,M=") << a << "," << b << "," << M << " (" << pos << ")" ;
*logptr(contextptr) << CLOCK() << endl;
}
#endif
int nrelationsb=0;
#ifdef LP_TAB_SIZE
#endif
for (int l=0;l=todo_rel)
break;
int shift=-M+l*slicesize;
int slicerelations=msieve(a,sqrtavals,
bvals,zq,basis,lp_basis_pos,
#ifdef LP_SMALL_PRIMES
small_basis,
#endif
maxadditional,
#ifdef ADDITIONAL_PRIMES_HASHMAP
additional_primes_map,
#else
additional_primes,additional_primes_twice,
#endif
N,isqrtN,
slice,slicesize,shift,puissancestab,puissancesptr,puissancesend,curpuissances,recheck,
axbmodn,
zx,zy,zr,alloc1,alloc2,alloc3,alloc4,alloc5,
#ifdef LP_TAB_SIZE
#ifdef LP_TAB_TOGETHER
lp_map[l+nslices*i],
#else
lp_map[l],
#endif
#endif
contextptr);
if (slicerelations==-1){
*logptr(contextptr) << gettext("Sieve error: Not enough memory ") << endl;
break;
}
nrelationsb += slicerelations;
#ifdef ADDITIONAL_PRIMES_HASHMAP
todo_rel=bs+marge;
#else
todo_rel=bs+marge+unsigned(additional_primes.size());
#endif
}
if (nrelationsb==0)
bvals.pop_back();
else
nrelationsa += nrelationsb;
}
#if defined( RTOS_THREADX) || defined(BESTA_OS) || defined NSPIRE
if (debug_infolevel){
#ifdef NSPIRE
static int count_print=0;
++count_print;
if (count_print%4==0)
#endif
*logptr(contextptr) << axbmodn.size() << " of " << todo_rel << " (" << 100-100*(todo_rel-axbmodn.size())/double(bs+marge) << "%)" << endl;
}
#endif
if (nrelationsa==0){
sqrtavals.pop_back();
}
#if !defined(RTOS_THREADX) && !defined(BESTA_OS) && !defined NSPIRE
if (debug_infolevel>1)
*logptr(contextptr) << CLOCK()<< gettext(" sieved : ") << axbmodn.size() << " of " << todo_rel << " (" << 100-100*(todo_rel-axbmodn.size())/double(bs+marge) << "%), M=" << M << endl;
#endif
} // end sieve loop
if (debug_infolevel)
*logptr(contextptr) << gettext("Polynomials a,b in use: #a ") << sqrtavals.size() << " and #b " << bvals.size() << endl;
delete [] slice;
#ifdef TIMEOUT
control_c();
#endif
if (ctrl_c || interrupted || puissancesptr==puissancesend){
mpz_clear(zx); mpz_clear(zy); mpz_clear(zq); mpz_clear(zr);
mpz_clear(alloc1); mpz_clear(alloc2); mpz_clear(alloc3); mpz_clear(alloc4); mpz_clear(alloc5);
delete [] puissancestab;
return false;
}
// We have enough relations, make matrix, reduce it then find x^2=y^2 mod n congruences
if (debug_infolevel)
*logptr(contextptr) << CLOCK() << gettext(" sieve done: used ") << (puissancesptr-puissancestab)*0.002 << " K for storing relations (of " << puissancestablength*0.002 << ")" << endl;
release_memory(isqrtNmodp);
#ifdef GIAC_ADDITIONAL_PRIMES
#ifdef ADDITIONAL_PRIMES_HASHMAP
additional_primes.reserve(axbmodn.size());
vector::const_iterator it=axbmodn.begin(),itend=axbmodn.end();
for (;it!=itend;++it) {
unsigned u=largep(*it,puissancestab);
if (u)
additional_primes.push_back(u);
}
sort(additional_primes.begin(),additional_primes.end()); // for binary search later
#else
if (debug_infolevel)
*logptr(contextptr) << CLOCK() << gettext(" removing additional primes") << endl;
// remove relations with additional primes which are used only once
int lastp=int(axbmodn.size())-1,lasta=int(additional_primes.size())-1;
for (int i=0;i<=lastp;++i){
ushort_t * curbeg=puissancestab+axbmodn[i].first, * curend=puissancestab+axbmodn[i].second;
bool done=false;
for (;curbeg!=curend;++curbeg){
if (*curbeg==1)
break;
}
if (curbeg==curend)
continue;
++curbeg;
additional_t u=*curbeg;
#if GIAC_ADDITIONAL_PRIMES==32 && !defined(PRIMES32)
u <<=16 ;
++curbeg;
u += *curbeg;
#endif
int pos=_equalposcomp(additional_primes,u);
if (!pos)
continue;
if (pos>lasta){
// *logptr(contextptr) << cur << endl;
continue;
}
--pos;
if (additional_primes_twice[pos])
continue;
axbmodn[i]=axbmodn[lastp];
--lastp;
additional_primes[pos]=additional_primes[lasta];
additional_primes_twice[pos]=additional_primes_twice[lasta];
--lasta;
--i; // recheck at current index
}
axbmodn.resize(lastp+1);
additional_primes.resize(lasta+1);
if (debug_infolevel)
*logptr(contextptr) << CLOCK() << gettext(" end removing additional primes") << endl;
#endif // ADDTIONAL_PRIMES_HASHMAP
#endif // GIAC_ADDITIONAL_PRIMES
// Make relations matrix (currently dense, FIXME improve to sparse and Lanczos algorithm)
int C32=int(std::ceil(axbmodn.size()/32./GIAC_RREF_UNROLL))*GIAC_RREF_UNROLL;
unsigned * tab=new unsigned[axbmodn.size()*C32],*tabend=tab+axbmodn.size()*C32;
if (!tab){
mpz_clear(zx); mpz_clear(zy); mpz_clear(zq); mpz_clear(zr);
mpz_clear(alloc1); mpz_clear(alloc2); mpz_clear(alloc3); mpz_clear(alloc4); mpz_clear(alloc5);
delete [] puissancestab;
return false;
}
// init tab
for (unsigned * ptr=tab;ptr!=tabend;++ptr)
*ptr=0;
int l32=C32*32;
vector< line_t > relations(axbmodn.size());
for (unsigned i=0;i2){
cout << i << ", p=";
if (i==0)
cout << "-1";
else {
if (i<=bs)
cout << basis[i-1].p << " " << relations[i].count << endl;
else
cout << endl;
}
}
}
if (debug_infolevel)
*logptr(contextptr) << CLOCK() << " begin rref size " << relations.size() << "x" << l32 << " K " << 0.004*relations.size()*C32 << ", " << count0 << " null lines, " << count1 << " 1-line" << endl;
#if 0 // debug only
for (int i=0;i relations2(l32);
i=0;
int j=0,rs=int(relations.size());
for (;i p(bs), add_p(additional_primes.size());
for (int j=0;j=sqrtavals.size() || axbmodn[j].bindex>=bvals.size())
return false; // check added because ifactor(nextprime(alog10(17))*nextprime(alog10(19))); fails on Prime (and unable to do parallel debug in giac)
update_xy(axbmodn[j],zx,zy,p,add_p,N,basis,additional_primes,sqrtavals,bvals,puissancestab,zq,zr,alloc1,alloc2,alloc3,alloc4,alloc5);
#ifdef ADDITIONAL_PRIMES_HASHMAP
unsigned u=largep(axbmodn[j],puissancestab);
if (u)
update_xy(additional_primes_map[u],zx,zy,p,add_p,N,basis,additional_primes,sqrtavals,bvals,puissancestab,zq,zr,alloc1,alloc2,alloc3,alloc4,alloc5);
#endif
} // end if (j6)
*logptr(contextptr) << CLOCK() << gettext("checking gcd") << cur << " " << N << endl;
if ( (cur.type==_INT_ && cur.val>7) ||
(cur.type==_ZINT && is_strictly_greater(n_orig,cur,contextptr))){
pn=cur;
mpz_clear(zx); mpz_clear(zy); mpz_clear(zq); mpz_clear(zr);
mpz_clear(alloc1); mpz_clear(alloc2); mpz_clear(alloc3); mpz_clear(alloc4); mpz_clear(alloc5);
delete [] puissancestab;
delete [] tab;
return true;
}
}
mpz_clear(zx); mpz_clear(zy); mpz_clear(zq); mpz_clear(zr);
mpz_clear(alloc1); mpz_clear(alloc2); mpz_clear(alloc3); mpz_clear(alloc4); mpz_clear(alloc5);
delete [] puissancestab;
delete [] tab;
return false;
}
// Pollard-rho algorithm
const int POLLARD_GCD=64;
#ifdef GIAC_MPQS
#if defined(RTOS_THREADX) // !defined(BESTA_OS)
const int POLLARD_MAXITER=3000;
#else
const int POLLARD_MAXITER=15000;
#endif
#else
const int POLLARD_MAXITER=15000;
#endif
static gen pollard(gen n, gen k,GIAC_CONTEXT){
k.uncoerce();
n.uncoerce();
int maxiter=POLLARD_MAXITER;
double nd=evalf_double(n,1,contextptr)._DOUBLE_val;
#if defined(RTOS_THREADX) || defined(BESTA_OS) || defined NSPIRE
int nd1=int(2000*(std::log10(nd)-34));
#else
int nd1=int(1500*std::pow(16.,(std::log10(nd)-40)/10));
#endif
if (nd1>maxiter)
maxiter=nd1;
int m,m1,a,a1,j;
m1=m=2;
a1=a=1;
int c=0;
mpz_t g,x,x1,x2,x2k,y,y1,p,q,tmpq,alloc1,alloc2,alloc3,alloc4,alloc5;
mpz_init_set_si(g,1); // ? mp_init_size to specify size
mpz_init_set_si(x,2);
mpz_init_set_si(x1,2);
mpz_init_set_si(y,2);
mpz_init(y1);
mpz_init(x2);
mpz_init(x2k);
mpz_init_set_si(p,1);
mpz_init(q);
mpz_init(tmpq);
mpz_init(alloc1);
mpz_init(alloc2);
mpz_init(alloc3);
mpz_init(alloc4);
mpz_init(alloc5);
while (!ctrl_c && !interrupted && mpz_cmp_si(g,1)==0) {
#ifdef TIMEOUT
control_c();
#endif
a=2*a+1;//a=2^(e+1)-1=2*l(m)-1
while (!ctrl_c && !interrupted && mpz_cmp_si(g,1)==0 && a>m) { // ok
#ifdef TIMEOUT
control_c();
#endif
// x=f(x,k,n,q);
#ifdef USE_GMP_REPLACEMENTS
mp_sqr(&x,&x2);
mpz_add(x2k,x2,*k._ZINTptr);
if (mpz_cmp(x2k,*n._ZINTptr)>0){
mp_grow(&alloc1,x2k.used+2);
mpz_set_ui(alloc1,0);
alloc1.used = x2k.used +2 ;
mpz_set(alloc2,x2k);
mpz_set(alloc3,*n._ZINTptr);
// mpz_set_si(alloc4,0);
// mpz_set_si(alloc5,0);
alloc_mp_div(&x2k,n._ZINTptr,&tmpq,&x,&alloc1,&alloc2,&alloc3,&alloc4,&alloc5);
}
else
mpz_set(x,x2k);
#else
mpz_mul(x2,x,x);
mpz_add(x2k,x2,*k._ZINTptr);
mpz_tdiv_r(x,x2k,*n._ZINTptr);
#endif
m += 1;
if (debug_infolevel && ((m %
#if defined(RTOS_THREADX) || defined(BESTA_OS) || defined NSPIRE
(1<<10)
#else
(1<<18)
#endif
)==0))
*logptr(contextptr) << CLOCK() << gettext(" Pollard-rho try ") << m << endl;
if (m > maxiter ){
if (debug_infolevel)
*logptr(contextptr) << CLOCK() << gettext(" Pollard-rho failure, ntries ") << m << endl;
mpz_clear(alloc5);
mpz_clear(alloc4);
mpz_clear(alloc3);
mpz_clear(alloc2);
mpz_clear(alloc1);
mpz_clear(tmpq);
mpz_clear(x);
mpz_clear(x1);
mpz_clear(x2);
mpz_clear(x2k);
mpz_clear(y);
mpz_clear(y1);
mpz_clear(p);
mpz_clear(q);
return -1;
}
// p=irem(p*(x1-x),n,q);
mpz_sub(q,x1,x);
mpz_mul(x2,p,q);
#if 0 // def USE_GMP_REPLACEMENTS
if (mpz_cmp(x2,*n._ZINTptr)>0){
mp_grow(&alloc1,x2.used+2);
mpz_set_ui(alloc1,0);
alloc1.used = x2.used +2 ;
mpz_set(alloc2,x2);
mpz_set(alloc3,*n._ZINTptr);
// mpz_set_si(alloc4,0);
// mpz_set_si(alloc5,0);
alloc_mp_div(&x2,n._ZINTptr,&tmpq,&p,&alloc1,&alloc2,&alloc3,&alloc4,&alloc5);
}
else
mpz_set(p,x2);
#else
mpz_tdiv_r(p,x2,*n._ZINTptr);
#endif
c += 1;
if (c==POLLARD_GCD) {
// g=gcd(abs(p,context0),n);
mpz_abs(q,p);
my_mpz_gcd(g,q,*n._ZINTptr);
if (mpz_cmp_si(g,1)==0) {
mpz_set(y,x); // y=x;
mpz_set(y1,x1); // y1=x1;
mpz_set_si(p,1); // p=1;
a1=a;
m1=m;
c=0;
}
}
}//m=a=2^e-1=l(m)
if (mpz_cmp_si(g,1)==0) {
mpz_set(x1,x); // x1=x;//x1=x_m=x_l(m)-1
j=3*(a+1)/2; // j=3*iquo(a+1,2);
for (long i=m+1;i<=j;i++){
// x=f(x,k,n,q);
mpz_mul(x2,x,x);
mpz_add(x2k,x2,*k._ZINTptr);
#if 0 // def USE_GMP_REPLACEMENTS
if (mpz_cmp(x2k,*n._ZINTptr)>0){
mp_grow(&alloc1,x2k.used+2);
mpz_set_ui(alloc1,0);
alloc1.used = x2k.used +2 ;
mpz_set(alloc2,x2k);
mpz_set(alloc3,*n._ZINTptr);
// mpz_set_si(alloc4,0);
// mpz_set_si(alloc5,0);
alloc_mp_div(&x2k,n._ZINTptr,&tmpq,&x,&alloc1,&alloc2,&alloc3,&alloc4,&alloc5);
}
else
mpz_set(x,x2);
#else
mpz_tdiv_r(x,x2k,*n._ZINTptr);
#endif
}
m=j;
}
}
//g<>1 ds le paquet de POLLARD_GCD
if (debug_infolevel>5)
CERR << CLOCK() << " Pollard-rho nloops " << m << endl;
mpz_set(x,y); // x=y;
mpz_set(x1,y1); // x1=y1;
mpz_set_si(g,1); // g=1;
a=(a1-1)/2; // a=iquo(a1-1,2);
m=m1;
while (!ctrl_c && !interrupted && mpz_cmp_si(g,1)==0) {
#ifdef TIMEOUT
control_c();
#endif
a=2*a+1;
while (!ctrl_c && !interrupted && mpz_cmp_si(g,1)==0 && a>m) { // ok
#ifdef TIMEOUT
control_c();
#endif
// x=f(x,k,n,q);
mpz_mul(x2,x,x);
mpz_add(x2k,x2,*k._ZINTptr);
#if 0 // def USE_GMP_REPLACEMENTS
if (mpz_cmp(x2k,*n._ZINTptr)>0){
mp_grow(&alloc1,x2k.used+2);
mpz_set_ui(alloc1,0);
alloc1.used = x2k.used +2 ;
mpz_set(alloc2,x2k);
mpz_set(alloc3,*n._ZINTptr);
alloc_mp_div(&x2k,n._ZINTptr,&tmpq,&x,&alloc1,&alloc2,&alloc3,&alloc4,&alloc5);
}
else
mpz_set(x,x2k);
#else
mpz_tdiv_r(x,x2k,*n._ZINTptr);
#endif
m += 1;
if (m > maxiter ){
mpz_clear(alloc5);
mpz_clear(alloc4);
mpz_clear(alloc3);
mpz_clear(alloc2);
mpz_clear(alloc1);
mpz_clear(tmpq);
mpz_clear(x);
mpz_clear(x1);
mpz_clear(x2);
mpz_clear(x2k);
mpz_clear(y);
mpz_clear(y1);
mpz_clear(p);
mpz_clear(q);
return -1;
}
// p=irem(x1-x,n,q);
mpz_sub(q,x1,x);
#if 0 // def USE_GMP_REPLACEMENTS
if (mpz_cmp(q,*n._ZINTptr)>0){
mp_grow(&alloc1,q.used+2);
mpz_set_ui(alloc1,0);
alloc1.used = q.used +2 ;
mpz_set(alloc2,q);
mpz_set(alloc3,*n._ZINTptr);
// mpz_set_si(alloc4,0);
// mpz_set_si(alloc5,0);
alloc_mp_div(&q,n._ZINTptr,&tmpq,&p,&alloc1,&alloc2,&alloc3,&alloc4,&alloc5);
}
else
mpz_set(p,q);
#else
mpz_tdiv_r(p,q,*n._ZINTptr);
#endif
// g=gcd(abs(p,context0),n); // ok
mpz_abs(q,p);
my_mpz_gcd(g,q,*n._ZINTptr);
}
if (mpz_cmp_si(g,1)==0) {
mpz_set(x1,x); // x1=x;
j=3*(a+1)/2; // j=3*iquo(a+1,2);
for (long i=m+1;j>=i;i++){
// x=f(x,k,n,q);
mpz_mul(x2,x,x);
mpz_add(x2k,x2,*k._ZINTptr);
mpz_tdiv_qr(tmpq,x,x2k,*n._ZINTptr);
}
m=j;
}
}
mpz_clear(alloc5);
mpz_clear(alloc4);
mpz_clear(alloc3);
mpz_clear(alloc2);
mpz_clear(alloc1);
mpz_clear(tmpq);
mpz_clear(x);
mpz_clear(x1);
mpz_clear(x2);
mpz_clear(x2k);
mpz_clear(y);
mpz_clear(y1);
mpz_clear(p);
mpz_clear(q);
#ifdef TIMEOUT
control_c();
#endif
if (ctrl_c || interrupted){
mpz_clear(g);
return 0;
}
if (mpz_cmp(g,*n._ZINTptr)==0) {
if (k==1) {
mpz_clear(g);
return(pollard(n,-1,contextptr));
}
else {
if (k*k==1){
mpz_clear(g);
return(pollard(n,3,contextptr));
}
else {
if (is_greater(k,50,contextptr)){
#if 1
return -1;
#else
ref_mpz_t * ptr=new ref_mpz_t;
mpz_init_set(ptr->z,g);
mpz_clear(g);
return ptr;
#endif
}
else {
mpz_clear(g);
return(pollard(n,k+2,contextptr));
}
}
}
}
ref_mpz_t * ptr=new ref_mpz_t;
mpz_init_set(ptr->z,g);
mpz_clear(g);
return ptr;
}
// const short int giac_primes[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997};
bool eratosthene(double n,vector * & v){
static vector erato;
v=&erato;
if (n+1>erato.size()){
unsigned N=int(n);
++N;
#if defined BESTA_OS
if (N>2e6)
return false;
#else
if (N>2e9)
return false;
#endif
N = (N*11)/10;
erato=vector(N+1,true);
// insure that we won't recompute all again from start for ithprime(i+1)
for (unsigned p=2;;++p){
while (!erato[p]) // find next prime
++p;
if (p*p>N) // finished
return true;
for (unsigned i=2*p;i<=N;i+=p)
erato[i]=false; // remove p multiples
}
}
return true;
}
bool eratosthene2(double n,vector * & v){
static vector erato;
v=&erato;
if (n/2>=erato.size()){
unsigned N=int(n);
++N;
#if defined BESTA_OS
if (N>4e6)
return false;
#else
if (N>2e9)
return false;
#endif
// 11/20 insures that we won't recompute all again from start for ithprime(i+1)
N = (N*11)/20; // keep only odd numbers in sieve
erato=vector(N+1,true); //erato[i] stands for 2*i+1 <-> n corresponds to erato[n/2]
for (unsigned p=3;;p+=2){
while (!erato[p/2]) // find next prime (first one is p==3)
p+=2;
if (p*p>2*N+1) // finished
return true;
// p is prime, set p*p, (p+2)*p, etc. to be non prime
for (unsigned i=(p*p)/2;i<=N;i+=p)
erato[i]=false; // remove p multiples
}
}
return true;
}
// ithprime(n) is approx invli(n)+invli(sqrt(n))/4 where invli is reciproc.
// of Li(x)=Ei(ln(x))
// For fast code, cf. https://github.com/kimwalisch/primecount
static const char _ithprime_s []="ithprime";
static symbolic symb_ithprime(const gen & args){
return symbolic(at_ithprime,args);
}
static gen ithprime(const gen & g_,GIAC_CONTEXT){
gen g(g_);
if (!is_integral(g))
return gentypeerr(contextptr);
if (g.type!=_INT_)
return gensizeerr(contextptr); // symb_ithprime(g);
int i=g.val;
if (i<0)
return gensizeerr(contextptr);
if (i==0)
return 1;
if (i<=int(sizeof(giac_primes)/sizeof(short int)))
return giac_primes[i-1];
vector * vptr=0;
#if 1
if (!eratosthene2(i*std::log(double(i))*1.1,vptr))
return gensizeerr(contextptr);
unsigned count=2;
unsigned s=unsigned(vptr->size());
for (unsigned k=2;ksize();
for (unsigned k=4;k * vptr=0;
if (!eratosthene2(i+2,vptr))
return gensizeerr(contextptr);
unsigned count=1; // 2 is prime, then count odd primes
i=(i-1)/2;
for (int k=1;k<=i;++k){
if ((*vptr)[k])
++count;
}
return int(count);
}
gen _nprimes(const gen & args,GIAC_CONTEXT){
if ( args.type==_STRNG && args.subtype==-1) return args;
if (args.type==_VECT)
return apply(args,_nprimes,contextptr);
return nprimes(args,contextptr);
}
static define_unary_function_eval (__nprimes,&giac::_nprimes,_nprimes_s);
define_unary_function_ptr5( at_nprimes ,alias_at_nprimes,&__nprimes,0,true);
bool is_divisible_by(const gen & n,unsigned long a){
if (n.type==_ZINT){
#ifdef USE_GMP_REPLACEMENTS
mp_digit c;
mp_mod_d(n._ZINTptr, a, &c);
return c==0;
#else
return mpz_divisible_ui_p(*n._ZINTptr,a);
#endif
}
return n.val%a==0;
}
// find trivial factors of n,
// if add_last is true the remainder is put in the vecteur,
// otherwise n contains the remainder
vecteur pfacprem(gen & n,bool add_last,GIAC_CONTEXT){
gen a;
gen q;
int p,i,prime;
vecteur v(2);
vecteur u;
if (is_zero(n))
return u;
if (n.type==_ZINT){
ref_mpz_t * cur = new ref_mpz_t;
mpz_t div,q,r,alloc1,alloc2,alloc3,alloc4,alloc5;
mpz_set(cur->z,*n._ZINTptr);
mpz_init_set(q,*n._ZINTptr);
mpz_init(r);
mpz_init(div);
mpz_init(alloc1);
mpz_init(alloc2);
mpz_init(alloc3);
mpz_init(alloc4);
mpz_init(alloc5);
for (i=0;iz,1)==0)
break;
prime=giac_primes[i];
mpz_set_ui(div,prime);
#ifdef USE_GMP_REPLACEMENTS
for (p=0;;p++){
mp_grow(&alloc1,cur->z.used+2);
mpz_set_ui(alloc1,0);
alloc1.used = cur->z.used +2 ;
mpz_set(alloc2,cur->z);
mpz_set(alloc3,div);
alloc_mp_div(&cur->z,&div,&q,&r,&alloc1,&alloc2,&alloc3,&alloc4,&alloc5);
// mpz_tdiv_qr(q,r,cur->z,div);
if (mpz_cmp_si(r,0))
break;
mp_exch(&cur->z,&q);
}
// *logptr(contextptr) << "Factor " << prime << " " << p << endl;
if (p){
u.push_back(prime);
u.push_back(p);
}
#else
if (mpz_divisible_ui_p(cur->z,prime)){
mpz_set_ui(div,prime);
for (p=0;;p++){
mpz_tdiv_qr(q,r,cur->z,div);
if (mpz_cmp_si(r,0))
break;
mpz_swap(cur->z,q);
}
// *logptr(contextptr) << "Factor " << prime << " " << p << endl;
u.push_back(prime);
u.push_back(p);
}
#endif
} // end for on smal primes
mpz_clear(alloc5);
mpz_clear(alloc4);
mpz_clear(alloc3);
mpz_clear(alloc2);
mpz_clear(alloc1);
mpz_clear(div); mpz_clear(r); mpz_clear(q);
n=cur;
}
else {
for (i=0;iTerminal.MakeUnvisible();
#endif
#endif
return res;
}
#else // USE_GMP_REPLACEMENTS
static gen pollardsieve(const gen &a,gen k,bool & do_pollard,GIAC_CONTEXT){
gen b=do_pollard?pollard(a,k,contextptr):-1;
#ifdef TIMEOUT
control_c();
#endif
#ifdef GIAC_MPQS
if (b==-1 && !ctrl_c && !interrupted){
do_pollard=false;
if (msieve(a,b,contextptr)) return b; else return -1; }
#endif
if (b==-1)
b=a;
return b;
}
#endif // USE_GMP_REPLACEMENTS
static gen ifactor2(const gen & n,vecteur & v,bool & do_pollard,GIAC_CONTEXT){
if (is_greater(giac_last_prime*giac_last_prime,n,contextptr) || is_probab_prime_p(n) ){
v.push_back(n);
return 1;
}
// Check for power of integer: arg must be > 1e4, n*ln(arg)=d => n2 && i%2==0) ||
(i>3 && i%3==0) ||
(i>5 && i%5==0) ||
(i>7 && i%7==0) )
continue;
gen u;
if (i==2)
u=isqrt(n);
else {
double x=std::pow(d,1./i);
u=longlong(x);
}
if (pow(u,i,contextptr)==n){
vecteur w;
do_pollard=true;
ifactor2(u,w,do_pollard,contextptr);
for (int j=0;j5)
CERR << "Pollard begin " << CLOCK() << endl;
bool do_pollard=true;
gen a=ifactor2(n,v,do_pollard,contextptr);
if (a==-1)
return makevecteur(gensizeerr(gettext("Quadratic sieve failure, perhaps number too large")));
if (is_zero(a))
return makevecteur(gensizeerr(gettext("Stopped by user interruption")));
n=1;
return v;
}
void mergeifactors(const vecteur & f,const vecteur &g,vecteur & h){
h=f;
for (unsigned i=0;iempty())
return giac_ifactors(n0._VECTptr->front(),contextptr);
#ifdef HAVE_LIBPARI
#ifdef __APPLE__
return vecteur(1,gensizeerr(gettext("(Mac OS) Large number, you can try pari(); pari_factor(")+n0.print(contextptr)+")"));
#endif
if (!is_integer(n0) || is_zero(n0))
return vecteur(1,gensizeerr(gettext("ifactors")));
if (is_one(n0))
return vecteur(0);
gen g(pari_ifactor(n0),contextptr);
if (g.type==_VECT){
matrice m(mtran(*g._VECTptr));
vecteur res;
const_iterateur it=m.begin(),itend=m.end();
for (;it!=itend;++it){
if (it->type!=_VECT) return vecteur(1,gensizeerr(gettext("ifactor.cc/ifactors")));
res.push_back(it->_VECTptr->front());
res.push_back(it->_VECTptr->back());
}
return res;
}
#endif // LIBPARI
return giac_ifactors(n0,contextptr);
}
vecteur ifactors(const gen & n0,GIAC_CONTEXT){
gen n(n0);
vecteur f=pfacprem(n,false,contextptr);
if (is_undef(f))
return f;
vecteur g=ifactors1(n,contextptr);
if (is_undef(g))
return g;
return mergevecteur(f,g);
}
vecteur ifactors(const gen & r,const gen & i,const gen & ri,GIAC_CONTEXT){
gen norm=r*r+i*i;
gen reste(ri);
const vecteur & facto = ifactors(norm,contextptr);
if (is_undef(facto))
return facto;
int l=int(facto.size())/2;
vecteur res;
for (int i=0;i0;--mult,++multp){
if (!is_zero(reste % prime))
break;
reste=reste/prime;
}
if (multp){
res.push_back(prime);
res.push_back(multp);
}
if (mult){
prime=conj(prime,contextptr);
res.push_back(prime);
res.push_back(mult);
reste=reste/pow(prime,mult,contextptr);
}
}
if (!is_one(reste)){
res.insert(res.begin(),1);
res.insert(res.begin(),reste);
}
return res;
}
gen ifactors(const gen & args,int maplemode,GIAC_CONTEXT){
if ( (args.type==_INT_) || (args.type==_ZINT)){
if (is_zero(args)){
if (maplemode==1)
return makevecteur(args,vecteur(0));
else
return makevecteur(args);
}
vecteur v(ifactors(abs(args,contextptr),contextptr)); // ok
if (!v.empty() && is_undef(v.front()))
return v.front();
if (maplemode!=1){
if (is_positive(args,context0))
return v;
return mergevecteur(makevecteur(minus_one,plus_one),v);
}
vecteur res;
const_iterateur it=v.begin(),itend=v.end();
for (;it!=itend;it+=2){
res.push_back(makevecteur(*it,*(it+1)));
}
if (is_positive(args,context0))
return makevecteur(plus_one,res);
else
return makevecteur(minus_one,res);
}
if (args.type==_CPLX && is_integer(*args._CPLXptr) && is_integer(*(args._CPLXptr+1)))
return ifactors(*args._CPLXptr,*(args._CPLXptr+1),args,contextptr);
return gentypeerr(gettext("ifactors"));
}
gen _ifactors(const gen & args,GIAC_CONTEXT){
if ( args.type==_STRNG && args.subtype==-1) return args;
if (args.type==_VECT)
return apply(args,_ifactors,contextptr);
gen g(args);
if (!is_integral(g))
return gensizeerr(contextptr);
if (calc_mode(contextptr)==1){ // ggb returns factors repeted instead of multiplicites
vecteur res;
gen in=ifactors(g,0,contextptr);
if (in.type==_VECT){
for (unsigned i=0;isize();i+=2){
gen f=in[i],m=in[i+1];
if (m.type==_INT_){
for (int j=0;jsommet;
if (u==at_inv){
vecteur v=in_factors(gf._SYMBptr->feuille,contextptr);
iterateur it=v.begin(),itend=v.end();
for (;it!=itend;it+=2)
*(it+1)=-*(it+1);
return v;
}
if (u==at_neg){
vecteur v=in_factors(gf._SYMBptr->feuille,contextptr);
v.push_back(minus_one);
v.push_back(plus_one);
return v;
}
if ( (u==at_pow) && (gf._SYMBptr->feuille._VECTptr->back().type==_INT_) ){
vecteur v=in_factors(gf._SYMBptr->feuille._VECTptr->front(),contextptr);
gen k=gf._SYMBptr->feuille._VECTptr->back();
iterateur it=v.begin(),itend=v.end();
for (;it!=itend;it+=2)
*(it+1)=k* *(it+1);
return v;
}
if (u!=at_prod)
return makevecteur(gf,plus_one);
vecteur res;
const_iterateur it=gf._SYMBptr->feuille._VECTptr->begin(),itend=gf._SYMBptr->feuille._VECTptr->end();
for (;it!=itend;++it){
res=mergevecteur(res,in_factors(*it,contextptr));
}
return res;
}
static vecteur in_factors1(const vecteur & res,GIAC_CONTEXT){
gen coeff(1);
vecteur v;
const_iterateur it=res.begin(),itend=res.end();
for (;it!=itend;it+=2){
if (lidnt(*it).empty())
coeff=coeff*(pow(*it,*(it+1),contextptr));
else
v.push_back(makevecteur(*it,*(it+1)));
}
return makevecteur(coeff,v);
}
vecteur factors(const gen & g,const gen & x,GIAC_CONTEXT){
gen gf=factor(g,x,false,contextptr);
vecteur res=in_factors(gf,contextptr);
if (xcas_mode(contextptr)!=1)
return res;
return in_factors1(res,contextptr);
}
static const char _factors_s []="factors";
gen _factors(const gen & args,GIAC_CONTEXT){
if ( args.type==_STRNG && args.subtype==-1) return args;
if (args.type==_VECT && args.subtype==_SEQ__VECT && args._VECTptr->size()==2){
gen j=args._VECTptr->back();
gen res=_factors(args._VECTptr->front()*j,contextptr);
if (res.type==_VECT && xcas_mode(contextptr)!=1)
res=in_factors1(*res._VECTptr,contextptr);
if (res.type==_VECT && res._VECTptr->size()==2){
res._VECTptr->front()=recursive_normal(res._VECTptr->front()/j,contextptr);
if (xcas_mode(contextptr)!=1){
if (is_one(res._VECTptr->front()))
res=res._VECTptr->back();
else {
j=res._VECTptr->front();
res=res._VECTptr->back();
if (res.type==_VECT)
res=mergevecteur(makevecteur(j,1),*res._VECTptr);
}
vecteur v;
aplatir(*res._VECTptr,v,contextptr);
res=v;
}
}
return res;
}
if (args.type==_VECT)
return apply(args,_factors,contextptr);
return factors(args,vx_var,contextptr);
}
static define_unary_function_eval (__factors,&giac::_factors,_factors_s);
define_unary_function_ptr5( at_factors ,alias_at_factors,&__factors,0,true);
static gen ifactors2ifactor(const vecteur & l,bool quote){
int s;
s=int(l.size());
gen r;
vecteur v(s/2);
for (int j=0;jsize()==1 && is_integer(n._VECTptr->front()))
return ifactor(n,contextptr);
if (n.type==_VECT)
return apply(n,_ifactor,contextptr);
if (!is_integral(n))
return gensizeerr(contextptr);
if (is_strictly_positive(-n,0))
return -_ifactor(-n,contextptr);
if (n.type==_INT_ && n.val<=3)
return n;
return ifactor(n,contextptr);
}
static const char _ifactor_s []="ifactor";
static define_unary_function_eval (__ifactor,&_ifactor,_ifactor_s);
define_unary_function_ptr5( at_ifactor ,alias_at_ifactor,&__ifactor,0,true);
static const char _factoriser_entier_s []="factoriser_entier";
static define_unary_function_eval (__factoriser_entier,&_ifactor,_factoriser_entier_s);
define_unary_function_ptr5( at_factoriser_entier ,alias_at_factoriser_entier,&__factoriser_entier,0,true);
static vecteur divis(const vecteur & l3,GIAC_CONTEXT){
vecteur l1(1);
gen d,e;
int s=int(l3.size());
gen taille=1;
for (int k=0;kLIST_SIZE_LIMIT)
return vecteur(1,gendimerr(contextptr));
l1.reserve(taille.val);
l1[0]=1;//l3.push_back(..);
for (int k=0;ksize()!=4) )
return gensizeerr(contextptr);
vecteur a(2).type==_STRNG && args.subtype==-1{
if ( (args.type!=_VECT) || (args._VECTptr->size()!=4) )
return gensizeerr(contextptr);
vecteur a(2))) return args){
if ( (args.type!=_VECT) || (args._VECTptr->size()!=4) )
return gensizeerr(contextptr);
vecteur a(2);
if ( (args.type!=_VECT) || (args._VECTptr->size()!=4) )
return gensizeerr(contextptr);
vecteur a(2),b(2);
a[0]=args[0];
a[1]=args[1];
b[0]=args[2];
b[1]=args[3];
//gen a=args[0],p=args[1], b=args[2],q=args[3];
return ichinreme(a,b);
}
static const char _ichinreme_s []="ichinreme";
static define_unary_function_eval (__ichinreme,&_ichinreme,_ichinreme_s);
define_unary_function_ptr5( at_ichinreme ,alias_at_ichinreme,&__ichinreme,0,true);
*/
gen euler(const gen & e,GIAC_CONTEXT){
if (e==0)
return e;
vecteur v(ifactors(e,contextptr));
if (!v.empty() && is_undef(v.front())) return v.front();
const_iterateur it=v.begin(),itend=v.end();
for (gen res(plus_one);;){
if (it==itend)
return res;
gen p=*it;
++it;
int n=it->val;
res = res * (p-plus_one)*pow(p,n-1);
++it;
}
}
static const char _euler_s []="euler";
gen _euler(const gen & args,GIAC_CONTEXT){
if ( args.type==_STRNG && args.subtype==-1) return args;
if (args.type==_VECT)
return apply(args,_euler,contextptr);
if ( is_integer(args) && is_positive(args,contextptr))
return euler(args,contextptr);
return gentypeerr(contextptr);
}
static define_unary_function_eval (__euler,&giac::_euler,_euler_s);
define_unary_function_ptr5( at_euler ,alias_at_euler,&__euler,0,true);
gen pa2b2(const gen & p,GIAC_CONTEXT){
if (p==2)
return makevecteur(1,1);
if (!is_integer(p) || (p%4)!=1 || is_greater(1,p,contextptr)) return gensizeerr(contextptr);// car p!=1 mod 4
gen q=(p-1)/4;
gen a=2;
gen ra;
ra=powmod(a,q,p);
//on cherche ra^2=-1 mod p avec ra!=1 et ra !=p-1
while ((a!=p-1) && ((ra==1)|| (ra==p-1))){
a=a+1;
ra=powmod(a,q,p);
}
if ((ra==1)||(ra==p-1)) return gensizeerr(contextptr);//car p n'est pas premier
gen ux=1,uy=ra,vx=0,vy=p,wx,wy;
gen m=1;
while(m!=0){
if (is_positive(vx*vx+vy*vy-ux*ux+uy*uy,0)){
//on echange u et v
wx=vx;
wy=vy;
vx=ux;
vy=uy;
ux=wx;
uy=wy;
}
gen alpha=inv(2,contextptr)-(ux*vx+uy*vy)*inv(vx*vx+vy*vy,contextptr);
//m=partie entiere de alpha (-v.v/2<(u+mv).v<=v.v/2)
m=_floor(alpha,contextptr);
ux=ux+m*vx;
uy=uy+m*vy;
}
vecteur v(2);
//v repond a la question
v[0]=abs(vx,contextptr); // ok
v[1]=abs(vy,contextptr); // ok
if (vx*vx+vy*vy!=p)
return gensizeerr(contextptr);
return v;
}
gen _pa2b2(const gen & args,GIAC_CONTEXT){
if ( args.type==_STRNG && args.subtype==-1) return args;
if (!is_integer(args))
return gensizeerr(contextptr);
gen n=args;
return pa2b2(n,contextptr);
}
static const char _pa2b2_s []="pa2b2";
static define_unary_function_eval (__pa2b2,&_pa2b2,_pa2b2_s);
define_unary_function_ptr5( at_pa2b2 ,alias_at_pa2b2,&__pa2b2,0,true);
static gen ipropfrac(const gen & a,const gen & b,GIAC_CONTEXT){
if (!is_integer(a) || !is_integer(b))
return gensizeerr(contextptr);
gen r=a%b;
gen q=(a-r)/b;
gen d=gcd(r,b);
r=r/d;
gen b1=b/d;
if (r==0)
return q;
gen v;
v=symbolic(at_division,gen(makevecteur(r,b1),_SEQ__VECT));
gen w;
w=symbolic(at_plus,gen(makevecteur(q,v),_SEQ__VECT));
if (calc_mode(contextptr)==1)
return symbolic(at_quote,w);
return w;
}
gen _propfrac(const gen & arg,GIAC_CONTEXT){
if ( arg.type==_STRNG && arg.subtype==-1) return arg;
gen args(arg);
vecteur v;
if (arg.type==_VECT && arg._VECTptr->size()==2){
v=vecteur(1,arg._VECTptr->back());
args=arg._VECTptr->front();
lvar(args,v);
}
else
v=lvar(arg);
gen g=e2r(args,v,contextptr);
gen a,b;
fxnd(g,a,b);
if (v.empty())
return ipropfrac(a,b,contextptr);
else {
gen d=r2e(b,v,contextptr);
g=_quorem(makesequence(r2e(a,v,contextptr),d,v.front()),contextptr);
if (is_undef(g)) return g;
vecteur &v=*g._VECTptr;
return v[0]+rdiv(v[1],d,contextptr);
}
}
static const char _propfrac_s []="propfrac";
static define_unary_function_eval (__propfrac,&_propfrac,_propfrac_s);
define_unary_function_ptr5( at_propfrac ,alias_at_propfrac,&__propfrac,0,true);
void step_egcd(int a,int b,GIAC_CONTEXT){
gprintf("===============",vecteur(0),1,contextptr);
gprintf("Extended Euclide algorithm for a=%gen and b=%gen",makevecteur(a,b),1,contextptr);
gprintf("L%gen: 1*a+0*b=%gen",makevecteur(1,a),1,contextptr);
gprintf("L%gen: 0*a+1*b=%gen",makevecteur(2,b),1,contextptr);
int i=3;
int u0=1,v0=0,u1=0,v1=1,u2,v2;
for (;b;++i){
int q=a/b;
u2=u0-q*u1;
v2=v0-q*v1;
int r=a-q*b;
gprintf("iquo(%gen,%gen)=%gen",makevecteur(a,b,q),1,contextptr);
gprintf("L%gen=L%gen-%gen*L%gen: %gen*a+%gen*b=%gen",makevecteur(i,i-2,q,i-1,u2,v2,r),1,contextptr);
u0=u1;
u1=u2;
v0=v1;
v1=v2;
a=b;
b=r;
}
gprintf("Bezout identity %gen*a+%gen*b=%gen",makevecteur(u0,v0,a),1,contextptr);
}
gen iabcuv(const gen & a,const gen & b,const gen & c,GIAC_CONTEXT){
gen d=gcd(a,b);
if (c%d!=0) return gensizeerr(gettext("No solution in ring"));
gen a1=a/d,b1=b/d,c1=c/d;
gen u,v,w;
if (a1.type==_INT_ && b1.type==_INT_ && step_infolevel(contextptr))
step_egcd(a1.val,b1.val,contextptr);
egcd(a1,b1,u,v,w);
vecteur r(2);
r[0]=smod(u*c1,b);
r[1]=iquo(c-r[0]*a,b);
return r;
}
gen _iabcuv(const gen & args,GIAC_CONTEXT){
if ( args.type==_STRNG && args.subtype==-1) return args;
if ( (args.type!=_VECT) || (args._VECTptr->size()!=3) )
return gensizeerr(contextptr);
gen a=args[0],b=args[1],c=args[2];
return iabcuv(a,b,c,contextptr);
}
static const char _iabcuv_s []="iabcuv";
static define_unary_function_eval (__iabcuv,&_iabcuv,_iabcuv_s);
define_unary_function_ptr5( at_iabcuv ,alias_at_iabcuv,&__iabcuv,0,true);
gen abcuv(const gen & a,const gen & b,const gen & c,const gen & x,GIAC_CONTEXT){
gen g=_egcd(makesequence(a,b,x),contextptr);
if (is_undef(g)) return g;
vecteur & v=*g._VECTptr;
gen h=_quorem(makesequence(c,v[2],x),contextptr);
if (is_undef(h)) return h;
vecteur & w=*h._VECTptr;
if (!is_zero(w[1]))
return gensizeerr(gettext("No solution in ring"));
gen U=v[0]*w[0],V=v[1]*w[0];
if (_degree(makesequence(c,x),contextptr).val<_degree(makesequence(a,x),contextptr).val+_degree(makesequence(b,x),contextptr).val ){
U=_rem(makesequence(U,b,x),contextptr);
V=_rem(makesequence(V,a,x),contextptr);
}
return makevecteur(U,V);
}
gen _abcuv(const gen & args,GIAC_CONTEXT){
if ( args.type==_STRNG && args.subtype==-1) return args;
if ( (args.type!=_VECT) || (args._VECTptr->size()<3) )
return gensizeerr(contextptr);
vecteur & v =*args._VECTptr;
if (v.size()>3)
return abcuv(v[0],v[1],v[2],v[3],contextptr);
return abcuv(v[0],v[1],v[2],vx_var,contextptr);
}
static const char _abcuv_s []="abcuv";
static define_unary_function_eval (__abcuv,&_abcuv,_abcuv_s);
define_unary_function_ptr5( at_abcuv ,alias_at_abcuv,&__abcuv,0,true);
gen simp2(const gen & a,const gen & b,GIAC_CONTEXT){
vecteur r(2);
gen d=gcd(a,b);
r[0]=normal(a/d,contextptr);
r[1]=normal(b/d,contextptr);
return r;
}
gen _simp2(const gen & args,GIAC_CONTEXT){
if ( args.type==_STRNG && args.subtype==-1) return args;
if ( (args.type!=_VECT) || (args._VECTptr->size()!=2) )
return gensizeerr(contextptr);
gen a=args[0],b=args[1];
if ( (a.type==_VECT) || (b.type==_VECT) )
return gensizeerr(contextptr);
return simp2(a,b,contextptr);
}
static const char _simp2_s []="simp2";
static define_unary_function_eval (__simp2,&_simp2,_simp2_s);
define_unary_function_ptr5( at_simp2 ,alias_at_simp2,&__simp2,0,true);
gen fxnd(const gen & a){
vecteur v(lvar(a));
gen g=e2r(a,v,context0); // ok
gen n,d;
fxnd(g,n,d);
return makevecteur(r2e(n,v,context0),r2e(d,v,context0)); // ok
}
gen _fxnd(const gen & args,GIAC_CONTEXT){
if ( args.type==_STRNG && args.subtype==-1) return args;
if (args.type==_VECT)
return apply(args,fxnd);
return fxnd(args);
}
static const char _fxnd_s []="fxnd";
static define_unary_function_eval (__fxnd,&_fxnd,_fxnd_s);
define_unary_function_ptr5( at_fxnd ,alias_at_fxnd,&__fxnd,0,true);
#ifndef NO_NAMESPACE_GIAC
} // namespace giac
#endif // ndef NO_NAMESPACE_GIAC