php_iovm-0.6.0

php_iovm-0.6.0.tgz

  • Io-2008-01-20で動作確認。
  • IoVectorクラスをチューニング、SPLへの依存を廃止。
    • ArrayAccess, Countableをimplementする代わりに独自のハンドラを実装。
    • []で要素を追加できるようになった。
  • RINIT_FUNCTION, RSHUTDOWN_FUNCTIONが値を返していなかったのを修正。
  • 他少々。

IoState

バージョン0.4.0からPHP 5.3/6.0の名前空間をサポートしました。
名前空間はIoのPHPオブジェクトのsetNamespaceメソッドで設定、namespaceメソッドで取得できます。setNamespaceメソッドを引数なしで呼び出したり、空文字列や"::"を与えたときはルート名前空間にリセットします。PHPオブジェクトを複製することでマルチ名前空間もできます。

ns1 := PHP clone setNamespace("Zend")
ns2 := PHP clone setNamespace("Hoge")


ZvalオブジェクトではUTF-8のシーケンスに変換するtoUTF8メソッドと、UTF-16のシーケンスに変換するtoUTF16メソッドを追加しました。toUTF16メソッドはPHP6でのみ使えます。


また、クラス定数やスタティックプロパティ・メソッドを扱うためのPHPClassオブジェクトを新たに設けました。PHPClassオブジェクトの実体はstdClassです。任意のクラスに対応したPHPClassオブジェクトの複製を得るにはPHPオブジェクトのclassメソッドを使います。
例えば、このPHPコードは

$dt1 = new DateTime;
$dt2 = new DateTime("-1 day");
echo $dt1->format(DateTime::W3C), PHP_EOL;
echo $dt2->format(DateTime::W3C), PHP_EOL;

これまでも、このように書けていましたが、

dt1 := PHP new("DateTime")
dt2 := PHP new("DateTime", "-1 day")
dt1 call("format", dt1 const("W3C")) println
dt2 call("format", dt2 const("W3C")) println

PHPClassオブジェクトを使うと、こう書くこともできます。

dt := PHP class("DateTime")
dt1 := dt new
dt2 := dt new("-1 day")
dt1 call("format", dt const("W3C")) println
dt2 call("format", dt const("W3C")) println

# この場合はconstメソッドよりzConstメソッドを使った方が効率が良いです。


以下はPHPClassオブジェクトのメソッド(スロット)一覧です。

メソッド 引数 戻り値 説明
asString - Sequence クラス名を取得する。
name -
new 任意のオブジェクト × 任意の数 Zval (新たなインスタンス) インスタンスを生成する。
引数はコンストラクタに渡される。
call Sequence (+ 任意のオブジェクト × 任意の数) Sequence, Number, List, Map, Date
(型に応じて自動変換)
指定されたスタティックメソッドをコールする。
二番目以降の引数はメソッドに渡される。
参照を引数にとるメソッドでは、引数がZvalオブジェクトの場合だけ値が更新される。
const Sequence クラス定数を取得する。
var Sequence スタティックプロパティを取得する。
zCall Sequence (+ 任意のオブジェクト × 任意の数) Zval (PHPの値をそのまま格納) 指定されたスタティックメソッドをコールする。
二番目以降の引数はメソッドに渡される。
参照を引数にとるメソッドでは、引数がZvalオブジェクトの場合だけ値が更新される。
zConst Sequence クラス定数を取得する。
zVar Sequence スタティックプロパティを取得する。

PHPClassオブジェクトの追加に伴い、Zvalオブジェクトのcall, const, varの各メソッドはレシーバのPHP変数としての型がオブジェクトでない場合はエラーとなるように仕様変更しました。


これ以外のオブジェクトの説明はバージョン0.3.0についてのエントリに書いています。

IoVector

32ビット実数のベクトル演算をするためのクラス。IoStateとは別に独立して使える。IoのVectorオブジェクトではなく、float32のUArrayのラッパー。SIMDをサポートしているため、演算が速い。
foreach文で要素に順番にアクセス、count関数で要素数をカウント、角括弧で要素へのアクセスができる。

API一覧
関数 説明
IoVector iovector([mixed $x[, mixed $y[, mixed $z[, ...]]]]) IoVectorオブジェクトを作成する。引数はIoVector::__construct()と同じ。

!マークつきのメソッドは破壊的なメソッドで、戻り値は自分自身です。

メソッド 説明
public void __construct([mixed $x[, mixed $y[, mixed $z[, ...]]]]) コンストラクタ。各引数がIoVectorなら全要素を追加、配列なら全要素を実数として追加、それ以外は実数として追加する。
public string toString(void) ベクトルの文字列表記を取得する。
public string __toString(void) toString()のエイリアス
public array toArray(void) ベクトルの全要素を実数の配列として取得する。
public IoVector duplicate(void) ベクトルを複製する。
public IoVector dup(void) duplicate()のエイリアス
public IoVector add(IoVector or float $v)! ベクトルを加算する。引数が実数なら全要素に同じ値を加算する。
public IoVector subtract(IoVector or float $v))! ベクトルを減算する。引数が実数なら全要素に同じ値を減算する。
public IoVector multiply(IoVector or float $v))! ベクトルを乗算する。引数が実数なら全要素に同じ値を乗算する。
public IoVector divide(IoVector or float $v))! ベクトルを除算する。引数が実数なら全要素に同じ値を除算する。
public IoVector sub(IoVector or float $v))! subtract()のエイリアス
public IoVector mul(IoVector or float $v))! multiply()のエイリアス
public IoVector div(IoVector or float $v))! divide()のエイリアス
public IoVector crossProduct(IoVector $v) ベクトルの外積を求める。
public float dotProduct(IoVector $v) ベクトルの内積を求める。
public float distanceTo(IoVector $v) 各要素の差の2乗の和の平方根を求める。
sqrt(pow($v1[0] - $v2[0], 2) + pow($v1[1] - $v2[1], 2) + ...)
public IoVector sin(void)! 各要素の正弦を求める。
public IoVector cos(void)! 各要素の余弦を求める。
public IoVector tan(void)! 各要素の正接を求める。
public IoVector asin(void)! 各要素の逆正弦を求める。
public IoVector acos(void)! 各要素の逆余弦を求める。
public IoVector atan(void)! 各要素の逆正接を求める。
public IoVector sinh(void)! 各要素の双曲線正弦を求める。
public IoVector cosh(void)! 各要素の双曲線余弦を求める。
public IoVector tanh(void)! 各要素の双曲線正接を求める。
public IoVector exp(void)! 各要素を自然対数の底に累乗する。
public IoVector log(void)! 各要素の自然対数を求める。
public IoVector log10(void)! 各要素の常用対数を求める。
public IoVector square(void)! 各要素の平方を求める。
public IoVector sqrt(void)! 各要素の平方根を求める。
public IoVector ceil(void)! 各要素の端数を切り上げる。
public IoVector fllor(void)! 各要素の端数を切り捨てる。
public IoVector abs(void)! 各要素の絶対値を求める。
public IoVector round(void)! 各要素を四捨五入する。
public IoVector normalize(void)! 各要素を各要素の2乗の和の平方根で割る。
$d = sqrt($v[0]*$v[0] + $v[1]*$v[1] + ...); $v[0] /= $d; $v[1] /= $d; ...
public bool equals(IoVector $v) 全要素が等しいか調べる。
public bool isZero(void) 全要素が0か調べる。
public float sum(void) 全要素の和を求める。
public float product(void) 全要素の積を求める。
public float max(void) 最大値を求める。
public float min(void) 最小値を求める。
public IoVector push(float $n)! 末尾に値を追加する。
public IoVector unshift(float $n)! 先頭に値を追加する。
public IoVector pop([float &$n])! 末尾から値を取り除く。取り除いた値は$nに代入される。
public IoVector shift([float &$n])! 先頭から値を取り除く。取り除いた値は$nに代入される。
public IoVector sort(void)! 昇順に並び替える。
public IoVector range(int $start, int $size) インデックス$startから$size個の要素のベクトルを取得する。
public IoVector slice(int $start, int $end) インデックス$startからインデックス$endの直前までの要素のベクトルを取得する。
public IoVector copy(IoVector $v)! 内容を置き換える。
public IoVector merge(IoVector $v)! 末尾にベクトルを追加する。
public IoVector setSize(int $size)! 素数を変更する。増えた要素の値は0.0。
public int size(void) 素数を取得する。
使用例

マンデルブロ集合の描画によるベンチマーク結果。(参考: http://www.timestretch.com/FractalBenchmark.html)
環境は Mac OS X 10.4.11 (Core 2 Duo 2.33GHz)
ベクトル版は爆速ですね (単精度だけど)。

C gcc-4.0.1 (-O3) 0.022 sec. 1.00 x
C gcc-4.0.1 (-O0) 0.030 sec. 1.36 x
PHP 5.2.5 IoVector (出力バッファリングあり) 0.121 sec. 5.50 x
Io 20080120 Vector 0.214 sec. 9.73 x
PHP 5.2.5 IoVector (出力バッファリングなし) 0.251 sec. 11.41 x
Python 2.5.1 (参考) 2.374 sec. 107.91 x
PHP 5.2.5 3.936 sec. 178.91 x
Io 20080120 37.733 sec. 1715.14 x

PHP+IoVector版のソースコード:

<?php
/**
 * IoVector version of Fractal Benchmark.
 * See also http://www.timestretch.com/FractalBenchmark.html
 */

class Mandelbrot
{
    const MAX_ITERATIONS = 1000;

    static public function benchmark()
    {
        $d1 = microtime(true);
        self::draw();
        $d2 = microtime(true);
        printf("\nPHP + IoVector Elapsed %f\n", $d2 - $d1);
    }

    static public function draw()
    {
        $cr = new IoVector;
        $ci = new IoVector;

        for ($y = -39; $y < 39; $y++) {
            $z  = $y / 40.0 - 0.5;
            for ($x = -39; $x < 39; $x++) {
                $cr[] = $z;
                $ci[] = $x / 40.0;
            }
        }

        $temp = new IoVector;
        $temp->setSize(count($cr));
        $zr = clone $temp;
        $zi = clone $temp;
        $zr2 = clone $temp;
        $zi2 = clone $temp;

        for ($i = 0; $i < self::MAX_ITERATIONS; $i++) {
            $temp->copy($zr)->multiply($zi);
            $zr2->copy($zr)->multiply($zr);
            $zi2->copy($zi)->multiply($zi);
            $zr->copy($zr2)->subtract($zi2)->add($cr);
            $zi->copy($temp)->multiply(2)->add($ci);
        }

        $result = $zi2->duplicate()->add($zr2);

        $i = 0;
        for ($y = -39; $y < 39; $y++) {
            echo "\n";
            for ($x = -39; $x < 39; $x++) {
                echo (!is_nan($result[$i]) && $result[$i] > 0) ? '*' : ' ';
                $i++;
            }
        }
    }
}

if (PHP_SAPI == 'cli' && realpath($_SERVER['SCRIPT_FILENAME']) == __FILE__) {
    ob_start();
    Mandelbrot::benchmark();
}