diff --git a/highs/interfaces/Highs/Enums/BasisStatus.cs b/highs/interfaces/Highs/Enums/BasisStatus.cs new file mode 100644 index 0000000000..cbb2b5db6d --- /dev/null +++ b/highs/interfaces/Highs/Enums/BasisStatus.cs @@ -0,0 +1,28 @@ +namespace Highs.Enums; + +/// +/// This defines the status of a variable (or slack variable for a constraint) in a basis +/// +public enum BasisStatus +{ + /// + /// The variable is nonbasic at its lower bound (or fixed value) + /// + Lower = 0, + /// + /// The variable is basic + /// + Basic, + /// + /// he variable is at its upper bound + /// + Upper, + /// + /// A free variable is nonbasic and set to zero + /// + Zero, + /// + /// The variable is nonbasic + /// + Nonbasic +} diff --git a/highs/interfaces/Highs/Enums/HessianFormat.cs b/highs/interfaces/Highs/Enums/HessianFormat.cs new file mode 100644 index 0000000000..c54b6bb0ca --- /dev/null +++ b/highs/interfaces/Highs/Enums/HessianFormat.cs @@ -0,0 +1,16 @@ +namespace Highs.Enums; + +/// +/// The format in which the Hessian is stored +/// +public enum HessianFormat +{ + /// + /// Store the Hessian in triangular format + /// + Triangular = 1, + /// + /// Store the Hessian in square format + /// + Square +} diff --git a/highs/interfaces/Highs/Enums/HighsStatus.cs b/highs/interfaces/Highs/Enums/HighsStatus.cs new file mode 100644 index 0000000000..40aa091574 --- /dev/null +++ b/highs/interfaces/Highs/Enums/HighsStatus.cs @@ -0,0 +1,20 @@ +namespace Highs.Enums; + +/// +/// This is (part of) the return value of most HiGHS methods +/// +public enum HighsStatus +{ + /// + /// The method has exposed an error + /// + Error = -1, + /// + /// The method has completed successfully + /// + Ok, + /// + /// The method has recovered from an unusual event, or has terminated due to reaching a time or iteration limit + /// + Warning +} diff --git a/highs/interfaces/Highs/Enums/MatrixFormat.cs b/highs/interfaces/Highs/Enums/MatrixFormat.cs new file mode 100644 index 0000000000..77f5bdb15a --- /dev/null +++ b/highs/interfaces/Highs/Enums/MatrixFormat.cs @@ -0,0 +1,16 @@ +namespace Highs.Enums; + +/// +/// This defines the format of a HighsSparseMatrix +/// +public enum MatrixFormat +{ + /// + /// The matrix is stored column-wise + /// + ColumnWise = 1, + /// + /// The matrix is stored row-wise + /// + RowWise +} diff --git a/highs/interfaces/Highs/Enums/ModelStatus.cs b/highs/interfaces/Highs/Enums/ModelStatus.cs new file mode 100644 index 0000000000..29736814ba --- /dev/null +++ b/highs/interfaces/Highs/Enums/ModelStatus.cs @@ -0,0 +1,75 @@ +namespace Highs.Enums; + +/// +/// This defines the status of the model after a call to run +/// +public enum ModelStatus +{ + /// + /// The model status has not been set + /// + Notset = 0, + LoadError, + /// + /// There is an error in the model + /// + ModelError, + PresolveError, + /// + /// There has been an error when solving the model + /// + SolveError, + PostsolveError, + /// + /// The model is empty + /// + ModelEmpty, + /// + /// The model has been solved to optimality + /// + Optimal, + /// + /// The model is infeasible + /// + Infeasible, + /// + /// The model is unbounded or infeasible + /// + UnboundedOrInfeasible, + /// + /// The model is unbounded + /// + Unbounded, + /// + /// The bound on the model objective value has been reached + /// + ObjectiveBound, + /// + /// The target value for the model objective has been reached + /// + ObjectiveTarget, + /// + /// The run time limit has been reached + /// + TimeLimit, + /// + /// The iteration limit has been reached + /// + IterationLimit, + /// + /// The model status is unknown + /// + Unknown, + /// + /// The MIP solver has reached the limit on the number of LPs solved + /// + SolutionLimit, + /// + /// The solver has been interrupted by the user + /// + Interrupt, + /// + /// The solver has been unable to allocate sufficient memory + /// + MemoryLimit +} diff --git a/highs/interfaces/Highs/Enums/ObjectiveSense.cs b/highs/interfaces/Highs/Enums/ObjectiveSense.cs new file mode 100644 index 0000000000..155741d4a3 --- /dev/null +++ b/highs/interfaces/Highs/Enums/ObjectiveSense.cs @@ -0,0 +1,16 @@ +namespace Highs.Enums; + +/// +/// This defines optimization sense of a HighsLp +/// +public enum ObjectiveSense +{ + /// + /// The objective is to be minimized + /// + Minimize = 1, + /// + /// The objective is to be maximized + /// + Maximize = -1 +} diff --git a/highs/interfaces/Highs/Enums/VariableType.cs b/highs/interfaces/Highs/Enums/VariableType.cs new file mode 100644 index 0000000000..e22f4610a5 --- /dev/null +++ b/highs/interfaces/Highs/Enums/VariableType.cs @@ -0,0 +1,28 @@ +namespace Highs.Enums; + +/// +/// This defines the feasible values of a variable within a model +/// +public enum VariableType +{ + /// + /// The variable can take continuous values between its bounds + /// + Continuous = 0, + /// + /// The variable must take integer values between its bounds + /// + Integer, + /// + /// The variable must be zero or take continuous values between its bounds + /// + SemiContinuous, + /// + /// The variable must be zero or take integer values between its bounds + /// + SemiInteger, + /// + /// The variable must take implicit integer values between its bounds + /// + ImplicitInteger, +} \ No newline at end of file diff --git a/highs/interfaces/Highs/Highs.csproj b/highs/interfaces/Highs/Highs.csproj new file mode 100644 index 0000000000..125f4c93bc --- /dev/null +++ b/highs/interfaces/Highs/Highs.csproj @@ -0,0 +1,9 @@ + + + + net9.0 + enable + enable + + + diff --git a/highs/interfaces/Highs/Highs.sln b/highs/interfaces/Highs/Highs.sln new file mode 100644 index 0000000000..01795d0c38 --- /dev/null +++ b/highs/interfaces/Highs/Highs.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.14.36811.4 d17.14 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Highs", "Highs.csproj", "{5BEA6A69-23A3-426C-A849-3B9A9A8D518A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5BEA6A69-23A3-426C-A849-3B9A9A8D518A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5BEA6A69-23A3-426C-A849-3B9A9A8D518A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5BEA6A69-23A3-426C-A849-3B9A9A8D518A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5BEA6A69-23A3-426C-A849-3B9A9A8D518A}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {F1C5253E-03B0-407C-B6C6-27C74E5FDF9F} + EndGlobalSection +EndGlobal diff --git a/highs/interfaces/Highs/HighsSolver.cs b/highs/interfaces/Highs/HighsSolver.cs new file mode 100644 index 0000000000..aee9ea8a34 --- /dev/null +++ b/highs/interfaces/Highs/HighsSolver.cs @@ -0,0 +1,881 @@ +using System.Text; +using Highs.Enums; +using Highs.Records; + +namespace Highs; + +/// +/// The Highs Solver interface. +/// +public class HighsSolver : IDisposable +{ + /// + /// The pointer to the _highs instance. + /// + private readonly IntPtr _highs; + + /// + /// Indicates whether the instance has been disposed. + /// + private bool _disposed; + + /// + /// Calls the Highs solver in a single call of a LP. + /// + /// + /// + /// + /// + /// + public static HighsStatus LpCall(HighsModel model, ref HighsSolution solution, out BasisInfo basisInfo, out ModelStatus modelStatus) + { + var numberOfColumns = model.ColumnCost.Length; + var numberOfRows = model.RowLower.Length; + var numberOfMatrixValues = model.MatrixValues.Length; + + var columnBasisStatus = new int[numberOfColumns]; + var rowBasisStatus = new int[numberOfRows]; + + var modelstate = 0; + + var status = (HighsStatus)Imports.Highs_lpCall( + numberOfColumns, + numberOfRows, + numberOfMatrixValues, + (int)model.MatrixFormat, + (int)model.ObjectiveSense, + model.Offset, + model.ColumnCost, + model.ColumnLower, + model.ColumnUpper, + model.RowLower, + model.RowUpper, + model.MatrixStart, + model.MatrixIndices, + model.MatrixValues, + solution.ColumnValue, + solution.ColumnDual, + solution.RowValue, + solution.RowDual, + columnBasisStatus, + rowBasisStatus, + ref modelstate); + + modelStatus = (ModelStatus)modelstate; + basisInfo = new(Array.ConvertAll(columnBasisStatus, c => (BasisStatus)c), Array.ConvertAll(rowBasisStatus, r => (BasisStatus)r)); + + return status; + } + + /// + /// Calls the Highs solver in a single call of a Mip. + /// + /// + /// + /// + /// + public static HighsStatus MipCall(HighsModel model, ref HighsSolution solution, out ModelStatus modelStatus) + { + var numberOfColumns = model.ColumnCost.Length; + var numberOfRows = model.RowLower.Length; + var numberOfMatrixValues = model.MatrixValues.Length; + + var modelstate = 0; + + var status = (HighsStatus)Imports.Highs_mipCall( + numberOfColumns, + numberOfRows, + numberOfMatrixValues, + (int)model.MatrixFormat, + (int)model.ObjectiveSense, + model.Offset, + model.ColumnCost, + model.ColumnLower, + model.ColumnUpper, + model.RowLower, + model.RowUpper, + model.MatrixStart, + model.MatrixIndices, + model.MatrixValues, + Array.ConvertAll(model.VariableTypes, v => (int)v), + solution.ColumnValue, + solution.RowValue, + ref modelstate); + + modelStatus = (ModelStatus)modelstate; + + return status; + } + + /// + /// Calls the Highs solver in a single call of a QP. + /// + /// + /// + /// + /// + public static HighsStatus QPCall(HighsModel model, ref HighsSolution solution, out BasisInfo basisInfo, out ModelStatus modelStatus) + { + var numberOfColumns = model.ColumnCost.Length; + var numberOfRows = model.RowLower.Length; + var numberOfMatrixValues = model.MatrixValues.Length; + var numberOfHessianValues = model.Hessian.Values.Length; + + var columnBasisStatus = new int[numberOfColumns]; + var rowBasisStatus = new int[numberOfRows]; + + var modelstate = 0; + + var status = (HighsStatus)Imports.Highs_qpCall( + numberOfColumns, + numberOfRows, + numberOfMatrixValues, + numberOfHessianValues, + (int)model.MatrixFormat, + (int)model.Hessian.HessianFormat, + (int)model.ObjectiveSense, + model.Offset, + model.ColumnCost, + model.ColumnLower, + model.ColumnUpper, + model.RowLower, + model.RowUpper, + model.MatrixStart, + model.MatrixIndices, + model.MatrixValues, + model.Hessian.Start, + model.Hessian.Index, + model.Hessian.Values, + solution.ColumnValue, + solution.ColumnDual, + solution.RowValue, + solution.RowDual, + columnBasisStatus, + rowBasisStatus, + ref modelstate); + + modelStatus = (ModelStatus)modelstate; + basisInfo = new(Array.ConvertAll(columnBasisStatus, c => (BasisStatus)c), Array.ConvertAll(rowBasisStatus, r => (BasisStatus)r)); + + return status; + } + + /// + /// The default constructor. + /// + public HighsSolver() => _highs = Imports.Highs_create(); + + /// + /// The destructor. + /// + ~HighsSolver() => Dispose(false); + + /// + /// Disposes the instance. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Disposes the instance. + /// + /// + protected virtual void Dispose(bool disposing) + { + if (_disposed) + { + return; + } + Imports.Highs_destroy(_highs); + _disposed = true; + } + + /// + /// Runs the solver. + /// + /// + public HighsStatus Run() => (HighsStatus)Imports.Highs_run(_highs); + + /// + /// Reads a model from file. + /// + /// + /// + public HighsStatus ReadModel(string filename) => (HighsStatus)Imports.Highs_readModel(_highs, filename); + + /// + /// Writes the model to file. + /// + /// + /// + public HighsStatus WriteModel(string filename) => (HighsStatus)Imports.Highs_writeModel(_highs, filename); + + /// + /// Writes the presolved model to file. + /// + /// + /// + public HighsStatus WritePresolvedModel(string filename) => (HighsStatus)Imports.Highs_writePresolvedModel(_highs, filename); + + /// + /// Writes the solution to file in a pretty format. + /// + /// + /// + public HighsStatus WriteSolutionPretty(string filename) => (HighsStatus)Imports.Highs_writeSolutionPretty(_highs, filename); + + /// + /// Gets the infinity value. + /// + /// + public double GetInfinity() => Imports.Highs_getInfinity(_highs); + + /// + /// Passes the LP model to Highs. + /// + /// + /// + public HighsStatus PassLp(HighsModel model) + { + return (HighsStatus)Imports.Highs_passLp( + _highs, + model.ColumnCost.Length, + model.RowLower.Length, + model.MatrixValues.Length, + (int)model.MatrixFormat, + (int)model.ObjectiveSense, + model.Offset, + model.ColumnCost, + model.ColumnLower, + model.ColumnUpper, + model.RowLower, + model.RowUpper, + model.MatrixStart, + model.MatrixIndices, + model.MatrixValues); + } + + /// + /// Passes the MIP model to Highs. + /// + /// + /// + public HighsStatus PassMip(HighsModel model) + { + return (HighsStatus)Imports.Highs_passMip( + _highs, + model.ColumnCost.Length, + model.RowLower.Length, + model.MatrixValues.Length, + (int)model.MatrixFormat, + (int)model.ObjectiveSense, + model.Offset, + model.ColumnCost, + model.ColumnLower, + model.ColumnUpper, + model.RowLower, + model.RowUpper, + model.MatrixStart, + model.MatrixIndices, + model.MatrixValues, + Array.ConvertAll(model.VariableTypes, v => (int)v)); + } + + /// + /// Sets the option value. + /// + /// + /// + /// + public HighsStatus SetOptionValue(string option, string value) => (HighsStatus)Imports.Highs_setOptionValue(_highs, option, value); + + /// + /// Sets the string option value. + /// + /// + /// + /// + public HighsStatus SetStringOptionValue(string option, string value) => (HighsStatus)Imports.Highs_setStringOptionValue(_highs, option, value); + + /// + /// Sets the boolean option value. + /// + /// + /// + /// + public HighsStatus SetBoolOptionValue(string option, int value) => (HighsStatus)Imports.Highs_setBoolOptionValue(_highs, option, value); + + /// + /// Sets the double option value. + /// + /// + /// + /// + public HighsStatus SetDoubleOptionValue(string option, double value) => (HighsStatus)Imports.Highs_setDoubleOptionValue(_highs, option, value); + + /// + /// Sets the integer option value. + /// + /// + /// + /// + public HighsStatus SetIntOptionValue(string option, int value) => (HighsStatus)Imports.Highs_setIntOptionValue(_highs, option, value); + + /// + /// Gets the string option value. + /// + /// + /// + /// + public HighsStatus GetStringOptionValue(string option, out string value) + { + var stringBuilder = new StringBuilder(); + var result = (HighsStatus)Imports.Highs_getStringOptionValue(_highs, option, stringBuilder); + value = stringBuilder.ToString(); + return result; + } + + /// + /// Gets the boolean option value. + /// + /// + /// + /// + public HighsStatus GetBoolOptionValue(string option, out int value) => (HighsStatus)Imports.Highs_getBoolOptionValue(_highs, option, out value); + + /// + /// Gets the double option value. + /// + /// + /// + /// + public HighsStatus GetDoubleOptionValue(string option, out double value) => (HighsStatus)Imports.Highs_getDoubleOptionValue(_highs, option, out value); + + /// + /// Gets the integer option value. + /// + /// + /// + /// + public HighsStatus GetIntOptionValue(string option, out int value) => (HighsStatus)Imports.Highs_getIntOptionValue(_highs, option, out value); + + /// + /// Gets the number of columns. + /// + /// + public int GetNumberOfColumns() => Imports.Highs_getNumCol(_highs); + + /// + /// Gets the number of rows. + /// + /// + public int GetNumberOfRows() => Imports.Highs_getNumRow(_highs); + + /// + /// Gets the number of non-zero entries. + /// + /// + public int GetNumberOfNonZeroEntries() => Imports.Highs_getNumNz(_highs); + + /// + /// Gets the solution. + /// + /// + /// + public HighsStatus GetSolution(out HighsSolution solution) + { + var numberOfColumns = GetNumberOfColumns(); + var numberOfRows = GetNumberOfRows(); + + solution = new HighsSolution(numberOfColumns, numberOfRows); + return (HighsStatus)Imports.Highs_getSolution(_highs, solution.ColumnValue, solution.ColumnDual, solution.RowValue, solution.RowDual); + } + + /// + /// Passes the Hessian to Highs. + /// + /// + /// + public HighsStatus PassHessian(Hessian hessian) + { + return (HighsStatus)Imports.Highs_passHessian(_highs, + hessian.Dimension, + hessian.Values.Length, + (int)hessian.HessianFormat, + hessian.Start, + hessian.Index, + hessian.Values); + } + + /// + /// Gets the basis information. + /// + /// + public HighsStatus GetBasis(out BasisInfo basisInfo) + { + var numberOfColumns = GetNumberOfColumns(); + var numberOfRows = GetNumberOfRows(); + + var columnBasisStatus = new int[numberOfColumns]; + var rowBasisStatus = new int[numberOfRows]; + + var status = (HighsStatus)Imports.Highs_getBasis(_highs, columnBasisStatus, rowBasisStatus); + if (status == HighsStatus.Error) + { + basisInfo = null; + return HighsStatus.Error; + } + + basisInfo = new BasisInfo(Array.ConvertAll(columnBasisStatus, x => (BasisStatus)x), Array.ConvertAll(rowBasisStatus, x => (BasisStatus)x)); + + return status; + } + + /// + /// Gets the objective value. + /// + /// + public double GetObjectiveValue() => Imports.Highs_getObjectiveValue(_highs); + + /// + /// Gets the model status. + /// + /// + public ModelStatus GetModelStatus() => (ModelStatus)Imports.Highs_getModelStatus(_highs); + + /// + /// Gets the iteration count. + /// + /// + public int GetIterationCount() => Imports.Highs_getIterationCount(_highs); + + /// + /// Adds a row to the model. + /// + /// + /// + /// + /// + /// + public HighsStatus AddRow(double lower, double upper, int[] indices, double[] values) + { + return (HighsStatus)Imports.Highs_addRow(_highs, lower, upper, indices.Length, indices, values); + } + + /// + /// Adds multiple rows to the model. + /// + /// + /// + /// + /// + /// + /// + public HighsStatus AddRows(double[] lower, double[] upper, int[] starts, int[] indices, double[] values) + { + return (HighsStatus)Imports.Highs_addRows(_highs, lower.Length, lower, upper, indices.Length, starts, indices, values); + } + + /// + /// Adds a column to the model. + /// + /// + /// + /// + /// + /// + /// + public HighsStatus AddColumn(double cost, double lower, double upper, int[] indices, double[] values) + { + return (HighsStatus)Imports.Highs_addCol(_highs, cost, lower, upper, indices.Length, indices, values); + } + + /// + /// Adds multiple columns to the model. + /// + /// + /// + /// + /// + /// + /// + /// + public HighsStatus AddColumns(double[] costs, double[] lower, double[] upper, int[] starts, int[] indices, double[] values) + { + return (HighsStatus)Imports.Highs_addCols( + _highs, + costs.Length, + costs, + lower, + upper, + indices.Length, + starts, + indices, + values); + } + + /// + /// Changes the objective sense. + /// + /// + /// + public HighsStatus ChangeObjectiveSense(ObjectiveSense sense) => (HighsStatus)Imports.Highs_changeObjectiveSense(_highs, (int)sense); + + /// + /// Changes the cost of a column. + /// + /// + /// + /// + public HighsStatus ChangeColumnCost(int column, double cost) => (HighsStatus)Imports.Highs_changeColCost(_highs, column, cost); + + /// + /// Changes the costs of multiple columns by set. + /// + /// + /// + /// + public HighsStatus ChangeColumnsCostBySet(int[] columns, double[] costs) => (HighsStatus)Imports.Highs_changeColsCostBySet(_highs, columns.Length, columns, costs); + + /// + /// Changes the costs of multiple columns by mask. + /// + /// + /// + /// + public HighsStatus ChangeColumnsCostByMask(bool[] mask, double[] cost) => (HighsStatus)Imports.Highs_changeColsCostByMask(_highs, Array.ConvertAll(mask, x => x ? 1 : 0), cost); + + /// + /// Changes the bounds of a column. + /// + /// + /// + /// + /// + public HighsStatus ChangeColumnBounds(int column, double lower, double upper) => (HighsStatus)Imports.Highs_changeColBounds(_highs, column, lower, upper); + + /// + /// Changes the bounds of multiple columns by range. + /// + /// + /// + /// + /// + /// + public HighsStatus ChangeColumnsBoundsByRange(int from, int to, double[] lower, double[] upper) => (HighsStatus)Imports.Highs_changeColsBoundsByRange(_highs, from, to, lower, upper); + + /// + /// Changes the bounds of multiple columns by set. + /// + /// + /// + /// + /// + public HighsStatus ChangeColumnsBoundsBySet(int[] columns, double[] lower, double[] upper) + { + return (HighsStatus)Imports.Highs_changeColsBoundsBySet(_highs, columns.Length, columns, lower, upper); + } + + /// + /// + /// + /// + /// + /// + /// + public HighsStatus ChangeColumnsBoundsByMask(bool[] mask, double[] lower, double[] upper) + { + return (HighsStatus)Imports.Highs_changeColsBoundsByMask(_highs, Array.ConvertAll(mask, x => x ? 1 : 0), lower, upper); + } + + /// + /// Changes the bounds of a row. + /// + /// + /// + /// + /// + public HighsStatus ChangeRowBounds(int row, double lower, double upper) => (HighsStatus)Imports.Highs_changeRowBounds(_highs, row, lower, upper); + + /// + /// Changes the bounds of multiple rows by range. + /// + /// + /// + /// + /// + public HighsStatus ChangeRowsBoundsBySet(int[] rows, double[] lower, double[] upper) => (HighsStatus)Imports.Highs_changeRowsBoundsBySet(_highs, rows.Length, rows, lower, upper); + + /// + /// Changes the bounds of multiple rows by mask. + /// + /// + /// + /// + /// + public HighsStatus ChangeRowsBoundsByMask(bool[] mask, double[] lower, double[] upper) => (HighsStatus)Imports.Highs_changeRowsBoundsByMask(_highs, Array.ConvertAll(mask, x => x ? 1 : 0), lower, upper); + + /// + /// Changes the integrality of multiple columns by range. + /// + /// + /// + /// + /// + public HighsStatus ChangeColumnsIntegralityByRange(int from_col, int to_col, VariableType[] integrality) + { + return (HighsStatus)Imports.Highs_changeColsIntegralityByRange(_highs, from_col, to_col, Array.ConvertAll(integrality, item => (int)item)); + } + + /// + /// Changes a coefficient in the constraint matrix. + /// + /// + /// + /// + /// + public HighsStatus ChangeCoefficient(int row, int column, double value) => (HighsStatus)Imports.Highs_changeCoeff(_highs, row, column, value); + + /// + /// Deletes multiple columns by range. + /// + /// + /// + /// + public HighsStatus DeleteColumnsByRange(int from, int to) => (HighsStatus)Imports.Highs_deleteColsByRange(_highs, from, to); + + /// + /// Deletes multiple columns by set. + /// + /// + /// + public HighsStatus DeleteColumnsBySet(int[] columns) => (HighsStatus)Imports.Highs_deleteColsBySet(_highs, columns.Length, columns); + + /// + /// Deletes multiple columns by mask. + /// + /// + /// + public HighsStatus DeleteColumnsByMask(bool[] mask) => (HighsStatus)Imports.Highs_deleteColsByMask(_highs, Array.ConvertAll(mask, x => x ? 1 : 0)); + + /// + /// Deletes multiple rows by range. + /// + /// + /// + /// + public HighsStatus DeleteRowsByRange(int from, int to) => (HighsStatus)Imports.Highs_deleteRowsByRange(_highs, from, to); + + /// + /// Deletes multiple rows by set. + /// + /// + /// + public HighsStatus DeleteRowsBySet(int[] rows) => (HighsStatus)Imports.Highs_deleteRowsBySet(_highs, rows.Length, rows); + + /// + /// Deletes multiple rows by mask. + /// + /// + /// + public HighsStatus DeleteRowsByMask(bool[] mask) => (HighsStatus)Imports.Highs_deleteRowsByMask(_highs, Array.ConvertAll(mask, x => x ? 1 : 0)); + + /// + /// Delegate for getting info values. + /// + /// + /// + /// + /// + /// + delegate int HighsGetInfoDelegate(IntPtr highs, string infoName, out TValue output); + + /// + /// Gets a value or a fallback if an error occurs. + /// + /// + /// + /// + /// + /// + private TValue GetValueOrFallback(HighsGetInfoDelegate highsGetInfoDelegate, string infoName, TValue fallback) + { + try + { + var status = (HighsStatus)highsGetInfoDelegate(_highs, infoName, out var value); + return status != HighsStatus.Ok ? fallback : value; + } + catch + { + return fallback; + } + } + + /// + /// Gets the current solution info. + /// + /// The . + public SolutionInfo GetInfo() + { + // TODO: This object does not contian the "complete" info from the C api. Add further props, if you need them. + return new SolutionInfo(GetValueOrFallback(Imports.Highs_getIntInfoValue, "simplex_iteration_count", 0), + GetValueOrFallback(Imports.Highs_getIntInfoValue, "ipm_iteration_count", 0), + GetValueOrFallback(Imports.Highs_getIntInfoValue, "pdlp_iteration_count", 0), + GetValueOrFallback(Imports.Highs_getDoubleInfoValue, "mip_gap", double.NaN), + GetValueOrFallback(Imports.Highs_getDoubleInfoValue, "mip_dual_bound", double.NaN), + GetValueOrFallback(Imports.Highs_getInt64InfoValue, "mip_node_count", 0L), + GetValueOrFallback(Imports.Highs_getDoubleInfoValue, "objective_function_value", double.NaN)); + } + + /// + /// Sets the solution. + /// + /// + /// + public HighsStatus SetSolution(HighsSolution solution) => (HighsStatus)Imports.Highs_setSolution(_highs, solution.ColumnValue, solution.ColumnDual, solution.RowValue, solution.RowDual); + + /// + /// Set a partial primal solution by passing values for a set of variables + /// + /// + /// The sparse solution set by this function has values for a subset of the model's variables. + /// For each entry in , the key identifies a variable by index, and + /// the value indicates the variable's value in the sparse solution. + /// + /// A dictionary that maps variable indices to variable values + /// + public HighsStatus SetSparseSolution(IReadOnlyDictionary valuesByIndex) + { + return (HighsStatus)Imports.Highs_setSparseSolution(_highs, valuesByIndex.Count, [.. valuesByIndex.Keys], [.. valuesByIndex.Values]); + } + + /// + /// Gets the basic variables. + /// + /// + /// + public HighsStatus GetBasicVariables(ref int[] basic_variables) => (HighsStatus)Imports.Highs_getBasicVariables(_highs, basic_variables); + + /// + /// Gets a row of the basis inverse. + /// + /// + /// + /// + /// + /// + public HighsStatus GetBasisInverseRow(int row, double[] row_vector, ref int row_num_nz, int[] row_indices) + { + return (HighsStatus)Imports.Highs_getBasisInverseRow(_highs, row, row_vector, ref row_num_nz, row_indices); + } + + /// + /// Gets a column of the basis inverse. + /// + /// + /// + /// + /// + /// + public HighsStatus GetBasisInverseColumn(int column, double[] column_vector, ref int column_num_nz, int[] column_indices) + { + return (HighsStatus)Imports.Highs_getBasisInverseCol(_highs, column, column_vector, ref column_num_nz, column_indices); + } + + /// + /// Gets the basis solve. + /// + /// + /// + /// + /// + /// + public HighsStatus GetBasisSolve(double[] rhs, double[] solution_vector, ref int solution_num_nz, int[] solution_indices) + { + return (HighsStatus)Imports.Highs_getBasisSolve(_highs, rhs, solution_vector, ref solution_num_nz, solution_indices); + } + + /// + /// Gets the basis transpose solve. + /// + /// + /// + /// + /// + /// + public HighsStatus GetBasisTransposeSolve(double[] rhs, double[] solution_vector, ref int solution_num_nz, int[] solution_indices) + { + return (HighsStatus)Imports.Highs_getBasisTransposeSolve(_highs, rhs, solution_vector, ref solution_num_nz, solution_indices); + } + + /// + /// Gets a reduced row. + /// + /// + /// + /// + /// + /// + public HighsStatus GetReducedRow(int row, double[] row_vector, ref int row_num_nz, int[] row_indices) + { + return (HighsStatus)Imports.Highs_getReducedRow(_highs, row, row_vector, ref row_num_nz, row_indices); + } + + /// + /// Gets a reduced column. + /// + /// + /// + /// + /// + /// + public HighsStatus GetReducedColumn(int column, double[] column_vector, ref int column_num_nz, int[] column_indices) + { + return (HighsStatus)Imports.Highs_getReducedColumn(_highs, column, column_vector, ref column_num_nz, column_indices); + } + + /// + /// Clears the model. + /// + /// + public HighsStatus ClearModel() => (HighsStatus)Imports.Highs_clearModel(_highs); + + /// + /// Clears the solver. + /// + /// + public HighsStatus ClearSolver() => (HighsStatus)Imports.Highs_clearSolver(_highs); + + /// + /// Passes the name of a column. + /// + /// + /// + /// + public HighsStatus PassColumnName(int column, string name) => (HighsStatus)Imports.Highs_passColName(_highs, column, name); + + /// + /// Passes the name of a row. + /// + /// + /// + /// + public HighsStatus PassRowName(int row, string name) => (HighsStatus)Imports.Highs_passRowName(_highs, row, name); + + /// + /// Writes the options to file. + /// + /// + /// + public HighsStatus WriteOptions(string filename) => (HighsStatus)Imports.Highs_writeOptions(_highs, filename); + + /// + /// Writes the options deviations to file. + /// + /// + /// + public HighsStatus WriteOptionsDeviations(string filename) => (HighsStatus)Imports.Highs_writeOptionsDeviations(_highs, filename); +} diff --git a/highs/interfaces/Highs/Imports.cs b/highs/interfaces/Highs/Imports.cs new file mode 100644 index 0000000000..2e6e0ed10a --- /dev/null +++ b/highs/interfaces/Highs/Imports.cs @@ -0,0 +1,480 @@ +using System.Runtime.InteropServices; +using System.Text; + +namespace Highs; + +/// +/// This contains the imports for the Highs library +/// +public static class Imports +{ + /// + /// The name of the Highs library. + /// + private const string HighsLibName = "highs"; + + #region Library Imports + [DllImport(HighsLibName)] + internal static extern int Highs_lpCall( + int numcol, + int numrow, + int numnz, + int aformat, + int sense, + double offset, + double[] colcost, + double[] collower, + double[] colupper, + double[] rowlower, + double[] rowupper, + int[] astart, + int[] aindex, + double[] avalue, + double[] colvalue, + double[] coldual, + double[] rowvalue, + double[] rowdual, + int[] colbasisstatus, + int[] rowbasisstatus, + ref int modelstatus); + + [DllImport(HighsLibName)] + internal static extern int Highs_mipCall( + int numcol, + int numrow, + int numnz, + int aformat, + int sense, + double offset, + double[] colcost, + double[] collower, + double[] colupper, + double[] rowlower, + double[] rowupper, + int[] astart, + int[] aindex, + double[] avalue, + int[] integrality, + double[] colvalue, + double[] rowvalue, + ref int modelstatus); + + [DllImport(HighsLibName)] + internal static extern int Highs_qpCall( + int numcol, + int numrow, + int numnz, + int qnumnz, + int aformat, + int qformat, + int sense, + double offset, + double[] colcost, + double[] collower, + double[] colupper, + double[] rowlower, + double[] rowupper, + int[] astart, + int[] aindex, + double[] avalue, + int[] qstart, + int[] qindex, + double[] qvalue, + + double[] colvalue, + double[] coldual, + double[] rowvalue, + double[] rowdual, + int[] colbasisstatus, + int[] rowbasisstatus, + ref int modelstatus); + + [DllImport(HighsLibName)] + internal static extern IntPtr Highs_create(); + + [DllImport(HighsLibName)] + internal static extern void Highs_destroy(IntPtr highs); + + [DllImport(HighsLibName)] + internal static extern int Highs_run(IntPtr highs); + + [DllImport(HighsLibName)] + internal static extern int Highs_readModel(IntPtr highs, string filename); + + [DllImport(HighsLibName)] + internal static extern int Highs_writeModel(IntPtr highs, string filename); + + [DllImport(HighsLibName)] + internal static extern int Highs_writePresolvedModel(IntPtr highs, string filename); + + [DllImport(HighsLibName)] + internal static extern int Highs_writeSolutionPretty(IntPtr highs, string filename); + + [DllImport(HighsLibName)] + internal static extern int Highs_getInfinity(IntPtr highs); + + [DllImport(HighsLibName)] + internal static extern int Highs_passLp( + IntPtr highs, + int numcol, + int numrow, + int numnz, + int aformat, + int sense, + double offset, + double[] colcost, + double[] collower, + double[] colupper, + double[] rowlower, + double[] rowupper, + int[] astart, + int[] aindex, + double[] avalue); + + [DllImport(HighsLibName)] + internal static extern int Highs_passMip( + IntPtr highs, + int numcol, + int numrow, + int numnz, + int aformat, + int sense, + double offset, + double[] colcost, + double[] collower, + double[] colupper, + double[] rowlower, + double[] rowupper, + int[] astart, + int[] aindex, + double[] avalue, + int[] highs_integrality); + + [DllImport(HighsLibName)] + internal static extern int Highs_passModel( + IntPtr highs, + int numcol, + int numrow, + int numnz, + int qnumnz, + int aformat, + int qformat, + int sense, + double offset, + double[] colcost, + double[] collower, + double[] colupper, + double[] rowlower, + double[] rowupper, + int[] astart, + int[] aindex, + double[] avalue, + int[] qstart, + int[] qindex, + double[] qvalue, + int[] highs_integrality); + + [DllImport(HighsLibName)] + internal static extern int Highs_passHessian( + IntPtr highs, + int dim, + int numnz, + int q_format, + int[] qstart, + int[] qindex, + double[] qvalue); + + [DllImport(HighsLibName)] + internal static extern int Highs_setOptionValue(IntPtr highs, string option, string value); + + [DllImport(HighsLibName)] + internal static extern int Highs_setBoolOptionValue(IntPtr highs, string option, int value); + + [DllImport(HighsLibName)] + internal static extern int Highs_setIntOptionValue(IntPtr highs, string option, int value); + + [DllImport(HighsLibName)] + internal static extern int Highs_setDoubleOptionValue(IntPtr highs, string option, double value); + + [DllImport(HighsLibName)] + internal static extern int Highs_setStringOptionValue(IntPtr highs, string option, string value); + + [DllImport(HighsLibName)] + internal static extern int Highs_getBoolOptionValue(IntPtr highs, string option, out int value); + + [DllImport(HighsLibName)] + internal static extern int Highs_getIntOptionValue(IntPtr highs, string option, out int value); + + [DllImport(HighsLibName)] + internal static extern int Highs_getDoubleOptionValue(IntPtr highs, string option, out double value); + + [DllImport(HighsLibName)] + internal static extern int Highs_getStringOptionValue(IntPtr highs, string option, [Out] StringBuilder value); + + [DllImport(HighsLibName)] + internal static extern int Highs_getSolution(IntPtr highs, double[] colvalue, double[] coldual, double[] rowvalue, double[] rowdual); + + [DllImport(HighsLibName)] + internal static extern int Highs_getNumCol(IntPtr highs); + + [DllImport(HighsLibName)] + internal static extern int Highs_getNumRow(IntPtr highs); + + [DllImport(HighsLibName)] + internal static extern int Highs_getNumNz(IntPtr highs); + + [DllImport(HighsLibName)] + internal static extern int Highs_getHessianNumNz(IntPtr highs); + + [DllImport(HighsLibName)] + internal static extern int Highs_getBasis(IntPtr highs, int[] colstatus, int[] rowstatus); + + [DllImport(HighsLibName)] + internal static extern double Highs_getObjectiveValue(IntPtr highs); + + [DllImport(HighsLibName)] + internal static extern int Highs_getIterationCount(IntPtr highs); + + [DllImport(HighsLibName)] + internal static extern int Highs_getModelStatus(IntPtr highs); + + [DllImport(HighsLibName)] + internal static extern int Highs_addRow(IntPtr highs, double lower, double upper, int num_new_nz, int[] indices, double[] values); + + [DllImport(HighsLibName)] + internal static extern int Highs_addRows( + IntPtr highs, + int num_new_row, + double[] lower, + double[] upper, + int num_new_nz, + int[] starts, + int[] indices, + double[] values); + + [DllImport(HighsLibName)] + internal static extern int Highs_addCol( + IntPtr highs, + double cost, + double lower, + double upper, + int num_new_nz, + int[] indices, + double[] values); + + [DllImport(HighsLibName)] + internal static extern int Highs_addCols( + IntPtr highs, + int num_new_col, + double[] costs, + double[] lower, + double[] upper, + int num_new_nz, + int[] starts, + int[] indices, + double[] values); + + [DllImport(HighsLibName)] + internal static extern int Highs_changeObjectiveSense(IntPtr highs, int sense); + + [DllImport(HighsLibName)] + internal static extern int Highs_changeColCost(IntPtr highs, int column, double cost); + + [DllImport(HighsLibName)] + internal static extern int Highs_changeColsCostBySet(IntPtr highs, int num_set_entries, int[] set, double[] cost); + + [DllImport(HighsLibName)] + internal static extern int Highs_changeColsCostByMask(IntPtr highs, int[] mask, double[] cost); + + [DllImport(HighsLibName)] + internal static extern int Highs_changeColBounds(IntPtr highs, int column, double lower, double upper); + + [DllImport(HighsLibName)] + internal static extern int Highs_changeColsBoundsByRange(IntPtr highs, int from_col, int to_col, double[] lower, double[] upper); + + [DllImport(HighsLibName)] + internal static extern int Highs_changeColsBoundsBySet(IntPtr highs, int num_set_entries, int[] set, double[] lower, double[] upper); + + [DllImport(HighsLibName)] + internal static extern int Highs_changeColsBoundsByMask(IntPtr highs, int[] mask, double[] lower, double[] upper); + + [DllImport(HighsLibName)] + internal static extern int Highs_changeRowBounds(IntPtr highs, int row, double lower, double upper); + + [DllImport(HighsLibName)] + internal static extern int Highs_changeRowsBoundsByRange(IntPtr highs, int from_row, int to_row, double[] lower, double[] upper); + + [DllImport(HighsLibName)] + internal static extern int Highs_changeRowsBoundsBySet(IntPtr highs, int num_set_entries, int[] set, double[] lower, double[] upper); + + [DllImport(HighsLibName)] + internal static extern int Highs_changeRowsBoundsByMask(IntPtr highs, int[] mask, double[] lower, double[] upper); + + [DllImport(HighsLibName)] + internal static extern int Highs_changeColsIntegralityByRange(IntPtr highs, int from_col, int to_col, int[] integrality); + + [DllImport(HighsLibName)] + internal static extern int Highs_changeCoeff(IntPtr highs, int row, int column, double value); + + [DllImport(HighsLibName)] + internal static extern int Highs_deleteColsByRange(IntPtr highs, int from_col, int to_col); + + [DllImport(HighsLibName)] + internal static extern int Highs_deleteColsBySet(IntPtr highs, int num_set_entries, int[] set); + + [DllImport(HighsLibName)] + internal static extern int Highs_deleteColsByMask(IntPtr highs, int[] mask); + + [DllImport(HighsLibName)] + internal static extern int Highs_deleteRowsByRange(IntPtr highs, int from_row, int to_row); + + [DllImport(HighsLibName)] + internal static extern int Highs_deleteRowsBySet(IntPtr highs, int num_set_entries, int[] set); + + [DllImport(HighsLibName)] + internal static extern int Highs_deleteRowsByMask(IntPtr highs, int[] mask); + + [DllImport(HighsLibName)] + internal static extern int Highs_getDoubleInfoValue(IntPtr highs, string info, out double value); + + [DllImport(HighsLibName)] + internal static extern int Highs_getIntInfoValue(IntPtr highs, string info, out int value); + + [DllImport(HighsLibName)] + internal static extern int Highs_getInt64InfoValue(IntPtr highs, string info, out long value); + + [DllImport(HighsLibName)] + internal static extern int Highs_setSolution(IntPtr highs, double[] col_value, double[] row_value, double[] col_dual, double[] row_dual); + + [DllImport(HighsLibName)] + internal static extern int Highs_setSparseSolution(IntPtr highs, int num_entries, int[] index, double[] value); + + [DllImport(HighsLibName)] + internal static extern int Highs_getColsByRange( + IntPtr highs, + int from_col, + int to_col, + ref int num_col, + double[] costs, + double[] lower, + double[] upper, + ref int num_nz, + int[] matrix_start, + int[] matrix_index, + double[] matrix_value); + + [DllImport(HighsLibName)] + internal static extern int Highs_getColsBySet( + IntPtr highs, + int num_set_entries, + int[] set, + ref int num_col, + double[] costs, + double[] lower, + double[] upper, + ref int num_nz, + int[] matrix_start, + int[] matrix_index, + double[] matrix_value); + + [DllImport(HighsLibName)] + internal static extern int Highs_getColsByMask( + IntPtr highs, + int[] mask, + ref int num_col, + double[] costs, + double[] lower, + double[] upper, + ref int num_nz, + int[] matrix_start, + int[] matrix_index, + double[] matrix_value); + + [DllImport(HighsLibName)] + internal static extern int Highs_getRowsByRange( + IntPtr highs, + int from_row, + int to_row, + ref int num_row, + double[] lower, + double[] upper, + ref int num_nz, + int[] matrix_start, + int[] matrix_index, + double[] matrix_value); + + [DllImport(HighsLibName)] + internal static extern int Highs_getRowsBySet( + IntPtr highs, + int num_set_entries, + int[] set, + ref int num_row, + double[] lower, + double[] upper, + ref int num_nz, + int[] matrix_start, + int[] matrix_index, + double[] matrix_value); + + [DllImport(HighsLibName)] + internal static extern int Highs_getRowsByMask( + IntPtr highs, + int[] mask, + ref int num_row, + double[] lower, + double[] upper, + ref int num_nz, + int[] matrix_start, + int[] matrix_index, + double[] matrix_value); + + [DllImport(HighsLibName)] + internal static extern int Highs_getBasicVariables(IntPtr highs, int[] basic_variables); + + [DllImport(HighsLibName)] + internal static extern int Highs_getBasisInverseRow(IntPtr highs, int row, double[] row_vector, ref int row_num_nz, int[] row_indices); + + [DllImport(HighsLibName)] + internal static extern int Highs_getBasisInverseCol(IntPtr highs, int column, double[] col_vector, ref int col_num_nz, int[] col_indices); + + [DllImport(HighsLibName)] + internal static extern int Highs_getBasisSolve( + IntPtr highs, + double[] rhs, + double[] solution_vector, + ref int solution_num_nz, + int[] solution_indices); + + [DllImport(HighsLibName)] + internal static extern int Highs_getBasisTransposeSolve( + IntPtr highs, + double[] rhs, + double[] solution_vector, + ref int solution_nz, + int[] solution_indices); + + [DllImport(HighsLibName)] + internal static extern int Highs_getReducedRow(IntPtr highs, int row, double[] row_vector, ref int row_num_nz, int[] row_indices); + + [DllImport(HighsLibName)] + internal static extern int Highs_getReducedColumn(IntPtr highs, int column, double[] col_vector, ref int col_num_nz, int[] col_indices); + + [DllImport(HighsLibName)] + internal static extern int Highs_clearModel(IntPtr highs); + + [DllImport(HighsLibName)] + internal static extern int Highs_clearSolver(IntPtr highs); + + [DllImport(HighsLibName)] + internal static extern int Highs_passColName(IntPtr highs, int column, string name); + + [DllImport(HighsLibName)] + internal static extern int Highs_passRowName(IntPtr highs, int row, string name); + + [DllImport(HighsLibName)] + internal static extern int Highs_writeOptions(IntPtr highs, string filename); + + [DllImport(HighsLibName)] + internal static extern int Highs_writeOptionsDeviations(IntPtr highs, string filename); + #endregion +} \ No newline at end of file diff --git a/highs/interfaces/Highs/Records/BasisInfo.cs b/highs/interfaces/Highs/Records/BasisInfo.cs new file mode 100644 index 0000000000..b6114a8aa3 --- /dev/null +++ b/highs/interfaces/Highs/Records/BasisInfo.cs @@ -0,0 +1,21 @@ +using Highs.Enums; + +namespace Highs.Records; + +/// +/// This defines the basis status of the columns and rows in a basis +/// +/// The column basis status +/// The row basis status +public record BasisInfo(BasisStatus[] ColumnBasisStatus, BasisStatus[] RowBasisStatus) +{ + /// + /// The default constructor creates empty arrays + /// + /// The number of columns + /// The number of rows + public BasisInfo(int numberOfColumns, int numberOfRows) : this(new BasisStatus[numberOfColumns], + new BasisStatus[numberOfRows]) + { + } +} diff --git a/highs/interfaces/Highs/Records/Hessian.cs b/highs/interfaces/Highs/Records/Hessian.cs new file mode 100644 index 0000000000..fcade220b9 --- /dev/null +++ b/highs/interfaces/Highs/Records/Hessian.cs @@ -0,0 +1,30 @@ +using Highs.Enums; + +namespace Highs.Records; + +/// +/// This defines the Hessian of the quadratic objective +/// +public record Hessian +{ + /// + /// Format of the Hessian + /// + public HessianFormat HessianFormat; + /// + /// Dimension of the Hessian + /// + public int Dimension; + /// + /// Start of each compressed column in the Hessian + /// + public int[] Start = []; + /// + /// Indices of the nonzeros in the Hessian + /// + public int[] Index = []; + /// + /// Values of the nonzeros in the Hessian + /// + public double[] Values = []; +} diff --git a/highs/interfaces/Highs/Records/HighsModel.cs b/highs/interfaces/Highs/Records/HighsModel.cs new file mode 100644 index 0000000000..0bd2d610ee --- /dev/null +++ b/highs/interfaces/Highs/Records/HighsModel.cs @@ -0,0 +1,62 @@ +using Highs.Enums; + +namespace Highs.Records; + +/// +/// This defines a model for Highs +/// +public record HighsModel +{ + /// + /// The objective sense + /// + public ObjectiveSense ObjectiveSense; + /// + /// The objective constant + /// + public double Offset; + /// + /// The column costs + /// + public double[] ColumnCost = []; + /// + /// The column lower bounds + /// + public double[] ColumnLower = []; + /// + /// The column upper bounds + /// + public double[] ColumnUpper = []; + /// + /// The row lower bounds + /// + public double[] RowLower = []; + /// + /// The row upper bounds + /// + public double[] RowUpper = []; + /// + /// The format of the constraint matrix. + /// + public MatrixFormat MatrixFormat; + /// + /// The starting index of each column (or row) in MatrixIndices. + /// + public int[] MatrixStart = []; + /// + /// The indices of matrix entries + /// + public int[] MatrixIndices = []; + /// + /// The values of matrix entries + /// + public double[] MatrixValues = []; + /// + /// The integrality of the variables + /// + public VariableType[] VariableTypes = []; + /// + /// The Hessian for quadratic objectives + /// + public Hessian Hessian = null; +} diff --git a/highs/interfaces/Highs/Records/HighsSolution.cs b/highs/interfaces/Highs/Records/HighsSolution.cs new file mode 100644 index 0000000000..76f0ddf7e0 --- /dev/null +++ b/highs/interfaces/Highs/Records/HighsSolution.cs @@ -0,0 +1,26 @@ +namespace Highs.Records; + +/// +/// The solution. +/// +/// The column value. +/// The column dual. +/// The row value. +/// The row dual. +public record HighsSolution(double[] ColumnValue, + double[] ColumnDual, + double[] RowValue, + double[] RowDual) +{ + /// + /// The default constructor creates empty arrays + /// + /// The number of columns + /// The number of rows + public HighsSolution(int numberOfColumns, int numberOfRows) : this(new double[numberOfColumns], + new double[numberOfColumns], + new double[numberOfRows], + new double[numberOfRows]) + { + } +} diff --git a/highs/interfaces/Highs/Records/SolutionInfo.cs b/highs/interfaces/Highs/Records/SolutionInfo.cs new file mode 100644 index 0000000000..710353062e --- /dev/null +++ b/highs/interfaces/Highs/Records/SolutionInfo.cs @@ -0,0 +1,21 @@ +namespace Highs.Records; + +/// +/// The solution info. +/// +/// The simplex iteration count. +/// The Interior Point Method (IPM) iteration count. +/// The PDLP iteration count. +/// The MIP gap. +/// The best dual bound. +/// The MIP node count. +/// The objective value. +public record SolutionInfo(int SimplexIterationCount, + int IpmIterationCount, + int PdlpIterationCount, + double MipGap, + double DualBound, + long NodeCount, + double ObjectiveValue) +{ +} diff --git a/highs/interfaces/highs_csharp_api.cs b/highs/interfaces/highs_csharp_api.cs deleted file mode 100644 index 4c8c31b164..0000000000 --- a/highs/interfaces/highs_csharp_api.cs +++ /dev/null @@ -1,1142 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; - -// mcs -out:highscslib.dll -t:library highs_csharp_api.cs -unsafe - -namespace Highs { -public enum HighsStatus -{ - kError = -1, - kOk, - kWarning -} - -public enum HighsMatrixFormat -{ - kColwise = 1, - kRowwise -} - -public enum HessianFormat -{ - kTriangular = 1, - kSquare -} - -public enum HighsBasisStatus -{ - kLower = 0, - kBasic, - kUpper, - kZero, - kNonbasic -} - -public enum HighsObjectiveSense -{ - kMinimize = 1, - kMaximize = -1 -} - -public enum HighsModelStatus -{ - kNotset = 0, - kLoadError, - kModelError, - kPresolveError, - kSolveError, - kPostsolveError, - kModelEmpty, - kOptimal, - kInfeasible, - kUnboundedOrInfeasible, - kUnbounded, - kObjectiveBound, - kObjectiveTarget, - kTimeLimit, - kIterationLimit, - kUnknown, - kSolutionLimit, - kInterrupt, - kMemoryLimit, - kHighsInterrupt -} - -public enum HighsIntegrality -{ - kContinuous = 0, - kInteger = 1, - kSemiContinuous = 2, - kSemiInteger = 3, - kImplicitInteger = 4, -} - -public class HighsModel -{ - public HighsObjectiveSense sense; - public double[] colcost; - public double offset; - public double[] collower; - public double[] colupper; - public double[] rowlower; - public double[] rowupper; - public HighsMatrixFormat a_format; - public int[] astart; - public int[] aindex; - public double[] avalue; - public int[] highs_integrality; - - public HighsModel() - { - - } - - public HighsModel(double[] colcost, double[] collower, double[] colupper, double[] rowlower, double[] rowupper, - int[] astart, int[] aindex, double[] avalue, int[] highs_integrality = null, double offset = 0, HighsMatrixFormat a_format = HighsMatrixFormat.kColwise, HighsObjectiveSense sense = HighsObjectiveSense.kMinimize) - { - this.colcost = colcost; - this.collower = collower; - this.colupper = colupper; - this.rowlower = rowlower; - this.rowupper = rowupper; - this.astart = astart; - this.aindex = aindex; - this.avalue = avalue; - this.offset = offset; - this.a_format = a_format; - this.sense = sense; - this.highs_integrality = highs_integrality; - } -} - -public class HighsHessian -{ - public HessianFormat q_format; - public int dim; - public int[] qstart; - public int[] qindex; - public double[] qvalue; - - public HighsHessian() - { - - } - - public HighsHessian(int dim, int[] qstart, int[] qindex, double[] qvalue, HessianFormat q_format = HessianFormat.kTriangular) - { - this.dim = dim; - this.qstart = qstart; - this.qindex = qindex; - this.qvalue = qvalue; - this.q_format = q_format; - } -} - -public class HighsSolution -{ - public double[] colvalue; - public double[] coldual; - public double[] rowvalue; - public double[] rowdual; - - public HighsSolution(int numcol, int numrow) - { - this.colvalue = new double[numcol]; - this.coldual = new double[numcol]; - this.rowvalue = new double[numrow]; - this.rowdual = new double[numrow]; - } - - public HighsSolution(double[] colvalue, double[] coldual, double[] rowvalue, double[] rowdual) - { - this.colvalue = colvalue; - this.coldual = coldual; - this.rowvalue = rowvalue; - this.rowdual = rowdual; - } -} - -public class HighsBasis -{ - public HighsBasisStatus[] colbasisstatus; - public HighsBasisStatus[] rowbasisstatus; - - public HighsBasis(int numcol, int numrow) - { - this.colbasisstatus = new HighsBasisStatus[numcol]; - this.rowbasisstatus = new HighsBasisStatus[numrow]; - } - - public HighsBasis(HighsBasisStatus[] colbasisstatus, HighsBasisStatus[] rowbasisstatus) - { - this.colbasisstatus = colbasisstatus; - this.rowbasisstatus = rowbasisstatus; - } -} - -public class HighsLpSolver : IDisposable -{ - private IntPtr highs; - - private bool _disposed; - - private const string highslibname = "highs"; - - [DllImport(highslibname)] - private static extern int Highs_call( - Int32 numcol, - Int32 numrow, - Int32 numnz, - double[] colcost, - double[] collower, - double[] colupper, - double[] rowlower, - double[] rowupper, - int[] astart, - int[] aindex, - double[] avalue, - double[] colvalue, - double[] coldual, - double[] rowvalue, - double[] rowdual, - int[] colbasisstatus, - int[] rowbasisstatus, - ref int modelstatus); - - [DllImport(highslibname)] - private static extern IntPtr Highs_create(); - - [DllImport(highslibname)] - private static extern void Highs_destroy(IntPtr highs); - - [DllImport(highslibname)] - private static extern int Highs_run(IntPtr highs); - - [DllImport(highslibname)] - private static extern int Highs_readModel(IntPtr highs, string filename); - - [DllImport(highslibname)] - private static extern int Highs_writeModel(IntPtr highs, string filename); - - [DllImport(highslibname)] - private static extern int Highs_writePresolvedModel(IntPtr highs, string filename); - - [DllImport(highslibname)] - private static extern int Highs_writeSolutionPretty(IntPtr highs, string filename); - - [DllImport(highslibname)] - private static extern int Highs_getInfinity(IntPtr highs); - - [DllImport(highslibname)] - private static extern int Highs_passLp( - IntPtr highs, - int numcol, - int numrow, - int numnz, - int aformat, - int sense, - double offset, - double[] colcost, - double[] collower, - double[] colupper, - double[] rowlower, - double[] rowupper, - int[] astart, - int[] aindex, - double[] avalue); - - [DllImport(highslibname)] - private static extern int Highs_passMip( - IntPtr highs, - int numcol, - int numrow, - int numnz, - int aformat, - int sense, - double offset, - double[] colcost, - double[] collower, - double[] colupper, - double[] rowlower, - double[] rowupper, - int[] astart, - int[] aindex, - double[] avalue, - int[] highs_integrality); - - [DllImport(highslibname)] - private static extern int Highs_passModel( - IntPtr highs, - int numcol, - int numrow, - int numnz, - int qnumnz, - int aformat, - int qformat, - int sense, - double offset, - double[] colcost, - double[] collower, - double[] colupper, - double[] rowlower, - double[] rowupper, - int[] astart, - int[] aindex, - double[] avalue, - int[] qstart, - int[] qindex, - double[] qvalue, - int[] highs_integrality); - - [DllImport(highslibname)] - private static extern int Highs_passHessian( - IntPtr highs, - int dim, - int numnz, - int q_format, - int[] qstart, - int[] qindex, - double[] qvalue); - - [DllImport(highslibname)] - private static extern int Highs_setOptionValue(IntPtr highs, string option, string value); - - [DllImport(highslibname)] - private static extern int Highs_setBoolOptionValue(IntPtr highs, string option, int value); - - [DllImport(highslibname)] - private static extern int Highs_setIntOptionValue(IntPtr highs, string option, int value); - - [DllImport(highslibname)] - private static extern int Highs_setDoubleOptionValue(IntPtr highs, string option, double value); - - [DllImport(highslibname)] - private static extern int Highs_setStringOptionValue(IntPtr highs, string option, string value); - - [DllImport(highslibname)] - private static extern int Highs_getBoolOptionValue(IntPtr highs, string option, out int value); - - [DllImport(highslibname)] - private static extern int Highs_getIntOptionValue(IntPtr highs, string option, out int value); - - [DllImport(highslibname)] - private static extern int Highs_getDoubleOptionValue(IntPtr highs, string option, out double value); - - [DllImport(highslibname)] - private static extern int Highs_getStringOptionValue(IntPtr highs, string option, [Out] StringBuilder value); - - [DllImport(highslibname)] - private static extern int Highs_getSolution(IntPtr highs, double[] colvalue, double[] coldual, double[] rowvalue, double[] rowdual); - - [DllImport(highslibname)] - private static extern int Highs_getNumCol(IntPtr highs); - - [DllImport(highslibname)] - private static extern int Highs_getNumRow(IntPtr highs); - - [DllImport(highslibname)] - private static extern int Highs_getNumNz(IntPtr highs); - - [DllImport(highslibname)] - private static extern int Highs_getHessianNumNz(IntPtr highs); - - [DllImport(highslibname)] - private static extern int Highs_getBasis(IntPtr highs, int[] colstatus, int[] rowstatus); - - [DllImport(highslibname)] - private static extern double Highs_getObjectiveValue(IntPtr highs); - - [DllImport(highslibname)] - private static extern int Highs_getIterationCount(IntPtr highs); - - [DllImport(highslibname)] - private static extern int Highs_getModelStatus(IntPtr highs); - - [DllImport(highslibname)] - private static extern int Highs_addRow(IntPtr highs, double lower, double upper, int num_new_nz, int[] indices, double[] values); - - [DllImport(highslibname)] - private static extern int Highs_addRows( - IntPtr highs, - int num_new_row, - double[] lower, - double[] upper, - int num_new_nz, - int[] starts, - int[] indices, - double[] values); - - [DllImport(highslibname)] - private static extern int Highs_addCol( - IntPtr highs, - double cost, - double lower, - double upper, - int num_new_nz, - int[] indices, - double[] values); - - [DllImport(highslibname)] - private static extern int Highs_addCols( - IntPtr highs, - int num_new_col, - double[] costs, - double[] lower, - double[] upper, - int num_new_nz, - int[] starts, - int[] indices, - double[] values); - - [DllImport(highslibname)] - private static extern int Highs_changeObjectiveSense(IntPtr highs, int sense); - - [DllImport(highslibname)] - private static extern int Highs_changeColCost(IntPtr highs, int col, double cost); - - [DllImport(highslibname)] - private static extern int Highs_changeColsCostBySet(IntPtr highs, int num_set_entries, int[] set, double[] cost); - - [DllImport(highslibname)] - private static extern int Highs_changeColsCostByMask(IntPtr highs, int[] mask, double[] cost); - - [DllImport(highslibname)] - private static extern int Highs_changeColBounds(IntPtr highs, int col, double lower, double upper); - - [DllImport(highslibname)] - private static extern int Highs_changeColsBoundsByRange(IntPtr highs, int from_col, int to_col, double[] lower, double[] upper); - - [DllImport(highslibname)] - private static extern int Highs_changeColsBoundsBySet(IntPtr highs, int num_set_entries, int[] set, double[] lower, double[] upper); - - [DllImport(highslibname)] - private static extern int Highs_changeColsBoundsByMask(IntPtr highs, int[] mask, double[] lower, double[] upper); - - [DllImport(highslibname)] - private static extern int Highs_changeRowBounds(IntPtr highs, int row, double lower, double upper); - - [DllImport(highslibname)] - private static extern int Highs_changeRowsBoundsByRange(IntPtr highs, int from_row, int to_row, double[] lower, double[] upper); - - [DllImport(highslibname)] - private static extern int Highs_changeRowsBoundsBySet(IntPtr highs, int num_set_entries, int[] set, double[] lower, double[] upper); - - [DllImport(highslibname)] - private static extern int Highs_changeRowsBoundsByMask(IntPtr highs, int[] mask, double[] lower, double[] upper); - - [DllImport(highslibname)] - private static extern int Highs_changeColsIntegralityByRange(IntPtr highs, int from_col, int to_col, int[] integrality); - - [DllImport(highslibname)] - private static extern int Highs_changeCoeff(IntPtr highs, int row, int col, double value); - - [DllImport(highslibname)] - private static extern int Highs_deleteColsByRange(IntPtr highs, int from_col, int to_col); - - [DllImport(highslibname)] - private static extern int Highs_deleteColsBySet(IntPtr highs, int num_set_entries, int[] set); - - [DllImport(highslibname)] - private static extern int Highs_deleteColsByMask(IntPtr highs, int[] mask); - - [DllImport(highslibname)] - private static extern int Highs_deleteRowsByRange(IntPtr highs, int from_row, int to_row); - - [DllImport(highslibname)] - private static extern int Highs_deleteRowsBySet(IntPtr highs, int num_set_entries, int[] set); - - [DllImport(highslibname)] - private static extern int Highs_deleteRowsByMask(IntPtr highs, int[] mask); - - [DllImport(highslibname)] - private static extern int Highs_getDoubleInfoValue(IntPtr highs, string info, out double value); - - [DllImport(highslibname)] - private static extern int Highs_getIntInfoValue(IntPtr highs, string info, out int value); - - [DllImport(highslibname)] - private static extern int Highs_getInt64InfoValue(IntPtr highs, string info, out long value); - - [DllImport(highslibname)] - private static extern int Highs_setSolution(IntPtr highs, double[] col_value, double[] row_value, double[] col_dual, double[] row_dual); - - [DllImport(highslibname)] - private static extern int Highs_setSparseSolution(IntPtr highs, int num_entries, int[] index, double[] value); - - [DllImport(highslibname)] - private static extern int Highs_getColsByRange( - IntPtr highs, - int from_col, - int to_col, - ref int num_col, - double[] costs, - double[] lower, - double[] upper, - ref int num_nz, - int[] matrix_start, - int[] matrix_index, - double[] matrix_value); - - [DllImport(highslibname)] - private static extern int Highs_getColsBySet( - IntPtr highs, - int num_set_entries, - int[] set, - ref int num_col, - double[] costs, - double[] lower, - double[] upper, - ref int num_nz, - int[] matrix_start, - int[] matrix_index, - double[] matrix_value); - - [DllImport(highslibname)] - private static extern int Highs_getColsByMask( - IntPtr highs, - int[] mask, - ref int num_col, - double[] costs, - double[] lower, - double[] upper, - ref int num_nz, - int[] matrix_start, - int[] matrix_index, - double[] matrix_value); - - [DllImport(highslibname)] - private static extern int Highs_getRowsByRange( - IntPtr highs, - int from_row, - int to_row, - ref int num_row, - double[] lower, - double[] upper, - ref int num_nz, - int[] matrix_start, - int[] matrix_index, - double[] matrix_value); - - [DllImport(highslibname)] - private static extern int Highs_getRowsBySet( - IntPtr highs, - int num_set_entries, - int[] set, - ref int num_row, - double[] lower, - double[] upper, - ref int num_nz, - int[] matrix_start, - int[] matrix_index, - double[] matrix_value); - - [DllImport(highslibname)] - private static extern int Highs_getRowsByMask( - IntPtr highs, - int[] mask, - ref int num_row, - double[] lower, - double[] upper, - ref int num_nz, - int[] matrix_start, - int[] matrix_index, - double[] matrix_value); - - [DllImport(highslibname)] - private static extern int Highs_getBasicVariables(IntPtr highs, int[] basic_variables); - - [DllImport(highslibname)] - private static extern int Highs_getBasisInverseRow(IntPtr highs, int row, double[] row_vector, ref int row_num_nz, int[] row_indices); - - [DllImport(highslibname)] - private static extern int Highs_getBasisInverseCol(IntPtr highs, int col, double[] col_vector, ref int col_num_nz, int[] col_indices); - - [DllImport(highslibname)] - private static extern int Highs_getBasisSolve( - IntPtr highs, - double[] rhs, - double[] solution_vector, - ref int solution_num_nz, - int[] solution_indices); - - [DllImport(highslibname)] - private static extern int Highs_getBasisTransposeSolve( - IntPtr highs, - double[] rhs, - double[] solution_vector, - ref int solution_nz, - int[] solution_indices); - - [DllImport(highslibname)] - private static extern int Highs_getReducedRow(IntPtr highs, int row, double[] row_vector, ref int row_num_nz, int[] row_indices); - - [DllImport(highslibname)] - private static extern int Highs_getReducedColumn(IntPtr highs, int col, double[] col_vector, ref int col_num_nz, int[] col_indices); - - [DllImport(highslibname)] - private static extern int Highs_clearModel(IntPtr highs); - - [DllImport(highslibname)] - private static extern int Highs_clearSolver(IntPtr highs); - - [DllImport(highslibname)] - private static extern int Highs_passColName(IntPtr highs, int col, string name); - - [DllImport(highslibname)] - private static extern int Highs_passRowName(IntPtr highs, int row, string name); - - [DllImport(highslibname)] - private static extern int Highs_writeOptions(IntPtr highs, string filename); - - [DllImport(highslibname)] - private static extern int Highs_writeOptionsDeviations(IntPtr highs, string filename); - - public static HighsStatus call(HighsModel model, ref HighsSolution sol, ref HighsBasis bas, ref HighsModelStatus modelstatus) - { - int nc = model.colcost.Length; - int nr = model.rowlower.Length; - int nnz = model.avalue.Length; - - int[] colbasstat = new int[nc]; - int[] rowbasstat = new int[nr]; - - int modelstate = 0; - - HighsStatus status = (HighsStatus)HighsLpSolver.Highs_call( - nc, - nr, - nnz, - model.colcost, - model.collower, - model.colupper, - model.rowlower, - model.rowupper, - model.astart, - model.aindex, - model.avalue, - sol.colvalue, - sol.coldual, - sol.rowvalue, - sol.rowdual, - colbasstat, - rowbasstat, - ref modelstate); - - modelstatus = (HighsModelStatus)modelstate; - - bas.colbasisstatus = colbasstat.Select(x => (HighsBasisStatus)x).ToArray(); - bas.rowbasisstatus = rowbasstat.Select(x => (HighsBasisStatus)x).ToArray(); - - return status; - } - - public HighsLpSolver() - { - this.highs = HighsLpSolver.Highs_create(); - } - - ~HighsLpSolver() - { - this.Dispose(false); - } - - public void Dispose() - { - this.Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (this._disposed) - { - return; - } - - HighsLpSolver.Highs_destroy(this.highs); - this._disposed = true; - } - - public HighsStatus run() - { - return (HighsStatus)HighsLpSolver.Highs_run(this.highs); - } - - public HighsStatus readModel(string filename) - { - return (HighsStatus)HighsLpSolver.Highs_readModel(this.highs, filename); - } - - public HighsStatus writeModel(string filename) - { - return (HighsStatus)HighsLpSolver.Highs_writeModel(this.highs, filename); - } - - public HighsStatus writePresolvedModel(string filename) - { - return (HighsStatus)HighsLpSolver.Highs_writePresolvedModel(this.highs, filename); - } - - public HighsStatus writeSolutionPretty(string filename) - { - return (HighsStatus)HighsLpSolver.Highs_writeSolutionPretty(this.highs, filename); - } - - public Double getInfinity() - { - return (Double)HighsLpSolver.Highs_getInfinity(this.highs); - } - - public HighsStatus passLp(HighsModel model) - { - return (HighsStatus)HighsLpSolver.Highs_passLp( - this.highs, - model.colcost.Length, - model.rowlower.Length, - model.avalue.Length, - (int)model.a_format, - (int)model.sense, - model.offset, - model.colcost, - model.collower, - model.colupper, - model.rowlower, - model.rowupper, - model.astart, - model.aindex, - model.avalue); - } - - public HighsStatus passMip(HighsModel model) - { - return (HighsStatus)HighsLpSolver.Highs_passMip( - this.highs, - model.colcost.Length, - model.rowlower.Length, - model.avalue.Length, - (int)model.a_format, - (int)model.sense, - model.offset, - model.colcost, - model.collower, - model.colupper, - model.rowlower, - model.rowupper, - model.astart, - model.aindex, - model.avalue, - model.highs_integrality); - } - - public HighsStatus passHessian(HighsHessian hessian) - { - return (HighsStatus)HighsLpSolver.Highs_passHessian( - this.highs, - hessian.dim, - hessian.qvalue.Length, - (int)hessian.q_format, - hessian.qstart, - hessian.qindex, - hessian.qvalue); - } - - public HighsStatus setOptionValue(string option, string value) - { - return (HighsStatus)HighsLpSolver.Highs_setOptionValue(this.highs, option, value); - } - - public HighsStatus setStringOptionValue(string option, string value) - { - return (HighsStatus)HighsLpSolver.Highs_setStringOptionValue(this.highs, option, value); - } - - public HighsStatus setBoolOptionValue(string option, int value) - { - return (HighsStatus)HighsLpSolver.Highs_setBoolOptionValue(this.highs, option, value); - } - - public HighsStatus setDoubleOptionValue(string option, double value) - { - return (HighsStatus)HighsLpSolver.Highs_setDoubleOptionValue(this.highs, option, value); - } - - public HighsStatus setIntOptionValue(string option, int value) - { - return (HighsStatus)HighsLpSolver.Highs_setIntOptionValue(this.highs, option, value); - } - - public HighsStatus getStringOptionValue(string option, out string value) - { - var stringBuilder = new StringBuilder(); - var result = (HighsStatus)HighsLpSolver.Highs_getStringOptionValue(this.highs, option, stringBuilder); - value = stringBuilder.ToString(); - return result; - } - - public HighsStatus getBoolOptionValue(string option, out int value) - { - return (HighsStatus)HighsLpSolver.Highs_getBoolOptionValue(this.highs, option, out value); - } - - public HighsStatus getDoubleOptionValue(string option, out double value) - { - return (HighsStatus)HighsLpSolver.Highs_getDoubleOptionValue(this.highs, option, out value); - } - - public HighsStatus getIntOptionValue(string option, out int value) - { - return (HighsStatus)HighsLpSolver.Highs_getIntOptionValue(this.highs, option, out value); - } - - public int getNumCol() - { - return HighsLpSolver.Highs_getNumCol(this.highs); - } - - public int getNumRow() - { - return HighsLpSolver.Highs_getNumRow(this.highs); - } - - public int getNumNz() - { - return HighsLpSolver.Highs_getNumNz(this.highs); - } - - public HighsSolution getSolution() - { - int nc = this.getNumCol(); - int nr = this.getNumRow(); - - HighsSolution sol = new HighsSolution(nc, nr); - HighsLpSolver.Highs_getSolution(this.highs, sol.colvalue, sol.coldual, sol.rowvalue, sol.rowdual); - - return sol; - } - - public HighsBasis getBasis() - { - int nc = this.getNumCol(); - int nr = this.getNumRow(); - - int[] colbasstat = new int[nc]; - int[] rowbasstat = new int[nr]; - - HighsLpSolver.Highs_getBasis(this.highs, colbasstat, rowbasstat); - HighsBasis bas = new HighsBasis( - colbasstat.Select(x => (HighsBasisStatus)x).ToArray(), - rowbasstat.Select(x => (HighsBasisStatus)x).ToArray()); - - return bas; - } - - public double getObjectiveValue() - { - return HighsLpSolver.Highs_getObjectiveValue(this.highs); - } - - public HighsModelStatus GetModelStatus() - { - return (HighsModelStatus)HighsLpSolver.Highs_getModelStatus(this.highs); - } - - public int getIterationCount() - { - return HighsLpSolver.Highs_getIterationCount(this.highs); - } - - public HighsStatus addRow(double lower, double upper, int[] indices, double[] values) - { - return (HighsStatus)HighsLpSolver.Highs_addRow(this.highs, lower, upper, indices.Length, indices, values); - } - - public HighsStatus addRows(double[] lower, double[] upper, int[] starts, int[] indices, double[] values) - { - return (HighsStatus)HighsLpSolver.Highs_addRows(this.highs, lower.Length, lower, upper, indices.Length, starts, indices, values); - } - - public HighsStatus addCol(double cost, double lower, double upper, int[] indices, double[] values) - { - return (HighsStatus)HighsLpSolver.Highs_addCol(this.highs, cost, lower, upper, indices.Length, indices, values); - } - - public HighsStatus addCols(double[] costs, double[] lower, double[] upper, int[] starts, int[] indices, double[] values) - { - return (HighsStatus)HighsLpSolver.Highs_addCols( - this.highs, - costs.Length, - costs, - lower, - upper, - indices.Length, - starts, - indices, - values); - } - - public HighsStatus changeObjectiveSense(HighsObjectiveSense sense) - { - return (HighsStatus)HighsLpSolver.Highs_changeObjectiveSense(this.highs, (int)sense); - } - - public HighsStatus changeColCost(int col, double cost) - { - return (HighsStatus)HighsLpSolver.Highs_changeColCost(this.highs, col, cost); - } - - public HighsStatus changeColsCostBySet(int[] cols, double[] costs) - { - return (HighsStatus)HighsLpSolver.Highs_changeColsCostBySet(this.highs, cols.Length, cols, costs); - } - - public HighsStatus changeColsCostByMask(bool[] mask, double[] cost) - { - return (HighsStatus)HighsLpSolver.Highs_changeColsCostByMask(this.highs, mask.Select(x => x ? 1 : 0).ToArray(), cost); - } - - public HighsStatus changeColBounds(int col, double lower, double upper) - { - return (HighsStatus)HighsLpSolver.Highs_changeColBounds(this.highs, col, lower, upper); - } - - public HighsStatus changeColsBoundsByRange(int from, int to, double[] lower, double[] upper) - { - return (HighsStatus)HighsLpSolver.Highs_changeColsBoundsByRange(this.highs, from, to, lower, upper); - } - - public HighsStatus changeColsBoundsBySet(int[] cols, double[] lower, double[] upper) - { - return (HighsStatus)HighsLpSolver.Highs_changeColsBoundsBySet(this.highs, cols.Length, cols, lower, upper); - } - - public HighsStatus changeColsBoundsByMask(bool[] mask, double[] lower, double[] upper) - { - return (HighsStatus)HighsLpSolver.Highs_changeColsBoundsByMask(this.highs, mask.Select(x => x ? 1 : 0).ToArray(), lower, upper); - } - - public HighsStatus changeRowBounds(int row, double lower, double upper) - { - return (HighsStatus)HighsLpSolver.Highs_changeRowBounds(this.highs, row, lower, upper); - } - - public HighsStatus changeRowsBoundsByRange(int from, int to, double[] lower, double[] upper) - { - return (HighsStatus)HighsLpSolver.Highs_changeRowsBoundsByRange(this.highs, from, to, lower, upper); - } - - public HighsStatus changeRowsBoundsBySet(int[] rows, double[] lower, double[] upper) - { - return (HighsStatus)HighsLpSolver.Highs_changeRowsBoundsBySet(this.highs, rows.Length, rows, lower, upper); - } - - public HighsStatus changeRowsBoundsByMask(bool[] mask, double[] lower, double[] upper) - { - return (HighsStatus)HighsLpSolver.Highs_changeRowsBoundsByMask(this.highs, mask.Select(x => x ? 1 : 0).ToArray(), lower, upper); - } - - public HighsStatus changeColsIntegralityByRange(int from_col, int to_col, HighsIntegrality[] integrality) - { - return (HighsStatus)HighsLpSolver.Highs_changeColsIntegralityByRange(this.highs, from_col, to_col, Array.ConvertAll(integrality, item => (int)item)); - } - - public HighsStatus changeCoeff(int row, int col, double value) - { - return (HighsStatus)HighsLpSolver.Highs_changeCoeff(this.highs, row, col, value); - } - - public HighsStatus deleteColsByRange(int from, int to) - { - return (HighsStatus)HighsLpSolver.Highs_deleteColsByRange(this.highs, from, to); - } - - public HighsStatus deleteColsBySet(int[] cols) - { - return (HighsStatus)HighsLpSolver.Highs_deleteColsBySet(this.highs, cols.Length, cols); - } - - public HighsStatus deleteColsByMask(bool[] mask) - { - return (HighsStatus)HighsLpSolver.Highs_deleteColsByMask(this.highs, mask.Select(x => x ? 1 : 0).ToArray()); - } - - public HighsStatus deleteRowsByRange(int from, int to) - { - return (HighsStatus)HighsLpSolver.Highs_deleteRowsByRange(this.highs, from, to); - } - - public HighsStatus deleteRowsBySet(int[] rows) - { - return (HighsStatus)HighsLpSolver.Highs_deleteRowsBySet(this.highs, rows.Length, rows); - } - - public HighsStatus deleteRowsByMask(bool[] mask) - { - return (HighsStatus)HighsLpSolver.Highs_deleteRowsByMask(this.highs, mask.Select(x => x ? 1 : 0).ToArray()); - } - - delegate int HighsGetInfoDelegate(IntPtr highs, string infoName, out TValue output); - - private TValue GetValueOrFallback(HighsGetInfoDelegate highsGetInfoDelegate, string infoName, TValue fallback) - { - try - { - var status = (HighsStatus)highsGetInfoDelegate(this.highs, infoName, out var value); - if (status != HighsStatus.kOk) - { - return fallback; - } - - return value; - } - catch - { - return fallback; - } - } - - /// - /// Gets the current solution info. - /// - /// The . - public SolutionInfo getInfo() - { - // TODO: This object does not contian the "complete" info from the C api. Add further props, if you need them. - var info = new SolutionInfo() - { - MipGap = this.GetValueOrFallback(HighsLpSolver.Highs_getDoubleInfoValue, "mip_gap", double.NaN), - DualBound = this.GetValueOrFallback(HighsLpSolver.Highs_getDoubleInfoValue, "mip_dual_bound", double.NaN), - ObjectiveValue = this.GetValueOrFallback(HighsLpSolver.Highs_getDoubleInfoValue, "objective_function_value", double.NaN), - NodeCount = this.GetValueOrFallback(HighsLpSolver.Highs_getInt64InfoValue, "mip_node_count", 0L), - IpmIterationCount = this.GetValueOrFallback(HighsLpSolver.Highs_getIntInfoValue, "ipm_iteration_count", 0), - SimplexIterationCount = this.GetValueOrFallback(HighsLpSolver.Highs_getIntInfoValue, "simplex_iteration_count", 0), - PdlpIterationCount = this.GetValueOrFallback(HighsLpSolver.Highs_getIntInfoValue, "pdlp_iteration_count", 0), - }; - return info; - } - - public HighsStatus setSolution(HighsSolution solution) - { - return (HighsStatus)HighsLpSolver.Highs_setSolution(this.highs, solution.colvalue, solution.rowvalue, solution.coldual, solution.rowdual); - } - - /// Set a partial primal solution by passing values for a set of variables - /// A dictionary that maps variable indices to variable values - /// The sparse solution set by this function has values for a subset of the model's variables. - /// For each entry in , the key identifies a variable by index, and - /// the value indicates the variable's value in the sparse solution. - /// A constant indicating whether the call succeeded - public HighsStatus setSparseSolution(IReadOnlyDictionary valuesByIndex) - { - return (HighsStatus)Highs_setSparseSolution(this.highs, valuesByIndex.Count, valuesByIndex.Keys.ToArray(), valuesByIndex.Values.ToArray()); - } - - public HighsStatus getBasicVariables(ref int[] basic_variables) - { - return (HighsStatus)Highs_getBasicVariables(this.highs, basic_variables); - } - - public HighsStatus getBasisInverseRow(int row, double[] row_vector, ref int row_num_nz, int[] row_indices) - { - return (HighsStatus)Highs_getBasisInverseRow(this.highs, row, row_vector, ref row_num_nz, row_indices); - } - - public HighsStatus getBasisInverseCol(int col, double[] col_vector, ref int col_num_nz, int[] col_indices) - { - return (HighsStatus)Highs_getBasisInverseCol(this.highs, col, col_vector, ref col_num_nz, col_indices); - } - - public HighsStatus getBasisSolve(double[] rhs, double[] solution_vector, ref int solution_num_nz, int[] solution_indices) - { - return (HighsStatus)Highs_getBasisSolve(this.highs, rhs, solution_vector, ref solution_num_nz, solution_indices); - } - - public HighsStatus getBasisTransposeSolve(double[] rhs, double[] solution_vector, ref int solution_num_nz, int[] solution_indices) - { - return (HighsStatus)Highs_getBasisTransposeSolve(this.highs, rhs, solution_vector, ref solution_num_nz, solution_indices); - } - - public HighsStatus getReducedRow(int row, double[] row_vector, ref int row_num_nz, int[] row_indices) - { - return (HighsStatus)Highs_getReducedRow(this.highs, row, row_vector, ref row_num_nz, row_indices); - } - - public HighsStatus getReducedColumn(int col, double[] col_vector, ref int col_num_nz, int[] col_indices) - { - return (HighsStatus)Highs_getReducedColumn(this.highs, col, col_vector, ref col_num_nz, col_indices); - } - - public HighsStatus clearModel() - { - return (HighsStatus)Highs_clearModel(this.highs); - } - - public HighsStatus clearSolver() - { - return (HighsStatus)Highs_clearSolver(this.highs); - } - - public HighsStatus passColName(int col, string name) - { - return (HighsStatus)Highs_passColName(this.highs, col, name); - } - - public HighsStatus passRowName(int row, string name) - { - return (HighsStatus)Highs_passRowName(this.highs, row, name); - } - - public HighsStatus writeOptions(string filename) - { - return (HighsStatus)Highs_writeOptions(this.highs, filename); - } - - public HighsStatus writeOptionsDeviations(string filename) - { - return (HighsStatus)Highs_writeOptionsDeviations(this.highs, filename); - } -} - -/// -/// The solution info. -/// -public class SolutionInfo -{ - /// - /// Gets or sets the simplex iteration count. - /// - public int SimplexIterationCount { get; set; } - - /// - /// Gets or sets the Interior Point Method (IPM) iteration count. - /// - public int IpmIterationCount { get; set; } - - /// - /// Gets or sets the PDLP iteration count. - /// - public int PdlpIterationCount { get; set; } - - /// - /// Gets or sets the MIP gap. - /// - public double MipGap { get; set; } - - /// - /// Gets or sets the best dual bound. - /// - public double DualBound { get; set; } - - /// - /// Gets or sets the MIP node count. - /// - public long NodeCount { get; set; } - - /// - /// Gets or sets the objective value. - /// - public double ObjectiveValue { get; set; } -} -}