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