content: package dk.alexandra.fresco.lib.lp;
  
  import dk.alexandra.fresco.framework.DRes;
  import dk.alexandra.fresco.framework.builder.Computation;
  import dk.alexandra.fresco.lib.common.math.AdvancedNumeric;
  import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric;
  import dk.alexandra.fresco.framework.value.SInt;
  import dk.alexandra.fresco.lib.common.collections.Matrix;
  import java.util.ArrayList;
  
  /**
   * Extracts the optimal value from a {@link LPTableau} and an update matrix representing a
   * terminated Simplex method. Returns the corresponding values of <code>score=p/q</code>
   */
  public class OptimalValue implements
      Computation<OptimalValue.Result, ProtocolBuilderNumeric> {
  
    private final Matrix<DRes<SInt>> updateMatrix;
    private final DRes<SInt> pivot;
    private final LPTableau tableau;
  
    /**
     * An general version of the protocol working any (valid) initial tableau.
     *
     * @param updateMatrix the final update matrix
     * @param tableau      the initial tableau
     * @param pivot        the final pivot
     */
    public OptimalValue(
        Matrix<DRes<SInt>> updateMatrix,
        LPTableau tableau,
        DRes<SInt> pivot) {
      this.updateMatrix = updateMatrix;
      this.tableau = tableau;
      this.pivot = pivot;
    }
  
    @Override
    public DRes<Result> buildComputation(ProtocolBuilderNumeric builder) {
      ArrayList<DRes<SInt>> row = updateMatrix.getRow(updateMatrix.getHeight() - 1);
      ArrayList<DRes<SInt>> column = new ArrayList<>(row.size());
      column.addAll(tableau.getB());
      column.add(tableau.getZ());
      AdvancedNumeric advanced = AdvancedNumeric.using(builder);
      DRes<SInt> numerator = advanced.innerProduct(row, column);
      DRes<SInt> invDenominator = advanced.invert(pivot);
      DRes<SInt> mult = builder.numeric().mult(numerator, invDenominator);
      return () -> new Result(mult.out(), numerator.out(), pivot.out());
    }
  
    public static class Result {
  
      public final SInt optimal;
      public final SInt numerator;
      public final SInt denominator;
  
      public Result(SInt optimal, SInt numerator, SInt denominator) {
        this.optimal = optimal;
        this.numerator = numerator;
        this.denominator = denominator;
      }
    }
  }
  