[Bug?] JuMP.read_from_file+Cbc gives infeasible, just Cbc gives feasible

I found the problem without using the read_from_file (i.e., it arose from a model built inside Julia, but the code to generate the model is long) in the corner case where the model is kinda empty but not really. The model in the LP format is printed as:

maximize
obj: 
subject to
c1:  <= 1
c2:  <= 1
c3:  <= 1
c4:  <= 1
Bounds
End

and in the MathOptFormat (.mof.json) as:

{
  "name": "MathOptFormat Model",
  "version": {
    "major": 0,
    "minor": 4
  },
  "variables": [],
  "objective": {
    "sense": "max",
    "function": {
      "head": "ScalarAffineFunction",
      "terms": [],
      "constant": 0.0
    }
  },
  "constraints": [
    {
      "name": "c1",
      "function": {
        "head": "ScalarAffineFunction",
        "terms": [],
        "constant": 0.0
      },
      "set": {
        "head": "LessThan",
        "upper": 1.0
      }
    },
    {
      "name": "c2",
      "function": {
        "head": "ScalarAffineFunction",
        "terms": [],
        "constant": 0.0
      },
      "set": {
        "head": "LessThan",
        "upper": 1.0
      }
    },
    {
      "name": "c3",
      "function": {
        "head": "ScalarAffineFunction",
        "terms": [],
        "constant": 0.0
      },
      "set": {
        "head": "LessThan",
        "upper": 1.0
      }
    },
    {
      "name": "c4",
      "function": {
        "head": "ScalarAffineFunction",
        "terms": [],
        "constant": 0.0
      },
      "set": {
        "head": "LessThan",
        "upper": 1.0
      }
    }
  ]
}

I used the following small program to read and solve the files:

using JuMP, Cbc

if length(ARGS) != 1
	print("usage: ./<script_name> <file supported by JuMP.read_from_file>")
end

m = JuMP.read_from_file(ARGS[1])
set_optimizer(m, Cbc.Optimizer)
optimize!(m)
@show JuMP.primal_status(m)
if JuMP.primal_status(m) == MOI.FEASIBLE_POINT
	@show JuMP.objective_value(m)
end

JuMP is version 0.21.1 and Cbc.jl is version 0.6.6.

Both the files return that the model is infeasible:

Welcome to the CBC MILP Solver 
Version: 2.10.3 
Build Date: Oct  7 2019 

command line - Cbc_C_Interface -solve -quit (default strategy 1)
** Current model not valid
Total time (CPU seconds):       0.00   (Wallclock seconds):       0.00

JuMP.primal_status(m) = NO_SOLUTION::ResultStatusCode = 0

But this seem to happen because they think the model is not valid?

If I just run cbc directly over the “.lp” file I get:

Welcome to the CBC MILP Solver 
Version: 2.10.3 
Build Date: Jun 15 2019 

command line - cbc ../../test/Cbc_false_infeasible.mps (default strategy 1)
At line 1 NAME
At line 2 ROWS
At line 8 COLUMNS
At line 9 RHS
At line 14 RANGES
At line 15 BOUNDS
At line 16 ENDATA
Problem no_name has 4 rows, 0 columns and 0 elements
Coin0008I no_name read with 0 errors
Empty problem - 4 rows, 0 columns and 0 elements
Optimal - objective value 0
Optimal objective 0 - 0 iterations time 0.002
Total time (CPU seconds):       0.00   (Wallclock seconds):       0.00

Other solvers give the correct (zero-valued) feasible solution. Only Cbc fails at this test of mine.

Reading from file is not saying the model is infeasible. It says there is no solution because the model is invalid (look at the Cbc log).

This is a difference between cbc’s c interface and their lp file reader. I don’t think it’s a bug. I would say it’s expected behavior.

Ok… but should this happen if the model is built in JuMP?

#!/usr/bin/env julia --project=@.

using JuMP, Cbc

m = Model(Cbc.Optimizer)

empty_terms = AffExpr()
@constraint(m, empty_terms <= 2)
optimize!(m)
@show JuMP.primal_status(m)
if JuMP.primal_status(m) == MOI.FEASIBLE_POINT
	@show JuMP.objective_value(m)
end

Also gives:

Welcome to the CBC MILP Solver 
Version: 2.10.3 
Build Date: Oct  7 2019 

command line - Cbc_C_Interface -solve -quit (default strategy 1)
** Current model not valid
Total time (CPU seconds):       0.00   (Wallclock seconds):       0.00

JuMP.primal_status(m) = NO_SOLUTION::ResultStatusCode = 0

Also, is it expected that for a solver (Cbc) the model above is “invalid” and gives NO_SOLUTION::ResultStatusCode and for another (GLPK) it says nothing about the model “invalidity” and gives the following output:

JuMP.primal_status(m) = FEASIBLE_POINT::ResultStatusCode = 1
JuMP.objective_value(m) = 0.0

Finally, there is a reason why the GLPK version takes 20 seconds, and the Cbc version takes about 4 minutes? The Cbc version has that much extra code to compile?

This is all expected behavior.

Solvers have different semantics for weird constraints like the one you’re formulating.

No idea on the time difference. Is it compile time or run time? What happens if you run twice in the same Julia session?

Edit: also, check the termination status for cbc and glpk.