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