All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.commons.math3.linear.HessenbergTransformer Maven / Gradle / Ivy

Go to download

The Apache Commons Math project is a library of lightweight, self-contained mathematics and statistics components addressing the most common practical problems not immediately available in the Java programming language or commons-lang.

There is a newer version: 3.6.1
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.apache.commons.math3.linear;

import org.apache.commons.math3.util.FastMath;
import org.apache.commons.math3.util.Precision;

/**
 * Class transforming a general real matrix to Hessenberg form.
 * 

A m × m matrix A can be written as the product of three matrices: A = P * × H × PT with P an orthogonal matrix and H a Hessenberg * matrix. Both P and H are m × m matrices.

*

Transformation to Hessenberg form is often not a goal by itself, but it is an * intermediate step in more general decomposition algorithms like * {@link EigenDecomposition eigen decomposition}. This class is therefore * intended for internal use by the library and is not public. As a consequence * of this explicitly limited scope, many methods directly returns references to * internal arrays, not copies.

*

This class is based on the method orthes in class EigenvalueDecomposition * from the JAMA library.

* * @see MathWorld * @see Householder Transformations * @version $Id: HessenbergTransformer.java 1334644 2012-05-06 14:33:32Z tn $ * @since 3.1 */ class HessenbergTransformer { /** Householder vectors. */ private final double householderVectors[][]; /** Temporary storage vector. */ private final double ort[]; /** Cached value of P. */ private RealMatrix cachedP; /** Cached value of Pt. */ private RealMatrix cachedPt; /** Cached value of H. */ private RealMatrix cachedH; /** * Build the transformation to Hessenberg form of a general matrix. * * @param matrix matrix to transform * @throws NonSquareMatrixException if the matrix is not square */ public HessenbergTransformer(final RealMatrix matrix) { if (!matrix.isSquare()) { throw new NonSquareMatrixException(matrix.getRowDimension(), matrix.getColumnDimension()); } final int m = matrix.getRowDimension(); householderVectors = matrix.getData(); ort = new double[m]; cachedP = null; cachedPt = null; cachedH = null; // transform matrix transform(); } /** * Returns the matrix P of the transform. *

P is an orthogonal matrix, i.e. its inverse is also its transpose.

* * @return the P matrix */ public RealMatrix getP() { if (cachedP == null) { final int n = householderVectors.length; final int high = n - 1; final double[][] pa = new double[n][n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { pa[i][j] = (i == j) ? 1 : 0; } } for (int m = high - 1; m >= 1; m--) { if (householderVectors[m][m - 1] != 0.0) { for (int i = m + 1; i <= high; i++) { ort[i] = householderVectors[i][m - 1]; } for (int j = m; j <= high; j++) { double g = 0.0; for (int i = m; i <= high; i++) { g += ort[i] * pa[i][j]; } // Double division avoids possible underflow g = (g / ort[m]) / householderVectors[m][m - 1]; for (int i = m; i <= high; i++) { pa[i][j] += g * ort[i]; } } } } cachedP = MatrixUtils.createRealMatrix(pa); } return cachedP; } /** * Returns the transpose of the matrix P of the transform. *

P is an orthogonal matrix, i.e. its inverse is also its transpose.

* * @return the transpose of the P matrix */ public RealMatrix getPT() { if (cachedPt == null) { cachedPt = getP().transpose(); } // return the cached matrix return cachedPt; } /** * Returns the Hessenberg matrix H of the transform. * * @return the H matrix */ public RealMatrix getH() { if (cachedH == null) { final int m = householderVectors.length; final double[][] h = new double[m][m]; for (int i = 0; i < m; ++i) { if (i > 0) { // copy the entry of the lower sub-diagonal h[i][i - 1] = householderVectors[i][i - 1]; } // copy upper triangular part of the matrix for (int j = i; j < m; ++j) { h[i][j] = householderVectors[i][j]; } } cachedH = MatrixUtils.createRealMatrix(h); } // return the cached matrix return cachedH; } /** * Get the Householder vectors of the transform. *

Note that since this class is only intended for internal use, it returns * directly a reference to its internal arrays, not a copy.

* * @return the main diagonal elements of the B matrix */ double[][] getHouseholderVectorsRef() { return householderVectors; } /** * Transform original matrix to Hessenberg form. *

Transformation is done using Householder transforms.

*/ private void transform() { final int n = householderVectors.length; final int high = n - 1; for (int m = 1; m <= high - 1; m++) { // Scale column. double scale = 0; for (int i = m; i <= high; i++) { scale += FastMath.abs(householderVectors[i][m - 1]); } if (!Precision.equals(scale, 0)) { // Compute Householder transformation. double h = 0; for (int i = high; i >= m; i--) { ort[i] = householderVectors[i][m - 1] / scale; h += ort[i] * ort[i]; } final double g = (ort[m] > 0) ? -FastMath.sqrt(h) : FastMath.sqrt(h); h = h - ort[m] * g; ort[m] = ort[m] - g; // Apply Householder similarity transformation // H = (I - u*u' / h) * H * (I - u*u' / h) for (int j = m; j < n; j++) { double f = 0; for (int i = high; i >= m; i--) { f += ort[i] * householderVectors[i][j]; } f = f / h; for (int i = m; i <= high; i++) { householderVectors[i][j] -= f * ort[i]; } } for (int i = 0; i <= high; i++) { double f = 0; for (int j = high; j >= m; j--) { f += ort[j] * householderVectors[i][j]; } f = f / h; for (int j = m; j <= high; j++) { householderVectors[i][j] -= f * ort[j]; } } ort[m] = scale * ort[m]; householderVectors[m][m - 1] = scale * g; } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy