001/* 002 * Copyright c 2018 Rusi Popov, MDA Tools.net All rights reserved. 003 * 004 * This program and the accompanying materials are made available under the terms of the 005 * Eclipse Public License v2.0 which accompanies this distribution, and is available at 006 * http://www.eclipse.org/legal/epl-v20.html 007 */ 008package net.mdatools.modelant.core.operation.model.topology; 009 010import java.util.ArrayList; 011import java.util.Collection; 012import java.util.IdentityHashMap; 013import java.util.Iterator; 014import java.util.List; 015import java.util.Map; 016 017/** 018 * @param <V> is the class of the mapped elements 019 * @author Rusi Popov (popovr@mdatools.net) 020 */ 021public class EquivalenceClassesMapImpl<V> implements EquivalenceClassesMap<V> { 022 023 /** 024 * Maps each element to the representative of the set it pertains to 025 */ 026 private final Map<V,V> elementToKey = new IdentityHashMap<V,V>(); 027 028 /** 029 * Maps the key (set representative) to the representative of the other set 030 */ 031 private final Map<V,V> keyToKey = new IdentityHashMap<V,V>(); 032 033 /** 034 * The unique keys of X elements added here 035 */ 036 private final List<V> xKeys = new ArrayList<>(); 037 038 /** 039 * @see net.mdatools.modelant.core.operation.model.topology.EquivalenceClassesMap#add(java.util.Collection, java.util.Collection) 040 */ 041 public void add(Collection<V> xClass, Collection<V> yClass) { 042 Iterator<V> xIterator; 043 Iterator<V> yIterator; 044 V x; 045 V y; 046 047 assert xClass != null : "Expected not null xClass"; 048 assert !xClass.isEmpty() : "Expected not empty xClass"; 049 050 assert yClass != null : "Expected not null yClass"; 051 assert !yClass.isEmpty() : "Expected not empty yClass"; 052 053 xIterator = xClass.iterator(); 054 yIterator = yClass.iterator(); 055 056 x = xIterator.next(); 057 y = yIterator.next(); 058 059 add(x,y); 060 while ( xIterator.hasNext() ) { 061 add( xIterator.next(), y ); 062 } 063 while ( yIterator.hasNext() ) { 064 add( x, yIterator.next() ); 065 } 066 } 067 068 /** 069 * @see net.mdatools.modelant.core.operation.model.topology.EquivalenceClassesMap#add(java.lang.Object, java.lang.Object) 070 */ 071 public final void add(V x, V y) throws IllegalArgumentException { 072 V xRep; 073 V yRep; 074 075 xRep = getRepresentative( x ); 076 yRep = getRepresentative( y ); 077 if ( xRep == null ) { 078 if ( yRep == null ) { // x, y still not mapped 079 // bind x,y as representatives == create a new equivalence set 080 elementToKey.put( x, x ); 081 elementToKey.put( y, y ); 082 083 // make the mapping symmetric 084 keyToKey.put(x, y); 085 keyToKey.put(y, x); 086 087 xKeys.add( x ); 088 } else { // y mapped to yRep, x not mapped 089 elementToKey.put( x, keyToKey.get( yRep )); 090 } 091 } else { // x mapped to xRep 092 if ( yRep == null ) { // y still not mapped 093 elementToKey.put( y, keyToKey.get( xRep )); 094 095 } else { // y mapped to yRep & x mapped 096 if ( yRep != keyToKey.get( xRep ) ) { // xRep != keyToKey.get( yRep ) 097 throw new IllegalArgumentException("Expected "+x+ " with its representative "+xRep 098 +" is mapped to be mapped to the representative of "+yRep+" of "+y); 099 } 100 } 101 } 102 } 103 104 /** 105 * @see net.mdatools.modelant.core.operation.model.topology.EquivalenceClassesMap#getXKeys() 106 */ 107 public final Collection<V> getXKeys() { 108 return xKeys; 109 } 110 111 /** 112 * @see net.mdatools.modelant.core.operation.model.topology.EquivalenceClassesMap#getEquivalents(java.lang.Object) 113 */ 114 public final Collection<V> getEquivalents(V element) { 115 Collection<V> result; 116 V representative; 117 118 result = new ArrayList<V>(); 119 representative = elementToKey.get( element ); 120 for (Map.Entry<V, V> entry: elementToKey.entrySet()) { 121 if ( entry.getValue() == representative ) { 122 result.add( entry.getKey() ); 123 } 124 } 125 return result; 126 } 127 128 /** 129 * @see net.mdatools.modelant.core.operation.model.topology.EquivalenceClassesMap#getRepresentative(java.lang.Object) 130 */ 131 public final V getRepresentative(V element) { 132 return elementToKey.get( element ); 133 } 134 135 /** 136 * @see net.mdatools.modelant.core.operation.model.topology.EquivalenceClassesMap#map(java.lang.Object) 137 */ 138 public final V map(V element) { 139 V result; 140 141 result = keyToKey.get( getRepresentative( element ) ); 142 143 return result; 144 } 145}