package inference.equivalence;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import exceptions.SubstituteFailedException;
import lombok.Getter;
import models.algebra.Expression;
import models.algebra.Variable;
import models.terms.RDLTerm;
import models.terms.meta.MetaRDLTerm;
import models.terms.meta.MetaVariable;
import models.terms.meta.OrderVariableConstraint;
import utils.Permutation;
@Getter
public class MetaSemanticEquivalenceRelation {
private MetaRDLTerm leftSideHand;
private MetaRDLTerm rightSideHand;
private Expression order;
public MetaSemanticEquivalenceRelation(MetaRDLTerm lsh, MetaRDLTerm rsh, Expression order) {
leftSideHand = lsh;
rightSideHand = rsh;
this.order = order;
}
public boolean isMatchedBy(SemanticEquivalenceRelation relation) {
Map<Variable, RDLTerm> binding = new HashMap<>();
Map<Variable, OrderVariableConstraint> orderConstraint = new HashMap<>();
return isMatchedBy(relation, binding, orderConstraint);
}
public boolean isMatchedBy(SemanticEquivalenceRelation relation, Map<Variable, RDLTerm> binding, Map<Variable, OrderVariableConstraint> orderConstraint) {
return leftSideHand.isMatchedBy(relation.getLeftSideHand(), binding, orderConstraint)
&& rightSideHand.isMatchedBy(relation.getRightSideHand(), binding, orderConstraint);
}
public Set<SemanticEquivalenceRelation> substitute(RDLTerm term, Collection<RDLTerm> existedTerms) {
Set<SemanticEquivalenceRelation> result = new HashSet<>();
Set<SemanticEquivalenceRelation> leftSub = leftSubstitute(term, existedTerms);
if (leftSub != null) {
result.addAll(leftSub);
}
Set<SemanticEquivalenceRelation> rightSub = rightSubstitute(term, existedTerms);
if (rightSub != null) {
result.addAll(rightSub);
}
return result;
}
private Set<SemanticEquivalenceRelation> leftSubstitute(RDLTerm term, Collection<RDLTerm> existedTerms) {
Set<SemanticEquivalenceRelation> result = new HashSet<>();
Map<Variable, RDLTerm> binding = new HashMap<>();
Map<Variable, OrderVariableConstraint> orderConstraint = new HashMap<>();
if (! leftSideHand.isMatchedBy(term, binding, orderConstraint)) {
return null;
}
if (! orderConstraint.containsKey(order)) {
return null;
}
int order = orderConstraint.get(this.order).getOrder();
if (order == -1) {
return null;
}
Set<Variable> allVariables = new HashSet<>(rightSideHand.getVariables().values());
allVariables.removeAll(binding.keySet());
List<Variable> leftVariables = new ArrayList<>(allVariables);
for (List<RDLTerm> useVariables: Permutation.permutation(existedTerms, leftVariables.size())) {
Map<Variable, RDLTerm> tempBinding = new HashMap<>();
tempBinding.putAll(binding);
for (int i = 0; i < leftVariables.size(); i++) {
tempBinding.put(leftVariables.get(i), useVariables.get(i));
}
RDLTerm tempTerm = rightSideHand.substitute(tempBinding);
if (! rightSideHand.isMatchedBy(tempTerm, binding, orderConstraint)) {
continue;
}
result.add(new SemanticEquivalenceRelation(leftSideHand.substitute(binding), rightSideHand.substitute(binding), order));
for (int i = 0; i < leftVariables.size(); i++) {
binding.remove(leftVariables.get(i));
}
}
try {
result.add(new SemanticEquivalenceRelation(leftSideHand.substitute(binding), rightSideHand.substitute(binding), order));
} catch (SubstituteFailedException e){}
return result;
}
private Set<SemanticEquivalenceRelation> rightSubstitute(RDLTerm term, Collection<RDLTerm> existedTerms) {
Set<SemanticEquivalenceRelation> result = new HashSet<>();
Map<Variable, RDLTerm> binding = new HashMap<>();
Map<Variable, OrderVariableConstraint> orderConstraint = new HashMap<>();
if (! rightSideHand.isMatchedBy(term, binding, orderConstraint)) {
return null;
};
if (! orderConstraint.containsKey(order)) {
return null;
}
int order = orderConstraint.get(this.order).getOrder();
if (order == -1) {
return null;
}
Set<Variable> allVariables = new HashSet<>();
for (MetaVariable vari : leftSideHand.getAllVariables()) {
allVariables.add(vari.getVariableName());
}
allVariables.removeAll(binding.keySet());
List<Variable> leftVariables = new ArrayList<>(allVariables);
for (List<RDLTerm> useVariables: Permutation.permutation(existedTerms, leftVariables.size())) {
Map<Variable, RDLTerm> tempBinding = new HashMap<>();
tempBinding.putAll(binding);
for (int i = 0; i < leftVariables.size(); i++) {
tempBinding.put(leftVariables.get(i), useVariables.get(i));
}
RDLTerm tempTerm = leftSideHand.substitute(tempBinding);
if (! leftSideHand.isMatchedBy(tempTerm, binding, orderConstraint)) {
for (int i = 0; i < leftVariables.size(); i++) {
binding.remove(leftVariables.get(i));
}
continue;
}
result.add(new SemanticEquivalenceRelation(leftSideHand.substitute(binding), rightSideHand.substitute(binding), order));
for (int i = 0; i < leftVariables.size(); i++) {
binding.remove(leftVariables.get(i));
}
}
try {
result.add(new SemanticEquivalenceRelation(leftSideHand.substitute(binding), rightSideHand.substitute(binding), order));
} catch (SubstituteFailedException e){}
return result;
}
@Override
public String toString() {
return leftSideHand.toString() + " ===(" + order + ") " + rightSideHand.toString();
}
@Override
public boolean equals(Object another) {
if (! (another instanceof SemanticEquivalenceRelation)) {
return false;
}
SemanticEquivalenceRelation relation = (SemanticEquivalenceRelation) another;
return leftSideHand.equals(relation.getLeftSideHand()) && rightSideHand.equals(relation.getRightSideHand());
}
@Override
public int hashCode() {
return toString().hashCode();
}
}