package agg.xt_basis; import java.util.Enumeration; import java.util.Iterator; import java.util.List; import java.util.Vector; import java.util.Hashtable; import agg.attribute.AttrMapping; import agg.attribute.impl.VarTuple; import agg.attribute.impl.VarMember; import agg.attribute.impl.CondTuple; import agg.attribute.impl.CondMember; import agg.attribute.impl.ContextView; import agg.attribute.impl.AttrTupleManager; import agg.util.XMLHelper; import agg.util.XMLObject; import agg.xt_basis.csp.CompletionPropertyBits; /** * This class is used to represent matches (morphism from the left side graph * of a rule into a host graph). Note that not every instance of this class is a * valid match in terms of theory, because in theory a match has to be a total * morphism satisfying all (nested) application conditions of the * corresponding rule. The methods <code>isTotal()</code> and * <code>isValid()</code> can be used to check for these additional properties * dynamically. * * @see agg.xt_basis.Morphism#isTotal() * @see agg.xt_basis.Match#isValid() * @author $Author: olga $ * @version $Id: Match.java,v 1.88 2010/11/28 22:16:06 olga Exp $ */ public class Match extends OrdinaryMorphism implements XMLObject { private Rule itsRule; private boolean matchValid; private transient NACStarMorphism itsCurrentNACstar; private Hashtable<OrdinaryMorphism, NACStarMorphism> itsNACstars; private transient PACStarMorphism itsCurrentPACstar; private Hashtable<OrdinaryMorphism, PACStarMorphism> itsPACstars; // Totality, Identification, Dangling, Gluing; private boolean condsTIDGchecked = false; private boolean ignoreInParam; protected Match() { super(); } protected Match(final Rule rule, final Graph graph) { super(rule.getLeft(), graph); this.itsAttrContext = this.itsAttrManager.newContext(AttrMapping.MATCH_MAP, rule.getAttrContext()); this.itsRule = rule; this.itsName = "MatchOf_" + rule.getName(); if (!rule.getNACsList().isEmpty()) { this.itsNACstars = new Hashtable<OrdinaryMorphism, NACStarMorphism>(rule .getNACsList().size()); } if (!rule.getPACsList().isEmpty()) { this.itsPACstars = new Hashtable<OrdinaryMorphism, PACStarMorphism>(rule .getPACsList().size()); } } /** * Remove all graph object mappings and all relations to its source and target graphs. */ public void dispose() { this.condsTIDGchecked = false; if (this.itsNACstars != null) { Iterator<NACStarMorphism> nacStars = this.itsNACstars.values().iterator(); while (nacStars.hasNext()) { nacStars.next().dispose(); } this.itsNACstars.clear(); this.itsCurrentNACstar = null; } if (this.itsPACstars != null) { Iterator<PACStarMorphism> pacStars = this.itsPACstars.values().iterator(); while (pacStars.hasNext()) { pacStars.next().dispose(); } this.itsPACstars.clear(); this.itsCurrentPACstar = null; } this.itsRule = null; super.dispose(); // System.out.println("Match.dispose() DONE "+this+" "+this.getName()); } public void finalize() { } /** * Return true if this morphism can be completed basically. */ public boolean canComplete() { // check graph size if injective morphism if (this.itsCompleter.getProperties().get(CompletionPropertyBits.INJECTIVE) && !(this.itsRule instanceof ParallelRule) && (this.itsOrig.getNodesCount() > this.itsImag.getNodesCount() || this.itsOrig.getArcsCount() > this.itsImag.getArcsCount())) { return false; } // check types: all types of the orig. graph should be in image, too final Vector<Type> origTypes = this.itsOrig.getUsedTypes(); final Vector<Type> imagTypes = this.itsImag.getUsedAndInheritedTypes(); for (int i = 0; i < origTypes.size(); i++) { if (!imagTypes.contains(origTypes.get(i))) return false; } return true; } public void clear() { super.clear(); this.condsTIDGchecked = false; if (this.itsNACstars != null) { final Enumeration<OrdinaryMorphism> nacs = this.itsNACstars.keys(); while (nacs.hasMoreElements()) { NACStarMorphism nacStar = this.itsNACstars.get(nacs.nextElement()); // nacStar.clear(); // ((VarTuple) nacStar.getAttrContext().getVariables()) // .unsetNotInputVariables(); nacStar.dispose(); } this.itsNACstars.clear(); } if (this.itsPACstars != null) { final Enumeration<OrdinaryMorphism> pacs = this.itsPACstars.keys(); while (pacs.hasMoreElements()) { PACStarMorphism pacStar = this.itsPACstars.get(pacs.nextElement()); // pacStar.clear(); // ((VarTuple) pacStar.getAttrContext().getVariables()) // .unsetNotInputVariables(); pacStar.dispose(); } this.itsPACstars.clear(); } } public void resetTarget(Graph g) { clear(); this.itsCompleter.resetSolver(false); this.itsImag = g; this.itsCompleter.resetTypeMap(this.itsImag); this.typeObjectsMapChanged = true; if (this.itsNACstars != null) { final Enumeration<OrdinaryMorphism> keys = this.itsNACstars.keys(); while (keys.hasMoreElements()) this.itsNACstars.get(keys.nextElement()).setTarget(this.itsImag); } if (this.itsPACstars != null) { final Enumeration<OrdinaryMorphism> keys = this.itsPACstars.keys(); while (keys.hasMoreElements()) this.itsPACstars.get(keys.nextElement()).setTarget(this.itsImag); } } /** Return the rule that I am a match for. */ public final Rule getRule() { return this.itsRule; } /** * Returns an empty message or null if this match is valid, * otherwise - an error message. */ public String getErrorMsg() { /* if (super.errors.size()>0) { String result = "["; for (int i=0; i<super.errors.size(); i++) { if (i<1) result = result + super.errors.get(i)+"\n"; else { result = result + "..."+"\n"; break; } } result = result.substring(0, result.length()-1); result = result + "]"; return result; } */ return this.errorMsg; } public String getLastErrorMsg() { // if (super.errors.size()>0) // return super.errors.lastElement(); return this.errorMsg; } public void clearErrorMsg() { super.clearErrorMsg(); } /** * Returns FALSE if a node of the specified abstract type is found in the target graph * of this match, * otherwise - TRUE. */ public boolean checkAbstractGraphObject(final Type abstractNodeType) { final Iterator<Node> en = this.itsImag.getNodesSet().iterator(); while (en.hasNext()) { if (this.getTarget().isCompleteGraph() && abstractNodeType.isAbstract() && en.next().getType().equals(abstractNodeType)) return false; } return true; } /** * Checks existing variables of the attribute context against the attribute * context of its rule. Adjusts the attribute context of this match, if * needed. */ public void adjustAttrInputParameter(boolean inputParameterOnly) { final VarTuple vtR = (VarTuple) this.itsRule.getAttrContext().getVariables(); final VarTuple vtM = (VarTuple) this.itsAttrContext.getVariables(); for (int i = 0; i < vtR.getNumberOfEntries(); i++) { final VarMember vmR = vtR.getVarMemberAt(i); final VarMember vmM = vtM.getVarMemberAt(vmR.getName()); if (vmM != null) { if (vmR.getExpr() != null) { if (inputParameterOnly) { if (vmR.isInputParameter()) vmM.setExprAsText(vmR.getExprAsText()); } else vmM.setExprAsText(vmR.getExprAsText()); } vmM.setInputParameter(vmR.isInputParameter()); } } } /** * Checks existing attribute conditions of the attribute context against the * attribute context of its rule. Adjusts the attribute conditions of this * match, if needed. */ public void adjustAttrCondition() { final CondTuple ctRule = (CondTuple) this.itsRule.getAttrContext().getConditions(); final CondTuple ct = (CondTuple) this.itsAttrContext.getConditions(); for (int i = 0; i < ct.getNumberOfEntries(); i++) { final CondMember cm = ct.getCondMemberAt(i); final CondMember cmRule = ctRule.getCondMemberAt(i); if (cm != null && cmRule != null && cm.getExprAsText().equals(cmRule.getExprAsText())) { cm.setMark(cmRule.getMark()); cm.setEnabled(cmRule.isEnabled()); } } } /** * Set the value of the variables of the attribute context to null. */ public void unsetInputParameter(boolean inputParameterOnly) { final VarTuple vt = (VarTuple) this.itsAttrContext.getVariables(); for (int i = 0; i < vt.getNumberOfEntries(); i++) { VarMember vm = vt.getVarMemberAt(i); if (inputParameterOnly) { if (vm.isInputParameter()) vm.setExpr(null); } else vm.setExpr(null); } } public void allowToIgnoreInputParameter(boolean b) { this.ignoreInParam = b; } public boolean allowedToIgnoreInputParameter() { return this.ignoreInParam; } /* * Checks variable declarations and attribute conditions. * Use method getErrorMsg() to get found error. * private boolean isReadyToTransform() { final AttrVariableTuple avt = this.itsAttrContext.getVariables(); final Vector<String> names = avt.getVariableNames(); final Vector<Pair<String, String>> vars = getVariableDeclarations(); for (int i = 0; i < vars.size(); i++) { final Pair<String, String> p = vars.elementAt(i); if (!names.contains(p.second)) { if (isClassName(p.second) == null) { this.errorMsg = "The variable: " + p.second + " isn't declared!"; this.errors.add(this.errorMsg); return false; } } else { final VarMember vm = avt.getVarMemberAt(p.second); final String t_vm = vm.getDeclaration().getTypeName(); if (!p.first.equals(t_vm)) { this.errorMsg = "The type of the variable: " + p.second + " is wrong!"; this.errors.add(this.errorMsg); return false; } } } try { this.itsAttrContext.getVariables().getAttrManager() .checkIfReadyToTransform(this.itsAttrContext); } catch (AttrException ex) { this.errorMsg = ex.getLocalizedMessage(); if (this.errorMsg.length()>0) this.errors.add(this.errorMsg); return false; } return true; } */ public void resetVariableDomainOfCompletionStrategy(boolean b) { this.itsCompleter.resetVariableDomain(b); } /** * Set the algorithm of morphism completion. Class * <code>CompletionStrategySelector</code> provides a way to present and * obtain available algorithms. * * @see agg.xt_basis.CompletionStrategySelector */ public void setCompletionStrategy(final MorphCompletionStrategy s, boolean rewrite) { super.setCompletionStrategy(s, rewrite); if (this.itsRule != null) { this.itsCompleter.enableParallelSearch(this.itsRule.parallelMatching); this.itsCompleter.setStartParallelSearchByFirst(this.itsRule.startParallelMatchByFirstCSPVar); } } /** * Set the algorithm of morphism completion. Class * <code>CompletionStrategySelector</code> provides a way to present and * obtain available algorithms. * The given strategy is internally cloned to prevent undesired side effects. * @see agg.xt_basis.CompletionStrategySelector */ public void setCompletionStrategy(final MorphCompletionStrategy s) { super.setCompletionStrategy(s); if (this.itsRule != null) { this.itsCompleter.enableParallelSearch(this.itsRule.parallelMatching); this.itsCompleter.setStartParallelSearchByFirst(this.itsRule.startParallelMatchByFirstCSPVar); } } private void adjustCompletionStrategy() { if (this.typeObjectsMapChanged) { if (this.itsRule.parallelMatching) { this.itsCompleter.reset(); this.itsTouchedFlag = false; this.itsCompleter.resetSolverVariables(); this.itsCompleter.resetSolverQuery_Type(); } else { // System.out.println(this.getName()+" of "+this.getRule().getName()+" "+this.typeObjectsMapChanged); this.itsCompleter.resetVariableDomain(true); this.itsCompleter.reinitializeSolver(false); } this.typeObjectsMapChanged = false; } else if (this.itsRule.parallelMatching && this.itsRule.startParallelMatchByFirstCSPVar) { this.itsCompleter.reset(); this.itsTouchedFlag = false; this.itsCompleter.resetSolverVariables(); } if (this.partialMorphCompletion) { this.itsCompleter.setPartialMorphism(this); this.partialMorphCompletion = false; } } public boolean nextCompletionWithConstantsChecking() { adjustCompletionStrategy(); boolean result = super.nextCompletion(); // the method areTotalityIdentificationDanglingGluingSatisfied() // is called now in Completion_CSP.doNext for Match instance! return result; } public boolean nextCompletionWithConstantsAndVariablesChecking() { adjustCompletionStrategy(); boolean result = super.nextCompletion(); // the method areTotalityIdentificationDanglingGluingSatisfied() // is called now in Completion_CSP.doNext for Match instance! return result; } /** * Check totality, identification, dangling and attribute gluing conditions. */ public boolean areTotalIdentDanglAttrGluingSatisfied() { boolean res = true; if (!isTotal()) { this.errorMsg = "Match is not total!"; // this.errors.add(this.errorMsg); res = false; } else if (!isIdentSatisfied()) { this.errorMsg = "Identification condition is violated!"; // this.errors.add(this.errorMsg); res = false; } else if (!isDanglingSatisfied()) { this.errorMsg = "Dangling condition is violated!"; // this.errors.add(this.errorMsg); res = false; } else if (!attributesOfGlueObjectsCorrect()) { this.errorMsg = "Non-injective match failed!\n"+this.errorMsg; // this.errors.add(this.errorMsg); res = false; } this.condsTIDGchecked = true; this.matchValid = res; return res; } /** * Check totality, identification and dangling conditions. */ public boolean areTotalIdentDanglSatisfied() { boolean res = true; if (!isTotal()) { this.errorMsg = "Match is not total!"; // this.errors.add(this.errorMsg); res = false; } else if (!isIdentSatisfied()) { this.errorMsg = "Identification condition is violated!"; // this.errors.add(this.errorMsg); res = false; } else if (!isDanglingSatisfied()) { this.errorMsg = "Dangling condition is violated!"; // this.errors.add(this.errorMsg); res = false; } return res; } /* * Checks whether the parallel arcs possible in case the rule of this Match * creates a new arc between the nodes which are preserved. */ public boolean isParallelArcSatisfied() { // final Type arct, final Node src, final Node tar) { if (!this.itsOrig.getTypeSet().isArcParallel() && this.itsRule.isCreating()) { Iterator<Arc> arcs = this.itsRule.getImage().getArcsSet().iterator(); while (arcs.hasNext()) { Arc a = arcs.next(); if (this.itsRule.isArcCreating(a)) { Enumeration<GraphObject> enSrc = this.itsRule.getInverseImage(a.getSource()); while (enSrc.hasMoreElements()) { Enumeration<GraphObject> enTar = this.itsRule.getInverseImage(a.getTarget()); while (enTar.hasMoreElements()) { Node src = (Node)enSrc.nextElement(); Node tar = (Node)enTar.nextElement(); // check the source node in the this.itsRule.LHS already contains an arc like a if (src.hasArc(a.getType(), tar)) { // does this.itsRule delete a such arc if (this.itsRule.isArcDeleting(src, a.getType(), tar)) {} else { this.errorMsg = "No parallel edges allowed."; return false; } } // check the graph m.getImage() already contains an arc like a else if (((Node)this.getImage(src)).hasArc(a.getType(), (Node)this.getImage(tar))) { this.errorMsg = "No parallel edges allowed."; return false; } else if (!this.getImage().getTypeSet().isArcDirected() && ((Node)this.getImage(tar)).hasArc(a.getType(), (Node)this.getImage(src))) { this.errorMsg = "No parallel edges allowed."; return false; } } } } } } return true; } /** * * Checks if this is a valid match.<br> * There are two cases to use this method: * <ol> * <li> After the method <code>nextCompletion()</code> is called and returned with TRUE. * In this case the check of conditions: * <code>totality, identification and dangling, NACs and PACs</code> * - is already done and only check of: <code>node resp. edge type multiplicity</code> * and <code>post rule application conditions</code> - will be performed. * </li> * <li> * The match mapping is set manually and the method <code>nextCompletion()</code> was not called. * Then all checks: <code>totality, identification and dangling, NACs and PACs</code> , * <code>node resp. edge type multiplicity</code> * and <code>post rule application conditions</code> - will be performed. * </li> * </ol> * <br> * For each condition the appropriate matching option should be set. * <p> * The usage of variables in the work graph is not allowed. * * @return <code>true</code> iff this is a total morphism and all conditions * of its rule are satisfied. */ public final boolean isValid() { return isValid(false); } public boolean nextCompletion() { if (this.getOriginal().getTypeSet().getLevelOfTypeGraphCheck() == TypeSet.ENABLED_MAX_MIN) { TypeError error = this.itsRule.checkNewNodeRequiresArc(); if (error != null) { this.errorMsg = error.getMessage(); return false; } } adjustCompletionStrategy(); boolean result = super.nextCompletion(); // the method areTotalityIdentificationDanglingGluingSatisfied() // will be called in Completion_CSP.doNext for Match instance! return result; } /** * This method is like the method isValid(), * additionally, the usage of variables * in a work graph is possible. * * @return <code>true</code> iff this is a total morphism and all conditions * of its rule are satisfied. */ public final boolean isValid(boolean allowVariables) { if (!this.condsTIDGchecked) { this.matchValid = areTotalIdentDanglAttrGluingSatisfied(); } boolean result = this.matchValid; if (result) { // check multiplicity constraints int typeLevel = getImage().getTypeSet().getLevelOfTypeGraphCheck(); if (typeLevel > TypeSet.ENABLED && getRule().getConstraints().isEmpty()) { // long time0 = System.currentTimeMillis(); if (this.itsRule.isInjective() && this.isInjective()) { result = isTypeMultiplicitySatisfied(); } } // make test step to check (multiplicity) // rule post application condition if (result && (!getRule().getConstraints().isEmpty() || (!this.itsRule.isInjective() && typeLevel > TypeSet.ENABLED)) || (!this.isInjective() && typeLevel > TypeSet.ENABLED) ) { OrdinaryMorphism isocopy = getImage().isomorphicCopy(); if (isocopy != null) { isocopy.getImage().setName(getImage().getName()); isocopy.getImage().setCompleteGraph(getImage().isCompleteGraph()); OrdinaryMorphism com = this.compose(isocopy); if (com != null) { Match m2 = BaseFactory.theFactory().makeMatch(getRule(), com); OrdinaryMorphism comatch = null; if (m2 != null) { comatch = makeTestStep(m2, allowVariables); if (comatch == null) { // errorMsg set in makeTestStep result = false; } else {// check consistency // errorMsg set in isConsistent result = result && isConsistent(comatch, m2); comatch.dispose(); } m2.dispose(); } com.dispose(); } else { result = false; } isocopy.dispose(false, true); if (typeLevel > TypeSet.ENABLED) this.getTarget().getTypeSet().setLevelOfTypeGraphCheck(TypeSet.ENABLED); this.getTarget().getTypeSet().setLevelOfTypeGraphCheck(typeLevel); } else { result = false; } } } this.matchValid = result; if (this.matchValid) clearErrorMsg(); return this.matchValid; } /** * Checks attribute condition of type <code>CondMember</code> which is enabled, * is marking by <code>CondMember.LHS</code>, all used variables are definite (set). * When at least one of these points failed, returns true. */ public boolean checkAttrCondition() { CondTuple conds = (CondTuple) this.getAttrContext().getConditions(); for (int i = 0; i < conds.getSize(); i++) { CondMember cond = conds.getCondMemberAt(i); if (!cond.isEnabled() || cond.getMark() != CondMember.LHS) { continue; } if (cond.isDefinite() && ! cond.isTrue()) { this.errorMsg = "Attribute condition [ " + cond.getExprAsText() + " ] failed."; ((VarTuple) this.getAttrContext().getVariables()).unsetVariables(); this.removeAllMappings(); return false; } } return true; } public boolean areGACsSatisfied() { return this.itsRule.evalFormula(); } public boolean areNACsSatisfied() { if (getCompletionStrategy().getProperties().get( CompletionPropertyBits.NAC)) { final List<OrdinaryMorphism> nacs = this.itsRule.getNACsList(); for (int l=0; l<nacs.size(); l++) { final OrdinaryMorphism nac = nacs.get(l); if (!nac.isEnabled()) continue; if (checkNAC(nac) != null) { this.errorMsg = "NAC \"" + nac.getName() + "\" is violated!"; // this.errors.add(this.errorMsg); return false; } } } return true; } public boolean arePACsSatisfied() { if (getCompletionStrategy().getProperties().get( CompletionPropertyBits.PAC)) { final List<OrdinaryMorphism> pacs = this.itsRule.getPACsList(); for (int l=0; l<pacs.size(); l++) { final OrdinaryMorphism pac = pacs.get(l); if (!pac.isEnabled()) continue; if (checkPAC(pac) == null) { this.errorMsg = "PAC \"" + pac.getName() + "\" is violated!"; // this.errors.add(this.errorMsg); return false; } } } return true; } public boolean areNACsSatisfied(boolean withVars) { if (withVars) { if (getCompletionStrategy().getProperties().get( CompletionPropertyBits.NAC)) { final List<OrdinaryMorphism> nacs = this.itsRule.getNACsList(); for (int l=0; l<nacs.size(); l++) { final OrdinaryMorphism nac = nacs.get(l); if (!nac.isEnabled()) continue; if (checkNAC(nac, true) != null) { this.errorMsg = "NAC \"" + nac.getName() + "\" is violated!"; // this.errors.add(this.errorMsg); return false; } } } return true; } return areNACsSatisfied(); } public boolean arePACsSatisfied(boolean withVars) { if (withVars) { if (getCompletionStrategy().getProperties().get( CompletionPropertyBits.PAC)) { final List<OrdinaryMorphism> pacs = this.itsRule.getPACsList(); for (int l=0; l<pacs.size(); l++) { final OrdinaryMorphism pac = pacs.get(l); if (!pac.isEnabled()) continue; if (checkPAC(pac, true) == null) { this.errorMsg = "PAC \"" + pac.getName() + "\" is violated!"; // this.errors.add(this.errorMsg); return false; } } } return true; } return arePACsSatisfied(); } /** * Check if this match satisfies the given negative application condition. * * @return <code>null</code> if <code>nac</code> is satisfied; otherwise * the morphism between <code>nac.getImage()</code> and * <code>this.getImage()</code>. * Note that the returned morphism is only valid until * the next call of <code>nextCompletion()</code> or * <code>checkNAC()</code>. * * <p> * <b>Pre:</b> * <ol> * <li><code>this.isTotal()</code>. * <li><code>nac.isTotal()</code>. (This is what theory demands. The * implementation works for partial NACs as well.) * </ol> */ public final Morphism checkNAC(final OrdinaryMorphism nac) { // 1. variante // destroyNACstar(this.itsCurrentNACstar); // this.itsCurrentNACstar = createNACstar(nac); // 2. variante this.itsCurrentNACstar = this.itsNACstars.get(nac); if (this.itsCurrentNACstar == null) { this.itsCurrentNACstar = MatchHelper.createNACstar(nac, this); this.itsNACstars.put(nac, this.itsCurrentNACstar); } else { this.itsCurrentNACstar.reinit(this.getAttrContext()); } // try to construct nacstar morphism such that nacstar after nac // commutes with match: Morphism m = MatchHelper.checkNACStar(this.itsCurrentNACstar, nac, this, false); if (m != null) { this.errorMsg = "NAC \"" + nac.getName() + "\" is violated!"; // this.errors.add(this.errorMsg); } return m; } /** * Check if this match satisfies the given negative application condition. * If the second parameter <code>withVars</code> is true, then the graph to check * may contain variables as attribute values of nodes and edges. * otherwise all attribute must be set by constants or java class instances. * * @return <code>null</code> if <code>nac</code> is satisfied; otherwise * the morphism between <code>nac.getImage()</code> and * <code>this.getImage()</code>. * Note that the returned morphism is only valid until * the next call of <code>nextCompletion()</code> or * <code>checkNAC()</code>. * * <p> * <b>Pre:</b> * <ol> * <li><code>this.isTotal()</code>. * <li><code>nac.isTotal()</code>. (This is what theory demands. The * implementation works for partial NACs as well.) * </ol> */ public final Morphism checkNAC(final OrdinaryMorphism nac, boolean withVars) { // destroyNACstar(this.itsCurrentNACstar); // this.itsCurrentNACstar = createNACstar(nac, withVars); if (withVars) // set variable context ((AttrTupleManager) AttrTupleManager.getDefaultManager()) .setVariableContext(true); this.itsCurrentNACstar = this.itsNACstars.get(nac); if (this.itsCurrentNACstar == null) { this.itsCurrentNACstar = MatchHelper.createNACstar(nac, this, withVars); this.itsNACstars.put(nac, this.itsCurrentNACstar); } else { this.itsCurrentNACstar.reinit(this.getAttrContext()); } // try to construct nacstar morphism such that nacstar after nac // commutes with match: Morphism m = MatchHelper.checkNACStar(this.itsCurrentNACstar, nac, this, withVars); if (withVars) // now unset variable context ((AttrTupleManager) AttrTupleManager.getDefaultManager()) .setVariableContext(false); if (m != null) { this.errorMsg = "NAC \"" + nac.getName() + "\" is violated!"; // this.errors.add(this.errorMsg); } return m; } /** * Check if this match satisfies the given positive application condition. * * @return <code>null</code> if <code>pac</code> is not satisfied; * otherwise the morphism between <code>pac.getImage()</code> and * <code>this.getImage()</code>. * Note that returned morphism is only valid * until the next call of <code>nextCompletion()</code> or * <code>checkPAC()</code>. * * <p> * <b>Pre:</b> * <ol> * <li><code>this.isTotal()</code>. * <li><code>pac.isTotal()</code>. (This is what theory demands. The * implementation works for partial PACs as well.) * </ol> */ public final Morphism checkPAC(final OrdinaryMorphism pac) { // destroyPACstar(this.itsCurrentPACstar); // this.itsCurrentPACstar = createPACstar(pac); this.itsCurrentPACstar = this.itsPACstars.get(pac); if (this.itsCurrentPACstar == null) { this.itsCurrentPACstar = MatchHelper.createPACstar(pac, this); this.itsPACstars.put(pac, this.itsCurrentPACstar); } else { this.itsCurrentPACstar.reinit(this.getAttrContext()); } // try to construct pacstar morphism such that pacstar after pac // commutes with match: Morphism m = MatchHelper.checkPACStar(this.itsCurrentPACstar, pac, this, false); if (m == null) { this.errorMsg = "PAC \"" + pac.getName() + "\" is violated!"; // this.errors.add(this.errorMsg); } return m; } /** * Check if this match satisfies the given positive application condition. * If the second parameter <code>withVars</code> is true, then the graph to check * may contain variables as attribute values of nodes and edges. * otherwise all attribute must be set by constants or java class instances. * * @return <code>null</code> if <code>pac</code> is not satisfied; * otherwise the morphism between <code>pac.getImage()</code> and * <code>this.getImage()</code>. * Note that returned morphism is only valid * until the next call of <code>nextCompletion()</code> or * <code>checkPAC()</code>. * * <p> * <b>Pre:</b> * <ol> * <li><code>this.isTotal()</code>. * <li><code>pac.isTotal()</code>. (This is what theory demands. The * implementation works for partial PACs as well.) * </ol> */ public final Morphism checkPAC(final OrdinaryMorphism pac, boolean withVars) { // destroyPACstar(this.itsCurrentPACstar); // this.itsCurrentPACstar = createPACstar(pac, withVars); if (withVars) // set variable context ((AttrTupleManager) AttrTupleManager.getDefaultManager()) .setVariableContext(true); this.itsCurrentPACstar = this.itsPACstars.get(pac); if (this.itsCurrentPACstar == null) { this.itsCurrentPACstar = MatchHelper.createPACstar(pac, this, withVars); this.itsPACstars.put(pac, this.itsCurrentPACstar); } else { this.itsCurrentPACstar.reinit(this.getAttrContext()); } // try to construct pacstar morphism such that pacstar after pac // commutes with match: Morphism m = MatchHelper.checkPACStar(this.itsCurrentPACstar, pac, this, withVars); if (withVars) // now unset variable context ((AttrTupleManager) AttrTupleManager.getDefaultManager()) .setVariableContext(false); if (m == null) { this.errorMsg = "PAC \"" + pac.getName() + "\" is violated!"; // this.errors.add(this.errorMsg); } return m; } public void enableInputParameter(final boolean enable) { final VarTuple vars = (VarTuple) this.getAttrContext().getVariables(); for (int i=0; i<vars.getNumberOfEntries(); i++) { VarMember vm = vars.getVarMemberAt(i); if (vm.isInputParameter()) { vm.setEnabled(enable); enableAttrConditionWithInputParameter(vm.getName(), enable); } } } private void enableAttrConditionWithInputParameter(final String ipName, final boolean enable) { final CondTuple conds = (CondTuple) this.getAttrContext().getConditions(); for (int i=0; i<conds.getNumberOfEntries(); i++) { CondMember cond = conds.getCondMemberAt(i); if (cond.getAllVariables().contains(ipName)) { cond.setEnabled(enable); } } } public void unsetVariables() { final VarTuple vars = (VarTuple) this.getAttrContext().getVariables(); final VarTuple rulevars = (VarTuple) this.itsRule.getAttrContext().getVariables(); for (int i = 0; i < vars.getSize(); i++) { VarMember vm = vars.getVarMemberAt(i); VarMember rulevm = rulevars.getVarMemberAt(i); if (!vm.isInputParameter()) { ((ContextView)this.getAttrContext()).removeValue(vm.getName()); ((ContextView)this.itsRule.getAttrContext()).removeValue(rulevm.getName()); } } } /* private void unsetVariablesOfNAC(final AttrContext attrContext, final OrdinaryMorphism nac) { final VarTuple vars = (VarTuple)attrContext.getVariables(); final Vector<String> nacVars = nac.getTarget().getVariableNamesOfAttributes(); for (int i = 0; i < vars.getSize(); i++) { VarMember vm = vars.getVarMemberAt(i); if (nacVars.contains(vm.getName()) && (vm.getMark() == VarMember.NAC) && !vm.isInputParameter()) { ((ContextView)attrContext).removeValue(vm.getName()); } } } private void unsetVariablesOfPAC(final AttrContext attrContext, final OrdinaryMorphism pac) { final VarTuple vars = (VarTuple)attrContext.getVariables(); final Vector<String> pacVars = pac.getTarget().getVariableNamesOfAttributes(); for (int i = 0; i < vars.getSize(); i++) { VarMember vm = vars.getVarMemberAt(i); if (pacVars.contains(vm.getName()) && (vm.getMark() == VarMember.PAC) && !vm.isInputParameter()) { ((ContextView)attrContext).removeValue(vm.getName()); } } } */ public boolean isAttrConditionSatisfied() { final CondTuple ct = (CondTuple) getAttrContext().getConditions(); for (int k = 0; k < ct.getSize(); k++) { CondMember cm = ct.getCondMemberAt(k); if ((cm.getMark() == CondMember.LHS) && !cm.isTrue()) { // ((VarTuple)this.getAttrContext().getVariables()).showVariables(); return false; } } return true; } public boolean hasInputParamInAttrCondition() { Vector<String> names = ((CondTuple) getAttrContext().getConditions()).getAllVariables(); VarTuple vars = (VarTuple)this.getAttrContext().getVariables(); for (int k = 0; k < names.size(); k++) { String n = names.get(k); VarMember var = vars.getVarMemberAt(n); if (var != null && var.isInputParameter()) return true; } return false; } /** * Check Identification condition for non-injective match objects. * They are must be preserved. * @return <code>true</code> if error message was null or empty, otherwise - <code>false</code> */ public boolean isIdentSatisfied() { this.errorMsg = MatchHelper.isIdentSatisfied(this); return (this.errorMsg == null || this.errorMsg.equals("")); } /** * Check Dangling condition for nodes to delete. * All edges of the image node must have a pre-image in the match. * @return <code>true</code> if error message was null or empty, otherwise - <code>false</code> */ public boolean isDanglingSatisfied() { this.errorMsg = MatchHelper.isDanglingSatisfied(this); return (this.errorMsg == null || this.errorMsg.equals("")); } protected void checkEdgeSourceTargetCompatibility( final GraphObject orig, final GraphObject image) throws BadMappingException { try { MatchHelper.checkSourceTargetCompatibilityOfEdge(this, orig, image); } catch (BadMappingException ex) { throw ex; } } /* private boolean checkVariableToNullMappping() { if (this.getSource().isAttributed()) return MatchHelper.checkVariableToNullMappping(this); else return true; } */ /** * Checks multiplicity of node resp. edge types due to the type graph of * the given match. * * @return true if type multiplicity satisfied, otherwise false. */ public boolean isTypeMultiplicitySatisfied() { this.errorMsg = MatchHelper.isTypeMultiplicitySatisfied(this); return (this.errorMsg == null || this.errorMsg.equals("")); } /** * Checks multiplicity of node resp. edge types due to the type graph of * the given match. * * @return true if type multiplicity satisfied, otherwise false. */ public boolean isTypeMaxMultiplicitySatisfied() { this.errorMsg = MatchHelper.isTypeMultiplicitySatisfied(this); return (this.errorMsg == null || this.errorMsg.equals("")); } private OrdinaryMorphism makeTestStep(final Match m2, boolean allowVariables) { // make test step to check post conditions: // - type graph constraints ( edge type multiplicity ) // - graph constraints final OrdinaryMorphism co_match = MatchHelper.makeTestStep(m2, allowVariables, false); if (co_match == null) { this.errorMsg = MatchHelper.errorMsg; } return co_match; } private boolean isConsistent(final OrdinaryMorphism testComatch, final OrdinaryMorphism testMatch) { this.errorMsg = MatchHelper.isConsistent(this.itsRule, testComatch, testMatch); // this.errors.add(this.errorMsg); return (this.errorMsg == null || this.errorMsg.equals("")); } private boolean attributesOfGlueObjectsCorrect() { this.errorMsg = MatchHelper.attributesOfGlueObjectsCorrect(this); return (this.errorMsg == null || this.errorMsg.equals("")); } public void XwriteObject(XMLHelper h) { h.openNewElem("Match", this); writeMorphism(h); h.close(); } public void XreadObject(XMLHelper h) { if (h.isTag("Match", this)) { readMorphism(h); h.close(); } } }