coin-or / coin-or/pulp

Unsupported bound type `MI` in `pulp.LpProblem.fromMPS`

Open
#791 2 comments 0 reactions 0 assignees View on GitHub
lp/mps
Dominant language
Python
Stars
2.5k
Forks
432
PR merge metrics
No merged PRs in 30d

Description

Details for the issue
--------------------

#### What did you do?
I attempted to read an `.mps` file using `pulp.LpProblem.fromMPS`.

I discovered the issue when converting problems to `pulp` style `.json` files, and an `.mps` file containing an `MI` type bound caused `pulp` to error. `MI` bounds specify that the lower bound is `-inf` for a variable ([see note E here](https://lpsolve.sourceforge.net/5.5/mps-format.htm))

##### MPS File bounds section (simplified):

```
BOUNDS
...
MI bnd d_losvq_trnsf
UP bnd d_losvq_trnsf 400
...
ENDATA
```

#### What did you expect to see?
Successful file read.

#### What did you see instead?
`IndexError` raised.

In the function `readMPSSetBounds`, a series of checks are made against the bound type. Bound types that do not specify a bound value are caught and handled separately (currently `FR`, `BV`, and `PL` are caught). If the type is not caught, the bound value is read from the `lines` object, which is a list.

Since the `MI` bound type does not specify a bound value, and it is not caught by the if statements, an index error is raised since the `lines` list is an unexpected length.

### Proposed Solution

Adding an additional clause to `readMPSSetBounds` in `pulp.mps_lp`.

```python
def readMPSSetBounds(line, variable_dict):
bound = line[0]
var_name = line[2]

def set_one_bound(bound_type, value):
variable_dict[var_name][BOUNDS_EQUIV[bound_type]] = value

def set_both_bounds(value_low, value_up):
set_one_bound("LO", value_low)
set_one_bound("UP", value_up)

if bound == "FR":
set_both_bounds(None, None)
return
elif bound == "BV":
set_both_bounds(0, 1)
return
elif bound == "PL":
# bounds equal to defaults
return
elif bound == "MI":
# Lower bound -inf
set_one_bound("LO", None)
return

value = float(line[3])
if bound in ["LO", "UP"]:
set_one_bound(bound, value)
elif bound == "FX":
set_both_bounds(value, value)
return
```

I am uncertain if this causes side effects, as I have not tested the solution against the unit-tests myself. I have successfully used this as a "patch" to finish my conversion effort.

I couldn't find any documentation discussing the support of `MI` bound types, so my assumption is that they are supported. If I am incorrect, disregard this issue.

Useful extra information
-------------------------

#### What operating system are you using?

- [X] Windows: (11, Version 10.0.22631 Build 22631)

#### I'm using python version:

- [X] 3.11

#### I installed PuLP via:

- [X] pypi (python -m pip install pulp)
- [X] Other: conda (conda environment, pulp is installed via pip, no other packages)

#### Did you also

- [ ] Tried out the latest github version: https://github.com/coin-or/pulp
- [X] Searched for an existing similar issue: https://github.com/coin-or/pulp/issues?utf8=%E2%9C%93&q=is%3Aissue%20

Contributor guide

Open the contributing guide

Research direction

Start in pulp.mps_lp at readMPSSetBounds and review the existing unit tests for MPS bounds handling. Reproduce the MI-bound example, verify that reading the file no longer raises IndexError, and run the unit tests to check for side effects.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
backend
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.