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 - 2019 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.selectRows(Ret.LINK, _r.rowHeads.indicesOf(rowHeads, false)).selectColumns( 881 Ret.LINK, 882 _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.selectRows(Ret.LINK, i).selectColumns(Ret.LINK, j).and( 956 Ret.ORIG, 957 _r.matrix.selectRows(Ret.LINK, _r.rowHeads.indicesOf(rowHeads, false)).selectColumns( 958 Ret.LINK, 959 _r.colHeads.indicesOf(colHeads, false))); 960 push(new RelationEvent<R, C>(RelationEvent.ALL_CHANGED, null, null, null)); 961 changed = true; 962 } else { 963 for (C col : colHeads) { 964 final Set<R> column = col(col); 965 if (r.colHeads().contains(col)) 966 changed |= column.retainAll(r.col(col)); 967 else { 968 changed |= !column.isEmpty(); 969 column.clear(); 970 } 971 } 972 } 973 return changed; 974 } 975 976 public final boolean contains(final Object o1, final Object o2) { 977 final int i = rowHeads.indexOf(o1); 978 if (i == -1) 979 return false; 980 final int j = colHeads.indexOf(o2); 981 return j != -1 && matrix.getBoolean(i, j); 982 } 983 984 public final boolean containsAll(final Relation<?, ?> r) { 985 if (rowHeads.containsAll(r.rowHeads()) && colHeads.containsAll(r.colHeads())) { 986 if (r instanceof MatrixRelation) { 987 final MatrixRelation<?, ?> _r = (MatrixRelation<?, ?>) r; 988 return matrix 989 .selectRows(Ret.LINK, rowHeads.indicesOf(_r.rowHeads, true)) 990 .selectColumns(Ret.LINK, colHeads.indicesOf(_r.colHeads, true)) 991 .equals(_r.matrix); 992 } else { 993 final Iterator<?> iterator = r.iterator(); 994 Pair<?, ?> next; 995 while (iterator.hasNext()) { 996 next = (Pair<?, ?>) iterator.next(); 997 if (!contains(next.x(), next.y())) 998 return false; 999 } 1000 return true; 1001 } 1002 } 1003 return false; 1004 } 1005 1006 public final Set<C> row(final Object o) { 1007 return new AbstractSet<C>() { 1008 1009 private final int i = rowHeads.indexOf(o); 1010 1011 @SuppressWarnings("unchecked") 1012 public final boolean add(final C col) { 1013 final int j = colHeads.indexOf(col); 1014 if (matrix.getBoolean(i, j)) 1015 return false; 1016 matrix.setBoolean(true, i, j); 1017 push( 1018 new RelationEvent<R, C>( 1019 RelationEvent.ENTRIES_ADDED, 1020 null, 1021 null, 1022 Collections.singleton(new Pair<R, C>((R) o, col)))); 1023 return true; 1024 } 1025 1026 public final boolean addAll(final Collection<? extends C> c) { 1027 boolean changed = false; 1028 @SuppressWarnings("unchecked") 1029 final Set<C> changes = new HashSet<C>(Collections3.<C> difference((Collection<C>) c, this)); 1030 for (C col : c) { 1031 final int j = colHeads.indexOf(col); 1032 if (!matrix.getBoolean(i, j)) { 1033 matrix.setBoolean(true, i, j); 1034 changed = true; 1035 push( 1036 new RelationEvent<R, C>( 1037 RelationEvent.ENTRIES_ADDED, 1038 null, 1039 null, 1040 new HashSet<Pair<R, C>>(Collections2.transform(changes, new Function<C, Pair<R, C>>() { 1041 1042 @SuppressWarnings("unchecked") 1043 public final Pair<R, C> apply(final C col) { 1044 return new Pair<R, C>((R) o, col); 1045 } 1046 })))); 1047 } 1048 } 1049 return changed; 1050 } 1051 1052 public final boolean contains(final Object o) { 1053 return matrix.getBoolean(i, colHeads.indexOf(o)); 1054 } 1055 1056 @SuppressWarnings("unchecked") 1057 public final boolean remove(final Object o2) { 1058 final int j = colHeads.indexOf(o2); 1059 if (!matrix.getBoolean(i, j)) 1060 return false; 1061 matrix.setBoolean(false, i, j); 1062 push( 1063 new RelationEvent<R, C>( 1064 RelationEvent.ENTRIES_REMOVED, 1065 null, 1066 null, 1067 Collections.singleton(new Pair<R, C>((R) o, (C) o2)))); 1068 return true; 1069 } 1070 1071 public final boolean removeAll(final Collection<?> c) { 1072 boolean changed = false; 1073 final Set<C> changes = new HashSet<C>(); 1074 for (C col : this) 1075 if (c.contains(col)) 1076 changes.add(col); 1077 for (Object o2 : c) { 1078 final int j = colHeads.indexOf(o2); 1079 if (matrix.getBoolean(i, j)) { 1080 matrix.setBoolean(false, i, j); 1081 changed = true; 1082 push( 1083 new RelationEvent<R, C>( 1084 RelationEvent.ENTRIES_REMOVED, 1085 null, 1086 null, 1087 new HashSet<Pair<R, C>>(Collections2.transform(changes, new Function<C, Pair<R, C>>() { 1088 1089 @SuppressWarnings("unchecked") 1090 public final Pair<R, C> apply(final C col) { 1091 return new Pair<R, C>((R) o, col); 1092 } 1093 })))); 1094 } 1095 } 1096 return changed; 1097 } 1098 1099 public final boolean retainAll(final Collection<?> c) { 1100 boolean changed = false; 1101 final Set<C> changes = new HashSet<C>(); 1102 for (C col : this) 1103 if (!c.contains(col)) 1104 changes.add(col); 1105 for (Object o2 : Collections2.filter(colHeads, Predicates.not(Predicates.in(c)))) { 1106 final int j = colHeads.indexOf(o2); 1107 if (matrix.getBoolean(i, j)) { 1108 matrix.setBoolean(false, i, j); 1109 changed = true; 1110 push( 1111 new RelationEvent<R, C>( 1112 RelationEvent.ENTRIES_REMOVED, 1113 null, 1114 null, 1115 new HashSet<Pair<R, C>>(Collections2.transform(changes, new Function<C, Pair<R, C>>() { 1116 1117 @SuppressWarnings("unchecked") 1118 public final Pair<R, C> apply(final C col) { 1119 return new Pair<R, C>((R) o, col); 1120 } 1121 })))); 1122 } 1123 } 1124 return changed; 1125 } 1126 1127 public final void clear() { 1128 for (int j = 0; j < colHeads.size(); j++) 1129 matrix.setBoolean(false, i, j); 1130 } 1131 1132 public final Iterator<C> iterator() { 1133 return Iterators 1134 .transform(Iterators.filter(ListIterators.integers(0, colHeads.size()), new Predicate<Integer>() { 1135 1136 public final boolean apply(final Integer j) { 1137 return matrix.getBoolean(i, j); 1138 } 1139 }), new Function<Integer, C>() { 1140 1141 public final C apply(final Integer j) { 1142 return colHeads.get(j); 1143 } 1144 }); 1145 } 1146 1147 public final int size() { 1148 int size = 0; 1149 if (i != -1) 1150 for (int j = 0; j < colHeads.size(); j++) 1151 if (matrix.getBoolean(i, j)) 1152 size++; 1153 return size; 1154 } 1155 1156 public final HashSet<C> clone() { 1157 return new HashSet<C>(this); 1158 } 1159 }; 1160 } 1161 1162 public final Set<R> col(final Object o) { 1163 return new AbstractSet<R>() { 1164 1165 private final int j = colHeads.indexOf(o); 1166 1167 @SuppressWarnings("unchecked") 1168 public final boolean add(final R row) { 1169 final int i = rowHeads.indexOf(row); 1170 if (matrix.getBoolean(i, j)) 1171 return false; 1172 matrix.setBoolean(true, i, j); 1173 push( 1174 new RelationEvent<R, C>( 1175 RelationEvent.ENTRIES_ADDED, 1176 null, 1177 null, 1178 Collections.singleton(new Pair<R, C>(row, (C) o)))); 1179 return true; 1180 }; 1181 1182 public final boolean addAll(Collection<? extends R> c) { 1183 boolean changed = false; 1184 @SuppressWarnings("unchecked") 1185 final Set<R> changes = new HashSet<R>(Collections3.<R> difference((Collection<R>) c, this)); 1186 for (R row : c) { 1187 final int i = rowHeads.indexOf(row); 1188 if (!matrix.getBoolean(i, j)) { 1189 matrix.setBoolean(true, i, j); 1190 changed = true; 1191 push( 1192 new RelationEvent<R, C>( 1193 RelationEvent.ENTRIES_ADDED, 1194 null, 1195 null, 1196 new HashSet<Pair<R, C>>(Collections2.transform(changes, new Function<R, Pair<R, C>>() { 1197 1198 @SuppressWarnings("unchecked") 1199 public final Pair<R, C> apply(final R row) { 1200 return new Pair<R, C>(row, (C) o); 1201 } 1202 })))); 1203 } 1204 } 1205 return changed; 1206 } 1207 1208 public final boolean contains(final Object o1) { 1209 return matrix.getBoolean(rowHeads.indexOf(o1), j); 1210 } 1211 1212 @SuppressWarnings("unchecked") 1213 public final boolean remove(final Object o1) { 1214 final int i = rowHeads.indexOf(o1); 1215 if (!matrix.getBoolean(i, j)) 1216 return false; 1217 matrix.setBoolean(false, i, j); 1218 push( 1219 new RelationEvent<R, C>( 1220 RelationEvent.ENTRIES_REMOVED, 1221 null, 1222 null, 1223 Collections.singleton(new Pair<R, C>((R) o1, (C) o)))); 1224 return true; 1225 } 1226 1227 public final boolean removeAll(final Collection<?> c) { 1228 boolean changed = false; 1229 final Set<R> changes = new HashSet<R>(); 1230 for (R row : this) 1231 if (c.contains(row)) 1232 changes.add(row); 1233 for (Object o1 : c) { 1234 final int i = rowHeads.indexOf(o1); 1235 if (matrix.getBoolean(i, j)) { 1236 matrix.setBoolean(false, i, j); 1237 changed = true; 1238 push( 1239 new RelationEvent<R, C>( 1240 RelationEvent.ENTRIES_REMOVED, 1241 null, 1242 null, 1243 new HashSet<Pair<R, C>>(Collections2.transform(changes, new Function<R, Pair<R, C>>() { 1244 1245 @SuppressWarnings("unchecked") 1246 public final Pair<R, C> apply(final R row) { 1247 return new Pair<R, C>(row, (C) o); 1248 } 1249 })))); 1250 } 1251 } 1252 return changed; 1253 } 1254 1255 public final boolean retainAll(final Collection<?> c) { 1256 boolean changed = false; 1257 final Set<R> changes = new HashSet<R>(); 1258 for (R row : this) 1259 if (!c.contains(row)) 1260 changes.add(row); 1261 for (Object o1 : Collections2.filter(rowHeads, Predicates.not(Predicates.in(c)))) { 1262 final int i = rowHeads.indexOf(o1); 1263 if (matrix.getBoolean(i, j)) { 1264 matrix.setBoolean(false, i, j); 1265 changed = true; 1266 push( 1267 new RelationEvent<R, C>( 1268 RelationEvent.ENTRIES_REMOVED, 1269 null, 1270 null, 1271 new HashSet<Pair<R, C>>(Collections2.transform(changes, new Function<R, Pair<R, C>>() { 1272 1273 @SuppressWarnings("unchecked") 1274 public final Pair<R, C> apply(final R row) { 1275 return new Pair<R, C>(row, (C) o); 1276 } 1277 })))); 1278 } 1279 } 1280 return changed; 1281 } 1282 1283 public final void clear() { 1284 for (int i = 0; i < rowHeads.size(); i++) 1285 matrix.setBoolean(false, i, j); 1286 } 1287 1288 public final Iterator<R> iterator() { 1289 return Iterators 1290 .transform(Iterators.filter(ListIterators.integers(0, rowHeads.size()), new Predicate<Integer>() { 1291 1292 public final boolean apply(final Integer i) { 1293 return matrix.getBoolean(i, j); 1294 } 1295 }), new Function<Integer, R>() { 1296 1297 public final R apply(final Integer i) { 1298 return rowHeads.get(i); 1299 } 1300 }); 1301 } 1302 1303 public final int size() { 1304 int size = 0; 1305 if (j != -1) 1306 for (int i = 0; i < rowHeads.size(); i++) 1307 if (matrix.getBoolean(i, j)) 1308 size++; 1309 return size; 1310 } 1311 1312 public final HashSet<R> clone() { 1313 return new HashSet<R>(this); 1314 } 1315 }; 1316 } 1317 1318 public final Set<C> rowAnd(final Collection<?> c) { 1319 if (rowHeads().size() == 0 || colHeads().size() == 0) 1320 return new HashSet<C>(colHeads()); 1321 return colHeads().parallelStream().filter(col -> c.parallelStream().allMatch(row -> contains(row, col))).collect( 1322 Collectors.toSet()); 1323// return Sets.filter(colHeads(), new Predicate<C>() { 1324// 1325// private final BooleanMatrix rowAnd = BooleanMatrices.andRow(matrix, rowHeads.indicesOf(c, true)); 1326// 1327// public final boolean apply(final C col) { 1328// return rowAnd.getBoolean(0, colHeads.indexOf(col)); 1329// } 1330// }); 1331 } 1332 1333 public final Set<R> colAnd(final Collection<?> c) { 1334 if (rowHeads().size() == 0 || colHeads().size() == 0) 1335 return new HashSet<R>(rowHeads()); 1336 return rowHeads().parallelStream().filter(row -> c.parallelStream().allMatch(col -> contains(row, col))).collect( 1337 Collectors.toSet()); 1338// return Sets.filter(rowHeads(), new Predicate<R>() { 1339// 1340// private final BooleanMatrix colAnd = BooleanMatrices.andCol(matrix, colHeads.indicesOf(c, true)); 1341// 1342// public final boolean apply(final R row) { 1343// return colAnd.getBoolean(rowHeads.indexOf(row), 0); 1344// } 1345// }); 1346 } 1347 1348 public final void _add(final int i, final int j) { 1349 matrix.setBoolean(true, i, j); 1350 push( 1351 new RelationEvent<R, C>( 1352 RelationEvent.ENTRIES_ADDED, 1353 null, 1354 null, 1355 Collections.singleton(new Pair<R, C>(rowHeads().get(i), colHeads().get(j))))); 1356 } 1357 1358 public final void _remove(final int i, final int j) { 1359 matrix.setBoolean(false, i, j); 1360 } 1361 1362 public final void _flip(final int i, final int j) { 1363 matrix.setBoolean(matrix.getBoolean(i, j), i, j); 1364 } 1365 1366 public final boolean _contains(final int i, final int j) { 1367 return matrix.getBoolean(i, j); 1368 } 1369 1370 public final Collection<Integer> _row(final int i) { 1371 return _row(i, SetLists.integers(colHeads.size())); 1372 } 1373 1374 public final Collection<Integer> _col(final int j) { 1375 return _col(j, SetLists.integers(rowHeads.size())); 1376 } 1377 1378 public final Collection<Integer> _row(final int i, final Collection<Integer> js) { 1379 final BitSetFX _row = new BitSetFX(); 1380 for (int j : js) 1381 if (matrix.getBoolean(i, j)) 1382 _row.set(j); 1383 return _row; 1384// return Collections3.newBitSetFX(Collections2.filter(j, new Predicate<Integer>() { 1385// 1386// public final boolean apply(final Integer j) { 1387// return matrix.getBoolean(i, j); 1388// } 1389// })); 1390 } 1391 1392 public final Collection<Integer> _col(final int j, final Collection<Integer> is) { 1393 final BitSetFX _col = new BitSetFX(); 1394 for (int i : is) 1395 if (matrix.getBoolean(i, j)) 1396 _col.set(i); 1397 return _col; 1398// return Collections3.newBitSetFX(Collections2.filter(i, new Predicate<Integer>() { 1399// 1400// public final boolean apply(final Integer i) { 1401// return matrix.getBoolean(i, j); 1402// } 1403// })); 1404 } 1405 1406 public final Collection<Integer> _rowAnd(final int... i) { 1407 if (i.length == 1) 1408 return _row(i[0]); 1409 return _rowAnd(Ints.asList(i)); 1410 } 1411 1412 public final Collection<Integer> _colAnd(final int... j) { 1413 if (j.length == 1) 1414 return _col(j[0]); 1415 return _colAnd(Ints.asList(j)); 1416 } 1417 1418 public synchronized final BitSetFX _rowAnd(final Iterable<Integer> i) { 1419// return _rowAnd(i, SetLists.integers(colHeads.size())); 1420 if (rowHeads().size() == 0 || colHeads().size() == 0) 1421 return Collections3.integers(colHeads.size()); 1422// return SetLists.integers(colHeads.size()); 1423 final BooleanMatrix rowAnd = BooleanMatrices.andRow(matrix, i); 1424 BitSetFX _rowAnd = new BitSetFX(); 1425 for (int j = 0; j < colHeads.size(); j++) 1426 if (rowAnd.getBoolean(0, j)) 1427 _rowAnd.add(j); 1428 return _rowAnd; 1429 } 1430 1431 public synchronized final BitSetFX _colAnd(final Iterable<Integer> j) { 1432// return _colAnd(j, SetLists.integers(rowHeads.size())); 1433 if (rowHeads().size() == 0 || colHeads().size() == 0) 1434 return Collections3.integers(rowHeads().size()); 1435// return SetLists.integers(rowHeads.size()); 1436 final BooleanMatrix colAnd = BooleanMatrices.andCol(matrix, j); 1437 BitSetFX _colAnd = new BitSetFX(); 1438 for (int i = 0; i < rowHeads.size(); i++) 1439 if (colAnd.getBoolean(i, 0)) 1440 _colAnd.add(i); 1441 return _colAnd; 1442 } 1443 1444 public final BitSetFX _rowAnd(final Iterable<Integer> i, final Collection<Integer> j) { 1445 if (rowHeads().size() == 0 || colHeads().size() == 0) 1446 return Collections3.integers(colHeads.size()); 1447// return SetLists.integers(colHeads.size()); 1448 final BooleanMatrix rowAnd = BooleanMatrices.andRow(matrix, i); 1449 return j.parallelStream().filter(_j -> rowAnd.getBoolean(0, _j)).collect( 1450 BitSetFX::new, 1451 BitSetFX::add, 1452 BitSetFX::addAll); 1453// return Collections3.newBitSetFX(Collections2.filter(j, new Predicate<Integer>() { 1454// 1455// private final BooleanMatrix rowAnd = BooleanMatrices.andRow(matrix, i); 1456// 1457// public final boolean apply(final Integer _j) { 1458// return rowAnd.getBoolean(0, _j); 1459// } 1460// })); 1461 } 1462 1463 public final BitSetFX _colAnd(final Iterable<Integer> j, final Collection<Integer> i) { 1464 if (rowHeads().size() == 0 || colHeads().size() == 0) 1465 return Collections3.integers(rowHeads().size()); 1466// return SetLists.integers(rowHeads.size()); 1467 final BooleanMatrix colAnd = BooleanMatrices.andCol(matrix, j); 1468 return i.parallelStream().filter(_i -> colAnd.getBoolean(_i, 0)).collect( 1469 BitSetFX::new, 1470 BitSetFX::add, 1471 BitSetFX::addAll); 1472// return Collections3.newBitSetFX(Collections2.filter(i, new Predicate<Integer>() { 1473// 1474// private final BooleanMatrix colAnd = BooleanMatrices.andCol(matrix, j); 1475// 1476// public final boolean apply(final Integer _i) { 1477// return colAnd.getBoolean(_i, 0); 1478// } 1479// })); 1480 } 1481 1482 public final void empty() { 1483 matrix = BooleanMatrices.empty(Math.max(rowHeads.size(), 1), Math.max(colHeads.size(), 1)); 1484 push(new RelationEvent<R, C>(RelationEvent.ALL_CHANGED)); 1485 } 1486 1487 public final void fill() { 1488 matrix = BooleanMatrices.full(Math.max(rowHeads.size(), 1), Math.max(colHeads.size(), 1)); 1489 push(new RelationEvent<R, C>(RelationEvent.ALL_CHANGED)); 1490 } 1491 1492 public final boolean isEmpty() { 1493 return !matrix.containsBoolean(true); 1494 } 1495 1496 public final boolean isFull() { 1497 return !matrix.containsBoolean(false); 1498 } 1499 1500 public final int size() { 1501 int size = 0; 1502 for (int i = 0; i < rowHeads.size(); i++) 1503 for (int j = 0; j < colHeads.size(); j++) 1504 if (matrix.getBoolean(i, j)) 1505 size++; 1506 return size; 1507 } 1508 1509 public final Iterator<Pair<R, C>> iterator() { 1510 return Iterators.transform(Iterators.filter(matrix.allCoordinates().iterator(), new Predicate<long[]>() { 1511 1512 public final boolean apply(final long[] ij) { 1513 return matrix.getBoolean(ij) && ij[0] < rowHeads.size() && ij[1] < colHeads.size(); 1514 } 1515 }), new Function<long[], Pair<R, C>>() { 1516 1517 public final Pair<R, C> apply(final long[] ij) { 1518 return new Pair<R, C>(rowHeads.get((int) ij[0]), colHeads.get((int) ij[1])); 1519 } 1520 }); 1521 } 1522 1523 public Relation<R, C> subRelation(final Collection<?> rows, final Collection<?> cols) { 1524 return new AbstractRelation<R, C>( 1525 SetLists.intersection(rowHeads, rows), 1526 SetLists.intersection(colHeads, cols), 1527 false) { 1528 1529 public final boolean contains(final Object o1, final Object o2) { 1530 return rowHeads().contains(o1) && colHeads().contains(o2) && MatrixRelation.this.contains(o1, o2); 1531 } 1532 1533 public final MatrixRelation<R, C> clone() { 1534 return new MatrixRelation<R, C>( 1535 rowHeads(), 1536 colHeads(), 1537 (BooleanMatrix) MatrixRelation.this.matrix 1538 .selectRows(Ret.NEW, MatrixRelation.this.rowHeads().indicesOf(rows, false)) 1539 .selectColumns(Ret.NEW, MatrixRelation.this.colHeads().indicesOf(cols, false)), 1540 false); 1541 } 1542 }; 1543 } 1544 1545 public final void pushAllChangedEvent() { 1546 synchronized (eventHandlers) { 1547 push(RelationEvent.ALL_CHANGED, new RelationEvent<R, C>(RelationEvent.ALL_CHANGED)); 1548 } 1549 } 1550 1551 protected final void push(final RelationEvent<R, C> event) { 1552 synchronized (eventHandlers) { 1553 RelationEvent.Type type = event.getType(); 1554 push(type, event); 1555 while ((type = type.getSuperType()) != null) 1556 push(type, event); 1557 } 1558 } 1559 1560 private final void push(final RelationEvent.Type type, final RelationEvent<R, C> event) { 1561 synchronized (eventHandlers) { 1562 if (eventHandlers.containsKey(type)) 1563 for (RelationEventHandler<R, C> eventHandler : eventHandlers.get(type)) 1564 eventHandler.handle(event); 1565 } 1566 } 1567 1568 public final void addEventHandler(final RelationEventHandler<R, C> eventHandler, final RelationEvent.Type... types) { 1569 synchronized (eventHandlers) { 1570 for (RelationEvent.Type type : types) { 1571 if (!eventHandlers.containsKey(type)) 1572 eventHandlers.put(type, new CopyOnWriteArrayList<>()); 1573 eventHandlers.get(type).add(eventHandler); 1574 } 1575 } 1576 } 1577 1578 public final void removeEventHandler(final RelationEvent.Type type, final RelationEventHandler<R, C> eventHandler) { 1579 synchronized (eventHandlers) { 1580 eventHandlers.remove(type, eventHandler); 1581 } 1582 } 1583 1584 protected final boolean hasEventHandlers(final RelationEvent.Type type) { 1585 synchronized (eventHandlers) { 1586 RelationEvent.Type type_ = type; 1587 if (!eventHandlers.get(type_).isEmpty()) 1588 return true; 1589 while ((type_ = type_.getSuperType()) != null) 1590 if (!eventHandlers.get(type_).isEmpty()) 1591 return true; 1592 return false; 1593 } 1594 } 1595 1596 public final BooleanMatrix matrix() { 1597 return matrix; 1598 } 1599 1600 public final void setMatrix(final BooleanMatrix matrix) { 1601 if (matrix.getSize(0) != rowHeads.size() || matrix.getSize(1) != colHeads.size()) 1602 throw new IllegalArgumentException(); 1603 this.matrix = matrix; 1604 pushAllChangedEvent(); 1605 } 1606 1607 public final void setContent(final SetList<R> rows, final SetList<C> cols, final BooleanMatrix matrix) { 1608 rowHeads.addAll(rows); 1609 if (!homogen) 1610 colHeads.addAll(cols); 1611 setMatrix(matrix); 1612 } 1613 1614 public void dispose() { 1615 rowHeads.clear(); 1616 colHeads.clear(); 1617 } 1618 1619 public MatrixRelation<R, C> clone() { 1620 return new MatrixRelation<R, C>(rowHeads, colHeads, BooleanMatrices.clone(matrix), homogen); 1621 } 1622 1623 public int hashCode() { 1624 return 7 * rowHeads.hashCode() + 11 * colHeads.hashCode() + 13 * matrix.hashCode(); 1625 } 1626 1627 public final boolean[][] toArray() { 1628 return matrix.toBooleanArray(); 1629 } 1630 1631 public Relation<R, R> subRelation(final Collection<?> c) { 1632 return new AbstractRelation<R, R>( 1633 SetLists.<R> intersection(rowHeads, c), 1634 SetLists.<R> intersection(rowHeads, c), 1635 true) { 1636 1637 public boolean contains(Object o1, Object o2) { 1638 return rowHeads().contains(o1) && rowHeads().contains(o2) && MatrixRelation.this.contains(o1, o2); 1639 } 1640 1641 public MatrixRelation<R, R> clone() { 1642 return new MatrixRelation<R, R>( 1643 rowHeads(), 1644 rowHeads(), 1645 (BooleanMatrix) MatrixRelation.this.matrix 1646 .selectRows(Ret.NEW, MatrixRelation.this.rowHeads().indicesOf(c, false)) 1647 .selectColumns(Ret.NEW, MatrixRelation.this.colHeads().indicesOf(c, false)), 1648 true); 1649 } 1650 }; 1651 } 1652 1653 public MatrixRelation<R, R> neighborhood() { 1654 checkHomogen(); 1655 return new MatrixRelation<R, R>( 1656 rowHeads(), 1657 rowHeads(), 1658 BooleanMatrices.transitiveReduction(BooleanMatrices.reflexiveReduction(matrix)), 1659 true); 1660 } 1661 1662 public MatrixRelation<R, R> order() { 1663 checkHomogen(); 1664 return new MatrixRelation<R, R>( 1665 rowHeads(), 1666 rowHeads(), 1667 BooleanMatrices.reflexiveClosure(BooleanMatrices.transitiveClosure(matrix)), 1668 true); 1669 } 1670 1671 public final boolean isReflexive() { 1672 return matrix.ge(Ret.NEW, BooleanMatrices.identity(size())).equals(BooleanMatrices.full(size())); 1673 } 1674 1675 public final boolean isIrreflexive() { 1676 return matrix.and(Ret.NEW, BooleanMatrices.identity(size())).equals(BooleanMatrices.empty(size())); 1677 } 1678 1679 public final boolean isSymmetric() { 1680 return matrix.equals(matrix.transpose(Ret.NEW)); 1681 } 1682 1683 public final boolean isAsymmetric() { 1684 return matrix.and(Ret.NEW, matrix.transpose(Ret.NEW)).equals(BooleanMatrices.empty(size())); 1685 } 1686 1687 public final boolean isConnex() { 1688 return matrix.or(Ret.NEW, matrix.transpose(Ret.NEW)).equals(BooleanMatrices.full(size())); 1689 } 1690 1691 public final boolean isAntisymmetric() { 1692 return matrix.and(Ret.NEW, matrix.transpose(Ret.NEW)).le(Ret.NEW, BooleanMatrices.identity(size())).equals( 1693 BooleanMatrices.full(size())); 1694 } 1695 1696 public final boolean isQuasiconnex() { 1697 return matrix.or(Ret.NEW, matrix.transpose(Ret.NEW)).ge(Ret.NEW, BooleanMatrices.negativeIdentity(size())).equals( 1698 BooleanMatrices.full(size())); 1699 } 1700 1701 public final boolean isAlternative() { 1702 return isAntisymmetric() && isQuasiconnex(); 1703 } 1704 1705 public final boolean isTransitive() { 1706 return matrix 1707 .mtimes(Ret.NEW, false, matrix) 1708 .toBooleanMatrix() 1709 .le(Ret.NEW, matrix) 1710 .equals(BooleanMatrices.full(size())); 1711 } 1712 1713 public final boolean isNegativeTransitive() { 1714 final BooleanMatrix2D not = (BooleanMatrix2D) matrix.not(Ret.NEW); 1715 return not.mtimes(Ret.NEW, false, not).toBooleanMatrix().le(Ret.NEW, not).equals(BooleanMatrices.full(size())); 1716 } 1717 1718 public final boolean isAtransitive() { 1719 return matrix 1720 .mtimes(Ret.NEW, false, matrix) 1721 .toBooleanMatrix() 1722 .and(Ret.NEW, matrix) 1723 .equals(BooleanMatrices.empty(size())); 1724 } 1725 1726 public final boolean isNegativAtransitive() { 1727 final BooleanMatrix2D not = (BooleanMatrix2D) matrix.not(Ret.NEW); 1728 return not.mtimes(Ret.NEW, false, not).toBooleanMatrix().and(Ret.NEW, not).equals(BooleanMatrices.empty(size())); 1729 } 1730 1731 public final boolean isNCyclic(final int n) { 1732 return BooleanMatrices 1733 .power(matrix(), n) 1734 .le(Ret.NEW, matrix.transpose(Ret.NEW)) 1735 .equals(BooleanMatrices.full(size())); 1736 } 1737 1738 public final boolean isCyclic() { 1739 return BooleanMatrices 1740 .transitiveClosure(matrix()) 1741 .le(Ret.NEW, matrix.transpose(Ret.NEW)) 1742 .equals(BooleanMatrices.full(size())); 1743 } 1744 1745 public final boolean isNAcyclic(final int n) { 1746 return BooleanMatrices 1747 .power(matrix(), n) 1748 .le(Ret.NEW, matrix.transpose(Ret.NEW).not(Ret.NEW)) 1749 .equals(BooleanMatrices.full(size())); 1750 } 1751 1752 public final boolean isAcyclic() { 1753 return BooleanMatrices.transitiveClosure(matrix()).le(Ret.NEW, matrix.transpose(Ret.NEW).not(Ret.NEW)).equals( 1754 BooleanMatrices.full(size())); 1755 } 1756 1757 public final boolean isNTransitive(final int n) { 1758 return BooleanMatrices.power(matrix(), n).le(Ret.NEW, matrix).equals(BooleanMatrices.full(size())); 1759 } 1760 1761 public final boolean isNAtransitive(final int n) { 1762 return BooleanMatrices.power(matrix(), n).le(Ret.NEW, matrix.not(Ret.NEW)).equals(BooleanMatrices.full(size())); 1763 } 1764 1765 public final boolean isLeftComparative() { 1766 return matrix.transpose(Ret.NEW).mtimes(Ret.NEW, false, matrix).toBooleanMatrix().le(Ret.NEW, matrix).equals( 1767 BooleanMatrices.full(size())); 1768 } 1769 1770 public final boolean isRightComparative() { 1771 return matrix.mtimes(Ret.NEW, false, matrix.transpose(Ret.NEW)).toBooleanMatrix().le(Ret.NEW, matrix).equals( 1772 BooleanMatrices.full(size())); 1773 } 1774}