package LBJ2.classify; import LBJ2.learn.ChildLexicon; import LBJ2.learn.Lexicon; import LBJ2.util.ByteString; import LBJ2.util.ExceptionlessInputStream; import LBJ2.util.ExceptionlessOutputStream; /** * A referring discrete feature is one that has its own identifier, but whose * value comes from a separate feature that it refers to. * * @author Nick Rizzolo **/ public abstract class DiscreteReferrer extends DiscreteFeature { /** The feature being referred to. */ protected DiscreteFeature referent; /** * For internal use only. * * @see Feature#readFeature(ExceptionlessInputStream) **/ protected DiscreteReferrer() { } /** * Sets both the identifier and the referent. * * @param c The classifier that produced this feature. * @param r The discrete feature referred to by this new feature. **/ public DiscreteReferrer(Classifier c, DiscreteFeature r) { this(c.containingPackage, c.name, r, r.getValueIndex(), r.totalValues()); } /** * Sets both the identifier and the referent. * * @param c The classifier that produced this feature. * @param r The discrete feature referred to by this new feature. * @param av The allowable values of the classifier that produced * <code>r</code>. **/ public DiscreteReferrer(Classifier c, DiscreteFeature r, String[] av) { this(c.containingPackage, c.name, r, c.valueIndexOf(av[r.getValueIndex()]), (short) c.allowableValues().length); } /** * Constructs a new referring feature. * * @param p The new discrete feature's package. * @param c The name of the classifier that produced this feature. * @param r The discrete feature referred to by this new feature. * @param vi The index corresponding to the value. * @param t The total allowable values for this feature. **/ public DiscreteReferrer(String p, String c, DiscreteFeature r, short vi, short t) { super(p, c, vi, t); referent = r; } /** * Determines if this feature is a referring feature. * * @return <code>true</code> iff this feature is a referring feature. **/ public boolean isReferrer() { return true; } /** Returns the value of {@link #referent}. */ public DiscreteFeature getReferent() { return referent; } /** * The depth of a feature is one more than the maximum depth of any of its * children, or 0 if it has no children. * * @return The depth of this feature as described above. **/ public int depth() { return referent.depth() + 1; } /** * Gives a string representation of the value of this feature. * * @return Whatever is returned by this method on {@link #referent}. **/ public String getStringValue() { return referent.getStringValue(); } /** * Gives a string representation of the value of this feature. * * @return Whatever is returned by this method on {@link #referent}. **/ public ByteString getByteStringValue() { return referent.getByteStringValue(); } /** * Determines whether or not the parameter is equivalent to the string * representation of the value of this feature. * * @param v The string to compare against. * @return <code>true</code> iff <code>v</code> is equivalent to the string * representation of the value of this feature. **/ public boolean valueEquals(String v) { return referent.valueEquals(v); } /** * Takes care of any feature-type-specific tasks that need to be taken care * of when removing a feature of this type from a {@link ChildLexicon}, in * particular updating parent counts and removing children of this feature * if necessary. * * @param lex The child lexicon this feature is being removed from. **/ public void removeFromChildLexicon(ChildLexicon lex) { lex.decrementParentCounts(referent); } /** * Does a feature-type-specific lookup of this feature in the given * {@link ChildLexicon}. * * @param lex The child lexicon this feature is being looked up in. * @param label The label of the example containing this feature, or -1 if * we aren't doing per class feature counting. * @return The index of <code>f</code> in this lexicon. **/ public int childLexiconLookup(ChildLexicon lex, int label) { return lex.childLexiconLookup(this, label); } /** * The hash code of a <code>DiscreteReferrer</code> is the sum of * the hash codes of its containing package, identifier, and the referent * feature. * * @return The hash code of this feature. **/ public int hashCode() { return 17 * super.hashCode() + referent.hashCode(); } /** * Used to sort features into an order that is convenient both to page * through and for the lexicon to read off disk. * * @param o An object to compare with. * @return Integers appropriate for sorting features first by package, then * by identifier, then by value. **/ public int compareTo(Object o) { int d = compareNameStrings(o); if (d != 0) return d; DiscreteReferrer r = (DiscreteReferrer) o; return referent.compareTo(r.referent); } /** * Writes a string representation of this <code>Feature</code> to the * specified buffer. * * @param buffer The buffer to write to. **/ public void write(StringBuffer buffer) { writeNameString(buffer); buffer.append("->"); referent.write(buffer); } /** * Writes a string representation of this <code>Feature</code> to the * specified buffer, omitting the package name. * * @param buffer The buffer to write to. **/ public void writeNoPackage(StringBuffer buffer) { String p = containingPackage; containingPackage = null; writeNameString(buffer); buffer.append("->"); referent.writeNoPackage(buffer); containingPackage = p; } /** * Writes a complete binary representation of the feature. * * @param out The output stream. **/ public void write(ExceptionlessOutputStream out) { super.write(out); referent.write(out); } /** * Reads the representation of a feaeture with this object's run-time type * from the given stream, overwriting the data in this object. * * @param in The input stream. **/ public void read(ExceptionlessInputStream in) { super.read(in); referent = (DiscreteFeature) Feature.readFeature(in); } /** * Writes a binary representation of the feature intended for use by a * lexicon, omitting redundant information when possible. * * @param out The output stream. * @param lex The lexicon out of which this feature is being written. * @param c The fully qualified name of the assumed class. The runtime * class of this feature won't be written if it's equivalent to * <code>c</code>. * @param p The assumed package string. This feature's package string * won't be written if it's equivalent to <code>p</code>. * @param g The assumed classifier name string. This feature's * classifier name string won't be written if it's equivalent * to <code>g</code>. * @param si The assumed identifier as a string. If this feature has a * string identifier, it won't be written if it's equivalent to * <code>si</code>. * @param bi The assumed identifier as a byte string. If this feature * has a byte string identifier, it won't be written if it's * equivalent to <code>bi</code>. * @return The name of the runtime type of this feature. **/ public String lexWrite(ExceptionlessOutputStream out, Lexicon lex, String c, String p, String g, String si, ByteString bi) { String result = super.lexWrite(out, lex, c, p, g, si, bi); out.writeInt(lex.lookupChild(referent)); return result; } /** * Reads the representation of a feature with this object's run-time type * as stored by a lexicon, overwriting the data in this object. * * <p> This method is appropriate for reading features as written by * {@link #lexWrite(ExceptionlessOutputStream,Lexicon,String,String,String,String,ByteString)}. * * @param in The input stream. * @param lex The lexicon we are reading in to. * @param p The assumed package string. If no package name is given in * the input stream, the instantiated feature is given this * package. * @param g The assumed classifier name string. If no classifier name * is given in the input stream, the instantiated feature is * given this classifier name. * @param si The assumed identifier as a string. If the feature being * read has a string identifier field and no identifier is * given in the input stream, the feature is given this * identifier. * @param bi The assumed identifier as a byte string. If the feature * being read has a byte string identifier field and no * identifier is given in the input stream, the feature is * given this identifier. **/ public void lexRead(ExceptionlessInputStream in, Lexicon lex, String p, String g, String si, ByteString bi) { super.lexRead(in, lex, p, g, si, bi); referent = (DiscreteFeature) lex.lookupKey(in.readInt()); } }