Cholesky Factorization in C? - c

I am implementing the Cholesky Method in C but the program quits when it arrives at this point.
After the answers : Now it works thanks to the answers of (devnull & piotruś) but it doens't give me the right answer
/* Ax=b
*This algorithm does:
* A = U * U'
* with
* U := lower left triangle matrix
* U' := the transposed form of U.
*/
double** cholesky(double **A, int N) //this gives me the U (edited)
{
int i, j, k;
double sum, **p, **U;
U=(double**)malloc(N*sizeof(double*));
for(p=U; p<U+N; p++)
*p=(double*)malloc(N*sizeof(double));
for (j=0; j<N; j++) {
sum = A[j][j];
for (k=0; k<(j-1); k++) sum -= U[k][j]*U[k][j];
U[j][j] = sqrt(sum);
for (i=j; i<N; i++) {
sum = A[j][i];
for (k=0; k<(j-1); k++)
sum -= U[k][j]*U[k][i];
U[j][i] = sum/U[j][j];
}
}
return U;
}
am I doing something wrong here?

double** cholesky(double **A, int N)
in this function you assume array length is N. This means the last index of array is at N-1 not at N. Change the code into:
for ( j = 0; j < N; ++j)
and the rest similarly.

Related

I am using wrong indexing in one of the loops but can't figure out which one. I have made the changes which were suggested

#include<stdio.h>
#include<math.h>
#include<stdlib.h>
const int N = 3;
void LUBKSB(double b[], double a[N][N], int N, int *indx)
{
int i, ii, ip, j;
double sum;
ii = 0;
for(i=0;i<N;i++)
{
ip = indx[i];
sum = b[ip];
b[ip] = b[i];
if (ii)
{
for(j = ii;j<i-1;j++)
{
sum = sum - a[i][j] * b[j];
}
}
else if(sum)
{
ii = i;
}
b[i] = sum;
}
for(i=N-1;i>=0;i--)
{
sum = b[i];
for (j = i; j<N;j++)
{
sum = sum - a[i][j] * b[j];
}
b[i] = sum/a[i][i];
}
for (i=0;i<N;i++)
{
printf("b[%d]: %lf \n",i,b[i]);
}
}
void ludecmp(double a[][3], int N)
{
int i, imax, j, k;
double big, dum, sum, temp, d;
double *vv = (double *) malloc(N * sizeof(double));
int *indx = (int *) malloc(N * sizeof(double));
double TINY = 0.000000001;
double b[3] = {2*M_PI,5*M_PI,-8*M_PI};
d = 1.0;
for(i=0;i<N;i++)
{
big = 0.0;
for(j=0;j<N;j++)
{
temp = fabs(a[i][j]);
if (temp > big)
{
big = temp;
}
}
if (big == 0.0)
{
printf("Singular matrix\n");
exit(1);
}
vv[i] = 1.0/big;
}
for(j=0;j<N;j++)
{
for(i=0;i<j-1;i++)
{
sum = a[i][j];
for(int k=0;k<i-1;k++)
{
sum = sum - (a[i][k] * a[k][j]);
}
a[i][j] = sum;
}
big = 0.0;
for(i=j;i<N;i++)
{
sum = a[i][j];
for(k=0;k<j-1;k++)
{
sum = sum - a[i][k] * a[k][j];
}
a[i][j] =sum;
dum = vv[i] * fabs(a[i][j]);
if(dum >= big)
{
big = dum;
imax = i;
}
}
if(j != imax)
{
for(k=0;k<N;k++)
{
dum = a[imax][k];
a[imax][k] = a[j][k];
a[j][k] = dum;
}
d = -d;
vv[imax] = vv[j];
}
indx[j] = imax;
if (a[j][j] == 0)
{
a[j][j] = TINY;
}
if (j != N)
{
dum = 1.0/a[j][j];
for(i = j; i<N; i++)
{
a[i][j] = a[i][j] * dum;
}
}
}
LUBKSB(b,a,N,indx);
free(vv);
free(indx);
}
int main()
{
int N, i, j;
N = 3;
double a[3][3] = { 1, 2, -1, 6, -5, 4, -9, 8, -7};
ludecmp(a,N);
}
I am using these algorithms to find LU decomposition of matrix and trying to find solution A.x = b
Given a N ×N matrix A denoted as {a}N,Ni,j=1, the routine replaces it by the LU
decomposition of a rowwise permutation of itself. “a” and “N” are input. “a” is also output,
modified to apply the LU decomposition; {indxi}N
i=1 is an output vector that records the
row permutation effected by the partial pivoting; “d” is output and adopts ±1 depending on
whether the number of row interchanges was even or odd. This routine is used in combination
with algorithm 2 to solve linear equations or invert a matrix.
Solves the set of N linear equations A . x = b. Matrix {a}
N,N
i,j=1 is actually the
LU decomposition of the original matrix A, obtained from algorithm 1. Vector {indxi}
N
i=1 is
input as the permutation vector returned by algorithm 1. Vector {bi}
N
i=1 is input as the righthand side vector B but returns with the solution vector X. Inputs {a}
N,N
i,j=1, N, and {indxi}
N
i=1
are not modified in this algorithm.
There are a number of problems with your code:
In your for-loops, i <= N should be i < N and i = N should be i = N - 1.
The absolute value of a double is returned by fabs, not abs.
The statement exit should be exit(1) or exit(EXIT_FALILURE).
Two of your functions lack a return statement.
You should also free the memory you have allocated with the function free. When you compile a C program you should also enable all warnings.

Implementing LU factorization with partial pivoting in C using only one matrix

I have designed the following C function in order to compute the PA = LU factorization, using only one matrix to store and compute the data:
double plupmc(int n, double **c, int *p, double tol) {
int i, j, k, pivot_ind = 0, temp_ind;
int ii, jj;
double pivot, *temp_row;
for (j = 0; j < n-1; ++j) {
pivot = 0.;
for (i = j; i < n; ++i)
if (fabs(c[i][j]) > fabs(pivot)) {
pivot = c[i][j];
pivot_ind = i;
}
temp_row = c[j];
c[j] = c[pivot_ind];
c[pivot_ind] = temp_row;
temp_ind = p[j];
p[j] = p[pivot_ind];
p[pivot_ind] = temp_ind;
for (k = j+1; k < n; ++k) {
c[k][j] /= c[j][j];
c[k][k] -= c[k][j]*c[j][k];
}
}
return 0.;
}
where n is the order of the matrix, c is a pointer to the matrix and p is a pointer to a vector storing the permutations done when partial pivoting the system. The variable tol is not relevant for now. The program works storing in c both the lower and upper triangular parts of the factorization, where U corresponds to the upper triangular part of c and L corresponds to the strictly lower triangular part of c, adding 1's in the diagonal. For what I have been able to test, the part of the program corresponding to partial pivoting is working properly, however, the algorithm used to compute the entries of the matrix is not giving the expected results, and I cannot see why. For instance, if I try to compute the LU factorization of the matrix
1. 2. 3.
4. 5. 6.
7. 8. 9.
I get
1. 0. 0. 7. 8. 9.
l : 0.143 1. 0. u : 0. 2. 1.714*
0.571 0.214* 1. 0. 0. 5.663*
the product of which does not correspond to any permutation of the matrix c. In fact, the wrong entries seem to be the ones marked with a star.
I would appreciate any suggestion to fix this problem.
I found the problem with your code, there was a little conceptual error in the way that you were normalizing the row while computing the actual decomposition:
for (k = j+1; k < n; ++k) {
c[k][j] /= c[j][j];
c[k][k] -= c[k][j]*c[j][k];
}
became:
for (k = j+1; k < n; ++k) {
temp=c[k][j]/=c[j][j];
for(int q=j+1;q<n;q++){
c[k][q] -= temp*c[j][q];
}
}
which returns the result:
7.000000 8.000000 9.000000
0.142857 0.857143 1.714286
0.571429 0.500000 -0.000000
If you have any questions I am happy to help.
Full implementation here:
#include<stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
double plupmc(int n, double **c, int *p, double tol) {
int i, j, k, pivot_ind = 0, temp_ind;
int ii, jj;
double *vv=calloc(n,sizeof(double));
double pivot, *temp_row;
double temp;
for (j = 0; j < n; ++j) {
pivot = 0;
for (i = j; i < n; ++i)
if (fabs(c[i][j]) > fabs(pivot)) {
pivot = c[i][j];
pivot_ind = i;
}
temp_row = c[j];
c[j] = c[pivot_ind];
c[pivot_ind] = temp_row;
temp_ind = p[j];
p[j] = p[pivot_ind];
p[pivot_ind] = temp_ind;
for (k = j+1; k < n; ++k) {
temp=c[k][j]/=c[j][j];
for(int q=j+1;q<n;q++){
c[k][q] -= temp*c[j][q];
}
}
for(int q=0;q<n;q++){
for(int l=0;l<n;l++){
printf("%lf ",c[q][l]);
}
printf("\n");
}
}
return 0.;
}
int main() {
double **x;
x=calloc(3,sizeof(double));
for(int i=0;i<3;i++){
x[i]=calloc(3,sizeof(double));
}
memcpy(x[0],(double[]){1,2,3},3*sizeof(double));
memcpy(x[1],(double[]){4,5,6},3*sizeof(double));
memcpy(x[2],(double[]){7,8,9},3*sizeof(double));
int *p=calloc(3,sizeof(int));
memcpy(p,(int[]){0,1,2},3*sizeof(int));
plupmc(3,x,p,1);
for(int i=0;i<3;i++){
free(x[i]);
}
free(p);
free(x);
}

DGEMM and DGEMV give different results

I want to implement the following equation in C:
C[l,q,m] = A[m,q,k] * B[k,l]
where the repeated index k is being summed over.
I implemented this in three ways:
Naive implementation with loops
Using the BLAS routine DGEMV (matrix-vector multiplication)
Using the BLAS routine DGEMM (matrix-matrix multiplication)
This is the minimal not-working code:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <cblas.h>
void main()
{
const size_t n = 3;
const size_t n2 = n*n;
const size_t n3 = n*n*n;
/* Fill rank 3 tensor with random numbers */
double a[n3];
for (size_t i = 0; i < n3; i++) {
a[i] = (double) rand() / RAND_MAX;
}
/* Fill matrix with random numbers */
double b[n2];
for (size_t i = 0; i < n2; i++) {
b[i] = (double) rand() / RAND_MAX;
}
/* All loops */
double c_exact[n3];
memset(c_exact, 0, n3 * sizeof(double));
for (size_t l = 0; l < n; l++) {
for (size_t q = 0; q < n; q++) {
for (size_t m = 0; m < n; m++) {
for (size_t k = 0; k < n; k++) {
c_exact[l*n2+q*n+m] += a[m*n2+q*n+k] * b[k*n+l];
}
}
}
}
/* Matrix-vector */
double c_mv[n3];
memset(c_mv, 0, n3 * sizeof(double));
for (size_t m = 0; m < n; m++) {
for (size_t l = 0; l < n; l++) {
cblas_dgemv(
CblasRowMajor, CblasNoTrans, n, n, 1.0, &a[m*n2],
n, &b[l], n, 0.0, &c_mv[l*n2+m], n);
}
}
/* Matrix-matrix */
double c_mm[n3];
memset(c_mm, 0, n3 * sizeof(double));
for (size_t m = 0; m < n; m++) {
cblas_dgemm(
CblasRowMajor, CblasTrans, CblasTrans, n, n, n, 1.0, b, n,
&a[m*n2], n, 0.0, &c_mm[m], n2);
}
/* Compute difference */
double diff_mv = 0.0;
double diff_mm = 0.0;
for (size_t idx = 0; idx < n3; idx++) {
diff_mv += c_mv[idx] - c_exact[idx];
diff_mm += c_mm[idx] - c_exact[idx];
}
printf("Difference matrix-vector: %e\n", diff_mv);
printf("Difference matrix-matrix: %e\n", diff_mm);
}
And this the output:
Difference matrix-vector: 0.000000e+00
Difference matrix-matrix: -1.188678e+01
i.e. the DGEMV implementation is correct, the DGEMM not - I really don't understand this. I switched around the multiplication (matrix-matrix multiplication is non commutative) and transposed both to get the right order C[l,q,m] instead of C[q,l,m], but I also tried it without switching/transposing and it does not work.
Can anyone please help?
Thanks.
edit: I thought about it a bit and feel like I'm trying to do something that DGEMM doe not support? Namely I try to insert a submatrix into C[:,:,m], which means that both the leading and trailing index are not contiguous in memory. DGEMM allows me to set the parameter LDC, which in this case needs to be n^2, but it does not know that also the second index is non-contiguous with a stride of n (and there is no parameter to tell it?). So why does DGEMM not support a second parameter for the stride of the trailing dimension?

Vector equations in C

Im trying to code this function which computes the projection formula
P(x) = x + (c- a dot x)a * (1/|a|^2). Note that x and a are vectors and c is a scalar. Also note that a dot x is the product dot/inner product of a and x. Here is what I have,
double dotProduct(double *q, double *b, int length) {
double runningSum = 0;
for (int index = 0; index < length; index++)
runningSum += q[index] * b[index];
return runningSum;
}
void project(double *x ,int n, double *a, double c)
{ double m_sum = 0.0;
for (int i = 0; i < n; i++) {
m_sum += a[i]*a[i];
}
for ( int j = 0; j < n; j++) {
x[j] = x[j] + (1/ m_sum)* (c - dotProduct(a, x, n))*a[j];
}
}
So my question is how do I create a test file to check the consistency of the project function since it doesn’t return anything. Is my code even right? does not return anything.

Multiplying two arrays in C

I'm trying to multiply two multidimensional arrays to form a matrix. I have this function. This should work in theory. However, I am just getting 0s and large/awkward numbers. Can someone help me with this?
int **matrix_mult( int **a, int **b, int nr1, int nc1, int nc2 )
{
int **c;
int i,j,k,l;
c = malloc(sizeof(int *)*nr1);
if (c == NULL){
printf("Insuff memm");
}
for(l=0;l<nr1;l++){
c[l] = malloc(sizeof(int)*nc1);
if (c[l] == NULL){
printf("Insuff memm");
}
}//for loop
for (i=0;i<nr1;i++){
for (j=0;j<nc2;j++){
for (k=0;k<nc1;k++){
c[i][j] = (a[i][k]) * (b[k][j]);
}
}
}
return( c );
}
Are you doing mathematical matrix multiplication? If so shouldn't it be:
for(i = 0; i < nr1; i++)
{
for(j = 0; j < nc1; j++)
{
c[i][k] = 0;
for(k = 0; k < nc2; k++)
{
c[i][k] += (a[i][j]) * (b[j][k]);
}
}
}
My full and final solution, tested to produce sensible results (I didn't actually do all the calculations myself manually to check them) and without any sensible niceties such as checking memory allocations work, is:
int **matrix_mult(int **a, int **b, int nr1, int nc1, int nc2)
{
int **c;
int i, j, k;
c = malloc(sizeof(int *) * nr1);
for (i = 0; i < nr1; i++)
{
c[i] = malloc(sizeof(int) * nc2);
for (k = 0; k < nc2; k++)
{
c[i][k] = 0;
for (j = 0; j < nc1; j++)
{
c[i][k] += (a[i][j]) * (b[j][k]);
}
}
}
return c;
}
There were a few typos in the core of the for loop in my original answer, mostly due to my being mislead by a different answer. These have been corrected for posterity.
If you change c[i][j] = (a[i][k]) * (b[k][j]); to c[i][j] += (a[i][k]) * (b[k][j]); in your code then it will work just fine provided that
nr1 is number of rows of matrix a
nc1 is the number of columns of the matrix a
nc2 is the number of columns of the matrix b
Just be sure that the matrix c is initiated with zeroes. You can just use calloc instead of malloc when allocating space, or memset the allocated array after a call to malloc.
One more tip is to avoid using the letter l when accessing array elements. when tired, you will have hard time noticing errors with l vs 1.

Resources