protected void visitCell(final HashSetChartCell cell) {
    final int start = cell.start(), end = cell.end();
    Collection<Production> possibleProds;
    ChartEdge edge;
    final ChartEdge[] bestEdges = new ChartEdge[grammar.numNonTerms()]; // inits to null

    // final int maxEdgesToAdd = (int) opts.param2;
    final int maxEdgesToAdd = Integer.MAX_VALUE;

    for (int mid = start + 1; mid <= end - 1; mid++) { // mid point
      final HashSetChartCell leftCell = chart.getCell(start, mid);
      final HashSetChartCell rightCell = chart.getCell(mid, end);
      for (final int leftNT : leftCell.getLeftChildNTs()) {
        for (final int rightNT : rightCell.getRightChildNTs()) {
          possibleProds = grammar.getBinaryProductionsWithChildren(leftNT, rightNT);
          if (possibleProds != null) {
            for (final Production p : possibleProds) {
              edge = chart.new ChartEdge(p, leftCell, rightCell);
              addEdgeToArray(edge, bestEdges);
            }
          }
        }
      }
    }

    addBestEdgesToChart(cell, bestEdges, maxEdgesToAdd);
  }
 public void addUnaryExtensionsToLexProds() {
   for (int i = 0; i < chart.size(); i++) {
     final HashSetChartCell cell = chart.getCell(i, i + 1);
     for (final int pos : cell.getPosNTs()) {
       for (final Production unaryProd : grammar.getUnaryProductionsWithChild(pos)) {
         // cell.addEdge(unaryProd, cell, null, cell.getBestEdge(pos).inside + unaryProd.prob);
         cell.updateInside(unaryProd, cell.getInside(pos) + unaryProd.prob);
       }
     }
   }
 }
  protected void initParser(final ParseTask parseTask) {
    chart = new CellChart(parseTask, this);
    this.maxEdgeFOM = new float[chart.size()][chart.size() + 1];
    this.spanAgenda = new PriorityQueue<HashSetChartCell>();

    // The chart is (chart.size()+1)*chart.size()/2
    for (int start = 0; start < chart.size(); start++) {
      for (int end = start + 1; end < chart.size() + 1; end++) {
        maxEdgeFOM[start][end] = Float.NEGATIVE_INFINITY;
      }
    }
  }
  protected void expandFrontier(final HashSetChartCell cell) {

    // connect edge as possible right non-term
    for (int start = 0; start < cell.start(); start++) {
      setSpanMaxEdgeFOM(chart.getCell(start, cell.start()), cell);
    }

    // connect edge as possible left non-term
    for (int end = cell.end() + 1; end <= chart.size(); end++) {
      setSpanMaxEdgeFOM(cell, chart.getCell(cell.end(), end));
    }
  }
 protected void addLexicalProductions(final int sent[]) {
   // ChartEdge newEdge;
   HashSetChartCell cell;
   for (int i = 0; i < chart.size(); i++) {
     cell = chart.getCell(i, i + 1);
     for (final Production lexProd : grammar.getLexicalProductionsWithChild(sent[i])) {
       // newEdge = chart.new ChartEdge(lexProd, chart.getCell(i, i + 1));
       // chart.getCell(i, i + 1).addEdge(newEdge);
       cell.updateInside(lexProd, lexProd.prob);
     }
   }
 }
 protected HashSetChartCell next() {
   // return spanAgenda.poll();
   HashSetChartCell bestSpan = null;
   float bestScore = Float.NEGATIVE_INFINITY;
   for (int span = 1; span <= chart.size(); span++) {
     for (int beg = 0; beg < chart.size() - span + 1; beg++) { // beginning
       if (maxEdgeFOM[beg][beg + span] > bestScore) {
         bestScore = maxEdgeFOM[beg][beg + span];
         bestSpan = chart.getCell(beg, beg + span);
       }
     }
   }
   return bestSpan;
 }
  @Override
  public BinaryTree<String> findBestParse(final ParseTask parseTask) {
    HashSetChartCell cell;

    initParser(parseTask);
    addLexicalProductions(parseTask.tokens);
    figureOfMerit.initSentence(parseTask, chart);
    addUnaryExtensionsToLexProds();

    for (int i = 0; i < chart.size(); i++) {
      expandFrontier(chart.getCell(i, i + 1));
    }

    while (hasNext() && !chart.hasCompleteParse(grammar.startSymbol)) {
      cell = next();
      // System.out.println(" nextCell: " + cell);
      visitCell(cell);
      expandFrontier(cell);
    }

    return chart.extractBestParse(grammar.startSymbol);
  }
  protected void setSpanMaxEdgeFOM(
      final HashSetChartCell leftCell, final HashSetChartCell rightCell) {
    ChartEdge edge;
    final int start = leftCell.start(), end = rightCell.end();
    float bestFOM = maxEdgeFOM[start][end];

    // System.out.println(" setSpanMax: " + leftCell + " && " + rightCell);

    Collection<Production> possibleProds;
    for (final int leftNT : leftCell.getLeftChildNTs()) {
      for (final int rightNT : rightCell.getRightChildNTs()) {
        possibleProds = grammar.getBinaryProductionsWithChildren(leftNT, rightNT);
        if (possibleProds != null) {
          for (final Production p : possibleProds) {
            // final float prob = p.prob + leftCell.getInside(leftNT) +
            // rightCell.getInside(rightNT);
            edge = chart.new ChartEdge(p, leftCell, rightCell);
            // System.out.println(" considering: " + edge);
            if (edge.fom > bestFOM) {
              bestFOM = edge.fom;
            }
          }
        }
      }
    }

    if (bestFOM > maxEdgeFOM[start][end]) {
      final HashSetChartCell parentCell = chart.getCell(start, end);
      // if (maxEdgeFOM[start][end] > Float.NEGATIVE_INFINITY) {
      // spanAgenda.remove(parentCell);
      // }
      maxEdgeFOM[start][end] = bestFOM;
      parentCell.fom = bestFOM;
      // spanAgenda.add(parentCell);
      // System.out.println(" addingSpan: " + parentCell);
    }
  }
 @Override
 public float getInside(final int start, final int end, final int nt) {
   return chart.getInside(start, end, nt);
 }