couldn't find the determinant of n*n matrix - c++

I have written the following code to calculate the determinant of a N*N matrix. it works perfectly for the matrix 4*4 and 5*5. but it could not find the determinant of the 40*40 matrix named Z_z. The elements of matrix Z_z are presented herein.
#include <iostream>
int const N_M=40;
void getCofactor(double A[N_M][N_M], double A_rc[N_M][N_M], int r,int c, int n)
{ int i = 0, j = 0;
// Looping for each element of the matrix
for (int row = 0; row < n; row++)
{
for (int col = 0; col < n; col++)
{
// Copying into temporary matrix only those element
// which are not in given row and column
if (row != r && col != c)
{
A_rc[i][j] = A[row][col];
j=j+1;
// Row is filled, so increase row index and
// reset col index
if (j == n - 1)
{
j = 0;
i=i+1;
}
}
}
}
}
double determinant(double A[N_M][N_M], int n)
{ double D = 0.0; // Initialize result
// Base case : if matrix contains single element
if (n==1) return A[0][0];
else if (n == 2) return (A[0][0]*A[1][1])-(A[0][1]*A[1][0]);
else {
double sub_Matrix_A_0c[N_M][N_M]; // To store cofactors
// Iterate for each element of first row
for (int c = 0; c < n; c++)
{
// Getting Cofactor of A[0][f]
getCofactor(A, sub_Matrix_A_0c, 0, c, n);
D += pow(-1.0,c) * A[0][c] * determinant(sub_Matrix_A_0c, n - 1);
}
return D;}
}
int main () {
double Z_z[N_M][N_M]=
{{-64,16,-4,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{-43.7213019529827,12.4106746539480,-3.52287874528034,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,-43.7213019529827,12.4106746539480,-3.52287874528034,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,-27,9,-3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,-27,9,-3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,-16.0579142269798,6.36491716338729,-2.52287874528034,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,-16.0579142269798,6.36491716338729,-2.52287874528034,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,-8,4,-2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-8,4,-2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-3.53179897265895,2.31915967282662,-1.52287874528034,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-3.53179897265895,2.31915967282662,-1.52287874528034,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,1,-1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,1,-1,1,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-0.142956190020121,0.273402182265940,-0.522878745280338,1,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-0.142956190020121,0.273402182265940,-0.522878745280338,1,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2.20222621658426,1.69267904961742,1.30102999566398,1},
{37.2320239618439,-7.04575749056068,1,0,-37.2320239618439,7.04575749056068,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,27,-6,1,0,-27,6,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,19.0947514901619,-5.04575749056068,1,0,-19.0947514901619,5.04575749056068,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,12,-4,1,0,-12,4,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6.95747901847985,-3.04575749056068,1,0,-6.95747901847985,3.04575749056068,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,-2,1,0,-3,2,-1,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.820206546797821,-1.04575749056068,1,0,-0.820206546797821,1.04575749056068,-1,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,-1,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,2,1,0,-3,-2,-1,0},
{-21.1372724716820,2,0,0,21.1372724716820,-2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,-18,2,0,0,18,-2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,-15.1372724716820,2,0,0,15.1372724716820,-2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,-12,2,0,0,12,-2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-9.13727247168203,2,0,0,9.13727247168203,-2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-6,2,0,0,6,-2,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-3.13727247168203,2,0,0,3.13727247168203,-2,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,-2,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,2,0,0,-6,-2,0,0},
{24,-2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-7.80617997398389,-2,0,0}};
double det=determinant(Z_z, 40);
cout<<det;
system ("pause");
return 0;}

You recursively call determinant() functuon n times at the first stage, then n - 1 times for each of n calls, etc. So total number of call would be closed to n! (factorial).
When n = 4 or n = 5 the number of calls is still acceptable, but at n = 40 you try to make 40! = 815915283247897734345611269596115894272000000000 virtual calls to say nothing about so many operations of any kind. I don't think you can find a machine to handle that.

Related

recursive implementation of nested for-loops (variable branching factors) to generate Catalans numbers

I am given the number of trees of size N with branching factor b and attempting to generate Catalans number without the use of a separate recursive function to generate the the number of nested for loops.
Ive tried this so far
int catalan(int size, int b)
{
int n = 0;
int c = b;
if (size < 2)
{
return 1;
}
if (b <= 0)
{
return n;
}
while(c--)
{
for (int s = 0; s < size; s++)
{
n += (catalan(s,b) * catalan(size-1-s-c, b) );
}
catalan(size--,c);
}
return n;
}
for a size of 4 and branching factor of 2 I expect this function to return 14 but instead I receive 21.
thanks in advance.

Trying to find the smallest number in a 2D array using recursion

I'm trying to find the smallest number in a 2D (pointer to pointer) array using recursion, here is the code so far:
int smallest(int **arr, int row_size, int column_size)
{
if (row_size == 0 && column_size == 0)
{
return *(*(arr + 0) + 0);
}
row_size--;
column_size--;
if ((*(*(arr + 0) + 0)) < (*(*arr + row_size) + column_size))
{
return smallest(arr, row_size, column_size);
}
else
{
*(*(arr + 0) + 0) = *(*(arr + row_size) + column_size);
return smallest(arr, row_size, column_size);
}
}
This works but has 2 drawbacks:
1- Only processes square arrays.
2- Only processes indexes where row & column numbers are the same (such as 1,1 2,2 & 3,3 etc.)
I'm trying to make it process non-square arrays as well but that would require decrementing rows and column numbers at different times, I'm not sure how to go about that. Any clues?
Bored professionals overkill introductory problems, volume 3! This version:
Uses a secondary function to traverse each row (that might be off-limits of the question's rules, but you can combine them and switch on whether the pointers array has only one row)
Works with empty arrays (and returns the maximal value of an int)
Does not use index notation
Is purely recursive
int smallest(int const * const array, int const length) {
return length == 0
? std::numeric_limits<int>::max()
: std::min(*array, smallest(array + 1, length - 1));
}
int smallest(int const * const * const array, int const rows, int const columns) {
return rows == 0
? std::numeric_limits<int>::max()
: std::min(
smallest(*array, columns), // Minimum from the current row
smallest(array + 1, rows - 1, columns) // Minimum from the rest of the rows
);
}
See it live on Coliru
not tested, but I think it would work.
#include <algorithm>
#include <limits>
//call with row = row_size-1, column = column_size -1
int smallest(int **arr, int row, int column)
{
if( row<0 || column<0 )return std::numeric_limits<int>::max();
return std::min( {arr[row][column], smallest(arr,row-1,column), smallest(arr,row,column-1)} );
}
The recursion is
Assumed requirements:
Cannot modify function signature (can be simpler if this is not the case)
Can only have a single function (ditto)
Must be purely recursive (i.e. no loops)
Must use pointer dereferencing (*(arr + 1) instead of arr[1])
Procedure:
Recurse through the first row only (setting rows to 1)
Recurse through all other rows (decrement rows)
Code:
int smallest(int **arr, int rows, int columns)
{
// invalid input
if (rows <= 0 || columns <= 0)
return INT_MAX;
// top-left element
int m = **arr;
// single row recursion
if (rows == 1) {
*arr++; // increment the temporary pointer from below
return min(m, smallest(arr, 1, columns - 1));
}
// create a temporary pointer to the first row
// and start recursion in this single row
int* row = *arr;
m = min(m, smallest(&row, 1, columns));
// rest of array
return min(m, smallest(arr + 1, rows, columns - 1));
}
EDIT: since you are allowed to modify the function signature, you can add an extra index for looping through each row; this removes the need for that extra temporary pointer.
int smallest(int **arr, int rows, int columns, int column_index = 0)
{
// invalid input
if (rows <= 0 || column_index >= columns)
return INT_MAX;
// single row recursion
if (rows == 1)
return min(*(*arr + column_index), // first element of row
smallest(arr, 1, columns - 1,
column_index + 1)); // rest of row
// rest of array
return min(smallest(arr, 1, columns), // start on first row
smallest(arr + 1, rows - 1, columns));
}
Note that external call signatures can still be the same as before due to the default argument value.
You'll need to pass the matrix bounds to the function so you can "move" in one dimension when you reach the end of the other.
Something like this (I find it more natural to count upwards than downwards):
int smallest(int **arr, int row, int column, int row_last, int column_last)
{
if (row == row_last && column == column_last)
{
return arr[row][column];
}
else if (column == column_last)
{
return min(arr[row][column], smallest(arr, row+1, 0, row_last, column_last));
}
else
{
return min(arr[row][column], smallest(arr, row, column+1, row_last, column_last));
}
}
(This is one of those exercises that introduces potentially useful concepts in a situation where they don't serve any purpose. It's not a good use of either recursion or pointer arithmetic.)
Though you can get away without recursion, if this is a purely learning excercise for recursion you could try DFS approach.
Have an entry point to start your search (i,j), from each point exhaust all possible areas you could go, (i+1,j)(i-1,j)(i,j+1)(i,j-1). Each recursion step would also check if you are in within the limits of the array which would be i < 0 || i >= rows || j < 0 || j >= cols || visited[i][j] you would just return at this point.
Notice the visited array. So at each point in the recursion there could be a chance that you return back to the same cell right? that would make it an infinite recrusion to avoid this, you track which cells you have already visited, visited[i][j]. Mark them. Each recrusion call keep track of the minimum element recorded by reference, which will be your minimum element.
void findMinElement(vector<vector<int>>& array, int& minelement, int i, int j, vector<vector<bool>>& visited)
{
if(i < 0 || i >= array.size() || j < 0 || j >= array[0].size() || visited[i][j]) return;
minelement = min(minelement,array[i][j]); // is this the best minimum?
visited[i][j] = true; // done visiting this cell
//lets visits others
findMinElement(array, minelement, i+1, j, visited);
findMinElement(array, minelement, i-1, j, visited);
findMinElement(array, minelement, i, j+1, visited);
findMinElement(array, minelement, i, j-1, visited);
}
int main()
{
vector<vector<int>> array =
{
{9,8,6,4},
{13,4,6,11},
{3,8,3,100}
};
int minElement = INT32_MAX;
//same dimensions as array
vector<vector<bool>> visited(array.size(), vector<bool>(array[0].size(),false));
//start from (0,0)
findMinElement(array,minElement,0,0,visited);
cout << minElement;
}
This now gives you the flexibility to start searching from any location in the array as well. It might be a bit to take in, but it will help you with many problems further down the line.
I couldn't help myself. This is an implementation that will divide the input array into four smaller arrays and calls iself on them (unless they are zero size):
int smallest(int **arr, int row_begin, int row_end, int column_begin, int column_end)
{
if (row_end - row_begin == 1 && column_end - column_begin == 1) return *(*(arr + row_begin) + column_begin);
int row_mid = (row_begin + row_end) / 2;
int column_mid = (column_begin + column_end) / 2;
int minimum = smallest(arr, row_mid, row_end, column_mid, column_end);
if (column_mid > column_begin) {
int m = smallest(arr, row_mid, row_end, column_begin, column_mid);
if (m < minimum) minimum = m;
}
if (row_mid > row_begin) {
int m = smallest(arr, row_begin, row_mid, column_begin, column_end);
if (m < minimum) minimum = m;
}
if (column_mid > column_begin && row_mid > row_begin) {
int m = smallest(arr, row_begin, row_mid, column_begin, column_mid);
if (m < minimum) minimum = m;
}
return minimum;
}
Call it like this:
cout << smallest(test_array, 0, rows, 0, columns);
I would do something like:
int smallest(int **arr, int row_size, int column_size)
{
if (row_size > 0 && column_size > 0)
{
int minRow = arr[0][0];
for (int j = 0; j < row_size; ++j)
{
const int *row = arr[j];
minRow = std::min(minRow, *std::min_element(row, row + column_size));
}
return minRow;
}
else return INT_MAX;
}

Calculating the determinant of a matrix

I am trying to calculate the determinant of a square matrix using row operations.
I ran into this code but I do not really understand how it works.
What do subi and subj do? Does it use row operations?
What is the logic behind this code?
int c, subi, i, j, subj;
double submat[10][10],d=0;
if (n == 2) {
return((mat[0][0] * mat[1][1]) - (mat[1][0] * mat[0][1]));
}
else {
for (c = 0; c < n; c++) {
subi = 0;
for (int i = 1; i < n; i++) {
subj = 0;
for (j = 0; j < n; j++) {
if (j == c)
continue;
submat[subi][subj] = mat[i][j];
subj++;
}
subi++;
}
d = d + (pow(-1, c)*mat[0][c] * determinant(n - 1, submat));
}
}
return d;
The function, which looks like:
double determinant(int n, double mat[10][10]);
recursively goes through rows and calls itself on the submatrices for that row and the first column return a value for all by matrices. The recursion ends for 2 by 2 matrices.
This is a recursive function using Laplace expansion to calculate the determinant whose base case is a 2 by 2 matrix.
However, it does not seem to be a good program to me for:
what if the input is a 1 by 1 matrix
submat is limited by size of 10 by 10
submat is a waste of memory
When matrix is large, it is better to use LU decomposition.

Backtracking - Filling a grid with coins

I was trying to do this question i came across while looking up interview questions. We are asked the number of ways of placing r coins on a n*m grid such that each row and col contain at least one coin.
I thought of a backtracking solution, processing each cell in the grid in a row major order, I have set up my recursion in this way. Seems my approach is faulty because it outputs 0 every time. Could someone please help me find the error in my approach. ? Thanks.
constraints. n , m < 200 and r < n*m;
Here is the code i came up with.
#include<cstdio>
#define N 201
int n, m , r;
int used[N][N];
int grid[N][N] ; // 1 is coin is placed . 0 otherwise. // -1 undecided.
bool isOk()
{
int rows[N];
int cols[N];
for(int i = 0 ; i < n ; i++) rows[i] = 0;
for(int i = 0 ; i < m ; i++) cols[i] = 0;
int sum = 0;
for(int i = 0 ; i < n ; i++)for(int j = 0; j < m ; j++)
{
if(grid[i][j]==1)
{
rows[i]++;
cols[j]++;
sum++;
}
}
for(int i = 0 ; i < n ; i++)
{
if(rows[i]==0) return false;
}
for(int j = 0 ; j < n ; j++)
{
if(cols[j]==0) return false;
}
if(sum==r) return true;
else return false;
}
int calc_ways(int row , int col, int coins)
{
if(row >= n) return 0;
if(col >= m) return 0;
if(coins > r) return 0;
if(coins == r)
{
bool res = isOk();
if(res) return 1;
else 0;
}
if(row == n - 1 and col== m- 1)
{
bool res = isOk();
if(res) return 1;
else return 0;
}
int nrow, ncol;
if(col + 1 >= m)
{
nrow = row + 1;
ncol = 0;
}
else
{
nrow = row;
ncol = col + 1;
}
if(used[row][col]) return calc_ways(nrow, ncol, coins);
int ans = 0;
used[row][col] = 1;
grid[row][col] = 0;
ans += calc_ways(nrow , ncol , coins);
grid[row][col] = 1;
ans += calc_ways(nrow , ncol , coins + 1);
return ans;
}
int main()
{
int t;
scanf("%d" , &t);
while(t--)
{
scanf("%d %d %d" , &n , &m , &r);
for(int i = 0 ; i <= n ; i++)
{
for(int j = 0; j <= m ; j++)
{
used[i][j] = 0;
grid[i][j] = -1;
}
}
printf("%d\n" , calc_ways(0 , 0 , 0 ));
}
return 0;
}
You barely need a program to solve this at all.
Without loss of generality, let m <= n.
To begin with, we must have n <= r, otherwise no solution is possible.
Then, we subdivide the problem into a square of size m x m, on to which we will place m coins along the major diagonal, and a remainder, on to which we will place n - m coins so as to fulfil the remaining condition.
There is one way to place the coins along the major diagonal of the square.
There are m^(n - m) possibilities for the remainder.
We can permute the total so far in n! ways, although some of those will be duplicates (how many is left as an exercise for the student).
Furthermore, there are r - n coins left to place and (m - 1)n places left to put them.
Putting these all together we have an upper bound of
1 x m^(n - m) x n! x C((m - 1)n, r - n)
solutions to the problem. Divide this number by the number of duplicate permutations and you're done.
Problem 1
The code will start by placing a coin on each square and marking each square as used.
It will then test the final position and decide that the final position does not meet the goal of r coins.
Next it will start backtracking, but will never actually try another choice because used[row][col] is set to 1 and this shortcircuits the code to place coins.
In other words, one problem is that entries in "used" are set, but never cleared during the recursion.
Problem 2
Another problem with the code is that if n,m are of size 200, then it will never complete.
The issue is that this backtracking code has complexity O(2^(n*m)) as it will try all possible combinations of placing coins (many universe lifetimes for n=m=200...).
I would recommend you look at a different approach. For example, you might want to consider dynamic programming to compute how many ways there are of placing "k" coins on the remaining "a" columns of the board such that we make sure that we place coins on the "b" rows of the board that currently have no coins.
It can be treated as total ways in which d grid can b filled with r coins -(total ways leaving a single row nd filling in d rest -total ways leaving a single column nd filling in d rest- total ways leaving a row nd column together nd filling d rest) which implies
p(n*m ,r) -( (p((n-1)*m , r) * c(n,1)) +(p((m-1)*n , r) * c(m,1))+(p((n-1)*(m-1) , r) * c(n,1)*c(m,1)) )
I just think so but not sure of it!

Sparse Matrix multiplication like (maxmin) in C++ using Octave libraries

I'm implementing a maxmin function, it works like matrix multiplication but instead of summing products it gets max of min between two numbers pointwise. An example of naive implementation is
double mx = 0;
double mn = 0;
for (i = 0; i < rowsC;i++)
{
for(j = 0; j < colsC;j++)
{
mx = 0;
for(k = 0; k < colsA; k++)
{
if (a(i, k) < b(k, j))
mn = a(i,k);
else
mn = b(k,j);
if (mn > mx)
mx = mn;
}
c(i, j) = mx;
}
}
I'm coding it as an Octave oct-file so i have to use oct.h data structure. The problem is that i want to implement a sparse version, but usually you need a reference to the next non zero element in a row or in a column like in this example (see 4.3 algorithm):
http://www.eecs.harvard.edu/~ellard/Q-97/HTML/root/node20.html
There doing row_p->next gave the next nonzero element of the row (the same for the column). Is there a way to do the same with the octave SparseMatrix class? Or is there another way of implementing the sparse matrix multiplication i can adopt for my maxmin function?
I don't know if anyoe would ever be interested, but i managed to find a solution.
The code of the solution is part of fl-core1.0 a fuzzy logic core package for Octave and it is released under LGPL license.
(The code relies on some octave functions)
// Calculate the S-Norm/T-Norm composition of sparse matrices (single thread)
void sparse_compose(octave_value_list args)
{
// Create constant versions of the input matrices to prevent them to be filled by zeros on reading.
// a is the const reference to the transpose of a because octave sparse matrices are column compressed
// (to cycle on the rows, we cycle on the columns of the transpose).
SparseMatrix atmp = args(0).sparse_matrix_value();
const SparseMatrix a = atmp.transpose();
const SparseMatrix b = args(1).sparse_matrix_value();
// Declare variables for the T-Norm and S-Norm values
float snorm_val;
float tnorm_val;
// Initialize the result sparse matrix
sparseC = SparseMatrix((int)colsB, (int)rowsA, (int)(colsB*rowsA));
// Initialize the number of nonzero elements in the sparse matrix c
int nel = 0;
sparseC.xcidx(0) = 0;
// Calculate the composition for each element
for (int i = 0; i < rowsC; i++)
{
for(int j = 0; j < colsC; j++)
{
// Get the index of the first element of the i-th column of a transpose (i-th row of a)
// and the index of the first element of the j-th column of b
int ka = a.cidx(i);
int kb = b.cidx(j);
snorm_val = 0;
// Check if the values of the matrix are really not 0 (it happens if the column of a or b hasn't any value)
// because otherwise the cidx(i) or cidx(j) returns the first nonzero element of the previous column
if(a(a.ridx(ka),i)!=0 && b(b.ridx(kb),j)!=0)
{
// Cicle on the i-th column of a transpose (i-th row of a) and j-th column of b
// From a.cidx(i) to a.cidx(i+1)-1 there are all the nonzero elements of the column i of a transpose (i-th row of a)
// From b.cidx(j) to b.cidx(j+1)-1 there are all the nonzero elements of the column j of b
while ((ka <= (a.cidx(i+1)-1)) && (kb <= (b.cidx(j+1)-1)))
{
// If a.ridx(ka) == b.ridx(kb) is true, then there's a nonzero value on the same row
// so there's a k for that a'(k, i) (equals to a(i, k)) and b(k, j) are both nonzero
if (a.ridx(ka) == b.ridx(kb))
{
tnorm_val = calc_tnorm(a.data(ka), b.data(kb));
snorm_val = calc_snorm(snorm_val, tnorm_val);
ka++;
kb++;
}
// If a.ridx(ka) == b.ridx(kb) ka should become the index of the next nonzero element on the i column of a
// transpose (i row of a)
else if (a.ridx(ka) < b.ridx(kb))
ka++;
// If a.ridx(ka) > b.ridx(kb) kb should become the index of the next nonzero element on the j column of b
else
kb++;
}
}
if (snorm_val != 0)
{
// Equivalent to sparseC(i, j) = snorm_val;
sparseC.xridx(nel) = j;
sparseC.xdata(nel++) = snorm_val;
}
}
sparseC.xcidx(i+1) = nel;
}
// Compress the result sparse matrix because it is initialized with a number of nonzero element probably greater than the real one
sparseC.maybe_compress();
// Transpose the result
sparseC = sparseC.transpose();
}