@Override
    public Matrix run(Matrix matrix, Matrix free) {
        if (matrix.getWidth() != matrix.getHeight()) {
            throw new IllegalArgumentException("matrix width != matrix height");
        }
        if (free.getWidth() != 1) {
            throw new IllegalArgumentException("width != 1");
        }
        if (free.getHeight() != matrix.getWidth()) {
            throw new IllegalArgumentException("free height != matrix width");
        }
        this.matrix = matrix;
        this.free = free;
        Matrix curGradient = getGradient(approximation);
        Matrix curP = curGradient.scale(-1);
        Matrix curRes = new Matrix(approximation);
        for (int i = 0; i < matrix.getWidth(); i++) {
            if (less(curRes)) {
                break;
            }
            curRes = curRes.add(curP.scale(alpha(curP, curGradient)));
            curGradient = getGradient(curRes);
            curP = nextP(curP, curGradient);
        }
        return curRes;
    }