Search code examples
visual-c++gccglpk

Why does the compiler change the result of a linear programming solution? (GLPLK/GLPSOL)


Attempting to solve linear programming problems using GLPLK's GLPSOL we've come upon a snag, namely that in very specific cases, the results between glpsol executables created with different compilers are different.

The situation is that we have a problem with several valid solutions. To put it simply, we have a table where each row (X) can be assigned only one column (Y), and viceversa. As such, all combinations that assign unique column/row pairs are valid.

Example, for a 2x2 table, these are valid:

 {(X0,Y0),(X1,Y1)}   {(X0,Y1),(X1,Y0)}

Now, the original glpsol binary we used under windows, returned the results in order, something like this:

 {(X0,Y0),(X1,Y1)...(Xn,Yn)}

We noticed an issue with the Linux binary, in that it returned the solution in a different order, something like this:

 {(X0,Y0),(Xn,Y1),(X1,Y2) ....}

Note that the order is not random, every execution follows the same pattern.

After much investigation I discovered that the issue lies in which compiler was used to create each binary. In our example above, the Windows binary was compiled using Visual C++, while the Linux binary used GCC.

I've verified this by recompiling the Windows binary using GCC, resulting in the same pattern. Compiling with Borland results in a different pattern.

So the question is, mainly, why is this happening?

I'm guessing it might be the result of how each compiler optimizes the binary, but I'm not sure, and my objective is to obtain the same results we had with the original executable (the one compiled with Visual C++) both for Windows and Linux. And I am suspecting cross-compiling with the Visual C++ toolchain won't be an option.

Note: I managed to determine the compiler used by each binary by opening them as text and locating text strings within the executable referencing Visual C++ and GNU GCC respectively.

Thanks!


Solution

  • Versions of the solver built with different compilers can take different paths during the optimization process which can result in the behavior you observe. Things that can affect this are: differences in floating-point semantics (possibly caused by -ffast-math), different implementations of sort (qsort is normally not a stable sort) - this is mentioned by Ben Voigt, different implementations of random number generators in standard libraries.

    If both solutions are optimal, I wouldn't be too much concerned about this.