// $Id: Solution_Backjump_PartialInj.java,v 1.4 2010/09/23 08:26:52 olga Exp $ // $Log: Solution_Backjump_PartialInj.java,v $ // Revision 1.4 2010/09/23 08:26:52 olga // tuning // // Revision 1.3 2010/06/09 10:24:31 olga // tuning // // Revision 1.2 2010/03/24 21:48:45 olga // search strategy of parallel rule // // Revision 1.1 2010/03/23 16:08:39 olga // new class for matching parallel rule // // Revision 1.34 2010/03/08 15:50:35 olga // code optimizing // // Revision 1.33 2010/03/04 14:13:42 olga // code optimizing // // Revision 1.32 2010/02/22 14:43:23 olga // code optimizing // // Revision 1.31 2009/11/23 09:02:45 olga // tests // // Revision 1.30 2009/10/15 13:53:48 olga // tuning // // Revision 1.29 2009/10/05 08:53:25 olga // RSA check - bug fixed // // Revision 1.28 2009/05/28 13:18:29 olga // Amalgamated graph transformation - development stage // // Revision 1.27 2009/05/12 10:36:53 olga // CPA: bug fixed // Applicability of Rule Seq. : bug fixed // // Revision 1.26 2009/02/12 13:03:38 olga // Some optimization of match searching // // Revision 1.25 2008/07/30 14:42:59 olga // Graph layouting tuning // // Revision 1.24 2008/07/30 14:03:37 olga // Graph Transformation - bug fixed // // Revision 1.23 2008/07/30 06:27:14 olga // Applicability of RS , concurrent rule - handling of attributes improved // // Revision 1.22 2008/04/21 09:32:19 olga // Visualization of inheritance edge - bugs fixed // Graph layout tuning // // Revision 1.21 2008/04/07 09:36:55 olga // Code tuning: refactoring + profiling // Extension: CPA - two new options added // // Revision 1.20 2007/12/10 08:42:58 olga // CPA of grammar with node type inheritance for attributed graphs - bug fixed // // Revision 1.19 2007/12/03 08:35:12 olga // - Some bugs fixed in visualization of morphism mappings after deleting and creating // nodes, edges // - implemented: matching with non-injective NAC and Match morphism // // Revision 1.18 2007/11/19 08:48:41 olga // Some GUI usability mistakes fixed. // Default values in node/edge of a type graph implemented. // Code tuning. // // Revision 1.17 2007/11/05 09:18:19 olga // code tuning // // Revision 1.16 2007/11/01 09:58:19 olga // Code refactoring: generic types- done // // Revision 1.15 2007/10/17 14:48:02 olga // EdRule: bug fixed // Code tuning // // Revision 1.14 2007/10/11 15:03:38 olga // code tuning // // Revision 1.13 2007/09/17 10:50:01 olga // Bug fixed in graph transformation by rules with NACs and PACs . // AGG help docus extended by new implemented features. // // Revision 1.12 2007/09/10 13:05:10 olga // In this update: // - package xerces2.5.0 is not used anymore; // - class com.objectspace.jgl.Pair is replaced by the agg own generic class agg.util.Pair; // - bugs fixed in: usage of PACs in rules; match completion; // usage of static method calls in attr. conditions // - graph editing: added some new features // // Revision 1.11 2007/05/07 07:59:35 olga // CSP: extentions of CSP variables concept // // Revision 1.10 2007/04/24 07:08:45 olga // undo/redo match mappings // // Revision 1.9 2007/01/31 09:19:28 olga // Bug fixed in case of transformating attributed grammar with inheritance and non-injective match // // Revision 1.8 2007/01/11 10:21:17 olga // Optimized Version 1.5.1beta , free for tests // // Revision 1.7 2006/12/13 13:33:04 enrico // reimplemented code // // Revision 1.6 2006/11/15 09:00:32 olga // Transform with input parameter : bug fixed // // Revision 1.5 2006/11/06 10:09:36 olga // Type editor GUI tuning // // Revision 1.4 2006/11/01 11:17:29 olga // Optimized agg sources of CSP algorithm, match usability, // graph isomorphic copy, // node/edge type multiplicity check for injective rule and match // // Revision 1.3 2006/05/08 08:24:12 olga // Some extentions of GUI: - Undo Delete button of tool bar to undo deletions // if grammar elements like rule, NAC, graph constraints; // - the possibility to add a new graph to a grammar or a copy of the current // host graph; // - to set one or more layer for consistency constraints. // Also some bugs fixed of matching and some optimizations of CSP algorithmus done. // // Revision 1.2 2006/04/20 11:58:39 olga // Attr type check: Bug fixed // // Revision 1.1 2005/08/25 11:56:55 enrico // *** empty log message *** // // Revision 1.2 2005/06/20 13:37:04 olga // Up to now the version 1.2.8 will be prepared. // // Revision 1.1 2005/05/30 12:58:01 olga // Version with Eclipse // // Revision 1.10 2004/12/20 14:53:48 olga // Changes because of matching optimisation. // // Revision 1.9 2004/05/06 17:23:27 olga // graph matching OK // // Revision 1.8 2004/04/28 12:46:38 olga // test CSP // // Revision 1.7 2004/01/28 17:58:38 olga // Errors suche // // Revision 1.6 2004/01/22 17:50:08 olga // test // // Revision 1.5 2004/01/15 16:43:06 olga // Korrektur an transformation // // Revision 1.4 2003/12/18 16:27:25 olga // . // // Revision 1.3 2003/03/05 18:24:25 komm // sorted/optimized import statements // // Revision 1.2 2002/12/04 14:00:19 komm // code newly formated for debuging // // Revision 1.1.1.1 2002/07/11 12:17:26 olga // Imported sources // // Revision 1.5 2000/05/17 11:58:38 olga // Testversion fuer Gabi mit diversen Aenderungen. Fehler sind moeglich!! // // Revision 1.4 1999/07/14 09:08:51 olga // Umstellung auf JAVA2.0 // Zum Testen oeffnet sich nur in // Transform/Step der InputParameterEditor // Verbesserung von GUI und AttrEditor // // Revision 1.3 1999/06/28 16:36:05 shultzke // Hoffentlich erzeigen wir eine uebersetzungsfaehige Version // // Revision 1.2 1998/04/07 14:21:00 mich // Updated for use with JGL V3.1. // // Revision 1.1 1997/12/26 21:17:13 mich // Initial revision // // ******************************************** // *** moved from util.csp.impl to util.csp *** // ******************************************** // // Revision 1.5 1997/10/15 07:37:50 mich // + Now checks preinstantiated Variables for consistency. // Tested. // // Revision 1.4 1997/09/23 14:14:42 mich // + option for injective solutions coded into the state machine. // Tested. // // Revision 1.3 1997/09/22 17:08:53 mich // + Additional Backstep counter for performance measurement. // // Revision 1.2 1997/09/22 05:13:30 mich // First working version after conversion from // VariableOrderingStrategy to SearchStrategy. // // Revision 1.1 1997/09/20 03:49:55 mich // Initial revision // package agg.util.csp; import java.lang.ref.WeakReference; import java.util.Dictionary; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.List; import java.util.Vector; import agg.xt_basis.GraphObject; import agg.xt_basis.csp.Query_Type; /** A CSP solution strategy using the backjumping technique. */ public class Solution_Backjump_PartialInj implements SolutionStrategy { private CSP itsCSP; private boolean itsInjectiveFlag; private boolean parallel; private boolean startParallelbyFirst; final private Vector<Query> itsQueries = new Vector<Query>(); final private Dictionary<Variable, Integer> itsVarIndexMap = new Hashtable<Variable, Integer>(); final private Dictionary<Object, Variable> itsInstanceVarMap = new Hashtable<Object, Variable>(); // the map of other solution solver private Dictionary<Object, Variable> otherInstanceVarMap; final private SearchStrategy itsSearcher = new Search_BreadthFirst(); /** * Vector elements are of type <code>OrderedSet</code> of * <code>Variable</code>. Elements are of type <code>Variable</code>. */ final private HashSet<Variable> itsBackjumpTargets = new HashSet<Variable>(); /** * Value is either <code>NEXT</code> or <code>BACK</code> according to * the recent traversal direction of the search tree. */ private int itsDirection; /** Index into <code>itsVariables</code>. */ private int itsCurrentIndex; /** * Index into <code>itsVariables</code>. Variables below this index are * considered to be preinstantiated and will not be touched by the solution * algorithm. */ private Variable itsCurrentVar; // private Variable itsStartVar; private Query itsCurrentQuery; private int itsState; // private int itsInstantiationCounter; // private int itsBackstepCounter; @SuppressWarnings("unused") private int allInstances = 0; private boolean solutionFound; private final HashMap<Variable,WeakReference<Object>> var2subcontext = new HashMap<Variable,WeakReference<Object>>(); // constants for csp solution state machine: private final static int START = 1; private final static int NEXT = 2; private final static int INSTANTIATE = 3; private final static int BACK = 4; private final static int SUCCESS = 5; private final static int NO_MORE_SOLUTIONS = 6; private final static int BACKJUMP = 7; public Solution_Backjump_PartialInj(boolean injective) { this.itsInjectiveFlag = injective; } public void setRelatedInstanceVarMap( Dictionary<Object, Variable> relatedVarIndexMap) { this.otherInstanceVarMap = relatedVarIndexMap; } public Dictionary<Object, Variable> getInstanceVarMap() { return this.itsInstanceVarMap; } public void setSubcontextOfVariable( final Enumeration<Variable> vars, final Object subcontext, final List<GraphObject> objs) { while (vars.hasMoreElements()) { Variable var = vars.nextElement(); for (int i=0; i<objs.size(); i++) { if (var.getGraphObject() == objs.get(i)) { this.var2subcontext.put(var, new WeakReference<Object>(subcontext)); } } } } /** * */ public void clear() { this.itsQueries.clear(); ((Hashtable<Object, Variable>)this. itsInstanceVarMap).clear(); ((Hashtable<Variable, Integer>) this.itsVarIndexMap).clear(); this.itsBackjumpTargets.clear(); } /** * Compute the search plan (variable order) and do some other initialization * stuff. * * @return <code>false</code> iff some preinstantiated variables are * violating some constraint. */ private synchronized final boolean initialize(CSP csp) { this.itsCSP = csp; clear(); this.itsQueries.addAll(this.itsSearcher.execute(this.itsCSP)); this.itsQueries.trimToSize(); for (int i = 0; i < this.itsQueries.size(); i++) { this.itsVarIndexMap.put(this.itsQueries.elementAt(i).getTarget(), Integer.valueOf(i)); } final Enumeration<Variable> anEnum = this.itsCSP.getVariables(); while (anEnum.hasMoreElements()) { final Variable aVar = anEnum.nextElement(); if (aVar.getInstance() != null) { if (aVar.checkConstraints().hasMoreElements()) { return false; } this.itsVarIndexMap.put(aVar, Integer.valueOf(-1)); this.itsInstanceVarMap.put(aVar.getInstance(), aVar); } } return true; } public final boolean reinitialize(boolean doUpdateQueries) { if (doUpdateQueries) { this.itsQueries.clear(); this.itsQueries.addAll(this.itsSearcher.execute(this.itsCSP)); this.itsQueries.trimToSize(); } ((Hashtable<Variable, Integer>) this.itsVarIndexMap).clear(); ((Hashtable<Object, Variable>) this.itsInstanceVarMap).clear(); this.itsBackjumpTargets.clear(); for (int i = 0; i < this.itsQueries.size(); i++) { Query q = this.itsQueries.elementAt(i); this.itsVarIndexMap.put(q.getTarget(), Integer.valueOf(i)); if (q instanceof Query_Type) { ((Query_Type)q).resetObjects(); } } final Enumeration<Variable> anEnum = this.itsCSP.getVariables(); while (anEnum.hasMoreElements()) { final Variable aVar = anEnum.nextElement(); if (aVar.getInstance() != null) { if (aVar.checkConstraints().hasMoreElements()) { return false; } this.itsVarIndexMap.put(aVar, Integer.valueOf(-1)); this.itsInstanceVarMap.put(aVar.getInstance(), aVar); } } this.itsState = START; return true; } public void reinitialize(final Variable var) { if (var.getInstance() != null) { this.itsInstanceVarMap.remove(var.getInstance()); } boolean queryExists = false; for (int i = 0; i < this.itsQueries.size(); i++) { if (var == this.itsQueries.elementAt(i).getTarget()) { this.itsVarIndexMap.put(var, Integer.valueOf(i)); this.itsState = START; queryExists = true; break; } } if (!queryExists) { if (var.getTypeQuery() != null) { this.itsQueries.add(0, var.getTypeQuery()); for (int i = 0; i < this.itsQueries.size(); i++) { final Variable v = this.itsQueries.elementAt(i).getTarget(); this.itsVarIndexMap.put(v, Integer.valueOf(i)); } this.itsState = START; } } // showQueries(itsQueries); } public Variable getStartVariable() { return this.itsQueries.get(0).itsTarget; } public Query getQuery(final Variable var) { return (!this.itsQueries.isEmpty())? this.itsQueries.get(this.itsVarIndexMap.get(var).intValue()): null; } /** * Set my state to <code>START</code>. */ public final void reset() { this.itsState = START; } /** * Reset the object domain of the query <code>Query_Type</code>. */ public void resetQuery_Type() { for (int i = 0; i < this.itsQueries.size(); i++) { if (this.itsQueries.elementAt(i) instanceof Query_Type) { ((Query_Type)this.itsQueries.elementAt(i)).resetObjects(); } } } /** * Search for next solution. */ public synchronized final boolean next(CSP csp) { // long t = System.nanoTime(); this.solutionFound = false; if (!csp.equals(this.itsCSP)) { if (!initialize(csp)) { return false; } this.itsState = START; } if (this.itsState == SUCCESS) { this.itsState = BACK; // we want to continue where we left off, instead of actually // making a back step: this.itsCurrentIndex++; } // showQueries(itsQueries); while (true) { switch (this.itsState) { case START: // itsInstantiationCounter = 0; // itsBackstepCounter = 0; this.itsCurrentIndex = -1; this.itsState = NEXT; break; case NEXT: if (this.itsCurrentIndex >= this.itsQueries.size() - 1) { this.itsState = SUCCESS; } else { this.itsCurrentQuery = this.itsQueries.elementAt(++this.itsCurrentIndex); this.itsCurrentVar = this.itsCurrentQuery.getTarget(); if (this.itsCurrentQuery.isApplicable() && !this.itsCurrentQuery.isDomainEmpty() ) { this.itsCurrentVar.setDomainEnum(this.itsCurrentQuery.execute()); addToBackjumpTargets(this.itsCurrentQuery.getSources()); this.itsState = INSTANTIATE; } else { this.itsState = NO_MORE_SOLUTIONS; } } this.itsDirection = NEXT; break; case INSTANTIATE: if (this.itsDirection == NEXT) { // we will use backjumping if instantiation fails this.itsState = BACKJUMP; } else { // we must not use backjumping because there was // a consistent instantiation found for the current // variable previously this.itsState = BACK; } // deactivate correspondent constraint before checking // pablo this.itsCurrentQuery.deactivateCorrespondent(); while (this.itsCurrentVar.hasNext()) { Object obj = this.itsCurrentVar.getNext(); // Node/Edge with graph context == null was destroyed, // but it remains in domain of CSP variable during parallel matching, // so it must be exclude as instance of a CSP variable if (//obj == null || ((GraphObject)obj).getContext() == null) { continue; } // itsInstantiationCounter++; this.itsCurrentVar.setInstance(obj); this.allInstances++; Variable aConflictVar = checkInjection(this.itsCurrentVar); if (aConflictVar != null) { this.itsCurrentVar.setInstance(null); this.allInstances--; if (this.itsVarIndexMap.get(aConflictVar) != null) { this.itsBackjumpTargets.add(aConflictVar); } continue; } Enumeration<Variable> allConflictVars = this.itsCurrentVar.checkConstraints(); if (!allConflictVars.hasMoreElements()) { this.itsState = NEXT; addInjection(this.itsCurrentVar); break; } if (this.itsState == BACKJUMP) { Variable conflictVar1 = getFirstOf(allConflictVars); this.itsBackjumpTargets.add(conflictVar1); } } // re-activate correspondent constraint after checking // pablo this.itsCurrentQuery.activateCorrespondent(); break; case BACK: // System.out.println("BACK"); // itsBackstepCounter++; if (this.itsCurrentIndex == 0) { if ((this.itsCurrentVar != null) && this.itsCurrentVar.hasNext()) { removeInjection(this.itsCurrentVar); this.itsCurrentVar.setInstance(null); this.allInstances--; this.itsState = INSTANTIATE; this.itsDirection = NEXT; } else { this.itsState = NO_MORE_SOLUTIONS; this.itsDirection = BACK; } } else if (this.itsCurrentIndex > 0) { removeInjection(this.itsCurrentVar); this.itsCurrentVar.setInstance(null); this.allInstances--; this.itsCurrentVar = this.itsQueries.get(--this.itsCurrentIndex).getTarget(); removeInjection(this.itsCurrentVar); this.itsState = INSTANTIATE; this.itsDirection = BACK; } else { this.itsState = NO_MORE_SOLUTIONS; this.itsDirection = BACK; } break; case BACKJUMP: // System.out.println("BACKJUMP"); // itsBackstepCounter++; // int aStepCounter = 0; this.itsState = NO_MORE_SOLUTIONS; while (this.itsCurrentIndex > 0) { // aStepCounter++; removeInjection(this.itsCurrentVar); this.itsCurrentVar.setInstance(null); this.allInstances--; this.itsCurrentVar = this.itsQueries.elementAt(--this.itsCurrentIndex) .getTarget(); removeInjection(this.itsCurrentVar); this.itsState = INSTANTIATE; if (this.itsBackjumpTargets.contains(this.itsCurrentVar)) { this.itsBackjumpTargets.remove(this.itsCurrentVar); break; } } this.itsDirection = BACK; break; case SUCCESS: // System.out.println("SUCCESS"); if (this.parallel && this.startParallelbyFirst) { removeUsedObjectFromDomain(); } this.solutionFound = true; // System.out.println("solution found in : "+(System.nanoTime()-t)+" nano"); return true; case NO_MORE_SOLUTIONS: // System.out.println("NO_MO_SOLUTIONS"); return false; default: System.out.println("Should have never come here " + this.itsState); } } } private void removeUsedObjectFromDomain() { for (int i=0; i<this.itsQueries.size(); i++) { Query q = this.itsQueries.get(i); if (q instanceof Query_Type) { ((Query_Type)q).removeObject((GraphObject) q.getTarget().getInstance()); } } ((Hashtable<Object, Variable>) this.itsInstanceVarMap).clear(); this.itsBackjumpTargets.clear(); } public boolean hasSolution() { return this.solutionFound; } public boolean hasQueries() { return (!this.itsQueries.isEmpty()); } /** * Return the Variable with the smallest index of <code>vars</code>. * <p> * <b>Pre:</b> <code>vars.hasMoreElements()</code>. */ private final Variable getFirstOf(Enumeration<Variable> vars) { Variable aFirstVar = vars.nextElement(); int aFirstIndex = this.itsQueries.size(); Variable aCurrentVar; int aCurrentIndex; while (vars.hasMoreElements()) { aCurrentVar = vars.nextElement(); if (this.itsVarIndexMap.get(aCurrentVar) != null) { aCurrentIndex = this.itsVarIndexMap.get(aCurrentVar).intValue(); if (aCurrentIndex < aFirstIndex) { aFirstIndex = aCurrentIndex; aFirstVar = aCurrentVar; } } } return aFirstVar; } private final void addInjection(Variable var) { if (this.itsInjectiveFlag && (var.getInstance() != null)) { this.itsInstanceVarMap.put(var.getInstance(), var); } } /* private final void removeInjection() { for (int i=1; i<itsQueries.size(); i++) { this.itsCurrentVar = itsQueries.get(i).getTarget(); if (itsInjectiveFlag && (this.itsCurrentVar.getInstance() != null)) { itsInstanceVarMap.remove(this.itsCurrentVar.getInstance()); this.itsCurrentVar.setInstance(null); } } } */ private final void removeInjection(Variable var) { if (this.itsInjectiveFlag && (var.getInstance() != null)) this.itsInstanceVarMap.remove(var.getInstance()); } // private final Variable checkInjection(Variable var) // { // if(itsInjectiveFlag && (var.getInstance() != null)) // return (Variable) itsInstanceVarMap.get(var.getInstance()); // else // return null; // } private final Variable checkInjection(Variable var) { // if (var.getInstance() != null) { if (this.otherInstanceVarMap != null) { // in case of NAC / PAC // this check is always injective Variable other = this.otherInstanceVarMap.get(var.getInstance()); if (other != null) { return other; } } if (this.itsInjectiveFlag) { Variable v = this.itsInstanceVarMap.get(var.getInstance()); if (v != null) { // these two variables must belong to defferent subcontext if (this.var2subcontext.get(var) != this.var2subcontext.get(v)) { // allow non-injection return null; } } return v; } } return null; } private final void addToBackjumpTargets(List<?> en) { for (int i=0; i<en.size(); i++) this.itsBackjumpTargets.add((Variable)en.get(i)); } /* (non-Javadoc) * @see agg.util.csp.SolutionStrategy#parallelSearch() */ public boolean parallelSearch() { return this.parallel; } public void enableParallelSearch(boolean b) { this.parallel = b; } /* (non-Javadoc) * @see agg.util.csp.SolutionStrategy#setStartParallelSearchByFirst(boolean) */ public void setStartParallelSearchByFirst(boolean b) { this.startParallelbyFirst = b; } }