/*******************************************************************************
* Copyright (c) 2010-2015 Henshin developers. 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:
* TU Berlin, University of Luxembourg, SES S.A.
*******************************************************************************/
package de.tub.tfs.henshin.tggeditor.util.rule.concurrent;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil.Copier;
import org.eclipse.emf.henshin.model.Attribute;
import org.eclipse.emf.henshin.model.Edge;
import org.eclipse.emf.henshin.model.Graph;
import org.eclipse.emf.henshin.model.Mapping;
import org.eclipse.emf.henshin.model.MappingList;
import org.eclipse.emf.henshin.model.Node;
import org.eclipse.emf.henshin.model.Rule;
import org.eclipse.emf.henshin.model.impl.MappingImpl;
import org.eclipse.emf.henshin.model.impl.MappingListImpl;
import de.tub.tfs.henshin.tgg.TAttribute;
import de.tub.tfs.henshin.tgg.TEdge;
import de.tub.tfs.henshin.tgg.TGGRule;
import de.tub.tfs.henshin.tgg.TNode;
import de.tub.tfs.henshin.tgg.TripleGraph;
import de.tub.tfs.henshin.tgg.interpreter.util.RuleUtil;
import de.tub.tfs.henshin.tggeditor.util.GraphicalNodeUtil;
public class ConcurrentRuleUtil {
public static boolean isConcurrent(Rule rule1, Rule rule2){
setLhsCoordinatesAndLayout(rule2);
setLhsCoordinatesAndLayout(rule1);
for (Node nr1 : rule1.getRhs().getNodes()){
for (Node nl2 : rule2.getLhs().getNodes()){
if (sameNodeType(nr1, nl2)){ //if nr1 has equal type and all attributes of nl2 then there is at least one intersecting node for creation of concurrent rule
return true;
}
}
}
return false;
}
public static String getConcurrentRuleName(Rule ruleL, Rule ruleR, int index){
return "("+ruleL.getName()+"|"+index+"|"+ruleR.getName()+")";
}
public static List<String> getAtomicRuleNames(String cRuleName){
List<String> names = new LinkedList<String>();
String delims = "[|()]";
if (cRuleName!=null){
String[] tokens = cRuleName.split(delims);
for (String token : tokens){
try{
Integer.valueOf(token);
}catch (NumberFormatException e){
if (!token.equals(""))
names.add(token);
}
}
}
return names;
}
public static Rule copyRule(Rule oldRule) {
Copier copier = new Copier();
EObject result = copier.copy(oldRule);
copier.copyReferences();
Rule r = (Rule)result;
setLhsCoordinatesAndLayout(r);
return r;
}
//NEW
public static Rule getInverse(Rule rule){
Rule inverseRule = copyRule(rule);
inverseRule.setName("Inverse_"+rule.getName());
setLhsCoordinatesAndLayout(inverseRule);
inverseRule.setCheckDangling(true);
inverseRule.setInjectiveMatching(true);
//switch Rhs and Lhs
Graph tmpLhs = inverseRule.getLhs();
inverseRule.setLhs(inverseRule.getRhs());
inverseRule.getLhs().setName("lhs");
inverseRule.setRhs(tmpLhs);
inverseRule.getRhs().setName("rhs");
//update mapping
MappingList ruleMappings = inverseRule.getMappings();
Test.check(ruleMappings.isEmpty()==rule.getMappings().isEmpty());
MappingList inverseRuleMappings = new MappingListImpl();
if (!ruleMappings.isEmpty()){
Test.check(!rule.getLhs().getNodes().contains(ruleMappings.get(0).getOrigin()));
}
for (Mapping ruleMapping : ruleMappings){
Node nodeLRule = ruleMapping.getOrigin();
Node nodeRRule = ruleMapping.getImage();
/*
Node nodeLInverseRule = null;
Node nodeRInverseRule = null;
boolean found = false;
for (Node nodeLInvRule : inverseRule.getLhs().getNodes()){
if (Graph2GraphCopyMappingList.isCopy(nodeLInvRule, nodeRRule)){
nodeLInverseRule = nodeLInvRule;
found =true;
break;
}
}
if (!found) throw new IllegalArgumentException("node not found");
found = false;
for (Node nodeRInvRule : inverseRule.getRhs().getNodes()){
if (Graph2GraphCopyMappingList.isCopy(nodeRInvRule, nodeLRule)){
nodeRInverseRule = nodeRInvRule;
found = true;
break;
}
}
if (!found) throw new IllegalArgumentException("node not found");*/
Mapping inverseRuleMapping = new MappingImpl();
//inverseRuleMapping.setOrigin(nodeLInverseRule);
//inverseRuleMapping.setImage(nodeRInverseRule);
inverseRuleMapping.setOrigin(ruleMapping.getImage());
inverseRuleMapping.setImage(ruleMapping.getOrigin());
inverseRuleMappings.add(inverseRuleMapping);
}
inverseRule.getMappings().clear();
inverseRule.getMappings().addAll(inverseRuleMappings);
return inverseRule;
}
public static boolean setLhsCoordinatesAndLayout(Rule rule){
if (rule.getLhs().getNodes().size() == 0) return false;
//if (((TNode)rule.getLhs().getNodes().get(0)).getX()!=0) return false;
for (Node n : rule.getLhs().getNodes()){
TNode tn = (TNode) n;
TNode tni = (TNode) rule.getAllMappings().getImage(n, rule.getRhs());
tn.setX(tni.getX());
tn.setY(tni.getY());
}
if (rule.getLhs() instanceof TripleGraph && rule.getRhs() instanceof TripleGraph){
TripleGraph tg = (TripleGraph) rule.getRhs();
((TripleGraph)rule.getLhs()).setDividerCT_X(tg.getDividerCT_X());
((TripleGraph)rule.getLhs()).setDividerSC_X(tg.getDividerSC_X());
((TripleGraph)rule.getLhs()).setDividerMaxY(tg.getDividerMaxY());
((TripleGraph)rule.getLhs()).setDividerYOffset(tg.getDividerYOffset());
}else{
throw new IllegalArgumentException("Lhs has to be of Type TripleGraph");
}
return true;
}
public static boolean strictGreater(Rule rule1, Rule rule2) {
List<String> atomNamesR2 = getAtomicRuleNames(rule2.getName());
Set<String> atomNamesR1 = new HashSet<String>(getAtomicRuleNames(rule1.getName()));
if (atomNamesR1.size() <= atomNamesR2.size()) {
return false;
}
for (String atomNameR2 : atomNamesR2) {
if (!atomNamesR1.contains(atomNameR2)) {
return false;
}
}
return true;
}
public static boolean intersectingAtomicNames(Rule ruleL, Rule ruleR) {
List<String> ruleLNames = getAtomicRuleNames(ruleL.getName());
List<String> ruleRNames = getAtomicRuleNames(ruleR.getName());
for (String nL : ruleLNames) {
for (String nR : ruleRNames) {
if (nL.equals(nR)) return true;
}
}
return false;
}
// public static boolean concatOfRuleNamesEquivalentToConcurrentRuleName(Rule ruleL, Rule ruleR, Rule cRule) {
// List<String> cRuleName = getAtomicRuleNames(cRule.getName());
// String concatName = getConcurrentRuleName(ruleL, ruleR, 0);
// List<String> conName = getAtomicRuleNames(concatName);
// if (conName.size()!=cRuleName.size()) return false;
// for (int i=0; i<conName.size();i++) {
// if (!conName.get(i).equals(cRuleName.get(i))) return false;
// }
// return true;
// }
//
public static boolean equivalent(Attribute a1, Attribute a2) {
if (a1 == null && a2 == null) {
return true;
}else if (a1 == null || a2 == null) {
return false;
}
return (a1.getValue() == a2.getValue()
|| (a1.getValue() != null
&& a2.getValue() != null
&& a1.getValue().equals(a2.getValue())))
&& (a1.getType() == a2.getType()
|| (a1.getType() != null
&& a2.getType() != null
&& a1.getType().getName().equals(a2.getType().getName())));
}
public static boolean sameNodeType(Node nodeL, Node nodeR) {
return (GraphicalNodeUtil.isCorrNode(nodeL) && GraphicalNodeUtil
.isCorrNode(nodeR))
|| !(nodeL == null
|| nodeR == null
|| nodeL.toString() != null
&& nodeR.toString() != null
&& !nodeL.toString().equals(nodeR.toString())
|| nodeL.getType() != null
&& nodeR.getType() != null
&& nodeL.getType().getEPackage() != null
&& nodeR.getType().getEPackage() != null
&& !nodeL.getType().getEPackage()
.equals(nodeR.getType().getEPackage())
|| nodeL.getName() != null
&& nodeR.getName() != null
&& !nodeL.getName().equals(nodeR.getName())
|| !GraphicalNodeUtil
.guessTC(nodeR).equals(
GraphicalNodeUtil.guessTC(nodeL)));
}
private static boolean equivalent(Node nodeR1, Node nodeR2){
if (nodeR1 == nodeR2) return true;
if (nodeR1 == null || nodeR2 == null) return false;
if (!sameNodeType(nodeR1, nodeR2)
|| nodeR1.getIncoming().size() != nodeR2.getIncoming().size()
|| nodeR1.getOutgoing().size() != nodeR2.getOutgoing().size()
|| nodeR1.getAttributes().size() != nodeR2.getAttributes().size()) {
return false;
}
boolean found = false;
boolean flag = false;
do {
for (Attribute a1 : nodeR1.getAttributes()) {
found = false;
for (Attribute a2 : nodeR2.getAttributes()) {
if (equivalent(a1, a2)){
found = true;
break;
}
}
if (!found) {
return false;
}
}
Node tmp = nodeR1;
nodeR1 = nodeR2;
nodeR2 = tmp;
flag = !flag;
} while(flag);
return true;
}
// public static boolean equivalentLHSNode(Node nodeR1, Node nodeR2) {
// if (!equivalent(nodeR1, nodeR2)) {
// return false;
// }
// Graph lhs1;
// Graph lhs2;
// Rule rule1;
// Rule rule2;
//
// if (nodeR1.getGraph() != null
// && nodeR2.getGraph() != null
// && nodeR1.getGraph().getRule() != null
// && nodeR2.getGraph().getRule() != null
// ){
// lhs1 = nodeR1.getGraph();
// lhs2 = nodeR2.getGraph();
// rule1 = lhs1.getRule();
// rule2 = lhs2.getRule();
//
// return equivalent(nodeL1, nodeL2);
// }else {
// return false;
// }
// }
public static Set<Node> identicalRHSGraphs(Node nodeR1, Node nodeR2, Map<Node, Node> mapR1ToR2, Map<Node, Node> mapR2ToR1){
if (nodeR1 == null || nodeR2 == null) throw new IllegalArgumentException("node can not be null");
if (nodeR1.getGraph() == null || nodeR2.getGraph() == null) throw new IllegalArgumentException("graph of node can not be null");
if (nodeR1.getGraph().getRule() == null || nodeR2.getGraph().getRule() == null) throw new IllegalArgumentException("rule of node can not be null");
if (!equivalent(nodeR1, nodeR2)) {
return null;
}
Node nodeL1 = RuleUtil.getLHSNode(nodeR1);
Node nodeL2 = RuleUtil.getLHSNode(nodeR2);
Set<Node> allAddedNodesR1 = new HashSet<Node>();
Set<Node> addedNodesR1 = null;
Node aNodeR1;
Node aNodeR2;
Node aNodeL1;
Node aNodeL2;
Node matchANodeR1;
Node matchANodeR2;
if (!equivalent(nodeL1, nodeL2)) {
return null;
}
mapR1ToR2.put(nodeR1, nodeR2);
mapR2ToR1.put(nodeR2, nodeR1);
allAddedNodesR1.add(nodeR1);
if (mapR1ToR2.keySet().size()==nodeR1.getGraph().getNodes().size()) {
return allAddedNodesR1;
}
boolean found = false;
boolean flag1 = false;
Node tmpNode = null;
do {
for (Edge edgeR1 : (flag1 ? nodeR1.getIncoming() : nodeR1.getOutgoing())) {
aNodeR1 = (flag1 ? edgeR1.getSource() : edgeR1.getTarget());
aNodeL1 = RuleUtil.getLHSNode(aNodeR1);
found = false;
matchANodeR1 = mapR1ToR2.get(aNodeR1);
for (Edge edgeR2 : (flag1 ? nodeR2.getIncoming() : nodeR2.getOutgoing())) {
aNodeR2 = (flag1 ? edgeR2.getSource() : edgeR2.getTarget());
matchANodeR2 = mapR2ToR1.get(aNodeR2);
aNodeL2 = RuleUtil.getLHSNode(aNodeR2);
if (matchANodeR1 == aNodeR2 && matchANodeR2 == aNodeR1) {
found = true;
break;
} else if (matchANodeR1 == null && matchANodeR2 == null && equivalent(aNodeR1, aNodeR2)) {
if (hasEdgeFrom(nodeR1, aNodeR1) != hasEdgeFrom(nodeR2, aNodeR2)
|| hasEdgeTo(nodeR1, aNodeR1) != hasEdgeTo(nodeR2, aNodeR2)
|| (aNodeL1 != null && aNodeL2 != null
&& (!equivalent(aNodeL1, aNodeL2)
|| (nodeL1 != null && nodeL2 != null &&
(hasEdgeFrom(nodeL1, aNodeL1) != hasEdgeFrom(nodeL2, aNodeL2)
|| hasEdgeTo(nodeL1, aNodeL1) != hasEdgeTo(nodeL2, aNodeL2)))))) {
continue;
}
addedNodesR1 = identicalRHSGraphs(aNodeR1, aNodeR2, mapR1ToR2, mapR2ToR1);
if (addedNodesR1 != null) {
allAddedNodesR1.addAll(addedNodesR1);
found = true;
break;
}
}
}
if (!found) {
for (Node addedNodeR1 : allAddedNodesR1) {
//Node addedNodeL1 = RuleUtil.getLHSNode(addedNodeR1);
Node removedNodeR2 = mapR1ToR2.remove(addedNodeR1);
Node removedNodeR1 = mapR2ToR1.remove(removedNodeR2);
if (removedNodeR1 != addedNodeR1) throw new IllegalArgumentException("Problem");
}
return null;
}
}
flag1 = !flag1;
} while (flag1);
return allAddedNodesR1;
}
public static boolean hasEdgeFrom(Node node, Node node2){
Graph graph = node.getGraph();
if (graph == null) return false;
for (Edge edge : node.getIncoming()) {
if (edge.getSource()==node2) return true;
}
return false;
}
public static boolean hasEdgeTo(Node node, Node node2){
Graph graph = node.getGraph();
if (graph == null) return false;
for (Edge edge : node.getOutgoing()) {
if (edge.getTarget()==node2) return true;
}
return false;
}
public static boolean equivalent(Rule rule1, Rule rule2){
if (rule1 == rule2) return true;
if (rule1 == null && rule2 == null) {
return true;
} else if (rule1 == null || rule2 == null){
return false;
}
Graph rhs1 = rule1.getRhs();
Graph rhs2 = rule2.getRhs();
Graph lhs1 = rule1.getLhs();
Graph lhs2 = rule2.getLhs();
if (rhs1 == null || rhs2 == null || lhs1 == null || lhs2 == null
|| rhs1.getNodes().size() != rhs2.getNodes().size()
|| lhs1.getNodes().size() != lhs2.getNodes().size()
|| rhs1.getEdges().size() != rhs2.getEdges().size()
|| lhs1.getEdges().size() != lhs2.getEdges().size()) {
return false;
}
Map<Node, Node> mapR1ToR2 = new HashMap<Node, Node>();
Map<Node, Node> mapR2ToR1 = new HashMap<Node, Node>();
for (Node nodeR1 : rhs1.getNodes()){
for (Node nodeR2 : rhs2.getNodes()){
System.out.println(nodeR1.getGraph().getRule()+ " "+nodeR2.getGraph().getRule());
if (null != identicalRHSGraphs(nodeR1, nodeR2, mapR1ToR2, mapR2ToR1)){
System.out.println("Equivalent rules : "+rule1.getName()+" : "+rule2.getName());
return true;
} else if (!mapR1ToR2.isEmpty() || !mapR2ToR1.isEmpty()){
throw new IllegalArgumentException("Problem");
};
}
}
// boolean found = false;
// Node uniqueNode1 = null;
// Node uniqueNode2 = null;
// //find unique node
// for (Node node1a : rhs1.getNodes()) {
// found = false;
// for (Node node1b : rhs1.getNodes()){
// if (node1a==node1b) {
// continue;
// }
// if (equivalent(node1a, node1b)) {
// found = true;
// break;
// }
// }
// if (!found) {
// uniqueNode1 = node1a;
// break;
// }
// }
// if (uniqueNode1!=null) {
// for (Node node2 : rhs2.getNodes()) {
// if (equivalent(uniqueNode1, node2)) {
// uniqueNode2 = node2;
// break;
// }
// }
// if (uniqueNode2 == null) {
// return false;
// }
// }
return false;
}
public static MappingList getInverseMappingList(MappingList mlist){
MappingList invMappings = new MappingListImpl();
for (Mapping ruleLMapping : mlist){
Node image = ruleLMapping.getImage();
Node origin = ruleLMapping.getOrigin();
invMappings.add(image, origin);
}
return invMappings;
}
// NEW
public static void mark(TGGRule rule) {
for (Node nr : rule.getRhs().getNodes()) {
TNode nodeR = (TNode) nr;
Test.check(nr.getGraph() ==rule.getRhs() && nr.getGraph().getRule() == rule);
Node nodeL = RuleUtil.getLHSNode(nr);
Node nL = rule.getMappings().getOrigin(nodeR);
Test.check(nL==nodeL);
if (nodeL == null) {
nodeR.setMarkerType(RuleUtil.NEW);
} else {
nodeR.setMarkerType(null);
}
// handle attributes
for (Attribute at : nodeR.getAttributes()) {
TAttribute attR = (TAttribute) at;
Attribute attL = RuleUtil.getLHSAttribute(attR);
if (attL == null) {
attR.setMarkerType(RuleUtil.NEW);
} else {
attR.setMarkerType(null);
}
}
}
for (Edge ed : rule.getRhs().getEdges()) {
TEdge edgeR = (TEdge) ed;
Edge edgeL = RuleUtil.getLHSEdge(edgeR);
if (edgeL == null) {
edgeR.setMarkerType(RuleUtil.NEW);
} else {
edgeR.setMarkerType(null);
}
}
}
}