はじめに
行列やベクトルは、数値計算や三次元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";
