TI-Nspire & Lua / スクリプティングのヒント / メタテーブルを使う 3 / 新しく行列型のデータを作って要素同士の四則演算ができるようにする

-- 行列同士のサイズの相違は想定しない。
-- 穴あき行列は想定しない。
-- 数値以外は想定しない。


-- 行列の要素同士の四則演算を行うためのメタメソッドを定義する。
function calc(operator)
   return function(matA, matB)
             local result = {}
             for row = 1, #matA do
                result[row] = {}
                for col = 1, #matA[row] do
                   if     operator == "+" then result[row][col] = matA[row][col] + matB[row][col]
                   elseif operator == "-" then result[row][col] = matA[row][col] - matB[row][col]
                   elseif operator == "*" then result[row][col] = matA[row][col] * matB[row][col] -- 行列積ではない
                   elseif operator == "/" then result[row][col] = matA[row][col] / matB[row][col]
                   end
                end
             end
             return Mat(result) -- 計算結果を Mat 型にして返す。
          end
end

-- 数値の符号を反転するためのメタメソッドを定義する。
function signInversion(mat)
   local result = {}
   for row = 1, #mat do
      result[row] = {}
      for col = 1, #mat[row] do
         result[row][col] = -mat[row][col]
      end
   end
   return Mat(result)
end

-- 行列を文字列としてコンソールに出力するためのメタメソッドを定義する。
-- {                               という形で出力できるようにする。
--    {1, 2, 3, ......, n},
--    {1, 2, 3, ......, n},
--    {1, 2, 3, ......, n},
-- }
function matConcat(mat)
   local string = ""
   for row = 1, #mat do
      string = string.."   {"..table.concat(mat[row], ", ").."},\n"
   end
   return "{\n"..
              string..
          "}"
end

-- 上の 3 つのメタメソッドでメタテーブルを定義する。
local matMetatable = { __add      = calc("+")     ,
                       __sub      = calc("-")     ,
                       __mul      = calc("*")     ,
                       __div      = calc("/")     ,
                       __unm      = signInversion ,
                       __tostring = matConcat
                     }

-- 新しく Mat 型のデータを作るためのコンストラクタを定義する。
function Mat(mat)
   return setmetatable(mat, matMetatable) -- 引数 mat にメタテーブル matMetatable をセットする。
end


----------------------------------------------------------------------------------------------------------
-- 確認として、Mat 型のデータを作って四則演算とコンソール出力とを実行してみる。
-- 行列に Mat() を適用すると、matMetatable というメタテーブルのセットされた Mat 型データに変換される。
-- Mat 型データは、matMetatable というメタテーブルがセットされたデータであるため、
-- + 演算子を適用すれば calc("+")() が実行され、print() を適用すれば matConcat() が実行される。
-- - 符号を適用すれば、行列に含まれている数値の符号が反転する。
----------------------------------------------------------------------------------------------------------
a = Mat({{1,2,3,4},{5,6,7,8},{9,10,11,12}})
print(a)
print(-a)
print(a+a+a)
print(-a-a-a)
print(a*-a)
print(a*-a*-a)
print(a/-a/a*-a)

f:id:ti-nspire:20170210122225p:plain