import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; import agg.attribute.impl.ContextView; import agg.parser.ConflictsDependenciesContainer; import agg.parser.DependencyPairContainer; import agg.parser.ExcludePairContainer; import agg.util.Pair; import agg.util.XMLHelper; import agg.xt_basis.BaseFactory; import agg.xt_basis.Completion_InjCSP; import agg.xt_basis.Graph; import agg.xt_basis.Match; import agg.xt_basis.OrdinaryMorphism; import agg.xt_basis.Rule; import agg.xt_basis.StaticStep; import agg.xt_basis.TypeException; /** * This class is responsible for taking structurally equivalent critical * overlappings and discarding all but one of them. * * * @author maz * */ public class StructuralEquivalenceAnalysis { private ConflictsDependenciesContainer cdc; private ExcludePairContainer epc; private DependencyPairContainer dpc; private String filename; private String newfilename; private static final int CONFLICT = 0; private static final int DEPENDENCY = 1; public StructuralEquivalenceAnalysis(String filename) { try { // this loads an XML file into its representation as java objects - // this was formulated before Olga (AGG developer) sent an email // instructing me how to achieve this. Her method was slightly // different but essentially the same. I have decided to keep my // original method this.cdc = new ConflictsDependenciesContainer(); XMLHelper xmlhelper = new XMLHelper(); if (xmlhelper.read_from_xml(filename)) { xmlhelper.getObjectSub(this.cdc); this.epc = this.cdc.getExcludePairContainer(); this.dpc = this.cdc.getDependencyPairContainer(); this.filename = filename; generateNewFileName(); } } catch (Exception e) { System.err.println("There was an error setting up the file:"); e.printStackTrace(); System.exit(-1); } } // generate a new filename, altering existing one with "structuremod" private void generateNewFileName() { String s = this.filename.substring(0, this.filename.indexOf(".cpx")); this.newfilename = s + "_structuremod.cpx"; } public void writeToNewFile() { XMLHelper xmlhelper = new XMLHelper(); xmlhelper.addObjectSub(this.cdc); xmlhelper.save_to_xml(this.newfilename); } public String getNewfilename() { return this.newfilename; } public ConflictsDependenciesContainer getCdc() { return this.cdc; } public void setCdc(ConflictsDependenciesContainer cdc) { this.cdc = cdc; } public ExcludePairContainer getEpc() { return this.epc; } public void setEpc(ExcludePairContainer epc) { this.epc = epc; } public DependencyPairContainer getDpc() { return this.dpc; } public void setDpc(DependencyPairContainer dpc) { this.dpc = dpc; } /** * This method does all the important work for this class. A * conflictContainer (field of ExcludePairContainer) or dependencyContainer * (field of DependencyPairContainer) are passed in. This contains * information about all the overlappings. This method then takes the * critical overlappings for a rule pair, compares them and only replaces * those that are different from each other (i.e. not identical up to * renaming (isomorphic)). * * @param allOverlappingsHash * @param type * */ @SuppressWarnings("unchecked") public void reduceStructurallyEquivalentOverlappings( Hashtable<Rule, java.util.Hashtable<Rule, Pair<java.lang.Boolean, java.util.Vector<Pair<Pair<OrdinaryMorphism, OrdinaryMorphism>, Pair<OrdinaryMorphism, OrdinaryMorphism>>>>>> allOverlappingsHash, int type) { // get an enumeration of all reaction rules Enumeration<Rule> allReactionRules = allOverlappingsHash.keys(); // for each reaction rule while (allReactionRules.hasMoreElements()) { Rule reactionRule = allReactionRules.nextElement(); System.out.println(reactionRule.getName() + " overlappings:"); // gets all the overlappings for this rule with the other identity // rules Hashtable<Rule, Pair<Boolean, Vector<Pair<Pair<OrdinaryMorphism, OrdinaryMorphism>, Pair<OrdinaryMorphism, OrdinaryMorphism>>>>> tempHash = allOverlappingsHash .get(reactionRule); // the following gets the keys for the overlappings hashtable, i.e. // identity rules that this rule is analysed against Enumeration<Rule> allIdentityRules = tempHash.keys(); while (allIdentityRules.hasMoreElements()) { Rule identityRule = allIdentityRules.nextElement(); System.out.print("\t" + identityRule.getName() + " : "); // this gets all the actual overlapping info Pair<Boolean, Vector<Pair<Pair<OrdinaryMorphism, OrdinaryMorphism>, Pair<OrdinaryMorphism, OrdinaryMorphism>>>> criticalPairingInfo = tempHash .get(identityRule); // check if this rule pair is critical, if it is not, we do // nothing boolean isCritical = criticalPairingInfo.first.booleanValue(); if (!isCritical) { System.out.println("Not Critical"); } else { // criticalPairingInfo.second.size() gives no. of critical // overlappings for this rule pair System.out.println(" --- " + criticalPairingInfo.second.size() + " raw critical overlappings"); // actually get all these overlappings as a vector "keepers" Vector<Pair<Pair<OrdinaryMorphism, OrdinaryMorphism>, Pair<OrdinaryMorphism, OrdinaryMorphism>>> keepers = criticalPairingInfo.second; // temporary array to store all the overlappings, a copy of // keepers Vector<Pair<Pair<OrdinaryMorphism, OrdinaryMorphism>, Pair<OrdinaryMorphism, OrdinaryMorphism>>> vect = (Vector<Pair<Pair<OrdinaryMorphism, OrdinaryMorphism>, Pair<OrdinaryMorphism, OrdinaryMorphism>>>) criticalPairingInfo.second .clone(); // next we clear keepers, because this holds references to // what will be written back to file keepers.clear(); // the alreadyAdded Vector will store all the graphs which // are the result of applying our reaction rule to the // delete-use-conflict graph at their individual matches Vector<Graph> alreadyAdded = new Vector<Graph>(); // now we cycle through all the critical overlappings for // this reactionRule, identityRule pair, stored in vect for (int i = 0; i < vect.size(); i++) { // this morphism has on the LHS, a match for the // reaction rule, and on the RHS a delete-use-conflict // graph which holds information about critical graph // objects OrdinaryMorphism omToCheck = vect.elementAt(i).first.first .simplecopy(); // this is the morphism which will be passed to Olga's // method, its value depends on whether we are looking // at conflict pairs or dependency pairs OrdinaryMorphism toCheckwithRuleApplied = null; if (type == CONFLICT) { // just apply the reaction rule with the morphism // directly from the overlappings vector toCheckwithRuleApplied = makeStep(reactionRule, omToCheck); } else if (type == DEPENDENCY) { // for dependencies, we need to reverse the rule // somehow and apply this to the // produce-use-dependency graph, using the match // information given in that graph - NOT YET // SOLVED!!!! // these 2 lines create the inverse rule - this // works Pair<Pair<Rule,Boolean>, Pair<OrdinaryMorphism, OrdinaryMorphism>> tempPair = BaseFactory .theFactory().reverseRule(reactionRule); Rule tempRule = tempPair.first.first; if (tempRule == null) System.out.println("DEBUG : returned reversed rule is null!!!"); //OrdinaryMorphism omForMatch = omToCheck;//.invert(); //Match toCheckMatch = BaseFactory.theFactory().makeMatch(tempRule, omToCheck); //OrdinaryMorphism omForMatch = omForMatchPair.first; //Match toCheckMatch = omForMatch.makeMatch(tempRule); //if (toCheckMatch == null) // System.out.println("DEBUG : makematch result is null"); //tempRule.setMatch(toCheckMatch); //Match returnedMatch = tempRule.getMatch(); //if (returnedMatch == null) // System.out.println("DEBUG : no match returned"); /* * Graph tg = temp.getLeft(); * Enumeration<GraphObject> goenum = * tg.getElements(); int ecount = 0; while * (goenum.hasMoreElements()){ GraphObject go = * goenum.nextElement(); ecount++; } * System.out.println("ecount = " + ecount); */ // OrdinaryMorphism newMorph = toCheck; toCheckwithRuleApplied = makeStep(tempRule, omToCheck); } if (toCheckwithRuleApplied != null) { // the resulting graph after make step Graph graphToCheck = toCheckwithRuleApplied.getTarget(); // variable to indicate if an isomorphic result graph // already exists for the critical overlappings we have // decided to store boolean found = false; // check against all matches already accepted as unique for (int j = 0; j < alreadyAdded.size(); j++) { Graph graphToCompare = alreadyAdded.get(j); // check for isomorphism if (graphToCompare.isIsomorphicTo(graphToCheck)) { found = true; } } // end of looping through existing overlappings to // find if duplicate if (!found) { // if the overlapping is structurally unique, add it // to the keepers vector to be written back, and add // the resultgraph to existing graphs keepers.add(vect.elementAt(i)); alreadyAdded.add(graphToCheck); } } }// end of looping through all critical overlappings System.out.println("\t\tNo of unique overlappings : " + keepers.size()); // System.out.println("\t\tNo of Unique overlappings // recorded : " // + criticalPairingInfo.second.size()); }// end of critical check }// end of processing this identity rule }// end of processing this reaction rule } /** * This method was kindly provided by Olga Runge, an original author of the * AGG project. This has fixed the problem of altered information in the * rewritten cpx file resulting from applying rules (see the method I * devised without help in LoadCPXFile_v3.java (SVN) which used a new * subclass of DefaultGraTraImpl class of AGG) * * Try to apply the rule at the target graph of the overlapping morphism. * The match mapping is given by morphism mapping. * * @param rule * the first or the second rule of a critical pair * @param morph * the first or the second overlapping morphism of a critical * pair * * @return a comatch if successful, otherwise - null */ private OrdinaryMorphism makeStep(final Rule rule, final OrdinaryMorphism morph) { OrdinaryMorphism comatch = null; // make isocopy of the target graph final OrdinaryMorphism graphIso = morph.getTarget().isomorphicCopy(); // morphTest: morph.source -> graphIso.target, // the mappings are set like mappings of morph final OrdinaryMorphism morphTest = morph.compose(graphIso); // set variable context for attribute context because we do not work // with a host graph ((ContextView) morphTest.getAttrContext()).setVariableContext(true); // make a match from morphTest final Match match = BaseFactory.theFactory().makeMatch(rule, morphTest); if (match != null) { match.setCompletionStrategy(new Completion_InjCSP(), true); boolean isValid = match.isTotal() && match.isValid(true); if (isValid) { // final Step s = new Step(); try { comatch = (OrdinaryMorphism) StaticStep.execute(match, true); } catch (TypeException e) { System.out.println("s.execute : " + e.getMessage()); } } } else { System.out.println("DEBUG : Not a valid match!!!!!"); } return comatch; } // end of makeStep method /** * this method issues all necessary instructions to process the provided cpx * file's overlappings for structural equivalence * */ public void processFileForStructuralEquivalence() { System.out.println("\n\nREMOVING STRUCTURALLY EQUIVALENT OVERLAPPINGS\n"); System.out.println("Conflict Pairs:\n"); // reduce conflict pairs reduceStructurallyEquivalentOverlappings(getEpc() .getConflictContainer(), CONFLICT); // reduce dependency pairs System.out.println("\nDependency Pairs:\n"); reduceStructurallyEquivalentOverlappings(getDpc() .getDependencyContainer(), DEPENDENCY); System.out.println(); // write to new file try { System.out.println("Writing new overlappings to file \"" + getNewfilename() + "\"..."); writeToNewFile(); System.out.println("Finished!"); } catch (Exception e) { System.err.println("Error writing modded pairs to file!"); System.exit(-1); } } /** * Program to be called from terminal to reduce pairs that are structurally * equivalent. The filename should be passed as an argument to the command * line. * * @param args * */ public static void main(String[] args) { try { StructuralEquivalenceAnalysis sea = new StructuralEquivalenceAnalysis( args[0]); sea.processFileForStructuralEquivalence(); } catch (ArrayIndexOutOfBoundsException e) { System.err .println("There was an error loading your specified file - please try again!"); e.printStackTrace(); System.exit(-1); } }// end of main method }// end of class