@Override
    public Matrix run(Matrix coef, Matrix free) {
        assert(free.getWidth() == 1);
        Matrix b1 = new Matrix(coef.getHeight(), coef.getWidth());
        Matrix b2 = new Matrix(coef.getHeight(), coef.getWidth());
        Matrix ieb = new Matrix(coef.getHeight(), coef.getWidth());
        Matrix c = new Matrix(coef.getHeight(), 1);
        for (int i = 0; i < coef.getHeight(); i++) {
            for (int j = 0; j < coef.getWidth(); j++) {
                if (i == j) {
                    b1.set(i, j, 0);
                } else {
                    b1.set(i, j, -coef.get(i, j) / coef.get(i, i));
                }
            }
            c.set(i, 0, free.get(i, 0) / coef.get(i, i));
        }
        bNorm = b1.getNorm();
        for (int i = 0; i < b1.getHeight(); i++) {
            for (int j = i + 1; j < b1.getWidth(); j++) {
                b2.set(i, j, b1.get(i, j));
                b1.set(i, j, 0);
            }
        }
        b1Norm = b1.getNorm();
        b2Norm = b2.getNorm();
        for (int i = 0; i < b1.getHeight(); i++) {
            for (int j = 0; j < i; j++) {
                ieb.set(i, j, -b1.get(i, j));
            }
            ieb.set(i, i, 1);
        }
        ieb = ieb.getInverse();
        Matrix prev;
        Matrix cur = approximation;
        iteration = 0;
        do {
            iteration++;
            prev = cur;
            cur = ieb.multiply(b2.multiply(prev).add(c));
        } while (!itIsTimeToStop(cur, prev));
        
        return cur;
    }