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}