load("gr"); load("sp"); module taji_alc; localf cpfd$ localf snoether$ localf laurent_expansion$ localf residue$ localf invpow$ localf rem_formula$ localf solve_ode_cp$ localf solve_ode_cp_ps$ localf fbt$ localf invfbt$ localf multiply_for_f_adic_poly$ localf snoether_s$ localf snoether_m$ localf residue_s$ localf residue_m$ localf small_invpow$ localf via_minipoly$ localf invpoly$ localf invpoly2$ localf invpow2$ localf rem_formula_s$ localf rem_formula_m$ localf h1$ localf h2$ localf crt_newton$ localf crt_newton_2$ localf crt_newton_n$ localf residue_s_for_solve_ode_cp$ localf residue_m_for_solve_ode_cp$ localf diff_rat$ localf diff_rat2$ localf solve_ode_cp2$ localf solve_ode_cp_ps2$ localf unite_fctr_list$ /* 有理関数の部分分数分解を求めるプログラム */ /* 第1引数 NUM : 多項式 */ /* 第2引数 DEN : 多項式 or リスト */ /* (注意) リストで入力する場合, 既約チェック, 有理式の約分, 整数係数化は行わない. */ /* オプション指定 switch case 0 : cpfd 分子は有理数係数多項式 case 1 : cpfd 分子は整数係数化リスト case 2 : cpfd キーデータを表示 case 10 : pfd 分子は有理数係数多項式 case 11 : pfd 分子は整数係数化リスト case 21 : cpfdのタイミングデータ case 22 : pfdのタイミングデータ case "t" : タイミングデータ default : case 0 */ /* 2007.05.17 invpowを実装, 戻り値を選択式にする. */ /* 2007.06.02 switchをオプション指定にした. */ /* 2007.06.19 戻り値のリストをreverseした. */ /* 2007.11.05 戻り値を[分子,[分母の因子,重複度]]と表現することにした. */ def cpfd(NUM,DEN){ /* Swのdefaultの設定 */ Sw=getopt(switch); if(Sw!=1&&Sw!=2&&Sw!=10&&Sw!=11&&Sw!=21&&Sw!=22&&Sw!="t") Sw=0; igcdcntl(3); T0=time(); /* 簡約化 */ if(type(DEN)==4){ Num=NUM; D=cons([1,1],DEN); }else{ Gcd=gcd(NUM,DEN); Num=sdiv(NUM,Gcd); Den=sdiv(DEN,Gcd); D=fctr(Den); } X=var(D[1][0]); Len=length(D); Ans=[]; AA=1;for(I=1;I20){T1=time();print(T1[0]-T0[0]);} for(II=1;II20){print("========== PFD of "+rtostr(D[II])+" ==========");T2=time();} F=D[II][0]; L=D[II][1]; DF=diff(F,X); B=0; for(I=1;I20){T3=time();print(T3[0]-T2[0]);} P=[0,0]; for(I=0;I20){T4=time();print(T4[0]-T3[0]);} /* ========== CPFD ========== */ if(Sw==0||Sw==1||Sw==2||Sw==21){ U=multiply_for_f_adic_poly(U,Num,F,IRD); if(Sw==21){T5=time();print(T5[0]-T4[0]);} if(Sw==0){ UU=newvect(L); T=1;for(I=0;I0;I--) AL=cons([UU[D[II][1]-I],[F,I]],AL); AL=reverse(AL); Ans=cons(AL,Ans); }else if(Sw==1){ UD=newvect(L); T=1; AL=[]; for(I=0;I20){print("========== total time ==========");EndT=time();return EndT[0]-T0[0];} return Ans; } /* 分子多項式の処理 */ def multiply_for_f_adic_poly(Alist,B,F,IRD){ if(type(B)<2) return Alist*B; LenA=length(Alist); Blist=[]; T=1; for(I=0;I における Poly の逆冪(逆元のM乗)を求めるプログラム */ /* オプション指定 switch case 0 : 有理数係数の多項式で返す case 1 : 整数係数化リストで返す case "t" : タイミングデータ default : case 0 */ /* 戻り値 : 逆冪 */ /* 2006.10.31 small_invpowを改良(擬剰余+約分)詳しくはa1 */ /* 2006.11.22 u^Rのところの計算法を変更 */ /* 2007.05.10 関数名変更 inversePolyn → invpoly */ /* 2007.05.10 invpolyの戻り値をリストにする. */ /* 2007.05.10 最初にPolyの共通整数をくくりだしておく処理を追加. */ /* 2007.05.19 戻り値を選択式にした. */ /* 2007.06.02 switchをオプション指定にした. */ /* 2007.06.19 戻り値のリストをreverseした. */ /* 2007.06.28 途中計算での戻り値の型のミスマッチのバグ修正 */ def invpow(Poly,F,M){ /* Swのdefaultの設定 */ Sw=getopt(switch); if(Sw!=1&&Sw!="t") Sw=0; if(M==1){return invpoly(Poly,F,Sw);} else if(M における Poly の逆元計算 */ def invpoly(Poly,F,Sw){ X=var(F); Alg=newalg(F); Inv=simpalg(1/subst(Poly,X,Alg)); InvR=algtorat(Inv); if(var(InvR)!=0) InvR=subst(InvR,var(InvR),X); if(Sw==1||Sw=="t"){ InvRN=ptozp(InvR); InvRD=sdiv(InvRN,InvR); return [InvRN,InvRD]; }else{ return InvR; } } /* 剰余体 K[x]/ における Poly の逆元計算 */ /* invpolyと同じ機能であるがアルゴリズムが違う(一長一短) */ def invpoly2(Poly,F,Sw){ X=var(F); Alg=newalg(F); set_field([Alg]); Inv=dalgtoalg(1/algtodalg(subst(Poly,X,Alg))); InvR=algtorat(Inv); if(var(InvR)!=0) InvR=subst(InvR,var(InvR),X); if(Sw==1||Sw=="t"){ InvRN=ptozp(InvR); InvRD=sdiv(InvRN,InvR); return [InvRN,InvRD]; }else{ return InvR; } } /* 検算用 */ def invpow2(Poly,F,LP){ /* Swのdefaultの設定 */ Sw=getopt(switch); if(Sw!=1&&Sw!="t") Sw=0; T0=time(); Q=invpoly(Poly,F,Sw); A=Q[0];LL=LP;M=1;UN=1;ZD=1; while(1){ if(LP%2==1){Z=srem(UN*A,F);UN=ptozp(Z);ZD*=sdiv(UN,Z)*M;} LP=idiv(LP,2);if(LP==0) break; B=srem(A*A,F);A=ptozp(B);M=sdiv(A,B)*M*M; } UD=Q[1]^LL*ZD; if(Sw=="t"){T1=time();return(T1[0]-T0[0]);} if(Sw==1){ return [UN,UD]; }else{ return UN/UD; } } /* Fxを与えたときの剰余公式を求めるプログラム */ /* 引数 Fx : 既約分解されたリスト */ /* リストで入力する場合は, D=[[既約因子,重複度,零点の記号],..]] */ /* 入力例 rem_formula([[x^2+1,2,z1],[x^3-x-1,2,z2]]); */ /* f(x)の冪で展開は一因子用である. 多因子の場合は, 自動的にxで整理される */ /* オプション指定 switch case 0 : xの冪で整理 & list case 10 : f(x)の冪で展開 & list case 20 : xの冪で整理 & symbolic case "t" : タイミングデータ default : case 0 */ /* 2007.05.16 hermite_rem と hermite_rem_g を一つにまとめた. */ /* 2007.05.30 関数名変更 hermite_rem → rem_formula */ /* 2007.06.02 switchをオプション指定にした. */ /* 2007.11.05 symbolicな戻り値のオプションの番号を 1 → 20 に変更. */ def rem_formula(Fx){ /* Swのdefaultの設定 */ Sw=getopt(switch); if(Sw!=10&&Sw!=20&&Sw!="t") Sw=0; /* 展開 */ D=Fx; X=var(D[0][0]); Len=length(D); Fx=1;for(I=0;I