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 013// GEN_COMMENT 014 015package org.eclipse.january.dataset; 016 017 018import java.util.Arrays; 019 020import org.apache.commons.math3.complex.Complex; 021 022 023/** 024 * Extend compound dataset to hold complex double values // PRIM_TYPE 025 */ 026public class ComplexDoubleDataset extends CompoundDoubleDataset { // CLASS_TYPE 027 // pin UID to base class 028 private static final long serialVersionUID = Dataset.serialVersionUID; 029 030 private static final int ISIZE = 2; // number of elements per item 031 032 @Override 033 public int getDType() { 034 return Dataset.COMPLEX128; // DATA_TYPE 035 } 036 037 /** 038 * Create a null dataset 039 */ 040 ComplexDoubleDataset() { 041 super(ISIZE); 042 } 043 044 /** 045 * Create a zero-filled dataset of given shape 046 * @param shape 047 */ 048 ComplexDoubleDataset(final int... shape) { 049 super(ISIZE, shape); 050 } 051 052 /** 053 * Create a dataset using given data (real and imaginary parts are grouped in pairs) 054 * @param data 055 * @param shape (can be null to create 1D dataset) 056 */ 057 ComplexDoubleDataset(final double[] data, final int... shape) { // PRIM_TYPE 058 super(ISIZE, data, shape); 059 } 060 061 /** 062 * Copy a dataset 063 * @param dataset 064 */ 065 ComplexDoubleDataset(final ComplexDoubleDataset dataset) { 066 super(dataset); 067 } 068 069 /** 070 * Create a dataset using given data (real and imaginary parts are given separately) 071 * @param realData 072 * @param imagData 073 * @param shape (can be null or zero-length to create 1D dataset) 074 */ 075 ComplexDoubleDataset(final double[] realData, final double[] imagData, int... shape) { // PRIM_TYPE 076 if (realData == null || imagData == null) { 077 throw new IllegalArgumentException("Data must not be null"); 078 } 079 int dsize = realData.length > imagData.length ? imagData.length : realData.length; 080 if (shape == null || shape.length == 0) { 081 shape = new int[] {dsize}; 082 } 083 isize = ISIZE; 084 size = ShapeUtils.calcSize(shape); 085 if (size != dsize) { 086 throw new IllegalArgumentException(String.format("Shape %s is not compatible with size of data array, %d", 087 Arrays.toString(shape), dsize)); 088 } 089 this.shape = size == 0 ? null : shape.clone(); 090 091 try { 092 odata = data = createArray(size); 093 } catch (Throwable t) { 094 logger.error("Could not create a dataset of shape {}", Arrays.toString(shape), t); 095 throw new IllegalArgumentException(t); 096 } 097 098 for (int i = 0, n = 0; i < size; i++) { 099 data[n++] = realData[i]; 100 data[n++] = imagData[i]; 101 } 102 } 103 104 /** 105 * Create a dataset using given data (real and imaginary parts are given separately) 106 * @param real 107 * @param imag 108 */ 109 ComplexDoubleDataset(final Dataset real, final Dataset imag) { 110 super(ISIZE, real.getShapeRef()); 111 real.checkCompatibility(imag); 112 113 IndexIterator riter = real.getIterator(); 114 IndexIterator iiter = imag.getIterator(); 115 116 for (int i = 0; riter.hasNext() && iiter.hasNext();) { 117 data[i++] = real.getElementDoubleAbs(riter.index); // ADD_CAST 118 data[i++] = imag.getElementDoubleAbs(iiter.index); // ADD_CAST 119 } 120 } 121 122 /** 123 * Copy and cast a dataset to this complex type 124 * @param dataset 125 */ 126 ComplexDoubleDataset(final Dataset dataset) { 127 super(ISIZE, dataset.getShapeRef()); 128 copyToView(dataset, this, true, false); 129 offset = 0; 130 stride = null; 131 base = null; 132 133 IndexIterator iter = dataset.getIterator(); 134 int disize = dataset.getElementsPerItem(); 135 if (disize == 1) { 136 for (int i = 0; iter.hasNext(); i += isize) { 137 data[i] = dataset.getElementDoubleAbs(iter.index); // ADD_CAST 138 } 139 } else { 140 for (int i = 0; iter.hasNext(); i += isize) { 141 data[i] = dataset.getElementDoubleAbs(iter.index); // ADD_CAST 142 data[i+1] = dataset.getElementDoubleAbs(iter.index+1); // ADD_CAST 143 } 144 } 145 } 146 147 @Override 148 public ComplexDoubleDataset clone() { 149 return new ComplexDoubleDataset(this); 150 } 151 152 /** 153 * Create a dataset from an object which could be a Java list, array (of arrays...) 154 * or Number. Ragged sequences or arrays are padded with zeros. 155 * 156 * @param obj 157 * @return dataset with contents given by input 158 */ 159 static ComplexDoubleDataset createFromObject(final Object obj) { 160 ComplexDoubleDataset result = new ComplexDoubleDataset(); 161 162 result.shape = ShapeUtils.getShapeFromObject(obj); 163 result.size = ShapeUtils.calcSize(result.shape); 164 165 try { 166 result.odata = result.data = result.createArray(result.size); 167 } catch (Throwable t) { 168 logger.error("Could not create a dataset of shape {}", Arrays.toString(result.shape), t); 169 throw new IllegalArgumentException(t); 170 } 171 172 int[] pos = new int[result.shape.length]; 173 result.fillData(obj, 0, pos); 174 return result; 175 } 176 177 /** 178 * @param stop 179 * @return a new 1D dataset, filled with values determined by parameters 180 */ 181 static ComplexDoubleDataset createRange(final double stop) { 182 return createRange(0, stop, 1); 183 } 184 185 /** 186 * @param start 187 * @param stop 188 * @param step 189 * @return a new 1D dataset, filled with values determined by parameters 190 */ 191 static ComplexDoubleDataset createRange(final double start, final double stop, final double step) { 192 int size = calcSteps(start, stop, step); 193 ComplexDoubleDataset result = new ComplexDoubleDataset(size); 194 for (int i = 0; i < size; i ++) { 195 result.data[i*ISIZE] = (start + i*step); // ADD_CAST 196 } 197 return result; 198 } 199 200 /** 201 * @param shape 202 * @return a dataset filled with ones 203 */ 204 static ComplexDoubleDataset ones(final int... shape) { 205 return new ComplexDoubleDataset(shape).fill(1); 206 } 207 208 @Override 209 public ComplexDoubleDataset fill(final Object obj) { 210 setDirty(); 211 double vr = DTypeUtils.toReal(obj); // PRIM_TYPE // ADD_CAST 212 double vi = DTypeUtils.toImag(obj); // PRIM_TYPE // ADD_CAST 213 IndexIterator iter = getIterator(); 214 215 while (iter.hasNext()) { 216 data[iter.index] = vr; 217 data[iter.index+1] = vi; 218 } 219 220 return this; 221 } 222 223 @Override 224 public ComplexDoubleDataset getView(boolean deepCopyMetadata) { 225 ComplexDoubleDataset view = new ComplexDoubleDataset(); 226 copyToView(this, view, true, deepCopyMetadata); 227 view.data = data; 228 return view; 229 } 230 231 /** 232 * Get complex value at absolute index in the internal array. 233 * 234 * This is an internal method with no checks so can be dangerous. Use with care or ideally with an iterator. 235 * 236 * @param index absolute index 237 * @return value 238 */ 239 public Complex getComplexAbs(final int index) { 240 return new Complex(data[index], data[index+1]); 241 } 242 243 @Override 244 public Object getObjectAbs(final int index) { 245 return new Complex(data[index], data[index+1]); 246 } 247 248 @Override 249 public String getStringAbs(final int index) { 250 double di = data[index + 1]; // PRIM_TYPE 251 if (stringFormat == null) { 252 return di >= 0 ? String.format("%.8g + %.8gj", data[index], di) : // FORMAT_STRING 253 String.format("%.8g - %.8gj", data[index], -di); // FORMAT_STRING 254 } 255 StringBuilder s = new StringBuilder(); 256 s.append(stringFormat.format(data[index])); 257 if (di >= 0) { 258 s.append(" + "); 259 s.append(stringFormat.format(di)); 260 } else { 261 s.append(" - "); 262 s.append(stringFormat.format(-di)); 263 } 264 s.append('j'); 265 return s.toString(); 266 } 267 268 /** 269 * Set values at absolute index in the internal array. 270 * 271 * This is an internal method with no checks so can be dangerous. Use with care or ideally with an iterator. 272 * @param index absolute index 273 * @param val new values 274 */ 275 @SuppressWarnings("cast") 276 public void setAbs(final int index, final Complex val) { 277 setAbs(index, (double) val.getReal(), (double) val.getImaginary()); // PRIM_TYPE 278 } 279 280 @SuppressWarnings("cast") 281 @Override 282 public void setObjectAbs(final int index, final Object obj) { 283 setAbs(index, (double) DTypeUtils.toReal(obj), (double) DTypeUtils.toImag(obj)); // PRIM_TYPE 284 } 285 286 /** 287 * Set item at index to complex value given by real and imaginary parts 288 * @param index absolute index 289 * @param real 290 * @param imag 291 */ 292 public void setAbs(final int index, final double real, final double imag) { // PRIM_TYPE 293 setDirty(); 294 data[index] = real; 295 data[index+1] = imag; 296 } 297 298 /** 299 * @return item in first position 300 * @since 2.0 301 */ 302 public Complex get() { 303 int n = getFirst1DIndex(); 304 Complex z = new Complex(data[n], data[n+1]); 305 return z; 306 } 307 308 /** 309 * @param i 310 * @return item in given position 311 */ 312 public Complex get(final int i) { 313 int n = get1DIndex(i); 314 Complex z = new Complex(data[n], data[n+1]); 315 return z; 316 } 317 318 /** 319 * @param i 320 * @param j 321 * @return item in given position 322 */ 323 public Complex get(final int i, final int j) { 324 int n = get1DIndex(i, j); 325 Complex z = new Complex(data[n], data[n+1]); 326 return z; 327 } 328 329 /** 330 * @param pos 331 * @return item in given position 332 */ 333 public Complex get(final int... pos) { 334 int n = get1DIndex(pos); 335 Complex z = new Complex(data[n], data[n+1]); 336 return z; 337 } 338 339 @Override 340 public Object getObject() { 341 return get(); 342 } 343 344 @Override 345 public Object getObject(final int i) { 346 return get(i); 347 } 348 349 @Override 350 public Object getObject(final int i, final int j) { 351 return get(i, j); 352 } 353 354 @Override 355 public Object getObject(final int... pos) { 356 return getComplex(pos); 357 } 358 359 /** 360 * @return item in first position 361 * @since 2.0 362 */ 363 @SuppressWarnings("cast") 364 public double getReal() { // PRIM_TYPE 365 return (double) getFirstValue(); // PRIM_TYPE 366 } 367 368 /** 369 * @param i 370 * @return item in given position 371 */ 372 @SuppressWarnings("cast") 373 public double getReal(final int i) { // PRIM_TYPE 374 return (double) getFirstValue(i); // PRIM_TYPE 375 } 376 377 /** 378 * @param i 379 * @param j 380 * @return item in given position 381 */ 382 @SuppressWarnings("cast") 383 public double getReal(final int i, final int j) { // PRIM_TYPE 384 return (double) getFirstValue(i, j); // PRIM_TYPE 385 } 386 387 /** 388 * @param pos 389 * @return item in given position 390 */ 391 @SuppressWarnings("cast") 392 public double getReal(final int... pos) { // PRIM_TYPE 393 return (double) getFirstValue(pos); // PRIM_TYPE 394 } 395 396 /** 397 * @return item in first position 398 * @since 2.0 399 */ 400 public double getImag() { // PRIM_TYPE 401 return data[getFirst1DIndex() + 1]; 402 } 403 404 /** 405 * @param i 406 * @return item in given position 407 */ 408 public double getImag(final int i) { // PRIM_TYPE 409 return data[get1DIndex(i) + 1]; 410 } 411 412 /** 413 * @param i 414 * @param j 415 * @return item in given position 416 */ 417 public double getImag(final int i, final int j) { // PRIM_TYPE 418 return data[get1DIndex(i, j) + 1]; 419 } 420 421 /** 422 * @param pos 423 * @return item in given position 424 */ 425 public double getImag(final int... pos) { // PRIM_TYPE 426 return data[get1DIndex(pos) + 1]; 427 } 428 429 /** 430 * @return item in first position 431 * @since 2.0 432 */ 433 public Complex getComplex() { 434 return get(); 435 } 436 437 /** 438 * @param i 439 * @return item in given position 440 */ 441 public Complex getComplex(final int i) { 442 return get(i); 443 } 444 445 /** 446 * @param i 447 * @param j 448 * @return item in given position 449 */ 450 public Complex getComplex(final int i, final int j) { 451 return get(i, j); 452 } 453 454 /** 455 * @param pos 456 * @return item in given position 457 */ 458 public Complex getComplex(final int... pos) { 459 return get(pos); 460 } 461 462 @SuppressWarnings("cast") 463 @Override 464 public void set(final Object obj, final int i) { 465 setItem(new double[] {(double) DTypeUtils.toReal(obj), (double) DTypeUtils.toImag(obj)}, i); // PRIM_TYPE 466 } 467 468 @SuppressWarnings("cast") 469 @Override 470 public void set(final Object obj, final int i, final int j) { 471 setItem(new double[] {(double) DTypeUtils.toReal(obj), (double) DTypeUtils.toImag(obj)}, i, j); // PRIM_TYPE 472 } 473 474 @SuppressWarnings("cast") 475 @Override 476 public void set(final Object obj, int... pos) { 477 if (pos == null || (pos.length == 0 && shape.length > 0)) { 478 pos = new int[shape.length]; 479 } 480 481 setItem(new double[] {(double) DTypeUtils.toReal(obj), (double) DTypeUtils.toImag(obj)}, pos); // PRIM_TYPE 482 } 483 484 /** 485 * Set real and imaginary values at given position 486 * @param dr 487 * @param di 488 * @param i 489 */ 490 public void set(final double dr, final double di, final int i) { // PRIM_TYPE 491 setItem(new double[] {dr, di}, i); // PRIM_TYPE 492 } 493 494 /** 495 * Set real and imaginary values at given position 496 * @param dr 497 * @param di 498 * @param i 499 * @param j 500 */ 501 public void set(final double dr, final double di, final int i, final int j) { // PRIM_TYPE 502 setItem(new double[] {dr, di}, i, j); // PRIM_TYPE 503 } 504 505 /** 506 * Set real and imaginary values at given position 507 * @param dr 508 * @param di 509 * @param pos 510 * @since 2.0 511 */ 512 public void set(final double dr, final double di, final int... pos) { // PRIM_TYPE 513 setItem(new double[] {dr, di}, pos); // PRIM_TYPE 514 } 515 516 /** 517 * @since 2.0 518 */ 519 @Override 520 public DoubleDataset getRealPart() { // CLASS_TYPE 521 return getElements(0); 522 } 523 524 /** 525 * @since 2.0 526 */ 527 @Override 528 public DoubleDataset getRealView() { // CLASS_TYPE 529 return getElementsView(0); 530 } 531 532 /** 533 * @return imaginary part of dataset as new dataset 534 * @since 2.0 535 */ 536 public DoubleDataset getImaginaryPart() { // CLASS_TYPE 537 return getElements(1); 538 } 539 540 /** 541 * @return view of imaginary values 542 */ 543 public DoubleDataset getImaginaryView() { // CLASS_TYPE 544 return getElementsView(1); 545 } 546 547 @Override 548 public Number max(boolean... switches) { 549 throw new UnsupportedOperationException("Cannot compare complex numbers"); 550 } 551 552 @Override 553 public Number min(boolean... switches) { 554 throw new UnsupportedOperationException("Cannot compare complex numbers"); 555 } 556 557 @Override 558 public Object sum(boolean... switches) { // FIXME 559 double[] sum = (double[]) super.sum(switches); 560 return new Complex(sum[0], sum[1]); 561 } 562 563 @Override 564 public Object mean(boolean... switches) { 565 double[] mean = (double[]) super.mean(switches); 566 return new Complex(mean[0], mean[1]); 567 } 568 569 @Override 570 public int[] maxPos(boolean... switches) { 571 throw new UnsupportedOperationException("Cannot compare complex numbers"); 572 } 573 574 @Override 575 public int[] minPos(boolean... switches) { 576 throw new UnsupportedOperationException("Cannot compare complex numbers"); 577 } 578 579 @Override 580 public ComplexDoubleDataset getSlice(final SliceIterator siter) { 581 ComplexDoubleDataset result = new ComplexDoubleDataset(siter.getShape()); 582 double[] rdata = result.data; // PRIM_TYPE 583 IndexIterator riter = result.getIterator(); 584 585 while (siter.hasNext() && riter.hasNext()) { 586 rdata[riter.index] = data[siter.index]; 587 rdata[riter.index+1] = data[siter.index+1]; 588 } 589 590 result.setName(name + BLOCK_OPEN + Slice.createString(siter.shape, siter.start, siter.stop, siter.step) + BLOCK_CLOSE); 591 return result; 592 } 593 594 @Override 595 ComplexDoubleDataset setSlicedView(Dataset view, Dataset d) { 596 setDirty(); 597 final BroadcastSelfIterator it = BroadcastSelfIterator.createIterator(view, d); 598 599 if (d instanceof ComplexFloatDataset || d instanceof ComplexDoubleDataset) { 600 while (it.hasNext()) { 601 data[it.aIndex] = it.bDouble; // BCAST_WITH_CAST d.getElementDoubleAbs(it.bIndex); 602 data[it.aIndex + 1] = d.getElementDoubleAbs(it.bIndex + 1); // GET_ELEMENT_WITH_CAST 603 } 604 } else { 605 while (it.hasNext()) { 606 data[it.aIndex] = it.bDouble; // BCAST_WITH_CAST d.getElementDoubleAbs(it.bIndex); 607 data[it.aIndex + 1] = 0; 608 } 609 } 610 return this; 611 } 612 613 @Override 614 public ComplexDoubleDataset setSlice(final Object o, final IndexIterator siter) { 615 setDirty(); 616 if (o instanceof ComplexFloatDataset) { 617 ComplexFloatDataset zds = (ComplexFloatDataset) o; 618 619 if (!ShapeUtils.areShapesCompatible(siter.getShape(), zds.shape)) { 620 throw new IllegalArgumentException(String.format( 621 "Input dataset is not compatible with slice: %s cf %s", Arrays.toString(zds.shape), 622 Arrays.toString(siter.getShape()))); 623 } 624 625 IndexIterator oiter = zds.getIterator(); 626 float[] odata = zds.data; 627 628 while (siter.hasNext() && oiter.hasNext()) { 629 data[siter.index] = odata[oiter.index]; 630 data[siter.index+1] = odata[oiter.index+1]; 631 } 632 } else if (o instanceof ComplexDoubleDataset) { // IGNORE_CLASS 633 ComplexDoubleDataset zds = (ComplexDoubleDataset) o; // IGNORE_CLASS 634 635 if (!ShapeUtils.areShapesCompatible(siter.getShape(), zds.shape)) { 636 throw new IllegalArgumentException(String.format( 637 "Input dataset is not compatible with slice: %s cf %s", Arrays.toString(zds.shape), 638 Arrays.toString(siter.getShape()))); 639 } 640 641 IndexIterator oiter = zds.getIterator(); 642 double[] odata = zds.data; 643 644 while (siter.hasNext() && oiter.hasNext()) { 645 data[siter.index] = odata[oiter.index]; // PRIM_TYPE // ADD_CAST 646 data[siter.index+1] = odata[oiter.index+1]; // PRIM_TYPE // ADD_CAST 647 } 648 } else if (o instanceof IDataset) { 649 super.setSlice(o, siter); 650 } else { 651 try { 652 double vr = DTypeUtils.toReal(o); // PRIM_TYPE // ADD_CAST 653 double vi = DTypeUtils.toImag(o); // PRIM_TYPE // ADD_CAST 654 655 while (siter.hasNext()) { 656 data[siter.index] = vr; 657 data[siter.index + 1] = vi; 658 } 659 } catch (IllegalArgumentException e) { 660 throw new IllegalArgumentException("Object for setting slice is not a dataset or number"); 661 } 662 } 663 return this; 664 } 665 666 @Override 667 public ComplexDoubleDataset iadd(final Object b) { 668 setDirty(); 669 Dataset bds = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); 670 boolean useLong = bds.getElementClass().equals(Long.class); 671 if (bds.getSize() == 1) { 672 final IndexIterator it = getIterator(); 673 final int bOffset = bds.getOffset(); 674 if (useLong) { // note no complex longs 675 final long lb = bds.getElementLongAbs(bOffset); 676 while (it.hasNext()) { 677 data[it.index] += lb; 678 } 679 } else { 680 final double db = bds.getElementDoubleAbs(bOffset); 681 if (!bds.isComplex() || bds.getElementDoubleAbs(bOffset + 1) == 0) { 682 while (it.hasNext()) { 683 data[it.index] += db; 684 } 685 } else { 686 final double vi = bds.getElementDoubleAbs(bOffset + 1); 687 while (it.hasNext()) { 688 data[it.index] += db; 689 data[it.index + 1] += vi; 690 } 691 } 692 } 693 } else { 694 final BroadcastSelfIterator it = BroadcastSelfIterator.createIterator(this, bds); 695 it.setOutputDouble(!useLong); 696 if (useLong) { // note no complex longs 697 while (it.hasNext()) { 698 data[it.aIndex] += it.bLong; 699 } 700 } else { 701 if (bds.isComplex()) { 702 while (it.hasNext()) { 703 data[it.aIndex] += it.bDouble; 704 data[it.aIndex + 1] += bds.getElementDoubleAbs(it.bIndex + 1); 705 } 706 } else { 707 while (it.hasNext()) { 708 data[it.aIndex] += it.bDouble; 709 } 710 } 711 } 712 } 713 return this; 714 } 715 716 @Override 717 public ComplexDoubleDataset isubtract(final Object b) { 718 setDirty(); 719 Dataset bds = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); 720 boolean useLong = bds.getElementClass().equals(Long.class); 721 if (bds.getSize() == 1) { 722 final IndexIterator it = getIterator(); 723 final int bOffset = bds.getOffset(); 724 if (useLong) { // note no complex longs 725 final long lb = bds.getElementLongAbs(bOffset); 726 while (it.hasNext()) { 727 data[it.index] -= lb; 728 } 729 } else { 730 final double db = bds.getElementDoubleAbs(bOffset); 731 if (!bds.isComplex() || bds.getElementDoubleAbs(bOffset + 1) == 0) { 732 while (it.hasNext()) { 733 data[it.index] -= db; 734 } 735 } else { 736 final double vi = bds.getElementDoubleAbs(bOffset + 1); 737 while (it.hasNext()) { 738 data[it.index] -= db; 739 data[it.index + 1] -= vi; 740 } 741 } 742 } 743 } else { 744 final BroadcastSelfIterator it = BroadcastSelfIterator.createIterator(this, bds); 745 it.setOutputDouble(!useLong); 746 if (useLong) { // note no complex longs 747 while (it.hasNext()) { 748 data[it.aIndex] -= it.bLong; 749 } 750 } else { 751 if (bds.isComplex()) { 752 while (it.hasNext()) { 753 data[it.aIndex] -= it.bDouble; 754 data[it.aIndex + 1] -= bds.getElementDoubleAbs(it.bIndex + 1); 755 } 756 } else { 757 while (it.hasNext()) { 758 data[it.aIndex] -= it.bDouble; 759 } 760 } 761 } 762 } 763 return this; 764 } 765 766 @Override 767 public ComplexDoubleDataset imultiply(final Object b) { 768 setDirty(); 769 Dataset bds = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); 770 boolean useLong = bds.getElementClass().equals(Long.class); 771 if (bds.getSize() == 1) { 772 final IndexIterator it = getIterator(); 773 final int bOffset = bds.getOffset(); 774 if (useLong) { // note no complex longs 775 final long r2 = bds.getElementLongAbs(bOffset); 776 while (it.hasNext()) { 777 data[it.index] *= r2; 778 data[it.index + 1] *= r2; 779 } 780 } else { 781 final double r2 = bds.getElementDoubleAbs(bOffset); 782 if (!bds.isComplex() || bds.getElementDoubleAbs(bOffset + 1) == 0) { 783 while (it.hasNext()) { 784 data[it.index] *= r2; 785 data[it.index + 1] *= r2; 786 } 787 } else { 788 final double i2 = bds.getElementDoubleAbs(bOffset + 1); 789 while (it.hasNext()) { 790 double r1 = data[it.index]; 791 double i1 = data[it.index + 1]; 792 data[it.index] = (r1*r2 - i1*i2); // ADD_CAST 793 data[it.index + 1] = (r1*i2 + i1*r2); // ADD_CAST 794 } 795 } 796 } 797 } else { 798 final BroadcastIterator it = BroadcastIterator.createIterator(this, bds); 799 it.setOutputDouble(!useLong); 800 if (useLong) { // note no complex longs 801 while (it.hasNext()) { 802 data[it.aIndex] *= it.bDouble; 803 data[it.aIndex + 1] *= it.bDouble; 804 } 805 } else { 806 if (bds.isComplex()) { 807 while (it.hasNext()) { 808 double r1 = it.aDouble; 809 double r2 = it.bDouble; 810 double i1 = data[it.aIndex + 1]; 811 double i2 = bds.getElementDoubleAbs(it.bIndex + 1); 812 data[it.aIndex] = (r1*r2 - i1*i2); // ADD_CAST 813 data[it.aIndex + 1] = (r1*i2 + i1*r2); // ADD_CAST 814 } 815 } else { 816 while (it.hasNext()) { 817 data[it.aIndex] *= it.bDouble; 818 data[it.aIndex + 1] *= it.bDouble; 819 } 820 } 821 } 822 } 823 return this; 824 } 825 826 @Override 827 public ComplexDoubleDataset idivide(final Object b) { 828 setDirty(); 829 Dataset bds = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); 830 boolean useLong = bds.getElementClass().equals(Long.class); 831 if (bds.getSize() == 1) { 832 final IndexIterator it = getIterator(); 833 final int bOffset = bds.getOffset(); 834 if (useLong) { // note no complex longs 835 final long r2 = bds.getElementLongAbs(bOffset); 836 while (it.hasNext()) { 837 data[it.index] /= r2; 838 data[it.index + 1] /= r2; 839 } 840 } else { 841 final double r2 = bds.getElementDoubleAbs(bOffset); 842 if (!bds.isComplex() || bds.getElementDoubleAbs(bOffset + 1) == 0) { 843 while (it.hasNext()) { 844 data[it.index] /= r2; 845 data[it.index + 1] /= r2; 846 } 847 } else { 848 final double i2 = bds.getElementDoubleAbs(bOffset + 1); 849 if (Math.abs(r2) < Math.abs(i2)) { 850 double q = r2/i2; 851 double den = r2*q + i2; 852 while (it.hasNext()) { 853 double r1 = data[it.index]; 854 double i1 = data[it.index + 1]; 855 data[it.index] = ((r1*q + i1) / den); // ADD_CAST 856 data[it.index + 1] = ((i1*q - r1) / den); // ADD_CAST 857 } 858 } else { 859 double q = i2/r2; 860 double den = i2*q + r2; 861 if (den == 0) { 862 while (it.hasNext()) { 863 data[it.index] = Double.NaN; // CLASS_TYPE 864 data[it.index + 1] = Double.NaN; // CLASS_TYPE 865 } 866 } else { 867 while (it.hasNext()) { 868 double r1 = data[it.index]; 869 double i1 = data[it.index + 1]; 870 data[it.index] = ((i1 * q + r1) / den); // ADD_CAST 871 data[it.index + 1] = ((i1 - r1 * q) / den); // ADD_CAST 872 } 873 } 874 } 875 } 876 } 877 } else { 878 final BroadcastIterator it = BroadcastIterator.createIterator(this, bds); 879 it.setOutputDouble(!useLong); 880 if (useLong) { 881 while (it.hasNext()) { 882 data[it.aIndex] /= it.bLong; 883 data[it.aIndex + 1] /= it.bLong; 884 } 885 } else { 886 if (bds.isComplex()) { 887 while (it.hasNext()) { 888 double r1 = it.aDouble; 889 double r2 = it.bDouble; 890 double i1 = data[it.aIndex + 1]; 891 double i2 = bds.getElementDoubleAbs(it.bIndex + 1); 892 if (Math.abs(r2) < Math.abs(i2)) { 893 double q = r2/i2; 894 double den = r2*q + i2; 895 data[it.aIndex] = ((r1*q + i1) / den); // ADD_CAST 896 data[it.aIndex + 1] = ((i1*q - r1) / den); // ADD_CAST 897 } else { 898 double q = i2/r2; 899 double den = i2*q + r2; 900 if (den == 0) { 901 data[it.aIndex] = Double.NaN; // CLASS_TYPE 902 data[it.aIndex + 1] = Double.NaN; // CLASS_TYPE 903 } else { 904 data[it.aIndex] = ((i1 * q + r1) / den); // ADD_CAST 905 data[it.aIndex + 1] = ((i1 - r1 * q) / den); // ADD_CAST 906 } 907 } 908 } 909 } else { 910 while (it.hasNext()) { 911 data[it.aIndex] /= it.bDouble; 912 data[it.aIndex + 1] /= it.bDouble; 913 } 914 } 915 } 916 } 917 return this; 918 } 919 920 @Override 921 public ComplexDoubleDataset iremainder(final Object b) { 922 throw new UnsupportedOperationException("Unsupported method for class"); 923 } 924 925 @Override 926 public ComplexDoubleDataset ipower(final Object b) { 927 setDirty(); 928 Dataset bds = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); 929 if (bds.getSize() == 1) { 930 final IndexIterator it = getIterator(); 931 final int bOffset = bds.getOffset(); 932 final double r2 = bds.getElementDoubleAbs(bOffset); 933 if (!bds.isComplex() || bds.getElementDoubleAbs(bOffset + 1) == 0) { 934 while (it.hasNext()) { 935 final Complex zd = new Complex(data[it.index], data[it.index + 1]).pow(r2); 936 data[it.index] = zd.getReal(); // ADD_CAST 937 data[it.index + 1] = zd.getImaginary(); // ADD_CAST 938 } 939 } else { 940 final Complex zv = new Complex(r2, bds.getElementDoubleAbs(bOffset + 1)); 941 while (it.hasNext()) { 942 final Complex zd = new Complex(data[it.index], data[it.index + 1]).pow(zv); 943 data[it.index] = zd.getReal(); // ADD_CAST 944 data[it.index + 1] = zd.getImaginary(); // ADD_CAST 945 } 946 } 947 } else { 948 final BroadcastIterator it = BroadcastIterator.createIterator(this, bds); 949 it.setOutputDouble(true); 950 if (bds.isComplex()) { 951 while (it.hasNext()) { 952 final Complex zv = new Complex(it.bDouble, bds.getElementDoubleAbs(it.bIndex + 1)); 953 final Complex zd = new Complex(it.aDouble, data[it.aIndex + 1]).pow(zv); 954 data[it.aIndex] = zd.getReal(); // ADD_CAST 955 data[it.aIndex + 1] = zd.getImaginary(); // ADD_CAST 956 } 957 } else { 958 while (it.hasNext()) { 959 final Complex zd = new Complex(it.aDouble, data[it.aIndex + 1]).pow(it.bDouble); 960 data[it.aIndex] = zd.getReal(); // ADD_CAST 961 data[it.aIndex + 1] = zd.getImaginary(); // ADD_CAST 962 } 963 } 964 } 965 return this; 966 } 967 968 @Override 969 public double residual(final Object b, Dataset w, boolean ignoreNaNs) { 970 Dataset bds = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); 971 final BroadcastIterator it = BroadcastIterator.createIterator(this, bds); 972 it.setOutputDouble(true); 973 double sum = 0; 974 double comp = 0; 975 final int bis = bds.getElementsPerItem(); 976 977 if (bis == 1) { 978 if (w == null) { 979 while (it.hasNext()) { 980 double diffr = it.aDouble - it.bDouble; 981 double diffi = data[it.aIndex + 1]; 982 if (ignoreNaNs && (Double.isNaN(diffr) || Double.isNaN(diffi))) { 983 continue; 984 } 985 double err = diffr * diffr - comp; 986 double temp = sum + err; 987 comp = (temp - sum) - err; 988 sum = temp; 989 990 err = diffi * diffi - comp; 991 temp = sum + err; 992 comp = (temp - sum) - err; 993 sum = temp; 994 } 995 } else { 996 IndexIterator itw = w.getIterator(); 997 while (it.hasNext() && itw.hasNext()) { 998 final double dw = w.getElementDoubleAbs(itw.index); 999 double diffr = it.aDouble - it.bDouble; 1000 double diffi = data[it.aIndex + 1]; 1001 if (ignoreNaNs && (Double.isNaN(diffr) || Double.isNaN(diffi))) { 1002 continue; 1003 } 1004 double err = diffr * diffr * dw - comp; 1005 double temp = sum + err; 1006 comp = (temp - sum) - err; 1007 sum = temp; 1008 1009 err = diffi * diffi * dw - comp; 1010 temp = sum + err; 1011 comp = (temp - sum) - err; 1012 sum = temp; 1013 } 1014 } 1015 } else { 1016 if (w == null) { 1017 while (it.hasNext()) { 1018 double diffr = it.aDouble - it.bDouble; 1019 double diffi = data[it.aIndex] - bds.getElementDoubleAbs(it.bIndex + 1); 1020 if (ignoreNaNs && (Double.isNaN(diffr) || Double.isNaN(diffi))) { 1021 continue; 1022 } 1023 double err = diffr * diffr - comp; 1024 double temp = sum + err; 1025 comp = (temp - sum) - err; 1026 sum = temp; 1027 1028 err = diffi * diffi - comp; 1029 temp = sum + err; 1030 comp = (temp - sum) - err; 1031 sum = temp; 1032 } 1033 } else { 1034 IndexIterator itw = w.getIterator(); 1035 while (it.hasNext() && itw.hasNext()) { 1036 final double dw = w.getElementDoubleAbs(itw.index); 1037 double diffr = it.aDouble - it.bDouble; 1038 double diffi = data[it.aIndex] - bds.getElementDoubleAbs(it.bIndex + 1); 1039 if (ignoreNaNs && (Double.isNaN(diffr) || Double.isNaN(diffi))) { 1040 continue; 1041 } 1042 double err = diffr * diffr * dw - comp; 1043 double temp = sum + err; 1044 comp = (temp - sum) - err; 1045 sum = temp; 1046 1047 err = diffi * diffi * dw - comp; 1048 temp = sum + err; 1049 comp = (temp - sum) - err; 1050 sum = temp; 1051 } 1052 } 1053 } 1054 return sum; 1055 } 1056}