@Test
  public void testLarge() throws Exception {

    final long start = System.currentTimeMillis();
    final List<IDataset> images = new ArrayList<IDataset>(10);

    final File dir = new File(System.getProperty("GDALargeTestFilesLocation") + "EDFLoaderTest/");
    final File[] files = dir.listFiles();
    for (int i = 0; i < files.length; i++) {
      if (files[i].getName().startsWith("billeA")) {
        images.add(LoaderFactory.getData(files[i].getAbsolutePath(), null).getDataset(0));
      }
    }

    final AbstractDataset median = CollectionStats.median(images);
    final long end = System.currentTimeMillis();
    if (median.getShape()[0] != 2048) throw new Exception("Median has wrong size!");
    if (median.getShape()[1] != 2048) throw new Exception("Median has wrong size!");

    System.out.println("Did median of ten images 2048x2048 in " + ((end - start) / 1000d) + "s");

    final AbstractDataset mean = CollectionStats.median(images);
    final long end1 = System.currentTimeMillis();
    if (mean.getShape()[0] != 2048) throw new Exception("Mean has wrong size!");
    if (mean.getShape()[1] != 2048) throw new Exception("Mean has wrong size!");

    System.out.println("Did mean of ten images 2048x2048 in " + ((end1 - end) / 1000d) + "s");
  }
  @Override
  public void setElements(AbstractDataset source, int element) {
    if (element < 0) element += isize;
    if (element < 0 || element > isize) {
      throw new IllegalArgumentException(
          String.format("Invalid choice of element: %d/%d", element, isize));
    }
    if (elementClass() != source.elementClass()) {
      throw new IllegalArgumentException(
          "Element class of destination does not match this dataset");
    }

    final IndexIterator it = getIterator(element);
    final int[] elements = ((IntegerDataset) source).data; // CLASS_TYPE // PRIM_TYPE

    if (source.isContiguous()) {
      int n = 0;
      while (it.hasNext()) {
        data[it.index] = elements[n];
        n++;
      }
    } else {
      final IndexIterator sit = source.getIterator();
      while (it.hasNext() && sit.hasNext()) {
        data[it.index] = elements[sit.index];
      }
    }
  }
  /**
   * Cast a dataset to this compound type. If repeat is set, the first element of each item in the
   * given dataset is repeated across all elements of an item. Otherwise, each item comprises a
   * truncated or zero-padded copy of elements from the given dataset.
   *
   * @param itemSize
   * @param repeat repeat first element
   * @param dataset
   */
  public CompoundIntegerDataset(
      final int itemSize, final boolean repeat, final AbstractDataset dataset) {
    isize = itemSize;
    size = dataset.size;
    shape = dataset.shape.clone();
    name = new String(dataset.name);

    odata = data = createArray(size);
    final int os = dataset.getElementsPerItem();

    IndexIterator iter = dataset.getIterator();
    if (repeat) {
      int i = 0;
      while (iter.hasNext()) {
        final int v =
            (int) dataset.getElementLongAbs(iter.index); // PRIM_TYPE // GET_ELEMENT_WITH_CAST
        for (int k = 0; k < isize; k++) data[i++] = v;
      }
    } else {
      final int kmax = Math.min(isize, os);
      int i = 0;
      while (iter.hasNext()) {
        for (int k = 0; k < kmax; k++)
          data[i + k] = (int) dataset.getElementLongAbs(iter.index + k); // GET_ELEMENT_WITH_CAST
        i += isize;
      }
    }
  }
  @Override
  public CompoundIntegerDataset ipower(final Object b) {
    if (b instanceof AbstractDataset) {
      final AbstractDataset bds = (AbstractDataset) b;
      checkCompatibility(bds);

      final IndexIterator it1 = getIterator();
      final IndexIterator it2 = bds.getIterator();
      final int bis = bds.getElementsPerItem();

      if (bis == 1) {
        while (it1.hasNext() && it2.hasNext()) {
          final int db =
              (int) bds.getElementLongAbs(it2.index); // PRIM_TYPE // GET_ELEMENT_WITH_CAST
          for (int i = 0; i < isize; i++) {
            final double v = Math.pow(data[it1.index + i], db);
            if (Double.isInfinite(v) || Double.isNaN(v)) { // INT_ZEROTEST
              data[it1.index + i] = 0; // INT_ZEROTEST // CLASS_TYPE
            } else { // INT_ZEROTEST
              data[it1.index + i] = (int) (long) v; // PRIM_TYPE_LONG // ADD_CAST
            } // INT_ZEROTEST
          }
        }
      } else if (bis == isize) {
        while (it1.hasNext() && it2.hasNext()) {
          for (int i = 0; i < isize; i++) {
            final double v = Math.pow(data[it1.index + i], bds.getElementDoubleAbs(it2.index + i));
            if (Double.isInfinite(v) || Double.isNaN(v)) { // INT_ZEROTEST
              data[it1.index + i] = 0; // INT_ZEROTEST // CLASS_TYPE
            } else { // INT_ZEROTEST
              data[it1.index + i] = (int) (long) v; // PRIM_TYPE_LONG // ADD_CAST
            } // INT_ZEROTEST
          }
        }
      } else {
        throw new IllegalArgumentException(
            "Argument does not have same number of elements per item or is not a non-compound dataset");
      }
    } else {
      final int[] vr = toIntegerArray(b, isize); // PRIM_TYPE // CLASS_TYPE
      final IndexIterator it1 = getIterator();

      while (it1.hasNext()) {
        for (int i = 0; i < isize; i++) {
          final double v = Math.pow(data[it1.index + i], vr[i]);
          if (Double.isInfinite(v) || Double.isNaN(v)) { // INT_ZEROTEST
            data[it1.index + i] = 0; // INT_ZEROTEST // CLASS_TYPE
          } else { // INT_ZEROTEST
            data[it1.index + i] = (int) (long) v; // PRIM_TYPE_LONG // ADD_CAST
          } // INT_ZEROTEST
        }
      }
    }
    setDirty();
    return this;
  }
  @Override
  public double residual(final Object b) {
    double sum = 0;
    if (b instanceof AbstractDataset) {
      final AbstractDataset bds = (AbstractDataset) b;
      checkCompatibility(bds);

      final IndexIterator it1 = getIterator();
      final IndexIterator it2 = bds.getIterator();
      final int bis = bds.getElementsPerItem();

      if (bis == 1) {
        double comp = 0;
        while (it1.hasNext() && it2.hasNext()) {
          final double db = bds.getElementDoubleAbs(it2.index);
          for (int i = 0; i < isize; i++) {
            final double diff = data[it1.index + i] - db;
            final double err = diff * diff - comp;
            final double temp = sum + err;
            comp = (temp - sum) - err;
            sum = temp;
          }
        }
      } else if (bis == isize) {
        double comp = 0;
        while (it1.hasNext() && it2.hasNext()) {
          for (int i = 0; i < isize; i++) {
            final double diff = data[it1.index + i] - bds.getElementDoubleAbs(it2.index + i);
            final double err = diff * diff - comp;
            final double temp = sum + err;
            comp = (temp - sum) - err;
            sum = temp;
          }
        }
      } else {
        throw new IllegalArgumentException(
            "Argument does not have same number of elements per item or is not a non-compound dataset");
      }
    } else {
      final double[] vr = toDoubleArray(b, isize);
      final IndexIterator it1 = getIterator();

      double comp = 0;
      while (it1.hasNext()) {
        for (int i = 0; i < isize; i++) {
          final double diff = data[it1.index + i] - vr[i];
          final double err = diff * diff - comp;
          final double temp = sum + err;
          comp = (temp - sum) - err;
          sum = temp;
        }
      }
    }
    return sum;
  }
  @Override
  public CompoundIntegerDataset iremainder(final Object b) {
    if (b instanceof AbstractDataset) {
      final AbstractDataset bds = (AbstractDataset) b;
      checkCompatibility(bds);

      final IndexIterator it1 = getIterator();
      final IndexIterator it2 = bds.getIterator();
      final int bis = bds.getElementsPerItem();

      if (bis == 1) {
        while (it1.hasNext() && it2.hasNext()) {
          final int db =
              (int) bds.getElementLongAbs(it2.index); // PRIM_TYPE // GET_ELEMENT_WITH_CAST
          if (db == 0) { // INT_ZEROTEST
            for (int i = 0; i < isize; i++) // INT_ZEROTEST
            data[it1.index + i] = 0; // INT_ZEROTEST
          } else { // INT_ZEROTEST
            for (int i = 0; i < isize; i++) data[it1.index + i] %= db;
          } // INT_ZEROTEST
        }
      } else if (bis == isize) {
        while (it1.hasNext() && it2.hasNext()) {
          for (int i = 0; i < isize; i++) {
            try {
              data[it1.index + i] %=
                  bds.getElementLongAbs(it2.index + i); // GET_ELEMENT // INT_EXCEPTION
            } catch (ArithmeticException e) {
              data[it1.index + i] = 0;
            }
          }
        }
      } else {
        throw new IllegalArgumentException(
            "Argument does not have same number of elements per item or is not a non-compound dataset");
      }
    } else {
      final double[] vr = toDoubleArray(b, isize);
      final IndexIterator it1 = getIterator();

      while (it1.hasNext()) {
        for (int i = 0; i < isize; i++) {
          if (vr[i] == 0) { // INT_ZEROTEST
            data[it1.index + i] = 0; // INT_ZEROTEST
          } else { // INT_ZEROTEST
            data[it1.index + i] %= vr[i];
          } // INT_ZEROTEST
        }
      }
    }
    setDirty();
    return this;
  }
  @Test
  public void test1D() throws Exception {

    final AbstractDataset median = CollectionStats.median(SETS1D);
    if (median.getDouble(0) != 1) throw new Exception("Median not calculated correctly!");
    if (median.getDouble(4) != 5) throw new Exception("Median not calculated correctly!");

    final AbstractDataset mean = CollectionStats.mean(SETS1D);
    if (!DoubleUtils.equalsWithinTolerance(mean.getDouble(0), 100.8, 0.0001))
      throw new Exception("Mean not calculated correctly!");
    if (!DoubleUtils.equalsWithinTolerance(mean.getDouble(4), 104, 0.0001))
      throw new Exception("Mean not calculated correctly!");
  }
  @Override
  public void fillDataset(AbstractDataset result, IndexIterator iter) {
    IndexIterator riter = result.getIterator();

    int[] rdata = ((CompoundIntegerDataset) result).data; // PRIM_TYPE

    while (riter.hasNext() && iter.hasNext()) {
      for (int i = 0; i < isize; i++) rdata[riter.index + i] = data[iter.index + i];
    }
  }
  @Override
  public CompoundIntegerDataset imultiply(final Object b) {
    if (b instanceof AbstractDataset) {
      final AbstractDataset bds = (AbstractDataset) b;
      checkCompatibility(bds);

      final IndexIterator it1 = getIterator();
      final IndexIterator it2 = bds.getIterator();
      final int bis = bds.getElementsPerItem();

      if (bis == 1) {
        while (it1.hasNext() && it2.hasNext()) {
          final int db =
              (int) bds.getElementLongAbs(it2.index); // PRIM_TYPE // GET_ELEMENT_WITH_CAST
          for (int i = 0; i < isize; i++) data[it1.index + i] *= db;
        }
      } else if (bis == isize) {
        while (it1.hasNext() && it2.hasNext()) {
          for (int i = 0; i < isize; i++)
            data[it1.index + i] *= bds.getElementLongAbs(it2.index + i); // GET_ELEMENT
        }
      } else {
        throw new IllegalArgumentException(
            "Argument does not have same number of elements per item or is not a non-compound dataset");
      }
    } else {
      final int[] vr = toIntegerArray(b, isize); // PRIM_TYPE // CLASS_TYPE
      final IndexIterator it1 = getIterator();

      while (it1.hasNext()) {
        for (int i = 0; i < isize; i++) data[it1.index + i] *= vr[i];
      }
    }
    setDirty();
    return this;
  }
  @Override
  public void copyItemsFromAxes(final int[] pos, final boolean[] axes, final AbstractDataset dest) {
    int[] ddata = (int[]) dest.odata; // PRIM_TYPE

    if (dest.getElementsPerItem() != isize) {
      throw new IllegalArgumentException(
          String.format(
              "Destination dataset is incompatible as it has %d elements per item not %d",
              dest.getElementsPerItem(), isize));
    }

    SliceIterator siter = getSliceIteratorFromAxes(pos, axes);
    int[] sshape = squeezeShape(siter.getSliceShape(), false);

    IndexIterator diter = dest.getSliceIterator(null, sshape, null);

    if (ddata.length < calcSize(sshape)) {
      throw new IllegalArgumentException("destination array is not large enough");
    }

    while (siter.hasNext() && diter.hasNext()) {
      for (int i = 0; i < isize; i++) ddata[diter.index + i] = data[siter.index + i];
    }
  }
  @Test
  public void test2D() throws Exception {

    final AbstractDataset median = CollectionStats.median(SETS2D);
    if (median.getDouble(0, 0) != 1) throw new Exception("Median not calculated correctly!");
    if (median.getDouble(1, 1) != 4) throw new Exception("Median not calculated correctly!");
    if (median.getShape()[0] != 2) throw new Exception("Median shape not correct!");
    if (median.getShape()[1] != 2) throw new Exception("Median shape not correct!");

    final AbstractDataset mean = CollectionStats.mean(SETS2D);
    if (!DoubleUtils.equalsWithinTolerance(mean.getDouble(0, 0), 100.8d, 0.01))
      throw new Exception("Mean not calculated correctly!");
    if (!DoubleUtils.equalsWithinTolerance(mean.getDouble(1, 1), 103.2d, 0.01))
      throw new Exception("Mean not calculated correctly!");
  }
  @Override
  public void copyElements(AbstractDataset destination, int element) {
    if (element < 0) element += isize;
    if (element < 0 || element > isize) {
      throw new IllegalArgumentException(
          String.format("Invalid choice of element: %d/%d", element, isize));
    }
    if (elementClass() != destination.elementClass()) {
      throw new IllegalArgumentException(
          "Element class of destination does not match this dataset");
    }

    final IndexIterator it = getIterator(element);
    final int[] elements = ((IntegerDataset) destination).data; // CLASS_TYPE // PRIM_TYPE

    int n = 0;
    while (it.hasNext()) {
      elements[n] = data[it.index];
      n++;
    }
  }
  @Override
  public CompoundIntegerDataset setByBoolean(final Object o, BooleanDataset selection) {
    if (o instanceof AbstractDataset) {
      AbstractDataset ds = (AbstractDataset) o;
      final int length = ((Number) selection.sum()).intValue();
      if (length != ds.getSize()) {
        throw new IllegalArgumentException(
            "Number of true items in selection does not match number of items in dataset");
      }

      IndexIterator iter = ds.getIterator();
      BooleanIterator biter = getBooleanIterator(selection);

      if (ds instanceof AbstractCompoundDataset) {
        if (isize != ds.getElementsPerItem()) {
          throw new IllegalArgumentException("Input dataset is not compatible with slice");
        }

        while (biter.hasNext() && iter.hasNext()) {
          for (int i = 0; i < isize; i++)
            data[biter.index + i] =
                (int) ds.getElementLongAbs(iter.index + i); // GET_ELEMENT_WITH_CAST
        }
      } else {
        while (biter.hasNext() && iter.hasNext()) {
          data[biter.index] = (int) ds.getElementLongAbs(iter.index); // GET_ELEMENT_WITH_CAST
          for (int i = 1; i < isize; i++) data[biter.index + i] = 0;
        }
      }
    } else {
      try {
        final int[] vr = toIntegerArray(o, isize); // PRIM_TYPE // CLASS_TYPE

        final BooleanIterator biter = getBooleanIterator(selection);

        while (biter.hasNext()) {
          for (int i = 0; i < isize; i++) data[biter.index + i] = vr[i];
        }
      } catch (IllegalArgumentException e) {
        throw new IllegalArgumentException("Object for setting is not a dataset or number");
      }
    }
    return this;
  }
  @Override
  public CompoundIntegerDataset setSlice(final Object o, final SliceIterator siter) {
    if (o instanceof IDataset) {
      final IDataset ds = (IDataset) o;
      final int[] oshape = ds.getShape();

      if (!areShapesCompatible(siter.getSliceShape(), oshape)) {
        throw new IllegalArgumentException(
            String.format(
                "Input dataset is not compatible with slice: %s cf %s",
                Arrays.toString(oshape), Arrays.toString(siter.getSliceShape())));
      }

      if (ds instanceof AbstractDataset) {
        final AbstractDataset ads = (AbstractDataset) ds;
        IndexIterator oiter = ads.getIterator();

        if (ds instanceof AbstractCompoundDataset) {
          if (isize != ads.getElementsPerItem()) {
            throw new IllegalArgumentException("Input dataset is not compatible with slice");
          }

          while (siter.hasNext() && oiter.hasNext()) {
            for (int i = 0; i < isize; i++)
              data[siter.index + i] =
                  (int) ads.getElementLongAbs(oiter.index + i); // GET_ELEMENT_WITH_CAST
          }
        } else {
          while (siter.hasNext() && oiter.hasNext()) {
            data[siter.index] = (int) ads.getElementLongAbs(oiter.index); // GET_ELEMENT_WITH_CAST
            for (int i = 1; i < isize; i++) data[siter.index + i] = 0;
          }
        }
      } else {
        final IndexIterator oiter = new PositionIterator(oshape);
        final int[] pos = oiter.getPos();

        if (ds.getElementsPerItem() == 1) {
          while (siter.hasNext() && oiter.hasNext()) {
            data[siter.index] = ds.getInt(pos); // PRIM_TYPE
            for (int i = 1; i < isize; i++) data[siter.index + i] = 0;
          }
        } else {
          while (siter.hasNext() && oiter.hasNext()) {
            final int[] val = toIntegerArray(ds.getObject(pos), isize); // PRIM_TYPE // CLASS_TYPE
            for (int i = 0; i < isize; i++) data[siter.index + i] = val[i];
          }
        }
      }
    } else {
      try {
        final int[] vr = toIntegerArray(o, isize); // PRIM_TYPE // CLASS_TYPE

        while (siter.hasNext()) {
          for (int i = 0; i < isize; i++) data[siter.index + i] = vr[i];
        }
      } catch (IllegalArgumentException e) {
        throw new IllegalArgumentException("Object for setting slice is not a dataset or number");
      }
    }
    setDirty();
    return this;
  }