Graphviz 15.1.0~dev.20260613.1552
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, 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
310static SparseMatrix SparseMatrix_general_new(int m, int n, size_t nz, int type,
311 size_t sz, int format) {
312 /* return a sparse matrix skeleton with row dimension m and storage nz. If nz == 0,
313 only row pointers are allocated. this is more general and allow elements to be
314 any data structure, not just real/int/complex etc
315 */
317
318 A = SparseMatrix_init(m, n, type, sz, format);
319
320 if (nz > 0) SparseMatrix_alloc(A, nz);
321 return A;
322
323}
324
325SparseMatrix SparseMatrix_new(int m, int n, size_t nz, int type, int format) {
326 /* return a sparse matrix skeleton with row dimension m and storage nz. If nz == 0,
327 only row pointers are allocated */
329 format);
330}
331
333 if (!A) return;
334 free(A->ia);
335 free(A->ja);
336 free(A->a);
337 free(A);
338}
339
341 const int m = A->m;
342
343 switch (A->type){
345 fprintf(f,"%%%%MatrixMarket matrix coordinate integer general\n");
346 break;
347 default:
348 fprintf(stderr, "export of non-integer matrices is unsupported\n");
349 abort();
350 }
351
352 fprintf(f, "%d %d %" PRISIZE_T "\n", A->m, A->n, A->nz);
353 const int *const ia = A->ia;
354 const int *const ja = A->ja;
355 const int *const ai = A->a;
356 for (int i = 0; i < m; i++) {
357 for (int j = ia[i]; j < ia[i + 1]; j++) {
358 fprintf(f, "%d %d %d\n", i + 1, ja[j] + 1, ai[j]);
359 }
360 }
361}
362
364
365 switch (A->format){
366 case FORMAT_CSR:
368 break;
369 case FORMAT_COORD:
370 fprintf(stderr, "exporting coordinate format matrices is not supported\n");
371 abort();
372 default:
373 UNREACHABLE();
374 }
375}
376
377
379 /* convert a sparse matrix in coordinate form to one in compressed row form.*/
380 int *irn, *jcn;
381
382 void *a = A->a;
383
384 assert(A->format == FORMAT_COORD);
385 if (A->format != FORMAT_COORD) {
386 return NULL;
387 }
388 irn = A->ia;
389 jcn = A->ja;
390 return SparseMatrix_from_coordinate_arrays(A->nz, A->m, A->n, irn, jcn, a, A->type, A->size);
391
392}
394 /* convert a sparse matrix in coordinate form to one in compressed row form.*/
395 int *irn, *jcn;
396
397 void *a = A->a;
398
399 assert(A->format == FORMAT_COORD);
400 if (A->format != FORMAT_COORD) {
401 return NULL;
402 }
403 irn = A->ia;
404 jcn = A->ja;
405 return SparseMatrix_from_coordinate_arrays_not_compacted(A->nz, A->m, A->n, irn, jcn, a, A->type, A->size);
406}
407
409 int m, int n,
410 int *irn,
411 int *jcn,
412 const void *val0,
413 int type,
414 size_t sz,
415 int sum_repeated) {
416 /* convert a sparse matrix in coordinate form to one in compressed row form.
417 nz: number of entries
418 irn: row indices 0-based
419 jcn: column indices 0-based
420 val values if not NULL
421 type: matrix type
422 */
423
425 int *ia, *ja;
426 double *a;
427 int *ai;
428
429 assert(m > 0 && n > 0);
430
431 if (m <=0 || n <= 0) return NULL;
432 A = SparseMatrix_general_new(m, n, nz, type, sz, FORMAT_CSR);
433 ia = A->ia;
434 ja = A->ja;
435
436 for (int i = 0; i <= m; i++){
437 ia[i] = 0;
438 }
439
440 switch (type){
441 case MATRIX_TYPE_REAL: {
442 const double *const val = val0;
443 a = A->a;
444 for (size_t i = 0; i < nz; i++){
445 if (irn[i] < 0 || irn[i] >= m || jcn[i] < 0 || jcn[i] >= n) {
446 UNREACHABLE();
447 }
448 ia[irn[i]+1]++;
449 }
450 for (int i = 0; i < m; i++) ia[i+1] += ia[i];
451 for (size_t i = 0; i < nz; i++){
452 a[ia[irn[i]]] = val[i];
453 ja[ia[irn[i]]++] = jcn[i];
454 }
455 for (int i = m; i > 0; i--) ia[i] = ia[i - 1];
456 ia[0] = 0;
457 break;
458 }
459 case MATRIX_TYPE_INTEGER: {
460 const int *const vali = val0;
461 ai = A->a;
462 for (size_t i = 0; i < nz; i++){
463 if (irn[i] < 0 || irn[i] >= m || jcn[i] < 0 || jcn[i] >= n) {
464 UNREACHABLE();
465 }
466 ia[irn[i]+1]++;
467 }
468 for (int i = 0; i < m; i++) ia[i+1] += ia[i];
469 for (size_t i = 0; i < nz; i++){
470 ai[ia[irn[i]]] = vali[i];
471 ja[ia[irn[i]]++] = jcn[i];
472 }
473 for (int i = m; i > 0; i--) ia[i] = ia[i - 1];
474 ia[0] = 0;
475 break;
476 }
478 for (size_t i = 0; i < nz; i++){
479 if (irn[i] < 0 || irn[i] >= m || jcn[i] < 0 || jcn[i] >= n) {
480 UNREACHABLE();
481 }
482 ia[irn[i]+1]++;
483 }
484 for (int i = 0; i < m; i++) ia[i+1] += ia[i];
485 for (size_t i = 0; i < nz; i++){
486 ja[ia[irn[i]]++] = jcn[i];
487 }
488 for (int i = m; i > 0; i--) ia[i] = ia[i - 1];
489 ia[0] = 0;
490 break;
491 default:
492 UNREACHABLE();
493 }
494 A->nz = nz;
495
496
497
498 if(sum_repeated) A = SparseMatrix_sum_repeat_entries(A);
499
500 return A;
501}
502
504 int *irn, int *jcn,
505 const void *val, int type,
506 size_t sz) {
507 return SparseMatrix_from_coordinate_arrays_internal(nz, m, n, irn, jcn, val, type, sz, SUM_REPEATED_ALL);
508}
509
511 int n, int *irn,
512 int *jcn,
513 void *val0,
514 int type,
515 size_t sz) {
516 return SparseMatrix_from_coordinate_arrays_internal(nz, m, n, irn, jcn, val0, type, sz, SUM_REPEATED_NONE);
517}
518
520 int m, n;
522 int *mask = NULL;
523 int *ia = A->ia, *ja = A->ja, *ib = B->ia, *jb = B->ja, *ic, *jc;
524 int j;
525
526 assert(A && B);
527 assert(A->format == B->format && A->format == FORMAT_CSR);/* other format not yet supported */
528 assert(A->type == B->type);
529 m = A->m;
530 n = A->n;
531 if (m != B->m || n != B->n) return NULL;
532
533 const size_t nzmax = A->nz + B->nz; // just assume that no entries overlaps for speed
534
535 C = SparseMatrix_new(m, n, nzmax, A->type, FORMAT_CSR);
536 ic = C->ia;
537 jc = C->ja;
538
539 mask = gv_calloc((size_t)n, sizeof(int));
540
541 for (int i = 0; i < n; i++) mask[i] = -1;
542
543 size_t nz = 0;
544 ic[0] = 0;
545 switch (A->type){
546 case MATRIX_TYPE_REAL:{
547 double *a = A->a;
548 double *b = B->a;
549 double *c = C->a;
550 for (int i = 0; i < m; i++) {
551 for (j = ia[i]; j < ia[i+1]; j++){
552 mask[ja[j]] = (int)nz;
553 jc[nz] = ja[j];
554 c[nz] = a[j];
555 nz++;
556 }
557 for (j = ib[i]; j < ib[i+1]; j++){
558 if (mask[jb[j]] < ic[i]){
559 jc[nz] = jb[j];
560 c[nz++] = b[j];
561 } else {
562 c[mask[jb[j]]] += b[j];
563 }
564 }
565 ic[i + 1] = (int)nz;
566 }
567 break;
568 }
570 int *a = A->a;
571 int *b = B->a;
572 int *c = C->a;
573 for (int i = 0; i < m; i++) {
574 for (j = ia[i]; j < ia[i+1]; j++){
575 mask[ja[j]] = (int)nz;
576 jc[nz] = ja[j];
577 c[nz] = a[j];
578 nz++;
579 }
580 for (j = ib[i]; j < ib[i+1]; j++){
581 if (mask[jb[j]] < ic[i]){
582 jc[nz] = jb[j];
583 c[nz] = b[j];
584 nz++;
585 } else {
586 c[mask[jb[j]]] += b[j];
587 }
588 }
589 ic[i + 1] = (int)nz;
590 }
591 break;
592 }
594 for (int i = 0; i < m; i++) {
595 for (j = ia[i]; j < ia[i+1]; j++){
596 mask[ja[j]] = (int)nz;
597 jc[nz] = ja[j];
598 nz++;
599 }
600 for (j = ib[i]; j < ib[i+1]; j++){
601 if (mask[jb[j]] < ic[i]){
602 jc[nz] = jb[j];
603 nz++;
604 }
605 }
606 ic[i + 1] = (int)nz;
607 }
608 break;
609 }
610 default:
611 UNREACHABLE();
612 }
613 C->nz = nz;
614
615 free(mask);
616
617 return C;
618}
619
620void SparseMatrix_multiply_dense(SparseMatrix A, const double *v, double *res,
621 int dim) {
622 // A × V, with A dimension m × n, with V a dense matrix of dimension n × dim.
623 // v[i×dim×j] gives V[i,j]. Result of dimension m × dim. Real only for now.
624 int i, j, k, *ia, *ja, m;
625 double *a;
626
627 assert(A->format == FORMAT_CSR);
628 assert(A->type == MATRIX_TYPE_REAL);
629
630 a = A->a;
631 ia = A->ia;
632 ja = A->ja;
633 m = A->m;
634
635 for (i = 0; i < m; i++){
636 for (k = 0; k < dim; k++) res[i * dim + k] = 0;
637 for (j = ia[i]; j < ia[i+1]; j++){
638 for (k = 0; k < dim; k++) res[i * dim + k] += a[j] * v[ja[j] *dim + k];
639 }
640 }
641}
642
643void SparseMatrix_multiply_vector(SparseMatrix A, double *v, double **res) {
644 /* A v or A^T v. Real only for now. */
645 int i, j, *ia, *ja, m;
646 double *a, *u = NULL;
647 int *ai;
648 assert(A->format == FORMAT_CSR);
649 assert(A->type == MATRIX_TYPE_REAL || A->type == MATRIX_TYPE_INTEGER);
650
651 ia = A->ia;
652 ja = A->ja;
653 m = A->m;
654 u = *res;
655
656 switch (A->type){
657 case MATRIX_TYPE_REAL:
658 a = A->a;
659 assert(v != NULL);
660 if (!u) u = gv_calloc((size_t)m, sizeof(double));
661 for (i = 0; i < m; i++){
662 u[i] = 0.;
663 for (j = ia[i]; j < ia[i+1]; j++){
664 u[i] += a[j]*v[ja[j]];
665 }
666 }
667 break;
669 ai = A->a;
670 assert(v != NULL);
671 if (!u) u = gv_calloc((size_t)m, sizeof(double));
672 for (i = 0; i < m; i++){
673 u[i] = 0.;
674 for (j = ia[i]; j < ia[i+1]; j++){
675 u[i] += ai[j]*v[ja[j]];
676 }
677 }
678 break;
679 default:
680 UNREACHABLE();
681 }
682 *res = u;
683
684}
685
687 int m;
689 int *mask = NULL;
690 int *ia = A->ia, *ja = A->ja, *ib = B->ia, *jb = B->ja, *ic, *jc;
691 int j, k, jj, type;
692
693 assert(A->format == B->format && A->format == FORMAT_CSR);/* other format not yet supported */
694
695 m = A->m;
696 if (A->n != B->m) return NULL;
697 if (A->type != B->type){
698#ifdef DEBUG
699 printf("in SparseMatrix_multiply, the matrix types do not match, right now only multiplication of matrices of the same type is supported\n");
700#endif
701 return NULL;
702 }
703 type = A->type;
704
705 mask = calloc((size_t)B->n, sizeof(int));
706 if (!mask) return NULL;
707
708 for (int i = 0; i < B->n; i++) mask[i] = -1;
709
710 size_t nz = 0;
711 for (int i = 0; i < m; i++) {
712 for (j = ia[i]; j < ia[i+1]; j++){
713 jj = ja[j];
714 for (k = ib[jj]; k < ib[jj+1]; k++){
715 if (mask[jb[k]] != -i - 2){
716 if (size_overflow(nz, 1, &nz)) {
717#ifdef DEBUG_PRINT
718 fprintf(stderr,"overflow in SparseMatrix_multiply !!!\n");
719#endif
720 free(mask);
721 return NULL;
722 }
723 mask[jb[k]] = -i - 2;
724 }
725 }
726 }
727 }
728
729 C = SparseMatrix_new(m, B->n, nz, type, FORMAT_CSR);
730 ic = C->ia;
731 jc = C->ja;
732
733 nz = 0;
734
735 switch (type){
736 case MATRIX_TYPE_REAL:
737 {
738 double *a = A->a;
739 double *b = B->a;
740 double *c = C->a;
741 ic[0] = 0;
742 for (int i = 0; i < m; i++) {
743 for (j = ia[i]; j < ia[i+1]; j++){
744 jj = ja[j];
745 for (k = ib[jj]; k < ib[jj+1]; k++){
746 if (mask[jb[k]] < ic[i]){
747 mask[jb[k]] = (int)nz;
748 jc[nz] = jb[k];
749 c[nz] = a[j]*b[k];
750 nz++;
751 } else {
752 assert(jc[mask[jb[k]]] == jb[k]);
753 c[mask[jb[k]]] += a[j]*b[k];
754 }
755 }
756 }
757 ic[i + 1] = (int)nz;
758 }
759 }
760 break;
762 {
763 int *a = A->a;
764 int *b = B->a;
765 int *c = C->a;
766 ic[0] = 0;
767 for (int i = 0; i < m; i++) {
768 for (j = ia[i]; j < ia[i+1]; j++){
769 jj = ja[j];
770 for (k = ib[jj]; k < ib[jj+1]; k++){
771 if (mask[jb[k]] < ic[i]){
772 mask[jb[k]] = (int)nz;
773 jc[nz] = jb[k];
774 c[nz] = a[j]*b[k];
775 nz++;
776 } else {
777 assert(jc[mask[jb[k]]] == jb[k]);
778 c[mask[jb[k]]] += a[j]*b[k];
779 }
780 }
781 }
782 ic[i + 1] = (int)nz;
783 }
784 }
785 break;
787 ic[0] = 0;
788 for (int i = 0; i < m; i++) {
789 for (j = ia[i]; j < ia[i+1]; j++){
790 jj = ja[j];
791 for (k = ib[jj]; k < ib[jj+1]; k++){
792 if (mask[jb[k]] < ic[i]){
793 mask[jb[k]] = (int)nz;
794 jc[nz] = jb[k];
795 nz++;
796 } else {
797 assert(jc[mask[jb[k]]] == jb[k]);
798 }
799 }
800 }
801 ic[i + 1] = (int)nz;
802 }
803 break;
804 default:
805 UNREACHABLE();
806 }
807
808 C->nz = nz;
809
810 free(mask);
811 return C;
812}
813
814
815
817 int m;
819 int *mask = NULL;
820 int *ia = A->ia, *ja = A->ja, *ib = B->ia, *jb = B->ja, *ic = C->ia, *jc = C->ja, *id, *jd;
821 int j, k, l, ll, jj, type;
822
823 assert(A->format == B->format && A->format == FORMAT_CSR);/* other format not yet supported */
824
825 m = A->m;
826 if (A->n != B->m) return NULL;
827 if (B->n != C->m) return NULL;
828
829 if (A->type != B->type || B->type != C->type){
830#ifdef DEBUG
831 printf("in SparseMatrix_multiply3, the matrix types do not match, right now only multiplication of matrices of the same type is supported\n");
832#endif
833 return NULL;
834 }
835 type = A->type;
836
837 assert(type == MATRIX_TYPE_REAL);
838
839 mask = calloc((size_t)C->n, sizeof(int));
840 if (!mask) return NULL;
841
842 for (int i = 0; i < C->n; i++) mask[i] = -1;
843
844 size_t nz = 0;
845 for (int i = 0; i < m; i++){
846 for (j = ia[i]; j < ia[i+1]; j++){
847 jj = ja[j];
848 for (l = ib[jj]; l < ib[jj+1]; l++){
849 ll = jb[l];
850 for (k = ic[ll]; k < ic[ll+1]; k++){
851 if (mask[jc[k]] != -i - 2){
852 if (size_overflow(nz, 1, &nz)) {
853#ifdef DEBUG_PRINT
854 fprintf(stderr, "overflow in SparseMatrix_multiply3 !!!\n");
855#endif
856 free(mask);
857 return NULL;
858 }
859 mask[jc[k]] = -i - 2;
860 }
861 }
862 }
863 }
864 }
865
866 D = SparseMatrix_new(m, C->n, nz, type, FORMAT_CSR);
867 id = D->ia;
868 jd = D->ja;
869
870 nz = 0;
871
872 double *a = A->a;
873 double *b = B->a;
874 double *c = C->a;
875 double *d = D->a;
876 id[0] = 0;
877 for (int i = 0; i < m; i++){
878 for (j = ia[i]; j < ia[i+1]; j++){
879 jj = ja[j];
880 for (l = ib[jj]; l < ib[jj+1]; l++){
881 ll = jb[l];
882 for (k = ic[ll]; k < ic[ll+1]; k++){
883 if (mask[jc[k]] < id[i]){
884 mask[jc[k]] = (int)nz;
885 jd[nz] = jc[k];
886 d[nz] = a[j]*b[l]*c[k];
887 nz++;
888 } else {
889 assert(jd[mask[jc[k]]] == jc[k]);
890 d[mask[jc[k]]] += a[j]*b[l]*c[k];
891 }
892 }
893 }
894 }
895 id[i + 1] = (int)nz;
896 }
897
898 D->nz = nz;
899
900 free(mask);
901 return D;
902}
903
905 /* sum repeated entries in the same row, i.e., {1,1}->1, {1,1}->2 becomes {1,1}->3 */
906 int *ia = A->ia, *ja = A->ja, type = A->type, n = A->n;
907 int *mask = NULL, j, sta;
908 size_t nz = 0;
909
910 mask = gv_calloc((size_t)n, sizeof(int));
911 for (int i = 0; i < n; i++) mask[i] = -1;
912
913 switch (type){
914 case MATRIX_TYPE_REAL:
915 {
916 double *a = A->a;
917 sta = ia[0];
918 for (int i = 0; i < A->m; i++) {
919 for (j = sta; j < ia[i+1]; j++){
920 if (mask[ja[j]] < ia[i]){
921 ja[nz] = ja[j];
922 a[nz] = a[j];
923 mask[ja[j]] = (int)nz++;
924 } else {
925 assert(ja[mask[ja[j]]] == ja[j]);
926 a[mask[ja[j]]] += a[j];
927 }
928 }
929 sta = ia[i+1];
930 ia[i + 1] = (int)nz;
931 }
932 }
933 break;
935 {
936 int *a = A->a;
937 sta = ia[0];
938 for (int i = 0; i < A->m; i++) {
939 for (j = sta; j < ia[i+1]; j++){
940 if (mask[ja[j]] < ia[i]){
941 ja[nz] = ja[j];
942 a[nz] = a[j];
943 mask[ja[j]] = (int)nz++;
944 } else {
945 assert(ja[mask[ja[j]]] == ja[j]);
946 a[mask[ja[j]]] += a[j];
947 }
948 }
949 sta = ia[i+1];
950 ia[i + 1] = (int)nz;
951 }
952 }
953 break;
955 {
956 sta = ia[0];
957 for (int i = 0; i < A->m; i++) {
958 for (j = sta; j < ia[i+1]; j++){
959 if (mask[ja[j]] < ia[i]){
960 ja[nz] = ja[j];
961 mask[ja[j]] = (int)nz++;
962 } else {
963 assert(ja[mask[ja[j]]] == ja[j]);
964 }
965 }
966 sta = ia[i+1];
967 ia[i + 1] = (int)nz;
968 }
969 }
970 break;
971 default:
972 free(mask);
973 return NULL;
974 }
975 A->nz = nz;
976 free(mask);
977 return A;
978}
979
981 int jcn, const void *val,
982 int type) {
983 static const size_t nentries = 1;
984
985 assert(A->format == FORMAT_COORD);
986 assert(A->type == type && "call to SparseMatrix_coordinate_form_add_entry "
987 "with incompatible value type");
988 const size_t nz = A->nz;
989
990 if (nz + nentries >= A->nzmax){
991 const size_t nzmax = nz + nentries + 10;
992 A = SparseMatrix_realloc(A, nzmax);
993 }
994 A->ia[nz] = irn;
995 A->ja[nz] = jcn;
996 if (A->size) memcpy((char *)A->a + nz * A->size / sizeof(char), val, A->size * nentries);
997 if (irn >= A->m) A->m = irn + 1;
998 if (jcn >= A->n) A->n = jcn + 1;
999 A->nz += nentries;
1000 return A;
1001}
1002
1003
1005 int i, j, *ia, *ja, sta;
1006
1007 if (!A) return A;
1008
1009 size_t nz = 0;
1010 ia = A->ia;
1011 ja = A->ja;
1012 sta = ia[0];
1013 switch (A->type){
1014 case MATRIX_TYPE_REAL:{
1015 double *a = A->a;
1016 for (i = 0; i < A->m; i++){
1017 for (j = sta; j < ia[i+1]; j++){
1018 if (ja[j] != i){
1019 ja[nz] = ja[j];
1020 a[nz++] = a[j];
1021 }
1022 }
1023 sta = ia[i+1];
1024 ia[i + 1] = (int)nz;
1025 }
1026 A->nz = nz;
1027 break;
1028 }
1029 case MATRIX_TYPE_INTEGER:{
1030 int *a = A->a;
1031 for (i = 0; i < A->m; i++){
1032 for (j = sta; j < ia[i+1]; j++){
1033 if (ja[j] != i){
1034 ja[nz] = ja[j];
1035 a[nz++] = a[j];
1036 }
1037 }
1038 sta = ia[i+1];
1039 ia[i + 1] = (int)nz;
1040 }
1041 A->nz = nz;
1042 break;
1043 }
1044 case MATRIX_TYPE_PATTERN:{
1045 for (i = 0; i < A->m; i++){
1046 for (j = sta; j < ia[i+1]; j++){
1047 if (ja[j] != i){
1048 ja[nz++] = ja[j];
1049 }
1050 }
1051 sta = ia[i+1];
1052 ia[i + 1] = (int)nz;
1053 }
1054 A->nz = nz;
1055 break;
1056 }
1057 default:
1058 UNREACHABLE();
1059 }
1060
1061 return A;
1062}
1063
1064
1065SparseMatrix SparseMatrix_remove_upper(SparseMatrix A){/* remove diag and upper diag */
1066 int i, j, *ia, *ja, sta;
1067
1068 if (!A) return A;
1069
1070 size_t nz = 0;
1071 ia = A->ia;
1072 ja = A->ja;
1073 sta = ia[0];
1074 switch (A->type){
1075 case MATRIX_TYPE_REAL:{
1076 double *a = A->a;
1077 for (i = 0; i < A->m; i++){
1078 for (j = sta; j < ia[i+1]; j++){
1079 if (ja[j] < i){
1080 ja[nz] = ja[j];
1081 a[nz++] = a[j];
1082 }
1083 }
1084 sta = ia[i+1];
1085 ia[i + 1] = (int)nz;
1086 }
1087 A->nz = nz;
1088 break;
1089 }
1090 case MATRIX_TYPE_INTEGER:{
1091 int *a = A->a;
1092 for (i = 0; i < A->m; i++){
1093 for (j = sta; j < ia[i+1]; j++){
1094 if (ja[j] < i){
1095 ja[nz] = ja[j];
1096 a[nz++] = a[j];
1097 }
1098 }
1099 sta = ia[i+1];
1100 ia[i + 1] = (int)nz;
1101 }
1102 A->nz = nz;
1103 break;
1104 }
1105 case MATRIX_TYPE_PATTERN:{
1106 for (i = 0; i < A->m; i++){
1107 for (j = sta; j < ia[i+1]; j++){
1108 if (ja[j] < i){
1109 ja[nz++] = ja[j];
1110 }
1111 }
1112 sta = ia[i+1];
1113 ia[i + 1] = (int)nz;
1114 }
1115 A->nz = nz;
1116 break;
1117 }
1118 default:
1119 UNREACHABLE();
1120 }
1121
1122 A->is_pattern_symmetric = false;
1123 A->is_symmetric = false;
1124 return A;
1125}
1126
1127
1128
1129
1131 int i, j, *ia;
1132 double deg;
1133
1134 if (!A) return A;
1135
1136 ia = A->ia;
1137 switch (A->type){
1138 case MATRIX_TYPE_REAL:{
1139 double *a = A->a;
1140 for (i = 0; i < A->m; i++){
1141 deg = ia[i+1] - ia[i];
1142 for (j = ia[i]; j < ia[i+1]; j++){
1143 a[j] = a[j]/deg;
1144 }
1145 }
1146 break;
1147 }
1149 UNREACHABLE(); // this operation would not make sense for int matrix
1150 case MATRIX_TYPE_PATTERN:{
1151 break;
1152 }
1153 default:
1154 UNREACHABLE();
1155 }
1156
1157 return A;
1158}
1159
1160
1162 /* symmetric, all entries to 1, diaginal removed */
1163 int *ia, *ja, m, n;
1164 double *a;
1166
1167 if (!A) return A;
1168
1169 const size_t nz = A->nz;
1170 ia = A->ia;
1171 ja = A->ja;
1172 n = A->n;
1173 m = A->m;
1174
1175 if (n != m) return NULL;
1176
1178
1179 memcpy(B->ia, ia, sizeof(int)*((size_t)(m+1)));
1180 memcpy(B->ja, ja, sizeof(int) * nz);
1181 B->nz = A->nz;
1182
1183 A = SparseMatrix_symmetrize(B, true);
1186 A->a = gv_calloc(A->nz, sizeof(double));
1187 a = A->a;
1188 for (size_t i = 0; i < A->nz; i++) a[i] = 1.;
1189 A->type = MATRIX_TYPE_REAL;
1190 A->size = sizeof(double);
1191 return A;
1192}
1193
1195 int i, j;
1196 double *a;
1197
1198
1199 if (!A) return A;
1200 if (A->format != FORMAT_CSR && A->type != MATRIX_TYPE_REAL) {
1201#ifdef DEBUG
1202 printf("only CSR and real matrix supported.\n");
1203#endif
1204 return A;
1205 }
1206
1207
1208 a = A->a;
1209 for (i = 0; i < A->m; i++){
1210 for (j = A->ia[i]; j < A->ia[i+1]; j++){
1211 a[j] = fun(a[j]);
1212 }
1213 }
1214 return A;
1215}
1216
1219 if (!A) return A;
1220 B = SparseMatrix_general_new(A->m, A->n, A->nz, A->type, A->size, A->format);
1221 memcpy(B->ia, A->ia, sizeof(int)*((size_t)(A->m+1)));
1222 if (A->ia[A->m] != 0) {
1223 memcpy(B->ja, A->ja, sizeof(int)*((size_t)(A->ia[A->m])));
1224 }
1225 if (A->a) memcpy(B->a, A->a, A->size * A->nz);
1226 B->is_pattern_symmetric = A->is_pattern_symmetric;
1227 B->is_symmetric = A->is_symmetric;
1228 B->is_undirected = A->is_undirected;
1229 B->nz = A->nz;
1230 return B;
1231}
1232
1234
1235 int i, j, m = A->m, *ia = A->ia, *ja = A->ja;
1236
1237 for (i = 0; i < m; i++){
1238 for (j = ia[i]; j < ia[i+1]; j++){
1239 if (i == ja[j]) return true;
1240 }
1241 }
1242 return false;
1243}
1244
1245static void SparseMatrix_level_sets(SparseMatrix A, int root, int *nlevel,
1246 int **levelset_ptr, int **levelset,
1247 int **mask, bool reinitialize_mask) {
1248 /* mask is assumed to be initialized to negative if provided.
1249 . On exit, mask = levels for visited nodes (1 for root, 2 for its neighbors, etc),
1250 . unless reinitialize_mask is true, in which case mask = -1.
1251 A: the graph, undirected
1252 root: starting node
1253 nlevel: max distance to root from any node (in the connected comp)
1254 levelset_ptr, levelset: the level sets
1255 */
1256 int j, sta = 0, sto = 1, ii;
1257 int m = A->m, *ia = A->ia, *ja = A->ja;
1258
1259 if (!(*levelset_ptr)) *levelset_ptr = gv_calloc((size_t)(m + 2), sizeof(int));
1260 if (!(*levelset)) *levelset = gv_calloc((size_t)m, sizeof(int));
1261 if (!(*mask)) {
1262 *mask = gv_calloc((size_t)m, sizeof(int));
1263 for (int i = 0; i < m; i++) (*mask)[i] = UNMASKED;
1264 }
1265
1266 *nlevel = 0;
1267 assert(root >= 0 && root < m);
1268 (*levelset_ptr)[0] = 0;
1269 (*levelset_ptr)[1] = 1;
1270 (*levelset)[0] = root;
1271 (*mask)[root] = 1;
1272 *nlevel = 1;
1273 size_t nz = 1;
1274 sta = 0; sto = 1;
1275 while (sto > sta){
1276 for (int i = sta; i < sto; i++){
1277 ii = (*levelset)[i];
1278 for (j = ia[ii]; j < ia[ii+1]; j++){
1279 if (ii == ja[j]) continue;
1280 if ((*mask)[ja[j]] < 0){
1281 (*levelset)[nz++] = ja[j];
1282 (*mask)[ja[j]] = *nlevel + 1;
1283 }
1284 }
1285 }
1286 (*levelset_ptr)[++(*nlevel)] = (int)nz;
1287 sta = sto;
1288 sto = (int)nz;
1289 }
1290 (*nlevel)--;
1291 if (reinitialize_mask) for (int i = 0; i < (*levelset_ptr)[*nlevel]; i++) (*mask)[(*levelset)[i]] = UNMASKED;
1292}
1293
1295 int **comps) {
1296 SparseMatrix A = A0;
1297 int *levelset_ptr = NULL, *levelset = NULL, *mask = NULL, nlevel;
1298 int m = A->m, i, nn;
1299
1300 if (!SparseMatrix_is_symmetric(A, true)){
1301 A = SparseMatrix_symmetrize(A, true);
1302 }
1303 int *comps_ptr = gv_calloc((size_t)(m + 1), sizeof(int));
1304
1305 *ncomp = 0;
1306 comps_ptr[0] = 0;
1307 for (i = 0; i < m; i++){
1308 if (i == 0 || mask[i] < 0) {
1309 SparseMatrix_level_sets(A, i, &nlevel, &levelset_ptr, &levelset, &mask, false);
1310 if (i == 0) *comps = levelset;
1311 nn = levelset_ptr[nlevel];
1312 levelset += nn;
1313 comps_ptr[(*ncomp)+1] = comps_ptr[(*ncomp)] + nn;
1314 (*ncomp)++;
1315 }
1316
1317 }
1318 if (A != A0) SparseMatrix_delete(A);
1319 free(levelset_ptr);
1320
1321 free(mask);
1322 return comps_ptr;
1323}
1324
1325void SparseMatrix_decompose_to_supervariables(SparseMatrix A, int *ncluster, int **cluster, int **clusterp){
1326 /* nodes for a super variable if they share exactly the same neighbors. This is know as modules in graph theory.
1327 We work on columns only and columns with the same pattern are grouped as a super variable
1328 */
1329 int *ia = A->ia, *ja = A->ja, n = A->n, m = A->m;
1330 int *super = NULL, *nsuper = NULL, j, *mask = NULL, isup, *newmap, isuper;
1331
1332 super = gv_calloc((size_t)n, sizeof(int));
1333 nsuper = gv_calloc((size_t)(n + 1), sizeof(int));
1334 mask = gv_calloc((size_t)n, sizeof(int));
1335 newmap = gv_calloc((size_t)n, sizeof(int));
1336 nsuper++;
1337
1338 isup = 0;
1339 for (int i = 0; i < n; i++) super[i] = isup;/* every node belongs to super variable 0 by default */
1340 nsuper[0] = n;
1341 for (int i = 0; i < n; i++) mask[i] = -1;
1342 isup++;
1343
1344 for (int i = 0; i < m; i++){
1345#ifdef DEBUG_PRINT1
1346 printf("\n");
1347 printf("doing row %d-----\n",i+1);
1348#endif
1349 for (j = ia[i]; j < ia[i+1]; j++){
1350 isuper = super[ja[j]];
1351 nsuper[isuper]--;/* those entries will move to a different super vars*/
1352 }
1353 for (j = ia[i]; j < ia[i+1]; j++){
1354 isuper = super[ja[j]];
1355 if (mask[isuper] < i){
1356 mask[isuper] = i;
1357 if (nsuper[isuper] == 0){/* all nodes in the isuper group exist in this row */
1358#ifdef DEBUG_PRINT1
1359 printf("node %d keep super node id %d\n",ja[j]+1,isuper+1);
1360#endif
1361 nsuper[isuper] = 1;
1362 newmap[isuper] = isuper;
1363 } else {
1364 newmap[isuper] = isup;
1365 nsuper[isup] = 1;
1366#ifdef DEBUG_PRINT1
1367 printf("make node %d into supernode %d\n",ja[j]+1,isup+1);
1368#endif
1369 super[ja[j]] = isup++;
1370 }
1371 } else {
1372#ifdef DEBUG_PRINT1
1373 printf("node %d join super node %d\n",ja[j]+1,newmap[isuper]+1);
1374#endif
1375 super[ja[j]] = newmap[isuper];
1376 nsuper[newmap[isuper]]++;
1377 }
1378 }
1379#ifdef DEBUG_PRINT1
1380 printf("nsuper=");
1381 for (j = 0; j < isup; j++) printf("(%d,%d),",j+1,nsuper[j]);
1382 printf("\n");
1383#endif
1384 }
1385#ifdef DEBUG_PRINT1
1386 for (int i = 0; i < n; i++){
1387 printf("node %d is in supernode %d\n",i, super[i]);
1388 }
1389#endif
1390#ifdef PRINT
1391 fprintf(stderr, "n = %d, nsup = %d\n",n,isup);
1392#endif
1393 /* now accumulate super nodes */
1394 nsuper--;
1395 nsuper[0] = 0;
1396 for (int i = 0; i < isup; i++) nsuper[i+1] += nsuper[i];
1397
1398 *cluster = newmap;
1399 for (int i = 0; i < n; i++) {
1400 isuper = super[i];
1401 (*cluster)[nsuper[isuper]++] = i;
1402 }
1403 for (int i = isup; i > 0; i--) nsuper[i] = nsuper[i-1];
1404 nsuper[0] = 0;
1405 *clusterp = nsuper;
1406 *ncluster = isup;
1407
1408#ifdef PRINT
1409 for (int i = 0; i < *ncluster; i++) {
1410 printf("{");
1411 for (j = (*clusterp)[i]; j < (*clusterp)[i+1]; j++){
1412 printf("%d, ",(*cluster)[j]);
1413 }
1414 printf("},");
1415 }
1416 printf("\n");
1417#endif
1418
1419 free(mask);
1420 free(super);
1421}
1422
1424 /* convert matrix A to an augmente dmatrix {{0,A},{A^T,0}} */
1425 int *irn = NULL, *jcn = NULL;
1426 void *val = NULL;
1427 size_t nz = A->nz;
1428 int type = A->type;
1429 int m = A->m, n = A->n, i, j;
1431 if (!A) return NULL;
1432 if (nz > 0){
1433 irn = gv_calloc(nz * 2, sizeof(int));
1434 jcn = gv_calloc(nz * 2, sizeof(int));
1435 }
1436
1437 if (A->a){
1438 assert(A->size != 0 && nz > 0);
1439 val = gv_calloc(2 * nz, A->size);
1440 memcpy(val, A->a, A->size * nz);
1441 memcpy((char *)val + nz * A->size, A->a, A->size * nz);
1442 }
1443
1444 nz = 0;
1445 for (i = 0; i < m; i++){
1446 for (j = (A->ia)[i]; j < (A->ia)[i+1]; j++){
1447 irn[nz] = i;
1448 jcn[nz++] = (A->ja)[j] + m;
1449 }
1450 }
1451 for (i = 0; i < m; i++){
1452 for (j = (A->ia)[i]; j < (A->ia)[i+1]; j++){
1453 jcn[nz] = i;
1454 irn[nz++] = (A->ja)[j] + m;
1455 }
1456 }
1457
1458 B = SparseMatrix_from_coordinate_arrays(nz, m + n, m + n, irn, jcn, val, type, A->size);
1459 B->is_symmetric = true;
1460 B->is_pattern_symmetric = true;
1461 free(irn);
1462 free(jcn);
1463 free(val);
1464 return B;
1465}
1466
1469 switch (bipartite_options){
1470 case BIPARTITE_RECT:
1471 if (A->m == A->n) return A;
1472 break;
1474 if (A->m == A->n && SparseMatrix_is_symmetric(A, true)) return A;
1475 break;
1476 case BIPARTITE_UNSYM:
1477 if (A->m == A->n && SparseMatrix_is_symmetric(A, false)) return A;
1478 break;
1479 case BIPARTITE_ALWAYS:
1480 break;
1481 default:
1482 UNREACHABLE();
1483 }
1486 return B;
1487}
1488
1489SparseMatrix SparseMatrix_get_submatrix(SparseMatrix A, int nrow, int ncol, int *rindices, int *cindices){
1490 /* get the submatrix from row/columns indices[0,...,l-1].
1491 row rindices[i] will be the new row i
1492 column cindices[i] will be the new column i.
1493 if rindices = NULL, it is assume that 1 -- nrow is needed. Same for cindices/ncol.
1494 */
1495 size_t nz = 0;
1496 int j, *irn, *jcn, *ia = A->ia, *ja = A->ja, m = A->m, n = A->n;
1497 int *cmask, *rmask;
1498 void *v = NULL;
1500 int irow = 0, icol = 0;
1501
1502 if (nrow <= 0 || ncol <= 0) return NULL;
1503
1504
1505
1506 rmask = gv_calloc((size_t)m, sizeof(int));
1507 cmask = gv_calloc((size_t)n, sizeof(int));
1508 for (int i = 0; i < m; i++) rmask[i] = -1;
1509 for (int i = 0; i < n; i++) cmask[i] = -1;
1510
1511 if (rindices){
1512 for (int i = 0; i < nrow; i++) {
1513 if (rindices[i] >= 0 && rindices[i] < m){
1514 rmask[rindices[i]] = irow++;
1515 }
1516 }
1517 } else {
1518 for (int i = 0; i < nrow; i++) {
1519 rmask[i] = irow++;
1520 }
1521 }
1522
1523 if (cindices){
1524 for (int i = 0; i < ncol; i++) {
1525 if (cindices[i] >= 0 && cindices[i] < n){
1526 cmask[cindices[i]] = icol++;
1527 }
1528 }
1529 } else {
1530 for (int i = 0; i < ncol; i++) {
1531 cmask[i] = icol++;
1532 }
1533 }
1534
1535 for (int i = 0; i < m; i++) {
1536 if (rmask[i] < 0) continue;
1537 for (j = ia[i]; j < ia[i+1]; j++){
1538 if (cmask[ja[j]] < 0) continue;
1539 nz++;
1540 }
1541 }
1542
1543
1544 switch (A->type){
1545 case MATRIX_TYPE_REAL:{
1546 double *a = A->a;
1547 double *val;
1548 irn = gv_calloc(nz, sizeof(int));
1549 jcn = gv_calloc(nz, sizeof(int));
1550 val = gv_calloc(nz, sizeof(double));
1551
1552 nz = 0;
1553 for (int i = 0; i < m; i++) {
1554 if (rmask[i] < 0) continue;
1555 for (j = ia[i]; j < ia[i+1]; j++){
1556 if (cmask[ja[j]] < 0) continue;
1557 irn[nz] = rmask[i];
1558 jcn[nz] = cmask[ja[j]];
1559 val[nz++] = a[j];
1560 }
1561 }
1562 v = val;
1563 break;
1564 }
1565 case MATRIX_TYPE_INTEGER:{
1566 int *a = A->a;
1567 int *val;
1568
1569 irn = gv_calloc(nz, sizeof(int));
1570 jcn = gv_calloc(nz, sizeof(int));
1571 val = gv_calloc(nz, sizeof(int));
1572
1573 nz = 0;
1574 for (int i = 0; i < m; i++) {
1575 if (rmask[i] < 0) continue;
1576 for (j = ia[i]; j < ia[i+1]; j++){
1577 if (cmask[ja[j]] < 0) continue;
1578 irn[nz] = rmask[i];
1579 jcn[nz] = cmask[ja[j]];
1580 val[nz] = a[j];
1581 nz++;
1582 }
1583 }
1584 v = val;
1585 break;
1586 }
1588 irn = gv_calloc(nz, sizeof(int));
1589 jcn = gv_calloc(nz, sizeof(int));
1590 nz = 0;
1591 for (int i = 0; i < m; i++) {
1592 if (rmask[i] < 0) continue;
1593 for (j = ia[i]; j < ia[i+1]; j++){
1594 if (cmask[ja[j]] < 0) continue;
1595 irn[nz] = rmask[i];
1596 jcn[nz++] = cmask[ja[j]];
1597 }
1598 }
1599 break;
1600 default:
1601 UNREACHABLE();
1602 }
1603
1604 B = SparseMatrix_from_coordinate_arrays(nz, nrow, ncol, irn, jcn, v, A->type, A->size);
1605 free(cmask);
1606 free(rmask);
1607 free(irn);
1608 free(jcn);
1609 if (v) free(v);
1610
1611
1612 return B;
1613
1614}
1615
1617 SparseMatrix D = D0;
1618 int m = D->m, n = D->n;
1619 int *levelset_ptr = NULL, *levelset = NULL, *mask = NULL;
1620 int i, j, k, nlevel;
1621
1622 if (!SparseMatrix_is_symmetric(D, false)){
1623 D = SparseMatrix_symmetrize(D, false);
1624 }
1625
1626 assert(m == n);
1627 (void)m;
1628
1629 SparseMatrix dist = SparseMatrix_new(n, n, (size_t)n * (size_t)n,
1631 int *const d = dist->a;
1632 for (i = 0; i <= n; ++i) {
1633 dist->ia[i] = i * n;
1634 }
1635 for (i = 0; i < n; ++i) {
1636 for (j = 0; j < n; ++j) {
1637 dist->ja[i * n + j] = j;
1638 d[i * n + j] = -1;
1639 }
1640 }
1641
1642 for (k = 0; k < n; k++) {
1643 SparseMatrix_level_sets(D, k, &nlevel, &levelset_ptr, &levelset, &mask, true);
1644 assert(levelset_ptr[nlevel] == n);
1645 for (i = 0; i < nlevel; i++) {
1646 for (j = levelset_ptr[i]; j < levelset_ptr[i+1]; j++) {
1647 d[k * n + levelset[j]] = i;
1648 }
1649 }
1650 }
1651
1652 free(levelset_ptr);
1653 free(levelset);
1654 free(mask);
1655
1656 if (D != D0) SparseMatrix_delete(D);
1657 return dist;
1658}
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)
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)
@ 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 *)
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 nz
the actual length used is nz, for CSR/CSC matrix this is the same as ia[n]
#define UNREACHABLE()
Definition unreachable.h:30