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