Multiplying Matrices with two for loops in C++ [duplicate] - c++

I came up with this algorithm for matrix multiplication. I read somewhere that matrix multiplication has a time complexity of o(n^2).
But I think my this algorithm will give o(n^3).
I don't know how to calculate time complexity of nested loops. So please correct me.
for i=1 to n
for j=1 to n
c[i][j]=0
for k=1 to n
c[i][j] = c[i][j]+a[i][k]*b[k][j]

Using linear algebra, there exist algorithms that achieve better complexity than the naive O(n3). Solvay Strassen algorithm achieves a complexity of O(n2.807) by reducing the number of multiplications required for each 2x2 sub-matrix from 8 to 7.
The fastest known matrix multiplication algorithm is Coppersmith-Winograd algorithm with a complexity of O(n2.3737). Unless the matrix is huge, these algorithms do not result in a vast difference in computation time. In practice, it is easier and faster to use parallel algorithms for matrix multiplication.

The naive algorithm, which is what you've got once you correct it as noted in comments, is O(n^3).
There do exist algorithms that reduce this somewhat, but you're not likely to find an O(n^2) implementation. I believe the question of the most efficient implementation is still open.
See this wikipedia article on Matrix Multiplication for more information.

The standard way of multiplying an m-by-n matrix by an n-by-p matrix has complexity O(mnp). If all of those are "n" to you, it's O(n^3), not O(n^2). EDIT: it will not be O(n^2) in the general case. But there are faster algorithms for particular types of matrices -- if you know more you may be able to do better.

In matrix multiplication there are 3 for loop, we are using since execution of each for loop requires time complexity O(n). So for three loops it becomes O(n^3)

I recently had a matrix multiplication problem in my college assignment, this is how I solved it in O(n^2).
import java.util.Scanner;
public class q10 {
public static int[][] multiplyMatrices(int[][] A, int[][] B) {
int ra = A.length; // rows in A
int ca = A[0].length; // columns in A
int rb = B.length; // rows in B
int cb = B[0].length; // columns in B
// if columns of A is not equal to rows of B, then the two matrices,
// cannot be multiplied.
if (ca != rb) {
System.out.println("Incorrect order, multiplication cannot be performed");
return A;
} else {
// AB is the product of A and B, and it will have rows,
// equal to rown in A and columns equal to columns in B
int[][] AB = new int[ra][cb];
int k = 0; // column number of matrix B, while multiplying
int entry; // = Aij, value in ith row and at jth index
for (int i = 0; i < A.length; i++) {
entry = 0;
k = 0;
for (int j = 0; j < A[i].length; j++) {
// to evaluate a new Aij, clear the earlier entry
if (j == 0) {
entry = 0;
}
int currA = A[i][j]; // number selected in matrix A
int currB = B[j][k]; // number selected in matrix B
entry += currA * currB; // adding to the current entry
// if we are done with all the columns for this entry,
// reset the loop for next one.
if (j + 1 == ca) {
j = -1;
// put the evaluated value at its position
AB[i][k] = entry;
// increase the column number of matrix B as we are done with this one
k++;
}
// if this row is done break this loop,
// move to next row.
if (k == cb) {
j = A[i].length;
}
}
}
return AB;
}
}
#SuppressWarnings({ "resource" })
public static void main(String[] args) {
Scanner ip = new Scanner(System.in);
System.out.println("Input order of first matrix (r x c):");
int ra = ip.nextInt();
int ca = ip.nextInt();
System.out.println("Input order of second matrix (r x c):");
int rb = ip.nextInt();
int cb = ip.nextInt();
int[][] A = new int[ra][ca];
int[][] B = new int[rb][cb];
System.out.println("Enter values in first matrix:");
for (int i = 0; i < ra; i++) {
for (int j = 0; j < ca; j++) {
A[i][j] = ip.nextInt();
}
}
System.out.println("Enter values in second matrix:");
for (int i = 0; i < rb; i++) {
for (int j = 0; j < cb; j++) {
B[i][j] = ip.nextInt();
}
}
int[][] AB = multiplyMatrices(A, B);
System.out.println("The product of first and second matrix is:");
for (int i = 0; i < AB.length; i++) {
for (int j = 0; j < AB[i].length; j++) {
System.out.print(AB[i][j] + " ");
}
System.out.println();
}
}
}

Related

How do I fill the contents of a matrix using 9 other matrixes?

I am creating a sudoku game
I have 9 3x3 matrixes and a large 9x9 matrix. The methods I tried didn't work so please help me:
void matrix_full_creation()
{
for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
{
matrix_full[i][j]==matrix1[i][j];
matrix_full[i][j+3]=matrix2[i][j];
matrix_full[i][j+6]=matrix3[i][j];
matrix_full[i+3][j]=matrix4[i][j];
matrix_full[i+3][j+3]=matrix5[i][j];
matrix_full[i+3][j+3]=matrix6[i][j];
matrix_full[i+6][j]=matrix7[i][j];
matrix_full[i+6][j+3]=matrix8[i][j];
matrix_full[i+6][j+6]=matrix9[i][j];
}
}
}
Given a submatrix index n, and a pair of indexes within that submatrix, i.e. row index i and column index j, and
considering you want to place each submatrix at positions (0,0), (0,1)..., (3,3) of the full matrix,
you can walk each cell of each submatrix, and
use the following formula to calculate the destination cell in the full matrix:
matrix_full[3*(n / 3) + i][3*(n % 3) + j] = submatrix[i][j];
[Demo]
Let's break your task into smaller pieces.
First, write a function that copies your small matrix into specific position
void Copy(int** small, int i, int j);
So if you pass 0, 0 for i, j... It should copy contents of small into top left 3x3 submatrix of the big 9x9 matrix.
When you complete this task, just run a for loop (similar to the one you already did)
int** bigMatrix; // assume we have it here
void Copy(int** small, int i, int j) {
for(int ii = 0; ii < 3; ++ii) {
for(int jj = 0; jj < 3; ++jj) {
bigMatrix[i + ii][j + jj] = small[ii][jj];
}
}
}
int main() {
int smalls[3][3][3] = {...}; // assume we have 3x3 init here
for(int i = 0; i < 9; i += 3) {
for(int j = 0; j < 9; j += 3) {
Copy(smalls[0], i, j];
}
}
return 0;
}
Good tip: divide and conquer!
I have corrected your code. Try this:
for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
{
matrix_full[i][j]=matrix1[i][j];
matrix_full[i][j+3]=matrix2[i][j];
matrix_full[i][j+6]=matrix3[i][j];
matrix_full[i+3][j]=matrix4[i][j];
matrix_full[i+3][j+3]=matrix5[i][j];
matrix_full[i+3][j+6]=matrix6[i][j];
matrix_full[i+6][j]=matrix7[i][j];
matrix_full[i+6][j+3]=matrix8[i][j];
matrix_full[i+6][j+6]=matrix9[i][j];
}
}
Hope this helps! :D

openmp increasing number of threads increases the execution time

I'm implementing sparse matrices multiplication(type of elements std::complex) after converting them to CSR(compressed sparse row) format and I'm using openmp for this, but what I noticed that increasing the number of threads doesn't necessarily increase the performance, sometimes is totally the opposite! why is that the case? and what can I do to solve the issue?
typedef std::vector < std::vector < std::complex < int >>> matrix;
struct CSR {
std::vector<std::complex<int>> values; //non-zero values
std::vector<int> row_ptr; //pointers of rows
std::vector<int> cols_index; //indices of columns
int rows; //number of rows
int cols; //number of columns
int NNZ; //number of non_zero elements
};
const matrix multiply_omp (const CSR& A,
const CSR& B,const unsigned int num_threds=4) {
if (A.cols != B.rows)
throw "Error";
CSR B_t = sparse_transpose(B);
omp_set_num_threads(num_threds);
matrix result(A.rows, std::vector < std::complex < int >>(B.cols, 0));
#pragma omp parallel
{
int i, j, k, l;
#pragma omp for
for (i = 0; i < A.rows; i++) {
for (j = 0; j < B_t.rows; j++) {
std::complex < int > sum(0, 0);
for (k = A.row_ptr[i]; k < A.row_ptr[i + 1]; k++)
for (l = B_t.row_ptr[j]; l < B_t.row_ptr[j + 1]; l++)
if (A.cols_index[k] == B_t.cols_index[l]) {
sum += A.values[k] * B_t.values[l];
break;
}
if (sum != std::complex < int >(0, 0)) {
result[i][j] += sum;
}
}
}
}
return result;
}
You can try to improve the scaling of this algorithm, but I would use a better algorithm. You are allocating a dense matrix (wrongly, but that's beside the point) for the product of two sparse matrices. That's wasteful since quite often the project of two sparse matrices will not be dense by a long shot.
Your algorithm also has the wrong time complexity. The way you search through the rows of B means that your complexity has an extra factor of something like the average number of nonzeros per row. A better algorithm would assume that the indices in each row are sorted, and then keep a pointer for how far you got into that row.
Read the literature on "Graph Blas" for references to efficient algorithms.

How has the second algorithm become more efficient than the first one and how is the right side of the subarray moving in the second algorithm?

Question - Given an array of n numbers, our task is to calculate the maximum subarray sum, i.e., the largest possible sum of a sequence of consecutive values in the
array. The problem is interesting when there may be negative values in the array. The array = {-1,2,4,-3,5,2,-5,2}.
First algorithm -
int best = 0;
for (int a = 0; a < n; a++) {
for (int b = a; b < n; b++) {
int sum = 0;
for (int k = a; k <= b; k++) {
sum += array[k];
}
best = max(best,sum);
}
}
cout << best << "\n";
Second algorithm -
int best = 0;
for (int a = 0; a < n; a++) {
int sum = 0;
for (int b = a; b < n; b++) {
sum += array[b];
best = max(best,sum);
}
}
cout << best << "\n";
This is what it says in the book - It is easy to make Algorithm 1 more efficient by removing one loop from it. This is possible by calculating the sum at the same time when the right end of the
subarray moves.
How is the right end of the subarray moving in the second algorithm, could someone explain it to me?
The first version does a brute force comparsion of all subarrays sums for subarrays starting at index a till index b, lets call those subarrays sums subsum(a,b).
The second version is also rather brute force but uses the fact that subsum(a,b+1) == subsum(a,b) + array[b+1].
In other words: To know the sum of the first say 10 elements you can use the previously calculated sum for the first 9 elements. If you would solve the problem with pen and paper this would be obvious, but the first version is not doing that. Instead the first version has two nested loops for all combinations of a and b and always starts with a fresh sum = 0, which is rather wasteful.
Consider only the outer loops of the first version:
for (int a = 0; a < n; a++) {
for (int b = a; b < n; b++) {
int sum = 0;
// ...
}
}
Here //... calculates subsum(a,b).
In the second version:
int best = 0;
for (int a = 0; a < n; a++) {
int sum = 0;
for (int b = a; b < n; b++) {
sum += array[b];
best = max(best,sum);
}
}
The outer loop is responsible for starting the subarray at different "left ends". And the inner loop "moves" the "righ end".
The inner loop body calculates subsum(a,b) and the next iteration of the inner loop "moves" b to the next index to calculate subsum(a,b) by using the above relation: subsum(a,b) == subsum(a,b-1) + array[b]. Because a is fixed in the inner loop, the author is talking about "moving the right end".

Matrix inversion via Gaussian Elimination

I'm focusing on 3x3 matrices for now as my code is volatile. I read the matrix from a text file and print to the console, based on its dimensions I generate the identity matrix.
const int m = 3;
const int n = 3;
int ID[m][n] = {};
for (i = 1; i <= n; ++i){
ID[i][i] = 1;
}
For some reason ID(2)[3] gets printed as 4227276 so I have to force it to zero manually after the fact.
Aside from other elementary row operations like swapping rows based on leading entry position, the main chunk of my code consists of the following:
float matrix[m][n];
int i,j,k,p,s;
for(s = 1;s <= m;++s){
j = s;
k = j + 1;
p = j;
for(i = n;i >= j;--i){ // makes leading entries 1
ID[j][i] = ID[j][i]/matrix[j][j];
matrix[j][i] = matrix[j][i]/matrix[j][j];
}
for(j = k;j <= m;++j){ //converts to upper triangular
for(i = n;i >= 1;--i){
ID[j][i] = ID[j][i] - matrix[j][i]*matrix[p][i];
matrix[j][i] = matrix[j][i] - matrix[j][i]*matrix[p][i];
}
}
}
for(j = (m-1);j >= 1;--j){ //makes entries above diagonal zero
for(i = n;i > j;--i){
ID[j][i] = ID[j][i] - matrix[j][i]*matrix[i][i];
matrix[j][i] = matrix[j][i] - matrix[j][i]*matrix[i][i];
}
}
I'm basically doing to the identity matrix whatever I do to matrix[m][n] to reduce it to row echelon form as you would with the augmented matrix. The row operations are pretty haphazard as I was just doing whatever worked to make matrix[m][n] an identity matrix. Afterwards, I just slotted ID[m][n] in there... not really sure what's happening but the result is half right.
my result
right answer
I realize that I the term I subtract from ID might need to be a multiple of ID but that makes it even worse. What mistakes have I made?
In C++ the indexes of a n-dimensional array start from 0 to n-1: so the first element of the array a is a[0], the second element is a[1], ..., the n-th element is a[n-1].
When you use the for
for (i = 1; i <= n; ++i){
ID[i][i] = 1;
}
you are discarding the first elements of each row and each column, accessing moreover to memory positions that do not belong to ID (e.g. ID[n][n]) which contain some unknown values.
You have to iterate over your arrays using for cycles such as
for (i = 0; i < n; ++i){
ID[i][i] = 1;
}
or if you desire
for (i = 1; i <= n; ++i){
ID[i-1][i-1] = 1;
}
but I found last solution quite confusing.

How find parallel diagonal reverse at other diagonal in matrix 2D in C++

I have a problem to manage a two-dimensional matrix nxn in C++. My problem is create a function that control if exists any diagonal, parallel line at the principal diagonal, that is reverse to other. I controlled the two index, necessary for the rows and columns, if are different and maybe I could help me with support arrays, which reverse the elements. Perhaps it's not a good idea with a huge matrix(such as 8x8, 14 arrays) so, I am asking your help.
Thanks
This is my code:
bool funct(short **M, int rows, int columns){
bool found = false;
for(int i = 0; i < rows; i++){
for(int j = 0; j < colums; j++){
if(i != j){
//control the reverse array
}
}
}
}
ps: my primary problem is general algorithm(nxn).
In a quadratic matrix, every diagonal has exactly one other diagonal with the same length (except the principal diagonal). So you just need to check this one:
for(int diagonal = 1; diagonal < cols - 1; ++diagonal)
{
//inspect the diagonal that starts at (0, diagonal)
//the other diagonal starts at (diagonal, 0)
int diagonalLength = cols - diagonal;
//Assume that this diagonal has a reverse counterpart
bool diagonalHasReverse = true;
//Now check if it really has
for(int i = 0; i < diagonalLength; ++i)
{
if(M[i][diagonal + i] !=
M[diagonal + diagonalLength - 1 - i][diagonalLength - 1 - i])
{
diagonalHasReverse = false;
break;
}
}
//do whatever you want with diagonalHasReverse
}
The outer loop does not process the very last (one-element) diagonal. If you want to include that, you have to modify the loop as follows:
for(int diagonal = 1; diagonal < cols; ++diagonal)