=================================================================== RCS file: /home/cvs/OpenXM/src/asir-contrib/testing/tr.rr,v retrieving revision 1.4 retrieving revision 1.8 diff -u -p -r1.4 -r1.8 --- OpenXM/src/asir-contrib/testing/tr.rr 2005/04/06 09:26:28 1.4 +++ OpenXM/src/asir-contrib/testing/tr.rr 2005/05/11 06:40:10 1.8 @@ -1,111 +1,601 @@ -/* $OpenXM: OpenXM/src/asir-contrib/testing/tr.rr,v 1.3 2005/04/03 11:05:21 takayama Exp $ */ -/* $Id: tr.rr,v 1.4 2005/04/06 09:26:28 takayama Exp $ */ +/* $OpenXM: OpenXM/src/asir-contrib/testing/tr.rr,v 1.7 2005/05/04 05:47:03 takayama Exp $ */ +/* $Id: tr.rr,v 1.8 2005/05/11 06:40:10 takayama Exp $ */ /* OpenXM版の Risa/Asir で実行のこと. OpenXM 版の関数を用いるため. */ -/* $Id: tr.rr,v 1.4 2005/04/06 09:26:28 takayama Exp $ +/* このファイルは 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)+")"); +} -def qt_node(F) { - if (type(F) == 17) F=quotetolist(F); +/* 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 tr_match0(F,P) { - dprint0("tr_match0: F="); dprint(F); - dprint0("tr_match0: P="); dprint(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) != 4) { + 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); + Node = qt.node(F); + Node2 = qt.node(P); /* pn に何の制約もなければ 2 を戻す. */ - if (Node2 == ["function","pn"]) return tr_check_pn(F,P); + 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; + N = qt.nchild(F); + if (N != qt.nchild(P)) return 0; for (I=0; I action 関数の中で再帰的に呼べば深さ優先となる. Todo: 書き換えがおこったかのフラグ. */ -def tr_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); +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); + return tr.apply_function0(Q,BindTable); } - if (type(F) != 4) return F; - Node = qt_node(F); - N = qt_nchild(F); + 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 qt_id(X) { - if (type(X) == 17) return quotetolist(X); - else return X; +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 --------------------------- */ -extern Rule_test2$ -/* " " と付けてもつけなくてもよい. 内部で rtostr してる. */ -/* Rule_test2=[quote(sin(pn("x")*@pi)),["qt_sin_int2","x"]]$ */ -Rule_test2=[quote(sin(pn(x)*@pi)),[qt_sin_int2,x]]$ + def test2() { /* 幅優先探索の場合, R0 は simplify できず. */ - Rule1=[quote(sin(pn("x")*@pi)),["qt_sin_int","x"]]; + 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]); + 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]); + R=tr.apply_rule1(R0,Rule_test2[0],Rule_test2[1]); print(print_input_form(R)); } -/* 右規則関数. sin(整数*@pi) を 0 に */ -def qt_sin_int(X) { - /* いま X は quote 型 */ - Y = quotetolist(X); - /* Todo: このようなものを作る機能は組み込みで欲しい. */ - R = "quote(sin("+listtoquote_str(Y)+"*@pi))"; - print(R); - R = eval_str(R); - /* Todo: X が 数字かどうか調べる機能も組み込みで欲しい. - */ - if (Y[0] == "internal") { - Z = eval_str(rtostr(Y[1])); - }else{ - return quotetolist(R); - } - if (type(Z) == 0) return quotetolist(quote(0)); - if ((type(Z) == 1) && (ntype(Z) == 0)) return quotetolist(quote(0)); - return quotetolist(R); -} -/* 右規則関数. sin(整数*@pi) を 0 に. 深さ優先用 */ -def qt_sin_int2(X) { - /* tr_apply_rule1 を再帰的によぶ. この方法で構文解析もかける. */ - X = tr_apply_rule1(X,Rule_test2[0],Rule_test2[1]); - Y = quotetolist(X); - R = "quote(sin("+listtoquote_str(Y)+"*@pi))"; - print(R); - R = eval_str(R); - if (qt_is_integer(Y)) return quotetolist(quote(0)); - else return quotetolist(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; } -/* --------------- end test -----------------------*/ -def qt_replace(F,Rule) { - return base_replace(F,Rule); +/* tr.simp_zero のテスト */ +def test_0() { + F = quote(x+(0*x+0)); + print(quote_input_form(F)); + return tr.simp_zero(F); } -/* F の中に不定元 X が含まれているか? - qt_dependent(quotetolist(quote(1+1/x)),x) -*/ -def qt_dependent(F,X) { - if (type(F) == 17) F = quotetolist(F); - Node = qt_node(F); - if ((F[0] == "internal") && (rtostr(F[1]) == rtostr(X))) { - return 1; - }else{ - N = qt_nchild(F); - for (I=0; I nn(f(nn(x),nn(y))) - qt_map_arg(nn,quote(1/4+f(x))) --> - テストは test4(). +/* これら以外のテストプログラムは test1-tr.rr を見よ. */ -def qt_map_arg(F,Q) { - F = rtostr(F); - if (type(Q) == 17) Q=quotetolist(Q); - if (rtostr(Q[0]) == "internal") { - T = listtoquote_str(Q); - return eval_str( "quote("+F+"("+T+"))" ); + +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