Мар
6
2008
PHP-класс для расчёта прямоугольных матриц
Автор: Азарёнок Иван
Очень простой класс. Позволяет складывать, умножать и транспонировать прямоугольные матрицы любой размерности, а также вычислять определитель матриц до 7-го порядка (из-за использования рекурсивного алгоритма время расчёта эспоненциально зависит от порядка) — конечно можно рассчитать и бОльшие матрицы, но это будет длительный процесс (не забываем также, что это php
).
Итак, собственно класс:
Теперь немного посмотрим пару служебных методов и перейдем к методам операций.
Для полного счастья не хватает возможности расчёта обратной матрицы, но в нём не было необходимости
class Matrix {
private $representation = array();
private $class = __CLASS__;
const DELIMITER = ',';
const BRACKETS = '[]';
// конструктор
function __construct($a, $rnd=false) {
if(is_array($a)) {
$this->representation = $a;
} elseif(is_string($a)) {
preg_match_all('~'.quotemeta(substr(self::BRACKETS, 0, 1)).'(.*)'.
quotemeta(substr(self::BRACKETS, 1, 1)).'~U', $a, $t);
foreach($t[1] as $k=>$v) {
$t[1][$k] = explode(self::DELIMITER, $v);
foreach($t[1][$k] as $cn=>$c) $t[1][$k][$cn] = trim($c);
}
$this->representation = $t[1];
} elseif(is_int($a) && $a > 0) {
for($i=0; $i< $a; $i++) {
$this->representation[$i] = array();
for($j=0; $j< $a; $j++)
$this->representation[$i][$j] = $rnd ? mt_rand(-10, 10) : 0;
}
}
}
// возвращает единичную матрицу заданного в $n порядка
static function identity($n) {
$class = __CLASS__;
$result = new $class($n);
for($i=0; $i< $n; $i++)
$result->setel($i, $i, 1);
return $result;
}
// выполняет сложение матриц
function sum($m, $self=false) {
if(!is_object($m) || get_class($m)!==__CLASS__) return null;
if($this->dimension()!==$m->dimension()) return null;
$result = array();
$m = $m->dump(true, true);
foreach($this->representation as $ln=>$l) {
foreach($l as $cn=>$c) {
$result[$ln][$cn] = $c+$m[$ln][$cn];
}
}
if($self) {
$this->representation = $result;
return $this;
} else return new $this->class($result);
}
// выполняет умножение матрицы на число или на другую матрицу
function multiple($n, $self=false) {
$result = array();
if(is_numeric($n)) { // тут на число
foreach($this->representation as $ln=>$l) {
foreach($l as $cn=>$c) {
$result[$ln][$cn] = $c*$n;
}
}
} elseif(is_object($n) && get_class($n)===__CLASS__) { // а тут - на другую матрицу
$d1 = $this->dimension();
$d2 = $n->dimension();
if($d1[1]!==$d2[0]) return null;
for($i=0; $i< $d1[0]; $i++) {
for($j=0; $j<$d2[1]; $j++) {
$row = $this->representation[$i];
$col = $n->column($j);
foreach($row as $k=>$v) $row[$k] = $v * $col[$k];
$result[$i][$j] = array_sum($row);
}
}
} else return null;
if($self) {
$this->representation = $result;
return $this;
} else return new $this->class($result);
}
// выполняет транспонирование матрицы
function transposition($self=false) {
$result = array();
$d = $this->dimension();
for($i=0; $i< $d[1]; $i++) {
for($j=0; $j<$d[0]; $j++) {
$result[$i][$j] = $this->representation[$j][$i];
}
}
if($self) {
$this->representation = $result;
return $this;
} else return new $this->class($result);
}
// вычисляет детерминант (определитель) матрицы
// используются рекурсивные вызовы, что не есть гуд при расчете больших матриц
function determinite() {
$det = 0;
$d = $this->dimension();
if($d[0]!==$d[1]) return null;
if($d[0]>7) return null; // вот тут ограничиваем возможный порядок матрицы
if($d[0]===2) {
$det = $this->representation[0][0]*$this->representation[1][1] -
$this->representation[0][1]*$this->representation[1][0];
return $det;
}
$ks = $this->representation[0];
foreach($ks as $k=>$a) {
$mpart = $this->representation;
unset($mpart[0]);
foreach($mpart as $ln=>$l)
foreach($l as $cn=>$c)
if($cn===$k) unset($mpart[$ln][$cn]);
else $mpart[$ln] = array_values($mpart[$ln]);
$mpart = array_values($mpart);
$tmp = new $this->class($mpart);
$det += pow(-1, $k+2)*$a*$tmp->determinite();
unset($tmp);
}
return $det;
}
// возвращает массив, содержащий значение заданного столбца $n матрицы
function column($i) {
$result = array();
foreach($this->representation as $ln=>$l) {
foreach($l as $cn=>$c) {
if($cn==$i) $result[] = $c;
}
}
return $result;
}
// возвращает размерность матрицы
function dimension() {
return array(count($this->representation), count($this->representation[0]));
}
// устанавливает элемент $m x $n в значение $value
function setel($m, $n, $value=0) {
if(!isset($this->representation[$m][$n])) return null;
$this->representation[$m][$n] = $value;
return true;
}
// вывод матрицы куда-нибудь в каком-нибудь виде
function dump($return=false, $array=false) {
$tmp = $this->representation;
if($array) {
if($return) return $tmp;
else {
print_r($tmp);
return null;
}
}
$result = array();
foreach($tmp as $ln=>$l)
$result[] = substr(self::BRACKETS, 0, 1).implode(self::DELIMITER, $l).
substr(self::BRACKETS, 1, 1);
$result = implode("\r\n", $result);
if($return) return $result;
else echo $result;
}
}
Разберём его подробнее.
В качестве первого аргумента конструктора может выступать строковое представление матрицы (парсер при этом использует костанты DELIMITER и BRACKETS — соответственно, разделитель элементов в строке и ограничители строк), двумерный массив, либо целое число.
В последнем случае будет создана нулевая матрица с порядком, соответствующим этому числу. Кроме того, в этом случае можно использовать второй аргумент коструктора — булеву величину. В случае равенства её true результирующая матрица будет заполнена случайными величинами из диапазона [-10, 10].
Примеры:
$m1 = new Matrix(
' [1,0,1] '.
' [0,0,1] '.
' [0,1,1] '
);
$m2 = new Matrix(array(array(0,1,0),array(1,0,1),array(0,0,1)));
$m3 = new Matrix(3);
Метод dump предназначен для вывода матрицы. Он может принимать два аргумента. Если первый из них установлен в true, результат будет возвращен из метода (по-умолчанию — false, что приведет к отправке результата в буфер вывода). Второй аргумент определяет представление результата. Если он установлен в false (по-умолчанию), результат будет строковым представлением, использующим те самые разделители и ограничители, о которых говорилось выше. В случае true это будет обычный массив.
Для примера вызовем этот метод на только что созданных объектах:
$m1->dump();
/* выведет в браузер:
[1,0,1]
[0,0,1]
[0,1,1]
*/
$result = $m2->dump(true, true);
// присвоит переменной $result двумерный массив,
// соответствующий структуре матрицы
Думаю, пока всё понятно - метод column — возвращает заданный столбец матрицы в виде массива.
- метод dimension — возвращает массив из двух элементов: количества строк и столбцов матрицы
- метод setel — устанавливает элемент $m x $n в значение $value
$m1->sum($m2)->dump();
/*
выведет сумму матриц:
[1,1,1]
[1,0,2]
[0,1,2]
*/
echo '<br />';
$m1->multiple(2)->dump();
/*
выведет результат умножения матрицы на 2:
[2,0,2]
[0,0,2]
[0,2,2]
*/
echo '<br />';
$m1->transposition(true)->dump();
/*
выведет транспонированную матрицу:
[1,0,0]
[0,0,1]
[1,1,1]
*/
Кроме того, у класса есть статический метод identity, который возвращает объект единичной матрицы заданного порядка n:
Matrix::identity(5)->dump();
/*
выведет единичную матрицу пятого порядка:
[1,0,0,0,0]
[0,1,0,0,0]
[0,0,1,0,0]
[0,0,0,1,0]
[0,0,0,0,1]
*/
Ну и напоследок, метод determinite вернёт определитель матрицы (целое число).
Краткий обзор закончен. Надеюсь, этот класс будет кому-нибудь полезен.
Alex пишет:
Братцы! Подскажите ссылочку как раз на обратные матрицы в php !
Азарёнок Иван пишет:
Всегда пожалуйста
Я бы и класс подправил, да некогда… Так что в php как-нибудь сами портируйте, тем более решений несколько.