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