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