001/* 002 * @author Francesco.Kriegel@gmx.de 003 */ 004package conexp.fx.core.collections.relation; 005 006/* 007 * #%L 008 * Concept Explorer FX 009 * %% 010 * Copyright (C) 2010 - 2023 Francesco Kriegel 011 * %% 012 * This program is free software: you can redistribute it and/or modify 013 * it under the terms of the GNU General Public License as 014 * published by the Free Software Foundation, either version 3 of the 015 * License, or (at your option) any later version. 016 * 017 * This program is distributed in the hope that it will be useful, 018 * but WITHOUT ANY WARRANTY; without even the implied warranty of 019 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 020 * GNU General Public License for more details. 021 * 022 * You should have received a copy of the GNU General Public 023 * License along with this program. If not, see 024 * <http://www.gnu.org/licenses/gpl-3.0.html>. 025 * #L% 026 */ 027 028import java.util.AbstractSet; 029import java.util.Collection; 030import java.util.Collections; 031import java.util.HashSet; 032import java.util.Iterator; 033import java.util.List; 034import java.util.ListIterator; 035import java.util.Map; 036import java.util.Set; 037import java.util.concurrent.ConcurrentHashMap; 038import java.util.concurrent.CopyOnWriteArrayList; 039import java.util.stream.Collectors; 040 041import org.ujmp.core.booleanmatrix.BooleanMatrix; 042import org.ujmp.core.booleanmatrix.BooleanMatrix2D; 043import org.ujmp.core.calculation.Calculation.Ret; 044 045import com.google.common.base.Function; 046import com.google.common.base.Predicate; 047import com.google.common.base.Predicates; 048import com.google.common.collect.Collections2; 049import com.google.common.collect.Iterators; 050import com.google.common.collect.Sets; 051import com.google.common.primitives.Ints; 052 053import conexp.fx.core.collections.BitSetFX; 054import conexp.fx.core.collections.Collections3; 055import conexp.fx.core.collections.ListIterators; 056import conexp.fx.core.collections.Pair; 057import conexp.fx.core.collections.setlist.HashSetArrayList; 058import conexp.fx.core.collections.setlist.SetList; 059import conexp.fx.core.collections.setlist.SetLists; 060import conexp.fx.core.math.BooleanMatrices; 061 062public class MatrixRelation<R, C> extends AbstractRelation<R, C> { 063 064 private final class RowHeads extends HashSetArrayList<R> { 065 066 private RowHeads(final Collection<? extends R> c) { 067 super(c); 068 } 069 070 public final boolean add(final R row) { 071 final boolean wasEmpty = isEmpty(); 072 if (super.add(row)) { 073 append(wasEmpty, 1); 074 push(new RelationEvent<R, C>(RelationEvent.ROWS_ADDED, row, null)); 075 return true; 076 } 077 return false; 078 } 079 080 public final void add(final int i, final R row) { 081 final int size0 = size(); 082 super.add(i, row); 083 if (size0 != size()) { 084 insert(i, size0, 1); 085 push(new RelationEvent<R, C>(RelationEvent.ROWS_ADDED, row, null)); 086 } 087 } 088 089 public final boolean addAll(final Collection<? extends R> c) { 090 final int size0 = size(); 091 @SuppressWarnings("unchecked") 092 final Set<R> changes = new HashSet<R>(Collections3.<R> difference((Collection<R>) c, this)); 093 if (super.addAll(c)) { 094 append(size0 == 0, size() - size0); 095 push(new RelationEvent<R, C>(RelationEvent.ROWS_ADDED, changes, null, null)); 096 return true; 097 } 098 return false; 099 } 100 101 public final boolean addAll(final int i, final Collection<? extends R> c) { 102 final int size0 = size(); 103 @SuppressWarnings("unchecked") 104 final Set<R> changes = new HashSet<R>(Collections3.<R> difference((Collection<R>) c, this)); 105 if (super.addAll(i, c)) { 106 insert(i, size0, size() - size0); 107 push(new RelationEvent<R, C>(RelationEvent.ROWS_ADDED, changes, null, null)); 108 return true; 109 } 110 return false; 111 } 112 113 @SuppressWarnings("unchecked") 114 @Override 115 public final boolean set(final Object o, final R row) { 116 if (super.set(o, row)) { 117 push(new RelationEvent<R, C>(RelationEvent.ROWS_SET, new Pair<R, R>((R) o, row), null)); 118 return true; 119 } 120 return false; 121 } 122 123 @Override 124 public final R set(final int i, final R row) { 125 final R row0 = super.set(i, row); 126 push(new RelationEvent<R, C>(RelationEvent.ROWS_SET, new Pair<R, R>(row0, row), null)); 127 return row0; 128 } 129 130 @SuppressWarnings("unchecked") 131 public final boolean remove(final Object o) { 132 final int i = indexOf(o); 133 if (i == -1) 134 return false; 135 super.remove(o); 136 if (isEmpty()) 137 matrix = BooleanMatrix2D.Factory.zeros(0, 0); 138 else 139 matrix = (BooleanMatrix) matrix.deleteRows(Ret.NEW, i); 140 push(new RelationEvent<R, C>(RelationEvent.ROWS_REMOVED, (R) o, null)); 141 return true; 142 } 143 144 public final R remove(final int i) { 145 final R row = super.remove(i); 146 if (row != null) { 147 if (isEmpty()) 148 matrix = BooleanMatrix2D.Factory.zeros(0, 0); 149 else 150 matrix = (BooleanMatrix) matrix.deleteRows(Ret.NEW, i); 151 push(new RelationEvent<R, C>(RelationEvent.ROWS_REMOVED, row, null)); 152 } 153 return row; 154 } 155 156 public final boolean removeAll(final Collection<?> c) { 157 final Collection<Integer> i = indicesOf(c, false); 158 final Set<R> changes = new HashSet<R>(); 159 for (R row : this) 160 if (c.contains(row)) 161 changes.add(row); 162 if (super.removeAll(c)) { 163 if (isEmpty()) 164 matrix = BooleanMatrix2D.Factory.zeros(0, 0); 165 else 166 matrix = (BooleanMatrix) matrix.deleteRows(Ret.NEW, i); 167 push(new RelationEvent<R, C>(RelationEvent.ROWS_REMOVED, changes, null, null)); 168 return true; 169 } 170 return false; 171 } 172 173 public final boolean retainAll(final Collection<?> c) { 174 final Collection<Integer> i = indicesOf(c, false); 175 final Set<R> changes = new HashSet<R>(); 176 for (R row : this) 177 if (!c.contains(row)) 178 changes.add(row); 179 if (super.retainAll(c)) { 180 if (isEmpty()) 181 matrix = BooleanMatrix2D.Factory.zeros(0, 0); 182 else 183 matrix = (BooleanMatrix) matrix.selectRows(Ret.NEW, i); 184 push(new RelationEvent<R, C>(RelationEvent.ROWS_REMOVED, changes, null, null)); 185 return true; 186 } 187 return false; 188 } 189 190 public final ListIterator<R> listIterator(final int i) { 191 return new ListIterator<R>() { 192 193 private final ListIterator<R> it = RowHeads.super.listIterator(i); 194 private R pointer; 195 private int j; 196 197 public final boolean hasNext() { 198 return it.hasNext(); 199 } 200 201 public final int nextIndex() { 202 return it.nextIndex(); 203 } 204 205 public final R next() { 206 j = it.nextIndex(); 207 pointer = it.next(); 208 return pointer; 209 } 210 211 public final boolean hasPrevious() { 212 return it.hasPrevious(); 213 } 214 215 public final int previousIndex() { 216 return it.previousIndex(); 217 } 218 219 public final R previous() { 220 j = it.previousIndex(); 221 pointer = it.previous(); 222 return pointer; 223 } 224 225 public final void add(final R row) { 226 pointer = row; 227 final int size0 = size(); 228 it.add(row); 229 if (size0 != size()) { 230 insert(++j, size0, 1); 231 push(new RelationEvent<R, C>(RelationEvent.ROWS_ADDED, row, null)); 232 } 233 } 234 235 public final void set(final R row) { 236 pointer = row; 237 it.set(row); 238 } 239 240 public final void remove() { 241 it.remove(); 242 if (isEmpty()) 243 matrix = BooleanMatrix2D.Factory.zeros(0, 0); 244 else 245 matrix = (BooleanMatrix) matrix.deleteRows(Ret.NEW, j); 246 push(new RelationEvent<R, C>(RelationEvent.ROWS_REMOVED, pointer, null)); 247 } 248 }; 249 } 250 251 public final void clear() { 252 super.clear(); 253 matrix = BooleanMatrix2D.Factory.zeros(0, 0); 254 push(new RelationEvent<R, C>(RelationEvent.ROWS_CLEARED)); 255 } 256 257 private final void append(final boolean wasEmpty, final int rows) { 258 if (colHeads == null) 259 return; 260 final BooleanMatrix zeros = BooleanMatrix2D.Factory.zeros(rows, colHeads.size()); 261 if (wasEmpty) 262 matrix = zeros; 263 else 264 matrix = (BooleanMatrix) matrix.appendVertically(Ret.NEW, zeros); 265 } 266 267 private final void insert(final int i, final int size0, final int rows) { 268 if (colHeads == null) 269 return; 270 final int cols = colHeads.size(); 271 final BooleanMatrix zeros = BooleanMatrix2D.Factory.zeros(rows, cols); 272 if (size0 == 0) 273 matrix = zeros; 274 else if (i == 0) 275 matrix = (BooleanMatrix) zeros.appendVertically(Ret.NEW, matrix); 276 else if (i == size0) 277 matrix = (BooleanMatrix) matrix.appendVertically(Ret.NEW, zeros); 278 else { 279 BooleanMatrix upper = matrix.subMatrix(Ret.LINK, 0, 0, i - 1, cols - 1).toBooleanMatrix(); 280 BooleanMatrix lower = matrix.subMatrix(Ret.LINK, i, 0, size0 - 1, cols - 1).toBooleanMatrix(); 281 matrix = (BooleanMatrix) upper.appendVertically(Ret.NEW, zeros).appendVertically(Ret.NEW, lower); 282 } 283 } 284 } 285 286 private final class ColHeads extends HashSetArrayList<C> { 287 288 private ColHeads(final Collection<? extends C> c) { 289 super(c); 290 } 291 292 public final boolean add(final C col) { 293 final boolean wasEmpty = isEmpty(); 294 if (super.add(col)) { 295 append(wasEmpty, 1); 296 push(new RelationEvent<R, C>(RelationEvent.COLUMNS_ADDED, null, col)); 297 return true; 298 } 299 return false; 300 } 301 302 public final void add(final int i, final C col) { 303 final int size0 = size(); 304 super.add(i, col); 305 if (size0 != size()) { 306 insert(i, size0, 1); 307 push(new RelationEvent<R, C>(RelationEvent.COLUMNS_ADDED, null, col)); 308 } 309 } 310 311 public final boolean addAll(final Collection<? extends C> c) { 312 final int size0 = size(); 313 @SuppressWarnings("unchecked") 314 final Set<C> changes = new HashSet<C>(Collections3.<C> difference((Collection<C>) c, this)); 315 if (super.addAll(c)) { 316 append(size0 == 0, size() - size0); 317 push(new RelationEvent<R, C>(RelationEvent.COLUMNS_ADDED, null, changes, null)); 318 return true; 319 } 320 return false; 321 } 322 323 public final boolean addAll(final int i, final Collection<? extends C> c) { 324 final int size0 = size(); 325 @SuppressWarnings("unchecked") 326 final Set<C> changes = new HashSet<C>(Collections3.<C> difference((Collection<C>) c, this)); 327 if (super.addAll(i, c)) { 328 insert(i, size0, size() - size0); 329 push(new RelationEvent<R, C>(RelationEvent.COLUMNS_ADDED, null, changes, null)); 330 return true; 331 } 332 return false; 333 } 334 335 @SuppressWarnings("unchecked") 336 @Override 337 public final boolean set(final Object o, final C col) { 338 if (super.set(o, col)) { 339 push(new RelationEvent<R, C>(RelationEvent.COLUMNS_SET, null, new Pair<C, C>((C) o, col))); 340 return true; 341 } 342 return false; 343 } 344 345 @Override 346 public final C set(final int i, final C col) { 347 final C col0 = super.set(i, col); 348 push(new RelationEvent<R, C>(RelationEvent.COLUMNS_SET, null, new Pair<C, C>(col0, col))); 349 return col0; 350 } 351 352 @SuppressWarnings("unchecked") 353 public final boolean remove(final Object o) { 354 final int i = indexOf(o); 355 if (i == -1) 356 return false; 357 super.remove(o); 358 if (isEmpty()) 359 matrix = BooleanMatrix2D.Factory.zeros(0, 0); 360 else 361 matrix = (BooleanMatrix) matrix.deleteColumns(Ret.NEW, i); 362 push(new RelationEvent<R, C>(RelationEvent.COLUMNS_REMOVED, null, (C) o)); 363 return true; 364 } 365 366 public final C remove(final int i) { 367 final C col = super.remove(i); 368 if (col != null) { 369 if (isEmpty()) 370 matrix = BooleanMatrix2D.Factory.zeros(0, 0); 371 else 372 matrix = (BooleanMatrix) matrix.deleteColumns(Ret.NEW, i); 373 push(new RelationEvent<R, C>(RelationEvent.COLUMNS_REMOVED, null, col)); 374 } 375 return col; 376 } 377 378 public final boolean removeAll(final Collection<?> c) { 379 final Collection<Integer> i = indicesOf(c, false); 380 final Set<C> changes = new HashSet<C>(); 381 for (C col : this) 382 if (c.contains(col)) 383 changes.add(col); 384 if (super.removeAll(c)) { 385 if (isEmpty()) 386 matrix = BooleanMatrix2D.Factory.zeros(0, 0); 387 else 388 matrix = (BooleanMatrix) matrix.deleteColumns(Ret.NEW, i); 389 push(new RelationEvent<R, C>(RelationEvent.COLUMNS_REMOVED, null, changes, null)); 390 return true; 391 } 392 return false; 393 } 394 395 public final boolean retainAll(final Collection<?> c) { 396 final Collection<Integer> i = indicesOf(c, false); 397 final Set<C> changes = new HashSet<C>(); 398 for (C col : this) 399 if (!c.contains(col)) 400 changes.add(col); 401 if (super.retainAll(c)) { 402 if (isEmpty()) 403 matrix = BooleanMatrix2D.Factory.zeros(0, 0); 404 else 405 matrix = (BooleanMatrix) matrix.selectColumns(Ret.NEW, i); 406 push(new RelationEvent<R, C>(RelationEvent.COLUMNS_REMOVED, null, changes, null)); 407 return true; 408 } 409 return false; 410 } 411 412 public final ListIterator<C> listIterator(final int i) { 413 return new ListIterator<C>() { 414 415 private final ListIterator<C> it = ColHeads.super.listIterator(i); 416 private C pointer; 417 private int j; 418 419 public final boolean hasNext() { 420 return it.hasNext(); 421 } 422 423 public final C next() { 424 j = it.nextIndex(); 425 pointer = it.next(); 426 return pointer; 427 } 428 429 public final boolean hasPrevious() { 430 return it.hasPrevious(); 431 } 432 433 public final C previous() { 434 j = it.previousIndex(); 435 pointer = it.previous(); 436 return pointer; 437 } 438 439 public final int nextIndex() { 440 return it.nextIndex(); 441 } 442 443 public final int previousIndex() { 444 return it.previousIndex(); 445 } 446 447 public final void remove() { 448 it.remove(); 449 if (isEmpty()) 450 matrix = BooleanMatrix2D.Factory.zeros(0, 0); 451 else 452 matrix = (BooleanMatrix) matrix.deleteColumns(Ret.NEW, j); 453 push(new RelationEvent<R, C>(RelationEvent.COLUMNS_REMOVED, null, pointer)); 454 } 455 456 public final void set(final C col) { 457 pointer = col; 458 it.set(col); 459 } 460 461 public final void add(final C col) { 462 pointer = col; 463 final int size0 = size(); 464 it.add(col); 465 if (size0 != size()) { 466 insert(++j, size0, 1); 467 push(new RelationEvent<R, C>(RelationEvent.COLUMNS_ADDED, null, col)); 468 } 469 } 470 }; 471 } 472 473 public final void clear() { 474 super.clear(); 475 matrix = BooleanMatrix2D.Factory.zeros(0, 0); 476 push(new RelationEvent<R, C>(RelationEvent.COLUMNS_CLEARED)); 477 } 478 479 private final void append(final boolean wasEmpty, final int cols) { 480 final BooleanMatrix zeros = BooleanMatrix2D.Factory.zeros(rowHeads.size(), cols); 481 if (wasEmpty) 482 matrix = zeros; 483 else 484 matrix = (BooleanMatrix) matrix.appendHorizontally(Ret.NEW, zeros); 485 } 486 487 private final void insert(final int i, final int size0, final int cols) { 488 final int rows = rowHeads.size(); 489 final BooleanMatrix zeros = BooleanMatrix2D.Factory.zeros(rows, cols); 490 if (size0 == 0) 491 matrix = zeros; 492 else if (i == 0) 493 matrix = (BooleanMatrix) zeros.appendHorizontally(Ret.NEW, matrix); 494 else if (i == size0) 495 matrix = (BooleanMatrix) matrix.appendHorizontally(Ret.NEW, zeros); 496 else { 497 final BooleanMatrix left = matrix.subMatrix(Ret.LINK, 0, 0, rows - 1, i - 1).toBooleanMatrix(); 498 final BooleanMatrix right = matrix.subMatrix(Ret.LINK, 0, i, rows - 1, size0 - 1).toBooleanMatrix(); 499 matrix = (BooleanMatrix) left.appendHorizontally(Ret.NEW, zeros).appendHorizontally(Ret.NEW, right); 500 } 501 } 502 } 503 504 private final class Heads extends HashSetArrayList<R> { 505 506 private Heads(final Collection<? extends R> c) { 507 super(c); 508 } 509 510 @SuppressWarnings("unchecked") 511 public final boolean add(final R head) { 512 if (super.add(head)) { 513 append(size() - 1, 1); 514 push(new RelationEvent<R, C>(RelationEvent.ROWS_ADDED, head, null)); 515 push(new RelationEvent<R, C>(RelationEvent.COLUMNS_ADDED, null, (C) head)); 516 return true; 517 } 518 return false; 519 } 520 521 @SuppressWarnings("unchecked") 522 public final void add(final int i, final R head) { 523 final int size0 = size(); 524 super.add(i, head); 525 if (size0 != size()) { 526 insert(i, size0, 1); 527 push(new RelationEvent<R, C>(RelationEvent.ROWS_ADDED, head, null)); 528 push(new RelationEvent<R, C>(RelationEvent.COLUMNS_ADDED, null, (C) head)); 529 } 530 } 531 532 @SuppressWarnings("unchecked") 533 public final boolean addAll(final Collection<? extends R> c) { 534 final int size0 = size(); 535 final Set<R> changes = new HashSet<R>(Collections3.<R> difference((Collection<R>) c, this)); 536 if (super.addAll(c)) { 537 append(size0, size() - size0); 538 push(new RelationEvent<R, C>(RelationEvent.ROWS_ADDED, changes, null, null)); 539 push(new RelationEvent<R, C>(RelationEvent.COLUMNS_ADDED, null, (Set<C>) changes, null)); 540 return true; 541 } 542 return false; 543 } 544 545 @SuppressWarnings("unchecked") 546 public final boolean addAll(final int i, final Collection<? extends R> c) { 547 final int size0 = size(); 548 final Set<R> changes = new HashSet<R>(Collections3.<R> difference((Collection<R>) c, this)); 549 if (super.addAll(i, c)) { 550 insert(i, size0, size() - size0); 551 push(new RelationEvent<R, C>(RelationEvent.ROWS_ADDED, changes, null, null)); 552 push(new RelationEvent<R, C>(RelationEvent.COLUMNS_ADDED, null, (Set<C>) changes, null)); 553 return true; 554 } 555 return false; 556 } 557 558 @SuppressWarnings("unchecked") 559 @Override 560 public final boolean set(final Object o, final R head) { 561 if (super.set(o, head)) { 562 push(new RelationEvent<R, C>(RelationEvent.ROWS_SET, new Pair<R, R>((R) o, head), null)); 563 push(new RelationEvent<R, C>(RelationEvent.COLUMNS_SET, null, new Pair<C, C>((C) o, (C) head))); 564 return true; 565 } 566 return false; 567 } 568 569 @SuppressWarnings("unchecked") 570 @Override 571 public final R set(final int i, final R head) { 572 final R head0 = super.set(i, head); 573 push(new RelationEvent<R, C>(RelationEvent.ROWS_SET, new Pair<R, R>(head0, head), null)); 574 push(new RelationEvent<R, C>(RelationEvent.COLUMNS_SET, null, new Pair<C, C>((C) head0, (C) head))); 575 return head0; 576 } 577 578 @SuppressWarnings("unchecked") 579 public final boolean remove(final Object o) { 580 final int i = indexOf(o); 581 if (i == -1) 582 return false; 583 super.remove(o); 584 if (isEmpty()) 585 matrix = BooleanMatrix2D.Factory.zeros(0, 0); 586 else 587 matrix = (BooleanMatrix) matrix.deleteRows(Ret.NEW, i).deleteColumns(Ret.NEW, i); 588 push(new RelationEvent<R, C>(RelationEvent.ROWS_REMOVED, (R) o, null)); 589 push(new RelationEvent<R, C>(RelationEvent.COLUMNS_REMOVED, null, (C) o)); 590 return true; 591 } 592 593 @SuppressWarnings("unchecked") 594 public final R remove(final int i) { 595 final R head = super.remove(i); 596 if (head != null) { 597 if (isEmpty()) 598 matrix = BooleanMatrix2D.Factory.zeros(0, 0); 599 else 600 matrix = (BooleanMatrix) matrix.deleteRows(Ret.NEW, i).deleteColumns(Ret.NEW, i); 601 push(new RelationEvent<R, C>(RelationEvent.ROWS_REMOVED, head, null)); 602 push(new RelationEvent<R, C>(RelationEvent.COLUMNS_REMOVED, null, (C) head)); 603 } 604 return head; 605 } 606 607 @SuppressWarnings("unchecked") 608 public final boolean removeAll(final Collection<?> c) { 609 final Collection<Integer> i = Sets.newHashSet(indicesOf(c, false)); 610 final Set<R> changes = new HashSet<R>(); 611 for (R head : this) 612 if (c.contains(head)) 613 changes.add(head); 614 if (super.removeAll(c)) { 615 if (isEmpty()) 616 matrix = BooleanMatrix2D.Factory.zeros(0, 0); 617 else 618 matrix = (BooleanMatrix) matrix.deleteRows(Ret.NEW, i).deleteColumns(Ret.NEW, i); 619 push(new RelationEvent<R, C>(RelationEvent.ROWS_REMOVED, changes, null, null)); 620 push(new RelationEvent<R, C>(RelationEvent.COLUMNS_REMOVED, null, (Set<C>) changes, null)); 621 return true; 622 } 623 return false; 624 } 625 626 @SuppressWarnings("unchecked") 627 public final boolean retainAll(final Collection<?> c) { 628 final Collection<Integer> i = indicesOf(c, false); 629 final Set<R> changes = new HashSet<R>(); 630 for (R head : this) 631 if (c.contains(head)) 632 changes.add(head); 633 if (super.removeAll(c)) { 634 if (isEmpty()) 635 matrix = BooleanMatrix2D.Factory.zeros(0, 0); 636 else 637 matrix = (BooleanMatrix) matrix.selectRows(Ret.NEW, i).selectColumns(Ret.NEW, i); 638 push(new RelationEvent<R, C>(RelationEvent.ROWS_REMOVED, changes, null, null)); 639 push(new RelationEvent<R, C>(RelationEvent.COLUMNS_REMOVED, null, (Set<C>) changes, null)); 640 return true; 641 } 642 return false; 643 } 644 645 public final ListIterator<R> listIterator(final int i) { 646 return new ListIterator<R>() { 647 648 private final ListIterator<R> it = Heads.super.listIterator(i); 649 private R pointer; 650 private int j; 651 652 public final boolean hasNext() { 653 return it.hasNext(); 654 } 655 656 public final int nextIndex() { 657 return it.nextIndex(); 658 } 659 660 public final R next() { 661 j = it.nextIndex(); 662 pointer = it.next(); 663 return pointer; 664 } 665 666 public final boolean hasPrevious() { 667 return it.hasPrevious(); 668 } 669 670 public final int previousIndex() { 671 return it.previousIndex(); 672 } 673 674 public final R previous() { 675 j = it.previousIndex(); 676 pointer = it.previous(); 677 return pointer; 678 } 679 680 @SuppressWarnings("unchecked") 681 public final void add(final R head) { 682 pointer = head; 683 final int size0 = size(); 684 it.add(head); 685 if (size0 != size()) { 686 j++; 687 insert(j, size0, 1); 688 push(new RelationEvent<R, C>(RelationEvent.ROWS_ADDED, head, null)); 689 push(new RelationEvent<R, C>(RelationEvent.COLUMNS_ADDED, null, (C) head)); 690 } 691 } 692 693 public final void set(final R head) { 694 pointer = head; 695 it.set(head); 696 } 697 698 @SuppressWarnings("unchecked") 699 public final void remove() { 700 it.remove(); 701 if (isEmpty()) 702 matrix = BooleanMatrix2D.Factory.zeros(0, 0); 703 else 704 matrix = (BooleanMatrix) matrix.deleteRows(Ret.NEW, j).deleteColumns(Ret.NEW, j); 705 push(new RelationEvent<R, C>(RelationEvent.ROWS_REMOVED, pointer, null)); 706 push(new RelationEvent<R, C>(RelationEvent.COLUMNS_REMOVED, null, (C) pointer)); 707 } 708 }; 709 } 710 711 public final void clear() { 712 super.clear(); 713 matrix = BooleanMatrix2D.Factory.zeros(0, 0); 714 push(new RelationEvent<R, C>(RelationEvent.ROWS_CLEARED)); 715 push(new RelationEvent<R, C>(RelationEvent.COLUMNS_CLEARED)); 716 } 717 718 private final void append(final int size0, final int heads) { 719 if (size0 == 0) { 720 matrix = BooleanMatrix2D.Factory.zeros(heads, heads); 721 return; 722 } 723 final BooleanMatrix rows = BooleanMatrix2D.Factory.zeros(heads, size0); 724 final BooleanMatrix cols = BooleanMatrix2D.Factory.zeros(size0 + heads, heads); 725 matrix = (BooleanMatrix) matrix.appendVertically(Ret.NEW, rows).appendHorizontally(Ret.NEW, cols); 726 } 727 728 private final void insert(final int i, final int size0, final int heads) { 729 if (size0 == 0) { 730 matrix = BooleanMatrix2D.Factory.zeros(heads, heads); 731 return; 732 } 733 final BooleanMatrix rows = BooleanMatrix2D.Factory.zeros(heads, size0); 734 final BooleanMatrix cols = BooleanMatrix2D.Factory.zeros(size0 + heads, heads); 735 if (i == 0) 736 matrix = (BooleanMatrix) cols.appendHorizontally(Ret.NEW, rows.appendVertically(Ret.NEW, matrix)); 737 else if (i == size0) 738 matrix = (BooleanMatrix) matrix.appendVertically(Ret.NEW, rows).appendHorizontally(Ret.NEW, cols); 739 else { 740 final BooleanMatrix upper = (BooleanMatrix) matrix.subMatrix(Ret.LINK, 0, 0, i - 1, size0 - 1); 741 final BooleanMatrix lower = (BooleanMatrix) matrix.subMatrix(Ret.LINK, i, 0, size0 - 1, size0 - 1); 742 matrix = (BooleanMatrix) upper.appendVertically(Ret.NEW, rows).appendVertically(Ret.NEW, lower); 743 final BooleanMatrix left = (BooleanMatrix) matrix.subMatrix(Ret.LINK, 0, 0, size0 + heads - 1, i - 1); 744 final BooleanMatrix right = (BooleanMatrix) matrix.subMatrix(Ret.LINK, 0, i, size0 + heads - 1, size0 - 1); 745 matrix = (BooleanMatrix) left.appendHorizontally(Ret.NEW, cols).appendHorizontally(Ret.NEW, right); 746 } 747 } 748 } 749 750 protected BooleanMatrix matrix; 751 private final Map<RelationEvent.Type, List<RelationEventHandler<R, C>>> eventHandlers = new ConcurrentHashMap<>(); 752 753 public MatrixRelation(final boolean homogen) { 754 this(SetLists.<R> empty(), SetLists.<C> empty(), BooleanMatrix2D.Factory.zeros(0, 0), homogen); 755 } 756 757 public MatrixRelation(final SetList<R> rowHeads, final SetList<C> colHeads, final boolean homogen) { 758 this(rowHeads, colHeads, BooleanMatrix2D.Factory.zeros(rowHeads.size(), colHeads.size()), homogen); 759 } 760 761 @SuppressWarnings("unchecked") 762 public MatrixRelation( 763 final SetList<R> rowHeads, 764 final SetList<C> colHeads, 765 final BooleanMatrix matrix, 766 final boolean homogen) { 767 super(homogen); 768 if (homogen) { 769 if (!rowHeads.equals(colHeads)) 770 throw new NoHomogenRelationException(); 771 this.rowHeads = new Heads(rowHeads); 772 this.colHeads = (SetList<C>) this.rowHeads; 773 } else { 774 this.rowHeads = new RowHeads(rowHeads); 775 this.colHeads = new ColHeads(colHeads); 776 } 777 this.matrix = matrix; 778 } 779 780 public final boolean add(final R row, final C col) { 781 boolean changed; 782 final int i; 783 if (rowHeads.add(row)) { 784 i = rowHeads.size() - 1; 785 changed = true; 786 } else { 787 i = rowHeads.indexOf(row); 788 changed = false; 789 } 790 final int j; 791 if (colHeads.add(col)) { 792 j = colHeads.size() - 1; 793 changed = true; 794 } else 795 j = colHeads.indexOf(col); 796 if (changed || !matrix.getBoolean(i, j)) { 797 matrix.setBoolean(true, i, j); 798 push( 799 new RelationEvent<R, C>( 800 RelationEvent.ENTRIES_ADDED, 801 null, 802 null, 803 Collections.singleton(new Pair<R, C>(row, col)))); 804 return true; 805 } 806 return false; 807 } 808 809 @SuppressWarnings("unchecked") 810 public boolean addFast(final Object o1, final Object o2) { 811 final int i = rowHeads.indexOf(o1); 812// if (i != -1) { 813 final int j = colHeads.indexOf(o2); 814// if (j != -1) 815 if (!matrix.getBoolean(i, j)) { 816 matrix.setBoolean(true, i, j); 817 push( 818 new RelationEvent<R, C>( 819 RelationEvent.ENTRIES_ADDED, 820 null, 821 null, 822 Collections.singleton(new Pair<R, C>((R) o1, (C) o2)))); 823 return true; 824 } 825// } 826 return false; 827 } 828 829// @SuppressWarnings("unchecked") 830 public void addFastSilent(final Object o1, final Object o2) { 831 final int i = rowHeads.indexOf(o1); 832// if (i != -1) { 833 final int j = colHeads.indexOf(o2); 834// if (j != -1) 835// if (!matrix.getBoolean(i, j)) { 836 matrix.setBoolean(true, i, j); 837// push(new RelationEvent<R, C>(RelationEvent.ENTRIES_ADDED, null, null, Collections.singleton(new Pair<R, C>( 838// (R) o1, 839// (C) o2)))); 840// return true; 841// } 842// } 843// return false; 844 } 845 846 @SuppressWarnings("unchecked") 847 public final boolean addAll(final Relation<? extends R, ? extends C> r) { 848 boolean changed = false; 849 if (r instanceof MatrixRelation) { 850 final MatrixRelation<? extends R, ? extends C> _r = (MatrixRelation<? extends R, ? extends C>) r; 851 rowHeads.addAll(_r.rowHeads); 852 colHeads.addAll(_r.colHeads); 853 matrix 854 .selectRows(Ret.LINK, rowHeads.indicesOf(_r.rowHeads, true)) 855 .selectColumns(Ret.LINK, colHeads.indicesOf(_r.colHeads, true)) 856 .or(Ret.ORIG, _r.matrix); 857 changed = true; 858 push(new RelationEvent<R, C>(RelationEvent.ALL_CHANGED, null, null, null)); 859 } else { 860 final Iterator<?> it = r.iterator(); 861 Pair<? extends R, ? extends C> next; 862 while (it.hasNext()) { 863 next = (Pair<? extends R, ? extends C>) it.next(); 864 changed |= add(next.x(), next.y()); 865 } 866 } 867 return changed; 868 } 869 870 @SuppressWarnings("unchecked") 871 public final boolean addAllFast(final Relation<?, ?> r) { 872 boolean changed = false; 873 if (r instanceof MatrixRelation) { 874 final MatrixRelation<?, ?> _r = (MatrixRelation<?, ?>) r; 875 matrix 876 .selectRows(Ret.LINK, rowHeads.indicesOf(_r.rowHeads, false)) 877 .selectColumns(Ret.LINK, colHeads.indicesOf(_r.colHeads, false)) 878 .or( 879 Ret.ORIG, 880 _r.matrix 881 .selectRows(Ret.LINK, _r.rowHeads.indicesOf(rowHeads, false)) 882 .selectColumns(Ret.LINK, _r.colHeads.indicesOf(colHeads, false))); 883 push(new RelationEvent<R, C>(RelationEvent.ALL_CHANGED, null, null, null)); 884 changed = true; 885 } else { 886 final Iterator<?> it = r.iterator(); 887 Pair<? extends R, ? extends C> next; 888 while (it.hasNext()) { 889 next = (Pair<? extends R, ? extends C>) it.next(); 890 changed |= addFast(next.x(), next.y()); 891 } 892 } 893 return changed; 894 } 895 896 @SuppressWarnings("unchecked") 897 public boolean remove(final Object o1, final Object o2) { 898 final int i = rowHeads.indexOf(o1); 899 if (i != -1) { 900 final int j = colHeads.indexOf(o2); 901 if (j != -1 && matrix.getBoolean(i, j)) { 902 matrix.setBoolean(false, i, j); 903 push( 904 new RelationEvent<R, C>( 905 RelationEvent.ENTRIES_REMOVED, 906 null, 907 null, 908 Collections.singleton(new Pair<R, C>((R) o1, (C) o2)))); 909 return true; 910 } 911 } 912 return false; 913 } 914 915 @SuppressWarnings("unchecked") 916 public final boolean removeAll(final Relation<?, ?> r) { 917 boolean changed = false; 918 if (r instanceof MatrixRelation) { 919 final MatrixRelation<?, ?> _r = (MatrixRelation<?, ?>) r; 920 matrix 921 .selectRows(Ret.LINK, rowHeads.indicesOf(_r.rowHeads, false)) 922 .selectColumns(Ret.LINK, colHeads.indicesOf(_r.colHeads, false)) 923 .and( 924 Ret.ORIG, 925 _r.matrix 926 .selectRows(Ret.LINK, _r.rowHeads.indicesOf(rowHeads, false)) 927 .selectColumns(Ret.LINK, _r.colHeads.indicesOf(colHeads, false)) 928 .not(Ret.LINK)); 929 push(new RelationEvent<R, C>(RelationEvent.ALL_CHANGED, null, null, null)); 930 changed = true; 931 } else { 932 final Iterator<?> it = r.iterator(); 933 Pair<? extends R, ? extends C> next; 934 while (it.hasNext()) { 935 next = (Pair<? extends R, ? extends C>) it.next(); 936 changed |= remove(next.x(), next.y()); 937 } 938 } 939 return changed; 940 } 941 942 public final boolean retainAll(final Relation<?, ?> r) { 943 boolean changed = false; 944 if (r instanceof MatrixRelation) { 945 final MatrixRelation<?, ?> _r = (MatrixRelation<?, ?>) r; 946 final Collection<Integer> i = rowHeads.indicesOf(_r.rowHeads, false); 947 final Collection<Integer> j = colHeads.indicesOf(_r.colHeads, false); 948 final Collection<Integer> i0 = 949 Collections2.filter(SetLists.integers(rowHeads.size()), Predicates.not(Predicates.in(i))); 950 final Collection<Integer> j0 = 951 Collections2.filter(SetLists.integers(colHeads.size()), Predicates.not(Predicates.in(j))); 952 matrix.selectRows(Ret.LINK, i0).selectColumns(Ret.LINK, j0).and(Ret.ORIG, false); 953 matrix.selectRows(Ret.LINK, i0).selectColumns(Ret.LINK, j).and(Ret.ORIG, false); 954 matrix.selectRows(Ret.LINK, i).selectColumns(Ret.LINK, j0).and(Ret.ORIG, false); 955 matrix 956 .selectRows(Ret.LINK, i) 957 .selectColumns(Ret.LINK, j) 958 .and( 959 Ret.ORIG, 960 _r.matrix 961 .selectRows(Ret.LINK, _r.rowHeads.indicesOf(rowHeads, false)) 962 .selectColumns(Ret.LINK, _r.colHeads.indicesOf(colHeads, false))); 963 push(new RelationEvent<R, C>(RelationEvent.ALL_CHANGED, null, null, null)); 964 changed = true; 965 } else { 966 for (C col : colHeads) { 967 final Set<R> column = col(col); 968 if (r.colHeads().contains(col)) 969 changed |= column.retainAll(r.col(col)); 970 else { 971 changed |= !column.isEmpty(); 972 column.clear(); 973 } 974 } 975 } 976 return changed; 977 } 978 979 public final boolean contains(final Object o1, final Object o2) { 980 final int i = rowHeads.indexOf(o1); 981 if (i == -1) 982 return false; 983 final int j = colHeads.indexOf(o2); 984 return j != -1 && matrix.getBoolean(i, j); 985 } 986 987 public final boolean containsAll(final Relation<?, ?> r) { 988 if (rowHeads.containsAll(r.rowHeads()) && colHeads.containsAll(r.colHeads())) { 989 if (r instanceof MatrixRelation) { 990 final MatrixRelation<?, ?> _r = (MatrixRelation<?, ?>) r; 991 return matrix 992 .selectRows(Ret.LINK, rowHeads.indicesOf(_r.rowHeads, true)) 993 .selectColumns(Ret.LINK, colHeads.indicesOf(_r.colHeads, true)) 994 .equals(_r.matrix); 995 } else { 996 final Iterator<?> iterator = r.iterator(); 997 Pair<?, ?> next; 998 while (iterator.hasNext()) { 999 next = (Pair<?, ?>) iterator.next(); 1000 if (!contains(next.x(), next.y())) 1001 return false; 1002 } 1003 return true; 1004 } 1005 } 1006 return false; 1007 } 1008 1009 public final Set<C> row(final Object o) { 1010 return new AbstractSet<C>() { 1011 1012 private final int i = rowHeads.indexOf(o); 1013 1014 @SuppressWarnings("unchecked") 1015 public final boolean add(final C col) { 1016 final int j = colHeads.indexOf(col); 1017 if (matrix.getBoolean(i, j)) 1018 return false; 1019 matrix.setBoolean(true, i, j); 1020 push( 1021 new RelationEvent<R, C>( 1022 RelationEvent.ENTRIES_ADDED, 1023 null, 1024 null, 1025 Collections.singleton(new Pair<R, C>((R) o, col)))); 1026 return true; 1027 } 1028 1029 public final boolean addAll(final Collection<? extends C> c) { 1030 boolean changed = false; 1031 @SuppressWarnings("unchecked") 1032 final Set<C> changes = new HashSet<C>(Collections3.<C> difference((Collection<C>) c, this)); 1033 for (C col : c) { 1034 final int j = colHeads.indexOf(col); 1035 if (!matrix.getBoolean(i, j)) { 1036 matrix.setBoolean(true, i, j); 1037 changed = true; 1038 push( 1039 new RelationEvent<R, C>( 1040 RelationEvent.ENTRIES_ADDED, 1041 null, 1042 null, 1043 new HashSet<Pair<R, C>>(Collections2.transform(changes, new Function<C, Pair<R, C>>() { 1044 1045 @SuppressWarnings("unchecked") 1046 public final Pair<R, C> apply(final C col) { 1047 return new Pair<R, C>((R) o, col); 1048 } 1049 })))); 1050 } 1051 } 1052 return changed; 1053 } 1054 1055 public final boolean contains(final Object o) { 1056 return matrix.getBoolean(i, colHeads.indexOf(o)); 1057 } 1058 1059 @SuppressWarnings("unchecked") 1060 public final boolean remove(final Object o2) { 1061 final int j = colHeads.indexOf(o2); 1062 if (!matrix.getBoolean(i, j)) 1063 return false; 1064 matrix.setBoolean(false, i, j); 1065 push( 1066 new RelationEvent<R, C>( 1067 RelationEvent.ENTRIES_REMOVED, 1068 null, 1069 null, 1070 Collections.singleton(new Pair<R, C>((R) o, (C) o2)))); 1071 return true; 1072 } 1073 1074 public final boolean removeAll(final Collection<?> c) { 1075 boolean changed = false; 1076 final Set<C> changes = new HashSet<C>(); 1077 for (C col : this) 1078 if (c.contains(col)) 1079 changes.add(col); 1080 for (Object o2 : c) { 1081 final int j = colHeads.indexOf(o2); 1082 if (matrix.getBoolean(i, j)) { 1083 matrix.setBoolean(false, i, j); 1084 changed = true; 1085 push( 1086 new RelationEvent<R, C>( 1087 RelationEvent.ENTRIES_REMOVED, 1088 null, 1089 null, 1090 new HashSet<Pair<R, C>>(Collections2.transform(changes, new Function<C, Pair<R, C>>() { 1091 1092 @SuppressWarnings("unchecked") 1093 public final Pair<R, C> apply(final C col) { 1094 return new Pair<R, C>((R) o, col); 1095 } 1096 })))); 1097 } 1098 } 1099 return changed; 1100 } 1101 1102 public final boolean retainAll(final Collection<?> c) { 1103 boolean changed = false; 1104 final Set<C> changes = new HashSet<C>(); 1105 for (C col : this) 1106 if (!c.contains(col)) 1107 changes.add(col); 1108 for (Object o2 : Collections2.filter(colHeads, Predicates.not(Predicates.in(c)))) { 1109 final int j = colHeads.indexOf(o2); 1110 if (matrix.getBoolean(i, j)) { 1111 matrix.setBoolean(false, i, j); 1112 changed = true; 1113 push( 1114 new RelationEvent<R, C>( 1115 RelationEvent.ENTRIES_REMOVED, 1116 null, 1117 null, 1118 new HashSet<Pair<R, C>>(Collections2.transform(changes, new Function<C, Pair<R, C>>() { 1119 1120 @SuppressWarnings("unchecked") 1121 public final Pair<R, C> apply(final C col) { 1122 return new Pair<R, C>((R) o, col); 1123 } 1124 })))); 1125 } 1126 } 1127 return changed; 1128 } 1129 1130 public final void clear() { 1131 for (int j = 0; j < colHeads.size(); j++) 1132 matrix.setBoolean(false, i, j); 1133 } 1134 1135 public final Iterator<C> iterator() { 1136 return Iterators 1137 .transform(Iterators.filter(ListIterators.integers(0, colHeads.size()), new Predicate<Integer>() { 1138 1139 public final boolean apply(final Integer j) { 1140 return matrix.getBoolean(i, j); 1141 } 1142 }), new Function<Integer, C>() { 1143 1144 public final C apply(final Integer j) { 1145 return colHeads.get(j); 1146 } 1147 }); 1148 } 1149 1150 public final int size() { 1151 int size = 0; 1152 if (i != -1) 1153 for (int j = 0; j < colHeads.size(); j++) 1154 if (matrix.getBoolean(i, j)) 1155 size++; 1156 return size; 1157 } 1158 1159 public final HashSet<C> clone() { 1160 return new HashSet<C>(this); 1161 } 1162 }; 1163 } 1164 1165 public final Set<R> col(final Object o) { 1166 return new AbstractSet<R>() { 1167 1168 private final int j = colHeads.indexOf(o); 1169 1170 @SuppressWarnings("unchecked") 1171 public final boolean add(final R row) { 1172 final int i = rowHeads.indexOf(row); 1173 if (matrix.getBoolean(i, j)) 1174 return false; 1175 matrix.setBoolean(true, i, j); 1176 push( 1177 new RelationEvent<R, C>( 1178 RelationEvent.ENTRIES_ADDED, 1179 null, 1180 null, 1181 Collections.singleton(new Pair<R, C>(row, (C) o)))); 1182 return true; 1183 }; 1184 1185 public final boolean addAll(Collection<? extends R> c) { 1186 boolean changed = false; 1187 @SuppressWarnings("unchecked") 1188 final Set<R> changes = new HashSet<R>(Collections3.<R> difference((Collection<R>) c, this)); 1189 for (R row : c) { 1190 final int i = rowHeads.indexOf(row); 1191 if (!matrix.getBoolean(i, j)) { 1192 matrix.setBoolean(true, i, j); 1193 changed = true; 1194 push( 1195 new RelationEvent<R, C>( 1196 RelationEvent.ENTRIES_ADDED, 1197 null, 1198 null, 1199 new HashSet<Pair<R, C>>(Collections2.transform(changes, new Function<R, Pair<R, C>>() { 1200 1201 @SuppressWarnings("unchecked") 1202 public final Pair<R, C> apply(final R row) { 1203 return new Pair<R, C>(row, (C) o); 1204 } 1205 })))); 1206 } 1207 } 1208 return changed; 1209 } 1210 1211 public final boolean contains(final Object o1) { 1212 return matrix.getBoolean(rowHeads.indexOf(o1), j); 1213 } 1214 1215 @SuppressWarnings("unchecked") 1216 public final boolean remove(final Object o1) { 1217 final int i = rowHeads.indexOf(o1); 1218 if (!matrix.getBoolean(i, j)) 1219 return false; 1220 matrix.setBoolean(false, i, j); 1221 push( 1222 new RelationEvent<R, C>( 1223 RelationEvent.ENTRIES_REMOVED, 1224 null, 1225 null, 1226 Collections.singleton(new Pair<R, C>((R) o1, (C) o)))); 1227 return true; 1228 } 1229 1230 public final boolean removeAll(final Collection<?> c) { 1231 boolean changed = false; 1232 final Set<R> changes = new HashSet<R>(); 1233 for (R row : this) 1234 if (c.contains(row)) 1235 changes.add(row); 1236 for (Object o1 : c) { 1237 final int i = rowHeads.indexOf(o1); 1238 if (matrix.getBoolean(i, j)) { 1239 matrix.setBoolean(false, i, j); 1240 changed = true; 1241 push( 1242 new RelationEvent<R, C>( 1243 RelationEvent.ENTRIES_REMOVED, 1244 null, 1245 null, 1246 new HashSet<Pair<R, C>>(Collections2.transform(changes, new Function<R, Pair<R, C>>() { 1247 1248 @SuppressWarnings("unchecked") 1249 public final Pair<R, C> apply(final R row) { 1250 return new Pair<R, C>(row, (C) o); 1251 } 1252 })))); 1253 } 1254 } 1255 return changed; 1256 } 1257 1258 public final boolean retainAll(final Collection<?> c) { 1259 boolean changed = false; 1260 final Set<R> changes = new HashSet<R>(); 1261 for (R row : this) 1262 if (!c.contains(row)) 1263 changes.add(row); 1264 for (Object o1 : Collections2.filter(rowHeads, Predicates.not(Predicates.in(c)))) { 1265 final int i = rowHeads.indexOf(o1); 1266 if (matrix.getBoolean(i, j)) { 1267 matrix.setBoolean(false, i, j); 1268 changed = true; 1269 push( 1270 new RelationEvent<R, C>( 1271 RelationEvent.ENTRIES_REMOVED, 1272 null, 1273 null, 1274 new HashSet<Pair<R, C>>(Collections2.transform(changes, new Function<R, Pair<R, C>>() { 1275 1276 @SuppressWarnings("unchecked") 1277 public final Pair<R, C> apply(final R row) { 1278 return new Pair<R, C>(row, (C) o); 1279 } 1280 })))); 1281 } 1282 } 1283 return changed; 1284 } 1285 1286 public final void clear() { 1287 for (int i = 0; i < rowHeads.size(); i++) 1288 matrix.setBoolean(false, i, j); 1289 } 1290 1291 public final Iterator<R> iterator() { 1292 return Iterators 1293 .transform(Iterators.filter(ListIterators.integers(0, rowHeads.size()), new Predicate<Integer>() { 1294 1295 public final boolean apply(final Integer i) { 1296 return matrix.getBoolean(i, j); 1297 } 1298 }), new Function<Integer, R>() { 1299 1300 public final R apply(final Integer i) { 1301 return rowHeads.get(i); 1302 } 1303 }); 1304 } 1305 1306 public final int size() { 1307 int size = 0; 1308 if (j != -1) 1309 for (int i = 0; i < rowHeads.size(); i++) 1310 if (matrix.getBoolean(i, j)) 1311 size++; 1312 return size; 1313 } 1314 1315 public final HashSet<R> clone() { 1316 return new HashSet<R>(this); 1317 } 1318 }; 1319 } 1320 1321 public final Set<C> rowAnd(final Collection<?> c) { 1322 if (rowHeads().size() == 0 || colHeads().size() == 0) 1323 return new HashSet<C>(colHeads()); 1324 return colHeads() 1325 .parallelStream() 1326 .filter(col -> c.parallelStream().allMatch(row -> contains(row, col))) 1327 .collect(Collectors.toSet()); 1328// return Sets.filter(colHeads(), new Predicate<C>() { 1329// 1330// private final BooleanMatrix rowAnd = BooleanMatrices.andRow(matrix, rowHeads.indicesOf(c, true)); 1331// 1332// public final boolean apply(final C col) { 1333// return rowAnd.getBoolean(0, colHeads.indexOf(col)); 1334// } 1335// }); 1336 } 1337 1338 public final Set<R> colAnd(final Collection<?> c) { 1339 if (rowHeads().size() == 0 || colHeads().size() == 0) 1340 return new HashSet<R>(rowHeads()); 1341 return rowHeads() 1342 .parallelStream() 1343 .filter(row -> c.parallelStream().allMatch(col -> contains(row, col))) 1344 .collect(Collectors.toSet()); 1345// return Sets.filter(rowHeads(), new Predicate<R>() { 1346// 1347// private final BooleanMatrix colAnd = BooleanMatrices.andCol(matrix, colHeads.indicesOf(c, true)); 1348// 1349// public final boolean apply(final R row) { 1350// return colAnd.getBoolean(rowHeads.indexOf(row), 0); 1351// } 1352// }); 1353 } 1354 1355 public final void _add(final int i, final int j) { 1356 matrix.setBoolean(true, i, j); 1357 push( 1358 new RelationEvent<R, C>( 1359 RelationEvent.ENTRIES_ADDED, 1360 null, 1361 null, 1362 Collections.singleton(new Pair<R, C>(rowHeads().get(i), colHeads().get(j))))); 1363 } 1364 1365 public final void _remove(final int i, final int j) { 1366 matrix.setBoolean(false, i, j); 1367 } 1368 1369 public final void _flip(final int i, final int j) { 1370 matrix.setBoolean(matrix.getBoolean(i, j), i, j); 1371 } 1372 1373 public final boolean _contains(final int i, final int j) { 1374 return matrix.getBoolean(i, j); 1375 } 1376 1377 public final Collection<Integer> _row(final int i) { 1378 return _row(i, SetLists.integers(colHeads.size())); 1379 } 1380 1381 public final Collection<Integer> _col(final int j) { 1382 return _col(j, SetLists.integers(rowHeads.size())); 1383 } 1384 1385 public final Collection<Integer> _row(final int i, final Collection<Integer> js) { 1386 final BitSetFX _row = new BitSetFX(); 1387 for (int j : js) 1388 if (matrix.getBoolean(i, j)) 1389 _row.set(j); 1390 return _row; 1391// return Collections3.newBitSetFX(Collections2.filter(j, new Predicate<Integer>() { 1392// 1393// public final boolean apply(final Integer j) { 1394// return matrix.getBoolean(i, j); 1395// } 1396// })); 1397 } 1398 1399 public final Collection<Integer> _col(final int j, final Collection<Integer> is) { 1400 final BitSetFX _col = new BitSetFX(); 1401 for (int i : is) 1402 if (matrix.getBoolean(i, j)) 1403 _col.set(i); 1404 return _col; 1405// return Collections3.newBitSetFX(Collections2.filter(i, new Predicate<Integer>() { 1406// 1407// public final boolean apply(final Integer i) { 1408// return matrix.getBoolean(i, j); 1409// } 1410// })); 1411 } 1412 1413 public final Collection<Integer> _rowAnd(final int... i) { 1414 if (i.length == 1) 1415 return _row(i[0]); 1416 return _rowAnd(Ints.asList(i)); 1417 } 1418 1419 public final Collection<Integer> _colAnd(final int... j) { 1420 if (j.length == 1) 1421 return _col(j[0]); 1422 return _colAnd(Ints.asList(j)); 1423 } 1424 1425 public synchronized final BitSetFX _rowAnd(final Iterable<Integer> i) { 1426// return _rowAnd(i, SetLists.integers(colHeads.size())); 1427 if (rowHeads().size() == 0 || colHeads().size() == 0) 1428 return Collections3.integers(colHeads.size()); 1429// return SetLists.integers(colHeads.size()); 1430 final BooleanMatrix rowAnd = BooleanMatrices.andRow(matrix, i); 1431 BitSetFX _rowAnd = new BitSetFX(); 1432 for (int j = 0; j < colHeads.size(); j++) 1433 if (rowAnd.getBoolean(0, j)) 1434 _rowAnd.add(j); 1435 return _rowAnd; 1436 } 1437 1438 public synchronized final BitSetFX _colAnd(final Iterable<Integer> j) { 1439// return _colAnd(j, SetLists.integers(rowHeads.size())); 1440 if (rowHeads().size() == 0 || colHeads().size() == 0) 1441 return Collections3.integers(rowHeads().size()); 1442// return SetLists.integers(rowHeads.size()); 1443 final BooleanMatrix colAnd = BooleanMatrices.andCol(matrix, j); 1444 BitSetFX _colAnd = new BitSetFX(); 1445 for (int i = 0; i < rowHeads.size(); i++) 1446 if (colAnd.getBoolean(i, 0)) 1447 _colAnd.add(i); 1448 return _colAnd; 1449 } 1450 1451 public final BitSetFX _rowAnd(final Iterable<Integer> i, final Collection<Integer> j) { 1452 if (rowHeads().size() == 0 || colHeads().size() == 0) 1453 return Collections3.integers(colHeads.size()); 1454// return SetLists.integers(colHeads.size()); 1455 final BooleanMatrix rowAnd = BooleanMatrices.andRow(matrix, i); 1456 return j 1457 .parallelStream() 1458 .filter(_j -> rowAnd.getBoolean(0, _j)) 1459 .collect(BitSetFX::new, BitSetFX::add, BitSetFX::addAll); 1460// return Collections3.newBitSetFX(Collections2.filter(j, new Predicate<Integer>() { 1461// 1462// private final BooleanMatrix rowAnd = BooleanMatrices.andRow(matrix, i); 1463// 1464// public final boolean apply(final Integer _j) { 1465// return rowAnd.getBoolean(0, _j); 1466// } 1467// })); 1468 } 1469 1470 public final BitSetFX _colAnd(final Iterable<Integer> j, final Collection<Integer> i) { 1471 if (rowHeads().size() == 0 || colHeads().size() == 0) 1472 return Collections3.integers(rowHeads().size()); 1473// return SetLists.integers(rowHeads.size()); 1474 final BooleanMatrix colAnd = BooleanMatrices.andCol(matrix, j); 1475 return i 1476 .parallelStream() 1477 .filter(_i -> colAnd.getBoolean(_i, 0)) 1478 .collect(BitSetFX::new, BitSetFX::add, BitSetFX::addAll); 1479// return Collections3.newBitSetFX(Collections2.filter(i, new Predicate<Integer>() { 1480// 1481// private final BooleanMatrix colAnd = BooleanMatrices.andCol(matrix, j); 1482// 1483// public final boolean apply(final Integer _i) { 1484// return colAnd.getBoolean(_i, 0); 1485// } 1486// })); 1487 } 1488 1489 public final void empty() { 1490 matrix = BooleanMatrices.empty(Math.max(rowHeads.size(), 1), Math.max(colHeads.size(), 1)); 1491 push(new RelationEvent<R, C>(RelationEvent.ALL_CHANGED)); 1492 } 1493 1494 public final void fill() { 1495 matrix = BooleanMatrices.full(Math.max(rowHeads.size(), 1), Math.max(colHeads.size(), 1)); 1496 push(new RelationEvent<R, C>(RelationEvent.ALL_CHANGED)); 1497 } 1498 1499 public final boolean isEmpty() { 1500 return !matrix.containsBoolean(true); 1501 } 1502 1503 public final boolean isFull() { 1504 return !matrix.containsBoolean(false); 1505 } 1506 1507 public final int size() { 1508 int size = 0; 1509 for (int i = 0; i < rowHeads.size(); i++) 1510 for (int j = 0; j < colHeads.size(); j++) 1511 if (matrix.getBoolean(i, j)) 1512 size++; 1513 return size; 1514 } 1515 1516 public final Iterator<Pair<R, C>> iterator() { 1517 return Iterators.transform(Iterators.filter(matrix.allCoordinates().iterator(), new Predicate<long[]>() { 1518 1519 public final boolean apply(final long[] ij) { 1520 return matrix.getBoolean(ij) && ij[0] < rowHeads.size() && ij[1] < colHeads.size(); 1521 } 1522 }), new Function<long[], Pair<R, C>>() { 1523 1524 public final Pair<R, C> apply(final long[] ij) { 1525 return new Pair<R, C>(rowHeads.get((int) ij[0]), colHeads.get((int) ij[1])); 1526 } 1527 }); 1528 } 1529 1530 public Relation<R, C> subRelation(final Collection<?> rows, final Collection<?> cols) { 1531 return new AbstractRelation<R, C>( 1532 SetLists.intersection(rowHeads, rows), 1533 SetLists.intersection(colHeads, cols), 1534 false) { 1535 1536 public final boolean contains(final Object o1, final Object o2) { 1537 return rowHeads().contains(o1) && colHeads().contains(o2) && MatrixRelation.this.contains(o1, o2); 1538 } 1539 1540 public final MatrixRelation<R, C> clone() { 1541 return new MatrixRelation<R, C>( 1542 rowHeads(), 1543 colHeads(), 1544 (BooleanMatrix) MatrixRelation.this.matrix 1545 .selectRows(Ret.NEW, MatrixRelation.this.rowHeads().indicesOf(rows, false)) 1546 .selectColumns(Ret.NEW, MatrixRelation.this.colHeads().indicesOf(cols, false)), 1547 false); 1548 } 1549 }; 1550 } 1551 1552 public final void pushAllChangedEvent() { 1553 synchronized (eventHandlers) { 1554 push(RelationEvent.ALL_CHANGED, new RelationEvent<R, C>(RelationEvent.ALL_CHANGED)); 1555 } 1556 } 1557 1558 protected final void push(final RelationEvent<R, C> event) { 1559 synchronized (eventHandlers) { 1560 RelationEvent.Type type = event.getType(); 1561 push(type, event); 1562 while ((type = type.getSuperType()) != null) 1563 push(type, event); 1564 } 1565 } 1566 1567 private final void push(final RelationEvent.Type type, final RelationEvent<R, C> event) { 1568 synchronized (eventHandlers) { 1569 if (eventHandlers.containsKey(type)) 1570 for (RelationEventHandler<R, C> eventHandler : eventHandlers.get(type)) 1571 eventHandler.handle(event); 1572 } 1573 } 1574 1575 public final void addEventHandler(final RelationEventHandler<R, C> eventHandler, final RelationEvent.Type... types) { 1576 synchronized (eventHandlers) { 1577 for (RelationEvent.Type type : types) { 1578 if (!eventHandlers.containsKey(type)) 1579 eventHandlers.put(type, new CopyOnWriteArrayList<>()); 1580 eventHandlers.get(type).add(eventHandler); 1581 } 1582 } 1583 } 1584 1585 public final void removeEventHandler(final RelationEvent.Type type, final RelationEventHandler<R, C> eventHandler) { 1586 synchronized (eventHandlers) { 1587 eventHandlers.remove(type, eventHandler); 1588 } 1589 } 1590 1591 protected final boolean hasEventHandlers(final RelationEvent.Type type) { 1592 synchronized (eventHandlers) { 1593 RelationEvent.Type type_ = type; 1594 if (!eventHandlers.get(type_).isEmpty()) 1595 return true; 1596 while ((type_ = type_.getSuperType()) != null) 1597 if (!eventHandlers.get(type_).isEmpty()) 1598 return true; 1599 return false; 1600 } 1601 } 1602 1603 public final BooleanMatrix matrix() { 1604 return matrix; 1605 } 1606 1607 public final void setMatrix(final BooleanMatrix matrix) { 1608 if (matrix.getSize(0) != rowHeads.size() || matrix.getSize(1) != colHeads.size()) 1609 throw new IllegalArgumentException(); 1610 this.matrix = matrix; 1611 pushAllChangedEvent(); 1612 } 1613 1614 @Deprecated 1615 public final void rewriteMatrix() { 1616 final BooleanMatrix copy = BooleanMatrices.clone(matrix); 1617 setMatrix(BooleanMatrices.empty(matrix.getRowCount(), matrix.getColumnCount())); 1618 matrix.or(Ret.ORIG, copy); 1619 } 1620 1621 public final void setContent(final SetList<R> rows, final SetList<C> cols, final BooleanMatrix matrix) { 1622 rowHeads.addAll(rows); 1623 if (!homogen) 1624 colHeads.addAll(cols); 1625 setMatrix(matrix); 1626 } 1627 1628 public void dispose() { 1629 rowHeads.clear(); 1630 colHeads.clear(); 1631 } 1632 1633 public MatrixRelation<R, C> clone() { 1634 return new MatrixRelation<R, C>(rowHeads, colHeads, BooleanMatrices.clone(matrix), homogen); 1635 } 1636 1637 public int hashCode() { 1638 return 7 * rowHeads.hashCode() + 11 * colHeads.hashCode() + 13 * matrix.hashCode(); 1639 } 1640 1641 public final boolean[][] toArray() { 1642 return matrix.toBooleanArray(); 1643 } 1644 1645 public Relation<R, R> subRelation(final Collection<?> c) { 1646 return new AbstractRelation<R, R>( 1647 SetLists.<R> intersection(rowHeads, c), 1648 SetLists.<R> intersection(rowHeads, c), 1649 true) { 1650 1651 public boolean contains(Object o1, Object o2) { 1652 return rowHeads().contains(o1) && rowHeads().contains(o2) && MatrixRelation.this.contains(o1, o2); 1653 } 1654 1655 public MatrixRelation<R, R> clone() { 1656 return new MatrixRelation<R, R>( 1657 rowHeads(), 1658 rowHeads(), 1659 (BooleanMatrix) MatrixRelation.this.matrix 1660 .selectRows(Ret.NEW, MatrixRelation.this.rowHeads().indicesOf(c, false)) 1661 .selectColumns(Ret.NEW, MatrixRelation.this.colHeads().indicesOf(c, false)), 1662 true); 1663 } 1664 }; 1665 } 1666 1667 public MatrixRelation<R, R> neighborhood() { 1668 checkHomogen(); 1669 return new MatrixRelation<R, R>( 1670 rowHeads(), 1671 rowHeads(), 1672 BooleanMatrices.transitiveReduction(BooleanMatrices.reflexiveReduction(matrix)), 1673 true); 1674 } 1675 1676 public MatrixRelation<R, R> order() { 1677 checkHomogen(); 1678 return new MatrixRelation<R, R>( 1679 rowHeads(), 1680 rowHeads(), 1681 BooleanMatrices.reflexiveClosure(BooleanMatrices.transitiveClosure(matrix)), 1682 true); 1683 } 1684 1685 public final boolean isReflexive() { 1686 return matrix.ge(Ret.NEW, BooleanMatrices.identity(size())).equals(BooleanMatrices.full(size())); 1687 } 1688 1689 public final boolean isIrreflexive() { 1690 return matrix.and(Ret.NEW, BooleanMatrices.identity(size())).equals(BooleanMatrices.empty(size())); 1691 } 1692 1693 public final boolean isSymmetric() { 1694 return matrix.equals(matrix.transpose(Ret.NEW)); 1695 } 1696 1697 public final boolean isAsymmetric() { 1698 return matrix.and(Ret.NEW, matrix.transpose(Ret.NEW)).equals(BooleanMatrices.empty(size())); 1699 } 1700 1701 public final boolean isConnex() { 1702 return matrix.or(Ret.NEW, matrix.transpose(Ret.NEW)).equals(BooleanMatrices.full(size())); 1703 } 1704 1705 public final boolean isAntisymmetric() { 1706 return matrix 1707 .and(Ret.NEW, matrix.transpose(Ret.NEW)) 1708 .le(Ret.NEW, BooleanMatrices.identity(size())) 1709 .equals(BooleanMatrices.full(size())); 1710 } 1711 1712 public final boolean isQuasiconnex() { 1713 return matrix 1714 .or(Ret.NEW, matrix.transpose(Ret.NEW)) 1715 .ge(Ret.NEW, BooleanMatrices.negativeIdentity(size())) 1716 .equals(BooleanMatrices.full(size())); 1717 } 1718 1719 public final boolean isAlternative() { 1720 return isAntisymmetric() && isQuasiconnex(); 1721 } 1722 1723 public final boolean isTransitive() { 1724 return matrix 1725 .mtimes(Ret.NEW, false, matrix) 1726 .toBooleanMatrix() 1727 .le(Ret.NEW, matrix) 1728 .equals(BooleanMatrices.full(size())); 1729 } 1730 1731 public final boolean isNegativeTransitive() { 1732 final BooleanMatrix2D not = (BooleanMatrix2D) matrix.not(Ret.NEW); 1733 return not.mtimes(Ret.NEW, false, not).toBooleanMatrix().le(Ret.NEW, not).equals(BooleanMatrices.full(size())); 1734 } 1735 1736 public final boolean isAtransitive() { 1737 return matrix 1738 .mtimes(Ret.NEW, false, matrix) 1739 .toBooleanMatrix() 1740 .and(Ret.NEW, matrix) 1741 .equals(BooleanMatrices.empty(size())); 1742 } 1743 1744 public final boolean isNegativAtransitive() { 1745 final BooleanMatrix2D not = (BooleanMatrix2D) matrix.not(Ret.NEW); 1746 return not.mtimes(Ret.NEW, false, not).toBooleanMatrix().and(Ret.NEW, not).equals(BooleanMatrices.empty(size())); 1747 } 1748 1749 public final boolean isNCyclic(final int n) { 1750 return BooleanMatrices 1751 .power(matrix(), n) 1752 .le(Ret.NEW, matrix.transpose(Ret.NEW)) 1753 .equals(BooleanMatrices.full(size())); 1754 } 1755 1756 public final boolean isCyclic() { 1757 return BooleanMatrices 1758 .transitiveClosure(matrix()) 1759 .le(Ret.NEW, matrix.transpose(Ret.NEW)) 1760 .equals(BooleanMatrices.full(size())); 1761 } 1762 1763 public final boolean isNAcyclic(final int n) { 1764 return BooleanMatrices 1765 .power(matrix(), n) 1766 .le(Ret.NEW, matrix.transpose(Ret.NEW).not(Ret.NEW)) 1767 .equals(BooleanMatrices.full(size())); 1768 } 1769 1770 public final boolean isAcyclic() { 1771 return BooleanMatrices 1772 .transitiveClosure(matrix()) 1773 .le(Ret.NEW, matrix.transpose(Ret.NEW).not(Ret.NEW)) 1774 .equals(BooleanMatrices.full(size())); 1775 } 1776 1777 public final boolean isNTransitive(final int n) { 1778 return BooleanMatrices.power(matrix(), n).le(Ret.NEW, matrix).equals(BooleanMatrices.full(size())); 1779 } 1780 1781 public final boolean isNAtransitive(final int n) { 1782 return BooleanMatrices.power(matrix(), n).le(Ret.NEW, matrix.not(Ret.NEW)).equals(BooleanMatrices.full(size())); 1783 } 1784 1785 public final boolean isLeftComparative() { 1786 return matrix 1787 .transpose(Ret.NEW) 1788 .mtimes(Ret.NEW, false, matrix) 1789 .toBooleanMatrix() 1790 .le(Ret.NEW, matrix) 1791 .equals(BooleanMatrices.full(size())); 1792 } 1793 1794 public final boolean isRightComparative() { 1795 return matrix 1796 .mtimes(Ret.NEW, false, matrix.transpose(Ret.NEW)) 1797 .toBooleanMatrix() 1798 .le(Ret.NEW, matrix) 1799 .equals(BooleanMatrices.full(size())); 1800 } 1801}