3

I have a system of equations of grade 1 to resolve in PHP. There are more equations than variables but there aren't less equations than variables.

The system would look like bellow. n equations, m variables, variables are x[i] where 'i' takes values from 1 to m. The system may have a solution or not. m may be maximum 100 and n maximum ~5000 (thousands).

I will have to resolve like a few thousands of these systems of equations. Speed may be a problem but I'm looking for an algorithm written in PHP for now.

a[1][1] * x[1] + a[1][2] * x[2] + ... + a[1][m] * x[m] = number 1
a[2][1] * x[1] + a[2][2] * x[2] + ... + a[2][m] * x[m] = number 2
...
a[n][1] * x[1] + a[n][2] * x[2] + ... + a[n][m] * x[m] = number n

There is Cramer Rule which may do it. I could make 1 square matrix of coefficients, resolve the system with Cramer Rule (by calculating matrices' determinants) and than I should check the values in the unused equations. I believe I could try Cramer by myself but I'm looking for a better solution.

This is a problem of Computational Science, http://en.wikipedia.org/wiki/Computational_science#Numerical_simulations I know there are some complex algorithms to solve my problem but I can't tell which one would do it and which is the best for my case. An algorithm would use me better than just the theory with the demonstration.

My question is, does anybody know a class, script, code of some sort written in PHP to resolve a system of linear equations of grade 1 ? Alternatively I could try an API or a Web Service, best to be free, a paid one would do it too.

Thank you

Daniel Ifrim
  • 277
  • 3
  • 12
  • 1
    Don't do Cramer's rule on matrices of this size! The determinant computations would kill you in terms of performance. Furthermore, if you have more equations than variables, you might be interested in [least-squares approximations](https://en.wikipedia.org/wiki/Linear_least_squares_(mathematics)#The_general_problem), i.e. finding the *x* which has the least sum of squared errors for all of the equations. That boils down to finding a solution to some different (and hopefully not over-determined) set of equations, so answers here wil help you with that, too. – MvG Aug 25 '16 at 12:40

4 Answers4

2

I needed exactly this, but I couldn't find determinant function, so I made one myself. And the Cramer rule function too. Maybe it'll help someone.

/**
 * $matrix must be 2-dimensional n x n array in following format
 * $matrix = array(array(1,2,3),array(1,2,3),array(1,2,3))
 */
function determinant($matrix = array()) {
    // dimension control - n x n
    foreach ($matrix as $row) {
        if (sizeof($matrix) != sizeof($row)) {
            return false;
        }
    }
    // count 1x1 and 2x2 manually - rest by recursive function
    $dimension = sizeof($matrix);
    if ($dimension == 1) {
        return $matrix[0][0];
    }
    if ($dimension == 2) {
        return ($matrix[0][0] * $matrix[1][1] - $matrix[0][1] * $matrix[1][0]);
    }
    // cycles for submatrixes calculations
    $sum = 0;
    for ($i = 0; $i < $dimension; $i++) {
        // for each "$i", you will create a smaller matrix based on the original matrix
        // by removing the first row and the "i"th column.
        $smallMatrix = array();
        for ($j = 0; $j < $dimension - 1; $j++) {
            $smallMatrix[$j] = array();
            for ($k = 0; $k < $dimension; $k++) {
                if ($k < $i) $smallMatrix[$j][$k] = $matrix[$j + 1][$k];
                if ($k > $i) $smallMatrix[$j][$k - 1] = $matrix[$j + 1][$k];
            }
        }
        // after creating the smaller matrix, multiply the "i"th element in the first
        // row by the determinant of the smaller matrix.
        // odd position is plus, even is minus - the index from 0 so it's oppositely
        if ($i % 2 == 0){
            $sum += $matrix[0][$i] * determinant($smallMatrix);
        } else {
            $sum -= $matrix[0][$i] * determinant($smallMatrix);
        }
    }
    return $sum;
}
/**
 * left side of equations - parameters:
 * $leftMatrix must be 2-dimensional n x n array in following format
 * $leftMatrix = array(array(1,2,3),array(1,2,3),array(1,2,3))
 * right side of equations - results:
 * $rightMatrix must be in format
 * $rightMatrix = array(1,2,3);
 */
function equationSystem($leftMatrix = array(), $rightMatrix = array()) {
    // matrixes and dimension check
    if (!is_array($leftMatrix) || !is_array($rightMatrix)) {
        return false;
    }
    if (sizeof($leftMatrix) != sizeof($rightMatrix)) {
        return false;
    }
    $M = determinant($leftMatrix);
    if (!$M) {
        return false;
    }
    $x = array();
    foreach ($rightMatrix as $rk => $rv) {
        $xMatrix = $leftMatrix;
        foreach ($rightMatrix as $rMk => $rMv) {
            $xMatrix[$rMk][$rk] = $rMv;
        }
        $x[$rk] = determinant($xMatrix) / $M;
    }
    return $x;
}
n0099
  • 520
  • 1
  • 4
  • 12
Uli
  • 539
  • 3
  • 11
  • This works beautifully. But it uses Cramer's rule, for which Wikipedia notes: "Though Cramer's rule is important theoretically, it has little practical value for large matrices, since the computation of large determinants is somewhat cumbersome." Indeed, I found that for 9 + variables, this code executes too slow. A faster alternative is Gaussian elimination (see my answer below). – Ivo Renkema Mar 20 '18 at 12:12
1

Wikipedia should have pseudocode for reducing the matrix representing your equations to reduced row echelon form. Once the matrix is in that form, you can walk through the rows to find a solution.

There's an unmaintained PEAR package which may save you the effort of writing the code.

Another question is whether you are looking mostly at "wide" systems (more variables than equations, which usually have many possible solutions) or "narrow" systems (more equations than variables, which usually have no solutions), since the best strategy depends on which case you are in — and narrow systems may benefit from using a linear regression technique such as least squares instead.

Victor Nicollet
  • 24,361
  • 4
  • 58
  • 89
1

This package uses Gaussian Elimination. I found that it executes fast for larger matrices (i.e. more variables/equations).

Ivo Renkema
  • 2,188
  • 1
  • 29
  • 40
0

There is a truly excellent package based on JAMA here: http://www.phpmath.com/build02/JAMA/docs/index.php

I've used it for simple linear right the way to highly complex Multiple Linear Regression (writing my own Backwards Stepwise MLR functions on top of that). Very comprehensive and will hopefully do what you need.

Speed could be considered an issue, for sure. But works a treat and matched SPSS when I cross referenced results on the BSMLR calculations.

Robbie
  • 17,605
  • 4
  • 35
  • 72