org.ojalgo.optimisation.linear.LinearSolver Maven / Gradle / Ivy
Show all versions of ojalgo Show documentation
/*
* Copyright 1997-2024 Optimatika
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.ojalgo.optimisation.linear;
import static org.ojalgo.function.constant.PrimitiveMath.*;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import org.ojalgo.ProgrammingError;
import org.ojalgo.array.ArrayR064;
import org.ojalgo.array.SparseArray;
import org.ojalgo.array.SparseArray.NonzeroView;
import org.ojalgo.function.multiary.LinearFunction;
import org.ojalgo.matrix.store.MatrixStore;
import org.ojalgo.matrix.store.PhysicalStore;
import org.ojalgo.optimisation.ExpressionsBasedModel;
import org.ojalgo.optimisation.GenericSolver;
import org.ojalgo.optimisation.Optimisation;
import org.ojalgo.optimisation.UpdatableSolver;
import org.ojalgo.optimisation.Variable;
import org.ojalgo.optimisation.convex.ConvexData;
import org.ojalgo.optimisation.convex.ConvexSolver;
import org.ojalgo.structure.Access1D;
import org.ojalgo.structure.Access2D;
import org.ojalgo.structure.Mutate1D;
import org.ojalgo.structure.Mutate2D;
import org.ojalgo.structure.Structure1D.IntIndex;
import org.ojalgo.type.IndexSelector;
public abstract class LinearSolver extends GenericSolver implements UpdatableSolver {
public static final class Configuration {
}
/**
*
* Compared to {@link LinearSolver.StandardBuilder} this builder:
* 1) Accepts inequality constraints
* 2) Has relaxed the requiremnt on the RHS to be non-negative (both equalities and inequalities)
*
* Compared to {@link ConvexSolver.Builder} this builder:
* 1) Requires the objective function to be linear (or only the linear factors will be concidered)
* 2) Assumes (requires) variables to be non-negative
*
*
* @author apete
*/
public static final class GeneralBuilder extends LinearSolver.Builder {
GeneralBuilder() {
super();
}
@Override
public LinearSolver.GeneralBuilder inequalities(final Access2D> mtrxAI, final Access1D> mtrxBI) {
return super.inequalities(mtrxAI, mtrxBI);
}
@Override
public LinearSolver.GeneralBuilder inequality(final double rhs, final double... factors) {
return super.inequality(rhs, factors);
}
/**
* Convert inequalities to equalities (adding slack variables) and make sure all RHS are non-negative.
*/
public StandardBuilder toStandardForm() {
int nbInequalites = this.countInequalityConstraints();
int nbEqualites = this.countEqualityConstraints();
int nbVariables = this.countVariables();
StandardBuilder retVal = LinearSolver.newStandardBuilder();
PhysicalStore mtrxC = null;
PhysicalStore mtrxAE = null;
PhysicalStore mtrxBE = null;
if (nbEqualites > 0) {
if (nbInequalites > 0) {
mtrxC = this.getC().below(nbInequalites).collect(this.getFactory());
mtrxAE = this.getAE().below(this.getAI()).right(nbInequalites).collect(this.getFactory());
mtrxAE.fillDiagonal(nbEqualites, nbVariables, ONE);
mtrxBE = this.getBE().below(this.getBI()).collect(this.getFactory());
} else {
mtrxC = this.getC().collect(this.getFactory());
mtrxAE = this.getAE().collect(this.getFactory());
mtrxBE = this.getBE().collect(this.getFactory());
}
} else if (nbInequalites > 0) {
mtrxC = this.getC().below(nbInequalites).collect(this.getFactory());
mtrxAE = this.getAI().right(nbInequalites).collect(this.getFactory());
mtrxAE.fillDiagonal(nbEqualites, nbVariables, ONE);
mtrxBE = this.getBI().collect(this.getFactory());
} else {
throw new IllegalStateException("The problem is unconstrained!");
}
for (int i = 0; i < mtrxBE.getRowDim(); i++) {
double rhs = mtrxBE.doubleValue(i, 0);
if (rhs < ZERO) {
mtrxAE.modifyRow(i, NEGATE);
mtrxBE.set(i, 0, -rhs);
}
}
retVal.objective(mtrxC);
retVal.equalities(mtrxAE, mtrxBE);
return retVal;
}
}
public static final class ModelIntegration extends ExpressionsBasedModel.Integration {
@Override
public LinearSolver build(final ExpressionsBasedModel model) {
boolean experimental = model.options.experimental;
this.setSwitch(model, experimental);
if (experimental) {
return NEW_INTEGRATION.build(model);
} else {
return OLD_INTEGRATION.build(model);
}
}
@Override
public boolean isCapable(final ExpressionsBasedModel model) {
return OLD_INTEGRATION.isCapable(model) || NEW_INTEGRATION.isCapable(model);
}
@Override
public Result toModelState(final Result solverState, final ExpressionsBasedModel model) {
if (this.isSwitch(model)) {
return NEW_INTEGRATION.toModelState(solverState, model);
} else {
return OLD_INTEGRATION.toModelState(solverState, model);
}
}
@Override
public Result toSolverState(final Result modelState, final ExpressionsBasedModel model) {
if (this.isSwitch(model)) {
return NEW_INTEGRATION.toSolverState(modelState, model);
} else {
return OLD_INTEGRATION.toSolverState(modelState, model);
}
}
@Override
protected int getIndexInSolver(final ExpressionsBasedModel model, final Variable variable) {
if (this.isSwitch(model)) {
return NEW_INTEGRATION.getIndexInSolver(model, variable);
} else {
return OLD_INTEGRATION.getIndexInSolver(model, variable);
}
}
}
/**
*
* Defines optimisation problems on the LP standard form:
*
* min [C]T[X]
* when [AE][X] == [BE]
* and 0 <= [X]
* and 0 <= [BE]
*
* A Linear Program is in Standard Form if:
*
* - All constraints are equality constraints.
*
- All variables have a nonnegativity sign restriction.
*
*
* Further it is required that the constraint right hand sides are nonnegative (nonnegative elements in
* [BE]). Don't think that's an actual LP standard form requirement, but it is commonly required, and also
* here.
*
* The LP standard form does not dictate if expressed on minimisation or maximisation form. Here it should
* be a minimisation.
*
*
* @author apete
*/
public static final class StandardBuilder extends LinearSolver.Builder {
/**
* @deprecated v50 Use {@link LinearSolver#newBuilder()} instead.
*/
@Deprecated
public StandardBuilder() {
super();
}
/**
* @deprecated v50 Use {@link LinearSolver#newBuilder()} instead.
*/
@Deprecated
public StandardBuilder(final MatrixStore mtrxC) {
super();
this.objective(mtrxC);
}
}
static abstract class Builder> extends GenericSolver.Builder {
Builder() {
super();
}
@Override
public B equalities(final Access2D> mtrxAE, final Access1D> mtrxBE) {
return super.equalities(mtrxAE, mtrxBE);
}
@Override
public B equality(final double rhs, final double... factors) {
return super.equality(rhs, factors);
}
@Override
public final LinearFunction getObjective() {
LinearFunction retVal = this.getObjective(LinearFunction.class);
if (retVal == null) {
retVal = LinearFunction.factory(this.getFactory()).make(this.countVariables());
super.setObjective(retVal);
}
return retVal;
}
public final B lower(final double... bounds) {
double[] lowerBounds = this.getLowerBounds(ZERO).data;
for (int i = 0, limit = Math.min(lowerBounds.length, bounds.length); i < limit; i++) {
lowerBounds[i] = bounds[i];
}
return (B) this;
}
public final B lower(final double bound) {
double[] lowerBounds = this.getLowerBounds(ZERO).data;
Arrays.fill(lowerBounds, bound);
return (B) this;
}
public final B objective(final double... factors) {
this.setNumberOfVariables(factors.length);
this.getObjective().linear().fillMatching(this.getFactory().column(factors));
return (B) this;
}
public final B objective(final int index, final double value) {
this.getObjective().linear().set(index, value);
return (B) this;
}
public final B objective(final MatrixStore mtrxC) {
this.setObjective(LinearSolver.toObjectiveFunction(mtrxC));
return (B) this;
}
public final B upper(final double... bounds) {
double[] upperBounds = this.getUpperBounds(POSITIVE_INFINITY).data;
for (int i = 0, limit = Math.min(upperBounds.length, bounds.length); i < limit; i++) {
upperBounds[i] = bounds[i];
}
return (B) this;
}
public final B upper(final double bound) {
double[] upperBounds = this.getUpperBounds(POSITIVE_INFINITY).data;
Arrays.fill(upperBounds, bound);
return (B) this;
}
@Override
protected LinearSolver doBuild(final Options options) {
int nbInequalites = this.countInequalityConstraints();
int nbEqualites = this.countEqualityConstraints();
int nbVariables = this.countVariables();
IndexSelector ineqSign = new IndexSelector(nbInequalites);
if (nbInequalites > 0) {
MatrixStore mtrxBI = this.getBI();
for (int i = 0; i < nbInequalites; i++) {
double valRHS = mtrxBI.doubleValue(i);
if (valRHS < ZERO) {
ineqSign.exclude(i);
} else {
ineqSign.include(i);
}
}
}
int nbIdentitySlackVariables = ineqSign.countIncluded();
int nbSlackVariables = ineqSign.countExcluded();
LinearStructure structure = new LinearStructure(false, nbInequalites, nbEqualites, nbVariables, 0, nbSlackVariables, nbIdentitySlackVariables);
SimplexTableau tableau = SimplexTableau.make(structure, options);
Primitive2D constraintsBody = tableau.constraintsBody();
Primitive1D constraintsRHS = tableau.constraintsRHS();
Primitive1D objective = tableau.objective();
if (nbInequalites > 0) {
int insIdSlack = 0;
int insGnSlack = 0;
for (int i = 0; i < nbInequalites; i++) {
SparseArray body = this.getAI(i);
double valRHS = this.getBI(i);
boolean positive = ineqSign.isIncluded(i);
int row = positive ? insIdSlack : nbIdentitySlackVariables + insGnSlack;
int col = positive ? nbVariables + nbSlackVariables + insIdSlack++ : nbVariables + insGnSlack++;
for (NonzeroView nz : body.nonzeros()) {
constraintsBody.set(row, nz.index(), positive ? nz.doubleValue() : -nz.doubleValue());
}
constraintsBody.set(row, col, positive ? ONE : NEG);
constraintsRHS.set(row, positive ? valRHS : -valRHS);
structure.negated(row, !positive);
}
}
if (nbEqualites > 0) {
MatrixStore mtrxAE = this.getAE();
MatrixStore mtrxBE = this.getBE();
for (int i = 0; i < nbEqualites; i++) {
double valRHS = mtrxBE.doubleValue(i);
boolean positive = valRHS >= ZERO;
int row = nbInequalites + i;
for (int j = 0; j < nbVariables; j++) {
double value = mtrxAE.doubleValue(i, j);
if (Math.abs(value) > MACHINE_EPSILON) {
constraintsBody.set(row, j, positive ? value : -value);
}
}
constraintsRHS.set(row, positive ? valRHS : -valRHS);
structure.negated(row, !positive);
}
}
MatrixStore mtrxC = this.getC();
for (int i = 0; i < nbVariables; i++) {
objective.set(i, mtrxC.doubleValue(i));
}
return new SimplexTableauSolver(tableau, options);
}
protected final double[] getLowerBounds() {
return super.getLowerBounds(ZERO).data;
}
protected final double[] getUpperBounds() {
return super.getUpperBounds(POSITIVE_INFINITY).data;
}
S newSimplexStore(final Function storeFactory, final int... basis) {
MatrixStore builderC = this.getObjective().getLinearFactors(false);
MatrixStore builderAE = this.getAE();
MatrixStore builderBE = this.getBE();
MatrixStore builderAI = this.getAI();
MatrixStore builderBI = this.getBI();
double[] builderLB = this.getLowerBounds();
double[] builderUB = this.getUpperBounds();
int nbUpConstr = builderAI.getRowDim();
int nbLoConstr = 0;
int nbEqConstr = builderAE.getRowDim();
int nbProbVars = builderC.size();
int nbSlckVars = nbUpConstr + nbLoConstr;
int nbArtiVars = basis.length == nbUpConstr + nbLoConstr + nbEqConstr ? 0 : nbEqConstr;
LinearStructure structure = new LinearStructure(false, nbUpConstr + nbLoConstr, nbEqConstr, nbProbVars, 0, 0, nbSlckVars);
S simplex = storeFactory.apply(structure);
double[] lowerBounds = simplex.getLowerBounds();
double[] upperBounds = simplex.getUpperBounds();
Mutate2D mtrxA = simplex.constraintsBody();
Mutate1D mtrxB = simplex.constraintsRHS();
Mutate1D mtrxC = simplex.objective();
for (int i = 0; i < nbUpConstr; i++) {
for (int j = 0; j < nbProbVars; j++) {
double factor = builderAI.doubleValue(i, j);
mtrxA.set(i, j, factor);
}
mtrxA.set(i, nbProbVars + i, ONE);
mtrxB.set(i, builderBI.doubleValue(i));
lowerBounds[nbProbVars + i] = ZERO;
upperBounds[nbProbVars + i] = POSITIVE_INFINITY;
}
for (int i = 0; i < nbEqConstr; i++) {
for (int j = 0; j < nbProbVars; j++) {
double factor = builderAE.doubleValue(i, j);
mtrxA.set(nbUpConstr + nbLoConstr + i, j, factor);
}
mtrxB.set(nbUpConstr + nbLoConstr + i, builderBE.doubleValue(i));
}
for (int j = 0; j < nbProbVars; j++) {
lowerBounds[j] = builderLB[j];
upperBounds[j] = builderUB[j];
double weight = builderC.doubleValue(j);
mtrxC.set(j, weight);
}
for (int j = 0; j < nbArtiVars; j++) {
mtrxA.set(nbUpConstr + nbLoConstr + j, nbProbVars + nbSlckVars + j, ONE);
lowerBounds[nbProbVars + nbSlckVars + j] = ZERO;
upperBounds[nbProbVars + nbSlckVars + j] = ZERO;
}
return simplex;
}
T newSimplexTableau(final Function tableauFactory) {
int nbVars = this.countVariables();
int nbEqus = this.countEqualityConstraints();
int nbInes = this.countInequalityConstraints();
IndexSelector ineqSign = new IndexSelector(nbInes);
if (nbInes > 0) {
MatrixStore mtrxBI = this.getBI();
for (int i = 0; i < nbInes; i++) {
double valRHS = mtrxBI.doubleValue(i);
if (valRHS < ZERO) {
ineqSign.exclude(i);
} else {
ineqSign.include(i);
}
}
}
int nbIdentSlackVars = ineqSign.countIncluded();
int nbOtherSlackVars = ineqSign.countExcluded();
LinearStructure structure = new LinearStructure(false, nbInes, nbEqus, nbVars, 0, nbOtherSlackVars, nbIdentSlackVars);
T tableau = tableauFactory.apply(structure);
Primitive2D constraintsBody = tableau.constraintsBody();
Primitive1D constraintsRHS = tableau.constraintsRHS();
Primitive1D objective = tableau.objective();
if (nbInes > 0) {
int insIdSlack = 0;
int insGnSlack = 0;
for (int i = 0; i < nbInes; i++) {
SparseArray body = this.getAI(i);
double valRHS = this.getBI(i);
boolean positive = ineqSign.isIncluded(i);
int row = positive ? insIdSlack : nbIdentSlackVars + insGnSlack;
int col = positive ? nbVars + nbOtherSlackVars + insIdSlack++ : nbVars + insGnSlack++;
for (NonzeroView nz : body.nonzeros()) {
constraintsBody.set(row, nz.index(), positive ? nz.doubleValue() : -nz.doubleValue());
}
constraintsBody.set(row, col, positive ? ONE : NEG);
constraintsRHS.set(row, positive ? valRHS : -valRHS);
}
}
if (nbEqus > 0) {
MatrixStore mtrxAE = this.getAE();
MatrixStore mtrxBE = this.getBE();
for (int i = 0; i < nbEqus; i++) {
double valRHS = mtrxBE.doubleValue(i);
boolean positive = valRHS >= ZERO;
int row = nbInes + i;
for (int j = 0; j < nbVars; j++) {
double value = mtrxAE.doubleValue(i, j);
if (Math.abs(value) > MACHINE_EPSILON) {
constraintsBody.set(row, j, positive ? value : -value);
}
}
constraintsRHS.set(row, positive ? valRHS : -valRHS);
}
}
MatrixStore mtrxC = this.getC();
for (int i = 0; i < nbVars; i++) {
objective.set(i, mtrxC.doubleValue(i));
}
return tableau;
}
}
/**
* An integration to a new/alternative/experimental LP-solver. That solver is intended to replace the
* current solver, but is not yet ready to do that. You're welcome to try it - just add this integration
* by calling {@link ExpressionsBasedModel#addIntegration(ExpressionsBasedModel.Integration)}.
*/
static final class NewIntegration extends ExpressionsBasedModel.Integration {
@Override
public SimplexSolver build(final ExpressionsBasedModel model) {
PhasedSimplexSolver solver = SimplexStore.build(model, structure -> {
if (Boolean.TRUE.equals(model.options.sparse)) {
return new RevisedStore(structure);
} else if (Boolean.FALSE.equals(model.options.sparse)) {
return new TableauStore(structure);
} else {
return SimplexStore.newInstance(structure);
}
}).newPhasedSimplexSolver(model.options);
if (model.options.validate) {
solver.setValidator(this.newValidator(model));
}
return solver;
}
@Override
public boolean isCapable(final ExpressionsBasedModel model) {
return !model.isAnyVariableInteger() && !model.isAnyExpressionQuadratic();
}
@Override
public Result toModelState(final Result solverState, final ExpressionsBasedModel model) {
List freeVariables = model.getFreeVariables();
Set fixedVariables = model.getFixedVariables();
int nbFreeVars = freeVariables.size();
int nbModelVars = model.countVariables();
ArrayR064 modelSolution = ArrayR064.make(nbModelVars);
for (int i = 0; i < nbFreeVars; i++) {
modelSolution.set(model.indexOf(freeVariables.get(i)), solverState.doubleValue(i));
}
for (IntIndex fixed : fixedVariables) {
modelSolution.set(fixed.index, model.getVariable(fixed.index).getValue());
}
return solverState.withSolution(modelSolution);
}
@Override
public Result toSolverState(final Result modelState, final ExpressionsBasedModel model) {
List freeVariables = model.getFreeVariables();
int nbFreeVars = freeVariables.size();
ArrayR064 solverSolution = ArrayR064.make(nbFreeVars);
for (int i = 0; i < nbFreeVars; i++) {
Variable variable = freeVariables.get(i);
int modelIndex = model.indexOf(variable);
solverSolution.set(i, modelState.doubleValue(modelIndex));
}
return modelState.withSolution(solverSolution);
}
@Override
protected int getIndexInSolver(final ExpressionsBasedModel model, final Variable variable) {
return super.getIndexInSolver(model, variable);
}
}
static final class OldIntegration extends ExpressionsBasedModel.Integration {
private static ArrayR064 toModelVariableValues(final Access1D> solverVariableValues, final ExpressionsBasedModel model,
final ArrayR064 modelVariableValues) {
List positiveVariables = model.getPositiveVariables();
for (int p = 0; p < positiveVariables.size(); p++) {
Variable variable = positiveVariables.get(p);
int index = model.indexOf(variable);
modelVariableValues.set(index, solverVariableValues.doubleValue(p));
}
List negativeVariables = model.getNegativeVariables();
for (int n = 0; n < negativeVariables.size(); n++) {
Variable variable = negativeVariables.get(n);
int index = model.indexOf(variable);
modelVariableValues.add(index, -solverVariableValues.doubleValue(positiveVariables.size() + n));
}
return modelVariableValues;
}
public SimplexTableauSolver build(final ConvexData convexBuilder, final Optimisation.Options options) {
SimplexTableau tableau = SimplexTableauSolver.buildPrimal(convexBuilder, options, false);
return new SimplexTableauSolver(tableau, options);
}
@Override
public SimplexTableauSolver build(final ExpressionsBasedModel model) {
SimplexTableau tableau = SimplexTableauSolver.build(model);
SimplexTableauSolver solver = new SimplexTableauSolver(tableau, model.options);
if (model.options.validate) {
solver.setValidator(this.newValidator(model));
}
return solver;
}
@Override
public boolean isCapable(final ExpressionsBasedModel model) {
return !model.isAnyVariableInteger() && !model.isAnyExpressionQuadratic();
}
@Override
public Result toModelState(final Result solverState, final ExpressionsBasedModel model) {
ArrayR064 modelSolution = ArrayR064.make(model.countVariables());
for (IntIndex fixed : model.getFixedVariables()) {
modelSolution.set(fixed.index, model.getVariable(fixed.index).getValue().doubleValue());
}
OldIntegration.toModelVariableValues(solverState, model, modelSolution);
return solverState.withSolution(modelSolution);
}
@Override
public Result toSolverState(final Result modelState, final ExpressionsBasedModel model) {
List tmpPositives = model.getPositiveVariables();
List tmpNegatives = model.getNegativeVariables();
int tmpCountPositives = tmpPositives.size();
int tmpCountNegatives = tmpNegatives.size();
ArrayR064 solverSolution = ArrayR064.make(tmpCountPositives + tmpCountNegatives);
for (int p = 0; p < tmpCountPositives; p++) {
Variable tmpVariable = tmpPositives.get(p);
int tmpIndex = model.indexOf(tmpVariable);
solverSolution.set(p, MAX.invoke(modelState.doubleValue(tmpIndex), ZERO));
}
for (int n = 0; n < tmpCountNegatives; n++) {
Variable tmpVariable = tmpNegatives.get(n);
int tmpIndex = model.indexOf(tmpVariable);
solverSolution.set(tmpCountPositives + n, MAX.invoke(-modelState.doubleValue(tmpIndex), ZERO));
}
return modelState.withSolution(solverSolution);
}
@Override
protected int getIndexInSolver(final ExpressionsBasedModel model, final Variable variable) {
int retVal = -1;
BigDecimal value = variable.getValue();
if ((value != null && value.signum() >= 0 || variable.isPositive()) && (retVal = model.indexOfPositiveVariable(variable)) >= 0) {
return retVal;
}
if ((value != null && value.signum() <= 0 || variable.isNegative()) && (retVal = model.indexOfNegativeVariable(variable)) >= 0) {
retVal += model.getPositiveVariables().size();
return retVal;
}
return -1;
}
}
public static final ExpressionsBasedModel.Integration INTEGRATION = new ModelIntegration();
/**
* An integration to a new/alternative/experimental LP-solver. This solver is intended to replace the
* current solver, but is not yet ready to do that. You're welcome to try it - just add this integration
* by calling {@link ExpressionsBasedModel#addIntegration(ExpressionsBasedModel.Integration)}.
*
* With the next major release this solver/integration is expected to be the default, and there will no
* longer be an integration constant named "NEW_INTEGRATION". Possibly there will instead be one named
* "OLD_INTEGRATION".
*/
static final NewIntegration NEW_INTEGRATION = new NewIntegration();
static final OldIntegration OLD_INTEGRATION = new OldIntegration();
public static LinearSolver.GeneralBuilder newGeneralBuilder() {
return new LinearSolver.GeneralBuilder();
}
public static LinearSolver.GeneralBuilder newGeneralBuilder(final double... objective) {
return LinearSolver.newGeneralBuilder().objective(objective);
}
public static LinearSolver newSolver(final ExpressionsBasedModel model) {
SimplexTableau tableau = SimplexTableauSolver.build(model);
return new SimplexTableauSolver(tableau, model.options);
}
public static LinearSolver.StandardBuilder newStandardBuilder() {
return new LinearSolver.StandardBuilder();
}
public static LinearSolver.StandardBuilder newStandardBuilder(final double... objective) {
return LinearSolver.newStandardBuilder().objective(objective);
}
public static Optimisation.Result solve(final ConvexData convex, final Optimisation.Options options, final boolean zeroC) {
int dualSize = SimplexTableauSolver.sizeOfDual(convex);
int primSize = SimplexTableauSolver.sizeOfPrimal(convex);
boolean dual = dualSize <= primSize;
return dual ? SimplexTableauSolver.doSolveDual(convex, options, zeroC) : SimplexTableauSolver.doSolvePrimal(convex, options, zeroC);
}
static LinearFunction toObjectiveFunction(final MatrixStore mtrxC) {
ProgrammingError.throwIfNull(mtrxC);
PhysicalStore tmpC = null;
if (mtrxC instanceof PhysicalStore) {
tmpC = (PhysicalStore) mtrxC;
} else {
tmpC = mtrxC.copy();
}
return LinearFunction.wrap(tmpC);
}
protected LinearSolver(final Options solverOptions) {
super(solverOptions);
}
}