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

org.nuiton.util.MatrixMap Maven / Gradle / Ivy

There is a newer version: 3.1
Show newest version
/*
 * #%L
 * Nuiton Utils :: Nuiton Utils
 * 
 * $Id: MatrixMap.java 2360 2012-06-11 10:24:36Z tchemit $
 * $HeadURL: http://svn.nuiton.org/svn/nuiton-utils/tags/nuiton-utils-2.6.10/nuiton-utils/src/main/java/org/nuiton/util/MatrixMap.java $
 * %%
 * Copyright (C) 2004 - 2012 CodeLutin, Chatellier Eric
 * %%
 * 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
 * .
 * #L%
 */
package org.nuiton.util;

import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.Serializable;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.RandomAccess;

/**
 * Permet de stocker des informations dans une matrix a N dimension
 * Si lors de l'ajout on indique une dimension qui n'existe pas encore ou
 * un element dans une dimension qui n'existe pas, la matrice ajoute
 * automatiquement les elements manquant pour que l'ajout se passe bien.
 * 

* MatrixMap permet de stocker les elements avec des cles de n'importe quel * type. Les coordonnees utilisant ces objets sont converti en coordonnees * numeriques qui est la seul chose que sait gere Matrix. Ces coordonnees * numeriques sont alors convertis en coordonnees lineaire pour le stockage * dans Vector. On decoupe ainsi les problemes et on minimise le stockage et * certain traitement sur les données puisqu'au final toutes les données sont * dans une simple liste. *

* Pour créer une nouvelle matrice, il faut utiliser une des méthodes de * {@link MatrixMap.Factory} * * @author poussin * @version $Revision: 2360 $ * @since 2.2.1 *

* Last update: $Date: 2012-06-11 12:24:36 +0200 (Mon, 11 Jun 2012) $ * by : $Author: tchemit $ */ public interface MatrixMap extends Iterable { /** Classe permettant la creation de matrice */ public static class Factory { public static MatrixMap create(List... semantics) { MatrixMap result = new MatrixMapFixed(semantics); return result; } public static MatrixMap create(String name, List... semantics) { MatrixMap result = new MatrixMapFixed(name, semantics); return result; } public static MatrixMap create(String name, String[] dimNames, List... semantics) { MatrixMap result = new MatrixMapFixed(name, dimNames, semantics); return result; } public static MatrixMap create(MatrixMap matrix) { MatrixMap result = new MatrixMapFixed(matrix); return result; } public static MatrixMap createElastic(List... semantics) { MatrixMap result = create(semantics); result = createElastic(result); return result; } public static MatrixMap createElastic(String name, List... semantics) { MatrixMap result = create(name, semantics); result = createElastic(result); return result; } public static MatrixMap createElastic(String name, String[] dimNames, List... semantics) { MatrixMap result = create(name, dimNames, semantics); result = createElastic(result); return result; } public static MatrixMap createElastic(MatrixMap matrix) { MatrixMap result = new MatrixMapElastic(matrix); return result; } } @Override public MatrixMapIterator iterator(); /** * Copy la matrice pour pouvoir la modifier sans perdre les donnees * initiales. * * @return new matrix */ public MatrixMap copy(); public SemanticList[] getSemantics(); public SemanticList getSemantic(int dim); public void setSemantic(int dim, List sem); public void setName(String name); public String getName(); public String[] getDimensionNames(); public void setDimensionNames(String[] names); public void setDimensionName(int dim, String name); public String getDimensionName(int dim); public int getDimCount(); public int[] getDim(); public int getDim(int d); /** * Applique sur chaque element de la matrice la fonction f * * @param f la fonction a appliquer * @return Retourne la matrice elle meme. Les modifications sont faites directement * dessus */ public MatrixMap map(MapFunction f); /** * Retourne l'element a une certaine position en utilisant des indices * ex: 2,3,1 * * @param coordinates * @return */ public E getValueIndex(int... coordinates); /** * Modifie l'element a une certaine position en utilisant des indices * ex: 2,3,1 * * @param value la nouvelle valeur * @param coordinates * @return */ public void setValueIndex(E value, int... coordinates); /** * Retourne l'element a une certaine position en utilisant les semantiques * * @param coordinates * @return */ public E getValue(Object... coordinates); /** * Modifie l'element a une certaine position en utilisant les semantiques * * @param value la nouvelle valeur * @param coordinates * @return */ public void setValue(E value, Object... coordinates); /** * Verifie que deux matrices sont completement equals * (dimension, semantique, nom, valeur, ...) * * @param mat * @return */ public boolean equals(MatrixMap mat); /** * Verifie si les matrices sont egales en ne regardant que les valeurs et * pas les semantiques * * @param mat * @return equality on values */ public boolean equalsValues(MatrixMap mat); /** * Representation string de la matrice quelque soit le nombre de dimension * * @return */ public String toStringGeneric(); /** * Indique si les semantiques passées en argument sont valable pour la * matrice courante * * @param semantics * @return */ public boolean isValidCoordinates(Object[] semantics); /** * Copie une matrice dans la matrice actuelle. La matrice à copier à le même * nombre de dimension. Si la matrice à copier est trop grande seul les * éléments pouvant être copier le seront. * * @param mat la matrice à copier * @return return la matrice courante. */ public MatrixMap paste(MatrixMap mat); /** * Permet de prendre une sous matrice dans la matrice courante. La sous * matrice a le même nombre de dimensions mais sur une des dimensions on ne * prend que certain élément. * * @param dim la dimension dans lequel on veut une sous matrice * @param start la position dans dim d'ou il faut partir pour prendre la * sous matrice. 0 <= start < dim.size si start est négatif alors * la position de départ est calculé par rapport à la fin de la * dimension, pour avoir le dernier élément il faut passer -1 * @param nb le nombre d'élément à prendre dans la dimension si nb est * inférieur ou égal à 0 alors cela indique qu'il faut prendre * tous les éléments jusqu'à la fin de la dimension. * @return new matrix */ public MatrixMap getSubMatrix(int dim, Object start, int nb); /** * Permet de prendre une sous matrice dans la matrice courante. La sous * matrice a le même nombre de dimensions mais sur une des dimensions on ne * prend que certain élément. * * @param dim la dimension dans lequel on veut une sous matrice * @param elem les éléments dans la dimension à conserver * @return new matrix */ public MatrixMap getSubMatrix(int dim, Object... elem); /** * Permet de prendre une sous matrice dans la matrice courante. *

* Réalise plusieurs appels à {@link #getSubMatrix(int, Object...)} suivant * l'implémentation. * * @param elems les éléments dans la dimension à conserver * @return new matrix */ public MatrixMap getSubMatrix(Object[]... elems); /** * Reduit la matrice de sorte que toutes les dimensions qui n'ont qu'un * élement soit supprimée. Au pire cette méthode retourne une matrice à une * seule dimension à un seul élément. * * @return une nouvelle matrice plus petite que la matrice actuelle ou egal * s'il n'y a aucune dimension à supprimer */ public MatrixMap reduce(); /** * Reduit le matrice seulement sur les dimensions passées en argument. Si * une des dimensions passées en arguement n'a pas qu'un seul élément, cette * dimension n'est pas prise en compte. * * @param dims les dimensions sur lequel il faut faire la reduction * @return une nouvelle matrice */ public MatrixMap reduceDims(int... dims); /** * Reduit la matrice de sorte que toutes les dimensions qui n'ont qu'un * élement soit supprimée. Au pire cette méthode retourne une matrice à une * seule dimension à un seul élément. * * @param minNbDim le nombre minimum de dimension que l'on souhaite pour la * matrice résultat * @return une nouvelle matrice plus petite que la matrice actuelle ou egal * s'il n'y a aucune dimension à supprimer */ public MatrixMap reduce(int minNbDim); /** * Permet de retourner une nouvelle matrice ayant les semantiques passées * en parametre. La nouvelle matrice contient les données de l'ancienne * matrice par copie en fonction des semantiques * * @param sems * @return */ public MatrixMap extend(Object... sems); /////////////////////////////////////////////////////////////////////////// // // C L A S S E I N T E R N E // /////////////////////////////////////////////////////////////////////////// /** * Classe contenant des méthodes statiques pour aider a la manipulation * des matrices */ public static class MatrixHelper { /** * Mais en forme un texte pour qu'il fasse exactement la longueur * demandee (length). Si length est possitif alors s'il y besoin * d'ajouter des espaces, ils seront mis devant le texte, sinon il * seront mis apres le texte * * @param o l'objet a convertir en string * @param length la longueur de representation souhaite * @param valueIfNull la valeur a utilise si l'objet est null * @return */ public static String format(Object o, int length, String valueIfNull) { if (o == null) { o = valueIfNull; } int absLength = Math.abs(length); String result = String.valueOf(o); if (absLength > 3) { result = StringUtils.abbreviate(result, absLength); } if (length < 0) { result = StringUtils.leftPad(result, absLength); } else if (length > 0) { result = StringUtils.rightPad(result, absLength); } return result; } /** * Permet de convertir des coordonnées définies par des entiers en coordonnées * semantique par des objets * * @param semantics la semantique à utilisé pour la conversion * @param coordinates les coordonnées à convertir * @return un tableau donnant les coordonnées sous forme semantique s'il n'y * a pas de semantique (liste pleine de null) alors un objet Integer * est créer pour représenter la semantique de la dimension. */ public static Object[] dimensionToSemantics(List[] semantics, int[] coordinates) { Object[] result = new Object[coordinates.length]; for (int i = 0; i < result.length; i++) { result[i] = semantics[i].get(coordinates[i]); } return result; } /** * Permet de convertir des coordonnées sémantiques en coordonnées défini par * des entiers. Cette fonction est l'inverse de * {@link #dimensionToSemantics}. * * @param semantics la semantique à utiliser pour la conversion * @param coordinates les coordonnées sémantique * @return les coordonnées en entier. */ public static int[] semanticsToDimension(List[] semantics, Object[] coordinates) { int[] result = new int[coordinates.length]; for (int i = 0; i < coordinates.length; i++) { result[i] = indexOf(semantics, i, coordinates[i]); } return result; } /** * Permet de retrouver la position d'un objet dans une liste * * @param semantics la semantique à utilisé pour la recherche * @param dim la dimension dans lequel il faut faire la recherche * @param o l'objet à rechercher * @return la position de l'objet dans la dimension demandée * @throws NoSuchElementException If element doesn't exists */ public static int indexOf(List[] semantics, int dim, Object o) throws NoSuchElementException { int result = -1; if ((0 <= dim) && (dim < semantics.length)) { result = semantics[dim].indexOf(o); } if (result == -1) { throw new NoSuchElementException( "L'objet passé en argument n'a pas été retrouvé ou la dimension donnée ne convient pas:" + o + " in " + semantics[dim]); } return result; } /** * Permet de savoir si deux dimension sont identiques. * * @param dim1 first dimensions * @param dim2 second dimensions * @return dimension equality */ public static boolean sameDimension(int[] dim1, int[] dim2) { return Arrays.equals(dim1, dim2); } } /** * Iterateur de matrice * * @param */ public static interface MatrixMapIterator extends Iterator { public int[] getCoordinates(); public E getValue(); public void setValue(E value); public Object[] getSemanticsCoordinates(); } public static class MatrixMapIteratorImpl implements MatrixMapIterator { // MatrixMapIteratorImpl protected MatrixIterator iterator = null; protected List[] semantics = null; protected int pos = 0; /** * @param iterator la matrice sur lequel l'iterator doit travailler * @param semantics la semantique de matrix, si matrix n'a pas de semantique * alors il faut passer null */ public MatrixMapIteratorImpl(MatrixIterator iterator, List[] semantics) { this.iterator = iterator; this.semantics = semantics; pos = 0; } @Override public boolean hasNext() { return iterator.hasNext(); } @Override public E next() { return iterator.next(); } @Override public void remove() { iterator.remove(); } public int[] getCoordinates() { return iterator.getCoordinates(); } public E getValue() { return iterator.getValue(); } public void setValue(E value) { iterator.setValue(value); } public Object[] getSemanticsCoordinates() { Object[] result = null; if (semantics != null) { int[] coordinates = getCoordinates(); result = MatrixHelper.dimensionToSemantics(semantics, coordinates); } return result; } } // MatrixMapIteratorImpl /** * Collection particuliere utilisee pour la stockage des semantiques. *

* Sert a optimiser la recherche de la position d'une donnee dans la liste. * Permet aussi de verifier qu'on ajoute pas de doublon dans la liste * * @param */ public static class SemanticList extends AbstractList implements RandomAccess { protected ArrayList datas = null; protected Map index = new HashMap(); public SemanticList() { this(new ArrayList()); } public SemanticList(Collection c) { datas = new ArrayList(c); } /* * @see java.util.AbstractList#get(int) */ @Override public T get(int index) { T result = datas.get(index); return result; } @Override public void add(int index, T element) { datas.add(index, element); this.index.clear(); } @Override public T set(int index, T element) { T result = datas.set(index, element); this.index.clear(); return result; } @Override public T remove(int index) { T result = super.remove(index); this.index.clear(); return result; } /* * @see java.util.AbstractCollection#size() */ @Override public int size() { int result = datas.size(); return result; } /* * @see java.util.AbstractList#indexOf(java.lang.Object) */ @Override public int indexOf(Object o) { Map index = getIndex(); Integer result = index.get(o); int resultIndex = -1; if (result != null) { resultIndex = result.intValue(); } return resultIndex; } protected Map getIndex() { if (index.isEmpty()) { for (int i = 0; i < datas.size(); i++) { index.put(datas.get(i), Integer.valueOf(i)); } } return index; } } /** * Implantation particuliere de matrice, qui lorsqu'on lui passe des * dimension qui n'existe pas, elle les ajoutes dans les semantiques. Ceci * n'est vrai que pour le set avec des semantiques, le set avec des indices * ne rend pas la matrice elastique. *

* Cette classe fonctionne avec une matrice interne que l'on change lorsque * l'on a besoin de modifier les dimensions. Le changement de dimension * a donc un cout (creation d'une nouvelle matrice, copie des elements) *

* Si on cree une sous matrice, et que l'on modifie la matrice mere * La sous matrice n'est pas impacter, puisqu'elle est base sur l'ancienne * represention interne de la matrice elastique, les deux matrices n'ont donc * plus de lien. *

* Les methodes reduce et extend retourne de nouvelle matrice qui ne sont * pas elastique. Si on veut qu'elle le soit, il faut les reencapsuler * * @param */ public static class MatrixMapElastic implements MatrixMap { protected MatrixMap internalMatrixMap; public MatrixMapElastic() { internalMatrixMap = Factory.create(); } public MatrixMapElastic(MatrixMap m) { setInternalMatrixMap(m); } public MatrixMap getInternalMatrixMap() { return internalMatrixMap; } public void setInternalMatrixMap(MatrixMap internalMatrixMap) { this.internalMatrixMap = internalMatrixMap; } public MatrixMapIterator iterator() { return getInternalMatrixMap().iterator(); } public MatrixMap copy() { return getInternalMatrixMap().copy(); } public SemanticList[] getSemantics() { return getInternalMatrixMap().getSemantics(); } public SemanticList getSemantic(int dim) { return getInternalMatrixMap().getSemantic(dim); } public void setSemantic(int dim, List sem) { getInternalMatrixMap().setSemantic(dim, sem); } public void setName(String name) { getInternalMatrixMap().setName(name); } public String getName() { return getInternalMatrixMap().getName(); } public String[] getDimensionNames() { return getInternalMatrixMap().getDimensionNames(); } public void setDimensionNames(String[] names) { getInternalMatrixMap().setDimensionNames(names); } public void setDimensionName(int dim, String name) { getInternalMatrixMap().setDimensionName(dim, name); } public String getDimensionName(int dim) { return getInternalMatrixMap().getDimensionName(dim); } public int getDimCount() { return getInternalMatrixMap().getDimCount(); } public int[] getDim() { return getInternalMatrixMap().getDim(); } public int getDim(int d) { return getInternalMatrixMap().getDim(d); } public MatrixMap map(MapFunction f) { return getInternalMatrixMap().map(f); } public E getValueIndex(int... coordinates) { return getInternalMatrixMap().getValueIndex(coordinates); } public void setValueIndex(E value, int... coordinates) { // la matrice est elastique que pour le set avec des semantics getInternalMatrixMap().setValueIndex(value, coordinates); } public E getValue(Object... coordinates) { return getInternalMatrixMap().getValue(coordinates); } public void setValue(E value, Object... coordinates) { // check si les coordonnees sont valide. // si non valide alors on extend la matrice interne // et on appelle sur la nouvelle matrice interne if (!isValidCoordinates(coordinates)) { MatrixMap newMatrixMap = getInternalMatrixMap().extend(coordinates); setInternalMatrixMap(newMatrixMap); } getInternalMatrixMap().setValue(value, coordinates); } @Override public boolean equals(Object obj) { return getInternalMatrixMap().equals(obj); } public boolean equals(MatrixMap mat) { return getInternalMatrixMap().equals(mat); } public boolean equalsValues(MatrixMap mat) { return getInternalMatrixMap().equalsValues(mat); } @Override public String toString() { return getInternalMatrixMap().toString(); } public String toStringGeneric() { return getInternalMatrixMap().toStringGeneric(); } public boolean isValidCoordinates(Object[] semantics) { return getInternalMatrixMap().isValidCoordinates(semantics); } public MatrixMap paste(MatrixMap mat) { return getInternalMatrixMap().paste(mat); } public MatrixMap getSubMatrix(int dim, Object start, int nb) { return getInternalMatrixMap().getSubMatrix(dim, start, nb); } public MatrixMap getSubMatrix(int dim, Object... elem) { return getInternalMatrixMap().getSubMatrix(dim, elem); } public MatrixMap getSubMatrix(Object[]... elems) { return getInternalMatrixMap().getSubMatrix(elems); } public MatrixMap reduce() { return getInternalMatrixMap().reduce(); } public MatrixMap reduceDims(int... dims) { return getInternalMatrixMap().reduceDims(dims); } public MatrixMap reduce(int minNbDim) { return getInternalMatrixMap().reduce(minNbDim); } public MatrixMap extend(Object... sems) { return getInternalMatrixMap().extend(sems); } } /** * Implantation de MatrixMap dont les dimensions sont fixees a la creation * Les dimensions ne change plus par la suite */ public static class MatrixMapFixed extends AbstractMatrixMap { /** to use log facility, just put in your code: log.info(\"...\"); */ static private Log log = LogFactory.getLog(MatrixMapFixed.class); protected Matrix matrix = null; public MatrixMapFixed(List... semantics) { super(semantics); } public MatrixMapFixed(String name, List... semantics) { this(semantics); setName(name); } public MatrixMapFixed(String name, String[] dimNames, List... semantics) { this(name, semantics); for (int i = 0; dimNames != null && i < dimNames.length; i++) { setDimensionName(i, dimNames[i]); } } public MatrixMapFixed(MatrixMap matrix) { this(matrix.getName(), matrix.getDimensionNames(), matrix.getSemantics()); this.pasteIndex(matrix); } protected Matrix getMatrix() { if (matrix == null) { matrix = new Matrix(getDim()); } return matrix; } @Override public MatrixMapIterator iterator() { return new MatrixMapIteratorImpl(getMatrix().iterator(), getSemantics()); } @Override public MatrixMap map(MapFunction f) { getMatrix().data.map(f); return this; } @Override public E getValueIndex(int... coordinates) { if (coordinates.length == 0) { throw new IllegalArgumentException("Coordinates must not be empty"); } return getMatrix().getValue(coordinates); } /** * Modifie un element de la matrice en fonction des dimensions passé en * paramètre.
*

* Exemple: Si on a un matrice 3D.
* m.set(v, [1,1,1]) modifie un element de la matrice.
* * @param value la value a inserer * @param coordinates les coordonées où faire le remplacement */ @Override public void setValueIndex(E value, int... coordinates) { if (coordinates.length == 0) { throw new IllegalArgumentException("Coordinates must not be empty"); } getMatrix().setValue(coordinates, value); } /** * Copie une matrice dans la matrice actuelle. La matrice à copier à le même * nombre de dimension. Si la matrice à copier est trop grande seul les * éléments pouvant être copier le seront. * * @param origin le point à partir duquel il faut faire la copie * @param mat la matrice à copier * @return return la matrice courante. */ public MatrixMap paste(int[] origin, MatrixMap mat) { if (mat != null) { // si les matrice mat et this on les memes dimensions // et que origin est 0, on optimise en appeler une methode paste // sur Matrix qui l'appel sur le vector // permet de savoir si l'origin est bien le point 0 de la matrice boolean origin0 = true; for (int i = 0; i < origin.length && origin0; i++) { origin0 = origin0 && origin[i] == 0; } if (origin0 && mat instanceof MatrixMapFixed && Arrays.equals(mat.getDim(), this.getDim())) { getMatrix().data.paste(((MatrixMapFixed) mat).getMatrix().data); } else { super.paste(origin, mat); } } return this; } } /** * Classe abstraite permettant de facilement implanter les matrice fixe, * elastique et submatrix * * @param */ public static abstract class AbstractMatrixMap implements MatrixMap { /** to use log facility, just put in your code: log.info(\"...\"); */ static private Log log = LogFactory.getLog(AbstractMatrixMap.class); protected String name = null; protected String[] dimNames = null; protected int[] dim = null; protected SemanticList[] semantics = null; protected void init(int[] dim) { this.dim = new int[dim.length]; System.arraycopy(dim, 0, this.dim, 0, dim.length); semantics = new SemanticList[dim.length]; dimNames = new String[dim.length]; } protected AbstractMatrixMap(int[] dim) { init(dim); for (int i = 0; i < getDimCount(); i++) { // par defaut les listes des semantiques contiennent des nulls // FIXME no multiple null allowed setSemantic(i, Collections.nCopies(dim[i], null)); } } public AbstractMatrixMap(List... semantics) { int[] dim = new int[semantics.length]; for (int i = 0; i < dim.length; i++) { if (semantics[i] == null) { dim[i] = 0; } else { dim[i] = semantics[i].size(); } } init(dim); for (int i = 0; i < getDimCount(); i++) { setSemantic(i, semantics[i]); } } protected AbstractMatrixMap(String name, int[] dim) { this(dim); setName(name); } protected AbstractMatrixMap(String name, int[] dim, String[] dimNames) { this(dim); setName(name); for (int i = 0; dimNames != null && i < dimNames.length; i++) { setDimensionName(i, dimNames[i]); } } public AbstractMatrixMap(String name, List... semantics) { this(semantics); setName(name); } public AbstractMatrixMap(String name, String[] dimNames, List... semantics) { this(name, semantics); for (int i = 0; dimNames != null && i < dimNames.length; i++) { setDimensionName(i, dimNames[i]); } } public AbstractMatrixMap(MatrixMap matrix) { this(matrix.getName(), matrix.getDimensionNames(), matrix.getSemantics()); this.pasteIndex(matrix); } /** * Copy la matrice pour pouvoir la modifier sans perdre les donnees * initiales. * * @return new matrix */ public MatrixMap copy() { MatrixMap result = new MatrixMapFixed(this); return result; } /* * @see java.lang.Object#clone() */ @Override public MatrixMap clone() { return copy(); } public SemanticList[] getSemantics() { return semantics; } public SemanticList getSemantic(int dim) { return semantics[dim]; } public void setSemantic(int dim, List sem) { // make copy because this matrix can change semantics SemanticList l = new SemanticList(sem); semantics[dim] = l; } public void setName(String name) { this.name = name; } public String getName() { return name; } public String[] getDimensionNames() { return dimNames; } public void setDimensionNames(String[] names) { for (int i = 0; names != null && i < names.length; i++) { setDimensionName(i, names[i]); } } public void setDimensionName(int dim, String name) { dimNames[dim] = name; } public String getDimensionName(int dim) { return dimNames[dim]; } public int getDimCount() { return dim.length; } public int[] getDim() { return dim; } public int getDim(int d) { return dim[d]; } /** * Retourne la matrice elle meme. Les modifications sont faites directement * dessus */ @Override public MatrixMap map(MapFunction f) { for (MatrixMapIterator i = iterator(); i.hasNext(); ) { i.setValue(f.apply(i.next())); } return this; } public E getValue(Object... coordinates) { if (coordinates.length == 0) { throw new IllegalArgumentException("Coordinates must not be empty"); } int[] intCoordinates = MatrixHelper.semanticsToDimension(getSemantics(), coordinates); E result = getValueIndex(intCoordinates); return result; } public void setValue(E value, Object... coordinates) { if (coordinates.length == 0) { throw new IllegalArgumentException("Coordinates must not be empty"); } int[] intCoordinates = MatrixHelper.semanticsToDimension(getSemantics(), coordinates); setValueIndex(value, intCoordinates); } // TODO peut-etre faire une variante de equals qui regarde par rapport au // coordonnées sémantique @Override public boolean equals(Object o) { return o instanceof MatrixMap && equals((MatrixMap) o); } public boolean equals(MatrixMap mat) { boolean result = true; // le nom doit être le même result = result && getName().equals(mat.getName()); result = result && equalsValues(mat); // les sémantiques doivent-être identique for (int i = 0; result && i < getDimCount(); i++) { String dimName1 = getDimensionName(i); String dimName2 = mat.getDimensionName(i); result = ObjectUtils.equals(dimName1, dimName2); if (log.isTraceEnabled()) { log.trace("dimName1(" + dimName1 + ")==dimName2(" + dimName2 + ")=" + result); } // System.out.println("dimName1("+dimName1+")==dimName2("+dimName2+ // ")="+result); List sem1 = getSemantic(i); List sem2 = mat.getSemantic(i); result = result && ObjectUtils.equals(sem1, sem2); if (log.isTraceEnabled()) { log.trace("sem1(" + sem1 + ")==sem2(" + sem2 + ")=" + result); } // System.out.println("sem1("+sem1+")==sem1("+sem2+ ")="+result); } if (log.isTraceEnabled()) { log.trace("result=" + result); } // System.out.println("result="+result); return result; } /** * Verifie si les matrices sont egales en ne regardant que les valeurs et * pas les semantiques * * @param mat * @return equality on values */ public boolean equalsValues(MatrixMap mat) { boolean result = true; // les dimensions doivent-être identique result = result && MatrixHelper.sameDimension(getDim(), mat.getDim()); // toutes les données doivent être identique for (MatrixMapIterator i = mat.iterator(); result && i.hasNext(); ) { E v1 = i.next(); E v2 = getValueIndex(i.getCoordinates()); result = v1 == v2; if (log.isTraceEnabled()) { log.trace("v1(" + v1 + ")==v2(" + v2 + ")=" + result); } } return result; } /** * Si la matrice est 1D *

         * MaMatrice(matrix1D) [
         * MaDimName: Dim1, Dim2, Dim3,
         *              v1,   v2,   v3
         * ]
         * 
*

* Si la matrice est 2D *

         * MaMatrice(matrix2D) [
         *            MaDimX
         * MaDimY     Dim1, Dim2, Dim3,
         * DimA       v1,     v2,   v3
         * DimB       v4,     v5,   v6
         * DimC       v7,     v8,   v9
         * ]
         * 
*

* Pour les autres types de matrice la methode {@link #toStringGeneric() } * est utilise * * @return */ @Override public String toString() { int LENGTH = 10; StringBuilder result = new StringBuilder(); if (getDimCount() == 1) { result.append(MatrixHelper.format(getName(), -LENGTH, "#NoNameMat")); result.append("(matrix1D)[\n"); String dimName = getDimensionName(0); result.append(MatrixHelper.format(dimName, LENGTH, "#NoNameDim")); for (Object sem : getSemantic(0)) { result.append(","); result.append(MatrixHelper.format(sem, -LENGTH, null)); } result.append(StringUtils.repeat(" ", LENGTH + 1)); for (int i = 0; i < getDim(0); i++) { Object v = getValueIndex(i); result.append(MatrixHelper.format(v, -LENGTH, null) + ","); } result.append("\n]"); } else if (getDimCount() == 2) { int[] pos = new int[2]; result.append(MatrixHelper.format(getName(), -LENGTH, "#NoNameMat")); result.append("(matrix2D) [\n"); result.append(StringUtils.repeat(" ", LENGTH + 1)); String dimNameX = getDimensionName(0); result.append(MatrixHelper.format(dimNameX, LENGTH, "#DimX")); result.append("\n"); String dimNameY = getDimensionName(1); result.append(MatrixHelper.format(dimNameY, LENGTH, "#DimY")); result.append(" "); for (Object sem : getSemantic(0)) { result.append(MatrixHelper.format(sem, -LENGTH, null)); result.append(","); } for (int y = 0; y < getDim(1); y++) { result.append("\n"); Object sem = getSemantic(1).get(y); result.append(MatrixHelper.format(sem, LENGTH, null)); result.append(" "); for (int x = 0; x < getDim(0); x++) { pos[0] = x; pos[1] = y; Object v = getValueIndex(pos); result.append(MatrixHelper.format(v, -LENGTH, null) + ","); } } result.append("\n]"); } else { result.append(toStringGeneric()); } return result.toString(); } /** * Representation string de la matrice quelque soit le nombre de dimension * * @return */ public String toStringGeneric() { StringBuilder result = new StringBuilder(); result.append(MatrixHelper.format(getName(), 0, "#NoNameMat")); result.append("(matrix" + getDimCount() + "D)[\n"); result.append("dimensions = ["); for (int i = 0; i < getDim().length; i++) { result.append(getDim()[i] + ","); } result.append("]\ndata = ["); for (MatrixMapIterator i = this.iterator(); i.hasNext(); ) { result.append(i.next() + ","); } result.append("]\n"); return result.toString(); } public boolean isValidCoordinates(int[] dim) { boolean result = getDimCount() == dim.length; for (int i = 0; result && i < dim.length; i++) { result = 0 <= dim[i] && dim[i] < getDim(i); } return result; } public boolean isValidCoordinates(Object[] semantics) { boolean result = getDimCount() == semantics.length; for (int i = 0; result && i < semantics.length; i++) { List semantic = getSemantic(i); result = semantic.contains(semantics[i]); } return result; } /** * Copie une matrice dans la matrice actuelle. La matrice à copier à le même * nombre de dimension. Si la matrice à copier est trop grande seul les * éléments pouvant être copier le seront. * * @param mat la matrice à copier * @return return la matrice courante. */ public MatrixMap pasteIndex(MatrixMap mat) { return paste(new int[getDimCount()], mat); } protected MatrixMap paste(int[] origin, MatrixMap mat) { if (mat != null) { for (MatrixMapIterator mi = mat.iterator(); mi.hasNext(); ) { E value = mi.next(); int[] coordinates = ArrayUtil.sum(origin, mi.getCoordinates()); if (isValidCoordinates(coordinates)) { setValueIndex(value, coordinates); } } } return this; } /** * Modifie la matrice actuel en metant les valeurs de mat passé en parametre * La copie se fait en fonction de la semantique, si un element dans une * dimension n'est pas trouvé, alors il est passé */ public MatrixMap paste(MatrixMap mat) { if (mat != null) { for (MatrixMapIterator mi = mat.iterator(); mi.hasNext(); ) { E value = mi.next(); Object[] sems = mi.getSemanticsCoordinates(); if (isValidCoordinates(sems)) { setValue(value, sems); } } } return this; } /** * Permet de prendre une sous matrice dans la matrice courante. La sous * matrice a le même nombre de dimensions mais sur une des dimensions on ne * prend que certain élément. * * @param dim la dimension dans lequel on veut une sous matrice si dim est * négatif alors la dimension est prise à partir de la fin par * exemple si l'on veut la derniere dimension il faut passer -1 * pour dim * @param start la position dans dim d'ou il faut partir pour prendre la * sous matrice. * @param nb le nombre d'élément à prendre dans la dimension. si nb est * inférieur ou égal à 0 alors cela indique qu'il faut prendre * tous les éléments jusqu'à la fin de la dimension. * @return new matrix */ public MatrixMap getSubMatrix(int dim, int start, int nb) { if (dim < 0) { dim = getDimCount() + dim; } if (start < 0) { start = getDim(dim) + start; } if (nb <= 0) { nb = getDim(dim) - start; } return new SubMatrix(this, dim, start, nb); } /** * Permet de prendre une sous matrice dans la matrice courante. La sous * matrice a le même nombre de dimensions mais sur une des dimensions on ne * prend que certain élément. * * @param dim la dimension dans lequel on veut une sous matrice * @param start la position dans dim d'ou il faut partir pour prendre la * sous matrice. 0 <= start < dim.size si start est négatif alors * la position de départ est calculé par rapport à la fin de la * dimension, pour avoir le dernier élément il faut passer -1 * @param nb le nombre d'élément à prendre dans la dimension si nb est * inférieur ou égal à 0 alors cela indique qu'il faut prendre * tous les éléments jusqu'à la fin de la dimension. * @return new matrix */ public MatrixMap getSubMatrix(int dim, Object start, int nb) { int begin = MatrixHelper.indexOf(getSemantics(), dim, start); return getSubMatrix(dim, begin, nb); } /** * Add to desambiguas some call with xpath engine, but do the same thing * {@link #getSubMatrix(int, Object[])} * * @param dim * @param elem * @return new matrix */ public MatrixMap getSubMatrixOnSemantic(int dim, Object... elem) { MatrixMap result = getSubMatrix(dim, elem); return result; } /** * Permet de prendre une sous matrice dans la matrice courante. La sous * matrice a le même nombre de dimensions mais sur une des dimensions on ne * prend que certain élément. * * @param dim la dimension dans lequel on veut une sous matrice * @param elem les éléments dans la dimension à conserver * @return new matrix */ public MatrixMap getSubMatrix(int dim, Object... elem) { int[] ielem = new int[elem.length]; for (int i = 0; i < ielem.length; i++) { ielem[i] = MatrixHelper.indexOf(getSemantics(), dim, elem[i]); } return getSubMatrix(dim, ielem); } /** * Permet de prendre une sous matrice dans la matrice courante. *

* Réalise plusieurs appels à {@link #getSubMatrix(int, Object...)} suivant * l'implémentation. * * @param elems les éléments dans la dimension à conserver * @return new matrix */ public MatrixMap getSubMatrix(Object[]... elems) { // la reduction doit se faire sur le meme nombre de dimension if (elems.length != dim.length) { throw new IllegalArgumentException(String.format( "Can't get sub matrix with different dimension count " + "(expected: %d, got %d)", dim.length, elems.length)); } MatrixMap result = this; for (int i = 0; i < elems.length; ++i) { if (elems[i] != null) { result = result.getSubMatrix(i, elems[i]); } } return result; } /** * Permet de prendre une sous matrice dans la matrice courante. La sous * matrice a le même nombre de dimensions mais sur une des dimensions on ne * prend que certain élément. * * @param dim la dimension dans lequel on veut une sous matrice * @param elem les indices des éléments dans la dimension à conserver * @return new matrix */ public MatrixMap getSubMatrix(int dim, int[] elem) { return new SubMatrix(this, dim, elem); } /** * Permet de prendre une sous matrice dans la matrice courante. *

* Réalise plusieurs appels a {@link #getSubMatrix(int, int[])} suivant * l'implementation. * * @param elems les indices des éléments pour chaque dimension à conserver * @return new matrix */ public MatrixMap getSubMatrix(int[]... elems) { // la reduction doit se faire sur le meme nombre de dimension if (elems.length != dim.length) { throw new IllegalArgumentException(String.format( "Can't get sub matrix with different dimension count " + "(expected: %d, got %d)", dim.length, elems.length)); } MatrixMap result = this; for (int i = 0; i < elems.length; ++i) { if (elems[i] != null) { result = new SubMatrix(result, i, elems[i]); } } return result; } /** * Reduit la matrice de sorte que toutes les dimensions qui n'ont qu'un * élement soit supprimée. Au pire cette méthode retourne une matrice à une * seule dimension à un seul élément. * * @return une nouvelle matrice plus petite que la matrice actuelle ou egal * s'il n'y a aucune dimension à supprimer */ public MatrixMap reduce() { return reduce(1); } /** * Reduit le matrice seulement sur les dimensions passées en argument. Si * une des dimensions passées en arguement n'a pas qu'un seul élément, cette * dimension n'est pas prise en compte. * * @param dims les dimensions sur lequel il faut faire la reduction * @return une nouvelle matrice */ public MatrixMap reduceDims(int... dims) { Arrays.sort(dims); // tableau permettant de faire la correspondance entre les dimensions // de la matrice actuelle et les dimentsions de la nouvelle matrice // l'element i du tableau qui correcpond à la dimensions i de la // nouvelle matrice contient la dimension equivalente dans // la matrice actuelle int[] correspondance = new int[getDimCount()]; // les nouvelles semantiques List sem = new ArrayList(); // les nouveaux noms de dimensions List dimName = new ArrayList(); // il faut au moins une dimension pour la matrice int minNbDim = 1; for (int j = getDimCount() - 1; j >= 0; j--) { // si la dimension à plus d'un élément ou qu'il n'est pas dans dims // on garde la dimension if (getDim(j) > 1 || Arrays.binarySearch(dims, j) < 0 || j < minNbDim) { // on ne conserve que les dimensions supérieure à 1 correspondance[sem.size()] = j; sem.add(getSemantic(j)); dimName.add(getDimensionName(j)); minNbDim--; } } MatrixMap result = reduce(dimName, sem, correspondance); return result; } /** * Reduit la matrice de sorte que toutes les dimensions qui n'ont qu'un * élement soit supprimée. Au pire cette méthode retourne une matrice à une * seule dimension à un seul élément. * * @param minNbDim le nombre minimum de dimension que l'on souhaite pour la * matrice résultat * @return une nouvelle matrice plus petite que la matrice actuelle ou egal * s'il n'y a aucune dimension à supprimer */ public MatrixMap reduce(int minNbDim) { // tableau permettant de faire la correspondance entre les dimensions // de la matrice actuelle et les dimentsions de la nouvelle matrice // l'element i du tableau qui correcpond à la dimensions i de la // nouvelle matrice contient la dimension equivalente dans // la matrice actuelle int[] correspondance = new int[getDimCount()]; // les nouvelles semantiques List sem = new ArrayList(); // les nouveaux noms de dimensions List dimName = new ArrayList(); for (int j = getDimCount() - 1; j >= 0; j--) { // si la dimension à plus d'un élément ou si on a pas assez de // dimension pour avoir le minimum demandé on prend la dimension if (getDim(j) > 1 || j < minNbDim) { // on ne conserve que les dimensions supérieure à 1 correspondance[sem.size()] = j; sem.add(getSemantic(j)); dimName.add(getDimensionName(j)); // on vient de prendre une dimension il nous en faut une de // moins minNbDim--; } } MatrixMap result = reduce(dimName, sem, correspondance); return result; } /** * Create new matrice from the current matrix. * * @param dimName dimension name for new matrix * @param sem semantic for new matrix * @param correspondance array to do the link between current matrix and * returned matrix * @return new matrix */ protected MatrixMap reduce(List dimName, List sem, int[] correspondance) { // on converti les listes en tableau en inversant l'ordre car on // a fait un parcours en sens inverse int nbDim = sem.size(); List[] newSemantics = new List[nbDim]; String[] newDimNames = new String[nbDim]; int[] tmpcorrespondance = new int[nbDim]; for (int i = 0; i < nbDim; i++) { newSemantics[i] = sem.get(nbDim - 1 - i); newDimNames[i] = dimName.get(nbDim - 1 - i); tmpcorrespondance[i] = correspondance[nbDim - 1 - i]; } correspondance = tmpcorrespondance; MatrixMap result = new MatrixMapFixed(getName(), newDimNames, newSemantics); // on reprend les valeurs int[] newCoordinates = new int[result.getDimCount()]; for (MatrixMapIterator mi = iterator(); mi.hasNext(); ) { E value = mi.next(); int[] oldCoordinates = mi.getCoordinates(); for (int i = 0; i < newCoordinates.length; i++) { newCoordinates[i] = oldCoordinates[correspondance[i]]; } result.setValueIndex(value, newCoordinates); } return result; } public MatrixMap extend(Object... sems) { String name = getName(); String[] dimNames = getDimensionNames(); SemanticList[] semantics = getSemantics(); // si pas assez de dimension on en rajoute if (sems.length > semantics.length) { String[] newDimNames = new String[sems.length]; System.arraycopy(dimNames, 0, newDimNames, 0, dimNames.length); dimNames = newDimNames; SemanticList[] newSems = new SemanticList[sems.length]; System.arraycopy(semantics, 0, newSems, 0, semantics.length); semantics = newSems; for (int i = semantics.length; i < newSems.length; i++) { newSems[i] = new SemanticList(); } } // si les objets demande n'existe pas dans la semantics on l'ajoute for (int i = 0; i < sems.length; i++) { if (semantics[i].indexOf(sems[i]) == -1) { semantics[i].add(sems[i]); } } MatrixMap result = MatrixMap.Factory.create(name, dimNames, semantics); result.paste(this); return result; } } /** * 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. *

* C'est comme une "vue" réduite sur la vraie matrices. */ public static class SubMatrix extends AbstractMatrixMap { // SubMatrix protected MatrixMap matrix = null; protected DimensionConverter converter = null; public SubMatrix(MatrixMap matrix, int dim, int start, int nb) { super(matrix.getName(), matrix.getDimensionNames(), matrix.getSemantics()); this.matrix = matrix; converter = new ShiftConverter(dim, start, nb); setSemantic(dim, getSemantic(dim).subList(start, start + nb)); getDim()[dim] = nb; } public SubMatrix(MatrixMap matrix, int dim, int[] elem) { super(matrix.getName(), matrix.getDimensionNames(), matrix.getSemantics()); 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 MatrixMapIterator iterator() { return new SubMatrixIterator(this); } @Override public E getValueIndex(int... coordinates) { return matrix.getValueIndex(converter.convertCoordinates(coordinates)); } @Override public void setValueIndex(E value, int... coordinates) { matrix.setValueIndex(value, converter.convertCoordinates(coordinates)); } protected class SubMatrixIterator implements MatrixMapIterator { protected SubMatrix subMatrix = null; protected int[] cpt = null; protected int[] last = null; public SubMatrixIterator(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 E next() { 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]; } E result = getValue(); return result; } @Override public void remove() { setValue(null); } public int[] getCoordinates() { return cpt; } public Object[] getSemanticsCoordinates() { int[] coordinates = getCoordinates(); Object[] result = MatrixHelper.dimensionToSemantics(subMatrix.getSemantics(), coordinates); return result; } public E getValue() { return subMatrix.getValueIndex(getCoordinates()); } public void setValue(E value) { subMatrix.setValue(value, getCoordinates()); } } /** * 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 static class ShiftConverter implements DimensionConverter { /** serialVersionUID. */ 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 static 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 /** * Objet matrice qui ne permet que le stockage avec des positions int * dans une matrice a autant de dimension que l'on souhaite. */ public static class Matrix implements Iterable { // BasicMatrix /** Les dimensions de la matrice */ protected int[] dimensions = null; /** La matrice en représentation linéaire */ protected Vector data = null; /** * tableau de facteur permettant de convertir les coordonnées dans la * matrice en un indice dans la représentation linéaire de la matrice */ protected int[] linearFactor = null; /** * Crée une nouvelle matrice ayant les dimensions demandées. * * @param dimensions dimensions */ public Matrix(int[] dimensions) { checkDim(dimensions); // copie des dimensions pour que personne à l'extérieur de l'objet // ne puisse les modifiers par la suite this.dimensions = new int[dimensions.length]; System.arraycopy(dimensions, 0, this.dimensions, 0, dimensions.length); // calcul du linearFactor linearFactor = new int[dimensions.length]; linearFactor[linearFactor.length - 1] = 1; for (int i = linearFactor.length - 2; i >= 0; i--) { linearFactor[i] = linearFactor[i + 1] * dimensions[i + 1]; } // creation de la matrice lineaire data = new Vector(linearFactor[0] * dimensions[0]); } /** * Retourne le nombre de dimension de la matrice * * @return le nombre de dimension de la matrice; */ public int getNbDim() { return dimensions.length; } /** * Retourne la taille d'une dimension * * @param dim la dimension dont on souhaite la taille * @return la taille d'une dimension */ public int getDim(int dim) { checkDim(dim); return dimensions[dim]; } /** * Retourne un tableau representant les dimensions de la matrice. Le tableau * retourné n'est pas une copie, il ne faut donc pas le modifier * * @return le tableau des dimensions. */ public int[] getDim() { return dimensions; } /** * Retourne un element de la matrice * * @param pos la position de l'element à retourner * @return un element de la matrice */ public E getValue(int[] pos) { int indice = coordonatesToLinear(pos); return data.getValue(indice); } /** * Modifie un élement de la matrice * * @param pos la position de l'element à modifier * @param value la nouvelle valeur à mettre dans la matrice */ public void setValue(int[] pos, E value) { int indice = coordonatesToLinear(pos); data.setValue(indice, value); } /** * Retourne un objet Inc pret a etre utilisé pour boucler sur tous les * element de la matrice. * * @return un objet Inc pret à être utilisé */ public MatrixIterator iterator() { return new MatrixIterator(this); } /** * Permet de faire un traitement sur chaque valeur de la matrice * * @param f la fonction a appliquer à chaque élement de la matrice */ public void map(MapFunction f) { data.map(f); } /** * Permet de convertir les coordonnées d'un élément en un indice dans la * représentation linéraire de la matrice. * * @param coordonates les coordonnées à lineariser * @return un indice réprésentant les coordonnées de façon linéaire */ protected int coordonatesToLinear(int[] coordonates) { checkPos(coordonates); int result = 0; for (int i = 0; i < linearFactor.length; i++) { result += coordonates[i] * linearFactor[i]; } return result; } /** * Convertie une coordonnée lineaire en coordonnées spaciales * * @param pos la coordonnée linéaire * @return les coordonnées spaciales de l'élément */ protected int[] linearToCoordinates(int pos) { int[] result = new int[linearFactor.length]; for (int i = 0; i < result.length; i++) { result[i] = pos / linearFactor[i]; pos -= result[i] * linearFactor[i]; } return result; } /** * Permet de vérifier que les dimensions de la nouvelle matrice sont * corrects * * @param dim les dimensions de la nouvelle matrice * @throws IllegalArgumentException si une dimension n'est pas valide */ protected void checkDim(int[] dim) { for (int i = 0; i < dim.length; i++) { if (dim[i] <= 0) { throw new IllegalArgumentException(String.format( "Dimension %s is invalid %s", i, dim[i])); } } } /** * Permet de vérifier qu'une dimension demandé existe bien dans la matrice * * @param dim la position de la dimension que l'on souhaite * @throws IndexOutOfBoundsException si la dimension demandée n'existe pas */ protected void checkDim(int dim) { if (dim < 0 || dim >= getNbDim()) { throw new IndexOutOfBoundsException(String.format( "Invalid dimension %s max dimension is %s", dim, getNbDim())); } } /** * Verifie que les coordonnées demandé appartiennent bien à la matrice * * @param pos les coordonnées souhaitées dans la matrice * @throws NoSuchElementException si les coordonnées ne correspondent pas à * un élement de la matrice */ protected void checkPos(int[] pos) { int[] dim = getDim(); boolean result = dim.length == pos.length; for (int i = 0; result && i < dim.length; i++) { result = (0 <= pos[i]) && (pos[i] < dim[i]); } if (!result) { throw new NoSuchElementException(String.format( "Invalid element asked %s for real dimension %s", Arrays.toString(pos), Arrays .toString(dim))); } } @Override public String toString() { StringBuffer result = new StringBuffer(); if (getNbDim() == 1) { result.append("matrix1D ["); for (int i = 0; i < data.size(); i++) { result.append(data.getValue(i) + ","); } result.append("]"); } else if (getNbDim() == 2) { int[] pos = new int[2]; result.append("matrix2D ["); for (int y = 0; y < getDim(1); y++) { result.append("\n"); for (int x = 0; x < getDim(0); x++) { pos[0] = x; pos[1] = y; result.append(getValue(pos) + ","); } } result.append("]"); } else { result.append("dimensions = [\n"); for (int i = 0; i < dimensions.length; i++) { result.append(dimensions[i] + ","); } result.append("\n]\nmatrice = [\n"); for (int i = 0; i < data.size(); i++) { result.append(data.getValue(i) + ","); } result.append("\n]\nlinearFactor = [\n"); for (int i = 0; i < linearFactor.length; i++) { result.append(linearFactor[i] + ","); } result.append("\n]\n"); } return result.toString(); } @Override public boolean equals(Object o) { if (o instanceof Matrix) { Matrix other = (Matrix) o; return this == o || (Arrays.equals(this.dimensions, other.dimensions) && this.data .equals(other.data)); } return false; } } // BasicMatrix public static class MatrixIterator implements Iterator { // MatrixIteratorImpl protected Matrix matrix = null; protected int pos = -1; /** @param matrix la matrice sur lequel l'iterator doit travailler */ public MatrixIterator(Matrix matrix) { this.matrix = matrix; pos = -1; } @Override public boolean hasNext() { return pos + 1 < matrix.data.size(); } @Override public E next() { if (hasNext()) { pos++; } else { throw new NoSuchElementException(); } E result = getValue(); return result; } @Override public void remove() { setValue(null); } public E getValue() { return matrix.data.getValue(pos); } public void setValue(E value) { matrix.data.setValue(pos, value); } public int[] getCoordinates() { return matrix.linearToCoordinates(pos); } } // MatrixIteratorImpl /** * Permet de stocker des données à une position lineaire et de la redemander. * Cette classe ne gére que les données lineaire. L'avantage de cette classe est * de ne conserver que les elements differents de la valeur par defaut, ce qui * minimize la taille du tableau necessaire a conserver les données. */ public static class Vector { // Vector /** maximum number of element, maximum pos value */ protected int capacity = 0; /** la valeur par defaut */ protected E defaultValue = null; /** contient la position de l'element, le tableau est trie */ protected int[] position; protected int positionSize = 0; /** contient la valeur de l'element */ protected ArrayList data = new ArrayList(); public Vector(int capacity) { this.capacity = capacity; position = new int[8]; Arrays.fill(position, Integer.MAX_VALUE); } public Vector(int capacity, E defaultValue) { this(capacity); this.defaultValue = defaultValue; } public int size() { return capacity; } // poussin 20060827 TODO: verifier l'implantation, il semble quelle soit // fausse et ne puisse pas recherche le nombre max correctement public E getMaxOccurrence() { E result = defaultValue; E[] tmp = (E[]) data.toArray(); // si potentiellement il y a plus d'element identique dans data // que de valeur par defaut, on recherche la valeur possible if (this.capacity < 2 * tmp.length) { Arrays.sort(tmp); // le nombre de fois que l'on a rencontrer la valeur la plus // nombreuse int max = 1; // le nombre de fois que l'on a rencontrer la valeur courante int count = 1; // la valeur la plus rencontrer result = tmp[0]; // la valeur que l'on vient de traiter précédement E old = tmp[0]; // la valeur courante lu dans le tableaux E current = tmp[0]; // tant que l'on peut encore trouve un element plus nombreux dans le // tableau on le parcours for (int i = 1; max < tmp.length - i + count && i < tmp.length; i++) { current = tmp[i]; if (current == old) { count++; } else { if (count > max) { max = count; result = old; } count = 1; old = current; } } if (count > max) { max = count; result = current; } if (max <= capacity - tmp.length) { // en fin de compte, il n'y a pas plus d'element identique // dans data que de defaultValue result = defaultValue; } } return result; } protected void checkPos(int pos) { if (pos < 0 || pos >= capacity) { throw new IllegalArgumentException("pos " + pos + " is not in [0, " + capacity + "]"); } } public E getValue(int pos) { checkPos(pos); E result = defaultValue; int index = findIndex(pos); if (index >= 0) { result = data.get(index); } return result; } public void setValue(int pos, E value) { checkPos(pos); int index = findIndex(pos); if (index >= 0) { if (value == defaultValue) { // il etait present, on supprime l'element removeElementAt(index); data.remove(index); } else { // il etait deja present, on modifie la valeur data.set(index, value); } } else { // il n'etait pas present if (value != defaultValue) { // il faut ajouter dans position et dans data index = -index - 1; addElementAt(index, pos); data.add(index, value); } } } public boolean equals(Object o) { boolean result = false; if (o instanceof Vector) { Vector other = (Vector) o; result = Arrays.equals(this.position, other.position) && data.equals(other.data); } return result; } /** * retourne la position dans le tableau position de la position lineaire * * @param pos * @return la position ou < 0 donnant la position de l'element s'il etait * present */ protected int findIndex(int pos) { return Arrays.binarySearch(position, pos); } protected void ensureCapacity(int mincap) { if (mincap > position.length) { int newcap = (position.length * 3) / 2 + 1; int olddata[] = position; position = new int[newcap >= mincap ? newcap : mincap]; System.arraycopy(olddata, 0, position, 0, positionSize); for (int i = positionSize; i < position.length; i++) { position[i] = Integer.MAX_VALUE; } } } protected void addElementAt(int index, int element) { ensureCapacity(positionSize + 1); int numtomove = positionSize - index; System.arraycopy(position, index, position, index + 1, numtomove); position[index] = element; positionSize++; } protected int removeElementAt(int index) { int oldval = position[index]; int numtomove = positionSize - index - 1; if (numtomove > 0) { System.arraycopy(position, index + 1, position, index, numtomove); } positionSize--; position[positionSize] = Integer.MAX_VALUE; return oldval; } /** * On recopie tous les attributs pour que le vector ressemble exactement a * celui passé en argument */ public void paste(Vector v) { this.capacity = v.capacity; this.defaultValue = v.defaultValue; this.positionSize = v.positionSize; this.position = new int[v.position.length]; System.arraycopy(v.position, 0, this.position, 0, this.position.length); this.data.clear(); this.data.addAll(v.data); } /** on applique sur chaque donnée existante et sur default */ public void map(MapFunction f) { // on commence toujours par modifier la valeur par defaut // car les valeurs suivante pourrait prendre cette valeur // et donc disparaitre des tableaux si besoin defaultValue = f.apply(defaultValue); // on fait la boucle a l'envers au cas ou on supprime des valeurs for (int i = data.size() - 1; i >= 0; i--) { E value = f.apply(data.get(i)); if (value == defaultValue) { // il etait present, on supprime l'element removeElementAt(i); data.remove(i); } else { // il etait deja present, on modifie la valeur data.set(i, value); } } } } // Vector /** * Permet de faire un traitement sur des valeurs et d'en retourner * des nouvelles. */ public static interface MapFunction { // MapFunction /** * Permet de faire un traitement sur value et de retourne une nouvelle * valeur. * * @param value la valeur courante sur lequel il faut faire le traitement * @return la nouvelle valeur à mettre dans la matrice à la place de * l'ancienne. */ E apply(E value); } // MapFunction }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy