How to use HiGHS solver ?

216 views
Skip to first unread message

タマキ/環耀の数学

unread,
Mar 10, 2023, 11:58:10 PM3/10/23
to OPTANO Modeling
Hello, I am a new OPTANO.Modeling user in Japan.

I have a basic question. I installed HiGHS solver v.1.4.2 following indications in  Get started in C++ · HiGHS Documentation (ergo-code.github.io). And I want to solve a LP below. But I get "System.DllNotFoundException: 'Unable to load DLL 'libhighs' or one of its dependencies:". How do I resolve this ?

My setup is:
- VS 2022
- Windows 10 64 bit
- OPTANO.Modeling" Version="3.15.1.588"
- .NET 6.0

using System.Diagnostics;
using OPTANO.Modeling.Optimization;
using OPTANO.Modeling.Optimization.Enums;
using OPTANO.Modeling.Optimization.Solver.Highs14x;

namespace demo
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var scope = new ModelScope())
            {
                var model = new Model();
                var x = new Variable("x");
                var y = new Variable("y");
                model.AddConstraint(1.5 * x + 3 * y <= 13.5);
                model.AddConstraint(3 * x + y <= 10);
                model.AddConstraint(x + 2 * y >= 7);
                var objective = new Objective(5 * x + 4 * y);
                objective.Sense = ObjectiveSense.Maximize;
                model.AddObjective(objective);

                using (var solver = new HighsSolver14x())
                {
                    var solution = solver.Solve(model);
                }
            }
        }
    }
}

Jannick Lange

unread,
Mar 11, 2023, 2:16:48 AM3/11/23
to OPTANO Modeling
Hello!

Here are a couple of steps that I used to get the HiGHS Solver up and running on my machine:

  • Download the pre-compiled binaries here.
    • Windows: if in doubt, choose the file ending in x86_64-w64-mingw32-cxx11.tar.gz.
    • I am not sure, if HiGHS 1.5.x will work with the current OPTANO.Modeling.HiGHS Adapter. I only tested/verified version 1.4.2
  • Download the compiler support libraries.
    • I only tested/used the linked version. Feel free to use/test a more recent release.
    • Use 7-zip to unpack the .gz and then the .tar package.
  • Copy the DLLs from CompilerSupportLbrariesXYZ/bin into the bin folder of the HiGHS package.
    • Open the CMD and call highs --help to make sure that all required DLLs are present.
  • Either add all DLLs from the HiGHS binary folder as resources to your project and set them to Copy always/if newer, or add the bin folder to your PATH variable

I hope this helps! Please let us know, if you need further assistance/tips.

Best Regards,
Jannick

タマキ/環耀の数学

unread,
Mar 13, 2023, 2:33:28 AM3/13/23
to OPTANO Modeling
Your instructions make the HiGHS solver run in the above VS2022 project, thank you !

But then, I got some new problems in the project.
  • Variable x is constructed with name = "x", so I expected x.Name == "x", but actually x.Name == "A". The same thing happens to Variable y constructed with name = "y" resulting y.Name == "B". Why this happen ?
2023年3月11日土曜日 16:16:48 UTC+9 Jannick Lange:

Jannick Lange

unread,
Mar 13, 2023, 4:39:45 AM3/13/23
to OPTANO Modeling
You're welcome!

It seems as though you're running the model with NameHandling set to "UniqueShortNames" (which is the default value). There are 3 different settings available:
You can set the value in the ModelScope-Configuration:

var scopeConfig = new Configuration() { NameHandling = NameHandlingStyle.Manual };
using (var scope = new ModelScope(scopeConfig))
{
    // ...
}

Best Regards,
Jannick

タマキ/環耀の数学

unread,
Mar 13, 2023, 5:27:28 AM3/13/23
to OPTANO Modeling
Hello, Jannick. I have additional questions to you.

I made a following new program to solve 2 LP models (say, 0th, 1st).
I think it is inefficient to construct a HiGHS solver instance per each LP model.
So, I made a sole HiGHS solver instance at the upper part of the program and used it to solve the 0th, 1st LP models serially.
But I get "System.NullReferenceException: 'Object reference not set to an instance of an object.'" at the 1st solving (red bold line).

Additionaly, I want to stop the solver instance to output its log to console during solving a model.
So, I specified a HiGHS solver configration setting 'LogToConsole=false', but it doesn't work as I expected (blue bold line).

My questions are:
  • Is it impossible to use a single HiGHS solver instance to solve at least 2 different models ? Do I have to initialize a solver instance per each model with different constraints to solve it ?
  • Is it possible to make solver instance "quiet" during solving a model ?
Thank you for your kind support !

-------------------- Program.cs --------------------
using OPTANO.Modeling.Common;
using OPTANO.Modeling.Optimization;
using OPTANO.Modeling.Optimization.Enums;
using OPTANO.Modeling.Optimization.Configuration;
using OPTANO.Modeling.Optimization.Solver;

using OPTANO.Modeling.Optimization.Solver.Highs14x;

namespace demo
{
    class Program
    {
        static void Main(string[] args)
        {
            var scopeConfig = new Configuration() { NameHandling=NameHandlingStyle.Manual};
            var solverConfig = new HighsSolverConfiguration14x() { LogToConsole=false, Solver="ipm" };

            using (var scope = new ModelScope(scopeConfig))
            using (var solver = new HighsSolver14x(solverConfig))

            {
                var model = new Model();
                var x = new Variable("x", 0, double.PositiveInfinity, VariableType.Continuous);
                var y = new Variable("y", 0, double.PositiveInfinity, VariableType.Continuous);
                void showModel(int index)
                {
                    Console.WriteLine("\n---------- LP index = {0} ----------", index);
                    model.Objectives.ForEach(ob => Console.WriteLine(ob.Sense == ObjectiveSense.Minimize ? "Minimize: {0}": "Maximize {0}", ob.Expression));
                    Console.WriteLine("Constraints:");
                    model.Constraints.ForEach(cn => Console.WriteLine("    {0}", cn.ToString()));
                }
                void showSolution(Solution solution)
                {
                    if (solution.Status == SolutionStatus.Optimal)
                    {
                        Console.WriteLine("Optimal Solution:");
                        model.VariableCollections.ForEach(vc => vc.SetVariableValues(solution.VariableValues));
                        Console.WriteLine("    ({0}, {1}) = ({2}, {3})", x.Name, y.Name, x.Value, y.Value);
                    }
                }
                // 0th LP
                var objective_0 = new Objective(x + y);
                objective_0.Sense = ObjectiveSense.Minimize;
                model.AddObjective(objective_0);
                model.AddConstraint(3 <= x + 2 * y);
                model.AddConstraint(3 <= 2 * x + y);
                showModel(0);
                var solution_0 = solver.Solve(model);
                showSolution(solution_0);
                model.Clear();
                // 1st LP
                var objective_1 = new Objective(2 * x + y);
                objective_1.Sense = ObjectiveSense.Maximize;
                model.AddObjective(objective_1);
                model.AddConstraint(1 <= x + y);
                showModel(1);
                var solution_1 = solver.Solve(model);
                showSolution(solution_1);
                model.Clear();
            }
        }
    }
}

2023年3月13日月曜日 17:39:45 UTC+9 Jannick Lange:

Jannick Lange

unread,
Mar 14, 2023, 1:14:19 PM3/14/23
to OPTANO Modeling
Hello!

The LogToConsole-Setting only seems to disable the output of the actual solving process. This behavior is not implemented by OPTANO.Modeling. We only set the parameter.
Maybe you can create a change request in the HiGHS HitHub forum: https://github.com/ERGO-Code/HiGHS/issues

Unfortunately, it seems as though the current HiGHS Adapter runs into an error when (re-)solving a 2nd model. The easiest way to circumvent this error is to simply initialize a new solver adapter when re-solving your model. This is also the suggested workaround.
Also, creating a 2nd model will most likely be more efficient, since you are not really modifying your existing formulation, but completely clear/purge the old data anyway.

If you really want to re-use the old adapter, you can use the following "hack", where the failing method is wrapped in a try/catch block:

public class CustomHighsSolver : HighsSolver14x
{
public override void ClearLastModel()
{
try
{
base.ClearLastModel();
}
catch (HighsWrapper14x.HighsSolverException)
{
// nothing
}

this.HighsModel = new HighsWrapper14x.HighsModel
  {
  colcost = Array.Empty<double>(),
  rowlower = Array.Empty<double>(),
  avalue = Array.Empty<double>()
  };
var status = this.HighsSolver.passMip(this.HighsModel);
if (status == HighsWrapper14x.HighsStatus.kError)
{
var error = $"HiGHS encountered an error. Status: {status}";
Console.WriteLine(error);
throw new HighsWrapper14x.HighsSolverException(error);
}
}
}

Best Regards,
Jannick

Jannick Lange

unread,
Mar 23, 2023, 11:37:06 AM3/23/23
to OPTANO Modeling
Hello again!

I just wanted to let you know that I was mistaken, when I said that the config-parameter log lines are produced my HiGHS itself.
They are actually printed by OPTANO.Modeling. I'm sorry about that.
We just released a new preview package, that should fix this issue. Now, Modeling will only print the parameter values that deviate from the HiGHS default value, while the Configuration.LogToConsole is set to true:

Best Regards
Jannick

タマキ/環耀の数学

unread,
Mar 24, 2023, 10:15:27 AM3/24/23
to OPTANO Modeling
Jannick, thank you for your new preview package !

I tried it to solve randomly generated LPs below. Now, LogToConsole=false makes annoying logs quiet, and I can reuse a sole HiGHS solver instance to solve LPs serially.

But, if I set solver to use internal point method instead of simplex method by specifying Solver="ipm" in the solver config, sometimes logs appear to console (red bold line).
And, even when LogToConsole=false, I still get these 4 lines in my console,

Normalizing all Expressions before Transforming the Model...
Normalizing 4 Constraints...
Normalizing OperatorConstraints...
Normalizing Objectives...

Especially, at the 1st solving I get these 2 lines,

Running HiGHS 1.4.2 [date: 1970-01-01, git hash: f797c1ab6]
Copyright (c) 2022 ERGO-Code under MIT licence terms

If possible, I want also to make these lines completely quiet, to use LP solvers as subloutines of my console programs.

Anyway, thank you for your kind support !


-------------------- Program.cs --------------------
using OPTANO.Modeling.Common;
using OPTANO.Modeling.Optimization;
using OPTANO.Modeling.Optimization.Enums;
using OPTANO.Modeling.Optimization.Configuration;
using OPTANO.Modeling.Optimization.Solver;
using OPTANO.Modeling.Optimization.Solver.Highs14x;

namespace demo
{
    class Program
    {
        static void Main(string[] args)
        {
            RandomLp();
        }
        static void RandomLp()
        {
            var scopeConfig = new Configuration() { NameHandling=NameHandlingStyle.Manual, CopySolutionToModel=true };

            var solverConfig = new HighsSolverConfiguration14x() { LogToConsole=false, Solver="ipm" };
            using (var scope = new ModelScope(scopeConfig))
            using (var solver = new HighsSolver14x(solverConfig))
            {
                var x = new Variable("x");
                var y = new Variable("y");
                var z = new Variable("z");
                int lpCount = 10;
                int cnCount = 4;
                int coefRange = 5;
                int constRange = 10;
                Random r = new Random();
                int rSign() => (r.Next(0, 2) % 2 == 0) ? 1 : -1;
                int rCoef() => rSign() * r.Next(1, coefRange + 1);
                int rConst() => rSign() * r.Next(1, constRange + 1);
                ObjectiveSense rObSense() => (r.Next(0, 2) % 2 == 0) ? ObjectiveSense.Minimize : ObjectiveSense.Maximize;
                void showLP(Model lp)
                {
                    Console.WriteLine("\n---------- {0} ----------", lp.Name);
                    Console.WriteLine("Variables:");
                    lp.Variables.ForEach(v => Console.WriteLine("    {0} <= {1} <= {2}", v.LowerBound, v.Name, v.UpperBound));
                    lp.Objectives.ForEach(ob => Console.WriteLine(ob.Sense == ObjectiveSense.Minimize ? "Minimize: {0}" : "Maximize {0}", ob.Expression));
                    Console.WriteLine("Constraints:");
                    lp.Constraints.ForEach(cn => Console.WriteLine("    {0}", cn.ToString()));
                }
                void showSol(Solution sol, Model lp)
                {
                    if (sol.Status == SolutionStatus.Optimal)
                    {
                        Console.WriteLine("Optimal Solution:");
                        //lp.VariableCollections.ForEach(vc => vc.SetVariableValues(sol.VariableValues));
                        lp.Variables.ForEach(v => Console.WriteLine("    {0} = {1}", v.Name, v.Value));
                    }
                    else
                    {
                        Console.WriteLine(sol.ModelStatus == ModelStatus.Infeasible ? "Infeasible Region." : sol.ModelStatus == ModelStatus.Unbounded ? "Unbounded Solution." : "");
                    }
                }
                for (int lpIdx = 0; lpIdx < lpCount; lpIdx++)
                {
                    var lp = new Model("LP_" + lpIdx.ToString());
                    for (int cnIdx = 0; cnIdx < cnCount; cnIdx++)
                    {
                        lp.AddConstraint(rCoef() * x + rCoef() * y + rCoef() * z <= rConst());
                    }
                    var ob = new Objective(rCoef() * x + rCoef() * y + rCoef() * z);
                    ob.Sense = rObSense();
                    lp.AddObjective(ob);
                    showLP(lp);
                    var sol = solver.Solve(lp);
                    showSol(sol, lp);
                    solver.ClearLastModel();
                }
            }
        }
    }
}

2023年3月24日金曜日 0:37:06 UTC+9 Jannick Lange:

OPTANO Team

unread,
Mar 24, 2023, 12:36:29 PM3/24/23
to OPTANO Modeling
Hi 

we are going to discuss, if we should collect solver's output when in silent mode. Might be a feature of a future version (and might be considered bad style)

As a workaround you might use this code

Console.WriteLine("Hello, World!"); // will print to console
var myFile = new FileStream("myFile.txt", FileMode.Create);
Console.SetOut( new StreamWriter(myFile)); // reassign output
for (int i = 0; i < 1000; i++)
{
    Console.WriteLine("Hello, World_!"); // will print to file myfile.txt only. 
}
myFile.Close(); // don't forget to close, you might loose latest output otherwise

タマキ/環耀の数学

unread,
Mar 25, 2023, 4:28:44 AM3/25/23
to OPTANO Modeling
Hi, OPTANO Team.

In python pulp module, we can disable logs ( python - How to disable the calculations log of pulp - Stack Overflow).
I simply wanted similar functionality implemented to OPTANO.Modeling, since silent mode is suitable when we need only optimization results which are accessible by variable instances (e.g. x.Value, y.Value, ...) and use these results in some subroutines.

To be more specific, I use LPs as subroutines to calculate directions which improve values of some quasiconvex functions, whose gradients cannot be computed since it is not generally differentiable.
Quasiconvex programming appears in Spherical Graph Drawing, Hyperbolic browsing, etc... (arXiv:cs/0101006v2 [cs.CG] 1 Feb 2001), which are I'm going to implement in my projects.
So, I just wanted to see in my console such directions of improvement in debug mode, but solver's logs are too long to see I want to exclude them.

For me, simple 'silent mode' will suffice. 
If it is possible to access in silent mode a feasible solution calculated at the first phase of LP solver's processing and to stop the second optimization phase, I think it is also convenient because sometimes we only need a feasible solution which is computable without objective functions. 
I think someone may need in silent mode internal paths of internal point method or simplex paths of simplex method.

2023年3月25日土曜日 1:36:29 UTC+9 OPTANO Team:
Reply all
Reply to author
Forward
0 new messages