package edu.vt.marian.search; import java.util.*; import java.io.*; import edu.vt.marian.common.*; /** * Class manager for a link class that functions only as the union of disjoint subclasses. This is the only sort of superclass manager supported by MARIAN v.2.1.

The algorithm for each method is the same: create a MergeSequencer for merging results. (We use a MergeSequencer rather than a PriQueuSequencer because class hierarchies are designed by humans and thus each superclass is only expected to combine a handful of subclasses.) Call each subclass manager in turn, and feed the results into the Sequencer. Calls for statistics work the same way, but use totals and averages in place of Sequencers. @author Robert France @see ClassManager @see LinkClassManager @see MergeSequencer */ public class LinkSuperclassManager implements LinkClassManager { protected Debug debug; /** The class of links that this can manage. */ protected ClassID classID; /** Vector of LinkClassManagers for the (disjoint) subclasses. */ protected Vector subclassMgrs; /** Create a LinkClassManager for a particular superclass of disjoint (link) subclasses. */ // I'm not sure these parameters are sufficient. public LinkSuperclassManager(ClassID linkClID, Vector subclassManagers, Debug d) { debug = d; classID = linkClID; subclassMgrs = subclassManagers; } /** Create (or find in the local cache) a set of matches to description. @param description An abstract description of the links we're looking for: specifically, the link class (presumably this.classID), the direction, and a description of what is on one end. @return a WtdObjSet of nodes on the other end. */ public WtdObjSet match(LinkDesc description) { MergeSequencer merger = new MergeSequencer(subclassMgrs.size(), debug); Enumeration mgrs = subclassMgrs.elements(); try { LinkClassManager subclass = (LinkClassManager) mgrs.nextElement(); merger.addSet( subclass.match(description) ); } catch( NoSuchElementException e ) { } return( new EnumCacheWtdObjSet(merger, debug) ); } /** * Take a single node on one end of this link to all the nodes at the other * end. * * @param key The node as a WtdObj. * @param dir Whether key functions as source or sink. * @return The set of all nodes linked to key by instances of this link * class, weighted by link weights (if any) and key.wt(). */ public WtdObjSet keyNodeToTargetSet(WtdObj key, int dir) { MergeSequencer merger = new MergeSequencer(subclassMgrs.size(), debug); Enumeration mgrs = subclassMgrs.elements(); try { LinkClassManager subclass = (LinkClassManager) mgrs.nextElement(); merger.addSet( subclass.keyNodeToTargetSet(key, dir) ); } catch( NoSuchElementException e ) { } return( new EnumCacheWtdObjSet(merger, debug) ); } /** * Take a weighted object set of nodes on one end of the links in this class * to all the nodes at the other end. *

* NOTE: Where two nodes in keySet are both linked to the same "target" * node, some function must be applied to compute the node's weight in the * combined set. The default for links is max(), but any implementing * LinkClassManager class may use any function that suits its semantics. * * @param key the node as a WtdObj. * @param dir Whether key functions as source or sink. * @return The set of all nodes linked to any node in keySet by instances * of this link class, weighted by link weights (if any) and key.wt(). */ public WtdObjSet keySetToTargetSet(WtdObjSet keySet, int dir) { MergeSequencer merger = new MergeSequencer(subclassMgrs.size(), debug); Enumeration mgrs = subclassMgrs.elements(); try { LinkClassManager subclass = (LinkClassManager) mgrs.nextElement(); merger.addSet( subclass.keySetToTargetSet(keySet, dir) ); } catch( NoSuchElementException e ) { } return( new EnumCacheWtdObjSet(merger, debug) ); } /** * Syntactic sugar on keyNodeToTargetSet(). */ public WtdObjSet sourceToSinks(WtdObj sourceNode) { return( keyNodeToTargetSet(sourceNode, LinkDesc.SOURCE_TO_SINK) ); } /** * Syntactic sugar on keySetToTargetSet(). */ public WtdObjSet sourcesToSinks(WtdObjSet sourceSet) { return( keySetToTargetSet(sourceSet, LinkDesc.SOURCE_TO_SINK) ); } /** * Syntactic sugar on keyNodeToTargetSet(). */ public WtdObjSet sinkToSources(WtdObj sinkNode) { return( keyNodeToTargetSet(sinkNode, LinkDesc.SINK_TO_SOURCE) ); } /** * Syntactic sugar on keySetToTargetSet(). */ public WtdObjSet sinksToSources(WtdObjSet sinkSet) { return( keySetToTargetSet(sinkSet, LinkDesc.SINK_TO_SOURCE) ); } /** * Return the number of class instances currently in the factory. * Syntactic sugar on super.classSize(). */ public long numLinks() { long total = 0; Enumeration mgrs = subclassMgrs.elements(); try { LinkClassManager subclass = (LinkClassManager) mgrs.nextElement(); total += subclass.numLinks(); } catch( NoSuchElementException e ) { } return( total ); } /** * Return the number of unique source nodes currently in the factory. */ public long numSources() { long total = 0; Enumeration mgrs = subclassMgrs.elements(); try { LinkClassManager subclass = (LinkClassManager) mgrs.nextElement(); total += subclass.numSources(); } catch( NoSuchElementException e ) { } return( total ); } /** * Return the number of unique sink nodes currently in the factory. */ public long numSinks() { long total = 0; Enumeration mgrs = subclassMgrs.elements(); try { LinkClassManager subclass = (LinkClassManager) mgrs.nextElement(); total += subclass.numSinks(); } catch( NoSuchElementException e ) { } return( total ); } /** * Return the average number of links in this class that impinge on * a source node currently (== numLinks / numSources). */ public double avgSourceDegree() { long totalLinks = 0; long totalSources = 0; Enumeration mgrs = subclassMgrs.elements(); try { LinkClassManager subclass = (LinkClassManager) mgrs.nextElement(); totalLinks += subclass.numLinks(); totalSources += subclass.numSources(); } catch( NoSuchElementException e ) { } return( ((double) totalSources) / ((double) totalLinks) ); } /** * Return the average number of links in this class that impinge on * a sinknode currently (== numLinks / numSinks). */ public double avgSinkDegree() { long totalLinks = 0; long totalSinks = 0; Enumeration mgrs = subclassMgrs.elements(); try { LinkClassManager subclass = (LinkClassManager) mgrs.nextElement(); totalLinks += subclass.numLinks(); totalSinks += subclass.numSinks(); } catch( NoSuchElementException e ) { } return( ((double) totalSinks) / ((double) totalLinks) ); } /** * Return the number of class instances currently in the factory. */ public long classSize() { return( numLinks() ); } }