GCD の利用

現在のオリジナルプログラムや RR6 では,分解体の primitive element A の中間体 K(w,a) 上の定義式が Lagrange resolvents の和となることを利用していますが,http://ehito.hatenablog.com/entry/2019/03/02/163023 で述べたように,A の K(w,a) 上の定義式と a の K(w) 上の定義式は,それぞれ A の K 上の定義式と冪根 a の一次の定義式との A に関する GCD と終結式(を因数分解したもの)なので,代数体での計算が高速なら,これに基づく実装の価値があります.

残念ながら maxima因数分解は逐次代数拡大に対応していませんが,GCD は対応(algebraic モード)しており,例えば

(%i4) tellrat(a2^3+21*a1+14,a1^2+a1+1)$algebraic:on$gcd:subres$
(%i7) gcd(A^12+4*A^10+24*A^8+48*A^6-560*A^4+3136,485968*a2+A^4*(18236*a1-9524)+A^10*(83*a1-563)+655424*a1+A^8*((-739*a1)-2672)+A^6*((-2012*a1)-12700)+A^2*(474768-28560*a1)+390432,A);
Evaluation took 0.0020 seconds (0.0020 elapsed) using 255.969 KB.
(%o7) A^2*((12*a1+4)*a2^2+28*a2+28)-28*a2^2+((-84*a1)-28)*a2+21*A^4+392
(%i8) algebraic:off$untellrat(a1,a2)$

といった具合に,tellrat の定義式が monic(つまり,扱えるのは代数的整数のみ)という制約さえクリアすれば,...という訳で,次の RR6m を作りました(m は monic の m).

(%i15) fundef(RR6m);
(%o15) RR6m(csGG):=block([],[cs1,cs2,cs3]:csGG,kill(w),DA0:DA,Dws:[[DA,A]],DP:aiA:[],
            for i thru length(cs3) do
                (push([DA0,A],DP),w[i]:concat(a,2*i-1),a[i]:concat(a,2*i),
                 Dw:rat((w[i]^(pp:cs3[i])-1)/(w[i]-1)),Dwf:factor2list(factor(Dw,DA))[1],
                 if (degDwf:hipow(Dwf,w[i])) = 1
                     then (w[i]:rhs(solve(Dwf,w[i])[1]),
                           if pp > 2 then printn(concat("PROU_",pp," is a member.")))
                     else (push([Dwf,w[i]],Dws),push([Dwf,w[i]],DP)),tellrat(DA),algebraic:on,
                 T:cs1[i+1],for g0 in cs1[i] while member(g:g0,T) do 0,
                 LRx:makelist(apply("*",makelist(x-assoc(t,GGRS),t,T:map(lambda([u],mul(g,u)),T))),
                              j,1,pp),printn(LRx),algebraic:off,untellrat(A),ai:0,
                 for cnt while ai = 0 do
                     (CNT:cnt,aix:rrem(sum(w[i]^mod(cnt*j,pp)*LRx[j],j,1,pp),append(Dws,DP)),
                      ai:if aix = 0 then 0 else coeff(aix,x,hipow(aix,x)),printn([[cnt],ai])),
                 printn(Dwf),
                 if degDwf = 1 then w[i]:rrem(w[i],DP)
                     else (pop(DP),push([Dwf:poly_normalize(rrem(Dwf,DP),[w[i]]),w[i]],DP)),
                 printn(Dwf),printn([ai,pp,DP]),aipp:rrem(ai^pp,DP)-a[i]^pp,a1n:num(rat(aipp)),
                 na1n:ifactors(abs(poly_content(subst(a[i] = 0,a1n),map(second,DP)))),
                 na1n:apply("*",map(lambda([s],s[1]^floor(s[2]/cs3[i])),na1n)),
                 da1n:ifactors(abs(coeff(a1n,a[i],cs3[i]))),
                 da1n:apply("*",map(lambda([s],s[1]^ceiling(s[2]/cs3[i])),da1n)),
                 printn("na1n/da1n:"),printn(na1n/da1n),
                 a1n:poly_normalize(subst(a[i] = (na1n*a[i])/da1n,a1n),[a[i]]),
                 DP:delete([DA0,A],DP),push([a1n,a[i]],DP),push([a[i]-(da1n*ai)/na1n,a[i]],aiA),
                 DA0:if hipow(ai,A) = 1 then a[i]-(da1n*ai)/na1n
                         else (DPr:reverse(DP),sDPr:map(second,DPr),
                               for j thru (lDPr:length(DPr)) do
                                   DPr:subst((vj2:sDPr[j])
                                               = vj2
                                               /mc[j]
                                                :coeff(num(rat(fj1:DPr[j][1])),vj2,hipow(fj1,vj2)),
                                             DPr),DPm:map("[",fDPr:map(first,DPr),sDPr),
                               [DA0m,aiaim]:subst(makelist((vj2:sDPr[j]) = vj2/mc[j],j,1,lDPr),
                                                  [DA0,a[i]-(da1n*ai)/na1n]),
                               print([num(rat(DA0m)),num(rat(aiaim)),A,reverse(DPm)]),
                               map(tellrat,fDPr),algebraic:on,
                               gcdA:subst(makelist((vj2:sDPr[j]) = vj2*mc[j],j,1,lDPr),
                                          gcd(aiaim,DA0m,A)),algebraic:off,map(untellrat,sDPr),
                               gcdA),printn([3,DA0,DP])),rr2:[solve(DA0,A)[1],DP],
            append([[DA0,A]],DP))

実行例 for i:1 thru 15 do print([p:PL[i],mp(p),RR6m(cs(nGG(DA)))]) の timer_info() では,[RR6,0.1656*sec,15,2.484*sec,0] の約 3/4 の処理時間になり,反復除算の簡約 rrem の回数も 210 から 112 になっています.

[[total,0.001120116300199891*sec,5503,6.164*sec,0],
       [mp,0.2176*sec,15,3.264*sec,0],[RR6m,0.1252*sec,15,1.878*sec,0],
       [nGG,0.0378*sec,15,0.5670000000000001*sec,0],
       [rrem,0.002366071428571429*sec,112,0.265*sec,0],
       [inv,6.372934697088908e-5*sec,1271,0.081*sec,0],
       [mul,1.597938144329897e-5*sec,3880,0.062*sec,0],
       [CC,6.486486486486487e-4*sec,37,0.024*sec,0],
       [mnsg,4.594594594594595e-4*sec,37,0.017*sec,0],
       [isG,1.351351351351351e-4*sec,37,0.005*sec,0],
       [factor2list,2.702702702702703e-5*sec,37,0.001*sec,0]]