I dont know why but my matrix multipication is very slow and I need to optimize it. and also the print of the matrix (1000X1000) taking long time.
The aim of the function is to calculate the matrix exponential, but my main problem is that this 2 actions are very slow for large matrices like 1000X1000.
These 2 actions implemented at poweMat() function and printeResult() function.
Here is the code:
#define M 1000
#define e 2.71828182845904523536;
//declaration of the functions
void sumMatrices(vector<vector<double> >& mat1, vector<vector<double> >& mat2);
void printResult(vector<vector<double> >&matRes);
void mulMatWithFactorial(long factorialValue);
long factorialCalculate(int n);
void initializeMatrix();
void initializeIdenticalMatrix();
void checkIfTheMatrixIsDiagonal();
void calculateExpoMatrixWithDiagonalMatrix();
void readMatrixFromFile();
void powerMat(vector<vector<double> >& mat, int powNum);
//declaration of the variables
vector<vector<double>> inputMatrix(M, vector<double>(M));
vector<vector<double>> sumMatrixResult(M, vector<double>(M));
vector<vector<double>> powerMatrixResult(M, vector<double>(M));
vector<vector<double>> mulFactorialMatrixResult(M, vector<double>(M));
vector<vector<double>> finalMatrixResult(M, vector<double>(M));
vector<vector<double>> identicalMatrix(M, vector<double>(M));
vector<vector<vector<double>>> listOfMatrices;
bool matrixIsNilpotent = false;
int diagonaMatrixlFlag = 1;
int main() {
//variables
long factorialValue;
initializeIdenticalMatrix();
readMatrixFromFile();
//check if the matrix is diagonal - so we will have easier and faster compute
checkIfTheMatrixIsDiagonal();
if (diagonaMatrixlFlag == 1) {
calculateExpoMatrixWithDiagonalMatrix();
goto endOfLoop;
}
//loop for taylor series
for (int i = 0; i < 5; i++) {
if (i == 0) { // first we add identical matrix when the power is 0
sumMatrices(finalMatrixResult, identicalMatrix); // summarize between this 2 matrices
finalMatrixResult = sumMatrixResult; //copy matrices
}
if (i == 1) { // we add the matrix itself because the power is 1
sumMatrices(finalMatrixResult, inputMatrix);
finalMatrixResult = sumMatrixResult; //copy matrices
}
if (i > 1 ) {
powerMat(inputMatrix, i);
if (matrixIsNilpotent) { // it means that A^i is 0 for some integer, so the series terminates after a finite number
goto endOfLoop;
}
factorialValue = factorialCalculate(i); // calculate the factorial of i
mulMatWithFactorial(factorialValue); // multiply (1/i) * matrix^i - like in the algorithm
sumMatrices(finalMatrixResult, mulFactorialMatrixResult); // summarize it with the previous result
finalMatrixResult = sumMatrixResult; //copy matrices
}
}
endOfLoop:
printResult(finalMatrixResult); // print the final result - e^M
return 0;
}
//Summarize matrices
void sumMatrices(vector<vector<double> >& mat1, vector<vector<double> >& mat2) {
for (int i = 0; i < M; i++)
for (int j = 0; j < M; j++)
sumMatrixResult[i][j] = mat1[i][j] + mat2[i][j];
}
//Print matrix
void printResult(vector<vector<double> >& matRes) {
for (int i = 0; i < M; i++) {
for (int j = 0; j < M; j++) {
printf("%f ", matRes[i][j]);
if (j == M - 1) {
printf("\n");
}
}
}
}
//Calculate the factorial of n
long factorialCalculate(int n) {
long factorial = 1.0;
for (int i = 1; i <= n; ++i) {
factorial *= i;
}
return factorial;
}
// mutiply the matrix with scalar
void mulMatWithFactorial(long factorialValue) {
for (int i = 0; i < M; i++) {
for (int j = 0; j < M; j++) {
mulFactorialMatrixResult[i][j] = powerMatrixResult[i][j] * 1/factorialValue;
}
}
}
//initialize matrix
void initializeMatrix() {
for (int i = 0; i < M; i++) {
for (int j = 0; j < M; j++) {
powerMatrixResult[i][j] = 0;
}
}
}
void checkIfTheMatrixIsDiagonal() {
for (int i = 0; i < M; i++) {
for (int j = 0; j < M; j++) {
if (i == j)
{
if (inputMatrix[i][j] == 0) {
diagonaMatrixlFlag = 0;
goto endOfLoop;
}
}
else
{
if (inputMatrix[i][j] != 0) {
diagonaMatrixlFlag = 0;
goto endOfLoop;
}
}
}
}
endOfLoop:
return;
}
void calculateExpoMatrixWithDiagonalMatrix() {
for (int i = 0; i < M; i++) {
for (int j = 0; j < M; j++) {
if (i == j)
{
for (int k = 0; k < inputMatrix[i][j]; ++k)// loop to calculate the pow of e^alpha
{
finalMatrixResult[i][j] *= e;
}
}
else
{
finalMatrixResult[i][j] = 0;
}
}
}
}
void readMatrixFromFile() {
ifstream f("inv_matrix(1000x1000).txt");
for (int i = 0; i < M; i++)
for (int j = 0; j < M; j++) {
f >> inputMatrix[i][j];
if (f.peek() == ',')
f.ignore();
}
listOfMatrices.push_back(inputMatrix);
}
void initializeIdenticalMatrix() {
for (int i = 0; i < M; i++) {
for (int k = 0; k < M; k++) {
if (i == k) {
identicalMatrix[i][k] = 1;
}
else {
identicalMatrix[i][k] = 0;
}
}
}
}
void powerMat(vector<vector<double> >& mat, int powNum) {
int counterForNilpotent = 0;
initializeMatrix();
auto start = high_resolution_clock::now();
for (int i = 0; i < M; i++) {
for (int k = 0; k < M; k++) {
for (int j = 0; j < M; j++) {
powerMatrixResult[i][j] += mat[i][k] * listOfMatrices[powNum-2][k][j];
}
}
}
auto stop = high_resolution_clock::now();
auto duration = duration_cast<seconds>(stop - start);
cout << duration.count() << " seconds" << endl; // checking run time
listOfMatrices.push_back(powerMatrixResult);
// check if after we we did A^i , the matrix is equal to 0
for (int i = 0; i < M; i++) {
for (int j = 0; j < M; j++) {
if (powerMatrixResult[i][j] == 0) {
counterForNilpotent++;
}
}
}
if (counterForNilpotent == M * M) {
matrixIsNilpotent = true;
}
}
Going through each element of an array of size "n" will have some computational efficiency of O(n^2), meaning for large arrays it will take a while but won't be "life-time-of-the-universe" lengths of time.
Usually to do operations on massive arrays like this, they're reduced in some form first so that the computation can be closer to O(n) or better using some truths about reduced forms of matrices.
So, a faster implementation for matrix multiplication would start with some rref() function upon both matrices and then only evaluating parts of those matrices that would have objects in the columns and rows.
Here are some great places to review/learn (for free) Linear Algebra:
"3b1b (2016): Essence of Linear Algebra" = https://www.youtube.com/watch?v=kjBOesZCoqc&list=PL0-GT3co4r2y2YErbmuJw2L5tW4Ew2O5B
"MIT OpenCourseWare (2009): Linear Algebra" = https://www.youtube.com/watch?v=ZK3O402wf1c&list=PL49CF3715CB9EF31D&index=1
Use SSE2. It’s not a library. It’s a method to use cpu vector hardware.
You set up operations to run in parallel.
https://en.wikipedia.org/wiki/SSE2
Related
I need make Pascal Triangle matrix using vectors and then print it.
This algorithm would work with arrays, but somehow it doesn't work with matrix using vectors.
#include <iomanip>
#include <iostream>
#include <vector>
typedef std::vector<std::vector<int>> Matrix;
int NumberOfRows(Matrix m) { return m.size(); }
int NumberOfColumns(Matrix m) {
if (m.size() != 0)
return m[0].size();
return 0;
}
Matrix PascalTriangle(int n) {
Matrix mat;
int a;
for (int i = 1; i <= n; i++) {
a = 1;
for (int j = 1; j <= i; j++) {
if (j == 1)
mat.push_back(j);
else
mat.push_back(a);
a = a * (i - j) / j;
}
}
return mat;
}
void PrintMatrix(Matrix m, int width) {
for (int i = 0; i < NumberOfRows(m); i++) {
for (int j = 0; j < NumberOfColumns(m); j++)
std::cout << std::setw(width) << m[i][j];
std::cout << std::endl;
}
}
int main() {
Matrix m = PascalTriangle(7);
PrintMatrix(m, 10);
return 0;
}
I get nothing on screen, and here's the same code just without matrix using vectors program (which works fine).
Could you help me fix this code?
The main problem is that in PascalTriangle, you are starting out with an empty Matrix in both the number of rows and columns.
Since my comments mentioned push_back, here is the way to use it if you did not initialize the Matrix with the number of elements that are passed in.
The other issue is that NumberOfColumns should specify the row, not just the matrix vector.
The final issue is that you should be passing the Matrix by const reference, not by value.
Addressing all of these issues, results in this:
Matrix PascalTriangle(int n)
{
Matrix mat;
for (int i = 0; i < n; i++)
{
mat.push_back({}); // creates a new empty row
std::vector<int>& newRow = mat.back(); // get reference to this row
int a = 1;
for (int j = 0; j < i + 1; j++)
{
if (j == 0)
newRow.push_back(1);
else
newRow.push_back(a);
a = a * (i - j) / (j + 1);
}
}
return mat;
}
And then in NumberOfColumns:
int NumberOfColumns(const Matrix& m, int row)
{
if (!m.empty())
return m[row].size();
return 0;
}
And then, NumberOfRows:
int NumberOfRows(const Matrix& m) { return m.size(); }
And last, PrintMatrix:
void PrintMatrix(const Matrix& m, int width)
{
for (int i = 0; i < NumberOfRows(m); i++)
{
for (int j = 0; j < NumberOfColumns(m, i); j++)
std::cout << std::setw(width) << m[i][j];
std::cout << std::endl;
}
}
Here is a live demo
Your code won't compile because you have numerous errors in PascalTriangle.
For one, you initialize a matrix with no elements. Additionally, you use matrix indices starting at 1 rather than 0.
The following prints things for me:
Matrix PascalTriangle(int n) {
Matrix mat(n, std::vector<int>(n, 0)); // Construct Matrix Properly
int a;
for (int i = 0; i < n; i++) { // Start index at 0
a = 1;
for (int j = 0; j < i + 1; j++) { // Start index at 0
if (j == 0) // Changed 1 to 0
mat[i][j] = 1;
else
mat[i][j] = a;
a = a * (i - j) / (j+1); // Changed j to j+1 since j starts at 0
}
}
return mat;
}
A great deal of unexpected numbers outputted on my console window when I compiled and ran the program.
The class "matrix" is declared as below:
class matrix
{
public:
vector<vector<int> > M;
matrix();
matrix(int m, int n);
matrix(vector<vector<int> > &m);
matrix Mul(matrix m1);
void Inverse();
bool SquareMatrix();
void GetDet();
int Det(vector<vector<int> > &m);
void Print();
};
the member function "Mul":
matrix matrix::Mul(matrix m1)
{
vector<vector<int> > Temp(M.size(), vector<int>(m1.M[0].size(), 0));
if (M[0].size() != m1.M.size())
{
cout << "Cannot do multiplication!" << endl;
return matrix();
}
else
{
for (int i = 0; i < M.size(); i++)
{
for (int j = 0; j < m1.M[0].size(); j++)
{
int ele_buf = 0;
for (int k = 0; k < M[0].size(); k++)
{
ele_buf += M[i][k] * m1.M[k][j];
}
Temp[i][j] = ele_buf;
}
}
}
int d1 = M.size(), d2 = m1.M[0].size();
for (int i = 0; i < M.size(); i++)
{
M[i].clear();
}
M.clear();
M.resize(Temp.size(), vector<int>(Temp[0].size(), 0));
for (int i = 0; i < d1; i++)
{
for (int j = 0; j < d2; j++)
{
M[i][j] = Temp[i][j];
}
}
}
M[i][j] hold the expected value at this point.
the member function "Print":
void matrix::Print()
{
for (int i = 0; i < M.size(); i++) {
for (int j = 0; j < M[0].size(); j++) {
cout << M[i][j] << " ";
}
cout << endl;
}
}
Output wrong M.
main:
/*
call constructor to initialize m1 and m2
*/
//...
matrix m3 = m1.Mul(m2);
m3.Print();
//...
How can I fix it?
I'm new here, plz let me know if I didn't make my question clear.
Editted:
matrix matrix::Mul(matrix m1)
{
vector<vector<int> > Temp(M.size(), vector<int>(m1.M[0].size(), 0));
if (M[0].size() != m1.M.size())
{
cout << "Cannot do multiplication!" << endl;
return matrix();
}
else
{
//TO_DO: Multiply two matrixes and print the result.
for (int i = 0; i < M.size(); i++)
{
for (int j = 0; j < m1.M[0].size(); j++)
{
int ele_buf = 0;
for (int k = 0; k < M[0].size(); k++)
{
ele_buf += M[i][k] * m1.M[k][j];
}
Temp[i][j] = ele_buf;
}
}
}
int d1 = M.size(), d2 = m1.M[0].size();
for (int i = 0; i < M.size(); i++)
{
M[i].clear();
}
M.clear();
return matrix(Temp);
}
Functionning properly,
thanks.
You forgot to add a return statement, which is trivial to fix. However, your code is not written in a good OO manner, so here come few suggestions for the improvement:
don't pass matrix m1 by value, because you are paying an expensive copy each time you invoke this function; use const matrix& m1 instead
in the body of Mul you are modifying member M, which is a serious side effect; remove the part of code:
int d1 = M.size(), d2 = m1.M[0].size();
for (int i = 0; i < M.size(); i++)
{
M[i].clear();
}
M.clear();
instead of implementing a separate function called Mul, overload the * operator (see e.g. here and here)
You are promised to return matrix from the Mul function
matrix matrix::Mul(matrix m1);
^^^^^^
and you did not keep the promise. This can cause undefined behaviour to your program.
Add an proper return statement in the function.
matrix matrix::Mul(matrix m1)
{
// ... code
return *this; // matrix(Temp) itself
}
I've tried to write a program that should be able to calculate the inverse of a matrix:
Here's what I have so far:
#include <iostream>
#include <vector>
#include <math.h>
#include <iomanip>
#include <stdexcept>
double getDeterminant(const std::vector<std::vector<double>> vect) {
if(vect.size() != vect[0].size()) {
throw std::runtime_error("Matrix is not quadratic");
}
int dimension = vect.size();
if(dimension == 0) {
return 1;
}
if(dimension == 1) {
return vect[0][0];
}
//Formula for 2x2-matrix
if(dimension == 2) {
return vect[0][0] * vect[1][1] - vect[0][1] * vect[1][0];
}
double result = 0;
int sign = 1;
for(int i = 0; i < dimension; i++) {
//Submatrix
std::vector<std::vector<double>> subVect(dimension - 1, std::vector<double> (dimension - 1));
for(int m = 1; m < dimension; m++) {
int z = 0;
for(int n = 0; n < dimension; n++) {
if(n != i) {
subVect[m-1][z] = vect[m][n];
z++;
}
}
}
//recursive call
result = result + sign * vect[0][i] * getDeterminant(subVect);
sign = -sign;
}
return result;
}
std::vector<std::vector<double>> getTranspose(const std::vector<std::vector<double>> matrix1) {
//Transpose-matrix: height = width(matrix), width = height(matrix)
std::vector<std::vector<double>> solution(matrix1[0].size(), std::vector<double> (matrix1.size()));
//Filling solution-matrix
for(size_t i = 0; i < matrix1.size(); i++) {
for(size_t j = 0; j < matrix1[0].size(); j++) {
solution[j][i] = matrix1[i][j];
}
}
return solution;
}
std::vector<std::vector<double>> getCofactor(const std::vector<std::vector<double>> vect) {
if(vect.size() != vect[0].size()) {
throw std::runtime_error("Matrix is not quadratic");
}
std::vector<std::vector<double>> solution(vect.size(), std::vector<double> (vect.size()));
std::vector<std::vector<double>> subVect(vect.size() - 1, std::vector<double> (vect.size() - 1));
for(std::size_t i = 0; i < vect.size(); i++) {
for(std::size_t j = 0; j < vect[0].size(); j++) {
int p = 0;
for(size_t x = 0; x < vect.size(); x++) {
if(x == i) {
continue;
}
int q = 0;
for(size_t y = 0; y < vect.size(); y++) {
if(y == j) {
continue;
}
subVect[p][q] = vect[x][y];
q++;
}
p++;
}
solution[i][j] = pow(-1, i + j) * getDeterminant(subVect);
}
}
return solution;
}
std::vector<std::vector<double>> getInverse(const std::vector<std::vector<double>> vect) {
if(getDeterminant(vect) == 0) {
throw std::runtime_error("Determinant is 0");
}
double d = 1.0/getDeterminant(vect);
std::vector<std::vector<double>> solution(vect.size(), std::vector<double> (vect.size()));
for(size_t i = 0; i < vect.size(); i++) {
for(size_t j = 0; j < vect.size(); j++) {
solution[i][j] = vect[i][j] * d;
}
}
return getTranspose(getCofactor(solution));
}
void printMatrix(const std::vector<std::vector<double>> vect) {
for(std::size_t i = 0; i < vect.size(); i++) {
for(std::size_t j = 0; j < vect[0].size(); j++) {
std::cout << std::setw(8) << vect[i][j] << " ";
}
std::cout << "\n";
}
}
int main() {
std::vector<std::vector<double>> matrix(3, std::vector<double> (3));
matrix = {
{1,2,3},
{4,5,6},
{7,8,8}
};
printMatrix(getInverse(matrix));
return 0;
}
The functions for calculating the determinant, the transpose- and the cofactor-matrix work correctly (as far as I can see), but the function for calculating the inverse-matrix doesn't.
I searched the internet and found this, which uses the same function for calculating the inverse.
Is this formula incorrect, or do you have any other idea, why it doesnt work?
The matrix I am using is
and the inverse of it should be
First of all, thanks for your comments.
The problem was the order of execution.
The correct solution is:
std::vector<std::vector<double>> getInverse(const std::vector<std::vector<double>> vect) {
if(getDeterminant(vect) == 0) {
throw std::runtime_error("Determinant is 0");
}
double d = 1.0/getDeterminant(vect);
std::vector<std::vector<double>> solution(vect.size(), std::vector<double> (vect.size()));
for(size_t i = 0; i < vect.size(); i++) {
for(size_t j = 0; j < vect.size(); j++) {
solution[i][j] = vect[i][j];
}
}
solution = getTranspose(getCofactor(solution));
for(size_t i = 0; i < vect.size(); i++) {
for(size_t j = 0; j < vect.size(); j++) {
solution[i][j] *= d;
}
}
return solution;
}
I know this is an old question but your code does not work when the input matrix's dimension is 1. Here is a workaround that I used:
vector<vector<double>> inverse(const vector<vector<double>> A) {
double d = 1.0/det(A);
vector<vector<double>> solution(A.size(), vector<double> (A.size()));
if(A.size() == 1){
vector<double> ans = {0};
ans[0] = 1.0/det(A);
solution[0] = ans;
return solution;
}
for(size_t i = 0; i < A.size(); i++) {
for(size_t j = 0; j < A.size(); j++) {
solution[i][j] = A[i][j] * d;
}
}
return transpose(cofactor(solution));
}
I am trying to transpose a matrix built with vectors.
Here is the transpose function I wrote:
void transpose(std::vector<std::vector<int>>& fill_mat) {
for (int i = 0; i < fill_mat.size(); ++i) {
for (int j = 0; j < fill_mat.size(); ++j) {
std::swap(fill_mat[i][j], fill_mat[j][i]);
}
}
}
It doesn't seem to be doing anything: my final results are the same as the starting ones.
Here is my full program:
#include<iostream>
#include<vector>
#include<utility>
void print_matrix(std::vector<std::vector<int>>& to_print) {
for (int i = 0; i < to_print.size(); ++i) {
for (int j = 0; j < to_print.size(); ++j) {
std::cout << " " << to_print[i][j];
}
std::cout << std::endl;
}
}
void make_matrix(std::vector<std::vector<int>>& fill_mat) {
for (int i = 0; i < fill_mat.size(); ++i) {
for (int j = 0; j < fill_mat.size(); ++j) {
fill_mat[i][j] = rand() % 15;
}
}
}
void transpose(std::vector<std::vector<int>>& fill_mat) {
for (int i = 0; i < fill_mat.size(); ++i) {
for (int j = 0; j < fill_mat.size(); ++j) {
std::swap(fill_mat[i][j], fill_mat[j][i]);
}
}
}
int main() {
int size = 3;
std::vector<std::vector<int>> matrix_sample(size, std::vector<int>(size));
make_matrix(matrix_sample);
print_matrix(matrix_sample);
transpose(matrix_sample);
std::cout << "----## transpose ##-----" << std::endl;
print_matrix(matrix_sample);
}
I expected to print out the transposed matrix but the input ends up being the same as the output. What am I doing wrong?
You swap (i,j) with (j,i) twice! That's why it has no effect.
You should only work on one half of your matrix. Plus minors improvements, we get:
void transpose(std::vector<std::vector<int>>& fill_mat)
{
using size_type = decltype(fill_mat)::size_type; // better use your matrix' size type
for (size_type i = 0; i < fill_mat.size(); ++i) {
for (size_type j = 0; j < i; ++j) {
using std::swap; // see swap idiom
swap(fill_mat[i][j], fill_mat[j][i]);
}
}
}
I'm trying to calculate the Covariance (matrix) of a vector in C++ ...
I have carried out the following:
std::vector<std::vector<double> > data = { {2.5, 2.4}, {0.5, 0.7} };
I have then calculated and subtracted the mean, which gave the following result:
data = { {0.05, -0.05}, {-0.1, 0.1} }
As far as I'm aware, the next step is to transpose the matrix, and multiply the origin together, take the sum and finally divide by the dimensions X - 1..
I have written the following:
void cover(std::vector<std::vector<double> > &d)
{
double cov = 0.0;
for(unsigned i=0; (i < d.size()); i++)
{
for(unsigned j=0; (j < d[i].size()); j++)
{
cov += d[i][j] * d[j][i] / (d[i].size() - 1);
std::cout << cov << " ";
}
std::cout << std::endl;
}
}
Where d is the vector after the mean has been subtracted from each of the points
Which gives me the result:
0.0025, 0.0075
0.0125, 0.0225
Where compared with matlab:
2.0000 1.7000
1.7000 1.4450
Does anyone have any ideas to where I am going wrong?
Thanks
This statement:
As far as I'm aware, the next step is to transpose the matrix, and multiply the origin together, take the sum and finally divide by the dimensions X - 1..
And this implementation:
cov += d[i][j] * d[j][i] / (d[i].size() - 1);
Don't say the same thing. Based on the definition here:
void outer_product(vector<double> row, vector<double> col, vector<vector<double>>& dst) {
for(unsigned i = 0; i < row.size(); i++) {
for(unsigned j = 0; j < col.size(); i++) {
dst[i][j] = row[i] * col[j];
}
}
}
//computes row[i] - val for all i;
void subtract(vector<double> row, double val, vector<double>& dst) {
for(unsigned i = 0; i < row.size(); i++) {
dst[i] = row[i] - val;
}
}
//computes m[i][j] + m2[i][j]
void add(vector<vector<double>> m, vector<vector<double>> m2, vector<vector<double>>& dst) {
for(unsigned i = 0; i < m.size(); i++) {
for(unsigned j = 0; j < m[i].size(); j++) {
dst[i][j] = m[i][j] + m2[i][j];
}
}
}
double mean(std::vector<double> &data) {
double mean = 0.0;
for(unsigned i=0; (i < data.size());i++) {
mean += data[i];
}
mean /= data.size();
return mean;
}
void scale(vector<vector<double>> & d, double alpha) {
for(unsigned i = 0; i < d.size(); i++) {
for(unsigned j = 0; j < d[i].size(); j++) {
d[i][j] *= alpha;
}
}
}
So, given these definitions, we can compute the value for the covariance matrix.
void compute_covariance_matrix(vector<vector<double>> & d, vector<vector<double>> & dst) {
for(unsigned i = 0; i < d.size(); i++) {
double y_bar = mean(d[i]);
vector<double> d_d_bar(d[i].size());
subtract(d[i], y_bar, d_d_bar);
vector<vector<double>> t(d.size());
outer_product(d_d_bar, d_d_bar, t);
add(dst, t, dst);
}
scale(dst, 1/(d.size() - 1));
}
I think maybe For loop in outer_product it's wrong:
void outer_product(vector<double> row, vector<double> col, vector<vector<double>>& dst) {
for(unsigned i = 0; i < row.size(); i++) {
for(unsigned j = 0; j < col.size(); i++) {
dst[i][j] = row[i] * col[j];
}
}
I will change i++ -> j++