File: [local] / OpenXM_contrib2 / asir2018 / builtin / poly.c (download)
Revision 1.3, Sun Mar 3 05:21:16 2019 UTC (5 years, 6 months ago) by noro
Branch: MAIN
Changes since 1.2: +6 -1
lines
Fixed many bugs:
asir2000, asir2018: a bug in ndv_homogenize()
asir2018: several bugs related to multiplication of univariate polynomials
bsave/bload of LM data
|
/*
* Copyright (c) 1994-2000 FUJITSU LABORATORIES LIMITED
* All rights reserved.
*
* FUJITSU LABORATORIES LIMITED ("FLL") hereby grants you a limited,
* non-exclusive and royalty-free license to use, copy, modify and
* redistribute, solely for non-commercial and non-profit purposes, the
* computer program, "Risa/Asir" ("SOFTWARE"), subject to the terms and
* conditions of this Agreement. For the avoidance of doubt, you acquire
* only a limited right to use the SOFTWARE hereunder, and FLL or any
* third party developer retains all rights, including but not limited to
* copyrights, in and to the SOFTWARE.
*
* (1) FLL does not grant you a license in any way for commercial
* purposes. You may use the SOFTWARE only for non-commercial and
* non-profit purposes only, such as academic, research and internal
* business use.
* (2) The SOFTWARE is protected by the Copyright Law of Japan and
* international copyright treaties. If you make copies of the SOFTWARE,
* with or without modification, as permitted hereunder, you shall affix
* to all such copies of the SOFTWARE the above copyright notice.
* (3) An explicit reference to this SOFTWARE and its copyright owner
* shall be made on your publication or presentation in any form of the
* results obtained by use of the SOFTWARE.
* (4) In the event that you modify the SOFTWARE, you shall notify FLL by
* e-mail at risa-admin@sec.flab.fujitsu.co.jp of the detailed specification
* for such modification or the source code of the modified part of the
* SOFTWARE.
*
* THE SOFTWARE IS PROVIDED AS IS WITHOUT ANY WARRANTY OF ANY KIND. FLL
* MAKES ABSOLUTELY NO WARRANTIES, EXPRESSED, IMPLIED OR STATUTORY, AND
* EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT OF THIRD PARTIES'
* RIGHTS. NO FLL DEALER, AGENT, EMPLOYEES IS AUTHORIZED TO MAKE ANY
* MODIFICATIONS, EXTENSIONS, OR ADDITIONS TO THIS WARRANTY.
* UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, TORT, CONTRACT,
* OR OTHERWISE, SHALL FLL BE LIABLE TO YOU OR ANY OTHER PERSON FOR ANY
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, PUNITIVE OR CONSEQUENTIAL
* DAMAGES OF ANY CHARACTER, INCLUDING, WITHOUT LIMITATION, DAMAGES
* ARISING OUT OF OR RELATING TO THE SOFTWARE OR THIS AGREEMENT, DAMAGES
* FOR LOSS OF GOODWILL, WORK STOPPAGE, OR LOSS OF DATA, OR FOR ANY
* DAMAGES, EVEN IF FLL SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF
* SUCH DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY. EVEN IF A PART
* OF THE SOFTWARE HAS BEEN DEVELOPED BY A THIRD PARTY, THE THIRD PARTY
* DEVELOPER SHALL HAVE NO LIABILITY IN CONNECTION WITH THE USE,
* PERFORMANCE OR NON-PERFORMANCE OF THE SOFTWARE.
*
* $OpenXM: OpenXM_contrib2/asir2018/builtin/poly.c,v 1.3 2019/03/03 05:21:16 noro Exp $
*/
#include "ca.h"
#include "parse.h"
#include "base.h"
void Pranp();
void Pheadsgn();
void Pmul_trunc(),Pquo_trunc();
void Pumul(),Pumul_ff(),Pusquare(),Pusquare_ff(),Putmul(),Putmul_ff();
void Pkmul(),Pksquare(),Pktmul();
void Pord(), Premove_vars(), Pcoef0(), Pcoef(), Pdeg(), Pmindeg(), Psetmod();
void Pcoef_gf2n();
void getcoef(), getdeglist(), mergedeglist(), change_mvar(), restore_mvar();
void Pp_mag(),Pmaxblen();
void Pmergelist(), Pch_mv(), Pre_mv(), Pdeglist();
void Pptomp(),Pmptop();
void Pptolmp(),Plmptop();
void Pptosfp(),Psfptop(),Psf_galois_action(),Psf_embed(),Psf_find_root();
void Psf_minipoly(),Psf_log(),Psfptopsfp();
void Pptogf2n(),Pgf2ntop(),Pgf2ntovect();
void Pptogfpn(),Pgfpntop();
void Pfind_root_gf2n();
void Pumul_specialmod(),Pusquare_specialmod(),Putmul_specialmod();
void Pureverse(),Putrunc(),Pudecomp(),Purembymul(),Purembymul_precomp();
void Puinvmod(),Purevinvmod();
void Ppwrmod_ff(),Ppwrtab_ff(),Pgeneric_pwrmod_ff();
void Pkpwrmod_lm(),Pkpwrtab_lm(),Pkgeneric_pwrmod_lm();
void Pkmulum();
void Pksquareum();
void Pfmultest();
void Phfmul_lm();
void Plazy_lm();
void Psetmod_ff();
void Psimp_ff();
void Pextdeg_ff();
void Pcharacteristic_ff();
void Pfield_type_ff();
void Pfield_order_ff();
void Prandom_ff();
void Ptracemod_gf2n();
void Psparsemod_gf2n();
void Pmultest_gf2n();
void Psquaretest_gf2n();
void Pinvtest_gf2n();
void Pbininv_gf2n();
void Prinvtest_gf2n();
void Pis_irred_gf2();
void Pis_irred_ddd_gf2();
void Pget_next_fft_prime();
void Puadj_coef();
void Preorder();
void Phomogeneous_part();
void Phomogeneous_deg();
void simp_ff(Obj,Obj *);
void ranp(int,UP *);
void field_order_ff(Z *);
int current_ff;
struct ftab poly_tab[] = {
{"headsgn",Pheadsgn,1},
{"quo_trunc",Pquo_trunc,2},
{"mul_trunc",Pmul_trunc,3},
{"homogeneous_deg",Phomogeneous_deg,-2},
{"homogeneous_part",Phomogeneous_part,-3},
{"reorder",Preorder,3},
{"uadj_coef",Puadj_coef,3},
{"ranp",Pranp,2},
{"p_mag",Pp_mag,1},
{"maxblen",Pmaxblen,1},
{"ord",Pord,-1},
{"remove_vars",Premove_vars,1},
{"delete_vars",Premove_vars,1},
{"coef0",Pcoef0,-3},
{"coef",Pcoef,-3},
{"coef_gf2n",Pcoef_gf2n,2},
{"deg",Pdeg,2},
{"mindeg",Pmindeg,2},
{"setmod",Psetmod,-1},
{"sparsemod_gf2n",Psparsemod_gf2n,-1},
{"setmod_ff",Psetmod_ff,-3},
{"simp_ff",Psimp_ff,1},
{"extdeg_ff",Pextdeg_ff,0},
{"characteristic_ff",Pcharacteristic_ff,0},
{"field_type_ff",Pfield_type_ff,0},
{"field_order_ff",Pfield_order_ff,0},
{"random_ff",Prandom_ff,0},
{"deglist",Pdeglist,2},
{"mergelist",Pmergelist,2},
{"ch_mv",Pch_mv,2},
{"re_mv",Pre_mv,2},
{"ptomp",Pptomp,-2},
{"mptop",Pmptop,1},
{"ptolmp",Pptolmp,1},
{"lmptop",Plmptop,1},
{"sf_galois_action",Psf_galois_action,2},
{"sf_find_root",Psf_find_root,1},
{"sf_minipoly",Psf_minipoly,2},
{"sf_embed",Psf_embed,3},
{"sf_log",Psf_log,1},
{"ptosfp",Pptosfp,1},
{"sfptop",Psfptop,1},
{"sfptopsfp",Psfptopsfp,2},
{"ptogf2n",Pptogf2n,1},
{"gf2ntop",Pgf2ntop,-2},
{"gf2ntovect",Pgf2ntovect,1},
{"ptogfpn",Pptogfpn,1},
{"gfpntop",Pgfpntop,-2},
{"kmul",Pkmul,2},
{"ksquare",Pksquare,1},
{"ktmul",Pktmul,3},
{"umul",Pumul,2},
{"usquare",Pusquare,1},
{"ureverse_inv_as_power_series",Purevinvmod,2},
{"uinv_as_power_series",Puinvmod,2},
{"umul_specialmod",Pumul_specialmod,3},
{"usquare_specialmod",Pusquare_specialmod,2},
{"utmul_specialmod",Putmul_specialmod,4},
{"utmul",Putmul,3},
{"umul_ff",Pumul_ff,2},
{"usquare_ff",Pusquare_ff,1},
{"utmul_ff",Putmul_ff,3},
/* for historical reason */
{"trunc",Putrunc,2},
{"decomp",Pudecomp,2},
{"utrunc",Putrunc,2},
{"udecomp",Pudecomp,2},
{"ureverse",Pureverse,-2},
{"urembymul",Purembymul,2},
{"urembymul_precomp",Purembymul_precomp,3},
{"lazy_lm",Plazy_lm,1},
{"lazy_ff",Plazy_lm,1},
{"pwrmod_ff",Ppwrmod_ff,1},
{"generic_pwrmod_ff",Pgeneric_pwrmod_ff,3},
{"pwrtab_ff",Ppwrtab_ff,2},
{"tracemod_gf2n",Ptracemod_gf2n,3},
{"b_find_root_gf2n",Pfind_root_gf2n,1},
{"is_irred_gf2",Pis_irred_gf2,1},
{"is_irred_ddd_gf2",Pis_irred_ddd_gf2,1},
{"kpwrmod_lm",Pkpwrmod_lm,1},
{"kgeneric_pwrmod_lm",Pkgeneric_pwrmod_lm,3},
{"kpwrtab_lm",Pkpwrtab_lm,2},
{"kmulum",Pkmulum,3},
{"ksquareum",Pksquareum,2},
{"fmultest",Pfmultest,3},
{"hfmul_lm",Phfmul_lm,2},
{"multest_gf2n",Pmultest_gf2n,2},
{"squaretest_gf2n",Psquaretest_gf2n,1},
{"bininv_gf2n",Pbininv_gf2n,2},
{"invtest_gf2n",Pinvtest_gf2n,1},
{"rinvtest_gf2n",Prinvtest_gf2n,0},
{"get_next_fft_prime",Pget_next_fft_prime,2},
{0,0,0},
};
void Pheadsgn(NODE arg,Z *rp)
{
int s;
s = headsgn((P)ARG0(arg));
STOZ(s,*rp);
}
void Pmul_trunc(NODE arg,P *rp)
{
P p1,p2,p,h;
VL vl0,vl1,vl2,tvl,vl;
VN vn;
int i,n;
p1 = (P)ARG0(arg);
p2 = (P)ARG1(arg);
get_vars((Obj)p1,&vl1); get_vars((Obj)p2,&vl2); mergev(CO,vl1,vl2,&tvl);
p = (P)ARG2(arg);
get_vars((Obj)p,&vl0); mergev(CO,tvl,vl0,&vl);
for ( tvl = vl, n = 0; tvl; tvl = NEXT(tvl), n++ );
vn = (VN) ALLOCA((n+1)*sizeof(struct oVN));
for ( i = 0, tvl = vl; i < n; tvl = NEXT(tvl), i++ ) {
vn[i].v = tvl->v;
vn[i].n = 0;
}
vn[i].v = 0;
vn[i].n = 0;
for ( h = p, i = 0; OID(h) == O_P; h = COEF(DC(h)) ) {
for ( ; vn[i].v != VR(h); i++ );
vn[i].n = ZTOS(DEG(DC(h)));
}
mulp_trunc(vl,p1,p2,vn,rp);
}
void Pquo_trunc(NODE arg,P *rp)
{
P p1,p2,p,h;
VL vl0,vl1,vl2,tvl,vl;
VN vn;
int i,n;
p1 = (P)ARG0(arg);
p2 = (P)ARG1(arg);
if ( !p1 )
*rp = 0;
else if ( NUM(p2) )
divsp(CO,p1,p2,rp);
else {
get_vars((Obj)p1,&vl1); get_vars((Obj)p2,&vl2); mergev(CO,vl1,vl2,&vl);
for ( tvl = vl, n = 0; tvl; tvl = NEXT(tvl), n++ );
vn = (VN) ALLOCA((n+1)*sizeof(struct oVN));
for ( i = 0, tvl = vl; i < n; tvl = NEXT(tvl), i++ ) {
vn[i].v = tvl->v;
vn[i].n = 0;
}
vn[i].v = 0;
vn[i].n = 0;
for ( h = p2, i = 0; OID(h) == O_P; h = COEF(DC(h)) ) {
for ( ; vn[i].v != VR(h); i++ );
vn[i].n = ZTOS(DEG(DC(h)));
}
quop_trunc(vl,p1,p2,vn,rp);
}
}
void Phomogeneous_part(NODE arg,P *rp)
{
if ( argc(arg) == 2 )
exthp(CO,(P)ARG0(arg),ZTOS((Q)ARG1(arg)),rp);
else
exthpc_generic(CO,(P)ARG0(arg),ZTOS((Q)ARG2(arg)),
VR((P)ARG1(arg)),rp);
}
void Phomogeneous_deg(NODE arg,Z *rp)
{
int d;
if ( argc(arg) == 1 )
d = homdeg((P)ARG0(arg));
else
d = getchomdeg(VR((P)ARG1(arg)),(P)ARG0(arg));
STOZ(d,*rp);
}
/*
p1 = reorder(p,ovl,nvl) => p1 is 'sorted accoding to nvl.
*/
void Preorder(NODE arg,P *rp)
{
VL ovl,nvl,tvl;
NODE n;
for ( ovl = 0, n = BDY((LIST)ARG1(arg)); n; n = NEXT(n) ) {
if ( !ovl ) {
NEWVL(ovl); tvl = ovl;
} else {
NEWVL(NEXT(tvl)); tvl = NEXT(tvl);
}
VR(tvl) = VR((P)BDY(n));
}
for ( nvl = 0, n = BDY((LIST)ARG2(arg)); n; n = NEXT(n) ) {
if ( !nvl ) {
NEWVL(nvl); tvl = nvl;
} else {
NEWVL(NEXT(tvl)); tvl = NEXT(tvl);
}
VR(tvl) = VR((P)BDY(n));
}
reorderp(nvl,ovl,(P)ARG0(arg),rp);
}
/*
uadj_coef(F,M,M2)
if ( F is a non-negative integer )
return F > M2 ? F-M : M2;
else
F = CN*V^N+...+C0
return uadj_coef(CN,M,M2)*V^N+...+uadj_coef(C0,M,M2);
*/
void Puadj_coef(NODE arg,P *rp)
{
UP f,r;
Z m,m2;
ptoup((P)ARG0(arg),&f);
m = (Z)ARG1(arg);
m2 = (Z)ARG2(arg);
adj_coefup(f,m,m2,&r);
uptop(r,rp);
}
/*
get_next_fft_prime(StartIndex,Bits)
tries to find smallest Index >= StartIndex s.t.
2^(Bits-1)|FFTprime[Index]-1
return [Index,Mod] or 0 (not exist)
*/
void Pget_next_fft_prime(NODE arg,LIST *rp)
{
unsigned int mod,d;
int start,bits,i;
NODE n;
Z q,ind;
start = ZTOS((Q)ARG0(arg));
bits = ZTOS((Q)ARG1(arg));
for ( i = start; ; i++ ) {
get_fft_prime(i,&mod,&d);
if ( !mod ) {
*rp = 0; return;
}
if ( bits <= (int)d ) {
UTOZ(mod,q);
UTOZ(i,ind);
n = mknode(2,ind,q);
MKLIST(*rp,n);
return;
}
}
}
void Pranp(NODE arg,P *rp)
{
int n;
UP c;
n = ZTOS((Q)ARG0(arg));
ranp(n,&c);
if ( c ) {
up_var = VR((P)ARG1(arg));
uptop(c,rp);
} else
*rp = 0;
}
void ranp(int n,UP *nr)
{
int i;
unsigned int r;
Z q;
UP c;
*nr = c = UPALLOC(n);
for ( i = 0; i <= n; i++ ) {
r = random();
UTOZ(r,q);
c->c[i] = (Num)q;
}
for ( i = n; i >= 0 && !c->c[i]; i-- );
if ( i >= 0 )
c->d = i;
else
*nr = 0;
}
void Pmaxblen(NODE arg,Z *rp)
{
int l;
l = maxblenp(ARG0(arg));
STOZ(l,*rp);
}
void Pp_mag(NODE arg,Z *rp)
{
int l;
l = p_mag(ARG0(arg));
STOZ(l,*rp);
}
void Pord(NODE arg,LIST *listp)
{
NODE n,tn,p,opt;
char *key;
Obj value;
int overwrite=0;
LIST l;
VL vl,tvl,svl;
P t;
int i,j;
V *va;
V v;
#if 0
printf("LASTCO="); printv(CO,LASTCO->v); printf("\n");
#endif
if ( current_option ) {
for ( opt = current_option; opt; opt = NEXT(opt) ) {
p = BDY((LIST)BDY(opt));
key = BDY((STRING)BDY(p));
value = (Obj)BDY(NEXT(p));
if ( !strcmp(key,"overwrite") && value ) {
overwrite = value ? 1 : 0;
break;
}
}
}
if ( argc(arg) ) {
asir_assert(ARG0(arg),O_LIST,"ord");
for ( vl = 0, i = 0, n = BDY((LIST)ARG0(arg));
n; n = NEXT(n), i++ ) {
if ( !vl ) {
NEWVL(vl); tvl = vl;
} else {
NEWVL(NEXT(tvl)); tvl = NEXT(tvl);
}
if ( !(t = (P)BDY(n)) || (OID(t) != O_P) )
error("ord : invalid argument");
VR(tvl) = VR(t);
}
if ( !overwrite ) {
va = (V *)ALLOCA(i*sizeof(V));
for ( j = 0, svl = vl; j < i; j++, svl = NEXT(svl) )
va[j] = VR(svl);
for ( svl = CO; svl; svl = NEXT(svl) ) {
v = VR(svl);
for ( j = 0; j < i; j++ )
if ( v == va[j] )
break;
if ( j == i ) {
if ( !vl ) {
NEWVL(vl); tvl = vl;
} else {
NEWVL(NEXT(tvl)); tvl = NEXT(tvl);
}
VR(tvl) = v;
}
}
} else {
for ( svl = vl; svl; svl = NEXT(svl) ) {
if ( svl->v->attr == (pointer)V_PF )
((PFINS)svl->v->priv)->pf->ins = 0;
}
}
if ( vl )
NEXT(tvl) = 0;
CO = vl;
update_LASTCO();
}
for ( n = 0, vl = CO; vl; vl = NEXT(vl) ) {
NEXTNODE(n,tn); MKV(VR(vl),t); BDY(tn) = (pointer)t;
}
NEXT(tn) = 0; MKLIST(l,n); *listp = l;
}
void Premove_vars(NODE arg,LIST *listp)
{
NODE l,nd,tnd;
V *v,*va;
int n,na,i,j;
VL vl,vl1;
P t;
LIST list;
asir_assert(ARG0(arg),O_LIST,"remove_vars");
l = BDY((LIST)ARG0(arg)); n = length(l);
v = (V *)ALLOCA(n*sizeof(V));
for ( i = 0; i < n; i++, l = NEXT(l) )
if ( !(t = (P)BDY(l)) || (OID(t) != O_P) )
error("ord : invalid argument");
else v[i] = VR(t);
for ( na = 0, vl = CO; vl; vl = NEXT(vl), na++ );
va = (V *)ALLOCA(na*sizeof(V));
for ( i = 0, vl = CO; i < na; i++, vl = NEXT(vl) ) va[i] = VR(vl);
for ( i = 0; i < na; i++ )
for ( j = 0; j < n; j++ ) if ( va[i] == v[j] ) va[i] = 0;
for ( vl = 0, i = na-1; i >= 0; i-- )
if ( va[i] ) {
NEWVL(vl1); VR(vl1) = va[i]; NEXT(vl1) = vl; vl = vl1;
}
CO = vl;
for ( nd = 0, vl = CO; vl; vl = NEXT(vl) ) {
NEXTNODE(nd,tnd); MKV(VR(vl),t); BDY(tnd) = (pointer)t;
}
if ( nd ) NEXT(tnd) = 0;
MKLIST(list,nd); *listp = list;
}
void Pcoef0(NODE arg,Obj *rp)
{
Obj t,n;
P s;
DCP dc;
int id;
V v;
VL vl;
if ( !(t = (Obj)ARG0(arg)) || ((id = OID(ARG0(arg))) > O_P) )
*rp = 0;
else if ( (n = (Obj)ARG1(arg)) && (OID(n) > O_N) )
*rp = 0;
else if ( id == O_N )
if ( !n )
*rp = t;
else
*rp = 0;
else {
if ( argc(arg) == 3 ) {
if ( (v = VR((P)ARG2(arg))) != VR((P)t) ) {
reordvar(CO,v,&vl); reorderp(vl,CO,(P)t,&s);
} else
s = (P)t;
if ( VR(s) != v ) {
if ( n )
*rp = 0;
else
*rp = t;
return;
}
} else
s = (P)t;
for ( dc = DC(s); dc && cmpz(DEG(dc),(Z)n); dc = NEXT(dc) );
if ( dc )
*rp = (Obj)COEF(dc);
else
*rp = 0;
}
}
void Pcoef(NODE arg,Obj *rp)
{
Obj t,n;
P s;
DCP dc;
int id;
V v;
if ( !(t = (Obj)ARG0(arg)) || ((id = OID(ARG0(arg))) > O_P) )
*rp = 0;
else if ( (n = (Obj)ARG1(arg)) && (OID(n) > O_N) )
*rp = 0;
else if ( id == O_N ) {
if ( !n )
*rp = t;
else
*rp = 0;
} else {
if ( argc(arg) == 3 ) {
if ( (v = VR((P)ARG2(arg))) != VR((P)t) ) {
getcoef(CO,(P)t,v,(Z)n,(P *)rp); return;
} else
s = (P)t;
if ( VR(s) != v ) {
if ( n )
*rp = 0;
else
*rp = t;
return;
}
} else
s = (P)t;
for ( dc = DC(s); dc && cmpz(DEG(dc),(Z)n); dc = NEXT(dc) );
if ( dc )
*rp = (Obj)COEF(dc);
else
*rp = 0;
}
}
void Pcoef_gf2n(NODE arg,Obj *rp)
{
Obj t,n;
int id,d;
UP2 up2;
if ( !(t = (Obj)ARG0(arg)) || ((id = OID(ARG0(arg))) > O_P) )
*rp = 0;
else if ( (n = (Obj)ARG1(arg)) && (OID(n) > O_N) )
*rp = 0;
else if ( id == O_N && NID((Num)t) == N_GF2N ) {
d = ZTOS((Q)n);
up2 = ((GF2N)t)->body;
if ( d > degup2(up2) )
*rp = 0;
else
*rp = (Obj)(up2->b[d/BSH]&(((unsigned long)1)<<(d%BSH))?ONE:0);
} else
*rp = 0;
}
void Pdeg(NODE arg,Z *rp)
{
Obj t,v;
int d;
#if 0
if ( !(t = (Obj)ARG0(arg)) || (OID(t) != O_P) )
*rp = 0;
else if ( !(v = (Obj)ARG1(arg)) || (VR((P)v) != VR((P)t)) )
*rp = 0;
else
*rp = (Obj)DEG(DC((P)t));
#endif
if ( !(t = (Obj)ARG0(arg)) )
STOZ(-1,*rp);
else if ( OID(t) != O_P ) {
if ( OID(t) == O_N && NID(t) == N_GF2N
&& (v=(Obj)ARG1(arg)) && OID(v)== O_N && NID(v) == N_GF2N ) {
d = degup2(((GF2N)t)->body);
STOZ(d,*rp);
} else
*rp = 0;
} else
degp(VR((P)ARG1(arg)),(P)ARG0(arg),rp);
}
void Pmindeg(NODE arg,Z *rp)
{
Obj t;
if ( !(t = (Obj)ARG0(arg)) || (OID(t) != O_P) )
*rp = 0;
else
getmindeg(VR((P)ARG1(arg)),(P)ARG0(arg),rp);
}
void Psetmod(NODE arg,Z *rp)
{
if ( arg ) {
asir_assert(ARG0(arg),O_N,"setmod");
current_mod = ZTOS((Q)ARG0(arg));
}
STOZ(current_mod,*rp);
}
void Psparsemod_gf2n(NODE arg,Z *rp)
{
int id;
if ( arg && current_mod_gf2n )
current_mod_gf2n->id = ARG0(arg)?1:0;
if ( !current_mod_gf2n )
id = -1;
else
id = current_mod_gf2n->id;
STOZ(id,*rp);
}
void Pmultest_gf2n(NODE arg,GF2N *rp)
{
GF2N a,b,c;
int i;
a = (GF2N)ARG0(arg); b = (GF2N)ARG0(arg);
for ( i = 0; i < 10000; i++ )
mulgf2n(a,b,&c);
*rp = c;
}
void Psquaretest_gf2n(NODE arg,GF2N *rp)
{
GF2N a,c;
int i;
a = (GF2N)ARG0(arg);
for ( i = 0; i < 10000; i++ )
squaregf2n(a,&c);
*rp = c;
}
void Pinvtest_gf2n(NODE arg,GF2N *rp)
{
GF2N a,c;
int i;
a = (GF2N)ARG0(arg);
for ( i = 0; i < 10000; i++ )
invgf2n(a,&c);
*rp = c;
}
void Pbininv_gf2n(NODE arg,GF2N *rp)
{
UP2 a,inv;
int n;
a = ((GF2N)ARG0(arg))->body;
n = ZTOS((Q)ARG1(arg));
type1_bin_invup2(a,n,&inv);
MKGF2N(inv,*rp);
}
void Prinvtest_gf2n(Real *rp)
{
GF2N *a;
GF2N c;
double t0,t1,r;
int i;
double get_clock();
a = (GF2N *)ALLOCA(1000*sizeof(GF2N));
for ( i = 0; i < 1000; i++ ) {
randomgf2n(&a[i]);
}
t0 = get_clock();
for ( i = 0; i < 1000; i++ )
invgf2n(a[i],&c);
t1 = get_clock();
r = (t1-t0)/1000;
MKReal(r,*rp);
}
void Pfind_root_gf2n(NODE arg,GF2N *rp)
{
#if 0
UP p;
ptoup((P)ARG0(arg),&p);
find_root_gf2n(p,rp);
#else
UP2 p;
ptoup2((P)ARG0(arg),&p);
find_root_up2(p,rp);
#endif
}
void Pis_irred_gf2(NODE arg,Z *rp)
{
UP2 t;
ptoup2(ARG0(arg),&t);
*rp = irredcheckup2(t) ? ONE : 0;
}
void Pis_irred_ddd_gf2(NODE arg,Z *rp)
{
UP2 t;
int ret;
ptoup2(ARG0(arg),&t);
ret = irredcheck_dddup2(t);
STOZ(ret,*rp);
}
void Psetmod_ff(NODE arg,Obj *rp)
{
int ac;
int d;
Obj mod,defpoly;
Z n;
UP up;
UP2 up2;
UM dp;
Z q,r;
P p,p1,y;
NODE n0,n1;
LIST list;
ac = argc(arg);
if ( ac == 1 ) {
mod = (Obj)ARG0(arg);
if ( !mod )
current_ff = FF_NOT_SET;
else {
switch ( OID(mod) ) {
case O_N:
current_ff = FF_GFP;
setmod_lm((Z)mod);
break;
case O_P:
current_ff = FF_GF2N;
setmod_gf2n((P)mod); break;
default:
error("setmod_ff : invalid argument");
}
}
} else if ( ac == 2 ) {
if ( OID(ARG0(arg)) == O_N ) {
/* small finite field; primitive root representation */
current_ff = FF_GFS;
setmod_sf(ZTOS((Q)ARG0(arg)),ZTOS((Q)ARG1(arg)));
} else {
mod = (Obj)ARG1(arg);
current_ff = FF_GFPN;
defpoly = (Obj)ARG0(arg);
if ( !mod || !defpoly )
error("setmod_ff : invalid argument");
setmod_lm((Z)mod);
setmod_gfpn((P)defpoly);
}
} else if ( ac == 3 ) {
/* finite extension of a small finite field */
current_ff = FF_GFS;
setmod_sf(ZTOS((Q)ARG0(arg)),ZTOS((Q)ARG1(arg)));
d = ZTOS((Q)ARG2(arg));
generate_defpoly_sfum(d,&dp);
setmod_gfsn(dp);
current_ff = FF_GFSN;
}
switch ( current_ff ) {
case FF_GFP:
getmod_lm(&n); *rp = (Obj)n; break;
case FF_GF2N:
getmod_gf2n(&up2); up2top(up2,&p); *rp = (Obj)p; break;
case FF_GFPN:
getmod_lm(&n);
getmod_gfpn(&up); uptop(up,&p);
MKNODE(n1,n,0); MKNODE(n0,p,n1);
MKLIST(list,n0);
*rp = (Obj)list; break;
case FF_GFS:
case FF_GFSN:
STOZ(current_gfs_p,q);
if ( current_gfs_ext )
enc_to_p(current_gfs_p,current_gfs_iton[1],
VR(current_gfs_ext),&p);
else {
if ( current_gfs_p == 2 )
r = ONE;
else if ( !current_gfs_ntoi )
r = 0;
else
STOZ(current_gfs_iton[1],r);
p = (P)r;
}
switch ( current_ff ) {
case FF_GFS:
n0 = mknode(3,q,current_gfs_ext,p);
break;
case FF_GFSN:
getmod_gfsn(&dp);
makevar("y",&y);
sfumtop(VR(y),dp,&p1);
n0 = mknode(4,q,current_gfs_ext,p,p1);
break;
}
MKLIST(list,n0);
*rp = (Obj)list; break;
default:
*rp = 0; break;
}
}
void Pextdeg_ff(Z *rp)
{
int d;
UP2 up2;
UP up;
UM dp;
switch ( current_ff ) {
case FF_GFP:
*rp = ONE; break;
case FF_GF2N:
getmod_gf2n(&up2); d = degup2(up2); STOZ(d,*rp); break;
case FF_GFPN:
getmod_gfpn(&up); STOZ(up->d,*rp); break;
case FF_GFS:
if ( !current_gfs_ext )
*rp = ONE;
else
*rp = DEG(DC(current_gfs_ext));
break;
case FF_GFSN:
getmod_gfsn(&dp);
STOZ(DEG(dp),*rp);
break;
default:
error("extdeg_ff : current_ff is not set");
}
}
void Pcharacteristic_ff(Z *rp)
{
switch ( current_ff ) {
case FF_GFP:
case FF_GFPN:
getmod_lm(rp); break;
case FF_GF2N:
STOZ(2,*rp); break;
case FF_GFS:
case FF_GFSN:
STOZ(current_gfs_p,*rp); break;
default:
error("characteristic_ff : current_ff is not set");
}
}
void Pfield_type_ff(Z *rp)
{
STOZ(current_ff,*rp);
}
void Pfield_order_ff(Z *rp)
{
field_order_ff(rp);
}
void Prandom_ff(Obj *rp)
{
LM l;
GF2N g;
GFPN p;
GFS s;
GFSN spn;
switch ( current_ff ) {
case FF_GFP:
random_lm(&l); *rp = (Obj)l; break;
case FF_GF2N:
randomgf2n(&g); *rp = (Obj)g; break;
case FF_GFPN:
randomgfpn(&p); *rp = (Obj)p; break;
case FF_GFS:
randomgfs(&s); *rp = (Obj)s; break;
case FF_GFSN:
randomgfsn(&spn); *rp = (Obj)spn; break;
default:
error("random_ff : current_ff is not set");
}
}
void Psimp_ff(NODE arg,Obj *rp)
{
simp_ff((Obj)ARG0(arg),rp);
}
void getcoef(VL vl,P p,V v,Z d,P *r)
{
P s,t,u,a,b,x;
DCP dc;
V w;
if ( !p )
*r = 0;
else if ( NUM(p) )
*r = d ? 0 : p;
else if ( (w=VR(p)) == v ) {
for ( dc = DC(p); dc && cmpz(DEG(dc),d); dc = NEXT(dc) );
*r = dc ? COEF(dc) : 0;
} else {
MKV(w,x);
for ( dc = DC(p), s = 0; dc; dc = NEXT(dc) ) {
getcoef(vl,COEF(dc),v,d,&t);
if ( t ) {
pwrp(vl,x,DEG(dc),&u); mulp(vl,t,u,&a);
addp(vl,s,a,&b); s = b;
}
}
*r = s;
}
}
void Pdeglist(NODE arg,LIST *rp)
{
NODE d;
getdeglist((P)ARG0(arg),VR((P)ARG1(arg)),&d);
MKLIST(*rp,d);
}
void Pch_mv(NODE arg,P *rp)
{
change_mvar(CO,(P)ARG0(arg),VR((P)ARG1(arg)),rp);
}
void Pre_mv(NODE arg,P *rp)
{
restore_mvar(CO,(P)ARG0(arg),VR((P)ARG1(arg)),rp);
}
void change_mvar(VL vl,P p,V v,P *r)
{
Z d;
DCP dc,dc0;
NODE dl;
if ( !p || NUM(p) || (VR(p) == v) )
*r = p;
else {
getdeglist(p,v,&dl);
for ( dc0 = 0; dl; dl = NEXT(dl) ) {
NEXTDC(dc0,dc); DEG(dc) = d = (Z)BDY(dl);
getcoef(vl,p,v,d,&COEF(dc));
}
NEXT(dc) = 0; MKP(v,dc0,*r);
}
}
void restore_mvar(VL vl,P p,V v,P *r)
{
P s,u,a,b,x;
DCP dc;
if ( !p || NUM(p) || (VR(p) != v) )
*r = p;
else {
MKV(v,x);
for ( dc = DC(p), s = 0; dc; dc = NEXT(dc) ) {
pwrp(vl,x,DEG(dc),&u); mulp(vl,COEF(dc),u,&a);
addp(vl,s,a,&b); s = b;
}
*r = s;
}
}
void getdeglist(P p,V v,NODE *d)
{
NODE n,n0,d0,d1,d2;
DCP dc;
if ( !p || NUM(p) ) {
MKNODE(n,0,0); *d = n;
} else if ( VR(p) == v ) {
for ( n0 = 0, dc = DC(p); dc; dc = NEXT(dc) ) {
NEXTNODE(n0,n); BDY(n) = (pointer)DEG(dc);
}
NEXT(n) = 0; *d = n0;
} else {
for ( dc = DC(p), d0 = 0; dc; dc = NEXT(dc) ) {
getdeglist(COEF(dc),v,&d1); mergedeglist(d0,d1,&d2); d0 = d2;
}
*d = d0;
}
}
void Pmergelist(NODE arg,LIST *rp)
{
NODE n;
asir_assert(ARG0(arg),O_LIST,"mergelist");
asir_assert(ARG1(arg),O_LIST,"mergelist");
mergedeglist(BDY((LIST)ARG0(arg)),BDY((LIST)ARG1(arg)),&n);
MKLIST(*rp,n);
}
void mergedeglist(NODE d0,NODE d1,NODE *dr)
{
NODE t0,t,dt;
Z d;
int c;
if ( !d0 )
*dr = d1;
else {
while ( d1 ) {
dt = d1; d1 = NEXT(d1); d = (Z)BDY(dt);
for ( t0 = 0, t = d0; t; t0 = t, t = NEXT(t) ) {
c = cmpz(d,(Z)BDY(t));
if ( !c )
break;
else if ( c > 0 ) {
if ( !t0 ) {
NEXT(dt) = d0; d0 = dt;
} else {
NEXT(t0) = dt; NEXT(dt) = t;
}
break;
}
}
if ( !t ) {
NEXT(t0) = dt; *dr = d0; return;
}
}
*dr = d0;
}
}
void Pptomp(NODE arg,P *rp)
{
int mod;
if ( argc(arg) == 1 ) {
if ( !current_mod )
error("ptomp : current_mod is not set");
else
mod = current_mod;
} else
mod = ZTOS((Q)ARG1(arg));
ptomp(mod,(P)ARG0(arg),rp);
}
void Pmptop(NODE arg,P *rp)
{
mptop((P)ARG0(arg),rp);
}
void Pptolmp(NODE arg,P *rp)
{
ptolmp((P)ARG0(arg),rp);
}
void Plmptop(NODE arg,P *rp)
{
lmptop((P)ARG0(arg),rp);
}
void Psf_galois_action(NODE arg,P *rp)
{
sf_galois_action(ARG0(arg),ARG1(arg),rp);
}
/*
sf_embed(F,B,PM)
F : an element of GF(pn)
B : the image of the primitive root of GF(pn)
PM : order of GF(pm)
*/
void Psf_embed(NODE arg,P *rp)
{
int k,pm;
/* GF(pn)={0,1,a,a^2,...}->GF(pm)={0,1,b,b^2,...}; a->b^k */
k = CONT((GFS)ARG1(arg));
pm = ZTOS((Q)ARG2(arg));
sf_embed((P)ARG0(arg),k,pm,rp);
}
void Psf_log(NODE arg,Z *rp)
{
int k;
if ( !ARG0(arg) )
error("sf_log : invalid armument");
k = CONT((GFS)ARG0(arg));
STOZ(k,*rp);
}
void Psf_find_root(NODE arg,GFS *rp)
{
P p;
Obj t;
int d;
UM u;
int *root;
p = (P)ARG0(arg);
simp_ff((Obj)p,&t); p = (P)t;
d = getdeg(VR(p),p);
u = W_UMALLOC(d);
ptosfum(p,u);
root = (int *)ALLOCA(d*sizeof(int));
find_rootsf(u,root);
MKGFS(IFTOF(root[0]),*rp);
}
void Psf_minipoly(NODE arg,P *rp)
{
Obj t;
P p1,p2;
int d1,d2;
UM up1,up2,m;
p1 = (P)ARG0(arg); simp_ff((Obj)p1,&t); p1 = (P)t;
p2 = (P)ARG1(arg); simp_ff((Obj)p2,&t); p2 = (P)t;
d1 = getdeg(VR(p1),p1); up1 = W_UMALLOC(d1); ptosfum(p1,up1);
d2 = getdeg(VR(p2),p2); up2 = W_UMALLOC(d2); ptosfum(p2,up2);
m = W_UMALLOC(d2);
minipolysf(up1,up2,m);
sfumtop(VR(p2),m,&p1);
sfptop(p1,rp);
}
void Pptosfp(NODE arg,P *rp)
{
ptosfp(ARG0(arg),rp);
}
void Psfptop(NODE arg,P *rp)
{
sfptop((P)ARG0(arg),rp);
}
void Psfptopsfp(NODE arg,P *rp)
{
sfptopsfp((P)ARG0(arg),VR((P)ARG1(arg)),rp);
}
void Pptogf2n(NODE arg,GF2N *rp)
{
ptogf2n((Obj)ARG0(arg),rp);
}
void Pgf2ntop(NODE arg,P *rp)
{
if ( argc(arg) == 2 )
up2_var = VR((P)ARG1(arg));
gf2ntop((GF2N)ARG0(arg),rp);
}
void Pgf2ntovect(NODE arg,VECT *rp)
{
gf2ntovect((GF2N)ARG0(arg),rp);
}
void Pptogfpn(NODE arg,GFPN *rp)
{
ptogfpn((Obj)ARG0(arg),rp);
}
void Pgfpntop(NODE arg,P *rp)
{
if ( argc(arg) == 2 )
up_var = VR((P)ARG1(arg));
gfpntop((GFPN)ARG0(arg),rp);
}
void Pureverse(NODE arg,P *rp)
{
UP p,r;
ptoup((P)ARG0(arg),&p);
if ( argc(arg) == 1 )
reverseup(p,p->d,&r);
else
reverseup(p,ZTOS((Q)ARG1(arg)),&r);
uptop(r,rp);
}
void Putrunc(NODE arg,P *rp)
{
UP p,r;
ptoup((P)ARG0(arg),&p);
truncup(p,ZTOS((Q)ARG1(arg))+1,&r);
uptop(r,rp);
}
void Pudecomp(NODE arg,LIST *rp)
{
P u,l;
UP p,up,low;
NODE n0,n1;
ptoup((P)ARG0(arg),&p);
decompup(p,ZTOS((Q)ARG1(arg))+1,&low,&up);
uptop(low,&l);
uptop(up,&u);
MKNODE(n1,u,0); MKNODE(n0,l,n1);
MKLIST(*rp,n0);
}
void Purembymul(NODE arg,P *rp)
{
UP p1,p2,r;
if ( !ARG0(arg) || !ARG1(arg) )
*rp = 0;
else {
ptoup((P)ARG0(arg),&p1);
ptoup((P)ARG1(arg),&p2);
rembymulup(p1,p2,&r);
uptop(r,rp);
}
}
/*
* d1 = deg(p1), d2 = deg(p2)
* d1 <= 2*d2-1
* p2*inv = 1 mod x^d2
*/
void Purembymul_precomp(NODE arg,P *rp)
{
UP p1,p2,inv,r;
if ( !ARG0(arg) || !ARG1(arg) )
*rp = 0;
else {
ptoup((P)ARG0(arg),&p1);
ptoup((P)ARG1(arg),&p2);
ptoup((P)ARG2(arg),&inv);
if ( p1->d >= 2*p2->d ) {
error("urembymul_precomp : degree of 1st arg is too large");
/* fprintf(stderr,"urembymul_precomp : degree of 1st arg is too large"); */
remup(p1,p2,&r);
} else
hybrid_rembymulup_special(current_ff,p1,p2,inv,&r);
uptop(r,rp);
}
}
void Puinvmod(NODE arg,P *rp)
{
UP p,r;
ptoup((P)ARG0(arg),&p);
invmodup(p,ZTOS((Q)ARG1(arg)),&r);
uptop(r,rp);
}
void Purevinvmod(NODE arg,P *rp)
{
UP p,pr,r;
ptoup((P)ARG0(arg),&p);
reverseup(p,p->d,&pr);
invmodup(pr,ZTOS((Q)ARG1(arg)),&r);
uptop(r,rp);
}
void Ppwrmod_ff(NODE arg,P *rp)
{
UP p1,p2;
ptoup((P)ARG0(arg),&p1);
switch ( current_ff ) {
case FF_GFP:
/* XXX : hybrid version may not be useful ... */
#if 1
hybrid_powermodup(p1,&p2); break;
#else
powermodup(p1,&p2); break;
#endif
case FF_GF2N:
powermodup_gf2n(p1,&p2); break;
case FF_GFPN:
case FF_GFS:
case FF_GFSN:
powermodup(p1,&p2); break;
default:
error("pwrmod_ff : current_ff is not set");
}
uptop(p2,rp);
}
void Pgeneric_pwrmod_ff(NODE arg,P *rp)
{
UP g,f,r;
ptoup((P)ARG0(arg),&g);
ptoup((P)ARG1(arg),&f);
switch ( current_ff ) {
case FF_GFP:
hybrid_generic_powermodup(g,f,(Z)ARG2(arg),&r); break;
case FF_GF2N:
generic_powermodup_gf2n(g,f,(Z)ARG2(arg),&r); break;
case FF_GFPN:
case FF_GFS:
case FF_GFSN:
generic_powermodup(g,f,(Z)ARG2(arg),&r); break;
default:
error("generic_pwrmod_ff : current_ff is not set");
}
uptop(r,rp);
}
void Ppwrtab_ff(NODE arg,VECT *rp)
{
UP f,xp;
UP *tab;
VECT r;
int i,d;
ptoup((P)ARG0(arg),&f);
ptoup((P)ARG1(arg),&xp);
d = f->d;
tab = (UP *)ALLOCA(d*sizeof(UP));
switch ( current_ff ) {
case FF_GFP:
hybrid_powertabup(f,xp,tab); break;
case FF_GF2N:
powertabup_gf2n(f,xp,tab); break;
case FF_GFPN:
case FF_GFS:
case FF_GFSN:
powertabup(f,xp,tab); break;
default:
error("pwrtab_ff : current_ff is not set");
}
MKVECT(r,d); *rp = r;
for ( i = 0; i < d; i++ )
uptop(tab[i],(P *)&BDY(r)[i]);
}
void Pkpwrmod_lm(NODE arg,P *rp)
{
UP p1,p2;
ptoup((P)ARG0(arg),&p1);
powermodup(p1,&p2);
uptop(p2,rp);
}
void Pkgeneric_pwrmod_lm(NODE arg,P *rp)
{
UP g,f,r;
ptoup((P)ARG0(arg),&g);
ptoup((P)ARG1(arg),&f);
generic_powermodup(g,f,(Z)ARG2(arg),&r);
uptop(r,rp);
}
void Pkpwrtab_lm(NODE arg,VECT *rp)
{
UP f,xp;
UP *tab;
VECT r;
int i,d;
ptoup((P)ARG0(arg),&f);
ptoup((P)ARG1(arg),&xp);
d = f->d;
tab = (UP *)ALLOCA(d*sizeof(UP));
powertabup(f,xp,tab);
MKVECT(r,d); *rp = r;
for ( i = 0; i < d; i++ )
uptop(tab[i],(P *)&BDY(r)[i]);
}
void Plazy_lm(NODE arg,Q *rp)
{
lm_lazy = ZTOS((Q)ARG0(arg));
*rp = 0;
}
void Pkmul(NODE arg,P *rp)
{
P n1,n2;
n1 = (P)ARG0(arg); n2 = (P)ARG1(arg);
asir_assert(n1,O_P,"kmul");
asir_assert(n2,O_P,"kmul");
kmulp(CO,n1,n2,rp);
}
void Pksquare(NODE arg,P *rp)
{
P n1;
n1 = (P)ARG0(arg);
asir_assert(n1,O_P,"ksquare");
ksquarep(CO,n1,rp);
}
void Pktmul(NODE arg,P *rp)
{
UP p1,p2,r;
ptoup((P)ARG0(arg),&p1);
ptoup((P)ARG1(arg),&p2);
tkmulup(p1,p2,ZTOS((Q)ARG2(arg))+1,&r);
uptop(r,rp);
}
void Pumul(NODE arg,P *rp)
{
P a1,a2;
UP p1,p2,r;
a1 = (P)ARG0(arg); a2 = (P)ARG1(arg);
if ( !a1 || !a2 || NUM(a1) || NUM(a2) )
mulp(CO,a1,a2,rp);
else {
if ( !uzpcheck((Obj)a1) || !uzpcheck((Obj)a2) || VR(a1) != VR(a2) )
error("umul : invalid argument");
ptoup(a1,&p1);
ptoup(a2,&p2);
hybrid_mulup(0,p1,p2,&r);
uptop(r,rp);
}
}
void Pusquare(NODE arg,P *rp)
{
UP p1,r;
ptoup((P)ARG0(arg),&p1);
hybrid_squareup(0,p1,&r);
uptop(r,rp);
}
void Putmul(NODE arg,P *rp)
{
UP p1,p2,r;
ptoup((P)ARG0(arg),&p1);
ptoup((P)ARG1(arg),&p2);
hybrid_tmulup(0,p1,p2,ZTOS((Q)ARG2(arg))+1,&r);
uptop(r,rp);
}
void Pumul_ff(NODE arg,Obj *rp)
{
P a1,a2;
UP p1,p2,r;
P p;
a1 = (P)ARG0(arg); a2 = (P)ARG1(arg);
ptoup(a1,&p1);
ptoup(a2,&p2);
hybrid_mulup(current_ff,p1,p2,&r);
uptop(r,&p);
simp_ff((Obj)p,rp);
}
void Pusquare_ff(NODE arg,Obj *rp)
{
UP p1,r;
P p;
ptoup((P)ARG0(arg),&p1);
hybrid_squareup(current_ff,p1,&r);
uptop(r,&p);
simp_ff((Obj)p,rp);
}
void Putmul_ff(NODE arg,Obj *rp)
{
UP p1,p2,r;
P p;
ptoup((P)ARG0(arg),&p1);
ptoup((P)ARG1(arg),&p2);
hybrid_tmulup(current_ff,p1,p2,ZTOS((Q)ARG2(arg))+1,&r);
uptop(r,&p);
simp_ff((Obj)p,rp);
}
void Phfmul_lm(NODE arg,P *rp)
{
UP p1,p2,r;
UP hi,lo,mid,t,s,p10,p11,p20,p21;
unsigned int m,d;
int i;
ptoup((P)ARG0(arg),&p1);
ptoup((P)ARG1(arg),&p2);
d = MAX(p1->d,p2->d);
for ( m = 1; m < d; m <<= 1 );
if ( m > d )
m >>= 1;
if ( d-m < 10000 ) {
decompup(p1,m,&p10,&p11); /* p1 = p11*x^m+p10 */
decompup(p2,m,&p20,&p21); /* p2 = p21*x^m+p20 */
fft_mulup_lm(p10,p20,&lo);
kmulup(p11,p21,&hi);
kmulup(p11,p20,&t); kmulup(p10,p21,&s); addup(t,s,&mid);
r = UPALLOC(2*d);
bzero((char *)COEF(r),(2*d+1)*sizeof(Num));
if ( lo )
bcopy((char *)COEF(lo),(char *)COEF(r),(DEG(lo)+1)*sizeof(Num));
if ( hi )
bcopy((char *)COEF(hi),(char *)(COEF(r)+2*m),(DEG(hi)+1)*sizeof(Num));
for ( i = 2*d; i >= 0 && !COEF(r)[i]; i-- );
if ( i < 0 )
r = 0;
else {
DEG(r) = i;
t = UPALLOC(DEG(mid)+m); DEG(t) = DEG(mid)+m;
bzero((char *)COEF(t),(DEG(mid)+m+1)*sizeof(Num));
bcopy((char *)COEF(mid),(char *)(COEF(t)+m),(DEG(mid)+1)*sizeof(Num));
addup(t,r,&s);
r = s;
}
} else
fft_mulup_lm(p1,p2,&r);
uptop(r,rp);
}
void Pfmultest(NODE arg,LIST *rp)
{
P p1,p2,r;
int d1,d2;
UM w1,w2,wr;
unsigned int *f1,*f2,*fr,*w;
int index,mod,root,d,maxint,i;
int cond;
Z prime;
NODE n0,n1;
p1 = (P)ARG0(arg); p2 = (P)ARG1(arg); index = ZTOS((Q)ARG2(arg));
FFT_primes(index,&mod,&root,&d);
maxint = 1<<d;
d1 = UDEG(p1); d2 = UDEG(p2);
if ( maxint < d1+d2+1 )
*rp = 0;
else {
w1 = W_UMALLOC(d1); w2 = W_UMALLOC(d2);
wr = W_UMALLOC(d1+d2);
ptoum(mod,p1,w1); ptoum(mod,p2,w2);
f1 = (unsigned int *)ALLOCA(maxint*sizeof(unsigned int));
f2 = (unsigned int *)ALLOCA(maxint*sizeof(unsigned int));
fr = (unsigned int *)ALLOCA(maxint*sizeof(unsigned int));
w = (unsigned int *)ALLOCA(12*maxint*sizeof(unsigned int));
for ( i = 0; i <= d1; i++ )
f1[i] = (unsigned int)w1->c[i];
for ( i = 0; i <= d2; i++ )
f2[i] = (unsigned int)w2->c[i];
cond = FFT_pol_product(d1,f1,d2,f2,fr,index,w);
if ( cond )
error("fmultest : ???");
wr->d = d1+d2;
for ( i = 0; i <= d1+d2; i++ )
wr->c[i] = (unsigned int)fr[i];
umtop(VR(p1),wr,&r);
STOZ(mod,prime);
MKNODE(n1,prime,0);
MKNODE(n0,r,n1);
MKLIST(*rp,n0);
}
}
void Pkmulum(NODE arg,P *rp)
{
P p1,p2;
int d1,d2,mod;
UM w1,w2,wr;
p1 = (P)ARG0(arg); p2 = (P)ARG1(arg); mod = ZTOS((Q)ARG2(arg));
d1 = UDEG(p1); d2 = UDEG(p2);
w1 = W_UMALLOC(d1); w2 = W_UMALLOC(d2);
wr = W_UMALLOC(d1+d2);
ptoum(mod,p1,w1); ptoum(mod,p2,w2);
kmulum(mod,w1,w2,wr);
umtop(VR(p1),wr,rp);
}
void Pksquareum(NODE arg,P *rp)
{
P p1;
int d1,mod;
UM w1,wr;
p1 = (P)ARG0(arg); mod = ZTOS((Q)ARG1(arg));
d1 = UDEG(p1);
w1 = W_UMALLOC(d1);
wr = W_UMALLOC(2*d1);
ptoum(mod,p1,w1);
kmulum(mod,w1,w1,wr);
umtop(VR(p1),wr,rp);
}
void Ptracemod_gf2n(NODE arg,P *rp)
{
UP g,f,r;
ptoup((P)ARG0(arg),&g);
ptoup((P)ARG1(arg),&f);
tracemodup_gf2n(g,f,(Z)ARG2(arg),&r);
uptop(r,rp);
}
void Pumul_specialmod(NODE arg,P *rp)
{
P a1,a2;
UP p1,p2,r;
int i,nmod;
int *modind;
NODE t,n;
a1 = (P)ARG0(arg); a2 = (P)ARG1(arg);
if ( !a1 || !a2 || NUM(a1) || NUM(a2) )
mulp(CO,a1,a2,rp);
else {
if ( !uzpcheck((Obj)a1) || !uzpcheck((Obj)a2) || VR(a1) != VR(a2) )
error("umul_specialmod : invalid argument");
ptoup(a1,&p1);
ptoup(a2,&p2);
n = BDY((LIST)ARG2(arg));
nmod = length(n);
modind = (int *)MALLOC_ATOMIC(nmod*sizeof(int));
for ( i = 0, t = n; i < nmod; i++, t = NEXT(t) )
modind[i] = ZTOS((Q)BDY(t));
fft_mulup_specialmod_main(p1,p2,0,modind,nmod,&r);
uptop(r,rp);
}
}
void Pusquare_specialmod(NODE arg,P *rp)
{
P a1;
UP p1,r;
int i,nmod;
int *modind;
NODE t,n;
a1 = (P)ARG0(arg);
if ( !a1 || NUM(a1) )
mulp(CO,a1,a1,rp);
else {
if ( !uzpcheck((Obj)a1) )
error("usquare_specialmod : invalid argument");
ptoup(a1,&p1);
n = BDY((LIST)ARG1(arg));
nmod = length(n);
modind = (int *)MALLOC_ATOMIC(nmod*sizeof(int));
for ( i = 0, t = n; i < nmod; i++, t = NEXT(t) )
modind[i] = ZTOS((Q)BDY(t));
fft_mulup_specialmod_main(p1,p1,0,modind,nmod,&r);
uptop(r,rp);
}
}
void Putmul_specialmod(NODE arg,P *rp)
{
P a1,a2;
UP p1,p2,r;
int i,nmod;
int *modind;
NODE t,n;
a1 = (P)ARG0(arg); a2 = (P)ARG1(arg);
if ( !a1 || !a2 || NUM(a1) || NUM(a2) )
mulp(CO,a1,a2,rp);
else {
if ( !uzpcheck((Obj)a1) || !uzpcheck((Obj)a2) || VR(a1) != VR(a2) )
error("utmul_specialmod : invalid argument");
ptoup(a1,&p1);
ptoup(a2,&p2);
n = BDY((LIST)ARG3(arg));
nmod = length(n);
modind = (int *)MALLOC_ATOMIC(nmod*sizeof(int));
for ( i = 0, t = n; i < nmod; i++, t = NEXT(t) )
modind[i] = ZTOS((Q)BDY(t));
fft_mulup_specialmod_main(p1,p2,ZTOS((Q)ARG2(arg))+1,modind,nmod,&r);
uptop(r,rp);
}
}