MinHittingSets.java
Go to the documentation of this file.
00001 /*
00002  * (c) copyright 2008, Technische Universitaet Graz and Technische Universitaet Wien
00003  *
00004  * This file is part of jdiagengine.
00005  *
00006  * jdiagengine is free software: you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation, either version 3 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * jdiagengine is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  * You should have received a copy of the GNU General Public License
00016  * along with jdiagengine. If not, see <http://www.gnu.org/licenses/>.
00017  *
00018  * Authors: Joerg Weber, Franz Wotawa
00019  * Contact: jweber@ist.tugraz.at (preferred), or fwotawa@ist.tugraz.at
00020  *
00021  */
00022 
00023 
00030 package hittingsetalg;
00031 
00032 import java.io.*;      // IO specific classes (File, Stream,..)
00033 import java.util.*;    // Java util
00034 
00035 import theoremprover.*;
00036 import utils.SortedIntList;
00037 
00047 public class MinHittingSets {
00048     
00049     protected final static int CS_COMPUTING = 0;
00050     
00051     public final static int CS_ALL_MIN_DIAGS_COMPUTED = 1;
00052 
00053     public final static int CS_MAX_HS_SIZE_REACHED = 2;
00054 
00055     public final static int CS_MAX_NUM_MIN_HS_REACHED = 3;
00056 
00057 
00058     // The computed min. hitting sets. Each one is a HSNode.
00059     protected ArrayList computedMinHS = new ArrayList();
00060     
00061     // max. size of desired min. hitting sets; -1 means all min. hitting sets are computed.
00062     protected int maxHSSize;
00063 
00064     // When maxNumMinHS are computed, then the algorithm stops. If -1: all min. hitting sets are computed.
00065     protected int maxNumMinHS;
00066 
00067     // True if the algorithm can rely on the fact that all conflicts are minimal.
00068     protected boolean conflictsAreMinimal;
00069 
00070     /* 
00071      * Conflict sets, either passed to a constructor or computed incrementally.
00072      *
00073      * ArrayList of SortedIntList.
00074      */
00075     protected ArrayList conflictSets = null;
00076 
00077     // The theorem prover. Remains "null" if the conflict sets are provided by the user of this class.
00078     protected ABTheoremProver theoremProver = null;
00079 
00080     // The assumptions of theoremProver.
00081     protected ArrayList assumptions = null;
00082 
00083     // The set COMP. Is actually the set {0,..,n} where n = assumption.size() - 1.
00084     // Only used when computeIncr=true.
00085     protected SortedIntList components = null;
00086 
00087     // Indicates if the conflict sets are computed incrementally or provided by the user of this class.
00088     protected boolean computeIncr;
00089 
00090     // The root node.
00091     protected HSNode rootNode = null;
00092 
00093     // ArrayList of LinkedList of HSNode. Contains the levels of the DAG.
00094     protected ArrayList levels = new ArrayList();
00095 
00096     protected int computationState = -1;
00097 
00098     protected HSNode attemptedPruneNode = null;
00099 
00100 
00113     public MinHittingSets(boolean conflictsAreMinimal, ArrayList conflictSets) {
00114         // precondition
00115         assert(conflictSets.size() >= 1);
00116 
00117         computeIncr = false;
00118         this.conflictsAreMinimal = conflictsAreMinimal;
00119         this.conflictSets = conflictSets;
00120     }
00121 
00130     public MinHittingSets(boolean conflictsAreMinimal,
00131                           ABTheoremProver tp) {
00132         // precondition
00133         assert((tp != null) && (tp.getAssumptions().size() > 0));
00134         
00135         computeIncr = true;
00136         this.conflictsAreMinimal = conflictsAreMinimal;
00137         this.conflictSets = new ArrayList();
00138         this.theoremProver = tp;
00139         
00140         // for all assumptions: set an integer tag
00141         assumptions = tp.getAssumptions();
00142         components = new SortedIntList();
00143         Iterator it = assumptions.iterator();
00144         int tag = 0;
00145         System.out.println("Assumption tags: ");
00146         while(it.hasNext()) {
00147             Assumption a = (Assumption)it.next();
00148             a.setIntTag(tag);
00149             System.out.println((new Integer(tag)).toString() + ": " + (String)a.identifier);
00150             components.addSorted(tag);
00151             ++tag;
00152         }
00153 
00154         System.out.println();
00155     }
00156 
00165     public ArrayList getMinHS() {
00166 
00167         if (theoremProver == null) {
00168             throw new UnsupportedOperationException("class MinHittingSets: if no theorem prover is used "
00169                                                     + "for the dynamic computation of conflicts sets, then "
00170                                                     + "getMinHSAsIntegers() must be used instead of "
00171                                                     + "getMinHS() !!");
00172         }                                       
00173 
00174         ArrayList result = new ArrayList();
00175         result.ensureCapacity(computedMinHS.size());
00176 
00177         Iterator itMinHS = computedMinHS.iterator();
00178         while (itMinHS.hasNext()) {
00179             HSNode node = (HSNode)itMinHS.next();
00180             if (node.state != HSNode.STATE_PRUNED) {
00181                 assert(node.state == HSNode.STATE_MINIMAL);
00182 
00183                 ArrayList candidate = new ArrayList();
00184                 Iterator itAss = node.edgeLabels.iterator();
00185                 while (itAss.hasNext()) {
00186                     Integer index = (Integer)itAss.next();
00187                     candidate.add(theoremProver.getAssumptions().get(index.intValue()));
00188                 }
00189                 result.add(candidate);
00190 
00191             }
00192         }
00193 
00194         return result;
00195     }
00196 
00197     /*
00198      * This method is used when no theorem prover is used, i.e., the conflict sets
00199      * were computed before executing the HS algorithm.
00200      *
00201      * Returns an ArrayList of SortedIntList, where eac SortedIntList represents a
00202      * min. diagnosis.
00203      */
00204     public ArrayList getMinHSAsIntLists() {
00205         ArrayList result = new ArrayList();
00206         result.ensureCapacity(computedMinHS.size());
00207 
00208         Iterator itMinHS = computedMinHS.iterator();
00209         while (itMinHS.hasNext()) {
00210             HSNode node = (HSNode)itMinHS.next();
00211             if (node.state != HSNode.STATE_PRUNED) {
00212                 assert(node.state == HSNode.STATE_MINIMAL);
00213 
00214                 result.add(node.edgeLabels);
00215             }
00216         }
00217 
00218         return result;
00219     }
00220 
00221     /*
00222      * Returns an ArrayList of ArrayList of Assumption representing the conflicts.
00223      *
00224      * This method can only be used when the theorem prover is used, i.e., these conflicts were
00225      * computed incrementally.
00226      */
00227     public ArrayList getConflictsAsAss() {
00228         ArrayList result = new ArrayList();
00229 
00230         Iterator itConflicts = conflictSets.iterator();
00231         while (itConflicts.hasNext()) {
00232             SortedIntList cs = (SortedIntList)itConflicts.next();
00233             if (cs != null) {  // there may be "null" entries in conflictSet due to pruning
00234                 ArrayList csAss = new ArrayList(cs.size());
00235 
00236                 Iterator itCS = cs.iterator();
00237                 while (itCS.hasNext()) {
00238                     int index = ((Integer)itCS.next()).intValue();
00239                     Assumption a = (Assumption)assumptions.get(index);
00240                     csAss.add(a);
00241                 }
00242                 
00243                 result.add(csAss);
00244             }
00245         }
00246 
00247         return result;
00248     }
00249 
00250     /*
00251      * @param maxHSSize The max. size of min. hitting sets to be computed, 
00252      *   -1 means all min. hitting sets are computed.
00253      * @param maxNumMinHS The max. number of computed hitting sets. The algorithm stops
00254      *   as soon as maxNumMinHS hitting sets have been computed. If -1: all min. hitting sets 
00255      *   are computed.
00256      */
00257     /*
00258      * Returns one of the CS_xxx constants.
00259      */
00260     public int compute(int maxHSSize, int maxNumMinHS) {
00261         
00262         assert((maxHSSize >= 1) && (maxNumMinHS >= 1));
00263 
00264         // some initializations
00265 
00266         computationState = CS_COMPUTING;
00267         this.maxHSSize = maxHSSize;
00268         this.maxNumMinHS = maxNumMinHS;
00269         LinkedList lastLevelNodes  = new LinkedList(); // the nodes of the last level in the DAG
00270         int lastLevel = 0;
00271         levels.add(lastLevelNodes);
00272 
00273         // create root node
00274 
00275         rootNode = new HSNode();
00276         rootNode.edgeLabels = new SortedIntList();  // H(n) is empty for the root node
00277         lastLevelNodes.add(rootNode);
00278 
00279         // create one DAG level after the other (breadth-first)
00280 
00281         while(computationState == CS_COMPUTING) {
00282 
00283             //System.out.println();
00284             //System.out.println("iterate through last level: " + lastLevel + "; expand nodes: " + expandNodes);
00285 
00286             LinkedList newLevelNodes = new LinkedList();
00287             levels.add(newLevelNodes);
00288             processLastLevel(lastLevel, lastLevelNodes, newLevelNodes, true);
00289             //if (expandNodes) System.out.println("total # of nodes in new level: " + newLevelNodes.size());
00290             
00291             lastLevelNodes = newLevelNodes;
00292             ++lastLevel;
00293 
00294             if (computationState == CS_COMPUTING) {
00295                 assert(lastLevelNodes.size() > 0);
00296                 if (lastLevel - 1 == maxHSSize) computationState = CS_MAX_HS_SIZE_REACHED;
00297             }   
00298         }
00299 
00300         assert(computationState != CS_COMPUTING);
00301         return computationState;
00302 
00303     }  // compute()
00304 
00305     public int computeMore(int newMaxHSSize, int newMaxNumMinHS) {
00306         assert((newMaxHSSize >= maxHSSize) && (newMaxNumMinHS >= maxNumMinHS));
00307 
00308         if (computationState == CS_ALL_MIN_DIAGS_COMPUTED) return CS_ALL_MIN_DIAGS_COMPUTED;
00309         else {
00310             
00311             this.maxHSSize = newMaxHSSize;
00312             this.maxNumMinHS = newMaxNumMinHS; 
00313             int lastLevel;
00314             LinkedList lastLevelNodes;
00315             LinkedList newLevelNodes;
00316 
00317             if (computationState == CS_MAX_HS_SIZE_REACHED) {
00318                 lastLevel = levels.size() - 1;
00319                 lastLevelNodes = (LinkedList)levels.get(lastLevel);
00320                 newLevelNodes = null;
00321             } else {
00322                 assert(computationState == CS_MAX_NUM_MIN_HS_REACHED);
00323                 lastLevel = levels.size() - 2;
00324                 lastLevelNodes = (LinkedList)levels.get(lastLevel);
00325                 newLevelNodes = (LinkedList)levels.get(lastLevel + 1);
00326             }
00327             
00328             if (computedMinHS.size() == maxNumMinHS) computationState = CS_MAX_NUM_MIN_HS_REACHED;
00329             else if (lastLevel - 1 == maxHSSize) computationState = CS_MAX_HS_SIZE_REACHED;
00330             else computationState = CS_COMPUTING;
00331 
00332             while(computationState == CS_COMPUTING) {
00333                  
00334                 if (newLevelNodes == null) {
00335                     newLevelNodes = new LinkedList();
00336                     levels.add(newLevelNodes);
00337                 }
00338                 
00339                 processLastLevel(lastLevel, lastLevelNodes, newLevelNodes, true);
00340                 lastLevelNodes = newLevelNodes;
00341                 ++lastLevel;
00342                 
00343                 if (computationState == CS_COMPUTING) {
00344                     if (lastLevelNodes.size() == 0) computationState = CS_ALL_MIN_DIAGS_COMPUTED;
00345                     else if (lastLevel - 1 == maxHSSize) computationState = CS_MAX_HS_SIZE_REACHED;
00346                 } 
00347             }
00348 
00349             assert(computationState != CS_COMPUTING);
00350             return computationState;
00351         }
00352     }
00353 
00354     // Performs the call: "TP(SD, COMP-H(n), OBS)" (in terms of Reiter's formalization).
00355     // Returns a new conflict set or, if no inconsistency was detected, return "null".
00356     protected SortedIntList callTheoremProver(SortedIntList edgeLabels) {
00357 
00358         SortedIntList assumptionSet = components.subtract(edgeLabels);  // compute COMP-H(n)
00359 
00360         // set assumptions in COMP-H(n) to "true"
00361 
00362         Iterator itAss = assumptionSet.iterator();
00363         while(itAss.hasNext()) {
00364             int assIndex = ((Integer)itAss.next()).intValue();
00365             Assumption a = (Assumption)assumptions.get(assIndex);
00366             
00367             if (a.getLabel() != true) {
00368                 a.setLabel(true);
00369                 a.propagateTrue();
00370             }
00371         }
00372 
00373         // set assumptions in H(n) to "false"
00374         
00375         Iterator itNegAss = edgeLabels.iterator();
00376         while(itNegAss.hasNext()) {
00377             int negassIndex = ((Integer)itNegAss.next()).intValue();
00378             Assumption a = (Assumption)assumptions.get(negassIndex);
00379 
00380             if (a.getLabel() != false)
00381             {
00382                 ArrayList v = new ArrayList();
00383                 v = a.propagateFalse(v); 
00384                 Iterator ve = v.iterator();                                
00385                 while (ve.hasNext()) {
00386                     Proposition p = (Proposition)ve.next();
00387                     p.correctLabels();
00388                 }
00389             }
00390         }
00391 
00392         //System.out.println("CALL THEOREM PROVER: true: " + assumptionSet + ";  false: " + edgeLabels);
00393 
00394         // consistency check
00395 
00396         if (theoremProver.isConsistent()) {
00397             //System.out.println("TP: consistent!");
00398             return null;  // consistent!!
00399         } else {
00400 
00401             // determine conflict set
00402 
00403             ArrayList conflicts = theoremProver.contradiction().collectAssumptions();
00404             SortedIntList cs = new SortedIntList();
00405             Iterator itConflicts = conflicts.iterator();
00406             while(itConflicts.hasNext()) {
00407                 Assumption a = (Assumption)itConflicts.next();
00408                 cs.addSorted(a.getIntTag());
00409             }
00410             //System.out.println("TP returns conflict: " + cs);
00411             
00412             return cs;
00413         }
00414 
00415     }  // callTheoremProver()
00416 
00417 
00418     /*
00419      * This node and all of its children are "removed", except of those nodes with another
00420      * parent which is not removed.
00421      */
00422     protected void prune(HSNode node, HSNode prunedParent) {
00423 
00424         assert(nodeInvariant(node));
00425 
00426         if ((node.state == HSNode.STATE_OPEN) || (node.state == HSNode.STATE_MINIMAL)) {
00427 
00428             boolean hasAliveParents;  // are there any parents which are NOT relabelled/removed?
00429             if (node.parents.size() == 1) hasAliveParents = false;
00430             else {
00431                 assert(node.parents.size() > 1);
00432                 
00433                 hasAliveParents = false;
00434 
00435                 Iterator itParents = node.parents.iterator();
00436                 while (itParents.hasNext()) {
00437                     HSNode parent = (HSNode)itParents.next();
00438                     if ((parent != prunedParent) && (parent.state != HSNode.STATE_PRUNED)) {
00439                         hasAliveParents = true;
00440                         break;
00441                     }
00442                 }
00443             }
00444 
00445             if (!hasAliveParents) {  // prune only if there are no alive parents!
00446                 
00447                 node.state = HSNode.STATE_PRUNED;
00448                 
00449                 //System.out.println("REMOVE node: " + node);
00450 
00451                 Iterator itChildren = node.children.iterator();
00452                 while (itChildren.hasNext()) {
00453                     HSNode child = ((EdgeNodePair)itChildren.next()).node;
00454                     if (child.state != HSNode.STATE_PRUNED) {
00455                         prune(child, node);
00456                     }
00457                 }
00458             }
00459             else {
00460                 //System.out.println("DONT remove node (alive parents): " + node);
00461             }
00462         }
00463 
00464         assert(nodeInvariant(node));
00465 
00466     }  // prune()
00467 
00468 
00469     /*
00470      * Called during pruning. node is to be relabelled by newNode.label. 
00471      * Some of its children may be pruned.
00472      */
00473     protected void relabel(HSNode node, HSNode newNode) {
00474 
00475         // precondition
00476         //assert(node.conflictSetIndex != newNode.conflictSetIndex);
00477         assert((node.state != HSNode.STATE_MINIMAL) &&  newNode.label.properSubsetOf(node.label));
00478         assert(nodeInvariant(node));
00479         assert(nodeInvariant(newNode));
00480         assert(newNode == attemptedPruneNode);
00481 
00482         // relabel node and interchange conflict sets
00483 
00484         SortedIntList removeLabel = node.label.subtract(newNode.label);
00485         node.label = newNode.label;
00486         conflictSets.set(node.conflictSetIndex, newNode.label);
00487         //conflictSets.set(newNode.conflictSetIndex, null);
00488         newNode.conflictSetIndex = node.conflictSetIndex;                
00489 
00490         // iterate through children: if child is to be removed, call prune() for it
00491 
00492         int prunedChildrenCount = 0;
00493         Iterator itChildren = node.children.iterator();
00494         while (itChildren.hasNext()) {
00495             EdgeNodePair child = (EdgeNodePair)itChildren.next();
00496 
00497             if (removeLabel.contains(child.edge)) {  // determine if child is to be removed
00498                 
00499                 if (child.node.state != HSNode.STATE_PRUNED) {
00500                     prune(child.node, node);
00501                 }
00502 
00503                 ++prunedChildrenCount;
00504             }    
00505             
00506             
00507         }
00508         assert(prunedChildrenCount == removeLabel.size());
00509         
00510         assert(nodeInvariant(node));
00511         assert(nodeInvariant(newNode));
00512         assert(node.label.equals(newNode.label));
00513     }  // relabel();
00514 
00515 
00516     // returns number of children which are NOT pruned
00517     protected int computeNumUnprunedChildren(HSNode node) {
00518         int n = 0;
00519         Iterator itChildren = node.children.iterator();
00520         while (itChildren.hasNext()) {
00521             HSNode child = ((EdgeNodePair)itChildren.next()).node;
00522             if (child.state != HSNode.STATE_PRUNED) ++n;
00523         }
00524 
00525         return n;
00526     }
00527 
00528 
00529     // node has just been labelled, now check if DAG can be pruned using this label
00530     protected void attemptPrune(HSNode node) {
00531         
00532         // precondition
00533         assert((node.state == HSNode.STATE_OPEN) && (node.label != null)               
00534                && (node.label.size() > 0) && (node != rootNode) && nodeInvariant(node));
00535 
00536         attemptedPruneNode = node;
00537         int oldConflictSetIndex = node.conflictSetIndex;
00538         boolean pruned = false;  // set to true when pruning is done
00539 
00540         // always try to relabel root node
00541         rootNode.relevantForPruning = true;
00542         boolean relevantNodesExist = true;
00543 
00544         // iterate through levels; stop when there are no more nodes which are candidates for relabelling
00545 
00546         Iterator itLevels = levels.iterator();
00547         while(itLevels.hasNext() && relevantNodesExist) {
00548         
00549             relevantNodesExist = false;
00550 
00551             LinkedList level = (LinkedList)itLevels.next();
00552             Iterator itLevelNodes = level.iterator();
00553 
00554             SortedIntList intersectionSet = new SortedIntList();
00555 
00556             // iterate through nodes of a level
00557 
00558             while(itLevelNodes.hasNext()) {
00559 
00560                 HSNode otherNode = (HSNode)itLevelNodes.next();
00561                 
00562                 if ((otherNode.state == HSNode.STATE_OPEN) && (otherNode.label != null) 
00563                     && otherNode.relevantForPruning) {
00564                     
00565                     // determine if we can prune; if not: are there irrelevant subtrees?
00566 
00567                     intersectionSet.clear();
00568                     boolean intersects = otherNode.label.intersection(node.label, intersectionSet);
00569                     assert((!intersects && (intersectionSet.size() == 0))
00570                            || (intersects && (intersectionSet.size() != 0)));
00571                    
00572                     // Note: "A.properSubsetOf(B)" is equivalent to "A.intersects(B) and (A = intersection(A, B))
00573                     // and (size(A) < size(B))"
00574                     boolean canPrune = (intersects && (intersectionSet.size() == node.label.size())
00575                                         && (node.label.size() < otherNode.label.size()));
00576                     assert(!canPrune || node.label.properSubsetOf(otherNode.label));
00577 
00578                     if (canPrune) {  // prune!
00579 
00580                         relabel(otherNode, node);
00581                         pruned = true;
00582 
00583                     } else {  // cannot prune: investigate which subtrees are not relevant for further search
00584                         
00585                         if ((intersectionSet.size() > 0)        // some subtrees are not relevant
00586                             && (otherNode.children.size() > 0)) {   // .. and otherNode has already been expanded
00587                             
00588                             //System.out.println("IGNORE children of node: " + otherNode + ";   child edges: " + intersectionSet); 
00589 
00590                             Iterator itIntersection = intersectionSet.iterator();
00591                             int nextItem;
00592                             if (itIntersection.hasNext()) 
00593                                 nextItem = ((Integer)itIntersection.next()).intValue();
00594                             else nextItem = Integer.MAX_VALUE;
00595                             
00596                             Iterator itChildren = otherNode.children.iterator();
00597                             while (itChildren.hasNext()) {
00598                                 EdgeNodePair child = (EdgeNodePair)itChildren.next();
00599                                 
00600                                 if (child.edge == nextItem) {
00601                                     child.node.relevantForPruning = false;
00602                                     assert(node.label.contains(child.edge));
00603                                     if (itIntersection.hasNext()) 
00604                                         nextItem = ((Integer)itIntersection.next()).intValue();
00605                                     else nextItem = Integer.MAX_VALUE;
00606                                 } else {
00607                                     child.node.relevantForPruning = true;
00608                                     relevantNodesExist = true;
00609                                 }
00610                             }
00611 
00612                             assert(!itIntersection.hasNext());
00613                             
00614                         } else {  // all subtrees are relevant
00615                             
00616                             Iterator itChildren = otherNode.children.iterator();
00617                             while (itChildren.hasNext()) {
00618                                 HSNode child = ((EdgeNodePair)itChildren.next()).node;
00619                                 child.relevantForPruning = true;
00620                             }
00621                             relevantNodesExist = true;
00622 
00623                         }
00624 
00625                     }  // !canPrune
00626 
00627                 }  // node is open and relevant for pruning
00628 
00629                 else if (!otherNode.relevantForPruning) {  // if node not relevant => children are not rel., too
00630 
00631                     Iterator itChildren = otherNode.children.iterator();
00632                     while(itChildren.hasNext()) {
00633                         HSNode child = ((EdgeNodePair)itChildren.next()).node;
00634                         child.relevantForPruning = false;
00635                     }
00636 
00637                 }
00638 
00639             }  // iterate through nodes of a level
00640 
00641         }  // iterate through levels
00642 
00643         if (pruned) conflictSets.set(oldConflictSetIndex, null);
00644         attemptedPruneNode = null;
00645 
00646         assert(nodeInvariant(node));
00647 
00648     }  // attemptPrune()
00649 
00650     /*
00651      * Searches in the list of already computed conflict sets for a conflict set cs
00652      * which refutes edgeLabel (= H(n) in Reiter's notation), i.e., cs shows that H(n)
00653      * is inconsistent with SD and OBS.
00654      *
00655      * If no such conflict is found, then this method returns -1. Otherwise, it returns
00656      * an index to the collection conflictSets such that edgeLabel does not intersect conflictSets[index].
00657      */
00658     protected int searchRefutingCS(SortedIntList edgeLabel) {
00659         for (int i = 0; i < conflictSets.size(); ++i) {
00660             Object o = conflictSets.get(i);
00661             if (o != null) {  // the conflict set at this index may have been removed by pruning!
00662                 SortedIntList cs = (SortedIntList)conflictSets.get(i);
00663                 assert(cs.size() > 0);
00664                 if (!edgeLabel.intersects(cs)) return i;
00665             }
00666         }
00667 
00668         return -1;
00669     }
00670     
00671 
00672     /*
00673      * Compute label of node: either it is detected that this node is a min. HS,
00674      * or it is labelled by a new conflict set. The CS is either taken from the 
00675      * provided conflict sets, or it is computed by calling the theorem prover.
00676      */
00677     protected void computeLabel(HSNode node) {
00678 
00679         assert((node.state == HSNode.STATE_OPEN) && (node.label == null)
00680             && nodeInvariant(node));
00681 
00682         // check if node can be closed
00683 
00684         if (canClose(node)) {
00685             node.state = HSNode.STATE_CLOSED;
00686             //System.out.println("CLOSE node: " + node);
00687         }
00688 
00689         else {
00690 
00691             if (computeIncr) {
00692                 
00693                 int existingCSIndex = searchRefutingCS(node.edgeLabels);
00694                 if (existingCSIndex >= 0) {
00695                     assert(callTheoremProver(node.edgeLabels) != null);
00696                     SortedIntList existingCS = (SortedIntList)conflictSets.get(existingCSIndex);
00697                     node.label = existingCS;
00698                     node.conflictSetIndex = existingCSIndex;
00699                     //System.out.println("REFUTE using existing conflict set: {" + existingCS + "} refutes " + node);
00700                     if (!conflictsAreMinimal && (node != rootNode)) attemptPrune(node);
00701                 }
00702                 else {
00703                     SortedIntList cs = callTheoremProver(node.edgeLabels);
00704                     if (cs == null) {
00705                         node.state = HSNode.STATE_MINIMAL;
00706                     }
00707                     else {
00708                         assert(cs.size() > 0);
00709                         conflictSets.add(cs);
00710                         node.label = cs;
00711                         node.conflictSetIndex = conflictSets.size() - 1;
00712                         //System.out.println("computed label of node: " + node);
00713                         if (!conflictsAreMinimal && (node != rootNode)) attemptPrune(node);
00714                     }
00715                 }
00716 
00717             }
00718             
00719             else {  // !computeIncr
00720                 
00721                 if (node.edgeLabels.size() == 0) {  // true only for root node
00722                     node.label = (SortedIntList)conflictSets.get(0);
00723                     node.conflictSetIndex = 0;
00724                 }
00725                 
00726                 else {  // nodes which are not the root node
00727                     
00728                     Iterator itCS = conflictSets.iterator();
00729                     int csIndex = 0;
00730                     boolean hitsAllCS = true;  // true if H(n) (n=node) hits all conflict sets
00731                     
00732                     // try to find a conflict set which is not hit by H(n)
00733                     while(itCS.hasNext() && hitsAllCS) {
00734                         SortedIntList cs = (SortedIntList)itCS.next();
00735                         
00736                         if (!node.edgeLabels.intersects(cs)) {
00737                             hitsAllCS = false;
00738                             node.label = cs;
00739                             node.conflictSetIndex = csIndex;
00740                             assert(cs.equals(conflictSets.get(csIndex)));
00741                             //System.out.println("computed label of node: " + node);
00742                         } else ++csIndex;
00743                     }
00744                     
00745                     if (hitsAllCS) {
00746                         node.state = HSNode.STATE_MINIMAL;
00747                         //System.out.println("new minimal hitting set: " + node);
00748                     } else {
00749                         if (!conflictsAreMinimal && (node != rootNode)) attemptPrune(node);
00750                     }
00751                     
00752                 }
00753                 
00754             }  // !computeIncr
00755             
00756 
00757 
00758         }  // node cannot be closed
00759 
00760         assert(nodeInvariant(node));
00761 
00762     }  // computeLabel()
00763 
00764 
00765     // Returns true iff the node can be closed (the 2nd pruning rule).
00766     protected boolean canClose(HSNode node) {
00767         
00768         assert(nodeInvariant(node));
00769 
00770         Iterator itMinHS = computedMinHS.iterator();
00771         while (itMinHS.hasNext()) {
00772             HSNode n1 = (HSNode)itMinHS.next();
00773             if (n1.state == HSNode.STATE_MINIMAL) {
00774                 SortedIntList hs = n1.edgeLabels;
00775                 if (hs.subsetOf(node.edgeLabels)) {
00776                     assert(hs.properSubsetOf(node.edgeLabels));
00777                     return true;
00778                 }
00779             } else assert(n1.state == HSNode.STATE_PRUNED);
00780         }
00781 
00782         return false;
00783     }
00784 
00785     /* 
00786      * Returns the new nodes which were created out of the nodes of the last level.
00787      * If expandNodes is true, then no new nodes are created (only the nodes of the last
00788      * level are checked if they are min. HS);
00789      */
00790     protected void processLastLevel(int lastLevel, LinkedList lastLevelNodes, 
00791                                     LinkedList newLevelNodes, boolean expandNodes) {
00792 
00793         //System.out.println("processLastLevel: ");
00794 
00795         boolean hasOpenNodes = false;
00796 
00797         Iterator itLastNodes = lastLevelNodes.iterator();
00798         while(itLastNodes.hasNext()) {
00799 
00800             HSNode node = (HSNode)itLastNodes.next();
00801             assert(nodeInvariant(node));
00802             if (node.state == HSNodeFM.STATE_OPEN) {
00803 
00804                 computeLabel(node);
00805 
00806                 if (node.state == HSNodeFM.STATE_MINIMAL) {
00807                     computedMinHS.add(node);
00808                     if (computedMinHS.size() == maxNumMinHS) {
00809                         computationState = CS_MAX_NUM_MIN_HS_REACHED;
00810                         break;
00811                     }
00812                 } else if (node.state == HSNodeFM.STATE_OPEN) {
00813                     hasOpenNodes = true;
00814                     if (expandNodes) {
00815                         expandNode(node, newLevelNodes, lastLevel);
00816                     }
00817                 }
00818             }
00819 
00820             assert(nodeInvariant(node));
00821 
00822         }  // while(itLastNodes.hasNext())
00823 
00824         if ((computationState == CS_COMPUTING) && !hasOpenNodes) {
00825             computationState = CS_ALL_MIN_DIAGS_COMPUTED;
00826         }
00827     }
00828 
00829     /*
00830      * Expand a node: generate child nodes and set their edgeLabels field.
00831      * The new nodes are added to newNodes.
00832      */
00833     protected void expandNode(HSNode node, LinkedList newNodes, int lastLevel) {
00834         // precondition
00835         assert((node.label != null) && (node.label.size() >= 1) && nodeInvariant(node));
00836 
00837         int oldNewNodesSize = newNodes.size();
00838 
00839         int newEdge;
00840 
00841         // iterate through the conflict set of this node
00842 
00843         Iterator itLabel = node.label.iterator();
00844         while(itLabel.hasNext()) {
00845 
00846             // compute H(n) for the new node
00847 
00848             newEdge = ((Integer)itLabel.next()).intValue();            
00849             SortedIntList newEdgeLabels = (SortedIntList)node.edgeLabels.clone();
00850             newEdgeLabels.addSorted(newEdge);
00851             
00852             //System.out.println("new H(n): " + newEdgeLabels);
00853 
00854             // check if "Reusing" rule can be applied. Iterate through new nodes only.
00855             // Consider only nodes which were NOT created by expansion of node (ie by this method call).
00856 
00857             boolean reused = false;
00858             Iterator itNewNodes = newNodes.iterator();
00859             for (int i = 0; i < oldNewNodesSize; ++i) {
00860                 HSNode m = (HSNode)itNewNodes.next();
00861                 if (newEdgeLabels.equals(m.edgeLabels)) {  // reuse of node m!!
00862                     node.children.add(new EdgeNodePair(newEdge, m));
00863                     m.parents.add(node);
00864                     reused = true;
00865                     //System.out.println("REUSE node m: " + m);
00866                     break;
00867                 }
00868             }
00869 
00870             if (!reused) {  // no reuse possible: create new node
00871 
00872                 HSNode newNode = new HSNode();
00873                 newNode.edgeLabels = newEdgeLabels;
00874 
00875                 node.children.add(new EdgeNodePair(newEdge, newNode));
00876                 newNode.parents.add(node);
00877                 newNodes.add(newNode);
00878 
00879                 //System.out.println("NO reuse possible, create new node: " + newNode);
00880             }
00881 
00882         }  // while(itLabel.hasNext())
00883  
00884         assert(nodeInvariant(node));
00885         
00886     }  // expandNode()
00887 
00888     public boolean checkMinimalityHS() {
00889 
00890         for (int i = 0; i < computedMinHS.size(); ++i) {
00891 
00892             HSNode node = (HSNode)computedMinHS.get(i);
00893 
00894             if (node.state == HSNode.STATE_MINIMAL) {
00895 
00896                 for (int j = i + 1; j < computedMinHS.size(); ++j) {
00897                     
00898                     HSNode otherNode = (HSNode)computedMinHS.get(j);
00899                     
00900                     if ((otherNode.state == HSNode.STATE_MINIMAL) 
00901                         && node.edgeLabels.subsetOf(otherNode.edgeLabels) 
00902                         || otherNode.edgeLabels.subsetOf(node.edgeLabels)) return false;
00903                     
00904                 }
00905             }
00906         }
00907 
00908         return true;
00909     }
00910 
00911     public boolean hitsAllConflictSets() {
00912 
00913         for (int i = 0; i < computedMinHS.size(); ++i) {
00914 
00915             HSNode node = (HSNode)computedMinHS.get(i);
00916             if (node.state == HSNode.STATE_MINIMAL) {
00917                 
00918                 Iterator itCS = conflictSets.iterator();
00919                 while (itCS.hasNext()) {
00920 
00921                     SortedIntList cs = (SortedIntList)itCS.next();
00922 
00923                     if (!node.edgeLabels.intersects(cs)) return false;
00924                     
00925                 }
00926 
00927             }
00928         }
00929 
00930         return true;
00931 
00932     }
00933 
00934     protected boolean nodeInvariant(HSNode node) {
00935 
00936         boolean a = ((node.label == null) || !node.label.intersects(node.edgeLabels));
00937         boolean b = ((node.conflictSetIndex == -1) 
00938                     || (node.label.equals(conflictSets.get(node.conflictSetIndex)))
00939                     || ((attemptedPruneNode != null) 
00940                         && attemptedPruneNode.label.equals(conflictSets.get(node.conflictSetIndex))));
00941         boolean c = ((node == rootNode) || (node.parents.size() >= 1));
00942 
00943         boolean result = (a && b && c);
00944 
00945         if (!result) {
00946             if (!a) {
00947                 System.out.println("NODE INVARIANT VIOLATED: a");
00948                 System.out.println("node.label: " + node.label);
00949                 System.out.println("node.edgeLabels: " + node.edgeLabels);
00950             }
00951             if (!b) System.out.println("NODE INVARIANT VIOLATED: b");
00952             if (!c) System.out.println("NODE INVARIANT VIOLATED: c");
00953         }
00954 
00955         if (!b) {
00956             System.out.println("node: " + node + "   |  " 
00957                                + (SortedIntList)conflictSets.get(node.conflictSetIndex)
00958                 + "   conflictSetIndex: " + node.conflictSetIndex);
00959             System.out.print("attemptedPruneNode: ");
00960             if (attemptedPruneNode != null) {
00961                 System.out.print("" + attemptedPruneNode);
00962                 System.out.println("   conflictSetIndex: " + attemptedPruneNode.conflictSetIndex);
00963                 System.out.println(conflictSets.get(attemptedPruneNode.conflictSetIndex));
00964             } else System.out.println("null");
00965         }
00966 
00967         return result; 
00968                  
00969                 /*&& ((node.children.size() == 0) || (node.children.size() == node.label.size())
00970                     || (node.label.size() == computeNumUnprunedChildren(node))
00971                     || (node.state == HSNode.STATE_PRUNED))*/
00972     }
00973 }
00974 
00975 
00976 class EdgeNodePair {
00977 
00978     public int edge = -1;
00979 
00980     public HSNode node;
00981 
00982     public EdgeNodePair(int edge, HSNode node) {
00983         this.edge = edge;
00984         this.node = node;
00985     }
00986 
00987 }
00988 
00989 // A node in the HS-DAG
00990 class HSNode {
00991 
00992     final static int STATE_OPEN = 0;  // The node is neither closed nor is it a min. HS
00993     final static int STATE_CLOSED = 1;  // The node is closed (see the "Close" rule in Reiter).
00994     final static int STATE_MINIMAL = 2;  // The node is a min HS
00995     final static int STATE_PRUNED = 3;  // Removed by pruning algorithm.
00996 
00997     int state = STATE_OPEN;
00998 
00999     // the H(n), in terms of Reiter's formalization.
01000     SortedIntList edgeLabels;  
01001     
01002     // parent nodes
01003     ArrayList parents = new ArrayList();
01004     
01005     // child nodes: each element is of type EdgeNodePair
01006     ArrayList children = new ArrayList();
01007 
01008     SortedIntList label;
01009    
01010     // The index of label in the conflictSets data structure.
01011     int conflictSetIndex = -1;
01012 
01013     // flag during pruning algorithm; if false: this node (and all of its children!) do not
01014     // need to be considered for pruning.
01015     boolean relevantForPruning = true;
01016 
01017     public String toString() {
01018 
01019         String result = "{" + edgeLabels + "}; ";
01020         
01021         if ((state == STATE_OPEN) || (state == STATE_PRUNED)) {
01022             if (label == null) result = result + "{??}";
01023             else {
01024                 result = result + "{" + label + "}";
01025             }
01026             if (state == STATE_PRUNED) result = result + "  PRUNED";
01027         } 
01028         else if (state == STATE_CLOSED) {
01029             result = result + "X";
01030         } else if (state == STATE_MINIMAL) {
01031             result = result + "!!!";
01032         }
01033 
01034         result = result + " csIndex: " + conflictSetIndex;
01035 
01036         result = result + "  #(parents): " + parents.size() 
01037             + "  #(children): " + children.size();
01038 
01039         return result;
01040     }
01041 
01042 
01043 }


tug_ist_diagnosis_engine
Author(s): Safdar Zaman, Gerald Steinbauer
autogenerated on Mon Jan 6 2014 11:51:16