Matrix multiplication using 2d vector - c++

Following is my code:
void matrix(int rowsInA, int columnsInA, int columnsInB){
std::vector< vector<int> > a;
std::vector< vector<int> > b;
for (int i = 0; i < rowsInA; i++) {
vector<int> myRow(1);
a.push_back(myRow);
for (int j = 0; j < columnsInA-1; j++) {
int x = rand() % 100;;
myRow.push_back(x);
}
}
for (int i = 0; i < rowsInA; i++) {
vector<int> myRow(1);
b.push_back(myRow);
for (int j = 0; j < columnsInB-1; j++) {
int x = rand() % 100;;
myRow.push_back(x);
}
}
std::vector< vector<int> > c = multiply(a, b);
for (int i = 0; i < rowsInA; i++) {
for (int j = 0; j < columnsInB; j++) {
cout << c[i][j];
}
}
}
std::vector< vector<int> > multiply(std::vector< vector<int> > a , std::vector< vector<int> > b) {
int rowsInA = 9;
int columnsInA = 9; // same as rows in B
int columnsInB = 9;
std::vector< vector<int> > d;
for (int i = 0; i < rowsInA; i++) {
for (int j = 0; j < columnsInB; j++) {
vector<int> myRow;
myRow.push_back(a[i][0]);
d.push_back(myRow);
for (int k = 0; k < columnsInA; k++) {
myRow.push_back(myRow[i]+ a[i][k] * b[k][j]);//error here
}
}
}
return d;
}
first function matrix() creates two vector within a vector and assigns random values to it and then call multiply in which vectors are multiplied.
It is giving vector subscript out of range error

Your code:
for (int i = 0; i < rowsInA; i++) {
vector<int> myRow(1);
a.push_back(myRow);
for (int j = 0; j < columnsInA-1; j++) {
int x = rand() % 100;;
myRow.push_back(x);
}
}
Constructs a single element vector, pushes it on to a, appends some
values to your temporary, and then throws it away. C++ is not Java or C#. The vector at the back of a is not changed by changes to myRow.
You also seem to be putting a fixed value as the first element of myRow, and
then appending randomness to it. Is that what you meant?
What you need is:
for (int i = 0; i < rowsInA; i++) {
vector<int> myRow;
myRow.reserve(columnsInA);
myRow.push_back(0); // First element fixed.
for (int j = 1; j < columnsInA; j++) {
const int x = rand() % 100;;
myRow.push_back(x);
}
a.push_back(myRow);
}
Alternatively, making all the values random, and working directly with the vector:
a.reserve(rowsInA);
for (int i = 0; i < rowsInA; i++) {
a.push_back( {} );
a.back().reserve(columnsInA);
for (int j = 0; j < columnsInA; j++) {
const int x = rand() % 100;;
a.back().push_back(x);
}
}
You have a similar problem with initializing B, and your multiply loop needs to accumulate a[i][k] * b[k][j] into a temporary sum, then push that onto myRow, and finally push myRow onto d.
Finally, when you have got this working, look up how to write a Matrix class that stores all the data in a vector with rows*cols elements and then uses an indexing function to refer to it. Your cache will thank you.

Related

Assign pointer to 2d array to an array

So I got a function which creates me 2D array and fill it with test data.
Now I need to assign the pointer to an array
//Fill matrix with test data
int *testArrData(int m, int n){
int arr[n][m];
int* ptr;
ptr = &arr[0][0];
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
*((ptr+i*n)+j) = rand()%10;
}
}
return (int *) arr;
}
int arr[m][n];
//Algorithm - transpose
for (int i = 0; i < m; i++){
for (int j = 0; j < n; j++){
arrT[j][i] = arr[i][j];
}
}
Is there any way of doing this?
There are at least four problems with the function.
//Fill matrix with test data
int *testArrData(int m, int n){
int arr[n][m];
int* ptr;
ptr = &arr[0][0];
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
*((ptr+i*n)+j) = rand()%10;
}
}
return (int *) arr;
}
First of all you declared a variable length array
int arr[n][m];
Variable length arrays are not a standard C++ feature.
The second problem is that these for loops
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
*((ptr+i*n)+j) = rand()%10;
}
}
are incorrect. It seems you mean
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
*((ptr+i*m)+j) = rand()%10;
}
}
You are returning a pointer to a local array with automatic storage duration that will not be alive after exiting the function. So the returned pointer will be invalid.
And arrays do not have the assignment operator.
Instead use the vector std::vector<std::vector<int>>. For example
std::vector<std::vector<int>> testArrData(int m, int n){
std::vector<std::vector<int>> v( n, std::vector<int>( m ) );
for ( auto &row : v )
{
for ( auto &item : row )
{
item = rand() % 10;
}
}
return v;
}
This is how I would accomplish this. I agree with int ** because it is easy to understand if you dont know how to use vectors. Also, the rand() can cause trouble if you are using the result to index an array. Make sure to use abs(rand() % number) if you don't want negative numbers.
I've updated the answer due to some vital missing code.
// This method creates the overhead / an array of pointers for each matrix
typedef int* matrix_cells;
int **create_row_col_matrix(int num_rows, int num_cols, bool init_rnd)
{
num_rows = min(max(num_rows, 1), 1000); // ensure num_rows = 1 - 1000
num_cols = min(max(num_cols, 1), 1000); // ensure num_cols = 1 - 1000
int *matrix_total = new int[num_rows*num_cols];
// overhead: create an array that points to each row
int **martix_row_col = new matrix_cells[num_rows];
// initialize the row pointers
for (int a = 0; a < num_rows; ++a)
{
// initialize the array of row pointers
matrix_row_col[a] = &matrix_total[num_cols*a];
}
// assign the test data
if (init_rnd)
{
for (int run_y = 0; run_y < num_rows; ++run_y)
{
for (int run_x = 0; run_x < num_cols; ++run_x)
{
matrix_row_col[run_y][run_x] = abs(rand() % 10);
}
}
}
return matrix_row_col;
}
int src_x = 7, dst_x = 11;
int src_y = 11, dst_y = 7;
int **arr_src = create_row_col_matrix(src_y, src_x, true);
int **arr_dst = create_row_col_matrix(dst_y, dst_x, false);
for (int a = 0; a < dst_y; ++a)
{
for (int b = 0; b < dst_x; ++b)
{
arr_dst[a][b] = arr_src[b][a];
}
}
delete matrix_src[0]; // int *matrix_total = new int[src_y*src_x]
delete matrix_src; // int **matrix_row_col = new matrix_cell[src_y]
delete matrix_dst[0]; // int *matrix_total = new int[dst_y*dst_x]
delete matrix_dst; // int **matrix_row_col = new matrix_cell[dst_y]
// the overhead is matrix_src and matrix_dst which are arrays of row pointers
// the row pointers makes it convenient to address the cells as [rown][coln]

How to transferring an array of main functions to a class?

First of all, I made this class.
class Matrix
{
public:
double ele[4][4];
int numOfRow;
int numOfColumns;
public:
Matrix() {
numOfRow = 0;
numOfColumns = 0;
ele[4][4] = 0;
}
Matrix(double mat[][4], int Row, int Col) {
numOfRow = Row;
numOfColumns = Col;
for (int i = 0; i < numOfRow; i++) {
for (int j = 0; i < numOfColumns; j++) {
ele[i][j] = mat[i][j];
}
}
}
Matrix Add(Matrix m) {
Matrix output;
for (int i = 0; i < numOfRow; i++) {
for (int j = 0; j < numOfColumns; j++) {
output.ele[i][j] = ele[i][j] + m.ele[i][j];
}
}
return output;
}
Matrix Subtract(Matrix m);
Matrix Multiply(Matrix m);
Matrix Transpose(void);
};
This is part of the main function. In this way, I'm going to bring up the values of the txt files that I've already made in matA and matB and replace them. It's just a process of putting numbers in.
double matA[4][4];
for (int i = 0; i < RowA; i++) {
for (int j = 0; j < ColA; j++) {
fscanf(fpInput, "%lf", &matA[i][j]);
}
}
double matB[4][4];
for (int i = 0; i < RowB; i++) {
for (int j = 0; j < ColB; j++) {
fscanf(fpInput, "%lf", &matB[i][j]);
}
}
And we substitute matrixA and matrixB class objects, respectively.
Matrix matrixA(matA, RowA, ColA);
Matrix matrixB(matB, RowB, ColB);
I tried substitute Value obtained by 'Add' function into class object called matrixO. but, The substituted values did not work smoothly. For example, if matrixA contains (1, 2, 3) in order and matrixB has (4, 5, 6), then the 'add function' requires that the array of matrixO contains (5, 7, 9), but it does not. The value of the matrixO.ele is not output at all.
Matrix matrixO = matrixA.Add(matrixB);
for (int i = 0; i < RowA; i++) {
for (int j = 0; j < ColA; j++) {
fprintf(fpOutput, "%lf ", matrixO.ele[i][j]);
printf("%lf", matrixO.ele[i][j]);
}
fprintf(fpOutput, "\n");
}
In the Matrix constructor section, I changed it like this.
public:
Matrix() {
numOfRow = 0;
numOfColumns = 0;
ele[4][4] = ele[0][0];
}
public:
Matrix() {
numOfRow = 0;
numOfColumns = 0;
ele[4][4] = {};
}
But both of these cases are wrong. How do we solve this issue?
You are assigning a value to your matrix out-of-bounds:
ele[4][4] = 0;
The last element of double ele[4][4]; is ele[3][3];
This is undefined behavior, so it makes no sense to analyze what happens after it.
You can 0-initialize your Matrix in its constructor like this:
Matrix(): ele(), numOfRow(), numOfColumns() {}

Multi Dimensional vectors

Require a 2D-vector with a pair(int, int) as elements.The following code gives SIGSEGV on running.How can it be resolved ?
int main()
{
vector< vector<pair<int, int> > >v;
//vector< vector<pair<int, int> > >v(3), problem is resolved, but how ?
for(int i = 0; i < 3; ++i)
for(int j = 0; j < 3; ++j)
v[i].push_back(make_pair(i, j));
for(int i = 0; i < 3; ++i)
{
cout<<"\n";
for(int j = 0; j < 3; ++j)
cout<<"{"<<v[i][j].first<<", "<<v[i][j].second<<"} ";
}
return 0;
}
In the beginning, v contains solely nothing, so the SIGSEGV if received at
v[0].push_back(make_pair(0, 0)); // First loop
If you initialize v with a length of 3, then v[0] is a valid statement and won't cause a segmentation fault.
The following code should work if you don't initialize v with a size.
for(int i = 0; i < 3; ++i){
vector<pair<int,int> > t;
for(int j = 0; j < 3; ++j)
t.push_back(make_pair(i, j));
v.push_back(std::move(t));
}
Thanks to Zereges for code improvement
You are inserting wrong.
for(int i = 0; i < 3; ++i)
for(int j = 0; j < 3; ++j)
v[i].push_back(make_pair(i, j));
Change your code of insertion like below to work properly:
for(int i = 0; i < 3; ++i)
{
vector<pair<int, int>> vctr;
for(int j = 0; j < 3; ++j)
{
vctr.push_back(make_pair(i, j));
}
v.push_back(vctr);
}
create a vector of pair, lets say: (vctr), then insert pair<i,j> in (vctr).
and then insert vctr to vector (v).

How do I copy the elements of a 2D array onto a 1D vector?

So i keep trying to transfer the elements but it keeps giving me repeated elements, it fails to properly copy the 2D array onto a 1D vector
// This was one of my attempts
vector<int> rando(int rowsize, int columnsize)
{
int elements = rowsize*columnsize;
vector<int> x(elements);
int matrix[100][100];
for(int i = 0; i < rowsize; i++)
{
for(int j = 0; j < columnsize; j++)
{
srand((int)time(0));
matrix[i][j]= -10 + rand() % 21;
for(int n=0; n < elements; n++)
x[n]=matrix[i][j];
}
// Ive also tried this
for(int n=0; n < elements; n++)
{
for(int i = 0; i < rowsize; i++)
{
for(int j = 0; j < columnsize; j++)
{
x[n]=matrix[i][j];
}
}
}
}
return x;
}
Why do you want to store data into the matrix first and copy it into the vector afterwards? Use the vector from the start.
std::vector<int> rando(std::size_t rowsize, std::size_t columnsize)
{
std::vector<int> v(rowsize*columnsize);
std::mt19937 mt{std::random_device{}()};
std::uniform_int_distribution<int> rand_dist(-10, 10);
for (auto & e : v) e = rand_dist(mt);
return v;
}
If you want to transfer data from a matrix into a vector you must calculate the proper index or just increment a single variable as Thomas Matthews suggests.
constexpr std::size_t n = 100, m = 100;
int matrix[n][m];
// do stuff with matrix
std::vector<int> v(n*m);
for (std::size_t i=0; i<n; ++i)
{
for (std::size_t j=0; j<m; ++j)
{
v[i*m + j] = matrix[i][j];
}
}
THe general copy should loop through the 2 dimensions, and just increment the target index at each iteration (no third nested loop):
int n=0;
for(int i = 0; i < rowsize; i++)
{
for(int j = 0; j < columnsize; j++)
{
...
x[n++]=matrix[i][j]; // not in an additional for loop !!
}
} // end of initialisation of matrix
If your matrix is a 2D array (i.e. contiguous elements) you can also take the following shortcut using <algorithm>:
copy (reinterpret_cast<int*>(matrix), reinterpret_cast<int*>(matrix)+elements, x.begin());
Try this:
unsigned int destination_index = 0;
for(int i = 0; i < rowsize; i++)
{
for(int j = 0; j < columnsize; j++)
{
x[destination_index++]=matrix[i][j];
}
}
The destination index is incremented after each assignment to a new slot.
No need for a 3rd loop.
It is enough to use two loops.
For example
srand((int)time(0));
for(int i = 0; i < rowsize; i++)
{
for(int j = 0; j < columnsize; j++)
{
matrix[i][j]= -10 + rand() % 21;
x[i * columnsize + j] = matrix[i][j];
}
}
In general if you have a two-dimensional array and want to copy nRows and nCols of each row elements in a vector then you can use standard algorithm std::copy declared in header <algorithm>
For example
auto it = x.begin();
for ( int i = 0; i < nRows; i++ )
{
it = std::copy( matrix[i], matrix[i] + nCols, it );
}

C++ create array with dynamic size

How can I create a array with dinamic size like this:
int sentLen = sentences.size();
double a[sentLen][sentLen];
for (int i = 0; i < sentLen; i++)
{
for (int j = 0; j < sentLen; j++)
{
a[i][j] = somefunction(i, j);
}
}
My research led me to malloc which isn't recommended or other too complicated methods. After I realised that size must be constant, I tried using unordered_map, and I have tried the following:
std::unordered_map <int, int, double> a;
for (int i = 0; i < sentLen; i++)
{
for (int j = 0; j < sentLen; j++)
{
a.insert({ i, j, somefunc(i, j) });
}
}
but still unsuccessful.
You don't really want to use arrays.
std::vector<std::vector<double>> a{
sentLen, std::vector<double>{ sentLen, 0.0 } };
for (int i = 0; i < sentLen; ++i)
{
for (int j = 0; j < sentLen; ++j)
{
a[i][j] = somefunc(i, j);
}
}
You're getting an error because you can't use variables as static array sizes. They must be known at compile time. You have to allocate dynamically or use a vector instead.