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
017import java.util.ArrayList;
018import java.util.Arrays;
019import java.util.List;
020import java.util.Set;
021import java.util.TreeSet;
022
023import org.apache.commons.math3.complex.Complex; // NAN_OMIT
024import org.eclipse.january.metadata.StatisticsMetadata;
025import org.slf4j.Logger;
026import org.slf4j.LoggerFactory;
027
028
029/**
030 * Extend dataset for double values // PRIM_TYPE
031 */
032public class DoubleDataset extends AbstractDataset {
033        // pin UID to base class
034        private static final long serialVersionUID = Dataset.serialVersionUID;
035
036        private static final Logger logger = LoggerFactory.getLogger(DoubleDataset.class);
037
038        protected double[] data; // subclass alias // PRIM_TYPE
039
040        @Override
041        protected void setData() {
042                data = (double[]) odata; // PRIM_TYPE
043        }
044
045        protected static double[] createArray(final int size) { // PRIM_TYPE
046                double[] array = null; // PRIM_TYPE
047
048                try {
049                        array = new double[size]; // PRIM_TYPE
050                } catch (OutOfMemoryError e) {
051                        logger.error("The size of the dataset ({}) that is being created is too large "
052                                        + "and there is not enough memory to hold it.", size);
053                        throw new OutOfMemoryError("The dimensions given are too large, and there is "
054                                        + "not enough memory available in the Java Virtual Machine");
055                }
056                return array;
057        }
058
059        /**
060         * Create a null dataset
061         */
062        DoubleDataset() {
063        }
064
065        /**
066         * Create a zero-filled dataset of given shape
067         * @param shape
068         */
069        DoubleDataset(final int... shape) {
070                if (shape != null) {
071                        size = ShapeUtils.calcSize(shape);
072                        this.shape = shape.clone();
073        
074                        try {
075                                odata = data = createArray(size);
076                        } catch (Throwable t) {
077                                logger.error("Could not create a dataset of shape {}", Arrays.toString(shape), t);
078                                throw new IllegalArgumentException(t);
079                        }
080                }
081        }
082
083        /**
084         * Create a dataset using given data
085         * @param data
086         * @param shape
087         *            (can be null to create 1D dataset)
088         */
089        DoubleDataset(final double[] data, int... shape) { // PRIM_TYPE
090                if (data == null) {
091                        throw new IllegalArgumentException("Data must not be null");
092                }
093                if (shape == null || shape.length == 0) {
094                        shape = new int[] { data.length };
095                }
096                size = ShapeUtils.calcSize(shape);
097                if (size != data.length) {
098                        throw new IllegalArgumentException(String.format("Shape %s is not compatible with size of data array, %d",
099                                        Arrays.toString(shape), data.length));
100                }
101                this.shape = size == 0 ? null : shape.clone();
102
103                odata = this.data = data;
104        }
105
106        /**
107         * Copy a dataset
108         * @param dataset
109         */
110        DoubleDataset(final DoubleDataset dataset) {
111                copyToView(dataset, this, true, true);
112
113                try {
114                        if (dataset.stride == null) {
115                                if (dataset.data != null) {
116                                        odata = data = dataset.data.clone();
117                                }
118                        } else {
119                                offset = 0;
120                                stride = null;
121                                base = null;
122                                odata = data = createArray(size);
123
124                                IndexIterator iter = dataset.getIterator();
125                                for (int i = 0; iter.hasNext(); i++) {
126                                        data[i] = dataset.data[iter.index];
127                                }
128                        }
129                } catch (Throwable t) {
130                        logger.error("Could not create a dataset of shape {}", Arrays.toString(shape), t);
131                        throw new IllegalArgumentException(t);
132                }
133        }
134
135        /**
136         * Copy and cast a dataset to this class type
137         * @param dataset
138         */
139        DoubleDataset(final Dataset dataset) {
140                copyToView(dataset, this, true, false);
141                offset = 0;
142                stride = null;
143                base = null;
144                try {
145                        odata = data = createArray(size);
146                } catch (Throwable t) {
147                        logger.error("Could not create a dataset of shape {}", Arrays.toString(shape), t);
148                        throw new IllegalArgumentException(t);
149                }
150                IndexIterator iter = dataset.getIterator();
151                for (int i = 0; iter.hasNext(); i++) {
152                        data[i] = dataset.getElementDoubleAbs(iter.index); // GET_ELEMENT_WITH_CAST
153                }
154        }
155
156        @Override
157        public boolean equals(Object obj) {
158                if (this == obj) {
159                        return true;
160                }
161
162                if (obj == null) {
163                        return false;
164                }
165
166                if (!getClass().equals(obj.getClass())) {
167                        if (getRank() == 0) { // for zero-rank datasets
168                                return obj.equals(getObjectAbs(offset));
169                        }
170                        return false;
171                }
172
173                DoubleDataset other = (DoubleDataset) obj;
174                if (size != other.size) {
175                        return false;
176                }
177                if (!Arrays.equals(shape, other.shape)) {
178                        return false;
179                }
180                if (data == other.data && stride == null && other.stride == null) {
181                        return true;
182                }
183
184                IndexIterator iter = getIterator();
185                IndexIterator oiter = other.getIterator();
186                while (iter.hasNext() && oiter.hasNext()) {
187                        if (data[iter.index] != other.data[oiter.index]) { // OBJECT_UNEQUAL
188                                return false;
189                        }
190                }
191                return true;
192        }
193
194        @Override
195        public int hashCode() {
196                return super.hashCode();
197        }
198
199        @Override
200        public DoubleDataset clone() {
201                return new DoubleDataset(this);
202        }
203
204        /**
205         * Create a dataset from an object which could be a Java list, array (of arrays...) or Number. Ragged
206         * sequences or arrays are padded with zeros.
207         * 
208         * @param obj
209         * @return dataset with contents given by input
210         */
211        static DoubleDataset createFromObject(final Object obj) {
212                DoubleDataset result = new DoubleDataset();
213
214                if (obj != null) {
215                        result.shape = ShapeUtils.getShapeFromObject(obj);
216                        result.size = ShapeUtils.calcSize(result.shape);
217        
218                        try {
219                                result.odata = result.data = createArray(result.size);
220                        } catch (Throwable t) {
221                                logger.error("Could not create a dataset of shape {}", Arrays.toString(result.shape), t);
222                                throw new IllegalArgumentException(t);
223                        }
224        
225                        int[] pos = new int[result.shape.length];
226                        result.fillData(obj, 0, pos);
227                }
228
229                return result;
230        }
231         // NAN_OMIT
232        /** // NAN_OMIT
233         * // NAN_OMIT
234         * @param stop // NAN_OMIT
235         * @return a new 1D dataset, filled with values determined by parameters // NAN_OMIT
236         */ // NAN_OMIT
237        static DoubleDataset createRange(final double stop) { // NAN_OMIT
238                return createRange(0, stop, 1); // NAN_OMIT
239        } // NAN_OMIT
240         // NAN_OMIT
241        /** // NAN_OMIT
242         * // NAN_OMIT
243         * @param start // NAN_OMIT
244         * @param stop // NAN_OMIT
245         * @param step // NAN_OMIT
246         * @return a new 1D dataset, filled with values determined by parameters // NAN_OMIT
247         */ // NAN_OMIT
248        static DoubleDataset createRange(final double start, final double stop, final double step) { // NAN_OMIT
249                int size = calcSteps(start, stop, step); // NAN_OMIT
250                DoubleDataset result = new DoubleDataset(size); // NAN_OMIT
251                for (int i = 0; i < size; i++) { // NAN_OMIT
252                        result.data[i] = (start + i * step); // PRIM_TYPE // NAN_OMIT // ADD_CAST
253                } // NAN_OMIT
254                return result; // NAN_OMIT
255        } // NAN_OMIT
256
257        /**
258         * @param shape
259         * @return a dataset filled with ones
260         */
261        static DoubleDataset ones(final int... shape) {
262                return new DoubleDataset(shape).fill(1);
263        }
264
265        @Override
266        public DoubleDataset fill(final Object obj) {
267                setDirty();
268                double dv = DTypeUtils.toReal(obj); // PRIM_TYPE // FROM_OBJECT
269                IndexIterator iter = getIterator();
270                while (iter.hasNext()) {
271                        data[iter.index] = dv;
272                }
273
274                return this;
275        }
276
277        /**
278         * This is a typed version of {@link #getBuffer()}
279         * @return data buffer as linear array
280         */
281        public double[] getData() { // PRIM_TYPE
282                return data;
283        }
284
285        @Override
286        protected int getBufferLength() {
287                if (data == null)
288                        return 0;
289                return data.length;
290        }
291
292        @Override
293        public DoubleDataset getView(boolean deepCopyMetadata) {
294                DoubleDataset view = new DoubleDataset();
295                copyToView(this, view, true, deepCopyMetadata);
296                view.setData();
297                return view;
298        }
299
300        /**
301         * Get a value from an absolute index of the internal array. This is an internal method with no checks so can be
302         * dangerous. Use with care or ideally with an iterator.
303         * 
304         * @param index
305         *            absolute index
306         * @return value
307         */
308        public double getAbs(final int index) { // PRIM_TYPE
309                return data[index];
310        }
311
312        @Override
313        public boolean getElementBooleanAbs(final int index) {
314                return data[index] != 0; // BOOLEAN_FALSE
315        }
316
317        @Override
318        public double getElementDoubleAbs(final int index) {
319                return data[index]; // BOOLEAN_ZERO
320        }
321
322        @Override
323        public long getElementLongAbs(final int index) {
324                return DTypeUtils.toLong(data[index]); // BOOLEAN_ZERO // OMIT_TOLONG_INT
325        }
326
327        @Override
328        public Object getObjectAbs(final int index) {
329                return data[index];
330        }
331
332        @Override
333        public String getStringAbs(final int index) {
334                return stringFormat == null ? String.format("%.8g", data[index]) : // FORMAT_STRING
335                        stringFormat.format(data[index]);
336        }
337
338        /**
339         * Set a value at absolute index in the internal array. This is an internal method with no checks so can be
340         * dangerous. Use with care or ideally with an iterator.
341         * 
342         * @param index
343         *            absolute index
344         * @param val
345         *            new value
346         */
347        public void setAbs(final int index, final double val) { // PRIM_TYPE
348                setDirty();
349                data[index] = val;
350        }
351
352        @Override
353        protected void setItemDirect(final int dindex, final int sindex, final Object src) {
354                setDirty();
355                double[] dsrc = (double[]) src; // PRIM_TYPE
356                data[dindex] = dsrc[sindex];
357        }
358
359        @Override
360        public void setObjectAbs(final int index, final Object obj) {
361                if (index < 0 || index > data.length) {
362                        throw new IndexOutOfBoundsException("Index given is outside dataset");
363                }
364
365                setAbs(index, DTypeUtils.toReal(obj)); // FROM_OBJECT
366        }
367
368        /**
369         * @return item in first position
370         * @since 2.0
371         */
372        public double get() { // PRIM_TYPE
373                return data[getFirst1DIndex()];
374        }
375
376        /**
377         * @param i position in first dimension
378         * @return item in given position
379         */
380        public double get(final int i) { // PRIM_TYPE
381                return data[get1DIndex(i)];
382        }
383
384        /**
385         * @param i position in first dimension
386         * @param j position in second dimension
387         * @return item in given position
388         */
389        public double get(final int i, final int j) { // PRIM_TYPE
390                return data[get1DIndex(i, j)];
391        }
392
393        /**
394         * @param pos position
395         * @return item in given position
396         */
397        public double get(final int... pos) { // PRIM_TYPE
398                return data[get1DIndex(pos)];
399        }
400
401        @Override
402        public Object getObject() {
403                return Double.valueOf(get()); // CLASS_TYPE
404        }
405
406        @Override
407        public Object getObject(final int i) {
408                return Double.valueOf(get(i)); // CLASS_TYPE
409        }
410
411        @Override
412        public Object getObject(final int i, final int j) {
413                return Double.valueOf(get(i, j)); // CLASS_TYPE
414        }
415
416        @Override
417        public Object getObject(final int... pos) {
418                return Double.valueOf(get(pos)); // CLASS_TYPE
419        }
420
421        @Override
422        public String getString() {
423                return getStringAbs(getFirst1DIndex());
424        }
425
426        @Override
427        public String getString(final int i) {
428                return getStringAbs(get1DIndex(i));
429        }
430
431        @Override
432        public String getString(final int i, final int j) {
433                return getStringAbs(get1DIndex(i, j));
434        }
435
436        @Override
437        public String getString(final int... pos) {
438                return getStringAbs(get1DIndex(pos));
439        }
440
441        @Override
442        public double getDouble() {
443                return get(); // BOOLEAN_ZERO
444        }
445
446        @Override
447        public double getDouble(final int i) {
448                return get(i); // BOOLEAN_ZERO
449        }
450
451        @Override
452        public double getDouble(final int i, final int j) {
453                return get(i, j); // BOOLEAN_ZERO
454        }
455
456        @Override
457        public double getDouble(final int... pos) {
458                return get(pos); // BOOLEAN_ZERO
459        }
460
461        @Override
462        public float getFloat() {
463                return (float) get(); // BOOLEAN_ZERO // OMIT_REAL_CAST
464        }
465
466        @Override
467        public float getFloat(final int i) {
468                return (float) get(i); // BOOLEAN_ZERO // OMIT_REAL_CAST
469        }
470
471        @Override
472        public float getFloat(final int i, final int j) {
473                return (float) get(i, j); // BOOLEAN_ZERO // OMIT_REAL_CAST
474        }
475
476        @Override
477        public float getFloat(final int... pos) {
478                return (float) get(pos); // BOOLEAN_ZERO // OMIT_REAL_CAST
479        }
480
481        @Override
482        public long getLong() {
483                return (long) get(); // BOOLEAN_ZERO // OMIT_UPCAST
484        }
485
486        @Override
487        public long getLong(final int i) {
488                return (long) get(i); // BOOLEAN_ZERO // OMIT_UPCAST
489        }
490
491        @Override
492        public long getLong(final int i, final int j) {
493                return (long) get(i, j); // BOOLEAN_ZERO // OMIT_UPCAST
494        }
495
496        @Override
497        public long getLong(final int... pos) {
498                return (long) get(pos); // BOOLEAN_ZERO // OMIT_UPCAST
499        }
500
501        @Override
502        public int getInt() {
503                return (int) get(); // BOOLEAN_ZERO // OMIT_UPCAST
504        }
505
506        @Override
507        public int getInt(final int i) {
508                return (int) get(i); // BOOLEAN_ZERO // OMIT_UPCAST
509        }
510
511        @Override
512        public int getInt(final int i, final int j) {
513                return (int) get(i, j); // BOOLEAN_ZERO // OMIT_UPCAST
514        }
515
516        @Override
517        public int getInt(final int... pos) {
518                return (int) get(pos); // BOOLEAN_ZERO // OMIT_UPCAST
519        }
520
521        @Override
522        public short getShort() {
523                return (short) get(); // BOOLEAN_ZERO // OMIT_UPCAST
524        }
525
526        @Override
527        public short getShort(final int i) {
528                return (short) get(i); // BOOLEAN_ZERO // OMIT_UPCAST
529        }
530
531        @Override
532        public short getShort(final int i, final int j) {
533                return (short) get(i, j); // BOOLEAN_ZERO // OMIT_UPCAST
534        }
535
536        @Override
537        public short getShort(final int... pos) {
538                return (short) get(pos); // BOOLEAN_ZERO // OMIT_UPCAST
539        }
540
541        @Override
542        public byte getByte() {
543                return (byte) get(); // BOOLEAN_ZERO // OMIT_UPCAST
544        }
545
546        @Override
547        public byte getByte(final int i) {
548                return (byte) get(i); // BOOLEAN_ZERO // OMIT_UPCAST
549        }
550
551        @Override
552        public byte getByte(final int i, final int j) {
553                return (byte) get(i, j); // BOOLEAN_ZERO // OMIT_UPCAST
554        }
555
556        @Override
557        public byte getByte(final int... pos) {
558                return (byte) get(pos); // BOOLEAN_ZERO // OMIT_UPCAST
559        }
560
561        @Override
562        public boolean getBoolean() {
563                return get() != 0; // BOOLEAN_FALSE
564        }
565
566        @Override
567        public boolean getBoolean(final int i) {
568                return get(i) != 0; // BOOLEAN_FALSE
569        }
570
571        @Override
572        public boolean getBoolean(final int i, final int j) {
573                return get(i, j) != 0; // BOOLEAN_FALSE
574        }
575
576        @Override
577        public boolean getBoolean(final int... pos) {
578                return get(pos) != 0; // BOOLEAN_FALSE
579        }
580
581        /**
582         * Sets the value at first point to the passed value. The dataset must not be null
583         * 
584         * @param value to set
585         * @since 2.0
586         */
587        public void setItem(final double value) { // PRIM_TYPE
588                setAbs(getFirst1DIndex(), value);
589        }
590
591        /**
592         * Sets the value at a particular point to the passed value. The dataset must be 1D
593         * 
594         * @param value to set
595         * @param i position in first dimension
596         */
597        public void setItem(final double value, final int i) { // PRIM_TYPE
598                setAbs(get1DIndex(i), value);
599        }
600
601        /**
602         * Sets the value at a particular point to the passed value. The dataset must be 2D
603         * 
604         * @param value to set
605         * @param i position in first dimension
606         * @param j position in second dimension
607         */
608        public void setItem(final double value, final int i, final int j) { // PRIM_TYPE
609                setAbs(get1DIndex(i, j), value);
610        }
611
612        /**
613         * Sets the value at a particular point to the passed value
614         * 
615         * @param value to set
616         * @param pos position
617         */
618        public void setItem(final double value, final int... pos) { // PRIM_TYPE
619                setAbs(get1DIndex(pos), value);
620        }
621
622        @Override
623        public void set(final Object obj) {
624                setItem(DTypeUtils.toReal(obj)); // FROM_OBJECT
625        }
626
627        @Override
628        public void set(final Object obj, final int i) {
629                setItem(DTypeUtils.toReal(obj), i); // FROM_OBJECT
630        }
631
632        @Override
633        public void set(final Object obj, final int i, final int j) {
634                setItem(DTypeUtils.toReal(obj), i, j); // FROM_OBJECT
635        }
636
637        @Override
638        public void set(final Object obj, int... pos) {
639                if (pos == null || (pos.length == 0 && shape.length > 0)) {
640                        pos = new int[shape.length];
641                }
642
643                setItem(DTypeUtils.toReal(obj), pos); // FROM_OBJECT
644        }
645
646        @Override
647        public void resize(int... newShape) {
648                setDirty();
649                final IndexIterator iter = getIterator();
650                final int nsize = ShapeUtils.calcSize(newShape);
651                final double[] ndata; // PRIM_TYPE
652                try {
653                        ndata = createArray(nsize);
654                } catch (Throwable t) {
655                        logger.error("Could not create a dataset of shape {}", Arrays.toString(shape), t);
656                        throw new IllegalArgumentException(t);
657                }
658                for (int i = 0; iter.hasNext() && i < nsize; i++) {
659                        ndata[i] = data[iter.index];
660                }
661
662                odata = data = ndata;
663                size = nsize;
664                shape = newShape;
665                stride = null;
666                offset = 0;
667                base = null;
668        }
669
670        @Override
671        public DoubleDataset sort(Integer axis) {
672                setDirty(); // BOOLEAN_OMIT
673                if (axis == null) { // BOOLEAN_OMIT
674                        if (stride == null) { // BOOLEAN_OMIT
675                                Arrays.sort(data); // BOOLEAN_OMIT
676                        } else { // BOOLEAN_OMIT
677                                DoubleDataset ads = clone().sort(null); // BOOLEAN_OMIT
678                                setSlicedView(getView(false), ads); // BOOLEAN_OMIT
679                        } // BOOLEAN_OMIT
680                } else { // BOOLEAN_OMIT
681                        axis = checkAxis(axis); // BOOLEAN_OMIT
682                         // BOOLEAN_OMIT 
683                        DoubleDataset ads = new DoubleDataset(shape[axis]); // BOOLEAN_OMIT
684                        PositionIterator pi = getPositionIterator(axis); // BOOLEAN_OMIT
685                        int[] pos = pi.getPos(); // BOOLEAN_OMIT
686                        boolean[] hit = pi.getOmit(); // BOOLEAN_OMIT
687                        while (pi.hasNext()) { // BOOLEAN_OMIT
688                                copyItemsFromAxes(pos, hit, ads); // BOOLEAN_OMIT
689                                Arrays.sort(ads.data); // BOOLEAN_OMIT
690                                setItemsOnAxes(pos, hit, ads.data); // BOOLEAN_OMIT
691                        } // BOOLEAN_OMIT
692                } // BOOLEAN_OMIT
693                return this; // BOOLEAN_OMIT
694                // throw new UnsupportedOperationException("Cannot sort dataset"); // BOOLEAN_USE
695        }
696
697        @Override
698        public DoubleDataset getUniqueItems() {
699                Set<Double> set = new TreeSet<Double>(); // CLASS_TYPE
700                IndexIterator it = getIterator();
701                while (it.hasNext()) {
702                        set.add(data[it.index]);
703                }
704
705                DoubleDataset u = new DoubleDataset(set.size()); // CLASS_TYPE
706                int i = 0;
707                double[] udata = u.getData(); // PRIM_TYPE
708                for (Double v : set) { // CLASS_TYPE
709                        udata[i++] = v;
710                }
711                return u;
712        }
713
714        @Override
715        public DoubleDataset getSlice(final SliceIterator siter) {
716                DoubleDataset result = new DoubleDataset(siter.getShape());
717                double[] rdata = result.data; // PRIM_TYPE
718
719                for (int i = 0; siter.hasNext(); i++)
720                        rdata[i] = data[siter.index];
721
722                result.setName(name + BLOCK_OPEN + Slice.createString(siter.shape, siter.start, siter.stop, siter.step) + BLOCK_CLOSE);
723                return result;
724        }
725
726        @Override
727        public void fillDataset(Dataset result, IndexIterator iter) {
728                IndexIterator riter = result.getIterator();
729                result.setDirty();
730
731                double[] rdata = ((DoubleDataset) result).data; // PRIM_TYPE
732
733                while (riter.hasNext() && iter.hasNext()) {
734                        rdata[riter.index] = data[iter.index];
735                }
736        }
737
738        @Override
739        public DoubleDataset setByBoolean(final Object obj, Dataset selection) {
740                setDirty();
741                if (obj instanceof Dataset) {
742                        final Dataset ds = (Dataset) obj;
743                        final int length = ((Number) selection.sum()).intValue();
744                        if (length != ds.getSize()) {
745                                throw new IllegalArgumentException(
746                                                "Number of true items in selection does not match number of items in dataset");
747                        }
748
749                        final IndexIterator oiter = ds.getIterator();
750                        final BooleanIterator biter = getBooleanIterator(selection);
751
752                        while (biter.hasNext() && oiter.hasNext()) {
753                                data[biter.index] = ds.getElementDoubleAbs(oiter.index); // GET_ELEMENT_WITH_CAST
754                        }
755                } else {
756                        final double dv = DTypeUtils.toReal(obj); // PRIM_TYPE // FROM_OBJECT
757                        final BooleanIterator biter = getBooleanIterator(selection);
758
759                        while (biter.hasNext()) {
760                                data[biter.index] = dv;
761                        }
762                }
763                return this;
764        }
765
766        @Override
767        public DoubleDataset setBy1DIndex(final Object obj, final Dataset index) {
768                setDirty();
769                if (obj instanceof Dataset) {
770                        final Dataset ds = (Dataset) obj;
771                        if (index.getSize() != ds.getSize()) {
772                                throw new IllegalArgumentException(
773                                                "Number of items in index dataset does not match number of items in dataset");
774                        }
775
776                        final IndexIterator oiter = ds.getIterator();
777                        final IntegerIterator iter = new IntegerIterator(index, size);
778
779                        while (iter.hasNext() && oiter.hasNext()) {
780                                data[iter.index] = ds.getElementDoubleAbs(oiter.index); // GET_ELEMENT_WITH_CAST
781                        }
782                } else {
783                        final double dv = DTypeUtils.toReal(obj); // PRIM_TYPE // FROM_OBJECT
784                        IntegerIterator iter = new IntegerIterator(index, size);
785
786                        while (iter.hasNext()) {
787                                data[iter.index] = dv;
788                        }
789                }
790                return this;
791        }
792
793        @Override
794        public DoubleDataset setByIndexes(final Object obj, final Object... indexes) {
795                setDirty();
796                final IntegersIterator iter = new IntegersIterator(shape, indexes);
797                final int[] pos = iter.getPos();
798
799                if (obj instanceof Dataset) {
800                        final Dataset ds = (Dataset) obj;
801                        if (ShapeUtils.calcSize(iter.getShape()) != ds.getSize()) {
802                                throw new IllegalArgumentException(
803                                                "Number of items in index datasets does not match number of items in dataset");
804                        }
805
806                        final IndexIterator oiter = ds.getIterator();
807
808                        while (iter.hasNext() && oiter.hasNext()) {
809                                setItem(ds.getElementDoubleAbs(oiter.index), pos); // GET_ELEMENT_WITH_CAST
810                        }
811                } else {
812                        final double dv = DTypeUtils.toReal(obj); // PRIM_TYPE // FROM_OBJECT
813
814                        while (iter.hasNext()) {
815                                setItem(dv, pos);
816                        }
817                }
818                return this;
819        }
820
821        @Override
822        DoubleDataset setSlicedView(Dataset view, Dataset d) {
823                setDirty();
824                final BroadcastSelfIterator it = BroadcastSelfIterator.createIterator(view, d);
825
826                while (it.hasNext()) {
827                        data[it.aIndex] = it.bDouble; // BCAST_WITH_CAST d.getElementDoubleAbs(it.bIndex);
828                }
829                return this;
830        }
831
832        @Override
833        public DoubleDataset setSlice(final Object obj, final IndexIterator siter) {
834                setDirty();
835
836                if (obj instanceof IDataset) {
837                        final IDataset ds = (IDataset) obj;
838                        final int[] oshape = ds.getShape();
839
840                        if (!ShapeUtils.areShapesCompatible(siter.getShape(), oshape)) {
841                                throw new IllegalArgumentException(String.format(
842                                                "Input dataset is not compatible with slice: %s cf %s", Arrays.toString(oshape),
843                                                Arrays.toString(siter.getShape())));
844                        }
845
846                        if (ds instanceof Dataset) {
847                                final Dataset ads = (Dataset) ds;
848                                final IndexIterator oiter = ads.getIterator();
849
850                                while (siter.hasNext() && oiter.hasNext())
851                                        data[siter.index] = ads.getElementDoubleAbs(oiter.index); // GET_ELEMENT_WITH_CAST
852                        } else {
853                                final IndexIterator oiter = new PositionIterator(oshape);
854                                final int[] pos = oiter.getPos();
855
856                                while (siter.hasNext() && oiter.hasNext())
857                                        data[siter.index] = ds.getDouble(pos); // PRIM_TYPE
858                        }
859                } else {
860                        try {
861                                double v = DTypeUtils.toReal(obj); // PRIM_TYPE // FROM_OBJECT
862
863                                while (siter.hasNext())
864                                        data[siter.index] = v;
865                        } catch (IllegalArgumentException e) {
866                                throw new IllegalArgumentException("Object for setting slice is not a dataset or number");
867                        }
868                }
869                return this;
870        }
871
872        @Override
873        public void copyItemsFromAxes(final int[] pos, final boolean[] axes, final Dataset dest) {
874                double[] ddata = (double[]) dest.getBuffer(); // PRIM_TYPE
875
876                SliceIterator siter = getSliceIteratorFromAxes(pos, axes);
877                int[] sshape = ShapeUtils.squeezeShape(siter.getShape(), false);
878
879                IndexIterator diter = dest.getSliceIterator(null, sshape, null);
880
881                if (ddata.length < ShapeUtils.calcSize(sshape)) {
882                        throw new IllegalArgumentException("destination array is not large enough");
883                }
884
885                dest.setDirty();
886                while (siter.hasNext() && diter.hasNext()) {
887                        ddata[diter.index] = data[siter.index];
888                }
889        }
890
891        @Override
892        public void setItemsOnAxes(final int[] pos, final boolean[] axes, final Object src) {
893                setDirty();
894                double[] sdata = (double[]) src; // PRIM_TYPE
895
896                SliceIterator siter = getSliceIteratorFromAxes(pos, axes);
897
898                if (sdata.length < ShapeUtils.calcSize(siter.getShape())) {
899                        throw new IllegalArgumentException("destination array is not large enough");
900                }
901
902                for (int i = 0; siter.hasNext(); i++) {
903                        data[siter.index] = sdata[i];
904                }
905        }
906
907        private List<int[]> findPositions(final double value) { // PRIM_TYPE
908                IndexIterator iter = getIterator(true);
909                List<int[]> posns = new ArrayList<int[]>();
910                int[] pos = iter.getPos();
911
912                if (Double.isNaN(value)) { // CLASS_TYPE // REAL_ONLY
913                        while (iter.hasNext()) { // REAL_ONLY
914                                if (Double.isNaN(data[iter.index])) { // REAL_ONLY
915                                        posns.add(pos.clone()); // REAL_ONLY
916                                } // REAL_ONLY
917                        } // REAL_ONLY
918                } else // REAL_ONLY
919                {
920                        while (iter.hasNext()) {
921                                if (data[iter.index] == value) {
922                                        posns.add(pos.clone());
923                                }
924                        }
925                }
926                return posns;
927        }
928
929        @Override
930        public int[] maxPos(boolean... ignoreInvalids) {
931                StatisticsMetadata<Number> md = getStats(); // PRIM_TYPE // NAN_OMIT
932                // StatisticsMetadata<Number> md = getStats(); // BOOLEAN_USE
933                // StatisticsMetadata<String> md = getStringStats(); // OBJECT_USE
934                List<int[]> max = md.getMaximumPositions(ignoreInvalids);
935
936                if (max == null) {
937                        max = findPositions(md.getMaximum(ignoreInvalids).doubleValue()); // PRIM_TYPE // NAN_OMIT
938                        // max = findPositions(md.getMaximum(ignoreInvalids).intValue() != 0); // BOOLEAN_USE
939                        // max = findPositions(md.getMaximum(ignoreInvalids).toString()); // OBJECT_USE
940
941                        md.setMaximumPositions(max);
942                }
943
944                return max.get(0); // first maximum
945        }
946
947        @Override
948        public int[] minPos(boolean... ignoreInvalids) {
949                StatisticsMetadata<Number> md = getStats(); // PRIM_TYPE // NAN_OMIT
950                // StatisticsMetadata<Number> md = getStats(); // BOOLEAN_USE
951                // StatisticsMetadata<String> md = getStringStats(); // OBJECT_USE
952                List<int[]> min = md.getMinimumPositions(ignoreInvalids);
953
954                if (min == null) {
955                        min = findPositions(md.getMinimum(ignoreInvalids).doubleValue()); // PRIM_TYPE // NAN_OMIT
956                        // min = findPositions(md.getMinimum(ignoreInvalids).intValue() != 0); // BOOLEAN_USE
957                        // min = findPositions(md.getMinimum(ignoreInvalids).toString()); // OBJECT_USE
958
959                        md.setMinimumPositions(min);
960                }
961
962                return min.get(0); // first minimum
963        }
964
965        @Override
966        public boolean containsNans() {
967                IndexIterator iter = getIterator(); // REAL_ONLY
968                while (iter.hasNext()) { // REAL_ONLY
969                        if (Double.isNaN(data[iter.index])) // CLASS_TYPE // REAL_ONLY
970                                return true; // REAL_ONLY
971                } // REAL_ONLY
972                return false;
973        }
974
975        @Override
976        public boolean containsInfs() {
977                IndexIterator iter = getIterator(); // REAL_ONLY
978                while (iter.hasNext()) { // REAL_ONLY
979                        if (Double.isInfinite(data[iter.index])) // CLASS_TYPE // REAL_ONLY
980                                return true; // REAL_ONLY
981                } // REAL_ONLY
982                return false;
983        }
984
985        @Override
986        public boolean containsInvalidNumbers() {
987                IndexIterator iter = getIterator(); // REAL_ONLY
988                while (iter.hasNext()) { // REAL_ONLY
989                        double x = data[iter.index]; // PRIM_TYPE // REAL_ONLY
990                        if (Double.isNaN(x) || Double.isInfinite(x)) // CLASS_TYPE // REAL_ONLY
991                                return true; // REAL_ONLY
992                } // REAL_ONLY
993                return false;
994        }
995
996        @Override
997        public DoubleDataset iadd(final Object b) {
998                setDirty(); // NAN_OMIT
999                Dataset bds = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); // NAN_OMIT
1000                boolean useLong = bds.getElementClass().equals(Long.class); // NAN_OMIT
1001                if (bds.getSize() == 1) { // NAN_OMIT
1002                        final IndexIterator it = getIterator(); // NAN_OMIT
1003                        final int bOffset = bds.getOffset(); // NAN_OMIT
1004                        if (useLong) { // NAN_OMIT
1005                                final long lb = bds.getElementLongAbs(bOffset); // NAN_OMIT
1006                                while (it.hasNext()) { // NAN_OMIT
1007                                        data[it.index] += lb; // NAN_OMIT
1008                                } // NAN_OMIT
1009                        } else { // NAN_OMIT
1010                                final double db = bds.getElementDoubleAbs(bOffset); // NAN_OMIT
1011                                while (it.hasNext()) { // NAN_OMIT
1012                                        data[it.index] += db; // NAN_OMIT
1013                                } // NAN_OMIT
1014                        } // NAN_OMIT
1015                } else { // NAN_OMIT
1016                        final BroadcastSelfIterator it = BroadcastSelfIterator.createIterator(this, bds); // NAN_OMIT
1017                        it.setOutputDouble(!useLong); // NAN_OMIT
1018                        if (useLong) { // NAN_OMIT
1019                                while (it.hasNext()) { // NAN_OMIT
1020                                        data[it.aIndex] += it.bLong; // NAN_OMIT
1021                                } // NAN_OMIT
1022                        } else { // NAN_OMIT
1023                                while (it.hasNext()) { // NAN_OMIT
1024                                        data[it.aIndex] += it.bDouble; // NAN_OMIT
1025                                } // NAN_OMIT
1026                        } // NAN_OMIT
1027                } // NAN_OMIT
1028                return this;
1029        }
1030
1031        @Override
1032        public DoubleDataset isubtract(final Object b) {
1033                setDirty(); // NAN_OMIT
1034                Dataset bds = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); // NAN_OMIT
1035                boolean useLong = bds.getElementClass().equals(Long.class); // NAN_OMIT
1036                if (bds.getSize() == 1) { // NAN_OMIT
1037                        final IndexIterator it = getIterator(); // NAN_OMIT
1038                        final int bOffset = bds.getOffset(); // NAN_OMIT
1039                        if (useLong) { // NAN_OMIT
1040                                final long lb = bds.getElementLongAbs(bOffset); // NAN_OMIT
1041                                while (it.hasNext()) { // NAN_OMIT
1042                                        data[it.index] -= lb; // NAN_OMIT
1043                                } // NAN_OMIT
1044                        } else { // NAN_OMIT
1045                                final double db = bds.getElementDoubleAbs(bOffset); // NAN_OMIT
1046                                while (it.hasNext()) { // NAN_OMIT
1047                                        data[it.index] -= db; // NAN_OMIT
1048                                } // NAN_OMIT
1049                        } // NAN_OMIT
1050                } else { // NAN_OMIT
1051                        final BroadcastSelfIterator it = BroadcastSelfIterator.createIterator(this, bds); // NAN_OMIT
1052                        if (useLong) { // NAN_OMIT
1053                                it.setOutputDouble(false); // NAN_OMIT
1054                                while (it.hasNext()) { // NAN_OMIT
1055                                        data[it.aIndex] -= it.bLong; // NAN_OMIT
1056                                } // NAN_OMIT
1057                        } else { // NAN_OMIT
1058                                it.setOutputDouble(true); // NAN_OMIT
1059                                while (it.hasNext()) { // NAN_OMIT
1060                                        data[it.aIndex] -= it.bDouble; // NAN_OMIT
1061                                } // NAN_OMIT
1062                        } // NAN_OMIT
1063                } // NAN_OMIT
1064                return this;
1065        }
1066
1067        @Override
1068        public DoubleDataset imultiply(final Object b) {
1069                setDirty(); // NAN_OMIT
1070                Dataset bds = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); // NAN_OMIT
1071                boolean useLong = bds.getElementClass().equals(Long.class); // NAN_OMIT
1072                if (bds.getSize() == 1) { // NAN_OMIT
1073                        final IndexIterator it = getIterator(); // NAN_OMIT
1074                        final int bOffset = bds.getOffset(); // NAN_OMIT
1075                        if (useLong) { // NAN_OMIT
1076                                final long lb = bds.getElementLongAbs(bOffset); // NAN_OMIT
1077                                while (it.hasNext()) { // NAN_OMIT
1078                                        data[it.index] *= lb; // NAN_OMIT
1079                                } // NAN_OMIT
1080                        } else { // NAN_OMIT
1081                                final double db = bds.getElementDoubleAbs(bOffset); // NAN_OMIT
1082                                while (it.hasNext()) { // NAN_OMIT
1083                                        data[it.index] *= db; // NAN_OMIT
1084                                } // NAN_OMIT
1085                        } // NAN_OMIT
1086                } else { // NAN_OMIT
1087                        final BroadcastSelfIterator it = BroadcastSelfIterator.createIterator(this, bds); // NAN_OMIT
1088                        it.setOutputDouble(!useLong); // NAN_OMIT
1089                        if (useLong) { // NAN_OMIT
1090                                while (it.hasNext()) { // NAN_OMIT
1091                                        data[it.aIndex] *= it.bLong; // NAN_OMIT
1092                                } // NAN_OMIT
1093                        } else { // NAN_OMIT
1094                                while (it.hasNext()) { // NAN_OMIT
1095                                        data[it.aIndex] *= it.bDouble; // NAN_OMIT
1096                                } // NAN_OMIT
1097                        } // NAN_OMIT
1098                } // NAN_OMIT
1099                return this;
1100        }
1101
1102        @Override
1103        public DoubleDataset idivide(final Object b) {
1104                setDirty(); // NAN_OMIT
1105                Dataset bds = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); // NAN_OMIT
1106                boolean useLong = bds.getElementClass().equals(Long.class); // NAN_OMIT
1107                if (bds.getSize() == 1) { // NAN_OMIT
1108                        final int bOffset = bds.getOffset(); // NAN_OMIT
1109                        if (useLong) { // NAN_OMIT
1110                                final long lb = bds.getElementLongAbs(bOffset); // NAN_OMIT
1111                                // if (lb == 0) { // INT_USE // NAN_OMIT
1112                                //      fill(0); // INT_USE // NAN_OMIT
1113                                // } else { // INT_USE // NAN_OMIT
1114                                final IndexIterator it = getIterator(); // NAN_OMIT
1115                                while (it.hasNext()) { // NAN_OMIT
1116                                        data[it.index] /= lb; // NAN_OMIT
1117                                } // NAN_OMIT
1118                                // } // INT_USE // NAN_OMIT
1119                        } else { // NAN_OMIT
1120                                final double db = bds.getElementDoubleAbs(bOffset); // NAN_OMIT
1121                                // if (db == 0) { // INT_USE // NAN_OMIT
1122                                //      fill(0); // INT_USE // NAN_OMIT
1123                                // } else { // INT_USE // NAN_OMIT
1124                                final IndexIterator it = getIterator(); // NAN_OMIT
1125                                while (it.hasNext()) { // NAN_OMIT
1126                                        data[it.index] /= db; // NAN_OMIT
1127                                } // NAN_OMIT
1128                                // } // INT_USE // NAN_OMIT
1129                        } // NAN_OMIT
1130                } else { // NAN_OMIT
1131                        final BroadcastSelfIterator it = BroadcastSelfIterator.createIterator(this, bds); // NAN_OMIT
1132                        it.setOutputDouble(!useLong); // NAN_OMIT
1133                        if (useLong) { // NAN_OMIT
1134                                while (it.hasNext()) { // NAN_OMIT
1135                                        // if (it.bLong == 0) { // INT_USE // NAN_OMIT
1136                                        //      data[it.aIndex] = 0; // INT_USE // NAN_OMIT
1137                                        // } else { // INT_USE // NAN_OMIT
1138                                        data[it.aIndex] /= it.bLong; // NAN_OMIT
1139                                        // } // INT_USE // NAN_OMIT
1140                                } // NAN_OMIT
1141                        } else { // NAN_OMIT
1142                                while (it.hasNext()) { // NAN_OMIT
1143                                        // if (it.bDouble == 0) { // INT_USE // NAN_OMIT
1144                                        //      data[it.aIndex] = 0; // INT_USE // NAN_OMIT
1145                                        // } else { // INT_USE // NAN_OMIT
1146                                        data[it.aIndex] /= it.bDouble; // NAN_OMIT
1147                                        // } // INT_USE // NAN_OMIT
1148                                } // NAN_OMIT
1149                        } // NAN_OMIT
1150                } // NAN_OMIT
1151                return this;
1152        }
1153
1154        @Override
1155        public DoubleDataset ifloor() {
1156                setDirty(); // REAL_ONLY
1157                IndexIterator it = getIterator(); // REAL_ONLY
1158                while (it.hasNext()) { // REAL_ONLY
1159                        data[it.index] = Math.floor(data[it.index]); // PRIM_TYPE // REAL_ONLY // ADD_CAST
1160                } // REAL_ONLY
1161                return this;
1162        }
1163
1164        @Override
1165        public DoubleDataset iremainder(final Object b) {
1166                setDirty(); // NAN_OMIT
1167                Dataset bds = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); // NAN_OMIT
1168                boolean useLong = bds.getElementClass().equals(Long.class); // NAN_OMIT
1169                if (bds.getSize() == 1) { // NAN_OMIT
1170                        final int bOffset = bds.getOffset(); // NAN_OMIT
1171                        if (useLong) { // NAN_OMIT
1172                                final long lb = bds.getElementLongAbs(bOffset); // NAN_OMIT
1173                                // if (lb == 0) { // INT_USE // NAN_OMIT
1174                                //      fill(0); // INT_USE // NAN_OMIT
1175                                // } else { // INT_USE // NAN_OMIT
1176                                final IndexIterator it = getIterator(); // NAN_OMIT
1177                                while (it.hasNext()) { // NAN_OMIT
1178                                        data[it.index] %= lb; // NAN_OMIT
1179                                } // NAN_OMIT
1180                                // } // INT_USE // NAN_OMIT
1181                        } else { // NAN_OMIT
1182                                final long lb = bds.getElementLongAbs(bOffset); // NAN_OMIT
1183                                // if (lb == 0) { // INT_USE // NAN_OMIT
1184                                //      fill(0); // INT_USE // NAN_OMIT
1185                                // } else { // INT_USE // NAN_OMIT
1186                                final IndexIterator it = getIterator(); // NAN_OMIT
1187                                while (it.hasNext()) { // NAN_OMIT
1188                                        data[it.index] %= lb; // NAN_OMIT
1189                                } // NAN_OMIT
1190                                // } // INT_USE // NAN_OMIT
1191                        } // NAN_OMIT
1192                } else { // NAN_OMIT
1193                        final BroadcastSelfIterator it = BroadcastSelfIterator.createIterator(this, bds); // NAN_OMIT
1194                        it.setOutputDouble(!useLong); // NAN_OMIT
1195                        if (useLong) { // NAN_OMIT
1196                                while (it.hasNext()) { // NAN_OMIT
1197                                        data[it.aIndex] %= it.bLong; // NAN_OMIT // INT_EXCEPTION
1198                                } // NAN_OMIT
1199                        } else { // NAN_OMIT
1200                                while (it.hasNext()) { // NAN_OMIT
1201                                        data[it.aIndex] %= it.bDouble; // NAN_OMIT
1202                                } // NAN_OMIT
1203                        } // NAN_OMIT
1204                } // NAN_OMIT
1205                return this;
1206        }
1207
1208        @Override
1209        public DoubleDataset ipower(final Object b) {
1210                setDirty(); // NAN_OMIT
1211                Dataset bds = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); // NAN_OMIT
1212                if (bds.getSize() == 1) { // NAN_OMIT
1213                        final int bOffset = bds.getOffset(); // NAN_OMIT
1214                        final double vr = bds.getElementDoubleAbs(bOffset); // NAN_OMIT
1215                        final IndexIterator it = getIterator(); // NAN_OMIT
1216                        if (bds.isComplex()) { // NAN_OMIT
1217                                final double vi = bds.getElementDoubleAbs(bOffset + 1); // NAN_OMIT
1218                                if (vi == 0) { // NAN_OMIT
1219                                        while (it.hasNext()) { // NAN_OMIT
1220                                                final double v = Math.pow(data[it.index], vr); // NAN_OMIT
1221                                                // if (Double.isInfinite(v) || Double.isNaN(v)) { // INT_USE // NAN_OMIT
1222                                                //      data[it.index] = 0; // INT_USE // NAN_OMIT
1223                                                // } else { // INT_USE // NAN_OMIT
1224                                                data[it.index] = v; // PRIM_TYPE_LONG // NAN_OMIT // ADD_CAST
1225                                                // } // INT_USE // NAN_OMIT
1226                                        } // NAN_OMIT
1227                                } else { // NAN_OMIT
1228                                        final Complex zv = new Complex(vr, vi); // NAN_OMIT
1229                                        while (it.hasNext()) { // NAN_OMIT
1230                                                Complex zd = new Complex(data[it.index], 0); // NAN_OMIT
1231                                                final double v = zd.pow(zv).getReal(); // NAN_OMIT
1232                                                // if (Double.isInfinite(v) || Double.isNaN(v)) { // INT_USE // NAN_OMIT
1233                                                //      data[it.index] = 0; // INT_USE // NAN_OMIT
1234                                                // } else { // INT_USE // NAN_OMIT
1235                                                data[it.index] = v; // PRIM_TYPE_LONG // NAN_OMIT // ADD_CAST
1236                                                // } // INT_USE // NAN_OMIT
1237                                        } // NAN_OMIT
1238                                } // NAN_OMIT
1239                        } else {// NAN_OMIT
1240                                while (it.hasNext()) { // NAN_OMIT
1241                                        final double v = Math.pow(data[it.index], vr); // NAN_OMIT
1242                                        // if (Double.isInfinite(v) || Double.isNaN(v)) { // INT_USE // NAN_OMIT
1243                                        //      data[it.index] = 0; // INT_USE // NAN_OMIT
1244                                        // } else { // INT_USE // NAN_OMIT
1245                                        data[it.index] = v; // PRIM_TYPE_LONG // NAN_OMIT // ADD_CAST
1246                                        // } // INT_USE // NAN_OMIT
1247                                } // NAN_OMIT
1248                        } // NAN_OMIT
1249                } else { // NAN_OMIT
1250                        final BroadcastIterator it = BroadcastIterator.createIterator(this, bds); // NAN_OMIT
1251                        it.setOutputDouble(true); // NAN_OMIT
1252                        if (bds.isComplex()) { // NAN_OMIT
1253                                while (it.hasNext()) { // NAN_OMIT
1254                                        final Complex zv = new Complex(it.bDouble, bds.getElementDoubleAbs(it.bIndex + 1)); // NAN_OMIT
1255                                        final double v = new Complex(it.aDouble, 0).pow(zv).getReal(); // NAN_OMIT
1256                                        // if (Double.isInfinite(v) || Double.isNaN(v)) { // INT_USE // NAN_OMIT
1257                                        //      data[it.aIndex] = 0; // INT_USE // NAN_OMIT
1258                                        // } else { // INT_USE // NAN_OMIT
1259                                        data[it.aIndex] = v; // PRIM_TYPE_LONG // NAN_OMIT // ADD_CAST
1260                                        // } // INT_USE // NAN_OMIT
1261                                } // NAN_OMIT
1262                        } else {// NAN_OMIT
1263                                while (it.hasNext()) { // NAN_OMIT
1264                                        final double v = Math.pow(it.aDouble, it.bDouble); // NAN_OMIT
1265                                        // if (Double.isInfinite(v) || Double.isNaN(v)) { // INT_USE // NAN_OMIT
1266                                        //      data[it.aIndex] = 0; // INT_USE // NAN_OMIT
1267                                        // } else { // INT_USE // NAN_OMIT
1268                                        data[it.aIndex] = v; // PRIM_TYPE_LONG // NAN_OMIT // ADD_CAST
1269                                        // } // INT_USE // NAN_OMIT
1270                                } // NAN_OMIT
1271                        } // NAN_OMIT
1272                } // NAN_OMIT
1273                return this;
1274        }
1275
1276        @Override
1277        public double residual(final Object b, final Dataset w, boolean ignoreNaNs) {
1278                Dataset bds = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); // NAN_OMIT
1279                final BroadcastIterator it = BroadcastIterator.createIterator(this, bds); // NAN_OMIT
1280                it.setOutputDouble(true); // NAN_OMIT
1281                double sum = 0;
1282                double comp = 0; // NAN_OMIT
1283                if (ignoreNaNs) { // REAL_ONLY // NAN_OMIT
1284                        if (w == null) { // REAL_ONLY // NAN_OMIT
1285                                while (it.hasNext()) { // REAL_ONLY // NAN_OMIT
1286                                        final double diff = it.aDouble - it.bDouble; // REAL_ONLY // NAN_OMIT
1287                                        if (Double.isNaN(diff)) // REAL_ONLY // NAN_OMIT
1288                                                continue; // REAL_ONLY // NAN_OMIT
1289                                        final double err = diff * diff - comp; // REAL_ONLY // NAN_OMIT
1290                                        final double temp = sum + err; // REAL_ONLY // NAN_OMIT
1291                                        comp = (temp - sum) - err; // REAL_ONLY // NAN_OMIT
1292                                        sum = temp; // REAL_ONLY // NAN_OMIT
1293                                } // REAL_ONLY // NAN_OMIT
1294                        } else { // REAL_ONLY // NAN_OMIT
1295                                IndexIterator itw = w.getIterator(); // REAL_ONLY // NAN_OMIT
1296                                while (it.hasNext() && itw.hasNext()) { // REAL_ONLY // NAN_OMIT
1297                                        final double diff = it.aDouble - it.bDouble; // REAL_ONLY // NAN_OMIT
1298                                        if (Double.isNaN(diff)) // REAL_ONLY // NAN_OMIT
1299                                                continue; // REAL_ONLY // NAN_OMIT
1300                                        final double err = diff * diff * w.getElementDoubleAbs(itw.index) - comp; // REAL_ONLY // NAN_OMIT
1301                                        final double temp = sum + err; // REAL_ONLY // NAN_OMIT
1302                                        comp = (temp - sum) - err; // REAL_ONLY // NAN_OMIT
1303                                        sum = temp; // REAL_ONLY // NAN_OMIT
1304                                } // REAL_ONLY // NAN_OMIT
1305                        } // REAL_ONLY // NAN_OMIT
1306                } else // REAL_ONLY // NAN_OMIT
1307                { // NAN_OMIT
1308                        if (w == null) { // NAN_OMIT
1309                                while (it.hasNext()) { // NAN_OMIT
1310                                        final double diff = it.aDouble - it.bDouble; // NAN_OMIT
1311                                        final double err = diff * diff - comp; // NAN_OMIT
1312                                        final double temp = sum + err; // NAN_OMIT
1313                                        comp = (temp - sum) - err; // NAN_OMIT
1314                                        sum = temp; // NAN_OMIT
1315                                } // NAN_OMIT
1316                        } else { // NAN_OMIT
1317                                IndexIterator itw = w.getIterator(); // NAN_OMIT
1318                                while (it.hasNext() && itw.hasNext()) { // NAN_OMIT
1319                                        final double diff = it.aDouble - it.bDouble; // NAN_OMIT
1320                                        final double err = diff * diff * w.getElementDoubleAbs(itw.index) - comp; // NAN_OMIT
1321                                        final double temp = sum + err; // NAN_OMIT
1322                                        comp = (temp - sum) - err; // NAN_OMIT
1323                                        sum = temp; // NAN_OMIT
1324                                } // NAN_OMIT
1325                        } // NAN_OMIT
1326                } // NAN_OMIT
1327                return sum;
1328        }
1329}