Opened 8 years ago

Last modified 8 years ago

#10127 new Bugs

coordinate_matrix sort() fails on to std::swap

Reported by: anonymous Owned by: Gunter
Milestone: Boost 1.58.0 Component: uBLAS
Version: Boost 1.54.0 Severity: Showstopper
Keywords: c++11, swap, sort, matrix, reference Cc:

Description

Orginally posted here:

http://stackoverflow.com/questions/24228772/c11-compatibility-of-sparse-matrix-implementations

The following program does not compile with gcc 4.8 or clang 3.4 when --std=c++11 is set:

#include <boost/numeric/ublas/io.hpp>
#include <boost/numeric/ublas/matrix_sparse.hpp>

using namespace boost::numeric::ublas;

int main(int argc, char** argv) {
  coordinate_matrix<int> m1(100, 100, 100);

  for (int i = 0; i < 100; i++)
    m1.insert_element(i,i,i);

  compressed_matrix<int> m2(m1, 100);
}

We can solve the issue by providing a swap() routine:

#include <boost/numeric/ublas/io.hpp>
#include <boost/numeric/ublas/matrix_sparse.hpp>

using namespace boost::numeric::ublas;

namespace std {
    template<class M>
    inline
    void swap (boost::numeric::ublas::index_triple<M> i1, boost::numeric::ublas::index_triple<M> i2) {
        i1.swap (i2);
    }
}


int main(int argc, char** argv) {
  coordinate_matrix<int> m1(100, 100, 100);

  for (int i = 0; i < 100; i++)
    m1.insert_element(i,i,i);
  
  compressed_matrix<int> m2(m1, 100);
}

I am not an expert C++ template programmer, so I am unable to decide what is the cause here, but the C++ reference on std::sort explicitly mentions a swap() method.

Change History (6)

comment:1 by Casey Carter <Casey@…>, 8 years ago

Test case can be minimized to:

#include <boost/numeric/ublas/matrix_sparse.hpp>

int main() {
  boost::numeric::ublas::coordinate_matrix<int> m1(1, 1, 1);
  m1.insert_element(0, 0, 0);
}

The problem seems to be that when BOOST_UBLAS_STRICT_MATRIX_SPARSE is defined, coordinate_matrix and its iterator types use a proxy class as their reference type:

#ifndef BOOST_UBLAS_STRICT_MATRIX_SPARSE
        typedef T &reference;
#else
        typedef sparse_matrix_element<self_type> reference;
#endif

which violates the C++ standard's requirement that the reference type for forward iterators is a true reference. C++11 [forward.iterators]/1 states: "A class or pointer type X satisfies the requirements of a forward iterator if ... if X is a mutable iterator, reference is a reference to T; if X is a const iterator, reference is a reference to const T, ...".

comment:2 by Andrew Medlin <amedlin@…>, 8 years ago

This also affects version 1.55.0 sparse vectors, which breaks the LU substitution.

For example, the following code produces incorrect output. It should swap the 2nd and 3rd elements, producing

1.000000, 3.000000, 2.000000

but instead it produces

1.000000, 3.000000, 3.000000

It is fixed by uncommenting the #define BOOST_UBLAS_NO_ELEMENT_PROXIES

//#define BOOST_UBLAS_NO_ELEMENT_PROXIES

#include <boost/numeric/ublas/vector_sparse.hpp>
#include <boost/numeric/ublas/lu.hpp>

using namespace boost::numeric::ublas;

int main()
{
    mapped_vector<float> y;
    y(0) = 1.0f;
    y(1) = 2.0f;
    y(2) = 3.0f;
    LOG("Initial vector is: " << y);
    permutation_matrix<std::size_t> perm(y.size());
    perm(0) = 0;
    perm(1) = 2;
    perm(2) = 2;
    swap_rows(perm, y);
    LOG("Swapped vector is: " << y);
}

comment:3 by viboes, 8 years ago

Component: NoneuBLAS
Owner: set to Gunter

comment:4 by eg@…, 8 years ago

Hi, any chance to get this ticket solved in the next release ? version 1.57 doesn't seem to offer a fix for this issue, as far as I know.

comment:5 by Andrew Medlin <amedlin@…>, 8 years ago

Milestone: To Be DeterminedBoost 1.58.0
Severity: ProblemShowstopper

I think this bug represents a fundamental break in core functionality, so I am raising the severity. I believe this should be fixed with priority.

comment:6 by eg@…, 8 years ago

Keywords: c++11 swap sort matrix reference added
Note: See TracTickets for help on using tickets.