Skip to content

[FileFormats] the MPS and LP writers mishandle the constant of a constraint function #3109

Closed

Description

@chriscoey
import MathOptInterface as MOI
for Model in (MOI.FileFormats.MPS.Model, MOI.FileFormats.LP.Model)
    model = Model()
    MOI.Utilities.loadfromstring!(
        model,
        """
        variables: x
        minobjective: 1.0 * x
        x >= 0.0
        c: 2.0 * x + -5.0 >= 0.0
        """,
    )
    print(sprint(write, model))
end

The MPS file has rhs c 0, so it says 2x >= 0 instead of 2x >= 5, and MOI reads it back that way. JuMP users can hit this by converting an LP file containing c: 2 x - 5 >= 0 to MPS with read_from_file and write_to_file.

The LP file has c: -5 + 2 x >= 0. That is valid in the grammar in the LP docs, and MOI reads it back correctly, but Gurobi reads 5 as a new variable and HiGHS 1.15.1 drops the -5, so both return an optimum of 0 instead of 2.5. HiGHS latest also ignores it, with a warning.

Indicators do the same: [z, 2x - 5] in Indicator{ACTIVATE_ON_ONE}(GreaterThan(0.0)) writes rhs c 0 in MPS and c: z = 1 -> -5 + 2 x >= 0 in LP.

For MPS, which has no field for a row constant, the options I can see:

  1. Record each nonzero constant while COLUMNS is collected (the writer already gets every function there), and subtract it in write_rhs. This passes one more argument through the _collect_* and _write_rhs calls.
  2. Get the function again in _write_rhs and subtract its constant. This is a smaller change, but it copies the constraint functions again.
  3. Throw an error when a function has a nonzero constant.

For LP:

  1. Move the constant to the right-hand side with MOI.Utilities.normalize_constant. This changes the expected output of three existing tests, for example c6: -1.4 + 1.3 x >= -0.1 becomes c6: 1.3 x >= 1.2999999999999998.
  2. Keep the output and document it in the "Differences" section of the LP docs.

I have prototypes of option 1 for both, with tests. Which would you prefer?

Activity

  1. odow commented on Oct 17, 2026

    @odow
    Member

    I’m undecided on this. It is not valid in the LP as implemented by the solvers.

  2. odow commented on Oct 18, 2026

    @odow
    Member

    I think the right answer or MPS is (3). We should throw an error when attempting to write LHS constants.

    I actually like the current LP behaviour. It's arguably the most correct. It's not our problem if there is a constant on the LHS and HiGHS.jl errors when there is a constant on the LHS. We read and write the model as written by the user.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions