はじめに
行列やベクトルは、数値計算や三次元CGには欠かせないものです。高性能が求められる数値計算の場合には『PCとスパコンの無理矢理な比較』で紹介しているLAPACKのようなライブラリ、本格的な三次元CGの場合にはDirectXやOpenGLが備えている行列演算機能を利用しますが、そのような場合以外にも、簡単な連立一次方程式を解きたいというのはよくあることです。
本稿では、簡単な連立一次方程式を解きたいときに役立つようなPEARパッケージであるMath_VectorとMath_Matrixを紹介します。これらは機能も性能もあまり高くはありませんが(例えば固有値・固有ベクトルを求めるルーチンが実装されていません)、PHPの中で手軽に使えるものなので、きっとどこかで役に立つでしょう。
必要な環境
XAMPP for Windows 1.6.4に含まれるPHP 5.2.4で動作を確認しました。利用したPEARのパッケージは以下の通りです。
- Math_Vector 0.6.2
- Math_Matrix 0.8.5
準備
必要なパッケージを次のようにインストールします(コマンドの実行前に、c:\xampp\php\pear.iniの「"\xampp」を「"C:\xampp」に修正)。β版なので、-betaを付けています(ディレクトリはインストール先に応じて適宜読み替えてください)。Math_Matrixが依存しているMath_Vectorも一緒にインストールされます。
c: cd \xampp\php pear install --alldeps Math_Matrix-beta
Math_MatrixはまだPHP 5に対応していないのですが、サポートの終了しているPHP 4を使いたくはないので、簡便な修正を施します。PEAR/Math/Matrix.phpをエディタ等で開いて、「clone()」となっているところをすべて「clone2()」に置き換えてください。これはPHP 5で「clone」がキーワードになったことへの対応です(あまりよい対応方法ではありませんが、Math_Matrixがどのように形でPHP 5に対応してくるかが分からないのでこうしました)。
Math_VectorとMath_VectorOp
ベクタに関する処理は、Math_Vector
とMath_Vector2
, Math_Vector3
, Math_VectorOp
で実装されています(主要なものを表にまとめました)。Math_Vector
はベクタを表現するためのクラス、Math_Vector2
とMath_Vector3
はMath_Vector
を継承し2次元と3次元に特化したクラス、Math_VectorOp
はベクタの演算を静的メソッドで提供するクラスです。
メンバ名 | 概要 |
Math_Vector() | コンストラクタ。引数はオプション(配列やMath_Vector等) |
cartesianDistance(Math_Vector) | デカルト距離を返す |
get($i) | 第$i成分を返す |
getDate() | 配列を返す |
length() | ベクタの長さを返す |
normalize() | 長さを1にする |
scale($f) | 要素を$f倍する |
set($i, $val) | 第$i成分の値を$valにする |
size() | 要素数を返す |
toString() | 文字列にする |
メンバ名 | 概要 |
getX() | X成分を返す |
getY() | Y成分を返す |
setX($val) | X成分の値を$valにする |
setY($val) | Y成分の値を$valにする |
メンバ名 | 概要 |
getX() | X成分を返す |
getY() | Y成分を返す |
getZ() | Z成分を返す |
setX($val) | X成分の値を$valにする |
setY($val) | Y成分の値を$valにする |
setZ($val) | Z成分の値を$valにする |
メンバ名 | 概要 |
add(Math_Vector, Math_Vector) | ベクタの加算 |
angleBetween(Math_Vector2[3], Math_Vector2[3]) | 2つのベクタのなす角を返す(Math_Vector2, Math_Vector3のみ) |
createBasis($size, $index) | 要素数は$size、第$index成分が1、それ以外は0のベクタを返す |
createOne($size) | 要素数は$size、すべての成分が1のベクタを返す |
createZero($size) | 要素数は$size、すべての成分が0のベクタを返す |
crossProduct(Math_Vector3, Math_Vector3) | 外積を返す(Math_Vector3のみ) |
dotProduct(Math_Vector, Math_Vector) | 内積を返す |
scale($f, Math_Vector) | $f倍した新しいベクタを返す |
次のようにパッケージをロードして利用します。
require_once 'Math/Vector/Vector.php'; require_once 'Math/Vector/Vector2.php'; require_once 'Math/Vector/Vector3.php'; require_once "Math/Vector/VectorOp.php";
ベクタオブジェクトは、配列を使って生成します。
$a = new Math_Vector(array(1,2,3)); $b = new Math_Vector(range(1,10)); $c = new Math_Vector3(array(1,2,3)); echo $a->toString()."\n"; echo $b->toString()."\n"; echo $c->toString()."\n";
実行すると、生成したベクトルが文字列になって表示されます。
Vector: < 1, 2, 3 > Vector: < 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 > Vector: < 1, 2, 3 >
Vectorオブジェクトのメソッドの一部は、次のように自分自身を変更することに注意してください。
$a->scale(2); echo $a->toString()."\n";////Vector: < 2, 4, 6 >($aが変わる)
これに対して、Math_VectorOp
の静的メソッドは、もとのベクタは変更せずに、新しいベクタを生成します。
$d=Math_VectorOp::scale(2,$c); echo $c->toString()."\n";//Vector: < 1, 2, 3 >($cは変わらない) echo $d->toString()."\n";//Vector: < 2, 4, 6 >
2つのベクタのなす角を返すangleBetween
や外積を返すcrossProduct
は、Math_Vector
を引数に取ることはできません。
$a = new Math_Vector3(array(1,2,3)); $b = new Math_Vector3(array(4,5,6)); $c = Math_VectorOp::crossProduct($a,$b); echo $c->toString()."\n";//Vector: < -3, 6, -3 >
Math_Vector3
を使うべき所でMath_Vector
を使うと、たとえ要素数が3であってもエラーになります。
$a = new Math_Vector(array(1,2,3)); $b = new Math_Vector(array(4,5,6)); $c = Math_VectorOp::crossProduct($a,$b);//エラー echo $c->toString()."\n";