原です。 >けいじゅ@日本ラショナルソフトウェアです. ># 私信ですが、横浜トリエンナーレ来ます? 某同居人は行きます。私はびんぼで行けまへん。(^^; >>私は、石塚さんの [ruby-math:00597] での det に関する > >>の説明が int/int->rational 派の意見では最も説得力を感じました。確かに >>基本的な演算、メソッドは、将来のポリモルフィズムの有効性が生かされるよ >>う、統一性のある仕様を持ってほしいですねえ。 > >これは、現状のままでは良くないって表明なんですよね? 逆に、まあそれはそれとして、今のままでも悪くないって思っているんで すけど。(^^;; >>mean はこれに加えて値域もはっきりさせないといけない、という例ですね。 >>もっとも、定義域と値域だけではまだ不十分で、最終的には関数の仕様をきち >>んと定義して明らかにしておくべき、という当たり前の結論になってしまう。 >>他の例では gcd(6*x*y, 9*x*y) は、整数上の多項式と考えれば、3*x*y だが、 >>有理数上の多項式としては x*y、Q(y)係数の x の多項式としては x となり、 >>gcd の引数だけで決まるわけではないわけです。 > >うーん. 最後の例はちょっとって気がしますが... 単に、メソッド名だけでの仕様が決定できない、っていう例なんだけど、 突拍子もなかったかしら。 >例えば、演算プロトコル``/''があるとして、本来、その意味(メソッド) >は、(定義域1、定義域2、値域)の組みによって確定しなくてはいけない。 >現行のRubyは、定義域1(とcoerceによって定義域2)だけでメソッドを決 >定しているのが良くない。と、言っているんですね? 更に「定義域1、定義域2、値域」の組みが与えられてもまだ不十分な場 合がある、って言ってるつもりでした。そしてそれは特に Ruby に落ち 度があるわけでもないと。 >>具体的には、例えば Matrix#det を考えてみます。これは sum の話にかなり >>似ていて、行列の直和の det は det の積になりますから、(0, 0) 行列の >>det は、考えている系の積の単位元であるべきなのに、0 要素の det は何を >>返してよいかわからない。つまり普通使われている「行列式」はΣと同じく、 >>数学的な意味での写像ではないわけです。 > >えと. 考えている系と言っていますが、これを演算系と呼ぶことにしましょうか、 >すると、演算系毎にMatrix#detが存在するわけですね? そう考えるべきだと思います。そうでない、汎用の det があってもいい けど、その汎用性には限界があり(今回の場合は int 成分のケース)、 汎用性を過大に重要視して、システムの仕様を変えてしまうのもどうか なあ、と思うわけです。 >でも、演算系の種類によってはアルゴリズムの共有はできるわけですよね? 今回 >のdetの例では、演算プロトコル``/''が、 > > a * x = b > >を満たすような系であれば、成立します。 > >つまり, まとめると > >* まず演算系というものがあって、その上で各メソッドは初めて定義できる >* 演算系間でアルゴリズムの共有はできるはず 「演算系」って面白い言葉ですね。「代数系」をコンパクトにした感じ の概念でしょうか。石塚さんの言っていることは良く分かります。つま り現状の Matrix#det は「体」であれば共有できるアルゴリズムなわけ ですね。繰り返しになるけど、私はアルゴリズムを共有させるために、 数値システムを変えるというのは、やりすぎな気がするわけです。程度 の問題なんだけど。 で、これととても関係あるような、あまりないような話なんですけど、 この前に言っていた「ユークリッド環」で共有できるアルゴリズムで 作ってみたらどうなるか、と、Matrix#det の変種を作ってみました。 (極小の変更なので、改良の余地はあります。) class Matrix def determinant2 return 0 unless square? size = row_size - 1 a = to_a det = 1 k = 0 begin if (akk = a[k][k]) == 0 i = k begin return 0 if (i += 1) > size end while a[i][k] == 0 a[i], a[k] = a[k], a[i] # akk = a[k][k] det *= -1 end (k + 1).upto(size) do |i| # q = a[i][k] / akk q = a[i][k] / a[k][k] # (k + 1).upto(size) do k.upto(size) do |j| a[i][j] -= a[k][j] * q end unless a[i][k].zero? a[i], a[k] = a[k], a[i] det *= -1 redo end end # det *= akk det *= a[k][k] # end while (k += 1) <= size det end alias det2 determinant2 end det2 は Rational 成分でも Integer 成分でもうく動きます。Float は だめですが。もちろん、Rational の場合には、自明な整除をする無駄が 若干あります。一方、整数成分の場合は、有理数化してオリジナルの det に放り込むより数倍速いみたいです。 これは、実質的に、(k + 1).upto(size) を k.upto(size) に変えて unless a[i][k].zero? a[i], a[k] = a[k], a[i] det *= -1 redo end を書き加えただけなんですが、期せずして内部でユークリッドの互除法 が行われていて「掃き出し法あるところ互除法あり」というのはあるか もしれないですね。det の他の方法としては、十分大きな素数 p を法と して計算し、後で整数に戻すというのも有効かと思います。 それはそれとして、上の例で * 演算系間でアルゴリズムの共有はできるが、アルゴリズムは一通りでない * アルゴリズムを変えると、適用できる演算系の範囲も効率も微妙に変わる という、やや曖昧な当たり前のような^^; 結論が読みとれると思います。 ゆえに、ある特定のアルゴリズムを中心に考えて、演算プロトコルの仕 様はこうあるべしと決めるのは、本末転倒になる場合がある、と思うわ けです。 >>この様に「数」を相対的に見る立場がどの程度一般に通用する考え方かちょっ >>とわかりません。でも計算機でプログラミングをする人には受け入れやすいみ >>たいだけど。 > >これはなかなかすごい主張していますよね. > >現行のRubyは、1つの絶対的演算系があって, 数を拡張するといえどもそれに従 >わない演算系(例えばmathn)は互換性との面で問題になりますね。つまり, 数の >相対化というのは, そういった系もちゃんと認めるようにしようってことですよ >ね. いえ、Ruby の絶対的演算系すなわち組み込みの演算系も、単なる道具に 過ぎないので、Integer が有理数と違う振る舞いをしてもいいじゃない か、という事なんですが、、、 >結局、Rubyとしては複数の演算系が共存できるような仕組みを作ったらどうか? >と言っているんでしょうね? 今それを求めているわけではないです。先の事は分からないけど。:-)