/** * */ package agg.xt_basis.agt; import java.util.Enumeration; import java.util.Hashtable; import java.util.List; import java.util.Vector; import agg.attribute.AttrConditionTuple; import agg.attribute.AttrContext; import agg.attribute.AttrMapping; import agg.attribute.AttrVariableTuple; import agg.attribute.impl.CondMember; import agg.attribute.impl.CondTuple; import agg.attribute.impl.VarMember; import agg.attribute.impl.VarTuple; import agg.util.XMLHelper; import agg.xt_basis.BadMappingException; import agg.xt_basis.BaseFactory; import agg.xt_basis.Graph; import agg.xt_basis.GraphKind; import agg.xt_basis.GraphObject; import agg.xt_basis.Match; import agg.xt_basis.MorphCompletionStrategy; import agg.xt_basis.NestedApplCond; import agg.xt_basis.OrdinaryMorphism; import agg.xt_basis.Rule; import agg.xt_basis.Type; import agg.xt_basis.TypeSet; /** * This class implements an interaction rule scheme * which contains a kernel rule (subrule) * and a set of multi rules (extending rules). * The kernel rule is a common subaction of multi rules * and it is used for synchronization of parallel application of multi rules. * This kind of rule application is known as amalgamated graph transformation. * * @author olga */ public class RuleScheme extends Rule //implements Observer { private String schemeName = "RuleScheme"; private int itsIndex = -1; private boolean hasInputParameter; private boolean valid; private KernelRule kernelRule; private final List<Rule> multiRules = new Vector<Rule>(); private AmalgamatedRule amalgamRule; private Hashtable<GraphObject, GraphObject> amalgamLHS2kernelLHS; private Hashtable<GraphObject, GraphObject> amalgamRHS2kernelRHS; private boolean parallelKernel; private boolean disjointMultis = true; private boolean checkDeleteUseConflict = true; private boolean atLeastOneMultiMatch; private boolean shiftDone; /** * Create new rule scheme with an empty kernel rule * and empty set of multi rules. * * @param aSchemeName * @param types */ public RuleScheme(final String aSchemeName, TypeSet types) { super(types); super.trimToSize(); this.itsName = aSchemeName; this.schemeName = aSchemeName; this.kernelRule = new KernelRule(types); this.kernelRule.setRuleScheme(this); // this.kernelRule.getLeft().addObserver(this); // this.kernelRule.getRight().addObserver(this); } /** * Create new rule scheme with the given kernel rule. * The typeSet of this RuleScheme is the TypeSet of the KernelRule. */ public RuleScheme(final String aSchemeName, KernelRule kernel) { super(kernel.getTypeSet()); super.trimToSize(); this.itsName = aSchemeName; this.schemeName = aSchemeName; this.kernelRule = kernel; this.kernelRule.setRuleScheme(this); // this.kernelRule.getLeft().addObserver(this); // this.kernelRule.getRight().addObserver(this); } /* * Create new rule scheme with a kernel rule based on the specified * left and right graphs * and empty set of multi rules. * * @param aSchemeName * @param leftOfKernelRule left graph of its kernel rule * @param rightOfKernelRule right graph of its kernel rule * public RuleScheme( final String aSchemeName, final Graph leftOfKernelRule, final Graph rightOfKernelRule) { super(leftOfKernelRule.getTypeSet()); this.itsName = aSchemeName; this.schemeName = aSchemeName; this.kernelRule = new KernelRule(leftOfKernelRule, rightOfKernelRule); this.kernelRule.setRuleScheme(this); // this.kernelRule.getLeft().addObserver(this); // this.kernelRule.getRight().addObserver(this); } */ public boolean hasNestedACs() { boolean hasGACs = this.kernelRule.hasNestedACs(); for (int i=0; i<this.multiRules.size(); i++) { hasGACs = hasGACs || this.multiRules.get(i).hasNestedACs(); } return hasGACs; } /** * Creates if needed a match of the kernel rule. * * @param graph host graph to apply the kernel rule * @return match of the kernel rule */ public Match getKernelMatch(final Graph graph) { if (this.kernelRule.getMatch() == null) { this.kernelRule.setMatch(BaseFactory.theFactory().createMatch(this.kernelRule, graph)); } return this.kernelRule.getMatch(); } /** * Clears existing match of the kernel and multi rules. */ public void clearMatches() { if (this.kernelRule.getMatch() != null) { this.kernelRule.getMatch().dispose(); this.kernelRule.setMatch(null); } this.clearMatchesOfMultiRules(); this.unsetAttrContextVars(); // for super rule of this RuleScheme this.clear(); ((VarTuple) this.getAttrContext().getVariables()).unsetVariables();//InputParameters(); } public void unsetAttrContextVars() { ((VarTuple) this.kernelRule.getAttrContext().getVariables()).unsetVariables(); int s = ((VarTuple) this.kernelRule.getAttrContext().getVariables()).getSize(); for (int j = 0; j < s; j++) { (((VarTuple) this.kernelRule.getAttrContext().getVariables()).getVarMemberAt(j)).setExpr(null); } for (int i=0; i<this.multiRules.size(); i++) { final MultiRule multiRule = (MultiRule) this.multiRules.get(i); ((VarTuple) multiRule.getAttrContext().getVariables()).unsetVariables();//InputParameters(); s = ((VarTuple) multiRule.getAttrContext().getVariables()).getSize(); for (int j = 0; j < s; j++) { (((VarTuple) multiRule.getAttrContext().getVariables()).getVarMemberAt(j)).setExpr(null); } } } public void showAttrContextVars() { ((VarTuple) this.kernelRule.getAttrContext().getVariables()).showVariables(); for (int i=0; i<this.multiRules.size(); i++) { final MultiRule multiRule = (MultiRule) this.multiRules.get(i); ((VarTuple) multiRule.getAttrContext().getVariables()).showVariables();//InputParameters(); } } public void clearMatchesOfMultiRules() { for (int i=0; i<this.multiRules.size(); i++) { final MultiRule multiRule = (MultiRule) this.multiRules.get(i); if (multiRule.getMatch() != null) { multiRule.getMatch().dispose(); multiRule.setMatch(null); } } } public void disposeMatch() { this.clearMatches(); this.unsetAttrContextVars(); if (this.amalgamRule != null) { if (this.amalgamRule.getMatch() != null) this.amalgamRule.getMatch().dispose(); } } /** * Destroys current amalgamated rule and its amalgamated match. */ public void disposeAmalgamatedRule() { this.clearMatches(); this.unsetAttrContextVars(); if (this.amalgamRule != null) { if (this.amalgamRule.getMatch() != null) this.amalgamRule.getMatch().dispose(); this.amalgamRule.dispose(); this.amalgamRule = null; } } /** * Destroys this RuleScheme instance . */ public void dispose() { super.dispose(); this.clearMatches(); if (this.amalgamRule != null) { this.amalgamRule.dispose(); this.amalgamRule = null; } for (int i=0; i<this.multiRules.size(); i++) { this.multiRules.get(i).dispose(); } this.multiRules.clear(); this.kernelRule.dispose(); } /** * Returns a copy of this rule scheme by using its types. */ public RuleScheme getClone() { return BaseFactory.theFactory().cloneRuleScheme(this); } /** * Returns a copy of this rule scheme by using the specified types. */ public RuleScheme getClone(TypeSet types) { return BaseFactory.theFactory().cloneRuleScheme(this, types); } /** * Replicate new rule mapping of the kernel rule. * * @param leftgo graph object of the LHS of the kernel rule * @param rightgo graph object of the RHS of the kernel rule * @throws BadMappingException */ public void propagateAddRuleMappingToMultiRule( final GraphObject leftgo, final GraphObject rightgo) throws BadMappingException { for(int i=0; i<this.multiRules.size(); i++) { final MultiRule multiRule = (MultiRule) this.multiRules.get(i); try { GraphObject objL = multiRule.getEmbeddingLeft().getImage(leftgo); GraphObject objR = multiRule.getEmbeddingRight().getImage(rightgo); if (objL != null && objR != null) multiRule.addMapping(objL, objR); } catch (BadMappingException ex) { System.out.println("RuleScheme.propagateCreatedMappingToMultiRule: " +ex.getLocalizedMessage()); throw ex; } } } /** * Replicate remove rule mapping of the kernel rule. * * @param go graph object of the kernel rule * @param left true if graph object belongs to the LHS of the kernel rule, * otherwise false */ public void propagateRemoveRuleMappingToMultiRule( final GraphObject go, boolean left) { for(int i=0; i<this.multiRules.size(); i++) { final MultiRule multiRule = (MultiRule) this.multiRules.get(i); if (left) { GraphObject objL = multiRule.getEmbeddingLeft().getImage(go); if (objL != null) multiRule.removeMapping(go); } else { GraphObject objR = multiRule.getEmbeddingRight().getImage(go); if (objR != null && this.getInverseImage(objR).hasMoreElements()) multiRule.removeMapping(this.getInverseImage(go).nextElement()); } } } /** * Checks the left, right and rule morphism embedding of the kernel rule. * * @return true if embedding holds, otherwise false */ public boolean isAmalgamable() { this.errorMsg = null; for(int i=0; i<this.multiRules.size(); i++) { final MultiRule multiRule = (MultiRule) this.multiRules.get(i); if (!multiRule.isLeftEmbeddingValid() || !multiRule.isRightEmbeddingValid() || !multiRule.isMorphismEmbeddingValid()) { this.errorMsg = multiRule.getName(); return false; } } return true; } /** * The methods <code>storeIndexOfRuleList</code> and <code>getStoredIndexOfRuleList</code> used * by GraGra class during save and load procedure of the XML object only.<br> * Stores the index of the current RuleScheme. */ public void storeIndexOfRuleList(int i) { this.itsIndex = i; } /** * The methods <code>storeIndexOfRuleList</code> and <code>getStoredIndexOfRuleList</code> used * by GraGra class during save and load procedure of the XML object only.<br> * Returns loaded index of the current RuleScheme * which is the index inside the rule list after the XML object loaded.<br> */ public int getStoredIndexOfRuleList() { return this.itsIndex; } /** * Trims the capacity of used vectors to be the vector's current * size. */ public void trimToSize() { this.kernelRule.trimToSize(); for(int i=0; i<this.multiRules.size(); i++) { this.multiRules.get(i).trimToSize(); } } public void setName(String aName) { this.schemeName = aName; this.itsName = this.schemeName; } public void setSchemeName(final String aName) { this.schemeName = aName; this.itsName = this.schemeName; } public String getSchemeName() { return this.schemeName; } /** * Sets its layer. The layer is used by layered grammar. */ public void setLayer(int l) { this.layer = l; this.kernelRule.setLayer(l); for (int i=0; i<this.multiRules.size(); i++) { this.multiRules.get(i).setLayer(l); } } public void setCheckDeleteUseConflictRequired(boolean b) { this.checkDeleteUseConflict = b; } public boolean checkDeleteUseConflictRequired() { return this.checkDeleteUseConflict; } public void setAtLeastOneMultiMatchRequired(boolean b) { this.atLeastOneMultiMatch = b; } public boolean atLeastOneMultiMatchRequired() { return this.atLeastOneMultiMatch; } /** * Requires that all matches of the multi rules are disjoint. * If false, then the multi rules have to be conflict free. * * @param b true if disjoint, otherwise false */ public void setDisjointMultiMatches(boolean b) { this.disjointMultis = b; } /** * @return true if disjoint, otherwise false */ public boolean disjointMultiMatches() { return this.disjointMultis; } /** * Allows to construct an amalgamated rule based on all possible disjoint * matches of the kernel rule. * @param b true in case of all possible disjoint matches of the kernel rule, * false in case of a single match of the kernel rule */ public void setParallelKernelMatch(boolean b) { this.parallelKernel = b; } /** * * @return true if parallel matches of the kernel rule, otherwise false */ public boolean parallelKernelMatch() { return this.parallelKernel; } public RuleScheme getRuleScheme() { return this; } public Rule getKernelRule() { return this.kernelRule; } public MultiRule getMultiRule(final Graph g) { for (int i = 0; i<this.multiRules.size(); i++) { final Rule multiRule = this.multiRules.get(i); if (multiRule.getLeft() == g || multiRule.getRight() == g) return (MultiRule)multiRule; } return null; } public MultiRule getMultiRule(int index) { if (index >= 0 && index < this.multiRules.size()) return (MultiRule) this.multiRules.get(index); return null; } public MultiRule getLastMultiRule() { return (MultiRule) this.multiRules.get(this.multiRules.size()-1); } public boolean isLastMultiRule(final Rule r) { return (this.multiRules.get(this.multiRules.size()-1) == r); } public Rule getRule(final String rulename) { if (this.getName().equals(rulename)) return this; else if (this.kernelRule.getName().equals(rulename) || rulename.equals(this.itsName+"."+this.kernelRule.getName())) return this.kernelRule; else { for(int i=0; i<this.multiRules.size(); i++) { final MultiRule multiRule = (MultiRule) this.multiRules.get(i); if (multiRule.getName().equals(rulename) || rulename.equals(this.itsName+"."+multiRule.getName())) return multiRule; } } return null; } public Rule getRuleByQualifiedName(final String rname) { if (this.getName().equals(rname)) return this; else if (this.kernelRule.getName().equals(rname) || rname.equals(this.itsName+"."+this.kernelRule.getName())) return this.kernelRule; else { for(int i=0; i<this.multiRules.size(); i++) { final MultiRule multiRule = (MultiRule) this.multiRules.get(i); if (multiRule.getName().equals(rname) || rname.equals(this.itsName+"."+multiRule.getName())) return multiRule; } } return null; } public List<Rule> getMultiRules() { return this.multiRules; } public int getCountOfMultiRules() { return this.multiRules.size(); } public Rule addMultiRule(final String name) { final MultiRule r = this.createMultiRule(name); this.kernelRule.getLeft().addObserver(r); this.kernelRule.getRight().addObserver(r); this.kernelRule.addObserver(r); return r; } public boolean isRuleOfScheme(final Rule r) { if (this == r) return true; else if (this.amalgamRule == r) return true; else if (this.kernelRule == r) return true; else { for(int i=0; i<this.multiRules.size(); i++) { if (this.multiRules.get(i) == r) return true; } } return false; } public void setAmalgamatedRule(final AmalgamatedRule amalgamRule) { this.amalgamRule = amalgamRule; if (this.amalgamRule != null) this.amalgamRule.setRuleScheme(this); } private AmalgamatedRule createAmalgamatedRule(final Graph g, final MorphCompletionStrategy s) { final Covering cov = new Covering(this, g, s); if (cov.amalgamate()) { this.errorMsg = ""; this.amalgamRHS2kernelRHS = cov.getRHSMappingAmalgamToKernelRule(); this.amalgamLHS2kernelLHS = cov.getLHSMappingAmalgamToKernelRule(); return cov.getAmalgamatedRule(); } this.errorMsg = cov.getErrorMessage(); return null; } /** * @deprecated replaced by getRHSKernelOfAmalgamRuleObject */ public GraphObject getKernelOfAmalgamRuleObject(final GraphObject amalgamObj) { return this.amalgamRHS2kernelRHS.get(amalgamObj); } public GraphObject getLHSKernelOfAmalgamRuleObject(final GraphObject amalgamObj) { return this.amalgamLHS2kernelLHS.get(amalgamObj); } public GraphObject getRHSKernelOfAmalgamRuleObject(final GraphObject amalgamObj) { return this.amalgamRHS2kernelRHS.get(amalgamObj); } /** * Constructs amalgamated rule of the specified host graph. * * @param g host graph * @return amalgamated rule */ public AmalgamatedRule getAmalgamatedRule(final Graph g, final MorphCompletionStrategy s) { this.amalgamRule = createAmalgamatedRule(g, s); return this.amalgamRule; } /** * Returns existing amalgamated rule, otherwise null. */ public AmalgamatedRule getAmalgamatedRule() { return this.amalgamRule; } public void removeAmalgamatedRule() { if (this.amalgamRule != null) { this.amalgamRule.setRuleScheme(null); this.amalgamRule.dispose(); this.amalgamRule = null; } } /** * Checks the kernel rule and all enabled multi rules are ready to transform. */ public boolean isValid() { this.valid = this.isReadyToTransform(); return this.valid; } public boolean isElement(Graph g) { if (this.kernelRule.isElement(g)) { return true; } for (int i=0; i<this.multiRules.size(); i++) { Rule r = this.multiRules.get(i); if (r.isElement(g)) return true; } return false; } public void refreshAttributed() { this.kernelRule.refreshAttributed(); for (int i=0; i<this.multiRules.size(); i++) { this.multiRules.get(i).refreshAttributed(); } } public boolean isUsingType(GraphObject typeObj) { if (this.kernelRule.isUsingType(typeObj)) { return true; } for (int i=0; i<this.multiRules.size(); i++) { if (this.multiRules.get(i).isUsingType(typeObj)) return true; } return false; } /** * Returns true if the kernel rule or ones of multi rules does require an input parameter, * otherwise false. */ public boolean hasInputParameter() { return this.hasInputParameter; } /** * If possible, creates amalgamated rule and match of this rule scheme * at the specified host graph. * @param g host graph * @return amalgamated match, otherwise null */ public Match getMatch(final Graph g, final MorphCompletionStrategy s) { if (this.hasInputParameter) { applyValueOfInputParameter(); } this.amalgamRule = createAmalgamatedRule(g, s); if (this.amalgamRule != null) { this.amalgamRule.setWaitBeforeApplyEnabled(this.isWaitBeforeApplyEnabled()); return this.amalgamRule.getMatch(); } return null; } /** * Returns existing amalgamated match, otherwise null. */ public Match getMatch() { if (this.amalgamRule != null) { this.amalgamRule.setWaitBeforeApplyEnabled(this.isWaitBeforeApplyEnabled()); return this.amalgamRule.getMatch(); } return null; } /** * Returns true, if its kernel rule or one of the multi rules * contains enabled nested application conditions. */ public boolean hasEnabledACs(boolean checkBefore) { if (checkBefore) { this.hasEnabledGACs = this.kernelRule.hasEnabledACs(checkBefore); if (!this.hasEnabledGACs) { for (int i=0; i<this.multiRules.size(); i++) { if (this.multiRules.get(i).isEnabled() && this.multiRules.get(i).hasEnabledACs(checkBefore)) { this.hasEnabledGACs = true; break; } } } } return this.hasEnabledGACs; } /** * Returns true if this rule scheme will create new graph elements, * otherwise - false. */ public boolean isCreating() { // LHS graph size > rule mapping size this.isCreating = this.kernelRule.isCreating(); for (int i=0; i<this.multiRules.size() && !this.isCreating; i++) { this.isCreating = this.multiRules.get(i).isCreating(); } return this.isCreating; } /** * Returns true if this rule scheme will delete some graph elements, * otherwise - false. */ public boolean isDeleting() { // LHS graph size > rule mapping size this.isDeleting = this.kernelRule.isDeleting(); for (int i=0; i<this.multiRules.size() && !this.isDeleting; i++) { this.isDeleting = this.multiRules.get(i).isDeleting(); } return this.isDeleting; } /** * Returns true if this rule scheme will delete at least one node, * otherwise - false. */ public boolean isNodeDeleting() { this.isNodeDeleting = this.kernelRule.isNodeDeleting(); for (int i=0; i<this.multiRules.size() && !this.isNodeDeleting; i++) { this.isNodeDeleting = this.multiRules.get(i).isNodeDeleting(); } return this.isNodeDeleting; } /** * Checks the kernel rule and all enabled multi rules be ready to transform. */ public boolean isReadyToTransform() { this.valid = false; if (!this.kernelRule.isReadyToTransform()) { return false; } for (int i=0; i<this.multiRules.size(); i++) { if (this.multiRules.get(i).isEnabled() && !this.multiRules.get(i).isReadyToTransform()) return false; } this.valid = true; return true; } /** * Checks whether its kernel rule is applicable at the specified graph by the * specified matching strategy or not. */ public boolean isApplicable( final Graph g, final MorphCompletionStrategy strategy, final boolean doCheckIfReadyToTransform) { boolean result = this.enabled; if (result && doCheckIfReadyToTransform) { result = this.isReadyToTransform(); } if (result) { result = false; Match m = BaseFactory.theFactory().createMatch(this.kernelRule, g); if (m != null) { m.setCompletionStrategy(strategy, true); m.enableInputParameter(false); // ((VarTuple) this.getAttrContext().getVariables()).showVariables(); // ((VarTuple) m.getAttrContext().getVariables()).showVariables(); if (m.nextCompletion()) { result = true; } m.dispose(); } } return result; } public void setApplicable(boolean appl) { this.applicable = appl; this.kernelRule.setApplicable(appl); } public boolean isInputParameterSet(boolean left) { Rule r = this.kernelRule; this.addToAttrContext((VarTuple) r.getAttrContext().getVariables()); if (r.getMatch() != null) { this.adaptAttrContextValues(r.getMatch().getAttrContext()); } else { this.adaptAttrContextValues(r.getAttrContext()); } // ((VarTuple) this.getAttrContext().getVariables()).showVariables(); for (int i=0; i<this.multiRules.size(); i++) { r = this.multiRules.get(i); if (r.isEnabled()) { this.addToAttrContext((VarTuple) r.getAttrContext().getVariables()); if (r.getMatch() != null) { this.adaptAttrContextValues(r.getMatch().getAttrContext()); } } } // ((VarTuple) this.getAttrContext().getVariables()).showVariables(); return isInputParameterSet(this.getAttrContext(), left); } /** * If the kernel rule is using an input parameter and its value is already set * do propagate this value to the attribute context of multi rules. */ public void applyValueOfInputParameter() { final VarTuple vars = (VarTuple) this.getAttrContext().getVariables(); for (int i = 0; i < vars.getNumberOfEntries(); i++) { final VarMember v = vars.getVarMemberAt(i); if (v.isInputParameter() && v.isSet()) { VarMember vm = ((VarTuple) this.kernelRule.getAttrContext().getVariables()) .getVarMemberAt(v.getName()); if (vm != null && (vm.getExpr() == null || !v.getExprAsText().equals(vm.getExprAsText()))) { // vm.setExprAsText(v.getExprAsText()); vm.setExpr(v.getExpr()); } for (int j=0; j<this.multiRules.size(); j++) { vm = ((VarTuple) this.multiRules.get(j).getAttrContext().getVariables()) .getVarMemberAt(v.getName()); if (vm != null && (vm.getExpr() == null || !v.getExprAsText().equals(vm.getExprAsText()))) { // vm.setExprAsText(v.getExprAsText()); vm.setExpr(v.getExpr()); } } } } // System.out.println("applyValueOfInputParameter... "+this.kernelRule.getName()); // ((VarTuple) this.kernelRule.getAttrContext().getVariables()).showVariables(); // for (int j=0; j<this.multiRules.size(); j++) { // System.out.println("applyValueOfInputParameter... "+this.multiRules.get(j).getName()); // ((VarTuple) this.multiRules.get(j).getAttrContext().getVariables()).showVariables(); // } } private boolean leftGraphIsUsingVariable(final VarMember var) { if (this.kernelRule.getLeft().isUsingVariable(var)) { return true; } else if (nacIsUsingVariable(var, this.kernelRule.getAttrContext().getConditions(), this.kernelRule.getNACsList())) { return true; } else if (pacIsUsingVariable(var, this.kernelRule.getAttrContext().getConditions(), this.kernelRule.getPACsList())) { return true; } for (int i=0; i<this.multiRules.size(); i++) { if (this.multiRules.get(i).getLeft().isUsingVariable(var)) { return true; } else if (nacIsUsingVariable(var, this.multiRules.get(i).getAttrContext().getConditions(), this.multiRules.get(i).getNACsList())) { return true; } else if (pacIsUsingVariable(var, this.multiRules.get(i).getAttrContext().getConditions(), this.multiRules.get(i).getPACsList())) { return true; } } return false; } private boolean nacIsUsingVariable( final VarMember var, final AttrConditionTuple act, final List<OrdinaryMorphism> nacs) { for (int l=0; l<nacs.size(); l++) { final OrdinaryMorphism nac = nacs.get(l); if (nac.getTarget().isUsingVariable(var)) { return true; } Vector<String> nacVars = nac.getTarget() .getVariableNamesOfAttributes(); for (int j = 0; j < nacVars.size(); j++) { String varName = nacVars.get(j); for (int k = 0; k < act.getNumberOfEntries(); k++) { CondMember cond = (CondMember) act.getMemberAt(k); Vector<String> condVars = cond.getAllVariables(); if (condVars.contains(varName) && condVars.contains(var.getName())) { return true; } } } } return false; } private boolean pacIsUsingVariable( final VarMember var, final AttrConditionTuple act, final List<OrdinaryMorphism> pacs) { for (int l=0; l<pacs.size(); l++) { final OrdinaryMorphism pac = pacs.get(l); if (pac.getTarget().isUsingVariable(var)) { return true; } Vector<String> pacVars = pac.getTarget() .getVariableNamesOfAttributes(); for (int j = 0; j < pacVars.size(); j++) { String varName = pacVars.get(j); for (int k = 0; k < act.getNumberOfEntries(); k++) { CondMember cond = (CondMember) act.getMemberAt(k); Vector<String> condVars = cond.getAllVariables(); if (condVars.contains(varName) && condVars.contains(var.getName())) { return true; } } } } return false; } private boolean rightGraphIsUsingVariable(final VarMember var) { if (this.kernelRule.getRight().isUsingVariable(var)) { return true; } for (int i=0; i<this.multiRules.size(); i++) { if (this.multiRules.get(i).getRight().isUsingVariable(var)) { return true; } } return false; } private boolean isInputParameterSet(final AttrContext attrContext, boolean left) { AttrVariableTuple avt = attrContext.getVariables(); for (int i = 0; i < avt.getNumberOfEntries(); i++) { VarMember v = avt.getVarMemberAt(i); if (v.isInputParameter()) { this.hasInputParameter = true; if (!v.isSet()) { if (left && leftGraphIsUsingVariable(v)) { return false; } else if (!left && rightGraphIsUsingVariable(v)) { return false; } } } } return true; } /* Create an empty multi rule. */ protected MultiRule createEmptyMultiRule() { MultiRule mr = new MultiRule(this.kernelRule.getTypeSet()); mr.setEmbeddingLeft(new OrdinaryMorphism( this.kernelRule.getLeft(), mr.getLeft(), agg.attribute.impl.AttrTupleManager .getDefaultManager().newContext(AttrMapping.PLAIN_MAP))); mr.setEmbeddingRight(new OrdinaryMorphism( this.kernelRule.getRight(), mr.getRight(), agg.attribute.impl.AttrTupleManager .getDefaultManager().newContext(AttrMapping.PLAIN_MAP))); mr.setRuleScheme(this); // test: use xy position as attributes mr.getLeft().xyAttr = this.kernelRule.getLeft().xyAttr; mr.getRight().xyAttr = this.kernelRule.getLeft().xyAttr; this.multiRules.add(mr); return mr; } /** Create new multi rule with embedding of the kernel rule. */ public MultiRule createMultiRule(final String ruleName) { OrdinaryMorphism embL = this.kernelRule.getLeft().plainCopy(); if (embL == null) { embL = new OrdinaryMorphism( this.kernelRule.getLeft(), BaseFactory.theFactory().createGraph(this.kernelRule.getLeft().getTypeSet(), false), agg.attribute.impl.AttrTupleManager .getDefaultManager().newContext(AttrMapping.PLAIN_MAP)); } OrdinaryMorphism embR = this.kernelRule.getRight().plainCopy(); if (embR == null) { embR = new OrdinaryMorphism( this.kernelRule.getRight(), BaseFactory.theFactory().createGraph(this.kernelRule.getRight().getTypeSet(), false), agg.attribute.impl.AttrTupleManager .getDefaultManager().newContext(AttrMapping.PLAIN_MAP)); } MultiRule multiRule = new MultiRule(this.kernelRule, embL, embR); // add only variables of LHS and RHS if (this.kernelRule.hasNACs() || this.kernelRule.hasPACs()) { final Vector<String> list = this.kernelRule.getLeft().getVariableNamesOfAttributes(); list.addAll(this.kernelRule.getRight().getVariableNamesOfAttributes()); multiRule.addToAttrContextAccordingList( (VarTuple)this.kernelRule.getAttrContext().getVariables(), list); } else { multiRule.addToAttrContext( (VarTuple)this.kernelRule.getAttrContext().getVariables()); } multiRule.setRuleScheme(this); multiRule.setName(ruleName); multiRule.getLeft().setKind(GraphKind.LHS); multiRule.getRight().setKind(GraphKind.RHS); // test: use xy position as attributes multiRule.getLeft().xyAttr = this.kernelRule.getLeft().xyAttr; multiRule.getRight().xyAttr = this.kernelRule.getLeft().xyAttr; this.multiRules.add(multiRule); this.kernelRule.getLeft().addObserver(multiRule); this.kernelRule.getRight().addObserver(multiRule); this.kernelRule.addObserver(multiRule); this.kernelRule.setChanged(false); return multiRule; } /** Remove all multi rules. */ public void removeMultiRules(){ this.multiRules.clear(); } /** Remove the specified multi rule. */ public void removeMultiRule(Rule r) { if (this.multiRules.contains(r)) { this.multiRules.remove(r); } } /** * Propagate application conditions (NAC / PAC) of the kernel rule along embedding morphism of each multi rule * (left embedding: kernel.LHS -> multi.LHS, right embedding: kernel.RHS -> multi.RHS). * Propagated application conditions are added to the list of the own * application conditions of each multi rule. */ public void propagateApplCondsOfKernelToMultiRules() { if (!this.shiftDone) { for (int j=0; j<this.multiRules.size(); j++) { Rule mRule = this.multiRules.get(j); if (mRule.isEnabled()) { shiftApplCondsOfKernelToMultiRule((MultiRule)mRule); } } this.shiftDone = true; } } /** * Shift application conditions (NAC / PAC) of the kernel rule along embedding morphism of the given multi rule * (left embedding: kernel.LHS -> multi.LHS, right embedding: kernel.RHS -> multi.RHS). * Shifted application condition is added to the list of the own * application conditions of the multi rule. */ private boolean shiftApplCondsOfKernelToMultiRule(final MultiRule multiRule) { // shift PACS List<OrdinaryMorphism> kernConds = this.kernelRule.getPACsList(); for (int i=0; i<kernConds.size(); i++) { OrdinaryMorphism kernCond = kernConds.get(i); if (kernCond.isEnabled()) { OrdinaryMorphism shiftCond = this.shiftApplCondAlongMorph( kernCond, multiRule.getEmbeddingLeft()); if (shiftCond != null) { shiftCond.setName(kernCond.getName().concat("(shifted)")); shiftCond.setEnabled(kernCond.isEnabled()); multiRule.addShiftedKernelApplCond(shiftCond, true); this.shiftDone = true; } } } // shift NACs kernConds = this.kernelRule.getNACsList(); for (int i=0; i<kernConds.size(); i++) { OrdinaryMorphism kernCond = kernConds.get(i); if (kernCond.isEnabled()) { OrdinaryMorphism shiftCond = this.shiftApplCondAlongMorph( kernCond, multiRule.getEmbeddingLeft()); if (shiftCond != null) { shiftCond.setName(kernCond.getName().concat("(shifted)")); shiftCond.setEnabled(kernCond.isEnabled()); multiRule.addShiftedKernelApplCond(shiftCond, false); this.shiftDone = true; } } } // shift NestedACs kernConds = this.kernelRule.getNestedACsList(); for (int i=0; i<kernConds.size(); i++) { if (kernConds.get(i) instanceof NestedApplCond) { NestedApplCond kernCond = (NestedApplCond) kernConds.get(i); if (kernCond.isEnabled()) { NestedApplCond shiftCond = this.shiftNestedApplCondAlongEmbMorphism( kernCond, multiRule.getEmbeddingLeft(), this.kernelRule.getRight().getAttrContext()); if (shiftCond != null) { shiftCond.setName(kernCond.getName().concat("(shifted)")); shiftCond.setEnabled(kernCond.isEnabled()); multiRule.addShiftedKernelNestedApplCond(shiftCond); this.shiftDone = true; } } } else break; } addAttrCondsOfKernelToMultiRule(multiRule); return true; } public void removeShiftedApplConditionsFromMultiRules() { for (int i=0; i<this.multiRules.size(); i++) { Rule mRule = this.multiRules.get(i); ((MultiRule) mRule).removeShiftedKernelApplConds(); this.removeAttrCondsOfKernelFromMultiRule(mRule); } this.shiftDone = false; } private void addAttrCondsOfKernelToMultiRule(final Rule multiRule) { CondTuple kernConds = (CondTuple)this.kernelRule.getAttrContext().getConditions(); CondTuple multiConds = (CondTuple)multiRule.getAttrContext().getConditions(); for (int i=0; i<kernConds.getNumberOfEntries(); i++) { String kernCond = kernConds.getCondMemberAt(i).getExprAsText(); if (!multiConds.contains(kernCond)) { CondMember cm = (CondMember)multiConds.addCondition(0, kernCond); cm.setShifted(true); } } } private void removeAttrCondsOfKernelFromMultiRule(final Rule multiRule) { CondTuple conds = (CondTuple)multiRule.getAttrContext().getConditions(); for (int i=0; i<conds.getNumberOfEntries(); i++) { CondMember cond = conds.getCondMemberAt(i); if (cond.isShifted()) { conds.getTupleType().deleteMemberAt(i); i--; } } } /** Create mapping pairs of objects of the embedding morphisms. */ private void mapKernel2MultiObject(final MultiRule multiRule) { final OrdinaryMorphism embLeft = multiRule.getEmbeddingLeft(); final Enumeration<GraphObject> domLeft = embLeft.getDomain(); while (domLeft.hasMoreElements()) { final GraphObject kern = domLeft.nextElement(); multiRule.mapKernel2MultiObject(kern, embLeft.getImage(kern)); } // final Enumeration<GraphObject> enLeft = multiRule.getLeft().getElements(); // while (enLeft.hasMoreElements()) { // final GraphObject obj = enLeft.nextElement(); // if (embLeft.getInverseImage(obj).hasMoreElements()){ // multiRule.mapKernel2MultiObject(embLeft.getInverseImage(obj).nextElement(), obj); // } // } final OrdinaryMorphism embRight = multiRule.getEmbeddingRight(); final Enumeration<GraphObject> domRight = embRight.getDomain(); while (domRight.hasMoreElements()) { final GraphObject kern = domRight.nextElement(); multiRule.mapKernel2MultiObject(kern, embRight.getImage(kern)); } // final Enumeration<GraphObject> enRight = multiRule.getRight().getElements(); // while (enRight.hasMoreElements()) { // final GraphObject obj = enRight.nextElement(); // if (embRight.getInverseImage(obj).hasMoreElements()) { // multiRule.mapKernel2MultiObject(embRight.getInverseImage(obj).nextElement(), obj); // } // } } public void createAttrInstanceWhereNeeded() { this.kernelRule.createAttrInstanceWhereNeeded(); for (int i=0; i<this.multiRules.size(); i++) { this.multiRules.get(i).createAttrInstanceWhereNeeded(); } } public void createAttrInstanceOfTypeWhereNeeded(final Type t) { this.kernelRule.createAttrInstanceOfTypeWhereNeeded(t); for (int i=0; i<this.multiRules.size(); i++) { this.multiRules.get(i).createAttrInstanceOfTypeWhereNeeded(t); } } /** * Shift the specified application condition (NAC / PAC / General AC) along the specified embedding morphism. * Required:<br> * cond.getSource() == embedding.getSource()<br> * Result morphism:<br> * embedding.getTarget() -> copy of cond.getSource() * * @param cond an application condition * @param morph an embedding morphism * @return shifted application condition, Returns null if shifting failed. */ private OrdinaryMorphism shiftApplCondAlongMorph( final OrdinaryMorphism cond, final OrdinaryMorphism morph) { if (cond.getSource() == morph.getSource()) { final OrdinaryMorphism condIso = cond.getTarget().isomorphicCopy(); if (condIso == null) return null; final OrdinaryMorphism shiftCond = (cond instanceof NestedApplCond)? BaseFactory.theFactory().createGeneralMorphism(morph.getTarget(), condIso.getTarget()) : BaseFactory.theFactory().createMorphism(morph.getTarget(), condIso.getTarget()); final Enumeration<GraphObject> condDom = cond.getDomain(); while (condDom.hasMoreElements()) { GraphObject go = condDom.nextElement(); GraphObject condImg = cond.getImage(go); if (condImg != null) { GraphObject embedImg = morph.getImage(go); GraphObject isoImg = condIso.getImage(condImg); if (embedImg != null && isoImg != null) { try { shiftCond.addMapping(embedImg, isoImg); } catch (BadMappingException ex) { shiftCond.dispose(); condIso.dispose(false, true); return null; } } else { shiftCond.dispose(); condIso.dispose(false, true); return null; } } } return shiftCond; } return null; } private NestedApplCond shiftNestedApplCondAlongEmbMorphism( final NestedApplCond cond, final OrdinaryMorphism embedding, final AttrContext ac) { if (cond.getSource() == embedding.getSource()) { final OrdinaryMorphism condIso = cond.getTarget().isomorphicCopy(); if (condIso == null) return null; final NestedApplCond shiftCond = new NestedApplCond( embedding.getTarget(), condIso.getTarget(), ac); if (this.propagateMapping(cond, shiftCond, embedding, condIso)) { for (int i=0; i<cond.getNestedACs().size(); i++) { NestedApplCond nc = cond.getNestedACAt(i); final NestedApplCond shiftnc = shiftNestedApplCondAlongEmbMorphism( nc, condIso, cond.getAttrContext()); if (shiftnc != null) { shiftnc.setName(nc.getName()); shiftnc.setEnabled(nc.isEnabled()); shiftCond.addNestedAC(shiftnc); } else return null; } return shiftCond; } shiftCond.dispose(); condIso.dispose(); } return null; } private boolean propagateMapping( final OrdinaryMorphism from, final OrdinaryMorphism to, final OrdinaryMorphism above1, final OrdinaryMorphism above2) { final Enumeration<GraphObject> condDom = from.getDomain(); while (condDom.hasMoreElements()) { GraphObject go = condDom.nextElement(); GraphObject condImg = from.getImage(go); if (condImg != null) { GraphObject embedImg = above1.getImage(go); GraphObject isoImg = above2.getImage(condImg); if (embedImg != null && isoImg != null) { try { to.addMapping(embedImg, isoImg); } catch (BadMappingException ex) { return false; } } // else // return false; } } return true; } /* (non-Javadoc) * @see java.util.Observer#update(java.util.Observable, java.lang.Object) * public void update(Observable o, Object arg) { } */ /** Save the rule scheme. * @param h AGG XML helper */ public void XwriteObject(XMLHelper h) { h.openNewElem("RuleScheme", this); h.addAttr("name", this.schemeName); if (!this.enabled) h.addAttr("enabled", "false"); h.addAttr("disjointMultis", String.valueOf(this.disjointMultis)); h.addAttr("parallelKernel", String.valueOf(this.parallelKernel)); h.addAttr("checkConflict", String.valueOf(this.checkDeleteUseConflict)); h.addAttr("atLeastOneMultiMatch", String.valueOf(this.atLeastOneMultiMatch)); h.addAttr("index", this.itsIndex); // String namestr = this.schemeName; h.openSubTag("Kernel"); h.addObject("", this.kernelRule, true); h.close(); for (int i=0; i<this.multiRules.size(); i++) { h.openSubTag("Multi"); final MultiRule r = (MultiRule) this.multiRules.get(i); h.addObject("", r, true); h.openSubTag("EmbeddingLeft"); r.getEmbeddingLeft().writeMorphism(h); h.close(); h.openSubTag("EmbeddingRight"); r.getEmbeddingRight().writeMorphism(h); h.close(); h.close(); } if (this.amalgamRule != null) { h.openSubTag("Amalgamated"); h.addObject("", this.amalgamRule, true); h.close(); // if (this.amalgamRule.getMatch() != null) { // this.amalgamRule.getMatch().setName("MatchOf_" + this.amalgamRule.getName()); // h.openSubTag("MatchOf"); // h.addObject("Rule", this.amalgamRule, false); // h.addObject("", this.amalgamRule.getMatch(), true); // h.close(); // } } // TaggedValue layer h.openSubTag("TaggedValue"); h.addAttr("Tag", "layer"); h.addAttr("TagValue", this.layer); h.close(); // TaggedValue priority h.openSubTag("TaggedValue"); h.addAttr("Tag", "priority"); h.addAttr("TagValue", this.priority); h.close(); h.close(); } /** Load the rule scheme. * @param h AGG XML helper */ public void XreadObject(XMLHelper h) { if (h.isTag("RuleScheme", this)) { Object attr_str = ""; // setSchemeName(h.readAttr("name")); attr_str = h.readAttr("atLeastOneMultiMatch"); if (!"".equals(attr_str)) { this.atLeastOneMultiMatch = Boolean.valueOf((String) attr_str).booleanValue(); } attr_str = h.readAttr("checkConflict"); if (!"".equals(attr_str)) { this.checkDeleteUseConflict = Boolean.valueOf((String) attr_str).booleanValue(); } attr_str = h.readAttr("disjointMultis"); if (!"".equals(attr_str)) { this.disjointMultis = Boolean.valueOf((String) attr_str).booleanValue(); } attr_str = h.readAttr("enabled"); if (!"".equals(attr_str)) { this.enabled = Boolean.valueOf((String) attr_str).booleanValue(); } attr_str = h.readAttr("index"); if (!"".equals(attr_str)) { this.itsIndex = Integer.valueOf((String) attr_str).intValue(); } attr_str = h.readAttr("name"); if (!"".equals(attr_str)) { setSchemeName((String) attr_str); } attr_str = h.readAttr("parallelKernel"); if (!"".equals(attr_str)) { this.parallelKernel = Boolean.valueOf((String) attr_str).booleanValue(); } // String namestr = this.schemeName; if (h.readSubTag("Kernel")) { this.kernelRule.getLeft().setKind(GraphKind.LHS); this.kernelRule.getRight().setKind(GraphKind.RHS); this.kernelRule.setRuleScheme(this); h.getObject("", this.kernelRule, true); h.close(); } while (h.readSubTag("Multi")) { MultiRule mr = createEmptyMultiRule(); mr.getLeft().setKind(GraphKind.LHS); mr.getRight().setKind(GraphKind.RHS); mr.setRuleScheme(this); h.getObject("", mr, true); if (h.readSubTag("EmbeddingLeft")) { mr.getEmbeddingLeft().readMorphism(h); h.close(); } if(h.readSubTag("EmbeddingRight")) { mr.getEmbeddingRight().readMorphism(h); h.close(); } h.close(); mr.applyEmbeddedRuleMapping(this.kernelRule); mapKernel2MultiObject(mr); this.kernelRule.getLeft().addObserver(mr); this.kernelRule.getRight().addObserver(mr); } this.kernelRule.setChanged(false); // if (h.readSubTag("Amalgamated")) { // this.amalgamRule = new AmalgamatedRule(this.getTypeSet()); // h.getObject("", amalgamRule, true); // h.close(); // this.amalgamRule.setRuleScheme(this); // // if (h.readSubTag("MatchOf")) { // Object obj = h.getObject("Rule", null, false); // if (obj instanceof Rule) { // Rule r = (Rule) obj; // Match m = createMatch(r); // h.getObject("Match", m, true); // if (m.getSize() > 0) // m.setPartialMorphismCompletion(true); // } // h.close(); // } // } // read layer if (h.readSubTag("TaggedValue")) { int v = 0; String t = h.readAttr("Tag"); // read new attribute int v2 = h.readIAttr("TagValue"); if (v2 > 0) v = v2; if (t.equals("layer")) this.layer = v; h.close(); } // read priority if (h.readSubTag("TaggedValue")) { int v = 0; String t = h.readAttr("Tag"); // read new attribute int v2 = h.readIAttr("TagValue"); if (v2 > 0) v = v2; if (t.equals("priority")) this.priority = v; h.close(); } h.close(); } } }