accelerInt  v0.1
linear-algebra.c
Go to the documentation of this file.
1 
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <math.h>
9 #include <float.h>
10 #include <string.h>
11 #include <complex.h>
12 
14 
23 void getInverseComplex (int n, double complex* A) {
24 
25  // Prototype for LAPACK ZGETRF (Fortran) function
26  extern void zgetrf_ (int *m, int *n, double complex* A, int* lda, int* ipiv, int* info);
27 
28  // Prototype for LAPACK ZGETRI (Fortran) function
29  extern void zgetri_ (int* n, double complex* A, int* lda, int* ipiv, double complex* work,
30  int* lwork, int* info);
31 
32  // pivot indices
33  int* ipiv = (int*) calloc (n, sizeof(int));
34 
35  // output flag
36  int info;
37 
38  // first call zgetrf for LU factorization
39  zgetrf_ (&n, &n, A, &n, ipiv, &info);
40 
41  // check for successful exit
42  if (info < 0) {
43  printf ("ZGETRF argument %d had illegal argument.\n", info);
44  exit (1);
45  } else if (info > 0) {
46  printf ("ZGETRF failure, U is singular\n.");
47  exit (1);
48  }
49 
50  // work array
51  double complex* work = (double complex*) calloc (1, sizeof(double complex));
52  int lwork = -1;
53 
54  // call zgetri for work array size
55  zgetri_ (&n, A, &n, ipiv, work, &lwork, &info);
56 
57  // increase size of work array
58  lwork = (int) creal(work[0]);
59  work = (double complex*) realloc (work, lwork * sizeof(double complex));
60 
61  // now call zgetri for inversion
62  zgetri_ (&n, A, &n, ipiv, work, &lwork, &info);
63 
64  // check for successful exit
65  if (info < 0) {
66  printf ("ZGETRI argument %d had illegal argument.\n", info);
67  exit (1);
68  } else if (info > 0) {
69  printf ("ZGETRI failure, matrix is singular\n.");
70  exit (1);
71  }
72 
73  free (ipiv);
74  free (work);
75 }
76 
78 
88 void linSolveComplex (int n, double complex* A, double complex* B, double complex* x) {
89 
90  extern void zcgesv_ (int* n, int* nrhs, double complex* A, int* lda, int* ipiv,
91  double complex* B, int* ldb, double complex* x, int* ldx,
92  double complex* work, float complex* swork, double* rwork,
93  int* iter, int* info);
94 
95  // number of right-hand sides: 1
96  int nrhs = 1;
97 
98  // double complex work array
99  double complex* work = (double complex*) calloc (n * nrhs, sizeof(double complex));
100 
101  // single complex work array
102  float complex* swork = (float complex*) calloc (n * (n + nrhs), sizeof(float complex));
103 
104  // double real work array
105  double* rwork = (double*) calloc (n, sizeof(double));
106 
107  // output flags
108  int ipiv, iter, info;
109 
110  zcgesv_ (&n, &nrhs, A, &n, &ipiv, B, &n, x, &n, work, swork, rwork, &iter, &info);
111 
112  // check for successful exit
113  if (info < 0) {
114  printf ("ZCGESV argument %d illegal argument.\n", info);
115  exit (1);
116  } else if (info > 0) {
117  printf ("ZCGESV failure, U is singular\n.");
118  exit (1);
119  }
120 
121  free (work);
122  free (swork);
123  free (rwork);
124 
125 }
126 
128 
141 void roots (int n, double* v, double complex* rt) {
142 
143  // number of roots
144  int m = n - 1;
145 
146  // Prototype for LAPACK DGEEV (Fortran) function
147  extern void dgeev_ (char* jobvl, char* jobvr, int* n, double* A, int* lda,
148  double* wr, double* wi, double* vl, int* ldvl, double *vr,
149  int* ldvr, double* work, int* lwork, int* info);
150 
151  // construct companion matrix
152  double *A = (double*) calloc (m * m, sizeof(double));
153  memset (A, 0.0, m * m * sizeof(double)); // fill with 0
154 
155  for (int i = 0; i < (m - 1); ++i) {
156  A[i + 1 + m * i] = 1.0;
157  }
158 
159  for (int i = 0; i < m; ++i) {
160  A[m * i] = -v[i + 1] / v[0];
161  }
162 
163  int info, lwork;
164  double* vl;
165  double* vr;
166  double wkopt;
167  double* work;
168 
169  // don't need eigenvectors
170  char job = 'N';
171 
172  // real and imaginary parts of eigenvalues
173  double* wr = (double*) calloc (m, sizeof(double));
174  double* wi = (double*) calloc (m, sizeof(double));
175 
176  // first compute optimal workspace
177  lwork = -1;
178  dgeev_ (&job, &job, &m, A, &m, wr, wi, vl, &m, vr, &m, &wkopt, &lwork, &info);
179  lwork = (int) wkopt;
180  work = (double*) calloc (lwork, sizeof(double));
181 
182  // compute eigenvalues
183  dgeev_ (&job, &job, &m, A, &m, wr, wi, vl, &m, vr, &m, work, &lwork, &info);
184 
185  // check for convergence
186  if (info > 0) {
187  printf ("DGEEV failed to compute the eigenvalues.\n");
188  exit (1);
189  }
190 
191  for (int i = 0; i < m; ++i) {
192  rt[i] = wr[i] + I * wi[i];
193  }
194 
195  free (A);
196  free (work);
197  free (wr);
198  free (wi);
199 }
200 
202 
215 void svd (int n, double* A, double* S, double* U, double* V) {
216 
217  // Prototype for LAPACK DGESVD (Fortran) function
218  extern void dgesvd_ (char* jobu, char* jobvt, int* m, int* n, double* A,
219  int* lda, double* s, double* u, int* ldu, double* vt,
220  int* ldvt, double* work, int* lwork, int* info);
221 
222  int info, lwork;
223  double wkopt;
224  double* work;
225  double* Vt = (double*) calloc (n * n, sizeof(double));
226 
227  // want all of U and V
228  char job = 'A';
229 
230  // first compute optimal workspace
231  lwork = -1;
232  dgesvd_ (&job, &job, &n, &n, A, &n, S, U, &n, Vt, &n, &wkopt, &lwork, &info);
233  lwork = (int) wkopt;
234  work = (double*) calloc (lwork, sizeof(double));
235 
236  // Compute SVD
237  dgesvd_ (&job, &job, &n, &n, A, &n, S, U, &n, Vt, &n, work, &lwork, &info);
238 
239  // check for convergence
240  if (info > 0) {
241  printf ("DGESVD failed.\n");
242  exit (1);
243  }
244 
245  // transpose Vt
246  for (int i = 0; i < n; ++i) {
247  for (int j = 0; j < n; ++j) {
248  V[i + j*n] = Vt[j + i*n];
249  }
250  }
251 
252  free (Vt);
253  free (work);
254 }
void zgetri_(const int *n, double complex *A, const int *LDA, int *ipiv, double complex *work, const int *LDB, int *info)
void linSolveComplex(int n, double complex *A, double complex *B, double complex *x)
Solves the complex linear system Ax = B.
void getInverseComplex(int n, double complex *A)
Interface function to LAPACK matrix inversion subroutine.
void roots(int n, double *v, double complex *rt)
Polynomial root finding function.
void zgetrf_(const int *m, const int *n, double complex *A, const int *lda, int *ipiv, int *info)
void svd(int n, double *A, double *S, double *U, double *V)
Singular value decomposition function.