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

org.nuiton.math.matrix.SubMatrix Maven / Gradle / Ivy

The newest version!
/*##% NuitonMatrix
 * Copyright (C) 2004 - 2009 CodeLutin
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * . ##%*/

package org.nuiton.math.matrix;

import java.io.Serializable;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.NoSuchElementException;

/**
 * Pour l'instant une sous matrice a obligatoirement le meme nombre de dimension
 * que la matrice qu'elle contient. Elle permet juste de reduire le nombre
 * d'element d'une dimension.
 * 
 * Created: 29 oct. 2004
 *
 * @author Benjamin Poussin 
 * @version $Revision: 187 $
 *
 * Mise a jour: $Date: 2009-10-16 19:17:29 +0200 (ven., 16 oct. 2009) $
 * par : $Author: tchemit $
 */
public class SubMatrix extends AbstractMatrixND { // SubMatrix

    /** serialVersionUID. */
    private static final long serialVersionUID = 4092234115185263506L;
    
    protected MatrixND matrix = null;
    protected DimensionConverter converter = null;

    public SubMatrix(MatrixND matrix, int dim, int start, int nb) {
        super(matrix.getFactory(), matrix.getName(), matrix.getSemantics(),
                matrix.getDimensionNames());
        this.matrix = matrix;

        converter = new ShiftConverter(dim, start, nb);
        setSemantic(dim, getSemantic(dim).subList(start, start + nb));
        getDim()[dim] = nb;
    }

    public SubMatrix(MatrixND matrix, int dim, int[] elem) {
        super(matrix.getFactory(), matrix.getName(), matrix.getSemantics(),
                matrix.getDimensionNames());
        this.matrix = matrix;

        converter = new MappingConverter(dim, elem);

        List oldSemantic = getSemantic(dim);
        List newSemantic = new LinkedList();
        for (int i = 0; i < elem.length; i++) {
            newSemantic.add(oldSemantic.get(elem[i]));
        }
        setSemantic(dim, newSemantic);
        getDim()[dim] = elem.length;
    }

    @Override
    public MatrixIterator iterator() {
        return new SubMatrixIteratorImpl(this);
    }

    @Override
    public double getValue(int[] coordinates) {
        return matrix.getValue(converter.convertCoordinates(coordinates));
    }

    @Override
    public void setValue(int[] coordinates, double d) {
        matrix.setValue(converter.convertCoordinates(coordinates), d);
    }

    protected class SubMatrixIteratorImpl implements MatrixIterator {

        protected SubMatrix subMatrix = null;
        protected int[] cpt = null;
        protected int[] last = null;

        public SubMatrixIteratorImpl(SubMatrix subMatrix) {
            this.subMatrix = subMatrix;
            cpt = new int[subMatrix.getDimCount()];
            cpt[cpt.length - 1] = -1;

            last = new int[subMatrix.getDimCount()];
            for (int i = 0; i < last.length; i++) {
                last[i] = subMatrix.getDim(i) - 1;
            }

        }

        @Override
        public boolean hasNext() {
            return !Arrays.equals(cpt, last);
        }

        @Override
        public boolean next() {
            boolean result = hasNext();
            int ret = 1;
            int[] dim = getDim();
            for (int i = cpt.length - 1; i >= 0; i--) {
                cpt[i] = cpt[i] + ret;
                ret = cpt[i] / dim[i];
                cpt[i] = cpt[i] % dim[i];
            }
            return result;
        }

        @Override
        public int[] getCoordinates() {
            return cpt;
        }

        @Override
        public Object[] getSemanticsCoordinates() {
            int[] coordinates = getCoordinates();
            Object[] result = MatrixHelper.dimensionToSemantics(subMatrix
                    .getSemantics(), coordinates);
            return result;
        }

        @Override
        public double getValue() {
            return subMatrix.getValue(getCoordinates());
        }

        @Override
        public void setValue(double value) {
            subMatrix.setValue(getCoordinates(), value);
        }

    }

    /**
     * Permet de faire une conversion de la dimension demandé dans la sous
     * matrice avec la position reel de la matrice sous jacente.
     */
    protected interface DimensionConverter extends Serializable {
        public int[] convertCoordinates(int[] coordinates);
    }

    /**
     * La conversion est juste un decalage d'indice
     */
    protected class ShiftConverter implements DimensionConverter {
        /**  */
        private static final long serialVersionUID = 1L;

        protected int dim;
        protected int start;
        protected int nb;

        public ShiftConverter(int dim, int start, int nb) {
            this.dim = dim;
            this.start = start;
            this.nb = nb;
        }

        @Override
        public int[] convertCoordinates(int[] coordinates) {
            int[] result = null;
            if (coordinates[dim] < nb) {
                result = new int[coordinates.length];
                System.arraycopy(coordinates, 0, result, 0, result.length);
                result[dim] = result[dim] + start;
            } else {
                throw new NoSuchElementException(
                        "L'indice est supérieur au nombre d'élement de la sous matrice pour cette dimension.");
            }
            return result;
        }
    }

    /**
     * La conversion est le mapping d'un element vers un autre element
     */
    protected class MappingConverter implements DimensionConverter {

        /** serialVersionUID. */
        private static final long serialVersionUID = -6367416559713556559L;
        
        protected int dim;
        protected int[] elem = null;

        public MappingConverter(int dim, int[] elem) {
            this.dim = dim;
            this.elem = new int[elem.length];
            System.arraycopy(elem, 0, this.elem, 0, elem.length);
        }

        @Override
        public int[] convertCoordinates(int[] coordinates) {
            int[] result = null;
            if (coordinates[dim] < elem.length) {
                result = new int[coordinates.length];
                System.arraycopy(coordinates, 0, result, 0, result.length);
                result[dim] = elem[coordinates[dim]];
                
            } else {
                throw new NoSuchElementException(
                        "L'indice est supérieur au nombre d'élements de la sous matrice pour cette dimension.");
            }
            return result;
        }
    }

} // SubMatrix