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         * @param comp
406         * @return true if supported
407         */
408        public static boolean isClassSupportedAsElement(Class<? extends Object> comp) {
409                return comp.isPrimitive() || Number.class.isAssignableFrom(comp) || comp.equals(Boolean.class)
410                                || comp.equals(Complex.class) || comp.equals(String.class) || comp.equals(Date.class);
411        }
412
413        /**
414         * @param dtype
415         * @return number of elements per item
416         */
417        public static int getElementsPerItem(final int dtype) {
418                switch (dtype) {
419                case Dataset.ARRAYINT8:
420                case Dataset.ARRAYINT16:
421                case Dataset.ARRAYINT32:
422                case Dataset.ARRAYINT64:
423                case Dataset.ARRAYFLOAT32:
424                case Dataset.ARRAYFLOAT64:
425                        throw new UnsupportedOperationException("Multi-element type unsupported");
426                case Dataset.COMPLEX64:
427                case Dataset.COMPLEX128:
428                        return 2;
429                case Dataset.RGB:
430                        return 3;
431                }
432                return 1;
433        }
434
435        /**
436         * @param dtype
437         * @return length of single item in bytes
438         */
439        public static int getItemBytes(final int dtype) {
440                return getItemBytes(dtype, getElementsPerItem(dtype));
441        }
442
443        /**
444         * @param dtype
445         * @param isize
446         *            number of elements in an item
447         * @return length of single item in bytes
448         */
449        public static int getItemBytes(final int dtype, final int isize) {
450                int size;
451        
452                switch (dtype) {
453                case Dataset.BOOL:
454                        size = 1; // How is this defined?
455                        break;
456                case Dataset.INT8:
457                case Dataset.ARRAYINT8:
458                        size = Byte.SIZE / 8;
459                        break;
460                case Dataset.INT16:
461                case Dataset.ARRAYINT16:
462                case Dataset.RGB:
463                        size = Short.SIZE / 8;
464                        break;
465                case Dataset.INT32:
466                case Dataset.ARRAYINT32:
467                        size = Integer.SIZE / 8;
468                        break;
469                case Dataset.INT64:
470                case Dataset.ARRAYINT64:
471                        size = Long.SIZE / 8;
472                        break;
473                case Dataset.FLOAT32:
474                case Dataset.ARRAYFLOAT32:
475                case Dataset.COMPLEX64:
476                        size = Float.SIZE / 8;
477                        break;
478                case Dataset.FLOAT64:
479                case Dataset.ARRAYFLOAT64:
480                case Dataset.COMPLEX128:
481                        size = Double.SIZE / 8;
482                        break;
483                default:
484                        size = 0;
485                        break;
486                }
487        
488                return size * isize;
489        }
490
491        public static boolean toBoolean(final Object b) {
492                if (b instanceof Number) {
493                        return ((Number) b).longValue() != 0;
494                } else if (b instanceof Boolean) {
495                        return ((Boolean) b).booleanValue();
496                } else if (b instanceof Complex) {
497                        return ((Complex) b).getReal() != 0;
498                } else if (b instanceof Dataset) {
499                        Dataset db = (Dataset) b;
500                        if (db.getSize() != 1) {
501                                logger.error("Given dataset must have only one item");
502                                throw new IllegalArgumentException("Given dataset must have only one item");
503                        }
504                        return toBoolean(db.getObjectAbs(0));
505                } else if (b instanceof IDataset) {
506                        IDataset db = (IDataset) b;
507                        if (db.getSize() != 1) {
508                                logger.error("Given dataset must have only one item");
509                                throw new IllegalArgumentException("Given dataset must have only one item");
510                        }
511                        return toBoolean(db.getObject(new int[db.getRank()]));
512                } else {
513                        logger.error("Argument is of unsupported class");
514                        throw new IllegalArgumentException("Argument is of unsupported class");
515                }
516        }
517
518        public static long toLong(final Object b) {
519                if (b instanceof Number) {
520                        return ((Number) b).longValue();
521                } else if (b instanceof Boolean) {
522                        return ((Boolean) b).booleanValue() ? 1 : 0;
523                } else if (b instanceof Complex) {
524                        return (long) ((Complex) b).getReal();
525                } else if (b instanceof Dataset) {
526                        Dataset db = (Dataset) b;
527                        if (db.getSize() != 1) {
528                                logger.error("Given dataset must have only one item");
529                                throw new IllegalArgumentException("Given dataset must have only one item");
530                        }
531                        return toLong(db.getObjectAbs(0));
532                } else if (b instanceof IDataset) {
533                        IDataset db = (IDataset) b;
534                        if (db.getSize() != 1) {
535                                logger.error("Given dataset must have only one item");
536                                throw new IllegalArgumentException("Given dataset must have only one item");
537                        }
538                        return toLong(db.getObject(new int[db.getRank()]));
539                } else {
540                        logger.error("Argument is of unsupported class");
541                        throw new IllegalArgumentException("Argument is of unsupported class");
542                }
543        }
544
545        public static double toReal(final Object b) {
546                if (b instanceof Number) {
547                        return ((Number) b).doubleValue();
548                } else if (b instanceof Boolean) {
549                        return ((Boolean) b).booleanValue() ? 1 : 0;
550                } else if (b instanceof Complex) {
551                        return ((Complex) b).getReal();
552                } else if (b.getClass().isArray()) {
553                        if (Array.getLength(b) == 0)
554                                return 0;
555                        return toReal(Array.get(b, 0));
556                } else if (b instanceof Dataset) {
557                        Dataset db = (Dataset) 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 toReal(db.getObjectAbs(0));
563                } else if (b instanceof IDataset) {
564                        IDataset db = (Dataset) b;
565                        if (db.getSize() != 1) {
566                                logger.error("Given dataset must have only one item");
567                                throw new IllegalArgumentException("Given dataset must have only one item");
568                        }
569                        return toReal(db.getObject(new int[db.getRank()]));
570                } else {
571                        logger.error("Argument is of unsupported class");
572                        throw new IllegalArgumentException("Argument is of unsupported class");
573                }
574        }
575
576        public static double toImag(final Object b) {
577                if (b instanceof Number) {
578                        return 0;
579                } else if (b instanceof Boolean) {
580                        return 0;
581                } else if (b instanceof Complex) {
582                        return ((Complex) b).getImaginary();
583                } else if (b.getClass().isArray()) {
584                        if (Array.getLength(b) < 2)
585                                return 0;
586                        return toReal(Array.get(b, 1));
587                } else if (b instanceof Dataset) {
588                        Dataset 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 toImag(db.getObjectAbs(0));
594                } else if (b instanceof IDataset) {
595                        IDataset db = (Dataset) b;
596                        if (db.getSize() != 1) {
597                                logger.error("Given dataset must have only one item");
598                                throw new IllegalArgumentException("Given dataset must have only one item");
599                        }
600                        return toImag(db.getObject(new int[db.getRank()]));
601                } else {
602                        logger.error("Argument is of unsupported class");
603                        throw new IllegalArgumentException("Argument is of unsupported class");
604                }
605        }
606
607        public static double[] toDoubleArray(final Object b, final int itemSize) {
608                double[] result = null;
609        
610                // ensure array is of given length
611                if (b instanceof Number) {
612                        result = new double[itemSize];
613                        double val = ((Number) b).doubleValue();
614                        for (int i = 0; i < itemSize; i++)
615                                result[i] = val;
616                } else if (b instanceof double[]) {
617                        result = (double[]) b;
618                        if (result.length < itemSize) {
619                                result = new double[itemSize];
620                                int ilen = result.length;
621                                for (int i = 0; i < ilen; i++)
622                                        result[i] = ((double[]) b)[i];
623                        }
624                } else if (b instanceof List<?>) {
625                        result = new double[itemSize];
626                        List<?> jl = (List<?>) b;
627                        int ilen = jl.size();
628                        if (ilen > 0 && !(jl.get(0) instanceof Number)) {
629                                logger.error("Given array was not of a numerical primitive type");
630                                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
631                        }
632                        ilen = Math.min(itemSize, ilen);
633                        for (int i = 0; i < ilen; i++) {
634                                result[i] = toReal(jl.get(i));
635                        }
636                } else if (b.getClass().isArray()) {
637                        result = new double[itemSize];
638                        int ilen = Array.getLength(b);
639                        if (ilen > 0 && !(Array.get(b, 0) instanceof Number)) {
640                                logger.error("Given array was not of a numerical primitive type");
641                                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
642                        }
643                        ilen = Math.min(itemSize, ilen);
644                        for (int i = 0; i < ilen; i++)
645                                result[i] = ((Number) Array.get(b, i)).doubleValue();
646                } else if (b instanceof Complex) {
647                        if (itemSize > 2) {
648                                logger.error("Complex number will not fit in compound dataset");
649                                throw new IllegalArgumentException("Complex number will not fit in compound dataset");
650                        }
651                        Complex cb = (Complex) b;
652                        switch (itemSize) {
653                        default:
654                        case 0:
655                                break;
656                        case 1:
657                                result = new double[] {cb.getReal()};
658                                break;
659                        case 2:
660                                result = new double[] {cb.getReal(), cb.getImaginary()};
661                                break;
662                        }
663                } else if (b instanceof Dataset) {
664                        Dataset db = (Dataset) b;
665                        if (db.getSize() != 1) {
666                                logger.error("Given dataset must have only one item");
667                                throw new IllegalArgumentException("Given dataset must have only one item");
668                        }
669                        return toDoubleArray(db.getObjectAbs(0), itemSize);
670                } else if (b instanceof IDataset) {
671                        IDataset db = (Dataset) b;
672                        if (db.getSize() != 1) {
673                                logger.error("Given dataset must have only one item");
674                                throw new IllegalArgumentException("Given dataset must have only one item");
675                        }
676                        return toDoubleArray(db.getObject(new int[db.getRank()]), itemSize);
677                }
678        
679                return result;
680        }
681
682        public static float[] toFloatArray(final Object b, final int itemSize) {
683                float[] result = null;
684        
685                if (b instanceof Number) {
686                        result = new float[itemSize];
687                        float val = ((Number) b).floatValue();
688                        for (int i = 0; i < itemSize; i++)
689                                result[i] = val;
690                } else if (b instanceof float[]) {
691                        result = (float[]) b;
692                        if (result.length < itemSize) {
693                                result = new float[itemSize];
694                                int ilen = result.length;
695                                for (int i = 0; i < ilen; i++)
696                                        result[i] = ((float[]) b)[i];
697                        }
698                } else if (b instanceof List<?>) {
699                        result = new float[itemSize];
700                        List<?> jl = (List<?>) b;
701                        int ilen = jl.size();
702                        if (ilen > 0 && !(jl.get(0) instanceof Number)) {
703                                logger.error("Given array was not of a numerical primitive type");
704                                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
705                        }
706                        ilen = Math.min(itemSize, ilen);
707                        for (int i = 0; i < ilen; i++) {
708                                result[i] = (float) toReal(jl.get(i));
709                        }
710                } else if (b.getClass().isArray()) {
711                        result = new float[itemSize];
712                        int ilen = Array.getLength(b);
713                        if (ilen > 0 && !(Array.get(b, 0) instanceof Number)) {
714                                logger.error("Given array was not of a numerical primitive type");
715                                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
716                        }
717                        ilen = Math.min(itemSize, ilen);
718                        for (int i = 0; i < ilen; i++)
719                                result[i] = ((Number) Array.get(b, i)).floatValue();
720                } else if (b instanceof Complex) {
721                        if (itemSize > 2) {
722                                logger.error("Complex number will not fit in compound dataset");
723                                throw new IllegalArgumentException("Complex number will not fit in compound dataset");
724                        }
725                        Complex cb = (Complex) b;
726                        switch (itemSize) {
727                        default:
728                        case 0:
729                                break;
730                        case 1:
731                                result = new float[] {(float) cb.getReal()};
732                                break;
733                        case 2:
734                                result = new float[] {(float) cb.getReal(), (float) cb.getImaginary()};
735                                break;
736                        }
737                } else if (b instanceof Dataset) {
738                        Dataset db = (Dataset) b;
739                        if (db.getSize() != 1) {
740                                logger.error("Given dataset must have only one item");
741                                throw new IllegalArgumentException("Given dataset must have only one item");
742                        }
743                        return toFloatArray(db.getObjectAbs(0), itemSize);
744                } else if (b instanceof IDataset) {
745                        IDataset db = (Dataset) b;
746                        if (db.getSize() != 1) {
747                                logger.error("Given dataset must have only one item");
748                                throw new IllegalArgumentException("Given dataset must have only one item");
749                        }
750                        return toFloatArray(db.getObject(new int[db.getRank()]), itemSize);
751                }
752        
753                return result;
754        }
755
756        public static long[] toLongArray(final Object b, final int itemSize) {
757                long[] result = null;
758        
759                if (b instanceof Number) {
760                        result = new long[itemSize];
761                        long val = ((Number) b).longValue();
762                        for (int i = 0; i < itemSize; i++)
763                                result[i] = val;
764                } else if (b instanceof long[]) {
765                        result = (long[]) b;
766                        if (result.length < itemSize) {
767                                result = new long[itemSize];
768                                int ilen = result.length;
769                                for (int i = 0; i < ilen; i++)
770                                        result[i] = ((long[]) b)[i];
771                        }
772                } else if (b instanceof List<?>) {
773                        result = new long[itemSize];
774                        List<?> jl = (List<?>) b;
775                        int ilen = jl.size();
776                        if (ilen > 0 && !(jl.get(0) instanceof Number)) {
777                                logger.error("Given array was not of a numerical primitive type");
778                                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
779                        }
780                        ilen = Math.min(itemSize, ilen);
781                        for (int i = 0; i < ilen; i++) {
782                                result[i] = toLong(jl.get(i));
783                        }
784                } else if (b.getClass().isArray()) {
785                        result = new long[itemSize];
786                        int ilen = Array.getLength(b);
787                        if (ilen > 0 && !(Array.get(b, 0) instanceof Number)) {
788                                logger.error("Given array was not of a numerical primitive type");
789                                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
790                        }
791                        ilen = Math.min(itemSize, ilen);
792                        for (int i = 0; i < ilen; i++)
793                                result[i] = ((Number) Array.get(b, i)).longValue();
794                } else if (b instanceof Complex) {
795                        if (itemSize > 2) {
796                                logger.error("Complex number will not fit in compound dataset");
797                                throw new IllegalArgumentException("Complex number will not fit in compound dataset");
798                        }
799                        Complex cb = (Complex) b;
800                        switch (itemSize) {
801                        default:
802                        case 0:
803                                break;
804                        case 1:
805                                result = new long[] {(long) cb.getReal()};
806                                break;
807                        case 2:
808                                result = new long[] {(long) cb.getReal(), (long) cb.getImaginary()};
809                                break;
810                        }
811                } else if (b instanceof Dataset) {
812                        Dataset db = (Dataset) b;
813                        if (db.getSize() != 1) {
814                                logger.error("Given dataset must have only one item");
815                                throw new IllegalArgumentException("Given dataset must have only one item");
816                        }
817                        return toLongArray(db.getObjectAbs(0), itemSize);
818                } else if (b instanceof IDataset) {
819                        IDataset db = (Dataset) b;
820                        if (db.getSize() != 1) {
821                                logger.error("Given dataset must have only one item");
822                                throw new IllegalArgumentException("Given dataset must have only one item");
823                        }
824                        return toLongArray(db.getObject(new int[db.getRank()]), itemSize);
825                }
826        
827                return result;
828        }
829
830        public static int[] toIntegerArray(final Object b, final int itemSize) {
831                int[] result = null;
832        
833                if (b instanceof Number) {
834                        result = new int[itemSize];
835                        int val = ((Number) b).intValue();
836                        for (int i = 0; i < itemSize; i++)
837                                result[i] = val;
838                } else if (b instanceof int[]) {
839                        result = (int[]) b;
840                        if (result.length < itemSize) {
841                                result = new int[itemSize];
842                                int ilen = result.length;
843                                for (int i = 0; i < ilen; i++)
844                                        result[i] = ((int[]) b)[i];
845                        }
846                } else if (b instanceof List<?>) {
847                        result = new int[itemSize];
848                        List<?> jl = (List<?>) b;
849                        int ilen = jl.size();
850                        if (ilen > 0 && !(jl.get(0) instanceof Number)) {
851                                logger.error("Given array was not of a numerical primitive type");
852                                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
853                        }
854                        ilen = Math.min(itemSize, ilen);
855                        for (int i = 0; i < ilen; i++) {
856                                result[i] = (int) toLong(jl.get(i));
857                        }
858                } else if (b.getClass().isArray()) {
859                        result = new int[itemSize];
860                        int ilen = Array.getLength(b);
861                        if (ilen > 0 && !(Array.get(b, 0) instanceof Number)) {
862                                logger.error("Given array was not of a numerical primitive type");
863                                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
864                        }
865                        ilen = Math.min(itemSize, ilen);
866                        for (int i = 0; i < ilen; i++)
867                                result[i] = (int) ((Number) Array.get(b, i)).longValue();
868                } else if (b instanceof Complex) {
869                        if (itemSize > 2) {
870                                logger.error("Complex number will not fit in compound dataset");
871                                throw new IllegalArgumentException("Complex number will not fit in compound dataset");
872                        }
873                        Complex cb = (Complex) b;
874                        switch (itemSize) {
875                        default:
876                        case 0:
877                                break;
878                        case 1:
879                                result = new int[] {(int) cb.getReal()};
880                                break;
881                        case 2:
882                                result = new int[] {(int) cb.getReal(), (int) cb.getImaginary()};
883                                break;
884                        }
885                } else if (b instanceof Dataset) {
886                        Dataset db = (Dataset) b;
887                        if (db.getSize() != 1) {
888                                logger.error("Given dataset must have only one item");
889                                throw new IllegalArgumentException("Given dataset must have only one item");
890                        }
891                        return toIntegerArray(db.getObjectAbs(0), itemSize);
892                } else if (b instanceof IDataset) {
893                        IDataset db = (Dataset) b;
894                        if (db.getSize() != 1) {
895                                logger.error("Given dataset must have only one item");
896                                throw new IllegalArgumentException("Given dataset must have only one item");
897                        }
898                        return toIntegerArray(db.getObject(new int[db.getRank()]), itemSize);
899                }
900        
901                return result;
902        }
903
904        public static short[] toShortArray(final Object b, final int itemSize) {
905                short[] result = null;
906        
907                if (b instanceof Number) {
908                        result = new short[itemSize];
909                        short val = ((Number) b).shortValue();
910                        for (int i = 0; i < itemSize; i++)
911                                result[i] = val;
912                } else if (b instanceof short[]) {
913                        result = (short[]) b;
914                        if (result.length < itemSize) {
915                                result = new short[itemSize];
916                                int ilen = result.length;
917                                for (int i = 0; i < ilen; i++)
918                                        result[i] = ((short[]) b)[i];
919                        }
920                } else if (b instanceof List<?>) {
921                        result = new short[itemSize];
922                        List<?> jl = (List<?>) b;
923                        int ilen = jl.size();
924                        if (ilen > 0 && !(jl.get(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] = (short) toLong(jl.get(i));
931                        }
932                } else if (b.getClass().isArray()) {
933                        result = new short[itemSize];
934                        int ilen = Array.getLength(b);
935                        if (ilen > 0 && !(Array.get(b, 0) instanceof Number)) {
936                                logger.error("Given array was not of a numerical primitive type");
937                                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
938                        }
939                        ilen = Math.min(itemSize, ilen);
940                        for (int i = 0; i < ilen; i++)
941                                result[i] = (short) ((Number) Array.get(b, i)).longValue();
942                } else if (b instanceof Complex) {
943                        if (itemSize > 2) {
944                                logger.error("Complex number will not fit in compound dataset");
945                                throw new IllegalArgumentException("Complex number will not fit in compound dataset");
946                        }
947                        Complex cb = (Complex) b;
948                        switch (itemSize) {
949                        default:
950                        case 0:
951                                break;
952                        case 1:
953                                result = new short[] {(short) cb.getReal()};
954                                break;
955                        case 2:
956                                result = new short[] {(short) cb.getReal(), (short) cb.getImaginary()};
957                                break;
958                        }
959                } else if (b instanceof Dataset) {
960                        Dataset db = (Dataset) b;
961                        if (db.getSize() != 1) {
962                                logger.error("Given dataset must have only one item");
963                                throw new IllegalArgumentException("Given dataset must have only one item");
964                        }
965                        return toShortArray(db.getObjectAbs(0), itemSize);
966                } else if (b instanceof IDataset) {
967                        IDataset db = (Dataset) b;
968                        if (db.getSize() != 1) {
969                                logger.error("Given dataset must have only one item");
970                                throw new IllegalArgumentException("Given dataset must have only one item");
971                        }
972                        return toShortArray(db.getObject(new int[db.getRank()]), itemSize);
973                }
974        
975                return result;
976        }
977
978        public static byte[] toByteArray(final Object b, final int itemSize) {
979                byte[] result = null;
980        
981                if (b instanceof Number) {
982                        result = new byte[itemSize];
983                        final byte val = ((Number) b).byteValue();
984                        for (int i = 0; i < itemSize; i++) {
985                                result[i] = val;
986                        }
987                } else if (b instanceof byte[]) {
988                        result = (byte[]) b;
989                        if (result.length < itemSize) {
990                                result = new byte[itemSize];
991                                int ilen = result.length;
992                                for (int i = 0; i < ilen; i++) {
993                                        result[i] = ((byte[]) b)[i];
994                                }
995                        }
996                } else if (b instanceof List<?>) {
997                        result = new byte[itemSize];
998                        List<?> jl = (List<?>) b;
999                        int ilen = jl.size();
1000                        if (ilen > 0 && !(jl.get(0) instanceof Number)) {
1001                                logger.error("Given array was not of a numerical primitive type");
1002                                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
1003                        }
1004                        ilen = Math.min(itemSize, ilen);
1005                        for (int i = 0; i < ilen; i++) {
1006                                result[i] = (byte) toLong(jl.get(i));
1007                        }
1008                } else if (b.getClass().isArray()) {
1009                        result = new byte[itemSize];
1010                        int ilen = Array.getLength(b);
1011                        if (ilen > 0 && !(Array.get(b, 0) instanceof Number)) {
1012                                logger.error("Given array was not of a numerical primitive type");
1013                                throw new IllegalArgumentException("Given array was not of a numerical primitive type");
1014                        }
1015                        ilen = Math.min(itemSize, ilen);
1016                        for (int i = 0; i < ilen; i++) {
1017                                result[i] = (byte) ((Number) Array.get(b, i)).longValue();
1018                        }
1019                } else if (b instanceof Complex) {
1020                        if (itemSize > 2) {
1021                                logger.error("Complex number will not fit in compound dataset");
1022                                throw new IllegalArgumentException("Complex number will not fit in compound dataset");
1023                        }
1024                        Complex cb = (Complex) b;
1025                        switch (itemSize) {
1026                        default:
1027                        case 0:
1028                                break;
1029                        case 1:
1030                                result = new byte[] {(byte) cb.getReal()};
1031                                break;
1032                        case 2:
1033                                result = new byte[] {(byte) cb.getReal(), (byte) cb.getImaginary()};
1034                                break;
1035                        }
1036                } else if (b instanceof Dataset) {
1037                        Dataset db = (Dataset) b;
1038                        if (db.getSize() != 1) {
1039                                logger.error("Given dataset must have only one item");
1040                                throw new IllegalArgumentException("Given dataset must have only one item");
1041                        }
1042                        return toByteArray(db.getObjectAbs(0), itemSize);
1043                } else if (b instanceof IDataset) {
1044                        IDataset db = (Dataset) b;
1045                        if (db.getSize() != 1) {
1046                                logger.error("Given dataset must have only one item");
1047                                throw new IllegalArgumentException("Given dataset must have only one item");
1048                        }
1049                        return toByteArray(db.getObject(new int[db.getRank()]), itemSize);
1050                }
1051        
1052                return result;
1053        }
1054
1055        public static Object fromDoublesToBiggestPrimitives(double[] x, int dtype) {
1056                switch (dtype) {
1057                case Dataset.BOOL:
1058                case Dataset.INT8:
1059                case Dataset.INT16:
1060                case Dataset.INT32:
1061                        int[] i32 = new int[x.length];
1062                        for (int i = 0; i < x.length; i++)
1063                                i32[i] = (int) (long) x[i];
1064                        return i32;
1065                case Dataset.INT64:
1066                        long[] i64 = new long[x.length];
1067                        for (int i = 0; i < x.length; i++)
1068                                i64[i] = (long) x[i];
1069                        return i64;
1070                case Dataset.FLOAT32:
1071                        float[] f32 = new float[x.length];
1072                        for (int i = 0; i < x.length; i++)
1073                                f32[i] = (float) x[i];
1074                        return f32;
1075                case Dataset.FLOAT64:
1076                        return x;
1077                }
1078                return null;
1079        }
1080
1081        /**
1082         * @param x
1083         * @param dtype
1084         * @return biggest native primitive if integer (should test for 64bit?)
1085         */
1086        public static Number fromDoubleToBiggestNumber(double x, int dtype) {
1087                switch (dtype) {
1088                case Dataset.BOOL:
1089                case Dataset.INT8:
1090                case Dataset.INT16:
1091                case Dataset.INT32:
1092                        return Integer.valueOf((int) (long) x);
1093                case Dataset.INT64:
1094                        return Long.valueOf((long) x);
1095                case Dataset.FLOAT32:
1096                        return Float.valueOf((float) x);
1097                case Dataset.FLOAT64:
1098                        return Double.valueOf(x);
1099                }
1100                return null;
1101        }
1102
1103        /**
1104         * @param b
1105         * @return length of object
1106         */
1107        public static final int getLength(final Object b) {
1108                if (b instanceof Number) {
1109                        return 1;
1110                } else if (b instanceof Complex) {
1111                        return 1;
1112                } else if (b instanceof List<?>) {
1113                        List<?> jl = (List<?>) b;
1114                        return jl.size();
1115                } else if (b.getClass().isArray()) {
1116                        return Array.getLength(b);
1117                } else if (b instanceof IDataset) {
1118                        IDataset db = (Dataset) b;
1119                        return db.getSize();
1120                }
1121        
1122                throw new IllegalArgumentException("Cannot find length as object not supported");
1123        }
1124
1125        /**
1126         * @param dtype
1127         * @return (boxed) class of constituent element
1128         */
1129        public static Class<?> getElementClass(final int dtype) {
1130                switch (dtype) {
1131                case Dataset.BOOL:
1132                        return Boolean.class;
1133                case Dataset.INT8:
1134                case Dataset.ARRAYINT8:
1135                        return Byte.class;
1136                case Dataset.INT16:
1137                case Dataset.ARRAYINT16:
1138                case Dataset.RGB:
1139                        return Short.class;
1140                case Dataset.INT32:
1141                case Dataset.ARRAYINT32:
1142                        return Integer.class;
1143                case Dataset.INT64:
1144                case Dataset.ARRAYINT64:
1145                        return Long.class;
1146                case Dataset.FLOAT32:
1147                case Dataset.ARRAYFLOAT32:
1148                        return Float.class;
1149                case Dataset.FLOAT64:
1150                case Dataset.ARRAYFLOAT64:
1151                        return Double.class;
1152                case Dataset.COMPLEX64:
1153                        return Float.class;
1154                case Dataset.COMPLEX128:
1155                        return Double.class;
1156                case Dataset.STRING:
1157                        return String.class;
1158                case Dataset.DATE:
1159                        return Date.class;
1160                }
1161                return Object.class;
1162        }
1163
1164}