/* $OpenXM: OpenXM/src/asir-contrib/testing/tr.rr,v 1.8 2005/05/11 06:40:10 takayama Exp $ */ /* $Id: tr.rr,v 1.26 2005/05/08 08:37:46 taka Exp $ */ /* OpenXM版の Risa/Asir で実行のこと. OpenXM 版の関数を用いるため. */ /* このファイルは quotetolist でリストに変換したデータに対して パターンマッチおよびそれを応用した変形を行う. tr.oxt の仕様とことなり quotetolist で変換したものを扱う. テストプログラムのため効率は無視. (append の多用, 無駄な2重呼び出し, など)) */ extern Debug$ Debug=0$ extern Debug2$ /* For tr.apply_or_rules. とても便利. */ Debug2=0$ def dprint(X) { if (Debug) print(X); } def dprint0(X) { if (Debug) print(X,0); } extern Debug2$ Debug2=0$ /* quotetolist の逆関数. ただし文字列で */ def listtoquote_str(L) { return quote_input_form_quote_list(L); } /* quotetolist の逆関数. quote を戻す */ def listtoquote(L) { return eval_str("quote("+quote_input_form_quote_list(L)+")"); } /* unix の uniq に同じ */ def uniq(L) { N = length(L); if (N > 0) A = [L[0]]; else A=[]; for (I=1; I nn(f(nn(x),nn(y))) qt.map_arg(nn,quote(1/4+f(x))) --> テストは test4(). */ def map_arg(F,Q) { F = rtostr(F); if (type(Q) == O_QUOTE) Q=quotetolist(Q); if (rtostr(Q[0]) == "internal") { T = listtoquote_str(Q); return eval_str( "quote("+F+"("+T+"))" ); } /* node の子供を F で評価する. */ N = qt.nchild(Q); L = []; for (I=0; I 1/2 へ この実装は効率は悪い. */ def cancel_number(Q) { if (type(Q) == O_LIST) Q=listtoquote(Q); if (qt.is_rational(Q)) { Ans = eval_quote(Q); return objtoquote(Ans); } A = quote_to_funargs(Q); N = length(A); R=[]; for (I=N-1; I>= 0; I--) { if (type(A[I]) == O_QUOTE) R = cons(qt.cancel_number(A[I]),R); else R = cons(A[I],R); } return funargs_to_quote(R); } /* 先頭に - があるか形式的にみる. -a+b -3 -34/y 等. */ def is_minus(Q) { if (type(Q) == O_LIST) Q=listtoquote(Q); A = quote_to_funargs(Q); if (A[0] == I_MINUS) return 1; if (A[0] == I_BOP) { if (qt.is_minus(A[2])) return 1; else return 0; } return 0; } /* 無条件に ( ) を加える. */ def add_paren0(Q) { A = [I_PAREN,Q]; return funargs_to_quote(A); } /* +- 等に ( ) を加える. 動作が不審なので bug があるかも. */ def add_paren(Q) { if (type(Q) == O_LIST) Q=listtoquote(Q); A = quote_to_funargs(Q); /* この処理は毎度使うのでまとめた方がいいのでは? */ N = length(A); R=[]; for (I=N-1; I>= 0; I--) { if (type(A[I]) == O_QUOTE) R = cons(qt.add_paren(A[I]),R); else R = cons(A[I],R); } A = R; if (A[0] == I_BOP) { if (get_function_name(A[1]) == "+") { if (qt.is_minus(A[3])) { /* x+-y ==> x+(-y) */ A2 = [I_BOP,A[1], qt.add_paren(A[2]), qt.add_paren0(A[3])]; return funargs_to_quote(A2); } }else if (get_function_name(A[1]) == "*" || get_function_name(A[1]) == "/") { if (qt.is_minus(A[2])) { /* -x*y ==> (-x)*y */ A2 = [I_BOP,A[1], qt.add_paren0(A[2]), qt.add_paren(A[3])]; return funargs_to_quote(A2); } } } return funargs_to_quote(A); } /* vars の真似. この関数も 変数の出現回数分のリストを作るので効率わるい. */ def vars(Q) { R = [ ]; if (type(Q) == O_LIST) Q=listtoquote(Q); A = quote_to_funargs(Q); if (A[0] == I_FORMULA) { if (type(A[1]) == O_P) { R = cons(A[1],R); } } /* この処理は毎度使うのでまとめた方がいいのでは? */ N = length(A); for (I=1; I hm(Q)=h, rest(Q)=r*r2, hop(Q)="*". ただし rest で quote は 左結合的に変更. flatten_quote(). */ def hm(Q) { if (type(Q) == O_LIST) Q = listtoquote(Q); A=quote_to_funargs(Q); if (A[0] == I_BOP) { Op = get_function_name(A[1]); if (Op == "+") { return A[2]; }else if (Op == "-") { return A[2]; }else if (Op == "*") { return A[2]; }else if (Op == "/") { return A[2]; }else if (Op == "^") { return A[2]; } } return Q; } def rest(Q) { if (type(Q) == O_LIST) Q = listtoquote(Q); A=quote_to_funargs(Q); if (A[0] == I_BOP) { Op = get_function_name(A[1]); if (Op == "+") { return flatten_quote(A[3],"+"); }else if (Op == "-") { return "not implented to return -A[3]"; }else if (Op == "*") { return flatten_quote(A[3],"*"); }else if (Op == "/") { return flatten_quote(A[3],"/"); }else if (Op == "^") { return flatten_quote(A[3],"^"); }else return 0; } return 0; } def hop(Q) { if (type(Q) == O_LIST) Q = listtoquote(Q); A=quote_to_funargs(Q); if (A[0] == I_BOP) return get_function_name(A[1]); return 0; } def input_form(Q) { T = type(Q); if ((T == O_VECT) || (T == O_MAT)) { Q = matrix_matrix_to_list(Q); } if (type(Q) == O_LIST) { A = []; for (I=length(Q)-1; I>=0; I--) { A = cons(qt.input_form(Q[I]),A); } if ((T == O_VECT) || (T == O_MAT)) { A = matrix_list_to_matrix(A); } return A; } if (T == O_QUOTE) return quote_input_form(Q); return rtostr(Q); } endmodule$ module tr; localf match0$ localf check_pn$ localf make_binding$ localf rp$ localf apply_function0$ localf apply_rule1$ localf rp_flag$ localf apply_rule1_flag$ localf apply_or_rules$ static Rule_test2$ /* int_sin2 が利用 */ /* " " と付けてもつけなくてもよい. 内部で rtostr してる. . が付いたら付けるしかない. */ /* Rule_test2=[quote(sin(pn("x")*@pi)),["qt.sin_int2","x"]]$ */ Rule_test2=[quote(sin(pn(x)*@pi)),["qt.sin_int2",x]]$ /* リスト F が リスト P に(先頭からの比較で)マッチしたら 1. そうでないから 0. 幅優先探索. Todo: P に任意関数を含む仕組みはまだ実装してない. */ def match0(F,P) { dprint0("tr.match0: F="); dprint(F); dprint0("tr.match0: P="); dprint(P); if (type(F) != type(P)) return 0; if (type(F) == O_QUOTE) {F=quotetolist(F); P=quotetolist(P);} if (type(F) != O_LIST) { if (F == P) return 1; else return 0; } Node = qt.node(F); Node2 = qt.node(P); /* pn に何の制約もなければ 2 を戻す. */ if (Node2 == ["function","pn"]) return tr.check_pn(F,P); if (Node != Node2) return 0; N = qt.nchild(F); if (N != qt.nchild(P)) return 0; for (I=0; I action 関数の中で再帰的に呼べば深さ優先となる. Todo: 書き換えがおこったかのフラグ. */ def rp(F,P,Q) { dprint0("tr.rp, F="); dprint(F); dprint0("tr.rp, P="); dprint(P); dprint0("tr.rp, Q="); dprint(Q); if (tr.match0(F,P)) { BindTable = tr.make_binding(F,P); dprint0("BindTable="); dprint(BindTable); return tr.apply_function0(Q,BindTable); } if (type(F) != O_LIST) return F; Node = qt.node(F); N = qt.nchild(F); Ans = Node; for (I=0; I "+RR+" by "); print(listtoquote_str(L));} if (Debug2) print("-------- end of tr.apply_rule1_flag ------------ "); return [Flag,eval_str(RR)]; } def apply_or_rules(Q,R) { Flag = 1; N = length(R); while (Flag) { Flag = 0; for (I=0; I 0 */ Rule2=[quote(pn(y)*0), ["qt.zero"]]; /* any*0 --> 0 */ Rule3=[quote(0/pn(y)), ["qt.zero"]]; /* 0/any --> 0 */ Rule4=[quote(pn(y)+0), ["qt.id",y]]; /* any+0 --> any */ Rule5=[quote(0+pn(y)), ["qt.id",y]]; /* 0+any --> any */ Rule6=[quote(-0), ["qt.zero",y]]; /* -0 --> 0 */ Rule7=[quote((0)), ["qt.zero",y]]; /* (0) --> 0 */ Rule8=[quote(1*pn(y)), ["qt.id",y]]; /* 1*any --> any */ Rule9=[quote(pn(y)*1), ["qt.id",y]]; /* any*1 --> any */ R=tr.apply_or_rules(R0,[Rule1,Rule2,Rule3,Rule4,Rule5, Rule6,Rule7, Rule8, Rule9]); return R; } def simp_unary(R0) { Rule1=[quote(pn(x))+quote(-pn(y)), ["qt.minus",x,y]]; /* x+-y -> x-y */ Rule2=[quote(-(-pn(x))), ["qt.id",x]]; /* -(-x) --> x */ Rule3=[quote(pn(x)-(-pn(y))), ["qt.plus",x,y]]; /* x-(-y) --> x+y */ R=tr.apply_or_rules(R0,[Rule1,Rule2,Rule3]); return R; } /* test_1() はサンプルテスト. */ def simp_sin(R0) { Rule1=[quote(sin(pn(x)*@pi)),["qt.sin_int",x]]; /* sin(整数*@pi) --> 0 */ Rule2=[quote(0*pn(y)), ["qt.zero"]]; /* 0*any --> 0 */ Rule3=[quote(pn(y)*0), ["qt.zero"]]; /* any*0 --> 0 */ Rule4=[quote(pn(y)+0), ["qt.id",y]]; /* any+0 --> any */ Rule5=[quote(0+pn(y)), ["qt.id",y]]; /* 0+any --> any */ Rule6=[quote(sin(0)), ["qt.zero"]]; /* sin(0) --> 0 */ Rule7=[quote(cos(0)), ["qt.one"]]; /* cos(0) --> 1 */ /* print(print_input_form(R0)); */ R=tr.apply_rule1_flag(R0,Rule1[0],Rule1[1]); /* print([R[0],print_input_form(R[1])]); */ R=tr.apply_or_rules(R0,[Rule1,Rule2,Rule3,Rule4,Rule5,Rule6,Rule7]); return R; } endmodule$ /* ------------ test --------------------------- */ def test2() { /* 幅優先探索の場合, R0 は simplify できず. */ Rule1=[quote(sin(pn("x")*@pi)),["qt.sin_int","x"]]; R0 = quote(1+sin(sin(2*@pi)*@pi)*sin(@pi/2)); print(print_input_form(R0)); R=tr.apply_rule1(R0,Rule1[0],Rule1[1]); print(print_input_form(R)); print("-----------------------"); /* 次のように書くと深さ優先で書ける */ R0 = quote(1+sin(sin(2*@pi)*@pi)*sin(@pi/2)); print(print_input_form(R0)); R=tr.apply_rule1(R0,Rule_test2[0],Rule_test2[1]); print(print_input_form(R)); } /* tr.check_pn の動作テスト */ def test2b() { Rule=[quote(sin(pn(x,qt.is_integer(x))*@pi)),["qt.zero"]]$ R0 = quote(1+sin(2*@pi)*sin(a*@pi));; print(print_input_form(R0)); R=tr.apply_rule1(R0,Rule[0],Rule[1]); return R; } /* tr.simp_zero のテスト */ def test_0() { F = quote(x+(0*x+0)); print(quote_input_form(F)); return tr.simp_zero(F); } /* tr.simp_sin のテスト */ def test_1() { F = quote(sin(sin(0))+sin(0)); print(quote_input_form(F)); return tr.simp_sin(F); } /* ------------------------------------------------ */ /* Index 付き変数を実現する */ def idxtov(V,I) { if (type(I) == 5) I=vtol(I); if (type(I) != O_LIST) I=[I]; if (type(V) != 2) V=rtostr(V); return util_v(V,I); } def vtoidx(V) { A = util_index(V); if (length(A[1]) == 0) return [A[0]]; if (length(A[1]) == 1) return [A[0],A[1][0]]; return A; } /* これら以外のテストプログラムは test1-tr.rr を見よ. */ module qt; localf dtoq$ localf qtod$ /* it has not yet been implemented. */ localf etoq$ localf hc_etov$ /* Distributed polynomial to quote qt.dtoq(dp_ptod((x-y)^3,[x,y]),[]); */ def dtoq(F,V) { if (F == 0) return quote(0); N = length(dp_etov(F)); if (N > length(V)) { for (I=length(V); I length(V)) { for (I=length(V); I