So for my application I would need to create a tri diagonal matrix. This is easy to do with any language, you loop through all rows and columns, then set the main diagonal values, the sub diagonal values and the super diagonal values. Usually, this is performed on a 2d array.
For my application, I need to create a 1d array of "tridiagonal". Otherway to say this is: take the 2d tridiagonal matrix then turn it into 1d. I can just start with 2d then write some functions that convert 2d array to 1d array. This, I can do. I would like to know if we ca go directly to a 1D "tridiagonal"? For example, say the 2D array is 10*10, then my 1D array would be 100 elements long, then I would need to figure out which index is the main, super and sub diagonal.
Is it possible to do this? Please let me know and thank you
The elements on the main diagonal are at indexes (i, i) and there are n of them; the supra- and infra- diagonals at (i, i-1) and (i, i+1) and there are n-1 of them (i starts at 2 and ends at n-1 respectively).
An option is to use three vectors and store the elements at the respective indexes i in those three vectors.
You can also pack all values in a single vector of length 3n (or 3n-2 if you want to spare space). Add n or 2n to the index, depending on the diagonal you want to address. For an element (i, j), the index of the diagonal is given by j-i+2.
You can just look at your 1D array using a 2D array pointer. Fortran:
integer, target :: A(100)
integer, pointer :: B(:,:)
B(1:10,1:10) => A
B = 0
do i = 1, 10
B(i,i) = 1
end do
print '(*(1x,g0))', A
end
> gfortran diag1d.f90
> ./a.out
1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1
In C++ the casting is easy as well.
Please consider also:
#YvesDaoust's answer, because proposes a better storage strategy: instead of storing all the elements of the tridiagonal matrix, store just the non-zero. You could write a derived-type to encapsulate behavior, if it worths.
#VladmirF's answer, because a pointer association maybe a better approach (depending on your use case), than copying over all the array through reshape, if all you want is a temporarily indexing change for convenience while working on data.
Said that, let's go to my answer.
Populating a tridiagonal matrix is not a different problem than constructing any matrix. I don't think it really matters here. Just bear in mind that Fortran stores arrays in Column Major order, 1 based index.
Changing the shape of your data is easy and obvious, if storage is contiuous. You can make a pointer association or transferring it to a new variable with reshape.
Extracting the main, super and sub diagonal is also a trivial problem, and can be done with simple manipulation of the array index triplet. Look:
program tridiagonal
implicit none
integer, parameter :: n = 4
integer :: A(n, n), B(n**2), main(n), sub(n-1), sup(n-1)
A(1,:) = [1, 4, 0, 0]
A(2,:) = [3, 4, 1, 0]
A(3,:) = [0, 2, 3, 4]
A(4,:) = [0, 0, 1, 3]
! Remember, colum major
B = reshape(A, shape(B)) ! 1, 3, 0, 0, 4, 4, 2, 0, 0, 1, 3, 1, 0, 0, 4, 3
main = B( 1:n**2:n+1) ! 1, 4, 3, 3
sub = B( 2:n**2:n+1) ! 3, 2, 1
sup = B(n+1:n**2:n+1) ! 4, 1, 4
end
Related
I just started using c++, so I am still new to vectors and data structures. I'm wondering how to I add a int value into a specific index location of 2d vector. For example, I have a multidimensional vector "chessboard" initialized like:
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
How do I use the insert() method to insert a integer value 1 into say the x,y index [4,3] so It looks like this:
0 0 0 0 0
0 0 0 0 0
0 0 0 1 0
0 0 0 0 0
This Is my code so far:
vector<vector<int>> board(boardsize, vector<int> (boardsize, 0));
int x = 4; // x position for value to be inserted
int y = 3; // y position for value to be inserted
In order to change a value of an element of a std::vector, you can use std::vector::operator[].
For example in your case of a vector containing vectors:
board[x][y] = 1;
Note that std::vector::insert does not modify an existing element, but rather adds a new element (or elements) to the vector. This is not what you want since you set the final desired size of the vector upon construction.
A side note: better to avoid using namespace std; - see here: Why is "using namespace std;" considered bad practice?.
I am trying to loop over a matrix and print its element, which should be a simple operation, but I experience some strange things...
I have a a null matrix :
cv::Mat accum = cv::Mat::zeros(3,5,CV_8U);
Doing this:
for(int i=0;i<accum.rows;i++)
{
for(int j=0;j<accum.cols;j++)
{
cout<<accum.at<int>(i,j) <<endl;
}
}
I get the following elements:
0
0
0
0
0
0
0
0
0
-536870912
0
0
0
2027945984
587217671
Why is there some random number at places where zero should be?
If I initialize the value of matrix at i=1,j=1 with number 1, I get the following
0
0
256
0
0
0
1
0
0
587202560
0
0
0
1931673600
587257437
I just dont understand those random values, I might do something wrong, but cant figure out what. Could you please help?
I would like to create a directed network graph using igraph c++ in which each node is randomly connected to exactly n other distinct nodes in the network (i.e. excluding connections to itself, and loops/multiple edges to the same loop). I was thinking of using the method igraph_erdos_renyi_game, but for some reason I do not get the desired degree distribution. In particular, if I set the arguments like this:
igraph_erdos_renyi_game(&g, IGRAPH_ERDOS_RENYI_GNM, n, m, true, false);
with n = 5, m = 1, I get this Adjacency Matrix (e.g.):
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
If I use igraph_k_regular_game(&g, n, m, true, false) instead, I get exactly the desired outcome, namely (e.g.):
0 0 0 0 1
1 0 0 0 0
0 0 0 0 1
0 1 0 0 0
0 0 0 1 0
So to summarize, I would like for each node to have 1 edge to n randomly selected agents. Am I misinterpreting the way the Erdos-Renyi method works, or am I passing the wrong arguments?
m is the total number of edges in erdos_renyi_game(). So just use k_regular_game(), it does exactly what you want.
Suppose I wanted to apply some generic operation a matrix consisting of some subset of its values that are not necessarily contiguous. How can I do this?
If the values were contiguous I would simply use the Eigen::block operation, but what if they are not?
One application might be that I have an eigen matrix of positive integers:
Eigen::Matrix<int, 4, 1> mat;
mat << 4, 1, 2, 8;
And I wanted to return the 0th, 2nd and 3rd values. If they were contiguous (0th, 1st and 2nd) I could simply use the block operation on this matrix, but what do I do in this case?
How about rearranging the elements to make them contiguous?
1 0 0 0 4 4
0 0 1 0 x 1 = 2
0 0 0 1 2 8
0 0 0 0 8 0
Using eigen2, and given a matrix A
a_0_0, a_0_1, a_0_2, ...
a_1_0, a_1_0, a_1_2, ...
...
and a matrix B:
b_0_0, b_0_1, b_0_2, ...
b_1_0, b_1_1, b_1_2, ...
...
and where A and B have the same dimensions, I would like to interleave the rows, producing:
a_0_0, a_0_1, a_0_2, ...
b_0_0, b_0_1, b_0_2, ...
a_1_0, a_1_0, a_1_2, ...
b_1_0, b_1_1, b_1_2, ...
...
Obviously I can write a function that will construct an output matrix of the proper dimensions, then loop over each of the input matrices and assign elements to the result. I'd rather not re-invent the wheel though, so if eigen2 already has a mechanism to express this sort of matrix surgery elegantly I'd much prefer to use it.
I did look through the eigen2 docs and nothing jumped out at me as obviously correct. The closest thing I found was MatrixBase::select, but that does 'element from a or element from b', where what I want is 'element from a then element from b in the next row'.
Efficiency is not of paramount concern since I don't need to do this in the fast path, only at initialization.
I apologize for the formatting if there is a better way to represent matrices.
Multiply each R x C matrix by a 2R x R matrix consisting of zeroes and ones on the appropriate diagonal, then add.
Matrix 1
1 0 0 0 ...
0 0 0 0 ...
0 1 0 0 ...
0 0 0 0 ...
Matrix 2
0 0 0 0 ...
1 0 0 0 ...
0 0 0 0 ...
0 1 0 0 ...
Not sure if this is specific to Eigen3, but you can interleave rows using the Map and Stride objects.
MatrixXi C(A.rows()+B.rows(),A.cols());
Map<MatrixXi,0,Stride<Dynamic,2> >(C.data(),A.rows(),A.cols(),Stride<Dynamic,2>(2*A.rows(),2)) = A;
Map<MatrixXi,0,Stride<Dynamic,2> >(C.data()+1,B.rows(),B.cols(),Stride<Dynamic,2>(2*B.rows(),2)) = B;
source