package org.eclipse.emf.henshin.interpreter.util; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.emf.henshin.interpreter.Match; import org.eclipse.emf.henshin.model.Edge; import org.eclipse.emf.henshin.model.Graph; import org.eclipse.emf.henshin.model.Module; import org.eclipse.emf.henshin.model.Node; import org.eclipse.emf.henshin.model.Rule; /** * This class contains informations about partial matches for a given module and generates a textual report,which can be used to give the Henshin users a detailed feedback. * * @author Svetlana Arifulina * */ public class PartialMatchReport { /** * Module to be used. */ Module module; /** * List of partial matches. */ List<Match> matches; /** * Map connecting a rule from the module with partial matches, which have been found for it. */ Map<Rule, List<PartialMatchInfo>> infos = new HashMap<Rule, List<PartialMatchInfo>>(); /** * @return */ public Map<Rule, List<PartialMatchInfo>> getInfos() { return infos; } /** * Constructor */ public PartialMatchReport(Module module, List<Match> matches) { super(); this.module = module; this.matches = matches; } /** * @return */ public Module getModule() { return module; } /** * Helping class containing the information about one partial match and the delta with the lhs. * * @author Svetlana Arifulina * */ public class PartialMatchInfo { /** * Complete or partial match */ Match match; /** * Delta from the partial match to the lhs */ Graph delta; /** * Flag to indicate a complete match */ boolean isComplete = false; /** * Coverage of the lhs with the partial match */ double coverage; public double getCoverage() { return coverage; } public void setCoverage(double coverage) { this.coverage = coverage; } public boolean isComplete() { return isComplete; } public void setComplete(boolean isComplete) { this.isComplete = isComplete; } public Match getMatch() { return match; } public void setMatch(Match match) { this.match = match; } public Graph getDelta() { return delta; } public void setDelta(Graph delta) { this.delta = delta; } } /** * The method generating a textual report. * * @return Textual report */ public String getReport() { StringBuffer buffer = new StringBuffer(); buffer.append("============================\n"); buffer.append("Partial match statistics\n"); if (infos.isEmpty()) { buffer.append("No matches were found.\n"); } else { for (Rule rule : infos.keySet()) { for (PartialMatchInfo partialMatchInfo : infos.get(rule)) { if (partialMatchInfo.isComplete()) { buffer.append("============================\n"); buffer.append("This is a complete match for " + rule.getName() + "\n"); buffer.append(partialMatchInfo.getMatch().toString() + "\n"); } else { buffer.append("============================\n"); buffer.append("This is a partial match for " + rule.getName() + "\n"); buffer.append(partialMatchInfo.getMatch().toString() + "\n"); buffer.append("----------------------------------\n"); buffer.append("Deltas are:\n"); buffer.append(partialMatchInfo.getDelta().toString() + "\n"); for (Node node : partialMatchInfo.getDelta().getNodes()) { buffer.append(node.toString() + "\n"); } for (Edge edge : partialMatchInfo.getDelta().getEdges()) { buffer.append(edge.toString() + "\n"); } } } } } buffer.append("============================\n"); return buffer.toString(); } /** * Method collecting the report information for the given partial matches * * @param originalRule Rule to collect infos about partial matches for. * @param matches Module to be used. * @return */ public void collectPartialMatchInfos( Rule originalRule, List<Match> matches) { for (Match match : matches) { if (!infos.containsKey(originalRule)) { infos.put(originalRule, new ArrayList<PartialMatchInfo>()); } PartialMatchInfo info = new PartialMatchInfo(); info.setMatch(match); info.setDelta(computeDelta(originalRule, match)); if (info.getDelta().getNodes().isEmpty() && info.getDelta().getEdges().isEmpty()) { info.setComplete(true); } double coverage = 1 - (double)(info.getDelta().getNodes().size() + info.getDelta().getEdges().size())/(originalRule.getLhs().getNodes().size() + originalRule.getLhs().getEdges().size()); coverage = (double)Math.round(100 * coverage)/100; info.setCoverage(coverage); infos.get(originalRule).add(info); } } /** * Method computing the different between a partial match and a lhs. * * @param originalRule Rule to compute a delta with the partial match for * @param match (Partial) match for originalRule * @return Graph as a delta between the originalRule and the given (partial) match */ private Graph computeDelta(Rule originalRule, Match match) { Graph delta = EcoreUtil.copy(originalRule.getLhs()); Rule matchingRule = match.getRule(); delta.setName("Partial match delta for " + matchingRule.getName()); List<Node> nodesToRemove = new ArrayList<Node>(); List<Edge> edgesToRemove = new ArrayList<Edge>(); for (Node node : delta.getNodes()) { for (Node node2 : matchingRule.getLhs().getNodes()) { if (node.getType().equals(node2.getType()) && node.getName() == (node2.getName())) { nodesToRemove.add(node); break; } } } for (Edge edge : delta.getEdges()) { for (Edge edge2 : matchingRule.getLhs().getEdges()) { if(edge.getType().equals(edge2.getType())) { edgesToRemove.add(edge); break; } } } for (Node node : nodesToRemove) { List<Edge> edgesToAdd = new ArrayList<Edge>(); edgesToAdd.addAll(node.getIncoming()); edgesToAdd.addAll(node.getOutgoing()); delta.removeNode(node); delta.getEdges().addAll(edgesToAdd); } for (Edge edge : edgesToRemove) { delta.removeEdge(edge); } return delta; } /** * Method computing the coverage of a lhs by a partial match * * @return Coverage of the module by the matches */ public double getCoverage() { double coverage = 0; if(!infos.isEmpty()) { for (Rule rule : infos.keySet()) { for (PartialMatchInfo info : infos.get(rule)) { coverage += info.getCoverage(); } } coverage = coverage/infos.keySet().size(); } return coverage; } }