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