1

I'm trying to get the null space(kernel) of a Matrix 3x3 in Java. I've tried using Efficient Java Matrix Library (Not really needs to be that one, it's just an example. I've tried with others like apache one and obtained the same result).

This is my code:

public static void main(String[] args) {
    double[][] data = new double[][] {
        {1,2,3},
        {1,2,3},
        {1,2,3}
    };
    SimpleMatrix m = new SimpleMatrix(data);
    SimpleSVD svd = m.svd();
    SimpleMatrix nullSpace = svd.nullSpace();
    nullSpace.print();
}

The problem is that I get the Orthonormal and I want it's basis

 0,964  0,000 
-0,148 -0,832 
-0,222  0,555 

Here the basis obtained using Matlab: null(M,'r')

-2    -3
 1     0
 0     1
Tsyvarev
  • 60,011
  • 17
  • 110
  • 153
Ricardo
  • 337
  • 5
  • 16

1 Answers1

0

So I found an answer by myself. I noticed that MATLAB scripts can be edited and opened the one I wanted and then made a implementation of the same script in Java. I'll post it here to everybode that could need it but keep into account that this script is a not so well made copy of the original .m one.

I use Apache Matrix Library as told before in addition with two more things with it.

  1. I use this class that I found navigating into apache test files.
  2. I use with it this function that a guy made in another java question (just the rref function but with some changes to it, So I will add it here aswell as my kernel function)

Now the code(I placed most of it inside MatrixFunctions.java for saving space mostly):

MatrixFunctions.java

//...Some other stuff
    public static double[][] rref(double[][] matrix, List<Integer> pivot) {
        double[][] rref = new double[matrix.length][];
        for (int i = 0; i < matrix.length; i++)
            rref[i] = Arrays.copyOf(matrix[i], matrix[i].length);

        int r = 0;
        for (int c = 0; c < rref[0].length && r < rref.length; c++) {
            int j = r;
            for (int i = r + 1; i < rref.length; i++)
                if (Math.abs(rref[i][c]) > Math.abs(rref[j][c]))
                    j = i;
            if (Math.abs(rref[j][c]) < 0.00001)
                continue;

            //Remember where we pivoted
            pivot.add(j);

            double[] temp = rref[j];
            rref[j] = rref[r];
            rref[r] = temp;

            double s = 1.0 / rref[r][c];
            for (j = 0; j < rref[0].length; j++)
                rref[r][j] *= s;
            for (int i = 0; i < rref.length; i++) {
                if (i != r) {
                    double t = rref[i][c];
                    for (j = 0; j < rref[0].length; j++)
                        rref[i][j] -= t * rref[r][j];
                }
            }
            r++;
        }

        return rref;
    }

    public static RealMatrix kernel(RealMatrix A) {
        int m = A.getRowDimension(), n = A.getColumnDimension();
        List<Integer> pivot = new ArrayList<>();
        RealMatrix R = MatrixUtils.createRealMatrix(MatrixFunctions.rref(A.getData(), pivot));
        int r = pivot.size();
        HashMap<Integer, Integer> nopiv = new HashMap<>();
        for (int i = 0; i < n; i++) {
            nopiv.put(i, i+1);
        }
        for (Integer e : pivot) {
            if (nopiv.containsValue(e+1))
                nopiv.remove(e, e+1);
        }
        //Remove ones contained inside pivot from nopiv
        for (int j = 0; j < r; j++) {
            int index = pivot.get(j);
            if (nopiv.containsValue(index))
                nopiv.remove(index);
        }

        double[][] Z = new double[n][n-r];    

        //Add 1(s) in the main diagonal
        if (n > r) {
            double[][] eye = new double[n-r][n-r];
            for (int i = 0; i < eye.length; i++) {
                for (int j = 0; j < eye[i].length; j++) {
                    if (j==i)
                        eye[i][j] = 1;
                    else
                        eye[i][j] = 0;
                }
            }
            //Add eye in Z
            Integer[] loc = nopiv.values().toArray(new Integer[nopiv.size()]);
            for (int i = 0; i < loc.length; i++) {
                int index = loc[i];
                for (int j = 0; j < Z[0].length; j++) {
                    Z[index-1][j] = eye[i][j];
                }
            }

            if (r > 0) {
                for (int i = 0; i < r; i++) {
                    int indexi = pivot.get(i);
                    for (int j = 0; j < loc.length; j++) {
                        int indexd = loc[j]-1;
                        Z[indexi][j] = -R.getEntry(i, indexd);
                    }
                }
            }
        }

        return MatrixUtils.createRealMatrix(Z);
    }
//...NnanananananaBATMAN!!

An finally a main to test it:

    public static void main(String[] args) {
        double[][] matrix = new double[][] {
            {1,2,3},
            {1,2,3},
            {1,2,3}
        };
        //Calculate
        RealMatrix A = MatrixFunctions.kernel(MatrixUtils.createRealMatrix(matrix));
        System.out.println(A); // displays C formatted appropriately
    }

And the output:

Array2DRowRealMatrix{
 {-2.0,-3.0},
 {1.0,0.0},
 {0.0,1.0}
}

Which fits the one I needed....

I tested this function with more elements just to make sure and it worked pretty well. But I cannot ensure that it will work fine all the time and surely it's not the most efficient method.

Ricardo
  • 337
  • 5
  • 16