Fill a symmetric matrix using an array - c++

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?

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)

Related

How to use thrust remove_if 's results

I am trying to use thrust remove_if and I have some questions. However first, the example in the documentation is not working as it should
Here the code (that contains the doc code too)
#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
//#include <thrust/copy.h>
#include <thrust/remove.h>
#include <iostream>
template<typename T>
struct is_zero {
__host__ __device__
auto operator()(T x) const -> bool {
return x == 0;
}
};
struct is_even
{
__host__ __device__
bool operator()(const int x)
{
return (x % 2) == 0;
}
};
int main(void){
int h_data[6] = {1, 0, 2, 0, 1, 3};
const int N = 6;
int A[N] = {1, 4, 2, 8, 5, 7};
int *new_end = thrust::remove_if(A, A + N, is_even());
int * d_data;
cudaMalloc((void**)&d_data, 6 * sizeof(int));
cudaMemcpy(d_data, h_data, 6 * sizeof(int), cudaMemcpyHostToDevice);
thrust::device_ptr<int> dev_ptr(d_data);
thrust::device_vector<int> output;
thrust::remove_if(dev_ptr, dev_ptr+6, is_zero<int>());
//thrust::remove_if(d_data, d_data+6, is_zero<int>()); //--> segmentation fault
cudaMemcpy(h_data, d_data, 6 * sizeof(int), cudaMemcpyDeviceToHost);
for(int i = 0; i < 6; i++)
std::cout << "H[" << i << "] = " << h_data[i]<< std::endl;
for(int i = 0; i < 6; i++)
std::cout << "new_end[" << i << "] = " << new_end[i]<< std::endl;
}
I run this and I got
H[0] = 1
H[1] = 2
H[2] = 1
H[3] = 3
H[4] = 1
H[5] = 3
new_end[0] = 8
new_end[1] = 5
new_end[2] = 7
new_end[3] = -491667200
new_end[4] = 541501445
new_end[5] = 2019959568
In the documentation it is said
// The first three values of A are now {1, 5, 7}
// Values beyond new_end are unspecified
The results of the part programmed seems to be working (if zero)
But the ones in the tutorial are not the results.

Dynamic Programming for Minimum Path Sum

I am not understanding how to exactly use dynamic programming for the Minimum Path Sum Problem. The problem statement is as follows.
Given a m x n grid filled with non-negative numbers, find a path from
top left to bottom right which minimizes the sum of all numbers
along its path.
Note: You can only move either down or right at any point in time.
Here is the code i tried using just recursion.
#include "stdafx.h"
#include "vector"
#include "iostream"
#include "cmath"
#include "algorithm"
using namespace std;
class Solution {
public:
int s = INT_MAX;
int helper(int sum, vector<vector<int>> &grid, int i, int j) {
if (i == grid.size() - 1 && j == grid[0].size() - 1) {
return s = min(s, sum + grid[i][j]);
}
if (i >= grid.size() || j >= grid[0].size()) {
return sum;
}
return min(helper(sum + grid[i][j], grid, i + 1, j) + helper(sum + grid[i][j], grid, i, j + 1), s);
}
int minPathSum(vector<vector<int>>& grid) {
return helper(0, grid, 0, 0);
}
};
int main()
{
vector<int> v = { 1,2,3 };
vector<vector<int>> r;
r.push_back(v);
v = { 4,5,6 };
r.push_back(v);
v = { 7,8,9 };
r.push_back(v);
v = { 1,2,3 };
r.push_back(v);
Solution s;
cout<<s.minPathSum(r);
return 0;
}
And here is a code where i tried using Dynamic programming where I am storing the least sum at a given index [i,j] and returning it, but its not being of much help, the Online Coding Judge says "Time Limit Exceeded"
Can you please help me improve the code.
#include "stdafx.h"
#include "vector"
#include "iostream"
#include "cmath"
#include "algorithm"
using namespace std;
class Solution {
public:
int s = INT_MAX;
int helper(int sum, vector<vector<int>> &grid, int i, int j,vector<vector<int>> &memoize) {
if (i == grid.size() - 1 && j == grid[0].size() - 1) {
return s = min(s, sum + grid[i][j]);
}
if (i >= grid.size() || j >= grid[0].size()) {
return sum;
}
if (sum + grid[i][j] < memoize[i][j])
memoize[i][j] = sum + grid[i][j];
else
return memoize[i][j];
return min(helper(sum + grid[i][j], grid, i + 1, j,memoize) + helper(sum + grid[i][j], grid, i, j + 1,memoize), s);
}
int minPathSum(vector<vector<int>>& grid) {
vector<vector<int>> memoize(grid.size(), vector<int>(grid[0].size(), INT_MAX));
return helper(0, grid, 0, 0,memoize);
}
};
int main()
{
vector<int> v = { 1,2,3 };
vector<vector<int>> r;
r.push_back(v);
v = { 4,5,6 };
r.push_back(v);
v = { 7,8,9 };
r.push_back(v);
v = { 1,2,3 };
r.push_back(v);
Solution s;
cout<<s.minPathSum(r);
return 0;
}

Error Eigen library on linux

I have implemented this code with Eigen library to have Triplet structure.
This code works very well in my project on my Mac OS X. However the same code don't work on Linux platform.
Eigen::SparseMatrix<double> spdiags(const MatrixXd& B, const
Eigen::Matrix<int, 1,1>& d, size_t m, size_t n)
{
Eigen::SparseMatrix<double> A(m,n);
typedef Eigen::Triplet<double> T;
std::vector<T> triplets;
triplets.reserve(std::min(m,n)*d.size());
for (int k = 0; k < d.size(); k++)
{
int i_min = std::max(0, -d(k));
int i_max = std::min(m - 1, n - d(k) - 1);
int B_idx_start = m >= n ? d(k) : 0;
for (int i = i_min; i <= i_max; i++) {
triplets.push_back( T(i, i+k, B(B_idx_start + i, k)) );
}
A.setFromTriplets(triplets.begin(), triplets.end());
std::cout << "Row\tCol\tVal" <<std::endl;
for (int k=0; k < A.outerSize(); ++k)
{
for (SparseMatrix<double>::InnerIterator it(A,k); it; ++it)
{
std::cout << it.row() << "\t"; // row index
std::cout << it.col() << "\t";
std::cout << it.value() << std::endl;
}
}
return A;
}
I have this error only on Linux (there is no error on Mac). The code source of the file DenseCoeffsBase.h is the same:
"/usr/local/include/Eigen/src/Core/DenseCoeffsBase.h:114:
Eigen::DenseCoeffsBase<Derived, 0>::CoeffReturnType
Eigen::DenseCoeffsBase<Derived, 0>::operator()
(Eigen::DenseCoeffsBase<Derived, 0>::Index,
Eigen::DenseCoeffsBase<Derived, 0>::Index) const
[with Derived = Eigen::Matrix<double, -1, -1>;
Eigen::DenseCoeffsBase<Derived, 0>::CoeffReturnType = const double&;
Eigen::DenseCoeffsBase<Derived, 0>::Index = long int]:
Assertion `row >= 0 && row < rows() && col >= 0 && col < cols()' failed."
Any ideas?
Here is an MVC as asked :
#include<Eigen/Sparse>
#include <Eigen/Sparse>
#include<Eigen/Dense>
#include<Eigen/Eigenvalues>
Matrix<int, 1, 1> d1; d1(0)=0;
MatrixXd d0; d0.resize(1,5);
d0(0)=10;d0(1)=20;d0(2)=30;d0(3)=30;d0(4)=40;d0(5)=50;
Eigen::SparseMatrix<double> Diag_laplacian=test.spdiags(d0,d1,5,5);
//--------------
//the result must be like this :
Row Col Val
0 0 10
1 1 20
2 2 30
3 3 30
4 4 40
This, my dear sir/madam, is an MCVE
#include <iostream>
#include <Eigen/Core>
#include <Eigen/Sparse>
using namespace Eigen;
Eigen::SparseMatrix<double> spdiags(const MatrixXd& B,
const Eigen::Matrix<int, 1, 1>& d, size_t m, size_t n)
{
Eigen::SparseMatrix<double> A(m, n);
typedef Eigen::Triplet<double> T;
std::vector<T> triplets;
triplets.reserve(std::min(m, n)*d.size());
for (int k = 0; k < d.size(); k++)
{
int i_min = std::max(0, -d(k));
int i_max = std::min(m - 1, n - d(k) - 1);
int B_idx_start = m >= n ? d(k) : 0;
for (int i = i_min; i <= i_max; i++)
triplets.push_back(T(i, i + k, B(B_idx_start + i, k)));
}
A.setFromTriplets(triplets.begin(), triplets.end());
std::cout << "Row\tCol\tVal" << std::endl;
for (int k = 0; k < A.outerSize(); ++k)
{
for (SparseMatrix<double>::InnerIterator it(A, k); it; ++it)
{
std::cout << it.row() << "\t"; // row index
std::cout << it.col() << "\t";
std::cout << it.value() << std::endl;
}
}
return A;
}
int main()
{
Matrix<int, 1, 1> d1; d1(0) = 0;
MatrixXd d0; d0.resize(1, 5);
// Note that you *have* to use (x,y) indices on a MatrixXd
// Otherwise, you get a different assertion failure
d0(0,0) = 10; d0(0,1) = 20;
d0(0,2) = 30; d0(0,3) = 30;
d0(0,4) = 40;
// d0(0,5) = 50; // OUT OF BOUNDS!!!
Eigen::SparseMatrix<double> Diag_laplacian = spdiags(d0, d1, 5, 5);
}
The expected result is (as you stated):
Row Col Val
0 0 10
1 1 20
2 2 30
3 3 30
4 4 40
To reproduce the results, I can either use VS (2013 in my case) or g++ (i.e. it's not Linux vs. Mac). As you are using g++, I will as well.
To reproduce the behavior you described on the Linux build, I compiled with
g++ -O3 -I"C:\usr\include" Source.cpp -o a.exe
Running a.exe gave me (as you stated)
Assertion failed: row >= 0 && row < rows() && col >= 0 && col < cols(), file C:\usr\include/Eigen/src/Core/DenseCoeffsBase.h, line 114
Debugging it showed me that it fails on the line
triplets.push_back(T(i, i + k, B(B_idx_start + i, k)));
when i == 1. Why? Exactly as #marc and I stated. B is not shaped/sized as you use it. Changing B(B_idx_start + i, k) with B(k, B_idx_start + i) resolves the issue.
Now, why does it work on the Mac? The answer has to do with the error itself. It's an assertion error. Assertions are not checked when NDEBUG is defined. So you probably compiled using something like
g++ -DNDEBUG -O3 -I"C:\usr\include" Source.cpp -o a.exe
on the Mac, and it ran fine, as then the assertions are ignored:
#ifdef NDEBUG
#define assert(_Expression) ((void)0)
#else
So, if there is an assertion failure, why does it work when we define NDEBUG? The answer to that is that the data pointer points to the first of five allocated doubles. Using the correct indexing, we should get index = k*1 + (B_idx_start + i), and since in this case k==0 and B_idx_start==0, we get index=i. This is within the bounds and therefore we don't get an out of bounds exception. Using the incorrect indexing, we get index = (B_idx_start + i)*1 + k which again, results in index=i. If the size of the matrix was (for example) 2x5, then we would have gotten an out of bounds exception.

Use C++ armadillo Expectation Maximization for Gaussian mixture model

I am trying to use armadillo's expectation maximization maximization gmm_diag class, but when I try to compile it I get "error gmm_diag was not declared in this scope".
My code is as follows:
#include <stdio.h>
#include <iostream>
#include <vector>
#include <armadillo>
#include <omp.h>
using namespace std;
using namespace arma;
int main()
{
// create synthetic data with 2 Gaussians
uword N = 10000;
uword d = 5;
mat data(d, N, fill::zeros);
vec mean0 = linspace<vec>(1,d,d);
vec mean1 = mean0 + 2;
uword i = 0;
while(i < N)
{
if(i < N) { data.col(i) = mean0 + randn<vec>(d); ++i; }
if(i < N) { data.col(i) = mean0 + randn<vec>(d); ++i; }
if(i < N) { data.col(i) = mean1 + randn<vec>(d); ++i; }
}
gmm_diag model;
model.learn(data, 2, maha_dist, random_subset, 10, 5, 1e-10, true);
model.means.print("means:");
double scalar_likelihood = model.log_p( data.col(0) );
rowvec set_likelihood = model.log_p( data.cols(0,9));
double overall_likelihood = model.avg_log_p(data);
uword gaus_id = model.assign( data.col(0), eucl_dist );
urowvec gaus_ids = model.assign( data.cols(0,9), prob_dist );
urowvec hist1 = model.raw_hist (data, prob_dist);
rowvec hist2 = model.norm_hist(data, eucl_dist);
model.save("my_model.gmm");
// the table is now initialized
}

Find the sum of digits of a sequence of integers

I made up my mind to write a little piece of code that gets two integers, lets say M and N ( M <= N ) and sum the digits of all the integers between them, inclusive. So for example if M = 1 and N = 9, DigitSum will equal to 45. If M = 10 and N = 11 the sum will be (1 + 0 (10) + 1 + 1 (11) = 3).
Here is my code so far (Done the for loop instead of the return):
#include <iostream>
#include <vector>
using namespace std;
// the partial digits sums digitSum[i] = the sum of the digits between 0 and i
int digitSum[] = {0, 1, 3, 6, 10, 15, 21, 28, 36, 45};
int pow_of_ten[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
// the sums of all the digits in the numbers from 1 to (10^(i) - 1) where i is the index in the array
long subsums[] = {0, 45, 20 * 45, 300 * 45, 4000 * 45, 50000 * 45, 600000 * 45, 7000000 * 45, 80000000 * 45,
900000000 * 45};
//Calculates the sum of all digits between 0 and M inclusive
long Digit_Sum(int M) {
if (M < 10) {
return digitSum[M];
}
long result = 0;
int same = M;
int counter = 0;
int lastdigit = 0;
while (same > 0) {
if (same < 10) {
lastdigit = same;
break;
}
same /= 10;
counter ++;
}
for(;counter >= 0; counter --) {
result += (subsums[counter] + M % pow_of_ten[counter] + 1) * lastdigit;
result += digitSum[lastdigit - 1] * pow_of_ten[counter];
if (counter == 0) {
break;
}
lastdigit = (M / pow_of_ten[counter - 1]) % 10;
}
return result;
}
int main() {
int M;
int N;
vector<long> sums;
while (true) {
cin >> M >> N;
if (M == 0 && N == 0) {
break;
}
sums.push_back(Digit_Sum(N) - Digit_Sum(M - 1));
}
for (vector<long>::iterator it = sums.begin(); it != sums.end(); ++it) {
cout << *it << endl;
}
}
For most cases this works well but an Online judge says it is wrong. I looked at other solutions that work but no one hard-coded the values in arrays the way I did. May this cause a partial problem, any ideas?
You can easily just create a for-loop to greatly simplify this code.
There is no need to go through all that effort.
for (Initialization Action, Boolean Expression, Update_Action)
Re deletion below: sorry, I have a bit influenza and mizread N as M. :(
I think a main error is M-1 in
sums.push_back(Digit_Sum(N) - Digit_Sum(M - 1));
Also noting that <when corrected that formula will only work for single-digit numbers. My comment earlier about using a simple formula was based on misunderstanding your problem description, in view of that formula and your examples. Both indicated single digit numbers only.
However, the complexity of the code appears unreasonably high. Consider this, assuming non-negative integers as input, and assuming m is always less than or equal to n:
#include <iostream>
#include <stdexcept>
using namespace std;
bool throwX() { throw std::runtime_error( "Ouch." ); }
auto main() -> int
{
for( ;; )
{
int m, n;
cin >> m >> n || throwX();
if( m == 0 && n == 0 ) { break; }
int sum = 0;
for( int i = m; i <= n; ++i )
{
for( int v = i; v != 0; v /= 10 )
{
sum += v % 10;
}
}
cout << sum << endl;
}
}
It needs not be more complicated than that.
Tested and working to spec, sans console input:
#include <iostream>
#include <string>
using namespace std;
void sum_a_to_b(const int & a, const int & b)
{
if (a <= b && a >= 0)
{
long long sum = 0;
for (int i = a; i <= b; i++)
{
sum += i;
}
cout << "Sum of digits from " << a << " through " << b << " is " << sum << ".\n";
}
}
int main()
{
sum_a_to_b(5, 6);
sum_a_to_b(1, 9);
}