/*******************************************************************************
* Copyright (c) 2010-2012, Andras Okros, Istvan Rath and Daniel Varro
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Andras Okros - initial API and implementation
*******************************************************************************/
package org.eclipse.incquery.patternlanguage.validation;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.incquery.patternlanguage.patternLanguage.Variable;
/**
* Just a basic Union-Find algorithm implementation for a validation problem.
*/
public class UnionFindForVariables {
private final List<Variable> inputVariables;
private final int[] unionIdArray;
/**
* @param inputVariables
* which are assumed to be disjoint at the start
*/
public UnionFindForVariables(List<Variable> inputVariables) {
this.inputVariables = new ArrayList<Variable>(inputVariables);
unionIdArray = new int[inputVariables.size()];
for (int i = 0; i < inputVariables.size(); i++) {
unionIdArray[i] = i;
}
}
/**
* @param variables
* @return true if the variables are in the same union/set
*/
public boolean isSameUnion(Set<Variable> variables) {
if (variables.size() > 1) {
Variable current = null;
for (Variable variable : variables) {
if (current != null) {
if (inputVariables.contains(variable) && !isSameUnion(current, variable)) {
return false;
}
} else {
if (inputVariables.contains(variable)) {
current = variable;
}
}
}
}
return true;
}
/**
* @param variables
* places the input variables in to the same union/set
*/
public void unite(Set<Variable> variables) {
if (variables.size() > 1) {
Variable current = null;
for (Variable variable : variables) {
if (current != null) {
if (inputVariables.contains(variable)) {
unite(current, variable);
}
} else {
if (inputVariables.contains(variable)) {
current = variable;
}
}
}
}
}
/**
* @return a human readable string input formatted based on the underlying unions/sets
*/
public String getCurrentPartitionsFormatted() {
String result = "";
for (Set<Variable> unionSet : getPartitions()) {
result = result.concat("[");
for (Variable variable : unionSet) {
result = result.concat(variable.getName() + " ");
}
result = result.concat("]");
}
return result;
}
/**
* @return true if there is more than one real union/set
*/
public boolean isMoreThanOneUnion() {
if (getPartitions().size() > 1) {
return true;
}
return false;
}
private boolean isSameUnion(Variable variable1, Variable variable2) {
// Should not be called with out of the scope variables!
return unionIdArray[inputVariables.indexOf(variable1)] == unionIdArray[inputVariables.indexOf(variable2)];
}
private void unite(Variable variable1, Variable variable2) {
// Should not be called with out of the scope variables!
if (!isSameUnion(variable1, variable2)) {
int variable1ID = unionIdArray[inputVariables.indexOf(variable1)];
int variable2ID = unionIdArray[inputVariables.indexOf(variable2)];
for (int i = 0; i < unionIdArray.length; i++) {
if (unionIdArray[i] == variable1ID) {
unionIdArray[i] = variable2ID;
}
}
}
}
private List<Set<Variable>> getPartitions() {
List<Set<Variable>> resultList = new ArrayList<Set<Variable>>();
Set<Integer> previousKeys = new HashSet<Integer>();
for (Variable variableOuter : inputVariables) {
int currentID = unionIdArray[inputVariables.indexOf(variableOuter)];
if (!previousKeys.contains(currentID)) {
previousKeys.add(currentID);
Set<Variable> currentSet = new HashSet<Variable>();
for (Variable variableInner : inputVariables) {
if (unionIdArray[inputVariables.indexOf(variableInner)] == currentID) {
currentSet.add(variableInner);
}
}
resultList.add(currentSet);
}
}
return resultList;
}
/**
*
* @param var
* @return the set of variables in the partition of a selected variable
*/
public Set<Variable> getPartitionOfVariable(Variable var) {
Set<Variable> set = new HashSet<Variable>();
set.add(var);
if (inputVariables.contains(var)) {
int id = unionIdArray[inputVariables.indexOf(var)];
for (Variable inner : inputVariables) {
if (id == unionIdArray[inputVariables.indexOf(inner)]) {
set.add(inner);
}
}
}
return set;
}
}