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