1<?php
2
3namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
4
5use Matrix\Builder;
6use Matrix\Exception as MatrixException;
7use Matrix\Matrix;
8use PhpOffice\PhpSpreadsheet\Calculation\Exception;
9use PhpOffice\PhpSpreadsheet\Calculation\Functions;
10
11class MatrixFunctions
12{
13    /**
14     * Convert parameter to matrix.
15     *
16     * @param mixed $matrixValues A matrix of values
17     */
18    private static function getMatrix($matrixValues): Matrix
19    {
20        $matrixData = [];
21        if (!is_array($matrixValues)) {
22            $matrixValues = [[$matrixValues]];
23        }
24
25        $row = 0;
26        foreach ($matrixValues as $matrixRow) {
27            if (!is_array($matrixRow)) {
28                $matrixRow = [$matrixRow];
29            }
30            $column = 0;
31            foreach ($matrixRow as $matrixCell) {
32                if ((is_string($matrixCell)) || ($matrixCell === null)) {
33                    throw new Exception(Functions::VALUE());
34                }
35                $matrixData[$row][$column] = $matrixCell;
36                ++$column;
37            }
38            ++$row;
39        }
40
41        return new Matrix($matrixData);
42    }
43
44    /**
45     * MDETERM.
46     *
47     * Returns the matrix determinant of an array.
48     *
49     * Excel Function:
50     *        MDETERM(array)
51     *
52     * @param mixed $matrixValues A matrix of values
53     *
54     * @return float|string The result, or a string containing an error
55     */
56    public static function determinant($matrixValues)
57    {
58        try {
59            $matrix = self::getMatrix($matrixValues);
60
61            return $matrix->determinant();
62        } catch (MatrixException $ex) {
63            return Functions::VALUE();
64        } catch (Exception $e) {
65            return $e->getMessage();
66        }
67    }
68
69    /**
70     * MINVERSE.
71     *
72     * Returns the inverse matrix for the matrix stored in an array.
73     *
74     * Excel Function:
75     *        MINVERSE(array)
76     *
77     * @param mixed $matrixValues A matrix of values
78     *
79     * @return array|string The result, or a string containing an error
80     */
81    public static function inverse($matrixValues)
82    {
83        try {
84            $matrix = self::getMatrix($matrixValues);
85
86            return $matrix->inverse()->toArray();
87        } catch (MatrixException $e) {
88            return (strpos($e->getMessage(), 'determinant') === false) ? Functions::VALUE() : Functions::NAN();
89        } catch (Exception $e) {
90            return $e->getMessage();
91        }
92    }
93
94    /**
95     * MMULT.
96     *
97     * @param mixed $matrixData1 A matrix of values
98     * @param mixed $matrixData2 A matrix of values
99     *
100     * @return array|string The result, or a string containing an error
101     */
102    public static function multiply($matrixData1, $matrixData2)
103    {
104        try {
105            $matrixA = self::getMatrix($matrixData1);
106            $matrixB = self::getMatrix($matrixData2);
107
108            return $matrixA->multiply($matrixB)->toArray();
109        } catch (MatrixException $ex) {
110            return Functions::VALUE();
111        } catch (Exception $e) {
112            return $e->getMessage();
113        }
114    }
115
116    /**
117     * MUnit.
118     *
119     * @param mixed $dimension Number of rows and columns
120     *
121     * @return array|string The result, or a string containing an error
122     */
123    public static function identity($dimension)
124    {
125        try {
126            $dimension = (int) Helpers::validateNumericNullBool($dimension);
127            Helpers::validatePositive($dimension, Functions::VALUE());
128            $matrix = Builder::createFilledMatrix(0, $dimension)->toArray();
129            for ($x = 0; $x < $dimension; ++$x) {
130                $matrix[$x][$x] = 1;
131            }
132
133            return $matrix;
134        } catch (Exception $e) {
135            return $e->getMessage();
136        }
137    }
138}
139