I am trying to multiply as column major and I can't seem to find the right formula!
I want to have the matrices as 1D.
Let's say I have these matrices:
A=
1 3
2 4
and B=
5 2 1
6 3 7
The above matrices are assumed that are stored already in column major order.
I am trying:
int main(int argc, const char* argv[]) {
int rows=2;
int cols=3;
int A[rows*rows];
int B[rows*cols];
int res[rows*cols];
A[0]=1;
A[1]=3;
A[2]=2;
A[3]=4;
B[0]=5;
B[1]=2;
B[2]=1;
B[3]=6;
B[4]=3;
B[5]=7;
/*A[0]=1;
A[1]=2;
A[2]=3;
A[3]=4;
B[0]=5;
B[1]=6;
B[2]=2;
B[3]=3;
B[4]=1;
B[5]=7;
*/
//multiplication as column major
for (int i=0;i<rows;i++){
for (int j=0;j<cols;j++){
res[i+j*rows]=0;
for (int k=0;k<rows;k++){
res[i+j*rows]+=A[i+k*rows]*B[k+j*cols];
}
}
}
for (int i=0;i<rows*cols;i++){
printf("\n\nB[%d]=%d\t",i,res[i]);
}
return 0;
}
I am not getting the correct results.
Also,I can't understand (in the case where the matrices are stored in column major already) ,how to index the matrices A and B.
A[0]=1;
A[1]=3;
...
or
A[0]=1;
A[1]=2;
...
I don't want to transpose the matrices and then use row major.
I want to handle the data as column major.
Because the indices ,if stored as column major,will be different (hence,will matter in order to do the multiplication).
There are two things that lead to your confusion here.
First, the data in your contiguous one-dimensional vector is not in column-major order as you say, but in row-major order, as is the usual layout of two-dimensional contiguous arrays in C. The linear one-dimensional indices of row i and column j in a matrix with M rows and N columns (MxN) are:
A[i*N + j] // row major
A[i + M*j] // column major
The "major" refers to the dimension of the outer loop when traversing the array sequentially with two nested loops:
n = 0;
for (i = 0; i < M; i++) {
for (j = 0; j < N; j++) {
printf("%8d", A[n++]);
}
printf("\n");
}
Second, you use the two dimensions rows and columns which are the dimensions of the resulting matrix, which is confusing, because the number of columns in A is rows.
In fact, there are three different dimensions involved in matrix multiplication when you multiply an MxL matrix A with an LxN matrix B to get an MxN matrix C. In your case, M and L happen to be both 2:
L (k) | N (j)
|
| 5 2 1
L (k) |
| 6 3 7
|
-----------------+-------------
|
1 3 | 23 11 22
M (i) |
2 4 | 34 16 30
|
The letters in parentheses are the variables the code below uses to iterate over the respective dimension.
Now you can multiply your matrices in row-major format:
#define M 2
#define N 3
#define L 2
int A[M * L] = {1, 3, 2, 4};
int B[L * N] = {5, 2, 1, 6, 3, 7};
int res[M * N];
int i, j, k;
for (i = 0; i < M; i++) {
for (j = 0; j < N; j++) {
res[j + i * N] = 0;
for (k = 0; k < L; k++) {
res[j + i * N] += A[k + i * L] * B[j + k * N];
}
}
}
for (i = 0; i < M * N; i++) printf("[%d] = %d\n", i, res[i]);
or in column-major format:
#define M 2
#define N 3
#define L 2
int A[M * L] = {1, 2, 3, 4};
int B[L * N] = {5, 6, 2, 3, 1, 7};
int res[M * N];
int i, j, k;
for (i = 0; i < M; i++) {
for (j = 0; j < N; j++) {
res[j * M + i] = 0;
for (k = 0; k < L; k++) {
res[j * M + i] += A[k * M + i] * B[j * L + k];
}
}
}
for (i = 0; i < M * N; i++) printf("[%d] = %d\n", i, res[i]);
Both input and output are in the respective matrix representation and differ in the two cases, of course.
What do you think about
res[i+j*rows]+=A[i+k*rows]*B[k+j*cols];
what it will do?
It will access array res, A and B out of bound when i and k becomes 1 and j becomes 2.
res[1+2*2]+=A[1+1*2]*B[1+2*3] = res[5]+=A[4]*B[7];
This will invoke undefined behavior and you may get either expected or unexpected result.
I think you need this:
res[i*rows+j] += A[i*rows + k] * B[j + k*cols];
Related
I am trying the following:
Eigen::SparseMatrix<double> bijection(2 * face_count, 2 * vert_count);
/* initialization */
Eigen::VectorXd toggles(2 * vert_count);
toggles.setOnes();
Eigen::SparseMatrix<double> deformed;
deformed = bijection * toggles;
Eigen is returning an error claiming:
error: static assertion failed: THE_EVAL_EVALTO_FUNCTION_SHOULD_NEVER_BE_CALLED_FOR_DENSE_OBJECTS
586 | EIGEN_STATIC_ASSERT((internal::is_same<Dest,void>::value),THE_EVAL_EVALTO_FUNCTION_SHOULD_NEVER_BE_CALLED_FOR_DENSE_OBJECTS);
According to the eigen documentaion
Sparse matrix and vector products are allowed. What am I doing wrong?
The problem is you have the wrong output type for the product.
The Eigen documentation states that the following type of multiplication is defined:
dv2 = sm1 * dv1;
Sparse matrix times dense vector equals dense vector.
If you actually do need a sparse representation, I think there is no better way of getting one than performing the multiplication as above and then converting the product to a sparse matrix with the sparseView member function. e.g.
Eigen::SparseMatrix<double> bijection(2 * face_count, 2 * vert_count);
/* initialization */
Eigen::VectorXd toggles(2 * vert_count);
toggles.setOnes();
Eigen::VectorXd deformedDense = bijection * toggles;
Eigen::SparseMatrix<double> deformedSparse = deformedDense.sparseView();
This can be faster than outputting to a dense vector if it is very sparse. Otherwise, 99/100 times the conventional product is faster.
void sparsem_densev_sparsev(const SparseMatrix<double>& A, const VectorX<double>& x, SparseVector<double>& Ax)
{
Ax.resize(x.size());
for (int j = 0; j < A.outerSize(); ++j)
{
if (A.outerIndexPtr()[j + 1] - A.outerIndexPtr()[j] > 0)
{
Ax.insertBack(j) = 0;
}
}
for (int j_idx = 0; j_idx < Ax.nonZeros(); j_idx++)
{
int j = Ax.innerIndexPtr()[j_idx];
for (int k = A.outerIndexPtr()[j]; k < A.outerIndexPtr()[j + 1]; ++k)
{
int i = A.innerIndexPtr()[k];
Ax.valuePtr()[j_idx] += A.valuePtr()[k] * x.coeff(i);
}
}
}
For a (probably not optimal) self-adjoint version (lower triangle), change the j_idx loop to:
for (int j_idx = 0; j_idx < Ax.nonZeros(); j_idx++)
{
int j = Ax.innerIndexPtr()[j_idx];
int i_idx = j_idx;//i>= j, trick to improve binary search
for (int k = A.outerIndexPtr()[j]; k < A.outerIndexPtr()[j + 1]; ++k)
{
int i = A.innerIndexPtr()[k];
Ax.valuePtr()[j_idx] += A.valuePtr()[k] * x.coeff(i);
if (i != j)
{
i_idx = std::distance(Ax.innerIndexPtr(), std::lower_bound(Ax.innerIndexPtr() + i_idx, Ax.innerIndexPtr() + Ax.nonZeros(), i));
Ax.valuePtr()[i_idx] += A.valuePtr()[k] * x.coeff(j);
}
}
}
Dear Friends I am having problem to transpose a matrix. The transposed matrix has elements that are undefined. Not sure what is wrong. Thank you for your time!
entries[i] is the dynamic array storing the elements in the matrix. Elements are stored row by row, from left to right. i.e. in a 3X3 matrix, entries[2] is 3rd element on the 1st row, entries[3] is 1st element on the 2nd row
n is the number of rows of matrix
m is the number of columns of matrix
Matrix Matrix::Transpose() const {
double* temp;
temp = new double[n * m];
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
temp[(j - 1) * m + i - 1] = entries[(i - 1) * m + j - 1];
}
Matrix Result(m, n, temp);
delete temp;
return Result;
}
When the original matrix is a square, all elements of the transposed matrix are defined. When the original matrix is 1x3, then the resulting transposed 3x1 matrix has undefined elements for the 2nd and 3rd elements. I.e. (1 1 3) after transposed returns (1 -3452346326236 -12351251515)
The Matrix Print out function is below. The error likely comes from here too.
void Matrix::Print() const
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
cout << setw(13) << entries[(i - 1) * m + j - 1];
cout << endl;
}
}
When the matrix is not square, the line
temp[(j - 1) * m + i - 1] = entries[(i - 1) * m + j - 1];
is not right. It needs to be:
temp[(j - 1) * n + i - 1] = entries[(i - 1) * m + j - 1];
// ^^ needs to be n, not m.
Think of the 2D analogue. You want to use:
temp[j][i] = entries[i][j];
entries is a n x m matrix. For it, the 2D indices [i][j] are translated as [i*m + j] for the 1D index.
temp is a m x n matrix. For it, the 2D indices [j][i] are translated as [j*n + i] for the 1D index.
Suggestion for improved readability
Instead of n and m, use num_rows, and num_columns. You will find your code a lot more readable.
The following loop generates the desired output, but I feel there is a more armadillo like way to produce the same result. Possible with .each_col() but I could not get it to work properly.
mat1 = n x 8, mat2 = n x 8, mat3 = n x 64,
arma v6.1, c++98
for (unsigned i= 0; i< 8; i++)
{
for (unsigned j= 0; j < 8; j++)
{
mat3.col(i * 8 + j) = mat1.col(i) % mat2.col(j);
}
}
I am trying to solve the following problem. Let's say I have a symmetric matrix with size n. I want to take all the "important values", and store them into a vector. Let me give an example to explain it better.
Let's say I have the following matrix A = [1, 2, 3 // 2, 5, 6 // 3, 6, 9]. I want to define vector of size n*(n+1)/2 such that:
V = [A(0,0), A(0,1), A(0,2), A(1,1), A(1,2), A(2,2) ]
I want to find a function that receives as input two integer i and j, and outputs the corresponding value of the matrix. The catch is that I do not want to access the matrix directly, instead I want to access the vector.
This is my reasoning so far. If I have an input with j < i, I just swap them since the matrix is symmetric. If I have that i == 0, the position in the array is just j. If that is not the case, I think I need to do something like this. (n is the dimension of the matrix, and position is the integer that I need when for the array.)
int position = 0;
for(int k = 0; k < i; k++){
position = position + (n-k);
}
position = position + j % i;
However, this code fails. I think I'm close to the solution but I am missing something. Any help?
The last j % i should be j - i.
In addition, the loop is essentially doing
position = n + (n - 1) + ... + (n - i + 1);
which can be simplified to
position = (n * 2 - i + 1) * i / 2;
So you can simply write
position = (n * 2 - i + 1) * i / 2 + j - i;
or
position = (n * 2 - i - 1) * i / 2 + j;
You can do simply this:
int myvector[matrix.size()];
int pos = 0;
for(int i = 0; i < matrix.size(); i++){
for(int j = 0; j < matrix.size(); j++){
if(j > i) myvector[pos++] = matrix[i][j];
else myvector[pos++] = matrix[j][i];
}
}
What is an elegant algorithm to mix the elements two by two in two arrays (of potentially differing sizes) so that the items are drawn in an alternating fashion from each array, with the leftovers added to the end?
E.g.
Array 1: 0, 2, 4, 6
Array 2: 1, 3, 5, 7
Mixed array: 0, 2, 1, 3, 4, 6, 5, 7
Don't worry about null checking or any other edge cases, I'll handle those.
Here is my solution but it does not work properly:
for (i = 0; i < N; i++) {
arr[2 * i + 0] = A[i];
arr[2 * i + 1] = A[i+1];
arr[2 * i + 0] = B[i];
arr[2 * i + 1] = B[i+1];
}
It is very fiddly to calculate the array indices explicitly, especially if your arrays can be of different and possibly odd lengths. It is easier if you keep three separate indices, one for each array:
int pairwise(int c[], const int a[], size_t alen, const int b[], size_t blen)
{
size_t i = 0; // index into a
size_t j = 0; // index into b
size_t k = 0; // index into c
while (i < alen || j < blen) {
if (i < alen) c[k++] = a[i++];
if (i < alen) c[k++] = a[i++];
if (j < blen) c[k++] = b[j++];
if (j < blen) c[k++] = b[j++];
}
return k;
}
The returned value k will be equal to alen + blen, which is the implicit dimension of the result array c. Because the availability of a next item is checked for each array operation, this code works for arrays of different lengths and when the arrays have an odd number of elements.
You can use the code like this:
#define countof(x) (sizeof(x) / sizeof(*x))
int main()
{
int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int b[] = {-1, -2, -3, -4, -5, -6};
int c[countof(a) + countof(b)];
int i, n;
n = pairwise(c, a, countof(a), b, countof(b));
for (i = 0; i < n; i++) {
if (i) printf(", ");
printf("%d", c[i]);
}
puts("");
return 0;
}
(The example is in C, not C++, but your code doesn't use any of C++'s containers such as vector, so I've uses plain old ´int` arrays with explicit dimensions, which are the same in C and C++.)
Some notes on the loop you have;
You use the same position in the result array arr to assign two values to it (one from A and one from B).
The calculation for the index is possibly more complex than it needs to be, consider using two indexers given the two ways you are indexing over the arrays.
I would propose you use a loop that has two indexers (i and j) and explicitly loop over the four elements of the result (i.e. two position for each input array). In each loop you increment the indexers appropriately (by 4 for the output array and by 2 for the input arrays).
#include <iostream>
int main()
{
using namespace std;
constexpr int N = 4;
int A[N] = {2, 4, 6, 8};
int B[N] = {1, 3, 5, 7};
int arr[N*2];
for (auto i = 0, j=0; i < N*2; i+=4, j+=2) {
arr[i + 0] = A[j];
arr[i + 1] = A[j+1];
arr[i + 2] = B[j];
arr[i + 3] = B[j+1];
}
for (auto i =0; i < N*2; ++i) {
cout << arr[i] << ",";
}
cout << endl;
}
Note: you mention you take care of corner cases, so the code here requires the input arrays to be of the same length and that the length is even.
Try this:
for (i = 0; i < N; i += 2) {
arr[2 * i + 0] = A[i];
arr[2 * i + 1] = A[i+1];
arr[2 * i + 2] = B[i];
arr[2 * i + 3] = B[i+1];
}
Didn't consider any corner case, just fixing your concept. For example, check whether any array index out of bound occurs or not. You can run live here.
it should like this.
for (i = 0; i < N; i+=2) {
arr[2 * i + 0] = A[i];
arr[2 * i + 1] = A[i+1];
arr[2 * i + 2] = B[i];
arr[2 * i + 3] = B[i+1];
}