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