Risa/AsirでF5アルゴリズムを実装してみた
まぁ、実装してみましたという以外、特にないのだけど
A new efficient algorithm for computing Groebner bases without reduction to zero (F5)
http://www.risc.jku.at/Groebner-Bases-Bibliography/gbbib_files/publication_502.pdf
http://dl.acm.org/citation.cfm?id=780516
F5C: a variant of Faugere's F5 algorithm with reduced Groebner bases
http://arxiv.org/abs/0906.2967
あたりを参考にした。上のはオリジナルの論文で、下のは、少し改良すると、もっと速くなる的なことが書いてある。が、実装したのはオリジナルの部分のみ。比較用として、何の工夫もないBuchbergerアルゴリズムも実装した。引数はgr関数と同じ。で、速度比較
gr | F5 | Buchberger | |
---|---|---|---|
katsura(3) | 0sec | 0.156sec | 28.94sec |
katsura(4) | 0.016sec | 24.66sec | very long |
cyclic(3) | 0sec | 0sec | 0sec |
cyclic(4) | 0sec | 0.016sec | 0.016sec |
しょぼいベンチマークではあるが、一応、単純なBuchbergerと比べると、大分速いっぽい?grは、Risa/Asir組み込みのgr関数で、これとは全然比較にならないくらい遅い
load("gr"); def cmpSig(R1 , R2){ for(I = 0 ; I < length(R1) ; I++){ HT1 = dp_ht(R1[I]); HT2 = dp_ht(R2[I]); if(HT1==HT2)continue; HT = dp_ht(HT1 + HT2); if(HT==HT1)return 1; if(HT==HT2)return 2; } return 0; } /* signaturedPolynomial newSigPol : Signature -> Polynomial -> signaturedPolynomial polyR : signaturedPolynomial -> Polynomial indexR : signaturedPolynomial -> Nat sigR : signaturedPolynomial -> Signature */ struct signaturedPolynomial {signature , polynomial , index , id}; def newSigPol(S , P){ SP = newstruct(signaturedPolynomial); SP->signature = S; SP->polynomial = P; SP->id = uc(); /* identifier */ for(I = 0 ; I < length(S) ; I++){ if(S[I]!=0){ SP->index = I; return SP; } } } def polyR(SP){ return SP->polynomial; } def indexR(SP){ return SP->index; } def sigR(SP){ return SP->signature; } def idR(SP){ return SP->id; } def sortCriticalPairs(Ps){ if(length(Ps)<=1){ return Ps; }else{ P = car(Ps); PDeg = dp_td(car(P)); L1 = []; L2 = []; for(Q=cdr(Ps) ; Q!=[] ; Q=cdr(Q)){ QDeg = dp_td(car( car(Q) )); if (QDeg<PDeg){ L1 = cons(car(Q),L1); }else{ L2 = cons(car(Q),L2); } } return append(sortCriticalPairs(L1) , cons(P , sortCriticalPairs(L2))); } } def sortSigPols(RS){ if(length(RS)<=1){ return RS; }else{ R1 = car(RS); L1 = []; L2 = []; for(RC = cdr(RS) ; RC!=[] ; RC=cdr(RC)){ R2 = car(RC); if(cmpSig(sigR(R1),sigR(R2))==2){ L2 = cons(R2,L2); }else{ L1 = cons(R2,L1); } } return append(sortSigPols(L1) , cons(R1 , sortSigPols(L2))); } } def criticalPair(R1 , R2 , K , G){ P1 = polyR(R1); P2 = polyR(R2); T = dp_lcm(dp_ht(P1) , dp_ht(P2)); U1 = dp_subd(T , P1); U2 = dp_subd(T , P2); IL = vtol(newvect(length(G))); if(cmpSig(U1*sigR(R1) , U2*sigR(R2))==2){ K2 = indexR(R2); if(K2>K)return []; UT2 = U2*sigR(R2)[K2]; if( dp_nf(IL , UT2 , G , 1)!=UT2 )return []; K1 = indexR(R1); UT1 = U1*sigR(R1)[K1]; if(K1==K && dp_nf(IL , UT1 , G , 1)!=UT1)return []; return [T,U2,R2,U1,R1]; }else{ K1 = indexR(R1); if(K1>K)return []; UT1 = U1*sigR(R1)[K1]; if( dp_nf(IL , UT1 , G , 1)!=UT1 )return []; K2 = indexR(R2); UT2 = U2*sigR(R2)[K2]; if(K2=K && dp_nf(IL , UT2 , G , 1)!=UT2)return []; return [T,U1,R1,U2,R2]; } } def isRewritable(U , RK , Rule){ I = indexR(RK); T = sigR(RK)[I]; for(L = Rule[I] ; L!=[] ; L=cdr(L)){ R = car(L); TI = sigR(R)[indexR(R)]; if( dp_redble(U*T , TI) ){ return (RK->id!=R->id); } } return 0; } def computeSPols(CritPairs , Rule){ Ret = []; for(Pairs = CritPairs ; Pairs!=[] ; Pairs=cdr(Pairs)){ CritPair = car(Pairs); T = car(CritPair); CritPair = cdr(CritPair); U = car(CritPair); CritPair = cdr(CritPair); RI = car(CritPair); CritPair = cdr(CritPair); V = car(CritPair); CritPair = cdr(CritPair); RJ = car(CritPair); if(!isRewritable(U,RI,Rule) && !isRewritable(V,RJ,Rule)){ PI = polyR(RI); PJ = polyR(RJ); /* assert(U*sigR(RI) >= V*sigR(RJ); */ RN = newSigPol(U*sigR(RI) , U*PI/dp_hc(PI) - V*PJ/dp_hc(PJ)); Ret = cons(RN,Ret); Idx = indexR(RN); Rule[Idx] = cons(RN , Rule[Idx]); } } Ret = sortSigPols(Ret); return Ret; } def reductionF5(S , G , Gsig_next , Rule){ ToDoList = S; CompletedList = []; IL = vtol(newvect(length(G))); while(ToDoList!=[]){ H = car(ToDoList); /* ToDoList is sorted */ HP = dp_nf(IL , polyR(H) , G , 1); H->polynomial = HP; Res = topReduction(H , G , append(Gsig_next,CompletedList) , Rule); CompletedList = append(CompletedList , car(Res)); ReDoList = cadr(Res); ToDoList = append(cdr(ToDoList) , ReDoList); if(length(ReDoList)>0){ ToDoList = sortSigPols(ToDoList); } } return CompletedList; } def topReduction(RK , G , Gsig_cand , Rule){ P = polyR(RK); if(P==0){ /* Warning:“the system is not a regular sequence”*/ return [ [] , []]; } /* find reductor */ IL = vtol(newvect(length(G))); T = dp_ht(P); for(RList = Gsig_cand ; RList!=[] ; RList=cdr(RList)){ RJ = car(RList); Q = polyR(RJ); T2 = dp_ht(Q); if(!dp_redble(T,T2))continue; U = dp_subd(T , T2); UT = U*sigR(RJ)[indexR(RJ)]; if( dp_nf(IL , UT , G , 1)!=UT )continue; if( isRewritable(U , RJ , Rule) )continue; CR = cmpSig(U*sigR(RJ) , sigR(RK)); if(CR==0)continue; P = P - dp_hc(P)*U*Q/dp_hc(Q); if(P!=0)P=dp_ptozp( P/dp_hc(P) ); if(CR==2){ RK->polynomial = P; return [ [] , [RK]]; }else{ /* CR==1 */ RN = newSigPol(U*sigR(RJ) , P); Rule[indexR(RN)] = cons(RN , Rule[indexR(RN)]); return [ [] , [RK,RN]]; } } RK->polynomial = dp_ptozp( P/dp_hc(P) ); return [ [RK] , []]; } def f5(Polys_ , Vars , Ord){ SaveOrd = dp_ord(); dp_ord(Ord); Polys = map(dp_ptod , Polys_ , Vars); Rule = newvect(length(Polys)); FVecs = []; for (I = 0 ; I <length(Polys) ; I++){ Rule[I] = []; V = newvect(length(Polys)); V[I] = 1; FVecs = cons(V,FVecs); if(dp_td(Polys[I])==0)return [1]; } FVecs = reverse(FVecs); R = newSigPol(FVecs[0] , Polys[0]); Gsig = [R]; for(I = 1 ; I < length(Polys) ; I++){ /* increment basis */ G = vect(map(polyR , Gsig)); /* G is Grobner basis for <Polys[0] , ... , Polys[I-1]> */ /* print( ["F5@loop:",I,map(dp_dtop , G , Vars)] ); */ R = newSigPol(FVecs[I] , Polys[I]); P = []; for(RC = Gsig ; RC!=[] ; RC=cdr(RC)){ CritPair = criticalPair(R , car(RC) , I , G); if(CritPair!=[])P = cons(CritPair , P); } Gsig_next = cons(R , Gsig); P = sortCriticalPairs(P); while(P!=[]){ CritPair = car(P); MinDeg = dp_td(car(CritPair)); /* assert(P is sorted by degree) */ for(Pd=[] ; P!=[] ; P=cdr(P)){ CritPair = car(P); if(dp_td(car(CritPair))==MinDeg){ Pd=cons(CritPair , Pd); }else{ break; } } F = computeSPols(Pd , Rule); Rd = reductionF5(F , G , Gsig_next , Rule); for( ; Rd!=[] ; Rd=cdr(Rd) ){ R = car(Rd); if( dp_td(polyR(R))==0 )return [1]; for( RC = Gsig_next ; RC!=[] ; RC=cdr(RC) ){ CritPair = criticalPair(R , car(RC) , I , G); if(CritPair!=[])P = cons(CritPair , P); } Gsig_next = cons(R , Gsig_next); } P = sortCriticalPairs(P); } Gsig = Gsig_next; /* end of increment basis */ } G = map(dp_dtop , map(polyR,Gsig) , Vars); /* compute reduced Grobner basis */ Hs = G; G = []; while(Hs!=[]){ H = p_nf(car(Hs) , append(G , cdr(Hs)) , Vars , Ord); C= dp_hc(dp_ptod(H,Vars)); if(H!=0)G=cons(ptozp(H/C),G); Hs=cdr(Hs); } dp_ord(SaveOrd); return G; } /* naive implementation of Buchberger algorithm */ def buchberger(Polys , Vars , Ord){ SaveOrd = dp_ord(); dp_ord(Ord); Pairs = []; IL = []; for(I=length(Polys)-1 ; I>=0 ; I--){ IL = cons(I,IL); for(J=length(Polys)-1 ; J>I ; J--){ Pairs = cons([I,J],Pairs); } } N = length(Polys); G = map(dp_ptod,Polys,Vars); while(Pairs!=[]){ Pair = car(Pairs); Pairs = cdr(Pairs); P = G[Pair[0]]; Q = G[Pair[1]]; LCM = dp_lcm(dp_hm(P) , dp_hm(Q)); SP = dp_subd(LCM , P)*P/dp_hc(P) - dp_subd(LCM , Q)*Q/dp_hc(Q); Rem = dp_nf(IL , SP , vect(G) , 1); if(Rem!=0){ G = append(G , [dp_ptozp(Rem/dp_hc(Rem))]); for(I = 0; I < N ; I++){ Pairs = cons([I,N],Pairs); } IL = append(IL , [N]); N++; } } G = map(dp_dtop,G,Vars); /* compute reduced Grobner basis */ Hs = G; G = []; while(Hs!=[]){ H = p_nf(car(Hs) , append(G , cdr(Hs)) , Vars , Ord); C= dp_hc(dp_ptod(H,Vars)); if(H!=0)G=cons(ptozp(H/C),G); Hs=cdr(Hs); } /* end of computing reduced Grobner basis */ dp_ord(SaveOrd); return G; }