001/*-
002 *******************************************************************************
003 * Copyright (c) 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 *******************************************************************************/
012package org.eclipse.january.dataset;
013
014import org.apache.commons.math3.complex.Complex;
015
016/**
017 * @since 2.0
018 */
019public class Operations {
020
021        /**
022         * This function returns the name of the dataset, bracketed if it already
023         * includes some mathematical symbol
024         * 
025         * @param a
026         * @return the bracketed if necessary method name
027         */
028        public static StringBuilder bracketIfNecessary(final String a) {
029                final String name = a.trim();
030                StringBuilder newName = new StringBuilder(name);
031                if (name.contains("+") || name.contains("-") || name.contains("*") || name.contains("/") || name.contains("%")
032                                || name.contains("^") || name.contains("'")) {
033                        newName.insert(0, '(');
034                        newName.append(')');
035                }
036
037                return newName;
038        }
039
040        /**
041         * Create a string for a binary operator and its operands
042         * 
043         * @param operator
044         * @param a
045         *            1st operand name
046         * @param b
047         *            2nd operand name
048         * @return name of operation
049         */
050        public static String createBinaryOperationName(final String operator, final String a, final String b) {
051                StringBuilder newName = bracketIfNecessary(a).append(operator).append(bracketIfNecessary(b));
052                return newName.toString();
053        }
054
055        /**
056         * Create a string for a function and its arguments
057         * 
058         * @param function
059         * @param arguments
060         * @return name of function
061         */
062        public static String createFunctionName(final String function, String... arguments) {
063                StringBuilder name = new StringBuilder(function);
064                name.append('(');
065                int length = arguments.length - 1;
066                for (int i = 0; i < length; i++) {
067                        name.append(arguments[i]);
068                        name.append(", ");
069                }
070                name.append(arguments[length]);
071                name.append(')');
072                return name.toString();
073        }
074
075        /**
076         * Negation with boolean not
077         */
078        public static class Negation implements UnaryOperation {
079
080                @Override
081                public boolean booleanOperate(long a) {
082                        return a == 0;
083                }
084
085                @Override
086                public long longOperate(long a) {
087                        return -a;
088                }
089
090                @Override
091                public double doubleOperate(double a) {
092                        return -a;
093                }
094
095                @Override
096                public void complexOperate(double[] out, double ra, double ia) {
097                        out[0] = -ra;
098                        out[1] = -ia;
099                }
100
101                @Override
102                public String toString(String a) {
103                        return createFunctionName(toString(), a);
104                }
105
106                @Override
107                public String toString() {
108                        return "-";
109                }
110        }
111
112        /**
113         * Addition with boolean or
114         */
115        public static class Addition implements BinaryOperation {
116
117                @Override
118                public boolean booleanOperate(long a, long b) {
119                        return a != 0 || b != 0;
120                }
121
122                @Override
123                public long longOperate(long a, long b) {
124                        return a + b;
125                }
126
127                @Override
128                public double doubleOperate(double a, double b) {
129                        return a + b;
130                }
131
132                @Override
133                public void complexOperate(double[] out, double ra, double ia, double rb, double ib) {
134                        out[0] = ra + rb;
135                        out[1] = ia + ib;
136                }
137
138                @Override
139                public String toString(String a, String b) {
140                        return createBinaryOperationName(toString(), a, b);
141                }
142
143                @Override
144                public String toString() {
145                        return "+";
146                }
147        }
148
149        /**
150         * Subtraction with boolean or of negated second operand
151         */
152        public static class Subtraction implements BinaryOperation {
153
154                @Override
155                public boolean booleanOperate(long a, long b) {
156                        return a != 0 || b == 0;
157                }
158
159                @Override
160                public long longOperate(long a, long b) {
161                        return a - b;
162                }
163
164                @Override
165                public double doubleOperate(double a, double b) {
166                        return a - b;
167                }
168
169                @Override
170                public void complexOperate(double[] out, double ra, double ia, double rb, double ib) {
171                        out[0] = ra - rb;
172                        out[1] = ia - ib;
173                }
174
175                @Override
176                public String toString(String a, String b) {
177                        return createBinaryOperationName(toString(), a, b);
178                }
179
180                @Override
181                public String toString() {
182                        return "-";
183                }
184        }
185
186        /**
187         * Multiplication with boolean and
188         */
189        public static class Multiplication implements BinaryOperation {
190
191                @Override
192                public boolean booleanOperate(long a, long b) {
193                        return a != 0 && b != 0;
194                }
195
196                @Override
197                public long longOperate(long a, long b) {
198                        return a * b;
199                }
200
201                @Override
202                public double doubleOperate(double a, double b) {
203                        return a * b;
204                }
205
206                @Override
207                public void complexOperate(double[] out, double ra, double ia, double rb, double ib) {
208                        out[0] = ra * rb - ia * ib;
209                        out[1] = ra * ib + ia * rb;
210                }
211
212                @Override
213                public String toString(String a, String b) {
214                        return createBinaryOperationName(toString(), a, b);
215                }
216
217                @Override
218                public String toString() {
219                        return "*";
220                }
221        }
222
223        /**
224         * Division with boolean and of negated second operand
225         */
226        public static class Division implements BinaryOperation {
227
228                @Override
229                public boolean booleanOperate(long a, long b) {
230                        return a != 0 && b == 0;
231                }
232
233                @Override
234                public long longOperate(long a, long b) {
235                        return b == 0 ? 0 : a / b;
236                }
237
238                @Override
239                public double doubleOperate(double a, double b) {
240                        return a / b;
241                }
242
243                @Override
244                public void complexOperate(double[] out, double ra, double ia, double rb, double ib) {
245                        double q;
246                        double den;
247                        if (ib == 0) {
248                                out[0] = ra / rb;
249                                out[1] = ia / rb;
250                        } else if (rb == 0) {
251                                out[0] = ia / ib;
252                                out[1] = -ra / ib;
253                        } else if (Math.abs(rb) < Math.abs(ib)) {
254                                q = rb / ib;
255                                den = rb * q + ib;
256                                out[0] = (ra * q + ia) / den;
257                                out[1] = (ia * q - rb) / den;
258                        } else {
259                                q = ib / rb;
260                                den = ib * q + rb;
261                                out[0] = (ia * q + ra) / den;
262                                out[1] = (ia - ra * q) / den;
263                        }
264                }
265
266                @Override
267                public String toString(String a, String b) {
268                        return createBinaryOperationName(toString(), a, b);
269                }
270
271                @Override
272                public String toString() {
273                        return "/";
274                }
275        }
276
277        /**
278         * Division with boolean and of negated second operand and returns zero if
279         * denominator is zero
280         */
281        public static class DivisionWithZero extends Division {
282
283                @Override
284                public double doubleOperate(double a, double b) {
285                        return b == 0 ? 0 : a / b;
286                }
287
288                @Override
289                public void complexOperate(double[] out, double ra, double ia, double rb, double ib) {
290                        double q;
291                        double den;
292                        if (ib == 0) {
293                                if (rb == 0) {
294                                        out[0] = 0;
295                                        out[1] = 0;
296                                } else {
297                                        out[0] = ra / rb;
298                                        out[1] = ia / rb;
299                                }
300                        } else if (rb == 0) {
301                                out[0] = ia / ib;
302                                out[1] = -ra / ib;
303                        } else if (Math.abs(rb) < Math.abs(ib)) {
304                                q = rb / ib;
305                                den = rb * q + ib;
306                                out[0] = (ra * q + ia) / den;
307                                out[1] = (ia * q - rb) / den;
308                        } else {
309                                q = ib / rb;
310                                den = ib * q + rb;
311                                out[0] = (ia * q + ra) / den;
312                                out[1] = (ia - ra * q) / den;
313                        }
314                }
315        }
316
317        /**
318         * Division with boolean and of negated second operand and rounds down to
319         * negative infinity
320         */
321        public static class DivisionTowardsFloor extends Division {
322
323                @Override
324                public long longOperate(long a, long b) {
325                        if (b == 0)
326                                return 0;
327
328                        long ox = a / b;
329                        if (a != ox * b && ((a < 0) ^ (b < 0))) {
330                                ox--;
331                        }
332
333                        return ox;
334                }
335        }
336
337        /**
338         * Remainder
339         */
340        public static class Remainder implements BinaryOperation {
341
342                @Override
343                public boolean booleanOperate(long a, long b) {
344                        throw new IllegalArgumentException("remainder does not support booleans");
345                }
346
347                @Override
348                public long longOperate(long a, long b) {
349                        return b == 0 ? 0 : a % b;
350                }
351
352                @Override
353                public double doubleOperate(double a, double b) {
354                        return a % b;
355                }
356
357                @Override
358                public void complexOperate(double[] out, double ra, double ia, double rb, double ib) {
359                        throw new IllegalArgumentException("remainder does not support complex numbers");
360                }
361
362                @Override
363                public String toString(String a, String b) {
364                        return createBinaryOperationName(toString(), a, b);
365                }
366
367                @Override
368                public String toString() {
369                        return "%";
370                }
371        }
372
373        /**
374         * Exponentiation with boolean and
375         */
376        public static class Exponentiation extends BinaryOperation.Stub {
377
378                @Override
379                public double doubleOperate(double a, double b) {
380                        return Math.pow(a, b);
381                }
382
383                @Override
384                public void complexOperate(double[] out, double ra, double ia, double rb, double ib) {
385                        Complex c = new Complex(ra, ia);
386                        c = ib == 0 ? c.pow(rb) : c.pow(new Complex(rb, ib));
387                        out[0] = c.getReal();
388                        out[1] = c.getImaginary();
389                }
390
391                @Override
392                public String toString(String a, String b) {
393                        return createBinaryOperationName(toString(), a, b);
394                }
395
396                @Override
397                public String toString() {
398                        return "**";
399                }
400        }
401
402        /**
403         * Select maximum of a and b
404         */
405        public static class Maximum implements BinaryOperation {
406                @Override
407                public boolean booleanOperate(long a, long b) {
408                        return a > b ? a != 0 : b != 0;
409                }
410
411                @Override
412                public long longOperate(long a, long b) {
413                        return a > b ? a : b;
414                }
415
416                @Override
417                public double doubleOperate(double a, double b) {
418                        return a > b ? a : b;
419                }
420
421                @Override
422                public void complexOperate(double[] out, double ra, double ia, double rb, double ib) {
423                        throw new IllegalArgumentException("select greater than does not support complex numbers");
424                }
425
426                @Override
427                public String toString(String a, String b) {
428                        return createFunctionName(toString(), a, b);
429                }
430
431                @Override
432                public String toString() {
433                        return "max";
434                }
435        }
436
437        /**
438         * Select minimum of a and b
439         */
440        public static class Minimum implements BinaryOperation {
441                @Override
442                public boolean booleanOperate(long a, long b) {
443                        return a < b ? a != 0 : b != 0;
444                }
445
446                @Override
447                public long longOperate(long a, long b) {
448                        return a < b ? a : b;
449                }
450
451                @Override
452                public double doubleOperate(double a, double b) {
453                        return a < b ? a : b;
454                }
455
456                @Override
457                public void complexOperate(double[] out, double ra, double ia, double rb, double ib) {
458                        throw new IllegalArgumentException("select less than does not support complex numbers");
459                }
460
461                @Override
462                public String toString(String a, String b) {
463                        return createFunctionName(toString(), a, b);
464                }
465
466                @Override
467                public String toString() {
468                        return "min";
469                }
470        }
471
472        /**
473         * Use given value if {@code a > b} else use a
474         */
475        public static class UseBase implements BinaryOperation {
476                protected boolean br;
477                protected long lr;
478                protected double dr;
479
480                /**
481                 * @param br
482                 *            given value as boolean
483                 * @param lr
484                 *            given value as long
485                 * @param dr
486                 *            given value as double
487                 */
488                UseBase(boolean br, long lr, double dr) {
489                        this.br = br;
490                        this.lr = lr;
491                        this.dr = dr;
492                }
493
494                /**
495                 * @param r
496                 *            given value as Number
497                 */
498                UseBase(Number r) {
499                        br = r.intValue() != 0;
500                        lr = r.longValue();
501                        dr = r.doubleValue();
502                }
503
504                @Override
505                public boolean booleanOperate(long a, long b) {
506                        return false;
507                }
508
509                @Override
510                public long longOperate(long a, long b) {
511                        return 0;
512                }
513
514                @Override
515                public double doubleOperate(double a, double b) {
516                        return 0;
517                }
518
519                @Override
520                public void complexOperate(double[] out, double ra, double ia, double rb, double ib) {
521                }
522
523                @Override
524                public String toString(String a, String b) {
525                        return createBinaryOperationName(toString(), a, b);
526                }
527        }
528
529        /**
530         * Use given value if {@code a > b} else use a
531         */
532        public static class UseIfGreaterThan extends UseBase {
533                /**
534                 * @param br
535                 *            given value as boolean
536                 * @param lr
537                 *            given value as long
538                 * @param dr
539                 *            given value as double
540                 */
541                public UseIfGreaterThan(boolean br, long lr, double dr) {
542                        super(br, lr, dr);
543                }
544
545                /**
546                 * @param r
547                 *            given value as Number
548                 */
549                public UseIfGreaterThan(Number r) {
550                        super(r);
551                }
552
553                @Override
554                public boolean booleanOperate(long a, long b) {
555                        return a > b ? br : a != 0;
556                }
557
558                @Override
559                public long longOperate(long a, long b) {
560                        return a > b ? lr : a;
561                }
562
563                @Override
564                public double doubleOperate(double a, double b) {
565                        return a > b ? dr : a;
566                }
567
568                @Override
569                public void complexOperate(double[] out, double ra, double ia, double rb, double ib) {
570                        throw new IllegalArgumentException("replace greater than does not support complex numbers");
571                }
572
573                @Override
574                public String toString() {
575                        return ">";
576                }
577        }
578
579        /**
580         * Use given value if {@code a >= b} else use a
581         */
582        public static class UseIfGreaterThanOrEqualTo extends UseBase {
583                /**
584                 * @param br
585                 *            given value as boolean
586                 * @param lr
587                 *            given value as long
588                 * @param dr
589                 *            given value as double
590                 */
591                public UseIfGreaterThanOrEqualTo(boolean br, long lr, double dr) {
592                        super(br, lr, dr);
593                }
594
595                /**
596                 * @param r
597                 *            given value as Number
598                 */
599                public UseIfGreaterThanOrEqualTo(Number r) {
600                        super(r);
601                }
602
603                @Override
604                public boolean booleanOperate(long a, long b) {
605                        return a >= b ? br : a != 0;
606                }
607
608                @Override
609                public long longOperate(long a, long b) {
610                        return a >= b ? lr : a;
611                }
612
613                @Override
614                public double doubleOperate(double a, double b) {
615                        return a >= b ? dr : a;
616                }
617
618                @Override
619                public void complexOperate(double[] out, double ra, double ia, double rb, double ib) {
620                        throw new IllegalArgumentException("replace greater than or equal to does not support complex numbers");
621                }
622
623                @Override
624                public String toString() {
625                        return ">";
626                }
627        }
628
629        /**
630         * Use given value if {@code a < b} else use a
631         */
632        public static class UseIfLessThan extends UseBase {
633                /**
634                 * @param br
635                 *            given value as boolean
636                 * @param lr
637                 *            given value as long
638                 * @param dr
639                 *            given value as double
640                 */
641                public UseIfLessThan(boolean br, long lr, double dr) {
642                        super(br, lr, dr);
643                }
644
645                /**
646                 * @param r
647                 *            given value as Number
648                 */
649                public UseIfLessThan(Number r) {
650                        super(r);
651                }
652
653                @Override
654                public boolean booleanOperate(long a, long b) {
655                        return a < b ? br : a != 0;
656                }
657
658                @Override
659                public long longOperate(long a, long b) {
660                        return a < b ? lr : a;
661                }
662
663                @Override
664                public double doubleOperate(double a, double b) {
665                        return a < b ? dr : a;
666                }
667
668                @Override
669                public void complexOperate(double[] out, double ra, double ia, double rb, double ib) {
670                        throw new IllegalArgumentException("replace less than does not support complex numbers");
671                }
672
673                @Override
674                public String toString() {
675                        return "<";
676                }
677        }
678
679        /**
680         * Use given value if {@code a <= b} else use a
681         */
682        public static class UseIfLessThanOrEqualTo extends UseBase {
683                /**
684                 * @param br
685                 *            given value as boolean
686                 * @param lr
687                 *            given value as long
688                 * @param dr
689                 *            given value as double
690                 */
691                public UseIfLessThanOrEqualTo(boolean br, long lr, double dr) {
692                        super(br, lr, dr);
693                }
694
695                /**
696                 * @param r
697                 *            given value as Number
698                 */
699                public UseIfLessThanOrEqualTo(Number r) {
700                        super(r);
701                }
702
703                @Override
704                public boolean booleanOperate(long a, long b) {
705                        return a <= b ? br : a != 0;
706                }
707
708                @Override
709                public long longOperate(long a, long b) {
710                        return a <= b ? lr : a;
711                }
712
713                @Override
714                public double doubleOperate(double a, double b) {
715                        return a <= b ? dr : a;
716                }
717
718                @Override
719                public void complexOperate(double[] out, double ra, double ia, double rb, double ib) {
720                        throw new IllegalArgumentException("replace less than or equal to does not support complex numbers");
721                }
722
723                @Override
724                public String toString() {
725                        return "<=";
726                }
727        }
728
729        /**
730         * Use given value if {@code a == b} else use a
731         */
732        public static class UseIfEqualTo extends UseBase {
733                private double di;
734
735                /**
736                 * @param br
737                 *            given value as boolean
738                 * @param lr
739                 *            given value as long
740                 * @param dr
741                 *            given value as double
742                 * @param di
743                 *            given value for imaginary part as double
744                 */
745                public UseIfEqualTo(boolean br, long lr, double dr, double di) {
746                        super(br, lr, dr);
747                        this.di = di;
748                }
749
750                /**
751                 * @param r
752                 *            given value as Number
753                 */
754                public UseIfEqualTo(Number r) {
755                        super(r);
756                        di = 0;
757                }
758
759                /**
760                 * @param z
761                 *            given value as Complex
762                 */
763                public UseIfEqualTo(Complex z) {
764                        super(z.getReal());
765                        di = z.getImaginary();
766                }
767
768                @Override
769                public boolean booleanOperate(long a, long b) {
770                        return a == b ? br : a != 0;
771                }
772
773                @Override
774                public long longOperate(long a, long b) {
775                        return a == b ? lr : a;
776                }
777
778                @Override
779                public double doubleOperate(double a, double b) {
780                        return a == b ? dr : a;
781                }
782
783                @Override
784                public void complexOperate(double[] out, double ra, double ia, double rb, double ib) {
785                        if (ra == rb && ia == ib) {
786                                out[0] = dr;
787                                out[1] = di;
788                        } else {
789                                out[0] = ra;
790                                out[1] = ia;
791                        }
792                }
793
794                @Override
795                public String toString() {
796                        return "==";
797                }
798        }
799
800        private static long toLong(double d) {
801                if (Double.isInfinite(d) || Double.isNaN(d))
802                        return 0;
803                return (long) d;
804        }
805
806        /**
807         * Operate on a dataset
808         * 
809         * @param op
810         *            unary operator
811         * @param a
812         *            dataset
813         * @param o
814         *            output can be null - in which case, a new dataset is created
815         * @return op(a), operation on a
816         */
817        public static Dataset operate(final UnaryOperation op, final Object a, final Dataset o) {
818                final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a);
819                final SingleInputBroadcastIterator it = new SingleInputBroadcastIterator(da, o, true, true, false);
820                final Dataset result = it.getOutput();
821                it.setOutputDouble(result.hasFloatingPointElements() || da.isComplex());
822                final int is = result.getElementsPerItem();
823                final int dt = result.getDType();
824                final int as = da.getElementsPerItem();
825                final double[] z;
826
827                switch (dt) {
828                case Dataset.BOOL:
829                        boolean[] bdata = ((BooleanDataset) result).getData();
830
831                        if (!da.isComplex()) {
832                                while (it.hasNext()) {
833                                        bdata[it.oIndex] = op.booleanOperate(it.aLong);
834                                }
835                        } else {
836                                z = new double[2];
837                                while (it.hasNext()) {
838                                        op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1));
839                                        bdata[it.oIndex] = z[0] != 0;
840                                }
841                        }
842                        break;
843                case Dataset.INT8:
844                        final byte[] i8data = ((ByteDataset) result).getData();
845
846                        if (!da.isComplex()) {
847                                while (it.hasNext()) {
848                                        i8data[it.oIndex] = (byte) op.longOperate(it.aLong);
849                                }
850                        } else {
851                                z = new double[2];
852                                while (it.hasNext()) {
853                                        op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1));
854                                        i8data[it.oIndex] = (byte) toLong(z[0]);
855                                }
856                        }
857                        break;
858                case Dataset.INT16:
859                        final short[] i16data = ((ShortDataset) result).getData();
860
861                        if (!da.isComplex()) {
862                                while (it.hasNext()) {
863                                        i16data[it.oIndex] = (short) op.longOperate(it.aLong);
864                                }
865                        } else {
866                                z = new double[2];
867                                while (it.hasNext()) {
868                                        op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1));
869                                        i16data[it.oIndex] = (short) toLong(z[0]);
870                                }
871                        }
872                        break;
873                case Dataset.INT32:
874                        final int[] i32data = ((IntegerDataset) result).getData();
875
876                        if (!da.isComplex()) {
877                                while (it.hasNext()) {
878                                        i32data[it.oIndex] = (int) op.longOperate(it.aLong);
879                                }
880                        } else {
881                                z = new double[2];
882                                while (it.hasNext()) {
883                                        op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1));
884                                        i32data[it.oIndex] = (int) toLong(z[0]);
885                                }
886                        }
887                        break;
888                case Dataset.INT64:
889                        final long[] i64data = ((LongDataset) result).getData();
890
891                        if (!da.isComplex()) {
892                                while (it.hasNext()) {
893                                        i64data[it.oIndex] = op.longOperate(it.aLong);
894                                }
895                        } else {
896                                z = new double[2];
897                                while (it.hasNext()) {
898                                        op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1));
899                                        i64data[it.oIndex] = toLong(z[0]);
900                                }
901                        }
902                        break;
903                case Dataset.ARRAYINT8:
904                        final byte[] ai8data = ((CompoundByteDataset) result).getData();
905
906                        if (!da.isComplex()) {
907                                if (is == 1) {
908                                        while (it.hasNext()) {
909                                                ai8data[it.oIndex] = (byte) op.longOperate(it.aLong);
910                                        }
911                                } else if (as == 1) { // broadcast to other elements of output
912                                        while (it.hasNext()) {
913                                                byte ox = (byte) op.longOperate(it.aLong);
914                                                for (int j = 0; j < is; j++) {
915                                                        ai8data[it.oIndex + j] = ox;
916                                                }
917                                        }
918                                } else { // use lowest common elements
919                                        int ms = Math.min(is, as);
920                                        while (it.hasNext()) {
921                                                ai8data[it.oIndex] = (byte) op.longOperate(it.aLong);
922                                                for (int j = 1; j < ms; j++) {
923                                                        ai8data[it.oIndex + j] = (byte) op.longOperate(da.getElementLongAbs(it.aIndex + j));
924                                                }
925                                        }
926                                }
927                        } else {
928                                z = new double[2];
929                                while (it.hasNext()) {
930                                        op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1));
931                                        byte ox = (byte) toLong(z[0]);
932                                        for (int j = 0; j < is; j++) {
933                                                ai8data[it.oIndex + j] = ox;
934                                        }
935                                }
936                        }
937                        break;
938                case Dataset.ARRAYINT16:
939                        final short[] ai16data = ((CompoundShortDataset) result).getData();
940
941                        if (!da.isComplex()) {
942                                if (is == 1) {
943                                        while (it.hasNext()) {
944                                                ai16data[it.oIndex] = (short) op.longOperate(it.aLong);
945                                        }
946                                } else if (as == 1) {
947                                        while (it.hasNext()) {
948                                                short ox = (short) op.longOperate(it.aLong);
949                                                for (int j = 0; j < is; j++) {
950                                                        ai16data[it.oIndex + j] = ox;
951                                                }
952                                        }
953                                } else {
954                                        int ms = Math.min(is, as);
955                                        while (it.hasNext()) {
956                                                ai16data[it.oIndex] = (short) op.longOperate(it.aLong);
957                                                for (int j = 1; j < ms; j++) {
958                                                        ai16data[it.oIndex + j] = (short) op.longOperate(da.getElementLongAbs(it.aIndex + j));
959                                                }
960                                        }
961                                }
962                        } else {
963                                z = new double[2];
964                                while (it.hasNext()) {
965                                        op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1));
966                                        short ox = (short) toLong(z[0]);
967                                        for (int j = 0; j < is; j++) {
968                                                ai16data[it.oIndex + j] = ox;
969                                        }
970                                }
971                        }
972                        break;
973                case Dataset.ARRAYINT32:
974                        final int[] ai32data = ((CompoundIntegerDataset) result).getData();
975
976                        if (!da.isComplex()) {
977                                if (is == 1) {
978                                        while (it.hasNext()) {
979                                                ai32data[it.oIndex] = (int) op.longOperate(it.aLong);
980                                        }
981                                } else if (as == 1) {
982                                        while (it.hasNext()) {
983                                                int ox = (int) op.longOperate(it.aLong);
984                                                for (int j = 0; j < is; j++) {
985                                                        ai32data[it.oIndex + j] = ox;
986                                                }
987                                        }
988                                } else {
989                                        final int ms = Math.min(is, as);
990                                        while (it.hasNext()) {
991                                                ai32data[it.oIndex] = (int) op.longOperate(it.aLong);
992                                                for (int j = 1; j < ms; j++) {
993                                                        ai32data[it.oIndex + j] = (int) op.longOperate(da.getElementLongAbs(it.aIndex + j));
994                                                }
995                                        }
996                                }
997                        } else {
998                                z = new double[2];
999                                while (it.hasNext()) {
1000                                        op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1));
1001                                        int ox = (int) toLong(z[0]);
1002                                        for (int j = 0; j < is; j++) {
1003                                                ai32data[it.oIndex + j] = ox;
1004                                        }
1005                                }
1006                        }
1007                        break;
1008                case Dataset.ARRAYINT64:
1009                        final long[] ai64data = ((CompoundLongDataset) result).getData();
1010
1011                        if (!da.isComplex()) {
1012                                if (is == 1) {
1013                                        while (it.hasNext()) {
1014                                                ai64data[it.oIndex] = op.longOperate(it.aLong);
1015                                        }
1016                                } else if (as == 1) {
1017                                        while (it.hasNext()) {
1018                                                long ox = op.longOperate(it.aLong);
1019                                                for (int j = 0; j < is; j++) {
1020                                                        ai64data[it.oIndex + j] = ox;
1021                                                }
1022                                        }
1023                                } else {
1024                                        int ms = Math.min(is, as);
1025                                        while (it.hasNext()) {
1026                                                ai64data[it.oIndex] = op.longOperate(it.aLong);
1027                                                for (int j = 1; j < ms; j++) {
1028                                                        ai64data[it.oIndex + j] = op.longOperate(da.getElementLongAbs(it.aIndex + j));
1029                                                }
1030                                        }
1031                                }
1032                        } else {
1033                                z = new double[2];
1034                                while (it.hasNext()) {
1035                                        op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1));
1036                                        long ox = toLong(z[0]);
1037                                        for (int j = 0; j < is; j++) {
1038                                                ai64data[it.oIndex + j] = ox;
1039                                        }
1040                                }
1041                        }
1042                        break;
1043                case Dataset.FLOAT32:
1044                        final float[] f32data = ((FloatDataset) result).getData();
1045
1046                        if (!da.isComplex()) {
1047                                while (it.hasNext()) {
1048                                        f32data[it.oIndex] = (float) op.doubleOperate(it.aDouble);
1049                                }
1050                        } else { // only for complex input
1051                                z = new double[2];
1052                                while (it.hasNext()) {
1053                                        op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1));
1054                                        f32data[it.oIndex] = (float) z[0];
1055                                }
1056                        }
1057                        break;
1058                case Dataset.FLOAT64:
1059                        final double[] f64data = ((DoubleDataset) result).getData();
1060
1061                        if (!da.isComplex()) {
1062                                while (it.hasNext()) {
1063                                        f64data[it.oIndex] = op.doubleOperate(it.aDouble);
1064                                }
1065                        } else {
1066                                z = new double[2];
1067                                while (it.hasNext()) {
1068                                        op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1));
1069                                        f64data[it.oIndex] = z[0];
1070                                }
1071                        }
1072                        break;
1073                case Dataset.ARRAYFLOAT32:
1074                        final float[] af32data = ((CompoundFloatDataset) result).getData();
1075
1076                        if (!da.isComplex()) {
1077                                if (is == 1) {
1078                                        while (it.hasNext()) {
1079                                                af32data[it.oIndex] = (float) op.doubleOperate(it.aDouble);
1080                                        }
1081                                } else if (as == 1) {
1082                                        while (it.hasNext()) {
1083                                                float ox = (float) op.doubleOperate(it.aDouble);
1084                                                for (int j = 0; j < is; j++) {
1085                                                        af32data[it.oIndex + j] = ox;
1086                                                }
1087                                        }
1088                                } else {
1089                                        int ms = Math.min(is, as);
1090                                        while (it.hasNext()) {
1091                                                af32data[it.oIndex] = (float) op.doubleOperate(it.aDouble);
1092                                                for (int j = 1; j < ms; j++) {
1093                                                        af32data[it.oIndex + j] = (float) op.doubleOperate(da.getElementDoubleAbs(it.aIndex + j));
1094                                                }
1095                                        }
1096                                }
1097                        } else {
1098                                z = new double[2];
1099                                while (it.hasNext()) {
1100                                        op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1));
1101                                        float ox = (float) z[0];
1102                                        for (int j = 0; j < is; j++) {
1103                                                af32data[it.oIndex + j] = ox;
1104                                        }
1105                                }
1106                        }
1107                        break;
1108                case Dataset.ARRAYFLOAT64:
1109                        final double[] af64data = ((CompoundDoubleDataset) result).getData();
1110
1111                        if (!da.isComplex()) {
1112                                if (is == 1) {
1113                                        while (it.hasNext()) {
1114                                                af64data[it.oIndex] = op.doubleOperate(it.aDouble);
1115                                        }
1116                                } else if (as == 1) {
1117                                        while (it.hasNext()) {
1118                                                final double ix = it.aDouble;
1119                                                double ox = op.doubleOperate(ix);
1120                                                for (int j = 0; j < is; j++) {
1121                                                        af64data[it.oIndex + j] = ox;
1122                                                }
1123                                        }
1124                                } else {
1125                                        int ms = Math.min(is, as);
1126                                        while (it.hasNext()) {
1127                                                af64data[it.oIndex] = op.doubleOperate(it.aDouble);
1128                                                for (int j = 1; j < ms; j++) {
1129                                                        af64data[it.oIndex + j] = op.doubleOperate(da.getElementDoubleAbs(it.aIndex + j));
1130                                                }
1131                                        }
1132                                }
1133                        } else {
1134                                z = new double[2];
1135                                while (it.hasNext()) {
1136                                        op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1));
1137                                        double ox = z[0];
1138                                        for (int j = 0; j < is; j++) {
1139                                                af64data[it.oIndex + j] = ox;
1140                                        }
1141                                }
1142                        }
1143                        break;
1144                case Dataset.COMPLEX64:
1145                        final float[] c64data = ((ComplexFloatDataset) result).getData();
1146                        z = new double[2];
1147
1148                        if (!da.isComplex()) {
1149                                while (it.hasNext()) {
1150                                        op.complexOperate(z, it.aDouble, 0);
1151                                        c64data[it.oIndex] = (float) z[0];
1152                                }
1153                        } else {
1154                                while (it.hasNext()) {
1155                                        op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1));
1156                                        c64data[it.oIndex] = (float) z[0];
1157                                        c64data[it.oIndex + 1] = (float) z[1];
1158                                }
1159                        }
1160                        break;
1161                case Dataset.COMPLEX128:
1162                        final double[] c128data = ((ComplexDoubleDataset) result).getData();
1163                        z = new double[2];
1164
1165                        if (!da.isComplex()) {
1166                                while (it.hasNext()) {
1167                                        op.complexOperate(z, it.aDouble, 0);
1168                                        c128data[it.oIndex] = z[0];
1169                                }
1170                        } else {
1171                                while (it.hasNext()) {
1172                                        op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1));
1173                                        c128data[it.oIndex] = z[0];
1174                                        c128data[it.oIndex + 1] = z[1];
1175                                }
1176                        }
1177                        break;
1178                default:
1179                        throw new UnsupportedOperationException("operate does not support this dataset type");
1180                }
1181
1182                result.setName(op.toString(da.getName()));
1183                return result;
1184        }
1185
1186        /**
1187         * Operate on a dataset
1188         * 
1189         * @param op
1190         *            binary operator
1191         * @param a
1192         * @param b
1193         * @param o
1194         *            output can be null - in which case, a new dataset is created
1195         * @return a op b, operation on a and b
1196         */
1197        public static Dataset operate(final BinaryOperation op, final Object a, final Object b, final Dataset o) {
1198                final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a);
1199                final Dataset db = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b);
1200
1201                final BroadcastIterator it = BroadcastIterator.createIterator(da, db, o, true);
1202                final Dataset result = it.getOutput();
1203                it.setOutputDouble(result.hasFloatingPointElements() || da.isComplex() || db.isComplex());
1204                final int is = result.getElementsPerItem();
1205                int as = da.getElementsPerItem();
1206                int bs = db.getElementsPerItem();
1207                final double[] z;
1208
1209                switch (result.getDType()) {
1210                case Dataset.BOOL:
1211                        boolean[] bdata = ((BooleanDataset) result).getData();
1212
1213                        if (!da.isComplex() && !db.isComplex()) {
1214                                while (it.hasNext()) {
1215                                        bdata[it.oIndex] = op.booleanOperate(it.aLong, it.aLong);
1216                                }
1217                        } else {
1218                                z = new double[2];
1219                                if (!db.isComplex()) {
1220                                        while (it.hasNext()) {
1221                                                op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1), it.bDouble, 0);
1222                                                bdata[it.oIndex] = z[0] != 0;
1223                                        }
1224                                } else if (!da.isComplex()) {
1225                                        while (it.hasNext()) {
1226                                                op.complexOperate(z, it.aDouble, 0, it.bDouble, db.getElementDoubleAbs(it.bIndex + 1));
1227                                                bdata[it.oIndex] = z[0] != 0;
1228                                        }
1229                                } else {
1230                                        while (it.hasNext()) {
1231                                                op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1),
1232                                                                it.bDouble, db.getElementDoubleAbs(it.bIndex + 1));
1233                                                bdata[it.oIndex] = z[0] != 0;
1234                                        }
1235                                }
1236                        }
1237                        break;
1238                case Dataset.INT8:
1239                        byte[] i8data = ((ByteDataset) result).getData();
1240
1241                        if (!da.isComplex() && !db.isComplex()) {
1242                                while (it.hasNext()) {
1243                                        i8data[it.oIndex] = (byte) op.longOperate(it.aLong, it.aLong);
1244                                }
1245                        } else {
1246                                z = new double[2];
1247                                if (!db.isComplex()) { // only a complex
1248                                        while (it.hasNext()) {
1249                                                op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1), it.bDouble, 0);
1250                                                i8data[it.oIndex] = (byte) toLong(z[0]);
1251                                        }
1252                                } else if (!da.isComplex()) { // only b complex
1253                                        while (it.hasNext()) {
1254                                                op.complexOperate(z, it.aDouble, 0, it.bDouble, db.getElementDoubleAbs(it.bIndex + 1));
1255                                                i8data[it.oIndex] = (byte) toLong(z[0]);
1256                                        }
1257                                } else {
1258                                        while (it.hasNext()) {
1259                                                op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1),
1260                                                                it.bDouble, db.getElementDoubleAbs(it.bIndex + 1));
1261                                                i8data[it.oIndex] = (byte) toLong(z[0]);
1262                                        }
1263                                }
1264                        }
1265                        break;
1266                case Dataset.INT16:
1267                        short[] i16data = ((ShortDataset) result).getData();
1268
1269                        if (!da.isComplex() && !db.isComplex()) {
1270                                while (it.hasNext()) {
1271                                        i16data[it.oIndex] = (short) op.longOperate(it.aLong, it.aLong);
1272                                }
1273                        } else {
1274                                z = new double[2];
1275                                if (!db.isComplex()) { // only a complex
1276                                        while (it.hasNext()) {
1277                                                op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1), it.bDouble, 0);
1278                                                i16data[it.oIndex] = (short) toLong(z[0]);
1279                                        }
1280                                } else if (!da.isComplex()) { // only b complex
1281                                        while (it.hasNext()) {
1282                                                op.complexOperate(z, it.aDouble, 0, it.bDouble, db.getElementDoubleAbs(it.bIndex + 1));
1283                                                i16data[it.oIndex] = (short) toLong(z[0]);
1284                                        }
1285                                } else {
1286                                        while (it.hasNext()) {
1287                                                op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1),
1288                                                                it.bDouble, db.getElementDoubleAbs(it.bIndex + 1));
1289                                                i16data[it.oIndex] = (short) toLong(z[0]);
1290                                        }
1291                                }
1292                        }
1293                        break;
1294                case Dataset.INT32:
1295                        int[] i32data = ((IntegerDataset) result).getData();
1296
1297                        if (!da.isComplex() && !db.isComplex()) {
1298                                while (it.hasNext()) {
1299                                        i32data[it.oIndex] = (int) op.longOperate(it.aLong, it.aLong);
1300                                }
1301                        } else {
1302                                z = new double[2];
1303                                if (!db.isComplex()) { // only a complex
1304                                        while (it.hasNext()) {
1305                                                op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1), it.bDouble, 0);
1306                                                i32data[it.oIndex] = (int) toLong(z[0]);
1307                                        }
1308                                } else if (!da.isComplex()) { // only b complex
1309                                        while (it.hasNext()) {
1310                                                op.complexOperate(z, it.aDouble, 0, it.bDouble, db.getElementDoubleAbs(it.bIndex + 1));
1311                                                i32data[it.oIndex] = (int) toLong(z[0]);
1312                                        }
1313                                } else {
1314                                        while (it.hasNext()) {
1315                                                op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1),
1316                                                                it.bDouble, db.getElementDoubleAbs(it.bIndex + 1));
1317                                                i32data[it.oIndex] = (int) toLong(z[0]);
1318                                        }
1319                                }
1320                        }
1321                        break;
1322                case Dataset.INT64:
1323                        long[] i64data = ((LongDataset) result).getData();
1324
1325                        if (!da.isComplex() && !db.isComplex()) {
1326                                while (it.hasNext()) {
1327                                        i64data[it.oIndex] = op.longOperate(it.aLong, it.aLong);
1328                                }
1329                        } else {
1330                                z = new double[2];
1331                                if (!db.isComplex()) { // only a complex
1332                                        while (it.hasNext()) {
1333                                                op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1), it.bDouble, 0);
1334                                                i64data[it.oIndex] = toLong(z[0]);
1335                                        }
1336                                } else if (!da.isComplex()) { // only b complex
1337                                        while (it.hasNext()) {
1338                                                op.complexOperate(z, it.aDouble, 0, it.bDouble, db.getElementDoubleAbs(it.bIndex + 1));
1339                                                i64data[it.oIndex] = toLong(z[0]);
1340                                        }
1341                                } else {
1342                                        while (it.hasNext()) {
1343                                                op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1),
1344                                                                it.bDouble, db.getElementDoubleAbs(it.bIndex + 1));
1345                                                i64data[it.oIndex] = toLong(z[0]);
1346                                        }
1347                                }
1348                        }
1349                        break;
1350                case Dataset.ARRAYINT8:
1351                        byte[] ai8data = ((CompoundByteDataset) result).getData();
1352
1353                        if (!da.isComplex() && !db.isComplex()) {
1354                                if (is == 1) {
1355                                        while (it.hasNext()) {
1356                                                ai8data[it.oIndex] = (byte) op.longOperate(it.aLong, it.bLong);
1357                                        }
1358                                } else { // broadcast to other elements of output if possible
1359                                        int ms;
1360                                        if (as == 1 && bs != 1) {
1361                                                ms = Math.min(is, bs);
1362                                                while (it.hasNext()) {
1363                                                        ai8data[it.oIndex] = (byte) op.longOperate(it.aLong, it.bLong);
1364                                                        for (int j = 1; j < ms; j++) {
1365                                                                ai8data[it.oIndex + j] = (byte) op.longOperate(it.aLong,
1366                                                                                db.getElementLongAbs(it.bIndex + j));
1367                                                        }
1368                                                }
1369                                        } else if (as != 1 && bs == 1) {
1370                                                ms = Math.min(is, as);
1371                                                while (it.hasNext()) {
1372                                                        ai8data[it.oIndex] = (byte) op.longOperate(it.aLong, it.bLong);
1373                                                        for (int j = 1; j < ms; j++) {
1374                                                                ai8data[it.oIndex + j] = (byte) op.longOperate(da.getElementLongAbs(it.aIndex + j),
1375                                                                                it.bLong);
1376                                                        }
1377                                                }
1378                                        } else {
1379                                                ms = Math.min(is, Math.min(as, bs));
1380                                                while (it.hasNext()) {
1381                                                        ai8data[it.oIndex] = (byte) op.longOperate(it.aLong, it.bLong);
1382                                                        for (int j = 1; j < ms; j++) {
1383                                                                ai8data[it.oIndex + j] = (byte) op.longOperate(da.getElementLongAbs(it.aIndex + j),
1384                                                                                db.getElementLongAbs(it.bIndex + j));
1385                                                        }
1386                                                }
1387                                        }
1388                                }
1389                        } else {
1390                                z = new double[2];
1391                                if (!db.isComplex()) { // only a complex
1392                                        while (it.hasNext()) {
1393                                                op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1), it.bDouble, 0);
1394                                                byte ox = (byte) toLong(z[0]);
1395                                                for (int j = 0; j < is; j++) {
1396                                                        ai8data[it.oIndex + j] = ox;
1397                                                }
1398                                        }
1399                                } else if (!da.isComplex()) { // only b complex
1400                                        while (it.hasNext()) {
1401                                                op.complexOperate(z, it.aDouble, 0, it.bDouble, db.getElementDoubleAbs(it.bIndex + 1));
1402                                                byte ox = (byte) toLong(z[0]);
1403                                                for (int j = 0; j < is; j++) {
1404                                                        ai8data[it.oIndex + j] = ox;
1405                                                }
1406                                        }
1407                                } else {
1408                                        while (it.hasNext()) {
1409                                                op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1),
1410                                                                it.bDouble, db.getElementDoubleAbs(it.bIndex + 1));
1411                                                byte ox = (byte) toLong(z[0]);
1412                                                for (int j = 0; j < is; j++) {
1413                                                        ai8data[it.oIndex + j] = ox;
1414                                                }
1415                                        }
1416                                }
1417                        }
1418                        break;
1419                case Dataset.ARRAYINT16:
1420                        short[] ai16data = ((CompoundShortDataset) result).getData();
1421
1422                        if (!da.isComplex() && !db.isComplex()) {
1423                                if (is == 1) {
1424                                        while (it.hasNext()) {
1425                                                ai16data[it.oIndex] = (short) op.longOperate(it.aLong, it.bLong);
1426                                        }
1427                                } else {
1428                                        int ms;
1429                                        if (as == 1 && bs != 1) {
1430                                                ms = Math.min(is, bs);
1431                                                while (it.hasNext()) {
1432                                                        ai16data[it.oIndex] = (short) op.longOperate(it.aLong, it.bLong);
1433                                                        for (int j = 1; j < ms; j++) {
1434                                                                ai16data[it.oIndex + j] = (short) op.longOperate(it.aLong,
1435                                                                                db.getElementLongAbs(it.bIndex + j));
1436                                                        }
1437                                                }
1438                                        } else if (as != 1 && bs == 1) {
1439                                                ms = Math.min(is, as);
1440                                                while (it.hasNext()) {
1441                                                        ai16data[it.oIndex] = (short) op.longOperate(it.aLong, it.bLong);
1442                                                        for (int j = 1; j < ms; j++) {
1443                                                                ai16data[it.oIndex + j] = (short) op.longOperate(da.getElementLongAbs(it.aIndex + j),
1444                                                                                it.bLong);
1445                                                        }
1446                                                }
1447                                        } else {
1448                                                ms = Math.min(is, Math.min(as, bs));
1449                                                while (it.hasNext()) {
1450                                                        ai16data[it.oIndex] = (short) op.longOperate(it.aLong, it.bLong);
1451                                                        for (int j = 1; j < ms; j++) {
1452                                                                ai16data[it.oIndex + j] = (short) op.longOperate(da.getElementLongAbs(it.aIndex + j),
1453                                                                                db.getElementLongAbs(it.bIndex + j));
1454                                                        }
1455                                                }
1456                                        }
1457                                }
1458                        } else {
1459                                z = new double[2];
1460                                if (!db.isComplex()) { // only a complex
1461                                        while (it.hasNext()) {
1462                                                op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1), it.bDouble, 0);
1463                                                short ox = (short) toLong(z[0]);
1464                                                for (int j = 0; j < is; j++) {
1465                                                        ai16data[it.oIndex + j] = ox;
1466                                                }
1467                                        }
1468                                } else if (!da.isComplex()) { // only b complex
1469                                        while (it.hasNext()) {
1470                                                op.complexOperate(z, it.aDouble, 0, it.bDouble, db.getElementDoubleAbs(it.bIndex + 1));
1471                                                short ox = (short) toLong(z[0]);
1472                                                for (int j = 0; j < is; j++) {
1473                                                        ai16data[it.oIndex + j] = ox;
1474                                                }
1475                                        }
1476                                } else {
1477                                        while (it.hasNext()) {
1478                                                op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1),
1479                                                                it.bDouble, db.getElementDoubleAbs(it.bIndex + 1));
1480                                                short ox = (short) toLong(z[0]);
1481                                                for (int j = 0; j < is; j++) {
1482                                                        ai16data[it.oIndex + j] = ox;
1483                                                }
1484                                        }
1485                                }
1486                        }
1487                        break;
1488                case Dataset.ARRAYINT32:
1489                        int[] ai32data = ((CompoundIntegerDataset) result).getData();
1490
1491                        if (!da.isComplex() && !db.isComplex()) {
1492                                if (is == 1) {
1493                                        while (it.hasNext()) {
1494                                                ai32data[it.oIndex] = (int) op.longOperate(it.aLong, it.bLong);
1495                                        }
1496                                } else {
1497                                        int ms;
1498                                        if (as == 1 && bs != 1) {
1499                                                ms = Math.min(is, bs);
1500                                                while (it.hasNext()) {
1501                                                        ai32data[it.oIndex] = (int) op.longOperate(it.aLong, it.bLong);
1502                                                        for (int j = 1; j < ms; j++) {
1503                                                                ai32data[it.oIndex + j] = (int) op.longOperate(it.aLong,
1504                                                                                db.getElementLongAbs(it.bIndex + j));
1505                                                        }
1506                                                }
1507                                        } else if (as != 1 && bs == 1) {
1508                                                ms = Math.min(is, as);
1509                                                while (it.hasNext()) {
1510                                                        ai32data[it.oIndex] = (int) op.longOperate(it.aLong, it.bLong);
1511                                                        for (int j = 1; j < ms; j++) {
1512                                                                ai32data[it.oIndex + j] = (int) op.longOperate(da.getElementLongAbs(it.aIndex + j),
1513                                                                                it.bLong);
1514                                                        }
1515                                                }
1516                                        } else {
1517                                                ms = Math.min(is, Math.min(as, bs));
1518                                                while (it.hasNext()) {
1519                                                        ai32data[it.oIndex] = (int) op.longOperate(it.aLong, it.bLong);
1520                                                        for (int j = 1; j < ms; j++) {
1521                                                                ai32data[it.oIndex + j] = (int) op.longOperate(da.getElementLongAbs(it.aIndex + j),
1522                                                                                db.getElementLongAbs(it.bIndex + j));
1523                                                        }
1524                                                }
1525                                        }
1526                                }
1527                        } else {
1528                                z = new double[2];
1529                                if (!db.isComplex()) { // only a complex
1530                                        while (it.hasNext()) {
1531                                                op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1), it.bDouble, 0);
1532                                                short ox = (short) toLong(z[0]);
1533                                                for (int j = 0; j < is; j++) {
1534                                                        ai32data[it.oIndex + j] = ox;
1535                                                }
1536                                        }
1537                                } else if (!da.isComplex()) { // only b complex
1538                                        while (it.hasNext()) {
1539                                                op.complexOperate(z, it.aDouble, 0, it.bDouble, db.getElementDoubleAbs(it.bIndex + 1));
1540                                                short ox = (short) toLong(z[0]);
1541                                                for (int j = 0; j < is; j++) {
1542                                                        ai32data[it.oIndex + j] = ox;
1543                                                }
1544                                        }
1545                                } else {
1546                                        while (it.hasNext()) {
1547                                                op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1),
1548                                                                it.bDouble, db.getElementDoubleAbs(it.bIndex + 1));
1549                                                short ox = (short) toLong(z[0]);
1550                                                for (int j = 0; j < is; j++) {
1551                                                        ai32data[it.oIndex + j] = ox;
1552                                                }
1553                                        }
1554                                }
1555                        }
1556                        break;
1557                case Dataset.ARRAYINT64:
1558                        long[] ai64data = ((CompoundLongDataset) result).getData();
1559
1560                        if (!da.isComplex() && !db.isComplex()) {
1561                                if (is == 1) {
1562                                        while (it.hasNext()) {
1563                                                ai64data[it.oIndex] = op.longOperate(it.aLong, it.bLong);
1564                                        }
1565                                } else {
1566                                        int ms;
1567                                        if (as == 1 && bs != 1) {
1568                                                ms = Math.min(is, bs);
1569                                                while (it.hasNext()) {
1570                                                        ai64data[it.oIndex] = op.longOperate(it.aLong, it.bLong);
1571                                                        for (int j = 1; j < ms; j++) {
1572                                                                ai64data[it.oIndex + j] = op.longOperate(it.aLong, db.getElementLongAbs(it.bIndex + j));
1573                                                        }
1574                                                }
1575                                        } else if (as != 1 && bs == 1) {
1576                                                ms = Math.min(is, as);
1577                                                while (it.hasNext()) {
1578                                                        ai64data[it.oIndex] = op.longOperate(it.aLong, it.bLong);
1579                                                        for (int j = 1; j < ms; j++) {
1580                                                                ai64data[it.oIndex + j] = op.longOperate(da.getElementLongAbs(it.aIndex + j), it.bLong);
1581                                                        }
1582                                                }
1583                                        } else {
1584                                                ms = Math.min(is, Math.min(as, bs));
1585                                                while (it.hasNext()) {
1586                                                        ai64data[it.oIndex] = op.longOperate(it.aLong, it.bLong);
1587                                                        for (int j = 1; j < ms; j++) {
1588                                                                ai64data[it.oIndex + j] = op.longOperate(da.getElementLongAbs(it.aIndex + j),
1589                                                                                db.getElementLongAbs(it.bIndex + j));
1590                                                        }
1591                                                }
1592                                        }
1593                                }
1594                        } else {
1595                                z = new double[2];
1596                                if (!db.isComplex()) { // only a complex
1597                                        while (it.hasNext()) {
1598                                                op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1), it.bDouble, 0);
1599                                                long ox = toLong(z[0]);
1600                                                for (int j = 0; j < is; j++) {
1601                                                        ai64data[it.oIndex + j] = ox;
1602                                                }
1603                                        }
1604                                } else if (!da.isComplex()) { // only b complex
1605                                        while (it.hasNext()) {
1606                                                op.complexOperate(z, it.aDouble, 0, it.bDouble, db.getElementDoubleAbs(it.bIndex + 1));
1607                                                long ox = toLong(z[0]);
1608                                                for (int j = 0; j < is; j++) {
1609                                                        ai64data[it.oIndex + j] = ox;
1610                                                }
1611                                        }
1612                                } else {
1613                                        while (it.hasNext()) {
1614                                                op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1),
1615                                                                it.bDouble, db.getElementDoubleAbs(it.bIndex + 1));
1616                                                long ox = toLong(z[0]);
1617                                                for (int j = 0; j < is; j++) {
1618                                                        ai64data[it.oIndex + j] = ox;
1619                                                }
1620                                        }
1621                                }
1622                        }
1623                        break;
1624                case Dataset.FLOAT32:
1625                        float[] f32data = ((FloatDataset) result).getData();
1626
1627                        if (!da.isComplex() && !db.isComplex()) {
1628                                while (it.hasNext()) {
1629                                        f32data[it.oIndex] = (float) op.doubleOperate(it.aDouble, it.bDouble);
1630                                }
1631                        } else {
1632                                z = new double[2];
1633                                if (!db.isComplex()) { // only a complex
1634                                        while (it.hasNext()) {
1635                                                op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1), it.bDouble, 0);
1636                                                f32data[it.oIndex] = (float) z[0];
1637                                        }
1638                                } else if (!da.isComplex()) { // only b complex
1639                                        while (it.hasNext()) {
1640                                                op.complexOperate(z, it.aDouble, 0, it.bDouble, db.getElementDoubleAbs(it.bIndex + 1));
1641                                                f32data[it.oIndex] = (float) z[0];
1642                                        }
1643                                } else {
1644                                        while (it.hasNext()) {
1645                                                op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1),
1646                                                                it.bDouble, db.getElementDoubleAbs(it.bIndex + 1));
1647                                                f32data[it.oIndex] = (float) z[0];
1648                                        }
1649                                }
1650                        }
1651                        break;
1652                case Dataset.FLOAT64:
1653                        double[] f64data = ((DoubleDataset) result).getData();
1654
1655                        if (!da.isComplex() && !db.isComplex()) {
1656                                while (it.hasNext()) {
1657                                        f64data[it.oIndex] = op.doubleOperate(it.aDouble, it.bDouble);
1658                                }
1659                        } else {
1660                                z = new double[2];
1661                                if (!db.isComplex()) { // only a complex
1662                                        while (it.hasNext()) {
1663                                                op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1), it.bDouble, 0);
1664                                                f64data[it.oIndex] = z[0];
1665                                        }
1666                                } else if (!da.isComplex()) { // only b complex
1667                                        while (it.hasNext()) {
1668                                                op.complexOperate(z, it.aDouble, 0, it.bDouble, db.getElementDoubleAbs(it.bIndex + 1));
1669                                                f64data[it.oIndex] = z[0];
1670                                        }
1671                                } else {
1672                                        while (it.hasNext()) {
1673                                                op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1),
1674                                                                it.bDouble, db.getElementDoubleAbs(it.bIndex + 1));
1675                                                f64data[it.oIndex] = z[0];
1676                                        }
1677                                }
1678                        }
1679                        break;
1680                case Dataset.ARRAYFLOAT32:
1681                        float[] af32data = ((CompoundFloatDataset) result).getData();
1682
1683                        if (!da.isComplex() && !db.isComplex()) {
1684                                if (is == 1) {
1685                                        while (it.hasNext()) {
1686                                                af32data[it.oIndex] = (float) op.doubleOperate(it.aDouble, it.bDouble);
1687                                        }
1688                                } else {
1689                                        int ms;
1690                                        if (as == 1 && bs != 1) {
1691                                                ms = Math.min(is, bs);
1692                                                while (it.hasNext()) {
1693                                                        af32data[it.oIndex] = (float) op.doubleOperate(it.aDouble, it.bDouble);
1694                                                        for (int j = 1; j < ms; j++) {
1695                                                                af32data[it.oIndex + j] = (float) op.doubleOperate(it.aDouble,
1696                                                                                db.getElementDoubleAbs(it.bIndex + j));
1697                                                        }
1698                                                }
1699                                        } else if (as != 1 && bs == 1) {
1700                                                ms = Math.min(is, as);
1701                                                while (it.hasNext()) {
1702                                                        af32data[it.oIndex] = (float) op.doubleOperate(it.aDouble, it.bDouble);
1703                                                        for (int j = 1; j < ms; j++) {
1704                                                                af32data[it.oIndex + j] = (float) op
1705                                                                                .doubleOperate(da.getElementDoubleAbs(it.aIndex + j), it.bDouble);
1706                                                        }
1707                                                }
1708                                        } else {
1709                                                ms = Math.min(is, Math.min(as, bs));
1710                                                while (it.hasNext()) {
1711                                                        af32data[it.oIndex] = (float) op.doubleOperate(it.aDouble, it.bDouble);
1712                                                        for (int j = 1; j < ms; j++) {
1713                                                                af32data[it.oIndex + j] = (float) op.doubleOperate(
1714                                                                                da.getElementDoubleAbs(it.aIndex + j), db.getElementDoubleAbs(it.bIndex + j));
1715                                                        }
1716                                                }
1717                                        }
1718                                }
1719                        } else {
1720                                z = new double[2];
1721                                if (!db.isComplex()) { // only a complex
1722                                        while (it.hasNext()) {
1723                                                op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1), it.bDouble, 0);
1724                                                float ox = (float) z[0];
1725                                                for (int j = 0; j < is; j++) {
1726                                                        af32data[it.oIndex + j] = ox;
1727                                                }
1728                                        }
1729                                } else if (!da.isComplex()) { // only b complex
1730                                        while (it.hasNext()) {
1731                                                op.complexOperate(z, it.aDouble, 0, it.bDouble, db.getElementDoubleAbs(it.bIndex + 1));
1732                                                float ox = (float) z[0];
1733                                                for (int j = 0; j < is; j++) {
1734                                                        af32data[it.oIndex + j] = ox;
1735                                                }
1736                                        }
1737                                } else {
1738                                        while (it.hasNext()) {
1739                                                op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1),
1740                                                                it.bDouble, db.getElementDoubleAbs(it.bIndex + 1));
1741                                                float ox = (float) z[0];
1742                                                for (int j = 0; j < is; j++) {
1743                                                        af32data[it.oIndex + j] = ox;
1744                                                }
1745                                        }
1746                                }
1747                        }
1748                        break;
1749                case Dataset.ARRAYFLOAT64:
1750                        double[] af64data = ((CompoundDoubleDataset) result).getData();
1751
1752                        if (!da.isComplex() && !db.isComplex()) {
1753                                if (is == 1) {
1754                                        while (it.hasNext()) {
1755                                                af64data[it.oIndex] = op.doubleOperate(it.aDouble, it.bDouble);
1756                                        }
1757                                } else {
1758                                        int ms;
1759                                        if (as == 1 && bs != 1) {
1760                                                ms = Math.min(is, bs);
1761                                                while (it.hasNext()) {
1762                                                        af64data[it.oIndex] = op.doubleOperate(it.aDouble, it.bDouble);
1763                                                        for (int j = 1; j < ms; j++) {
1764                                                                af64data[it.oIndex + j] = op.doubleOperate(it.aDouble,
1765                                                                                db.getElementDoubleAbs(it.bIndex + j));
1766                                                        }
1767                                                }
1768                                        } else if (as != 1 && bs == 1) {
1769                                                ms = Math.min(is, as);
1770                                                while (it.hasNext()) {
1771                                                        af64data[it.oIndex] = op.doubleOperate(it.aDouble, it.bDouble);
1772                                                        for (int j = 1; j < ms; j++) {
1773                                                                af64data[it.oIndex + j] = op.doubleOperate(da.getElementDoubleAbs(it.aIndex + j),
1774                                                                                it.bDouble);
1775                                                        }
1776                                                }
1777                                        } else {
1778                                                ms = Math.min(is, Math.min(as, bs));
1779                                                while (it.hasNext()) {
1780                                                        af64data[it.oIndex] = op.doubleOperate(it.aDouble, it.bDouble);
1781                                                        for (int j = 1; j < ms; j++) {
1782                                                                af64data[it.oIndex + j] = op.doubleOperate(da.getElementDoubleAbs(it.aIndex + j),
1783                                                                                db.getElementDoubleAbs(it.bIndex + j));
1784                                                        }
1785                                                }
1786                                        }
1787                                }
1788                        } else {
1789                                z = new double[2];
1790                                if (!db.isComplex()) { // only a complex
1791                                        while (it.hasNext()) {
1792                                                op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1), it.bDouble, 0);
1793                                                double ox = z[0];
1794                                                for (int j = 0; j < is; j++) {
1795                                                        af64data[it.oIndex + j] = ox;
1796                                                }
1797                                        }
1798                                } else if (!da.isComplex()) { // only b complex
1799                                        while (it.hasNext()) {
1800                                                op.complexOperate(z, it.aDouble, 0, it.bDouble, db.getElementDoubleAbs(it.bIndex + 1));
1801                                                double ox = z[0];
1802                                                for (int j = 0; j < is; j++) {
1803                                                        af64data[it.oIndex + j] = ox;
1804                                                }
1805                                        }
1806                                } else {
1807                                        while (it.hasNext()) {
1808                                                op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1),
1809                                                                it.bDouble, db.getElementDoubleAbs(it.bIndex + 1));
1810                                                double ox = z[0];
1811                                                for (int j = 0; j < is; j++) {
1812                                                        af64data[it.oIndex + j] = ox;
1813                                                }
1814                                        }
1815                                }
1816                        }
1817                        break;
1818                case Dataset.COMPLEX64:
1819                        float[] c64data = ((ComplexFloatDataset) result).getData();
1820                        z = new double[2];
1821
1822                        if (da.isComplex() || db.isComplex()) {
1823                                if (!db.isComplex()) { // only a complex
1824                                        while (it.hasNext()) {
1825                                                op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1), it.bDouble, 0);
1826                                                c64data[it.oIndex] = (float) z[0];
1827                                                c64data[it.oIndex + 1] = (float) z[1];
1828                                        }
1829                                } else if (!da.isComplex()) { // only b complex
1830                                        while (it.hasNext()) {
1831                                                op.complexOperate(z, it.aDouble, 0, it.bDouble, db.getElementDoubleAbs(it.bIndex + 1));
1832                                                c64data[it.oIndex] = (float) z[0];
1833                                                c64data[it.oIndex + 1] = (float) z[1];
1834                                        }
1835                                } else {
1836                                        while (it.hasNext()) {
1837                                                op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1), it.bDouble,
1838                                                                db.getElementDoubleAbs(it.bIndex + 1));
1839                                                c64data[it.oIndex] = (float) z[0];
1840                                                c64data[it.oIndex + 1] = (float) z[1];
1841                                        }
1842                                }
1843                        } else {
1844                                while (it.hasNext()) {
1845                                        op.complexOperate(z, it.aDouble, 0, it.bDouble, 0);
1846                                        c64data[it.oIndex] = (float) z[0];
1847                                        c64data[it.oIndex + 1] = (float) z[1];
1848                                }
1849                        }
1850                        break;
1851                case Dataset.COMPLEX128:
1852                        double[] c128data = ((ComplexDoubleDataset) result).getData();
1853                        z = new double[2];
1854
1855                        if (da.isComplex() || db.isComplex()) {
1856                                if (!db.isComplex()) { // only a complex
1857                                        while (it.hasNext()) {
1858                                                op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1), it.bDouble, 0);
1859                                                c128data[it.oIndex] = z[0];
1860                                                c128data[it.oIndex + 1] = z[1];
1861                                        }
1862                                } else if (!da.isComplex()) { // only b complex
1863                                        while (it.hasNext()) {
1864                                                op.complexOperate(z, it.aDouble, 0, it.bDouble, db.getElementDoubleAbs(it.bIndex + 1));
1865                                                c128data[it.oIndex] = z[0];
1866                                                c128data[it.oIndex + 1] = z[1];
1867                                        }
1868                                } else {
1869                                        while (it.hasNext()) {
1870                                                op.complexOperate(z, it.aDouble, da.getElementDoubleAbs(it.aIndex + 1), it.bDouble,
1871                                                                db.getElementDoubleAbs(it.bIndex + 1));
1872                                                c128data[it.oIndex] = z[0];
1873                                                c128data[it.oIndex + 1] = z[1];
1874                                        }
1875                                }
1876                        } else {
1877                                while (it.hasNext()) {
1878                                        op.complexOperate(z, it.aDouble, 0, it.bDouble, 0);
1879                                        c128data[it.oIndex] = z[0];
1880                                        c128data[it.oIndex + 1] = z[1];
1881                                }
1882                        }
1883                        break;
1884                default:
1885                        throw new UnsupportedOperationException("operate does not support this dataset type");
1886                }
1887
1888                // set the name based on the changes made
1889                result.setName(op.toString(da.getName(), db.getName()));
1890
1891                return result;
1892        }
1893}