1 /*
2 * #%L
3 * Nuiton Utils
4 * %%
5 * Copyright (C) 2004 - 2012 CodeLutin, Chatellier Eric
6 * %%
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Lesser Public License for more details.
16 *
17 * You should have received a copy of the GNU General Lesser Public
18 * License along with this program. If not, see
19 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
20 * #L%
21 */
22 package org.nuiton.util;
23
24 import org.apache.commons.lang3.ObjectUtils;
25 import org.apache.commons.lang3.StringUtils;
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28
29 import java.io.Serializable;
30 import java.util.*;
31
32 /**
33 * Permet de stocker des informations dans une matrix a N dimension
34 * Si lors de l'ajout on indique une dimension qui n'existe pas encore ou
35 * un element dans une dimension qui n'existe pas, la matrice ajoute
36 * automatiquement les elements manquant pour que l'ajout se passe bien.
37 * <p>
38 * MatrixMap permet de stocker les elements avec des cles de n'importe quel
39 * type. Les coordonnees utilisant ces objets sont converti en coordonnees
40 * numeriques qui est la seul chose que sait gere Matrix. Ces coordonnees
41 * numeriques sont alors convertis en coordonnees lineaire pour le stockage
42 * dans Vector. On decoupe ainsi les problemes et on minimise le stockage et
43 * certain traitement sur les données puisqu'au final toutes les données sont
44 * dans une simple liste.
45 * <p>
46 * Pour créer une nouvelle matrice, il faut utiliser une des méthodes de
47 * {@link MatrixMap.Factory}
48 *
49 * @author Benjamin Poussin - poussin@codelutin.com
50 * @since 2.2.1
51 */
52 public interface MatrixMap<E> extends Iterable<E> {
53
54 /**
55 * Classe permettant la creation de matrice
56 */
57 class Factory {
58 public static <T> MatrixMap<T> create(List... semantics) {
59 MatrixMap<T> result = new MatrixMapFixed<T>(semantics);
60 return result;
61 }
62
63 public static <T> MatrixMap<T> create(String name, List... semantics) {
64 MatrixMap<T> result = new MatrixMapFixed<T>(name, semantics);
65 return result;
66 }
67
68 public static <T> MatrixMap<T> create(String name, String[] dimNames, List... semantics) {
69 MatrixMap<T> result = new MatrixMapFixed<T>(name, dimNames, semantics);
70 return result;
71 }
72
73 public static <T> MatrixMap<T> create(MatrixMap<T> matrix) {
74 MatrixMap<T> result = new MatrixMapFixed<T>(matrix);
75 return result;
76 }
77
78 public static <T> MatrixMap<T> createElastic(List... semantics) {
79 MatrixMap<T> result = create(semantics);
80 result = createElastic(result);
81 return result;
82 }
83
84 public static <T> MatrixMap<T> createElastic(String name, List... semantics) {
85 MatrixMap<T> result = create(name, semantics);
86 result = createElastic(result);
87 return result;
88 }
89
90 public static <T> MatrixMap<T> createElastic(String name, String[] dimNames, List... semantics) {
91 MatrixMap<T> result = create(name, dimNames, semantics);
92 result = createElastic(result);
93 return result;
94 }
95
96 public static <T> MatrixMap<T> createElastic(MatrixMap<T> matrix) {
97 MatrixMap<T> result = new MatrixMapElastic<T>(matrix);
98 return result;
99 }
100 }
101
102 @Override
103 MatrixMapIterator<E> iterator();
104
105 /**
106 * Copy la matrice pour pouvoir la modifier sans perdre les donnees
107 * initiales.
108 *
109 * @return new matrix
110 */
111 MatrixMap<E> copy();
112
113 SemanticList[] getSemantics();
114
115 SemanticList getSemantic(int dim);
116
117 void setSemantic(int dim, List sem);
118
119 void setName(String name);
120
121 String getName();
122
123 String[] getDimensionNames();
124
125 void setDimensionNames(String[] names);
126
127 void setDimensionName(int dim, String name);
128
129 String getDimensionName(int dim);
130
131 int getDimCount();
132
133 int[] getDim();
134
135 int getDim(int d);
136
137 /**
138 * Applique sur chaque element de la matrice la fonction f
139 *
140 * @param f la fonction a appliquer
141 * @return Retourne la matrice elle meme. Les modifications sont faites directement
142 * dessus
143 */
144 MatrixMap<E> map(MapFunction<E> f);
145
146 /**
147 * Retourne l'element a une certaine position en utilisant des indices
148 * ex: 2,3,1
149 *
150 * @param coordinates FIXME
151 * @return FIXME
152 */
153 E getValueIndex(int... coordinates);
154
155 /**
156 * Modifie l'element a une certaine position en utilisant des indices
157 * ex: 2,3,1
158 *
159 * @param value la nouvelle valeur
160 * @param coordinates FIXME
161 */
162 void setValueIndex(E value, int... coordinates);
163
164 /**
165 * Retourne l'element a une certaine position en utilisant les semantiques
166 *
167 * @param coordinates FIXME
168 * @return FIXME
169 */
170 E getValue(Object... coordinates);
171
172 /**
173 * Modifie l'element a une certaine position en utilisant les semantiques
174 *
175 * @param value la nouvelle valeur
176 * @param coordinates FIXME
177 */
178 void setValue(E value, Object... coordinates);
179
180 /**
181 * Verifie que deux matrices sont completement equals
182 * (dimension, semantique, nom, valeur, ...)
183 *
184 * @param mat FIXME
185 * @return FIXME
186 */
187 boolean equals(MatrixMap mat);
188
189 /**
190 * Verifie si les matrices sont egales en ne regardant que les valeurs et
191 * pas les semantiques
192 *
193 * @param mat FIXME
194 * @return equality on values
195 */
196 boolean equalsValues(MatrixMap<E> mat);
197
198 /**
199 * Representation string de la matrice quelque soit le nombre de dimension
200 *
201 * @return FIXME
202 */
203 String toStringGeneric();
204
205 /**
206 * Indique si les semantiques passées en argument sont valable pour la
207 * matrice courante
208 *
209 * @param semantics FIXME
210 * @return FIXME
211 */
212 boolean isValidCoordinates(Object[] semantics);
213
214 /**
215 * Copie une matrice dans la matrice actuelle. La matrice à copier à le même
216 * nombre de dimension. Si la matrice à copier est trop grande seul les
217 * éléments pouvant être copier le seront.
218 *
219 * @param mat la matrice à copier
220 * @return return la matrice courante.
221 */
222 MatrixMap paste(MatrixMap<E> mat);
223
224 /**
225 * Permet de prendre une sous matrice dans la matrice courante. La sous
226 * matrice a le même nombre de dimensions mais sur une des dimensions on ne
227 * prend que certain élément.
228 *
229 * @param dim la dimension dans lequel on veut une sous matrice
230 * @param start la position dans dim d'ou il faut partir pour prendre la
231 * sous matrice. 0 ≤ start < dim.size si start est négatif alors
232 * la position de départ est calculé par rapport à la fin de la
233 * dimension, pour avoir le dernier élément il faut passer -1
234 * @param nb le nombre d'élément à prendre dans la dimension si nb est
235 * inférieur ou égal à 0 alors cela indique qu'il faut prendre
236 * tous les éléments jusqu'à la fin de la dimension.
237 * @return new matrix
238 */
239 MatrixMap<E> getSubMatrix(int dim, Object start, int nb);
240
241 /**
242 * Permet de prendre une sous matrice dans la matrice courante. La sous
243 * matrice a le même nombre de dimensions mais sur une des dimensions on ne
244 * prend que certain élément.
245 *
246 * @param dim la dimension dans lequel on veut une sous matrice
247 * @param elem les éléments dans la dimension à conserver
248 * @return new matrix
249 */
250 MatrixMap<E> getSubMatrix(int dim, Object... elem);
251
252 /**
253 * Permet de prendre une sous matrice dans la matrice courante.
254 * <p>
255 * Réalise plusieurs appels à {@link #getSubMatrix(int, Object...)} suivant
256 * l'implémentation.
257 *
258 * @param elems les éléments dans la dimension à conserver
259 * @return new matrix
260 */
261 MatrixMap<E> getSubMatrix(Object[]... elems);
262
263 /**
264 * Reduit la matrice de sorte que toutes les dimensions qui n'ont qu'un
265 * élement soit supprimée. Au pire cette méthode retourne une matrice à une
266 * seule dimension à un seul élément.
267 *
268 * @return une nouvelle matrice plus petite que la matrice actuelle ou egal
269 * s'il n'y a aucune dimension à supprimer
270 */
271 MatrixMap<E> reduce();
272
273 /**
274 * Reduit le matrice seulement sur les dimensions passées en argument. Si
275 * une des dimensions passées en arguement n'a pas qu'un seul élément, cette
276 * dimension n'est pas prise en compte.
277 *
278 * @param dims les dimensions sur lequel il faut faire la reduction
279 * @return une nouvelle matrice
280 */
281 MatrixMap<E> reduceDims(int... dims);
282
283 /**
284 * Reduit la matrice de sorte que toutes les dimensions qui n'ont qu'un
285 * élement soit supprimée. Au pire cette méthode retourne une matrice à une
286 * seule dimension à un seul élément.
287 *
288 * @param minNbDim le nombre minimum de dimension que l'on souhaite pour la
289 * matrice résultat
290 * @return une nouvelle matrice plus petite que la matrice actuelle ou egal
291 * s'il n'y a aucune dimension à supprimer
292 */
293 MatrixMap<E> reduce(int minNbDim);
294
295 /**
296 * Permet de retourner une nouvelle matrice ayant les semantiques passées
297 * en parametre. La nouvelle matrice contient les données de l'ancienne
298 * matrice par copie en fonction des semantiques
299 *
300 * @param sems FIXME
301 * @return FIXME
302 */
303 MatrixMap<E> extend(Object... sems);
304
305 ///////////////////////////////////////////////////////////////////////////
306 //
307 // C L A S S E I N T E R N E
308 //
309 ///////////////////////////////////////////////////////////////////////////
310
311 /**
312 * Classe contenant des méthodes statiques pour aider a la manipulation
313 * des matrices
314 */
315 class MatrixHelper {
316
317 /**
318 * Mais en forme un texte pour qu'il fasse exactement la longueur
319 * demandee (length). Si length est possitif alors s'il y besoin
320 * d'ajouter des espaces, ils seront mis devant le texte, sinon il
321 * seront mis apres le texte
322 *
323 * @param o l'objet a convertir en string
324 * @param length la longueur de representation souhaite
325 * @param valueIfNull la valeur a utilise si l'objet est null
326 * @return FIXME
327 */
328 public static String format(Object o, int length, String valueIfNull) {
329 if (o == null) {
330 o = valueIfNull;
331 }
332 int absLength = Math.abs(length);
333
334 String result = String.valueOf(o);
335 if (absLength > 3) {
336 result = StringUtils.abbreviate(result, absLength);
337 }
338 if (length < 0) {
339 result = StringUtils.leftPad(result, absLength);
340 } else if (length > 0) {
341 result = StringUtils.rightPad(result, absLength);
342 }
343
344 return result;
345 }
346
347 /**
348 * Permet de convertir des coordonnées définies par des entiers en coordonnées
349 * semantique par des objets
350 *
351 * @param semantics la semantique à utilisé pour la conversion
352 * @param coordinates les coordonnées à convertir
353 * @return un tableau donnant les coordonnées sous forme semantique s'il n'y
354 * a pas de semantique (liste pleine de null) alors un objet Integer
355 * est créer pour représenter la semantique de la dimension.
356 */
357 public static Object[] dimensionToSemantics(List[] semantics,
358 int[] coordinates) {
359 Object[] result = new Object[coordinates.length];
360 for (int i = 0; i < result.length; i++) {
361 result[i] = semantics[i].get(coordinates[i]);
362 }
363 return result;
364 }
365
366 /**
367 * Permet de convertir des coordonnées sémantiques en coordonnées défini par
368 * des entiers. Cette fonction est l'inverse de
369 * {@link #dimensionToSemantics}.
370 *
371 * @param semantics la semantique à utiliser pour la conversion
372 * @param coordinates les coordonnées sémantique
373 * @return les coordonnées en entier.
374 */
375 public static int[] semanticsToDimension(List[] semantics,
376 Object[] coordinates) {
377 int[] result = new int[coordinates.length];
378 for (int i = 0; i < coordinates.length; i++) {
379 result[i] = indexOf(semantics, i, coordinates[i]);
380 }
381 return result;
382 }
383
384 /**
385 * Permet de retrouver la position d'un objet dans une liste
386 *
387 * @param semantics la semantique à utilisé pour la recherche
388 * @param dim la dimension dans lequel il faut faire la recherche
389 * @param o l'objet à rechercher
390 * @return la position de l'objet dans la dimension demandée
391 * @throws NoSuchElementException If element doesn't exists
392 */
393 public static int indexOf(List[] semantics, int dim, Object o)
394 throws NoSuchElementException {
395 int result = -1;
396 if ((0 <= dim) && (dim < semantics.length)) {
397 result = semantics[dim].indexOf(o);
398 }
399 if (result == -1) {
400 throw new NoSuchElementException(
401 "L'objet passé en argument n'a pas été retrouvé ou la dimension donnée ne convient pas:"
402 + o + " in " + semantics[dim]);
403 }
404 return result;
405 }
406
407 /**
408 * Permet de savoir si deux dimension sont identiques.
409 *
410 * @param dim1 first dimensions
411 * @param dim2 second dimensions
412 * @return dimension equality
413 */
414 public static boolean sameDimension(int[] dim1, int[] dim2) {
415 return Arrays.equals(dim1, dim2);
416 }
417
418 }
419
420 /**
421 * Iterateur de matrice
422 *
423 * @param <E> FIXME
424 */
425 interface MatrixMapIterator<E> extends Iterator<E> {
426 int[] getCoordinates();
427
428 E getValue();
429
430 void setValue(E value);
431
432 Object[] getSemanticsCoordinates();
433 }
434
435 class MatrixMapIteratorImpl<E> implements MatrixMapIterator<E> { // MatrixMapIteratorImpl
436
437 protected MatrixIterator<E> iterator = null;
438
439 protected List[] semantics = null;
440
441 protected int pos = 0;
442
443 /**
444 * @param iterator la matrice sur lequel l'iterator doit travailler
445 * @param semantics la semantique de matrix, si matrix n'a pas de semantique
446 * alors il faut passer null
447 */
448 public MatrixMapIteratorImpl(MatrixIterator<E> iterator, List[] semantics) {
449 this.iterator = iterator;
450 this.semantics = semantics;
451 pos = 0;
452 }
453
454 @Override
455 public boolean hasNext() {
456 return iterator.hasNext();
457 }
458
459 @Override
460 public E next() {
461 return iterator.next();
462 }
463
464 @Override
465 public void remove() {
466 iterator.remove();
467 }
468
469 public int[] getCoordinates() {
470 return iterator.getCoordinates();
471 }
472
473 public E getValue() {
474 return iterator.getValue();
475 }
476
477 public void setValue(E value) {
478 iterator.setValue(value);
479 }
480
481 public Object[] getSemanticsCoordinates() {
482 Object[] result = null;
483 if (semantics != null) {
484 int[] coordinates = getCoordinates();
485 result = MatrixHelper.dimensionToSemantics(semantics,
486 coordinates);
487 }
488 return result;
489 }
490
491 } // MatrixMapIteratorImpl
492
493 /**
494 * Collection particuliere utilisee pour la stockage des semantiques.
495 * <p>
496 * Sert a optimiser la recherche de la position d'une donnee dans la liste.
497 * Permet aussi de verifier qu'on ajoute pas de doublon dans la liste
498 *
499 * @param <T> FIXME
500 */
501 class SemanticList<T> extends AbstractList<T> implements RandomAccess {
502
503 protected ArrayList<T> datas = null;
504
505 protected Map<T, Integer> index = new HashMap<T, Integer>();
506
507 public SemanticList() {
508 this(new ArrayList<T>());
509 }
510
511 public SemanticList(Collection<T> c) {
512 datas = new ArrayList<T>(c);
513 }
514
515 /*
516 * @see java.util.AbstractList#get(int)
517 */
518 @Override
519 public T get(int index) {
520 T result = datas.get(index);
521 return result;
522 }
523
524 @Override
525 public void add(int index, T element) {
526 datas.add(index, element);
527 this.index.clear();
528 }
529
530 @Override
531 public T set(int index, T element) {
532 T result = datas.set(index, element);
533 this.index.clear();
534 return result;
535 }
536
537 @Override
538 public T remove(int index) {
539 T result = super.remove(index);
540 this.index.clear();
541 return result;
542 }
543
544
545 /*
546 * @see java.util.AbstractCollection#size()
547 */
548 @Override
549 public int size() {
550 int result = datas.size();
551 return result;
552 }
553
554 /*
555 * @see java.util.AbstractList#indexOf(java.lang.Object)
556 */
557 @Override
558 public int indexOf(Object o) {
559 Map<T, Integer> index = getIndex();
560 Integer result = index.get(o);
561 int resultIndex = -1;
562 if (result != null) {
563 resultIndex = result.intValue();
564 }
565 return resultIndex;
566 }
567
568 protected Map<T, Integer> getIndex() {
569 if (index.isEmpty()) {
570 for (int i = 0; i < datas.size(); i++) {
571 index.put(datas.get(i), Integer.valueOf(i));
572 }
573 }
574 return index;
575 }
576 }
577
578 /**
579 * Implantation particuliere de matrice, qui lorsqu'on lui passe des
580 * dimension qui n'existe pas, elle les ajoutes dans les semantiques. Ceci
581 * n'est vrai que pour le set avec des semantiques, le set avec des indices
582 * ne rend pas la matrice elastique.
583 * <p>
584 * Cette classe fonctionne avec une matrice interne que l'on change lorsque
585 * l'on a besoin de modifier les dimensions. Le changement de dimension
586 * a donc un cout (creation d'une nouvelle matrice, copie des elements)
587 * <p>
588 * Si on cree une sous matrice, et que l'on modifie la matrice mere
589 * La sous matrice n'est pas impacter, puisqu'elle est base sur l'ancienne
590 * represention interne de la matrice elastique, les deux matrices n'ont donc
591 * plus de lien.
592 * <p>
593 * Les methodes reduce et extend retourne de nouvelle matrice qui ne sont
594 * pas elastique. Si on veut qu'elle le soit, il faut les reencapsuler
595 *
596 * @param <E> FIXME
597 */
598 class MatrixMapElastic<E> implements MatrixMap<E> {
599
600 protected MatrixMap<E> internalMatrixMap;
601
602 public MatrixMapElastic() {
603 internalMatrixMap = Factory.create();
604 }
605
606 public MatrixMapElastic(MatrixMap<E> m) {
607 setInternalMatrixMap(m);
608 }
609
610 public MatrixMap<E> getInternalMatrixMap() {
611 return internalMatrixMap;
612 }
613
614 public void setInternalMatrixMap(MatrixMap<E> internalMatrixMap) {
615 this.internalMatrixMap = internalMatrixMap;
616 }
617
618 public MatrixMapIterator<E> iterator() {
619 return getInternalMatrixMap().iterator();
620 }
621
622 public MatrixMap<E> copy() {
623 return getInternalMatrixMap().copy();
624 }
625
626 public SemanticList[] getSemantics() {
627 return getInternalMatrixMap().getSemantics();
628 }
629
630 public SemanticList getSemantic(int dim) {
631 return getInternalMatrixMap().getSemantic(dim);
632 }
633
634 public void setSemantic(int dim, List sem) {
635 getInternalMatrixMap().setSemantic(dim, sem);
636 }
637
638 public void setName(String name) {
639 getInternalMatrixMap().setName(name);
640 }
641
642 public String getName() {
643 return getInternalMatrixMap().getName();
644 }
645
646 public String[] getDimensionNames() {
647 return getInternalMatrixMap().getDimensionNames();
648 }
649
650 public void setDimensionNames(String[] names) {
651 getInternalMatrixMap().setDimensionNames(names);
652 }
653
654 public void setDimensionName(int dim, String name) {
655 getInternalMatrixMap().setDimensionName(dim, name);
656 }
657
658 public String getDimensionName(int dim) {
659 return getInternalMatrixMap().getDimensionName(dim);
660 }
661
662 public int getDimCount() {
663 return getInternalMatrixMap().getDimCount();
664 }
665
666 public int[] getDim() {
667 return getInternalMatrixMap().getDim();
668 }
669
670 public int getDim(int d) {
671 return getInternalMatrixMap().getDim(d);
672 }
673
674 public MatrixMap<E> map(MapFunction<E> f) {
675 return getInternalMatrixMap().map(f);
676 }
677
678 public E getValueIndex(int... coordinates) {
679 return getInternalMatrixMap().getValueIndex(coordinates);
680 }
681
682 public void setValueIndex(E value, int... coordinates) {
683 // la matrice est elastique que pour le set avec des semantics
684 getInternalMatrixMap().setValueIndex(value, coordinates);
685 }
686
687 public E getValue(Object... coordinates) {
688 return getInternalMatrixMap().getValue(coordinates);
689 }
690
691 public void setValue(E value, Object... coordinates) {
692 // check si les coordonnees sont valide.
693 // si non valide alors on extend la matrice interne
694 // et on appelle sur la nouvelle matrice interne
695 if (!isValidCoordinates(coordinates)) {
696 MatrixMap<E> newMatrixMap = getInternalMatrixMap().extend(coordinates);
697 setInternalMatrixMap(newMatrixMap);
698 }
699 getInternalMatrixMap().setValue(value, coordinates);
700 }
701
702 @Override
703 public boolean equals(Object obj) {
704 return getInternalMatrixMap().equals(obj);
705 }
706
707 public boolean equals(MatrixMap mat) {
708 return getInternalMatrixMap().equals(mat);
709 }
710
711 public boolean equalsValues(MatrixMap<E> mat) {
712 return getInternalMatrixMap().equalsValues(mat);
713 }
714
715 @Override
716 public String toString() {
717 return getInternalMatrixMap().toString();
718 }
719
720 public String toStringGeneric() {
721 return getInternalMatrixMap().toStringGeneric();
722 }
723
724 public boolean isValidCoordinates(Object[] semantics) {
725 return getInternalMatrixMap().isValidCoordinates(semantics);
726 }
727
728 public MatrixMap paste(MatrixMap<E> mat) {
729 return getInternalMatrixMap().paste(mat);
730 }
731
732 public MatrixMap<E> getSubMatrix(int dim, Object start, int nb) {
733 return getInternalMatrixMap().getSubMatrix(dim, start, nb);
734 }
735
736 public MatrixMap<E> getSubMatrix(int dim, Object... elem) {
737 return getInternalMatrixMap().getSubMatrix(dim, elem);
738 }
739
740 public MatrixMap<E> getSubMatrix(Object[]... elems) {
741 return getInternalMatrixMap().getSubMatrix(elems);
742 }
743
744 public MatrixMap<E> reduce() {
745 return getInternalMatrixMap().reduce();
746 }
747
748 public MatrixMap<E> reduceDims(int... dims) {
749 return getInternalMatrixMap().reduceDims(dims);
750 }
751
752 public MatrixMap<E> reduce(int minNbDim) {
753 return getInternalMatrixMap().reduce(minNbDim);
754 }
755
756 public MatrixMap<E> extend(Object... sems) {
757 return getInternalMatrixMap().extend(sems);
758 }
759
760 }
761
762 /**
763 * Implantation de MatrixMap dont les dimensions sont fixees a la creation
764 * Les dimensions ne change plus par la suite
765 *
766 * @param <E> FIXME
767 */
768 class MatrixMapFixed<E> extends AbstractMatrixMap<E> {
769 /**
770 * Logger.
771 */
772 private static final Log log = LogFactory.getLog(MatrixMapFixed.class);
773
774 protected Matrix<E> matrix = null;
775
776 public MatrixMapFixed(List... semantics) {
777 super(semantics);
778 }
779
780 public MatrixMapFixed(String name, List... semantics) {
781 this(semantics);
782 setName(name);
783 }
784
785 public MatrixMapFixed(String name, String[] dimNames, List... semantics) {
786 this(name, semantics);
787 for (int i = 0; dimNames != null && i < dimNames.length; i++) {
788 setDimensionName(i, dimNames[i]);
789 }
790 }
791
792 public MatrixMapFixed(MatrixMap<E> matrix) {
793 this(matrix.getName(), matrix.getDimensionNames(), matrix.getSemantics());
794 this.pasteIndex(matrix);
795 }
796
797 protected Matrix<E> getMatrix() {
798 if (matrix == null) {
799 matrix = new Matrix<E>(getDim());
800 }
801 return matrix;
802 }
803
804 @Override
805 public MatrixMapIterator<E> iterator() {
806 return new MatrixMapIteratorImpl<E>(getMatrix().iterator(), getSemantics());
807 }
808
809 @Override
810 public MatrixMap<E> map(MapFunction<E> f) {
811 getMatrix().data.map(f);
812 return this;
813 }
814
815 @Override
816 public E getValueIndex(int... coordinates) {
817 if (coordinates.length == 0) {
818 throw new IllegalArgumentException("Coordinates must not be empty");
819 }
820 return getMatrix().getValue(coordinates);
821 }
822
823 /**
824 * Modifie un element de la matrice en fonction des dimensions passé en
825 * paramètre.<br>
826 * <p>
827 * Exemple: Si on a un matrice 3D.<br>
828 * m.set(v, [1,1,1]) modifie un element de la matrice.<br>
829 *
830 * @param value la value a inserer
831 * @param coordinates les coordonées où faire le remplacement
832 */
833 @Override
834 public void setValueIndex(E value, int... coordinates) {
835 if (coordinates.length == 0) {
836 throw new IllegalArgumentException("Coordinates must not be empty");
837 }
838 getMatrix().setValue(coordinates, value);
839 }
840
841 /**
842 * Copie une matrice dans la matrice actuelle. La matrice à copier à le même
843 * nombre de dimension. Si la matrice à copier est trop grande seul les
844 * éléments pouvant être copier le seront.
845 *
846 * @param origin le point à partir duquel il faut faire la copie
847 * @param mat la matrice à copier
848 * @return return la matrice courante.
849 */
850 public MatrixMap<E> paste(int[] origin, MatrixMap<E> mat) {
851 if (mat != null) {
852 // si les matrice mat et this on les memes dimensions
853 // et que origin est 0, on optimise en appeler une methode paste
854 // sur Matrix qui l'appel sur le vector
855
856 // permet de savoir si l'origin est bien le point 0 de la matrice
857 boolean origin0 = true;
858 for (int i = 0; i < origin.length && origin0; i++) {
859 origin0 = origin0 && origin[i] == 0;
860 }
861 if (origin0
862 && mat instanceof MatrixMapFixed
863 && Arrays.equals(mat.getDim(), this.getDim())) {
864 getMatrix().data.paste(((MatrixMapFixed<E>) mat).getMatrix().data);
865 } else {
866 super.paste(origin, mat);
867 }
868 }
869 return this;
870 }
871
872 }
873
874 /**
875 * Classe abstraite permettant de facilement implanter les matrice fixe,
876 * elastique et submatrix
877 *
878 * @param <E> FIXME
879 */
880 abstract class AbstractMatrixMap<E> implements MatrixMap<E> {
881
882 /**
883 * Logger.
884 */
885 private static final Log log = LogFactory.getLog(AbstractMatrixMap.class);
886
887 protected String name = null;
888
889 protected String[] dimNames = null;
890
891 protected int[] dim = null;
892
893 protected SemanticList[] semantics = null;
894
895 protected void init(int[] dim) {
896 this.dim = new int[dim.length];
897 System.arraycopy(dim, 0, this.dim, 0, dim.length);
898 semantics = new SemanticList[dim.length];
899 dimNames = new String[dim.length];
900 }
901
902 protected AbstractMatrixMap(int[] dim) {
903 init(dim);
904 for (int i = 0; i < getDimCount(); i++) {
905 // par defaut les listes des semantiques contiennent des nulls
906 // FIXME no multiple null allowed
907 setSemantic(i, Collections.nCopies(dim[i], null));
908 }
909 }
910
911 public AbstractMatrixMap(List... semantics) {
912 int[] dim = new int[semantics.length];
913 for (int i = 0; i < dim.length; i++) {
914 if (semantics[i] == null) {
915 dim[i] = 0;
916 } else {
917 dim[i] = semantics[i].size();
918 }
919 }
920 init(dim);
921 for (int i = 0; i < getDimCount(); i++) {
922 setSemantic(i, semantics[i]);
923 }
924 }
925
926 protected AbstractMatrixMap(String name, int[] dim) {
927 this(dim);
928 setName(name);
929 }
930
931 protected AbstractMatrixMap(String name, int[] dim, String[] dimNames) {
932 this(dim);
933 setName(name);
934 for (int i = 0; dimNames != null && i < dimNames.length; i++) {
935 setDimensionName(i, dimNames[i]);
936 }
937 }
938
939 public AbstractMatrixMap(String name, List... semantics) {
940 this(semantics);
941 setName(name);
942 }
943
944 public AbstractMatrixMap(String name, String[] dimNames, List... semantics) {
945 this(name, semantics);
946 for (int i = 0; dimNames != null && i < dimNames.length; i++) {
947 setDimensionName(i, dimNames[i]);
948 }
949 }
950
951 public AbstractMatrixMap(MatrixMap<E> matrix) {
952 this(matrix.getName(), matrix.getDimensionNames(), matrix.getSemantics());
953 this.pasteIndex(matrix);
954 }
955
956 /**
957 * Copy la matrice pour pouvoir la modifier sans perdre les donnees
958 * initiales.
959 *
960 * @return new matrix
961 */
962 public MatrixMap<E> copy() {
963 MatrixMap<E> result = new MatrixMapFixed<E>(this);
964 return result;
965 }
966
967 @Override
968 public MatrixMap clone() {
969 return copy();
970 }
971
972 public SemanticList[] getSemantics() {
973 return semantics;
974 }
975
976 public SemanticList getSemantic(int dim) {
977 return semantics[dim];
978 }
979
980 public void setSemantic(int dim, List sem) {
981 // make copy because this matrix can change semantics
982 SemanticList l = new SemanticList(sem);
983 semantics[dim] = l;
984 }
985
986 public void setName(String name) {
987 this.name = name;
988 }
989
990 public String getName() {
991 return name;
992 }
993
994 public String[] getDimensionNames() {
995 return dimNames;
996 }
997
998 public void setDimensionNames(String[] names) {
999 for (int i = 0; names != null && i < names.length; i++) {
1000 setDimensionName(i, names[i]);
1001 }
1002 }
1003
1004 public void setDimensionName(int dim, String name) {
1005 dimNames[dim] = name;
1006 }
1007
1008 public String getDimensionName(int dim) {
1009 return dimNames[dim];
1010 }
1011
1012 public int getDimCount() {
1013 return dim.length;
1014 }
1015
1016 public int[] getDim() {
1017 return dim;
1018 }
1019
1020 public int getDim(int d) {
1021 return dim[d];
1022 }
1023
1024 /**
1025 * Retourne la matrice elle meme. Les modifications sont faites directement
1026 * dessus
1027 */
1028 @Override
1029 public MatrixMap<E> map(MapFunction<E> f) {
1030 for (MatrixMapIterator<E> i = iterator(); i.hasNext(); ) {
1031 i.setValue(f.apply(i.next()));
1032 }
1033 return this;
1034 }
1035
1036 public E getValue(Object... coordinates) {
1037 if (coordinates.length == 0) {
1038 throw new IllegalArgumentException("Coordinates must not be empty");
1039 }
1040 int[] intCoordinates =
1041 MatrixHelper.semanticsToDimension(getSemantics(), coordinates);
1042 E result = getValueIndex(intCoordinates);
1043 return result;
1044 }
1045
1046 public void setValue(E value, Object... coordinates) {
1047 if (coordinates.length == 0) {
1048 throw new IllegalArgumentException("Coordinates must not be empty");
1049 }
1050 int[] intCoordinates =
1051 MatrixHelper.semanticsToDimension(getSemantics(), coordinates);
1052 setValueIndex(value, intCoordinates);
1053 }
1054
1055 // TODO peut-etre faire une variante de equals qui regarde par rapport au
1056 // coordonnées sémantique
1057 @Override
1058 public boolean equals(Object o) {
1059 return o instanceof MatrixMap && equals((MatrixMap) o);
1060 }
1061
1062 public boolean equals(MatrixMap mat) {
1063 boolean result = true;
1064 // le nom doit être le même
1065 result = result && getName().equals(mat.getName());
1066
1067 result = result && equalsValues(mat);
1068
1069 // les sémantiques doivent-être identique
1070 for (int i = 0; result && i < getDimCount(); i++) {
1071 String dimName1 = getDimensionName(i);
1072 String dimName2 = mat.getDimensionName(i);
1073 result = Objects.equals(dimName1, dimName2);
1074 if (log.isTraceEnabled()) {
1075 log.trace("dimName1(" + dimName1 + ")==dimName2(" + dimName2
1076 + ")=" + result);
1077 }
1078 // System.out.println("dimName1("+dimName1+")==dimName2("+dimName2+
1079 // ")="+result);
1080
1081 List sem1 = getSemantic(i);
1082 List sem2 = mat.getSemantic(i);
1083 result = result && Objects.equals(sem1, sem2);
1084 if (log.isTraceEnabled()) {
1085 log.trace("sem1(" + sem1 + ")==sem2(" + sem2 + ")=" + result);
1086 }
1087 // System.out.println("sem1("+sem1+")==sem1("+sem2+ ")="+result);
1088 }
1089
1090 if (log.isTraceEnabled()) {
1091 log.trace("result=" + result);
1092 }
1093 // System.out.println("result="+result);
1094 return result;
1095 }
1096
1097 /**
1098 * Verifie si les matrices sont egales en ne regardant que les valeurs et
1099 * pas les semantiques
1100 *
1101 * @param mat FIXME
1102 * @return equality on values
1103 */
1104 public boolean equalsValues(MatrixMap mat) {
1105 boolean result = true;
1106 // les dimensions doivent-être identique
1107 result = result && MatrixHelper.sameDimension(getDim(), mat.getDim());
1108
1109 // toutes les données doivent être identique
1110 for (MatrixMapIterator<E> i = mat.iterator(); result && i.hasNext(); ) {
1111 E v1 = i.next();
1112 E v2 = getValueIndex(i.getCoordinates());
1113 result = v1 == v2;
1114 if (log.isTraceEnabled()) {
1115 log.trace("v1(" + v1 + ")==v2(" + v2 + ")=" + result);
1116 }
1117 }
1118
1119 return result;
1120 }
1121
1122 /**
1123 * Si la matrice est 1D
1124 * <pre>
1125 * MaMatrice(matrix1D) [
1126 * MaDimName: Dim1, Dim2, Dim3,
1127 * v1, v2, v3
1128 * ]
1129 * </pre>
1130 * <p>
1131 * Si la matrice est 2D
1132 * <pre>
1133 * MaMatrice(matrix2D) [
1134 * MaDimX
1135 * MaDimY Dim1, Dim2, Dim3,
1136 * DimA v1, v2, v3
1137 * DimB v4, v5, v6
1138 * DimC v7, v8, v9
1139 * ]
1140 * </pre>
1141 * <p>
1142 * Pour les autres types de matrice la methode {@link #toStringGeneric() }
1143 * est utilise
1144 *
1145 * @return FIXME
1146 */
1147 @Override
1148 public String toString() {
1149 int LENGTH = 10;
1150 StringBuilder result = new StringBuilder();
1151 if (getDimCount() == 1) {
1152 result.append(MatrixHelper.format(getName(), -LENGTH, "#NoNameMat"));
1153 result.append("(matrix1D)[\n");
1154 String dimName = getDimensionName(0);
1155 result.append(MatrixHelper.format(dimName, LENGTH, "#NoNameDim"));
1156 for (Object sem : getSemantic(0)) {
1157 result.append(",");
1158 result.append(MatrixHelper.format(sem, -LENGTH, null));
1159 }
1160 result.append(StringUtils.repeat(" ", LENGTH + 1));
1161 for (int i = 0; i < getDim(0); i++) {
1162 Object v = getValueIndex(i);
1163 result.append(MatrixHelper.format(v, -LENGTH, null) + ",");
1164 }
1165 result.append("\n]");
1166 } else if (getDimCount() == 2) {
1167 int[] pos = new int[2];
1168 result.append(MatrixHelper.format(getName(), -LENGTH, "#NoNameMat"));
1169 result.append("(matrix2D) [\n");
1170
1171 result.append(StringUtils.repeat(" ", LENGTH + 1));
1172 String dimNameX = getDimensionName(0);
1173 result.append(MatrixHelper.format(dimNameX, LENGTH, "#DimX"));
1174 result.append("\n");
1175 String dimNameY = getDimensionName(1);
1176 result.append(MatrixHelper.format(dimNameY, LENGTH, "#DimY"));
1177 result.append(" ");
1178 for (Object sem : getSemantic(0)) {
1179 result.append(MatrixHelper.format(sem, -LENGTH, null));
1180 result.append(",");
1181 }
1182
1183 for (int y = 0; y < getDim(1); y++) {
1184 result.append("\n");
1185 Object sem = getSemantic(1).get(y);
1186 result.append(MatrixHelper.format(sem, LENGTH, null));
1187 result.append(" ");
1188 for (int x = 0; x < getDim(0); x++) {
1189 pos[0] = x;
1190 pos[1] = y;
1191 Object v = getValueIndex(pos);
1192 result.append(MatrixHelper.format(v, -LENGTH, null) + ",");
1193 }
1194 }
1195 result.append("\n]");
1196 } else {
1197 result.append(toStringGeneric());
1198 }
1199 return result.toString();
1200 }
1201
1202 /**
1203 * Representation string de la matrice quelque soit le nombre de dimension
1204 *
1205 * @return FIXME
1206 */
1207 public String toStringGeneric() {
1208 StringBuilder result = new StringBuilder();
1209 result.append(MatrixHelper.format(getName(), 0, "#NoNameMat"));
1210 result.append("(matrix" + getDimCount() + "D)[\n");
1211 result.append("dimensions = [");
1212 for (int i = 0; i < getDim().length; i++) {
1213 result.append(getDim()[i] + ",");
1214 }
1215 result.append("]\ndata = [");
1216 for (MatrixMapIterator i = this.iterator(); i.hasNext(); ) {
1217 result.append(i.next() + ",");
1218 }
1219 result.append("]\n");
1220 return result.toString();
1221 }
1222
1223 public boolean isValidCoordinates(int[] dim) {
1224 boolean result = getDimCount() == dim.length;
1225 for (int i = 0; result && i < dim.length; i++) {
1226 result = 0 <= dim[i] && dim[i] < getDim(i);
1227 }
1228 return result;
1229 }
1230
1231 public boolean isValidCoordinates(Object[] semantics) {
1232 boolean result = getDimCount() == semantics.length;
1233 for (int i = 0; result && i < semantics.length; i++) {
1234 List semantic = getSemantic(i);
1235 result = semantic.contains(semantics[i]);
1236 }
1237 return result;
1238 }
1239
1240 /**
1241 * Copie une matrice dans la matrice actuelle. La matrice à copier à le même
1242 * nombre de dimension. Si la matrice à copier est trop grande seul les
1243 * éléments pouvant être copier le seront.
1244 *
1245 * @param mat la matrice à copier
1246 * @return return la matrice courante.
1247 */
1248 public MatrixMap pasteIndex(MatrixMap<E> mat) {
1249 return paste(new int[getDimCount()], mat);
1250 }
1251
1252 protected MatrixMap<E> paste(int[] origin, MatrixMap<E> mat) {
1253 if (mat != null) {
1254 for (MatrixMapIterator<E> mi = mat.iterator(); mi.hasNext(); ) {
1255 E value = mi.next();
1256 int[] coordinates = ArrayUtil.sum(origin, mi.getCoordinates());
1257 if (isValidCoordinates(coordinates)) {
1258 setValueIndex(value, coordinates);
1259 }
1260 }
1261 }
1262 return this;
1263 }
1264
1265 /**
1266 * Modifie la matrice actuel en metant les valeurs de mat passé en parametre
1267 * La copie se fait en fonction de la semantique, si un element dans une
1268 * dimension n'est pas trouvé, alors il est passé
1269 */
1270 public MatrixMap<E> paste(MatrixMap<E> mat) {
1271 if (mat != null) {
1272 for (MatrixMapIterator<E> mi = mat.iterator(); mi.hasNext(); ) {
1273 E value = mi.next();
1274 Object[] sems = mi.getSemanticsCoordinates();
1275 if (isValidCoordinates(sems)) {
1276 setValue(value, sems);
1277 }
1278 }
1279 }
1280 return this;
1281 }
1282
1283 /**
1284 * Permet de prendre une sous matrice dans la matrice courante. La sous
1285 * matrice a le même nombre de dimensions mais sur une des dimensions on ne
1286 * prend que certain élément.
1287 *
1288 * @param dim la dimension dans lequel on veut une sous matrice si dim est
1289 * négatif alors la dimension est prise à partir de la fin par
1290 * exemple si l'on veut la derniere dimension il faut passer -1
1291 * pour dim
1292 * @param start la position dans dim d'ou il faut partir pour prendre la
1293 * sous matrice.
1294 * @param nb le nombre d'élément à prendre dans la dimension. si nb est
1295 * inférieur ou égal à 0 alors cela indique qu'il faut prendre
1296 * tous les éléments jusqu'à la fin de la dimension.
1297 * @return new matrix
1298 */
1299 public MatrixMap<E> getSubMatrix(int dim, int start, int nb) {
1300 if (dim < 0) {
1301 dim = getDimCount() + dim;
1302 }
1303 if (start < 0) {
1304 start = getDim(dim) + start;
1305 }
1306 if (nb <= 0) {
1307 nb = getDim(dim) - start;
1308 }
1309 return new SubMatrix<E>(this, dim, start, nb);
1310 }
1311
1312 /**
1313 * Permet de prendre une sous matrice dans la matrice courante. La sous
1314 * matrice a le même nombre de dimensions mais sur une des dimensions on ne
1315 * prend que certain élément.
1316 *
1317 * @param dim la dimension dans lequel on veut une sous matrice
1318 * @param start la position dans dim d'ou il faut partir pour prendre la
1319 * sous matrice. 0 ≤ start < dim.size si start est négatif alors
1320 * la position de départ est calculé par rapport à la fin de la
1321 * dimension, pour avoir le dernier élément il faut passer -1
1322 * @param nb le nombre d'élément à prendre dans la dimension si nb est
1323 * inférieur ou égal à 0 alors cela indique qu'il faut prendre
1324 * tous les éléments jusqu'à la fin de la dimension.
1325 * @return new matrix
1326 */
1327 public MatrixMap<E> getSubMatrix(int dim, Object start, int nb) {
1328 int begin = MatrixHelper.indexOf(getSemantics(), dim, start);
1329 return getSubMatrix(dim, begin, nb);
1330 }
1331
1332 /**
1333 * Add to desambiguas some call with xpath engine, but do the same thing
1334 * {@link #getSubMatrix(int, Object[])}
1335 *
1336 * @param dim FIXME
1337 * @param elem FIXME
1338 * @return new matrix
1339 */
1340 public MatrixMap<E> getSubMatrixOnSemantic(int dim, Object... elem) {
1341 MatrixMap<E> result = getSubMatrix(dim, elem);
1342 return result;
1343 }
1344
1345 /**
1346 * Permet de prendre une sous matrice dans la matrice courante. La sous
1347 * matrice a le même nombre de dimensions mais sur une des dimensions on ne
1348 * prend que certain élément.
1349 *
1350 * @param dim la dimension dans lequel on veut une sous matrice
1351 * @param elem les éléments dans la dimension à conserver
1352 * @return new matrix
1353 */
1354 public MatrixMap<E> getSubMatrix(int dim, Object... elem) {
1355 int[] ielem = new int[elem.length];
1356 for (int i = 0; i < ielem.length; i++) {
1357 ielem[i] = MatrixHelper.indexOf(getSemantics(), dim, elem[i]);
1358 }
1359 return getSubMatrix(dim, ielem);
1360 }
1361
1362 /**
1363 * Permet de prendre une sous matrice dans la matrice courante.
1364 * <p>
1365 * Réalise plusieurs appels à {@link #getSubMatrix(int, Object...)} suivant
1366 * l'implémentation.
1367 *
1368 * @param elems les éléments dans la dimension à conserver
1369 * @return new matrix
1370 */
1371 public MatrixMap<E> getSubMatrix(Object[]... elems) {
1372
1373 // la reduction doit se faire sur le meme nombre de dimension
1374 if (elems.length != dim.length) {
1375 throw new IllegalArgumentException(String.format(
1376 "Can't get sub matrix with different dimension count "
1377 + "(expected: %d, got %d)", dim.length, elems.length));
1378 }
1379
1380 MatrixMap<E> result = this;
1381 for (int i = 0; i < elems.length; ++i) {
1382 if (elems[i] != null) {
1383 result = result.getSubMatrix(i, elems[i]);
1384 }
1385 }
1386 return result;
1387 }
1388
1389 /**
1390 * Permet de prendre une sous matrice dans la matrice courante. La sous
1391 * matrice a le même nombre de dimensions mais sur une des dimensions on ne
1392 * prend que certain élément.
1393 *
1394 * @param dim la dimension dans lequel on veut une sous matrice
1395 * @param elem les indices des éléments dans la dimension à conserver
1396 * @return new matrix
1397 */
1398 public MatrixMap<E> getSubMatrix(int dim, int[] elem) {
1399 return new SubMatrix<E>(this, dim, elem);
1400 }
1401
1402 /**
1403 * Permet de prendre une sous matrice dans la matrice courante.
1404 * <p>
1405 * Réalise plusieurs appels a {@link #getSubMatrix(int, int[])} suivant
1406 * l'implementation.
1407 *
1408 * @param elems les indices des éléments pour chaque dimension à conserver
1409 * @return new matrix
1410 */
1411 public MatrixMap<E> getSubMatrix(int[]... elems) {
1412
1413 // la reduction doit se faire sur le meme nombre de dimension
1414 if (elems.length != dim.length) {
1415 throw new IllegalArgumentException(String.format(
1416 "Can't get sub matrix with different dimension count "
1417 + "(expected: %d, got %d)", dim.length, elems.length));
1418 }
1419
1420 MatrixMap<E> result = this;
1421 for (int i = 0; i < elems.length; ++i) {
1422 if (elems[i] != null) {
1423 result = new SubMatrix<E>(result, i, elems[i]);
1424 }
1425 }
1426 return result;
1427 }
1428
1429 /**
1430 * Reduit la matrice de sorte que toutes les dimensions qui n'ont qu'un
1431 * élement soit supprimée. Au pire cette méthode retourne une matrice à une
1432 * seule dimension à un seul élément.
1433 *
1434 * @return une nouvelle matrice plus petite que la matrice actuelle ou egal
1435 * s'il n'y a aucune dimension à supprimer
1436 */
1437 public MatrixMap<E> reduce() {
1438 return reduce(1);
1439 }
1440
1441 /**
1442 * Reduit le matrice seulement sur les dimensions passées en argument. Si
1443 * une des dimensions passées en arguement n'a pas qu'un seul élément, cette
1444 * dimension n'est pas prise en compte.
1445 *
1446 * @param dims les dimensions sur lequel il faut faire la reduction
1447 * @return une nouvelle matrice
1448 */
1449 public MatrixMap<E> reduceDims(int... dims) {
1450 Arrays.sort(dims);
1451 // tableau permettant de faire la correspondance entre les dimensions
1452 // de la matrice actuelle et les dimentsions de la nouvelle matrice
1453 // l'element i du tableau qui correcpond à la dimensions i de la
1454 // nouvelle matrice contient la dimension equivalente dans
1455 // la matrice actuelle
1456 int[] correspondance = new int[getDimCount()];
1457 // les nouvelles semantiques
1458 List<List> sem = new ArrayList<List>();
1459 // les nouveaux noms de dimensions
1460 List<String> dimName = new ArrayList<String>();
1461 // il faut au moins une dimension pour la matrice
1462 int minNbDim = 1;
1463 for (int j = getDimCount() - 1; j >= 0; j--) {
1464 // si la dimension à plus d'un élément ou qu'il n'est pas dans dims
1465 // on garde la dimension
1466 if (getDim(j) > 1 || Arrays.binarySearch(dims, j) < 0
1467 || j < minNbDim) {
1468 // on ne conserve que les dimensions supérieure à 1
1469 correspondance[sem.size()] = j;
1470 sem.add(getSemantic(j));
1471 dimName.add(getDimensionName(j));
1472 minNbDim--;
1473 }
1474 }
1475 MatrixMap<E> result = reduce(dimName, sem, correspondance);
1476 return result;
1477 }
1478
1479 /**
1480 * Reduit la matrice de sorte que toutes les dimensions qui n'ont qu'un
1481 * élement soit supprimée. Au pire cette méthode retourne une matrice à une
1482 * seule dimension à un seul élément.
1483 *
1484 * @param minNbDim le nombre minimum de dimension que l'on souhaite pour la
1485 * matrice résultat
1486 * @return une nouvelle matrice plus petite que la matrice actuelle ou egal
1487 * s'il n'y a aucune dimension à supprimer
1488 */
1489 public MatrixMap<E> reduce(int minNbDim) {
1490 // tableau permettant de faire la correspondance entre les dimensions
1491 // de la matrice actuelle et les dimentsions de la nouvelle matrice
1492 // l'element i du tableau qui correcpond à la dimensions i de la
1493 // nouvelle matrice contient la dimension equivalente dans
1494 // la matrice actuelle
1495 int[] correspondance = new int[getDimCount()];
1496 // les nouvelles semantiques
1497 List<List> sem = new ArrayList<List>();
1498 // les nouveaux noms de dimensions
1499 List<String> dimName = new ArrayList<String>();
1500 for (int j = getDimCount() - 1; j >= 0; j--) {
1501 // si la dimension à plus d'un élément ou si on a pas assez de
1502 // dimension pour avoir le minimum demandé on prend la dimension
1503 if (getDim(j) > 1 || j < minNbDim) {
1504 // on ne conserve que les dimensions supérieure à 1
1505 correspondance[sem.size()] = j;
1506 sem.add(getSemantic(j));
1507 dimName.add(getDimensionName(j));
1508 // on vient de prendre une dimension il nous en faut une de
1509 // moins
1510 minNbDim--;
1511 }
1512 }
1513
1514 MatrixMap<E> result = reduce(dimName, sem, correspondance);
1515 return result;
1516 }
1517
1518 /**
1519 * Create new matrice from the current matrix.
1520 *
1521 * @param dimName dimension name for new matrix
1522 * @param sem semantic for new matrix
1523 * @param correspondance array to do the link between current matrix and
1524 * returned matrix
1525 * @return new matrix
1526 */
1527 protected MatrixMap<E> reduce(List<String> dimName, List<List> sem, int[] correspondance) {
1528 // on converti les listes en tableau en inversant l'ordre car on
1529 // a fait un parcours en sens inverse
1530 int nbDim = sem.size();
1531 List[] newSemantics = new List[nbDim];
1532 String[] newDimNames = new String[nbDim];
1533 int[] tmpcorrespondance = new int[nbDim];
1534 for (int i = 0; i < nbDim; i++) {
1535 newSemantics[i] = sem.get(nbDim - 1 - i);
1536 newDimNames[i] = dimName.get(nbDim - 1 - i);
1537 tmpcorrespondance[i] = correspondance[nbDim - 1 - i];
1538 }
1539 correspondance = tmpcorrespondance;
1540
1541 MatrixMap<E> result = new MatrixMapFixed<E>(getName(), newDimNames, newSemantics);
1542
1543 // on reprend les valeurs
1544 int[] newCoordinates = new int[result.getDimCount()];
1545 for (MatrixMapIterator<E> mi = iterator(); mi.hasNext(); ) {
1546 E value = mi.next();
1547 int[] oldCoordinates = mi.getCoordinates();
1548 for (int i = 0; i < newCoordinates.length; i++) {
1549 newCoordinates[i] = oldCoordinates[correspondance[i]];
1550 }
1551 result.setValueIndex(value, newCoordinates);
1552 }
1553 return result;
1554 }
1555
1556 public MatrixMap<E> extend(Object... sems) {
1557 String name = getName();
1558 String[] dimNames = getDimensionNames();
1559 SemanticList[] semantics = getSemantics();
1560
1561 // si pas assez de dimension on en rajoute
1562 if (sems.length > semantics.length) {
1563 String[] newDimNames = new String[sems.length];
1564 System.arraycopy(dimNames, 0, newDimNames, 0, dimNames.length);
1565 dimNames = newDimNames;
1566
1567 SemanticList[] newSems = new SemanticList[sems.length];
1568 System.arraycopy(semantics, 0, newSems, 0, semantics.length);
1569 semantics = newSems;
1570
1571 for (int i = semantics.length; i < newSems.length; i++) {
1572 newSems[i] = new SemanticList();
1573 }
1574 }
1575
1576 // si les objets demande n'existe pas dans la semantics on l'ajoute
1577 for (int i = 0; i < sems.length; i++) {
1578 if (semantics[i].indexOf(sems[i]) == -1) {
1579 semantics[i].add(sems[i]);
1580 }
1581 }
1582
1583 MatrixMap<E> result = MatrixMap.Factory.create(name, dimNames, semantics);
1584 result.paste(this);
1585 return result;
1586 }
1587
1588 }
1589
1590 /**
1591 * Pour l'instant une sous matrice a obligatoirement le meme nombre de dimension
1592 * que la matrice qu'elle contient. Elle permet juste de reduire le nombre
1593 * d'element d'une dimension.
1594 * <p>
1595 * C'est comme une "vue" réduite sur la vraie matrices.
1596 */
1597 class SubMatrix<E> extends AbstractMatrixMap<E> { // SubMatrix
1598
1599 protected MatrixMap<E> matrix = null;
1600
1601 protected DimensionConverter converter = null;
1602
1603 public SubMatrix(MatrixMap<E> matrix, int dim, int start, int nb) {
1604 super(matrix.getName(), matrix.getDimensionNames(), matrix.getSemantics());
1605 this.matrix = matrix;
1606
1607 converter = new ShiftConverter(dim, start, nb);
1608 setSemantic(dim, getSemantic(dim).subList(start, start + nb));
1609 getDim()[dim] = nb;
1610 }
1611
1612 public SubMatrix(MatrixMap<E> matrix, int dim, int[] elem) {
1613 super(matrix.getName(), matrix.getDimensionNames(), matrix.getSemantics());
1614 this.matrix = matrix;
1615
1616 converter = new MappingConverter(dim, elem);
1617
1618 List oldSemantic = getSemantic(dim);
1619 List newSemantic = new LinkedList();
1620 for (int i = 0; i < elem.length; i++) {
1621 newSemantic.add(oldSemantic.get(elem[i]));
1622 }
1623 setSemantic(dim, newSemantic);
1624 getDim()[dim] = elem.length;
1625 }
1626
1627 @Override
1628 public MatrixMapIterator<E> iterator() {
1629 return new SubMatrixIterator<E>(this);
1630 }
1631
1632 @Override
1633 public E getValueIndex(int... coordinates) {
1634 return matrix.getValueIndex(converter.convertCoordinates(coordinates));
1635 }
1636
1637 @Override
1638 public void setValueIndex(E value, int... coordinates) {
1639 matrix.setValueIndex(value, converter.convertCoordinates(coordinates));
1640 }
1641
1642 protected class SubMatrixIterator<E> implements MatrixMapIterator<E> {
1643
1644 protected SubMatrix<E> subMatrix = null;
1645
1646 protected int[] cpt = null;
1647
1648 protected int[] last = null;
1649
1650 public SubMatrixIterator(SubMatrix<E> subMatrix) {
1651 this.subMatrix = subMatrix;
1652 cpt = new int[subMatrix.getDimCount()];
1653 cpt[cpt.length - 1] = -1;
1654
1655 last = new int[subMatrix.getDimCount()];
1656 for (int i = 0; i < last.length; i++) {
1657 last[i] = subMatrix.getDim(i) - 1;
1658 }
1659
1660 }
1661
1662 @Override
1663 public boolean hasNext() {
1664 return !Arrays.equals(cpt, last);
1665 }
1666
1667 @Override
1668 public E next() {
1669 int ret = 1;
1670 int[] dim = getDim();
1671 for (int i = cpt.length - 1; i >= 0; i--) {
1672 cpt[i] = cpt[i] + ret;
1673 ret = cpt[i] / dim[i];
1674 cpt[i] = cpt[i] % dim[i];
1675 }
1676 E result = getValue();
1677 return result;
1678 }
1679
1680 @Override
1681 public void remove() {
1682 setValue(null);
1683 }
1684
1685 public int[] getCoordinates() {
1686 return cpt;
1687 }
1688
1689 public Object[] getSemanticsCoordinates() {
1690 int[] coordinates = getCoordinates();
1691 Object[] result = MatrixHelper.dimensionToSemantics(subMatrix.getSemantics(), coordinates);
1692 return result;
1693 }
1694
1695 public E getValue() {
1696 return subMatrix.getValueIndex(getCoordinates());
1697 }
1698
1699 public void setValue(E value) {
1700 subMatrix.setValue(value, getCoordinates());
1701 }
1702 }
1703
1704 /**
1705 * Permet de faire une conversion de la dimension demandé dans la sous
1706 * matrice avec la position reel de la matrice sous jacente.
1707 */
1708 protected interface DimensionConverter extends Serializable {
1709 int[] convertCoordinates(int[] coordinates);
1710 }
1711
1712 /**
1713 * La conversion est juste un decalage d'indice
1714 */
1715 protected static class ShiftConverter implements DimensionConverter {
1716
1717 /**
1718 * serialVersionUID.
1719 */
1720 private static final long serialVersionUID = 1L;
1721
1722 protected int dim;
1723
1724 protected int start;
1725
1726 protected int nb;
1727
1728 public ShiftConverter(int dim, int start, int nb) {
1729 this.dim = dim;
1730 this.start = start;
1731 this.nb = nb;
1732 }
1733
1734 @Override
1735 public int[] convertCoordinates(int[] coordinates) {
1736 int[] result = null;
1737 if (coordinates[dim] < nb) {
1738 result = new int[coordinates.length];
1739 System.arraycopy(coordinates, 0, result, 0, result.length);
1740 result[dim] = result[dim] + start;
1741 } else {
1742 throw new NoSuchElementException(
1743 "L'indice est supérieur au nombre d'élement de la sous matrice pour cette dimension.");
1744 }
1745 return result;
1746 }
1747 }
1748
1749 /**
1750 * La conversion est le mapping d'un element vers un autre element.
1751 */
1752 protected static class MappingConverter implements DimensionConverter {
1753
1754 /**
1755 * serialVersionUID.
1756 */
1757 private static final long serialVersionUID = -6367416559713556559L;
1758
1759 protected int dim;
1760
1761 protected int[] elem = null;
1762
1763 public MappingConverter(int dim, int[] elem) {
1764 this.dim = dim;
1765 this.elem = new int[elem.length];
1766 System.arraycopy(elem, 0, this.elem, 0, elem.length);
1767 }
1768
1769 @Override
1770 public int[] convertCoordinates(int[] coordinates) {
1771 int[] result = null;
1772 if (coordinates[dim] < elem.length) {
1773 result = new int[coordinates.length];
1774 System.arraycopy(coordinates, 0, result, 0, result.length);
1775 result[dim] = elem[coordinates[dim]];
1776
1777 } else {
1778 throw new NoSuchElementException(
1779 "L'indice est supérieur au nombre d'élements de la sous matrice pour cette dimension.");
1780 }
1781 return result;
1782 }
1783 }
1784 } // SubMatrix
1785
1786 /**
1787 * Objet matrice qui ne permet que le stockage avec des positions int
1788 * dans une matrice a autant de dimension que l'on souhaite.
1789 *
1790 * @param <E> FIXME
1791 */
1792 class Matrix<E> implements Iterable<E> { // BasicMatrix
1793
1794 /**
1795 * Les dimensions de la matrice
1796 */
1797 protected int[] dimensions = null;
1798
1799 /**
1800 * La matrice en représentation linéaire
1801 */
1802 protected Vector<E> data = null;
1803
1804 /**
1805 * tableau de facteur permettant de convertir les coordonnées dans la
1806 * matrice en un indice dans la représentation linéaire de la matrice
1807 */
1808 protected int[] linearFactor = null;
1809
1810 /**
1811 * Crée une nouvelle matrice ayant les dimensions demandées.
1812 *
1813 * @param dimensions dimensions
1814 */
1815 public Matrix(int[] dimensions) {
1816 checkDim(dimensions);
1817
1818 // copie des dimensions pour que personne à l'extérieur de l'objet
1819 // ne puisse les modifiers par la suite
1820 this.dimensions = new int[dimensions.length];
1821 System.arraycopy(dimensions, 0, this.dimensions, 0, dimensions.length);
1822
1823 // calcul du linearFactor
1824 linearFactor = new int[dimensions.length];
1825 linearFactor[linearFactor.length - 1] = 1;
1826 for (int i = linearFactor.length - 2; i >= 0; i--) {
1827 linearFactor[i] = linearFactor[i + 1] * dimensions[i + 1];
1828 }
1829
1830 // creation de la matrice lineaire
1831 data = new Vector<E>(linearFactor[0] * dimensions[0]);
1832 }
1833
1834 /**
1835 * Retourne le nombre de dimension de la matrice
1836 *
1837 * @return le nombre de dimension de la matrice;
1838 */
1839 public int getNbDim() {
1840 return dimensions.length;
1841 }
1842
1843 /**
1844 * Retourne la taille d'une dimension
1845 *
1846 * @param dim la dimension dont on souhaite la taille
1847 * @return la taille d'une dimension
1848 */
1849 public int getDim(int dim) {
1850 checkDim(dim);
1851 return dimensions[dim];
1852 }
1853
1854 /**
1855 * Retourne un tableau representant les dimensions de la matrice. Le tableau
1856 * retourné n'est pas une copie, il ne faut donc pas le modifier
1857 *
1858 * @return le tableau des dimensions.
1859 */
1860 public int[] getDim() {
1861 return dimensions;
1862 }
1863
1864 /**
1865 * Retourne un element de la matrice
1866 *
1867 * @param pos la position de l'element à retourner
1868 * @return un element de la matrice
1869 */
1870 public E getValue(int[] pos) {
1871 int indice = coordonatesToLinear(pos);
1872 return data.getValue(indice);
1873 }
1874
1875 /**
1876 * Modifie un élement de la matrice
1877 *
1878 * @param pos la position de l'element à modifier
1879 * @param value la nouvelle valeur à mettre dans la matrice
1880 */
1881 public void setValue(int[] pos, E value) {
1882 int indice = coordonatesToLinear(pos);
1883 data.setValue(indice, value);
1884 }
1885
1886 /**
1887 * Retourne un objet Inc pret a etre utilisé pour boucler sur tous les
1888 * element de la matrice.
1889 *
1890 * @return un objet Inc pret à être utilisé
1891 */
1892 @Override
1893 public MatrixIterator<E> iterator() {
1894 return new MatrixIterator<E>(this);
1895 }
1896
1897 /**
1898 * Permet de faire un traitement sur chaque valeur de la matrice
1899 *
1900 * @param f la fonction a appliquer à chaque élement de la matrice
1901 */
1902 public void map(MapFunction f) {
1903 data.map(f);
1904 }
1905
1906 /**
1907 * Permet de convertir les coordonnées d'un élément en un indice dans la
1908 * représentation linéraire de la matrice.
1909 *
1910 * @param coordonates les coordonnées à lineariser
1911 * @return un indice réprésentant les coordonnées de façon linéaire
1912 */
1913 protected int coordonatesToLinear(int[] coordonates) {
1914 checkPos(coordonates);
1915
1916 int result = 0;
1917 for (int i = 0; i < linearFactor.length; i++) {
1918 result += coordonates[i] * linearFactor[i];
1919 }
1920 return result;
1921 }
1922
1923 /**
1924 * Convertie une coordonnée lineaire en coordonnées spaciales
1925 *
1926 * @param pos la coordonnée linéaire
1927 * @return les coordonnées spaciales de l'élément
1928 */
1929 protected int[] linearToCoordinates(int pos) {
1930 int[] result = new int[linearFactor.length];
1931
1932 for (int i = 0; i < result.length; i++) {
1933 result[i] = pos / linearFactor[i];
1934 pos -= result[i] * linearFactor[i];
1935 }
1936 return result;
1937 }
1938
1939 /**
1940 * Permet de vérifier que les dimensions de la nouvelle matrice sont
1941 * corrects
1942 *
1943 * @param dim les dimensions de la nouvelle matrice
1944 * @throws IllegalArgumentException si une dimension n'est pas valide
1945 */
1946 protected void checkDim(int[] dim) {
1947 for (int i = 0; i < dim.length; i++) {
1948 if (dim[i] <= 0) {
1949 throw new IllegalArgumentException(String.format(
1950 "Dimension %s is invalid %s", i, dim[i]));
1951 }
1952 }
1953 }
1954
1955 /**
1956 * Permet de vérifier qu'une dimension demandé existe bien dans la matrice
1957 *
1958 * @param dim la position de la dimension que l'on souhaite
1959 * @throws IndexOutOfBoundsException si la dimension demandée n'existe pas
1960 */
1961 protected void checkDim(int dim) {
1962 if (dim < 0 || dim >= getNbDim()) {
1963 throw new IndexOutOfBoundsException(String.format(
1964 "Invalid dimension %s max dimension is %s",
1965 dim, getNbDim()));
1966 }
1967 }
1968
1969 /**
1970 * Verifie que les coordonnées demandé appartiennent bien à la matrice
1971 *
1972 * @param pos les coordonnées souhaitées dans la matrice
1973 * @throws NoSuchElementException si les coordonnées ne correspondent pas à
1974 * un élement de la matrice
1975 */
1976 protected void checkPos(int[] pos) {
1977 int[] dim = getDim();
1978 boolean result = dim.length == pos.length;
1979 for (int i = 0; result && i < dim.length; i++) {
1980 result = (0 <= pos[i]) && (pos[i] < dim[i]);
1981 }
1982 if (!result) {
1983 throw new NoSuchElementException(String.format(
1984 "Invalid element asked %s for real dimension %s", Arrays.toString(pos), Arrays
1985 .toString(dim)));
1986 }
1987 }
1988
1989 @Override
1990 public String toString() {
1991 StringBuffer result = new StringBuffer();
1992 if (getNbDim() == 1) {
1993 result.append("matrix1D [");
1994 for (int i = 0; i < data.size(); i++) {
1995 result.append(data.getValue(i) + ",");
1996 }
1997 result.append("]");
1998 } else if (getNbDim() == 2) {
1999 int[] pos = new int[2];
2000 result.append("matrix2D [");
2001 for (int y = 0; y < getDim(1); y++) {
2002 result.append("\n");
2003 for (int x = 0; x < getDim(0); x++) {
2004 pos[0] = x;
2005 pos[1] = y;
2006 result.append(getValue(pos) + ",");
2007 }
2008 }
2009 result.append("]");
2010 } else {
2011 result.append("dimensions = [\n");
2012 for (int i = 0; i < dimensions.length; i++) {
2013 result.append(dimensions[i] + ",");
2014 }
2015 result.append("\n]\nmatrice = [\n");
2016 for (int i = 0; i < data.size(); i++) {
2017 result.append(data.getValue(i) + ",");
2018 }
2019 result.append("\n]\nlinearFactor = [\n");
2020 for (int i = 0; i < linearFactor.length; i++) {
2021 result.append(linearFactor[i] + ",");
2022 }
2023 result.append("\n]\n");
2024 }
2025 return result.toString();
2026 }
2027
2028 @Override
2029 public boolean equals(Object o) {
2030 if (o instanceof Matrix) {
2031 Matrix other = (Matrix) o;
2032 return this == o
2033 || (Arrays.equals(this.dimensions, other.dimensions) && this.data
2034 .equals(other.data));
2035 }
2036 return false;
2037 }
2038
2039 } // BasicMatrix
2040
2041 class MatrixIterator<E> implements Iterator<E> { // MatrixIteratorImpl
2042
2043 protected Matrix<E> matrix = null;
2044
2045 protected int pos = -1;
2046
2047 /**
2048 * @param matrix la matrice sur lequel l'iterator doit travailler
2049 */
2050 public MatrixIterator(Matrix<E> matrix) {
2051 this.matrix = matrix;
2052 pos = -1;
2053 }
2054
2055 @Override
2056 public boolean hasNext() {
2057 return pos + 1 < matrix.data.size();
2058 }
2059
2060 @Override
2061 public E next() {
2062 if (hasNext()) {
2063 pos++;
2064 } else {
2065 throw new NoSuchElementException();
2066 }
2067 E result = getValue();
2068 return result;
2069 }
2070
2071 @Override
2072 public void remove() {
2073 setValue(null);
2074 }
2075
2076 public E getValue() {
2077 return matrix.data.getValue(pos);
2078 }
2079
2080 public void setValue(E value) {
2081 matrix.data.setValue(pos, value);
2082 }
2083
2084 public int[] getCoordinates() {
2085 return matrix.linearToCoordinates(pos);
2086 }
2087
2088 } // MatrixIteratorImpl
2089
2090 /**
2091 * Permet de stocker des données à une position lineaire et de la redemander.
2092 * Cette classe ne gére que les données lineaire. L'avantage de cette classe est
2093 * de ne conserver que les elements differents de la valeur par defaut, ce qui
2094 * minimize la taille du tableau necessaire a conserver les données.
2095 *
2096 * @param <E> FIXME
2097 */
2098 class Vector<E> { // Vector
2099
2100 /**
2101 * maximum number of element, maximum pos value
2102 */
2103 protected int capacity = 0;
2104
2105 /**
2106 * la valeur par defaut
2107 */
2108 protected E defaultValue = null;
2109
2110 /**
2111 * contient la position de l'element, le tableau est trie
2112 */
2113 protected int[] position;
2114
2115 protected int positionSize = 0;
2116
2117 /**
2118 * contient la valeur de l'element
2119 */
2120 protected ArrayList<E> data = new ArrayList<E>();
2121
2122 public Vector(int capacity) {
2123 this.capacity = capacity;
2124 position = new int[8];
2125 Arrays.fill(position, Integer.MAX_VALUE);
2126 }
2127
2128 public Vector(int capacity, E defaultValue) {
2129 this(capacity);
2130 this.defaultValue = defaultValue;
2131 }
2132
2133 public int size() {
2134 return capacity;
2135 }
2136
2137 // poussin 20060827 TODO: verifier l'implantation, il semble quelle soit
2138 // fausse et ne puisse pas recherche le nombre max correctement
2139 public E getMaxOccurrence() {
2140 E result = defaultValue;
2141
2142 E[] tmp = (E[]) data.toArray();
2143
2144 // si potentiellement il y a plus d'element identique dans data
2145 // que de valeur par defaut, on recherche la valeur possible
2146 if (this.capacity < 2 * tmp.length) {
2147 Arrays.sort(tmp);
2148
2149 // le nombre de fois que l'on a rencontrer la valeur la plus
2150 // nombreuse
2151 int max = 1;
2152 // le nombre de fois que l'on a rencontrer la valeur courante
2153 int count = 1;
2154 // la valeur la plus rencontrer
2155 result = tmp[0];
2156 // la valeur que l'on vient de traiter précédement
2157 E old = tmp[0];
2158 // la valeur courante lu dans le tableaux
2159 E current = tmp[0];
2160 // tant que l'on peut encore trouve un element plus nombreux dans le
2161 // tableau on le parcours
2162 for (int i = 1; max < tmp.length - i + count && i < tmp.length; i++) {
2163 current = tmp[i];
2164
2165 if (current == old) {
2166 count++;
2167 } else {
2168 if (count > max) {
2169 max = count;
2170 result = old;
2171 }
2172 count = 1;
2173 old = current;
2174 }
2175 }
2176 if (count > max) {
2177 max = count;
2178 result = current;
2179 }
2180
2181 if (max <= capacity - tmp.length) {
2182 // en fin de compte, il n'y a pas plus d'element identique
2183 // dans data que de defaultValue
2184 result = defaultValue;
2185 }
2186 }
2187
2188 return result;
2189 }
2190
2191 protected void checkPos(int pos) {
2192 if (pos < 0 || pos >= capacity) {
2193 throw new IllegalArgumentException("pos " + pos + " is not in [0, "
2194 + capacity + "]");
2195 }
2196 }
2197
2198 public E getValue(int pos) {
2199 checkPos(pos);
2200
2201 E result = defaultValue;
2202 int index = findIndex(pos);
2203 if (index >= 0) {
2204 result = data.get(index);
2205 }
2206 return result;
2207 }
2208
2209 public void setValue(int pos, E value) {
2210 checkPos(pos);
2211
2212 int index = findIndex(pos);
2213 if (index >= 0) {
2214 if (value == defaultValue) {
2215 // il etait present, on supprime l'element
2216 removeElementAt(index);
2217 data.remove(index);
2218 } else {
2219 // il etait deja present, on modifie la valeur
2220 data.set(index, value);
2221 }
2222 } else {
2223 // il n'etait pas present
2224 if (value != defaultValue) {
2225 // il faut ajouter dans position et dans data
2226 index = -index - 1;
2227
2228 addElementAt(index, pos);
2229 data.add(index, value);
2230 }
2231 }
2232 }
2233
2234 public boolean equals(Object o) {
2235 boolean result = false;
2236 if (o instanceof Vector) {
2237 Vector other = (Vector) o;
2238 result = Arrays.equals(this.position, other.position)
2239 && data.equals(other.data);
2240 }
2241 return result;
2242 }
2243
2244 /**
2245 * retourne la position dans le tableau position de la position lineaire
2246 *
2247 * @param pos FIXME
2248 * @return la position ou < 0 donnant la position de l'element s'il etait
2249 * present
2250 */
2251 protected int findIndex(int pos) {
2252 return Arrays.binarySearch(position, pos);
2253 }
2254
2255 protected void ensureCapacity(int mincap) {
2256 if (mincap > position.length) {
2257 int newcap = (position.length * 3) / 2 + 1;
2258 int olddata[] = position;
2259 position = new int[newcap >= mincap ? newcap : mincap];
2260 System.arraycopy(olddata, 0, position, 0, positionSize);
2261 for (int i = positionSize; i < position.length; i++) {
2262 position[i] = Integer.MAX_VALUE;
2263 }
2264 }
2265 }
2266
2267 protected void addElementAt(int index, int element) {
2268 ensureCapacity(positionSize + 1);
2269 int numtomove = positionSize - index;
2270 System.arraycopy(position, index, position, index + 1, numtomove);
2271 position[index] = element;
2272 positionSize++;
2273 }
2274
2275 protected int removeElementAt(int index) {
2276 int oldval = position[index];
2277 int numtomove = positionSize - index - 1;
2278 if (numtomove > 0) {
2279 System.arraycopy(position, index + 1, position, index, numtomove);
2280 }
2281 positionSize--;
2282 position[positionSize] = Integer.MAX_VALUE;
2283 return oldval;
2284 }
2285
2286 /**
2287 * On recopie tous les attributs pour que le vector ressemble exactement a
2288 * celui passé en argument
2289 * @param v FIXME
2290 */
2291 public void paste(Vector<E> v) {
2292 this.capacity = v.capacity;
2293 this.defaultValue = v.defaultValue;
2294 this.positionSize = v.positionSize;
2295 this.position = new int[v.position.length];
2296 System.arraycopy(v.position, 0, this.position, 0,
2297 this.position.length);
2298 this.data.clear();
2299 this.data.addAll(v.data);
2300 }
2301
2302 /**
2303 * on applique sur chaque donnée existante et sur default
2304 * @param f FIXME
2305 */
2306 public void map(MapFunction<E> f) {
2307 // on commence toujours par modifier la valeur par defaut
2308 // car les valeurs suivante pourrait prendre cette valeur
2309 // et donc disparaitre des tableaux si besoin
2310 defaultValue = f.apply(defaultValue);
2311 // on fait la boucle a l'envers au cas ou on supprime des valeurs
2312 for (int i = data.size() - 1; i >= 0; i--) {
2313 E value = f.apply(data.get(i));
2314 if (value == defaultValue) {
2315 // il etait present, on supprime l'element
2316 removeElementAt(i);
2317 data.remove(i);
2318 } else {
2319 // il etait deja present, on modifie la valeur
2320 data.set(i, value);
2321 }
2322 }
2323 }
2324 } // Vector
2325
2326 /**
2327 * Permet de faire un traitement sur des valeurs et d'en retourner
2328 * des nouvelles.
2329 *
2330 * @param <E> FIXME
2331 */
2332 interface MapFunction<E> { // MapFunction
2333
2334 /**
2335 * Permet de faire un traitement sur value et de retourne une nouvelle
2336 * valeur.
2337 *
2338 * @param value la valeur courante sur lequel il faut faire le traitement
2339 * @return la nouvelle valeur à mettre dans la matrice à la place de
2340 * l'ancienne.
2341 */
2342 E apply(E value);
2343
2344 } // MapFunction
2345
2346 }