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