Jacobian matrix
I would like to add the Jacobian matrix to this package. Do you have an opinion on how to implement it? It's the partial derivative of a function evaluated at a variety of X values, with respect to each parameter. Should I make a function that returns a Matrix, or should I make it it's own object that extends the Mateix base class.
Once Matrix inverse is done I can use the Jacobian to do non-linear least squares.
I was also thinking about Square and Diagonal could also be subclasses of Matrix. Certain matrix operations only work on square matrixes, or diagonals, etc. Also, matrix decompositions are a kind of special case of a Matrix.
There are a bunch of cases where triangle matrices are expected as well.
Have you given any thought to tensors? Rank 2 tensors are represented by square matrices. Similarly, rank 1 tensors are Vectors, which are represented by an array.
I was thinking this over as I was in bed last night. I would need a really good argument for what advantages there would be to having a special square matrix class.
I can imagine a diagonal matrix having its own constructor, wherein it accepts an array. Maybe there would be some memory management savings due to storing only the array of diagonals instead of all the zeros as well. Though, once this diagonal matrix is used in some operations , it will have to be converted into a full-fledged Matrix. Can a Matrix parent class somehow self convert to a Diagonal if a test for isDiagonal() == TRUE? The calculation for the matrix determinant is certainly easier for a diagonal matrix.
A Jacobian on the other hand, is a completely different type of matrix, it's a matrix of functions, which can be evaluated with different parameters. For example, you can do something like:
$J_functions = [
[function ($x,$y){return $y * $x ** 2;}],
[function ($x,$y){return 5 * $x + sin($y);}],
]
// Tell the constructor that there are two parameters in the functions.
$J = new Jacobian($J_functions, 2);
$J->evaluate(1,2);
// The evaluate method would use numerical differentiation to produce the following and evaluate at x=1 and y=2
//[
// [2*$x*$y, $x **2],
// [5, cos($y)],
//];
//
//OR
//[
// [ 4, 1],
// [5, -.41615],
// ]
$J->determinent(4,5); // equals 2*x*y*cos(y) - 5*x²
The benefit of a Square matrix class I was thinking of in terms of type hinting. For example, if a method only worked on a Square matrix, it could type hint instead of doing a manual check: public static someMethod(Square $matrix)
However, the methods that would only work on a Square matrix, like trace and determinant, probably aren't going to take any parameters, so the benefit wouldn't be realized.
Anyways, if we were to do something like this, I'd imagine a factory method that would create the Matrices, instead of using the individual constructors. For example: $matrix = MatrixFactory::createMatrix($array);
Then, depending on the values passed in, the factory method would return a Matrix of the subtype that best fits the data. Maybe this is all over engineering and not really necessary at this time. Just an idea. For now I think we are OK to continue with just the base Matrix class.
The Jacobian matrix sounds like a good case for a new class, since it will have different private attribute variables than a regular Matrix.
Btw, I'm not so familiar with tensors, so if you have an idea of how to implement those, let me know, or go ahead and do a pull request. Don't worry if it isn't perfect first try. Code is made to be refactored in a continuous improvement process. Any ideas on the base Matrix class as well, or if you want to go ahead and implement something because I'm taking too long, go ahead.
And always, thanks for the feedback.
If the MIT license allow, I'd say grab the determinant and inverse code from that other project I linked to and just stick it in this library. That's the only thing I'm waiting for.
I'm planning on extending Matrix by two more classes. First will be a FunctionMatrix, which will be a matrix of functions. Them I'll extend this to the Jacobian Matrix, which is a special type of function matrix, where each element is a partial derivative of a function. Any preference on how parameters should be passed to the functions?
I imagine the most generic and flexible way would be something like:
$A = [
[function (array $params){
$y = $params['y'];
$x = $params['x'];
return $y * $x ** 2;
}],
[function (array $params){
$y = $params['y'];
$x = $params['x'];
$z = $params['z'];
return 5 * $x + sin($y) ** $z;
}],
]
$M = new FunctionMatrix($A);
$params = [
['x' => 1, 'y' => 2,],
['x' => 3, 'y' => 4, 'z'=> 1,],
];
$E = $M->functionEvaluate($params); // $E = [ [2], [15.0698] ]
Let me know if you see any initial problems.
I think being explicit with the parameters by using an associative array is probably a good idea. Go ahead and implement it and we can refactor as necessary.
Btw, if you use any of the Matrix private attributes, you will have to update the Matrix class and change them to protected so the inheriting class can access them.