Graphviz 14.1.2~dev.20251216.0548
Loading...
Searching...
No Matches
SparseMatrix.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11#include <stdio.h>
12#include <string.h>
13#include <math.h>
14#include <assert.h>
15#include <common/arith.h>
16#include <limits.h>
17#include <sparse/SparseMatrix.h>
18#include <stddef.h>
19#include <stdbool.h>
20#include <util/alloc.h>
21#include <util/overflow.h>
22#include <util/prisize_t.h>
23#include <util/unreachable.h>
24
25static size_t size_of_matrix_type(int type){
26 size_t size = 0;
27 switch (type){
29 size = sizeof(double);
30 break;
32 size = 2*sizeof(double);
33 break;
35 size = sizeof(int);
36 break;
38 size = 0;
39 break;
40 default:
42 }
43
44 return size;
45}
46
56 /* make it strictly low diag only, and set flag to undirected */
58 B = SparseMatrix_symmetrize(A, false);
59 B->is_undirected = true;
61}
63 if (!A) return NULL;
64
65 int *ia = A->ia, *ja = A->ja, *ib, *jb, m = A->m, n = A->n, type = A->type, format = A->format;
66 const size_t nz = A->nz;
68 int i, j;
69
70 assert(A->format == FORMAT_CSR);/* only implemented for CSR right now */
71
72 B = SparseMatrix_new(n, m, nz, type, format);
73 B->nz = nz;
74 ib = B->ia;
75 jb = B->ja;
76
77 for (i = 0; i <= n; i++) ib[i] = 0;
78 for (i = 0; i < m; i++){
79 for (j = ia[i]; j < ia[i+1]; j++){
80 ib[ja[j]+1]++;
81 }
82 }
83
84 for (i = 0; i < n; i++) ib[i+1] += ib[i];
85
86 switch (A->type){
87 case MATRIX_TYPE_REAL:{
88 double *a = A->a;
89 double *b = B->a;
90 for (i = 0; i < m; i++){
91 for (j = ia[i]; j < ia[i+1]; j++){
92 jb[ib[ja[j]]] = i;
93 b[ib[ja[j]]++] = a[j];
94 }
95 }
96 break;
97 }
99 double *a = A->a;
100 double *b = B->a;
101 for (i = 0; i < m; i++){
102 for (j = ia[i]; j < ia[i+1]; j++){
103 jb[ib[ja[j]]] = i;
104 b[2*ib[ja[j]]] = a[2*j];
105 b[2*ib[ja[j]]+1] = a[2*j+1];
106 ib[ja[j]]++;
107 }
108 }
109 break;
110 }
112 int *ai = A->a;
113 int *bi = B->a;
114 for (i = 0; i < m; i++){
115 for (j = ia[i]; j < ia[i+1]; j++){
116 jb[ib[ja[j]]] = i;
117 bi[ib[ja[j]]++] = ai[j];
118 }
119 }
120 break;
121 }
123 for (i = 0; i < m; i++){
124 for (j = ia[i]; j < ia[i+1]; j++){
125 jb[ib[ja[j]]++] = i;
126 }
127 }
128 break;
129 default:
130 UNREACHABLE();
131 }
132
133
134 for (i = n-1; i >= 0; i--) ib[i+1] = ib[i];
135 ib[0] = 0;
136
137
138 return B;
139}
140
142 bool pattern_symmetric_only) {
144 if (SparseMatrix_is_symmetric(A, pattern_symmetric_only)) return SparseMatrix_copy(A);
146 if (!B) return NULL;
147 A = SparseMatrix_add(A, B);
149 A->is_symmetric = true;
150 A->is_pattern_symmetric = true;
151 return A;
152}
153
154bool SparseMatrix_is_symmetric(SparseMatrix A, bool test_pattern_symmetry_only) {
155 if (!A) return false;
156
157 /* assume no repeated entries! */
159 int *ia, *ja, *ib, *jb, type, m;
160 int *mask;
161 bool res = false;
162 int i, j;
163 assert(A->format == FORMAT_CSR);/* only implemented for CSR right now */
164
165 if (A->is_symmetric) return true;
166 if (test_pattern_symmetry_only && A->is_pattern_symmetric) return true;
167
168 if (A->m != A->n) return false;
169
171 if (!B) return false;
172
173 ia = A->ia;
174 ja = A->ja;
175 ib = B->ia;
176 jb = B->ja;
177 m = A->m;
178
179 mask = gv_calloc((size_t)m, sizeof(int));
180 for (i = 0; i < m; i++) mask[i] = -1;
181
182 type = A->type;
183 if (test_pattern_symmetry_only) type = MATRIX_TYPE_PATTERN;
184
185 switch (type){
186 case MATRIX_TYPE_REAL:{
187 double *a = A->a;
188 double *b = B->a;
189 for (i = 0; i <= m; i++) if (ia[i] != ib[i]) goto RETURN;
190 for (i = 0; i < m; i++){
191 for (j = ia[i]; j < ia[i+1]; j++){
192 mask[ja[j]] = j;
193 }
194 for (j = ib[i]; j < ib[i+1]; j++){
195 if (mask[jb[j]] < ia[i]) goto RETURN;
196 }
197 for (j = ib[i]; j < ib[i+1]; j++){
198 if (fabs(b[j] - a[mask[jb[j]]]) > SYMMETRY_EPSILON) goto RETURN;
199 }
200 }
201 res = true;
202 break;
203 }
205 double *a = A->a;
206 double *b = B->a;
207 for (i = 0; i <= m; i++) if (ia[i] != ib[i]) goto RETURN;
208 for (i = 0; i < m; i++){
209 for (j = ia[i]; j < ia[i+1]; j++){
210 mask[ja[j]] = j;
211 }
212 for (j = ib[i]; j < ib[i+1]; j++){
213 if (mask[jb[j]] < ia[i]) goto RETURN;
214 }
215 for (j = ib[i]; j < ib[i+1]; j++){
216 if (fabs(b[2*j] - a[2*mask[jb[j]]]) > SYMMETRY_EPSILON) goto RETURN;
217 if (fabs(b[2*j+1] - a[2*mask[jb[j]]+1]) > SYMMETRY_EPSILON) goto RETURN;
218 }
219 }
220 res = true;
221 break;
222 }
224 int *ai = A->a;
225 int *bi = B->a;
226 for (i = 0; i < m; i++){
227 for (j = ia[i]; j < ia[i+1]; j++){
228 mask[ja[j]] = j;
229 }
230 for (j = ib[i]; j < ib[i+1]; j++){
231 if (mask[jb[j]] < ia[i]) goto RETURN;
232 }
233 for (j = ib[i]; j < ib[i+1]; j++){
234 if (bi[j] != ai[mask[jb[j]]]) goto RETURN;
235 }
236 }
237 res = true;
238 break;
239 }
241 for (i = 0; i < m; i++){
242 for (j = ia[i]; j < ia[i+1]; j++){
243 mask[ja[j]] = j;
244 }
245 for (j = ib[i]; j < ib[i+1]; j++){
246 if (mask[jb[j]] < ia[i]) goto RETURN;
247 }
248 }
249 res = true;
250 break;
251 default:
252 UNREACHABLE();
253 }
254
255 if (!test_pattern_symmetry_only) {
256 A->is_symmetric = true;
257 }
258 A->is_pattern_symmetric = true;
259 RETURN:
260 free(mask);
261
263 return res;
264}
265
266static SparseMatrix SparseMatrix_init(int m, int n, int type, size_t sz, int format){
267 SparseMatrix A = gv_alloc(sizeof(struct SparseMatrix_struct));
268 A->m = m;
269 A->n = n;
270 A->nz = 0;
271 A->nzmax = 0;
272 A->type = type;
273 A->size = sz;
274 switch (format){
275 case FORMAT_COORD:
276 A->ia = NULL;
277 break;
278 case FORMAT_CSR:
279 default:
280 A->ia = gv_calloc((size_t)(m + 1), sizeof(int));
281 }
282 A->ja = NULL;
283 A->a = NULL;
284 A->format = format;
285 return A;
286}
287
288static void SparseMatrix_alloc(SparseMatrix A, size_t nz) {
289 int format = A->format;
290
291 A->a = NULL;
292 switch (format){
293 case FORMAT_COORD:
294 A->ia = gv_calloc(nz, sizeof(int));
295 A->ja = gv_calloc(nz, sizeof(int));
296 A->a = gv_calloc(nz, A->size);
297 break;
298 case FORMAT_CSR:
299 default:
300 A->ja = gv_calloc(nz, sizeof(int));
301 if (A->size > 0 && nz > 0) {
302 A->a = gv_calloc(nz, A->size);
303 }
304 break;
305 }
306 A->nzmax = nz;
307}
308
310 int format = A->format;
311
312 switch (format){
313 case FORMAT_COORD:
314 A->ia = gv_recalloc(A->ia, A->nzmax, nz, sizeof(int));
315 A->ja = gv_recalloc(A->ja, A->nzmax, nz, sizeof(int));
316 if (A->size > 0) {
317 if (A->a){
318 A->a = gv_recalloc(A->a, A->nzmax, nz, A->size);
319 } else {
320 A->a = gv_calloc(nz, A->size);
321 }
322 }
323 break;
324 case FORMAT_CSR:
325 default:
326 A->ja = gv_recalloc(A->ja, A->nzmax, nz, sizeof(int));
327 if (A->size > 0) {
328 if (A->a){
329 A->a = gv_recalloc(A->a, A->nzmax, nz, A->size);
330 } else {
331 A->a = gv_calloc(nz, A->size);
332 }
333 }
334 break;
335 }
336 A->nzmax = nz;
337 return A;
338}
339
340SparseMatrix SparseMatrix_new(int m, int n, size_t nz, int type, int format) {
341 /* return a sparse matrix skeleton with row dimension m and storage nz. If nz == 0,
342 only row pointers are allocated */
344 size_t sz;
345
347 A = SparseMatrix_init(m, n, type, sz, format);
348
349 if (nz > 0) SparseMatrix_alloc(A, nz);
350 return A;
351
352}
353
357static SparseMatrix SparseMatrix_general_new(int m, int n, size_t nz, int type,
358 size_t sz, int format) {
359 /* return a sparse matrix skeleton with row dimension m and storage nz. If nz == 0,
360 only row pointers are allocated. this is more general and allow elements to be
361 any data structure, not just real/int/complex etc
362 */
364
365 A = SparseMatrix_init(m, n, type, sz, format);
366
367 if (nz > 0) SparseMatrix_alloc(A, nz);
368 return A;
369
370}
371
373 if (!A) return;
374 free(A->ia);
375 free(A->ja);
376 free(A->a);
377 free(A);
378}
379
381 const int m = A->m;
382
383 switch (A->type){
384 case MATRIX_TYPE_REAL:
385 fprintf(f,"%%%%MatrixMarket matrix coordinate real general\n");
386 break;
388 fprintf(f,"%%%%MatrixMarket matrix coordinate complex general\n");
389 break;
391 fprintf(f,"%%%%MatrixMarket matrix coordinate integer general\n");
392 break;
394 fprintf(f,"%%%%MatrixMarket matrix coordinate pattern general\n");
395 break;
396 default:
397 UNREACHABLE();
398 }
399
400 fprintf(f, "%d %d %" PRISIZE_T "\n", A->m, A->n, A->nz);
401 const int *const ia = A->ia;
402 const int *const ja = A->ja;
403 switch (A->type){
404 case MATRIX_TYPE_REAL: {
405 const double *const a = A->a;
406 for (int i = 0; i < m; i++){
407 for (int j = ia[i]; j < ia[i+1]; j++){
408 fprintf(f, "%d %d %16.8g\n",i+1, ja[j]+1, a[j]);
409 }
410 }
411 break;
412 }
413 case MATRIX_TYPE_COMPLEX: {
414 const double *const a = A->a;
415 for (int i = 0; i < m; i++){
416 for (int j = ia[i]; j < ia[i+1]; j++){
417 fprintf(f, "%d %d %16.8g %16.8g\n",i+1, ja[j]+1, a[2*j], a[2*j+1]);
418 }
419 }
420 break;
421 }
422 case MATRIX_TYPE_INTEGER: {
423 const int *const ai = A->a;
424 for (int i = 0; i < m; i++){
425 for (int j = ia[i]; j < ia[i+1]; j++){
426 fprintf(f, "%d %d %d\n",i+1, ja[j]+1, ai[j]);
427 }
428 }
429 break;
430 }
432 for (int i = 0; i < m; i++){
433 for (int j = ia[i]; j < ia[i+1]; j++){
434 fprintf(f, "%d %d\n",i+1, ja[j]+1);
435 }
436 }
437 break;
438 default:
439 UNREACHABLE();
440 }
441
442}
443
445 switch (A->type){
446 case MATRIX_TYPE_REAL:
447 fprintf(f,"%%%%MatrixMarket matrix coordinate real general\n");
448 break;
450 fprintf(f,"%%%%MatrixMarket matrix coordinate complex general\n");
451 break;
453 fprintf(f,"%%%%MatrixMarket matrix coordinate integer general\n");
454 break;
456 fprintf(f,"%%%%MatrixMarket matrix coordinate pattern general\n");
457 break;
458 default:
459 UNREACHABLE();
460 }
461
462 fprintf(f, "%d %d %" PRISIZE_T "\n", A->m, A->n, A->nz);
463 const int *const ia = A->ia;
464 const int *const ja = A->ja;
465 switch (A->type){
466 case MATRIX_TYPE_REAL: {
467 const double *const a = A->a;
468 for (size_t i = 0; i < A->nz; i++) {
469 fprintf(f, "%d %d %16.8g\n",ia[i]+1, ja[i]+1, a[i]);
470 }
471 break;
472 }
473 case MATRIX_TYPE_COMPLEX: {
474 const double *const a = A->a;
475 for (size_t i = 0; i < A->nz; i++) {
476 fprintf(f, "%d %d %16.8g %16.8g\n",ia[i]+1, ja[i]+1, a[2*i], a[2*i+1]);
477 }
478 break;
479 }
480 case MATRIX_TYPE_INTEGER: {
481 const int *const ai = A->a;
482 for (size_t i = 0; i < A->nz; i++) {
483 fprintf(f, "%d %d %d\n",ia[i]+1, ja[i]+1, ai[i]);
484 }
485 break;
487 for (size_t i = 0; i < A->nz; i++){
488 fprintf(f, "%d %d\n",ia[i]+1, ja[i]+1);
489 }
490 break;
491 }
492 default:
493 UNREACHABLE();
494 }
495}
496
497
498
500
501 switch (A->format){
502 case FORMAT_CSR:
504 break;
505 case FORMAT_COORD:
507 break;
508 default:
509 UNREACHABLE();
510 }
511}
512
513
515 /* convert a sparse matrix in coordinate form to one in compressed row form.*/
516 int *irn, *jcn;
517
518 void *a = A->a;
519
520 assert(A->format == FORMAT_COORD);
521 if (A->format != FORMAT_COORD) {
522 return NULL;
523 }
524 irn = A->ia;
525 jcn = A->ja;
526 return SparseMatrix_from_coordinate_arrays(A->nz, A->m, A->n, irn, jcn, a, A->type, A->size);
527
528}
530 /* convert a sparse matrix in coordinate form to one in compressed row form.*/
531 int *irn, *jcn;
532
533 void *a = A->a;
534
535 assert(A->format == FORMAT_COORD);
536 if (A->format != FORMAT_COORD) {
537 return NULL;
538 }
539 irn = A->ia;
540 jcn = A->ja;
541 return SparseMatrix_from_coordinate_arrays_not_compacted(A->nz, A->m, A->n, irn, jcn, a, A->type, A->size);
542}
543
545 int m, int n,
546 int *irn,
547 int *jcn,
548 const void *val0,
549 int type,
550 size_t sz,
551 int sum_repeated) {
552 /* convert a sparse matrix in coordinate form to one in compressed row form.
553 nz: number of entries
554 irn: row indices 0-based
555 jcn: column indices 0-based
556 val values if not NULL
557 type: matrix type
558 */
559
561 int *ia, *ja;
562 double *a;
563 int *ai;
564
565 assert(m > 0 && n > 0);
566
567 if (m <=0 || n <= 0) return NULL;
568 A = SparseMatrix_general_new(m, n, nz, type, sz, FORMAT_CSR);
569 ia = A->ia;
570 ja = A->ja;
571
572 for (int i = 0; i <= m; i++){
573 ia[i] = 0;
574 }
575
576 switch (type){
577 case MATRIX_TYPE_REAL: {
578 const double *const val = val0;
579 a = A->a;
580 for (size_t i = 0; i < nz; i++){
581 if (irn[i] < 0 || irn[i] >= m || jcn[i] < 0 || jcn[i] >= n) {
582 UNREACHABLE();
583 }
584 ia[irn[i]+1]++;
585 }
586 for (int i = 0; i < m; i++) ia[i+1] += ia[i];
587 for (size_t i = 0; i < nz; i++){
588 a[ia[irn[i]]] = val[i];
589 ja[ia[irn[i]]++] = jcn[i];
590 }
591 for (int i = m; i > 0; i--) ia[i] = ia[i - 1];
592 ia[0] = 0;
593 break;
594 }
595 case MATRIX_TYPE_COMPLEX: {
596 const double *const val = val0;
597 a = A->a;
598 for (size_t i = 0; i < nz; i++){
599 if (irn[i] < 0 || irn[i] >= m || jcn[i] < 0 || jcn[i] >= n) {
600 UNREACHABLE();
601 }
602 ia[irn[i]+1]++;
603 }
604 for (int i = 0; i < m; i++) ia[i+1] += ia[i];
605 for (size_t i = 0; i < nz; i++){
606 a[2*ia[irn[i]]] = val[2 * i];
607 a[2*ia[irn[i]]+1] = val[2 * i + 1];
608 ja[ia[irn[i]]++] = jcn[i];
609 }
610 for (int i = m; i > 0; i--) ia[i] = ia[i - 1];
611 ia[0] = 0;
612 break;
613 }
614 case MATRIX_TYPE_INTEGER: {
615 const int *const vali = val0;
616 ai = A->a;
617 for (size_t i = 0; i < nz; i++){
618 if (irn[i] < 0 || irn[i] >= m || jcn[i] < 0 || jcn[i] >= n) {
619 UNREACHABLE();
620 }
621 ia[irn[i]+1]++;
622 }
623 for (int i = 0; i < m; i++) ia[i+1] += ia[i];
624 for (size_t i = 0; i < nz; i++){
625 ai[ia[irn[i]]] = vali[i];
626 ja[ia[irn[i]]++] = jcn[i];
627 }
628 for (int i = m; i > 0; i--) ia[i] = ia[i - 1];
629 ia[0] = 0;
630 break;
631 }
633 for (size_t i = 0; i < nz; i++){
634 if (irn[i] < 0 || irn[i] >= m || jcn[i] < 0 || jcn[i] >= n) {
635 UNREACHABLE();
636 }
637 ia[irn[i]+1]++;
638 }
639 for (int i = 0; i < m; i++) ia[i+1] += ia[i];
640 for (size_t i = 0; i < nz; i++){
641 ja[ia[irn[i]]++] = jcn[i];
642 }
643 for (int i = m; i > 0; i--) ia[i] = ia[i - 1];
644 ia[0] = 0;
645 break;
646 default:
647 UNREACHABLE();
648 }
649 A->nz = nz;
650
651
652
653 if(sum_repeated) A = SparseMatrix_sum_repeat_entries(A);
654
655 return A;
656}
657
659 int *irn, int *jcn,
660 const void *val, int type,
661 size_t sz) {
662 return SparseMatrix_from_coordinate_arrays_internal(nz, m, n, irn, jcn, val, type, sz, SUM_REPEATED_ALL);
663}
664
666 int n, int *irn,
667 int *jcn,
668 void *val0,
669 int type,
670 size_t sz) {
671 return SparseMatrix_from_coordinate_arrays_internal(nz, m, n, irn, jcn, val0, type, sz, SUM_REPEATED_NONE);
672}
673
675 int m, n;
677 int *mask = NULL;
678 int *ia = A->ia, *ja = A->ja, *ib = B->ia, *jb = B->ja, *ic, *jc;
679 int i, j;
680
681 assert(A && B);
682 assert(A->format == B->format && A->format == FORMAT_CSR);/* other format not yet supported */
683 assert(A->type == B->type);
684 m = A->m;
685 n = A->n;
686 if (m != B->m || n != B->n) return NULL;
687
688 const size_t nzmax = A->nz + B->nz; // just assume that no entries overlaps for speed
689
690 C = SparseMatrix_new(m, n, nzmax, A->type, FORMAT_CSR);
691 ic = C->ia;
692 jc = C->ja;
693
694 mask = gv_calloc((size_t)n, sizeof(int));
695
696 for (i = 0; i < n; i++) mask[i] = -1;
697
698 size_t nz = 0;
699 ic[0] = 0;
700 switch (A->type){
701 case MATRIX_TYPE_REAL:{
702 double *a = A->a;
703 double *b = B->a;
704 double *c = C->a;
705 for (i = 0; i < m; i++){
706 for (j = ia[i]; j < ia[i+1]; j++){
707 mask[ja[j]] = (int)nz;
708 jc[nz] = ja[j];
709 c[nz] = a[j];
710 nz++;
711 }
712 for (j = ib[i]; j < ib[i+1]; j++){
713 if (mask[jb[j]] < ic[i]){
714 jc[nz] = jb[j];
715 c[nz++] = b[j];
716 } else {
717 c[mask[jb[j]]] += b[j];
718 }
719 }
720 ic[i + 1] = (int)nz;
721 }
722 break;
723 }
725 double *a = A->a;
726 double *b = B->a;
727 double *c = C->a;
728 for (i = 0; i < m; i++){
729 for (j = ia[i]; j < ia[i+1]; j++){
730 mask[ja[j]] = (int)nz;
731 jc[nz] = ja[j];
732 c[2*nz] = a[2*j];
733 c[2*nz+1] = a[2*j+1];
734 nz++;
735 }
736 for (j = ib[i]; j < ib[i+1]; j++){
737 if (mask[jb[j]] < ic[i]){
738 jc[nz] = jb[j];
739 c[2*nz] = b[2*j];
740 c[2*nz+1] = b[2*j+1];
741 nz++;
742 } else {
743 c[2*mask[jb[j]]] += b[2*j];
744 c[2*mask[jb[j]]+1] += b[2*j+1];
745 }
746 }
747 ic[i + 1] = (int)nz;
748 }
749 break;
750 }
752 int *a = A->a;
753 int *b = B->a;
754 int *c = C->a;
755 for (i = 0; i < m; i++){
756 for (j = ia[i]; j < ia[i+1]; j++){
757 mask[ja[j]] = (int)nz;
758 jc[nz] = ja[j];
759 c[nz] = a[j];
760 nz++;
761 }
762 for (j = ib[i]; j < ib[i+1]; j++){
763 if (mask[jb[j]] < ic[i]){
764 jc[nz] = jb[j];
765 c[nz] = b[j];
766 nz++;
767 } else {
768 c[mask[jb[j]]] += b[j];
769 }
770 }
771 ic[i + 1] = (int)nz;
772 }
773 break;
774 }
776 for (i = 0; i < m; i++){
777 for (j = ia[i]; j < ia[i+1]; j++){
778 mask[ja[j]] = (int)nz;
779 jc[nz] = ja[j];
780 nz++;
781 }
782 for (j = ib[i]; j < ib[i+1]; j++){
783 if (mask[jb[j]] < ic[i]){
784 jc[nz] = jb[j];
785 nz++;
786 }
787 }
788 ic[i + 1] = (int)nz;
789 }
790 break;
791 }
792 default:
793 UNREACHABLE();
794 }
795 C->nz = nz;
796
797 free(mask);
798
799 return C;
800}
801
802void SparseMatrix_multiply_dense(SparseMatrix A, const double *v, double *res,
803 int dim) {
804 // A × V, with A dimension m × n, with V a dense matrix of dimension n × dim.
805 // v[i×dim×j] gives V[i,j]. Result of dimension m × dim. Real only for now.
806 int i, j, k, *ia, *ja, m;
807 double *a;
808
809 assert(A->format == FORMAT_CSR);
810 assert(A->type == MATRIX_TYPE_REAL);
811
812 a = A->a;
813 ia = A->ia;
814 ja = A->ja;
815 m = A->m;
816
817 for (i = 0; i < m; i++){
818 for (k = 0; k < dim; k++) res[i * dim + k] = 0;
819 for (j = ia[i]; j < ia[i+1]; j++){
820 for (k = 0; k < dim; k++) res[i * dim + k] += a[j] * v[ja[j] *dim + k];
821 }
822 }
823}
824
825void SparseMatrix_multiply_vector(SparseMatrix A, double *v, double **res) {
826 /* A v or A^T v. Real only for now. */
827 int i, j, *ia, *ja, m;
828 double *a, *u = NULL;
829 int *ai;
830 assert(A->format == FORMAT_CSR);
831 assert(A->type == MATRIX_TYPE_REAL || A->type == MATRIX_TYPE_INTEGER);
832
833 ia = A->ia;
834 ja = A->ja;
835 m = A->m;
836 u = *res;
837
838 switch (A->type){
839 case MATRIX_TYPE_REAL:
840 a = A->a;
841 if (v){
842 if (!u) u = gv_calloc((size_t)m, sizeof(double));
843 for (i = 0; i < m; i++){
844 u[i] = 0.;
845 for (j = ia[i]; j < ia[i+1]; j++){
846 u[i] += a[j]*v[ja[j]];
847 }
848 }
849 } else {
850 /* v is assumed to be all 1's */
851 if (!u) u = gv_calloc((size_t)m, sizeof(double));
852 for (i = 0; i < m; i++){
853 u[i] = 0.;
854 for (j = ia[i]; j < ia[i+1]; j++){
855 u[i] += a[j];
856 }
857 }
858 }
859 break;
861 ai = A->a;
862 if (v){
863 if (!u) u = gv_calloc((size_t)m, sizeof(double));
864 for (i = 0; i < m; i++){
865 u[i] = 0.;
866 for (j = ia[i]; j < ia[i+1]; j++){
867 u[i] += ai[j]*v[ja[j]];
868 }
869 }
870 } else {
871 /* v is assumed to be all 1's */
872 if (!u) u = gv_calloc((size_t)m, sizeof(double));
873 for (i = 0; i < m; i++){
874 u[i] = 0.;
875 for (j = ia[i]; j < ia[i+1]; j++){
876 u[i] += ai[j];
877 }
878 }
879 }
880 break;
881 default:
882 UNREACHABLE();
883 }
884 *res = u;
885
886}
887
889 int m;
891 int *mask = NULL;
892 int *ia = A->ia, *ja = A->ja, *ib = B->ia, *jb = B->ja, *ic, *jc;
893 int i, j, k, jj, type;
894
895 assert(A->format == B->format && A->format == FORMAT_CSR);/* other format not yet supported */
896
897 m = A->m;
898 if (A->n != B->m) return NULL;
899 if (A->type != B->type){
900#ifdef DEBUG
901 printf("in SparseMatrix_multiply, the matrix types do not match, right now only multiplication of matrices of the same type is supported\n");
902#endif
903 return NULL;
904 }
905 type = A->type;
906
907 mask = calloc((size_t)B->n, sizeof(int));
908 if (!mask) return NULL;
909
910 for (i = 0; i < B->n; i++) mask[i] = -1;
911
912 size_t nz = 0;
913 for (i = 0; i < m; i++){
914 for (j = ia[i]; j < ia[i+1]; j++){
915 jj = ja[j];
916 for (k = ib[jj]; k < ib[jj+1]; k++){
917 if (mask[jb[k]] != -i - 2){
918 if (size_overflow(nz, 1, &nz)) {
919#ifdef DEBUG_PRINT
920 fprintf(stderr,"overflow in SparseMatrix_multiply !!!\n");
921#endif
922 free(mask);
923 return NULL;
924 }
925 mask[jb[k]] = -i - 2;
926 }
927 }
928 }
929 }
930
931 C = SparseMatrix_new(m, B->n, nz, type, FORMAT_CSR);
932 ic = C->ia;
933 jc = C->ja;
934
935 nz = 0;
936
937 switch (type){
938 case MATRIX_TYPE_REAL:
939 {
940 double *a = A->a;
941 double *b = B->a;
942 double *c = C->a;
943 ic[0] = 0;
944 for (i = 0; i < m; i++){
945 for (j = ia[i]; j < ia[i+1]; j++){
946 jj = ja[j];
947 for (k = ib[jj]; k < ib[jj+1]; k++){
948 if (mask[jb[k]] < ic[i]){
949 mask[jb[k]] = (int)nz;
950 jc[nz] = jb[k];
951 c[nz] = a[j]*b[k];
952 nz++;
953 } else {
954 assert(jc[mask[jb[k]]] == jb[k]);
955 c[mask[jb[k]]] += a[j]*b[k];
956 }
957 }
958 }
959 ic[i + 1] = (int)nz;
960 }
961 }
962 break;
964 {
965 double *a = A->a;
966 double *b = B->a;
967 double *c = C->a;
968 ic[0] = 0;
969 for (i = 0; i < m; i++){
970 for (j = ia[i]; j < ia[i+1]; j++){
971 jj = ja[j];
972 for (k = ib[jj]; k < ib[jj+1]; k++){
973 if (mask[jb[k]] < ic[i]){
974 mask[jb[k]] = (int)nz;
975 jc[nz] = jb[k];
976 c[2*nz] = a[2*j]*b[2*k] - a[2*j+1]*b[2*k+1];/*real part */
977 c[2*nz+1] = a[2*j]*b[2*k+1] + a[2*j+1]*b[2*k];/*img part */
978 nz++;
979 } else {
980 assert(jc[mask[jb[k]]] == jb[k]);
981 c[2*mask[jb[k]]] += a[2*j]*b[2*k] - a[2*j+1]*b[2*k+1];/*real part */
982 c[2*mask[jb[k]]+1] += a[2*j]*b[2*k+1] + a[2*j+1]*b[2*k];/*img part */
983 }
984 }
985 }
986 ic[i + 1] = (int)nz;
987 }
988 }
989 break;
991 {
992 int *a = A->a;
993 int *b = B->a;
994 int *c = C->a;
995 ic[0] = 0;
996 for (i = 0; i < m; i++){
997 for (j = ia[i]; j < ia[i+1]; j++){
998 jj = ja[j];
999 for (k = ib[jj]; k < ib[jj+1]; k++){
1000 if (mask[jb[k]] < ic[i]){
1001 mask[jb[k]] = (int)nz;
1002 jc[nz] = jb[k];
1003 c[nz] = a[j]*b[k];
1004 nz++;
1005 } else {
1006 assert(jc[mask[jb[k]]] == jb[k]);
1007 c[mask[jb[k]]] += a[j]*b[k];
1008 }
1009 }
1010 }
1011 ic[i + 1] = (int)nz;
1012 }
1013 }
1014 break;
1016 ic[0] = 0;
1017 for (i = 0; i < m; i++){
1018 for (j = ia[i]; j < ia[i+1]; j++){
1019 jj = ja[j];
1020 for (k = ib[jj]; k < ib[jj+1]; k++){
1021 if (mask[jb[k]] < ic[i]){
1022 mask[jb[k]] = (int)nz;
1023 jc[nz] = jb[k];
1024 nz++;
1025 } else {
1026 assert(jc[mask[jb[k]]] == jb[k]);
1027 }
1028 }
1029 }
1030 ic[i + 1] = (int)nz;
1031 }
1032 break;
1033 default:
1034 UNREACHABLE();
1035 }
1036
1037 C->nz = nz;
1038
1039 free(mask);
1040 return C;
1041}
1042
1043
1044
1046 int m;
1048 int *mask = NULL;
1049 int *ia = A->ia, *ja = A->ja, *ib = B->ia, *jb = B->ja, *ic = C->ia, *jc = C->ja, *id, *jd;
1050 int i, j, k, l, ll, jj, type;
1051
1052 assert(A->format == B->format && A->format == FORMAT_CSR);/* other format not yet supported */
1053
1054 m = A->m;
1055 if (A->n != B->m) return NULL;
1056 if (B->n != C->m) return NULL;
1057
1058 if (A->type != B->type || B->type != C->type){
1059#ifdef DEBUG
1060 printf("in SparseMatrix_multiply3, the matrix types do not match, right now only multiplication of matrices of the same type is supported\n");
1061#endif
1062 return NULL;
1063 }
1064 type = A->type;
1065
1066 assert(type == MATRIX_TYPE_REAL);
1067
1068 mask = calloc((size_t)C->n, sizeof(int));
1069 if (!mask) return NULL;
1070
1071 for (i = 0; i < C->n; i++) mask[i] = -1;
1072
1073 size_t nz = 0;
1074 for (i = 0; i < m; i++){
1075 for (j = ia[i]; j < ia[i+1]; j++){
1076 jj = ja[j];
1077 for (l = ib[jj]; l < ib[jj+1]; l++){
1078 ll = jb[l];
1079 for (k = ic[ll]; k < ic[ll+1]; k++){
1080 if (mask[jc[k]] != -i - 2){
1081 if (size_overflow(nz, 1, &nz)) {
1082#ifdef DEBUG_PRINT
1083 fprintf(stderr, "overflow in SparseMatrix_multiply3 !!!\n");
1084#endif
1085 free(mask);
1086 return NULL;
1087 }
1088 mask[jc[k]] = -i - 2;
1089 }
1090 }
1091 }
1092 }
1093 }
1094
1095 D = SparseMatrix_new(m, C->n, nz, type, FORMAT_CSR);
1096 id = D->ia;
1097 jd = D->ja;
1098
1099 nz = 0;
1100
1101 double *a = A->a;
1102 double *b = B->a;
1103 double *c = C->a;
1104 double *d = D->a;
1105 id[0] = 0;
1106 for (i = 0; i < m; i++){
1107 for (j = ia[i]; j < ia[i+1]; j++){
1108 jj = ja[j];
1109 for (l = ib[jj]; l < ib[jj+1]; l++){
1110 ll = jb[l];
1111 for (k = ic[ll]; k < ic[ll+1]; k++){
1112 if (mask[jc[k]] < id[i]){
1113 mask[jc[k]] = (int)nz;
1114 jd[nz] = jc[k];
1115 d[nz] = a[j]*b[l]*c[k];
1116 nz++;
1117 } else {
1118 assert(jd[mask[jc[k]]] == jc[k]);
1119 d[mask[jc[k]]] += a[j]*b[l]*c[k];
1120 }
1121 }
1122 }
1123 }
1124 id[i + 1] = (int)nz;
1125 }
1126
1127 D->nz = nz;
1128
1129 free(mask);
1130 return D;
1131}
1132
1134 /* sum repeated entries in the same row, i.e., {1,1}->1, {1,1}->2 becomes {1,1}->3 */
1135 int *ia = A->ia, *ja = A->ja, type = A->type, n = A->n;
1136 int *mask = NULL, i, j, sta;
1137 size_t nz = 0;
1138
1139 mask = gv_calloc((size_t)n, sizeof(int));
1140 for (i = 0; i < n; i++) mask[i] = -1;
1141
1142 switch (type){
1143 case MATRIX_TYPE_REAL:
1144 {
1145 double *a = A->a;
1146 sta = ia[0];
1147 for (i = 0; i < A->m; i++){
1148 for (j = sta; j < ia[i+1]; j++){
1149 if (mask[ja[j]] < ia[i]){
1150 ja[nz] = ja[j];
1151 a[nz] = a[j];
1152 mask[ja[j]] = (int)nz++;
1153 } else {
1154 assert(ja[mask[ja[j]]] == ja[j]);
1155 a[mask[ja[j]]] += a[j];
1156 }
1157 }
1158 sta = ia[i+1];
1159 ia[i + 1] = (int)nz;
1160 }
1161 }
1162 break;
1164 {
1165 double *a = A->a;
1166 sta = ia[0];
1167 for (i = 0; i < A->m; i++) {
1168 for (j = sta; j < ia[i+1]; j++) {
1169 if (mask[ja[j]] < ia[i]) {
1170 ja[nz] = ja[j];
1171 a[2 * nz] = a[2 * j];
1172 a[2 * nz + 1] = a[2 * j + 1];
1173 mask[ja[j]] = (int)nz++;
1174 } else {
1175 assert(ja[mask[ja[j]]] == ja[j]);
1176 a[2 * mask[ja[j]]] += a[2 * j];
1177 a[2 * mask[ja[j]]+1] += a[2 * j + 1];
1178 }
1179 }
1180 sta = ia[i + 1];
1181 ia[i + 1] = (int)nz;
1182 }
1183 }
1184 break;
1186 {
1187 int *a = A->a;
1188 sta = ia[0];
1189 for (i = 0; i < A->m; i++){
1190 for (j = sta; j < ia[i+1]; j++){
1191 if (mask[ja[j]] < ia[i]){
1192 ja[nz] = ja[j];
1193 a[nz] = a[j];
1194 mask[ja[j]] = (int)nz++;
1195 } else {
1196 assert(ja[mask[ja[j]]] == ja[j]);
1197 a[mask[ja[j]]] += a[j];
1198 }
1199 }
1200 sta = ia[i+1];
1201 ia[i + 1] = (int)nz;
1202 }
1203 }
1204 break;
1206 {
1207 sta = ia[0];
1208 for (i = 0; i < A->m; i++){
1209 for (j = sta; j < ia[i+1]; j++){
1210 if (mask[ja[j]] < ia[i]){
1211 ja[nz] = ja[j];
1212 mask[ja[j]] = (int)nz++;
1213 } else {
1214 assert(ja[mask[ja[j]]] == ja[j]);
1215 }
1216 }
1217 sta = ia[i+1];
1218 ia[i + 1] = (int)nz;
1219 }
1220 }
1221 break;
1222 default:
1223 free(mask);
1224 return NULL;
1225 }
1226 A->nz = nz;
1227 free(mask);
1228 return A;
1229}
1230
1232 int jcn, const void *val) {
1233 static const size_t nentries = 1;
1234
1235 assert(A->format == FORMAT_COORD);
1236 const size_t nz = A->nz;
1237
1238 if (nz + nentries >= A->nzmax){
1239 const size_t nzmax = nz + nentries + 10;
1240 A = SparseMatrix_realloc(A, nzmax);
1241 }
1242 A->ia[nz] = irn;
1243 A->ja[nz] = jcn;
1244 if (A->size) memcpy((char *)A->a + nz * A->size / sizeof(char), val, A->size * nentries);
1245 if (irn >= A->m) A->m = irn + 1;
1246 if (jcn >= A->n) A->n = jcn + 1;
1247 A->nz += nentries;
1248 return A;
1249}
1250
1251
1253 int i, j, *ia, *ja, sta;
1254
1255 if (!A) return A;
1256
1257 size_t nz = 0;
1258 ia = A->ia;
1259 ja = A->ja;
1260 sta = ia[0];
1261 switch (A->type){
1262 case MATRIX_TYPE_REAL:{
1263 double *a = A->a;
1264 for (i = 0; i < A->m; i++){
1265 for (j = sta; j < ia[i+1]; j++){
1266 if (ja[j] != i){
1267 ja[nz] = ja[j];
1268 a[nz++] = a[j];
1269 }
1270 }
1271 sta = ia[i+1];
1272 ia[i + 1] = (int)nz;
1273 }
1274 A->nz = nz;
1275 break;
1276 }
1277 case MATRIX_TYPE_COMPLEX:{
1278 double *a = A->a;
1279 for (i = 0; i < A->m; i++){
1280 for (j = sta; j < ia[i+1]; j++){
1281 if (ja[j] != i){
1282 ja[nz] = ja[j];
1283 a[2*nz] = a[2*j];
1284 a[2*nz+1] = a[2*j+1];
1285 nz++;
1286 }
1287 }
1288 sta = ia[i+1];
1289 ia[i + 1] = (int)nz;
1290 }
1291 A->nz = nz;
1292 break;
1293 }
1294 case MATRIX_TYPE_INTEGER:{
1295 int *a = A->a;
1296 for (i = 0; i < A->m; i++){
1297 for (j = sta; j < ia[i+1]; j++){
1298 if (ja[j] != i){
1299 ja[nz] = ja[j];
1300 a[nz++] = a[j];
1301 }
1302 }
1303 sta = ia[i+1];
1304 ia[i + 1] = (int)nz;
1305 }
1306 A->nz = nz;
1307 break;
1308 }
1309 case MATRIX_TYPE_PATTERN:{
1310 for (i = 0; i < A->m; i++){
1311 for (j = sta; j < ia[i+1]; j++){
1312 if (ja[j] != i){
1313 ja[nz++] = ja[j];
1314 }
1315 }
1316 sta = ia[i+1];
1317 ia[i + 1] = (int)nz;
1318 }
1319 A->nz = nz;
1320 break;
1321 }
1322 default:
1323 UNREACHABLE();
1324 }
1325
1326 return A;
1327}
1328
1329
1330SparseMatrix SparseMatrix_remove_upper(SparseMatrix A){/* remove diag and upper diag */
1331 int i, j, *ia, *ja, sta;
1332
1333 if (!A) return A;
1334
1335 size_t nz = 0;
1336 ia = A->ia;
1337 ja = A->ja;
1338 sta = ia[0];
1339 switch (A->type){
1340 case MATRIX_TYPE_REAL:{
1341 double *a = A->a;
1342 for (i = 0; i < A->m; i++){
1343 for (j = sta; j < ia[i+1]; j++){
1344 if (ja[j] < i){
1345 ja[nz] = ja[j];
1346 a[nz++] = a[j];
1347 }
1348 }
1349 sta = ia[i+1];
1350 ia[i + 1] = (int)nz;
1351 }
1352 A->nz = nz;
1353 break;
1354 }
1355 case MATRIX_TYPE_COMPLEX:{
1356 double *a = A->a;
1357 for (i = 0; i < A->m; i++){
1358 for (j = sta; j < ia[i+1]; j++){
1359 if (ja[j] < i){
1360 ja[nz] = ja[j];
1361 a[2*nz] = a[2*j];
1362 a[2*nz+1] = a[2*j+1];
1363 nz++;
1364 }
1365 }
1366 sta = ia[i+1];
1367 ia[i + 1] = (int)nz;
1368 }
1369 A->nz = nz;
1370 break;
1371 }
1372 case MATRIX_TYPE_INTEGER:{
1373 int *a = A->a;
1374 for (i = 0; i < A->m; i++){
1375 for (j = sta; j < ia[i+1]; j++){
1376 if (ja[j] < i){
1377 ja[nz] = ja[j];
1378 a[nz++] = a[j];
1379 }
1380 }
1381 sta = ia[i+1];
1382 ia[i + 1] = (int)nz;
1383 }
1384 A->nz = nz;
1385 break;
1386 }
1387 case MATRIX_TYPE_PATTERN:{
1388 for (i = 0; i < A->m; i++){
1389 for (j = sta; j < ia[i+1]; j++){
1390 if (ja[j] < i){
1391 ja[nz++] = ja[j];
1392 }
1393 }
1394 sta = ia[i+1];
1395 ia[i + 1] = (int)nz;
1396 }
1397 A->nz = nz;
1398 break;
1399 }
1400 default:
1401 UNREACHABLE();
1402 }
1403
1404 A->is_pattern_symmetric = false;
1405 A->is_symmetric = false;
1406 return A;
1407}
1408
1409
1410
1411
1413 int i, j, *ia, *ja;
1414 double deg;
1415
1416 if (!A) return A;
1417
1418 ia = A->ia;
1419 ja = A->ja;
1420 switch (A->type){
1421 case MATRIX_TYPE_REAL:{
1422 double *a = A->a;
1423 for (i = 0; i < A->m; i++){
1424 deg = ia[i+1] - ia[i];
1425 for (j = ia[i]; j < ia[i+1]; j++){
1426 a[j] = a[j]/deg;
1427 }
1428 }
1429 break;
1430 }
1431 case MATRIX_TYPE_COMPLEX:{
1432 double *a = A->a;
1433 for (i = 0; i < A->m; i++){
1434 deg = ia[i+1] - ia[i];
1435 for (j = ia[i]; j < ia[i+1]; j++){
1436 if (ja[j] != i){
1437 a[2*j] = a[2*j]/deg;
1438 a[2*j+1] = a[2*j+1]/deg;
1439 }
1440 }
1441 }
1442 break;
1443 }
1445 UNREACHABLE(); // this operation would not make sense for int matrix
1446 case MATRIX_TYPE_PATTERN:{
1447 break;
1448 }
1449 default:
1450 UNREACHABLE();
1451 }
1452
1453 return A;
1454}
1455
1456
1458 /* symmetric, all entries to 1, diaginal removed */
1459 int *ia, *ja, m, n;
1460 double *a;
1462
1463 if (!A) return A;
1464
1465 const size_t nz = A->nz;
1466 ia = A->ia;
1467 ja = A->ja;
1468 n = A->n;
1469 m = A->m;
1470
1471 if (n != m) return NULL;
1472
1474
1475 memcpy(B->ia, ia, sizeof(int)*((size_t)(m+1)));
1476 memcpy(B->ja, ja, sizeof(int) * nz);
1477 B->nz = A->nz;
1478
1479 A = SparseMatrix_symmetrize(B, true);
1482 A->a = gv_calloc(A->nz, sizeof(double));
1483 a = A->a;
1484 for (size_t i = 0; i < A->nz; i++) a[i] = 1.;
1485 A->type = MATRIX_TYPE_REAL;
1486 A->size = sizeof(double);
1487 return A;
1488}
1489
1491 int i, j;
1492 double *a;
1493
1494
1495 if (!A) return A;
1496 if (A->format != FORMAT_CSR && A->type != MATRIX_TYPE_REAL) {
1497#ifdef DEBUG
1498 printf("only CSR and real matrix supported.\n");
1499#endif
1500 return A;
1501 }
1502
1503
1504 a = A->a;
1505 for (i = 0; i < A->m; i++){
1506 for (j = A->ia[i]; j < A->ia[i+1]; j++){
1507 a[j] = fun(a[j]);
1508 }
1509 }
1510 return A;
1511}
1512
1515 if (!A) return A;
1516 B = SparseMatrix_general_new(A->m, A->n, A->nz, A->type, A->size, A->format);
1517 memcpy(B->ia, A->ia, sizeof(int)*((size_t)(A->m+1)));
1518 if (A->ia[A->m] != 0) {
1519 memcpy(B->ja, A->ja, sizeof(int)*((size_t)(A->ia[A->m])));
1520 }
1521 if (A->a) memcpy(B->a, A->a, A->size * A->nz);
1522 B->is_pattern_symmetric = A->is_pattern_symmetric;
1523 B->is_symmetric = A->is_symmetric;
1524 B->is_undirected = A->is_undirected;
1525 B->nz = A->nz;
1526 return B;
1527}
1528
1530
1531 int i, j, m = A->m, *ia = A->ia, *ja = A->ja;
1532
1533 for (i = 0; i < m; i++){
1534 for (j = ia[i]; j < ia[i+1]; j++){
1535 if (i == ja[j]) return true;
1536 }
1537 }
1538 return false;
1539}
1540
1541static void SparseMatrix_level_sets(SparseMatrix A, int root, int *nlevel,
1542 int **levelset_ptr, int **levelset,
1543 int **mask, bool reinitialize_mask) {
1544 /* mask is assumed to be initialized to negative if provided.
1545 . On exit, mask = levels for visited nodes (1 for root, 2 for its neighbors, etc),
1546 . unless reinitialize_mask is true, in which case mask = -1.
1547 A: the graph, undirected
1548 root: starting node
1549 nlevel: max distance to root from any node (in the connected comp)
1550 levelset_ptr, levelset: the level sets
1551 */
1552 int i, j, sta = 0, sto = 1, ii;
1553 int m = A->m, *ia = A->ia, *ja = A->ja;
1554
1555 if (!(*levelset_ptr)) *levelset_ptr = gv_calloc((size_t)(m + 2), sizeof(int));
1556 if (!(*levelset)) *levelset = gv_calloc((size_t)m, sizeof(int));
1557 if (!(*mask)) {
1558 *mask = gv_calloc((size_t)m, sizeof(int));
1559 for (i = 0; i < m; i++) (*mask)[i] = UNMASKED;
1560 }
1561
1562 *nlevel = 0;
1563 assert(root >= 0 && root < m);
1564 (*levelset_ptr)[0] = 0;
1565 (*levelset_ptr)[1] = 1;
1566 (*levelset)[0] = root;
1567 (*mask)[root] = 1;
1568 *nlevel = 1;
1569 size_t nz = 1;
1570 sta = 0; sto = 1;
1571 while (sto > sta){
1572 for (i = sta; i < sto; i++){
1573 ii = (*levelset)[i];
1574 for (j = ia[ii]; j < ia[ii+1]; j++){
1575 if (ii == ja[j]) continue;
1576 if ((*mask)[ja[j]] < 0){
1577 (*levelset)[nz++] = ja[j];
1578 (*mask)[ja[j]] = *nlevel + 1;
1579 }
1580 }
1581 }
1582 (*levelset_ptr)[++(*nlevel)] = (int)nz;
1583 sta = sto;
1584 sto = (int)nz;
1585 }
1586 (*nlevel)--;
1587 if (reinitialize_mask) for (i = 0; i < (*levelset_ptr)[*nlevel]; i++) (*mask)[(*levelset)[i]] = UNMASKED;
1588}
1589
1591 int **comps) {
1592 SparseMatrix A = A0;
1593 int *levelset_ptr = NULL, *levelset = NULL, *mask = NULL, nlevel;
1594 int m = A->m, i, nn;
1595
1596 if (!SparseMatrix_is_symmetric(A, true)){
1597 A = SparseMatrix_symmetrize(A, true);
1598 }
1599 int *comps_ptr = gv_calloc((size_t)(m + 1), sizeof(int));
1600
1601 *ncomp = 0;
1602 comps_ptr[0] = 0;
1603 for (i = 0; i < m; i++){
1604 if (i == 0 || mask[i] < 0) {
1605 SparseMatrix_level_sets(A, i, &nlevel, &levelset_ptr, &levelset, &mask, false);
1606 if (i == 0) *comps = levelset;
1607 nn = levelset_ptr[nlevel];
1608 levelset += nn;
1609 comps_ptr[(*ncomp)+1] = comps_ptr[(*ncomp)] + nn;
1610 (*ncomp)++;
1611 }
1612
1613 }
1614 if (A != A0) SparseMatrix_delete(A);
1615 free(levelset_ptr);
1616
1617 free(mask);
1618 return comps_ptr;
1619}
1620
1621void SparseMatrix_decompose_to_supervariables(SparseMatrix A, int *ncluster, int **cluster, int **clusterp){
1622 /* nodes for a super variable if they share exactly the same neighbors. This is know as modules in graph theory.
1623 We work on columns only and columns with the same pattern are grouped as a super variable
1624 */
1625 int *ia = A->ia, *ja = A->ja, n = A->n, m = A->m;
1626 int *super = NULL, *nsuper = NULL, i, j, *mask = NULL, isup, *newmap, isuper;
1627
1628 super = gv_calloc((size_t)n, sizeof(int));
1629 nsuper = gv_calloc((size_t)(n + 1), sizeof(int));
1630 mask = gv_calloc((size_t)n, sizeof(int));
1631 newmap = gv_calloc((size_t)n, sizeof(int));
1632 nsuper++;
1633
1634 isup = 0;
1635 for (i = 0; i < n; i++) super[i] = isup;/* every node belongs to super variable 0 by default */
1636 nsuper[0] = n;
1637 for (i = 0; i < n; i++) mask[i] = -1;
1638 isup++;
1639
1640 for (i = 0; i < m; i++){
1641#ifdef DEBUG_PRINT1
1642 printf("\n");
1643 printf("doing row %d-----\n",i+1);
1644#endif
1645 for (j = ia[i]; j < ia[i+1]; j++){
1646 isuper = super[ja[j]];
1647 nsuper[isuper]--;/* those entries will move to a different super vars*/
1648 }
1649 for (j = ia[i]; j < ia[i+1]; j++){
1650 isuper = super[ja[j]];
1651 if (mask[isuper] < i){
1652 mask[isuper] = i;
1653 if (nsuper[isuper] == 0){/* all nodes in the isuper group exist in this row */
1654#ifdef DEBUG_PRINT1
1655 printf("node %d keep super node id %d\n",ja[j]+1,isuper+1);
1656#endif
1657 nsuper[isuper] = 1;
1658 newmap[isuper] = isuper;
1659 } else {
1660 newmap[isuper] = isup;
1661 nsuper[isup] = 1;
1662#ifdef DEBUG_PRINT1
1663 printf("make node %d into supernode %d\n",ja[j]+1,isup+1);
1664#endif
1665 super[ja[j]] = isup++;
1666 }
1667 } else {
1668#ifdef DEBUG_PRINT1
1669 printf("node %d join super node %d\n",ja[j]+1,newmap[isuper]+1);
1670#endif
1671 super[ja[j]] = newmap[isuper];
1672 nsuper[newmap[isuper]]++;
1673 }
1674 }
1675#ifdef DEBUG_PRINT1
1676 printf("nsuper=");
1677 for (j = 0; j < isup; j++) printf("(%d,%d),",j+1,nsuper[j]);
1678 printf("\n");
1679#endif
1680 }
1681#ifdef DEBUG_PRINT1
1682 for (i = 0; i < n; i++){
1683 printf("node %d is in supernode %d\n",i, super[i]);
1684 }
1685#endif
1686#ifdef PRINT
1687 fprintf(stderr, "n = %d, nsup = %d\n",n,isup);
1688#endif
1689 /* now accumulate super nodes */
1690 nsuper--;
1691 nsuper[0] = 0;
1692 for (i = 0; i < isup; i++) nsuper[i+1] += nsuper[i];
1693
1694 *cluster = newmap;
1695 for (i = 0; i < n; i++){
1696 isuper = super[i];
1697 (*cluster)[nsuper[isuper]++] = i;
1698 }
1699 for (i = isup; i > 0; i--) nsuper[i] = nsuper[i-1];
1700 nsuper[0] = 0;
1701 *clusterp = nsuper;
1702 *ncluster = isup;
1703
1704#ifdef PRINT
1705 for (i = 0; i < *ncluster; i++){
1706 printf("{");
1707 for (j = (*clusterp)[i]; j < (*clusterp)[i+1]; j++){
1708 printf("%d, ",(*cluster)[j]);
1709 }
1710 printf("},");
1711 }
1712 printf("\n");
1713#endif
1714
1715 free(mask);
1716 free(super);
1717}
1718
1720 /* convert matrix A to an augmente dmatrix {{0,A},{A^T,0}} */
1721 int *irn = NULL, *jcn = NULL;
1722 void *val = NULL;
1723 size_t nz = A->nz;
1724 int type = A->type;
1725 int m = A->m, n = A->n, i, j;
1727 if (!A) return NULL;
1728 if (nz > 0){
1729 irn = gv_calloc(nz * 2, sizeof(int));
1730 jcn = gv_calloc(nz * 2, sizeof(int));
1731 }
1732
1733 if (A->a){
1734 assert(A->size != 0 && nz > 0);
1735 val = gv_calloc(2 * nz, A->size);
1736 memcpy(val, A->a, A->size * nz);
1737 memcpy((char *)val + nz * A->size, A->a, A->size * nz);
1738 }
1739
1740 nz = 0;
1741 for (i = 0; i < m; i++){
1742 for (j = (A->ia)[i]; j < (A->ia)[i+1]; j++){
1743 irn[nz] = i;
1744 jcn[nz++] = (A->ja)[j] + m;
1745 }
1746 }
1747 for (i = 0; i < m; i++){
1748 for (j = (A->ia)[i]; j < (A->ia)[i+1]; j++){
1749 jcn[nz] = i;
1750 irn[nz++] = (A->ja)[j] + m;
1751 }
1752 }
1753
1754 B = SparseMatrix_from_coordinate_arrays(nz, m + n, m + n, irn, jcn, val, type, A->size);
1755 B->is_symmetric = true;
1756 B->is_pattern_symmetric = true;
1757 free(irn);
1758 free(jcn);
1759 free(val);
1760 return B;
1761}
1762
1765 switch (bipartite_options){
1766 case BIPARTITE_RECT:
1767 if (A->m == A->n) return A;
1768 break;
1770 if (A->m == A->n && SparseMatrix_is_symmetric(A, true)) return A;
1771 break;
1772 case BIPARTITE_UNSYM:
1773 if (A->m == A->n && SparseMatrix_is_symmetric(A, false)) return A;
1774 break;
1775 case BIPARTITE_ALWAYS:
1776 break;
1777 default:
1778 UNREACHABLE();
1779 }
1782 return B;
1783}
1784
1785SparseMatrix SparseMatrix_get_submatrix(SparseMatrix A, int nrow, int ncol, int *rindices, int *cindices){
1786 /* get the submatrix from row/columns indices[0,...,l-1].
1787 row rindices[i] will be the new row i
1788 column cindices[i] will be the new column i.
1789 if rindices = NULL, it is assume that 1 -- nrow is needed. Same for cindices/ncol.
1790 */
1791 size_t nz = 0;
1792 int i, j, *irn, *jcn, *ia = A->ia, *ja = A->ja, m = A->m, n = A->n;
1793 int *cmask, *rmask;
1794 void *v = NULL;
1796 int irow = 0, icol = 0;
1797
1798 if (nrow <= 0 || ncol <= 0) return NULL;
1799
1800
1801
1802 rmask = gv_calloc((size_t)m, sizeof(int));
1803 cmask = gv_calloc((size_t)n, sizeof(int));
1804 for (i = 0; i < m; i++) rmask[i] = -1;
1805 for (i = 0; i < n; i++) cmask[i] = -1;
1806
1807 if (rindices){
1808 for (i = 0; i < nrow; i++) {
1809 if (rindices[i] >= 0 && rindices[i] < m){
1810 rmask[rindices[i]] = irow++;
1811 }
1812 }
1813 } else {
1814 for (i = 0; i < nrow; i++) {
1815 rmask[i] = irow++;
1816 }
1817 }
1818
1819 if (cindices){
1820 for (i = 0; i < ncol; i++) {
1821 if (cindices[i] >= 0 && cindices[i] < n){
1822 cmask[cindices[i]] = icol++;
1823 }
1824 }
1825 } else {
1826 for (i = 0; i < ncol; i++) {
1827 cmask[i] = icol++;
1828 }
1829 }
1830
1831 for (i = 0; i < m; i++){
1832 if (rmask[i] < 0) continue;
1833 for (j = ia[i]; j < ia[i+1]; j++){
1834 if (cmask[ja[j]] < 0) continue;
1835 nz++;
1836 }
1837 }
1838
1839
1840 switch (A->type){
1841 case MATRIX_TYPE_REAL:{
1842 double *a = A->a;
1843 double *val;
1844 irn = gv_calloc(nz, sizeof(int));
1845 jcn = gv_calloc(nz, sizeof(int));
1846 val = gv_calloc(nz, sizeof(double));
1847
1848 nz = 0;
1849 for (i = 0; i < m; i++){
1850 if (rmask[i] < 0) continue;
1851 for (j = ia[i]; j < ia[i+1]; j++){
1852 if (cmask[ja[j]] < 0) continue;
1853 irn[nz] = rmask[i];
1854 jcn[nz] = cmask[ja[j]];
1855 val[nz++] = a[j];
1856 }
1857 }
1858 v = val;
1859 break;
1860 }
1861 case MATRIX_TYPE_COMPLEX:{
1862 double *a = A->a;
1863 double *val;
1864
1865 irn = gv_calloc(nz, sizeof(int));
1866 jcn = gv_calloc(nz, sizeof(int));
1867 val = gv_calloc(2 * nz, sizeof(double));
1868
1869 nz = 0;
1870 for (i = 0; i < m; i++){
1871 if (rmask[i] < 0) continue;
1872 for (j = ia[i]; j < ia[i+1]; j++){
1873 if (cmask[ja[j]] < 0) continue;
1874 irn[nz] = rmask[i];
1875 jcn[nz] = cmask[ja[j]];
1876 val[2*nz] = a[2*j];
1877 val[2*nz+1] = a[2*j+1];
1878 nz++;
1879 }
1880 }
1881 v = val;
1882 break;
1883 }
1884 case MATRIX_TYPE_INTEGER:{
1885 int *a = A->a;
1886 int *val;
1887
1888 irn = gv_calloc(nz, sizeof(int));
1889 jcn = gv_calloc(nz, sizeof(int));
1890 val = gv_calloc(nz, sizeof(int));
1891
1892 nz = 0;
1893 for (i = 0; i < m; i++){
1894 if (rmask[i] < 0) continue;
1895 for (j = ia[i]; j < ia[i+1]; j++){
1896 if (cmask[ja[j]] < 0) continue;
1897 irn[nz] = rmask[i];
1898 jcn[nz] = cmask[ja[j]];
1899 val[nz] = a[j];
1900 nz++;
1901 }
1902 }
1903 v = val;
1904 break;
1905 }
1907 irn = gv_calloc(nz, sizeof(int));
1908 jcn = gv_calloc(nz, sizeof(int));
1909 nz = 0;
1910 for (i = 0; i < m; i++){
1911 if (rmask[i] < 0) continue;
1912 for (j = ia[i]; j < ia[i+1]; j++){
1913 if (cmask[ja[j]] < 0) continue;
1914 irn[nz] = rmask[i];
1915 jcn[nz++] = cmask[ja[j]];
1916 }
1917 }
1918 break;
1919 default:
1920 UNREACHABLE();
1921 }
1922
1923 B = SparseMatrix_from_coordinate_arrays(nz, nrow, ncol, irn, jcn, v, A->type, A->size);
1924 free(cmask);
1925 free(rmask);
1926 free(irn);
1927 free(jcn);
1928 if (v) free(v);
1929
1930
1931 return B;
1932
1933}
1934
1936 double *a;
1937
1938 free(A->a);
1939 A->a = gv_calloc(A->nz, sizeof(double));
1940 a = A->a;
1941 for (size_t i = 0; i < A->nz; i++) a[i] = 1.;
1942 A->type = MATRIX_TYPE_REAL;
1943 A->size = sizeof(double);
1944 return A;
1945
1946}
1947
1948SparseMatrix SparseMatrix_from_dense(int m, int n, double *x){
1949 int i, j, *ja;
1950 double *a;
1951 SparseMatrix A = SparseMatrix_new(m, n, (size_t)m * (size_t)n,
1953
1954 A->ia[0] = 0;
1955 for (i = 1; i <= m; i++) (A->ia)[i] = (A->ia)[i-1] + n;
1956
1957 ja = A->ja;
1958 a = A->a;
1959 for (i = 0; i < m; i++){
1960 for (j = 0; j < n; j++) {
1961 ja[j] = j;
1962 a[j] = x[i*n+j];
1963 }
1964 ja += n; a += j;
1965 }
1966 A->nz = (size_t)m * (size_t)n;
1967 return A;
1968
1969}
1970
1972 /*
1973 Input:
1974 D: the graph. Entry values are unused.
1975 Output:
1976 dist: of dimension nxn, dist[i*n+j] gives the distance of node i to j.
1977 */
1978 SparseMatrix D = D0;
1979 int m = D->m, n = D->n;
1980 int *levelset_ptr = NULL, *levelset = NULL, *mask = NULL;
1981 int i, j, k, nlevel;
1982
1983 if (!SparseMatrix_is_symmetric(D, false)){
1984 D = SparseMatrix_symmetrize(D, false);
1985 }
1986
1987 assert(m == n);
1988 (void)m;
1989
1990 if (!(*dist0)) *dist0 = gv_calloc(n * n, sizeof(double));
1991 for (i = 0; i < n*n; i++) (*dist0)[i] = -1;
1992
1993 for (k = 0; k < n; k++) {
1994 SparseMatrix_level_sets(D, k, &nlevel, &levelset_ptr, &levelset, &mask, true);
1995 assert(levelset_ptr[nlevel] == n);
1996 for (i = 0; i < nlevel; i++) {
1997 for (j = levelset_ptr[i]; j < levelset_ptr[i+1]; j++) {
1998 (*dist0)[k*n+levelset[j]] = i;
1999 }
2000 }
2001 }
2002
2003 free(levelset_ptr);
2004 free(levelset);
2005 free(mask);
2006
2007 if (D != D0) SparseMatrix_delete(D);
2008}
SparseMatrix SparseMatrix_from_coordinate_arrays_not_compacted(size_t nz, int m, int n, int *irn, int *jcn, void *val0, int type, size_t sz)
void SparseMatrix_distance_matrix(SparseMatrix D0, double **dist0)
static SparseMatrix SparseMatrix_realloc(SparseMatrix A, size_t nz)
void SparseMatrix_decompose_to_supervariables(SparseMatrix A, int *ncluster, int **cluster, int **clusterp)
SparseMatrix SparseMatrix_from_coordinate_format(SparseMatrix A)
SparseMatrix SparseMatrix_transpose(SparseMatrix A)
SparseMatrix SparseMatrix_remove_upper(SparseMatrix A)
SparseMatrix SparseMatrix_get_submatrix(SparseMatrix A, int nrow, int ncol, int *rindices, int *cindices)
SparseMatrix SparseMatrix_symmetrize(SparseMatrix A, bool pattern_symmetric_only)
SparseMatrix SparseMatrix_get_augmented(SparseMatrix A)
static void SparseMatrix_alloc(SparseMatrix A, size_t nz)
static size_t size_of_matrix_type(int type)
void SparseMatrix_multiply_dense(SparseMatrix A, const double *v, double *res, int dim)
SparseMatrix SparseMatrix_coordinate_form_add_entry(SparseMatrix A, int irn, int jcn, const void *val)
bool SparseMatrix_is_symmetric(SparseMatrix A, bool test_pattern_symmetry_only)
SparseMatrix SparseMatrix_to_square_matrix(SparseMatrix A, int bipartite_options)
void SparseMatrix_multiply_vector(SparseMatrix A, double *v, double **res)
SparseMatrix SparseMatrix_multiply(SparseMatrix A, SparseMatrix B)
SparseMatrix SparseMatrix_divide_row_by_degree(SparseMatrix A)
void SparseMatrix_export(FILE *f, SparseMatrix A)
static void SparseMatrix_export_csr(FILE *f, SparseMatrix A)
SparseMatrix SparseMatrix_from_coordinate_arrays(size_t nz, int m, int n, int *irn, int *jcn, const void *val, int type, size_t sz)
static void SparseMatrix_export_coord(FILE *f, SparseMatrix A)
void SparseMatrix_delete(SparseMatrix A)
static SparseMatrix SparseMatrix_from_coordinate_arrays_internal(size_t nz, int m, int n, int *irn, int *jcn, const void *val0, int type, size_t sz, int sum_repeated)
SparseMatrix SparseMatrix_make_undirected(SparseMatrix A)
SparseMatrix SparseMatrix_copy(SparseMatrix A)
SparseMatrix SparseMatrix_set_entries_to_real_one(SparseMatrix A)
static void SparseMatrix_level_sets(SparseMatrix A, int root, int *nlevel, int **levelset_ptr, int **levelset, int **mask, bool reinitialize_mask)
SparseMatrix SparseMatrix_get_real_adjacency_matrix_symmetrized(SparseMatrix A)
SparseMatrix SparseMatrix_sort(SparseMatrix A)
SparseMatrix SparseMatrix_sum_repeat_entries(SparseMatrix A)
SparseMatrix SparseMatrix_add(SparseMatrix A, SparseMatrix B)
SparseMatrix SparseMatrix_multiply3(SparseMatrix A, SparseMatrix B, SparseMatrix C)
SparseMatrix SparseMatrix_apply_fun(SparseMatrix A, double(*fun)(double x))
bool SparseMatrix_has_diagonal(SparseMatrix A)
static SparseMatrix SparseMatrix_init(int m, int n, int type, size_t sz, int format)
static SparseMatrix SparseMatrix_general_new(int m, int n, size_t nz, int type, size_t sz, int format)
int * SparseMatrix_weakly_connected_components(SparseMatrix A0, int *ncomp, int **comps)
SparseMatrix SparseMatrix_from_coordinate_format_not_compacted(SparseMatrix A)
SparseMatrix SparseMatrix_remove_diagonal(SparseMatrix A)
SparseMatrix SparseMatrix_from_dense(int m, int n, double *x)
SparseMatrix SparseMatrix_new(int m, int n, size_t nz, int type, int format)
@ MATRIX_TYPE_REAL
@ MATRIX_TYPE_PATTERN
@ MATRIX_TYPE_COMPLEX
@ MATRIX_TYPE_INTEGER
#define SYMMETRY_EPSILON
@ UNMASKED
@ SUM_REPEATED_ALL
@ SUM_REPEATED_NONE
@ FORMAT_COORD
@ FORMAT_CSR
@ BIPARTITE_PATTERN_UNSYM
@ BIPARTITE_UNSYM
@ BIPARTITE_RECT
@ BIPARTITE_ALWAYS
Memory allocation wrappers that exit on failure.
static void * gv_recalloc(void *ptr, size_t old_nmemb, size_t new_nmemb, size_t size)
Definition alloc.h:73
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
static void * gv_alloc(size_t size)
Definition alloc.h:47
expr procedure type
Definition exparse.y:208
#define A(n, t)
Definition expr.h:76
void free(void *)
node NULL
Definition grammar.y:181
static uint64_t id
Definition gv2gml.c:40
GVIO_API const char * format
Definition gvio.h:51
#define B
Definition hierarchy.c:118
#define D
Definition hierarchy.c:120
static const int dim
arithmetic overflow helpers
static bool size_overflow(size_t a, size_t b, size_t *res)
Definition overflow.h:51
#define C
Definition pack.c:30
#define PRISIZE_T
Definition prisize_t.h:25
#define RETURN(v)
Definition strmatch.c:144
size_t nz
the actual length used is nz, for CSR/CSC matrix this is the same as ia[n]
#define UNREACHABLE()
Definition unreachable.h:30