    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}