/* * Copyright (c) 2009-2013, Peter Abeles. All Rights Reserved. * * This file is part of Efficient Java Matrix Library (EJML). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package mikera.matrixx.decompose.impl.eigen; import mikera.vectorz.Vector2; /** * @author Peter Abeles */ public class EigenvalueSmall { public Vector2 value0 = new Vector2(); public Vector2 value1 = new Vector2(); // if |a11-a22| >> |a12+a21| there might be a better way. see pg371 public void value2x2( double a11 , double a12, double a21 , double a22 ) { // apply a rotators such that th a11 and a22 elements are the same double c,s; if( a12 + a21 == 0 ) { // is this pointless since c = s = 1.0/Math.sqrt(2); } else { double aa = (a11-a22); double bb = (a12+a21); double t_hat = aa/bb; double t = t_hat/(1.0+Math.sqrt(1.0+t_hat*t_hat)); c = 1.0/Math.sqrt(1.0+t*t); s = c*t; } double c2 = c*c; double s2 = s*s; double cs = c*s; double b11 = c2*a11 + s2*a22 - cs*(a12+a21); double b12 = c2*a12 - s2*a21 + cs*(a11-a22); double b21 = c2*a21 - s2*a12 + cs*(a11-a22); // double b22 = c2*a22 + s2*a11 + cs*(a12+a21); // apply second rotator to make A upper triangular if real eigenvalues if( b21*b12 >= 0 ) { if( b12 == 0 ) { c = 0; s = 1; } else { s = Math.sqrt(b21/(b12+b21)); c = Math.sqrt(b12/(b12+b21)); } // c2 = b12;//c*c; // s2 = b21;//s*s; cs = c*s; a11 = b11 - cs*(b12 + b21); // a12 = c2*b12 - s2*b21; // a21 = c2*b21 - s2*b12; a22 = b11 + cs*(b12 + b21); value0.setValues(a11, 0); value1.setValues(a22, 0); } else { value0.setValues(b11, Math.sqrt(-b21*b12)); value1.setValues(b11, -value0.get(1)); } } /** * Computes the eigenvalues of a 2 by 2 matrix using a faster but more prone to errors method. This * is the typical method. */ public void value2x2_fast( double a11 , double a12, double a21 , double a22 ) { double left = (a11+a22)/2.0; double inside = 4.0*a12*a21 + (a11-a22)*(a11-a22); if( inside < 0 ) { value0.setValues(left, Math.sqrt(-inside)/2.0); value1.setValues(left, -value0.get(1)); } else { double right = Math.sqrt(inside)/2.0; value0.setValues(left+right, 0.0); value1.setValues(left-right, 0.0); } } /** * Compute the symmetric eigenvalue using a slightly safer technique */ // See page 385 of Fundamentals of Matrix Computations 2nd public void symm2x2_fast( double a11 , double a12, double a22 ) { // double p = (a11 - a22)*0.5; // double r = Math.sqrt(p*p + a12*a12); // // value0.real = a22 + a12*a12/(r-p); // value1.real = a22 - a12*a12/(r+p); // } // // public void symm2x2_std( double a11 , double a12, double a22 ) // { double left = (a11+a22)*0.5; double b = (a11-a22)*0.5; double right = Math.sqrt(b*b+a12*a12); value0.set(0, left + right); value1.set(0, left - right); } }