ERGO-Code / HiGHS

Linear optimization software
MIT License
971 stars 179 forks source link

Access from PuLP in Python #527

Closed samiit closed 2 years ago

samiit commented 3 years ago

Hi,

I am very glad to have realized HiGHS solver over the last two weeks, since I see that it performs consistently compared to Cbc and at times does better than it. All that I miss is if I could access it from Python using the nice PuLP modelling language. Is there any work in this regard that I can use or contribute to?

Thanks, Sam

odow commented 3 years ago

Issue for the Python wrapper: https://github.com/ERGO-Code/HiGHS/issues/156

SciPy use HiGHS https://github.com/scipy/scipy/blob/master/scipy/optimize/_linprog_highs.py

There is also a Python wrapper: https://github.com/ERGO-Code/HiGHS/blob/master/src/interfaces/highs_mip_solver.py but it has some problems (hard-coded executable path, for example).

You can pass an MPS file to HiGHS, so that might be an easier first-path if you just ask users to place the binary somewhere.

samiit commented 3 years ago

Thanks, I will try this out.

mckib2 commented 3 years ago

PuLP support and modeling languages in general are not currently on the SciPy optimize.linprog module roadmap, but as @odow mentioned, there is a wrapper built on the HiGHS C++ API and we're planning on adding a HiGHS MIP wrapper in the near future

samiit commented 3 years ago

Thanks for the answers.

While trying to write a PuLP wrapper myself, I am unable to access the different options specified in the options file from the command line. The most important I would be glad for is write_solution_to_file, solution_file and write_solution_pretty. It gives the following error:

sam@sam-laptop:~/$ highs test_lp.mps --time_limit 10 --solution_file

Running HiGHS 1.0.0 [date: 2021-06-14, git hash: 28227cb6]
Copyright (c) 2021 ERGO-Code under MIT licence terms

ERROR:   Error parsing options: Option ‘solution_file’ does not exist

Is there any way that these can be given via the command line?

Thanks, Sam

samiit commented 3 years ago

Hi,

I solved the above problem by creating a temporary options file and get the most important things in it to run and obtain a solution file. But I am faced with another problem.

When trying to run HiGHS using subprocess.call in Python, I am getting a non-zero return code (1) even though there is a feasible solution. It seems HiGHS run on the command line returns 0 only if it could find an optimal solution. I still managed to process the stdout and get the Solution status, but it has been a challenge to get the output of HiGHS written to a log file while also displaying it in the stdout. It would be helpful if there is any way to get the Solution status and Model status while running HiGHS through subprocess.call or subprocess.run

Thanks, Sam

mckib2 commented 3 years ago

I'm not familiar enough with what you're trying to do to recommend any solutions, but if you're comfortable modifying the code, you can almost certainly do what you need by modifying the HiGHS runner

samiit commented 3 years ago

Thanks @mckib2 for your answer. Before I modify the HiGHS runner, let me share the problem in more detail, just in case it lights up some paths to tread! Here is a minimal Python code and a corresponding MPS file to run on

import subprocess as sb

highs_loc = "/home/user/HiGHS/"

highs_exec = highs_loc + "build/bin/highs"
mps_file = highs_loc + 'check/instances/bell5.mps'

max_time = 0.1
time_limit = f"--time_limit {max_time}"

highs_cmd = " ".join( [highs_exec, mps_file, time_limit] )

proc = sb.Popen(highs_cmd.split(), stdout=None, stderr=None)

print( "Return code for the process: ", proc.wait() )

The point I am trying to make is that within the max_time, HiGHS has found the best solution it could, although it is not the optimal. This is reflected in the Highs.log generated in the same folder. But why does the process (HiGHS) solver return 1, instead of 0? Is this intended that if the maximum time is reached then the process is considered to be terminated with errors?

I hope I could make myself more understandable and would appreciate some feedback on this.

Best regards, Sam

mckib2 commented 3 years ago

The HiGHS runner is returning the Highs.run() return code, which for a timeout will be nonzero. So yes, I believe the intended behavior is to return that value instead of 0 if maximum time is reached. There's an older discussion in https://github.com/ERGO-Code/HiGHS/issues/324 about retrieving a solution in the case of a "stepout" or timeout, but generally a solution is not available so no solution will be returned

samiit commented 3 years ago

Thanks for that answer @mckib2

I see that HiGHS then seems to be different when compared to other solvers like Cplex, Gurobi and Cbc, which all return 0 if the solver ran and got to some level of optimality within the time or iteration constraints! But surely the developers have thought long enough about it.

So, I had to add conditions for HiGHS specific scenarios when the return code is non-zero and I managed to even retrieve the solution file which I can get back into PuLP for further processing. And I must admit that HiGHS is beating Cbc big time (also that it gives consistent results). I will be making this available soon. If there is nothing more from your side or other developers, we may close this issue. I will put the link to my code in the next few days here in this thread.

Thanks and warm regards, Sam

jajhall commented 3 years ago

Hi Sam. Thanks for your interest, and thanks @odow and @mckib2 for your contributions to this thread - I've been on holiday for a week.

It does look as if the HiGHS runner has given you the functionality that you require but, if not, or you need more, please let us know.

For the HiGHS Python API, I fixed the failure to return model or run status correctly yesterday, but it's not yet in the master branch. As for reaching the time/iteration limit leading to a return status of 1, this is the "warning" value in master. An error return would be 2. We've recognised that this is inconsistent with C convention so, in our first formal release, error is -1 and warning (still) 1. HiGHS is also returning a primal and dual solution (if it can) when the model status is not optimal.

Interested to read your comments about performance relative to Cbc. Yes, we've left Cbc lying in the dust, and there's more performance improvement coming.

If you've got the time, you can help us out since no one in the HiGHS team really knows much about Python.

samiit commented 3 years ago

Hi @jajhall

Hope you had a nice week. I am done with the PuLP interface for HiGHS which just makes me more efficient to use it on a variety of problems within Python. I will try to add it to their repo if they accept my PR.

There is only one bottle-neck I am facing for now, to package the HiGHS executable! Of course we can ask the users to download the HiGHS code and compile at their end and share the path to the executable in the PuLP interface, but this may dissuade people from quickly using it. Any suggestions to package the HiGHS executable that is created in the /build/bin folder?

Thanks, Sam

mckib2 commented 3 years ago

There is only one bottle-neck I am facing for now, to package the HiGHS executable! Of course we can ask the users to download the HiGHS code and compile at their end and share the path to the executable in the PuLP interface, but this may dissuade people from quickly using it. Any suggestions to package the HiGHS executable that is created in the /build/bin folder?

SciPy vendors the HiGHS repo and compiles/links using the numpy.distutils package (see the setup.py file). We build SciPy binaries for many target platforms/architectures and provide those via pypi. The Julia library seems to have a binary distribution system that similarly provides precompiled binaries for many systems.

If you wish to have a standalone installation that doesn't require users to compile HiGHS, there are a couple of options:

odow commented 3 years ago

Currently the HiGHS_jll build doesn't include the executable, just the C shared library. Unfortunately you can't just copy-paste the binaries from a JLL because they may need additional dependencies. People are think of ways to make this work from python etc, but it's a thing for the future, not right now.

The easiest way for now might be to compile three generic windows/linux/Mac binaries and host them here, then tell people to just download the binaries? Even just a windows binary would probably be enough. Linux/Mac people can probably compile their own.

odow commented 3 years ago

@samiit there are binaries available now: https://github.com/ERGO-Code/HiGHS/issues/557#issuecomment-894559097. But I've only confirmed they work independently of Julia on Linux. Need some debugging on Mac and testing on Windows.

samiit commented 3 years ago

@odow that is great to know. Just this was putting me off from a PR on PuLP for the HiGHS solver. Otherwise, I had a hard time on Windows to compile HiGHS using MSYS2. In any case, I can share the HiGHS interface through PuLP independently, asking the users to install HiGHS on their machine.

Sam

odow commented 3 years ago

Did you try the windows binaries?

You probably need this one: https://github.com/JuliaBinaryWrappers/HiGHS_jll.jl/releases/download/HiGHS-v0.3.3%2B0/HiGHS.v0.3.3.x86_64-w64-mingw32-cxx11.tar.gz

asking the users to install HiGHS on their machine.

Yeah I think asking them to grab HiGHS_jll is fine. Since we need them for HiGHS.jl, I'll make sure that they stay up-to-date.

samiit commented 3 years ago

I am not so experienced with fork -> PR and the steps that follow, so in case it helps others, please find the python code that you would need to place in the PuLP's package location, e.g., /home/sam/anaconda3/envs/Optimization/lib/python3.8/site-packages/pulp/apis/

# PuLP : Python LP Modeler
# Version 2.4

# Copyright (c) 2002-2005, Jean-Sebastien Roy (js@jeannot.org)
# Modifications Copyright (c) 2007- Stuart Anthony Mitchell (s.mitchell@auckland.ac.nz)
# $Id:solvers.py 1791 2008-04-23 22:54:34Z smit023 $

# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:

# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."""

# Modified by Sam Mathew (@samiit on Github)
# Users would need to install HiGHS on their machine and provide the path to the executable. Please look at this thread: https://github.com/ERGO-Code/HiGHS/issues/527#issuecomment-894852288
# More instructions on: https://www.highs.dev

from .core import LpSolver_CMD, subprocess, PulpSolverError
import os, sys
from .. import constants
import warnings

class HiGHS_CMD(LpSolver_CMD):
    """The HiGHS_CMD solver"""
    name = 'HiGHS_CMD'

    def __init__(self, path=None, keepFiles=False, mip=True, msg=True, options=None,  timeLimit=None):
        """
        :param bool mip: if False, assume LP even if integer variables
        :param bool msg: if False, no log is shown
        :param float timeLimit: maximum time for solver (in seconds)
        :param list options: list of additional options to pass to solver
        :param bool keepFiles: if True, files are saved in the current directory and not deleted after solving
        :param str path: path to the solver binary
        """
        LpSolver_CMD.__init__(self, mip=mip, msg=msg, timeLimit=timeLimit,
                              options=options, path=path, keepFiles=keepFiles)

    def defaultPath(self):
        return self.executableExtension("")

    def available(self):
        """True if the solver is available"""
        return self.executable(self.path)

    def actualSolve(self, lp):
        """Solve a well formulated lp problem"""
        if not self.executable(self.path):
            raise PulpSolverError("PuLP: cannot execute " + self.path)
        tmpMps, tmpSol, tmpOptions, tmpLog = self.create_tmp_files(lp.name, 'mps', 'sol', 'HiGHS', 'HiGHS_log')
        write_lines = [f"solution_file = {tmpSol}\n", 
                       "write_solution_to_file = true\n", 
                       "write_solution_pretty = true\n"]
        with open(tmpOptions, "w") as fp: 
            fp.writelines(write_lines)

        if lp.sense == constants.LpMaximize:
            # we swap the objectives
            # because it does not handle maximization.
            warnings.warn('HiGHS_CMD does not currently allow maximization, '
                          'we will minimize the inverse of the objective function.')
            lp += -lp.objective
        lp.checkDuplicateVars()
        lp.checkLengthVars(52)
        lp.writeMPS(tmpMps, mpsSense=lp.sense)

        # just to report duplicated variables:
        try:
            os.remove(tmpSol)
        except:
            pass
        cmd = self.path
        cmd += ' %s' % tmpMps
        cmd += ' --options_file %s' % tmpOptions
        if self.timeLimit is not None:
            cmd += ' --time_limit %s' % self.timeLimit
        for option in self.options:
            cmd += ' ' + option
        if lp.isMIP():
            if not self.mip:
                warnings.warn("HiGHS_CMD cannot solve the relaxation of a problem")
        if self.msg:
            pipe = None
        else:
            pipe = open(os.devnull, 'w')
        lp_status = None
        with subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) as proc, open(tmpLog, "w") as log_file:
            for line in proc.stdout:
                if self.msg: sys.__stdout__.write(line)
                log_file.write(line)

        # We need to undo the objective swap before finishing
        if lp.sense == constants.LpMaximize:
            lp += -lp.objective

        # The return code for HiGHS follows: 0:optimal, 1: Iteration/time limit, 2: Infeasible, 3: Unbounded, 4: Solver error. See the return status here: https://docs.scipy.org/doc/scipy/reference/optimize.linprog-highs.html
        if proc.wait() == 0:
            status = constants.LpStatusOptimal
            status_sol = constants.LpSolutionOptimal
        elif proc.wait() == 1:
            status = constants.LpStatusOptimal # this is following the PuLP convention; in case, there is no feasible solution, the empty solution file will update the status of problem and solution later
            status_sol = constants.LpSolutionIntegerFeasible
        elif proc.wait() == 2:
            status = constants.LpStatusInfeasible
            status_sol = constants.LpSolutionNoSolutionFound
        elif proc.wait() == 3:
            status = constants.LpStatusUnbounded
            status_sol = constants.LpSolutionNoSolutionFound
        elif proc.wait() == 4:
            status = constants.LpStatusNotSolved
            status_sol = constants.LpSolutionNoSolutionFound
        else:
            status = constants.LpStatusUndefined
            status_sol = constants.LpSolutionNoSolutionFound
            raise PulpSolverError("Pulp: Error while executing", self.path)

        if not os.path.exists(tmpSol):
            status = constants.LpStatusNotSolved
            status_sol = constants.LpSolutionNoSolutionFound

        values, status, status_sol = self.readsol(tmpSol, status, status_sol)
        self.delete_tmp_files(tmpMps, tmpSol, tmpOptions, tmpLog)
        lp.assignStatus(status, status_sol)

        if status == constants.LpStatusOptimal:
            lp.assignVarsVals(values)

        return status

    @staticmethod
    def readsol(filename, status, status_sol):
        """Read a HiGHS solution file"""
        if status != constants.LpStatusOptimal:
            values = None
            return values, status, status_sol
        else:
            with open(filename) as f:
                content = f.readlines()
            content = [l.strip() for l in content]
            values = {}
            if not len(content): # if file is empty, update the status_sol
                return values, constants.LpStatusNotSolved, constants.LpSolutionNoSolutionFound
            # extract everything up to the line with Rows
            row_id = content.index("Rows")
            content = content[2:row_id]
            for line in content:
                value, name = line.split()[-2:]
                values[name] = float(value)
            return values, status, status_sol

Additionally, we would need the Windows/Linux binaries which @odow already linked to above.

odow commented 3 years ago

I am not so experienced

I see you managed https://github.com/coin-or/pulp/pull/477 so you're on the right track!

samiit commented 3 years ago

Thanks @odow . I had to overcome some inhibitions.

samiit commented 3 years ago

Did you try the windows binaries?

You probably need this one: https://github.com/JuliaBinaryWrappers/HiGHS_jll.jl/releases/download/HiGHS-v0.3.3%2B0/HiGHS.v0.3.3.x86_64-w64-mingw32-cxx11.tar.gz

asking the users to install HiGHS on their machine.

Yeah I think asking them to grab HiGHS_jll is fine. Since we need them for HiGHS.jl, I'll make sure that they stay up-to-date.

I checked the Windows binaries and they worked fine with different .mps files from the repos' check/instances folder. Besides, I checked them on my own MILP model and I get consistent results. Thanks.

samiit commented 3 years ago

The HiGHS runner is returning the Highs.run() return code, which for a timeout will be nonzero. So yes, I believe the intended behavior is to return that value instead of 0 if maximum time is reached. There's an older discussion in #324 about retrieving a solution in the case of a "stepout" or timeout, but generally a solution is not available so no solution will be returned

Just to be sure, is HiGHS return value along the lines of what scipy returns as status?

statusint

    An integer representing the exit status of the algorithm.

    0 : Optimization terminated successfully.
    1 : Iteration or time limit reached.
    2 : Problem appears to be infeasible.
    3 : Problem appears to be unbounded.
    4 : The HiGHS solver ran into a problem.

I solved an infeasible problem and get a return status in Python as 0. Or does anyone have a suggestion how I can get a suitable return code after running HiGHS on the command line?

Thanks, Sam

jajhall commented 3 years ago

No, the return value when HiGHS is run from the command line is one of

These were based on the conventional "main" return values, indicating the success with which HiGHS has run, but not the status of the model.

I can see that the level of information of 'statusint' is valuable and, more importantly, information that's not available when HiGHS is run from the command line. The 'HighsModelStatus' (an enum class in C++ or collection of integers in the C API) gives this information. The integers run from 0 to 15, covering (in order) the error cases, the success cases and the warning cases. We could shift these so that the error cases are negative, optimality is 0, followed by the other 6 success cases, and then the two warning (time or iteration limit reached). However, this would make (say) "Infeasible" sound like a non-success.

Any views? @lgottwald @galabovaa @feldmeier @mckib2 @odow

samiit commented 3 years ago

Thanks a lot for that clear information.

Unfortunately, I have no way left but to extract the status for Python/PuLP from the HiGHS log file! Will this remain consistent? I see two distinct cases for now:

  1. LP problem I need to extract the Model status : Optimal, Infeasible, ...?
  2. ILP problem I need to extract i) Status : Optimal, Reached time limit, Infeasible, .... ? ii) Solution status: feasible, - ?
samiit commented 3 years ago

By the way, I already had to update the PuLP interface quite a bit, because the solution_file's format has changed quite a bit since Aug '21! Do you plan to change this as well? Sorry but these are the issues that lie ahead when I don't directly integrate with the C/C++ API, and it would be too much for me to get there now.

Thanks for your efforts and looking forward to the teams' response.

Sam

jajhall commented 3 years ago

Sorry for the rug moving under your feet regarding the solution file. We now have a third style of solution file, and had to introduce it in a hurry. We needed this so that our MIP solutions could be parsed to check optimality for the Mittelmann benchmarks, and we needed this to be the default. The original "raw" solution style can be obtained by setting the option write_solution_style = 0 (in an options file when running from the command line).

There's a lot of undocumented changes to the way HiGHS is run - a lack of documentation, full stop! - and I know we must be annoying some users. Unfortunately, at the moment our priority is developing the MIP solver. That this is so powerful is, hopefully, due compensation for users! Things are looking brighter after Christmas, when I won't have time to code, so will return to the issue of documentation.

mckib2 commented 3 years ago

As for what SciPy is doing, we map the HiGHS statuses to the reduced set of existing scipy.optimize.linprog statuses along with a message indicating what the original HiGHS status code was: https://github.com/scipy/scipy/blob/838cfbe51a2aecaba19b24813769ef5aeebfe056/scipy/optimize/_linprog_highs.py#L270

samiit commented 3 years ago

Sorry for the rug moving under your feet regarding the solution file. We now have a third style of solution file, and had to introduce it in a hurry. We needed this so that our MIP solutions could be parsed to check optimality for the Mittelmann benchmarks, and we needed this to be the default. The original "raw" solution style can be obtained by setting the option write_solution_style = 0 (in an options file when running from the command line).

There's a lot of undocumented changes to the way HiGHS is run - a lack of documentation, full stop! - and I know we must be annoying some users. Unfortunately, at the moment our priority is developing the MIP solver. That this is so powerful is, hopefully, due compensation for users! Things are looking brighter after Christmas, when I won't have time to code, so will return to the issue of documentation.

I don't complain, since these surprises do expose me to the fragility of the current solutions and push to make this robust in future. Thanks for doing so much and I look forward to the documentations.

Sam

jajhall commented 3 years ago

Regarding the Solution status, wherever possible, HiGHS gives a primal and (if appropriate) dual solution. In particular, I'm pretty certain that one is given whenever such a solution would be useful: notably when HiGHS reaches its time or iteration limit. It's not given in cases where, for example, an LP is shown to be infeasible by the presolve. However, finding and returning an infeasible primal solution isn't so useful. Naturally no dual solution is given when solving MIPs

Hope this helps

odow commented 3 years ago

JuMP doesn't really call solvers from the command line, but in general, our approach has been to separate "why did the solver stop?" from "what type of solution did it find?"

I'd return 0 for any case where HiGHS ran successfully and did not error. The solution file should contain information about primal/dual feasibility etc.

jajhall commented 2 years ago

By the way, I already had to update the PuLP interface quite a bit, because the solution_file's format has changed quite a bit since Aug '21! Do you plan to change this as well? Sorry but these are the issues that lie ahead when I don't directly integrate with the C/C++ API, and it would be too much for me to get there now.

Thanks for your efforts and looking forward to the teams' response.

Sam

I'm about to reduce the two solution formats to one, so that what's produced when --solution_file=filename is specified in the command line is clearer.

Rather than combining the primal, dual and basis status (when available) into a single line for a particular variable or constraint, they would come one after the other. The opening lines would be (for example)

=obj= -7.75 Solution Feasible, Infeasible or None Columns C1 0 C2 1 C3 0.75 C4 0.25 C5 0.5 C6 0.25 C7 0.75 C8 0 Rows -1 -1 -1 -2 -2 0 0 0 0 Dual solution Feasible, Infeasible or None Columns ... Rows ... Basis Valid or None Columns 0 1 2 1 1 0 1 1 Rows ...

with values written out to high precision. For ease of parsing, the solution, dual solution and basis keywords will always be present, but followed by "None" if the attribute is unavailable.

samiit commented 2 years ago

The HiGHS interface has now become part of PuLP.

jajhall commented 2 years ago

That's great news! Thanks

samiit commented 2 years ago

Hi @jajhall

After the interface became part of PuLP, unfortunately I realize that I did not incorporate the latest solution file format that you mentioned above in the thread. I had already updated the code to the format before which was like:

3 3 : Number of columns and rows for primal or dual solution or basis
T Primal solution
F Dual solution
F Basis
Columns
3 
-0.5 
7 
Rows
2.5 
10 
7.5 

But now I cannot get that format by changing write_solution_style value to 0 or 1. Is there a way I can get this format again, at least as a quick solution for now? I will update the interface to the latest format afterwards.

Thanks, Sam

jajhall commented 2 years ago

I should be able to hack this in to correspond to an unadvertised write_solution_style of 2. What's the GitHash of the version of HiGHS that you are using?

samiit commented 2 years ago

697c7a88

Running HiGHS 1.1.1 [date: 2022-01-17, git hash: 697c7a88]

jajhall commented 2 years ago

So, you're using up-to-date master. I'm on it

jajhall commented 2 years ago

OK If you set write_solution_style=2 (which is kSolutionStyleOldRaw in HConst.h) you'll get the old style

samiit commented 2 years ago

Thanks very much.

jajhall commented 2 years ago

I'll close the issue, but feel free to comment on it if anything else crops up

samiit commented 2 years ago

Hi @jajhall

Sorry to ask it here, but did things proceed regarding the documentation already? I am just checking things out to update the PuLP interface and start working on the MIP interface which you commented a while ago, and hoped to go through the new documentation before starting off!

Thanks, Sam

jajhall commented 2 years ago

No progress on general external documentation, sorry. The C API has much better internal documentation, though

odow commented 2 years ago

The C API methods are documented here: https://github.com/ERGO-Code/HiGHS/blob/master/src/interfaces/highs_c_api.h

jajhall commented 2 years ago

The C API methods are documented here: https://github.com/ERGO-Code/HiGHS/blob/master/src/interfaces/highs_c_api.h

We added these docstrings so that documentation could be generated automatically. Is there a published instance of this?

jajhall commented 2 years ago

OK If you set write_solution_style=2 (which is kSolutionStyleOldRaw in HConst.h) you'll get the old style

@samiit Do you still need the "old style" raw solution output from HiGHS? I'm asking because I'm introducing a new solution style format, and would like to use 2 for it.

If you do, I'll keep kSolutionStyleOldRaw, but change its value to -1.

This change will take place in future releases and allow me to delete it in future without leaving a "gap".

samiit commented 2 years ago

Hi @jajhall,

I haven't taken time to update to the new style, but can do so in future, maybe to your new 2 style! I will wait and watch. For now, you can please put it to -1 at least!

Thanks, Sam

jajhall commented 2 years ago

Thanks. The new style is for reading in to glpsol, so probably won't help you

samiit commented 2 years ago

Hi @jajhall

I have opened a PR for the temporary solution that you proposed, at least for now. Can you please direct me to the latest solution file format, that I should use henceforth? Sorry if you already explained above, but I couldn't figure out for sure if this above is what you mean by the new solution format? Does it generalize?

Thanks, Sam

jajhall commented 2 years ago

@samiit For distillation.mps.txt here's the solution file solved as an LP distillation-lp.sol.txt and as a MIP distillation-mip.sol.txt