| 984 |
bates |
1 |
#include "dgBCMatrix.h"
|
| 883 |
bates |
2 |
/* TODO
|
|
|
3 |
* - code for trans = 'T' in cscb_syrk
|
| 1108 |
bates |
4 |
* - code for non-trivial cscb_trmm
|
| 883 |
bates |
5 |
*/
|
| 934 |
bates |
6 |
|
| 984 |
bates |
7 |
SEXP dgBCMatrix_validate(SEXP x)
|
| 566 |
bates |
8 |
{
|
|
|
9 |
SEXP pp = GET_SLOT(x, Matrix_pSym),
|
|
|
10 |
ip = GET_SLOT(x, Matrix_iSym),
|
|
|
11 |
xp = GET_SLOT(x, Matrix_xSym),
|
|
|
12 |
dp = getAttrib(xp, R_DimSymbol);
|
|
|
13 |
int *pv = INTEGER(pp),
|
|
|
14 |
*dim = INTEGER(dp),
|
|
|
15 |
ncol = length(pp) - 1;
|
|
|
16 |
int nnz = pv[ncol];
|
|
|
17 |
|
| 669 |
bates |
18 |
if (!(isReal(xp) && isArray(xp)))
|
| 1190 |
bates |
19 |
return mkString(_("slot x should be a real array"));
|
| 566 |
bates |
20 |
if (length(dp) != 3)
|
| 1190 |
bates |
21 |
return mkString(_("slot x should be a 3-dimensional array"));
|
| 566 |
bates |
22 |
if (length(ip) != nnz)
|
| 1190 |
bates |
23 |
return mkString(_("length of slot i does not match last element of slot p"));
|
| 566 |
bates |
24 |
if (dim[2] != nnz)
|
| 883 |
bates |
25 |
return
|
| 1190 |
bates |
26 |
mkString(_("third dimension of slot x does not match number of nonzeros"));
|
| 566 |
bates |
27 |
return ScalarLogical(1);
|
|
|
28 |
}
|
|
|
29 |
|
| 572 |
bates |
30 |
/**
|
|
|
31 |
* Perform one of the matrix operations
|
|
|
32 |
* C := alpha*op(A)*B + beta*C
|
|
|
33 |
* or
|
|
|
34 |
* C := alpha*B*op(A) + beta*C
|
|
|
35 |
* where A is a compressed, sparse, blocked matrix and
|
|
|
36 |
* B and C are dense matrices.
|
|
|
37 |
*
|
| 1115 |
bates |
38 |
* @param side LFT or RGT
|
|
|
39 |
* @param transa TRN or NTR
|
| 572 |
bates |
40 |
* @param m number of rows in C
|
|
|
41 |
* @param n number of columns in C
|
| 1115 |
bates |
42 |
* @param k number of rows in B if side == LFT, otherwise
|
| 883 |
bates |
43 |
* number of columns in B.
|
| 572 |
bates |
44 |
* @param alpha
|
| 984 |
bates |
45 |
* @param A pointer to a dgBCMatrix object
|
| 883 |
bates |
46 |
* @param B matrix to be multiplied
|
|
|
47 |
* @param ldb leading dimension of b as declared in the calling
|
|
|
48 |
* routine
|
|
|
49 |
* @param beta scalar multiplier of c
|
|
|
50 |
* @param C product matrix to be modified
|
|
|
51 |
* @param ldc leading dimension of c as declared in the calling
|
|
|
52 |
* routine
|
|
|
53 |
*/
|
|
|
54 |
void
|
| 934 |
bates |
55 |
cscb_mm(enum CBLAS_SIDE side, enum CBLAS_TRANSPOSE transa,
|
|
|
56 |
int m, int n, int k, double alpha, SEXP A,
|
|
|
57 |
const double B[], int ldb, double beta, double C[], int ldc)
|
| 883 |
bates |
58 |
{
|
|
|
59 |
SEXP AxP = GET_SLOT(A, Matrix_xSym),
|
|
|
60 |
ApP = GET_SLOT(A, Matrix_pSym);
|
|
|
61 |
int *adims = INTEGER(getAttrib(AxP, R_DimSymbol)),
|
|
|
62 |
*Ap = INTEGER(ApP),
|
|
|
63 |
*Ai = INTEGER(GET_SLOT(A, Matrix_iSym)),
|
|
|
64 |
ancb = length(ApP) - 1, /* number of column blocks */
|
|
|
65 |
anrb; /* number of row blocks */
|
|
|
66 |
int absz = adims[0] * adims[1]; /* block size */
|
|
|
67 |
int j;
|
|
|
68 |
double *Ax = REAL(AxP);
|
|
|
69 |
|
| 1190 |
bates |
70 |
if (ldc < m) error(_("incompatible dims m=%d, ldc=%d"), m, ldc);
|
| 935 |
bates |
71 |
if (side == LFT) {
|
| 883 |
bates |
72 |
/* B is of size k by n */
|
|
|
73 |
if (ldb < k)
|
| 1190 |
bates |
74 |
error(_("incompatible L dims k=%d, ldb=%d, n=%d, nr=%d, nc=%d"),
|
| 883 |
bates |
75 |
k, ldb, n, adims[0], adims[1]);
|
| 934 |
bates |
76 |
if (transa == TRN) {
|
| 883 |
bates |
77 |
if (m % adims[1] || k % adims[0])
|
| 1190 |
bates |
78 |
error(_("incompatible LT dims m=%d, k = %d, nr=%d, nc=%d"),
|
| 883 |
bates |
79 |
m, k, adims[0], adims[1]);
|
|
|
80 |
if (ancb != m/adims[1])
|
| 1190 |
bates |
81 |
error(_("incompatible LT dims m=%d, ancb=%d, adims=[%d,%d,%d]"),
|
| 934 |
bates |
82 |
m, ancb, adims[0], adims[1], adims[2]);
|
| 883 |
bates |
83 |
anrb = k/adims[0];
|
|
|
84 |
} else {
|
|
|
85 |
if (m % adims[0] || k % adims[1])
|
| 1190 |
bates |
86 |
error(_("incompatible LN dims m=%d, k = %d, nr=%d, nc=%d"),
|
| 883 |
bates |
87 |
m, k, adims[0], adims[1]);
|
|
|
88 |
if (ancb != k/adims[1])
|
| 1190 |
bates |
89 |
error(_("incompatible LN dims k=%d, ancb=%d, adims=[%d,%d,%d]"),
|
| 934 |
bates |
90 |
k, ancb, adims[0], adims[1], adims[2]);
|
| 883 |
bates |
91 |
anrb = m/adims[0];
|
|
|
92 |
}
|
|
|
93 |
for (j = 0; j < ancb; j++) {
|
|
|
94 |
int kk, j2 = Ap[j + 1];
|
|
|
95 |
for (kk = Ap[j]; kk < j2; kk++) {
|
|
|
96 |
int ii = Ai[kk];
|
|
|
97 |
if (ii < 0 || ii >= anrb)
|
| 1190 |
bates |
98 |
error(_("improper row index ii=%d, anrb=%d"), ii, anrb);
|
| 934 |
bates |
99 |
if (transa == TRN) {
|
| 883 |
bates |
100 |
F77_CALL(dgemm)("T", "N", adims+1, &n, adims,
|
|
|
101 |
&alpha, Ax + kk * absz, adims,
|
|
|
102 |
B + ii * adims[0], &ldb,
|
|
|
103 |
&beta, C + j * adims[1], &ldc);
|
|
|
104 |
} else {
|
|
|
105 |
F77_CALL(dgemm)("N", "N", adims, &n, adims+1,
|
|
|
106 |
&alpha, Ax + kk * absz, adims,
|
| 934 |
bates |
107 |
B + j * adims[1], &ldb,
|
| 890 |
bates |
108 |
&beta, C + ii * adims[0], &ldc);
|
| 883 |
bates |
109 |
}
|
|
|
110 |
}
|
|
|
111 |
}
|
|
|
112 |
} else {
|
|
|
113 |
/* B is of size m by k */
|
| 1190 |
bates |
114 |
error(_("Call to cscb_mm must have side == LFT"));
|
| 883 |
bates |
115 |
}
|
|
|
116 |
}
|
|
|
117 |
|
|
|
118 |
/**
|
| 742 |
bates |
119 |
* Perform one of the matrix operations
|
|
|
120 |
* C := alpha*A*A' + beta*C,
|
|
|
121 |
* or
|
|
|
122 |
* C := alpha*A'*A + beta*C,
|
|
|
123 |
* where A is a compressed, sparse, blocked matrix and
|
|
|
124 |
* C is a compressed, sparse, symmetric blocked matrix.
|
|
|
125 |
*
|
| 1131 |
bates |
126 |
* @param uplo UPP or LOW for upper or lower
|
|
|
127 |
* @param trans TRN or NTR for transpose or no transpose
|
| 742 |
bates |
128 |
* @param alpha scalar multiplier of outer product
|
|
|
129 |
* @param A compressed sparse blocked matrix
|
|
|
130 |
* @param beta scalar multiplier of c
|
|
|
131 |
* @param C compressed sparse blocked symmetric matrix to be updated
|
|
|
132 |
*/
|
| 934 |
bates |
133 |
void
|
|
|
134 |
cscb_syrk(enum CBLAS_UPLO uplo, enum CBLAS_TRANSPOSE trans,
|
|
|
135 |
double alpha, SEXP A,
|
|
|
136 |
double beta, SEXP C)
|
| 742 |
bates |
137 |
{
|
| 883 |
bates |
138 |
SEXP AxP = GET_SLOT(A, Matrix_xSym),
|
|
|
139 |
ApP = GET_SLOT(A, Matrix_pSym),
|
|
|
140 |
CxP = GET_SLOT(C, Matrix_xSym),
|
|
|
141 |
CpP = GET_SLOT(C, Matrix_pSym);
|
|
|
142 |
int *adims = INTEGER(getAttrib(AxP, R_DimSymbol)),
|
|
|
143 |
*Ai = INTEGER(GET_SLOT(A, Matrix_iSym)),
|
|
|
144 |
*Ap = INTEGER(ApP),
|
|
|
145 |
*cdims = INTEGER(getAttrib(CxP, R_DimSymbol)),
|
|
|
146 |
*Ci = INTEGER(GET_SLOT(C, Matrix_iSym)),
|
|
|
147 |
*Cp = INTEGER(CpP),
|
| 890 |
bates |
148 |
j, k;
|
| 883 |
bates |
149 |
double *Ax = REAL(AxP), *Cx = REAL(CxP), one = 1.;
|
|
|
150 |
int scalar = (adims[0] == 1 && adims[1] == 1),
|
| 915 |
bates |
151 |
anc = length(ApP) - 1,
|
| 883 |
bates |
152 |
asz = adims[0] * adims[1],
|
|
|
153 |
csz = cdims[0] * cdims[1];
|
| 742 |
bates |
154 |
|
| 883 |
bates |
155 |
|
| 1190 |
bates |
156 |
if (cdims[0] != cdims[1]) error(_("blocks in C must be square"));
|
| 935 |
bates |
157 |
if (trans == TRN) {
|
| 938 |
bates |
158 |
/* FIXME: Write this part */
|
| 1190 |
bates |
159 |
error(_("Code for trans == TRN not yet written"));
|
| 883 |
bates |
160 |
} else {
|
| 890 |
bates |
161 |
if (adims[0] != cdims[0])
|
| 1190 |
bates |
162 |
error(_("Inconsistent dimensions: A[%d,%d,%d], C[%d,%d,%d]"),
|
| 890 |
bates |
163 |
adims[0], adims[1], adims[2],
|
|
|
164 |
cdims[0], cdims[1], cdims[2]);
|
| 742 |
bates |
165 |
/* check the row indices */
|
| 883 |
bates |
166 |
for (k = 0; k < adims[2]; k++) {
|
|
|
167 |
int aik = Ai[k];
|
| 890 |
bates |
168 |
if (aik < 0 || aik >= cdims[2])
|
| 1190 |
bates |
169 |
error(_("Row index %d = %d is out of range [0, %d]"),
|
| 890 |
bates |
170 |
k, aik, cdims[2] - 1);
|
| 883 |
bates |
171 |
}
|
|
|
172 |
/* multiply C by beta */
|
|
|
173 |
if (beta != 1.)
|
|
|
174 |
for (j = 0; j < csz * cdims[2]; j++) Cx[j] *= beta;
|
|
|
175 |
/* individual products */
|
| 915 |
bates |
176 |
for (j = 0; j < anc; j++) {
|
| 883 |
bates |
177 |
int k, kk, k2 = Ap[j+1];
|
|
|
178 |
for (k = Ap[j]; k < k2; k++) {
|
| 1544 |
bates |
179 |
int ii = Ai[k];
|
|
|
180 |
int K = check_csc_index(Cp, Ci, ii, ii, 0);
|
| 883 |
bates |
181 |
|
|
|
182 |
if (scalar) Cx[K] += alpha * Ax[k] * Ax[k];
|
| 1097 |
bates |
183 |
else F77_CALL(dsyrk)((uplo == UPP) ? "U" : "L", "N",
|
|
|
184 |
cdims, adims + 1,
|
| 883 |
bates |
185 |
&alpha, Ax + k * asz, adims,
|
|
|
186 |
&one, Cx + K * csz, cdims);
|
|
|
187 |
for (kk = k+1; kk < k2; kk++) {
|
|
|
188 |
int jj = Ai[kk];
|
| 1054 |
bates |
189 |
K = (uplo == UPP) ? check_csc_index(Cp, Ci, ii, jj, 0) :
|
|
|
190 |
check_csc_index(Cp, Ci, jj, ii, 0);
|
| 935 |
bates |
191 |
|
| 883 |
bates |
192 |
if (scalar) Cx[K] += alpha * Ax[k] * Ax[kk];
|
| 1097 |
bates |
193 |
else F77_CALL(dgemm)("N", "T", cdims, cdims + 1,
|
|
|
194 |
adims + 1, &alpha,
|
|
|
195 |
Ax+((uplo==UPP)?k:kk)*asz, adims,
|
|
|
196 |
Ax+((uplo==UPP)?kk:k)*asz, adims,
|
| 1082 |
bates |
197 |
&one, Cx + K * csz, cdims);
|
| 742 |
bates |
198 |
}
|
|
|
199 |
}
|
|
|
200 |
}
|
|
|
201 |
}
|
| 883 |
bates |
202 |
}
|
|
|
203 |
|
| 1108 |
bates |
204 |
static void
|
|
|
205 |
copy_transpose(double dest[], const double src[], int n)
|
|
|
206 |
{
|
|
|
207 |
int i, j;
|
|
|
208 |
for (i = 0; i < n; i++) {
|
|
|
209 |
for (j = 0; j < n; j++) {
|
|
|
210 |
dest[i + j * n] = src[j + i * n];
|
|
|
211 |
}
|
|
|
212 |
}
|
|
|
213 |
}
|
|
|
214 |
|
| 883 |
bates |
215 |
/**
|
| 938 |
bates |
216 |
* Create the LD^{T/2}D^{1/2}L' decomposition of the positive definite
|
| 1054 |
bates |
217 |
* symmetric dgBCMatrix matrix A (upper triangle stored) in L and D^{1/2}.
|
|
|
218 |
* D^{1/2} denotes the upper Cholesky factor of the positive definite positive
|
|
|
219 |
* definite block diagonal matrix D. The diagonal blocks are of size nci.
|
| 883 |
bates |
220 |
*
|
| 984 |
bates |
221 |
* @param A pointer to a dgBCMatrix object containing the upper
|
| 883 |
bates |
222 |
* triangle of a positive definite symmetric matrix.
|
|
|
223 |
* @param Parent the parent array for A
|
| 984 |
bates |
224 |
* @param L pointer to a dgBCMatrix object to hold L
|
| 883 |
bates |
225 |
* @param D pointer to a 3D array to hold D
|
|
|
226 |
*
|
|
|
227 |
* @return n the number of column blocks in A for success. A value
|
|
|
228 |
* less than n indicates the first column block whose diagonal was not
|
|
|
229 |
* positive definite.
|
|
|
230 |
*/
|
|
|
231 |
int
|
|
|
232 |
cscb_ldl(SEXP A, const int Parent[], SEXP L, SEXP D)
|
|
|
233 |
{
|
|
|
234 |
SEXP ApP = GET_SLOT(A, Matrix_pSym),
|
|
|
235 |
AxP = GET_SLOT(A, Matrix_xSym);
|
|
|
236 |
int *adims = INTEGER(getAttrib(AxP, R_DimSymbol)),
|
| 915 |
bates |
237 |
diag, info, j, k, n = length(ApP) - 1;
|
| 883 |
bates |
238 |
int *Ai = INTEGER(GET_SLOT(A, Matrix_iSym)),
|
|
|
239 |
*Ap = INTEGER(ApP),
|
|
|
240 |
*Li = INTEGER(GET_SLOT(L, Matrix_iSym)),
|
| 915 |
bates |
241 |
*Lp = INTEGER(GET_SLOT(L, Matrix_pSym)), nci = adims[0];
|
| 1054 |
bates |
242 |
int ncisqr = nci * nci;
|
| 883 |
bates |
243 |
double *Lx = REAL(GET_SLOT(L, Matrix_xSym)),
|
| 915 |
bates |
244 |
*Ax = REAL(AxP), *Dx = REAL(D), minus1 = -1., one = 1.;
|
| 883 |
bates |
245 |
|
| 915 |
bates |
246 |
if (adims[1] != nci || nci < 1)
|
| 1190 |
bates |
247 |
error(_("cscb_ldl: dim(A) is [%d, %d, %d]"), adims[0], adims[1], adims[2]);
|
| 883 |
bates |
248 |
for (j = 0, diag = 1; j < n; j++) { /* check for trivial structure */
|
|
|
249 |
if (Parent[j] >= 0) {diag = 0; break;}
|
|
|
250 |
}
|
|
|
251 |
if (diag) {
|
| 915 |
bates |
252 |
Memcpy(Dx, Ax, ncisqr * n);
|
|
|
253 |
for (j = 0; j < n; j++) { /* form D_i^{1/2} */
|
|
|
254 |
F77_CALL(dpotrf)("U", &nci, Dx + j * ncisqr, &nci, &k);
|
| 1108 |
bates |
255 |
if (k) return j; /* return block number, not col no. */
|
| 915 |
bates |
256 |
}
|
| 883 |
bates |
257 |
return n;
|
|
|
258 |
}
|
| 915 |
bates |
259 |
if (nci == 1) {
|
|
|
260 |
k = R_ldl_numeric(n, Ap, Ai, Ax, Lp, Parent, Li, Lx, Dx,
|
|
|
261 |
(int *) NULL, (int *) NULL);
|
| 1108 |
bates |
262 |
if (k < n) return k;
|
| 915 |
bates |
263 |
for (j = 0; j < n; j++) Dx[j] = sqrt(Dx[j]);
|
|
|
264 |
return n;
|
|
|
265 |
} else { /* Copy of ldl_numeric from the LDL package
|
|
|
266 |
* modified for blocked sparse matrices */
|
| 1054 |
bates |
267 |
int i, k, p, p2, len, top;
|
| 915 |
bates |
268 |
int *Lnz = Calloc(n, int),
|
|
|
269 |
*Pattern = Calloc(n, int),
|
|
|
270 |
*Flag = Calloc(n, int);
|
|
|
271 |
double *Y = Calloc(n * ncisqr, double), *Yi = Calloc(ncisqr, double);
|
| 883 |
bates |
272 |
|
| 915 |
bates |
273 |
for (k = 0; k < n; k++) {
|
|
|
274 |
/* compute nonzero Pattern of kth row of L, in topological order */
|
|
|
275 |
AZERO(Y + k*ncisqr, ncisqr); /* Y[,,0:k] is now all zero */
|
|
|
276 |
top = n; /* stack for pattern is empty */
|
|
|
277 |
Flag[k] = k; /* mark node k as visited */
|
|
|
278 |
Lnz[k] = 0; /* count of nonzeros in column k of L */
|
|
|
279 |
p2 = Ap[k+1];
|
|
|
280 |
for (p = Ap[k]; p < p2; p++) {
|
|
|
281 |
i = Ai[p]; /* get A[i,k] */
|
| 1190 |
bates |
282 |
if (i > k) error(_("cscb_ldl: A has nonzeros below diagonal"));
|
| 915 |
bates |
283 |
/* copy A(i,k) into Y */
|
| 1108 |
bates |
284 |
Memcpy(Y + i * ncisqr, Ax + p * ncisqr, ncisqr);
|
|
|
285 |
/* follow path from i to root of etree,
|
|
|
286 |
* stop at flagged node */
|
|
|
287 |
for (len = 0; Flag[i] != k; i = Parent[i]) {
|
|
|
288 |
Pattern[len++] = i; /* L[k,i] is nonzero */
|
|
|
289 |
Flag[i] = k; /* mark i as visited */
|
| 915 |
bates |
290 |
}
|
| 1108 |
bates |
291 |
while (len > 0) { /* push path on top of stack */
|
|
|
292 |
Pattern[--top] = Pattern[--len];
|
|
|
293 |
}
|
| 915 |
bates |
294 |
}
|
|
|
295 |
/* Pattern [top ... n-1] now contains nonzero pattern of L[,k] */
|
| 1097 |
bates |
296 |
/* compute numerical values in kth row of L
|
|
|
297 |
* (a sparse triangular solve) */
|
| 915 |
bates |
298 |
Memcpy(Dx + k * ncisqr, Y + k * ncisqr, ncisqr); /* get D[,,k] */
|
|
|
299 |
AZERO(Y + k*ncisqr, ncisqr); /* clear Y[,,k] */
|
|
|
300 |
for (; top < n; top++) {
|
|
|
301 |
i = Pattern[top];
|
|
|
302 |
Memcpy(Yi, Y + i*ncisqr, ncisqr); /* copy Y[,,i] */
|
|
|
303 |
AZERO(Y + i*ncisqr, ncisqr); /* clear Y[,,i] */
|
|
|
304 |
p2 = Lp[i] + Lnz[i];
|
|
|
305 |
for (p = Lp[i]; p < p2; p++) {
|
|
|
306 |
F77_CALL(dgemm)("N", "N", &nci, &nci, &nci, &minus1,
|
|
|
307 |
Lx + p*ncisqr, &nci, Yi, &nci,
|
|
|
308 |
&one, Y + Li[p]*ncisqr, &nci);
|
|
|
309 |
}
|
| 1097 |
bates |
310 |
/* FIXME: Is this the correct order and transposition? */
|
| 1108 |
bates |
311 |
F77_CALL(dtrsm)("L", "U", "T", "N", &nci, &nci,
|
| 915 |
bates |
312 |
&one, Dx + i*ncisqr, &nci, Yi, &nci);
|
| 1108 |
bates |
313 |
F77_CALL(dsyrk)("U", "T", &nci, &nci, &minus1, Yi, &nci,
|
| 915 |
bates |
314 |
&one, Dx + k*ncisqr, &nci);
|
| 1108 |
bates |
315 |
F77_CALL(dtrsm)("L", "U", "N", "N", &nci, &nci,
|
| 915 |
bates |
316 |
&one, Dx + i*ncisqr, &nci, Yi, &nci);
|
|
|
317 |
Li[p] = k; /* store L[k,i] in column form of L */
|
| 1108 |
bates |
318 |
/* Yi contains L[k,i]', not L[k,i] */
|
|
|
319 |
copy_transpose(Lx + p * ncisqr, Yi, nci);
|
|
|
320 |
Lnz[i]++; /* increment count of nonzeros in col i */
|
| 915 |
bates |
321 |
}
|
|
|
322 |
F77_CALL(dpotrf)("U", &nci, Dx + k*ncisqr, &nci, &info);
|
|
|
323 |
if (info) {
|
|
|
324 |
Free(Y); Free(Yi); Free(Pattern); Free(Flag); Free(Lnz);
|
| 1108 |
bates |
325 |
return k; /* failure, D[,,k] not positive definite */
|
| 915 |
bates |
326 |
}
|
|
|
327 |
}
|
|
|
328 |
Free(Y); Free(Yi); Free(Pattern); Free(Flag); Free(Lnz);
|
|
|
329 |
return n; /* success, diagonal of D is all nonzero */
|
| 883 |
bates |
330 |
}
|
| 1054 |
bates |
331 |
return -1; /* -Wall */
|
| 883 |
bates |
332 |
}
|
|
|
333 |
|
|
|
334 |
/**
|
| 984 |
bates |
335 |
* Perform one of the dgBCMatrix-matrix operations B := alpha*op(A)*B
|
| 883 |
bates |
336 |
* or B := alpha*B*op(A)
|
|
|
337 |
*
|
| 1131 |
bates |
338 |
* @param side LFT or RGT for left or right
|
|
|
339 |
* @param uplo UPP or LOW for upper or lower
|
|
|
340 |
* @param transa TRN or NTR for transpose or no transpose
|
|
|
341 |
* @param diag UNT or NUN for unit or non-unit
|
|
|
342 |
* @param alpha scalar multiplier
|
| 984 |
bates |
343 |
* @param A pointer to a triangular dgBCMatrix object
|
| 935 |
bates |
344 |
* @param B contents of the matrix B
|
| 883 |
bates |
345 |
* @param m number of rows in B
|
|
|
346 |
* @param n number of columns in B
|
|
|
347 |
* @param ldb leading dimension of B as declared in the calling function
|
|
|
348 |
*/
|
| 934 |
bates |
349 |
void
|
|
|
350 |
cscb_trmm(enum CBLAS_SIDE side, enum CBLAS_UPLO uplo,
|
|
|
351 |
enum CBLAS_TRANSPOSE transa, enum CBLAS_DIAG diag,
|
|
|
352 |
double alpha, SEXP A, double B[], int m, int n, int ldb)
|
| 883 |
bates |
353 |
{
|
| 938 |
bates |
354 |
SEXP /* ApP = GET_SLOT(A, Matrix_pSym), */
|
| 883 |
bates |
355 |
AxP = GET_SLOT(A, Matrix_xSym);
|
| 938 |
bates |
356 |
int /* *Ai = INTEGER(GET_SLOT(A, Matrix_iSym)), */
|
|
|
357 |
/* *Ap = INTEGER(ApP), */
|
| 883 |
bates |
358 |
*xdims = INTEGER(getAttrib(AxP, R_DimSymbol)),
|
| 938 |
bates |
359 |
i, j/* , nb = length(ApP) - 1 */;
|
| 883 |
bates |
360 |
|
|
|
361 |
if (xdims[0] != xdims[1])
|
| 1190 |
bates |
362 |
error(_("Argument A to cscb_trmm is not triangular"));
|
| 883 |
bates |
363 |
if (alpha != 1.0) {
|
|
|
364 |
for (j = 0; j < n; j++) { /* scale by alpha */
|
|
|
365 |
for (i = 0; i < m; i++)
|
|
|
366 |
B[i + j * ldb] *= alpha;
|
|
|
367 |
}
|
|
|
368 |
}
|
| 935 |
bates |
369 |
if (diag == UNT && xdims[2] < 1) return; /* A is the identity */
|
| 1190 |
bates |
370 |
error(_("Code for non-identity cases of cscb_trmm not yet written"));
|
| 883 |
bates |
371 |
}
|
|
|
372 |
|
|
|
373 |
/**
|
| 915 |
bates |
374 |
* Solve a triangular system of the form op(A)*X = alpha*B where A
|
| 984 |
bates |
375 |
* is a dgBCMatrix triangular matrix and B is a dense matrix.
|
| 915 |
bates |
376 |
*
|
| 1115 |
bates |
377 |
* @param uplo UPP or LOW
|
| 1131 |
bates |
378 |
* @param transa TRN or NTR
|
| 1115 |
bates |
379 |
* @param diag UNT or NUN
|
| 1131 |
bates |
380 |
* @param alpha scalar multiplier
|
| 984 |
bates |
381 |
* @param A pointer to a triangular dgBCMatrix object
|
| 915 |
bates |
382 |
* @param m number of rows in B
|
|
|
383 |
* @param n number of columns in B
|
| 1115 |
bates |
384 |
* @param B pointer to the contents of the matrix B
|
| 915 |
bates |
385 |
* @param ldb leading dimension of B as declared in the calling function
|
|
|
386 |
*/
|
| 934 |
bates |
387 |
void
|
| 1108 |
bates |
388 |
cscb_trsm(enum CBLAS_UPLO uplo, enum CBLAS_TRANSPOSE transa,
|
|
|
389 |
enum CBLAS_DIAG diag, double alpha, SEXP A,
|
| 1115 |
bates |
390 |
int m, int n, double B[], int ldb)
|
| 915 |
bates |
391 |
{
|
|
|
392 |
SEXP ApP = GET_SLOT(A, Matrix_pSym),
|
|
|
393 |
AxP = GET_SLOT(A, Matrix_xSym);
|
|
|
394 |
int *Ai = INTEGER(GET_SLOT(A, Matrix_iSym)),
|
|
|
395 |
*Ap = INTEGER(ApP),
|
|
|
396 |
*xdims = INTEGER(getAttrib(AxP, R_DimSymbol)),
|
|
|
397 |
i, j, nb = length(ApP) - 1;
|
| 935 |
bates |
398 |
double *Ax = REAL(GET_SLOT(A, Matrix_xSym)), minus1 = -1., one = 1.;
|
| 915 |
bates |
399 |
|
|
|
400 |
if (xdims[0] != xdims[1])
|
| 1190 |
bates |
401 |
error(_("Argument A to cscb_trsm is not triangular"));
|
| 915 |
bates |
402 |
if (ldb < m || ldb <= 0 || n <= 0)
|
| 1190 |
bates |
403 |
error(_("cscb_trsm: inconsistent dims m = %d, n = %d, ldb = %d"),
|
| 915 |
bates |
404 |
m, n, ldb);
|
|
|
405 |
if (m != (nb * xdims[0]))
|
| 1190 |
bates |
406 |
error(_("cscb_trsm: inconsistent dims m = %d, A[%d,%d,]x%d"),
|
| 915 |
bates |
407 |
m, xdims[0], xdims[1], xdims[2]);
|
|
|
408 |
if (alpha != 1.0) {
|
|
|
409 |
for (j = 0; j < n; j++) { /* scale by alpha */
|
|
|
410 |
for (i = 0; i < m; i++)
|
|
|
411 |
B[i + j * ldb] *= alpha;
|
|
|
412 |
}
|
|
|
413 |
}
|
| 935 |
bates |
414 |
if (diag == UNT) {
|
| 915 |
bates |
415 |
if (xdims[2] < 1) return; /* A is the identity */
|
| 935 |
bates |
416 |
if (xdims[0] == 1) { /* scalar case */
|
| 1190 |
bates |
417 |
if (uplo == UPP) error(_("Code for upper triangle not yet written"));
|
| 935 |
bates |
418 |
if (transa == TRN) {
|
| 915 |
bates |
419 |
for (j = 0; j < n; j++)
|
|
|
420 |
R_ldl_ltsolve(m, B + j * ldb, Ap, Ai, Ax);
|
|
|
421 |
} else {
|
|
|
422 |
for (j = 0; j < n; j++)
|
|
|
423 |
R_ldl_lsolve(m, B + j * ldb, Ap, Ai, Ax);
|
|
|
424 |
}
|
|
|
425 |
return;
|
| 935 |
bates |
426 |
} else {
|
| 1115 |
bates |
427 |
int p, p2, sza = xdims[0] * xdims[0];
|
|
|
428 |
|
| 1190 |
bates |
429 |
if (uplo == UPP) error(_("Code for upper triangle not yet written"));
|
| 935 |
bates |
430 |
if (transa == TRN) {
|
|
|
431 |
for (j = nb - 1; j >= 0; j--) {
|
|
|
432 |
p2 = Ap[j+1];
|
|
|
433 |
for (p = Ap[j]; p < p2; p++)
|
|
|
434 |
F77_CALL(dgemm)("T", "N", xdims, &n, xdims,
|
|
|
435 |
&minus1, Ax + p * sza, xdims,
|
|
|
436 |
B + Ai[p] * xdims[0], &ldb,
|
| 1115 |
bates |
437 |
&one, B + j * xdims[0], &ldb);
|
| 935 |
bates |
438 |
}
|
|
|
439 |
} else {
|
|
|
440 |
for (j = 0; j < nb; j++) {
|
|
|
441 |
p2 = Ap[j+1];
|
|
|
442 |
for (p = Ap[j]; p < p2; p++)
|
|
|
443 |
F77_CALL(dgemm)("N", "N", xdims, &n, xdims,
|
|
|
444 |
&minus1, Ax + p * sza, xdims,
|
| 1115 |
bates |
445 |
B + j * xdims[0], &ldb,
|
|
|
446 |
&one, B + Ai[p] * xdims[0], &ldb);
|
| 935 |
bates |
447 |
}
|
|
|
448 |
}
|
| 915 |
bates |
449 |
}
|
| 1190 |
bates |
450 |
} else {error(_("Code for non-unit cases of cscb_trsm not yet written"));}
|
| 915 |
bates |
451 |
}
|
|
|
452 |
|
|
|
453 |
/**
|
| 883 |
bates |
454 |
* Perform one of the operations B := alpha*op(A)*B or
|
| 984 |
bates |
455 |
* B := alpha*B*op(A) where A and B are both dgBCMatrix.
|
| 883 |
bates |
456 |
*
|
| 935 |
bates |
457 |
* @param side
|
|
|
458 |
* @param uplo
|
|
|
459 |
* @param transa
|
|
|
460 |
* @param diag
|
| 883 |
bates |
461 |
* @param alpha scalar multiplier
|
| 984 |
bates |
462 |
* @param A pointer to a triangular dgBCMatrix object
|
|
|
463 |
* @param B pointer to a general dgBCMatrix matrix
|
| 883 |
bates |
464 |
*/
|
| 934 |
bates |
465 |
void
|
| 935 |
bates |
466 |
cscb_trcbm(enum CBLAS_SIDE side, enum CBLAS_UPLO uplo,
|
|
|
467 |
enum CBLAS_TRANSPOSE transa, enum CBLAS_DIAG diag,
|
| 934 |
bates |
468 |
double alpha, SEXP A, SEXP B)
|
| 883 |
bates |
469 |
{
|
| 938 |
bates |
470 |
SEXP
|
|
|
471 |
/* ApP = GET_SLOT(A, Matrix_pSym), */
|
|
|
472 |
AxP = GET_SLOT(A, Matrix_xSym),
|
|
|
473 |
/* , BpP = GET_SLOT(B, Matrix_pSym) */
|
|
|
474 |
BxP = GET_SLOT(B, Matrix_xSym);
|
| 935 |
bates |
475 |
int
|
| 938 |
bates |
476 |
/* *Ai = INTEGER(GET_SLOT(A, Matrix_iSym)), */
|
|
|
477 |
/* *Ap = INTEGER(ApP), */
|
|
|
478 |
/* *Bi = INTEGER(GET_SLOT(B, Matrix_iSym)), */
|
|
|
479 |
/* *Bp = INTEGER(BpP), */
|
| 883 |
bates |
480 |
*axdims = INTEGER(getAttrib(AxP, R_DimSymbol)),
|
| 938 |
bates |
481 |
*bxdims = INTEGER(getAttrib(BxP, R_DimSymbol))
|
|
|
482 |
/* , ncbA = length(ApP) - 1 */
|
|
|
483 |
/* , ncbB = length(BpP) - 1 */
|
|
|
484 |
;
|
| 883 |
bates |
485 |
int i, nbx = bxdims[0] * bxdims[1] * bxdims[2];
|
|
|
486 |
|
|
|
487 |
if (axdims[0] != axdims[1])
|
| 1190 |
bates |
488 |
error(_("Argument A to cscb_trcbm is not triangular"));
|
| 883 |
bates |
489 |
if (alpha != 1.0) {
|
|
|
490 |
for (i = 0; i < nbx; i++) { /* scale by alpha */
|
|
|
491 |
REAL(BxP)[i] *= alpha;
|
|
|
492 |
}
|
|
|
493 |
}
|
| 935 |
bates |
494 |
if (diag == UNT && axdims[2] < 1) return; /* A is the identity */
|
| 1190 |
bates |
495 |
error(_("Code for non-trivial cscb_trcbm not yet written"));
|
| 883 |
bates |
496 |
}
|
|
|
497 |
|
|
|
498 |
/**
|
| 915 |
bates |
499 |
* Solve one of the systems op(A)*X = alpha*B or
|
| 984 |
bates |
500 |
* X*op(A) = alpha*B where A dgBCMatrix triangular and B is dgBCMatrix.
|
| 915 |
bates |
501 |
*
|
| 1131 |
bates |
502 |
* @param side LFT or RGT for left or right
|
|
|
503 |
* @param uplo UPP or LOW for upper or lower
|
|
|
504 |
* @param transa TRN or NTR for transpose or no transpose
|
|
|
505 |
* @param diag UNT or NON for unit or non-unit
|
| 915 |
bates |
506 |
* @param alpha scalar multiplier
|
| 984 |
bates |
507 |
* @param A pointer to a triangular dgBCMatrix object
|
| 1131 |
bates |
508 |
* @param Parent parent array for the column blocks of A
|
| 984 |
bates |
509 |
* @param B pointer to a general dgBCMatrix matrix
|
| 915 |
bates |
510 |
*/
|
| 934 |
bates |
511 |
void
|
| 935 |
bates |
512 |
cscb_trcbsm(enum CBLAS_SIDE side, enum CBLAS_UPLO uplo,
|
|
|
513 |
enum CBLAS_TRANSPOSE transa, enum CBLAS_DIAG diag,
|
| 934 |
bates |
514 |
double alpha, SEXP A, const int Parent[], SEXP B)
|
| 915 |
bates |
515 |
{
|
|
|
516 |
SEXP ApP = GET_SLOT(A, Matrix_pSym),
|
|
|
517 |
AxP = GET_SLOT(A, Matrix_xSym),
|
|
|
518 |
BpP = GET_SLOT(B, Matrix_pSym),
|
|
|
519 |
BxP = GET_SLOT(B, Matrix_xSym);
|
|
|
520 |
int *Ai = INTEGER(GET_SLOT(A, Matrix_iSym)),
|
|
|
521 |
*Ap = INTEGER(ApP),
|
|
|
522 |
*Bi = INTEGER(GET_SLOT(B, Matrix_iSym)),
|
|
|
523 |
*Bp = INTEGER(BpP),
|
|
|
524 |
*axdims = INTEGER(getAttrib(AxP, R_DimSymbol)),
|
|
|
525 |
*bxdims = INTEGER(getAttrib(BxP, R_DimSymbol)),
|
| 938 |
bates |
526 |
/* ncbA = length(ApP) - 1, */
|
| 915 |
bates |
527 |
ncbB = length(BpP) - 1;
|
|
|
528 |
int i, j, nbx = bxdims[0] * bxdims[1] * bxdims[2];
|
|
|
529 |
double *Ax = REAL(AxP), *Bx = REAL(BxP);
|
|
|
530 |
|
|
|
531 |
if (axdims[0] != axdims[1])
|
| 1190 |
bates |
532 |
error(_("Argument A to cscb_trcbm is not triangular"));
|
| 915 |
bates |
533 |
if (alpha != 1.0) {
|
|
|
534 |
for (i = 0; i < nbx; i++) { /* scale by alpha */
|
|
|
535 |
REAL(BxP)[i] *= alpha;
|
|
|
536 |
}
|
|
|
537 |
}
|
| 935 |
bates |
538 |
if (diag == UNT && axdims[2] < 1) return; /* A is the identity */
|
|
|
539 |
if (diag == UNT && axdims[0] == 1) { /* can use R_ldl code */
|
|
|
540 |
if ((side != LFT) && transa == TRN) { /* case required for lmer */
|
| 915 |
bates |
541 |
int *BTp, nnz = bxdims[2], nrbB;
|
| 1317 |
bates |
542 |
int *tmp = expand_cmprPt(ncbB, Bp, Calloc(nnz, int));
|
| 915 |
bates |
543 |
int *BTi = Calloc(nnz, int);
|
|
|
544 |
double *BTx = Calloc(nnz, double), *rhs;
|
|
|
545 |
|
|
|
546 |
/* transpose B */
|
| 1108 |
bates |
547 |
for (i = 0, nrbB = -1; i < nnz; i++)
|
|
|
548 |
if (Bi[i] > nrbB) nrbB = Bi[i];
|
| 1544 |
bates |
549 |
nrbB++; /* max 0-based index is 1 too small */
|
| 915 |
bates |
550 |
BTp = Calloc(nrbB, int);
|
| 987 |
bates |
551 |
triplet_to_col(ncbB, nrbB, nnz, tmp, Bi, Bx, BTp, BTi, BTx);
|
| 915 |
bates |
552 |
/* sanity check */
|
| 1190 |
bates |
553 |
if (BTp[nrbB] != nnz) error(_("cscb_trcbsm: transpose operation failed"));
|
| 915 |
bates |
554 |
Free(tmp);
|
|
|
555 |
/* Solve one column at a time */
|
|
|
556 |
rhs = Calloc(ncbB, double);
|
|
|
557 |
AZERO(Bx, nnz); /* zero the result */
|
|
|
558 |
for (i = 0; i < nrbB; i++) {
|
| 1108 |
bates |
559 |
R_ldl_lsolve(ncbB,
|
|
|
560 |
expand_csc_column(rhs, ncbB, i, BTp, BTi, BTx),
|
| 915 |
bates |
561 |
Ap, Ai, Ax);
|
| 1108 |
bates |
562 |
/* write non-zeros in sol'n into B */
|
|
|
563 |
for (j = 0; j < ncbB; j++) {
|
| 1544 |
bates |
564 |
if (rhs[j]) Bx[check_csc_index(Bp, Bi, i, j, 0)] = rhs[j];
|
| 915 |
bates |
565 |
}
|
|
|
566 |
}
|
| 1544 |
bates |
567 |
Free(rhs); Free(BTp); Free(BTx); Free(BTi);
|
|
|
568 |
return;
|
| 915 |
bates |
569 |
}
|
| 1190 |
bates |
570 |
error(_("cscb_trcbsm: method not yet written"));
|
| 915 |
bates |
571 |
}
|
| 1190 |
bates |
572 |
error(_("cscb_trcbsm: method not yet written"));
|
| 915 |
bates |
573 |
}
|
|
|
574 |
|
|
|
575 |
/**
|
| 883 |
bates |
576 |
* Perform one of the matrix-matrix operations
|
|
|
577 |
* C := alpha*op(A)*op(B) + beta*C
|
|
|
578 |
* on compressed, sparse, blocked matrices.
|
|
|
579 |
*
|
| 1131 |
bates |
580 |
* @param transa TRN or NTR for transpose or no transpose of A
|
|
|
581 |
* @param transb TRN or NTR for transpose or no transpose of B
|
| 883 |
bates |
582 |
* @param alpha scalar multiplier
|
| 984 |
bates |
583 |
* @param A pointer to a dgBCMatrix object
|
|
|
584 |
* @param B pointer to a dgBCMatrix object
|
| 883 |
bates |
585 |
* @param beta scalar multiplier
|
| 984 |
bates |
586 |
* @param C pointer to a dgBCMatrix object
|
| 883 |
bates |
587 |
*/
|
| 934 |
bates |
588 |
void
|
|
|
589 |
cscb_cscbm(enum CBLAS_TRANSPOSE transa, enum CBLAS_TRANSPOSE transb,
|
|
|
590 |
double alpha, SEXP A, SEXP B, double beta, SEXP C)
|
| 883 |
bates |
591 |
{
|
|
|
592 |
SEXP ApP = GET_SLOT(A, Matrix_pSym),
|
|
|
593 |
AxP = GET_SLOT(A, Matrix_xSym),
|
|
|
594 |
BpP = GET_SLOT(B, Matrix_pSym),
|
|
|
595 |
BxP = GET_SLOT(B, Matrix_xSym),
|
|
|
596 |
CxP = GET_SLOT(C, Matrix_xSym);
|
|
|
597 |
int *Ap = INTEGER(ApP),
|
|
|
598 |
*Ai = INTEGER(GET_SLOT(A, Matrix_iSym)),
|
|
|
599 |
*Bp = INTEGER(BpP),
|
|
|
600 |
*Bi = INTEGER(GET_SLOT(B, Matrix_iSym)),
|
|
|
601 |
*Cp = INTEGER(GET_SLOT(C, Matrix_pSym)),
|
|
|
602 |
*Ci = INTEGER(GET_SLOT(C, Matrix_iSym)),
|
|
|
603 |
*adims = INTEGER(getAttrib(AxP, R_DimSymbol)),
|
|
|
604 |
*bdims = INTEGER(getAttrib(BxP, R_DimSymbol)),
|
|
|
605 |
*cdims = INTEGER(getAttrib(CxP, R_DimSymbol)),
|
|
|
606 |
nca = length(ApP) - 1,
|
|
|
607 |
ncb = length(BpP) - 1;
|
|
|
608 |
int ablk = adims[0] * adims[1],
|
|
|
609 |
bblk = bdims[0] * bdims[1],
|
|
|
610 |
cblk = cdims[0] * cdims[1];
|
|
|
611 |
double *Ax = REAL(AxP),
|
|
|
612 |
*Bx = REAL(BxP),
|
|
|
613 |
*Cx = REAL(CxP),
|
|
|
614 |
one = 1.0;
|
|
|
615 |
|
| 935 |
bates |
616 |
if ((transa == NTR) && transb == TRN) { /* transposed crossproduct */
|
| 883 |
bates |
617 |
int jj;
|
|
|
618 |
|
|
|
619 |
if (adims[1] != bdims[1] ||
|
|
|
620 |
adims[0] != cdims[0] ||
|
|
|
621 |
bdims[0] != cdims[1])
|
| 1190 |
bates |
622 |
error(_("C[%d,%d,%d] := A[%d,%d,%d] %*% t(B[%d,%d,%d])"),
|
| 883 |
bates |
623 |
cdims[0], cdims[1], cdims[2],
|
|
|
624 |
adims[0], adims[1], adims[2],
|
|
|
625 |
bdims[0], bdims[1], bdims[2]);
|
|
|
626 |
if (nca != ncb)
|
| 1190 |
bates |
627 |
error(_("C := A(ncblocks = %d) %*% t(B(ncblocks = %d)"), nca, ncb);
|
| 883 |
bates |
628 |
if (beta != 1.) { /* scale C by beta */
|
|
|
629 |
int ctot = cdims[0] * cdims[1] * cdims[2];
|
|
|
630 |
for (jj = 0; jj < ctot; jj++) Cx[jj] *= beta;
|
|
|
631 |
}
|
|
|
632 |
for (jj = 0; jj < nca; jj++) {
|
|
|
633 |
int ia, ib, a2 = Ap[jj + 1], b2 = Bp[jj + 1];
|
|
|
634 |
for (ia = Ap[jj]; ia < a2; ia++) {
|
| 935 |
bates |
635 |
for (ib = Bp[jj]; ib < b2; ib++) {
|
|
|
636 |
F77_CALL(dgemm)("N", "T", cdims, cdims + 1, adims + 1,
|
| 1054 |
bates |
637 |
&alpha, Ax + ia * ablk, adims,
|
|
|
638 |
Bx + ib * bblk, bdims, &one,
|
| 1108 |
bates |
639 |
Cx + check_csc_index(Cp,Ci,Ai[ia],Bi[ib],0)*cblk,
|
| 1054 |
bates |
640 |
cdims);
|
| 742 |
bates |
641 |
}
|
|
|
642 |
}
|
|
|
643 |
}
|
| 883 |
bates |
644 |
return;
|
| 742 |
bates |
645 |
}
|
| 1190 |
bates |
646 |
error(_("Code not yet written"));
|
| 742 |
bates |
647 |
}
|
| 938 |
bates |
648 |
|
| 1131 |
bates |
649 |
/**
|
|
|
650 |
* Coerce a dgBCMatrix to a dgCMatrix
|
|
|
651 |
*
|
|
|
652 |
* @param A pointer to a dgBCMatrix object to coerce
|
|
|
653 |
*
|
|
|
654 |
* @return pointer to a dgCMatrix
|
|
|
655 |
*/
|
| 984 |
bates |
656 |
SEXP dgBCMatrix_to_dgCMatrix(SEXP A)
|
| 938 |
bates |
657 |
{
|
| 977 |
bates |
658 |
SEXP val = PROTECT(NEW_OBJECT(MAKE_CLASS("dgCMatrix"))),
|
| 938 |
bates |
659 |
ApP = GET_SLOT(A, Matrix_pSym),
|
|
|
660 |
AiP = GET_SLOT(A, Matrix_iSym),
|
|
|
661 |
AxP = GET_SLOT(A, Matrix_xSym);
|
|
|
662 |
int *Ai = INTEGER(AiP), *Ap = INTEGER(ApP), *Bi, *Bp, *Dims,
|
|
|
663 |
*adims = INTEGER(getAttrib(AxP, R_DimSymbol)),
|
|
|
664 |
ii, j, ncb = length(ApP) - 1, nnz, nrb;
|
|
|
665 |
int nc = adims[1], nr = adims[0];
|
|
|
666 |
int sz = nc * nr;
|
|
|
667 |
double *Ax = REAL(AxP), *Bx;
|
|
|
668 |
|
| 975 |
bates |
669 |
SET_SLOT(val, Matrix_factorSym, allocVector(VECSXP, 0));
|
| 938 |
bates |
670 |
SET_SLOT(val, Matrix_DimSym, allocVector(INTSXP, 2));
|
|
|
671 |
Dims = INTEGER(GET_SLOT(val, Matrix_DimSym));
|
|
|
672 |
Dims[1] = ncb * adims[1];
|
|
|
673 |
/* find number of row blocks */
|
|
|
674 |
for (j = 0, nrb = -1; j < adims[2]; j++) if (Ai[j] > nrb) nrb = Ai[j];
|
| 1054 |
bates |
675 |
Dims[0] = (nrb + 1) * adims[0]; /* +1 because of 0-based indices */
|
| 938 |
bates |
676 |
nnz = length(AxP);
|
|
|
677 |
|
|
|
678 |
if (nc == 1) { /* x slot is in the correct order */
|
|
|
679 |
SET_SLOT(val, Matrix_pSym, duplicate(ApP));
|
|
|
680 |
SET_SLOT(val, Matrix_iSym, allocVector(INTSXP, nnz));
|
|
|
681 |
SET_SLOT(val, Matrix_xSym, allocVector(REALSXP, nnz));
|
|
|
682 |
Memcpy(REAL(GET_SLOT(val, Matrix_xSym)), Ax, nnz);
|
|
|
683 |
if (nr == 1) {
|
|
|
684 |
Memcpy(INTEGER(GET_SLOT(val, Matrix_iSym)), Ai, nnz);
|
|
|
685 |
} else {
|
|
|
686 |
Bi = INTEGER(GET_SLOT(val, Matrix_iSym));
|
|
|
687 |
Bp = INTEGER(GET_SLOT(val, Matrix_pSym));
|
|
|
688 |
for (j = 0; j <= ncb; j++) Bp[j] *= nr;
|
|
|
689 |
for (j = 0; j < adims[2]; j++) {
|
|
|
690 |
for (ii = 0; ii < nr; ii++) {
|
|
|
691 |
Bi[j * nr + ii] = Ai[j] * nr + ii;
|
|
|
692 |
}
|
|
|
693 |
}
|
|
|
694 |
}
|
|
|
695 |
} else {
|
|
|
696 |
SET_SLOT(val, Matrix_pSym, allocVector(INTSXP, Dims[1] + 1));
|
|
|
697 |
Bp = INTEGER(GET_SLOT(val, Matrix_pSym));
|
|
|
698 |
SET_SLOT(val, Matrix_iSym, allocVector(INTSXP, nnz));
|
|
|
699 |
Bi = INTEGER(GET_SLOT(val, Matrix_iSym));
|
|
|
700 |
SET_SLOT(val, Matrix_xSym, allocVector(REALSXP, nnz));
|
|
|
701 |
Bx = REAL(GET_SLOT(val, Matrix_xSym));
|
|
|
702 |
|
|
|
703 |
Bp[0] = 0;
|
|
|
704 |
for (j = 0; j < ncb; j++) { /* Column blocks of A */
|
|
|
705 |
int i, i1 = Ap[j], i2 = Ap[j + 1], jj;
|
|
|
706 |
int nzbc = (i2 - i1) * nr; /* No. of non-zeroes in B column */
|
|
|
707 |
|
|
|
708 |
for (jj = 0; jj < nc; jj++) { /* column within blocks */
|
|
|
709 |
int jb = nc * j + jj; /* Column number in B */
|
|
|
710 |
|
|
|
711 |
Bp[jb] = i1 * sz + jj * nzbc;
|
|
|
712 |
for (i = i1; i < i2; i++) { /* index in Ai and Ax */
|
|
|
713 |
for (ii = 0; ii < adims[0]; ii++) { /* row within blocks */
|
|
|
714 |
int ind = ii + (i - i1) * nr + Bp[jb];
|
|
|
715 |
|
|
|
716 |
Bi[ind] = Ai[i] * sz + jj * nzbc + ii;
|
|
|
717 |
Bx[ind] = Ax[i * sz + jj * nc + ii];
|
|
|
718 |
}
|
|
|
719 |
}
|
|
|
720 |
}
|
|
|
721 |
}
|
|
|
722 |
}
|
|
|
723 |
UNPROTECT(1);
|
|
|
724 |
return val;
|
|
|
725 |
}
|
| 1054 |
bates |
726 |
|
|
|
727 |
SEXP dgBCMatrix_to_dgTMatrix(SEXP A)
|
|
|
728 |
{
|
|
|
729 |
SEXP val = PROTECT(NEW_OBJECT(MAKE_CLASS("dgTMatrix"))),
|
|
|
730 |
ApP = GET_SLOT(A, Matrix_pSym),
|
|
|
731 |
AxP = GET_SLOT(A, Matrix_xSym);
|
|
|
732 |
int *Ai = INTEGER(GET_SLOT(A, Matrix_iSym)), *Ap = INTEGER(ApP),
|
|
|
733 |
*bdims = INTEGER(GET_SLOT(val, Matrix_DimSym)),
|
|
|
734 |
*adims = INTEGER(getAttrib(AxP, R_DimSymbol)),
|
|
|
735 |
i, j, k, kk, ncb = length(ApP) - 1, nnz = length(AxP), nrb;
|
| 1317 |
bates |
736 |
int *Aj = expand_cmprPt(ncb, Ap, Calloc(nnz, int)),
|
| 1054 |
bates |
737 |
*Bi = INTEGER(ALLOC_SLOT(val, Matrix_iSym, INTSXP, nnz)),
|
|
|
738 |
*Bj = INTEGER(ALLOC_SLOT(val, Matrix_jSym, INTSXP, nnz)),
|
|
|
739 |
nblk = adims[2], nc = adims[1], nr = adims[0];
|
|
|
740 |
int sz = nc * nr;
|
|
|
741 |
int *ai = Calloc(sz, int), *aj = Calloc(sz, int);
|
|
|
742 |
double *Ax = REAL(AxP),
|
|
|
743 |
*Bx = REAL(ALLOC_SLOT(val, Matrix_xSym, REALSXP, nnz));
|
|
|
744 |
|
| 1108 |
bates |
745 |
Memcpy(Bx, Ax, nnz); /* x slot stays as is but w/o dim attribute */
|
| 1054 |
bates |
746 |
|
| 1108 |
bates |
747 |
bdims[1] = ncb * adims[1];
|
|
|
748 |
/* find number of row blocks */
|
| 1054 |
bates |
749 |
for (j = 0, nrb = -1; j < adims[2]; j++) if (Ai[j] > nrb) nrb = Ai[j];
|
|
|
750 |
bdims[0] = (nrb + 1) * adims[0]; /* +1 because of 0-based indices */
|
|
|
751 |
|
|
|
752 |
for (j = 0; j < nc; j++) { /* arrays of inner indices */
|
|
|
753 |
for (i = 0; i < nr; i++) {
|
|
|
754 |
int ind = j * nc + i;
|
|
|
755 |
ai[ind] = i;
|
|
|
756 |
aj[ind] = j;
|
|
|
757 |
}
|
|
|
758 |
}
|
|
|
759 |
for (i = 0, k = 0; k < nblk; k++) {
|
|
|
760 |
for (kk = 0; kk < sz; kk++) {
|
|
|
761 |
Bi[k * sz + kk] = Ai[k] * nr + ai[kk];
|
|
|
762 |
Bj[k * sz + kk] = Aj[k] * nc + aj[kk];
|
|
|
763 |
}
|
|
|
764 |
}
|
|
|
765 |
|
|
|
766 |
Free(Aj); Free(ai); Free(aj);
|
|
|
767 |
UNPROTECT(1);
|
|
|
768 |
return val;
|
|
|
769 |
}
|