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