Cholesky with ScaLAPACK - c++

I am trying to do a Cholesky decomposition via pdpotrf() of MKL-Intel's library, which uses ScaLAPACK. I am reading the whole matrix in the master node and then distribute it like in this example. Everything works fine when the dimension of the SPD matrix is even. However, when it's odd, pdpotrf() thinks that the matrix is not positive definite.
Could it be because the submatrices are not SPD? I am working with this matrix:
and the submatrices are (with 4 processes and blocks of size 2x2):
A_loc on node 0
4 1 2
1 0.5 0
2 0 16
nrows = 3, ncols = 2
A_loc on node 1
2 0.5
0 0
0 0
nrows = 2, ncols = 3
A_loc on node 2
2 0 0
0.5 0 0
nrows = 2, ncols = 2
A_loc on node 3
3 0
0 0.625
Here, every submatrix is not SPD, however, the overall matrix is SPD (have checked with running with 1 process). What should I do? Or there is nothing I can do and pdpotrf() does not work with matrices of odd size?
Here is how I call the routine:
int iZERO = 0;
int descA[9];
// N, M dimensions of matrix. lda = N
// Nb, Mb dimensions of block
descinit_(descA, &N, &M, &Nb, &Mb, &iZERO, &iZERO, &ctxt, &lda, &info);
...
pdpotrf((char*)"L", &ord, A_loc, &IA, &JA, descA, &info);
I also tried this:
// nrows/ncols is the number of rows/columns a submatrix has
descinit_(descA, &N, &M, &nrows, &ncols, &iZERO, &iZERO, &ctxt, &lda, &info);
but I get an error:
{ 0, 0}: On entry to { 0, 1}: On entry to PDPOTR{ 1,
0}: On entry to PDPOTRF parameter number 605 had an illegal value {
1, 1}: On entry to PDPOTRF parameter number 605 had an illegal
value F parameter number 605 had an illegal value
PDPOTRF parameter number 605 had an illegal value info < 0: If the
i-th argument is an array and the j-entry had an illegal value, then
INFO = -(i*100+j), if the i-th argument is a scalar and had an illegal
value, then INFO = -i. info = -605
From my answer, you can see what the arguments of the function mean.
The code is based on this question. Output:
gsamaras#pythagoras:~/konstantis/check_examples$ ../../mpich-install/bin/mpic++ -o test minor.cpp -I../../intel/mkl/include ../../intel/mkl/lib/intel64/libmkl_scalapack_lp64.a -Wl,--start-group ../../intel/mkl/lib/intel64/libmkl_intel_lp64.a ../../intel/mkl/lib/intel64/libmkl_core.a ../../intel/mkl/lib/intel64/libmkl_sequential.a -Wl,--end-group ../../intel/mkl/lib/intel64/libmkl_blacs_intelmpi_lp64.a -lpthread -lm -ldl
gsamaras#pythagoras:~/konstantis/check_examples$ mpiexec -n 4 ./test
Processes grid pattern:
0 1
2 3
nrows = 3, ncols = 3
A_loc on node 0
4 1 2
1 0.5 0
2 0 16
nrows = 3, ncols = 2
A_loc on node 1
2 0.5
0 0
0 0
nrows = 2, ncols = 3
A_loc on node 2
2 0 0
0.5 0 0
nrows = 2, ncols = 2
A_loc on node 3
3 0
0 0.625
Description init sucesss!
matrix is not positive definte
Matrix A result:
2 1 2 0.5 2
0.5 0.5 0 0 0
1 0 1 0 -0.25
0.25 -1 -0.5 0.625 0
1 -1 -2 -0.5 14

The issue may come from :
MPI_Bcast(&lda, 1, MPI_INT, 0, MPI_COMM_WORLD);
Before this line, lda is different on each process if the dimension of the matrix is odd. Two processes handle 2 rows and two processes handle 3 rows. But after the MPI_Bcast(), lda is the same everywhere (3).
The problem is that the argument lda of the subroutine DESCINIT must be the leading dimension of the local array, that is either 2 or 3.
By commenting MPI_Bcast(), i got:
Description init sucesss!
SUCCESS
Matrix A result:
2 1 2 0.5 2
0.5 0.5 0 0 0
1 -1 1 0 0
0.25 -0.25 -0.5 0.5 0
1 -1 -2 -3 1
At last, it would explain that the program works well for even dimensions and fails for odd dimensions !

Related

Given a directed graph and two vertices ‘u’ and ‘v’ in it, count all the possible walks from ‘u’ to ‘v’ with exactly k edges on the walk

My code is failing for the following test case , please help
1
10
1 1 1 1 0 0 0 1 0 1
0 1 1 0 0 0 1 1 1 1
0 0 0 1 0 1 1 1 0 1
0 0 0 1 0 0 0 1 1 1
1 1 1 1 1 1 1 1 0 1
0 0 0 0 0 1 0 0 1 0
1 0 1 0 1 0 1 1 1 0
0 1 0 0 0 0 1 0 1 0
0 1 0 1 1 0 0 0 0 1
1 0 1 0 1 1 1 0 1 1
2 7 3
Its Correct output is:
11
And Your Code's output is:
6
Given a directed graph and two vertices ‘u’ and ‘v’ in it, count all the possible walks from ‘u’ to ‘v’ with exactly k edges on the walk.
Input:
The first line of input contains an integer T denoting the number of test cases. Then T test cases follow. Each test case consists of three lines.
The first line of each test case is N which is number of vertices in input graph.
The second line of each test case contains N x N binary values that represent graph[N][N].
The third line of each test case contains u, v, k where u is starting position, v is destination and k is number of edges.
Output:
Print all possible walks from 'u' to 'v'.
Constraints:
1 ≤ T ≤ 50
1 ≤ N ≤ 20
0 ≤ graph[][] ≤ 1
Example:
Input
1
4
0 1 1 1
0 0 0 1
0 0 0 1
0 0 0 0
0 3 2
Output
2
Explanation:
For example consider the following graph. Let source ‘u’ be vertex 0, destination ‘v’ be 3 and k be 2. The output should be 2 as there are two walk from 0 to 3 with exactly 2 edges. The walks are {0, 2, 3} and {0, 1, 3}
MY CODE
#include <iostream>
using namespace std;
int main() {
//code
int t;
cin>>t;
while(t--)
{
int r,c;
cin>>r;
c=r;
int arr[r][c];
for(int i=0;i<r;i++)
{
for(int j=0;j<c;j++)
{
cin>>arr[i][j];
}
}
int u,v,k;
cin>>u>>v>>k;
int dp[r][k+1];
for(int i=0;i<r;i++)
{
for(int j=0;j<k+1;j++)
{
dp[i][j]=0;
}
}
dp[u][0]=1;
for(int j=0;j<k+1;j++)
{
for(int i=0;i<r;i++)
{
if(dp[i][j]!=0)
{
for(int x=0;x<r;x++)
{
if(arr[i][x]==1)
{if(j+1<k+1)
dp[x][j+1]++;
}
}
}
}
}
cout<<dp[v][k]<<endl;
}
return 0;
}

How to create a tri diagonal matrix as 1D

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

How to fix a bug in my homework solution in C++?

I need to write a program which reads the statistics of n League A football teams and prints the teams name which fall in League B.
A team falls in League B, if it has less than k points after having played m weeks where m is between 1 and 150. Each team gets three points for a win, one point for draw and zero points when lost.
Input Specification: In the first line, you will be given the number of teams 0 < n ≤ 500 and the points 0 < k ≤ 300 needed to stay in league A. Then in the following n lines, there will be the team name and its results. Semicolon indicates the end of input series.
Number 2 represents win, number one represents draw and number zero represents loss.
Output specification:
Sample Input I
4 19
Team_A 1 1 1 1 1 1 1 1 1 0 1 1 1 0 2 1 0 ;
Team_B 0 1 0 2 2 1 1 0 1 1 0 2 0 1 0 0 2 ;
Team_C 0 0 1 0 2 2 2 1 1 1 1 1 0 0 2 1 2 ;
Team_D 0 1 0 1 2 1 2 1 0 0 0 2 2 2 0 0 0 ;
Sample Output I
Team_A 16
Team_B 18
This is the code I came up with, but the output is wrong and I don't know why,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int n,points,sum=0,i,value;
char name[15];
char p;
scanf("%d %d",&n,&points);
for(i=1;i<=n;i++)
{
scanf("%s",&name);
do
{
scanf("%c ",&p);
if(p!=';')
{
value=p-48;
sum=sum+value;
}
}while(p!=';');
if(sum<=points)
printf("%s %d",name,sum);
}
return 0;
}
You might look for problems by stuffing the program with output statements.
If you add after scanf("%c ",&p); an output statement to show the value of p, you will find that the first value for p is a space character, which spoils your calculation.
In the same way, if you trace the value of value, you will find that you forgot to initialize this variable to zero for each team.

2-D array of zeroes and ones

I want to generate a 2-D array of zeroes and ones so that it is 25% zeroes and 75% ones.
I know that I will be using the rand()%2 function but how do i limit the zeroes to be only 25 percent of the array?
Create vector of size N with zeroes.
Set the first N*0.75 elements to one.
Randomize the vector.
Example code:
#include <iostream>
#include <algorithm>
#include <vector>
#include <ctime>
#include <cstdlib>
#include <iterator>
int main ()
{
std::srand ( unsigned ( std::time(0) ) );
const int N = 100;
const int zero_percent = 25;
const int one_percent = 100-zero_percent;
const int one_count = (N * one_percent)/100;
std::vector<int> v(N);
std::fill(v.begin(), v.begin()+one_count, 1);
std::random_shuffle (v.begin(), v.end());
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
return 0;
}
output
1 0 1 0 1 0 1 1 1 0 0 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 0 1 1 0 1 0 1 0 1 1 1 1 1 1 1 1 1 0 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 0 0 1 0 0 1 0 1 1 0 1 1 0 1 1 1 0 1 0 1 1 1 1 1 1 1 1 1 1 1 0 1 1
live example: http://ideone.com/CdlaMy
You could initialize every element of the array with the following:
int zeroOr1() { // Generates
static std::default_random_engine gen;
static std::uniform_int_distribution<int> dist(0,3);
return (dist(gen) % 4) >= 1;
}
Because dist(gen) % 4 produces one of [0, 1, 2, 3] about equally likely, (dist(gen) % 4) >= 1 will evaluate to true about 75% of the time and false about 25% of the time.
Note: this doesn't guarantee a perfect 25/75 distribution like the other answers, but it works for all array sizes. I'd need more information about the application to decide if this is good enough or not suitable.
If there are only 0s and 1s, one possible solution would be keeping all the coordinates in some kind of a "set" and randomly taking out then ( N/M /4 (n and m are the sizes of the array ) times ( to get 25% random coordinates) ) and mark as 1, then mark the rest as 0.

Distribution of M objects in N container

Given a N size array whose elements denotes the capacity of containers ...In how many ways M similar objects can be distributed so that each containers is filled at the end.
for example
for arr={2,1,2,1} N=4 and M=10 there comes out be 35 ways.
Please help me out with this question.
First calculate the sum of the container sizes. I your case 2+1+2+1 = 6 let this be P. Find the number of ways of choosing P objects from M. There are M choices for the first object, M-1 for the second, M-2 for the third etc. This gives use M * (M-1) * ... (M-p+1) or M! / (M-P)!. This will give us more states than you want for example
1 2 | 3 | 4 5 | 6
2 1 | 3 | 4 5 | 6
There is q! ways of arranging q object in q slots so we need to divide by factorial(arr[0]) and factorial(arr[1]) etc. In this case divide by 2! * 1! * 2! * 1! = 4.
I'm getting a very much larger number than 35. 10! / 4! = 151200 divide that by 4 gives 37800, so I'm not sure if I have understood your question correctly.
Ah so looking at the problem you need to find N integers n1, n2, ... ,nN so that n1+n2+...+nN = M and n1>= arr[1], n2>=arr[2].
Looks quite simple let P be as above. Take the first P pills and give the students their minimum number, arr[1], arr[2] etc. You will have M-P pills left, let this be R.
Essentially the problem simplifies to finding N number >=0 which sum to R. This is a classic problem. As its a challenges I won't do the answer for you but if we break the N=4, R=4 answer down you may see the pattern
4 0 0 0 - 1 case starting with 4
3 1 0 0 - 3 cases starting with 3
3 0 1 0
3 0 0 1
2 2 0 0 - 6 cases
2 1 1 0
2 1 0 1
2 0 2 0
2 0 1 1
2 0 0 2
1 3 0 0 - 10 cases
1 2 1 0
1 2 0 1
1 1 2 0
1 1 1 1
1 1 0 2
1 0 3 0
1 0 2 1
1 0 1 2
1 0 0 3
0 4 0 0 - 15 cases
0 3 1 0
0 3 0 1
0 2 2 0
0 2 1 1
0 2 0 2
0 1 3 0
0 1 2 1
0 1 1 2
0 1 0 3
0 0 4 0
0 0 3 1
0 0 2 2
0 0 1 3
0 0 0 4
You should recognise the numbers 1, 3, 6, 10, 15.