0

In my implementation of some equation I need to build a NXN diagonal matrix.I'm using vector of vectors for representing matrices. However the N is around 300000 so,

std::vector<std::vector<double> > new_matrix(300000,std::vector<double>(300000,0)) 

on running, gives me

terminate called after throwing an instance of 'std::bad_alloc'

  what():  std::bad_alloc

Is this not possible due to memory limit?

Imanpal Singh
  • 1,105
  • 1
  • 12
  • 22
  • 6
    For reference, that's about 670GiB of information... which is quite a bit. Need a pretty hefty computer to deal with that much! – N. Shead Mar 21 '20 at 07:42
  • 4
    Just how much memory do you have? This will be at least `300000 * 300000 * 8 = 670GB` of memory. – JohnFilleau Mar 21 '20 at 07:42
  • I wouldn't even have that much space on harddrive. Luckily, for a diagonal matrix you need only 300000 elements (everything else is 0), if memory serves ;) But I think you really need some different approach, you can't keep all the data in memory at once. – Lukas-T Mar 21 '20 at 07:44
  • By different approach do you mean, performing some mathematical changes to the equation or some coding approach? – Imanpal Singh Mar 21 '20 at 07:49
  • @ImanpalSingh Maybe you can chang/simplify the equation, yes. Try to take advantage of the special structure of a diagonal matrix. – Lukas-T Mar 21 '20 at 07:53
  • 2
    I propose to take one step back and describe what you want to achieve by the approach you describe. Have a look at this concept to understand what I mean https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem – Yunnosch Mar 21 '20 at 07:55
  • 2
    Is there any chance that you are dealing with a [sparse matrix](https://en.wikipedia.org/wiki/Sparse_matrix)? – Bob__ Mar 21 '20 at 08:12
  • 1
    Its a *NxN* matrix that holds `p(x1;B) * (1 - p(x1;B))` at diagonals for the optimization using newton-raphson method for the cost function of Logistic Regression. – Imanpal Singh Mar 21 '20 at 08:41

1 Answers1

3

The question can be answered generally: Dealing with large amounts of data in c++

In your case,

The error is due to insufficient contiguous heap memory for a

300,000 * 300,000 vector of double precision floating point numbers.

Maybe, a different container could be preferred that does not need contiguous memory like std::list. But wait, what would be the amount of memory needed for this?

300000 * 300000 * sizeof(double) =

300000 * 300000 * 8 =

720000000000 bytes =

703125000 KB =

686646 MB =

671 GB!

Unless you are working with a supercomputer, forget about this idea.

Back in the olden days, programmers had to come up with clever solutions to work within the limits of tiny RAM. Why not do it today? Let's start by digging patterns in your problem. You are working with a

Diagonal matrix:

A matrix having non-zero elements only in the diagonal running from the upper left to the lower right

Therefore, you do not have to store the non-diagonal elements in the memory because it is guaranteed that those elements are 0. So the problem boils down to storing just the main diagonal elements (matrix[0][0], matrix[1][1],... matrix[n-1][n-1]), a total of n elements only. Now you can consider just 300000 elements, which is way shorter than 90000000000!

Calculating the memory for this:

300000 * sizeof(double) =

300000 * 8 =

2400000 bytes =

2344 KB =

2.3 MB!

As you can see, this approach has reduced our requirement from 670 GB to just 2 MB. It might still not work on some stack memory but it doesn't matter because we are dealing with heap memory (std::vector is a dynamic array).

Now that we have reduced the space complexity, it is just a matter of implementing this logic. But be careful to maintain this convention throughout while accessing, traversing, and storing the array.

For example:

#include <iostream>
#include <vector>

typedef std::vector<double> DiagonalMatrix;

int main()
{
    // std::vector<std::vector<double>> new_matrix(300000, std::vector<double>(300000, 0));
    DiagonalMatrix m(300000, 0);

    // Store the main diagonal elements only

    // Keep this convention in mind while using this implementation of DiagonalMatrix

    return 0;
}

Edit:

To demonstrate this design and after your request in the comments, below is an implementation of the necessary logic:

// Product = DiagonalMatrix * Matrix
Matrix DiagonalMatrix::preMultiply(Matrix multiplier)
{
    // Check if multiplication is possible
    if (multiplier.r != this->n)
        return Matrix();

    // Product is the same as the multiplier where
    // every element in the ith row of the multiplier is
    // multiplied by the ith diagonal element of the diagonal matrix
    Matrix& product = multiplier;
    for (int i = 0; i < multiplier.r; ++i)
    {
        for (int j = 0; j < multiplier.c; ++j)
        {
            product.m[i][j] *= this->m[i];
        }
    }
    return product;
}

// Product = Matrix * DiagonalMatrix
Matrix DiagonalMatrix::postMultiply(Matrix multiplier)
{
    // Check if multiplication is possible
    if (multiplier.c != this->n)
        return Matrix();

    // Product is the same as the multiplier where
    // every element in the jth column of the multiplier is
    // multiplied by the jth diagonal element of the diagonal matrix
    Matrix& product = multiplier;
    for (int j = 0; j < multiplier.c; ++j)
    {
        for (int i = 0; i < multiplier.r; ++i)
        {
            product.m[i][j] *= this->m[j];
        }
    }
    return product;
}
Ardent Coder
  • 3,777
  • 9
  • 27
  • 53
  • Thanks, But I have to multiply the diagonal matrix with other matrices. So I have to come up with a separate algorithm for multiplying then? – Imanpal Singh Mar 21 '20 at 08:44
  • @ImanpalSingh Alright, I was searching for an example to demonstrate this implementation. I'll take this, wait for the edit. But before the edit, is that it or do you need anything more? Because I would like to know how you are going to store *other matrices* of such an order!? – Ardent Coder Mar 21 '20 at 08:49
  • 1
    My other matrices are not of this order except for the Feature Matrix which is about the size of *300000 x 8* and my prediction matrix of order *300000 x 1* and they didn't throw any `std::std::bad_alloc`. – Imanpal Singh Mar 21 '20 at 08:53
  • @ImanpalSingh I'm having to type lots of code because of this general description. Could you post a different question for this purpose where you are just seeking for the algorithm to multiply a matrix with a diagonal matrix? Please be specific with the order of all the matrices, and whether you want to pre-multiply or post-multiply. – Ardent Coder Mar 21 '20 at 09:06
  • I don't mind writing an algorithm of my own for such application . I just wanted to know if there was already an implementation for this. Thank you – Imanpal Singh Mar 21 '20 at 09:30
  • 1
    @ImanpalSingh You may read [this](https://scicomp.stackexchange.com/questions/351/recommendations-for-a-usable-fast-c-matrix-library) until I finish my implementation. – Ardent Coder Mar 21 '20 at 09:34
  • Yes those are great libraries. But I'm looking for writing my own functions. However I can look up on how those libraries implement the functions. Thanks again. – Imanpal Singh Mar 21 '20 at 10:07
  • 1
    Yes, that is really helpful. – Imanpal Singh Mar 21 '20 at 10:13