1

I am trying to create a symmetric matrix n x n matrix and fill it using a n*(n+1)/2 dimension array using the boost library in c++.

So far, I am able to create the matrix, and fill it with random values using the following code

#include <iostream>
#include <fstream>    
#include </usr/include/boost/numeric/ublas/matrix.hpp>
#include </usr/include/boost/numeric/ublas/matrix_sparse.hpp>
#include </usr/include/boost/numeric/ublas/symmetric.hpp>
#include </usr/include/boost/numeric/ublas/io.hpp>

using namespace std;



int test_boost () {
    using namespace boost::numeric::ublas;
    symmetric_matrix<double, upper> m_sym (3, 3);

    double filler[6] = {0, 1, 2, 3, 4, 5};        

    for (unsigned i = 0; i < m_sym.size1 (); ++ i)
        for (unsigned j = i; j < m_sym.size2 (); ++ j)
            m_sym (i, j) = filler[i+j*m_sym.size1()];

    std::cout << m_sym << std::endl;
    return 0;
}

What I am trying to do is fill the upper (or lower) part of the symmetric matrix using the values from the array filler. So the output upper symmetric matrix should be

         |      0    |      1    |      2    |
------------------------------------------------
   0 |          0           1           3    
   1 |          1           2           4
   2 |          3           4           5

Any idea on how to do that?

Thanos
  • 594
  • 2
  • 7
  • 28
  • 1
    Well, I think you've got all cards in hand to answer your own question. Answer this: what does `index` must be for the following to be correct: `m_sym(i, j) = filler[index];`? – YSC Feb 21 '18 at 17:14
  • @YSC : Thanks a lot for your comment! That is the problem...I can't think a way... Elememnt `00` in the matrix should be filled with element `0` from the array, `01` with `1`, `02` with `2`, `11` with `3` and so on...so I can't think of an evident way! – Thanos Feb 22 '18 at 06:14

1 Answers1

1

I'd simplify this a bit by just keeping an iterator that traverses filler from start to end:

symmetric_matrix<double, upper> m_sym (3, 3);

double filler[6] = {0, 1, 2, 3, 4, 5};        

assert(m_sym.size1() == m_sym.size2());

double const* in = std::begin(filler);
for (size_t i = 0; i < m_sym.size1(); ++ i)
    for (size_t j = 0; j <= i && in != std::end(filler); ++ j)
        m_sym (i, j) = *in++;

Prints: Live On Coliru

I'd personally suggest creating a helper function like:

Live On Wandbox

#include <iostream>
#include <fstream>    
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/matrix_sparse.hpp>
#include <boost/numeric/ublas/symmetric.hpp>
#include <boost/numeric/ublas/io.hpp>

namespace bnu = boost::numeric::ublas;

template <typename T = double>
bnu::symmetric_matrix<T, bnu::upper> make_symmetric(std::initializer_list<T> filler) {
    size_t n = (sqrt(8*filler.size() + 1) - 1)/2;
    assert((n*(n+1))/2 == filler.size());

    bnu::symmetric_matrix<T, bnu::upper> result(n, n);

    auto in = std::begin(filler);
    for (size_t i = 0; i < result.size1(); ++ i)
        for (size_t j = 0; j <= i && in != std::end(filler); ++ j)
            result (i, j) = *in++;

    return result;
}

int main() {
    std::cout << make_symmetric({0,1,2}) << "\n";
    std::cout << make_symmetric({0,1,2,3,4,5}) << "\n";
    std::cout << make_symmetric({0,1,2,3,4,5,6,7,8,9}) << "\n";
}

Prints

[2,2]((0,1),(1,2))
[3,3]((0,1,3),(1,2,4),(3,4,5))
[4,4]((0,1,3,6),(1,2,4,7),(3,4,5,8),(6,7,8,9))

Note: the size checks use the series expansion for 1 + ... + n and the inverse of that: n = 1/2 (sqrt(8 x + 1) - 1)

sehe
  • 374,641
  • 47
  • 450
  • 633
  • Wow!!! Thank you so much for you reply and help! I have to say that I am confused about the first part on the for loop. I didn't know you could add conditions on a `for loop! As far as the second part is concerned, I have to say that I wish I could learn to do it like that by myslef! It's a beauty! – Thanos Feb 22 '18 at 10:36
  • `for(a;b;c){/*...*/}` is really just `{ a; while(b) { /*...*/ continue_label: c; } }` http://en.cppreference.com/w/cpp/language/for – sehe Feb 22 '18 at 10:38
  • What I don't get is how to use the second part as a constructor i.e. `make_symmetric m_sym(size, filler)` or as a function to fill symmetric i.e. `symmetric_matrix m_sym (3, 3); m_sym->make_symmetric(filler)` – Thanos Feb 22 '18 at 10:58
  • Just change the definition around a bit. I can show you later – sehe Feb 22 '18 at 11:09
  • Thank you very very very much! – Thanos Feb 22 '18 at 11:20