MinHittingSetsFM.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 
00042 public class MinHittingSetsFM {
00043 
00044     protected final static int CS_COMPUTING = 0;
00045     
00046     public final static int CS_ALL_MIN_DIAGS_COMPUTED = 1;
00047 
00048     public final static int CS_MAX_HS_SIZE_REACHED = 2;
00049 
00050     public final static int CS_MAX_NUM_MIN_HS_REACHED = 3;
00051     
00052 
00053     // The computed min. hitting sets. Each one is a HSNodeFM.
00054     protected ArrayList computedMinHS = new ArrayList();
00055     
00056     // max. size of desired min. hitting sets; -1 means all min. hitting sets are computed.
00057     protected int maxHSSize;
00058 
00059     // When maxNumMinHS are computed, then the algorithm stops. If -1: all min. hitting sets are computed.
00060     protected int maxNumMinHS;
00061 
00062     // True if the algorithm can rely on the fact that all conflicts are minimal.
00063     protected boolean conflictsAreMinimal;
00064 
00065     // List of ConflictSet instances.
00066     protected ArrayList fmConflictSets = new ArrayList();
00067 
00068     // The theorem prover. Remains "null" if the conflict sets are provided by the user of this class.
00069     protected ABTheoremProver theoremProver = null;
00070 
00071     // objects of class Component; sorted by name (string)
00072     protected TreeMap components = new TreeMap();
00073 
00074     // list of Component's. The index in the ArrayList corresponds to Component.id.
00075     protected ArrayList componentList = new ArrayList();
00076 
00077     // The set COMP. Is actually the set {0,..,n-1} where n is the number of components.
00078     protected SortedIntList componentIdSet = new SortedIntList();
00079 
00080     // The root node.
00081     protected HSNodeFM rootNode = null;
00082 
00083     // ArrayList of LinkedList of HSNodeFM. Contains the levels of the DAG.
00084     protected ArrayList levels = new ArrayList();
00085 
00086     protected int computationState = -1;
00087 
00088     protected HSNodeFM attemptedPruneNode = null;
00089 
00090     protected int numTPCalls;
00091     protected int numPrunings;
00092     protected int numReuses;
00093     protected int numExpansions;
00094 
00095     // the string identifier of the AB assumption, e.g.: "AB", "N_OK", "ABNORMAL",..
00096     //protected String assumptionAB;
00097 
00098     // e.g.: "NAB", "N_AB", "OK", "GOOD", "NOMINAL", ..
00099     //protected String assumptionNAB;
00100 
00101 
00122     public MinHittingSetsFM(boolean conflictsAreMinimal, ABTheoremProver tp, 
00123                             String assumptionAB, String assumptionNAB) 
00124         throws IllegalAssumption {
00125 
00126         // precondition
00127         assert(tp != null);
00128         
00129         this.conflictsAreMinimal = conflictsAreMinimal;
00130         this.theoremProver = tp;
00131 
00132         // extract components from assumptions
00133 
00134         Iterator it = tp.getAssumptions().iterator();
00135         int id = 0;
00136         
00137         while(it.hasNext()) {
00138             Assumption a = (Assumption)it.next();
00139             
00140             String ass = (String)a.identifier;
00141             boolean ass_ab = true;
00142             String compName = null;
00143 
00144             if (ass.matches(assumptionAB + "\\(" + "[a-zA-Z_0-9]+" + "\\)")) {
00145 
00146                 compName = ass.substring(assumptionAB.length() + 1,
00147                                                 ass.length() - 1);
00148                 ass_ab = true;
00149             } else if (ass.matches(assumptionNAB + "\\(" + "[a-zA-Z_0-9]+" + "\\)")) {
00150 
00151                 compName = ass.substring(assumptionNAB.length() + 1,
00152                                          ass.length() - 1);
00153                 ass_ab = false;
00154             } else throw new IllegalAssumption(ass);
00155 
00156             if (compName.length() == 0) throw new IllegalAssumption(ass);
00157 
00158             Object obj = components.get(compName);
00159             Component c;
00160             if (obj == null) {
00161                 c = new Component(compName, id);
00162                 //System.out.println("add new component: " + compName);
00163                 components.put(compName, c);
00164                 componentList.add(c);
00165                 ++id;
00166             } else {
00167                 c = (Component)obj;
00168             }
00169             if (ass_ab) c.ab = a; else c.nab = a;
00170             a.objTag = c;
00171         
00172         }
00173 
00174         for (int i = 0; i < components.size(); ++i) componentIdSet.addSorted(i);
00175         
00176     }  // constructo
00177 
00183     public ArrayList getMinHS() {
00184         ArrayList result = new ArrayList();
00185         result.ensureCapacity(computedMinHS.size());
00186         
00187         Iterator itMinHS = computedMinHS.iterator();
00188         while (itMinHS.hasNext()) {
00189             HSNodeFM node = (HSNodeFM)itMinHS.next();
00190             if (node.state != HSNodeFM.STATE_PRUNED) {
00191                 assert(node.state == HSNodeFM.STATE_MINIMAL);
00192                 
00193                 ArrayList candidate = new ArrayList();
00194                 Iterator itComps = node.edgeLabels.iterator();
00195                 while (itComps.hasNext()) {
00196                     Integer compId = (Integer)itComps.next();
00197                     Component c = (Component)componentList.get(compId.intValue());
00198                     candidate.add(c.nab);
00199                 }
00200                 if (candidate.size() > 0) {  // == 0 if root node is already consistent
00201                     result.add(candidate);
00202                 }
00203             }
00204         }
00205         
00206         return result;
00207     }
00208 
00214     public ArrayList getConflictsAsAss() {
00215         ArrayList result = new ArrayList();
00216 
00217         Iterator itConflicts = fmConflictSets.iterator();
00218         while (itConflicts.hasNext()) {
00219             ConflictSet cs = (ConflictSet)itConflicts.next();
00220             if (cs != null) {  // may be null due to pruning
00221                 ArrayList csAss = new ArrayList();
00222                 
00223                 Iterator itAbComp = cs.abComps.iterator();
00224                 while (itAbComp.hasNext()) {
00225                     int compIndex = ((Integer)itAbComp.next()).intValue();
00226                     Component c = (Component)componentList.get(compIndex);
00227                     csAss.add(c.ab);
00228                 }
00229                 
00230                 Iterator itNabComp = cs.nabComps.iterator();
00231                 while (itNabComp.hasNext()) {
00232                     int compIndex = ((Integer)itNabComp.next()).intValue();
00233                     Component c = (Component)componentList.get(compIndex);
00234                     csAss.add(c.nab);
00235                 }
00236 
00237                 result.add(csAss);
00238             }
00239             
00240         }
00241 
00242         return result;
00243     }
00244 
00245     /*
00246      * Returns one of the CS_xxx constants.
00247      */
00248     public int compute(int maxHSSize, int maxNumMinHS) {
00249         
00250         assert((maxHSSize >= 1) && (maxNumMinHS >= 1));
00251 
00252         // some initializations
00253 
00254         computationState = CS_COMPUTING;
00255         numTPCalls = 0;
00256         numPrunings = 0;
00257         numReuses = 0;
00258         numExpansions = 0;
00259         this.maxHSSize = maxHSSize;
00260         this.maxNumMinHS = maxNumMinHS;
00261         LinkedList lastLevelNodes  = new LinkedList(); // the nodes of the last level in the DAG
00262         int lastLevel = 0;
00263         levels.add(lastLevelNodes);
00264 
00265         // create root node
00266 
00267         rootNode = new HSNodeFM();
00268         rootNode.edgeLabels = new SortedIntList();  // H(n) is empty for the root node
00269         lastLevelNodes.add(rootNode);
00270 
00271         // create one DAG level after the other (breadth-first)
00272 
00273         while(computationState == CS_COMPUTING) {
00274 
00275             boolean expandNodes = (lastLevel < maxHSSize);
00276 
00277             LinkedList newLevelNodes; 
00278             if (expandNodes) {
00279                 newLevelNodes = new LinkedList();
00280                 levels.add(newLevelNodes);
00281             } else {
00282                 newLevelNodes = null;
00283             }
00284             
00285             processLastLevel(lastLevel, lastLevelNodes, newLevelNodes, expandNodes);
00286             //if (expandNodes) System.out.println("total # of nodes in new level: " + newLevelNodes.size());
00287 
00288             if (expandNodes) {
00289                 if (computationState == CS_COMPUTING) {
00290                     lastLevelNodes = newLevelNodes;
00291                     ++lastLevel;
00292                     assert(lastLevelNodes.size() > 0);
00293                 }
00294             } else {
00295                 if (computationState == CS_COMPUTING) {
00296                     computationState = CS_MAX_HS_SIZE_REACHED;
00297                 }
00298             }
00299   
00300         }
00301 
00302         assert(computationState != CS_COMPUTING);
00303         System.out.println("compute(): computationState: " + computationState);
00304         System.out.println("\nNumber of TP calls: " + numTPCalls);
00305         System.out.println("\nNumber prunings: " + numPrunings);
00306         System.out.println("\nNumber reuses: " + numReuses);
00307         System.out.println("\nNumber expansions: " + numExpansions);
00308         return computationState;
00309 
00310     }  // compute()
00311 
00312     public int computeMore(int newMaxHSSize, int newMaxNumMinHS) {
00313         
00314         assert((newMaxHSSize >= maxHSSize) && (newMaxNumMinHS >= maxNumMinHS));
00315 
00316         //System.out.println("computationState: " + computationState);
00317 
00318         if (computationState == CS_ALL_MIN_DIAGS_COMPUTED) return CS_ALL_MIN_DIAGS_COMPUTED;
00319         else {
00320             
00321             this.maxHSSize = newMaxHSSize;
00322             this.maxNumMinHS = newMaxNumMinHS; 
00323             int lastLevel = -1;
00324             LinkedList lastLevelNodes = null;
00325             LinkedList newLevelNodes = null;
00326 
00327             if (computationState == CS_MAX_HS_SIZE_REACHED) {
00328                 lastLevel = levels.size() - 1;
00329                 boolean expandNodes = (lastLevel < maxHSSize);
00330                 if (expandNodes) {
00331 
00332                     if (computedMinHS.size() < maxNumMinHS) {
00333 
00334                         computationState = CS_COMPUTING;
00335                         
00336                         lastLevelNodes = (LinkedList)levels.get(lastLevel);
00337                         assert(lastLevelNodes != null);
00338                         newLevelNodes = new LinkedList();
00339                         levels.add(newLevelNodes);
00340                         
00341                         expandLastLevel(lastLevel, lastLevelNodes, newLevelNodes);
00342                         ++lastLevel;
00343                         lastLevelNodes = newLevelNodes;
00344                         newLevelNodes = null;
00345                     
00346                     } else {
00347                         computationState = CS_MAX_NUM_MIN_HS_REACHED;
00348                     }
00349 
00350                 } else {
00351                     computationState = CS_MAX_HS_SIZE_REACHED;
00352                 }
00353                 
00354             } else {       
00355                 assert(computationState == CS_MAX_NUM_MIN_HS_REACHED);
00356 
00357                 if (computedMinHS.size() == maxNumMinHS) computationState = CS_MAX_NUM_MIN_HS_REACHED;
00358                 else {
00359                     computationState = CS_COMPUTING;
00360                     lastLevel = levels.size() - 2;
00361                     lastLevelNodes = (LinkedList)levels.get(lastLevel);
00362                     newLevelNodes = (LinkedList)levels.get(lastLevel + 1);
00363                 }
00364             }
00365 
00366             while(computationState == CS_COMPUTING) {
00367                  
00368                 assert(lastLevelNodes != newLevelNodes);
00369                 
00370                 boolean expandNodes = (lastLevel < maxHSSize);
00371                 if (expandNodes) {
00372                     if (newLevelNodes == null) {
00373                         newLevelNodes = new LinkedList();
00374                         levels.add(newLevelNodes);
00375                     }
00376                 } else {
00377                     newLevelNodes = null;
00378                 }
00379                 
00380                 processLastLevel(lastLevel, lastLevelNodes, newLevelNodes, expandNodes);
00381                 
00382                 if (expandNodes) {
00383                     //System.out.println("expand nodes, state = " + computationState);
00384                     if (computationState == CS_COMPUTING) {
00385                         lastLevelNodes = newLevelNodes;
00386                         newLevelNodes = null;
00387                         ++lastLevel;
00388                         assert(lastLevelNodes.size() > 0);
00389                     }
00390                 } else {
00391                     //System.out.println("not expand nodes, state = " + computationState);
00392                     if (computationState == CS_COMPUTING) {
00393                         computationState = CS_MAX_HS_SIZE_REACHED;
00394                     }
00395                 }
00396 
00397             }
00398 
00399             assert(computationState != CS_COMPUTING);
00400             //System.out.println("computeMore(): computationState: " + computationState);
00401             return computationState;
00402         }        
00403         
00404     }  // computeMore()
00405     
00406 
00407     // Performs the call: "TP(SD, COMP-H(n), OBS)" (in terms of Reiter's formalization).
00408     // Returns false if an inconsistency is detected.
00409     // If inconsistent: all NAB components in the conflict set are returned in nabConflicts,
00410     // the AB comp. in abConflicts.
00411     protected ConflictSet callTheoremProver(SortedIntList edgeLabels, ConflictSet label) {
00412 
00413         //System.out.println("Reiter: callTheoremProver(): size(edgeLabels) = " 
00414         //                   + edgeLabels.size());
00415 
00416         SortedIntList nabAssumptions = componentIdSet.subtract(edgeLabels);  // compute COMP-H(n)
00417 
00418         // set components in COMP-H(n) to "nab"
00419 
00420         Iterator itAss = nabAssumptions.iterator();
00421         while(itAss.hasNext()) {
00422             int assIndex = ((Integer)itAss.next()).intValue();
00423             Component c = (Component)componentList.get(assIndex);
00424             
00425             assert(c.nab != null);
00426             theoremProver.setAssumption(c.nab, true);
00427 
00428             if (c.ab != null) theoremProver.setAssumption(c.ab, false);
00429         }
00430 
00431         // set components in H(n) to "ab"
00432         
00433         Iterator itNegAss = edgeLabels.iterator();
00434         while(itNegAss.hasNext()) {
00435             int negassIndex = ((Integer)itNegAss.next()).intValue();
00436             Component c = (Component)componentList.get(negassIndex);
00437 
00438             assert(c.nab != null);
00439             theoremProver.setAssumption(c.nab, false);
00440             
00441             if (c.ab != null) theoremProver.setAssumption(c.ab, true); 
00442          }
00443 
00444         //System.out.println("CALL THEOREM PROVER: set add. to false: " + edgeLabels);
00445 
00446         // consistency check
00447 
00448         ++numTPCalls;
00449         if (theoremProver.isConsistent()) {
00450             //System.out.println("TP: consistent!");
00451             return null;  // consistent!!
00452         } else {
00453 
00454             // determine conflict set (set of assumptions) and add them to fmConflictSets
00455 
00456             ArrayList conflictingAss = theoremProver.contradiction().collectAssumptions();
00457             ConflictSet cs = new ConflictSet();
00458 
00459             Iterator itConflictingAss = conflictingAss.iterator();
00460             //System.out.print("TP returns conflict: ");
00461             while(itConflictingAss.hasNext()) {
00462                 Assumption a = (Assumption)itConflictingAss.next();
00463                 //System.out.print((String)a.getIdentifier() + ", ");
00464 
00465                 assert(a.objTag != null);
00466                 Component c = (Component)a.objTag;
00467                 if (c.nab == a) {
00468                     cs.nabComps.addSorted(c.id);
00469                     label.nabComps.addSorted(c.id);  
00470                 }
00471                 else {
00472                     assert(c.ab == a);
00473                     cs.abComps.addSorted(c.id);
00474                     label.abComps.addSorted(c.id);
00475                 }
00476             }
00477 
00478             return cs;
00479         }
00480 
00481     }  // callTheoremProver()
00482 
00483 
00484     /*
00485      * This node and all of its children are "removed", except of those nodes with another
00486      * parent which is not removed.
00487      */
00488     protected void prune(HSNodeFM node, HSNodeFM prunedParent) {
00489 
00490         assert(nodeInvariant(node));
00491 
00492         if ((node.state == HSNodeFM.STATE_OPEN) || (node.state == HSNodeFM.STATE_EXPANDED)
00493             || (node.state == HSNodeFM.STATE_MINIMAL)) {
00494 
00495             boolean hasAliveParents;  // are there any parents which are NOT relabelled/removed?
00496             if (node.parents.size() == 1) hasAliveParents = false;
00497             else {
00498                 assert(node.parents.size() > 1);
00499                 
00500                 hasAliveParents = false;
00501 
00502                 Iterator itParents = node.parents.iterator();
00503                 while (itParents.hasNext()) {
00504                     HSNodeFM parent = (HSNodeFM)itParents.next();
00505                     if ((parent != prunedParent) && (parent.state != HSNodeFM.STATE_PRUNED)) {
00506                         hasAliveParents = true;
00507                         break;
00508                     }
00509                 }
00510             }
00511 
00512             if (!hasAliveParents) {  // prune only if there are no alive parents!
00513                 
00514                 node.state = HSNodeFM.STATE_PRUNED;
00515                 ++numPrunings;
00516 
00517                 //System.out.println("REMOVE node: " + node);
00518 
00519                 Iterator itChildren = node.children.iterator();
00520                 while (itChildren.hasNext()) {
00521                     HSNodeFM child = ((EdgeNodePairFM)itChildren.next()).node;
00522                     if (child.state != HSNodeFM.STATE_PRUNED) {
00523                         prune(child, node);
00524                     }
00525                 }
00526             }
00527             else {
00528                 //System.out.println("DONT remove node (alive parents): " + node);
00529             }
00530         }
00531 
00532         assert(nodeInvariant(node));
00533 
00534     }  // prune()
00535 
00536 
00537     /*
00538      * Called during pruning. node is to be relabelled by newNode.label. 
00539      * Some of its children may be pruned.
00540      */
00541     protected void relabel(HSNodeFM node, HSNodeFM newNode) {
00542 
00543         // precondition
00544         assert((node.state != HSNodeFM.STATE_MINIMAL) 
00545                &&  newNode.label.nabComps.properSubsetOf(node.label.nabComps)
00546                && newNode.label.abComps.subsetOf(node.label.abComps));
00547            
00548         assert(nodeInvariant(node));
00549         assert(nodeInvariant(newNode));
00550         
00551         // relabel node
00552 
00553         SortedIntList removeLabel = node.label.nabComps.subtract(newNode.label.nabComps);
00554         node.label = newNode.label;
00555         fmConflictSets.set(node.conflictSetIndex, new ConflictSet(newNode.label));
00556         newNode.conflictSetIndex = node.conflictSetIndex;
00557 
00558         // iterate through children: if child is to be removed, call prune() for it
00559 
00560         int prunedChildrenCount = 0;
00561         Iterator itChildren = node.children.iterator();
00562         while (itChildren.hasNext()) {
00563             EdgeNodePairFM child = (EdgeNodePairFM)itChildren.next();
00564 
00565             if (removeLabel.contains(child.edge)) {  // determine if child is to be removed
00566                 
00567                 if (child.node.state != HSNodeFM.STATE_PRUNED) {
00568                     prune(child.node, node);
00569                 }
00570 
00571                 ++prunedChildrenCount;
00572             }    
00573             
00574             
00575         }
00576         assert(prunedChildrenCount == removeLabel.size());
00577         
00578         assert(nodeInvariant(node));
00579         assert(nodeInvariant(newNode));
00580         assert(node.label.equals(newNode.label));
00581     }  // relabel();
00582 
00583 
00584     // returns number of children which are NOT pruned
00585     protected int computeNumUnprunedChildren(HSNodeFM node) {
00586         int n = 0;
00587         Iterator itChildren = node.children.iterator();
00588         while (itChildren.hasNext()) {
00589             HSNodeFM child = ((EdgeNodePairFM)itChildren.next()).node;
00590             if (child.state != HSNodeFM.STATE_PRUNED) ++n;
00591         }
00592 
00593         return n;
00594     }
00595 
00596 
00597     // node has just been labelled, now check if DAG can be pruned using this label
00598     protected void attemptPrune(HSNodeFM node) {
00599 
00600         // precondition
00601         assert(((node.state == HSNodeFM.STATE_OPEN) || (node.state == HSNodeFM.STATE_EXPANDED))
00602                && ((node.label.nabComps.size() > 0) || (node.label.abComps.size() > 0))
00603                && (node != rootNode) && nodeInvariant(node));
00604 
00605         attemptedPruneNode = node;
00606         int oldConflictSetIndex = node.conflictSetIndex;
00607         boolean pruned = false;  // set to true when pruning is done
00608 
00609         // always try to relabel root node
00610         rootNode.relevantForPruning = true;
00611         boolean relevantNodesExist = true;
00612 
00613         // iterate through levels; stop when there are no more nodes which are candidates for relabelling
00614 
00615         Iterator itLevels = levels.iterator();
00616         while(itLevels.hasNext() && relevantNodesExist) {
00617         
00618             relevantNodesExist = false;
00619 
00620             LinkedList level = (LinkedList)itLevels.next();
00621             Iterator itLevelNodes = level.iterator();
00622 
00623             SortedIntList nabIntersectionSet = new SortedIntList();
00624   
00625             // iterate through nodes of a level
00626 
00627             while(itLevelNodes.hasNext()) {
00628 
00629                 HSNodeFM otherNode = (HSNodeFM)itLevelNodes.next();
00630                 
00631                 if (((otherNode.state == HSNodeFM.STATE_OPEN) || (otherNode.state == HSNodeFM.STATE_EXPANDED)) 
00632                     && (otherNode.label != null) 
00633                     && otherNode.relevantForPruning) {
00634                     
00635                     // determine if we can prune; if not: are there irrelevant subtrees?
00636 
00637                     // does the NAB part of the labels of the two nodes intersect?
00638                     nabIntersectionSet.clear();
00639                     boolean intersects = otherNode.label.nabComps.intersection(node.label.nabComps, nabIntersectionSet);
00640 
00641                     assert((!intersects && (nabIntersectionSet.size() == 0))
00642                            || (intersects && (nabIntersectionSet.size() != 0)));
00643                    
00644                     // "A.properSubsetOf(B)" is equivalent to "A.intersects(B) and (A = intersection(A, B))
00645                     // and (size(A) < size(B))"
00646                     boolean canPrune = (intersects && (nabIntersectionSet.size() == node.label.nabComps.size())
00647                                         && (node.label.nabComps.size() < otherNode.label.nabComps.size())
00648                                         && node.label.abComps.subsetOf(otherNode.label.abComps));
00649                   
00650                     assert(canPrune && node.label.nabComps.properSubsetOf(otherNode.label.nabComps)
00651                            && node.label.abComps.subsetOf(otherNode.label.abComps)
00652                            ||
00653                            !canPrune && (!node.label.nabComps.properSubsetOf(otherNode.label.nabComps)
00654                                          || !node.label.abComps.subsetOf(otherNode.label.abComps))
00655                         );
00656 
00657                     if (canPrune) {  // prune!
00658 
00659                         //System.out.println("MinHittingSetsFM: prune node, relabel " + otherNode + "  with " + node);
00660 
00661                         relabel(otherNode, node);
00662                         pruned = true;
00663 
00664                     } else {  // cannot prune: investigate which subtrees are not relevant for further search
00665     
00666                         if ((nabIntersectionSet.size() > 0)        // some subtrees are not relevant
00667                             && (otherNode.children.size() > 0)) {   // .. and otherNode has already been expanded
00668                             
00669                             //System.out.println("IGNORE children of node: " + otherNode + ";   child edges: " + nabIntersectionSet); 
00670 
00671                             Iterator itIntersection = nabIntersectionSet.iterator();
00672                             int nextItem;
00673                             if (itIntersection.hasNext()) 
00674                                 nextItem = ((Integer)itIntersection.next()).intValue();
00675                             else nextItem = Integer.MAX_VALUE;
00676                             
00677                             Iterator itChildren = otherNode.children.iterator();
00678                             while (itChildren.hasNext()) {
00679                                 EdgeNodePairFM child = (EdgeNodePairFM)itChildren.next();
00680                                 
00681                                 if (child.edge == nextItem) {
00682                                     child.node.relevantForPruning = false;
00683                                     assert(node.label.nabComps.contains(child.edge));
00684                                     if (itIntersection.hasNext()) 
00685                                         nextItem = ((Integer)itIntersection.next()).intValue();
00686                                     else nextItem = Integer.MAX_VALUE;
00687                                 } else {
00688                                     child.node.relevantForPruning = true;
00689                                     relevantNodesExist = true;
00690                                 }
00691                             }
00692 
00693                             assert(!itIntersection.hasNext());
00694                             
00695                         } else {  // all subtrees are relevant
00696                             
00697                             Iterator itChildren = otherNode.children.iterator();
00698                             while (itChildren.hasNext()) {
00699                                 HSNodeFM child = ((EdgeNodePairFM)itChildren.next()).node;
00700                                 child.relevantForPruning = true;
00701                             }
00702                             relevantNodesExist = true;
00703 
00704                         }
00705 
00706                     }  // !canPrune
00707 
00708                 }  // node is open and relevant for pruning
00709 
00710                 else if (!otherNode.relevantForPruning) {  // if node not relevant => children are not rel., too
00711 
00712                     Iterator itChildren = otherNode.children.iterator();
00713                     while(itChildren.hasNext()) {
00714                         HSNodeFM child = ((EdgeNodePairFM)itChildren.next()).node;
00715                         child.relevantForPruning = false;
00716                     }
00717 
00718                 }
00719 
00720             }  // iterate through nodes of a level
00721 
00722         }  // iterate through levels
00723 
00724         if (pruned) fmConflictSets.set(oldConflictSetIndex, null);
00725         attemptedPruneNode = null;
00726 
00727         assert(nodeInvariant(node));
00728 
00729     }  // attemptPrune()
00730 
00731     /*
00732      * Searches in the list of already computed conflict sets for a conflict set cs
00733      * which refutes edgeLabel (= H(n) in Reiter's notation), i.e., cs shows that H(n)
00734      * is inconsistent with SD and OBS.
00735      *
00736      * If no such conflict is found, then this method returns -1. Otherwise, it returns
00737      * an index to the collection conflictSets such that the following holds for cs (= conflictsSets[index]):
00738      *   cs.abComps is an improper subset of H(n)  [= edgeLabel]
00739      *   AND cs.nabComps does not intersect H(n)
00740      *   
00741      */
00742     protected int searchRefutingCS(SortedIntList edgeLabel) {
00743         for (int i = 0; i < fmConflictSets.size(); ++i) {
00744 
00745             Object o = fmConflictSets.get(i);
00746             if (o != null) {  // the conflict set at this index may have been removed by pruning!
00747                 ConflictSet cs = (ConflictSet)fmConflictSets.get(i);
00748                 assert((cs.nabComps.size() > 0) || (cs.abComps.size() > 0));
00749                 
00750                 /*
00751                 System.out.println("searchRefutingCS: cs.nabComps: " + cs.nabComps + ";  abComps: " + cs.abComps);
00752                 System.out.println("searchRefutingCS: edgeLabel: " + edgeLabel);
00753 
00754                 if (cs.abComps.subsetOf(edgeLabel)) {
00755                     System.out.println("SUBSET");
00756                 }
00757                 else System.out.println("NOT SUBSET");
00758 
00759                 if (cs.nabComps.intersects(edgeLabel)) {
00760                     System.out.println("INTERSECTS");
00761                 }
00762                 else System.out.println("NOT INTERSECTS");
00763                 */
00764                 
00765                 if (cs.abComps.subsetOf(edgeLabel)
00766                     && !cs.nabComps.intersects(edgeLabel)) {
00767                     
00768                     return i;
00769                 }
00770 
00771                 
00772                     
00773             }
00774         }
00775 
00776         return -1;
00777     }
00778 
00779     /*
00780      * Compute label of node: either it is detected that this node is a min. HS,
00781      * or it is labelled by a new conflict set. The CS is either taken from the 
00782      * provided conflict sets, or it is computed by calling the theorem prover.
00783      */
00784     protected void computeLabel(HSNodeFM node) {
00785 
00786         assert(node.state == HSNodeFM.STATE_OPEN);
00787         assert(node.label == null);
00788         assert(nodeInvariant(node));
00789 
00790         // check if node can be closed
00791 
00792         if (canClose(node)) {
00793             node.state = HSNodeFM.STATE_CLOSED;
00794             //System.out.println("CLOSE node: " + node);
00795         }
00796 
00797         else {
00798 
00799             // before making call to TP: check if there is already a conflict set which refutes this node
00800 
00801             int existingCSIndex = searchRefutingCS(node.edgeLabels);
00802             if (existingCSIndex >= 0) {
00803                 assert(callTheoremProver(node.edgeLabels, new ConflictSet()) != null);
00804                 ConflictSet existingCS = (ConflictSet)fmConflictSets.get(existingCSIndex);
00805                 assert(existingCS != null);
00806                 node.label = existingCS;
00807                 node.conflictSetIndex = existingCSIndex;
00808                 //System.out.println("REFUTE mode assignment using an existing conflict set: {" + existingCS + "} refutes " + node);
00809                 //if (!conflictsAreMinimal && (node != rootNode)) attemptPrune(node);
00810                 
00811             
00812             } else {  // no refuting conflict set found
00813 
00814                 ConflictSet label = new ConflictSet();
00815                 ConflictSet csForDB = callTheoremProver(node.edgeLabels, label);
00816                 boolean consistent = (csForDB == null);
00817                 if (consistent) {
00818                     node.state = HSNodeFM.STATE_MINIMAL;
00819                 }
00820                 else {
00821                     fmConflictSets.add(csForDB);
00822                     if (label.nabComps.size() == 0) {  // conflict: if only AB's, no NAB's => close node
00823                         node.state = HSNodeFM.STATE_CLOSED;
00824                     }
00825                     else {
00826                         node.label = label;
00827                         node.conflictSetIndex = fmConflictSets.size() - 1;
00828                         //System.out.println("computed label of node: " + node);
00829                         if (!conflictsAreMinimal && (node != rootNode)) attemptPrune(node);
00830                     }
00831                 }
00832             }
00833             
00834         }  // node cannot be closed
00835 
00836         assert(nodeInvariant(node));
00837 
00838     }  // computeLabel()
00839 
00840 
00841     // Returns true iff the node can be closed (the 2nd pruning rule).
00842     protected boolean canClose(HSNodeFM node) {
00843         
00844         assert(nodeInvariant(node));
00845 
00846         Iterator itMinHS = computedMinHS.iterator();
00847         while (itMinHS.hasNext()) {
00848             HSNodeFM n1 = (HSNodeFM)itMinHS.next();
00849             if (n1.state == HSNodeFM.STATE_MINIMAL) {
00850                 SortedIntList hs = n1.edgeLabels;
00851                 if (hs.subsetOf(node.edgeLabels)) {
00852                     assert(hs.properSubsetOf(node.edgeLabels));
00853                     return true;
00854                 }
00855             } else assert(n1.state == HSNodeFM.STATE_PRUNED);
00856         }
00857 
00858         return false;
00859     }
00860 
00861 
00862     /* 
00863      * Returns the new nodes which were created out of the nodes of the last level.
00864      * If expandNodes is true, then no new nodes are created (only the nodes of the last
00865      * level are checked if they are min. HS);
00866      */
00867     protected void processLastLevel(int lastLevel, LinkedList lastLevelNodes, 
00868                                     LinkedList newLevelNodes, boolean expandNodes) {
00869 
00870         //System.out.println("processLastLevel: ");
00871 
00872         boolean hasOpenNodes = false;
00873 
00874         Iterator itLastNodes = lastLevelNodes.iterator();
00875         while(itLastNodes.hasNext()) {
00876 
00877             HSNodeFM node = (HSNodeFM)itLastNodes.next();
00878             assert(nodeInvariant(node));
00879             if (node.state == HSNodeFM.STATE_OPEN) {
00880 
00881                 if (node.label == null) {  // node may already be refuted by a CS
00882                     computeLabel(node);
00883                 }
00884 
00885                 if (node.state == HSNodeFM.STATE_MINIMAL) {
00886                     computedMinHS.add(node);
00887                     if (computedMinHS.size() == maxNumMinHS) {
00888                         computationState = CS_MAX_NUM_MIN_HS_REACHED;
00889                         break;
00890                     }
00891                 } else if (node.state == HSNodeFM.STATE_OPEN) {
00892                     hasOpenNodes = true;
00893                     if (expandNodes) {
00894                         expandNode(node, newLevelNodes, lastLevel);
00895                     }
00896                 }
00897             } else if (node.state == HSNodeFM.STATE_EXPANDED) {
00898                 hasOpenNodes = true;
00899             }
00900 
00901             assert(nodeInvariant(node));
00902 
00903         }  // while(itLastNodes.hasNext())
00904 
00905         if ((computationState == CS_COMPUTING) && !hasOpenNodes) {
00906             computationState = CS_ALL_MIN_DIAGS_COMPUTED;
00907         }
00908     }
00909 
00910     protected void expandLastLevel(int lastLevel, LinkedList lastLevelNodes, 
00911                                    LinkedList newLevelNodes) {
00912 
00913         boolean hasOpenNodes = false;
00914 
00915         Iterator itLastNodes = lastLevelNodes.iterator();
00916         while(itLastNodes.hasNext()) {
00917 
00918             HSNodeFM node = (HSNodeFM)itLastNodes.next();
00919             assert(nodeInvariant(node));
00920             
00921             if (node.state == HSNodeFM.STATE_OPEN) {
00922                 assert(node.label != null);  // this method presumes that a TP call has already been performed 
00923                 hasOpenNodes = true;
00924                 expandNode(node, newLevelNodes, lastLevel);               
00925             }
00926                 
00927             assert(nodeInvariant(node));
00928 
00929         }  // while(itLastNodes.hasNext())
00930 
00931         assert(computationState == CS_COMPUTING);
00932         if (!hasOpenNodes) {
00933             computationState = CS_ALL_MIN_DIAGS_COMPUTED;
00934         }
00935     }
00936 
00937 
00938     /*
00939      * Expand a node: generate child nodes and set their edgeLabels field.
00940      * The new nodes are added to newNodes.
00941      */
00942     protected void expandNode(HSNodeFM node, LinkedList newNodes, int lastLevel) {
00943         // precondition
00944         assert((node.label != null) && nodeInvariant(node));
00945 
00946         ++numExpansions;
00947 
00948         int oldNewNodesSize = newNodes.size();
00949         int newEdge;
00950 
00951         // iterate through the conflict set of this node
00952 
00953         Iterator itLabel = node.label.nabComps.iterator();
00954         while(itLabel.hasNext()) {
00955 
00956             // compute H(n) for the new node
00957 
00958             newEdge = ((Integer)itLabel.next()).intValue();            
00959             SortedIntList newEdgeLabels = (SortedIntList)node.edgeLabels.clone();
00960             newEdgeLabels.addSorted(newEdge);
00961             
00962             //System.out.println("new H(n): " + newEdgeLabels);
00963 
00964             // check if "Reusing" rule can be applied. Iterate through new nodes only.
00965             // Consider only nodes which were NOT created by expansion of node (ie by this method call).
00966 
00967             boolean reused = false;
00968             Iterator itNewNodes = newNodes.iterator();
00969             for (int i = 0; i < oldNewNodesSize; ++i) {
00970                 HSNodeFM m = (HSNodeFM)itNewNodes.next();
00971                 if (newEdgeLabels.equals(m.edgeLabels)) {  // reuse of node m!!
00972                     node.children.add(new EdgeNodePairFM(newEdge, m));
00973                     m.parents.add(node);
00974                     reused = true;
00975                     ++numReuses;
00976                     //System.out.println("REUSE node m: " + m);
00977                     break;
00978                 }
00979             }
00980 
00981             if (!reused) {  // no reuse possible: create new node
00982 
00983                 HSNodeFM newNode = new HSNodeFM();
00984                 newNode.edgeLabels = newEdgeLabels;
00985 
00986                 node.children.add(new EdgeNodePairFM(newEdge, newNode));
00987                 newNode.parents.add(node);
00988                 newNodes.add(newNode);
00989 
00990                 //System.out.println("NO reuse possible, create new node: " + newNode);
00991             }
00992 
00993         }  // while(itLabel.hasNext())
00994  
00995         node.state = HSNodeFM.STATE_EXPANDED;
00996         assert(nodeInvariant(node));
00997         
00998     }  // expandNode()
00999 
01000     // for testing purposes only.
01001     public boolean checkMinimalityHS() {
01002 
01003         for (int i = 0; i < computedMinHS.size(); ++i) {
01004 
01005             HSNodeFM node = (HSNodeFM)computedMinHS.get(i);
01006 
01007             if (node.state == HSNodeFM.STATE_MINIMAL) {
01008 
01009                 for (int j = i + 1; j < computedMinHS.size(); ++j) {
01010                     
01011                     HSNodeFM otherNode = (HSNodeFM)computedMinHS.get(j);
01012                     
01013                     if ((otherNode.state == HSNodeFM.STATE_MINIMAL) 
01014                         && node.edgeLabels.subsetOf(otherNode.edgeLabels) 
01015                         || otherNode.edgeLabels.subsetOf(node.edgeLabels)) return false;
01016                     
01017                 }
01018             }
01019         }
01020 
01021         return true;
01022     }
01023 
01024     // for testing purposes only.
01025     protected boolean nodeInvariant(HSNodeFM node) {
01026 
01027         boolean a = ((node.label == null) || !node.label.nabComps.intersects(node.edgeLabels));
01028         boolean b = (node.conflictSetIndex == -1) || (node.label.equals(fmConflictSets.get(node.conflictSetIndex)));
01029         boolean c = ((node == rootNode) || (node.parents.size() >= 1));
01030 
01031         boolean result = (a && b && c);
01032 
01033         if (!result) {
01034             if (!a) System.out.println("NODE INVARIANT VIOLATED: a");
01035             if (!b) {
01036                 System.out.println("NODE INVARIANT VIOLATED: b");
01037                 System.out.println("node: " + node);
01038                 System.out.println("fmConflictSets.get(node.conflictSetIndex): " + fmConflictSets.get(node.conflictSetIndex));
01039             }
01040             if (!c) System.out.println("NODE INVARIANT VIOLATED: c");
01041         }
01042 
01043         return result; 
01044                  
01045                 /*&& ((node.children.size() == 0) || (node.children.size() == node.label.size())
01046                     || (node.label.size() == computeNumUnprunedChildren(node))
01047                     || (node.state == HSNodeFM.STATE_PRUNED))*/
01048     }
01049 }
01050 
01051 
01052 /*
01053  * Internally used by MinHittingSetsFM.
01054  * A record which encapsulates a component.
01055  */
01056 class Component {
01057 
01058     public Component(String name, int id) {
01059         this.name = name;
01060         this.id = id;
01061     }
01062 
01063     // The name of the component. E.g., if there is an assumption "NAB(C1)", then name = "C1".
01064     String name;
01065 
01066     /* 
01067      * In internal integer ID is assigned to each component. 
01068      * This allows for efficient set operations (e.g., create the diff of two integer sets).
01069      */
01070     int id;
01071 
01072     // an assumption of the style "NAB(x)"
01073     Assumption nab;
01074 
01075     // an assumption of the style "AB(x)"
01076     Assumption ab;
01077 
01078 
01079 }
01080 
01081 class ConflictSet {
01082 
01083     SortedIntList abComps;
01084 
01085     SortedIntList nabComps;
01086 
01087     public ConflictSet(SortedIntList abComps, SortedIntList nabComps) {
01088         this.abComps = abComps;
01089         this.nabComps = nabComps;
01090     }
01091 
01092     public ConflictSet() {
01093         abComps = new SortedIntList();
01094         nabComps = new SortedIntList();
01095     }
01096 
01097     public ConflictSet(ConflictSet other) {
01098         abComps = (SortedIntList)other.abComps.clone();
01099         nabComps = (SortedIntList)other.nabComps.clone();
01100     }
01101 
01102     public String toString() {
01103         return "AB: [" + abComps + "];  NAB: [" + nabComps + "]";
01104     }
01105 
01106     public boolean equals(Object o) {
01107         ConflictSet other = (ConflictSet)o;
01108         return (abComps.equals(other.abComps) && nabComps.equals(other.nabComps));
01109     }
01110 }
01111 
01112 class EdgeNodePairFM {
01113 
01114     public int edge = -1;
01115 
01116     public HSNodeFM node;
01117 
01118     public EdgeNodePairFM(int edge, HSNodeFM node) {
01119         this.edge = edge;
01120         this.node = node;
01121     }
01122 
01123 }
01124 
01125 // A node in the HS-DAG
01126 class HSNodeFM {
01127 
01128     final static int STATE_OPEN = 0;  // The node is neither closed nor is it a min. HS
01129     final static int STATE_CLOSED = 1;  // The node is closed (see the "Close" rule in Reiter).
01130     final static int STATE_MINIMAL = 2;  // The node is a min HS
01131     final static int STATE_PRUNED = 3;  // Removed by pruning algorithm.
01132     final static int STATE_EXPANDED = 4;
01133 
01134 
01135     int state = STATE_OPEN;
01136 
01137     // the H(n), in terms of Reiter's formalization.
01138     SortedIntList edgeLabels;  
01139     
01140     // parent nodes
01141     ArrayList parents = new ArrayList();
01142     
01143     // child nodes: each element is of type EdgeNodePair
01144     ArrayList children = new ArrayList();
01145 
01146     ConflictSet label;
01147 
01148     // The index of label in the conflictSets data structure.
01149     int conflictSetIndex = -1;
01150 
01151     // flag during pruning algorithm; if false: this node (and all of its children!) do not
01152     // need to be considered for pruning.
01153     boolean relevantForPruning = true;
01154 
01155     public String toString() {
01156 
01157         String result = "{" + edgeLabels + "}; ";
01158         
01159         if ((state == STATE_OPEN) || (state == STATE_PRUNED) || (state == STATE_EXPANDED)) {
01160             if (label == null) result = result + "{??}";
01161             else {
01162                 result += "label NAB: {" + label.nabComps + "}";
01163                 if (label.abComps.size() > 0) result += ", label AB: {" + label.abComps + "}";
01164             }
01165             if (state == STATE_PRUNED) result = result + "  PRUNED";
01166         } 
01167         else if (state == STATE_CLOSED) {
01168             result = result + "X";
01169         } else if (state == STATE_MINIMAL) {
01170             result = result + "!!!";
01171         }
01172 
01173         result = result + "  #(parents): " + parents.size() 
01174             + "  #(children): " + children.size();
01175 
01176         return result;
01177     }
01178 
01179 
01180 }


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