gsl_multifit__qrsolv.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /* This function computes the solution to the least squares system
  2. phi = [ A x = b , lambda D x = 0 ]^2
  3. where A is an M by N matrix, D is an N by N diagonal matrix, lambda
  4. is a scalar parameter and b is a vector of length M.
  5. The function requires the factorization of A into A = Q R P^T,
  6. where Q is an orthogonal matrix, R is an upper triangular matrix
  7. with diagonal elements of non-increasing magnitude and P is a
  8. permuation matrix. The system above is then equivalent to
  9. [ R z = Q^T b, P^T (lambda D) P z = 0 ]
  10. where x = P z. If this system does not have full rank then a least
  11. squares solution is obtained. On output the function also provides
  12. an upper triangular matrix S such that
  13. P^T (A^T A + lambda^2 D^T D) P = S^T S
  14. Parameters,
  15. r: On input, contains the full upper triangle of R. On output the
  16. strict lower triangle contains the transpose of the strict upper
  17. triangle of S, and the diagonal of S is stored in sdiag. The full
  18. upper triangle of R is not modified.
  19. p: the encoded form of the permutation matrix P. column j of P is
  20. column p[j] of the identity matrix.
  21. lambda, diag: contains the scalar lambda and the diagonal elements
  22. of the matrix D
  23. qtb: contains the product Q^T b
  24. x: on output contains the least squares solution of the system
  25. wa: is a workspace of length N
  26. */
  27. static int
  28. qrsolv (gsl_matrix * r, const gsl_permutation * p, const double lambda,
  29. const gsl_vector * diag, const gsl_vector * qtb,
  30. gsl_vector * x, gsl_vector * sdiag, gsl_vector * wa)
  31. {
  32. size_t n = r->size2;
  33. size_t i, j, k, nsing;
  34. /* Copy r and qtb to preserve input and initialise s. In particular,
  35. save the diagonal elements of r in x */
  36. for (j = 0; j < n; j++)
  37. {
  38. double rjj = gsl_matrix_get (r, j, j);
  39. double qtbj = gsl_vector_get (qtb, j);
  40. for (i = j + 1; i < n; i++)
  41. {
  42. double rji = gsl_matrix_get (r, j, i);
  43. gsl_matrix_set (r, i, j, rji);
  44. }
  45. gsl_vector_set (x, j, rjj);
  46. gsl_vector_set (wa, j, qtbj);
  47. }
  48. /* Eliminate the diagonal matrix d using a Givens rotation */
  49. for (j = 0; j < n; j++)
  50. {
  51. double qtbpj;
  52. size_t pj = gsl_permutation_get (p, j);
  53. double diagpj = lambda * gsl_vector_get (diag, pj);
  54. if (diagpj == 0)
  55. {
  56. continue;
  57. }
  58. gsl_vector_set (sdiag, j, diagpj);
  59. for (k = j + 1; k < n; k++)
  60. {
  61. gsl_vector_set (sdiag, k, 0.0);
  62. }
  63. /* The transformations to eliminate the row of d modify only a
  64. single element of qtb beyond the first n, which is initially
  65. zero */
  66. qtbpj = 0;
  67. for (k = j; k < n; k++)
  68. {
  69. /* Determine a Givens rotation which eliminates the
  70. appropriate element in the current row of d */
  71. double sine, cosine;
  72. double wak = gsl_vector_get (wa, k);
  73. double rkk = gsl_matrix_get (r, k, k);
  74. double sdiagk = gsl_vector_get (sdiag, k);
  75. if (sdiagk == 0)
  76. {
  77. continue;
  78. }
  79. if (fabs (rkk) < fabs (sdiagk))
  80. {
  81. double cotangent = rkk / sdiagk;
  82. sine = 0.5 / sqrt (0.25 + 0.25 * cotangent * cotangent);
  83. cosine = sine * cotangent;
  84. }
  85. else
  86. {
  87. double tangent = sdiagk / rkk;
  88. cosine = 0.5 / sqrt (0.25 + 0.25 * tangent * tangent);
  89. sine = cosine * tangent;
  90. }
  91. /* Compute the modified diagonal element of r and the
  92. modified element of [qtb,0] */
  93. {
  94. double new_rkk = cosine * rkk + sine * sdiagk;
  95. double new_wak = cosine * wak + sine * qtbpj;
  96. qtbpj = -sine * wak + cosine * qtbpj;
  97. gsl_matrix_set(r, k, k, new_rkk);
  98. gsl_vector_set(wa, k, new_wak);
  99. }
  100. /* Accumulate the transformation in the row of s */
  101. for (i = k + 1; i < n; i++)
  102. {
  103. double rik = gsl_matrix_get (r, i, k);
  104. double sdiagi = gsl_vector_get (sdiag, i);
  105. double new_rik = cosine * rik + sine * sdiagi;
  106. double new_sdiagi = -sine * rik + cosine * sdiagi;
  107. gsl_matrix_set(r, i, k, new_rik);
  108. gsl_vector_set(sdiag, i, new_sdiagi);
  109. }
  110. }
  111. /* Store the corresponding diagonal element of s and restore the
  112. corresponding diagonal element of r */
  113. {
  114. double rjj = gsl_matrix_get (r, j, j);
  115. double xj = gsl_vector_get(x, j);
  116. gsl_vector_set (sdiag, j, rjj);
  117. gsl_matrix_set (r, j, j, xj);
  118. }
  119. }
  120. /* Solve the triangular system for z. If the system is singular then
  121. obtain a least squares solution */
  122. nsing = n;
  123. for (j = 0; j < n; j++)
  124. {
  125. double sdiagj = gsl_vector_get (sdiag, j);
  126. if (sdiagj == 0)
  127. {
  128. nsing = j;
  129. break;
  130. }
  131. }
  132. for (j = nsing; j < n; j++)
  133. {
  134. gsl_vector_set (wa, j, 0.0);
  135. }
  136. for (k = 0; k < nsing; k++)
  137. {
  138. double sum = 0;
  139. j = (nsing - 1) - k;
  140. for (i = j + 1; i < nsing; i++)
  141. {
  142. sum += gsl_matrix_get(r, i, j) * gsl_vector_get(wa, i);
  143. }
  144. {
  145. double waj = gsl_vector_get (wa, j);
  146. double sdiagj = gsl_vector_get (sdiag, j);
  147. gsl_vector_set (wa, j, (waj - sum) / sdiagj);
  148. }
  149. }
  150. /* Permute the components of z back to the components of x */
  151. for (j = 0; j < n; j++)
  152. {
  153. size_t pj = gsl_permutation_get (p, j);
  154. double waj = gsl_vector_get (wa, j);
  155. gsl_vector_set (x, pj, waj);
  156. }
  157. return GSL_SUCCESS;
  158. }