coin-or / Ipopt

COIN-OR Interior Point Optimizer IPOPT
https://coin-or.github.io/Ipopt
Other
1.43k stars 284 forks source link

Single precision use #403

Closed mdclemen closed 3 years ago

mdclemen commented 4 years ago

What would it take to make a single precision (32 bit floating point) version of IPOPT?

svigerske commented 4 years ago

One would need to change the type for Number and change the interfaces to external codes (BLAS, LAPACK, linear solver, ...) to convert between float and double.

mdclemen commented 3 years ago

It seems that in a number of interface files, there is mixed use of types defined in src/Common/IpTypes.h with double and int. For example in in src/Algorithms/LinearSolvers/IpPardisoSolverInterface.cpp/.hpp, in the class ESymSolverStatus PardisoSolverInterface::MultiSolve has inputs: (bool new_matrix, const Index* ia, const Index* ja, Index nrhs, double* rhs_vals, bool check_NegEVals, Index numberOfNegEVals) It would seem reasonable that double could be changed to Number in most of these cases (since Index is being used vice int), and then the type of Number can be controlled in IpTypes.h. Does this sound right, or am I missing something on why double is hard coded here?

svigerske commented 3 years ago

On this example, the method declaration has probably been taken from the upper class, which also uses double* already (https://github.com/coin-or/Ipopt/blob/master/src/Algorithm/LinearSolvers/IpSparseSymLinearSolverInterface.hpp#L188). Also SparseSymLinearSolverInterface::GetValuesArrayPtr() gives a double* instead of a Number*.
One argument why this could be intentionally is that the authors thought that linear solvers always use double-precision floating point numbers. So if there would be a code added to convert between Number and double, then that could be added once to the routines that call MultiSolve() and fill the ValuesArray, instead of implementing this in every linear solver interface.

mdclemen commented 3 years ago

I've created a fork at https://github.com/mdclemen/Ipopt, that demonstrates single precision functionality (in case anyone else desires this functionality). Pardiso is the only solver I was easily able to update the interface for to use single precision. There is a configure option now, --enable-single-precision, which enables single precision. I'm not sure this is anything you guys would like to add to the library, but if it is, I can submit a pull request.

svigerske commented 3 years ago

That looks like a lot of work and a nice addition that could potentially be useful to others, too.

I'm ok with all the changes from double to Number, but wonder whether the distinction for every fabs, pow, sqrt is necessary. It looks to me as if std::pow is also available for float (https://en.cppreference.com/w/cpp/numeric/math/pow), so function overloading could be used here. Also powf introduces dependency on C++11.
If one does all the effort to get Ipopt working also with Number=float, then it would be nice to make it simpler to add support for other typedefs for Number in the future, too.

mdclemen commented 3 years ago

Valid points. I have removed calls to precision specific math functions and am using the overloaded functions. I builds for me without complaining.

I have also asked HSL if they can give me the single precision source files for their solvers so I can try to write interfaces for those.

svigerske commented 3 years ago

Thank you! A pull request would be great.

svigerske commented 3 years ago

Some more TODOs:

svigerske commented 3 years ago

I would consider this done for now.

All changes are shown in https://github.com/coin-or/Ipopt/compare/master...a21c9af3cf2a6f117136c5bb158872dfb76b181c Note in particular the updates to CHANGELOG and documentation.

mdclemen commented 3 years ago

HSL has sent me a beta version of coinhsl that includes single precision codes. @svigerske would you be interested in testing it out?

svigerske commented 3 years ago

yes, I can try

svigerske commented 3 years ago

They seem to work fine. I updated Ipopt/devel in 5694ddfa1a17cabf65e1c84c45cc9caeab0be1f0.

Cfather commented 1 month ago

Hi, just as a follow-up question since I'm trying to incorporate single precision floating number computation. I have compiled Ipopt with option --with-precision=single. But it returns the error:

Exception of type: DYNAMIC_LIBRARY_FAILURE in file "../../src/Common/IpLibraryLoader.cpp" at line 198:
 Exception message: /usr/local/lib/libhsl.so: undefined symbol: MA57A
EXIT: Library loading failure.

It seems like I did not get the correct versions of HSL libraries. I wonder if anyone knows what I should do on the HSL side? HSL only provides me ma57d.f and ma57s.f in their source code, which seem to be the double precision version and the single precision version, respectively. So I'm not sure what MA57A means here. Maybe there is a similar ma57a.f?

I would appreciate any help!

svigerske commented 1 month ago

ma57s.f defines a subroutine MA57A, at least in my coinhsl version from 2021.5.5. Maybe your build of the HSL library missed compiling ma57s.f.

(The double precision version of MA57A is called MA57AD and implemented in ma57d.f.)