    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}