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 if (useLong) { // note no complex longs 674 final long lb = bds.getElementLongAbs(0); 675 while (it.hasNext()) { 676 data[it.index] += lb; 677 } 678 } else { 679 final double db = bds.getElementDoubleAbs(0); 680 if (!bds.isComplex() || bds.getElementDoubleAbs(1) == 0) { 681 while (it.hasNext()) { 682 data[it.index] += db; 683 } 684 } else { 685 final double vi = bds.getElementDoubleAbs(1); 686 while (it.hasNext()) { 687 data[it.index] += db; 688 data[it.index + 1] += vi; 689 } 690 } 691 } 692 } else { 693 final BroadcastSelfIterator it = BroadcastSelfIterator.createIterator(this, bds); 694 it.setOutputDouble(!useLong); 695 if (useLong) { // note no complex longs 696 while (it.hasNext()) { 697 data[it.aIndex] += it.bLong; 698 } 699 } else { 700 if (bds.isComplex()) { 701 while (it.hasNext()) { 702 data[it.aIndex] += it.bDouble; 703 data[it.aIndex + 1] += bds.getElementDoubleAbs(it.bIndex + 1); 704 } 705 } else { 706 while (it.hasNext()) { 707 data[it.aIndex] += it.bDouble; 708 } 709 } 710 } 711 } 712 return this; 713 } 714 715 @Override 716 public ComplexDoubleDataset isubtract(final Object b) { 717 setDirty(); 718 Dataset bds = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); 719 boolean useLong = bds.getElementClass().equals(Long.class); 720 if (bds.getSize() == 1) { 721 final IndexIterator it = getIterator(); 722 if (useLong) { // note no complex longs 723 final long lb = bds.getElementLongAbs(0); 724 while (it.hasNext()) { 725 data[it.index] -= lb; 726 } 727 } else { 728 final double db = bds.getElementDoubleAbs(0); 729 if (!bds.isComplex() || bds.getElementDoubleAbs(1) == 0) { 730 while (it.hasNext()) { 731 data[it.index] -= db; 732 } 733 } else { 734 final double vi = bds.getElementDoubleAbs(1); 735 while (it.hasNext()) { 736 data[it.index] -= db; 737 data[it.index + 1] -= vi; 738 } 739 } 740 } 741 } else { 742 final BroadcastSelfIterator it = BroadcastSelfIterator.createIterator(this, bds); 743 it.setOutputDouble(!useLong); 744 if (useLong) { // note no complex longs 745 while (it.hasNext()) { 746 data[it.aIndex] -= it.bLong; 747 } 748 } else { 749 if (bds.isComplex()) { 750 while (it.hasNext()) { 751 data[it.aIndex] -= it.bDouble; 752 data[it.aIndex + 1] -= bds.getElementDoubleAbs(it.bIndex + 1); 753 } 754 } else { 755 while (it.hasNext()) { 756 data[it.aIndex] -= it.bDouble; 757 } 758 } 759 } 760 } 761 return this; 762 } 763 764 @Override 765 public ComplexDoubleDataset imultiply(final Object b) { 766 setDirty(); 767 Dataset bds = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); 768 boolean useLong = bds.getElementClass().equals(Long.class); 769 if (bds.getSize() == 1) { 770 final IndexIterator it = getIterator(); 771 if (useLong) { // note no complex longs 772 final long r2 = bds.getElementLongAbs(0); 773 while (it.hasNext()) { 774 data[it.index] *= r2; 775 data[it.index + 1] *= r2; 776 } 777 } else { 778 final double r2 = bds.getElementDoubleAbs(0); 779 if (!bds.isComplex() || bds.getElementDoubleAbs(1) == 0) { 780 while (it.hasNext()) { 781 data[it.index] *= r2; 782 data[it.index + 1] *= r2; 783 } 784 } else { 785 final double i2 = bds.getElementDoubleAbs(1); 786 while (it.hasNext()) { 787 double r1 = data[it.index]; 788 double i1 = data[it.index + 1]; 789 data[it.index] = (r1*r2 - i1*i2); // ADD_CAST 790 data[it.index + 1] = (r1*i2 + i1*r2); // ADD_CAST 791 } 792 } 793 } 794 } else { 795 final BroadcastIterator it = BroadcastIterator.createIterator(this, bds); 796 it.setOutputDouble(!useLong); 797 if (useLong) { // note no complex longs 798 while (it.hasNext()) { 799 data[it.aIndex] *= it.bDouble; 800 data[it.aIndex + 1] *= it.bDouble; 801 } 802 } else { 803 if (bds.isComplex()) { 804 while (it.hasNext()) { 805 double r1 = it.aDouble; 806 double r2 = it.bDouble; 807 double i1 = data[it.aIndex + 1]; 808 double i2 = bds.getElementDoubleAbs(it.bIndex + 1); 809 data[it.aIndex] = (r1*r2 - i1*i2); // ADD_CAST 810 data[it.aIndex + 1] = (r1*i2 + i1*r2); // ADD_CAST 811 } 812 } else { 813 while (it.hasNext()) { 814 data[it.aIndex] *= it.bDouble; 815 data[it.aIndex + 1] *= it.bDouble; 816 } 817 } 818 } 819 } 820 return this; 821 } 822 823 @Override 824 public ComplexDoubleDataset idivide(final Object b) { 825 setDirty(); 826 Dataset bds = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); 827 boolean useLong = bds.getElementClass().equals(Long.class); 828 if (bds.getSize() == 1) { 829 final IndexIterator it = getIterator(); 830 if (useLong) { // note no complex longs 831 final long r2 = bds.getElementLongAbs(0); 832 while (it.hasNext()) { 833 data[it.index] /= r2; 834 data[it.index + 1] /= r2; 835 } 836 } else { 837 final double r2 = bds.getElementDoubleAbs(0); 838 if (!bds.isComplex() || bds.getElementDoubleAbs(1) == 0) { 839 while (it.hasNext()) { 840 data[it.index] /= r2; 841 data[it.index + 1] /= r2; 842 } 843 } else { 844 final double i2 = bds.getElementDoubleAbs(1); 845 if (Math.abs(r2) < Math.abs(i2)) { 846 double q = r2/i2; 847 double den = r2*q + i2; 848 while (it.hasNext()) { 849 double r1 = data[it.index]; 850 double i1 = data[it.index + 1]; 851 data[it.index] = ((r1*q + i1) / den); // ADD_CAST 852 data[it.index + 1] = ((i1*q - r1) / den); // ADD_CAST 853 } 854 } else { 855 double q = i2/r2; 856 double den = i2*q + r2; 857 if (den == 0) { 858 while (it.hasNext()) { 859 data[it.index] = Double.NaN; // CLASS_TYPE 860 data[it.index + 1] = Double.NaN; // CLASS_TYPE 861 } 862 } else { 863 while (it.hasNext()) { 864 double r1 = data[it.index]; 865 double i1 = data[it.index + 1]; 866 data[it.index] = ((i1 * q + r1) / den); // ADD_CAST 867 data[it.index + 1] = ((i1 - r1 * q) / den); // ADD_CAST 868 } 869 } 870 } 871 } 872 } 873 } else { 874 final BroadcastIterator it = BroadcastIterator.createIterator(this, bds); 875 it.setOutputDouble(!useLong); 876 if (useLong) { 877 while (it.hasNext()) { 878 data[it.aIndex] /= it.bLong; 879 data[it.aIndex + 1] /= it.bLong; 880 } 881 } else { 882 if (bds.isComplex()) { 883 while (it.hasNext()) { 884 double r1 = it.aDouble; 885 double r2 = it.bDouble; 886 double i1 = data[it.aIndex + 1]; 887 double i2 = bds.getElementDoubleAbs(it.bIndex + 1); 888 if (Math.abs(r2) < Math.abs(i2)) { 889 double q = r2/i2; 890 double den = r2*q + i2; 891 data[it.aIndex] = ((r1*q + i1) / den); // ADD_CAST 892 data[it.aIndex + 1] = ((i1*q - r1) / den); // ADD_CAST 893 } else { 894 double q = i2/r2; 895 double den = i2*q + r2; 896 if (den == 0) { 897 data[it.aIndex] = Double.NaN; // CLASS_TYPE 898 data[it.aIndex + 1] = Double.NaN; // CLASS_TYPE 899 } else { 900 data[it.aIndex] = ((i1 * q + r1) / den); // ADD_CAST 901 data[it.aIndex + 1] = ((i1 - r1 * q) / den); // ADD_CAST 902 } 903 } 904 } 905 } else { 906 while (it.hasNext()) { 907 data[it.aIndex] /= it.bDouble; 908 data[it.aIndex + 1] /= it.bDouble; 909 } 910 } 911 } 912 } 913 return this; 914 } 915 916 @Override 917 public ComplexDoubleDataset iremainder(final Object b) { 918 throw new UnsupportedOperationException("Unsupported method for class"); 919 } 920 921 @Override 922 public ComplexDoubleDataset ipower(final Object b) { 923 setDirty(); 924 Dataset bds = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); 925 if (bds.getSize() == 1) { 926 final IndexIterator it = getIterator(); 927 final double r2 = bds.getElementDoubleAbs(0); 928 if (!bds.isComplex() || bds.getElementDoubleAbs(1) == 0) { 929 while (it.hasNext()) { 930 final Complex zd = new Complex(data[it.index], data[it.index + 1]).pow(r2); 931 data[it.index] = zd.getReal(); // ADD_CAST 932 data[it.index + 1] = zd.getImaginary(); // ADD_CAST 933 } 934 } else { 935 final Complex zv = new Complex(r2, bds.getElementDoubleAbs(1)); 936 while (it.hasNext()) { 937 final Complex zd = new Complex(data[it.index], data[it.index + 1]).pow(zv); 938 data[it.index] = zd.getReal(); // ADD_CAST 939 data[it.index + 1] = zd.getImaginary(); // ADD_CAST 940 } 941 } 942 } else { 943 final BroadcastIterator it = BroadcastIterator.createIterator(this, bds); 944 it.setOutputDouble(true); 945 if (bds.isComplex()) { 946 while (it.hasNext()) { 947 final Complex zv = new Complex(it.bDouble, bds.getElementDoubleAbs(it.bIndex + 1)); 948 final Complex zd = new Complex(it.aDouble, data[it.aIndex + 1]).pow(zv); 949 data[it.aIndex] = zd.getReal(); // ADD_CAST 950 data[it.aIndex + 1] = zd.getImaginary(); // ADD_CAST 951 } 952 } else { 953 while (it.hasNext()) { 954 final Complex zd = new Complex(it.aDouble, data[it.aIndex + 1]).pow(it.bDouble); 955 data[it.aIndex] = zd.getReal(); // ADD_CAST 956 data[it.aIndex + 1] = zd.getImaginary(); // ADD_CAST 957 } 958 } 959 } 960 return this; 961 } 962 963 @Override 964 public double residual(final Object b, Dataset w, boolean ignoreNaNs) { 965 Dataset bds = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); 966 final BroadcastIterator it = BroadcastIterator.createIterator(this, bds); 967 it.setOutputDouble(true); 968 double sum = 0; 969 double comp = 0; 970 final int bis = bds.getElementsPerItem(); 971 972 if (bis == 1) { 973 if (w == null) { 974 while (it.hasNext()) { 975 double diffr = it.aDouble - it.bDouble; 976 double diffi = data[it.aIndex + 1]; 977 if (ignoreNaNs && (Double.isNaN(diffr) || Double.isNaN(diffi))) { 978 continue; 979 } 980 double err = diffr * diffr - comp; 981 double temp = sum + err; 982 comp = (temp - sum) - err; 983 sum = temp; 984 985 err = diffi * diffi - comp; 986 temp = sum + err; 987 comp = (temp - sum) - err; 988 sum = temp; 989 } 990 } else { 991 IndexIterator itw = w.getIterator(); 992 while (it.hasNext() && itw.hasNext()) { 993 final double dw = w.getElementDoubleAbs(itw.index); 994 double diffr = it.aDouble - it.bDouble; 995 double diffi = data[it.aIndex + 1]; 996 if (ignoreNaNs && (Double.isNaN(diffr) || Double.isNaN(diffi))) { 997 continue; 998 } 999 double err = diffr * diffr * dw - comp; 1000 double temp = sum + err; 1001 comp = (temp - sum) - err; 1002 sum = temp; 1003 1004 err = diffi * diffi * dw - comp; 1005 temp = sum + err; 1006 comp = (temp - sum) - err; 1007 sum = temp; 1008 } 1009 } 1010 } else { 1011 if (w == null) { 1012 while (it.hasNext()) { 1013 double diffr = it.aDouble - it.bDouble; 1014 double diffi = data[it.aIndex] - bds.getElementDoubleAbs(it.bIndex + 1); 1015 if (ignoreNaNs && (Double.isNaN(diffr) || Double.isNaN(diffi))) { 1016 continue; 1017 } 1018 double err = diffr * diffr - comp; 1019 double temp = sum + err; 1020 comp = (temp - sum) - err; 1021 sum = temp; 1022 1023 err = diffi * diffi - comp; 1024 temp = sum + err; 1025 comp = (temp - sum) - err; 1026 sum = temp; 1027 } 1028 } else { 1029 IndexIterator itw = w.getIterator(); 1030 while (it.hasNext() && itw.hasNext()) { 1031 final double dw = w.getElementDoubleAbs(itw.index); 1032 double diffr = it.aDouble - it.bDouble; 1033 double diffi = data[it.aIndex] - bds.getElementDoubleAbs(it.bIndex + 1); 1034 if (ignoreNaNs && (Double.isNaN(diffr) || Double.isNaN(diffi))) { 1035 continue; 1036 } 1037 double err = diffr * diffr * dw - comp; 1038 double temp = sum + err; 1039 comp = (temp - sum) - err; 1040 sum = temp; 1041 1042 err = diffi * diffi * dw - comp; 1043 temp = sum + err; 1044 comp = (temp - sum) - err; 1045 sum = temp; 1046 } 1047 } 1048 } 1049 return sum; 1050 } 1051}