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

jacobi.core.decomp.gauss.GenericGaussianElim Maven / Gradle / Ivy

/* 
 * The MIT License
 *
 * Copyright 2017 Y.K. Chan
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package jacobi.core.decomp.gauss;

import jacobi.api.Matrix;
import java.util.function.Function;
import java.util.stream.IntStream;

/**
 * Perform Gaussian Elimination with given elementary operator.
 * 
 * @author Y.K. Chan
 */
public class GenericGaussianElim {
    
    /**
     * Perform Gaussian Elimination.
     * @param matrix   Matrix to be performed
     */
    public void compute(Matrix matrix) {
        this.compute(matrix, Function.identity());
    }
    
    /**
     * Perform Gaussian Elimination with potential listener
     * @param   Type after decorating
     * @param matrix  Matrix to be performed
     * @param decor  Decorating function
     * @return  Elementary operator after elimination
     */
    public  T compute(Matrix matrix, Function decor) {
        T oper = decor.apply(new FrontElementEliminator(matrix));
        int end = Math.min(
                matrix.getRowCount(), 
                matrix.getColCount()) - 1;
        int nextPivot = -1;
        for(int i = 0; i < end; i++){
            if(nextPivot < 0){
                nextPivot = this.findPivot(matrix, i);
            }
            nextPivot = this.eliminate(oper, i, nextPivot);
        }
        return oper;
    }
    
    /**
     * Eliminate the frontal element of a row given a pivot row.
     * @param op  Elementary operator
     * @param from  Start row index of interest
     * @param pivotIndex  Pivot row index
     * @return   Next pivot row index, or negative if not computed.
     */
    protected int eliminate(ElementaryOperator op, int from, int pivotIndex) {
        op.swapRows(from, pivotIndex);
        double pivot = op.getMatrix().get(from, from);        
        if(Math.abs(pivot) < EPILSON){
            return -1;
        }
        double next = op.getMatrix().get(from, from + 1);
        return this.serial(op, from, pivot, next);
    }
    
    /**
     * Eliminate the frontal element of a row given a pivot row in serial.
     * @param op  Elementary operator
     * @param from  Start and pivot row index of interest
     * @param pivot  Pivot row frontal element
     * @param next  Pivot row column element after frontal
     * @return    Next pivot row index
     */
    protected int serial(ElementaryOperator op, int from, double pivot, double next) {
        int maxIndex = -1;
        double maxElem = 0.0;
        
        for(int i = from + 1; i < op.getMatrix().getRowCount(); i++){
            double elem = this.eliminateFront(op, from, i, pivot, next);
            if(elem > maxElem){
                maxElem = elem;
                maxIndex = i;
            }
        }
        return maxIndex;
    }
    
    /**
     * Eliminate the frontal element of a row given a pivot row in parallel by stream.
     * @param op  Elementary operator
     * @param from  Start and pivot row index of interest
     * @param pivot  Pivot row frontal element
     * @param next  Pivot row column element after frontal
     * @return    Next pivot row index
     */
    protected int stream(ElementaryOperator op, int from, double pivot, double next) {
        return IntStream.range(from + 1, op.getMatrix().getRowCount())
                .mapToObj((i) -> new Element(i, this.eliminateFront(op, from, i, pivot, next)))
                .reduce((a, b) -> a.getValue() > b.getValue() ? a : b)
                .map((e) -> e.getIndex())
                .get();
    }
    
    private double eliminateFront(ElementaryOperator op, int from, int target, double pivot, double next) {
        double factor = op.getMatrix().get(target, from) / pivot;
        double front = op.getMatrix().get(target, from + 1) - factor * next;
        op.rowOp(target, -factor, from);
        return Math.abs(front);
    }
    
    private int findPivot(Matrix matrix, int from) {
        int maxIndex = from;
        double maxElem = Math.abs(matrix.get(from, from));
        for(int i = from + 1; i < matrix.getRowCount(); i++){
            double elem = Math.abs(matrix.get(i, from));
            if(elem > maxElem){
                maxIndex = i;
                maxElem = elem;
            }
        }
        return maxIndex;
    }
    
    private static class Element {

        public Element(int index, double value) {
            this.index = index;
            this.value = value;
        }

        public int getIndex() {
            return index;
        }

        public double getValue() {
            return value;
        }
        
        private int index;
        private double value;
    }
    
    private static class FrontElementEliminator implements ElementaryOperator {

        public FrontElementEliminator(Matrix matrix) {
            this.matrix = matrix;
        }

        @Override
        public void swapRows(int i, int j) {
            this.matrix.swapRow(i, j);
        }

        @Override
        public void rowOp(int i, double a, int j) {
            double[] r0 = this.matrix.getRow(i);
            double[] r1 = this.matrix.getRow(j);
            r0[j] = 0.0;
            for(int k = j + 1; k < r0.length; k++){
                r0[k] += a * r1[k];
            }
            this.matrix.setRow(i, r0);
        }

        @Override
        public Matrix getMatrix() {
            return this.matrix;
        }
        
        private Matrix matrix;
    }
    
    private static final double EPILSON = 1e-10;
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy