001/*-
002 *******************************************************************************
003 * Copyright (c) 2011, 2016 Diamond Light Source Ltd.
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 * Contributors:
010 *    Peter Chang - initial API and implementation and/or initial documentation
011 *******************************************************************************/
012
013package org.eclipse.january.dataset;
014
015import java.util.Date;
016import java.util.List;
017
018public class DatasetFactory {
019
020        /**
021         * Create dataset with items ranging from 0 up to given stop in steps of 1
022         * @param stop stop value is <strong>not</strong> included
023         * @param dtype dataset type
024         * @return a new dataset of given shape and type, filled with values determined by parameters
025         * 
026         * @deprecated Please use the class-based methods in DatasetFactory,
027         *             such as {@link #createRange(Class, double)}
028         */
029        @Deprecated
030        public static Dataset createRange(final double stop, final int dtype) {
031                return createRange(0, stop, 1, dtype);
032        }
033
034        /**
035         * Create dataset with items ranging from given start up to given stop in given steps
036         * @param start start value start value
037         * @param stop stop value is <strong>not</strong> included
038         * @param step spacing between items
039         * @param dtype dataset type
040         * @return a new 1D dataset of given type, filled with values determined by parameters
041         * 
042         * @deprecated Please use the class-based methods in DatasetFactory,
043         *             such as {@link #createRange(Class, double, double, double)}
044         */
045        @Deprecated
046        public static Dataset createRange(final double start, final double stop, final double step, final int dtype) {
047                return createRange(DTypeUtils.getInterface(dtype), start, stop, step);
048        }
049
050        /**
051         * Create compound dataset with items of given size ranging from 0 up to given stop in steps of 1
052         * @param itemSize item size
053         * @param stop stop value is <strong>not</strong> included
054         * @param dtype dataset type
055         * @return a new dataset of given shape and type, filled with values determined by parameters
056         * 
057         * @deprecated Please use the class-based methods in DatasetFactory,
058         *             such as {@link #createRange(int, Class, double)}
059         */
060        @Deprecated
061        public static CompoundDataset createRange(final int itemSize, final double stop, final int dtype) {
062                return createRange(itemSize, 0, stop, 1, dtype);
063        }
064
065        /**
066         * Create compound dataset with items of given size ranging from given start up to given stop in given steps
067         * @param itemSize item size
068         * @param start start value
069         * @param stop stop value is <strong>not</strong> included
070         * @param step spacing between items
071         * @param dtype dataset type
072         * @return a new 1D dataset of given type, filled with values determined by parameters
073         * 
074         * @deprecated Please use the class-based methods in DatasetFactory,
075         *             such as {@link #createRange(int, Class, double, double, double)}
076         */
077        @Deprecated
078        public static CompoundDataset createRange(final int itemSize, final double start, final double stop, final double step, final int dtype) {
079                Class<? extends CompoundDataset> clazz = InterfaceUtils.getCompoundInterface(DTypeUtils.getInterface(dtype));
080                return createRange(itemSize, clazz, start, stop, step);
081        }
082
083        /**
084         * Create a dataset from object
085         * @param dtype dataset type
086         * @param obj
087         *            can be a Java list, array or Number
088         * @return dataset
089         * @throws IllegalArgumentException if dataset type is not known
090         * 
091         * @deprecated Please use the class-based methods in DatasetFactory,
092         *             such as {@link #createFromObject(Class, Object, int...)}
093         */
094        @Deprecated
095        public static Dataset createFromObject(final int dtype, final Object obj) {
096                return createFromObject(dtype, obj, null);
097        }
098
099        /**
100         * Create a dataset from object
101         * @param dtype dataset type
102         * @param obj
103         *            can be a Java list, array or Number
104         * @param shape can be null
105         * @return dataset
106         * @throws IllegalArgumentException if dataset type is not known
107         * 
108         * @deprecated Please use the class-based methods in DatasetFactory,
109         *             such as {@link #createFromObject(Class, Object, int...)}
110         */
111        @Deprecated
112        public static Dataset createFromObject(final int dtype, final Object obj, final int... shape) {
113                return createFromObject(1, dtype, obj, shape);
114        }
115
116        /**
117         * Create a dataset from object
118         * @param itemSize item size
119         * @param dtype dataset type
120         * @param obj
121         *            can be a Java list, array or Number
122         * @param shape can be null
123         * @return dataset
124         * @throws IllegalArgumentException if dataset type is not known
125         * 
126         * @deprecated Please use the class-based methods in DatasetFactory,
127         *             such as {@link #createFromObject(int, Class, Object, int...)}
128         */
129        @Deprecated
130        public static Dataset createFromObject(final int itemSize, final int dtype, final Object obj, final int... shape) {
131                return createFromObject(itemSize, DTypeUtils.getInterface(dtype), obj, shape);
132        }
133
134        /**
135         * Create dataset of given type from list
136         *
137         * @param dtype dataset type
138         * @param objectList inputs
139         * @return dataset filled with values from list
140         * 
141         * @deprecated Please use the class-based methods in DatasetFactory,
142         *             such as {@link #createFromList(Class, List)}
143         */     
144        @Deprecated
145        public static Dataset createFromList(final int dtype, List<?> objectList) {
146                return createFromList(DTypeUtils.getInterface(dtype), objectList);
147        }
148
149        /**
150         * Create compound dataset of given type from given parts
151         *
152         * @param dtype dataset type
153         * @param objects inputs
154         * @return compound dataset
155         * 
156         * @deprecated Please use the class-based methods in DatasetFactory,
157         *             such as {@link #createCompoundDataset(Class, Object...)}
158         */
159        @Deprecated
160        public static CompoundDataset createCompoundDataset(final int dtype, Object... objects) {
161                return (CompoundDataset) createCompoundDataset(DTypeUtils.getInterface(dtype), objects);
162        }
163
164        /**
165         * Create complex dataset of given type from real and imaginary parts
166         *
167         * @param dtype dataset type
168         * @param real real part
169         * @param imag imaginary part
170         * @return complex dataset
171         * 
172         * @deprecated Please use the class-based methods in DatasetFactory,
173         *             such as {@link #createComplexDataset(Class, Object, Object)}
174         */
175        @Deprecated
176        public static CompoundDataset createComplexDataset(final int dtype, Object real, Object imag) {
177                return createComplexDataset(DTypeUtils.getInterface(dtype), real, imag);
178        }
179
180        /**
181         * @param shape output shape
182         * @param dtype dataset type
183         * @return a new dataset of given shape and type, filled with zeros
184         * 
185         * @deprecated Please use the class-based methods in DatasetFactory,
186         *             such as {@link #zeros(Class, int...)}
187         */
188        @Deprecated
189        public static Dataset zeros(final int[] shape, final int dtype) {
190                return zeros(DTypeUtils.getInterface(dtype), shape);
191        }
192
193        /**
194         * @param itemSize item size
195         *            if equal to 1, then non-compound dataset is returned
196         * @param shape output shape
197         * @param dtype dataset type
198         * @return a new dataset of given item size, shape and type, filled with zeros
199         * 
200         * @deprecated Please use the class-based methods in DatasetFactory,
201         *             such as {@link #zeros(int, Class, int...)}
202         */
203        @Deprecated
204        public static Dataset zeros(final int itemSize, final int[] shape, final int dtype) {
205                if (itemSize == 1) {
206                        return zeros(shape, dtype);
207                }
208                return compoundZeros(itemSize, shape, dtype);
209        }
210
211        /**
212         * @param itemSize item size
213         * @param shape output shape
214         * @param dtype dataset type
215         * @return a new dataset of given item size, shape and type, filled with zeros
216         * @since 2.0
217         * 
218         * @deprecated Please use the class-based methods in DatasetFactory,
219         *             such as {@link #compoundZeros(int, Class, int...)}
220         */
221        @Deprecated
222        public static CompoundDataset compoundZeros(final int itemSize, final int[] shape, final int dtype) {
223                return compoundZeros(itemSize, InterfaceUtils.getCompoundInterface(DTypeUtils.getInterface(dtype)), shape);
224        }
225
226        /**
227         * Create a new dataset of same shape as input dataset, filled with zeros. If dtype is not
228         * explicitly compound then an elemental dataset is created 
229         * @param dataset input
230         * @param dtype dataset type
231         * @return a new dataset
232         * 
233         * @deprecated Please use the class-based methods in DatasetFactory,
234         *             such as {@link #zeros(Dataset, Class)}
235         */
236        @Deprecated
237        public static Dataset zeros(final Dataset dataset, final int dtype) {
238                Class<? extends Dataset> clazz = DTypeUtils.getInterface(dtype);
239                final int isize = InterfaceUtils.isElemental(clazz) ? 1 :dataset.getElementsPerItem();
240
241                return zeros(isize, clazz, dataset.getShapeRef());
242        }
243
244        /**
245         * Create a new dataset of same shape as input dataset, filled with ones. If dtype is not
246         * explicitly compound then an elemental dataset is created
247         * @param dataset input
248         * @param dtype dataset type
249         * @return a new dataset
250         * 
251         * @deprecated Please use the class-based methods in DatasetFactory,
252         *             such as {@link #ones(Dataset, Class)}
253         */
254        @Deprecated
255        public static Dataset ones(final Dataset dataset, final int dtype) {
256                Class<? extends Dataset> clazz = DTypeUtils.getInterface(dtype);
257                final int isize = InterfaceUtils.isElemental(clazz) ? 1 :dataset.getElementsPerItem();
258
259                return ones(isize, clazz, dataset.getShapeRef());
260        }
261
262        /**
263         * @param shape output shape
264         * @param dtype dataset type
265         * @return a new dataset of given shape and type, filled with ones
266         * 
267         * @deprecated Please use the class-based methods in DatasetFactory,
268         *             such as {@link #ones(Class, int...)}
269         */
270        @Deprecated
271        public static Dataset ones(final int[] shape, final int dtype) {
272                return ones(DTypeUtils.getInterface(dtype), shape);
273        }
274
275        /**
276         * @param itemSize item size
277         *            if equal to 1, then non-compound dataset is returned
278         * @param shape output shape
279         * @param dtype dataset type
280         * @return a new dataset of given item size, shape and type, filled with ones
281         * 
282         * @deprecated Please use the class-based methods in DatasetFactory,
283         *             such as {@link #ones(Class, int...)}
284         */
285        @Deprecated
286        public static Dataset ones(final int itemSize, final int[] shape, final int dtype) {
287                return ones(itemSize, DTypeUtils.getInterface(dtype), shape);
288        }
289
290        /**
291         * Create a 1D dataset of linearly spaced values in closed interval
292         * 
293         * @param start start value
294         * @param stop stop value is included
295         * @param length number of points
296         * @param dtype dataset type
297         * @return dataset with linearly spaced values
298         * 
299         * @deprecated Please use the class-based methods in DatasetFactory,
300         *             such as {@link #createLinearSpace(Class, double, double, int)}
301         */
302        @Deprecated
303        public static Dataset createLinearSpace(final double start, final double stop, final int length, final int dtype) {
304                return createLinearSpace(DTypeUtils.getInterface(dtype), start, stop, length);
305        }
306
307        /**
308         * Create a 1D dataset of logarithmically spaced values in closed interval. The base value is used to
309         * determine the factor between values: factor = base ** step, where step is the interval between linearly
310         * spaced sequence of points
311         * 
312         * @param start start value
313         * @param stop stop value is included
314         * @param length number of points
315         * @param base for exponentiation
316         * @param dtype dataset type
317         * @return dataset with logarithmically spaced values
318         * 
319         * @deprecated Please use the class-based methods in DatasetFactory,
320         *             such as {@link #createLogSpace(Class, double, double, int, double)}
321         */
322        @Deprecated
323        public static Dataset createLogSpace(final double start, final double stop, final int length, final double base, final int dtype) {
324                return createLogSpace(DTypeUtils.getInterface(dtype), start, stop, length, base);
325        }
326
327        /**
328         * Create a 1D dataset of linearly spaced values in closed interval
329         * 
330         * @param <T> dataset sub-interface
331         * @param clazz dataset sub-interface
332         * @param start start value
333         * @param stop stop value is included
334         * @param length number of points
335         * @return dataset with linearly spaced values
336         */
337        public static <T extends Dataset> T createLinearSpace(Class<T> clazz, final double start, final double stop, final int length) {
338                if (length < 1) {
339                        throw new IllegalArgumentException("Length is less than one");
340                } else if (length == 1) {
341                        return createFromObject(clazz, start);
342                } else {
343                        T ds = zeros(clazz, length);
344                        double num = stop - start;
345                        double den = length - 1;
346                        double value;
347        
348                        for (int i = 0; i < length; i++) {
349                                value = start + (num * i) / den;
350                                ds.setObjectAbs(i, value);
351                        }
352        
353                        return ds;
354                }
355        }
356
357        /**
358         * Create a 1D dataset of logarithmically spaced values in closed interval. The base value is used to
359         * determine the factor between values: factor = base ** step, where step is the interval between linearly
360         * spaced sequence of points
361         * 
362         * @param <T> dataset sub-interface
363         * @param clazz dataset sub-interface
364         * @param start start value
365         * @param stop stop value is included
366         * @param length number of points
367         * @param base for exponentiation
368         * @return dataset with logarithmically spaced values
369         */
370        public static <T extends Dataset> T createLogSpace(Class<T> clazz, final double start, final double stop, final int length, final double base) {
371                if (length < 1) {
372                        throw new IllegalArgumentException("Length is less than one");
373                } else if (length == 1) {
374                        return createFromObject(clazz, Math.pow(base, start));
375                } else {
376                        T ds = zeros(clazz, length);
377                        double step = (stop - start) / (length - 1);
378                        double value;
379        
380                        for (int i = 0; i < length; i++) {
381                                value = start + i * step;
382                                ds.setObjectAbs(i, Math.pow(base, value));
383                        }
384        
385                        return ds;
386                }
387        }
388
389        /**
390         * Create dataset with items ranging from 0 up to given stop in steps of 1
391         * @param stop stop value is <strong>not</strong> included
392         * @return a new double dataset of given shape and type, filled with values determined by parameters
393         */
394        public static DoubleDataset createRange(final double stop) {
395                return createRange(DoubleDataset.class, 0, stop, 1);
396        }
397
398        /**
399         * Create dataset with items ranging from given start up to given stop in given steps
400         * @param start start value
401         * @param stop stop value is <strong>not</strong> included
402         * @param step spacing between items
403         * @return a new 1D dataset of given type, filled with values determined by parameters
404         * @since 2.1
405         */
406        public static DoubleDataset createRange(final double start, final double stop, final double step) {
407                return createRange(DoubleDataset.class, start, stop, step);
408        }
409
410        /**
411         * Create dataset with items ranging from 0 up to given stop in steps of 1
412         * @param <T> dataset sub-interface
413         * @param clazz dataset sub-interface
414         * @param stop stop value is <strong>not</strong> included
415         * @return a new dataset of given shape and class, filled with values determined by parameters
416         */
417        public static <T extends Dataset> T createRange(Class<T> clazz, final double stop) {
418                return createRange(clazz, 0, stop, 1);
419        }
420
421        /**
422         * Create dataset with items ranging from given start up to given stop in given steps
423         * @param <T> dataset sub-interface
424         * @param clazz dataset sub-interface
425         * @param start start value
426         * @param stop stop value is <strong>not</strong> included
427         * @param step spacing between items
428         * @return a new 1D dataset of given class, filled with values determined by parameters
429         */
430        @SuppressWarnings("unchecked")
431        public static <T extends Dataset> T createRange(Class<T> clazz, final double start, final double stop, final double step) {
432                if ((step > 0) != (start <= stop)) {
433                        throw new IllegalArgumentException("Invalid parameters: start and stop must be in correct order for step");
434                }
435
436                Dataset d = null;
437                if (ByteDataset.class.isAssignableFrom(clazz)) {
438                        d = ByteDataset.createRange(start, stop, step);
439                } else if (ShortDataset.class.isAssignableFrom(clazz)) {
440                        d = ShortDataset.createRange(start, stop, step);
441                } else if (IntegerDataset.class.isAssignableFrom(clazz)) {
442                        d = IntegerDataset.createRange(start, stop, step);
443                } else if (LongDataset.class.isAssignableFrom(clazz)) {
444                        d = LongDataset.createRange(start, stop, step);
445                } else if (FloatDataset.class.isAssignableFrom(clazz)) {
446                        d = FloatDataset.createRange(start, stop, step);
447                } else if (DoubleDataset.class.isAssignableFrom(clazz)) {
448                        d = DoubleDataset.createRange(start, stop, step);
449                } else if (ComplexFloatDataset.class.isAssignableFrom(clazz)) {
450                        d = ComplexFloatDataset.createRange(start, stop, step);
451                } else if (ComplexDoubleDataset.class.isAssignableFrom(clazz)) {
452                        d = ComplexDoubleDataset.createRange(start, stop, step);
453                } else {
454                        throw new IllegalArgumentException("Dataset interface not supported");
455                }
456
457                return (T) d;
458        }
459
460        /**
461         * Create compound dataset with items ranging from 0 up to given stop in steps of 1
462         * @param <T> compound dataset sub-interface
463         * @param itemSize item size
464         * @param clazz compound dataset sub-interface
465         * @param stop stop value is <strong>not</strong> included
466         * @return a new 1D dataset of given class, filled with values determined by parameters
467         * @since 2.1
468         */
469        public static <T extends CompoundDataset> T createRange(final int itemSize, Class<T> clazz, final double stop) {
470                return createRange(itemSize, clazz, 0, stop, 1);
471        }
472
473        /**
474         * Create compound dataset with items ranging from given start up to given stop in given steps
475         * @param <T> compound dataset sub-interface
476         * @param itemSize item size
477         * @param clazz compound dataset sub-interface
478         * @param start start value
479         * @param stop stop value is <strong>not</strong> included
480         * @param step spacing between items
481         * @return a new 1D dataset of given class, filled with values determined by parameters
482         * @since 2.1
483         */
484        @SuppressWarnings("unchecked")
485        public static <T extends CompoundDataset> T createRange(final int itemSize, Class<T> clazz, final double start, final double stop, final double step) {
486                if (itemSize < 1) {
487                        throw new IllegalArgumentException("Item size must be greater or equal to 1");
488                }
489                if ((step > 0) != (start <= stop)) {
490                        throw new IllegalArgumentException("Invalid parameters: start and stop must be in correct order for step");
491                }
492
493                CompoundDataset c = null;
494                if (CompoundByteDataset.class.isAssignableFrom(clazz)) {
495                        c = CompoundIntegerDataset.createRange(itemSize, start, stop, step);
496                } else if (CompoundShortDataset.class.isAssignableFrom(clazz)) {
497                        c = CompoundShortDataset.createRange(itemSize, start, stop, step);
498                } else if (CompoundIntegerDataset.class.isAssignableFrom(clazz)) {
499                        c = CompoundIntegerDataset.createRange(itemSize, start, stop, step);
500                } else if (CompoundLongDataset.class.isAssignableFrom(clazz)) {
501                        c = CompoundLongDataset.createRange(itemSize, start, stop, step);
502                } else if (ComplexFloatDataset.class.isAssignableFrom(clazz)) {
503                        if (itemSize != 2) {
504                                throw new IllegalArgumentException("Item size must be equal to 2");
505                        }
506                        c = ComplexFloatDataset.createRange(start, stop, step);
507                } else if (ComplexDoubleDataset.class.isAssignableFrom(clazz)) {
508                        if (itemSize != 2) {
509                                throw new IllegalArgumentException("Item size must be equal to 2");
510                        }
511                        c = ComplexDoubleDataset.createRange(start, stop, step);
512                } else if (CompoundFloatDataset.class.isAssignableFrom(clazz)) {
513                        c = CompoundFloatDataset.createRange(itemSize, start, stop, step);
514                } else if (CompoundDoubleDataset.class.isAssignableFrom(clazz)) {
515                        c = CompoundDoubleDataset.createRange(itemSize, start, stop, step);
516                } else {
517                        throw new IllegalArgumentException("dtype not known");
518                }
519                return (T) c;
520        }
521
522        /**
523         * Create a dataset from object (automatically detect dataset type)
524         *
525         * @param obj
526         *            can be Java list, array or Number
527         * @return dataset
528         */
529        public static Dataset createFromObject(Object obj) {
530                return createFromObject(obj, null);
531        }
532
533        /**
534         * Create a dataset from object (automatically detect dataset type)
535         * 
536         * @param obj
537         *            can be Java list, array or Number
538         * @param shape can be null
539         * @return dataset
540         */
541        public static Dataset createFromObject(Object obj, int... shape) {
542                if (obj instanceof IDataset) {
543                        Dataset d = DatasetUtils.convertToDataset((IDataset) obj);
544                        if (shape != null) {
545                                d.setShape(shape);
546                        }
547                        return d;
548                }
549        
550                return createFromObject(InterfaceUtils.getInterface(obj), obj, shape);
551        }
552
553        /**
554         * Create a dataset from object (automatically detect dataset type)
555         * @param isUnsigned
556         *            if true, interpret integer values as unsigned by increasing element bit width if required
557         * @param obj
558         *            can be a Java list, array or Number
559         * @return dataset
560         */
561        public static Dataset createFromObject(boolean isUnsigned, final Object obj) {
562                Dataset a = createFromObject(obj);
563                if (isUnsigned) {
564                        a = DatasetUtils.makeUnsigned(a, true);
565                }
566                return a;
567        }
568
569        /**
570         * Create dataset of appropriate type from list
571         * 
572         * @param objectList inputs for each item
573         * @return dataset filled with values from list
574         */
575        public static Dataset createFromList(List<?> objectList) {
576                if (objectList == null || objectList.size() == 0) {
577                        throw new IllegalArgumentException("No list or zero-length list given");
578                }
579        
580                Object obj = null;
581                for (Object o : objectList) {
582                        if (o != null) {
583                                obj = o;
584                                break;
585                        }
586                }
587                if (obj == null) {
588                        return zeros(ObjectDataset.class, objectList.size());
589                }
590        
591                Class<? extends Object> clazz = obj.getClass();
592                if (InterfaceUtils.isElementSupported(clazz)) {
593                        return createFromList(InterfaceUtils.getInterface(obj), objectList);
594                }
595        
596                return createFromObject(objectList);
597        }
598
599        /**
600         * Create compound dataset of given type from given parts
601         *
602         * @param objects inputs across dataset for each element
603         * @return compound dataset
604         */
605        public static CompoundDataset createCompoundDataset(Object... objects) {
606                Dataset[] datasets = new Dataset[objects.length];
607                for (int i = 0; i < objects.length; i++) {
608                        datasets[i] = createFromObject(objects[i]);
609                }
610                return DatasetUtils.createCompoundDataset(datasets);
611        }
612
613        /**
614         * Create a dataset from object
615         * @param <T> dataset sub-interface
616         * @param clazz dataset sub-interface
617         * @param obj
618         *            can be a Java list, array or Number
619         * @return dataset
620         * @throws IllegalArgumentException if dataset class is not known
621         * @since 2.1
622         */
623        public static <T extends Dataset> T createFromObject(Class<T> clazz, Object obj) {
624                return createFromObject(1, clazz, obj, null);
625        }
626
627
628        /**
629         * Create a dataset from object
630         * @param <T> dataset sub-interface
631         * @param clazz dataset sub-interface
632         * @param obj
633         *            can be a Java list, array or Number
634         * @param shape can be null
635         * @return dataset
636         */
637        public static <T extends Dataset> T createFromObject(Class<T> clazz, Object obj, int... shape) {
638                return createFromObject(1, clazz, obj, shape);
639        }
640
641        /**
642         * Create a compound dataset from object
643         * @param <T> compound dataset sub-interface
644         * @param itemSize item size
645         * @param clazz compound dataset sub-interface
646         * @param obj
647         *            can be a Java list, array or Number
648         * @param shape can be null
649         * @return dataset
650         */
651        @SuppressWarnings("unchecked")
652        public static <T extends Dataset> T createFromObject(final int itemSize, Class<T> clazz, Object obj, int... shape) {
653                Dataset d = null;
654
655                if (obj instanceof IDataset) {
656                        d = itemSize == 1 ? DatasetUtils.cast(clazz, (IDataset) obj) :
657                                DatasetUtils.cast(itemSize, clazz, (IDataset) obj, false);
658                } else {
659                        // primitive arrays
660                        Class<? extends Object> ca = obj == null ? null : obj.getClass().getComponentType();
661                        if (ca != null && (ca.isPrimitive() || ca.equals(String.class))) {
662                                if (ComplexFloatDataset.class.isAssignableFrom(clazz)) {
663                                        return (T) new ComplexFloatDataset(DTypeUtils.toFloatArray(obj, DTypeUtils.getLength(obj)), shape);
664                                } else if (ComplexDoubleDataset.class.isAssignableFrom(clazz)) {
665                                        return (T) new ComplexDoubleDataset(DTypeUtils.toDoubleArray(obj, DTypeUtils.getLength(obj)), shape);
666                                } else {
667                                        d = createFromPrimitiveArray(InterfaceUtils.getInterfaceFromClass(1, ca), obj);
668                                        if (!InterfaceUtils.isElemental(clazz)) {
669                                                if (RGBByteDataset.class.isAssignableFrom(clazz) || RGBDataset.class.isAssignableFrom(clazz)) {
670                                                        d = DatasetUtils.createCompoundDataset(d, 3);
671                                                        if (d.getSize() == 1) { // special case of allowing a zero-rank RGB dataset
672                                                                d.setShape();
673                                                        }
674                                                } else {
675                                                        d = DatasetUtils.createCompoundDataset(d, itemSize);
676                                                }
677                                        }
678                                        d = d.cast(clazz);
679                                }
680                        } else {
681//                              if (itemSize != 1 && !InterfaceUtils.isElemental(clazz)) {
682//                                      throw new IllegalArgumentException("Compound dataset interface needed for itemSize > 1");
683//                              }
684                                if (BooleanDataset.class.isAssignableFrom(clazz)) {
685                                        d = BooleanDataset.createFromObject(obj);
686                                } else if (ByteDataset.class.isAssignableFrom(clazz)) {
687                                        d = ByteDataset.createFromObject(obj);
688                                } else if (ShortDataset.class.isAssignableFrom(clazz)) {
689                                        d = ShortDataset.createFromObject(obj);
690                                } else if (IntegerDataset.class.isAssignableFrom(clazz)) {
691                                        d = IntegerDataset.createFromObject(obj);
692                                } else if (LongDataset.class.isAssignableFrom(clazz)) {
693                                        d = LongDataset.createFromObject(obj);
694                                } else if (RGBByteDataset.class.isAssignableFrom(clazz)) {
695                                        d = RGBByteDataset.createFromObject(obj);
696                                } else if (CompoundByteDataset.class.isAssignableFrom(clazz)) {
697                                        d = CompoundByteDataset.createFromObject(itemSize, obj);
698                                } else if (RGBDataset.class.isAssignableFrom(clazz)) {
699                                        d = RGBDataset.createFromObject(obj);
700                                } else if (CompoundShortDataset.class.isAssignableFrom(clazz)) {
701                                        d = CompoundShortDataset.createFromObject(itemSize, obj);
702                                } else if (CompoundIntegerDataset.class.isAssignableFrom(clazz)) {
703                                        d = CompoundIntegerDataset.createFromObject(itemSize, obj);
704                                } else if (CompoundLongDataset.class.isAssignableFrom(clazz)) {
705                                        d = CompoundLongDataset.createFromObject(itemSize, obj);
706                                } else if (FloatDataset.class.isAssignableFrom(clazz)) {
707                                        d = FloatDataset.createFromObject(obj);
708                                } else if (DoubleDataset.class.isAssignableFrom(clazz)) {
709                                        d = DoubleDataset.createFromObject(obj);
710                                } else if (ComplexFloatDataset.class.isAssignableFrom(clazz)) {
711                                        d = ComplexFloatDataset.createFromObject(obj);
712                                } else if (ComplexDoubleDataset.class.isAssignableFrom(clazz)) {
713                                        d = ComplexDoubleDataset.createFromObject(obj);
714                                } else if (CompoundFloatDataset.class.isAssignableFrom(clazz)) {
715                                        d = CompoundFloatDataset.createFromObject(itemSize, obj);
716                                } else if (CompoundDoubleDataset.class.isAssignableFrom(clazz)) {
717                                        d = CompoundDoubleDataset.createFromObject(itemSize, obj);
718                                } else if (DateDataset.class.isAssignableFrom(clazz)) {
719                                        d = DateDatasetImpl.createFromObject(obj);
720                                } else if (StringDataset.class.isAssignableFrom(clazz)) {
721                                        d = StringDataset.createFromObject(obj);
722                                } else if (ObjectDataset.class.isAssignableFrom(clazz)) {
723                                        d = ObjectDataset.createFromObject(obj);
724                                } else {
725                                        throw new IllegalArgumentException("Dataset interface is not unsupported");
726                                }
727                        }
728                }
729
730                if (shape != null && !(shape.length == 0 && d.getSize() > 1)) { // allow zero-rank datasets
731                        d.setShape(shape);
732                }
733                return (T) d;
734        }
735
736        private static Dataset createFromPrimitiveArray(Class<? extends Dataset> clazz, final Object array) {
737                if (BooleanDataset.class.isAssignableFrom(clazz)) {
738                        return new BooleanDataset((boolean[]) array);
739                } else if (ByteDataset.class.isAssignableFrom(clazz)) {
740                        return new ByteDataset((byte[]) array);
741                } else if (ShortDataset.class.isAssignableFrom(clazz)) {
742                        return new ShortDataset((short[]) array);
743                } else if (IntegerDataset.class.isAssignableFrom(clazz)) {
744                        return new IntegerDataset((int[]) array, null);
745                } else if (LongDataset.class.isAssignableFrom(clazz)) {
746                        return new LongDataset((long[]) array);
747                } else if (FloatDataset.class.isAssignableFrom(clazz)) {
748                        return new FloatDataset((float[]) array);
749                } else if (DoubleDataset.class.isAssignableFrom(clazz)) {
750                        return new DoubleDataset((double[]) array);
751                } else if (StringDataset.class.isAssignableFrom(clazz)) {
752                        return new StringDataset((String[]) array);
753                } else if (DateDataset.class.isAssignableFrom(clazz)) {
754                        return new DateDatasetImpl((Date[]) array);
755                }
756                return null;
757        }
758
759        /**
760         * Create dataset of given class from list
761         *
762         * @param <T> dataset sub-interface
763         * @param clazz dataset sub-interface
764         * @param objectList inputs for each item
765         * @return dataset filled with values from list
766         */
767        public static <T extends Dataset> T createFromList(Class<T> clazz, List<?> objectList) {
768                int len = objectList.size();
769                T result = zeros(clazz, len);
770
771                for (int i = 0; i < len; i++) {
772                        result.setObjectAbs(i, objectList.get(i));
773                }
774                return result;
775        }
776
777        /**
778         * Create compound dataset of given class from given parts
779         *
780         * @param <T> compound dataset sub-interface
781         * @param clazz compound dataset sub-interface
782         * @param objects inputs across dataset for each element
783         * @return compound dataset
784         * @since 2.3
785         */
786        public static <T extends CompoundDataset> T createCompoundDataset(Class<T> clazz, Object... objects) {
787                Dataset[] datasets = new Dataset[objects.length];
788                for (int i = 0; i < objects.length; i++) {
789                        datasets[i] = createFromObject(objects[i]);
790                }
791                return DatasetUtils.createCompoundDataset(clazz, datasets);
792        }
793
794        /**
795         * Create complex dataset of given class from real and imaginary parts
796         *
797         * @param <T> complex dataset sub-interface
798         * @param clazz complex dataset sub-interface
799         * @param real real part
800         * @param imag imaginary part
801         * @return complex dataset
802         * @since 2.3
803         */
804        @SuppressWarnings("unchecked")
805        public static <T extends CompoundDataset> T createComplexDataset(Class<? extends Dataset> clazz, Object real, Object imag) {
806                if (ComplexFloatDataset.class.isAssignableFrom(clazz)) {
807                        return (T) new ComplexFloatDataset(createFromObject(real), createFromObject(imag));
808                } else if (ComplexDoubleDataset.class.isAssignableFrom(clazz)) {
809                        return (T) new ComplexDoubleDataset(createFromObject(real), createFromObject(imag));
810                } else {
811                        throw new IllegalArgumentException("Dataset class must be a complex one");
812                }
813        }
814
815        /**
816         * @param shape output shape
817         * @return a new double dataset of given shape, filled with zeros
818         */
819        public static DoubleDataset zeros(final int... shape) {
820                return zeros(DoubleDataset.class, shape);
821        }
822
823        /**
824         * @param <T> dataset subclass
825         * @param dataset input
826         * @return a new dataset of same shape and class as input dataset, filled with zeros
827         */
828        public static <T extends Dataset> T zeros(final T dataset) {
829                return zeros(dataset, dataset.getShapeRef());
830        }
831
832        /**
833         * @param <T> dataset subclass
834         * @param dataset input
835         * @param shape output shape
836         * @return a new dataset of same class as input dataset and given shape, filled with zeros
837         * @since 2.3
838         */
839        @SuppressWarnings("unchecked")
840        public static <T extends Dataset> T zeros(final T dataset, int... shape) {
841                Class<? extends Dataset> clazz = dataset.getClass();
842                return (T) (InterfaceUtils.isElemental(dataset.getClass()) ? zeros(clazz, shape) :
843                        compoundZeros(dataset.getElementsPerItem(), InterfaceUtils.getCompoundInterface(clazz), shape));
844        }
845
846        /**
847         * @param <T> dataset sub-interface
848         * @param clazz dataset sub-interface
849         * @param shape output shape
850         * @return a new dataset of given shape and class, filled with zeros
851         */
852        @SuppressWarnings("unchecked")
853        public static <T extends Dataset> T zeros(Class<T> clazz, int... shape) {
854                if (BooleanDataset.class.isAssignableFrom(clazz)) {
855                        return (T) new BooleanDataset(shape);
856                } else if (ByteDataset.class.isAssignableFrom(clazz)) {
857                        return (T) new ByteDataset(shape);
858                } else if (ShortDataset.class.isAssignableFrom(clazz)) {
859                        return (T) new ShortDataset(shape);
860                } else if (IntegerDataset.class.isAssignableFrom(clazz)) {
861                        return (T) new IntegerDataset(shape);
862                } else if (LongDataset.class.isAssignableFrom(clazz)) {
863                        return (T) new LongDataset(shape);
864                } else if (FloatDataset.class.isAssignableFrom(clazz)) {
865                        return (T) new FloatDataset(shape);
866                } else if (DoubleDataset.class.isAssignableFrom(clazz)) {
867                        return (T) new DoubleDataset(shape);
868                } else if (RGBByteDataset.class.isAssignableFrom(clazz)) {
869                        return (T) new RGBByteDataset(shape);
870                } else if (RGBDataset.class.isAssignableFrom(clazz)) {
871                        return (T) new RGBDataset(shape);
872                } else if (ComplexFloatDataset.class.isAssignableFrom(clazz)) {
873                        return (T) new ComplexFloatDataset(shape);
874                } else if (ComplexDoubleDataset.class.isAssignableFrom(clazz)) {
875                        return (T) new ComplexDoubleDataset(shape);
876                } else if (StringDataset.class.isAssignableFrom(clazz)) {
877                        return (T) new StringDataset(shape);
878                } else if (DateDataset.class.isAssignableFrom(clazz)) {
879                        return (T) new DateDatasetImpl(shape);
880                } else if (ObjectDataset.class.isAssignableFrom(clazz)) {
881                        return (T) new ObjectDataset(shape);
882                }
883
884                throw new IllegalArgumentException("Interface not known or unsupported");
885        }
886
887        /**
888         * @param <T> dataset sub-interface
889         * @param itemSize item size. If equal to 1, then non-compound dataset is returned
890         * @param clazz dataset sub-interface
891         * @param shape output shape
892         * @return a new dataset of given item size, shape and class, filled with zeros
893         */
894        @SuppressWarnings("unchecked")
895        public static <T extends Dataset> T zeros(int itemSize, Class<T> clazz, int... shape) {
896                if (itemSize == 1 && InterfaceUtils.isElemental(clazz)) {
897                        return zeros(clazz, shape);
898                }
899                return (T) compoundZeros(itemSize, InterfaceUtils.getCompoundInterface(clazz), shape);
900        }
901
902        /**
903         * @param <T> dataset subclass
904         * @param dataset input
905         * @param clazz dataset class
906         * @return a new dataset of given class with same shape as input dataset, filled with zeros
907         */
908        public static <T extends Dataset> T zeros(Dataset dataset, Class<T> clazz) {
909                return (T) zeros(dataset.getElementsPerItem(), clazz, dataset.getShapeRef());
910        }
911
912        /**
913         * @param <T> compound dataset sub-interface
914         * @param itemSize item size
915         * @param clazz compound dataset sub-interface
916         * @param shape output shape
917         * @return a new compound dataset of given item size, shape and class, filled with zeros
918         * @since 2.0
919         */
920        @SuppressWarnings("unchecked")
921        public static <T extends CompoundDataset> T compoundZeros(int itemSize, Class<T> clazz, int... shape) {
922                if (RGBByteDataset.class.isAssignableFrom(clazz)) {
923                        if (itemSize != 3) {
924                                throw new IllegalArgumentException("Number of elements not compatible with RGB type");
925                        }
926                        return (T) new RGBByteDataset(shape);
927                } else if (CompoundByteDataset.class.isAssignableFrom(clazz)) {
928                        return (T) new CompoundByteDataset(itemSize, shape);
929                } else  if (RGBDataset.class.isAssignableFrom(clazz)) {
930                        if (itemSize != 3) {
931                                throw new IllegalArgumentException("Number of elements not compatible with RGB type");
932                        }
933                        return (T) new RGBDataset(shape);
934                } else if (CompoundShortDataset.class.isAssignableFrom(clazz)) {
935                        return (T) new CompoundShortDataset(itemSize, shape);
936                } else if (CompoundIntegerDataset.class.isAssignableFrom(clazz)) {
937                        return (T) new CompoundIntegerDataset(itemSize, shape);
938                } else if (CompoundLongDataset.class.isAssignableFrom(clazz)) {
939                        return (T) new CompoundLongDataset(itemSize, shape);
940                } else if (ComplexFloatDataset.class.isAssignableFrom(clazz)) {
941                        if (itemSize != 2) {
942                                throw new IllegalArgumentException("Number of elements not compatible with complex type");
943                        }
944                        return (T) new ComplexFloatDataset(shape);
945                } else if (CompoundFloatDataset.class.isAssignableFrom(clazz)) {
946                        return (T) new CompoundFloatDataset(itemSize, shape);
947                } else if (ComplexDoubleDataset.class.isAssignableFrom(clazz)) {
948                        if (itemSize != 2) {
949                                throw new IllegalArgumentException("Number of elements not compatible with complex type");
950                        }
951                        return (T) new ComplexDoubleDataset(shape);
952                } else if (CompoundDoubleDataset.class.isAssignableFrom(clazz)) {
953                        return (T) new CompoundDoubleDataset(itemSize, shape);
954                }
955                throw new IllegalArgumentException("Class not a known compound interface");
956        }
957
958        /**
959         * @param shape output shape
960         * @return a new double dataset of given shape, filled with ones
961         */
962        public static DoubleDataset ones(final int... shape) {
963                return ones(DoubleDataset.class, shape);
964        }
965
966        /**
967         * @param <T> dataset subclass
968         * @param dataset input
969         * @return a new dataset of same shape and class as input dataset, filled with ones
970         */
971        @SuppressWarnings("unchecked")
972        public static <T extends Dataset> T ones(final T dataset) {
973                return (T) ones(dataset, dataset.getClass());
974        }
975
976        /**
977         * @param <T> dataset sub-interface
978         * @param clazz dataset sub-interface
979         * @param shape output shape
980         * @return a new dataset of given shape and class, filled with ones
981         */
982        @SuppressWarnings("unchecked")
983        public static <T extends Dataset> T ones(Class<T> clazz, int... shape) {
984                if (BooleanDataset.class.isAssignableFrom(clazz)) {
985                        return (T) BooleanDataset.ones(shape);
986                } else if (ByteDataset.class.isAssignableFrom(clazz)) {
987                        return (T) ByteDataset.ones(shape);
988                } else if (ShortDataset.class.isAssignableFrom(clazz)) {
989                        return (T) ShortDataset.ones(shape);
990                } else if (IntegerDataset.class.isAssignableFrom(clazz)) {
991                        return (T) IntegerDataset.ones(shape);
992                } else if (LongDataset.class.isAssignableFrom(clazz)) {
993                        return (T) LongDataset.ones(shape);
994                } else if (FloatDataset.class.isAssignableFrom(clazz)) {
995                        return (T) FloatDataset.ones(shape);
996                } else if (DoubleDataset.class.isAssignableFrom(clazz)) {
997                        return (T) DoubleDataset.ones(shape);
998                } else if (RGBByteDataset.class.isAssignableFrom(clazz)) {
999                        return (T) new RGBByteDataset(shape).fill(1);
1000                } else if (RGBDataset.class.isAssignableFrom(clazz)) {
1001                        return (T) new RGBDataset(shape).fill(1);
1002                } else if (ComplexFloatDataset.class.isAssignableFrom(clazz)) {
1003                        return (T) ComplexFloatDataset.ones(shape);
1004                } else if (ComplexDoubleDataset.class.isAssignableFrom(clazz)) {
1005                        return (T) ComplexDoubleDataset.ones(shape);
1006                } else if (StringDataset.class.isAssignableFrom(clazz)) {
1007                        return (T) StringDataset.ones(shape);
1008                } else if (DateDataset.class.isAssignableFrom(clazz)) {
1009                        return (T) DateDatasetImpl.ones(shape);
1010                } else if (ObjectDataset.class.isAssignableFrom(clazz)) {
1011                        return (T) ObjectDataset.ones(shape);
1012                }
1013                throw new IllegalArgumentException("Interface not known or unsupported");
1014        }
1015
1016        /**
1017         * @param <T> dataset sub-interface
1018         * @param itemSize item size. If equal to 1, then non-compound dataset is returned
1019         * @param clazz dataset sub-interface
1020         * @param shape output shape
1021         * @return a new dataset of given item size, shape and class, filled with ones
1022         */
1023        @SuppressWarnings("unchecked")
1024        public static <T extends Dataset> T ones(int itemSize, Class<T> clazz, int... shape) {
1025                if (InterfaceUtils.isElemental(clazz)) {
1026                        return ones(clazz, shape);
1027                }
1028
1029                if (RGBByteDataset.class.isAssignableFrom(clazz)) {
1030                        if (itemSize != 3) {
1031                                throw new IllegalArgumentException("Number of elements not compatible with RGB type");
1032                        }
1033                        return (T) new RGBByteDataset(shape).fill(1);
1034                } else if (CompoundByteDataset.class.isAssignableFrom(clazz)) {
1035                        return (T) CompoundByteDataset.ones(itemSize, shape);
1036                } else if (RGBDataset.class.isAssignableFrom(clazz)) {
1037                        if (itemSize != 3) {
1038                                throw new IllegalArgumentException("Number of elements not compatible with RGB type");
1039                        }
1040                        return (T) new RGBDataset(shape).fill(1);
1041                } else if (CompoundShortDataset.class.isAssignableFrom(clazz)) {
1042                        return (T) CompoundShortDataset.ones(itemSize, shape);
1043                } else if (CompoundIntegerDataset.class.isAssignableFrom(clazz)) {
1044                        return (T) CompoundIntegerDataset.ones(itemSize, shape);
1045                } else if (CompoundLongDataset.class.isAssignableFrom(clazz)) {
1046                        return (T) CompoundLongDataset.ones(itemSize, shape);
1047                } else if (CompoundFloatDataset.class.isAssignableFrom(clazz)) {
1048                        return (T) CompoundFloatDataset.ones(itemSize, shape);
1049                } else if (CompoundDoubleDataset.class.isAssignableFrom(clazz)) {
1050                        return (T) CompoundDoubleDataset.ones(itemSize, shape);
1051                }
1052                throw new IllegalArgumentException("Class not a known compound interface");
1053        }
1054
1055        /**
1056         * @param <T> dataset subclass
1057         * @param dataset input
1058         * @param clazz dataset class
1059         * @return a new dataset of given class with same shape as input dataset, filled with ones
1060         */
1061        public static <T extends Dataset> T ones(Dataset dataset, Class<T> clazz) {
1062                return (T) ones(dataset.getElementsPerItem(), clazz, dataset.getShapeRef());
1063        }
1064}