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