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