The R Project SVN R-packages

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
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
}