pybind11
pybind11 copied to clipboard
[BUG]: Eigen::SparseMatrix -> unexpected overload-resolution / template-instantiation
Required prerequisites
- [X] Make sure you've read the documentation. Your issue may be addressed there.
- [X] Search the issue tracker and Discussions to verify that this hasn't already been reported. +1 or comment there if it has.
- [ ] Consider asking first in the Gitter chat room or in a Discussion.
What version (or hash if on master) of pybind11 are you using?
723307283ed7dc03c901fba1da1127c7b16a4a0d
Problem description
I'm trying to wrap dense as well as sparse-matrices (py -> c++): specifically
Eigen::Array<T, Eigen::Dynamic, Eigen::Dynamic>Eigen::SparseMatrix<T, Eigen::RowMajor>Eigen::SparseMatrix<T, Eigen::ColMajor>
Having tried two approaches, one being based on EigenBase<Derived>, the other being based on splitting the target functions into a dense and a sparse variant (as shown in example).
In both cases, something unexpected is happening to the type in the sparse-case while the dense case works as expected.
tests/test_basic.py
Dense matrix @ python
[[1. 2. 3. 4.]
[5. 6. 7. 8.]]
float32
Sparse matrix @ python
(0, 0) 1.0
(0, 1) 2.0
(0, 2) 3.0
(0, 3) 4.0
(1, 0) 5.0
(1, 1) 6.0
(1, 2) 7.0
(1, 3) 8.0
float32
CALL instantiation -> with dense => c++ receives type?
Dense overload
float
CALL instantiation -> with sparse => c++ receives type?
Sparse overload
bool ??? WHY ???
Reproducible example: https://github.com/sschnug/cmake_example/tree/eigen_sparse_matrix_overload_issue_example
Reproducible example code
See: https://github.com/sschnug/cmake_example/tree/eigen_sparse_matrix_overload_issue_example
But basically:
// OKAY BEHAVIOUR -> dense
template <typename ScalarT>
static void take_matrix(const Eigen::Array<ScalarT, Eigen::Dynamic, Eigen::Dynamic> matrix_in) {
std::cout << "Dense overload" << std::endl;
if constexpr(std::is_same_v<ScalarT, float>) {
std::cout << "float" << std::endl;
}
else if constexpr(std::is_same_v<ScalarT, double>) {
std::cout << "double" << std::endl;
}
else if constexpr(std::is_same_v<ScalarT, bool>) {
std::cout << "bool" << std::endl;
}
else if constexpr(std::is_same_v<ScalarT, int8_t>) {
std::cout << "int8_t" << std::endl;
}
else if constexpr(std::is_same_v<ScalarT, int16_t>) {
std::cout << "int16_t" << std::endl;
}
else if constexpr(std::is_same_v<ScalarT, int32_t>) {
std::cout << "int32_t" << std::endl;
}
else if constexpr(std::is_same_v<ScalarT, int64_t>) {
std::cout << "int64_t" << std::endl;
}
else if constexpr(std::is_same_v<ScalarT, uint8_t>) {
std::cout << "uint8_t" << std::endl;
}
else if constexpr(std::is_same_v<ScalarT, uint16_t>) {
std::cout << "uint16_t" << std::endl;
}
else if constexpr(std::is_same_v<ScalarT, uint32_t>) {
std::cout << "uint32_t" << std::endl;
}
else if constexpr(std::is_same_v<ScalarT, uint64_t>) {
std::cout << "uint64_t" << std::endl;
}
else
std::cout << "some other type" << std::endl;
}
// NOT OKAY BEHAVIOUR -> sparse
template<typename ScalarT, int Options>
static void take_matrix(const Eigen::SparseMatrix<ScalarT, Options> matrix_in) {
std::cout << "Sparse overload" << std::endl;
if constexpr(std::is_same_v<ScalarT, float>) {
std::cout << "float" << std::endl;
}
else if constexpr(std::is_same_v<ScalarT, double>) {
std::cout << "double" << std::endl;
}
else if constexpr(std::is_same_v<ScalarT, bool>) {
std::cout << "bool" << std::endl;
}
else if constexpr(std::is_same_v<ScalarT, int8_t>) {
std::cout << "int8_t" << std::endl;
}
else if constexpr(std::is_same_v<ScalarT, int16_t>) {
std::cout << "int16_t" << std::endl;
}
else if constexpr(std::is_same_v<ScalarT, int32_t>) {
std::cout << "int32_t" << std::endl;
}
else if constexpr(std::is_same_v<ScalarT, int64_t>) {
std::cout << "int64_t" << std::endl;
}
else if constexpr(std::is_same_v<ScalarT, uint8_t>) {
std::cout << "uint8_t" << std::endl;
}
else if constexpr(std::is_same_v<ScalarT, uint16_t>) {
std::cout << "uint16_t" << std::endl;
}
else if constexpr(std::is_same_v<ScalarT, uint32_t>) {
std::cout << "uint32_t" << std::endl;
}
else if constexpr(std::is_same_v<ScalarT, uint64_t>) {
std::cout << "uint64_t" << std::endl;
}
else
std::cout << "some other type" << std::endl;
}
PYBIND11_MODULE(cmake_example, m) {
// dense
// -----
m.def("take_matrix", &take_matrix<bool>, pybind11::arg("matrix_in").noconvert());
m.def("take_matrix", &take_matrix<float>, pybind11::arg("matrix_in").noconvert());
m.def("take_matrix", &take_matrix<double>, pybind11::arg("matrix_in").noconvert());
// sparse
// ------
m.def("take_matrix", &take_matrix<bool, Eigen::ColMajor>, pybind11::arg("matrix_in").noconvert());
m.def("take_matrix", &take_matrix<bool, Eigen::RowMajor>, pybind11::arg("matrix_in").noconvert());
m.def("take_matrix", &take_matrix<float, Eigen::ColMajor>, pybind11::arg("matrix_in").noconvert());
m.def("take_matrix", &take_matrix<float, Eigen::RowMajor>, pybind11::arg("matrix_in").noconvert());
m.def("take_matrix", &take_matrix<double, Eigen::ColMajor>, pybind11::arg("matrix_in").noconvert());
m.def("take_matrix", &take_matrix<double, Eigen::RowMajor>, pybind11::arg("matrix_in").noconvert());
Is this a regression? Put the last known working version here if it is.
Not a regression