Python API Expression Class Precision
I have been creating a Python version of an application we have here and trying to match the results. I figured out a way to compare the .mps files generated from Python and MATLAB. I am absolutely sure I am giving both languages the same problem. The only differences in the .mps are these random "offset" terms.
For example, in Python, I see the following line:
UP BND1 XXXXXXE 2.3390000000000004e03
But in MATLAB, I see the following line:
UP BND1 XXXXXXE 0.002339
These differences are randomly peppered through out the files. Some times its MATLAB that has the small perturbation and sometimes its Python.
Is this due to the difference in API? For Python, I use the expression class to build my constraints and objective function but in MATLAB, the constraints and objective function is passed as a sparse matrix. Are there floating point precision differences between using the expression class vs. the sparse matrix in MATLAB?

Hopefully this may provide some clues...I have the gurobi outputs from both Python and MATLAB below. Comparing output lines, I think I am giving the exact same problem.
Python:
Gurobi 8.1.1 (win64) logging started 12/03/19 15:34:42
Changed value of parameter LogFile to python_gurobi.log
Prev: gurobi.log Default:
Parameter MIPFocus unchanged
Value: 0 Min: 0 Max: 3 Default: 0
Changed value of parameter MIPGap to 0.01
Prev: 0.0001 Min: 0.0 Max: 1e+100 Default: 0.0001
Changed value of parameter MIPGapAbs to 1e06
Prev: 1e10 Min: 0.0 Max: 1e+100 Default: 1e10
Changed value of parameter TimeLimit to 300.0
Prev: 1e+100 Min: 0.0 Max: 1e+100 Default: 1e+100
Parameter NumericFocus unchanged
Value: 0 Min: 0 Max: 3 Default: 0
Optimize a model with 54127 rows, 53740 columns and 199891 nonzeros
Model has 1 quadratic constraint
Variable types: 33613 continuous, 20127 integer (20127 binary)
Coefficient statistics:
Matrix range [2e05, 2e+00]
QMatrix range [1e03, 2e+04]
QLMatrix range [3e04, 3e+02]
Objective range [1e+00, 1e+00]
Bounds range [2e03, 1e+00]
RHS range [2e03, 2e+02]
QRHS range [2e+02, 2e+02]
Presolve removed 51786 rows and 51543 columns
Presolve time: 0.19s
Presolved: 2341 rows, 2197 columns, 22964 nonzeros
Variable types: 1123 continuous, 1074 integer (1074 binary)Root relaxation: objective 1.970000e+00, 973 iterations, 0.02 seconds
Nodes  Current Node  Objective Bounds  Work
Expl Unexpl  Obj Depth IntInf  Incumbent BestBd Gap  It/Node Time0 0 1.97000 0 4  1.97000   0s
0 0 1.97000 0 4  1.97000   0s
0 0 1.97000 0 2  1.97000   0s
0 0 1.97000 0 2  1.97000   0s
0 2 1.97000 0 2  1.97000   0s
H 75 7 1.9699989 1.97000 0.00% 102 1s
* 75 7 2 1.9699989 1.97000 0.00% 102 1sCutting planes:
Gomory: 1
Cover: 1
MIR: 1
Flow cover: 1Explored 84 nodes (9567 simplex iterations) in 1.43 seconds
Thread count was 8 (of 8 available processors)Solution count 1: 1.97
Optimal solution found (tolerance 1.00e02)
Warning: max constraint violation (1.1856e06) exceeds tolerance
Best objective 1.969998894384e+00, best bound 1.969998894384e+00, gap 0.0000%
Optimize a model with 54127 rows, 53740 columns and 199891 nonzeros
Model has 6106 quadratic objective terms
Model has 1 quadratic constraint
Variable types: 33613 continuous, 20127 integer (20127 binary)
Coefficient statistics:
Matrix range [2e05, 2e+00]
QMatrix range [1e03, 2e+04]
QLMatrix range [3e04, 3e+02]
Objective range [2e07, 2e01]
QObjective range [1e06, 2e+01]
Bounds range [2e03, 1e+00]
RHS range [2e03, 2e+02]
QRHS range [2e+02, 2e+02]Loaded MIP start with objective 0.0872508
Presolve removed 51782 rows and 51539 columns
Presolve time: 0.19s
Presolved: 2345 rows, 2201 columns, 22972 nonzeros
Presolved model has 2452 quadratic objective terms
Variable types: 1127 continuous, 1074 integer (1074 binary)Root relaxation: objective 1.317051e01, 3141 iterations, 0.21 seconds
Nodes  Current Node  Objective Bounds  Work
Expl Unexpl  Obj Depth IntInf  Incumbent BestBd Gap  It/Node Time0 0 0.13171 0 19 0.08725 0.13171 51.0%  0s
H 0 0 0.1316187 0.13171 0.07%  0sExplored 1 nodes (3141 simplex iterations) in 0.52 seconds
Thread count was 8 (of 8 available processors)Solution count 2: 0.131619 0.0872508
Optimal solution found (tolerance 1.00e02)
Best objective 1.316187146063e01, best bound 1.317051087920e01, gap 0.0656%MATLAB:
Compute Server job ID: efd4000b4c4b4f93b711f524efab07dc
Capacity available on 'GUROBITEST'  connecting...
Established HTTP unencrypted connection
Optimize a model with 54127 rows, 53740 columns and 199891 nonzeros
Model has 1 quadratic constraint
Variable types: 33613 continuous, 20127 integer (20127 binary)
Coefficient statistics:
Matrix range [2e05, 2e+00]
QMatrix range [1e03, 2e+04]
QLMatrix range [3e04, 3e+02]
Objective range [1e+00, 1e+00]
Bounds range [2e03, 1e+00]
RHS range [2e03, 2e+02]
QRHS range [2e+02, 2e+02]
Presolve removed 51786 rows and 51543 columns
Presolve time: 0.20s
Presolved: 2341 rows, 2197 columns, 22964 nonzeros
Variable types: 1123 continuous, 1074 integer (1074 binary)Root relaxation: objective 1.970000e+00, 1009 iterations, 0.03 seconds
Nodes  Current Node  Objective Bounds  Work
Expl Unexpl  Obj Depth IntInf  Incumbent BestBd Gap  It/Node Time0 0 1.97000 0 3  1.97000   0s
0 0 1.97000 0 2  1.97000   0s
H 0 0 1.9700001 1.97000 0.00%  0s
* 0 0 0 1.9700001 1.97000 0.00%  0sCutting planes:
Gomory: 2
Cover: 2
MIR: 1
Flow cover: 1Explored 1 nodes (1585 simplex iterations) in 0.90 seconds
Thread count was 8 (of 8 available processors)Solution count 1: 1.97
Optimal solution found (tolerance 1.00e02)
Best objective 1.970000097123e+00, best bound 1.970000000000e+00, gap 0.0000%
gurobi_safe: optimal solution found
writing data to P:\vk_backup\gurobi_models\test_17420.lp
Compute Server job ID: 4147efc691ea444981659c51ea29ac1a
Capacity available on 'GUROBITEST'  connecting...
Established HTTP unencrypted connection
Optimize a model with 54127 rows, 53740 columns and 199891 nonzeros
Model has 6106 quadratic objective terms
Model has 1 quadratic constraint
Variable types: 33613 continuous, 20127 integer (20127 binary)
Coefficient statistics:
Matrix range [2e05, 2e+00]
QMatrix range [1e03, 2e+04]
QLMatrix range [3e04, 3e+02]
Objective range [2e07, 2e01]
QObjective range [1e06, 2e+01]
Bounds range [2e03, 1e+00]
RHS range [2e03, 2e+02]
QRHS range [2e+02, 2e+02]
Presolve removed 51782 rows and 51539 columns
Presolve time: 0.19s
Presolved: 2345 rows, 2201 columns, 22972 nonzeros
Presolved model has 2452 quadratic objective terms
Variable types: 1127 continuous, 1074 integer (1074 binary)Root relaxation: objective 1.317051e01, 3140 iterations, 0.21 seconds
Nodes  Current Node  Objective Bounds  Work
Expl Unexpl  Obj Depth IntInf  Incumbent BestBd Gap  It/Node Time0 0 0.13171 0 20  0.13171   0s
H 0 0 0.1316172 0.13171 0.07%  0sExplored 1 nodes (3140 simplex iterations) in 0.44 seconds
Thread count was 8 (of 8 available processors)Solution count 1: 0.131617
Optimal solution found (tolerance 1.00e02)
Best objective 1.316172097689e01, best bound 1.317051131492e01, gap 0.0668%
gurobi_safe: optimal solution found0 
Hi Quang,
Can you check if there is a roundoff error in either of your scripts? E.g., in Python, we sometimes see calculations like this:
>>> 0.1 + 0.2
0.30000000000000004Thanks,
Eli0 
Hi Eli,
Thanks for looking into this.
Python:
It looks like Python is contributing a roundoff error in my scripts.
MATLAB:
It looks like there is a roundoff error in my MATLAB script as well.
Potential Solutions?
Python: This is a bit tricky. I use the quad/linear expression class to set the constraints and objective function and I don't know how I can roundoff the coefficients in the expression class. I don't want to round the numbers going into the expression class. I'm guessing the expression class does some arithmetic with the numbers I pass it. Is there a good way to do this? or do I have to loop through all the coefficients and round it?
MATLAB: I tried rounding the Q, A, Qc, and etc.. matrices before passing it to gurobi but it looks like the rounding errors are still there, probably due to how MATLAB stores the numbers. Is there a way to tell gurobi to drop the least significant decimals?
0
Please sign in to leave a comment.
Comments
3 comments