/* This file is part of the Joshua Machine Translation System.
*
* Joshua is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
package joshua.decoder.hypergraph;
import joshua.decoder.chart_parser.Prunable;
import joshua.decoder.ff.state_maintenance.DPState;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
/**
* this class implement Hypergraph node (i.e., HGNode); also known
* as Item in parsing.
*
* @author Zhifei Li, <zhifei.work@gmail.com>
* @version $LastChangedDate: 2010-02-08 13:03:13 -0600 (Mon, 08 Feb 2010) $
*/
//@todo: handle the case that the Hypergraph only maintains the one-best tree
public class HGNode implements Prunable<HGNode> {
public int i, j;
// this is the symbol like: NP, VP, and so on
public int lhs;
// each hyperedge is an "and" node
public List<HyperEdge> hyperedges = null;
// used in pruning, compute_item, and transit_to_goal
public HyperEdge bestHyperedge = null;
// the key is the state id; remember the state required by each model, for example, edge-ngrams for LM model
HashMap<Integer,DPState> dpStates;
//============== auxiluary variables, no need to store on disk
// signature of this item: lhs, states
private String signature = null;
// seperator for the signature for each state
private static final String STATE_SIG_SEP = " -f- ";
//============== for pruning purpose
public boolean isDead = false;
private double estTotalLogP = 0.0; //it includes the estimated LogP
//===============================================================
// Constructors
//===============================================================
public HGNode(int i, int j, int lhs, HashMap<Integer,DPState> dpStates, HyperEdge initHyperedge, double estTotalLogP) {
this.i = i;
this.j = j;
this.lhs = lhs;
this.dpStates = dpStates;
this.estTotalLogP = estTotalLogP;
addHyperedgeInNode(initHyperedge);
}
//used by disk hg
public HGNode(int i, int j, int lhs, List<HyperEdge> hyperedges, HyperEdge bestHyperedge, HashMap<Integer,DPState> states) {
this.i = i;
this.j = j;
this.lhs = lhs;
this.hyperedges = hyperedges;
this.bestHyperedge = bestHyperedge;
this.dpStates = states;
}
//===============================================================
// Methods
//===============================================================
public void addHyperedgeInNode(HyperEdge dt) {
if(dt!=null){
if (null == hyperedges) {
hyperedges = new ArrayList<HyperEdge>();
}
hyperedges.add(dt);
semiringPlus(dt);
}
}
public void semiringPlus(HyperEdge dt){
if (null == bestHyperedge || bestHyperedge.bestDerivationLogP < dt.bestDerivationLogP){//semiring + operation
bestHyperedge = dt; //no change when tied
}
}
public void addHyperedgesInNode(List<HyperEdge> hyperedges) {
for(HyperEdge hyperEdge : hyperedges)
addHyperedgeInNode(hyperEdge);
}
public HashMap<Integer,DPState> getDPStates() {
return dpStates;
}
public DPState getDPState(int stateID) {
if (null == this.dpStates) {
return null;
} else {
return this.dpStates.get(stateID);
}
}
public void printInfo(Level level) {
if (HyperGraph.logger.isLoggable(level))
HyperGraph.logger.log(level,
String.format("lhs: %s; logP: %.3f",
lhs, bestHyperedge.bestDerivationLogP));
}
//signature of this item: lhs, states (we do not need i, j)
public String getSignature() {
if (null == this.signature) {
StringBuffer s = new StringBuffer();
s.append(lhs);
s.append(" ");
if (null != this.dpStates && this.dpStates.size() > 0) {
Iterator<Map.Entry<Integer,DPState>> it = this.dpStates.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Integer,DPState> entry = it.next();
s.append(entry.getValue().getSignature(false));
if (it.hasNext())
s.append(STATE_SIG_SEP);
}
}
this.signature = s.toString();
}
return this.signature;
}
public void releaseDPStatesMemory(){
dpStates = null;
}
public double getEstTotalLogP(){
return this.estTotalLogP;
}
/*this will called by the sorting
* in Cell.ensureSorted()*/
//sort by estTotalLogP: for pruning purpose
public int compareTo(HGNode anotherItem) {
System.out.println("HGNode, compare functiuon should never be called");
System.exit(1);
return 0;
/*
if (this.estTotalLogP > anotherItem.estTotalLogP) {
return -1;
} else if (this.estTotalLogP == anotherItem.estTotalLogP) {
return 0;
} else {
return 1;
}*/
}
public static Comparator<HGNode> inverseLogPComparator = new Comparator<HGNode>() {
public int compare(HGNode item1, HGNode item2) {
double logp1 = item1.estTotalLogP;
double logp2 = item2.estTotalLogP;
if (logp1 > logp2) {
return -1;
} else if (logp1 == logp2) {
return 0;
} else {
return 1;
}
}
};
/**natural order
* */
public static Comparator<HGNode> logPComparator = new Comparator<HGNode>() {
public int compare(HGNode item1, HGNode item2) {
double logp1 = item1.estTotalLogP;
double logp2 = item2.estTotalLogP;
if (logp1 > logp2) {
return 1;
} else if (logp1 == logp2) {
return 0;
} else {
return -1;
}
}
};
public boolean isDead() {
return this.isDead;
}
public double getPruneLogP() {
return this.estTotalLogP;
}
public void setDead() {
this.isDead = true;
}
public void setPruneLogP(double estTotalLogP) {
this.estTotalLogP = estTotalLogP;
}
}