| 2304 |
bates |
1 |
/* Sparse matrices in compressed column-oriented form */
|
| 1830 |
bates |
2 |
#include "Csparse.h"
|
| 4972 |
maechler |
3 |
#include "Tsparse.h"
|
| 1830 |
bates |
4 |
#include "chm_common.h"
|
|
|
5 |
|
|
|
6 |
SEXP Csparse_validate(SEXP x)
|
|
|
7 |
{
|
| 3791 |
maechler |
8 |
/* NB: we do *NOT* check a potential 'x' slot here, at all */
|
| 1830 |
bates |
9 |
SEXP pslot = GET_SLOT(x, Matrix_pSym),
|
|
|
10 |
islot = GET_SLOT(x, Matrix_iSym);
|
| 4456 |
maechler |
11 |
Rboolean sorted, strictly;
|
|
|
12 |
int j, k,
|
| 1830 |
bates |
13 |
*dims = INTEGER(GET_SLOT(x, Matrix_DimSym)),
|
| 3943 |
maechler |
14 |
nrow = dims[0],
|
|
|
15 |
ncol = dims[1],
|
| 3931 |
maechler |
16 |
*xp = INTEGER(pslot),
|
| 1830 |
bates |
17 |
*xi = INTEGER(islot);
|
|
|
18 |
|
| 3931 |
maechler |
19 |
if (length(pslot) != dims[1] + 1)
|
|
|
20 |
return mkString(_("slot p must have length = ncol(.) + 1"));
|
| 1830 |
bates |
21 |
if (xp[0] != 0)
|
|
|
22 |
return mkString(_("first element of slot p must be zero"));
|
| 4456 |
maechler |
23 |
if (length(islot) < xp[ncol]) /* allow larger slots from over-allocation!*/
|
| 3766 |
bates |
24 |
return
|
|
|
25 |
mkString(_("last element of slot p must match length of slots i and x"));
|
|
|
26 |
for (j = 0; j < length(islot); j++) {
|
|
|
27 |
if (xi[j] < 0 || xi[j] >= nrow)
|
|
|
28 |
return mkString(_("all row indices must be between 0 and nrow-1"));
|
|
|
29 |
}
|
| 4456 |
maechler |
30 |
sorted = TRUE; strictly = TRUE;
|
| 1830 |
bates |
31 |
for (j = 0; j < ncol; j++) {
|
|
|
32 |
if (xp[j] > xp[j+1])
|
|
|
33 |
return mkString(_("slot p must be non-decreasing"));
|
| 4456 |
maechler |
34 |
if(sorted)
|
|
|
35 |
for (k = xp[j] + 1; k < xp[j + 1]; k++) {
|
|
|
36 |
if (xi[k] < xi[k - 1])
|
|
|
37 |
sorted = FALSE;
|
|
|
38 |
else if (xi[k] == xi[k - 1])
|
|
|
39 |
strictly = FALSE;
|
|
|
40 |
}
|
| 1830 |
bates |
41 |
}
|
| 3931 |
maechler |
42 |
if (!sorted) {
|
| 4565 |
maechler |
43 |
CHM_SP chx = AS_CHM_SP(x);
|
|
|
44 |
R_CheckStack();
|
|
|
45 |
|
| 3931 |
maechler |
46 |
cholmod_sort(chx, &c);
|
| 4456 |
maechler |
47 |
/* Now re-check that row indices are *strictly* increasing
|
|
|
48 |
* (and not just increasing) within each column : */
|
|
|
49 |
for (j = 0; j < ncol; j++) {
|
|
|
50 |
for (k = xp[j] + 1; k < xp[j + 1]; k++)
|
|
|
51 |
if (xi[k] == xi[k - 1])
|
|
|
52 |
return mkString(_("slot i is not *strictly* increasing inside a column (even after cholmod_sort)"));
|
|
|
53 |
}
|
|
|
54 |
|
|
|
55 |
} else if(!strictly) { /* sorted, but not strictly */
|
|
|
56 |
return mkString(_("slot i is not *strictly* increasing inside a column"));
|
| 3931 |
maechler |
57 |
}
|
| 1830 |
bates |
58 |
return ScalarLogical(1);
|
|
|
59 |
}
|
|
|
60 |
|
| 4573 |
maechler |
61 |
SEXP Rsparse_validate(SEXP x)
|
|
|
62 |
{
|
|
|
63 |
/* NB: we do *NOT* check a potential 'x' slot here, at all */
|
|
|
64 |
SEXP pslot = GET_SLOT(x, Matrix_pSym),
|
|
|
65 |
jslot = GET_SLOT(x, Matrix_jSym);
|
|
|
66 |
Rboolean sorted, strictly;
|
|
|
67 |
int i, k,
|
|
|
68 |
*dims = INTEGER(GET_SLOT(x, Matrix_DimSym)),
|
|
|
69 |
nrow = dims[0],
|
|
|
70 |
ncol = dims[1],
|
|
|
71 |
*xp = INTEGER(pslot),
|
|
|
72 |
*xj = INTEGER(jslot);
|
|
|
73 |
|
|
|
74 |
if (length(pslot) != dims[0] + 1)
|
|
|
75 |
return mkString(_("slot p must have length = nrow(.) + 1"));
|
|
|
76 |
if (xp[0] != 0)
|
|
|
77 |
return mkString(_("first element of slot p must be zero"));
|
|
|
78 |
if (length(jslot) < xp[nrow]) /* allow larger slots from over-allocation!*/
|
|
|
79 |
return
|
|
|
80 |
mkString(_("last element of slot p must match length of slots j and x"));
|
|
|
81 |
for (i = 0; i < length(jslot); i++) {
|
|
|
82 |
if (xj[i] < 0 || xj[i] >= ncol)
|
|
|
83 |
return mkString(_("all column indices must be between 0 and ncol-1"));
|
|
|
84 |
}
|
|
|
85 |
sorted = TRUE; strictly = TRUE;
|
|
|
86 |
for (i = 0; i < nrow; i++) {
|
|
|
87 |
if (xp[i] > xp[i+1])
|
|
|
88 |
return mkString(_("slot p must be non-decreasing"));
|
|
|
89 |
if(sorted)
|
|
|
90 |
for (k = xp[i] + 1; k < xp[i + 1]; k++) {
|
|
|
91 |
if (xj[k] < xj[k - 1])
|
|
|
92 |
sorted = FALSE;
|
|
|
93 |
else if (xj[k] == xj[k - 1])
|
|
|
94 |
strictly = FALSE;
|
|
|
95 |
}
|
|
|
96 |
}
|
|
|
97 |
if (!sorted)
|
|
|
98 |
/* cannot easily use cholmod_sort(.) ... -> "error out" :*/
|
|
|
99 |
return mkString(_("slot j is not increasing inside a column"));
|
|
|
100 |
else if(!strictly) /* sorted, but not strictly */
|
|
|
101 |
return mkString(_("slot j is not *strictly* increasing inside a column"));
|
|
|
102 |
|
|
|
103 |
return ScalarLogical(1);
|
|
|
104 |
}
|
|
|
105 |
|
|
|
106 |
|
| 4109 |
maechler |
107 |
/* Called from ../R/Csparse.R : */
|
|
|
108 |
/* Can only return [dln]geMatrix (no symm/triang);
|
|
|
109 |
* FIXME: replace by non-CHOLMOD code ! */
|
| 2022 |
bates |
110 |
SEXP Csparse_to_dense(SEXP x)
|
|
|
111 |
{
|
| 4565 |
maechler |
112 |
CHM_SP chxs = AS_CHM_SP(x);
|
| 4109 |
maechler |
113 |
/* This loses the symmetry property, since cholmod_dense has none,
|
|
|
114 |
* BUT, much worse (FIXME!), it also transforms CHOLMOD_PATTERN ("n") matrices
|
|
|
115 |
* to numeric (CHOLMOD_REAL) ones : */
|
| 4565 |
maechler |
116 |
CHM_DN chxd = cholmod_sparse_to_dense(chxs, &c);
|
| 4109 |
maechler |
117 |
int Rkind = (chxs->xtype == CHOLMOD_PATTERN)? -1 : Real_kind(x);
|
| 4565 |
maechler |
118 |
R_CheckStack();
|
| 2022 |
bates |
119 |
|
| 4093 |
maechler |
120 |
return chm_dense_to_SEXP(chxd, 1, Rkind, GET_SLOT(x, Matrix_DimNamesSym));
|
| 2022 |
bates |
121 |
}
|
|
|
122 |
|
| 3755 |
maechler |
123 |
SEXP Csparse_to_nz_pattern(SEXP x, SEXP tri)
|
| 3406 |
bates |
124 |
{
|
| 4565 |
maechler |
125 |
CHM_SP chxs = AS_CHM_SP(x);
|
|
|
126 |
CHM_SP chxcp = cholmod_copy(chxs, chxs->stype, CHOLMOD_PATTERN, &c);
|
| 4418 |
bates |
127 |
int tr = asLogical(tri);
|
| 4565 |
maechler |
128 |
R_CheckStack();
|
| 3406 |
bates |
129 |
|
| 4565 |
maechler |
130 |
return chm_sparse_to_SEXP(chxcp, 1/*do_free*/,
|
| 4418 |
bates |
131 |
tr ? ((*uplo_P(x) == 'U') ? 1 : -1) : 0,
|
|
|
132 |
0, tr ? diag_P(x) : "",
|
| 3755 |
maechler |
133 |
GET_SLOT(x, Matrix_DimNamesSym));
|
| 3406 |
bates |
134 |
}
|
|
|
135 |
|
| 3401 |
bates |
136 |
SEXP Csparse_to_matrix(SEXP x)
|
| 1830 |
bates |
137 |
{
|
| 4565 |
maechler |
138 |
return chm_dense_to_matrix(cholmod_sparse_to_dense(AS_CHM_SP(x), &c),
|
|
|
139 |
1 /*do_free*/, GET_SLOT(x, Matrix_DimNamesSym));
|
| 3401 |
bates |
140 |
}
|
|
|
141 |
|
|
|
142 |
SEXP Csparse_to_Tsparse(SEXP x, SEXP tri)
|
|
|
143 |
{
|
| 4565 |
maechler |
144 |
CHM_SP chxs = AS_CHM_SP(x);
|
|
|
145 |
CHM_TR chxt = cholmod_sparse_to_triplet(chxs, &c);
|
| 4418 |
bates |
146 |
int tr = asLogical(tri);
|
| 4093 |
maechler |
147 |
int Rkind = (chxs->xtype != CHOLMOD_PATTERN) ? Real_kind(x) : 0;
|
| 4565 |
maechler |
148 |
R_CheckStack();
|
| 1830 |
bates |
149 |
|
| 4418 |
bates |
150 |
return chm_triplet_to_SEXP(chxt, 1,
|
|
|
151 |
tr ? ((*uplo_P(x) == 'U') ? 1 : -1) : 0,
|
|
|
152 |
Rkind, tr ? diag_P(x) : "",
|
| 3406 |
bates |
153 |
GET_SLOT(x, Matrix_DimNamesSym));
|
| 1830 |
bates |
154 |
}
|
|
|
155 |
|
| 3502 |
bates |
156 |
/* this used to be called sCMatrix_to_gCMatrix(..) [in ./dsCMatrix.c ]: */
|
| 3406 |
bates |
157 |
SEXP Csparse_symmetric_to_general(SEXP x)
|
|
|
158 |
{
|
| 4565 |
maechler |
159 |
CHM_SP chx = AS_CHM_SP(x), chgx;
|
| 4093 |
maechler |
160 |
int Rkind = (chx->xtype != CHOLMOD_PATTERN) ? Real_kind(x) : 0;
|
| 4565 |
maechler |
161 |
R_CheckStack();
|
| 3406 |
bates |
162 |
|
|
|
163 |
if (!(chx->stype))
|
| 3755 |
maechler |
164 |
error(_("Nonsymmetric matrix in Csparse_symmetric_to_general"));
|
| 3410 |
maechler |
165 |
chgx = cholmod_copy(chx, /* stype: */ 0, chx->xtype, &c);
|
|
|
166 |
/* xtype: pattern, "real", complex or .. */
|
| 3755 |
maechler |
167 |
return chm_sparse_to_SEXP(chgx, 1, 0, Rkind, "",
|
| 3406 |
bates |
168 |
GET_SLOT(x, Matrix_DimNamesSym));
|
|
|
169 |
}
|
|
|
170 |
|
| 3876 |
maechler |
171 |
SEXP Csparse_general_to_symmetric(SEXP x, SEXP uplo)
|
| 3835 |
maechler |
172 |
{
|
| 4565 |
maechler |
173 |
CHM_SP chx = AS_CHM_SP(x), chgx;
|
| 4953 |
maechler |
174 |
int uploT = (*CHAR(STRING_ELT(uplo,0)) == 'U') ? 1 : -1;
|
| 4093 |
maechler |
175 |
int Rkind = (chx->xtype != CHOLMOD_PATTERN) ? Real_kind(x) : 0;
|
| 4565 |
maechler |
176 |
R_CheckStack();
|
| 3835 |
maechler |
177 |
|
| 3876 |
maechler |
178 |
chgx = cholmod_copy(chx, /* stype: */ uploT, chx->xtype, &c);
|
| 3835 |
maechler |
179 |
/* xtype: pattern, "real", complex or .. */
|
|
|
180 |
return chm_sparse_to_SEXP(chgx, 1, 0, Rkind, "",
|
|
|
181 |
GET_SLOT(x, Matrix_DimNamesSym));
|
|
|
182 |
}
|
|
|
183 |
|
| 3404 |
bates |
184 |
SEXP Csparse_transpose(SEXP x, SEXP tri)
|
| 1830 |
bates |
185 |
{
|
| 4500 |
maechler |
186 |
/* TODO: lgCMatrix & igC* currently go via double prec. cholmod -
|
|
|
187 |
* since cholmod (& cs) lacks sparse 'int' matrices */
|
| 4565 |
maechler |
188 |
CHM_SP chx = AS_CHM_SP(x);
|
| 4093 |
maechler |
189 |
int Rkind = (chx->xtype != CHOLMOD_PATTERN) ? Real_kind(x) : 0;
|
| 4565 |
maechler |
190 |
CHM_SP chxt = cholmod_transpose(chx, chx->xtype, &c);
|
| 3401 |
bates |
191 |
SEXP dn = PROTECT(duplicate(GET_SLOT(x, Matrix_DimNamesSym))), tmp;
|
| 4418 |
bates |
192 |
int tr = asLogical(tri);
|
| 4565 |
maechler |
193 |
R_CheckStack();
|
| 3404 |
bates |
194 |
|
| 3401 |
bates |
195 |
tmp = VECTOR_ELT(dn, 0); /* swap the dimnames */
|
|
|
196 |
SET_VECTOR_ELT(dn, 0, VECTOR_ELT(dn, 1));
|
|
|
197 |
SET_VECTOR_ELT(dn, 1, tmp);
|
|
|
198 |
UNPROTECT(1);
|
| 4418 |
bates |
199 |
return chm_sparse_to_SEXP(chxt, 1, /* SWAP 'uplo' for triangular */
|
|
|
200 |
tr ? ((*uplo_P(x) == 'U') ? -1 : 1) : 0,
|
|
|
201 |
Rkind, tr ? diag_P(x) : "", dn);
|
| 1830 |
bates |
202 |
}
|
|
|
203 |
|
|
|
204 |
SEXP Csparse_Csparse_prod(SEXP a, SEXP b)
|
|
|
205 |
{
|
| 4972 |
maechler |
206 |
CHM_SP
|
|
|
207 |
cha = AS_CHM_SP(Csparse_diagU2N(a)),
|
|
|
208 |
chb = AS_CHM_SP(Csparse_diagU2N(b)),
|
| 4979 |
maechler |
209 |
chc = cholmod_ssmult(cha, chb, /*out_stype:*/ 0,
|
|
|
210 |
cha->xtype, /*out sorted:*/ 1, &c);
|
|
|
211 |
const char *cl_a = class_P(a), *cl_b = class_P(b);
|
|
|
212 |
char diag[] = {'\0', '\0'};
|
|
|
213 |
int uploT = 0;
|
| 3401 |
bates |
214 |
SEXP dn = allocVector(VECSXP, 2);
|
| 4565 |
maechler |
215 |
R_CheckStack();
|
| 1830 |
bates |
216 |
|
| 4979 |
maechler |
217 |
/* Preserve triangularity and even unit-triangularity if appropriate.
|
|
|
218 |
* Note that in that case, the multiplication itself should happen
|
|
|
219 |
* faster. But there's no support for that in CHOLMOD */
|
|
|
220 |
|
|
|
221 |
/* UGLY hack -- rather should have (fast!) C-level version of
|
|
|
222 |
* is(a, "triangularMatrix") etc */
|
|
|
223 |
if (cl_a[1] == 't' && cl_b[1] == 't')
|
|
|
224 |
/* FIXME: fails for "Cholesky","BunchKaufmann"..*/
|
|
|
225 |
if(*uplo_P(a) == *uplo_P(b)) { /* both upper, or both lower tri. */
|
|
|
226 |
uploT = (*uplo_P(a) == 'U') ? 1 : -1;
|
|
|
227 |
if(*diag_P(a) == 'U' && *diag_P(b) == 'U') { /* return UNIT-triag. */
|
|
|
228 |
/* "remove the diagonal entries": */
|
|
|
229 |
chm_diagN2U(chc, uploT, /* do_realloc */ FALSE);
|
|
|
230 |
diag[0]= 'U';
|
|
|
231 |
}
|
|
|
232 |
else diag[0]= 'N';
|
|
|
233 |
}
|
| 3401 |
bates |
234 |
SET_VECTOR_ELT(dn, 0, /* establish dimnames */
|
|
|
235 |
duplicate(VECTOR_ELT(GET_SLOT(a, Matrix_DimNamesSym), 0)));
|
|
|
236 |
SET_VECTOR_ELT(dn, 1,
|
|
|
237 |
duplicate(VECTOR_ELT(GET_SLOT(b, Matrix_DimNamesSym), 1)));
|
| 4979 |
maechler |
238 |
return chm_sparse_to_SEXP(chc, 1, uploT, /*Rkind*/0, diag, dn);
|
| 1830 |
bates |
239 |
}
|
|
|
240 |
|
| 3942 |
maechler |
241 |
SEXP Csparse_Csparse_crossprod(SEXP a, SEXP b, SEXP trans)
|
| 3940 |
bates |
242 |
{
|
| 3942 |
maechler |
243 |
int tr = asLogical(trans);
|
| 4972 |
maechler |
244 |
CHM_SP
|
|
|
245 |
cha = AS_CHM_SP(Csparse_diagU2N(a)),
|
|
|
246 |
chb = AS_CHM_SP(Csparse_diagU2N(b)),
|
|
|
247 |
chTr, chc;
|
| 4979 |
maechler |
248 |
const char *cl_a = class_P(a), *cl_b = class_P(b);
|
|
|
249 |
char diag[] = {'\0', '\0'};
|
|
|
250 |
int uploT = 0;
|
| 3940 |
bates |
251 |
SEXP dn = allocVector(VECSXP, 2);
|
| 4565 |
maechler |
252 |
R_CheckStack();
|
| 3940 |
bates |
253 |
|
| 4565 |
maechler |
254 |
chTr = cholmod_transpose((tr) ? chb : cha, chb->xtype, &c);
|
| 3942 |
maechler |
255 |
chc = cholmod_ssmult((tr) ? cha : chTr, (tr) ? chTr : chb,
|
| 4979 |
maechler |
256 |
/*out_stype:*/ 0, cha->xtype, /*out sorted:*/ 1, &c);
|
| 4565 |
maechler |
257 |
cholmod_free_sparse(&chTr, &c);
|
| 3942 |
maechler |
258 |
|
| 4979 |
maechler |
259 |
/* Preserve triangularity and unit-triangularity if appropriate;
|
|
|
260 |
* see Csparse_Csparse_prod() for comments */
|
|
|
261 |
if (cl_a[1] == 't' && cl_b[1] == 't')
|
|
|
262 |
if(*uplo_P(a) != *uplo_P(b)) { /* one 'U', the other 'L' */
|
|
|
263 |
uploT = (*uplo_P(b) == 'U') ? 1 : -1;
|
|
|
264 |
if(*diag_P(a) == 'U' && *diag_P(b) == 'U') { /* return UNIT-triag. */
|
|
|
265 |
chm_diagN2U(chc, uploT, /* do_realloc */ FALSE);
|
|
|
266 |
diag[0]= 'U';
|
|
|
267 |
}
|
|
|
268 |
else diag[0]= 'N';
|
|
|
269 |
}
|
|
|
270 |
|
| 3940 |
bates |
271 |
SET_VECTOR_ELT(dn, 0, /* establish dimnames */
|
| 3942 |
maechler |
272 |
duplicate(VECTOR_ELT(GET_SLOT(a, Matrix_DimNamesSym), (tr) ? 0 : 1)));
|
| 3940 |
bates |
273 |
SET_VECTOR_ELT(dn, 1,
|
| 3942 |
maechler |
274 |
duplicate(VECTOR_ELT(GET_SLOT(b, Matrix_DimNamesSym), (tr) ? 0 : 1)));
|
| 4979 |
maechler |
275 |
return chm_sparse_to_SEXP(chc, 1, uploT, /*Rkind*/0, diag, dn);
|
| 3940 |
bates |
276 |
}
|
|
|
277 |
|
| 1830 |
bates |
278 |
SEXP Csparse_dense_prod(SEXP a, SEXP b)
|
|
|
279 |
{
|
| 4972 |
maechler |
280 |
CHM_SP cha = AS_CHM_SP(Csparse_diagU2N(a));
|
| 3943 |
maechler |
281 |
SEXP b_M = PROTECT(mMatrix_as_dgeMatrix(b));
|
| 4565 |
maechler |
282 |
CHM_DN chb = AS_CHM_DN(b_M);
|
|
|
283 |
CHM_DN chc = cholmod_allocate_dense(cha->nrow, chb->ncol, cha->nrow,
|
|
|
284 |
chb->xtype, &c);
|
|
|
285 |
SEXP dn = PROTECT(allocVector(VECSXP, 2));
|
|
|
286 |
double one[] = {1,0}, zero[] = {0,0};
|
|
|
287 |
R_CheckStack();
|
| 1830 |
bates |
288 |
|
| 4565 |
maechler |
289 |
cholmod_sdmult(cha, 0, one, zero, chb, chc, &c);
|
| 3943 |
maechler |
290 |
SET_VECTOR_ELT(dn, 0, /* establish dimnames */
|
|
|
291 |
duplicate(VECTOR_ELT(GET_SLOT(a, Matrix_DimNamesSym), 0)));
|
|
|
292 |
SET_VECTOR_ELT(dn, 1,
|
|
|
293 |
duplicate(VECTOR_ELT(GET_SLOT(b_M, Matrix_DimNamesSym), 1)));
|
| 4565 |
maechler |
294 |
UNPROTECT(2);
|
| 3943 |
maechler |
295 |
return chm_dense_to_SEXP(chc, 1, 0, dn);
|
| 1830 |
bates |
296 |
}
|
| 1833 |
maechler |
297 |
|
| 2030 |
bates |
298 |
SEXP Csparse_dense_crossprod(SEXP a, SEXP b)
|
|
|
299 |
{
|
| 4972 |
maechler |
300 |
CHM_SP cha = AS_CHM_SP(Csparse_diagU2N(a));
|
| 3943 |
maechler |
301 |
SEXP b_M = PROTECT(mMatrix_as_dgeMatrix(b));
|
| 4565 |
maechler |
302 |
CHM_DN chb = AS_CHM_DN(b_M);
|
|
|
303 |
CHM_DN chc = cholmod_allocate_dense(cha->ncol, chb->ncol, cha->ncol,
|
|
|
304 |
chb->xtype, &c);
|
|
|
305 |
SEXP dn = PROTECT(allocVector(VECSXP, 2));
|
|
|
306 |
double one[] = {1,0}, zero[] = {0,0};
|
|
|
307 |
R_CheckStack();
|
| 2030 |
bates |
308 |
|
| 4565 |
maechler |
309 |
cholmod_sdmult(cha, 1, one, zero, chb, chc, &c);
|
| 3943 |
maechler |
310 |
SET_VECTOR_ELT(dn, 0, /* establish dimnames */
|
|
|
311 |
duplicate(VECTOR_ELT(GET_SLOT(a, Matrix_DimNamesSym), 1)));
|
|
|
312 |
SET_VECTOR_ELT(dn, 1,
|
|
|
313 |
duplicate(VECTOR_ELT(GET_SLOT(b_M, Matrix_DimNamesSym), 1)));
|
| 4565 |
maechler |
314 |
UNPROTECT(2);
|
| 3943 |
maechler |
315 |
return chm_dense_to_SEXP(chc, 1, 0, dn);
|
| 2030 |
bates |
316 |
}
|
|
|
317 |
|
| 4979 |
maechler |
318 |
/* Computes x'x or x x' -- *also* for Tsparse (triplet = TRUE)
|
|
|
319 |
see Csparse_Csparse_crossprod above for x'y and x y' */
|
| 1836 |
bates |
320 |
SEXP Csparse_crossprod(SEXP x, SEXP trans, SEXP triplet)
|
| 1830 |
bates |
321 |
{
|
| 1870 |
maechler |
322 |
int trip = asLogical(triplet),
|
|
|
323 |
tr = asLogical(trans); /* gets reversed because _aat is tcrossprod */
|
| 4972 |
maechler |
324 |
CHM_TR cht = trip ? AS_CHM_TR(Tsparse_diagU2N(x)) : (CHM_TR) NULL;
|
| 4565 |
maechler |
325 |
CHM_SP chcp, chxt,
|
| 4972 |
maechler |
326 |
chx = (trip ?
|
|
|
327 |
cholmod_triplet_to_sparse(cht, cht->nnz, &c) :
|
|
|
328 |
AS_CHM_SP(Csparse_diagU2N(x)));
|
| 3401 |
bates |
329 |
SEXP dn = PROTECT(allocVector(VECSXP, 2));
|
| 4565 |
maechler |
330 |
R_CheckStack();
|
| 1830 |
bates |
331 |
|
| 4565 |
maechler |
332 |
if (!tr) chxt = cholmod_transpose(chx, chx->xtype, &c);
|
| 1836 |
bates |
333 |
chcp = cholmod_aat((!tr) ? chxt : chx, (int *) NULL, 0, chx->xtype, &c);
|
| 4972 |
maechler |
334 |
if(!chcp) {
|
|
|
335 |
UNPROTECT(1);
|
|
|
336 |
error(_("Csparse_crossprod(): error return from cholmod_aat()"));
|
|
|
337 |
}
|
| 3388 |
bates |
338 |
cholmod_band_inplace(0, chcp->ncol, chcp->xtype, chcp, &c);
|
|
|
339 |
chcp->stype = 1;
|
| 4565 |
maechler |
340 |
if (trip) cholmod_free_sparse(&chx, &c);
|
| 1831 |
bates |
341 |
if (!tr) cholmod_free_sparse(&chxt, &c);
|
| 4565 |
maechler |
342 |
SET_VECTOR_ELT(dn, 0, /* establish dimnames */
|
| 3401 |
bates |
343 |
duplicate(VECTOR_ELT(GET_SLOT(x, Matrix_DimNamesSym),
|
| 3943 |
maechler |
344 |
(tr) ? 0 : 1)));
|
| 3401 |
bates |
345 |
SET_VECTOR_ELT(dn, 1, duplicate(VECTOR_ELT(dn, 0)));
|
|
|
346 |
UNPROTECT(1);
|
| 3755 |
maechler |
347 |
return chm_sparse_to_SEXP(chcp, 1, 0, 0, "", dn);
|
| 1830 |
bates |
348 |
}
|
| 1831 |
bates |
349 |
|
| 3876 |
maechler |
350 |
SEXP Csparse_drop(SEXP x, SEXP tol)
|
|
|
351 |
{
|
| 4565 |
maechler |
352 |
CHM_SP chx = AS_CHM_SP(x);
|
|
|
353 |
CHM_SP ans = cholmod_copy(chx, chx->stype, chx->xtype, &c);
|
| 3876 |
maechler |
354 |
double dtol = asReal(tol);
|
| 4093 |
maechler |
355 |
int Rkind = (chx->xtype != CHOLMOD_PATTERN) ? Real_kind(x) : 0;
|
| 4565 |
maechler |
356 |
R_CheckStack();
|
| 3876 |
maechler |
357 |
|
|
|
358 |
if(!cholmod_drop(dtol, ans, &c))
|
|
|
359 |
error(_("cholmod_drop() failed"));
|
| 4093 |
maechler |
360 |
return chm_sparse_to_SEXP(ans, 1, 0, Rkind, "",
|
|
|
361 |
GET_SLOT(x, Matrix_DimNamesSym));
|
| 3876 |
maechler |
362 |
}
|
|
|
363 |
|
| 2304 |
bates |
364 |
SEXP Csparse_horzcat(SEXP x, SEXP y)
|
|
|
365 |
{
|
| 4565 |
maechler |
366 |
CHM_SP chx = AS_CHM_SP(x), chy = AS_CHM_SP(y);
|
| 3755 |
maechler |
367 |
int Rkind = 0; /* only for "d" - FIXME */
|
| 4565 |
maechler |
368 |
R_CheckStack();
|
| 3410 |
maechler |
369 |
|
| 3401 |
bates |
370 |
/* FIXME: currently drops dimnames */
|
| 4565 |
maechler |
371 |
return chm_sparse_to_SEXP(cholmod_horzcat(chx, chy, 1, &c),
|
|
|
372 |
1, 0, Rkind, "", R_NilValue);
|
| 2304 |
bates |
373 |
}
|
|
|
374 |
|
|
|
375 |
SEXP Csparse_vertcat(SEXP x, SEXP y)
|
|
|
376 |
{
|
| 4565 |
maechler |
377 |
CHM_SP chx = AS_CHM_SP(x), chy = AS_CHM_SP(y);
|
| 3755 |
maechler |
378 |
int Rkind = 0; /* only for "d" - FIXME */
|
| 4565 |
maechler |
379 |
R_CheckStack();
|
| 3410 |
maechler |
380 |
|
| 3401 |
bates |
381 |
/* FIXME: currently drops dimnames */
|
| 4565 |
maechler |
382 |
return chm_sparse_to_SEXP(cholmod_vertcat(chx, chy, 1, &c),
|
|
|
383 |
1, 0, Rkind, "", R_NilValue);
|
| 2304 |
bates |
384 |
}
|
| 3134 |
bates |
385 |
|
|
|
386 |
SEXP Csparse_band(SEXP x, SEXP k1, SEXP k2)
|
|
|
387 |
{
|
| 4565 |
maechler |
388 |
CHM_SP chx = AS_CHM_SP(x);
|
| 4093 |
maechler |
389 |
int Rkind = (chx->xtype != CHOLMOD_PATTERN) ? Real_kind(x) : 0;
|
| 4565 |
maechler |
390 |
CHM_SP ans = cholmod_band(chx, asInteger(k1), asInteger(k2), chx->xtype, &c);
|
|
|
391 |
R_CheckStack();
|
| 3134 |
bates |
392 |
|
| 4093 |
maechler |
393 |
return chm_sparse_to_SEXP(ans, 1, 0, Rkind, "",
|
|
|
394 |
GET_SLOT(x, Matrix_DimNamesSym));
|
| 3134 |
bates |
395 |
}
|
| 3401 |
bates |
396 |
|
|
|
397 |
SEXP Csparse_diagU2N(SEXP x)
|
|
|
398 |
{
|
| 4972 |
maechler |
399 |
const char *cl = class_P(x);
|
|
|
400 |
/* dtCMatrix, etc; [1] = the second character =?= 't' for triangular */
|
|
|
401 |
if (cl[1] != 't' || *diag_P(x) != 'U') {
|
| 4979 |
maechler |
402 |
/* "trivially fast" when not triangular (<==> no 'diag' slot),
|
|
|
403 |
or not *unit* triangular */
|
| 4052 |
maechler |
404 |
return (x);
|
|
|
405 |
}
|
| 4979 |
maechler |
406 |
else { /* unit triangular (diag='U'): "fill the diagonal" & diag:= "N" */
|
| 4565 |
maechler |
407 |
CHM_SP chx = AS_CHM_SP(x);
|
|
|
408 |
CHM_SP eye = cholmod_speye(chx->nrow, chx->ncol, chx->xtype, &c);
|
| 4052 |
maechler |
409 |
double one[] = {1, 0};
|
| 4565 |
maechler |
410 |
CHM_SP ans = cholmod_add(chx, eye, one, one, TRUE, TRUE, &c);
|
| 4055 |
maechler |
411 |
int uploT = (*uplo_P(x) == 'U') ? 1 : -1;
|
| 4093 |
maechler |
412 |
int Rkind = (chx->xtype != CHOLMOD_PATTERN) ? Real_kind(x) : 0;
|
| 3401 |
bates |
413 |
|
| 4565 |
maechler |
414 |
R_CheckStack();
|
|
|
415 |
cholmod_free_sparse(&eye, &c);
|
| 4052 |
maechler |
416 |
return chm_sparse_to_SEXP(ans, 1, uploT, Rkind, "N",
|
| 4093 |
maechler |
417 |
GET_SLOT(x, Matrix_DimNamesSym));
|
| 4052 |
maechler |
418 |
}
|
| 3401 |
bates |
419 |
}
|
|
|
420 |
|
| 4979 |
maechler |
421 |
SEXP Csparse_diagN2U(SEXP x)
|
|
|
422 |
{
|
|
|
423 |
const char *cl = class_P(x);
|
|
|
424 |
/* dtCMatrix, etc; [1] = the second character =?= 't' for triangular */
|
|
|
425 |
if (cl[1] != 't' || *diag_P(x) != 'N') {
|
|
|
426 |
/* "trivially fast" when not triangular (<==> no 'diag' slot),
|
|
|
427 |
or already *unit* triangular */
|
|
|
428 |
return (x);
|
|
|
429 |
}
|
|
|
430 |
else { /* triangular with diag='N'): now drop the diagonal */
|
|
|
431 |
/* duplicate, since chx will be modified: */
|
|
|
432 |
CHM_SP chx = AS_CHM_SP(duplicate(x));
|
|
|
433 |
int uploT = (*uplo_P(x) == 'U') ? 1 : -1,
|
|
|
434 |
Rkind = (chx->xtype != CHOLMOD_PATTERN) ? Real_kind(x) : 0;
|
|
|
435 |
R_CheckStack();
|
|
|
436 |
|
|
|
437 |
chm_diagN2U(chx, uploT, /* do_realloc */ FALSE);
|
|
|
438 |
|
|
|
439 |
return chm_sparse_to_SEXP(chx, /*dofree*/ 0/* or 1 ?? */,
|
|
|
440 |
uploT, Rkind, "U",
|
|
|
441 |
GET_SLOT(x, Matrix_DimNamesSym));
|
|
|
442 |
}
|
|
|
443 |
}
|
|
|
444 |
|
| 3401 |
bates |
445 |
SEXP Csparse_submatrix(SEXP x, SEXP i, SEXP j)
|
|
|
446 |
{
|
| 4565 |
maechler |
447 |
CHM_SP chx = AS_CHM_SP(x);
|
| 3401 |
bates |
448 |
int rsize = (isNull(i)) ? -1 : LENGTH(i),
|
|
|
449 |
csize = (isNull(j)) ? -1 : LENGTH(j);
|
| 4093 |
maechler |
450 |
int Rkind = (chx->xtype != CHOLMOD_PATTERN) ? Real_kind(x) : 0;
|
| 4565 |
maechler |
451 |
R_CheckStack();
|
| 3401 |
bates |
452 |
|
|
|
453 |
if (rsize >= 0 && !isInteger(i))
|
|
|
454 |
error(_("Index i must be NULL or integer"));
|
|
|
455 |
if (csize >= 0 && !isInteger(j))
|
|
|
456 |
error(_("Index j must be NULL or integer"));
|
| 4093 |
maechler |
457 |
|
| 3401 |
bates |
458 |
return chm_sparse_to_SEXP(cholmod_submatrix(chx, INTEGER(i), rsize,
|
| 3410 |
maechler |
459 |
INTEGER(j), csize,
|
| 3401 |
bates |
460 |
TRUE, TRUE, &c),
|
| 4093 |
maechler |
461 |
1, 0, Rkind, "",
|
|
|
462 |
/* FIXME: drops dimnames */ R_NilValue);
|
| 3401 |
bates |
463 |
}
|
| 4734 |
bates |
464 |
|
|
|
465 |
SEXP Csparse_MatrixMarket(SEXP x, SEXP fname)
|
|
|
466 |
{
|
|
|
467 |
FILE *f = fopen(CHAR(asChar(fname)), "w");
|
|
|
468 |
|
|
|
469 |
if (!f)
|
|
|
470 |
error(_("failure to open file \"%s\" for writing"),
|
|
|
471 |
CHAR(asChar(fname)));
|
| 4972 |
maechler |
472 |
if (!cholmod_write_sparse(f, AS_CHM_SP(Csparse_diagU2N(x)),
|
|
|
473 |
(CHM_SP)NULL, (char*) NULL, &c))
|
| 4734 |
bates |
474 |
error(_("cholmod_write_sparse returned error code"));
|
|
|
475 |
fclose(f);
|
|
|
476 |
return R_NilValue;
|
|
|
477 |
}
|
| 4994 |
maechler |
478 |
|
|
|
479 |
|
|
|
480 |
/**
|
|
|
481 |
* Extract the diagonal entries from *triangular* Csparse matrix __or__ a
|
|
|
482 |
* cholmod_sparse factor (LDL = TRUE).
|
|
|
483 |
*
|
|
|
484 |
* @param n dimension of the matrix.
|
|
|
485 |
* @param x_p 'p' (column pointer) slot contents
|
|
|
486 |
* @param x_x 'x' (non-zero entries) slot contents
|
|
|
487 |
* @param perm 'perm' (= permutation vector) slot contents
|
|
|
488 |
* @param resultKind a (SEXP) string indicating which kind of result is desired.
|
|
|
489 |
*
|
|
|
490 |
* @return a SEXP, either a (double) number or a length n-vector of diagonal entries
|
|
|
491 |
*/
|
|
|
492 |
SEXP diag_tC_ptr(int n, int *x_p, double *x_x, int *perm, SEXP resultKind)
|
|
|
493 |
/* ^^^^^^ FIXME[Generalize] to int / ... */
|
|
|
494 |
{
|
|
|
495 |
const char* res_ch = CHAR(STRING_ELT(resultKind,0));
|
|
|
496 |
enum diag_kind { diag, diag_backpermuted, trace, prod, sum_log
|
|
|
497 |
} res_kind = ((!strcmp(res_ch, "trace")) ? trace :
|
|
|
498 |
((!strcmp(res_ch, "sumLog")) ? sum_log :
|
|
|
499 |
((!strcmp(res_ch, "prod")) ? prod :
|
|
|
500 |
((!strcmp(res_ch, "diag")) ? diag :
|
|
|
501 |
((!strcmp(res_ch, "diagBack")) ? diag_backpermuted :
|
|
|
502 |
-1)))));
|
|
|
503 |
int i, n_x, i_from = 0;
|
|
|
504 |
SEXP ans = PROTECT(allocVector(REALSXP,
|
|
|
505 |
/* ^^^^ FIXME[Generalize] */
|
|
|
506 |
(res_kind == diag ||
|
|
|
507 |
res_kind == diag_backpermuted) ? n : 1));
|
|
|
508 |
double *v = REAL(ans);
|
|
|
509 |
/* ^^^^^^ ^^^^ FIXME[Generalize] */
|
|
|
510 |
|
|
|
511 |
#define for_DIAG(v_ASSIGN) \
|
|
|
512 |
for(i = 0; i < n; i++, i_from += n_x) { \
|
|
|
513 |
/* looking at i-th column */ \
|
|
|
514 |
n_x = x_p[i+1] - x_p[i];/* #{entries} in this column */ \
|
|
|
515 |
v_ASSIGN; \
|
|
|
516 |
}
|
|
|
517 |
|
|
|
518 |
/* NOTA BENE: we assume -- uplo = "L" i.e. lower triangular matrix
|
|
|
519 |
* for uplo = "U" (makes sense with a "dtCMatrix" !),
|
|
|
520 |
* should use x_x[i_from + (nx - 1)] instead of x_x[i_from],
|
|
|
521 |
* where nx = (x_p[i+1] - x_p[i])
|
|
|
522 |
*/
|
|
|
523 |
|
|
|
524 |
switch(res_kind) {
|
|
|
525 |
case trace:
|
|
|
526 |
v[0] = 0.;
|
|
|
527 |
for_DIAG(v[0] += x_x[i_from]);
|
|
|
528 |
break;
|
|
|
529 |
|
|
|
530 |
case sum_log:
|
|
|
531 |
v[0] = 0.;
|
|
|
532 |
for_DIAG(v[0] += log(x_x[i_from]));
|
|
|
533 |
break;
|
|
|
534 |
|
|
|
535 |
case prod:
|
|
|
536 |
v[0] = 1.;
|
|
|
537 |
for_DIAG(v[0] *= x_x[i_from]);
|
|
|
538 |
break;
|
|
|
539 |
|
|
|
540 |
case diag:
|
|
|
541 |
for_DIAG(v[i] = x_x[i_from]);
|
|
|
542 |
break;
|
|
|
543 |
|
|
|
544 |
case diag_backpermuted:
|
|
|
545 |
for_DIAG(v[i] = x_x[i_from]);
|
|
|
546 |
|
|
|
547 |
error(_("resultKind = 'diagBack' (back-permuted) is not yet implemented"));
|
| 5003 |
maechler |
548 |
/* now back_permute : */
|
|
|
549 |
for(i = 0; i < n; i++) {
|
|
|
550 |
double tmp = v[i]; v[i] = v[perm[i]]; v[perm[i]] = tmp;
|
|
|
551 |
/*^^^^ FIXME[Generalize] */
|
|
|
552 |
}
|
| 4994 |
maechler |
553 |
break;
|
|
|
554 |
|
|
|
555 |
default: /* -1 from above */
|
|
|
556 |
error("diag_tC(): invalid 'resultKind'");
|
|
|
557 |
/* Wall: */ ans = R_NilValue; v = REAL(ans);
|
|
|
558 |
}
|
|
|
559 |
|
|
|
560 |
UNPROTECT(1);
|
|
|
561 |
return ans;
|
|
|
562 |
}
|
|
|
563 |
|
|
|
564 |
/**
|
|
|
565 |
* Extract the diagonal entries from *triangular* Csparse matrix __or__ a
|
|
|
566 |
* cholmod_sparse factor (LDL = TRUE).
|
|
|
567 |
*
|
|
|
568 |
* @param pslot 'p' (column pointer) slot of Csparse matrix/factor
|
|
|
569 |
* @param xslot 'x' (non-zero entries) slot of Csparse matrix/factor
|
|
|
570 |
* @param perm_slot 'perm' (= permutation vector) slot of corresponding CHMfactor
|
|
|
571 |
* @param resultKind a (SEXP) string indicating which kind of result is desired.
|
|
|
572 |
*
|
|
|
573 |
* @return a SEXP, either a (double) number or a length n-vector of diagonal entries
|
|
|
574 |
*/
|
|
|
575 |
SEXP diag_tC(SEXP pslot, SEXP xslot, SEXP perm_slot, SEXP resultKind)
|
|
|
576 |
{
|
|
|
577 |
int n = length(pslot) - 1, /* n = ncol(.) = nrow(.) */
|
|
|
578 |
*x_p = INTEGER(pslot),
|
|
|
579 |
*perm = INTEGER(perm_slot);
|
|
|
580 |
double *x_x = REAL(xslot);
|
|
|
581 |
/* ^^^^^^ ^^^^ FIXME[Generalize] to INTEGER(.) / LOGICAL(.) / ... xslot !*/
|
|
|
582 |
|
|
|
583 |
return diag_tC_ptr(n, x_p, x_x, perm, resultKind);
|
|
|
584 |
}
|