/**
   * Tests an imagined example cartesian-product vector (based very loosely on the computation of
   * the top cell in the 'systems analyst arbitration chef' example)
   *
   * @throws Exception if something bad happens
   */
  @Test
  public void testCartesianProductVectorExample() throws Exception {

    // Create the parser
    final SparseMatrixGrammar g = (SparseMatrixGrammar) simpleGrammar1;
    final P p = createParser(g, parserOptions(), configProperties());
    final ParseTask parseTask =
        new ParseTask(
            "systems analyst arbitration chef",
            Parser.InputFormat.Text,
            g,
            DecodeMethod.ViterbiMax);
    p.initSentence(parseTask);
    final Chart chart = p.chart;

    final int nn = g.mapNonterminal("NN");
    final int np = g.mapNonterminal("NP");
    // Cell 0,1 contains NN (-2)
    // Cell 1,4 contains NN (-3), NP (-4)
    // So: 0,1 X 1,4 cross-product = NN/NN (-5,1), NN/NP (-6,1)
    final ChartCell cell_0_1 = chart.getCell(0, 1);
    cell_0_1.updateInside(new Production("NN", "NN", -2, false, g), cell_0_1, null, -2f);
    cell_0_1.finalizeCell();

    final ChartCell cell_1_3 = chart.getCell(1, 3);
    final ChartCell cell_1_4 = chart.getCell(1, 4);
    cell_1_4.updateInside(new Production("NN", "NN", -3f, false, g), cell_1_3, null, -3f);
    cell_1_4.updateInside(new Production("NP", "NP", -4f, false, g), cell_1_3, null, -4f);
    cell_1_4.finalizeCell();

    // Cell 0,2 contains NN (-2), NP (-3)
    // Cell 2,4 contains NN (-4), NP (-4)
    // So: 0,2 X 2,4 cross-product = NN/NN (-6,2), NN/NP (-6,2), NP/NN (-7,2), NP/NP (-7,2)
    final ChartCell cell_0_2 = chart.getCell(0, 2);
    cell_0_2.updateInside(
        new Production("NN", "NN", -2f, false, g), chart.getCell(0, 1), null, -2f);
    cell_0_2.updateInside(
        new Production("NP", "NP", -3f, false, g), chart.getCell(0, 1), null, -3f);
    cell_0_2.finalizeCell();

    final ChartCell cell_2_4 = chart.getCell(2, 4);
    cell_2_4.updateInside(
        new Production("NN", "NN", -4f, false, g), chart.getCell(2, 3), null, -4f);
    cell_2_4.updateInside(
        new Production("NP", "NP", -4f, false, g), chart.getCell(2, 3), null, -4f);
    cell_2_4.finalizeCell();

    // Cell 0,3 contains NP (-2)
    // Cell 3,4 contains NP (-2)
    // So: 0,3 X 3,4 cross-product = NP/NP (-4,3)
    final ChartCell cell_0_3 = chart.getCell(0, 3);
    cell_0_3.updateInside(new Production("NP", "NP", -2, false, g), chart.getCell(0, 2), null, -2f);
    cell_0_3.finalizeCell();

    final ChartCell cell_3_4 = chart.getCell(3, 4);
    cell_3_4.updateInside(
        new Production("NP", "NP", -2f, false, g), chart.getCell(3, 4), null, -2f);
    cell_3_4.finalizeCell();

    // So: 0,1 X 1,4 cross-product = NN/NN (-5,1), NN/NP (-6,1)
    // So: 0,2 X 2,4 cross-product = NN/NN (-6,2), NN/NP (-6,2), NP/NN (-7,2), NP/NP (-7,2)
    // So: 0,3 X 3,4 cross-product = NP/NP (-4,3)

    // Cross-product union should be NN/NN (-5,1), NN/NP (-6,1), NP/NN (-7,2), NP/NP (-4,3)
    final SparseMatrixVectorParser.CartesianProductVector crossProductVector =
        p.cartesianProductUnion(0, 4);
    final int[] expectedChildren =
        new int[] {pack(g, nn, nn), pack(g, nn, np), pack(g, np, nn), pack(g, np, np)};
    final float[] expectedProbabilities = new float[] {-5f, -6f, -7f, -4f};
    final int[] expectedMidpoints = new int[] {1, 1, 2, 3};

    for (int i = 0; i < expectedChildren.length; i++) {
      assertEquals(
          "Wrong probability #" + i,
          expectedProbabilities[i],
          crossProductVector.probability(expectedChildren[i]),
          .01f);
      assertEquals(
          "Wrong midpoint #" + i,
          expectedMidpoints[i],
          crossProductVector.midpoint(expectedChildren[i]));
    }
  }