code: package edu.berkeley.nlp.PCFGLA;
  
  import java.util.Random;
  
  import edu.berkeley.nlp.util.ArrayUtil;
  import edu.berkeley.nlp.util.Numberer;
  import edu.berkeley.nlp.util.StringUtils;
  
  /**
   * Unary Rules (with ints for parent and child)
   * 
   * @author Dan Klein
   */
  public class UnaryRule extends Rule implements java.io.Serializable, Comparable {
  
  	public short childState = -1;
  	/**
  	 * NEW: scores[childSubState][parentSubState]
  	 */
  	public double[][] scores;
  
  	/*
  	 * public UnaryRule(String s, Numberer n) { String[] fields =
  	 * StringUtils.splitOnCharWithQuoting(s, ' ', '\"', '\\'); //
  	 * System.out.println("fields:\n" + fields[0] + "\n" + fields[2] + "\n" +
  	 * fields[3]); this.parent = n.number(fields[0]); this.child =
  	 * n.number(fields[2]); this.score = Double.parseDouble(fields[3]); }
  	 */
  	public UnaryRule(short pState, short cState, double[][] scores) {
  		this.parentState = pState;
  		this.childState = cState;
  		this.scores = scores;
  	}
  
  	public UnaryRule(short pState, short cState) {
  		this.parentState = pState;
  		this.childState = cState;
  		// this.scores = new double[1][1];
  	}
  
  	/** Copy constructor */
  	public UnaryRule(UnaryRule u) {
  		this(u.parentState, u.childState, ArrayUtil.copy(u.scores));
  	}
  
  	public UnaryRule(UnaryRule u, double[][] newScores) {
  		this(u.parentState, u.childState, newScores);
  	}
  
  	public UnaryRule(short pState, short cState, short pSubStates,
  			short cSubStates) {
  		this.parentState = pState;
  		this.childState = cState;
  		this.scores = new double[cSubStates][pSubStates];
  	}
  
  	@Override
  	public boolean isUnary() {
  		return true;
  	}
  
  	@Override
  	public int hashCode() {
  		return (parentState << 18) ^ (childState);
  	}
  
  	@Override
  	public boolean equals(Object o) {
  		if (this == o) {
  			return true;
  		}
  		if (o instanceof UnaryRule) {
  			UnaryRule ur = (UnaryRule) o;
  			if (parentState == ur.parentState && childState == ur.childState) {
  				return true;
  			}
  		}
  		return false;
  	}
  
  	public int compareTo(Object o) {
  		UnaryRule ur = (UnaryRule) o;
  		if (parentState < ur.parentState) {
  			return -1;
  		}
  		if (parentState > ur.parentState) {
  			return 1;
  		}
  		if (childState < ur.childState) {
  			return -1;
  		}
  		if (childState > ur.childState) {
  			return 1;
  		}
  		return 0;
  	}
  
  	private static final char[] charsToEscape = new char[] { '\"' };
  
  	@Override
  	public String toString() {
  		Numberer n = Numberer.getGlobalNumberer("tags");
  		String cState = (String) n.object(childState);
  		if (cState.endsWith("^g"))
  			cState = cState.substring(0, cState.length() - 2);
  		String pState = (String) n.object(parentState);
  		if (pState.endsWith("^g"))
  			pState = pState.substring(0, pState.length() - 2);
  		if (scores == null)
  			return pState + " -> " + cState + "\n";
  		StringBuilder sb = new StringBuilder();
  		for (int cS = 0; cS < scores.length; cS++) {
  			if (scores[cS] == null)
  				continue;
  			for (int pS = 0; pS < scores[cS].length; pS++) {
  				double p = scores[cS][pS];
  				if (p > 0)
  					sb.append(pState + "_" + pS + " -> " + cState + "_" + cS
  							+ " " + p + "\n");
  			}
  		}
  		return sb.toString();
  	}
  
  	public String toString_old() {
  		Numberer n = Numberer.getGlobalNumberer("tags");
  		return "\""
  				+ StringUtils.escapeString(n.object(parentState).toString(),
  						charsToEscape, '\\')
  				+ "\" -> \""
  				+ StringUtils.escapeString(n.object(childState).toString(),
  						charsToEscape, '\\') + "\" "
  				+ ArrayUtil.toString(scores);
  	}
  
  	public short getChildState() {
  		return childState;
  	}
  
  	public void setScore(int pS, int cS, double score) {
  		// sets the score for a particular combination of substates
  		scores[cS][pS] = score;
  	}
  
  	public double getScore(int pS, int cS) {
  		// gets the score for a particular combination of substates
  		if (scores[cS] == null) {
  			if (logarithmMode)
  				return Double.NEGATIVE_INFINITY;
  			return 0;
  		}
  		return scores[cS][pS];
  	}
  
  	public void setScores2(double[][] scores) {
  		this.scores = scores;
  	}
  
  	/**
  	 * scores[parentSubState][childSubState]
  	 */
  	public double[][] getScores2() {
  		return scores;
  	}
  
  	public void setNodes(short pState, short cState) {
  		this.parentState = pState;
  		this.childState = cState;
  	}
  
  	private static final long serialVersionUID = 2L;
  
  	/**
  	 * @return
  	 */
  	public UnaryRule splitRule(short[] numSubStates, short[] newNumSubStates,
  			Random random, double randomness, boolean doNotNormalize, int mode) {
  		// when splitting on parent, never split on ROOT parent
  		short parentSplitFactor = this.getParentState() == 0 ? (short) 1
  				: (short) 2;
  		if (newNumSubStates[this.parentState] == numSubStates[this.parentState]) {
  			parentSplitFactor = 1;
  		}
  		int childSplitFactor = 2;
  		if (newNumSubStates[this.childState] == numSubStates[this.childState]) {
  			childSplitFactor = 1;
  		}
  		double[][] oldScores = this.getScores2();
  		double[][] newScores = new double[newNumSubStates[this.childState]][];
  
  		// for all current substates
  		for (short cS = 0; cS < oldScores.length; cS++) {
  			if (oldScores[cS] == null)
  				continue;
  
  			for (short c = 0; c < childSplitFactor; c++) {
  				short newCS = (short) (childSplitFactor * cS + c);
  				newScores[newCS] = new double[newNumSubStates[this.parentState]];
  			}
  
  			for (short pS = 0; pS < oldScores[cS].length; pS++) {
  				double score = oldScores[cS][pS];
  				// split on parent
  				for (short p = 0; p < parentSplitFactor; p++) {
  					double divFactor = (doNotNormalize) ? 1.0
  							: childSplitFactor;
  					double randomComponent = score / divFactor * randomness
  							/ 100 * (random.nextDouble() - 0.5);
  					// split on child
  					for (short c = 0; c < childSplitFactor; c++) {
  						if (c == 1) {
  							randomComponent *= -1;
  						}
  						if (childSplitFactor == 1) {
  							randomComponent = 0;
  						}
  						// divide score by divFactor because we're splitting
  						// each rule in 1/divFactor
  						short newPS = (short) (parentSplitFactor * pS + p);
  						short newCS = (short) (childSplitFactor * cS + c);
  						double splitFactor = (doNotNormalize) ? 1.0
  								: childSplitFactor;
  						newScores[newCS][newPS] = (score / splitFactor + randomComponent);
  						// sparsifier.splitUnaryWeight(
  						// oldRule.getParentState(), cS,
  						// oldRule.getChildState(), pS,
  						// newPS, newCS, childSplitFactor, randomComponent,
  						// score, tagNumberer);
  						if (mode == 2)
  							newScores[newCS][newPS] = 1.0 + random.nextDouble() / 100.0;
  					}
  				}
  			}
  		}
  		return new UnaryRule(this, newScores);
  	}
  
  }
  