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