001package conexp.fx.core.collections.relation; 002 003/* 004 * #%L 005 * Concept Explorer FX 006 * %% 007 * Copyright (C) 2010 - 2023 Francesco Kriegel 008 * %% 009 * This program is free software: you can redistribute it and/or modify 010 * it under the terms of the GNU General Public License as 011 * published by the Free Software Foundation, either version 3 of the 012 * License, or (at your option) any later version. 013 * 014 * This program is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017 * GNU General Public License for more details. 018 * 019 * You should have received a copy of the GNU General Public 020 * License along with this program. If not, see 021 * <http://www.gnu.org/licenses/gpl-3.0.html>. 022 * #L% 023 */ 024 025import java.util.Arrays; 026import java.util.Collection; 027import java.util.HashSet; 028import java.util.Iterator; 029import java.util.ListIterator; 030import java.util.NoSuchElementException; 031import java.util.Set; 032import java.util.function.BiPredicate; 033 034import com.google.common.base.Predicate; 035import com.google.common.collect.Iterators; 036import com.google.common.collect.Sets; 037 038import conexp.fx.core.collections.Collections3; 039import conexp.fx.core.collections.ListIterators; 040import conexp.fx.core.collections.Pair; 041import conexp.fx.core.collections.SimpleListIterator; 042import conexp.fx.core.collections.setlist.AbstractSetList; 043import conexp.fx.core.collections.setlist.SetList; 044import conexp.fx.core.collections.setlist.SetLists; 045 046public abstract class AbstractRelation<R, C> implements Relation<R, C> { 047 048 public static <R, C> AbstractRelation<R, C> 049 fromPredicate(final SetList<R> rowHeads, final SetList<C> colHeads, final BiPredicate<R, C> predicate) { 050 return new AbstractRelation<R, C>(rowHeads, colHeads, false) { 051 052 @Override 053 public final boolean contains(final Object o1, final Object o2) { 054 try { 055 return predicate.test((R) o1, (C) o2); 056 } catch (ClassCastException e) { 057 return false; 058 } 059 } 060 061 }; 062 } 063 064 public static <R> AbstractRelation<R, R> fromPredicate(final SetList<R> heads, final BiPredicate<R, R> predicate) { 065 return new AbstractRelation<R, R>(heads, heads, true) { 066 067 @Override 068 public final boolean contains(final Object o1, final Object o2) { 069 try { 070 return predicate.test((R) o1, (R) o2); 071 } catch (ClassCastException e) { 072 return false; 073 } 074 } 075 076 }; 077 } 078 079 protected final boolean homogen; 080 protected SetList<R> rowHeads; 081 protected SetList<C> colHeads; 082 083 @SuppressWarnings("unchecked") 084 protected AbstractRelation(final SetList<R> rowHeads, final SetList<C> colHeads, final boolean homogen) { 085 this(homogen); 086 if (homogen) { 087 if (!rowHeads.equals(colHeads)) 088 throw new NoHomogenRelationException(); 089 this.rowHeads = rowHeads; 090 this.colHeads = (SetList<C>) this.rowHeads; 091 } else { 092 this.rowHeads = rowHeads; 093 this.colHeads = colHeads; 094 } 095 } 096 097 protected AbstractRelation(final boolean homogen) { 098 super(); 099 this.homogen = homogen; 100 } 101 102 public SetList<R> rowHeads() { 103 return rowHeads; 104 } 105 106 public SetList<C> colHeads() { 107 return colHeads; 108 } 109 110 public abstract boolean contains(Object o1, Object o2); 111 112 public boolean containsAll(final Relation<?, ?> r) { 113 for (Pair<?, ?> p : r) 114 if (!contains(p.x(), p.y())) 115 return false; 116 return true; 117 } 118 119 public Set<C> row(final Object o) { 120 return rowAnd(o); 121 } 122 123 public Set<R> col(final Object o) { 124 return colAnd(o); 125 } 126 127 public final Set<C> rowAnd(final Object... rows) { 128 return rowAnd(Arrays.asList(rows)); 129 } 130 131 public final Set<R> colAnd(final Object... cols) { 132 return colAnd(Arrays.asList(cols)); 133 } 134 135 public Set<C> rowAnd(final Collection<?> rows) { 136 return Sets.filter(colHeads(), new Predicate<C>() { 137 138 public final boolean apply(C col) { 139 for (Object row : rows) 140 if (!AbstractRelation.this.contains(row, col)) 141 return false; 142 return true; 143 } 144 }); 145 } 146 147 public Set<R> colAnd(final Collection<?> cols) { 148 return Sets.filter(rowHeads(), new Predicate<R>() { 149 150 public final boolean apply(final R row) { 151 for (Object col : cols) 152 if (!AbstractRelation.this.contains(row, col)) 153 return false; 154 return true; 155 } 156 }); 157 } 158 159 public Relation<R, C> subRelation(final Collection<?> rows, final Collection<?> cols) { 160 return new AbstractRelation<R, C>( 161 SetLists.intersection(rowHeads, rows), 162 SetLists.intersection(colHeads, cols), 163 false) { 164 165 public final boolean contains(final Object o1, final Object o2) { 166 return rowHeads().contains(o1) && colHeads().contains(o2) && AbstractRelation.this.contains(o1, o2); 167 } 168 }; 169 } 170 171 public Relation<R, C> filter( 172 final Predicate<? super R> rowPredicate, 173 final Predicate<? super C> colPredicate, 174 final Predicate<Pair<R, C>> relationPredicate) { 175 return new AbstractRelation<R, C>(rowHeads.filter(rowPredicate), colHeads.filter(colPredicate), false) { 176 177 @SuppressWarnings("unchecked") 178 public final boolean contains(final Object o1, final Object o2) { 179 return rowHeads().contains(o1) && colHeads().contains(o2) && AbstractRelation.this.contains(o1, o2) 180 && relationPredicate.apply(new Pair<R, C>((R) o1, (C) o2)); 181 } 182 }; 183 } 184 185 public boolean equals(final Object o) { 186 return this == o 187 || (o instanceof Relation && size() == ((Relation<?, ?>) o).size() && containsAll((Relation<?, ?>) o)); 188 } 189 190 public final boolean smallerEq(final Relation<R, C> r) { 191 return r.containsAll(this); 192 } 193 194 public final boolean smaller(final Relation<R, C> r) { 195 return size() < r.size() && smallerEq(r); 196 } 197 198 public final boolean greaterEq(final Relation<R, C> r) { 199 return r.smallerEq(this); 200 } 201 202 public final boolean greater(final Relation<R, C> r) { 203 return r.smaller(this); 204 } 205 206 public final boolean uncomparable(final Relation<R, C> r) { 207 return !smallerEq(r) && !greaterEq(r); 208 } 209 210 public final int compareTo(final Relation<R, C> r) { 211 if (equals(r)) 212 return 0; 213 if (smallerEq(r)) 214 return -1; 215 if (greaterEq(r)) 216 return 1; 217 return Integer.MAX_VALUE; 218 } 219 220 public Iterator<Pair<R, C>> iterator() { 221 return Iterators 222 .filter( 223 ListIterators.<R, C> cartesianProduct(rowHeads().listIterator(), colHeads().listIterator(), 0), 224 new Predicate<Pair<R, C>>() { 225 226 public final boolean apply(final Pair<R, C> p) { 227 return contains(p.x(), p.y()); 228 } 229 }); 230 } 231 232 public int size() { 233 int size = 0; 234 for (R row : rowHeads()) 235 for (C col : colHeads()) 236 if (contains(row, col)) 237 size++; 238 return size; 239 } 240 241 public boolean isFull() { 242 for (R row : rowHeads()) 243 for (C col : colHeads()) 244 if (!contains(row, col)) 245 return false; 246 return true; 247 } 248 249 public boolean isEmpty() { 250 for (R row : rowHeads()) 251 for (C col : colHeads()) 252 if (contains(row, col)) 253 return false; 254 return true; 255 } 256 257 public MatrixRelation<R, C> clone() { 258 final MatrixRelation<R, C> clone = new MatrixRelation<R, C>(rowHeads(), colHeads(), homogen); 259 clone.addAllFast(this); 260 return clone; 261 } 262 263 public boolean[][] toArray() { 264 final boolean[][] a = new boolean[rowHeads().size()][colHeads().size()]; 265 for (int i = 0; i < rowHeads().size(); i++) 266 for (int j = 0; j < colHeads().size(); j++) 267 a[i][j] = contains(rowHeads().get(i), colHeads().get(j)); 268 return a; 269 } 270 271 private static final int colspan = 8; 272 273 public String toString() { 274 final StringBuilder s = new StringBuilder(); 275 s.append(getClass().getName() + "@" + hashCode() + "\r\n"); 276 s.append(rowHeads().size() + " domain elements: " + rowHeads() + "\r\n"); 277 s.append(colHeads().size() + " codomain elements. " + colHeads() + "\r\n"); 278 String spaces = ""; 279 while (spaces.length() < colspan) 280 spaces += " "; 281 s.append(spaces); 282 spaces = spaces.substring(1); 283 String c; 284 for (C col : colHeads()) { 285 c = col.toString().substring(0, Math.min(colspan, col.toString().length())); 286 while (c.length() < colspan) 287 c += " "; 288 s.append("\t" + c); 289 } 290 s.append("\r\n"); 291 String r; 292 for (R row : rowHeads()) { 293 r = row.toString().substring(0, Math.min(colspan, row.toString().length())); 294 while (r.length() < colspan) 295 r += " "; 296 s.append(r); 297 for (C col : colHeads()) 298 if (contains(row, col)) 299 s.append("\tX" + spaces); 300 else 301 s.append("\t." + spaces); 302 s.append("\r\n"); 303 } 304 return s.toString(); 305 } 306 307 public void empty() { 308 throw new UnsupportedOperationException(); 309 } 310 311 public void fill() { 312 throw new UnsupportedOperationException(); 313 } 314 315 public void dispose() { 316 throw new UnsupportedOperationException(); 317 } 318 319 public boolean add(final R row, final C col) { 320 throw new UnsupportedOperationException(); 321 } 322 323 public boolean addFast(final Object o1, final Object o2) { 324 throw new UnsupportedOperationException(); 325 } 326 327 public boolean addAll(final Relation<? extends R, ? extends C> r) { 328 throw new UnsupportedOperationException(); 329 } 330 331 public boolean addAllFast(final Relation<?, ?> r) { 332 throw new UnsupportedOperationException(); 333 } 334 335 public boolean remove(final Object o1, final Object o2) { 336 throw new UnsupportedOperationException(); 337 } 338 339 public boolean removeAll(final Relation<?, ?> r) { 340 throw new UnsupportedOperationException(); 341 } 342 343 public boolean retainAll(final Relation<?, ?> r) { 344 throw new UnsupportedOperationException(); 345 } 346 347 @Override 348 public boolean isHomogen() { 349 return homogen; 350 } 351 352 protected final void checkHomogen() throws NoHomogenRelationException { 353 if (!isHomogen()) 354 throw new NoHomogenRelationException(); 355 } 356 357 public MatrixRelation<R, R> neighborhood() { 358 checkHomogen(); 359 return clone().neighborhood(); 360 } 361 362 public MatrixRelation<R, R> order() { 363 checkHomogen(); 364 return clone().order(); 365 } 366 367 public SetList<Set<R>> equivalenceClasses() { 368 checkHomogen(); 369 return new AbstractSetList<Set<R>>() { 370 371 @Override 372 public final ListIterator<Set<R>> listIterator(final int i) { 373 return new SimpleListIterator<Set<R>>(true) { 374 375 private final HashSet<R> available = new HashSet<R>(rowHeads()); 376 377 { 378 createFirst(i); 379 } 380 381 @Override 382 protected final Set<R> createNext() { 383 try { 384 final R head = Collections3.firstElement(available); 385 final Set<R> eq = new HashSet<R>(col(head)); 386 available.removeAll(eq); 387 return eq; 388 } catch (NoSuchElementException e) { 389 return null; 390 } 391 } 392 393 @Override 394 protected final Set<R> createPrevious() { 395 // TODO Auto-generated method stub 396 return null; 397 } 398 }; 399 } 400 }; 401 } 402}