読者です 読者をやめる 読者になる 読者になる

好き勝手に・げーあにん?

ファミコンと同い年の社会人ヌルオタの日記

行列の乗算の文字列表示

プログラム Ruby

回転行列からオイラー角を求めるために紙に計算をしてたら、あってんだか間違ってるんだかわけわからなくなってきたので作った。

結果の方をあとで使うので、まず結果から貼っとく。

[["XYZ",
  [["cosY*conZ", "-cosY*sinZ", "sinY"],
   ["sinX*sinY*conZ+cosX*sinZ", "-sinX*sinY*sinZ+cosX*cosZ", "-sinX*conY"],
   ["-cosX*sinY*conZ+sinX*sinZ", "cosX*sinY*sinZ+sinX*cosZ", "cosX*conY"]]],
 ["XZY",
  [["conZ*cosY", "-sinZ", "conZ*sinY"],
   ["cosX*sinZ*cosY+sinX*sinY", "cosX*cosZ", "cosX*sinZ*sinY+-sinX*conY"],
   ["sinX*sinZ*cosY+-cosX*sinY", "sinX*cosZ", "sinX*sinZ*sinY+cosX*conY"]]],
 ["YXZ",
  [["cosY*conZ+sinY*sinX*sinZ", "-cosY*sinZ+sinY*sinX*cosZ", "sinY*cosX"],
   ["cosX*sinZ", "cosX*cosZ", "-sinX"],
   ["-sinY*conZ+conY*sinX*sinZ", "sinY*sinZ+conY*sinX*cosZ", "conY*cosX"]]],
 ["YZX",
  [["cosY*conZ", "-cosY*sinZ*cosX+sinY*sinX", "cosY*sinZ*sinX+sinY*cosX"],
   ["sinZ", "cosZ*cosX", "-cosZ*sinX"],
   ["-sinY*conZ", "sinY*sinZ*cosX+conY*sinX", "-sinY*sinZ*sinX+conY*cosX"]]],
 ["ZXY",
  [["conZ*cosY+-sinZ*sinX*sinY", "-sinZ*cosX", "conZ*sinY+sinZ*sinX*conY"],
   ["sinZ*cosY+cosZ*sinX*sinY", "cosZ*cosX", "sinZ*sinY+-cosZ*sinX*conY"],
   ["-cosX*sinY", "sinX", "cosX*conY"]]],
 ["ZYX",
  [["conZ*cosY", "-sinZ*cosX+conZ*sinY*sinX", "sinZ*sinX+conZ*sinY*cosX"],
   ["sinZ*cosY", "cosZ*cosX+sinZ*sinY*sinX", "-cosZ*sinX+sinZ*sinY*cosX"],
   ["-sinY", "conY*sinX", "conY*cosX"]]]]

出すのに使ったプログラム

#! ruby -Ku
# coding: utf-8


# 行列の乗算を文字列にして見たかった

require 'matrix'

class String
  alias :plus :+
  alias :mul :*

  def +(x)
    x = x.to_s
    case x
    when '0'; self.clone
    else    ; "#{self}+#{x}"
    end
  end

  def *(x)
    x = x.to_s
    case x
    when '0'; 0
    when '1'; self.clone
    else
      # 単項マイナスをキレイにする
      if x[0] == '-'
        if self[0] == '-'
          # - * -
          "#{self[1..-1]}*#{x[1..-1]}"
        else
          # + * -
          "-#{self}*#{x[1..-1]}"
        end
      else
        # + * +
        "#{self}*#{x}"
      end
    end
  end
end

class Fixnum
  alias :plus :+
  alias :mul :*

  def +(x)
    case x
    when String
      self == 0 ? x.clone : self.to_s + x
    else
      self == 0 ? x : self.plus(x)
    end
  end

  def *(x)
    case x
    when String
      case self
      when 0; 0
      when 1; x.clone
      else  ; "#{self}*#{x}"
      end
    else
      self.mul(x)
    end
  end
end


rx = Matrix[
  [  1,      0,      0],
  [  0, 'cosX','-sinX'],
  [  0, 'sinX', 'cosX'],
]

ry = Matrix[
  [ 'cosY',  0,'sinY'],
  [      0,  1,     0],
  ['-sinY',  0,'conY'],
]

rz = Matrix[
  [ 'conZ','-sinZ',  0],
  [ 'sinZ', 'cosZ',  0],
  [      0,      0,  1],
]

a = {
  'XYZ'=>rx*ry*rz,
  'XZY'=>rx*rz*ry,
  'YXZ'=>ry*rx*rz,
  'YZX'=>ry*rz*rx,
  'ZXY'=>rz*rx*ry,
  'ZYX'=>rz*ry*rx,
}


# 表示の前に元に戻す
class String
  alias :+ :plus
  alias :* :mul
end

require 'pp'
pp a.map{|k,v| [k, v.to_a]}

野良プログラムすぎるので細かいことは気にしない方向で。 * と + で文字列連結して、ちょっと小細工してキレイに見えるようにしただけ。1.8 でも動くけど、order hash な 1.9 がよいよい。

/ にも対応したら逆数とかも見れるようになるんだろうか。めんどくさいからやらないけど。