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