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.Collection; 011import java.util.HashSet; 012import java.util.Set; 013 014/** 015 * A mechanism to map sets <b> 1:1 </b> to other sets. 016 * <b>All sets do not intersect.</b> 017 * The mapping is symmetric, allowing <pre> 018 * map(getRepresentative(a))=getRepresentative(b) 019 * map(getRepresentative(b))=getRepresentative(a) 020 * </pre> 021 * @param <V> the class of the elements in the mapped sets. 022 * @author Rusi Popov (popovr@mdatools.net) 023 */ 024public interface EquivalenceClassesMap<V> { 025 026 /** 027 * Register the X equivalence class mapped to Y equivalence class, 028 * Any existing mappings of the equivalence classes' elements are overridden. 029 * @param xClass not null, not empty equivalence class at x side 030 * @param yClass not null, not empty equivalence class at y side 031 */ 032 void add(Collection<V> xClass, Collection<V> yClass); 033 034 /** 035 * This method guarantees that each x or y objects pertain to no more than a single set and there is 036 * one-to-one mapping between these sets 037 * If there is a set containing y and there is no set containing x, then {x} is put as the set that is mapped to y; 038 * If there is a set containing x and there is no set containing y, then {y} is put as the set that is mapped to x; 039 * If there is no set containing x and there is no set containing y, then a new set {x} is created and mapped to the new set {y} 040 * If there is a set containing x A.K.A {x} and there is a set containing y A.K.A {y}, then if {x} not mapped to {y}, this method fails. 041 * @param x not null, conditionally named key 042 * @param y not null, conditionally named value 043 * @throws IllegalArgumentException when mapping x,y that have already mapped representatives that do not match 044 */ 045 void add(V x, V y) throws IllegalArgumentException; 046 047 048 /** 049 * @return a non-null collection the representatives for elements X add(X,y) was called with. 050 */ 051 Collection<V> getXKeys(); 052 053 /** 054 * @param element is non-null 055 * @return a non-null collection of objects of the same equivalence class the element pertains to 056 */ 057 Collection<V> getEquivalents(V element); 058 059 /** 060 * @param element 061 * @return the element that represents the equivalence class this element pertains to 062 */ 063 V getRepresentative(V element); 064 065 /** 066 * @param element 067 * @return the element this element (any element of its equivalence class) is mapped to 068 */ 069 V map(V element); 070 071 072 /** 073 * @param elements non null collection 074 * @return a collection of their representatives or the objects themselves, if they have not been matched in 075 * the target model and therefore have no representatives 076 */ 077 default Set<V> getRepresentativesOrSelf(Collection<V> elements) { 078 Set<V> result; 079 V mapped; 080 081 result = new HashSet<>(elements.size()<<2); 082 083 for(V element: elements) { 084 mapped = getRepresentative( element ); 085 086 if ( mapped == null ) { // no representative - use the element itself 087 result.add( element ); 088 } else { 089 result.add( mapped ); 090 } 091 } 092 return result; 093 } 094 095 /** 096 * @param elements not null 097 * @return a non-null set of the elements are mapped on. Mapped nulls are skipped. 098 */ 099 default Set<V> getMappedRepresentatives(Collection<V> elements) { 100 Set<V> result; 101 V mapped; 102 103 result = new HashSet<V>(elements.size()<<1); 104 105 // collect the matched model elements for these nodes 106 for(V element : elements ) { 107 mapped = map( element ); 108 109 if ( mapped != null ) { 110 result.add( mapped ); 111 } 112 } 113 return result; 114 } 115 116 /** 117 * @param elements non null collection 118 * @return a collection of their representatives. null representatives are skipped 119 */ 120 default Set<V> getRepresentatives(Collection<V> elements) { 121 Set<V> result; 122 V mapped; 123 124 result = new HashSet<>(elements.size()<<2); 125 126 for(V element: elements) { 127 mapped = getRepresentative( element ); 128 129 if ( mapped != null ) { // no representative - use the element itself 130 result.add( mapped ); 131 } 132 } 133 return result; 134 } 135}