You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@commons.apache.org by "Tom Milac (JIRA)" <ji...@apache.org> on 2010/09/14 01:21:33 UTC

[jira] Created: (MATH-416) EigenDecompositionImpl.getV() returns eigen matrix with indeterminate determinant

EigenDecompositionImpl.getV() returns eigen matrix with indeterminate determinant
---------------------------------------------------------------------------------

                 Key: MATH-416
                 URL: https://issues.apache.org/jira/browse/MATH-416
             Project: Commons Math
          Issue Type: Improvement
    Affects Versions: 2.1
         Environment: Mac OS X 10.6.4
            Reporter: Tom Milac



A call to EigenDecompositionImpl.getV() returns a RealMatrix the columns of which are the eigenvectors of the matrix with which EigenDecompositionImpl is constructed. Because EigenDecompositionImpl works only with real, symmetric matrices, the eigenvectors (columns) returned are orthogonal.  In addition, the eigenvectors are normalized to have 2-norm = 1. Unfortunately, for 3x3 input matrices, the determinant of the eigenvector matrix is indeterminate, sometimes +1 and other times -1.  The -1 output can be 
'repaired' simply by multiplying the matrix by -1.  Example code is included below.

Because the columns are eigenvectors, the result with either determinant is correct.  However, in the case that the matrix returned is to be interpreted as specifying a coordinate system, the principal axes of a body in my case,  the +1 result specifies a right-handed coordinate for the principal coordinate system of the body, and the -1 result specifies a left-handed coordinate system.  Once discovered, this indeterminacy is easy to deal with, but nevertheless an inconvenience.

I believe it would improve EigenDecompositionImpl.getV() to return an eigenvector matrix with a consistent determinant = +1.

Tom Milac

---------------------------------------------------------

import org.apache.commons.math.geometry.NotARotationMatrixException;
import org.apache.commons.math.geometry.Rotation;
import org.apache.commons.math.linear.Array2DRowRealMatrix;
import org.apache.commons.math.linear.EigenDecompositionImpl;
import org.apache.commons.math.linear.InvalidMatrixException;
import org.apache.commons.math.linear.LUDecompositionImpl;
import org.apache.commons.math.linear.RealMatrix;

/**
 *
 * @author Tom Milac
 */
public class BugReport {

    /**
     * Moment of inertia tensor #1.
     */
    public static final double[][] MOI1 =
            {{128.52722633757742, -29.11849805467669, 8.577081342861376},
             {-29.11849805467669, 521.3276639228706,  35.512665035385666},
             {8.577081342861376,  35.512665035385666, 490.2479495932442}};

    /**
     * Moment of inertia tensor #2.
     */
    public static final double[][] MOI2 =
            {{440.09350934414175, 44.23154125186637, -9.41455073681743},
             {44.23154125186637,  387.1291457565648, -38.07596950448303},
             {-9.41455073681743, -38.07596950448303, 762.0451513430822}};

    /**
     * Constructor.
     */
    public BugReport() {
    }

    /**
     * Main.
     */
    public static void main(String[] args) {

        // Compute the principal axes (eigenvectors) of the #1 moment
        // of inertia tensor.
        RealMatrix moi1  = new Array2DRowRealMatrix(MOI1);
        RealMatrix axes1 = null;
        EigenDecompositionImpl eigenDecompositionImpl = null;
        try {
            eigenDecompositionImpl = new EigenDecompositionImpl(moi1, 0.0d);

            axes1 = eigenDecompositionImpl.getV();
        } catch (InvalidMatrixException ex) {
            System.err.println("MOI1: InvalidMatrixException thrown.");
            System.err.println("Exiting ...");
            System.exit(-1);
        }

        // Compute the principal axes (eigenvectors) of the #2 moment
        // of inertia tensor.
        RealMatrix moi2  = new Array2DRowRealMatrix(MOI2);
        RealMatrix axes2 = null;
        try {
            eigenDecompositionImpl = new EigenDecompositionImpl(moi2, 0.0d);

            axes2 = eigenDecompositionImpl.getV();
        } catch (InvalidMatrixException ex) {
            System.err.println("MOI2: InvalidMatrixException thrown.");
            System.err.println("Exiting ...");
            System.exit(-1);
        }

        // Determinant of axes 1 eigenvector matrix = -1.  If the matrix
        // is interpreted as a Rotation, throws and Exception.
        System.out.print("Determinant of the #1 moment of inertia tensor = ");
        System.out.println(new LUDecompositionImpl(axes1).getDeterminant());

        try {
            Rotation axes1_rotation = new Rotation(axes1.getData(), 1.0E-7);
        } catch (NotARotationMatrixException ex) {
            System.out.println("NotARotationMatrixException thrown for 'axes1'.");
        }

        System.out.println();

        // Determinant of axes 2 eigenvector matrix = +1.
        System.out.print("Determinant of the #2 moment of inertia tensor = ");
        System.out.println(new LUDecompositionImpl(axes2).getDeterminant());

        try {
            Rotation axes2_rotation = new Rotation(axes2.getData(), 1.0E-7);
        } catch (NotARotationMatrixException ex) {
            System.out.println("NotARotationMatrixException thrown for 'axes2'.");
        }
    }
}

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Commented: (MATH-416) EigenDecompositionImpl.getV() returns eigen matrix with indeterminate determinant

Posted by "Tom Milac (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/MATH-416?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12909955#action_12909955 ] 

Tom Milac commented on MATH-416:
--------------------------------

  Hello Dimitri,
On reflection - and as you likely already realize - I recognize that 
simply nailing
down the determinant of the result returned by getV() is insufficient in 
the general
NxN case.  What I think one would like is that the columns, ordered as 
they are
from left to right by the value of the eigenvalues, be oriented in a 
predictable fashion,
ideally in a "right-hand rule" fashion generally used in three 
dimensions.  The result
would then be immediately useful as a coordinate system.  To achieve 
this would
require that the N-dimensional analog of the cross product of N-1 
eigenvectors point
in the direction of the remaining eigenvector cyclically across the 
matrix of eigenvectors.

I think your suggestion for a separate call is good one if the 
orientation of the eigenvectors
returned can be guaranteed.  If not, then I suggest that it would be 
best not to change
the API but to simply note in the documentation that the eigenvectors 
cannot be assumed to
have any particular orientation.

Parenthetically, I don't see the need for the getVt() call in the 
EigenDecomposition interface.
It seems that a call to getV().transpose() (in the RealMatrix interface) 
should be sufficient.

Thank you, Dimitri.
Tom  Milac



> EigenDecompositionImpl.getV() returns eigen matrix with indeterminate determinant
> ---------------------------------------------------------------------------------
>
>                 Key: MATH-416
>                 URL: https://issues.apache.org/jira/browse/MATH-416
>             Project: Commons Math
>          Issue Type: Improvement
>    Affects Versions: 2.1
>         Environment: Mac OS X 10.6.4
>            Reporter: Tom Milac
>            Assignee: Dimitri Pourbaix
>
> A call to EigenDecompositionImpl.getV() returns a RealMatrix the columns of which are the eigenvectors of the matrix with which EigenDecompositionImpl is constructed. Because EigenDecompositionImpl works only with real, symmetric matrices, the eigenvectors (columns) returned are orthogonal.  In addition, the eigenvectors are normalized to have 2-norm = 1. Unfortunately, for 3x3 input matrices, the determinant of the eigenvector matrix is indeterminate, sometimes +1 and other times -1.  The -1 output can be 
> 'repaired' simply by multiplying the matrix by -1.  Example code is included below.
> Because the columns are eigenvectors, the result with either determinant is correct.  However, in the case that the matrix returned is to be interpreted as specifying a coordinate system, the principal axes of a body in my case,  the +1 result specifies a right-handed coordinate for the principal coordinate system of the body, and the -1 result specifies a left-handed coordinate system.  Once discovered, this indeterminacy is easy to deal with, but nevertheless an inconvenience.
> I believe it would improve EigenDecompositionImpl.getV() to return an eigenvector matrix with a consistent determinant = +1.
> Tom Milac
> ---------------------------------------------------------
> import org.apache.commons.math.geometry.NotARotationMatrixException;
> import org.apache.commons.math.geometry.Rotation;
> import org.apache.commons.math.linear.Array2DRowRealMatrix;
> import org.apache.commons.math.linear.EigenDecompositionImpl;
> import org.apache.commons.math.linear.InvalidMatrixException;
> import org.apache.commons.math.linear.LUDecompositionImpl;
> import org.apache.commons.math.linear.RealMatrix;
> /**
>  *
>  * @author Tom Milac
>  */
> public class BugReport {
>     /**
>      * Moment of inertia tensor #1.
>      */
>     public static final double[][] MOI1 =
>             {{128.52722633757742, -29.11849805467669, 8.577081342861376},
>              {-29.11849805467669, 521.3276639228706,  35.512665035385666},
>              {8.577081342861376,  35.512665035385666, 490.2479495932442}};
>     /**
>      * Moment of inertia tensor #2.
>      */
>     public static final double[][] MOI2 =
>             {{440.09350934414175, 44.23154125186637, -9.41455073681743},
>              {44.23154125186637,  387.1291457565648, -38.07596950448303},
>              {-9.41455073681743, -38.07596950448303, 762.0451513430822}};
>     /**
>      * Constructor.
>      */
>     public BugReport() {
>     }
>     /**
>      * Main.
>      */
>     public static void main(String[] args) {
>         // Compute the principal axes (eigenvectors) of the #1 moment
>         // of inertia tensor.
>         RealMatrix moi1  = new Array2DRowRealMatrix(MOI1);
>         RealMatrix axes1 = null;
>         EigenDecompositionImpl eigenDecompositionImpl = null;
>         try {
>             eigenDecompositionImpl = new EigenDecompositionImpl(moi1, 0.0d);
>             axes1 = eigenDecompositionImpl.getV();
>         } catch (InvalidMatrixException ex) {
>             System.err.println("MOI1: InvalidMatrixException thrown.");
>             System.err.println("Exiting ...");
>             System.exit(-1);
>         }
>         // Compute the principal axes (eigenvectors) of the #2 moment
>         // of inertia tensor.
>         RealMatrix moi2  = new Array2DRowRealMatrix(MOI2);
>         RealMatrix axes2 = null;
>         try {
>             eigenDecompositionImpl = new EigenDecompositionImpl(moi2, 0.0d);
>             axes2 = eigenDecompositionImpl.getV();
>         } catch (InvalidMatrixException ex) {
>             System.err.println("MOI2: InvalidMatrixException thrown.");
>             System.err.println("Exiting ...");
>             System.exit(-1);
>         }
>         // Determinant of axes 1 eigenvector matrix = -1.  If the matrix
>         // is interpreted as a Rotation, throws and Exception.
>         System.out.print("Determinant of the #1 moment of inertia tensor = ");
>         System.out.println(new LUDecompositionImpl(axes1).getDeterminant());
>         try {
>             Rotation axes1_rotation = new Rotation(axes1.getData(), 1.0E-7);
>         } catch (NotARotationMatrixException ex) {
>             System.out.println("NotARotationMatrixException thrown for 'axes1'.");
>         }
>         System.out.println();
>         // Determinant of axes 2 eigenvector matrix = +1.
>         System.out.print("Determinant of the #2 moment of inertia tensor = ");
>         System.out.println(new LUDecompositionImpl(axes2).getDeterminant());
>         try {
>             Rotation axes2_rotation = new Rotation(axes2.getData(), 1.0E-7);
>         } catch (NotARotationMatrixException ex) {
>             System.out.println("NotARotationMatrixException thrown for 'axes2'.");
>         }
>     }
> }

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Commented: (MATH-416) EigenDecompositionImpl.getV() returns eigen matrix with indeterminate determinant

Posted by "Dimitri Pourbaix (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/MATH-416?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12910062#action_12910062 ] 

Dimitri Pourbaix commented on MATH-416:
---------------------------------------

The (n-1)-ary product is a generalization of the cross product in a n-dimension space.  So, one could implement what you suggest: take the fist n-1 eigen vectors, compute their 'cross' product and its dot product with the n-th eigen vector.  If the resulting scalar is negative, multiply this n-th vector by -1.  So, yes, it is feasible.  

However, just the derivation of the cross product requires the computation of n determinants of size n-1.  So I would rather stick to your suggestion of simply stating in the javadoc that there is no guaranty about the orientation of the vectors of V.

> EigenDecompositionImpl.getV() returns eigen matrix with indeterminate determinant
> ---------------------------------------------------------------------------------
>
>                 Key: MATH-416
>                 URL: https://issues.apache.org/jira/browse/MATH-416
>             Project: Commons Math
>          Issue Type: Improvement
>    Affects Versions: 2.1
>         Environment: Mac OS X 10.6.4
>            Reporter: Tom Milac
>            Assignee: Dimitri Pourbaix
>
> A call to EigenDecompositionImpl.getV() returns a RealMatrix the columns of which are the eigenvectors of the matrix with which EigenDecompositionImpl is constructed. Because EigenDecompositionImpl works only with real, symmetric matrices, the eigenvectors (columns) returned are orthogonal.  In addition, the eigenvectors are normalized to have 2-norm = 1. Unfortunately, for 3x3 input matrices, the determinant of the eigenvector matrix is indeterminate, sometimes +1 and other times -1.  The -1 output can be 
> 'repaired' simply by multiplying the matrix by -1.  Example code is included below.
> Because the columns are eigenvectors, the result with either determinant is correct.  However, in the case that the matrix returned is to be interpreted as specifying a coordinate system, the principal axes of a body in my case,  the +1 result specifies a right-handed coordinate for the principal coordinate system of the body, and the -1 result specifies a left-handed coordinate system.  Once discovered, this indeterminacy is easy to deal with, but nevertheless an inconvenience.
> I believe it would improve EigenDecompositionImpl.getV() to return an eigenvector matrix with a consistent determinant = +1.
> Tom Milac
> ---------------------------------------------------------
> import org.apache.commons.math.geometry.NotARotationMatrixException;
> import org.apache.commons.math.geometry.Rotation;
> import org.apache.commons.math.linear.Array2DRowRealMatrix;
> import org.apache.commons.math.linear.EigenDecompositionImpl;
> import org.apache.commons.math.linear.InvalidMatrixException;
> import org.apache.commons.math.linear.LUDecompositionImpl;
> import org.apache.commons.math.linear.RealMatrix;
> /**
>  *
>  * @author Tom Milac
>  */
> public class BugReport {
>     /**
>      * Moment of inertia tensor #1.
>      */
>     public static final double[][] MOI1 =
>             {{128.52722633757742, -29.11849805467669, 8.577081342861376},
>              {-29.11849805467669, 521.3276639228706,  35.512665035385666},
>              {8.577081342861376,  35.512665035385666, 490.2479495932442}};
>     /**
>      * Moment of inertia tensor #2.
>      */
>     public static final double[][] MOI2 =
>             {{440.09350934414175, 44.23154125186637, -9.41455073681743},
>              {44.23154125186637,  387.1291457565648, -38.07596950448303},
>              {-9.41455073681743, -38.07596950448303, 762.0451513430822}};
>     /**
>      * Constructor.
>      */
>     public BugReport() {
>     }
>     /**
>      * Main.
>      */
>     public static void main(String[] args) {
>         // Compute the principal axes (eigenvectors) of the #1 moment
>         // of inertia tensor.
>         RealMatrix moi1  = new Array2DRowRealMatrix(MOI1);
>         RealMatrix axes1 = null;
>         EigenDecompositionImpl eigenDecompositionImpl = null;
>         try {
>             eigenDecompositionImpl = new EigenDecompositionImpl(moi1, 0.0d);
>             axes1 = eigenDecompositionImpl.getV();
>         } catch (InvalidMatrixException ex) {
>             System.err.println("MOI1: InvalidMatrixException thrown.");
>             System.err.println("Exiting ...");
>             System.exit(-1);
>         }
>         // Compute the principal axes (eigenvectors) of the #2 moment
>         // of inertia tensor.
>         RealMatrix moi2  = new Array2DRowRealMatrix(MOI2);
>         RealMatrix axes2 = null;
>         try {
>             eigenDecompositionImpl = new EigenDecompositionImpl(moi2, 0.0d);
>             axes2 = eigenDecompositionImpl.getV();
>         } catch (InvalidMatrixException ex) {
>             System.err.println("MOI2: InvalidMatrixException thrown.");
>             System.err.println("Exiting ...");
>             System.exit(-1);
>         }
>         // Determinant of axes 1 eigenvector matrix = -1.  If the matrix
>         // is interpreted as a Rotation, throws and Exception.
>         System.out.print("Determinant of the #1 moment of inertia tensor = ");
>         System.out.println(new LUDecompositionImpl(axes1).getDeterminant());
>         try {
>             Rotation axes1_rotation = new Rotation(axes1.getData(), 1.0E-7);
>         } catch (NotARotationMatrixException ex) {
>             System.out.println("NotARotationMatrixException thrown for 'axes1'.");
>         }
>         System.out.println();
>         // Determinant of axes 2 eigenvector matrix = +1.
>         System.out.print("Determinant of the #2 moment of inertia tensor = ");
>         System.out.println(new LUDecompositionImpl(axes2).getDeterminant());
>         try {
>             Rotation axes2_rotation = new Rotation(axes2.getData(), 1.0E-7);
>         } catch (NotARotationMatrixException ex) {
>             System.out.println("NotARotationMatrixException thrown for 'axes2'.");
>         }
>     }
> }

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Resolved: (MATH-416) EigenDecompositionImpl.getV() returns eigen matrix with indeterminate determinant

Posted by "Dimitri Pourbaix (JIRA)" <ji...@apache.org>.
     [ https://issues.apache.org/jira/browse/MATH-416?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Dimitri Pourbaix resolved MATH-416.
-----------------------------------

    Fix Version/s: Nightly Builds
       Resolution: Fixed

Javadoc updated to make clear that no assumption is made about the orientation of V.

Correction applied to both trunk and branches/MATH_2_x


> EigenDecompositionImpl.getV() returns eigen matrix with indeterminate determinant
> ---------------------------------------------------------------------------------
>
>                 Key: MATH-416
>                 URL: https://issues.apache.org/jira/browse/MATH-416
>             Project: Commons Math
>          Issue Type: Improvement
>    Affects Versions: 2.1
>         Environment: Mac OS X 10.6.4
>            Reporter: Tom Milac
>            Assignee: Dimitri Pourbaix
>             Fix For: Nightly Builds
>
>
> A call to EigenDecompositionImpl.getV() returns a RealMatrix the columns of which are the eigenvectors of the matrix with which EigenDecompositionImpl is constructed. Because EigenDecompositionImpl works only with real, symmetric matrices, the eigenvectors (columns) returned are orthogonal.  In addition, the eigenvectors are normalized to have 2-norm = 1. Unfortunately, for 3x3 input matrices, the determinant of the eigenvector matrix is indeterminate, sometimes +1 and other times -1.  The -1 output can be 
> 'repaired' simply by multiplying the matrix by -1.  Example code is included below.
> Because the columns are eigenvectors, the result with either determinant is correct.  However, in the case that the matrix returned is to be interpreted as specifying a coordinate system, the principal axes of a body in my case,  the +1 result specifies a right-handed coordinate for the principal coordinate system of the body, and the -1 result specifies a left-handed coordinate system.  Once discovered, this indeterminacy is easy to deal with, but nevertheless an inconvenience.
> I believe it would improve EigenDecompositionImpl.getV() to return an eigenvector matrix with a consistent determinant = +1.
> Tom Milac
> ---------------------------------------------------------
> import org.apache.commons.math.geometry.NotARotationMatrixException;
> import org.apache.commons.math.geometry.Rotation;
> import org.apache.commons.math.linear.Array2DRowRealMatrix;
> import org.apache.commons.math.linear.EigenDecompositionImpl;
> import org.apache.commons.math.linear.InvalidMatrixException;
> import org.apache.commons.math.linear.LUDecompositionImpl;
> import org.apache.commons.math.linear.RealMatrix;
> /**
>  *
>  * @author Tom Milac
>  */
> public class BugReport {
>     /**
>      * Moment of inertia tensor #1.
>      */
>     public static final double[][] MOI1 =
>             {{128.52722633757742, -29.11849805467669, 8.577081342861376},
>              {-29.11849805467669, 521.3276639228706,  35.512665035385666},
>              {8.577081342861376,  35.512665035385666, 490.2479495932442}};
>     /**
>      * Moment of inertia tensor #2.
>      */
>     public static final double[][] MOI2 =
>             {{440.09350934414175, 44.23154125186637, -9.41455073681743},
>              {44.23154125186637,  387.1291457565648, -38.07596950448303},
>              {-9.41455073681743, -38.07596950448303, 762.0451513430822}};
>     /**
>      * Constructor.
>      */
>     public BugReport() {
>     }
>     /**
>      * Main.
>      */
>     public static void main(String[] args) {
>         // Compute the principal axes (eigenvectors) of the #1 moment
>         // of inertia tensor.
>         RealMatrix moi1  = new Array2DRowRealMatrix(MOI1);
>         RealMatrix axes1 = null;
>         EigenDecompositionImpl eigenDecompositionImpl = null;
>         try {
>             eigenDecompositionImpl = new EigenDecompositionImpl(moi1, 0.0d);
>             axes1 = eigenDecompositionImpl.getV();
>         } catch (InvalidMatrixException ex) {
>             System.err.println("MOI1: InvalidMatrixException thrown.");
>             System.err.println("Exiting ...");
>             System.exit(-1);
>         }
>         // Compute the principal axes (eigenvectors) of the #2 moment
>         // of inertia tensor.
>         RealMatrix moi2  = new Array2DRowRealMatrix(MOI2);
>         RealMatrix axes2 = null;
>         try {
>             eigenDecompositionImpl = new EigenDecompositionImpl(moi2, 0.0d);
>             axes2 = eigenDecompositionImpl.getV();
>         } catch (InvalidMatrixException ex) {
>             System.err.println("MOI2: InvalidMatrixException thrown.");
>             System.err.println("Exiting ...");
>             System.exit(-1);
>         }
>         // Determinant of axes 1 eigenvector matrix = -1.  If the matrix
>         // is interpreted as a Rotation, throws and Exception.
>         System.out.print("Determinant of the #1 moment of inertia tensor = ");
>         System.out.println(new LUDecompositionImpl(axes1).getDeterminant());
>         try {
>             Rotation axes1_rotation = new Rotation(axes1.getData(), 1.0E-7);
>         } catch (NotARotationMatrixException ex) {
>             System.out.println("NotARotationMatrixException thrown for 'axes1'.");
>         }
>         System.out.println();
>         // Determinant of axes 2 eigenvector matrix = +1.
>         System.out.print("Determinant of the #2 moment of inertia tensor = ");
>         System.out.println(new LUDecompositionImpl(axes2).getDeterminant());
>         try {
>             Rotation axes2_rotation = new Rotation(axes2.getData(), 1.0E-7);
>         } catch (NotARotationMatrixException ex) {
>             System.out.println("NotARotationMatrixException thrown for 'axes2'.");
>         }
>     }
> }

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Commented: (MATH-416) EigenDecompositionImpl.getV() returns eigen matrix with indeterminate determinant

Posted by "Dimitri Pourbaix (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/MATH-416?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12909140#action_12909140 ] 

Dimitri Pourbaix commented on MATH-416:
---------------------------------------

Returning V such that det(V) is always +1 would please you but would cost some substantial computation in general, which would make mad users for whom speed is an issue.  A compromise could consist in a second accessor to V (and to Vt too I guess) which would guarantee that the determinant is +1.  Would it be OK for you?

> EigenDecompositionImpl.getV() returns eigen matrix with indeterminate determinant
> ---------------------------------------------------------------------------------
>
>                 Key: MATH-416
>                 URL: https://issues.apache.org/jira/browse/MATH-416
>             Project: Commons Math
>          Issue Type: Improvement
>    Affects Versions: 2.1
>         Environment: Mac OS X 10.6.4
>            Reporter: Tom Milac
>            Assignee: Dimitri Pourbaix
>
> A call to EigenDecompositionImpl.getV() returns a RealMatrix the columns of which are the eigenvectors of the matrix with which EigenDecompositionImpl is constructed. Because EigenDecompositionImpl works only with real, symmetric matrices, the eigenvectors (columns) returned are orthogonal.  In addition, the eigenvectors are normalized to have 2-norm = 1. Unfortunately, for 3x3 input matrices, the determinant of the eigenvector matrix is indeterminate, sometimes +1 and other times -1.  The -1 output can be 
> 'repaired' simply by multiplying the matrix by -1.  Example code is included below.
> Because the columns are eigenvectors, the result with either determinant is correct.  However, in the case that the matrix returned is to be interpreted as specifying a coordinate system, the principal axes of a body in my case,  the +1 result specifies a right-handed coordinate for the principal coordinate system of the body, and the -1 result specifies a left-handed coordinate system.  Once discovered, this indeterminacy is easy to deal with, but nevertheless an inconvenience.
> I believe it would improve EigenDecompositionImpl.getV() to return an eigenvector matrix with a consistent determinant = +1.
> Tom Milac
> ---------------------------------------------------------
> import org.apache.commons.math.geometry.NotARotationMatrixException;
> import org.apache.commons.math.geometry.Rotation;
> import org.apache.commons.math.linear.Array2DRowRealMatrix;
> import org.apache.commons.math.linear.EigenDecompositionImpl;
> import org.apache.commons.math.linear.InvalidMatrixException;
> import org.apache.commons.math.linear.LUDecompositionImpl;
> import org.apache.commons.math.linear.RealMatrix;
> /**
>  *
>  * @author Tom Milac
>  */
> public class BugReport {
>     /**
>      * Moment of inertia tensor #1.
>      */
>     public static final double[][] MOI1 =
>             {{128.52722633757742, -29.11849805467669, 8.577081342861376},
>              {-29.11849805467669, 521.3276639228706,  35.512665035385666},
>              {8.577081342861376,  35.512665035385666, 490.2479495932442}};
>     /**
>      * Moment of inertia tensor #2.
>      */
>     public static final double[][] MOI2 =
>             {{440.09350934414175, 44.23154125186637, -9.41455073681743},
>              {44.23154125186637,  387.1291457565648, -38.07596950448303},
>              {-9.41455073681743, -38.07596950448303, 762.0451513430822}};
>     /**
>      * Constructor.
>      */
>     public BugReport() {
>     }
>     /**
>      * Main.
>      */
>     public static void main(String[] args) {
>         // Compute the principal axes (eigenvectors) of the #1 moment
>         // of inertia tensor.
>         RealMatrix moi1  = new Array2DRowRealMatrix(MOI1);
>         RealMatrix axes1 = null;
>         EigenDecompositionImpl eigenDecompositionImpl = null;
>         try {
>             eigenDecompositionImpl = new EigenDecompositionImpl(moi1, 0.0d);
>             axes1 = eigenDecompositionImpl.getV();
>         } catch (InvalidMatrixException ex) {
>             System.err.println("MOI1: InvalidMatrixException thrown.");
>             System.err.println("Exiting ...");
>             System.exit(-1);
>         }
>         // Compute the principal axes (eigenvectors) of the #2 moment
>         // of inertia tensor.
>         RealMatrix moi2  = new Array2DRowRealMatrix(MOI2);
>         RealMatrix axes2 = null;
>         try {
>             eigenDecompositionImpl = new EigenDecompositionImpl(moi2, 0.0d);
>             axes2 = eigenDecompositionImpl.getV();
>         } catch (InvalidMatrixException ex) {
>             System.err.println("MOI2: InvalidMatrixException thrown.");
>             System.err.println("Exiting ...");
>             System.exit(-1);
>         }
>         // Determinant of axes 1 eigenvector matrix = -1.  If the matrix
>         // is interpreted as a Rotation, throws and Exception.
>         System.out.print("Determinant of the #1 moment of inertia tensor = ");
>         System.out.println(new LUDecompositionImpl(axes1).getDeterminant());
>         try {
>             Rotation axes1_rotation = new Rotation(axes1.getData(), 1.0E-7);
>         } catch (NotARotationMatrixException ex) {
>             System.out.println("NotARotationMatrixException thrown for 'axes1'.");
>         }
>         System.out.println();
>         // Determinant of axes 2 eigenvector matrix = +1.
>         System.out.print("Determinant of the #2 moment of inertia tensor = ");
>         System.out.println(new LUDecompositionImpl(axes2).getDeterminant());
>         try {
>             Rotation axes2_rotation = new Rotation(axes2.getData(), 1.0E-7);
>         } catch (NotARotationMatrixException ex) {
>             System.out.println("NotARotationMatrixException thrown for 'axes2'.");
>         }
>     }
> }

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.