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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * @param a 875 * @return true if all elements are true 876 */ 877 public static BooleanDataset allTrue(IDataset a, int axis) { 878 axis = AbstractDataset.checkAxis(a.getRank(), axis); 879 880 int rank = a.getRank(); 881 int[] oshape = a.getShape(); 882 int alen = oshape[axis]; 883 oshape[axis] = 1; 884 885 int[] nshape = ShapeUtils.squeezeShape(oshape, false); 886 887 BooleanDataset result = DatasetFactory.zeros(BooleanDataset.class, nshape); 888 889 IndexIterator qiter = result.getIterator(true); 890 int[] qpos = qiter.getPos(); 891 int[] spos = oshape; 892 893 while (qiter.hasNext()) { 894 int i = 0; 895 for (; i < axis; i++) { 896 spos[i] = qpos[i]; 897 } 898 spos[i++] = 0; 899 for (; i < rank; i++) { 900 spos[i] = qpos[i-1]; 901 } 902 903 boolean br = true; 904 for (int j = 0; br && j < alen; j++) { 905 spos[axis] = j; 906 br &= a.getBoolean(spos); 907 } 908 result.set(br, qpos); 909 } 910 return result; 911 } 912 913 /** 914 * @param a 915 * @return true if any element is true 916 */ 917 public static boolean anyTrue(Object a) { 918 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 919 final IndexIterator it = da.getIterator(); 920 final int as = da.getElementsPerItem(); 921 922 if (as == 1) { 923 while (it.hasNext()) { 924 if (da.getElementBooleanAbs(it.index)) 925 return true; 926 } 927 } else { 928 while (it.hasNext()) { 929 for (int j = 0; j < as; j++) { 930 if (da.getElementBooleanAbs(it.index + j)) 931 return true; 932 } 933 } 934 } 935 return false; 936 } 937 938 /** 939 * @param a 940 * @return true if any element is true 941 */ 942 public static BooleanDataset anyTrue(IDataset a, int axis) { 943 axis = AbstractDataset.checkAxis(a.getRank(), axis); 944 945 int rank = a.getRank(); 946 int[] oshape = a.getShape(); 947 int alen = oshape[axis]; 948 oshape[axis] = 1; 949 950 int[] nshape = ShapeUtils.squeezeShape(oshape, false); 951 952 BooleanDataset result = DatasetFactory.zeros(BooleanDataset.class, nshape); 953 954 IndexIterator qiter = result.getIterator(true); 955 int[] qpos = qiter.getPos(); 956 int[] spos = oshape; 957 958 while (qiter.hasNext()) { 959 int i = 0; 960 for (; i < axis; i++) { 961 spos[i] = qpos[i]; 962 } 963 spos[i++] = 0; 964 for (; i < rank; i++) { 965 spos[i] = qpos[i-1]; 966 } 967 968 boolean br = false; 969 for (int j = 0; !br && j < alen; j++) { 970 spos[axis] = j; 971 br |= a.getBoolean(spos); 972 } 973 result.set(br, qpos); 974 } 975 return result; 976 } 977 978 /** 979 * Negate item-wise 980 * <p> 981 * For multi-element items, negation is false if all elements in a pair of items 982 * are true. 983 * @param a 984 * @return dataset where item is true when a is false 985 */ 986 public static BooleanDataset logicalNot(Object a) { 987 return logicalNot(a, null); 988 } 989 990 /** 991 * Negate item-wise 992 * <p> 993 * For multi-element items, negation is false if all elements in a pair of items 994 * are true. 995 * @param a 996 * @param o output can be null - in which case, a new dataset is created 997 * @return dataset where item is true when a is false 998 */ 999 public static BooleanDataset logicalNot(Object a, BooleanDataset o) { 1000 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 1001 1002 List<int[]> sl = BroadcastUtils.broadcastShapes(da.getShapeRef(), o == null ? null : o.getShapeRef()); 1003 1004 final BooleanDataset r = o == null ? DatasetFactory.zeros(BooleanDataset.class, sl.get(0)) : o; 1005 1006 final SingleInputBroadcastIterator it = new SingleInputBroadcastIterator(da, r); 1007 final int as = da.getElementsPerItem(); 1008 1009 if (as == 1) { 1010 while (it.hasNext()) { 1011 r.setAbs(it.oIndex, !da.getElementBooleanAbs(it.aIndex)); 1012 } 1013 } else { 1014 boolean br = true; 1015 while (it.hasNext()) { 1016 for (int j = 0; j < as; j++) { 1017 br &= da.getElementBooleanAbs(it.aIndex + j); 1018 } 1019 r.setAbs(it.oIndex, !br); 1020 } 1021 } 1022 return r; 1023 } 1024 1025 /** 1026 * Compare item-wise for whether a's item is true and b's true too. 1027 * <p> 1028 * For multi-element items, comparison is true if all elements in a pair of items 1029 * are true. Where the datasets have mismatched item sizes, the first element 1030 * of the dataset with smaller items is used for comparison. 1031 * @param a 1032 * @param b 1033 * @return dataset where item is true if a && b is true 1034 */ 1035 public static BooleanDataset logicalAnd(Object a, Object b) { 1036 return logicalAnd(a, b, null); 1037 } 1038 1039 /** 1040 * Compare item-wise for whether a's item is true and b's true too. 1041 * <p> 1042 * For multi-element items, comparison is true if all elements in a pair of items 1043 * are true. Where the datasets have mismatched item sizes, the first element 1044 * of the dataset with smaller items is used for comparison. 1045 * @param a 1046 * @param b 1047 * @param o output can be null - in which case, a new dataset is created 1048 * @return dataset where item is true if a && b is true 1049 */ 1050 public static BooleanDataset logicalAnd(Object a, Object b, BooleanDataset o) { 1051 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 1052 final Dataset db = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); 1053 1054 List<int[]> sl = BroadcastUtils.broadcastShapes(da.getShapeRef(), db.getShapeRef(), o == null ? null : o.getShapeRef()); 1055 1056 final BooleanDataset r = o == null ? DatasetFactory.zeros(BooleanDataset.class, sl.get(0)) : o; 1057 1058 final BroadcastIterator it = BroadcastIterator.createIterator(da, db, r); 1059 it.setOutputDouble(true); 1060 final int as = da.getElementsPerItem(); 1061 final int bs = db.getElementsPerItem(); 1062 1063 if (as > bs) { 1064 while (it.hasNext()) { 1065 final boolean bb = db.getElementBooleanAbs(it.bIndex); 1066 boolean rb = true; 1067 for (int j = 0; rb && j < as; j++) { 1068 rb &= da.getElementBooleanAbs(it.aIndex + j) && bb; 1069 } 1070 r.setAbs(it.oIndex, rb); 1071 } 1072 } else if (as < bs) { 1073 while (it.hasNext()) { 1074 final boolean ab = da.getElementBooleanAbs(it.aIndex); 1075 boolean rb = true; 1076 for (int j = 0; rb && j < bs; j++) { 1077 rb &= ab && db.getElementBooleanAbs(it.bIndex + j); 1078 } 1079 r.setAbs(it.oIndex, rb); 1080 } 1081 } else { 1082 if (as == 1) { 1083 while (it.hasNext()) { 1084 r.setAbs(it.oIndex, da.getElementBooleanAbs(it.aIndex) && db.getElementBooleanAbs(it.bIndex)); 1085 } 1086 } else { 1087 while (it.hasNext()) { 1088 boolean rb = true; 1089 for (int j = 0; rb && j < bs; j++) { 1090 rb &= da.getElementBooleanAbs(it.aIndex + j) && db.getElementBooleanAbs(it.bIndex + j); 1091 } 1092 r.setAbs(it.oIndex, rb); 1093 } 1094 } 1095 } 1096 1097 return r; 1098 } 1099 1100 /** 1101 * Compare item-wise for whether a's item is true or b's true. 1102 * <p> 1103 * For multi-element items, comparison is true if any elements in a pair of items 1104 * are true. Where the datasets have mismatched item sizes, the first element 1105 * of the dataset with smaller items is used for comparison. 1106 * @param a 1107 * @param b 1108 * @return dataset where item is true if a || b is true 1109 */ 1110 public static BooleanDataset logicalOr(Object a, Object b) { 1111 return logicalOr(a, b, null); 1112 } 1113 1114 /** 1115 * Compare item-wise for whether a's item is true or b's true. 1116 * <p> 1117 * For multi-element items, comparison is true if any elements in a pair of items 1118 * are true. Where the datasets have mismatched item sizes, the first element 1119 * of the dataset with smaller items is used for comparison. 1120 * @param a 1121 * @param b 1122 * @param o output can be null - in which case, a new dataset is created 1123 * @return dataset where item is true if a || b is true 1124 */ 1125 public static BooleanDataset logicalOr(Object a, Object b, BooleanDataset o) { 1126 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 1127 final Dataset db = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); 1128 1129 List<int[]> sl = BroadcastUtils.broadcastShapes(da.getShapeRef(), db.getShapeRef(), o == null ? null : o.getShapeRef()); 1130 1131 final BooleanDataset r = o == null ? DatasetFactory.zeros(BooleanDataset.class, sl.get(0)) : o; 1132 1133 final BroadcastIterator it = BroadcastIterator.createIterator(da, db, r); 1134 it.setOutputDouble(true); 1135 final int as = da.getElementsPerItem(); 1136 final int bs = db.getElementsPerItem(); 1137 1138 if (as > bs) { 1139 while (it.hasNext()) { 1140 final boolean bb = db.getElementBooleanAbs(it.bIndex); 1141 boolean rb = true; 1142 for (int j = 0; j < as; j++) { 1143 rb |= da.getElementBooleanAbs(it.aIndex + j) || bb; 1144 } 1145 r.setAbs(it.oIndex, rb); 1146 } 1147 } else if (as < bs) { 1148 while (it.hasNext()) { 1149 final boolean ab = da.getElementBooleanAbs(it.aIndex); 1150 boolean rb = true; 1151 for (int j = 0; rb && j < bs; j++) { 1152 rb |= ab || db.getElementBooleanAbs(it.bIndex + j); 1153 } 1154 r.setAbs(it.oIndex, rb); 1155 } 1156 } else { 1157 if (as == 1) { 1158 while (it.hasNext()) { 1159 r.setAbs(it.oIndex, da.getElementBooleanAbs(it.aIndex) || db.getElementBooleanAbs(it.bIndex)); 1160 } 1161 } else { 1162 while (it.hasNext()) { 1163 boolean rb = true; 1164 for (int j = 0; rb && j < bs; j++) { 1165 rb &= da.getElementBooleanAbs(it.aIndex + j) || db.getElementBooleanAbs(it.bIndex + j); 1166 } 1167 r.setAbs(it.oIndex, rb); 1168 } 1169 } 1170 } 1171 1172 return r; 1173 } 1174 1175 /** 1176 * Compare item-wise for whether a's item is true or b's true exclusively. 1177 * <p> 1178 * For multi-element items, comparison is true if one element in a pair of items 1179 * is true. Where the datasets have mismatched item sizes, the first element 1180 * of the dataset with smaller items is used for comparison. 1181 * @param a 1182 * @param b 1183 * @return dataset where item is true if a ^ b is true 1184 */ 1185 public static BooleanDataset logicalXor(Object a, Object b) { 1186 return logicalXor(a, b, null); 1187 } 1188 1189 /** 1190 * Compare item-wise for whether a's item is true or b's true exclusively. 1191 * <p> 1192 * For multi-element items, comparison is true if one element in a pair of items 1193 * is true. Where the datasets have mismatched item sizes, the first element 1194 * of the dataset with smaller items is used for comparison. 1195 * @param a 1196 * @param b 1197 * @param o output can be null - in which case, a new dataset is created 1198 * @return dataset where item is true if a ^ b is true 1199 */ 1200 public static BooleanDataset logicalXor(Object a, Object b, BooleanDataset o) { 1201 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 1202 final Dataset db = b instanceof Dataset ? (Dataset) b : DatasetFactory.createFromObject(b); 1203 1204 List<int[]> sl = BroadcastUtils.broadcastShapes(da.getShapeRef(), db.getShapeRef(), o == null ? null : o.getShapeRef()); 1205 1206 final BooleanDataset r = o == null ? DatasetFactory.zeros(BooleanDataset.class, sl.get(0)) : o; 1207 1208 final BroadcastIterator it = BroadcastIterator.createIterator(da, db, r); 1209 it.setOutputDouble(true); 1210 final int as = da.getElementsPerItem(); 1211 final int bs = db.getElementsPerItem(); 1212 1213 if (as > bs) { 1214 while (it.hasNext()) { 1215 boolean rb = db.getElementBooleanAbs(it.bIndex); 1216 for (int j = 0; j < as; j++) { 1217 rb ^= da.getElementBooleanAbs(it.aIndex + j); 1218 } 1219 r.setAbs(it.oIndex, rb); 1220 } 1221 } else if (as < bs) { 1222 while (it.hasNext()) { 1223 boolean rb = da.getElementBooleanAbs(it.aIndex); 1224 for (int j = 0; rb && j < bs; j++) { 1225 rb ^= db.getElementBooleanAbs(it.bIndex + j); 1226 } 1227 r.setAbs(it.oIndex, rb); 1228 } 1229 } else { 1230 if (as == 1) { 1231 while (it.hasNext()) { 1232 r.setAbs(it.oIndex, da.getElementBooleanAbs(it.aIndex) ^ db.getElementBooleanAbs(it.bIndex)); 1233 } 1234 } else { 1235 while (it.hasNext()) { 1236 boolean rb = true; 1237 for (int j = 0; rb && j < bs; j++) { 1238 rb &= da.getElementBooleanAbs(it.aIndex + j) ^ db.getElementBooleanAbs(it.bIndex + j); 1239 } 1240 r.setAbs(it.oIndex, rb); 1241 } 1242 } 1243 } 1244 1245 return r; 1246 } 1247 1248 /** 1249 * Create a list of indices of positions where items are non-zero 1250 * @param a 1251 * @return list of positions as integer datasets 1252 */ 1253 @SuppressWarnings("deprecation") 1254 public static List<IntegerDataset> nonZero(Dataset a) { 1255 final int rank = a.getRank(); 1256 final List<List<Integer>> indices = new ArrayList<List<Integer>>(); 1257 List<IntegerDataset> indexList = new ArrayList<IntegerDataset>(); 1258 1259 if (rank == 0) 1260 return indexList; 1261 1262 for (int j = 0; j < rank; j++) { 1263 indices.add(new ArrayList<Integer>()); 1264 } 1265 1266 final IndexIterator iter = a.getIterator(true); 1267 final int[] pos = iter.getPos(); 1268 while (iter.hasNext()) { 1269 if (a.getElementBooleanAbs(iter.index)) { 1270 for (int j = 0; j < rank; j++) { 1271 indices.get(j).add(pos[j]); 1272 } 1273 } 1274 } 1275 1276 for (int j = 0; j < rank; j++) { 1277 indexList.add((IntegerDataset) DatasetFactory.createFromList(Dataset.INT32, indices.get(j))); 1278 } 1279 return indexList; 1280 } 1281 1282 /** 1283 * Check item-wise for whether any a's elements are Not-a-Numbers 1284 * <p> 1285 * For multi-element items, check is true if any elements in an item is Not-a-Number. 1286 * @param a 1287 * @return dataset where item is true if any of its elements are NaNs 1288 */ 1289 public static BooleanDataset isNaN(Object a) { 1290 return isNaN(a, null); 1291 } 1292 1293 /** 1294 * Check item-wise for whether any a's elements are Not-a-Numbers 1295 * <p> 1296 * For multi-element items, check is true if any elements in an item is Not-a-Number. 1297 * @param a 1298 * @param o output can be null - in which case, a new dataset is created 1299 * @return dataset where item is true if any of its elements are NaNs 1300 */ 1301 public static BooleanDataset isNaN(Object a, BooleanDataset o) { 1302 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 1303 1304 List<int[]> sl = BroadcastUtils.broadcastShapes(da.getShapeRef(), o == null ? null : o.getShapeRef()); 1305 1306 final BooleanDataset r = o == null ? DatasetFactory.zeros(BooleanDataset.class, sl.get(0)) : o; 1307 1308 if (!da.hasFloatingPointElements()) { 1309 if (r == o) { 1310 r.fill(false); 1311 } 1312 return r; 1313 } 1314 1315 final SingleInputBroadcastIterator it = new SingleInputBroadcastIterator(da, r); 1316 it.setOutputDouble(true); 1317 final int as = da.getElementsPerItem(); 1318 1319 if (as == 1) { 1320 while (it.hasNext()) { 1321 r.setAbs(it.oIndex, Double.isNaN(it.aDouble)); 1322 } 1323 } else { 1324 if (da instanceof ComplexFloatDataset || da instanceof ComplexDoubleDataset) { 1325 while (it.hasNext()) { 1326 r.setAbs(it.oIndex, Double.isNaN(it.aDouble) || Double.isNaN(da.getElementDoubleAbs(it.aIndex + 1))); 1327 } 1328 } else { 1329 while (it.hasNext()) { 1330 boolean rb = false; 1331 for (int j = 0; !rb && j < as; j++) { 1332 rb &= Double.isNaN(da.getElementDoubleAbs(it.aIndex + j)); 1333 } 1334 r.setAbs(it.oIndex, rb); 1335 } 1336 } 1337 } 1338 return r; 1339 } 1340 1341 /** 1342 * Check item-wise for whether any a's elements are infinite 1343 * <p> 1344 * For multi-element items, check is true if any elements in an item is infinite 1345 * @param a 1346 * @return dataset where item is true if any of its elements are infinite 1347 */ 1348 public static BooleanDataset isInfinite(Object a) { 1349 return isInfinite(a, null); 1350 } 1351 1352 /** 1353 * Check item-wise for whether any a's elements are infinite 1354 * <p> 1355 * For multi-element items, check is true if any elements in an item is infinite 1356 * @param a 1357 * @param o output can be null - in which case, a new dataset is created 1358 * @return dataset where item is true if any of its elements are infinite 1359 */ 1360 public static BooleanDataset isInfinite(Object a, BooleanDataset o) { 1361 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 1362 1363 List<int[]> sl = BroadcastUtils.broadcastShapes(da.getShapeRef(), o == null ? null : o.getShapeRef()); 1364 1365 final BooleanDataset r = o == null ? DatasetFactory.zeros(BooleanDataset.class, sl.get(0)) : o; 1366 1367 if (!da.hasFloatingPointElements()) { 1368 if (r == o) { 1369 r.fill(false); 1370 } 1371 return r; 1372 } 1373 1374 final SingleInputBroadcastIterator it = new SingleInputBroadcastIterator(da, r); 1375 it.setOutputDouble(true); 1376 final int as = da.getElementsPerItem(); 1377 1378 if (as == 1) { 1379 while (it.hasNext()) { 1380 r.setAbs(it.oIndex, Double.isInfinite(it.aDouble)); 1381 } 1382 } else { 1383 if (da instanceof ComplexFloatDataset || da instanceof ComplexDoubleDataset) { 1384 while (it.hasNext()) { 1385 r.setAbs(it.oIndex, Double.isInfinite(it.aDouble) || Double.isInfinite(da.getElementDoubleAbs(it.aIndex + 1))); 1386 } 1387 } else { 1388 while (it.hasNext()) { 1389 boolean rb = false; 1390 for (int j = 0; !rb && j < as; j++) { 1391 rb &= Double.isInfinite(da.getElementDoubleAbs(it.aIndex + j)); 1392 } 1393 r.setAbs(it.oIndex, rb); 1394 } 1395 } 1396 } 1397 return r; 1398 } 1399 1400 /** 1401 * Check item-wise for whether any a's elements are positive infinite 1402 * <p> 1403 * For multi-element items, the check is true if any elements in an item is positive infinite 1404 * @param a 1405 * @return dataset where items are true if any of its elements are positive infinite 1406 */ 1407 public static BooleanDataset isPositiveInfinite(Object a) { 1408 return isEqual(a, null, Double.POSITIVE_INFINITY); 1409 } 1410 1411 /** 1412 * Check item-wise for whether any a's elements are positive infinite 1413 * <p> 1414 * For multi-element items, the check is true if any elements in an item is positive infinite 1415 * @param a 1416 * @param o output can be null - in which case, a new dataset is created 1417 * @return dataset where items are true if any of its elements are positive infinite 1418 */ 1419 public static BooleanDataset isPositiveInfinite(Object a, BooleanDataset o) { 1420 return isEqual(a, o, Double.POSITIVE_INFINITY); 1421 } 1422 1423 /** 1424 * Check item-wise for whether any a's elements are negative infinite 1425 * <p> 1426 * For multi-element items, the check is true if any elements in an item is negative infinite 1427 * @param a 1428 * @return dataset where items are true if any of its elements are negative infinite 1429 */ 1430 public static BooleanDataset isNegativeInfinite(Object a) { 1431 return isEqual(a, null, Double.NEGATIVE_INFINITY); 1432 } 1433 1434 /** 1435 * Check item-wise for whether any a's elements are negative infinite 1436 * <p> 1437 * For multi-element items, the check is true if any elements in an item is negative infinite 1438 * @param a 1439 * @param o output can be null - in which case, a new dataset is created 1440 * @return dataset where items are true if any of its elements are negative infinite 1441 */ 1442 public static BooleanDataset isNegativeInfinite(Object a, BooleanDataset o) { 1443 return isEqual(a, o, Double.NEGATIVE_INFINITY); 1444 } 1445 1446 /** 1447 * Check item-wise for whether any a's elements match given item 1448 * <p> 1449 * For multi-element items, the check is true if any elements in an item matches 1450 * @param a 1451 * @param o output can be null - in which case, a new dataset is created 1452 * @param match 1453 * @return dataset where items are true if any of its elements match 1454 */ 1455 private static BooleanDataset isEqual(Object a, BooleanDataset o, final double match) { 1456 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 1457 1458 List<int[]> sl = BroadcastUtils.broadcastShapes(da.getShapeRef(), o == null ? null : o.getShapeRef()); 1459 1460 final BooleanDataset r = o == null ? DatasetFactory.zeros(BooleanDataset.class, sl.get(0)) : o; 1461 1462 if (!da.hasFloatingPointElements()) { 1463 if (r == o) { 1464 r.fill(false); 1465 } 1466 return r; 1467 } 1468 1469 final SingleInputBroadcastIterator it = new SingleInputBroadcastIterator(da, r); 1470 it.setOutputDouble(true); 1471 final int as = da.getElementsPerItem(); 1472 1473 if (as == 1) { 1474 while (it.hasNext()) { 1475 r.setAbs(it.oIndex, it.aDouble == match); 1476 } 1477 } else { 1478 if (da instanceof ComplexFloatDataset || da instanceof ComplexDoubleDataset) { 1479 while (it.hasNext()) { 1480 final double rv = it.aDouble; 1481 final double iv = da.getElementDoubleAbs(it.aIndex + 1); 1482 r.setAbs(it.oIndex, (rv == match) || (iv == match)); 1483 } 1484 } else { 1485 while (it.hasNext()) { 1486 boolean rb = false; 1487 for (int j = 0; !rb && j < as; j++) { 1488 rb &= da.getElementDoubleAbs(it.aIndex + j) == match; 1489 } 1490 r.setAbs(it.oIndex, rb); 1491 } 1492 } 1493 } 1494 return r; 1495 } 1496 1497 /** 1498 * Check item-wise for whether any a's elements are finite (or not infinite and not Not-a-Number) 1499 * <p> 1500 * For multi-element items, check is true if any elements in an item is finite 1501 * @param a 1502 * @return dataset where item is true if any of its elements are finite 1503 */ 1504 public static BooleanDataset isFinite(Object a) { 1505 return isFinite(a, null); 1506 } 1507 1508 /** 1509 * Check item-wise for whether any a's elements are finite (or not infinite and not Not-a-Number) 1510 * <p> 1511 * For multi-element items, check is true if any elements in an item is finite 1512 * @param a 1513 * @param o output can be null - in which case, a new dataset is created 1514 * @return dataset where item is true if any of its elements are finite 1515 */ 1516 public static BooleanDataset isFinite(Object a, BooleanDataset o) { 1517 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 1518 1519 List<int[]> sl = BroadcastUtils.broadcastShapes(da.getShapeRef(), o == null ? null : o.getShapeRef()); 1520 1521 final BooleanDataset r = o == null ? DatasetFactory.zeros(BooleanDataset.class, sl.get(0)) : o; 1522 1523 if (!da.hasFloatingPointElements()) { 1524 r.fill(true); 1525 return r; 1526 } 1527 1528 final SingleInputBroadcastIterator it = new SingleInputBroadcastIterator(da, r); 1529 it.setOutputDouble(true); 1530 final int as = da.getElementsPerItem(); 1531 1532 if (as == 1) { 1533 while (it.hasNext()) { 1534 final double rv = it.aDouble; 1535 r.setAbs(it.oIndex, !(Double.isInfinite(rv) || Double.isNaN(rv))); 1536 } 1537 } else { 1538 if (da instanceof ComplexFloatDataset || da instanceof ComplexDoubleDataset) { 1539 while (it.hasNext()) { 1540 final double rv = it.aDouble; 1541 final double iv = da.getElementDoubleAbs(it.aIndex + 1); 1542 r.setAbs(it.oIndex, !(Double.isInfinite(rv) || Double.isNaN(rv) || Double.isInfinite(iv) || Double.isNaN(iv))); 1543 } 1544 } else { 1545 while (it.hasNext()) { 1546 boolean rb = false; 1547 for (int j = 0; !rb && j < as; j++) { 1548 final double rv = it.aDouble; 1549 rb &= !(Double.isInfinite(rv) || Double.isNaN(rv)); 1550 } 1551 r.setAbs(it.oIndex, rb); 1552 } 1553 } 1554 } 1555 return r; 1556 } 1557 1558 /** 1559 * Enumeration of monotonicity. NaNs are ignored or considered not equal 1560 */ 1561 public static enum Monotonicity { 1562 /** 1563 * No order: x_0 != x_1 != x_2 ... 1564 */ 1565 NOT_ORDERED, 1566 /** 1567 * All equal: x_0 == x_1 == x_2 ... 1568 */ 1569 ALL_EQUAL, 1570 /** 1571 * Strictly decreasing x_0 > x_1 > x_2 ... 1572 */ 1573 STRICTLY_DECREASING, 1574 /** 1575 * Non-increasing or weakly decreasing x_0 >= x_1 >= x_2 ... 1576 */ 1577 NONINCREASING, 1578 /** 1579 * Non-decreasing or weakly increasing x_0 <= x_1 <= x_2 ... 1580 */ 1581 NONDECREASING, 1582 /** 1583 * Strictly increasing x_0 < x_1 < x_2 ... 1584 */ 1585 STRICTLY_INCREASING, 1586 } 1587 1588 /** 1589 * @param a 1590 * @return true if all elements are in a monotonic order 1591 * @see #findMonotonicity(Object) 1592 */ 1593 public static boolean isMonotonic(Object a) { 1594 return findMonotonicity(a) != Monotonicity.NOT_ORDERED; 1595 } 1596 1597 /** 1598 * @param a 1599 * @param monotonicity 1600 * @return true if all elements are in given monotonic ordering 1601 */ 1602 public static boolean isMonotonic(Object a, Monotonicity monotonicity) { 1603 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 1604 if (da.getRank() > 1) { 1605 throw new IllegalArgumentException("Only 0 or 1D datasets are allowed"); 1606 } 1607 1608 if (da.getElementsPerItem() > 1) { 1609 throw new IllegalArgumentException("Cannot compare compound datsets"); 1610 } 1611 1612 final IndexIterator it = da.getIterator(); 1613 double previous = Double.NaN; 1614 while (Double.isNaN(previous) && it.hasNext()) { // look for first non-NaN 1615 previous = da.getElementDoubleAbs(it.index); 1616 } 1617 1618 Boolean increasing = null; 1619 boolean equality = false; 1620 while (it.hasNext()) { // look for first change 1621 double next = da.getElementDoubleAbs(it.index); 1622 if (!Double.isNaN(next)) { 1623 if (previous != next) { 1624 increasing = previous < next; 1625 previous = next; 1626 break; 1627 } else if (!equality) { 1628 equality = true; 1629 if (monotonicity == Monotonicity.STRICTLY_DECREASING || monotonicity == Monotonicity.STRICTLY_DECREASING) 1630 return false; 1631 } 1632 } 1633 } 1634 1635 if (increasing == null) { 1636 if (equality) 1637 return monotonicity == Monotonicity.ALL_EQUAL || monotonicity == Monotonicity.NONDECREASING || monotonicity == Monotonicity.NONINCREASING; 1638 return Double.isNaN(previous) ? monotonicity == Monotonicity.NOT_ORDERED : true; 1639 } 1640 1641 if (increasing) { 1642 if (monotonicity == Monotonicity.ALL_EQUAL || monotonicity == Monotonicity.NONINCREASING || monotonicity == Monotonicity.STRICTLY_DECREASING) 1643 return false; 1644 1645 while (it.hasNext()) { 1646 double next = da.getElementDoubleAbs(it.index); 1647 if (!Double.isNaN(next)) { 1648 if (previous > next) { 1649 return monotonicity == Monotonicity.NOT_ORDERED; 1650 } else if (previous < next) { 1651 previous = next; 1652 } else if (!equality) { 1653 equality = true; 1654 if (monotonicity == Monotonicity.STRICTLY_INCREASING) 1655 return false; 1656 } 1657 } 1658 } 1659 1660 return monotonicity != Monotonicity.NOT_ORDERED; 1661 } 1662 1663 if (monotonicity == Monotonicity.ALL_EQUAL || monotonicity == Monotonicity.NONDECREASING || monotonicity == Monotonicity.STRICTLY_INCREASING) 1664 return false; 1665 1666 while (it.hasNext()) { 1667 double next = da.getElementDoubleAbs(it.index); 1668 if (!Double.isNaN(next)) { 1669 if (previous < next) { 1670 return monotonicity == Monotonicity.NOT_ORDERED; 1671 } else if (previous > next) { 1672 previous = next; 1673 } else if (!equality) { 1674 equality = true; 1675 if (monotonicity == Monotonicity.STRICTLY_DECREASING) 1676 return false; 1677 } 1678 } 1679 } 1680 1681 return monotonicity != Monotonicity.NOT_ORDERED; 1682 } 1683 1684 /** 1685 * @param a 1686 * @return true if all elements are in a strictly monotonic order 1687 * @see #findMonotonicity(Object) 1688 */ 1689 public static boolean isStrictlyMonotonic(Object a) { 1690 Monotonicity mono = findMonotonicity(a); 1691 return mono == Monotonicity.STRICTLY_DECREASING || mono == Monotonicity.STRICTLY_INCREASING; 1692 } 1693 1694 /** 1695 * Find monotonicity. NaNs are ignored or considered not equal 1696 * @param a 1697 * @return monotonicity 1698 */ 1699 public static Monotonicity findMonotonicity(Object a) { 1700 final Dataset da = a instanceof Dataset ? (Dataset) a : DatasetFactory.createFromObject(a); 1701 if (da.getRank() > 1) { 1702 throw new IllegalArgumentException("Only 0 or 1D datasets are allowed"); 1703 } 1704 1705 if (da.getElementsPerItem() > 1) { 1706 throw new IllegalArgumentException("Cannot compare compound datsets"); 1707 } 1708 1709 final IndexIterator it = da.getIterator(); 1710 double previous = Double.NaN; 1711 while (Double.isNaN(previous) && it.hasNext()) { // look for first non-NaN 1712 previous = da.getElementDoubleAbs(it.index); 1713 } 1714 1715 Boolean increasing = null; 1716 boolean equality = false; 1717 while (it.hasNext()) { // look for first change 1718 double next = da.getElementDoubleAbs(it.index); 1719 if (!Double.isNaN(next)) { 1720 if (previous != next) { 1721 increasing = previous < next; 1722 previous = next; 1723 break; 1724 } else if (!equality) { 1725 equality = true; 1726 } 1727 } 1728 } 1729 1730 if (increasing == null) { 1731 return Double.isNaN(previous) ? Monotonicity.NOT_ORDERED : Monotonicity.ALL_EQUAL; 1732 } 1733 1734 if (increasing) { 1735 while (it.hasNext()) { 1736 double next = da.getElementDoubleAbs(it.index); 1737 if (!Double.isNaN(next)) { 1738 if (previous > next) { 1739 return Monotonicity.NOT_ORDERED; 1740 } else if (previous < next) { 1741 previous = next; 1742 } else if (!equality) { 1743 equality = true; 1744 } 1745 } 1746 } 1747 return equality ? Monotonicity.NONDECREASING : Monotonicity.STRICTLY_INCREASING; 1748 } 1749 1750 while (it.hasNext()) { 1751 double next = da.getElementDoubleAbs(it.index); 1752 if (!Double.isNaN(next)) { 1753 if (previous < next) { 1754 return Monotonicity.NOT_ORDERED; 1755 } else if (previous > next) { 1756 previous = next; 1757 } else if (!equality) { 1758 equality = true; 1759 } 1760 } 1761 } 1762 return equality ? Monotonicity.NONINCREASING : Monotonicity.STRICTLY_DECREASING; 1763 } 1764}