35    private array $matrix = [];
 
   39    public function offsetExists($offset) : 
bool{
 
   40        return isset($this->matrix[(
int) $offset]);
 
   43    #[\ReturnTypeWillChange] 
   44    public function offsetGet($offset){
 
   45        return $this->matrix[(int) $offset];
 
   48    public function offsetSet($offset, $value) : 
void{
 
   49        $this->matrix[(int) $offset] = $value;
 
   52    public function offsetUnset($offset) : 
void{
 
   53        unset($this->matrix[(
int) $offset]);
 
   59    public function __construct(
int $rows, 
int $columns, array $set = []){
 
   60        $this->rows = max(1, $rows);
 
   61        $this->columns = max(1, $columns);
 
 
   68    public function set(array $m) : void{
 
   69        for($r = 0; $r < $this->rows; ++$r){
 
   70            $this->matrix[$r] = [];
 
   71            for($c = 0; $c < $this->columns; ++$c){
 
   72                $this->matrix[$r][$c] = $m[$r][$c] ?? 0;
 
 
   77    public function getRows() : int{
 
   81    public function getColumns() : int{
 
   82        return $this->columns;
 
   85    public function setElement(
int $row, 
int $column, 
float $value) : void{
 
   86        if($row > $this->rows or $row < 0 or $column > $this->columns or $column < 0){
 
   87            throw new \InvalidArgumentException(
"Row or column out of bounds (have $this->rows rows $this->columns columns)");
 
   89        $this->matrix[$row][$column] = $value;
 
   92    public function getElement(
int $row, 
int $column) : float{
 
   93        if($row > $this->rows or $row < 0 or $column > $this->columns or $column < 0){
 
   94            throw new \InvalidArgumentException(
"Row or column out of bounds (have $this->rows rows $this->columns columns)");
 
   97        return $this->matrix[$row][$column];
 
  100    public function isSquare() : bool{
 
  101        return $this->rows === $this->columns;
 
  104    public function add(Matrix $matrix) : Matrix{
 
  105        if($this->rows !== $matrix->getRows() or $this->columns !== $matrix->getColumns()){
 
  106            throw new \InvalidArgumentException(
"Matrix does not have the same number of rows and/or columns");
 
  108        $result = 
new Matrix($this->rows, $this->columns);
 
  109        for($r = 0; $r < $this->rows; ++$r){
 
  110            for($c = 0; $c < $this->columns; ++$c){
 
  111                $element = $matrix->getElement($r, $c);
 
  112                $result->setElement($r, $c, $this->matrix[$r][$c] + $element);
 
  119    public function subtract(Matrix $matrix) : Matrix{
 
  120        if($this->rows !== $matrix->getRows() or $this->columns !== $matrix->getColumns()){
 
  121            throw new \InvalidArgumentException(
"Matrix does not have the same number of rows and/or columns");
 
  123        $result = clone $this;
 
  124        for($r = 0; $r < $this->rows; ++$r){
 
  125            for($c = 0; $c < $this->columns; ++$c){
 
  126                $element = $matrix->getElement($r, $c);
 
  127                $result->setElement($r, $c, $this->matrix[$r][$c] - $element);
 
  134    public function multiplyScalar(
float $number) : Matrix{
 
  135        $result = clone $this;
 
  136        for($r = 0; $r < $this->rows; ++$r){
 
  137            for($c = 0; $c < $this->columns; ++$c){
 
  138                $result->setElement($r, $c, $this->matrix[$r][$c] * $number);
 
  145    public function divideScalar(
float $number) : Matrix{
 
  146        $result = clone $this;
 
  147        for($r = 0; $r < $this->rows; ++$r){
 
  148            for($c = 0; $c < $this->columns; ++$c){
 
  149                $result->setElement($r, $c, $this->matrix[$r][$c] / $number);
 
  156    public function transpose() : Matrix{
 
  157        $result = new Matrix($this->columns, $this->rows);
 
  158        for($r = 0; $r < $this->rows; ++$r){
 
  159            for($c = 0; $c < $this->columns; ++$c){
 
  160                $result->setElement($c, $r, $this->matrix[$r][$c]);
 
  171        if($this->columns !== $matrix->getRows()){
 
  172            throw new \InvalidArgumentException(
"Expected a matrix with $this->columns rows"); 
 
  174        $c = $matrix->getColumns();
 
  175        $result = 
new Matrix($this->rows, $c);
 
  176        for($i = 0; $i < $this->rows; ++$i){
 
  177            for($j = 0; $j < $c; ++$j){
 
  179                for($k = 0; $k < $this->columns; ++$k){
 
  180                    $sum += $this->matrix[$i][$k] * $matrix->getElement($k, $j);
 
  182                $result->setElement($i, $j, $sum);
 
 
  193        if($this->isSquare() !== true){
 
  194            throw new \LogicException(
"Cannot calculate determinant of a non-square matrix");
 
  196        return match($this->rows){
 
  197            1 => $this->matrix[0][0],
 
  199                $this->matrix[0][0] * $this->matrix[1][1] -
 
  200                $this->matrix[0][1] * $this->matrix[1][0],
 
  202                $this->matrix[0][0] * $this->matrix[1][1] * $this->matrix[2][2] +
 
  203                $this->matrix[0][1] * $this->matrix[1][2] * $this->matrix[2][0] +
 
  204                $this->matrix[0][2] * $this->matrix[1][0] * $this->matrix[2][1] -
 
  205                $this->matrix[2][0] * $this->matrix[1][1] * $this->matrix[0][2] -
 
  206                $this->matrix[2][1] * $this->matrix[1][2] * $this->matrix[0][0] -
 
  207                $this->matrix[2][2] * $this->matrix[1][0] * $this->matrix[0][1],
 
  208            default => 
throw new \LogicException(
"Not implemented")
 
 
  212    public function __toString() : string{
 
  214        for($r = 0; $r < $this->rows; ++$r){
 
  215            $s .= implode(
",", $this->matrix[$r]) . 
";";
 
  218        return "Matrix({$this->rows}x{$this->columns};" . substr($s, 0, -1) . 
")";