Matrix r5059
Loading...
Searching...
No Matches
isSymmetric.c
Go to the documentation of this file.
1/* C implementation of methods for isSymmetric */
2
3#include "Mdefines.h"
4#include "M5.h"
5#include "idz.h"
6
7/* defined in ./isDiagonal.c :*/
8int dense_is_diagonal(SEXP, const char *);
9int sparse_is_diagonal(SEXP, const char *);
10
11int dense_is_symmetric(SEXP obj, const char *class,
12 char op_ct, int exact, int checkDN)
13{
14 if (class[0] != 'z') {
15 op_ct = '\0';
16 if (class[0] != 'd')
17 exact = 1;
18 }
19
20 char ct = '\0';
21 if (class[1] == 's') {
22 if (class[0] != 'z')
23 return 1;
24 ct = TRANS(obj);
25 if (op_ct == ct)
26 return 1;
27 checkDN = 0;
28 }
29
30 if (checkDN && !DimNames_is_symmetric(DIMNAMES(obj, 0)))
31 return 0;
32
33 char nu = '\0';
34 if (class[1] == 't') {
35 nu = DIAG(obj);
36 if (exact && (nu != 'N' || op_ct != 'C'))
37 return dense_is_diagonal(obj, class);
38 }
39
40 int *pdim = DIM(obj), n = pdim[1];
41 if (pdim[0] != n)
42 return 0;
43 if (n == 0 || (n == 1 && op_ct != 'C'))
44 return 1;
45 if (!exact)
46 return NA_LOGICAL; /* do inexact numerical test in R */
47
48 char ul = '\0';
49 if (class[1] != 'g')
50 ul = UPLO(obj);
51
52 SEXP x = GET_SLOT(obj, Matrix_xSym);
53 int i, j;
54
55 if (class[1] == 'g') {
56
57#define TEMPLATE(c) \
58 do { \
59 c##TYPE *px = c##PTR(x); \
60 if (c##NAME(test2)(px, (size_t) n, '\0', op_ct, '\0')) \
61 return 0; \
62 } while (0)
63
64 SWITCH5(class[0], TEMPLATE);
65
66#undef TEMPLATE
67
68 } else {
69
70 Rcomplex *px = COMPLEX(x), *pu = px, *pl = px;
71 int packed = class[2] == 'p';
72 if (class[1] == 's') {
73 /* Testing if Hermitian matrix is symmetric */
74 /* or if symmetric matrix is Hermitian */
75 /* <=====> if matrix is real */
76 if (ul == 'U')
77 for (j = 0; j < n; ++j) {
78 for (i = 0; i < j; ++i) {
79 if (zNOT_ZERO_IMAG(*pu))
80 return 0;
81 pu += 1;
82 }
83 if (op_ct == 'C' && zNOT_ZERO_IMAG(*pu))
84 return 0;
85 pu += 1;
86 if (!packed)
87 pu += n - j - 1;
88 }
89 else
90 for (j = 0; j < n; ++j) {
91 if (!packed)
92 pl += j;
93 if (op_ct == 'C' && zNOT_ZERO_IMAG(*pl))
94 return 0;
95 pl += 1;
96 for (i = j + 1; i < n; ++i) {
97 if (zNOT_ZERO_IMAG(*pl))
98 return 0;
99 pl += 1;
100 }
101 }
102 } else {
103 /* Testing if non-unit triangular matrix is Hermitian */
104 /* <=====> if matrix is real and diagonal */
105 if (ul == 'U')
106 for (j = 0; j < n; ++j) {
107 for (i = 0; i < j; ++i) {
108 if (zNOT_ZERO(*pu))
109 return 0;
110 pu += 1;
111 }
112 if (zNOT_ZERO_IMAG(*pu))
113 return 0;
114 pu += 1;
115 if (!packed)
116 pu += n - j - 1;
117 }
118 else
119 for (j = 0; j < n; ++j) {
120 if (!packed)
121 pl += j;
122 if (zNOT_ZERO_IMAG(*pl))
123 return 0;
124 pl += 1;
125 for (i = j + 1; i < n; ++i) {
126 if (zNOT_ZERO(*pl))
127 return 0;
128 pl += 1;
129 }
130 }
131 }
132
133 }
134
135 return 1;
136}
137
138int sparse_is_symmetric(SEXP obj, const char *class,
139 char op_ct, int exact, int checkDN)
140{
141 if (class[0] != 'z') {
142 op_ct = '\0';
143 if (class[0] != 'd')
144 exact = 1;
145 }
146
147 char ct = '\0';
148 if (class[1] == 's') {
149 if (class[0] != 'z')
150 return 1;
151 ct = TRANS(obj);
152 if (op_ct == ct)
153 return 1;
154 checkDN = 0;
155 }
156
157 if (checkDN && !DimNames_is_symmetric(DIMNAMES(obj, 0)))
158 return 0;
159
160 char nu = '\0';
161 if (class[1] == 't') {
162 if (!sparse_is_diagonal(obj, class))
163 return 0;
164 nu = DIAG(obj);
165 if (nu != 'N' || op_ct != 'C')
166 return 1;
167 }
168
169 int *pdim = DIM(obj), n = pdim[1];
170 if (pdim[0] != n)
171 return 0;
172 if (n == 0 || (n == 1 && op_ct != 'C'))
173 return 1;
174 if (!exact && class[0] != 'g')
175 return NA_LOGICAL; /* do inexact numerical test in R */
176
177 if (class[2] == 'T') {
178 /* defined in ./coerce.c : */
179 SEXP sparse_as_Csparse(SEXP, const char *);
180 if (exact)
181 obj = sparse_as_Csparse(obj, class);
182 else {
183 /* Testing for symmetric nonzero pattern, hence : */
184 char cl[] = "n.TMatrix";
185 cl[1] = class[1];
186 obj = sparse_as_Csparse(obj, cl);
187 }
188 }
189 PROTECT(obj);
190
191 SEXP iSym = (class[2] != 'R') ? Matrix_iSym : Matrix_jSym,
192 p_ = PROTECT(GET_SLOT(obj, Matrix_pSym)),
193 i_ = PROTECT(GET_SLOT(obj, iSym));
194 int *pp = INTEGER(p_), *pi = INTEGER(i_), i, j, k, kend,
195 *iwork = NULL;
196 if (class[1] == 'g') {
197 Matrix_Calloc(iwork, n, int);
198 memcpy(iwork, pp, sizeof(int) * (size_t) n);
199 }
200 pp++;
201
202 int ans = 0;
203
204 if (class[1] == 'g' && !(exact && op_ct == 'C')) {
205
206#define TEMPLATE(c) \
207 do { \
208 c##IF_NPATTERN( \
209 SEXP x = GET_SLOT(obj, Matrix_xSym); \
210 c##TYPE *px = c##PTR(x); \
211 ); \
212 for (j = 0, k = 0; j < n; ++j) { \
213 kend = pp[j]; \
214 while (k < kend) { \
215 i = pi[k]; \
216 if (i < j) { \
217 if (iwork[i] == pp[i] || pi[iwork[i]] != j) \
218 goto done; \
219 c##IF_NPATTERN( \
220 if (c##NOT_IDEN(px[k], px[iwork[i]])) \
221 goto done; \
222 ); \
223 ++iwork[i]; \
224 ++iwork[j]; \
225 ++k; \
226 } else { \
227 if (pi[k] == j) \
228 ++iwork[j]; \
229 k = kend; \
230 } \
231 } \
232 } \
233 } while (0)
234
235 SWITCH5((exact) ? class[0] : 'n', TEMPLATE);
236
237#undef TEMPLATE
238
239 } else {
240
241 SEXP x = GET_SLOT(obj, Matrix_xSym);
242 Rcomplex *px = COMPLEX(x);
243 if (class[1] == 'g')
244 for (j = 0, k = 0; j < n; ++j) {
245 kend = pp[j];
246 while (k < kend) {
247 i = pi[k];
248 if (i < j) {
249 if (iwork[i] == pp[i] || pi[iwork[i]] != j) \
250 goto done;
251 if (zNOT_CONJ(px[k], px[iwork[i]]))
252 goto done;
253 ++iwork[i];
254 ++iwork[j];
255 ++k;
256 } else {
257 if (i == j) {
258 if (zNOT_ZERO_IMAG(px[k]))
259 goto done;
260 ++iwork[j];
261 }
262 k = kend;
263 }
264 }
265 }
266 else if (class[1] == 's')
267 /* Testing if Hermitian matrix is symmetric */
268 /* or if symmetric matrix is Hermitian */
269 /* <=====> if matrix is real */
270 for (j = 0, k = 0; j < n; ++j) {
271 kend = pp[j];
272 while (k < kend) {
273 if (zNOT_ZERO_IMAG(px[k]) && (pi[k] != j || op_ct == 'C'))
274 goto done;
275 ++k;
276 }
277 }
278 else
279 /* Testing if non-unit triangular matrix is Hermitian */
280 /* <=====> if matrix is real and diagonal */
281 /* NB: diagonal nonzero pattern is already known */
282 for (j = 0, k = 0; j < n; ++j) {
283 kend = pp[j];
284 if (k < kend && zNOT_ZERO_IMAG(px[k]))
285 goto done;
286 k = kend;
287 }
288
289 }
290
291 if (class[1] == 'g')
292 for (j = 0; j < n; ++j)
293 if (iwork[j] != pp[j])
294 goto done;
295
296 ans = (exact) ? 1 : NA_LOGICAL;
297
298done:
299 if (class[1] == 'g')
300 Matrix_Free(iwork, n);
301 UNPROTECT(3); /* i_, p_, obj */
302 return ans;
303}
304
305SEXP R_dense_is_symmetric(SEXP s_obj,
306 SEXP s_trans, SEXP s_exact, SEXP s_checkDN)
307{
308 if (TYPEOF(s_obj) != OBJSXP) {
309 /* defined in ./coerce.c : */
310 SEXP matrix_as_dense(SEXP, const char *, char, char, char, int, int);
311 s_obj = matrix_as_dense(s_obj, ".ge", '\0', '\0', '\0', 1, 0);
312 }
313 PROTECT(s_obj);
314 const char *class = Matrix_class(s_obj, valid_dense, 6, __func__);
315
316 char ct;
317 VALID_TRANS(s_trans, ct);
318
319 int exact, checkDN;
320 VALID_LOGIC2(s_exact , exact );
321 VALID_LOGIC2(s_checkDN, checkDN);
322
323 int ans_ = dense_is_symmetric(s_obj, class, ct, exact, checkDN);
324 SEXP ans = Rf_ScalarLogical(ans_);
325 UNPROTECT(1);
326 return ans;
327}
328
329
330/* NB: requires symmetric nonzero pattern */
331SEXP R_sparse_is_symmetric(SEXP s_obj,
332 SEXP s_trans, SEXP s_exact, SEXP s_checkDN)
333{
334 const char *class = Matrix_class(s_obj, valid_sparse, 6, __func__);
335
336 char ct;
337 VALID_TRANS(s_trans, ct);
338
339 int exact, checkDN;
340 VALID_LOGIC2(s_exact , exact );
341 VALID_LOGIC2(s_checkDN, checkDN);
342
343 int ans_ = sparse_is_symmetric(s_obj, class, ct, exact, checkDN);
344 SEXP ans = Rf_ScalarLogical(ans_);
345 return ans;
346}
SEXP sparse_as_Csparse(SEXP, const char *)
Definition coerce.c:2731
#define SWITCH5(c, template)
Definition M5.h:327
#define zNOT_ZERO(x)
Definition M5.h:64
#define zNOT_CONJ(x, y)
Definition M5.h:116
#define zNOT_ZERO_IMAG(x)
Definition M5.h:76
const char * valid_dense[]
Definition objects.c:3
#define Matrix_Calloc(p, n, t)
Definition Mdefines.h:45
#define DIAG(x)
Definition Mdefines.h:111
#define UPLO(x)
Definition Mdefines.h:101
const char * Matrix_class(SEXP, const char **, int, const char *)
Definition objects.c:112
#define Matrix_Free(p, n)
Definition Mdefines.h:56
#define DIMNAMES(x, mode)
Definition Mdefines.h:96
#define TRANS(x)
Definition Mdefines.h:106
#define DIM(x)
Definition Mdefines.h:85
#define GET_SLOT(x, name)
Definition Mdefines.h:72
#define VALID_TRANS(s, c)
Definition Mdefines.h:166
const char * valid_sparse[]
Definition Mdefines.h:328
#define VALID_LOGIC2(s, d)
Definition Mdefines.h:216
#define TYPEOF(s)
Definition Mdefines.h:123
int DimNames_is_symmetric(SEXP dn)
Definition attrib.c:46
cholmod_common cl
Definition cholmod-etc.c:6
SEXP matrix_as_dense(SEXP from, const char *zzz, char ul, char ct, char nu, int mg, int new)
Definition coerce.c:262
SEXP Matrix_xSym
Definition init.c:635
SEXP Matrix_iSym
Definition init.c:607
SEXP Matrix_jSym
Definition init.c:610
SEXP Matrix_pSym
Definition init.c:622
SEXP R_sparse_is_symmetric(SEXP s_obj, SEXP s_trans, SEXP s_exact, SEXP s_checkDN)
int dense_is_symmetric(SEXP obj, const char *class, char op_ct, int exact, int checkDN)
Definition isSymmetric.c:11
int dense_is_diagonal(SEXP, const char *)
Definition isDiagonal.c:7
#define TEMPLATE(c)
SEXP R_dense_is_symmetric(SEXP s_obj, SEXP s_trans, SEXP s_exact, SEXP s_checkDN)
int sparse_is_diagonal(SEXP, const char *)
Definition isDiagonal.c:45
int sparse_is_symmetric(SEXP obj, const char *class, char op_ct, int exact, int checkDN)