class LPReduction<D, R> { Closure vars Closure objFunc Closure constraints Closure result // default is maximisation problem boolean max = true // default is to allow negative solution values boolean nonNegative = false LPSolver solver // caches the variables to avoid calling 'vars' closure more than once, // in case 'constraints' closure needs this info. def variables /** * Maps an instance x of P into an LP instance y * * @param x the domain object * @return the reduced LP instance y */ LPInstance mapToLP(D x) { variables = vars(x) new LPInstance(variables, objFunc ? objFunc(x) : new LPFunction([:], 0), constraints(x), max, nonNegative) } /** * Solves the specified LP instance. * If no solver is set, it uses ApacheSimplexSolver by default. * * @param lpi the LP instance to solve * @return the solution of the LP instance */ private Solution solve(LPInstance lpi) { if (!solver) { solver = new ApacheSimplexSolver() } solver.solve(lpi) } /** * Computes P(x) by reducing P to LP * * @param x the domain object * @return P(x) */ R reduce(D x) { LPInstance y = mapToLP(x) Solution solution = solve(y) result(solution) } }