Очень простой класс. Позволяет складывать, умножать и транспонировать прямоугольные матрицы любой размерности, а также вычислять определитель матриц до 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
Действия над матрицами. Для сложения используется метод sum, первым аргументом которого должен быть передан объект матрицы, с которой мы складываем текущую. Второй аргумент влияет на то, где будет находится результат. Если он установлен в false (по-умолчанию), то результат суммирования будет возвращён методом в виде нового объекта класса. Если же он равен true, результат заменит собой текущую матрицу и вернёт ссылку на этот же объект. Замечу, что это справедливо также для методов multiple и transposition (в последнем это единственный аргумент). Для умножения матрицы на число или на другую матрицу используется метод multiple. Соответственно, первым аргументом ему передается нужный множитель. Метод transposition выполняет операцию транспонирования над матрицей. Немного примеров:
$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 вернёт определитель матрицы (целое число). Краткий обзор закончен. Надеюсь, этот класс будет кому-нибудь полезен.

Метки: ,

Комментариев: 2 “PHP-класс для расчёта прямоугольных матриц”

  1. Братцы! Подскажите ссылочку как раз на обратные матрицы в php !

  2. Братцы! Подскажите ссылочку как раз на обратные матрицы в php !

    Всегда пожалуйста :)
    Я бы и класс подправил, да некогда… Так что в php как-нибудь сами портируйте, тем более решений несколько.