Coverage Report - eu.simuline.octave.type.matrix.AbstractGenericMatrix
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractGenericMatrix
88%
95/107
78%
48/61
2.8
 
 1  
 /*
 2  
  * Copyright 2009 Ange Optimization ApS
 3  
  *
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  *     http://www.apache.org/licenses/LICENSE-2.0
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package eu.simuline.octave.type.matrix;
 17  
 
 18  
 import eu.simuline.octave.type.OctaveObject;
 19  
 import eu.simuline.octave.type.OctaveDouble;
 20  
 
 21  
 import java.util.Arrays;
 22  
 import java.util.List;
 23  
 
 24  
 /**
 25  
  * A general matrix that does not even know 
 26  
  * that it is an array it stores its  in.
 27  
  * 
 28  
  * @param <D>
 29  
  *    an array type, partially of primitive element type 
 30  
  * @param <L> 
 31  
  *    a list corresponding with the array of type D
 32  
  */
 33  
 // used as superclass of classes of this package only 
 34  2
 public abstract class AbstractGenericMatrix<D, L extends List<?>> 
 35  
     implements OctaveObject { //, E
 36  
 
 37  
     private static final int PRIME = 31;
 38  
 
 39  
     /**
 40  
      * The dimensions, rows x columns x depth x ....
 41  
      */
 42  
     @SuppressWarnings("checkstyle:visibilitymodifier")
 43  
     protected final int[] size;
 44  
 
 45  
     /**
 46  
      * The data, vectorized.
 47  
      */
 48  
     @SuppressWarnings("checkstyle:visibilitymodifier")
 49  
      protected L dataL;//final 
 50  
 
 51  
     /**
 52  
      * Constructor that creates new blank matrix. 
 53  
      * 
 54  
      * @param size
 55  
      */
 56  1062
     protected AbstractGenericMatrix(final int... size) {
 57  1062
         this.size = size.clone();
 58  1062
         checkSize();
 59  1058
         int size1 = product(size);
 60  1058
         this.dataL = newL(size1);
 61  1058
     }
 62  
 
 63  
     /**
 64  
      * Constructor that reuses data in the new object. 
 65  
      * 
 66  
      * @param dataA
 67  
      *    data as an array 
 68  
      * @param size
 69  
      *    must have at least two dimensions 
 70  
      */
 71  156
     protected AbstractGenericMatrix(D dataA, int... size) { //List<E> dataL, 
 72  156
         this.size = size;
 73  156
         checkSize();
 74  156
         int dataLength = initL(dataA, product(size));
 75  156
         checkDataSize(dataLength);
 76  154
     }
 77  
 
 78  
     /**
 79  
      * Copy constructor. 
 80  
      * 
 81  
      * @param o
 82  
      */
 83  358
     protected AbstractGenericMatrix(final AbstractGenericMatrix<D, L> o) { //, E
 84  358
         this.size = o.size.clone();
 85  358
         int size1 = product(this.size);
 86  358
         initL(o.getDataA(), size1);
 87  358
     }
 88  
 
 89  
     /**
 90  
      * Checks the field {@link #size}: dimension at lest two 
 91  
      * and each entry non-negative. 
 92  
      */
 93  
     private void checkSize() throws IllegalArgumentException {
 94  1218
         switch (this.size.length) {
 95  
         case 0:
 96  0
             throw new IllegalArgumentException("no size");
 97  
         case 1:
 98  4
             throw new IllegalArgumentException
 99  
                 ("size must have a least 2 dimensions");
 100  
         default:
 101  4340
             for (final int s : this.size) {
 102  
                 // **** what does s=0 mean?
 103  3126
                 if (s < 0) {
 104  0
                     throw new IllegalArgumentException
 105  
                         ("element in size less than zero. =" + s);
 106  
                 }
 107  
             }
 108  
         }
 109  1214
     }
 110  
 
 111  
     /**
 112  
      * Check that the overall size given by the product of {@link #size} 
 113  
      * does not exceed the length of the backed array. 
 114  
      */
 115  
     private void checkDataSize(int dataLength) {
 116  156
         if (product(this.size) > dataLength) {
 117  2
             final StringBuilder text = new StringBuilder();
 118  2
             text.append("length of data(");
 119  2
             text.append(dataLength);
 120  2
             text.append(") is smaller than size([");
 121  2
             boolean first = true;
 122  8
             for (final int i : this.size) {
 123  6
                 if (first) {
 124  2
                     first = false;
 125  
                 } else {
 126  4
                     text.append(", ");
 127  
                 }
 128  6
                 text.append(i);
 129  
             }
 130  2
             text.append("])");
 131  2
             throw new IllegalArgumentException(text.toString());
 132  
         }
 133  154
     }
 134  
 
 135  
     /**
 136  
      * Returns a new data store with given size 
 137  
      * and entries carrying the default value. 
 138  
      * The latter depends on the types: false for boolean, 
 139  
      * 0 for int, 0.0 for double and null for GenericMatrix's. 
 140  
      * 
 141  
      * @param size
 142  
      * @return new D[size]
 143  
      */
 144  
     protected abstract L newL(int size);
 145  
 
 146  
     // as a side effect sets dataL and returns length of array 'data'
 147  
     protected abstract int initL(D data, int size);
 148  
 
 149  
     /**
 150  
      * The number of data entries. 
 151  
      * Note that it is heavy load to compute this at the moment. 
 152  
      */
 153  
     public final int dataSize() {
 154  6598
          return this.dataL.size();
 155  
     }
 156  
 
 157  
     /**
 158  
      * Returns the data store as an array. 
 159  
      * There are subclasses with array of primitive types. 
 160  
      */
 161  
     protected abstract D getDataA();
 162  
 
 163  
     /**
 164  
      * Sets the entry with plain position <code>pos</code> 
 165  
      * to value parsing the string <code>value</code>. 
 166  
      * Note that this base class cannot provide setter methods 
 167  
      * for java's primitive data types. 
 168  
      *
 169  
      * @param value
 170  
      *    
 171  
      * @param pos
 172  
      *    see e.g. {@link AbstractObjectMatrix#setPlain(String, int)} 
 173  
      *    and {@link OctaveDouble#setPlain(String, int)} 
 174  
      */
 175  
     // throws UnsupportedOperationException for GenericMatrix by default 
 176  
     // design ok? **** 
 177  
     public abstract void setPlain(String value, int pos);
 178  
 
 179  
     /**
 180  
      * @param ns
 181  
      * @return product of ns
 182  
      */
 183  
     private static int product(final int... ns) {
 184  43250
         int p = 1;
 185  131116
         for (final int n : ns) {
 186  
             // **** here a check against overflow is required. 
 187  87866
             p *= n;
 188  
         }
 189  43250
         return p;
 190  
     }
 191  
 
 192  
     /**
 193  
      * Resize matrix up to include pos if necessary, 
 194  
      * i.e. if an entry of <code>pos</code> is greater 
 195  
      * than the according entry in {@link #size}. 
 196  
      * 
 197  
      * @param pos
 198  
      *    an index vector with same dimension as {@link #size} 
 199  
      * @throws UnsupportedOperationException
 200  
      *   if <code>pos</code> has dimension other than that of {@link #size}. 
 201  
      */
 202  
     // could be protected if not used in OctaveComplex
 203  
     public final void resizeUp(final int... pos) {
 204  41580
         if (this.size.length != pos.length) {
 205  0
             throw new UnsupportedOperationException
 206  
                 ("Change in number of dimensions not supported (" + size.length
 207  
                  + "!=" + pos.length + ")");
 208  
         }
 209  
 
 210  41580
         if (this.size.length == 0) {
 211  
             // no entry and thus no resize 
 212  0
             return;
 213  
         }
 214  
 
 215  41580
         int[] orgSize = this.size.clone();
 216  41580
         boolean resizeNeeded = false;
 217  124962
         for (int idx = 0; idx < this.size.length; idx++) {
 218  83382
             if (pos[idx] > this.size[idx]) {
 219  20628
                 this.size[idx] = pos[idx];
 220  20628
                 resizeNeeded = true;
 221  
             }
 222  
         }
 223  
         // Here, this.size is updated whereas orgSize contains original size
 224  
 
 225  41580
         if (!resizeNeeded) {
 226  21010
             return;
 227  
         }
 228  
 
 229  
         // Here, orgSize[0] is defined 
 230  20570
         final int cpyLen    = orgSize[0];
 231  20570
         final int osp = product(orgSize);
 232  
 
 233  
         // initialize resulting array with default values 
 234  20570
         D dataInL  = getDataA();
 235  20570
         this.dataL = newL(product(this.size));
 236  20570
         int idxSrc = 0;
 237  20570
         int idxTrg = 0;
 238  20570
         int[] idxTrgMulti = new int[orgSize.length]; // 0th entry not used 
 239  
         int idxIdx;
 240  
         int lenUnitGap;
 241  34143180
         while (idxSrc < osp) {
 242  68286276
             System.arraycopy(dataInL, idxSrc, 
 243  34143138
                              getDataA(), idxTrg, cpyLen);
 244  34143138
             idxSrc += cpyLen;
 245  
 
 246  
             // update idxTrgMulti and idxTrg 
 247  34143138
             idxIdx = 1;
 248  34143138
             lenUnitGap = this.size[0];
 249  34163762
             while (idxIdx < orgSize.length 
 250  
                        &&  idxTrgMulti[idxIdx] >= orgSize[idxIdx] - 1) {
 251  20624
                     assert idxTrgMulti[idxIdx] == orgSize[idxIdx] - 1;
 252  
 
 253  20624
                 idxTrg -= lenUnitGap * idxTrgMulti[idxIdx];
 254  20624
                     idxTrgMulti[idxIdx] = 0;
 255  
 
 256  20624
                 lenUnitGap *= this.size[idxIdx];
 257  20624
                     idxIdx++;
 258  
             }
 259  34143138
             assert idxIdx == orgSize.length 
 260  
                     ||  idxTrgMulti[idxIdx] < orgSize[idxIdx];
 261  
 //            assert idxIdx < orgSize.length;
 262  34143138
             if (idxIdx >= orgSize.length) {
 263  20528
                 break;
 264  
             }
 265  
             // update top 
 266  
 
 267  34122610
             idxTrg += lenUnitGap;
 268  34122610
             idxTrgMulti[idxIdx]++;
 269  
         } // while 
 270  20570
     }
 271  
 
 272  
     /**
 273  
      * @param pos
 274  
      * @return the index into data() for the position
 275  
      */
 276  
     public final int pos2ind(final int... pos) {
 277  43788
         int idx = 0;
 278  43788
         int factor = 1;
 279  134688
         for (int dim = 0; dim < pos.length; ++dim) {
 280  90932
             if (pos[dim] > this.size[dim]) {
 281  28
                 throw new IndexOutOfBoundsException
 282  
                     ("pos exceeded dimension for dimension " + 
 283  
                      dim + " (" + pos[dim] + " > " + this.size[dim] + ")");
 284  
             }
 285  90900
             idx += (pos[dim] - 1) * factor;
 286  90900
             factor *= this.size[dim];
 287  
         }
 288  43756
         return idx;
 289  
     }
 290  
 
 291  
     /**
 292  
      * Returns the string representation of the given plain position. 
 293  
      */
 294  
     public abstract String getPlainString(int pos);
 295  
 
 296  
     public final int getSizeLength() {
 297  2174
         return this.size.length;
 298  
     }
 299  
 
 300  
     /**
 301  
      * @param i
 302  
      *            dimension number in 1 based numbering, 1=row, 2=column
 303  
      * @return the size in dimension i
 304  
      */
 305  
     public final int getSize(final int i) {
 306  2258
         return this.size[i - 1];
 307  
     }
 308  
 
 309  
     @Override
 310  
     public final int hashCode() {
 311  0
         int result = 1;
 312  0
         result = PRIME * result + 
 313  0
             ((this.dataL == null) ? 0 : this.dataL.hashCode());
 314  0
         result = PRIME * result + Arrays.hashCode(this.size);
 315  0
         return result;
 316  
     }
 317  
 
 318  
     @SuppressWarnings("unchecked")
 319  
     @Override
 320  
     public final boolean equals(final Object obj) {
 321  720
         if (this == obj) {
 322  0
             return true;
 323  
         }
 324  720
         if (obj == null || getClass() != obj.getClass()) {
 325  36
             return false;
 326  
         }
 327  684
         final AbstractGenericMatrix<D, List<?>> other = 
 328  
             (AbstractGenericMatrix<D, List<?>>) obj;
 329  684
         if (!Arrays.equals(this.size, other.size)) {
 330  302
             return false;
 331  
         }
 332  
         
 333  382
         assert this.dataL.size() == product(this.size);
 334  382
         return this.dataL.equals(other.dataL);
 335  
     }
 336  
 
 337  
     // to implement OctaveObject 
 338  
     public abstract OctaveObject shallowCopy();
 339  
 
 340  
     public static void main(String[] args) {
 341  0
         System.out.println("R" + product());
 342  0
     }
 343  
 
 344  
 }