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