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