001/*-
002 * Copyright (c) 2016 Diamond Light Source Ltd.
003 *
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
010package org.eclipse.january.dataset;
011
012import java.lang.reflect.Array;
013import java.util.Date;
014import java.util.HashMap;
015import java.util.LinkedHashMap;
016import java.util.List;
017import java.util.Map;
018import java.util.Map.Entry;
019
020import org.apache.commons.math3.complex.Complex;
021import org.slf4j.Logger;
022import org.slf4j.LoggerFactory;
023
024public class DTypeUtils {
025        protected static final Logger logger = LoggerFactory.getLogger(DTypeUtils.class);
026
027        private static Map<Class<? extends Dataset>, Integer> createInterfaceMap() {
028                Map<Class<? extends Dataset>, Integer> map = new LinkedHashMap<>();
029                map.put(BooleanDataset.class, Dataset.BOOL);
030                map.put(ByteDataset.class, Dataset.INT8);
031                map.put(ShortDataset.class, Dataset.INT16);
032                map.put(IntegerDataset.class, Dataset.INT32);
033                map.put(LongDataset.class, Dataset.INT64);
034                map.put(FloatDataset.class, Dataset.FLOAT32);
035                map.put(DoubleDataset.class, Dataset.FLOAT64);
036                map.put(ComplexFloatDataset.class, Dataset.COMPLEX64);
037                map.put(ComplexDoubleDataset.class, Dataset.COMPLEX128);
038                map.put(CompoundByteDataset.class, Dataset.ARRAYINT8);
039                map.put(CompoundShortDataset.class, Dataset.ARRAYINT16);
040                map.put(CompoundIntegerDataset.class, Dataset.ARRAYINT32);
041                map.put(CompoundLongDataset.class, Dataset.ARRAYINT64);
042                map.put(CompoundFloatDataset.class, Dataset.ARRAYFLOAT32);
043                map.put(CompoundDoubleDataset.class, Dataset.ARRAYFLOAT64);
044                map.put(StringDataset.class, Dataset.STRING);
045                map.put(ObjectDataset.class, Dataset.OBJECT);
046                map.put(DateDataset.class, Dataset.DATE);
047                map.put(RGBDataset.class, Dataset.RGB);
048                return map;
049        }
050
051        static final Map<Class<? extends Dataset>, Integer> interface2DTypes; // map interface to dataset type
052        private static final Map<Integer, Class<? extends Dataset>> dtype2Interface; // map dataset type to interface
053        static {
054                interface2DTypes = createInterfaceMap();
055                dtype2Interface = new HashMap<>();
056                for (Entry<Class<? extends Dataset>, Integer> e : interface2DTypes.entrySet()) {
057                        dtype2Interface.put(e.getValue(), e.getKey());
058                }
059        }
060
061        /**
062         * @param a
063         * @return name of dataset type
064         */
065        public static String getDTypeName(Dataset a) {
066                return getDatasetName(a);
067        }
068
069        /**
070         * @param a
071         * @return name of dataset type
072         */
073        public static String getDTypeName(ILazyDataset a) {
074                return getDatasetName(a);
075        }
076
077        /**
078         * @param dtype
079         * @param itemSize
080         * @return name of dataset type
081         */
082        public static String getDTypeName(int dtype, int itemSize) {
083                return getDatasetName(dtype2Interface.get(dtype), itemSize);
084        }
085
086        /**
087         * @param clazz dataset class
088         * @return dataset type for dataset class
089         */
090        public static int getDType(Class<? extends Dataset> clazz) {
091                if (!interface2DTypes.containsKey(clazz)) {
092                        throw new IllegalArgumentException("Interface class not allowed or supported");
093                }
094                return interface2DTypes.get(clazz);
095        }
096
097        public static boolean isDTypeElemental(int dtype) {
098                return dtype <= Dataset.DATE;
099        }
100
101        public static boolean isDTypeInteger(int dtype) {
102                return dtype == Dataset.INT8 || dtype == Dataset.INT16 || dtype == Dataset.INT32 || dtype == Dataset.INT64 ||
103                                dtype == Dataset.ARRAYINT8 || dtype == Dataset.ARRAYINT16 || dtype == Dataset.ARRAYINT32 || dtype == Dataset.ARRAYINT64 || dtype == Dataset.RGB;
104        }
105
106        public static boolean isDTypeFloating(int dtype) {
107                return dtype == Dataset.FLOAT32 || dtype == Dataset.FLOAT64 || dtype == Dataset.COMPLEX64 || dtype == Dataset.COMPLEX128 ||
108                                dtype == Dataset.ARRAYFLOAT32 || dtype == Dataset.ARRAYFLOAT64;
109        }
110
111        public static boolean isDTypeComplex(int dtype) {
112                return dtype == Dataset.COMPLEX64 || dtype == Dataset.COMPLEX128;
113        }
114
115        /**
116         * @param dtype
117         * @return true if dataset type is numerical, i.e. a dataset contains numbers
118         */
119        public static boolean isDTypeNumerical(int dtype) {
120                return isDTypeInteger(dtype) || isDTypeFloating(dtype) || dtype == Dataset.BOOL;
121        }
122
123        /**
124         * Find dataset type that best fits given types The best type takes into account complex and array datasets
125         *
126         * @param atype
127         *            first dataset type
128         * @param btype
129         *            second dataset type
130         * @return best dataset type
131         */
132        public static int getBestDType(final int atype, final int btype) {
133                return interface2DTypes.get(InterfaceUtils.getBestInterface(getInterface(atype), getInterface(btype)));
134        }
135
136        /**
137         * Find floating point dataset type that best fits given types. The best type takes into account complex and array
138         * datasets
139         *
140         * @param otype
141         *            old dataset type
142         * @return best dataset type
143         */
144        public static int getBestFloatDType(final int otype) {
145                return getDType(InterfaceUtils.getBestFloatInterface(getInterface(otype)));
146        }
147
148        /**
149         * Find floating point dataset type that best fits given class The best type takes into account complex and array
150         * datasets
151         *
152         * @param cls
153         *            of an item or element
154         * @return best dataset type
155         */
156        public static int getBestFloatDType(Class<? extends Object> cls) {
157                return getBestFloatDType(getDTypeFromClass(cls));
158        }
159
160        /**
161         * Get dataset type from an element class
162         *
163         * @param cls element class
164         * @return dataset type
165         */
166        public static int getDTypeFromClass(Class<? extends Object> cls) {
167                return getDTypeFromClass(cls, 1);
168        }
169
170        /**
171         * Get dataset type from an element class
172         *
173         * @param cls element class
174         * @return dataset type
175         */
176        public static int getDTypeFromClass(Class<? extends Object> cls, int isize) {
177                return getDType(InterfaceUtils.getInterfaceFromClass(isize, cls));
178        }
179
180        /**
181         * Get dataset type from an object. The following are supported: Java Number objects, Apache common math Complex
182         * objects, Java arrays and lists
183         *
184         * @param obj
185         * @return dataset type
186         */
187        public static int getDTypeFromObject(Object obj) {
188                int dtype = -1;
189
190                if (obj == null) {
191                        return Dataset.OBJECT;
192                }
193
194                if (obj instanceof List<?>) {
195                        List<?> jl = (List<?>) obj;
196                        int l = jl.size();
197                        for (int i = 0; i < l; i++) {
198                                int ldtype = getDTypeFromObject(jl.get(i));
199                                if (ldtype > dtype) {
200                                        dtype = ldtype;
201                                }
202                        }
203                } else if (obj.getClass().isArray()) {
204                        Class<?> ca = obj.getClass().getComponentType();
205                        if (InterfaceUtils.isElementSupported(ca)) {
206                                return getDTypeFromClass(ca);
207                        }
208                        int l = Array.getLength(obj);
209                        for (int i = 0; i < l; i++) {
210                                Object lo = Array.get(obj, i);
211                                int ldtype = getDTypeFromObject(lo);
212                                if (ldtype > dtype) {
213                                        dtype = ldtype;
214                                }
215                        }
216                } else if (obj instanceof Dataset) {
217                        return ((Dataset) obj).getDType();
218                } else if (obj instanceof ILazyDataset) {
219                        dtype = getDTypeFromClass(((ILazyDataset) obj).getElementClass(), ((ILazyDataset) obj).getElementsPerItem());
220                } else {
221                        dtype = getDTypeFromClass(obj.getClass());
222                }
223                return dtype;
224        }
225
226        /**
227         * Get dataset type from given dataset
228         * @param d
229         * @return dataset type
230         */
231        public static int getDType(ILazyDataset d) {
232                if (d instanceof LazyDatasetBase)
233                        return ((LazyDatasetBase) d).getDType();
234                return getDTypeFromClass(d.getElementClass(), d.getElementsPerItem());
235        }
236
237        /**
238         * The largest dataset type suitable for a summation of around a few thousand items without changing from the "kind"
239         * of dataset
240         *
241         * @param otype
242         * @return largest dataset type available for given dataset type
243         */
244        public static int getLargestDType(final int otype) {
245                switch (otype) {
246                case Dataset.BOOL:
247                case Dataset.INT8:
248                case Dataset.INT16:
249                        return Dataset.INT32;
250                case Dataset.INT32:
251                case Dataset.INT64:
252                        return Dataset.INT64;
253                case Dataset.FLOAT32:
254                case Dataset.FLOAT64:
255                        return Dataset.FLOAT64;
256                case Dataset.COMPLEX64:
257                case Dataset.COMPLEX128:
258                        return Dataset.COMPLEX128;
259                case Dataset.ARRAYINT8:
260                case Dataset.ARRAYINT16:
261                        return Dataset.ARRAYINT32;
262                case Dataset.ARRAYINT32:
263                case Dataset.ARRAYINT64:
264                        return Dataset.ARRAYINT64;
265                case Dataset.ARRAYFLOAT32:
266                case Dataset.ARRAYFLOAT64:
267                        return Dataset.ARRAYFLOAT64;
268                case Dataset.DATE:
269                case Dataset.STRING:
270                case Dataset.RGB:
271                case Dataset.OBJECT:
272                        return otype;
273                }
274                throw new IllegalArgumentException("Unsupported dataset type");
275        }
276
277        /**
278         * The largest dataset class suitable for a summation of around a few thousand items without changing from the "kind"
279         * of dataset
280         *
281         * @param clazz
282         * @return largest dataset class available for given dataset class
283         * @since 2.3
284         */
285        public static Class<? extends Dataset> getLargestDataset(final Class<? extends Dataset> clazz) {
286                if (BooleanDataset.class.equals(clazz) || ByteDataset.class.equals(clazz) || ShortDataset.class.equals(clazz)) {
287                        return IntegerDataset.class;
288                } else if (IntegerDataset.class.equals(clazz) || LongDataset.class.equals(clazz)) {
289                        return LongDataset.class;
290                } else if (FloatDataset.class.equals(clazz) || DoubleDataset.class.equals(clazz)) {
291                        return DoubleDataset.class;
292                } else if (ComplexFloatDataset.class.equals(clazz) || ComplexDoubleDataset.class.equals(clazz)) {
293                        return ComplexDoubleDataset.class;
294                } else if (CompoundByteDataset.class.equals(clazz) || CompoundShortDataset.class.equals(clazz)) {
295                        return CompoundIntegerDataset.class;
296                } else if (CompoundIntegerDataset.class.equals(clazz) || CompoundLongDataset.class.equals(clazz)) {
297                        return CompoundLongDataset.class;
298                }
299
300                return clazz;
301        }
302
303        /**
304         * @param otype
305         * @return elemental dataset type available for given dataset type
306         */
307        public static int getElementalDType(final int otype) {
308                switch (otype) {
309                case Dataset.COMPLEX64:
310                        return Dataset.FLOAT32;
311                case Dataset.COMPLEX128:
312                        return Dataset.FLOAT64;
313                case Dataset.ARRAYINT8:
314                        return Dataset.INT8;
315                case Dataset.ARRAYINT16:
316                case Dataset.RGB:
317                        return Dataset.INT16;
318                case Dataset.ARRAYINT32:
319                        return Dataset.INT32;
320                case Dataset.ARRAYINT64:
321                        return Dataset.INT64;
322                case Dataset.ARRAYFLOAT32:
323                        return Dataset.FLOAT32;
324                case Dataset.ARRAYFLOAT64:
325                        return Dataset.FLOAT64;
326                default:
327                        return otype;
328                }
329        }
330
331        /**
332         * @param dtype
333         * @return number of elements per item
334         */
335        public static int getElementsPerItem(final int dtype) {
336                switch (dtype) {
337                case Dataset.ARRAYINT8:
338                case Dataset.ARRAYINT16:
339                case Dataset.ARRAYINT32:
340                case Dataset.ARRAYINT64:
341                case Dataset.ARRAYFLOAT32:
342                case Dataset.ARRAYFLOAT64:
343                        throw new UnsupportedOperationException("Multi-element type unsupported");
344                case Dataset.COMPLEX64:
345                case Dataset.COMPLEX128:
346                        return 2;
347                case Dataset.RGB:
348                        return 3;
349                }
350                return 1;
351        }
352
353        /**
354         * @param dtype
355         * @return length of single item in bytes
356         */
357        public static int getItemBytes(final int dtype) {
358                return getItemBytes(dtype, getElementsPerItem(dtype));
359        }
360
361        /**
362         * @param dtype
363         * @param isize
364         *            number of elements in an item
365         * @return length of single item in bytes
366         */
367        public static int getItemBytes(final int dtype, final int isize) {
368                int size;
369
370                switch (dtype) {
371                case Dataset.BOOL:
372                        size = 1; // How is this defined?
373                        break;
374                case Dataset.INT8:
375                case Dataset.ARRAYINT8:
376                        size = Byte.SIZE / 8;
377                        break;
378                case Dataset.INT16:
379                case Dataset.ARRAYINT16:
380                case Dataset.RGB:
381                        size = Short.SIZE / 8;
382                        break;
383                case Dataset.INT32:
384                case Dataset.ARRAYINT32:
385                        size = Integer.SIZE / 8;
386                        break;
387                case Dataset.INT64:
388                case Dataset.ARRAYINT64:
389                        size = Long.SIZE / 8;
390                        break;
391                case Dataset.FLOAT32:
392                case Dataset.ARRAYFLOAT32:
393                case Dataset.COMPLEX64:
394                        size = Float.SIZE / 8;
395                        break;
396                case Dataset.FLOAT64:
397                case Dataset.ARRAYFLOAT64:
398                case Dataset.COMPLEX128:
399                        size = Double.SIZE / 8;
400                        break;
401                default:
402                        size = 0;
403                        break;
404                }
405
406                return size * isize;
407        }
408
409        public static boolean toBoolean(final Object b) {
410                if (b instanceof Number) {
411                        return ((Number) b).longValue() != 0;
412                } else if (b instanceof Boolean) {
413                        return ((Boolean) b).booleanValue();
414                } else if (b instanceof Complex) {
415                        return ((Complex) b).getReal() != 0;
416                } else if (b instanceof Dataset) {
417                        Dataset db = (Dataset) b;
418                        if (db.getSize() != 1) {
419                                logger.error("Given dataset must have only one item");
420                                throw new IllegalArgumentException("Given dataset must have only one item");
421                        }
422                        return db.getBoolean();
423                } else if (b instanceof IDataset) {
424                        IDataset db = (IDataset) b;
425                        if (db.getSize() != 1) {
426                                logger.error("Given dataset must have only one item");
427                                throw new IllegalArgumentException("Given dataset must have only one item");
428                        }
429                        return db.getBoolean(new int[db.getRank()]);
430                } else {
431                        logger.error("Argument is of unsupported class");
432                        throw new IllegalArgumentException("Argument is of unsupported class");
433                }
434        }
435
436        /**
437         * @param d
438         * @return returns a long or 0 if d is NaN or infinite
439         * @since 2.1
440         */
441        public static final long toLong(double d) {
442                if (Double.isInfinite(d) || Double.isNaN(d))
443                        return 0l;
444                return (long) d;
445        }
446
447        /**
448         * @param d
449         * @return returns a long or 0 if d is NaN or infinite
450         * @since 2.1
451         */
452        public static final long toLong(float d) {
453                if (Float.isInfinite(d) || Float.isNaN(d))
454                        return 0l;
455                return (long) d;
456        }
457
458        public static long toLong(final Object b) {
459                if (b instanceof Number) {
460                        final Number n = (Number) b;
461                        return (n instanceof Double || n instanceof Float) ? toLong(n.doubleValue()) : n.longValue();
462                } else if (b instanceof Boolean) {
463                        return ((Boolean) b).booleanValue() ? 1 : 0;
464                } else if (b instanceof Complex) {
465                        return (long) ((Complex) b).getReal();
466                } else if (b instanceof Dataset) {
467                        Dataset db = (Dataset) b;
468                        if (db.getSize() != 1) {
469                                logger.error("Given dataset must have only one item");
470                                throw new IllegalArgumentException("Given dataset must have only one item");
471                        }
472                        return db.getLong();
473                } else if (b instanceof IDataset) {
474                        IDataset db = (IDataset) b;
475                        if (db.getSize() != 1) {
476                                logger.error("Given dataset must have only one item");
477                                throw new IllegalArgumentException("Given dataset must have only one item");
478                        }
479                        return db.getLong(new int[db.getRank()]);
480                } else {
481                        logger.error("Argument is of unsupported class");
482                        throw new IllegalArgumentException("Argument is of unsupported class");
483                }
484        }
485
486        public static double toReal(final Object b) {
487                if (b instanceof Number) {
488                        return ((Number) b).doubleValue();
489                } else if (b instanceof Boolean) {
490                        return ((Boolean) b).booleanValue() ? 1 : 0;
491                } else if (b instanceof Complex) {
492                        return ((Complex) b).getReal();
493                } else if (b.getClass().isArray()) {
494                        if (Array.getLength(b) == 0)
495                                return 0;
496                        return toReal(Array.get(b, 0));
497                } else if (b instanceof Dataset) {
498                        Dataset db = (Dataset) b;
499                        if (db.getSize() != 1) {
500                                logger.error("Given dataset must have only one item");
501                                throw new IllegalArgumentException("Given dataset must have only one item");
502                        }
503                        return db.getDouble();
504                } else if (b instanceof IDataset) {
505                        IDataset db = (Dataset) b;
506                        if (db.getSize() != 1) {
507                                logger.error("Given dataset must have only one item");
508                                throw new IllegalArgumentException("Given dataset must have only one item");
509                        }
510                        return db.getDouble(new int[db.getRank()]);
511                } else {
512                        logger.error("Argument is of unsupported class");
513                        throw new IllegalArgumentException("Argument is of unsupported class");
514                }
515        }
516
517        public static double toImag(final Object b) {
518                if (b instanceof Number) {
519                        return 0;
520                } else if (b instanceof Boolean) {
521                        return 0;
522                } else if (b instanceof Complex) {
523                        return ((Complex) b).getImaginary();
524                } else if (b.getClass().isArray()) {
525                        if (Array.getLength(b) < 2)
526                                return 0;
527                        return toReal(Array.get(b, 1));
528                } else if (b instanceof Dataset) {
529                        Dataset db = (Dataset) b;
530                        if (db.getSize() != 1) {
531                                logger.error("Given dataset must have only one item");
532                                throw new IllegalArgumentException("Given dataset must have only one item");
533                        }
534                        return toImag(db.getObjectAbs(db.getOffset()));
535                } else if (b instanceof IDataset) {
536                        IDataset db = (Dataset) b;
537                        if (db.getSize() != 1) {
538                                logger.error("Given dataset must have only one item");
539                                throw new IllegalArgumentException("Given dataset must have only one item");
540                        }
541                        return toImag(db.getObject(new int[db.getRank()]));
542                } else {
543                        logger.error("Argument is of unsupported class");
544                        throw new IllegalArgumentException("Argument is of unsupported class");
545                }
546        }
547
548        public static double[] toDoubleArray(final Object b, final int itemSize) {
549                double[] result = null;
550
551                // ensure array is of given length
552                if (b instanceof Number) {
553                        result = new double[itemSize];
554                        final double val = ((Number) b).doubleValue();
555                        for (int i = 0; i < itemSize; i++) {
556                                result[i] = val;
557                        }
558                } else if (b instanceof double[]) {
559                        final double[] old = (double[]) b;
560                        result = old;
561                        final int ilen = old.length;
562                        if (ilen < itemSize) {
563                                result = new double[itemSize];
564                                for (int i = 0; i < ilen; i++) {
565                                        result[i] = old[i];
566                                }
567                        }
568                } else if (b instanceof List<?>) {
569                        result = new double[itemSize];
570                        List<?> jl = (List<?>) b;
571                        int ilen = jl.size();
572                        if (ilen > 0 && !(jl.get(0) instanceof Number)) {
573                                logger.error("Given array was not of a numerical primitive type");
574                                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
575                        }
576                        ilen = Math.min(itemSize, ilen);
577                        for (int i = 0; i < ilen; i++) {
578                                result[i] = toReal(jl.get(i));
579                        }
580                } else if (b.getClass().isArray()) {
581                        result = new double[itemSize];
582                        int ilen = Array.getLength(b);
583                        if (ilen > 0 && !(Array.get(b, 0) instanceof Number)) {
584                                logger.error("Given array was not of a numerical primitive type");
585                                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
586                        }
587                        ilen = Math.min(itemSize, ilen);
588                        for (int i = 0; i < ilen; i++) {
589                                result[i] = ((Number) Array.get(b, i)).doubleValue();
590                        }
591                } else if (b instanceof Complex) {
592                        if (itemSize > 2) {
593                                logger.error("Complex number will not fit in compound dataset");
594                                throw new IllegalArgumentException("Complex number will not fit in compound dataset");
595                        }
596                        Complex cb = (Complex) b;
597                        switch (itemSize) {
598                        default:
599                        case 0:
600                                break;
601                        case 1:
602                                result = new double[] {cb.getReal()};
603                                break;
604                        case 2:
605                                result = new double[] {cb.getReal(), cb.getImaginary()};
606                                break;
607                        }
608                } else if (b instanceof Dataset) {
609                        Dataset db = (Dataset) b;
610                        if (db.getSize() != 1) {
611                                logger.error("Given dataset must have only one item");
612                                throw new IllegalArgumentException("Given dataset must have only one item");
613                        }
614                        return toDoubleArray(db.getObjectAbs(db.getOffset()), itemSize);
615                } else if (b instanceof IDataset) {
616                        IDataset db = (Dataset) b;
617                        if (db.getSize() != 1) {
618                                logger.error("Given dataset must have only one item");
619                                throw new IllegalArgumentException("Given dataset must have only one item");
620                        }
621                        return toDoubleArray(db.getObject(new int[db.getRank()]), itemSize);
622                }
623
624                return result;
625        }
626
627        public static float[] toFloatArray(final Object b, final int itemSize) {
628                float[] result = null;
629
630                if (b instanceof Number) {
631                        result = new float[itemSize];
632                        final float val = ((Number) b).floatValue();
633                        for (int i = 0; i < itemSize; i++)
634                                result[i] = val;
635                } else if (b instanceof float[]) {
636                        final float[] old = (float[]) b;
637                        result = old;
638                        final int ilen = old.length;
639                        if (ilen < itemSize) {
640                                result = new float[itemSize];
641                                for (int i = 0; i < ilen; i++) {
642                                        result[i] = old[i];
643                                }
644                        }
645                } else if (b instanceof double[]) {
646                        final double[] old = (double[]) b;
647                        final int ilen = Math.min(itemSize, old.length);
648                        result = new float[itemSize];
649                        for (int i = 0; i < ilen; i++) {
650                                result[i] = (float) old[i];
651                        }
652                } else if (b instanceof List<?>) {
653                        result = new float[itemSize];
654                        List<?> jl = (List<?>) b;
655                        int ilen = jl.size();
656                        if (ilen > 0 && !(jl.get(0) instanceof Number)) {
657                                logger.error("Given array was not of a numerical primitive type");
658                                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
659                        }
660                        ilen = Math.min(itemSize, ilen);
661                        for (int i = 0; i < ilen; i++) {
662                                result[i] = (float) toReal(jl.get(i));
663                        }
664                } else if (b.getClass().isArray()) {
665                        result = new float[itemSize];
666                        int ilen = Array.getLength(b);
667                        if (ilen > 0 && !(Array.get(b, 0) instanceof Number)) {
668                                logger.error("Given array was not of a numerical primitive type");
669                                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
670                        }
671                        ilen = Math.min(itemSize, ilen);
672                        for (int i = 0; i < ilen; i++) {
673                                result[i] = ((Number) Array.get(b, i)).floatValue();
674                        }
675                } else if (b instanceof Complex) {
676                        if (itemSize > 2) {
677                                logger.error("Complex number will not fit in compound dataset");
678                                throw new IllegalArgumentException("Complex number will not fit in compound dataset");
679                        }
680                        Complex cb = (Complex) b;
681                        switch (itemSize) {
682                        default:
683                        case 0:
684                                break;
685                        case 1:
686                                result = new float[] {(float) cb.getReal()};
687                                break;
688                        case 2:
689                                result = new float[] {(float) cb.getReal(), (float) cb.getImaginary()};
690                                break;
691                        }
692                } else if (b instanceof Dataset) {
693                        Dataset db = (Dataset) b;
694                        if (db.getSize() != 1) {
695                                logger.error("Given dataset must have only one item");
696                                throw new IllegalArgumentException("Given dataset must have only one item");
697                        }
698                        return toFloatArray(db.getObjectAbs(db.getOffset()), itemSize);
699                } else if (b instanceof IDataset) {
700                        IDataset db = (Dataset) b;
701                        if (db.getSize() != 1) {
702                                logger.error("Given dataset must have only one item");
703                                throw new IllegalArgumentException("Given dataset must have only one item");
704                        }
705                        return toFloatArray(db.getObject(new int[db.getRank()]), itemSize);
706                }
707
708                return result;
709        }
710
711        public static long[] toLongArray(final Object b, final int itemSize) {
712                long[] result = null;
713
714                if (b instanceof Number) {
715                        result = new long[itemSize];
716                        final long val = toLong(b);
717                        for (int i = 0; i < itemSize; i++) {
718                                result[i] = val;
719                        }
720                } else if (b instanceof long[]) {
721                        final long[] old = (long[]) b;
722                        result = old;
723                        final int ilen = result.length;
724                        if (ilen < itemSize) {
725                                result = new long[itemSize];
726                                for (int i = 0; i < ilen; i++) {
727                                        result[i] = old[i];
728                                }
729                        }
730                } else if (b instanceof double[]) {
731                        final double[] old = (double[]) b;
732                        final int ilen = Math.min(itemSize, old.length);
733                        result = new long[itemSize];
734                        for (int i = 0; i < ilen; i++) {
735                                result[i] = toLong(old[i]);
736                        }
737                } else if (b instanceof List<?>) {
738                        result = new long[itemSize];
739                        List<?> jl = (List<?>) b;
740                        int ilen = jl.size();
741                        if (ilen > 0 && !(jl.get(0) instanceof Number)) {
742                                logger.error("Given array was not of a numerical primitive type");
743                                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
744                        }
745                        ilen = Math.min(itemSize, ilen);
746                        for (int i = 0; i < ilen; i++) {
747                                result[i] = toLong(jl.get(i));
748                        }
749                } else if (b.getClass().isArray()) {
750                        result = new long[itemSize];
751                        int ilen = Array.getLength(b);
752                        if (ilen > 0 && !(Array.get(b, 0) instanceof Number)) {
753                                logger.error("Given array was not of a numerical primitive type");
754                                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
755                        }
756                        ilen = Math.min(itemSize, ilen);
757                        for (int i = 0; i < ilen; i++) {
758                                result[i] = toLong(Array.get(b, i));
759                        }
760                } else if (b instanceof Complex) {
761                        if (itemSize > 2) {
762                                logger.error("Complex number will not fit in compound dataset");
763                                throw new IllegalArgumentException("Complex number will not fit in compound dataset");
764                        }
765                        Complex cb = (Complex) b;
766                        switch (itemSize) {
767                        default:
768                        case 0:
769                                break;
770                        case 1:
771                                result = new long[] {(long) cb.getReal()};
772                                break;
773                        case 2:
774                                result = new long[] {(long) cb.getReal(), (long) cb.getImaginary()};
775                                break;
776                        }
777                } else if (b instanceof Dataset) {
778                        Dataset db = (Dataset) b;
779                        if (db.getSize() != 1) {
780                                logger.error("Given dataset must have only one item");
781                                throw new IllegalArgumentException("Given dataset must have only one item");
782                        }
783                        return toLongArray(db.getObjectAbs(db.getOffset()), itemSize);
784                } else if (b instanceof IDataset) {
785                        IDataset db = (Dataset) b;
786                        if (db.getSize() != 1) {
787                                logger.error("Given dataset must have only one item");
788                                throw new IllegalArgumentException("Given dataset must have only one item");
789                        }
790                        return toLongArray(db.getObject(new int[db.getRank()]), itemSize);
791                }
792
793                return result;
794        }
795
796        public static int[] toIntegerArray(final Object b, final int itemSize) {
797                int[] result = null;
798
799                if (b instanceof Number) {
800                        result = new int[itemSize];
801                        final int val = (int) toLong(b);
802                        for (int i = 0; i < itemSize; i++) {
803                                result[i] = val;
804                        }
805                } else if (b instanceof int[]) {
806                        final int[] old = (int[]) b;
807                        result = old;
808                        final int ilen = result.length;
809                        if (ilen < itemSize) {
810                                result = new int[itemSize];
811                                for (int i = 0; i < ilen; i++) {
812                                        result[i] = old[i];
813                                }
814                        }
815                } else if (b instanceof double[]) {
816                        final double[] old = (double[]) b;
817                        final int ilen = Math.min(itemSize, old.length);
818                        result = new int[itemSize];
819                        for (int i = 0; i < ilen; i++) {
820                                result[i] = (int) toLong(old[i]);
821                        }
822                } else if (b instanceof List<?>) {
823                        result = new int[itemSize];
824                        List<?> jl = (List<?>) b;
825                        int ilen = jl.size();
826                        if (ilen > 0 && !(jl.get(0) instanceof Number)) {
827                                logger.error("Given array was not of a numerical primitive type");
828                                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
829                        }
830                        ilen = Math.min(itemSize, ilen);
831                        for (int i = 0; i < ilen; i++) {
832                                result[i] = (int) toLong(jl.get(i));
833                        }
834                } else if (b.getClass().isArray()) {
835                        result = new int[itemSize];
836                        int ilen = Array.getLength(b);
837                        if (ilen > 0 && !(Array.get(b, 0) instanceof Number)) {
838                                logger.error("Given array was not of a numerical primitive type");
839                                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
840                        }
841                        ilen = Math.min(itemSize, ilen);
842                        for (int i = 0; i < ilen; i++) {
843                                result[i] = (int) toLong(Array.get(b, i));
844                        }
845                } else if (b instanceof Complex) {
846                        if (itemSize > 2) {
847                                logger.error("Complex number will not fit in compound dataset");
848                                throw new IllegalArgumentException("Complex number will not fit in compound dataset");
849                        }
850                        Complex cb = (Complex) b;
851                        switch (itemSize) {
852                        default:
853                        case 0:
854                                break;
855                        case 1:
856                                result = new int[] {(int) cb.getReal()};
857                                break;
858                        case 2:
859                                result = new int[] {(int) cb.getReal(), (int) cb.getImaginary()};
860                                break;
861                        }
862                } else if (b instanceof Dataset) {
863                        Dataset db = (Dataset) b;
864                        if (db.getSize() != 1) {
865                                logger.error("Given dataset must have only one item");
866                                throw new IllegalArgumentException("Given dataset must have only one item");
867                        }
868                        return toIntegerArray(db.getObjectAbs(db.getOffset()), itemSize);
869                } else if (b instanceof IDataset) {
870                        IDataset db = (Dataset) b;
871                        if (db.getSize() != 1) {
872                                logger.error("Given dataset must have only one item");
873                                throw new IllegalArgumentException("Given dataset must have only one item");
874                        }
875                        return toIntegerArray(db.getObject(new int[db.getRank()]), itemSize);
876                }
877
878                return result;
879        }
880
881        public static short[] toShortArray(final Object b, final int itemSize) {
882                short[] result = null;
883
884                if (b instanceof Number) {
885                        result = new short[itemSize];
886                        final short val = (short) toLong(b);
887                        for (int i = 0; i < itemSize; i++) {
888                                result[i] = val;
889                        }
890                } else if (b instanceof short[]) {
891                        final short[] old = (short[]) b;
892                        result = old;
893                        final int ilen = result.length;
894                        if (ilen < itemSize) {
895                                result = new short[itemSize];
896                                for (int i = 0; i < ilen; i++) {
897                                        result[i] = old[i];
898                                }
899                        }
900                } else if (b instanceof double[]) {
901                        final double[] old = (double[]) b;
902                        final int ilen = Math.min(itemSize, old.length);
903                        result = new short[itemSize];
904                        for (int i = 0; i < ilen; i++) {
905                                result[i] = (short) toLong(old[i]);
906                        }
907                } else if (b instanceof List<?>) {
908                        result = new short[itemSize];
909                        List<?> jl = (List<?>) b;
910                        int ilen = jl.size();
911                        if (ilen > 0 && !(jl.get(0) instanceof Number)) {
912                                logger.error("Given array was not of a numerical primitive type");
913                                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
914                        }
915                        ilen = Math.min(itemSize, ilen);
916                        for (int i = 0; i < ilen; i++) {
917                                result[i] = (short) toLong(jl.get(i));
918                        }
919                } else if (b.getClass().isArray()) {
920                        result = new short[itemSize];
921                        int ilen = Array.getLength(b);
922                        if (ilen > 0 && !(Array.get(b, 0) instanceof Number)) {
923                                logger.error("Given array was not of a numerical primitive type");
924                                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
925                        }
926                        ilen = Math.min(itemSize, ilen);
927                        for (int i = 0; i < ilen; i++) {
928                                result[i] = (short) toLong(Array.get(b, i));
929                        }
930                } else if (b instanceof Complex) {
931                        if (itemSize > 2) {
932                                logger.error("Complex number will not fit in compound dataset");
933                                throw new IllegalArgumentException("Complex number will not fit in compound dataset");
934                        }
935                        Complex cb = (Complex) b;
936                        switch (itemSize) {
937                        default:
938                        case 0:
939                                break;
940                        case 1:
941                                result = new short[] {(short) cb.getReal()};
942                                break;
943                        case 2:
944                                result = new short[] {(short) cb.getReal(), (short) cb.getImaginary()};
945                                break;
946                        }
947                } else if (b instanceof Dataset) {
948                        Dataset db = (Dataset) b;
949                        if (db.getSize() != 1) {
950                                logger.error("Given dataset must have only one item");
951                                throw new IllegalArgumentException("Given dataset must have only one item");
952                        }
953                        return toShortArray(db.getObjectAbs(db.getOffset()), itemSize);
954                } else if (b instanceof IDataset) {
955                        IDataset db = (Dataset) b;
956                        if (db.getSize() != 1) {
957                                logger.error("Given dataset must have only one item");
958                                throw new IllegalArgumentException("Given dataset must have only one item");
959                        }
960                        return toShortArray(db.getObject(new int[db.getRank()]), itemSize);
961                }
962
963                return result;
964        }
965
966        public static byte[] toByteArray(final Object b, final int itemSize) {
967                byte[] result = null;
968
969                if (b instanceof Number) {
970                        result = new byte[itemSize];
971                        final byte val = (byte) toLong(b);
972                        for (int i = 0; i < itemSize; i++) {
973                                result[i] = val;
974                        }
975                } else if (b instanceof byte[]) {
976                        final byte[] old = (byte[]) b;
977                        result = old;
978                        final int ilen = result.length;
979                        if (ilen < itemSize) {
980                                result = new byte[itemSize];
981                                for (int i = 0; i < ilen; i++) {
982                                        result[i] = old[i];
983                                }
984                        }
985                } else if (b instanceof double[]) {
986                        final double[] old = (double[]) b;
987                        final int ilen = Math.min(itemSize, old.length);
988                        result = new byte[itemSize];
989                        for (int i = 0; i < ilen; i++) {
990                                result[i] = (byte) toLong(old[i]);
991                        }
992                } else if (b instanceof List<?>) {
993                        result = new byte[itemSize];
994                        List<?> jl = (List<?>) b;
995                        int ilen = jl.size();
996                        if (ilen > 0 && !(jl.get(0) instanceof Number)) {
997                                logger.error("Given array was not of a numerical primitive type");
998                                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
999                        }
1000                        ilen = Math.min(itemSize, ilen);
1001                        for (int i = 0; i < ilen; i++) {
1002                                result[i] = (byte) toLong(jl.get(i));
1003                        }
1004                } else if (b.getClass().isArray()) {
1005                        result = new byte[itemSize];
1006                        int ilen = Array.getLength(b);
1007                        if (ilen > 0 && !(Array.get(b, 0) instanceof Number)) {
1008                                logger.error("Given array was not of a numerical primitive type");
1009                                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
1010                        }
1011                        ilen = Math.min(itemSize, ilen);
1012                        for (int i = 0; i < ilen; i++) {
1013                                result[i] = (byte) toLong(Array.get(b, i));
1014                        }
1015                } else if (b instanceof Complex) {
1016                        if (itemSize > 2) {
1017                                logger.error("Complex number will not fit in compound dataset");
1018                                throw new IllegalArgumentException("Complex number will not fit in compound dataset");
1019                        }
1020                        Complex cb = (Complex) b;
1021                        switch (itemSize) {
1022                        default:
1023                        case 0:
1024                                break;
1025                        case 1:
1026                                result = new byte[] {(byte) cb.getReal()};
1027                                break;
1028                        case 2:
1029                                result = new byte[] {(byte) cb.getReal(), (byte) cb.getImaginary()};
1030                                break;
1031                        }
1032                } else if (b instanceof Dataset) {
1033                        Dataset db = (Dataset) b;
1034                        if (db.getSize() != 1) {
1035                                logger.error("Given dataset must have only one item");
1036                                throw new IllegalArgumentException("Given dataset must have only one item");
1037                        }
1038                        return toByteArray(db.getObjectAbs(db.getOffset()), itemSize);
1039                } else if (b instanceof IDataset) {
1040                        IDataset db = (Dataset) b;
1041                        if (db.getSize() != 1) {
1042                                logger.error("Given dataset must have only one item");
1043                                throw new IllegalArgumentException("Given dataset must have only one item");
1044                        }
1045                        return toByteArray(db.getObject(new int[db.getRank()]), itemSize);
1046                }
1047
1048                return result;
1049        }
1050
1051        public static Object fromDoublesToBiggestPrimitives(double[] x, int dtype) {
1052                switch (dtype) {
1053                case Dataset.BOOL:
1054                case Dataset.INT8:
1055                case Dataset.INT16:
1056                case Dataset.INT32:
1057                        int[] i32 = new int[x.length];
1058                        for (int i = 0; i < x.length; i++)
1059                                i32[i] = (int) (long) x[i];
1060                        return i32;
1061                case Dataset.INT64:
1062                        long[] i64 = new long[x.length];
1063                        for (int i = 0; i < x.length; i++)
1064                                i64[i] = (long) x[i];
1065                        return i64;
1066                case Dataset.FLOAT32:
1067                        float[] f32 = new float[x.length];
1068                        for (int i = 0; i < x.length; i++)
1069                                f32[i] = (float) x[i];
1070                        return f32;
1071                case Dataset.FLOAT64:
1072                        return x;
1073                }
1074                return null;
1075        }
1076
1077        /**
1078         * @param dtype
1079         * @return (boxed) class of constituent element
1080         */
1081        public static Class<?> getElementClass(final int dtype) {
1082                switch (dtype) {
1083                case Dataset.BOOL:
1084                        return Boolean.class;
1085                case Dataset.INT8:
1086                case Dataset.ARRAYINT8:
1087                        return Byte.class;
1088                case Dataset.INT16:
1089                case Dataset.ARRAYINT16:
1090                case Dataset.RGB:
1091                        return Short.class;
1092                case Dataset.INT32:
1093                case Dataset.ARRAYINT32:
1094                        return Integer.class;
1095                case Dataset.INT64:
1096                case Dataset.ARRAYINT64:
1097                        return Long.class;
1098                case Dataset.FLOAT32:
1099                case Dataset.ARRAYFLOAT32:
1100                        return Float.class;
1101                case Dataset.FLOAT64:
1102                case Dataset.ARRAYFLOAT64:
1103                        return Double.class;
1104                case Dataset.COMPLEX64:
1105                        return Float.class;
1106                case Dataset.COMPLEX128:
1107                        return Double.class;
1108                case Dataset.STRING:
1109                        return String.class;
1110                case Dataset.DATE:
1111                        return Date.class;
1112                }
1113                return Object.class;
1114        }
1115
1116        /**
1117         * @param dtype dataset type
1118         * @return dataset interface can be null
1119         * @since 2.3
1120         */
1121        public static Class<? extends Dataset> getInterface(final int dtype) {
1122                return dtype2Interface.get(dtype);
1123        }
1124
1125        /**
1126         * @param x
1127         * @param dtype
1128         * @return biggest native primitive if integer (should test for 64bit?)
1129         * @since 2.2
1130         */
1131        public static Number fromDoubleToBiggestNumber(double x, int dtype) {
1132                switch (dtype) {
1133                case Dataset.BOOL:
1134                case Dataset.INT8:
1135                case Dataset.INT16:
1136                case Dataset.INT32:
1137                        return Integer.valueOf((int) (long) x);
1138                case Dataset.INT64:
1139                        return Long.valueOf((long) x);
1140                case Dataset.FLOAT32:
1141                        return Float.valueOf((float) x);
1142                case Dataset.FLOAT64:
1143                        return Double.valueOf(x);
1144                }
1145                return null;
1146        }
1147
1148        /**
1149         * @param clazz
1150         * @return true if supported
1151         * @deprecated Use {@link InterfaceUtils#isElementSupported(Class)}
1152         */
1153        @Deprecated
1154        public static boolean isClassSupportedAsElement(Class<? extends Object> clazz) {
1155                return InterfaceUtils.isElementSupported(clazz);
1156        }
1157
1158        /**
1159         * @param b
1160         * @return length of object
1161         */
1162        public static final int getLength(final Object b) {
1163                if (b instanceof Number) {
1164                        return 1;
1165                } else if (b instanceof Complex) {
1166                        return 1;
1167                } else if (b instanceof List<?>) {
1168                        List<?> jl = (List<?>) b;
1169                        return jl.size();
1170                } else if (b.getClass().isArray()) {
1171                        return Array.getLength(b);
1172                } else if (b instanceof IDataset) {
1173                        IDataset db = (Dataset) b;
1174                        return db.getSize();
1175                }
1176
1177                throw new IllegalArgumentException("Cannot find length as object not supported");
1178        }
1179
1180        /**
1181         * @param a
1182         * @return name of dataset interface
1183         * @since 2.3
1184         */
1185        public static String getDatasetName(Dataset a) {
1186                return getDatasetName(a.getClass(), a.getElementsPerItem());
1187        }
1188
1189        /**
1190         * @param a
1191         * @return name of dataset interface
1192         * @since 2.3
1193         */
1194        public static String getDatasetName(ILazyDataset a) {
1195                if (a instanceof Dataset) {
1196                        return getDatasetName((Dataset) a);
1197                }
1198                int isize = a.getElementsPerItem();
1199                return getDatasetName(InterfaceUtils.getInterfaceFromClass(isize, a.getElementClass()), isize);
1200        }
1201
1202        /**
1203         * @param clazz dataset interface
1204         * @param itemSize
1205         * @return name of dataset interface
1206         * @since 2.3
1207         */
1208        public static String getDatasetName(final Class<? extends Dataset> clazz, int itemSize) {
1209                int bytes = InterfaceUtils.getItemBytes(1, clazz);
1210                if (InterfaceUtils.isComplex(clazz)) {
1211                        return "COMPLEX" + bytes*16;
1212                } else if (RGBDataset.class.equals(clazz)) {
1213                        return "RGB";
1214                }
1215
1216                String prefix = itemSize > 1 ? ("ARRAY of " + itemSize + " ") : "";
1217                if (InterfaceUtils.isFloating(clazz)) {
1218                        return prefix + "FLOAT" + bytes*8;
1219                }
1220                if (BooleanDataset.class.equals(clazz)) {
1221                        return prefix + "BOOLEAN";
1222                }
1223                if (StringDataset.class.equals(clazz)) {
1224                        return prefix + "STRING";
1225                }
1226                if (DateDataset.class.isAssignableFrom(clazz)) {
1227                        return prefix + "DATE";
1228                }
1229                if (ObjectDataset.class.equals(clazz)) {
1230                        return prefix + "OBJECT";
1231                }
1232
1233                return prefix + "INT" + bytes*8;
1234        }
1235}