001/*- 002 ******************************************************************************* 003 * Copyright (c) 2011, 2016 Diamond Light Source Ltd. 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the Eclipse Public License v1.0 006 * which accompanies this distribution, and is available at 007 * http://www.eclipse.org/legal/epl-v10.html 008 * 009 * Contributors: 010 * Peter Chang - initial API and implementation and/or initial documentation 011 *******************************************************************************/ 012 013package org.eclipse.january.dataset; 014 015import java.util.ArrayList; 016import java.util.List; 017 018/** 019 * Comparison and logical methods 020 */ 021public class Comparisons { 022 /** 023 * Compare item-wise for whether a's element is equal b's 024 * <p> 025 * For multi-element items, comparison is true if all elements in an item 026 * are equal. Where the datasets have mismatched item sizes, the first element 027 * of the dataset with smaller items is used for comparison. 028 * @param a first operand 029 * @param b second operand 030 * @return dataset where item is true if {@code a == b} 031 */ 032 public static BooleanDataset equalTo(Object a, Object b) { 033 return equalTo(a, b, null); 034 } 035 036 /** 037 * Compare item-wise for whether a's element is equal b's 038 * <p> 039 * For multi-element items, comparison is true if all elements in an item 040 * are equal. Where the datasets have mismatched item sizes, the first element 041 * of the dataset with smaller items is used for comparison. 042 * @param a first operand 043 * @param b second operand 044 * @param o output can be null - in which case, a new dataset is created 045 * @return dataset where item is true if {@code a == b} 046 */ 047 public static BooleanDataset equalTo(Object a, Object b, BooleanDataset o) { 048 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 049 final Dataset db = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); 050 051 List<int[]> sl = BroadcastUtils.broadcastShapes(da.getShapeRef(), db.getShapeRef(), o == null ? null : o.getShapeRef()); 052 053 final BooleanDataset r = o == null ? DatasetFactory.zeros(BooleanDataset.class, sl.get(0)) : o; 054 055 final BroadcastIterator it = BroadcastIterator.createIterator(da, db, r); 056 final int as = da.getElementsPerItem(); 057 final int bs = db.getElementsPerItem(); 058 059 if (as > bs) { 060 if (da.isComplex()) { 061 while (it.hasNext()) { 062 final double bd = it.bDouble; 063 boolean rb = it.aDouble == bd && da.getElementDoubleAbs(it.aIndex + 1) == 0; 064 r.setAbs(it.oIndex, rb); 065 } 066 } else if (it.isOutputDouble()) { 067 while (it.hasNext()) { 068 final double bd = it.bDouble; 069 boolean rb = true; 070 for (int j = 0; rb && j < as; j++) { 071 rb &= da.getElementDoubleAbs(it.aIndex + j) == bd; 072 } 073 r.setAbs(it.oIndex, rb); 074 } 075 } else { 076 while (it.hasNext()) { 077 final long bl = it.bLong; 078 boolean rb = true; 079 for (int j = 0; rb && j < as; j++) { 080 rb &= da.getElementLongAbs(it.aIndex + j) == bl; 081 } 082 r.setAbs(it.oIndex, rb); 083 } 084 } 085 } else if (as < bs) { 086 if (db.isComplex()) { 087 while (it.hasNext()) { 088 final double ad = it.aDouble; 089 boolean rb = ad == it.bDouble && 0 == db.getElementDoubleAbs(it.bIndex + 1); 090 r.setAbs(it.oIndex, rb); 091 } 092 } else if (it.isOutputDouble()) { 093 while (it.hasNext()) { 094 final double ad = it.aDouble; 095 boolean rb = true; 096 for (int j = 0; rb && j < bs; j++) { 097 rb &= ad == db.getElementDoubleAbs(it.bIndex + j); 098 } 099 r.setAbs(it.oIndex, rb); 100 } 101 } else { 102 while (it.hasNext()) { 103 final long al = it.aLong; 104 boolean rb = true; 105 for (int j = 0; rb && j < bs; j++) { 106 rb &= al == db.getElementLongAbs(it.bIndex + j); 107 } 108 r.setAbs(it.oIndex, rb); 109 } 110 } 111 } else { 112 if (as == 1) { 113 if (it.isOutputDouble()) { 114 while (it.hasNext()) { 115 r.setAbs(it.oIndex, it.aDouble == it.bDouble); 116 } 117 } else { 118 while (it.hasNext()) { 119 r.setAbs(it.oIndex, it.aLong == it.bLong); 120 } 121 } 122 } else if (it.isOutputDouble()) { 123 while (it.hasNext()) { 124 boolean rb = true; 125 for (int j = 0; rb && j < bs; j++) { 126 rb &= da.getElementDoubleAbs(it.aIndex + j) == db.getElementDoubleAbs(it.bIndex + j); 127 } 128 r.setAbs(it.oIndex, rb); 129 } 130 } else { 131 while (it.hasNext()) { 132 boolean rb = true; 133 for (int j = 0; rb && j < bs; j++) { 134 rb &= da.getElementLongAbs(it.aIndex + j) == db.getElementLongAbs(it.bIndex + j); 135 } 136 r.setAbs(it.oIndex, rb); 137 } 138 } 139 } 140 141 return r; 142 } 143 144 /** 145 * Compare item-wise for whether a's element is equal b's 146 * <p> 147 * For multi-element items, comparison is true if all elements in an item 148 * are equal. Where the datasets have mismatched item sizes, the first element 149 * of the dataset with smaller items is used for comparison. 150 * @param a first operand 151 * @param b second operand 152 * @param relTolerance relative tolerance 153 * @param absTolerance absolute tolerance 154 * @return dataset where item is true if {@code abs(a - b) <= absTol + relTol*max(abs(a),abs(b))} 155 */ 156 public static BooleanDataset almostEqualTo(Object a, Object b, double relTolerance, double absTolerance) { 157 return almostEqualTo(a, b, null, relTolerance, absTolerance); 158 } 159 160 /** 161 * @param a first operand 162 * @param b second operand 163 * @param relTolerance relative tolerance 164 * @param absTolerance absolute tolerance 165 * @return true if {@code abs(a - b) <= max(absTol, relTol*max(abs(a),abs(b)))} 166 */ 167 public final static boolean isClose(double a, double b, double relTolerance, double absTolerance) { 168 return Math.abs(a - b) <= Math.max(absTolerance, relTolerance * Math.max(Math.abs(a), Math.abs(b))); 169 } 170 171 private final static boolean isCloseNP(double a, double b, double rt, double at) { 172 return Math.abs(a - b) <= at + rt * Math.max(Math.abs(a), Math.abs(b)); 173 } 174 175 private final static boolean isCloseNP(double a, double rt, double at) { 176 double aa = Math.abs(a); 177 return aa <= at + rt * aa; 178 } 179 180 /** 181 * Compare item-wise for whether a's element is equal b's 182 * <p> 183 * For multi-element items, comparison is true if all elements in an item 184 * are equal. Where the datasets have mismatched item sizes, the first element 185 * of the dataset with smaller items is used for comparison. 186 * @param a first operand 187 * @param b second operand 188 * @param o output can be null - in which case, a new dataset is created 189 * @param relTolerance relative tolerance 190 * @param absTolerance absolute tolerance 191 * @return dataset where item is true if {@code abs(a - b) <= absTol + relTol*max(abs(a),abs(b))} 192 */ 193 public static BooleanDataset almostEqualTo(Object a, Object b, BooleanDataset o, double relTolerance, double absTolerance) { 194 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 195 final Dataset db = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); 196 197 List<int[]> sl = BroadcastUtils.broadcastShapes(da.getShapeRef(), db.getShapeRef(), o == null ? null : o.getShapeRef()); 198 199 final BooleanDataset r = o == null ? DatasetFactory.zeros(BooleanDataset.class, sl.get(0)) : o; 200 201 final BroadcastIterator it = BroadcastIterator.createIterator(da, db, r); 202 it.setOutputDouble(true); 203 final int as = da.getElementsPerItem(); 204 final int bs = db.getElementsPerItem(); 205 206 if (as > bs) { 207 if (da.isComplex()) { 208 while (it.hasNext()) { 209 boolean rb = isCloseNP(it.aDouble, it.bDouble, relTolerance, absTolerance); 210 if (rb) { 211 rb = isCloseNP(da.getElementDoubleAbs(it.aIndex + 1), relTolerance, absTolerance); 212 } 213 r.setAbs(it.oIndex, rb); 214 } 215 } else { 216 while (it.hasNext()) { 217 final double bd = it.bDouble; 218 boolean rb = true; 219 for (int j = 0; rb && j < as; j++) { 220 rb &= isCloseNP(da.getElementDoubleAbs(it.aIndex + j), bd, relTolerance, absTolerance); 221 } 222 r.setAbs(it.oIndex, rb); 223 } 224 } 225 } else if (as < bs) { 226 if (db.isComplex()) { 227 while (it.hasNext()) { 228 boolean rb = isCloseNP(it.aDouble, it.bDouble, relTolerance, absTolerance); 229 if (rb) { 230 rb = isCloseNP(db.getElementDoubleAbs(it.bIndex + 1), relTolerance, absTolerance); 231 } 232 r.setAbs(it.oIndex, rb); 233 } 234 } else { 235 while (it.hasNext()) { 236 final double ad = it.aDouble; 237 boolean rb = true; 238 for (int j = 0; rb && j < bs; j++) { 239 rb &= isCloseNP(ad, db.getElementDoubleAbs(it.bIndex + j), relTolerance, absTolerance); 240 } 241 r.setAbs(it.oIndex, rb); 242 } 243 } 244 } else { 245 if (as == 1) { 246 while (it.hasNext()) { 247 r.setAbs(it.oIndex, isCloseNP(it.aDouble, it.bDouble, relTolerance, absTolerance)); 248 } 249 } else { 250 while (it.hasNext()) { 251 boolean rb = isCloseNP(it.aDouble, it.bDouble, relTolerance, absTolerance); 252 for (int j = 1; rb && j < bs; j++) { 253 rb &= isCloseNP(da.getElementDoubleAbs(it.aIndex + j), db.getElementDoubleAbs(it.bIndex + j), relTolerance, absTolerance); 254 } 255 r.setAbs(it.oIndex, rb); 256 } 257 } 258 } 259 260 return r; 261 } 262 263 /** 264 * Compare item-wise for whether a's element is greater than b's 265 * <p> 266 * For multi-element items, comparison is true if all elements in an item 267 * are greater. Where the datasets have mismatched item sizes, the first element 268 * of the dataset with smaller items is used for comparison. 269 * @param a first operand 270 * @param b second operand 271 * @return dataset where item is true if {@code a > b} 272 */ 273 public static BooleanDataset greaterThan(Object a, Object b) { 274 return greaterThan(a, b, null); 275 } 276 277 /** 278 * Compare item-wise for whether a's element is greater than b's 279 * <p> 280 * For multi-element items, comparison is true if all elements in an item 281 * are greater. Where the datasets have mismatched item sizes, the first element 282 * of the dataset with smaller items is used for comparison. 283 * @param a first operand 284 * @param b second operand 285 * @param o output can be null - in which case, a new dataset is created 286 * @return dataset where item is true if {@code a > b} 287 */ 288 public static BooleanDataset greaterThan(Object a, Object b, BooleanDataset o) { 289 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 290 final Dataset db = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); 291 292 List<int[]> sl = BroadcastUtils.broadcastShapes(da.getShapeRef(), db.getShapeRef(), o == null ? null : o.getShapeRef()); 293 294 final BooleanDataset r = o == null ? DatasetFactory.zeros(BooleanDataset.class, sl.get(0)) : o; 295 296 final BroadcastIterator it = BroadcastIterator.createIterator(da, db, r); 297 final int as = da.getElementsPerItem(); 298 final int bs = db.getElementsPerItem(); 299 300 if (it.isOutputDouble()) { 301 if (as > bs) { 302 while (it.hasNext()) { 303 final double bd = it.bDouble; 304 boolean rb = true; 305 for (int j = 0; rb && j < as; j++) { 306 rb &= da.getElementDoubleAbs(it.aIndex + j) > bd; 307 } 308 r.setAbs(it.oIndex, rb); 309 } 310 } else if (as < bs) { 311 while (it.hasNext()) { 312 final double ad = it.aDouble; 313 boolean rb = true; 314 for (int j = 0; rb && j < bs; j++) { 315 rb &= ad > db.getElementDoubleAbs(it.bIndex + j); 316 } 317 r.setAbs(it.oIndex, rb); 318 } 319 } else { 320 if (as == 1) { 321 while (it.hasNext()) { 322 r.setAbs(it.oIndex, it.aDouble > it.bDouble); 323 } 324 } else { 325 while (it.hasNext()) { 326 boolean rb = true; 327 for (int j = 0; rb && j < bs; j++) { 328 rb &= da.getElementDoubleAbs(it.aIndex + j) > db.getElementDoubleAbs(it.bIndex + j); 329 } 330 r.setAbs(it.oIndex, rb); 331 } 332 } 333 } 334 } else { 335 if (as > bs) { 336 while (it.hasNext()) { 337 final double bl = it.bLong; 338 boolean rb = true; 339 for (int j = 0; rb && j < as; j++) { 340 rb &= da.getElementLongAbs(it.aIndex + j) > bl; 341 } 342 r.setAbs(it.oIndex, rb); 343 } 344 } else if (as < bs) { 345 while (it.hasNext()) { 346 final double al = it.aLong; 347 boolean rb = true; 348 for (int j = 0; rb && j < bs; j++) { 349 rb &= al > db.getElementLongAbs(it.bIndex + j); 350 } 351 r.setAbs(it.oIndex, rb); 352 } 353 } else { 354 if (as == 1) { 355 while (it.hasNext()) { 356 r.setAbs(it.oIndex, it.aLong > it.bLong); 357 } 358 } else { 359 while (it.hasNext()) { 360 boolean rb = true; 361 for (int j = 0; rb && j < bs; j++) { 362 rb &= da.getElementLongAbs(it.aIndex + j) > db.getElementLongAbs(it.bIndex + j); 363 } 364 r.setAbs(it.oIndex, rb); 365 } 366 } 367 } 368 } 369 370 return r; 371 } 372 373 /** 374 * Compare item-wise for whether a's element is greater than or equal to b's 375 * <p> 376 * For multi-element items, comparison is true if all elements in an item 377 * are greater or equal. Where the datasets have mismatched item sizes, the first element 378 * of the dataset with smaller items is used for comparison. 379 * @param a first operand 380 * @param b second operand 381 * @return dataset where item is true if {@code a >= b} 382 */ 383 public static BooleanDataset greaterThanOrEqualTo(Object a, Object b) { 384 return greaterThanOrEqualTo(a, b, null); 385 } 386 387 /** 388 * Compare item-wise for whether a's element is greater than or equal to b's 389 * <p> 390 * For multi-element items, comparison is true if all elements in an item 391 * are greater or equal. Where the datasets have mismatched item sizes, the first element 392 * of the dataset with smaller items is used for comparison. 393 * @param a first operand 394 * @param b second operand 395 * @param o output can be null - in which case, a new dataset is created 396 * @return dataset where item is true if {@code a >= b} 397 */ 398 public static BooleanDataset greaterThanOrEqualTo(Object a, Object b, BooleanDataset o) { 399 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 400 final Dataset db = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); 401 402 List<int[]> sl = BroadcastUtils.broadcastShapes(da.getShapeRef(), db.getShapeRef(), o == null ? null : o.getShapeRef()); 403 404 final BooleanDataset r = o == null ? DatasetFactory.zeros(BooleanDataset.class, sl.get(0)) : o; 405 406 final BroadcastIterator it = BroadcastIterator.createIterator(da, db, r); 407 final int as = da.getElementsPerItem(); 408 final int bs = db.getElementsPerItem(); 409 410 if (it.isOutputDouble()) { 411 if (as > bs) { 412 while (it.hasNext()) { 413 final double bd = it.bDouble; 414 boolean rb = true; 415 for (int j = 0; rb && j < as; j++) { 416 rb &= da.getElementDoubleAbs(it.aIndex + j) >= bd; 417 } 418 r.setAbs(it.oIndex, rb); 419 } 420 } else if (as < bs) { 421 while (it.hasNext()) { 422 final double ad = it.aDouble; 423 boolean rb = true; 424 for (int j = 0; rb && j < bs; j++) { 425 rb &= ad >= db.getElementDoubleAbs(it.bIndex + j); 426 } 427 r.setAbs(it.oIndex, rb); 428 } 429 } else { 430 if (as == 1) { 431 while (it.hasNext()) { 432 r.setAbs(it.oIndex, it.aDouble >= it.bDouble); 433 } 434 } else { 435 while (it.hasNext()) { 436 boolean rb = true; 437 for (int j = 0; rb && j < bs; j++) { 438 rb &= da.getElementDoubleAbs(it.aIndex + j) >= db.getElementDoubleAbs(it.bIndex + j); 439 } 440 r.setAbs(it.oIndex, rb); 441 } 442 } 443 } 444 } else { 445 if (as > bs) { 446 while (it.hasNext()) { 447 final double bl = it.bLong; 448 boolean rb = true; 449 for (int j = 0; rb && j < as; j++) { 450 rb &= da.getElementLongAbs(it.aIndex + j) >= bl; 451 } 452 r.setAbs(it.oIndex, rb); 453 } 454 } else if (as < bs) { 455 while (it.hasNext()) { 456 final double al = it.aLong; 457 boolean rb = true; 458 for (int j = 0; rb && j < bs; j++) { 459 rb &= al >= db.getElementLongAbs(it.bIndex + j); 460 } 461 r.setAbs(it.oIndex, rb); 462 } 463 } else { 464 if (as == 1) { 465 while (it.hasNext()) { 466 r.setAbs(it.oIndex, it.aLong >= it.bLong); 467 } 468 } else { 469 while (it.hasNext()) { 470 boolean rb = true; 471 for (int j = 0; rb && j < bs; j++) { 472 rb &= da.getElementLongAbs(it.aIndex + j) >= db.getElementLongAbs(it.bIndex + j); 473 } 474 r.setAbs(it.oIndex, rb); 475 } 476 } 477 } 478 } 479 480 return r; 481 } 482 483 /** 484 * Compare item-wise for whether a's element is less than b's 485 * <p> 486 * For multi-element items, comparison is true if all elements in an item 487 * are lesser. Where the datasets have mismatched item sizes, the first element 488 * of the dataset with smaller items is used for comparison. 489 * @param a first operand 490 * @param b second operand 491 * @return dataset where item is true if {@code a < b} 492 */ 493 public static BooleanDataset lessThan(Object a, Object b) { 494 return lessThan(a, b, null); 495 } 496 497 /** 498 * Compare item-wise for whether a's element is less than b's 499 * <p> 500 * For multi-element items, comparison is true if all elements in an item 501 * are lesser. Where the datasets have mismatched item sizes, the first element 502 * of the dataset with smaller items is used for comparison. 503 * @param a first operand 504 * @param b second operand 505 * @param o output can be null - in which case, a new dataset is created 506 * @return dataset where item is true if {@code a < b} 507 */ 508 public static BooleanDataset lessThan(Object a, Object b, BooleanDataset o) { 509 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 510 final Dataset db = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); 511 512 List<int[]> sl = BroadcastUtils.broadcastShapes(da.getShapeRef(), db.getShapeRef(), o == null ? null : o.getShapeRef()); 513 514 final BooleanDataset r = o == null ? DatasetFactory.zeros(BooleanDataset.class, sl.get(0)) : o; 515 516 final BroadcastIterator it = BroadcastIterator.createIterator(da, db, r); 517 it.setOutputDouble(true); 518 final int as = da.getElementsPerItem(); 519 final int bs = db.getElementsPerItem(); 520 521 if (it.isOutputDouble()) { 522 if (as > bs) { 523 while (it.hasNext()) { 524 final double bd = it.bDouble; 525 boolean rb = true; 526 for (int j = 0; rb && j < as; j++) { 527 rb &= da.getElementDoubleAbs(it.aIndex + j) < bd; 528 } 529 r.setAbs(it.oIndex, rb); 530 } 531 } else if (as < bs) { 532 while (it.hasNext()) { 533 final double ad = it.aDouble; 534 boolean rb = true; 535 for (int j = 0; rb && j < bs; j++) { 536 rb &= ad < db.getElementDoubleAbs(it.bIndex + j); 537 } 538 r.setAbs(it.oIndex, rb); 539 } 540 } else { 541 if (as == 1) { 542 while (it.hasNext()) { 543 r.setAbs(it.oIndex, it.aDouble < it.bDouble); 544 } 545 } else { 546 while (it.hasNext()) { 547 boolean rb = true; 548 for (int j = 0; rb && j < bs; j++) { 549 rb &= da.getElementDoubleAbs(it.aIndex + j) < db.getElementDoubleAbs(it.bIndex + j); 550 } 551 r.setAbs(it.oIndex, rb); 552 } 553 } 554 } 555 } else { 556 if (as > bs) { 557 while (it.hasNext()) { 558 final double bl = it.bLong; 559 boolean rb = true; 560 for (int j = 0; rb && j < as; j++) { 561 rb &= da.getElementLongAbs(it.aIndex + j) < bl; 562 } 563 r.setAbs(it.oIndex, rb); 564 } 565 } else if (as < bs) { 566 while (it.hasNext()) { 567 final double al = it.aLong; 568 boolean rb = true; 569 for (int j = 0; rb && j < bs; j++) { 570 rb &= al < db.getElementLongAbs(it.bIndex + j); 571 } 572 r.setAbs(it.oIndex, rb); 573 } 574 } else { 575 if (as == 1) { 576 while (it.hasNext()) { 577 r.setAbs(it.oIndex, it.aLong < it.bLong); 578 } 579 } else { 580 while (it.hasNext()) { 581 boolean rb = true; 582 for (int j = 0; rb && j < bs; j++) { 583 rb &= da.getElementLongAbs(it.aIndex + j) < db.getElementLongAbs(it.bIndex + j); 584 } 585 r.setAbs(it.oIndex, rb); 586 } 587 } 588 } 589 } 590 591 return r; 592 } 593 594 /** 595 * Compare item-wise for whether a's element is less than or equal to b's 596 * <p> 597 * For multi-element items, comparison is true if all elements in an item 598 * are lesser or equal. Where the datasets have mismatched item sizes, the first element 599 * of the dataset with smaller items is used for comparison. 600 * @param a first operand 601 * @param b second operand 602 * @return dataset where item is true if {@code a <= b} 603 */ 604 public static BooleanDataset lessThanOrEqualTo(Object a, Object b) { 605 return lessThanOrEqualTo(a, b, null); 606 } 607 608 /** 609 * Compare item-wise for whether a's element is less than or equal to b's 610 * <p> 611 * For multi-element items, comparison is true if all elements in an item 612 * are lesser or equal. Where the datasets have mismatched item sizes, the first element 613 * of the dataset with smaller items is used for comparison. 614 * @param a first operand 615 * @param b second operand 616 * @param o output can be null - in which case, a new dataset is created 617 * @return dataset where item is true if {@code a <= b} 618 */ 619 public static BooleanDataset lessThanOrEqualTo(Object a, Object b, BooleanDataset o) { 620 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 621 final Dataset db = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); 622 623 List<int[]> sl = BroadcastUtils.broadcastShapes(da.getShapeRef(), db.getShapeRef(), o == null ? null : o.getShapeRef()); 624 625 final BooleanDataset r = o == null ? DatasetFactory.zeros(BooleanDataset.class, sl.get(0)) : o; 626 627 final BroadcastIterator it = BroadcastIterator.createIterator(da, db, r); 628 it.setOutputDouble(true); 629 final int as = da.getElementsPerItem(); 630 final int bs = db.getElementsPerItem(); 631 632 if (it.isOutputDouble()) { 633 if (as > bs) { 634 while (it.hasNext()) { 635 final double bd = it.bDouble; 636 boolean rb = true; 637 for (int j = 0; rb && j < as; j++) { 638 rb &= da.getElementDoubleAbs(it.aIndex + j) <= bd; 639 } 640 r.setAbs(it.oIndex, rb); 641 } 642 } else if (as < bs) { 643 while (it.hasNext()) { 644 final double ad = it.aDouble; 645 boolean rb = true; 646 for (int j = 0; rb && j < bs; j++) { 647 rb &= ad <= db.getElementDoubleAbs(it.bIndex + j); 648 } 649 r.setAbs(it.oIndex, rb); 650 } 651 } else { 652 if (as == 1) { 653 while (it.hasNext()) { 654 r.setAbs(it.oIndex, it.aDouble <= it.bDouble); 655 } 656 } else { 657 while (it.hasNext()) { 658 boolean rb = true; 659 for (int j = 0; rb && j < bs; j++) { 660 rb &= da.getElementDoubleAbs(it.aIndex + j) <= db.getElementDoubleAbs(it.bIndex + j); 661 } 662 r.setAbs(it.oIndex, rb); 663 } 664 } 665 } 666 } else { 667 if (as > bs) { 668 while (it.hasNext()) { 669 final double bl = it.bLong; 670 boolean rb = true; 671 for (int j = 0; rb && j < as; j++) { 672 rb &= da.getElementLongAbs(it.aIndex + j) <= bl; 673 } 674 r.setAbs(it.oIndex, rb); 675 } 676 } else if (as < bs) { 677 while (it.hasNext()) { 678 final double al = it.aLong; 679 boolean rb = true; 680 for (int j = 0; rb && j < bs; j++) { 681 rb &= al <= db.getElementLongAbs(it.bIndex + j); 682 } 683 r.setAbs(it.oIndex, rb); 684 } 685 } else { 686 if (as == 1) { 687 while (it.hasNext()) { 688 r.setAbs(it.oIndex, it.aLong <= it.bLong); 689 } 690 } else { 691 while (it.hasNext()) { 692 boolean rb = true; 693 for (int j = 0; rb && j < bs; j++) { 694 rb &= da.getElementLongAbs(it.aIndex + j) <= db.getElementLongAbs(it.bIndex + j); 695 } 696 r.setAbs(it.oIndex, rb); 697 } 698 } 699 } 700 } 701 702 return r; 703 } 704 705 /** 706 * @param a operand 707 * @param lo lower bound 708 * @param hi upper bound 709 * @return dataset where item is true if {@code l <= a <= h} 710 */ 711 public static BooleanDataset withinRange(Object a, Number lo, Number hi) { 712 return withinRange(a, null, lo, hi); 713 } 714 715 /** 716 * @param a operand 717 * @param lo lower bound 718 * @param hi upper bound 719 * @param o output can be null - in which case, a new dataset is created 720 * @return dataset where item is true if {@code l <= a <= h} 721 */ 722 public static BooleanDataset withinRange(Object a, BooleanDataset o, Number lo, Number hi) { 723 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 724 725 List<int[]> sl = BroadcastUtils.broadcastShapes(da.getShapeRef(), o == null ? null : o.getShapeRef()); 726 727 final BooleanDataset r = o == null ? DatasetFactory.zeros(BooleanDataset.class, sl.get(0)) : o; 728 729 final SingleInputBroadcastIterator it = new SingleInputBroadcastIterator(da, r); 730 final int as = da.getElementsPerItem(); 731 732 if (it.isOutputDouble()) { 733 final double l = lo.doubleValue(); 734 final double h = hi.doubleValue(); 735 if (as == 1) { 736 while (it.hasNext()) { 737 final double ad = it.aDouble; 738 r.setAbs(it.oIndex, ad >= l && ad <= h); 739 } 740 } else { 741 while (it.hasNext()) { 742 boolean rb = true; 743 for (int j = 0; rb && j < as; j++) { 744 final double ad = da.getElementDoubleAbs(it.aIndex); 745 rb &= ad >= l && ad <= h; 746 } 747 r.setAbs(it.oIndex, rb); 748 } 749 } 750 } else { 751 final long l = lo.longValue(); 752 final long h = hi.longValue(); 753 if (as == 1) { 754 while (it.hasNext()) { 755 final long al = it.aLong; 756 r.setAbs(it.oIndex, al >= l && al <= h); 757 } 758 } else { 759 while (it.hasNext()) { 760 boolean rb = true; 761 for (int j = 0; rb && j < as; j++) { 762 final long al = da.getElementLongAbs(it.aIndex); 763 rb &= al >= l && al <= h; 764 } 765 r.setAbs(it.oIndex, rb); 766 } 767 } 768 } 769 770 return r; 771 } 772 773 /** 774 * Compare item-wise for whether a's element is almost equal to b's 775 * <p> 776 * For multi-element items, comparison is true if all elements in an item 777 * are equal up to a tolerance. Where the datasets have mismatched item sizes, the first element 778 * of the dataset with smaller items is used for comparison. 779 * @param a first operand 780 * @param b second operand 781 * @param relTolerance relative tolerance 782 * @param absTolerance absolute tolerance 783 * @return true if all items satisfy {@code abs(a - b) <= absTol + relTol*max(abs(a),abs(b))} 784 */ 785 public static boolean allCloseTo(Object a, Object b, double relTolerance, double absTolerance) { 786 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 787 final Dataset db = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); 788 789 final BroadcastIterator it = BroadcastIterator.createIterator(da, db); 790 it.setOutputDouble(true); 791 final int as = da.getElementsPerItem(); 792 final int bs = db.getElementsPerItem(); 793 794 if (as > bs) { 795 if (da.isComplex()) { 796 while (it.hasNext()) { 797 if (!isCloseNP(it.aDouble, it.bDouble, relTolerance, absTolerance)) 798 return false; 799 if (!isCloseNP(da.getElementDoubleAbs(it.aIndex + 1), relTolerance, absTolerance)) 800 return false; 801 } 802 } else { 803 while (it.hasNext()) { 804 final double bd = it.bDouble; 805 for (int j = 0; j < as; j++) { 806 if (!isCloseNP(da.getElementDoubleAbs(it.aIndex + j), bd, relTolerance, absTolerance)) 807 return false; 808 } 809 } 810 } 811 } else if (as < bs) { 812 if (db.isComplex()) { 813 while (it.hasNext()) { 814 if (!isCloseNP(it.aDouble, it.bDouble, relTolerance, absTolerance)) 815 return false; 816 if (!isCloseNP(db.getElementDoubleAbs(it.bIndex + 1), relTolerance, absTolerance)) 817 return false; 818 } 819 } else { 820 while (it.hasNext()) { 821 final double ad = it.aDouble; 822 for (int j = 0; j < bs; j++) { 823 if (!isCloseNP(ad, db.getElementDoubleAbs(it.bIndex + j), relTolerance, absTolerance)) 824 return false; 825 } 826 } 827 } 828 } else { 829 if (as == 1) { 830 while (it.hasNext()) { 831 if (!isCloseNP(it.aDouble, it.bDouble, relTolerance, absTolerance)) 832 return false; 833 } 834 } else { 835 while (it.hasNext()) { 836 for (int j = 0; j < bs; j++) { 837 if (!isCloseNP(da.getElementDoubleAbs(it.aIndex + j), db.getElementDoubleAbs(it.bIndex + j), relTolerance, absTolerance)) 838 return false; 839 } 840 } 841 } 842 } 843 844 return true; 845 } 846 847 /** 848 * @param a operand 849 * @return true if all elements are true 850 */ 851 public static boolean allTrue(Object a) { 852 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 853 final IndexIterator it = da.getIterator(); 854 final int as = da.getElementsPerItem(); 855 856 if (as == 1) { 857 while (it.hasNext()) { 858 if (!da.getElementBooleanAbs(it.index)) 859 return false; 860 } 861 } else { 862 while (it.hasNext()) { 863 for (int j = 0; j < as; j++) { 864 if (!da.getElementBooleanAbs(it.index + j)) 865 return false; 866 } 867 } 868 } 869 return true; 870 } 871 872 /** 873 * Test if all items along given axis are true in the input dataset 874 * @param a operand 875 * @param axis to reduce along 876 * @return boolean dataset 877 */ 878 public static BooleanDataset allTrue(IDataset a, int axis) { 879 axis = ShapeUtils.checkAxis(a.getRank(), axis); 880 881 int rank = a.getRank(); 882 int[] oshape = a.getShape(); 883 int alen = oshape[axis]; 884 oshape[axis] = 1; 885 886 int[] nshape = ShapeUtils.squeezeShape(oshape, false); 887 888 BooleanDataset result = DatasetFactory.zeros(BooleanDataset.class, nshape); 889 890 IndexIterator qiter = result.getIterator(true); 891 int[] qpos = qiter.getPos(); 892 int[] spos = oshape; 893 894 while (qiter.hasNext()) { 895 int i = 0; 896 for (; i < axis; i++) { 897 spos[i] = qpos[i]; 898 } 899 spos[i++] = 0; 900 for (; i < rank; i++) { 901 spos[i] = qpos[i-1]; 902 } 903 904 boolean br = true; 905 for (int j = 0; br && j < alen; j++) { 906 spos[axis] = j; 907 br &= a.getBoolean(spos); 908 } 909 result.set(br, qpos); 910 } 911 return result; 912 } 913 914 /** 915 * @param a operand 916 * @return true if any element is true 917 */ 918 public static boolean anyTrue(Object a) { 919 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 920 final IndexIterator it = da.getIterator(); 921 final int as = da.getElementsPerItem(); 922 923 if (as == 1) { 924 while (it.hasNext()) { 925 if (da.getElementBooleanAbs(it.index)) 926 return true; 927 } 928 } else { 929 while (it.hasNext()) { 930 for (int j = 0; j < as; j++) { 931 if (da.getElementBooleanAbs(it.index + j)) 932 return true; 933 } 934 } 935 } 936 return false; 937 } 938 939 /** 940 * Test if any items along given axis are true in the input dataset 941 * @param a operand 942 * @param axis to reduce along 943 * @return boolean dataset 944 */ 945 public static BooleanDataset anyTrue(IDataset a, int axis) { 946 axis = ShapeUtils.checkAxis(a.getRank(), axis); 947 948 int rank = a.getRank(); 949 int[] oshape = a.getShape(); 950 int alen = oshape[axis]; 951 oshape[axis] = 1; 952 953 int[] nshape = ShapeUtils.squeezeShape(oshape, false); 954 955 BooleanDataset result = DatasetFactory.zeros(BooleanDataset.class, nshape); 956 957 IndexIterator qiter = result.getIterator(true); 958 int[] qpos = qiter.getPos(); 959 int[] spos = oshape; 960 961 while (qiter.hasNext()) { 962 int i = 0; 963 for (; i < axis; i++) { 964 spos[i] = qpos[i]; 965 } 966 spos[i++] = 0; 967 for (; i < rank; i++) { 968 spos[i] = qpos[i-1]; 969 } 970 971 boolean br = false; 972 for (int j = 0; !br && j < alen; j++) { 973 spos[axis] = j; 974 br |= a.getBoolean(spos); 975 } 976 result.set(br, qpos); 977 } 978 return result; 979 } 980 981 /** 982 * Negate item-wise 983 * <p> 984 * For multi-element items, negation is false if all elements in a pair of items 985 * are true. 986 * @param a operand 987 * @return dataset where item is true when a is false 988 */ 989 public static BooleanDataset logicalNot(Object a) { 990 return logicalNot(a, null); 991 } 992 993 /** 994 * Negate item-wise 995 * <p> 996 * For multi-element items, negation is false if all elements in a pair of items 997 * are true. 998 * @param a operand 999 * @param o output can be null - in which case, a new dataset is created 1000 * @return dataset where item is true when a is false 1001 */ 1002 public static BooleanDataset logicalNot(Object a, BooleanDataset o) { 1003 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 1004 1005 List<int[]> sl = BroadcastUtils.broadcastShapes(da.getShapeRef(), o == null ? null : o.getShapeRef()); 1006 1007 final BooleanDataset r = o == null ? DatasetFactory.zeros(BooleanDataset.class, sl.get(0)) : o; 1008 1009 final SingleInputBroadcastIterator it = new SingleInputBroadcastIterator(da, r); 1010 final int as = da.getElementsPerItem(); 1011 1012 if (as == 1) { 1013 while (it.hasNext()) { 1014 r.setAbs(it.oIndex, !da.getElementBooleanAbs(it.aIndex)); 1015 } 1016 } else { 1017 boolean br = true; 1018 while (it.hasNext()) { 1019 for (int j = 0; j < as; j++) { 1020 br &= da.getElementBooleanAbs(it.aIndex + j); 1021 } 1022 r.setAbs(it.oIndex, !br); 1023 } 1024 } 1025 return r; 1026 } 1027 1028 /** 1029 * Compare item-wise for whether a's item is true and b's true too. 1030 * <p> 1031 * For multi-element items, comparison is true if all elements in a pair of items 1032 * are true. Where the datasets have mismatched item sizes, the first element 1033 * of the dataset with smaller items is used for comparison. 1034 * @param a first operand 1035 * @param b second operand 1036 * @return dataset where item is true if {@code a && b} is true 1037 */ 1038 public static BooleanDataset logicalAnd(Object a, Object b) { 1039 return logicalAnd(a, b, null); 1040 } 1041 1042 /** 1043 * Compare item-wise for whether a's item is true and b's true too. 1044 * <p> 1045 * For multi-element items, comparison is true if all elements in a pair of items 1046 * are true. Where the datasets have mismatched item sizes, the first element 1047 * of the dataset with smaller items is used for comparison. 1048 * @param a first operand 1049 * @param b second operand 1050 * @param o output can be null - in which case, a new dataset is created 1051 * @return dataset where item is true if {@code a && b} is true 1052 */ 1053 public static BooleanDataset logicalAnd(Object a, Object b, BooleanDataset o) { 1054 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 1055 final Dataset db = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); 1056 1057 List<int[]> sl = BroadcastUtils.broadcastShapes(da.getShapeRef(), db.getShapeRef(), o == null ? null : o.getShapeRef()); 1058 1059 final BooleanDataset r = o == null ? DatasetFactory.zeros(BooleanDataset.class, sl.get(0)) : o; 1060 1061 final BroadcastIterator it = BroadcastIterator.createIterator(da, db, r); 1062 it.setOutputDouble(true); 1063 final int as = da.getElementsPerItem(); 1064 final int bs = db.getElementsPerItem(); 1065 1066 if (as > bs) { 1067 while (it.hasNext()) { 1068 final boolean bb = db.getElementBooleanAbs(it.bIndex); 1069 boolean rb = true; 1070 for (int j = 0; rb && j < as; j++) { 1071 rb &= da.getElementBooleanAbs(it.aIndex + j) && bb; 1072 } 1073 r.setAbs(it.oIndex, rb); 1074 } 1075 } else if (as < bs) { 1076 while (it.hasNext()) { 1077 final boolean ab = da.getElementBooleanAbs(it.aIndex); 1078 boolean rb = true; 1079 for (int j = 0; rb && j < bs; j++) { 1080 rb &= ab && db.getElementBooleanAbs(it.bIndex + j); 1081 } 1082 r.setAbs(it.oIndex, rb); 1083 } 1084 } else { 1085 if (as == 1) { 1086 while (it.hasNext()) { 1087 r.setAbs(it.oIndex, da.getElementBooleanAbs(it.aIndex) && db.getElementBooleanAbs(it.bIndex)); 1088 } 1089 } else { 1090 while (it.hasNext()) { 1091 boolean rb = true; 1092 for (int j = 0; rb && j < bs; j++) { 1093 rb &= da.getElementBooleanAbs(it.aIndex + j) && db.getElementBooleanAbs(it.bIndex + j); 1094 } 1095 r.setAbs(it.oIndex, rb); 1096 } 1097 } 1098 } 1099 1100 return r; 1101 } 1102 1103 /** 1104 * Compare item-wise for whether a's item is true or b's true. 1105 * <p> 1106 * For multi-element items, comparison is true if any elements in a pair of items 1107 * are true. Where the datasets have mismatched item sizes, the first element 1108 * of the dataset with smaller items is used for comparison. 1109 * @param a first operand 1110 * @param b second operand 1111 * @return dataset where item is true if {@code a || b} is true 1112 */ 1113 public static BooleanDataset logicalOr(Object a, Object b) { 1114 return logicalOr(a, b, null); 1115 } 1116 1117 /** 1118 * Compare item-wise for whether a's item is true or b's true. 1119 * <p> 1120 * For multi-element items, comparison is true if any elements in a pair of items 1121 * are true. Where the datasets have mismatched item sizes, the first element 1122 * of the dataset with smaller items is used for comparison. 1123 * @param a first operand 1124 * @param b second operand 1125 * @param o output can be null - in which case, a new dataset is created 1126 * @return dataset where item is true if {@code a || b} is true 1127 */ 1128 public static BooleanDataset logicalOr(Object a, Object b, BooleanDataset o) { 1129 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 1130 final Dataset db = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); 1131 1132 List<int[]> sl = BroadcastUtils.broadcastShapes(da.getShapeRef(), db.getShapeRef(), o == null ? null : o.getShapeRef()); 1133 1134 final BooleanDataset r = o == null ? DatasetFactory.zeros(BooleanDataset.class, sl.get(0)) : o; 1135 1136 final BroadcastIterator it = BroadcastIterator.createIterator(da, db, r); 1137 it.setOutputDouble(true); 1138 final int as = da.getElementsPerItem(); 1139 final int bs = db.getElementsPerItem(); 1140 1141 if (as > bs) { 1142 while (it.hasNext()) { 1143 final boolean bb = db.getElementBooleanAbs(it.bIndex); 1144 boolean rb = true; 1145 for (int j = 0; j < as; j++) { 1146 rb |= da.getElementBooleanAbs(it.aIndex + j) || bb; 1147 } 1148 r.setAbs(it.oIndex, rb); 1149 } 1150 } else if (as < bs) { 1151 while (it.hasNext()) { 1152 final boolean ab = da.getElementBooleanAbs(it.aIndex); 1153 boolean rb = true; 1154 for (int j = 0; rb && j < bs; j++) { 1155 rb |= ab || db.getElementBooleanAbs(it.bIndex + j); 1156 } 1157 r.setAbs(it.oIndex, rb); 1158 } 1159 } else { 1160 if (as == 1) { 1161 while (it.hasNext()) { 1162 r.setAbs(it.oIndex, da.getElementBooleanAbs(it.aIndex) || db.getElementBooleanAbs(it.bIndex)); 1163 } 1164 } else { 1165 while (it.hasNext()) { 1166 boolean rb = true; 1167 for (int j = 0; rb && j < bs; j++) { 1168 rb &= da.getElementBooleanAbs(it.aIndex + j) || db.getElementBooleanAbs(it.bIndex + j); 1169 } 1170 r.setAbs(it.oIndex, rb); 1171 } 1172 } 1173 } 1174 1175 return r; 1176 } 1177 1178 /** 1179 * Compare item-wise for whether a's item is true or b's true exclusively. 1180 * <p> 1181 * For multi-element items, comparison is true if one element in a pair of items 1182 * is true. Where the datasets have mismatched item sizes, the first element 1183 * of the dataset with smaller items is used for comparison. 1184 * @param a first operand 1185 * @param b second operand 1186 * @return dataset where item is true if {@code a ^ b} is true 1187 */ 1188 public static BooleanDataset logicalXor(Object a, Object b) { 1189 return logicalXor(a, b, null); 1190 } 1191 1192 /** 1193 * Compare item-wise for whether a's item is true or b's true exclusively. 1194 * <p> 1195 * For multi-element items, comparison is true if one element in a pair of items 1196 * is true. Where the datasets have mismatched item sizes, the first element 1197 * of the dataset with smaller items is used for comparison. 1198 * @param a first operand 1199 * @param b second operand 1200 * @param o output can be null - in which case, a new dataset is created 1201 * @return dataset where item is true if a ^ b is true 1202 */ 1203 public static BooleanDataset logicalXor(Object a, Object b, BooleanDataset o) { 1204 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 1205 final Dataset db = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); 1206 1207 List<int[]> sl = BroadcastUtils.broadcastShapes(da.getShapeRef(), db.getShapeRef(), o == null ? null : o.getShapeRef()); 1208 1209 final BooleanDataset r = o == null ? DatasetFactory.zeros(BooleanDataset.class, sl.get(0)) : o; 1210 1211 final BroadcastIterator it = BroadcastIterator.createIterator(da, db, r); 1212 it.setOutputDouble(true); 1213 final int as = da.getElementsPerItem(); 1214 final int bs = db.getElementsPerItem(); 1215 1216 if (as > bs) { 1217 while (it.hasNext()) { 1218 boolean rb = db.getElementBooleanAbs(it.bIndex); 1219 for (int j = 0; j < as; j++) { 1220 rb ^= da.getElementBooleanAbs(it.aIndex + j); 1221 } 1222 r.setAbs(it.oIndex, rb); 1223 } 1224 } else if (as < bs) { 1225 while (it.hasNext()) { 1226 boolean rb = da.getElementBooleanAbs(it.aIndex); 1227 for (int j = 0; rb && j < bs; j++) { 1228 rb ^= db.getElementBooleanAbs(it.bIndex + j); 1229 } 1230 r.setAbs(it.oIndex, rb); 1231 } 1232 } else { 1233 if (as == 1) { 1234 while (it.hasNext()) { 1235 r.setAbs(it.oIndex, da.getElementBooleanAbs(it.aIndex) ^ db.getElementBooleanAbs(it.bIndex)); 1236 } 1237 } else { 1238 while (it.hasNext()) { 1239 boolean rb = true; 1240 for (int j = 0; rb && j < bs; j++) { 1241 rb &= da.getElementBooleanAbs(it.aIndex + j) ^ db.getElementBooleanAbs(it.bIndex + j); 1242 } 1243 r.setAbs(it.oIndex, rb); 1244 } 1245 } 1246 } 1247 1248 return r; 1249 } 1250 1251 /** 1252 * Create a list of indices of positions where items are non-zero 1253 * @param a operand 1254 * @return list of positions as integer datasets 1255 */ 1256 public static List<IntegerDataset> nonZero(Dataset a) { 1257 final int rank = a.getRank(); 1258 final List<List<Integer>> indices = new ArrayList<List<Integer>>(); 1259 List<IntegerDataset> indexList = new ArrayList<IntegerDataset>(); 1260 1261 if (rank == 0) 1262 return indexList; 1263 1264 for (int j = 0; j < rank; j++) { 1265 indices.add(new ArrayList<Integer>()); 1266 } 1267 1268 final IndexIterator iter = a.getIterator(true); 1269 final int[] pos = iter.getPos(); 1270 while (iter.hasNext()) { 1271 if (a.getElementBooleanAbs(iter.index)) { 1272 for (int j = 0; j < rank; j++) { 1273 indices.get(j).add(pos[j]); 1274 } 1275 } 1276 } 1277 1278 for (int j = 0; j < rank; j++) { 1279 indexList.add((IntegerDataset) DatasetFactory.createFromList(IntegerDataset.class, indices.get(j))); 1280 } 1281 return indexList; 1282 } 1283 1284 /** 1285 * Check item-wise for whether any a's elements are Not-a-Numbers 1286 * <p> 1287 * For multi-element items, check is true if any elements in an item is Not-a-Number. 1288 * @param a operand 1289 * @return dataset where item is true if any of its elements are NaNs 1290 */ 1291 public static BooleanDataset isNaN(Object a) { 1292 return isNaN(a, null); 1293 } 1294 1295 /** 1296 * Check item-wise for whether any a's elements are Not-a-Numbers 1297 * <p> 1298 * For multi-element items, check is true if any elements in an item is Not-a-Number. 1299 * @param a operand 1300 * @param o output can be null - in which case, a new dataset is created 1301 * @return dataset where item is true if any of its elements are NaNs 1302 */ 1303 public static BooleanDataset isNaN(Object a, BooleanDataset o) { 1304 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 1305 1306 List<int[]> sl = BroadcastUtils.broadcastShapes(da.getShapeRef(), o == null ? null : o.getShapeRef()); 1307 1308 final BooleanDataset r = o == null ? DatasetFactory.zeros(BooleanDataset.class, sl.get(0)) : o; 1309 1310 if (!da.hasFloatingPointElements()) { 1311 if (r == o) { 1312 r.fill(false); 1313 } 1314 return r; 1315 } 1316 1317 final SingleInputBroadcastIterator it = new SingleInputBroadcastIterator(da, r); 1318 it.setOutputDouble(true); 1319 final int as = da.getElementsPerItem(); 1320 1321 if (as == 1) { 1322 while (it.hasNext()) { 1323 r.setAbs(it.oIndex, Double.isNaN(it.aDouble)); 1324 } 1325 } else { 1326 if (da instanceof ComplexFloatDataset || da instanceof ComplexDoubleDataset) { 1327 while (it.hasNext()) { 1328 r.setAbs(it.oIndex, Double.isNaN(it.aDouble) || Double.isNaN(da.getElementDoubleAbs(it.aIndex + 1))); 1329 } 1330 } else { 1331 while (it.hasNext()) { 1332 boolean rb = false; 1333 for (int j = 0; !rb && j < as; j++) { 1334 rb &= Double.isNaN(da.getElementDoubleAbs(it.aIndex + j)); 1335 } 1336 r.setAbs(it.oIndex, rb); 1337 } 1338 } 1339 } 1340 return r; 1341 } 1342 1343 /** 1344 * Check item-wise for whether any a's elements are infinite 1345 * <p> 1346 * For multi-element items, check is true if any elements in an item is infinite 1347 * @param a operand 1348 * @return dataset where item is true if any of its elements are infinite 1349 */ 1350 public static BooleanDataset isInfinite(Object a) { 1351 return isInfinite(a, null); 1352 } 1353 1354 /** 1355 * Check item-wise for whether any a's elements are infinite 1356 * <p> 1357 * For multi-element items, check is true if any elements in an item is infinite 1358 * @param a operand 1359 * @param o output can be null - in which case, a new dataset is created 1360 * @return dataset where item is true if any of its elements are infinite 1361 */ 1362 public static BooleanDataset isInfinite(Object a, BooleanDataset o) { 1363 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 1364 1365 List<int[]> sl = BroadcastUtils.broadcastShapes(da.getShapeRef(), o == null ? null : o.getShapeRef()); 1366 1367 final BooleanDataset r = o == null ? DatasetFactory.zeros(BooleanDataset.class, sl.get(0)) : o; 1368 1369 if (!da.hasFloatingPointElements()) { 1370 if (r == o) { 1371 r.fill(false); 1372 } 1373 return r; 1374 } 1375 1376 final SingleInputBroadcastIterator it = new SingleInputBroadcastIterator(da, r); 1377 it.setOutputDouble(true); 1378 final int as = da.getElementsPerItem(); 1379 1380 if (as == 1) { 1381 while (it.hasNext()) { 1382 r.setAbs(it.oIndex, Double.isInfinite(it.aDouble)); 1383 } 1384 } else { 1385 if (da instanceof ComplexFloatDataset || da instanceof ComplexDoubleDataset) { 1386 while (it.hasNext()) { 1387 r.setAbs(it.oIndex, Double.isInfinite(it.aDouble) || Double.isInfinite(da.getElementDoubleAbs(it.aIndex + 1))); 1388 } 1389 } else { 1390 while (it.hasNext()) { 1391 boolean rb = false; 1392 for (int j = 0; !rb && j < as; j++) { 1393 rb &= Double.isInfinite(da.getElementDoubleAbs(it.aIndex + j)); 1394 } 1395 r.setAbs(it.oIndex, rb); 1396 } 1397 } 1398 } 1399 return r; 1400 } 1401 1402 /** 1403 * Check item-wise for whether any a's elements are positive infinite 1404 * <p> 1405 * For multi-element items, the check is true if any elements in an item is positive infinite 1406 * @param a operand 1407 * @return dataset where items are true if any of its elements are positive infinite 1408 */ 1409 public static BooleanDataset isPositiveInfinite(Object a) { 1410 return isEqual(a, null, Double.POSITIVE_INFINITY); 1411 } 1412 1413 /** 1414 * Check item-wise for whether any a's elements are positive infinite 1415 * <p> 1416 * For multi-element items, the check is true if any elements in an item is positive infinite 1417 * @param a operand 1418 * @param o output can be null - in which case, a new dataset is created 1419 * @return dataset where items are true if any of its elements are positive infinite 1420 */ 1421 public static BooleanDataset isPositiveInfinite(Object a, BooleanDataset o) { 1422 return isEqual(a, o, Double.POSITIVE_INFINITY); 1423 } 1424 1425 /** 1426 * Check item-wise for whether any a's elements are negative infinite 1427 * <p> 1428 * For multi-element items, the check is true if any elements in an item is negative infinite 1429 * @param a operand 1430 * @return dataset where items are true if any of its elements are negative infinite 1431 */ 1432 public static BooleanDataset isNegativeInfinite(Object a) { 1433 return isEqual(a, null, Double.NEGATIVE_INFINITY); 1434 } 1435 1436 /** 1437 * Check item-wise for whether any a's elements are negative infinite 1438 * <p> 1439 * For multi-element items, the check is true if any elements in an item is negative infinite 1440 * @param a operand 1441 * @param o output can be null - in which case, a new dataset is created 1442 * @return dataset where items are true if any of its elements are negative infinite 1443 */ 1444 public static BooleanDataset isNegativeInfinite(Object a, BooleanDataset o) { 1445 return isEqual(a, o, Double.NEGATIVE_INFINITY); 1446 } 1447 1448 /** 1449 * Check item-wise for whether any a's elements match given item 1450 * <p> 1451 * For multi-element items, the check is true if any elements in an item matches 1452 * @param a operand 1453 * @param o output can be null - in which case, a new dataset is created 1454 * @param match value to match 1455 * @return dataset where items are true if any of its elements match 1456 */ 1457 private static BooleanDataset isEqual(Object a, BooleanDataset o, final double match) { 1458 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 1459 1460 List<int[]> sl = BroadcastUtils.broadcastShapes(da.getShapeRef(), o == null ? null : o.getShapeRef()); 1461 1462 final BooleanDataset r = o == null ? DatasetFactory.zeros(BooleanDataset.class, sl.get(0)) : o; 1463 1464 if (!da.hasFloatingPointElements()) { 1465 if (r == o) { 1466 r.fill(false); 1467 } 1468 return r; 1469 } 1470 1471 final SingleInputBroadcastIterator it = new SingleInputBroadcastIterator(da, r); 1472 it.setOutputDouble(true); 1473 final int as = da.getElementsPerItem(); 1474 1475 if (as == 1) { 1476 while (it.hasNext()) { 1477 r.setAbs(it.oIndex, it.aDouble == match); 1478 } 1479 } else { 1480 if (da instanceof ComplexFloatDataset || da instanceof ComplexDoubleDataset) { 1481 while (it.hasNext()) { 1482 final double rv = it.aDouble; 1483 final double iv = da.getElementDoubleAbs(it.aIndex + 1); 1484 r.setAbs(it.oIndex, (rv == match) || (iv == match)); 1485 } 1486 } else { 1487 while (it.hasNext()) { 1488 boolean rb = false; 1489 for (int j = 0; !rb && j < as; j++) { 1490 rb &= da.getElementDoubleAbs(it.aIndex + j) == match; 1491 } 1492 r.setAbs(it.oIndex, rb); 1493 } 1494 } 1495 } 1496 return r; 1497 } 1498 1499 /** 1500 * Check item-wise for whether any a's elements are finite (or not infinite and not Not-a-Number) 1501 * <p> 1502 * For multi-element items, check is true if any elements in an item is finite 1503 * @param a operand 1504 * @return dataset where item is true if any of its elements are finite 1505 */ 1506 public static BooleanDataset isFinite(Object a) { 1507 return isFinite(a, null); 1508 } 1509 1510 /** 1511 * Check item-wise for whether any a's elements are finite (or not infinite and not Not-a-Number) 1512 * <p> 1513 * For multi-element items, check is true if any elements in an item is finite 1514 * @param a operand 1515 * @param o output can be null - in which case, a new dataset is created 1516 * @return dataset where item is true if any of its elements are finite 1517 */ 1518 public static BooleanDataset isFinite(Object a, BooleanDataset o) { 1519 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 1520 1521 List<int[]> sl = BroadcastUtils.broadcastShapes(da.getShapeRef(), o == null ? null : o.getShapeRef()); 1522 1523 final BooleanDataset r = o == null ? DatasetFactory.zeros(BooleanDataset.class, sl.get(0)) : o; 1524 1525 if (!da.hasFloatingPointElements()) { 1526 r.fill(true); 1527 return r; 1528 } 1529 1530 final SingleInputBroadcastIterator it = new SingleInputBroadcastIterator(da, r); 1531 it.setOutputDouble(true); 1532 final int as = da.getElementsPerItem(); 1533 1534 if (as == 1) { 1535 while (it.hasNext()) { 1536 final double rv = it.aDouble; 1537 r.setAbs(it.oIndex, !(Double.isInfinite(rv) || Double.isNaN(rv))); 1538 } 1539 } else { 1540 if (da instanceof ComplexFloatDataset || da instanceof ComplexDoubleDataset) { 1541 while (it.hasNext()) { 1542 final double rv = it.aDouble; 1543 final double iv = da.getElementDoubleAbs(it.aIndex + 1); 1544 r.setAbs(it.oIndex, !(Double.isInfinite(rv) || Double.isNaN(rv) || Double.isInfinite(iv) || Double.isNaN(iv))); 1545 } 1546 } else { 1547 while (it.hasNext()) { 1548 boolean rb = false; 1549 for (int j = 0; !rb && j < as; j++) { 1550 final double rv = it.aDouble; 1551 rb &= !(Double.isInfinite(rv) || Double.isNaN(rv)); 1552 } 1553 r.setAbs(it.oIndex, rb); 1554 } 1555 } 1556 } 1557 return r; 1558 } 1559 1560 /** 1561 * Enumeration of monotonicity. NaNs are ignored or considered not equal 1562 */ 1563 public static enum Monotonicity { 1564 /** 1565 * No order: {@code x_0 != x_1 != x_2 ...} 1566 */ 1567 NOT_ORDERED, 1568 /** 1569 * All equal: {@code x_0 == x_1 == x_2 ...} 1570 */ 1571 ALL_EQUAL, 1572 /** 1573 * Strictly decreasing {@code x_0 > x_1 > x_2 ...} 1574 */ 1575 STRICTLY_DECREASING, 1576 /** 1577 * Non-increasing or weakly decreasing {@code x_0 >= x_1 >= x_2 ...} 1578 */ 1579 NONINCREASING, 1580 /** 1581 * Non-decreasing or weakly increasing {@code x_0 <= x_1 <= x_2 ...} 1582 */ 1583 NONDECREASING, 1584 /** 1585 * Strictly increasing {@code x_0 < x_1 < x_2 ...} 1586 */ 1587 STRICTLY_INCREASING, 1588 } 1589 1590 /** 1591 * @param a operand 1592 * @return true if all elements are in a monotonic order 1593 * @see #findMonotonicity(Object) 1594 */ 1595 public static boolean isMonotonic(Object a) { 1596 return findMonotonicity(a) != Monotonicity.NOT_ORDERED; 1597 } 1598 1599 /** 1600 * @param a operand 1601 * @param monotonicity type 1602 * @return true if all elements are in given monotonic ordering 1603 */ 1604 public static boolean isMonotonic(Object a, Monotonicity monotonicity) { 1605 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 1606 if (da.getRank() > 1) { 1607 throw new IllegalArgumentException("Only 0 or 1D datasets are allowed"); 1608 } 1609 1610 if (da.getElementsPerItem() > 1) { 1611 throw new IllegalArgumentException("Cannot compare compound datsets"); 1612 } 1613 1614 final IndexIterator it = da.getIterator(); 1615 double previous = Double.NaN; 1616 while (Double.isNaN(previous) && it.hasNext()) { // look for first non-NaN 1617 previous = da.getElementDoubleAbs(it.index); 1618 } 1619 1620 Boolean increasing = null; 1621 boolean equality = false; 1622 while (it.hasNext()) { // look for first change 1623 double next = da.getElementDoubleAbs(it.index); 1624 if (!Double.isNaN(next)) { 1625 if (previous != next) { 1626 increasing = previous < next; 1627 previous = next; 1628 break; 1629 } else if (!equality) { 1630 equality = true; 1631 if (monotonicity == Monotonicity.STRICTLY_DECREASING || monotonicity == Monotonicity.STRICTLY_DECREASING) 1632 return false; 1633 } 1634 } 1635 } 1636 1637 if (increasing == null) { 1638 if (equality) 1639 return monotonicity == Monotonicity.ALL_EQUAL || monotonicity == Monotonicity.NONDECREASING || monotonicity == Monotonicity.NONINCREASING; 1640 return Double.isNaN(previous) ? monotonicity == Monotonicity.NOT_ORDERED : true; 1641 } 1642 1643 if (increasing) { 1644 if (monotonicity == Monotonicity.ALL_EQUAL || monotonicity == Monotonicity.NONINCREASING || monotonicity == Monotonicity.STRICTLY_DECREASING) 1645 return false; 1646 1647 while (it.hasNext()) { 1648 double next = da.getElementDoubleAbs(it.index); 1649 if (!Double.isNaN(next)) { 1650 if (previous > next) { 1651 return monotonicity == Monotonicity.NOT_ORDERED; 1652 } else if (previous < next) { 1653 previous = next; 1654 } else if (!equality) { 1655 equality = true; 1656 if (monotonicity == Monotonicity.STRICTLY_INCREASING) 1657 return false; 1658 } 1659 } 1660 } 1661 1662 return monotonicity != Monotonicity.NOT_ORDERED; 1663 } 1664 1665 if (monotonicity == Monotonicity.ALL_EQUAL || monotonicity == Monotonicity.NONDECREASING || monotonicity == Monotonicity.STRICTLY_INCREASING) 1666 return false; 1667 1668 while (it.hasNext()) { 1669 double next = da.getElementDoubleAbs(it.index); 1670 if (!Double.isNaN(next)) { 1671 if (previous < next) { 1672 return monotonicity == Monotonicity.NOT_ORDERED; 1673 } else if (previous > next) { 1674 previous = next; 1675 } else if (!equality) { 1676 equality = true; 1677 if (monotonicity == Monotonicity.STRICTLY_DECREASING) 1678 return false; 1679 } 1680 } 1681 } 1682 1683 return monotonicity != Monotonicity.NOT_ORDERED; 1684 } 1685 1686 /** 1687 * @param a operand 1688 * @return true if all elements are in a strictly monotonic order 1689 * @see #findMonotonicity(Object) 1690 */ 1691 public static boolean isStrictlyMonotonic(Object a) { 1692 Monotonicity mono = findMonotonicity(a); 1693 return mono == Monotonicity.STRICTLY_DECREASING || mono == Monotonicity.STRICTLY_INCREASING; 1694 } 1695 1696 /** 1697 * Find monotonicity. NaNs are ignored or considered not equal 1698 * @param a operand 1699 * @return monotonicity 1700 */ 1701 public static Monotonicity findMonotonicity(Object a) { 1702 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 1703 if (da.getRank() > 1) { 1704 throw new IllegalArgumentException("Only 0 or 1D datasets are allowed"); 1705 } 1706 1707 if (da.getElementsPerItem() > 1) { 1708 throw new IllegalArgumentException("Cannot compare compound datsets"); 1709 } 1710 1711 final IndexIterator it = da.getIterator(); 1712 double previous = Double.NaN; 1713 while (Double.isNaN(previous) && it.hasNext()) { // look for first non-NaN 1714 previous = da.getElementDoubleAbs(it.index); 1715 } 1716 1717 Boolean increasing = null; 1718 boolean equality = false; 1719 while (it.hasNext()) { // look for first change 1720 double next = da.getElementDoubleAbs(it.index); 1721 if (!Double.isNaN(next)) { 1722 if (previous != next) { 1723 increasing = previous < next; 1724 previous = next; 1725 break; 1726 } else if (!equality) { 1727 equality = true; 1728 } 1729 } 1730 } 1731 1732 if (increasing == null) { 1733 return Double.isNaN(previous) ? Monotonicity.NOT_ORDERED : Monotonicity.ALL_EQUAL; 1734 } 1735 1736 if (increasing) { 1737 while (it.hasNext()) { 1738 double next = da.getElementDoubleAbs(it.index); 1739 if (!Double.isNaN(next)) { 1740 if (previous > next) { 1741 return Monotonicity.NOT_ORDERED; 1742 } else if (previous < next) { 1743 previous = next; 1744 } else if (!equality) { 1745 equality = true; 1746 } 1747 } 1748 } 1749 return equality ? Monotonicity.NONDECREASING : Monotonicity.STRICTLY_INCREASING; 1750 } 1751 1752 while (it.hasNext()) { 1753 double next = da.getElementDoubleAbs(it.index); 1754 if (!Double.isNaN(next)) { 1755 if (previous < next) { 1756 return Monotonicity.NOT_ORDERED; 1757 } else if (previous > next) { 1758 previous = next; 1759 } else if (!equality) { 1760 equality = true; 1761 } 1762 } 1763 } 1764 return equality ? Monotonicity.NONINCREASING : Monotonicity.STRICTLY_DECREASING; 1765 } 1766}