1 // This code has been mechanically translated from the original FORTRAN
2 // code at http://netlib.org/minpack.
3 
4 /** Authors:    Lars Tandle Kyllingstad
5     Copyright:  Copyright (c) 2009, Lars T. Kyllingstad. All rights reserved.
6     License:    Boost Licence 1.0
7 */
8 module scid.ports.minpack.r1mpyq;
9 
10 
11 private import std.math: abs, sqrt;
12 
13 
14 
15 
16 /** Given an m by n matrix A, this subroutine computes AQ where
17     Q is the product of 2*(n-1) transformations
18     ---
19     gv(n-1)*...*gv(1)*gw(1)*...*gw(n-1)
20     ---
21     and gv(i), gw(i) are Givens rotations in the (i,n) plane which
22     eliminate elements in the i-th and n-th planes, respectively.
23     Q itself is not given, rather the information to recover the
24     gv, gw rotations is supplied.
25 
26 
27     Params:
28         m = a positive integer input variable set to the number
29             of rows of A.
30         
31         n = a positive integer input variable set to the number
32             of columns of A.
33         
34         a = an array of length m^2. On input a must contain the matrix
35             A to be postmultiplied by the orthogonal matrix Q
36             described above. On output AQ has replaced A.
37             the first min(m,n) columns of Q contains the factored form.
38             on output Q has been accumulated into a square matrix.
39         
40         lda = a positive integer input variable not less than m
41             which specifies the leading dimension of the array a.
42         
43         v = an input array of length n. v(i) must contain the
44             information necessary to recover the Givens rotation gv(i)
45             described above.
46 
47         v = an input array of length n. v(i) must contain the
48             information necessary to recover the Givens rotation gw(i)
49             described above.
50 */
51 void r1mpyq(Real)(size_t m, size_t n, Real* a, size_t lda, Real* v, Real* w)
52 {
53     size_t i, j, ij, in_, nmj;
54     Real cos, sin, temp;
55     
56     enum  Real one = 1.0;
57 
58     
59     // Apply the first set of Givens rotations to A.
60     if (n > 1)
61     {
62         size_t nm1 = n - 1;
63         for (nmj=2; nmj<=n; nmj++)
64         {
65             j = n - nmj;
66             if (abs(v[j]) > one)
67             {
68                 cos = one/v[j];
69                 sin = sqrt(one-cos*cos);
70             }
71             else
72             {
73                 sin = v[j];
74                 cos = sqrt(one-sin*sin);
75             }
76 
77             for (i=0; i<m; i++)
78             {
79                 ij = i + j*lda;
80                 in_ = i + nm1*lda;
81                 temp = cos*a[ij] - sin*a[in_];
82                 a[in_] = sin*a[ij] + cos*a[in_];
83                 a[ij] = temp;
84             }
85         }
86 
87 
88         // Apply the second set of Givens rotations to A.
89         for (j=0; j<nm1; j++)
90         {
91             if (abs(w[j]) > one)
92             {
93                 cos = one/w[j];
94                 sin = sqrt(one-cos*cos);
95             }
96             else
97             {
98                 sin = w[j];
99                 cos = sqrt(one-sin*sin);
100             }
101 
102             for (i=0; i<m; i++)
103             {
104                 ij = i + j*lda;
105                 in_ = i + nm1*lda;
106                 temp = cos*a[ij] + sin*a[in_];
107                 a[in_] = -sin*a[ij] + cos*a[in_];
108                 a[ij] = temp;
109             }
110         }
111     } 
112 }
113 
114 
115 unittest { alias r1mpyq!(real) rr1mpyq; }