001/*- 002 ******************************************************************************* 003 * Copyright (c) 2011, 2016 Diamond Light Source Ltd. 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the Eclipse Public License v1.0 006 * which accompanies this distribution, and is available at 007 * http://www.eclipse.org/legal/epl-v10.html 008 * 009 * Contributors: 010 * Peter Chang - initial API and implementation and/or initial documentation 011 *******************************************************************************/ 012 013package org.eclipse.january.dataset; 014 015import java.util.Arrays; 016 017import org.eclipse.january.DatasetException; 018import org.eclipse.january.IMonitor; 019import org.eclipse.january.metadata.StatisticsMetadata; 020import org.eclipse.january.metadata.internal.StatisticsMetadataImpl; 021 022/** 023 * Generic container class for data that is compound in nature 024 * 025 * Each subclass has an array of compound types, items of this array are composed of primitive types 026 * 027 * Data items can be Complex, Vector, etc 028 * 029 */ 030public abstract class AbstractCompoundDataset extends AbstractDataset implements CompoundDataset { 031 // pin UID to base class 032 private static final long serialVersionUID = Dataset.serialVersionUID; 033 034 protected int isize; // number of elements per item 035 036 @Override 037 public int getElementsPerItem() { 038 return isize; 039 } 040 041 @Override 042 protected int get1DIndex(final int i) { 043 int n = super.get1DIndex(i); 044 return stride == null ? isize * n : n; 045 } 046 047 @Override 048 protected int get1DIndex(final int i, final int j) { 049 int n = super.get1DIndex(i, j); 050 return stride == null ? isize * n : n; 051 } 052 053 @Override 054 protected int get1DIndexFromShape(final int[] n) { 055 return isize * super.get1DIndexFromShape(n); 056 } 057 058 @Override 059 public Dataset getUniqueItems() { 060 throw new UnsupportedOperationException("Cannot sort compound datasets"); 061 } 062 063 @Override 064 public IndexIterator getIterator(final boolean withPosition) { 065 if (stride != null) { 066 return base.getSize() == 1 ? 067 (withPosition ? new PositionIterator(offset, shape) : new SingleItemIterator(offset, size)) : new StrideIterator(isize, shape, stride, offset); 068 } 069 return withPosition ? getSliceIterator(null, null, null) : 070 new ContiguousIterator(size, isize); 071 } 072 073 /** 074 * Get an iterator that picks out the chosen element from all items 075 * @param element 076 * @return an iterator 077 */ 078 public IndexIterator getIterator(int element) { 079 if (element < 0) 080 element += isize; 081 if (element < 0 || element > isize) { 082 logger.error("Invalid choice of element: {}/{}", element, isize); 083 throw new IllegalArgumentException("Invalid choice of element: " + element + "/" + isize); 084 } 085 086 final IndexIterator it; 087 if (stride != null) { 088 it = base.getSize() == 1 ? new SingleItemIterator(offset + element, size) : new StrideIterator(isize, shape, stride, offset, element); 089 } else { 090 it = new ContiguousIterator(size, isize, element); 091 } 092 093 return it; 094 } 095 096 @Override 097 public IndexIterator getSliceIterator(SliceND slice) { 098 if (stride != null) 099 return new StrideIterator(isize, shape, stride, offset, slice); 100 101 return new SliceIterator(shape, size, isize, slice); 102 } 103 104 /** 105 * Constructor required for serialisation. 106 */ 107 public AbstractCompoundDataset() { 108 } 109 110 @Override 111 public boolean equals(Object obj) { 112 if (!super.equals(obj)) { 113 return false; 114 } 115 116 CompoundDataset other = (CompoundDataset) obj; 117 return isize == other.getElementsPerItem(); 118 } 119 120 @Override 121 public int hashCode() { 122 return getCompoundStats().getHash(shape); 123 } 124 125 @Override 126 public CompoundDataset cast(boolean repeat, int dtype, int isize) { 127 return (CompoundDataset) super.cast(repeat, dtype, isize); 128 } 129 130 @Override 131 public CompoundDataset cast(int dtype) { 132 return (CompoundDataset) super.cast(dtype); 133 } 134 135 @Override 136 abstract public AbstractCompoundDataset clone(); 137 138 @Override 139 public CompoundDataset flatten() { 140 return (CompoundDataset) super.flatten(); 141 } 142 143 @Override 144 public CompoundDataset getBy1DIndex(IntegerDataset index) { 145 return (CompoundDataset) super.getBy1DIndex(index); 146 } 147 148 @Override 149 public CompoundDataset getByBoolean(Dataset selection) { 150 return (CompoundDataset) super.getByBoolean(selection); 151 } 152 153 @Override 154 public CompoundDataset getByIndexes(Object... indexes) { 155 return (CompoundDataset) super.getByIndexes(indexes); 156 } 157 158 @Override 159 public CompoundDataset getSlice(IMonitor mon, int[] start, int[] stop, int[] step) { 160 return (CompoundDataset) super.getSlice(mon, start, stop, step); 161 } 162 163 @Override 164 public CompoundDataset getSlice(IMonitor mon, Slice... slice) { 165 return (CompoundDataset) super.getSlice(mon, slice); 166 } 167 168 @Override 169 public CompoundDataset getSlice(IMonitor mon, SliceND slice) { 170 return (CompoundDataset) super.getSlice(mon, slice); 171 } 172 173 @Override 174 public CompoundDataset getSlice(int[] start, int[] stop, int[] step) { 175 return (CompoundDataset) super.getSlice(start, stop, step); 176 } 177 178 @Override 179 public CompoundDataset getSlice(Slice... slice) { 180 return (CompoundDataset) super.getSlice(slice); 181 } 182 183 @Override 184 public CompoundDataset getSlice(SliceND slice) { 185 return (CompoundDataset) super.getSlice(slice); 186 } 187 188 @Override 189 abstract public AbstractCompoundDataset getSlice(SliceIterator iterator); 190 191 @Override 192 public CompoundDataset getSliceView(int[] start, int[] stop, int[] step) { 193 return (CompoundDataset) super.getSliceView(start, stop, step); 194 } 195 196 @Override 197 public CompoundDataset getSliceView(Slice... slice) { 198 return (CompoundDataset) super.getSliceView(slice); 199 } 200 201 @Override 202 public CompoundDataset getSliceView(SliceND slice) { 203 return (CompoundDataset) super.getSliceView(slice); 204 } 205 206 @Override 207 public CompoundDataset getTransposedView(int... axes) { 208 return (CompoundDataset) super.getTransposedView(axes); 209 } 210 211 @Override 212 abstract public AbstractCompoundDataset getView(boolean deepCopyMetadata); 213 214 @Override 215 public CompoundDataset getBroadcastView(int... broadcastShape) { 216 return (CompoundDataset) super.getBroadcastView(broadcastShape); 217 } 218 219 @Override 220 public CompoundDataset ifloorDivide(Object o) { 221 return (CompoundDataset) super.ifloorDivide(o); 222 } 223 224 @Override 225 public CompoundDataset reshape(int... shape) { 226 return (CompoundDataset) super.reshape(shape); 227 } 228 229 @Override 230 public CompoundDataset setSlice(Object obj, int[] start, int[] stop, int[] step) { 231 return (CompoundDataset) super.setSlice(obj, start, stop, step); 232 } 233 234 @Override 235 public CompoundDataset setSlice(Object object, Slice... slice) { 236 return (CompoundDataset) super.setSlice(object, slice); 237 } 238 239 @Override 240 public CompoundDataset sort(Integer axis) { 241 throw new UnsupportedOperationException("Cannot sort dataset"); 242 } 243 244 @Override 245 public CompoundDataset squeezeEnds() { 246 return (CompoundDataset) super.squeezeEnds(); 247 } 248 249 @Override 250 public CompoundDataset squeeze() { 251 return (CompoundDataset) super.squeeze(); 252 } 253 254 @Override 255 public CompoundDataset squeeze(boolean onlyFromEnd) { 256 return (CompoundDataset) super.squeeze(onlyFromEnd); 257 } 258 259 @Override 260 public CompoundDataset swapAxes(int axis1, int axis2) { 261 return (CompoundDataset) super.swapAxes(axis1, axis2); 262 } 263 264 @Override 265 public synchronized CompoundDataset synchronizedCopy() { 266 return clone(); 267 } 268 269 @Override 270 public CompoundDataset transpose(int... axes) { 271 return (CompoundDataset) super.transpose(axes); 272 } 273 274 /** 275 * @since 2.0 276 */ 277 abstract protected double getFirstValue(); 278 279 abstract protected double getFirstValue(final int i); 280 281 abstract protected double getFirstValue(final int i, final int j); 282 283 abstract protected double getFirstValue(final int...pos); 284 285 @Override 286 public boolean getBoolean() { 287 return getFirstValue() != 0; 288 } 289 290 @Override 291 public boolean getBoolean(final int i) { 292 return getFirstValue(i) != 0; 293 } 294 295 @Override 296 public boolean getBoolean(final int i, final int j) { 297 return getFirstValue(i, j) != 0; 298 } 299 300 @Override 301 public boolean getBoolean(final int... pos) { 302 return getFirstValue(pos) != 0; 303 } 304 305 @Override 306 public byte getByte() { 307 return (byte) getFirstValue(); 308 } 309 310 @Override 311 public byte getByte(final int i) { 312 return (byte) getFirstValue(i); 313 } 314 315 @Override 316 public byte getByte(final int i, final int j) { 317 return (byte) getFirstValue(i, j); 318 } 319 320 @Override 321 public byte getByte(final int... pos) { 322 return (byte) getFirstValue(pos); 323 } 324 325 @Override 326 public short getShort() { 327 return (short) getFirstValue(); 328 } 329 330 @Override 331 public short getShort(final int i) { 332 return (short) getFirstValue(i); 333 } 334 335 @Override 336 public short getShort(final int i, final int j) { 337 return (short) getFirstValue(i, j); 338 } 339 340 @Override 341 public short getShort(final int... pos) { 342 return (short) getFirstValue(pos); 343 } 344 345 @Override 346 public int getInt() { 347 return (int) getFirstValue(); 348 } 349 350 @Override 351 public int getInt(final int i) { 352 return (int) getFirstValue(i); 353 } 354 355 @Override 356 public int getInt(final int i, final int j) { 357 return (int) getFirstValue(i, j); 358 } 359 360 @Override 361 public int getInt(final int... pos) { 362 return (int) getFirstValue(pos); 363 } 364 365 @Override 366 public long getLong() { 367 return (long) getFirstValue(); 368 } 369 370 @Override 371 public long getLong(final int i) { 372 return (long) getFirstValue(i); 373 } 374 375 @Override 376 public long getLong(final int i, final int j) { 377 return (long) getFirstValue(i, j); 378 } 379 380 @Override 381 public long getLong(final int... pos) { 382 return (long) getFirstValue(pos); 383 } 384 385 @Override 386 public float getFloat() { 387 return (float) getFirstValue(); 388 } 389 390 @Override 391 public float getFloat(final int i) { 392 return (float) getFirstValue(i); 393 } 394 395 @Override 396 public float getFloat(final int i, final int j) { 397 return (float) getFirstValue(i, j); 398 } 399 400 @Override 401 public float getFloat(final int... pos) { 402 return (float) getFirstValue(pos); 403 } 404 405 @Override 406 public double getDouble() { 407 return getFirstValue(); 408 } 409 410 @Override 411 public double getDouble(final int i) { 412 return getFirstValue(i); 413 } 414 415 @Override 416 public double getDouble(final int i, final int j) { 417 return getFirstValue(i, j); 418 } 419 420 @Override 421 public double getDouble(final int... pos) { 422 return getFirstValue(pos); 423 } 424 425 @Override 426 public void getDoubleArray(final double[] darray) { 427 getDoubleArrayAbs(getFirst1DIndex(), darray); 428 } 429 430 @Override 431 public void getDoubleArray(final double[] darray, final int i) { 432 getDoubleArrayAbs(get1DIndex(i), darray); 433 } 434 435 @Override 436 public void getDoubleArray(final double[] darray, final int i, final int j) { 437 getDoubleArrayAbs(get1DIndex(i, j), darray); 438 } 439 440 @Override 441 public void getDoubleArray(final double[] darray, final int... pos) { 442 getDoubleArrayAbs(get1DIndex(pos), darray); 443 } 444 445 /** 446 * @since 2.0 447 */ 448 @SuppressWarnings("unchecked") 449 protected StatisticsMetadata<double[]> getCompoundStats() { 450 StatisticsMetadata<double[]> md = getFirstMetadata(StatisticsMetadata.class); 451 if (md == null || md.isDirty()) { 452 md = new StatisticsMetadataImpl<double[]>(); 453 md.initialize(this); 454 setMetadata(md); 455 } 456 return md; 457 } 458 459 @Override 460 public IntegerDataset argMax(int axis, boolean... ignoreInvalids) { 461 logger.error("Cannot compare compound numbers"); 462 throw new UnsupportedOperationException("Cannot compare compound numbers"); 463 } 464 465 @Override 466 public IntegerDataset argMin(int axis, boolean... ignoreInvalids) { 467 logger.error("Cannot compare compound numbers"); 468 throw new UnsupportedOperationException("Cannot compare compound numbers"); 469 } 470 471 @Override 472 public Number max(boolean... ignoreInvalids) { 473 logger.error("Cannot compare compound numbers"); 474 throw new UnsupportedOperationException("Cannot compare compound numbers"); 475 } 476 477 @Override 478 public CompoundDataset max(int axis, boolean... ignoreInvalids) { 479 logger.error("Cannot compare compound numbers"); 480 throw new UnsupportedOperationException("Cannot compare compound numbers"); 481 } 482 483 @Override 484 public Number min(boolean... ignoreInvalids) { 485 logger.error("Cannot compare compound numbers"); 486 throw new UnsupportedOperationException("Cannot compare compound numbers"); 487 } 488 489 @Override 490 public CompoundDataset min(int axis, boolean... ignoreInvalids) { 491 logger.error("Cannot compare compound numbers"); 492 throw new UnsupportedOperationException("Cannot compare compound numbers"); 493 } 494 495 496 @Override 497 public int[] maxPos(boolean... ignoreNaNs) { 498 logger.error("Cannot compare compound numbers"); 499 throw new UnsupportedOperationException("Cannot compare compound numbers"); 500 } 501 502 @Override 503 public int[] minPos(boolean... ignoreNaNs) { 504 logger.error("Cannot compare compound numbers"); 505 throw new UnsupportedOperationException("Cannot compare compound numbers"); 506 } 507 508 @Override 509 public CompoundDataset peakToPeak(int axis, boolean... ignoreInvalids) { 510 logger.error("Cannot compare compound numbers"); 511 throw new UnsupportedOperationException("Cannot compare compound numbers"); 512 } 513 514 @Override 515 public double[] maxItem() { 516 return getCompoundStats().getMaximum(); 517 } 518 519 @Override 520 public double[] minItem() { 521 return getCompoundStats().getMinimum(); 522 } 523 524 @Override 525 public Object mean(boolean... ignoreInvalids) { 526 return getCompoundStats().getMean(); 527 } 528 529 @Override 530 public CompoundDataset mean(int axis, boolean... ignoreInvalids) { 531 return (CompoundDataset) super.mean(axis, ignoreInvalids); 532 } 533 534 @Override 535 public CompoundDataset product(int axis, boolean... ignoreInvalids) { 536 return (CompoundDataset) super.product(axis, ignoreInvalids); 537 } 538 539 @Override 540 public CompoundDataset rootMeanSquare(int axis, boolean... ignoreInvalids) { 541 return (CompoundDataset) super.rootMeanSquare(axis, ignoreInvalids); 542 } 543 544 @Override 545 public CompoundDataset stdDeviation(int axis) { 546 return (CompoundDataset) super.stdDeviation(axis, false); 547 } 548 549 @Override 550 public CompoundDataset stdDeviation(int axis, boolean isWholePopulation, boolean... ignoreInvalids) { 551 return (CompoundDataset) super.stdDeviation(axis, isWholePopulation, ignoreInvalids); 552 } 553 554 @Override 555 public Object sum(boolean... ignoreInvalids) { 556 return getCompoundStats().getSum(); 557 } 558 559 @Override 560 public CompoundDataset sum(int axis, boolean... ignoreInvalids) { 561 return (CompoundDataset) super.sum(axis, ignoreInvalids); 562 } 563 564 @Override 565 public double variance(boolean isWholePopulation, boolean... ignoreInvalids) { 566 return getCompoundStats().getVariance(isWholePopulation, ignoreInvalids); 567 } 568 569 @Override 570 public CompoundDataset variance(int axis) { 571 return (CompoundDataset) super.variance(axis, false); 572 } 573 574 @Override 575 public CompoundDataset variance(int axis, boolean isWholePopulation, boolean... ignoreInvalids) { 576 return (CompoundDataset) super.variance(axis, isWholePopulation, ignoreInvalids); 577 } 578 579 @Override 580 public double rootMeanSquare(boolean... ignoreInvalids) { 581 StatisticsMetadata<double[]> stats = getCompoundStats(); 582 583 double[] mean = stats.getMean(ignoreInvalids); 584 double result = 0; 585 for (int i = 0; i < isize; i++) { 586 double m = mean[i]; 587 result += m * m; 588 } 589 return Math.sqrt(result + stats.getVariance(true)); 590 } 591 592 /** 593 * @return error 594 */ 595 private CompoundDataset getInternalError() { 596 ILazyDataset led = super.getErrors(); 597 if (led == null) 598 return null; 599 600 Dataset ed = null; 601 try { 602 ed = DatasetUtils.sliceAndConvertLazyDataset(led); 603 } catch (DatasetException e) { 604 logger.error("Could not get data from lazy dataset", e); 605 } 606 607 CompoundDataset ced; // ensure it has the same number of elements 608 if (!(ed instanceof CompoundDataset) || ed.getElementsPerItem() != isize) { 609 ced = new CompoundDoubleDataset(isize, true, ed); 610 } else { 611 ced = (CompoundDataset) ed; 612 } 613 614 if (led != ced) { 615 setErrors(ced); // set back 616 } 617 return ced; 618 } 619 620 @Override 621 public CompoundDataset getErrors() { 622 CompoundDataset ed = getInternalError(); 623 if (ed == null) 624 return null; 625 626 return ed.getBroadcastView(shape); 627 } 628 629 @Override 630 public double getError(final int i) { 631 return calcError(getInternalErrorArray(true, i)); 632 } 633 634 @Override 635 public double getError(final int i, final int j) { 636 return calcError(getInternalErrorArray(true, i, j)); 637 } 638 639 @Override 640 public double getError(final int... pos) { 641 return calcError(getInternalErrorArray(true, pos)); 642 } 643 644 private double calcError(double[] es) { 645 if (es == null) 646 return 0; 647 648 // assume elements are independent 649 double e = 0; 650 for (int k = 0; k < isize; k++) { 651 e += es[k]; 652 } 653 654 return Math.sqrt(e); 655 } 656 657 @Override 658 public double[] getErrorArray(final int i) { 659 return getInternalErrorArray(false, i); 660 } 661 662 @Override 663 public double[] getErrorArray(final int i, final int j) { 664 return getInternalErrorArray(false, i, j); 665 } 666 667 @Override 668 public double[] getErrorArray(final int... pos) { 669 return getInternalErrorArray(false, pos); 670 } 671 672 private Dataset getInternalError(final boolean squared) { 673 Dataset sed = squared ? getInternalSquaredError() : getInternalError(); 674 if (sed == null) 675 return null; 676 677 return sed.getBroadcastView(shape); 678 } 679 680 private double[] getInternalErrorArray(final boolean squared, final int i) { 681 Dataset sed = getInternalError(squared); 682 if (sed == null) 683 return null; 684 685 double[] es; 686 if (sed instanceof CompoundDoubleDataset) { 687 es = ((CompoundDoubleDataset) sed).getDoubleArray(i); 688 if (sed.getElementsPerItem() != isize) { // ensure error is broadcasted 689 Arrays.fill(es, es[0]); 690 } 691 } else { 692 es = new double[isize]; 693 Arrays.fill(es, ((DoubleDataset) sed).getDouble(i)); 694 } 695 return es; 696 } 697 698 private double[] getInternalErrorArray(final boolean squared, final int i, final int j) { 699 Dataset sed = getInternalError(squared); 700 if (sed == null) 701 return null; 702 703 double[] es; 704 if (sed instanceof CompoundDoubleDataset) { 705 es = ((CompoundDoubleDataset) sed).getDoubleArray(i, j); 706 if (sed.getElementsPerItem() != isize) { // ensure error is broadcasted 707 Arrays.fill(es, es[0]); 708 } 709 } else { 710 es = new double[isize]; 711 Arrays.fill(es, ((DoubleDataset) sed).getDouble(i, j)); 712 } 713 return es; 714 } 715 716 private double[] getInternalErrorArray(final boolean squared, final int... pos) { 717 Dataset sed = getInternalError(squared); 718 if (sed == null) 719 return null; 720 721 double[] es = new double[isize]; 722 if (sed instanceof CompoundDoubleDataset) { 723 es = ((CompoundDoubleDataset) sed).getDoubleArray(pos); 724 if (sed.getElementsPerItem() != isize) { // ensure error is broadcasted 725 Arrays.fill(es, es[0]); 726 } 727 } else { 728 es = new double[isize]; 729 Arrays.fill(es, ((DoubleDataset) sed).getDouble(pos)); 730 } 731 return es; 732 } 733} 734