1 //------------------------------------------------------------------------------
2 // GB_matvec_check: print a GraphBLAS matrix and check if it is valid
3 //------------------------------------------------------------------------------
4
5 // SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2021, All Rights Reserved.
6 // SPDX-License-Identifier: Apache-2.0
7
8 //------------------------------------------------------------------------------
9
10 // for code development only:
11 // #define GB_DEVELOPER 1
12
13 #include "GB_Pending.h"
14 #include "GB.h"
15
16 GB_PUBLIC // accessed by the MATLAB tests in GraphBLAS/Test only
GB_matvec_check(const GrB_Matrix A,const char * name,int pr,FILE * f,const char * kind)17 GrB_Info GB_matvec_check // check a GraphBLAS matrix or vector
18 (
19 const GrB_Matrix A, // GraphBLAS matrix to print and check
20 const char *name, // name of the matrix, optional
21 int pr, // print level; if negative, ignore nzombie
22 // conditions and use GB_FLIP(pr) for diagnostics
23 FILE *f, // file for output
24 const char *kind // "matrix" or "vector"
25 )
26 {
27
28 //--------------------------------------------------------------------------
29 // decide what to print
30 //--------------------------------------------------------------------------
31
32 bool is_hyper = GB_IS_HYPERSPARSE (A) ;
33 bool is_full = GB_IS_FULL (A) ;
34 bool is_bitmap = GB_IS_BITMAP (A) ;
35 bool is_sparse = GB_IS_SPARSE (A) ;
36
37 bool ignore_zombies = false ;
38 if (pr < 0)
39 {
40 pr = GB_FLIP (pr) ;
41 ignore_zombies = true ;
42 }
43 pr = GB_IMIN (pr, GxB_COMPLETE_VERBOSE) ;
44 bool phantom = (is_full && A->x == NULL) ;
45 if (phantom)
46 {
47 // convert GxB_COMPLETE* to GxB_SHORT*
48 if (pr == GxB_COMPLETE_VERBOSE) pr = GxB_SHORT_VERBOSE ;
49 if (pr == GxB_COMPLETE ) pr = GxB_SHORT ;
50 }
51 bool pr_silent = (pr == GxB_SILENT) ;
52 bool pr_complete = (pr == GxB_COMPLETE || pr == GxB_COMPLETE_VERBOSE) ;
53 bool pr_short = (pr == GxB_SHORT || pr == GxB_SHORT_VERBOSE ) ;
54 bool one_based = GB_Global_print_one_based_get ( ) ;
55 int64_t offset = (one_based) ? 1 : 0 ;
56 #if GB_DEVELOPER
57 int pr_type = pr ;
58 #else
59 int pr_type = 0 ;
60 #endif
61
62 GBPR0 ("\n " GBd "x" GBd " GraphBLAS %s %s",
63 (A != NULL) ? GB_NROWS (A) : 0,
64 (A != NULL) ? GB_NCOLS (A) : 0,
65 (A != NULL && A->type != NULL && A->type->name != NULL) ?
66 A->type->name : "", kind) ;
67
68 //--------------------------------------------------------------------------
69 // check if null, freed, or uninitialized
70 //--------------------------------------------------------------------------
71
72 if (A == NULL)
73 {
74 GBPR0 (" NULL\n") ;
75 return (GrB_NULL_POINTER) ;
76 }
77
78 GB_CHECK_MAGIC (A, kind) ;
79
80 //--------------------------------------------------------------------------
81 // print the header
82 //--------------------------------------------------------------------------
83
84 if (is_full)
85 {
86 // A->p, A->h, A->i, and A->b all null
87 GBPR0 (", full") ;
88 }
89 else if (is_bitmap)
90 {
91 // A->b not null
92 GBPR0 (", bitmap") ;
93 }
94 else if (is_sparse)
95 {
96 // A->h null, A->p not null
97 GBPR0 (", sparse") ;
98 }
99 else if (is_hyper)
100 {
101 // A->h not null
102 GBPR0 (", hypersparse") ;
103 }
104 else
105 {
106 // A is not hyper, sparse, bitmap, or full
107 GBPR0 (" invalid structure\n") ;
108 return (GrB_INVALID_OBJECT) ;
109 }
110 if (A->jumbled)
111 {
112 GBPR0 (" (jumbled)") ;
113 }
114 GBPR0 (" %s\n", A->is_csc ? "by col" : "by row") ;
115
116 #if GB_DEVELOPER
117 GBPR0 (" max # entries: " GBd "\n", A->nzmax) ;
118 GBPR0 (" vlen: " GBd , A->vlen) ;
119 if (A->nvec_nonempty != -1)
120 {
121 GBPR0 (" nvec_nonempty: " GBd , A->nvec_nonempty) ;
122 }
123 GBPR0 (" nvec: " GBd " plen: " GBd " vdim: " GBd "\n hyper_switch %g "
124 "bitmap_switch %g\n",
125 A->nvec, A->plen, A->vdim, A->hyper_switch, A->bitmap_switch) ;
126 #endif
127
128 switch (A->sparsity)
129 {
130
131 // 1
132 case GxB_HYPERSPARSE :
133 GBPR0 (" sparsity control: hypersparse only\n") ;
134 break ;
135
136 // 2
137 case GxB_SPARSE :
138 GBPR0 (" sparsity control: sparse only\n") ;
139 break ;
140
141 // 3
142 case GxB_HYPERSPARSE + GxB_SPARSE :
143 GBPR0 (" sparsity control: sparse/hypersparse\n") ;
144 break ;
145
146 // 4
147 case GxB_BITMAP :
148 GBPR0 (" sparsity control: bitmap only\n") ;
149 break ;
150
151 // 5
152 case GxB_HYPERSPARSE + GxB_BITMAP :
153 GBPR0 (" sparsity control: hypersparse/bitmap\n") ;
154 break ;
155
156 // 6
157 case GxB_SPARSE + GxB_BITMAP :
158 GBPR0 (" sparsity control: sparse/bitmap\n") ;
159 break ;
160
161 // 7
162 case GxB_HYPERSPARSE + GxB_SPARSE + GxB_BITMAP :
163 GBPR0 (" sparsity control: hypersparse/sparse/bitmap\n") ;
164 break ;
165
166 // 8
167 case GxB_FULL :
168 GBPR0 (" sparsity control: full\n") ;
169 break ;
170
171 // 9
172 case GxB_HYPERSPARSE + GxB_FULL :
173 GBPR0 (" sparsity control: hypersparse/full\n") ;
174 break ;
175
176 // 10
177 case GxB_SPARSE + GxB_FULL :
178 GBPR0 (" sparsity control: sparse/full\n") ;
179 break ;
180
181 // 11
182 case GxB_HYPERSPARSE + GxB_SPARSE + GxB_FULL :
183 GBPR0 (" sparsity control: hypersparse/sparse/full\n") ;
184 break ;
185
186 // 12
187 case GxB_FULL + GxB_BITMAP :
188 GBPR0 (" sparsity control: bitmap/full\n") ;
189 break ;
190
191 // 13
192 case GxB_HYPERSPARSE + GxB_BITMAP + GxB_FULL :
193 GBPR0 (" sparsity control: hypersparse/bitmap/full\n") ;
194 break ;
195
196 // 14
197 case GxB_SPARSE + GxB_BITMAP + GxB_FULL :
198 GBPR0 (" sparsity control: sparse/bitmap/full\n") ;
199 break ;
200
201 // 15
202 case GxB_HYPERSPARSE + GxB_SPARSE + GxB_BITMAP + GxB_FULL :
203 #if GB_DEVELOPER
204 GBPR0 (" sparsity control: hyper/sparse/bitmap/full\n") ;
205 #endif
206 break ;
207
208 default :
209 // invalid sparsity control
210 GBPR0 (" sparsity control: invalid\n") ;
211 return (GrB_INVALID_OBJECT) ;
212 break ;
213 }
214
215 //--------------------------------------------------------------------------
216 // check the dimensions
217 //--------------------------------------------------------------------------
218
219 if (A->vlen < 0 || A->vlen > GxB_INDEX_MAX ||
220 A->vdim < 0 || A->vdim > GxB_INDEX_MAX ||
221 A->nzmax < 0 || A->nzmax > GxB_INDEX_MAX)
222 {
223 GBPR0 (" invalid %s dimensions\n", kind) ;
224 return (GrB_INVALID_OBJECT) ;
225 }
226
227 //--------------------------------------------------------------------------
228 // check vector structure
229 //--------------------------------------------------------------------------
230
231 if (is_full)
232 {
233 // A is full
234 if (! (A->nvec == A->vdim && A->plen == -1))
235 {
236 GBPR0 (" invalid full %s structure\n", kind) ;
237 return (GrB_INVALID_OBJECT) ;
238 }
239 }
240 else if (is_bitmap)
241 {
242 // A is bitmap
243 if (! (A->nvec == A->vdim && A->plen == -1 &&
244 A->h == NULL && A->p == NULL && A->i == NULL))
245 {
246 GBPR0 (" invalid bitmap %s structure\n", kind) ;
247 return (GrB_INVALID_OBJECT) ;
248 }
249 }
250 else if (is_sparse)
251 {
252 // A is sparse
253 if (! (A->nvec == A->plen && A->plen == A->vdim))
254 {
255 GBPR0 (" invalid sparse %s structure\n", kind) ;
256 return (GrB_INVALID_OBJECT) ;
257 }
258 }
259 else
260 {
261 // A is hypersparse
262 if (! (A->nvec >= 0 && A->nvec <= A->plen && A->plen <= A->vdim))
263 {
264 GBPR0 (" invalid hypersparse %s structure\n", kind) ;
265 return (GrB_INVALID_OBJECT) ;
266 }
267 }
268
269 //--------------------------------------------------------------------------
270 // count the allocated blocks
271 //--------------------------------------------------------------------------
272
273 GB_Pending Pending = A->Pending ;
274
275 // a matrix contains 0 to 10 dynamically malloc'd blocks
276 int64_t nallocs = 0 ;
277 bool ok = true ;
278
279 if (!A->static_header)
280 {
281 nallocs++ ;
282 #ifdef GB_DEBUG
283 ok = ok && (A->header_size == GB_Global_memtable_size (A)) ;
284 #endif
285 }
286
287 if (A->p != NULL && !A->p_shallow)
288 {
289 nallocs++ ;
290 #ifdef GB_DEBUG
291 ok = ok && (A->p_size == GB_Global_memtable_size (A->p)) ;
292 #endif
293 }
294
295 if (A->h != NULL && !A->h_shallow)
296 {
297 nallocs++ ;
298 #ifdef GB_DEBUG
299 ok = ok && (A->h_size == GB_Global_memtable_size (A->h)) ;
300 #endif
301 }
302
303 if (A->b != NULL && !A->b_shallow)
304 {
305 nallocs++ ;
306 #ifdef GB_DEBUG
307 ok = ok && (A->b_size == GB_Global_memtable_size (A->b)) ;
308 #endif
309 }
310
311 if (A->i != NULL && !A->i_shallow)
312 {
313 nallocs++ ;
314 #ifdef GB_DEBUG
315 ok = ok && (A->i_size == GB_Global_memtable_size (A->i)) ;
316 #endif
317 }
318
319 if (A->x != NULL && !A->x_shallow)
320 {
321 nallocs++ ;
322 #ifdef GB_DEBUG
323 ok = ok && (A->x_size == GB_Global_memtable_size (A->x)) ;
324 #endif
325 }
326
327 if (Pending != NULL)
328 {
329 nallocs++ ;
330 #ifdef GB_DEBUG
331 ok = ok && (Pending->header_size == GB_Global_memtable_size (Pending)) ;
332 #endif
333 }
334
335 if (Pending != NULL && Pending->i != NULL)
336 {
337 nallocs++ ;
338 #ifdef GB_DEBUG
339 ok = ok && (Pending->i_size == GB_Global_memtable_size (Pending->i)) ;
340 #endif
341 }
342
343 if (Pending != NULL && Pending->j != NULL)
344 {
345 nallocs++ ;
346 #ifdef GB_DEBUG
347 ok = ok && (Pending->j_size == GB_Global_memtable_size (Pending->j)) ;
348 #endif
349 }
350
351 if (Pending != NULL && Pending->x != NULL)
352 {
353 nallocs++ ;
354 #ifdef GB_DEBUG
355 ok = ok && (Pending->x_size == GB_Global_memtable_size (Pending->x)) ;
356 #endif
357 }
358
359 #if GB_DEVELOPER
360 if (pr_short || pr_complete)
361 {
362 if (A->static_header)
363 {
364 GBPR (" static header,") ;
365 }
366 else
367 {
368 GBPR (" header %p", A) ;
369 }
370 GBPR (" number of memory blocks: " GBd "\n", nallocs) ;
371 }
372 #endif
373
374 if (!ok)
375 {
376 GBPR0 (" internal memory error\n") ;
377 return (GrB_INVALID_OBJECT) ;
378 }
379
380 //--------------------------------------------------------------------------
381 // check the type
382 //--------------------------------------------------------------------------
383
384 GrB_Info info = GB_Type_check (A->type, "", pr_type, f) ;
385 if (info != GrB_SUCCESS)
386 {
387 GBPR0 (" %s has an invalid type\n", kind) ;
388 return (GrB_INVALID_OBJECT) ;
389 }
390
391 //--------------------------------------------------------------------------
392 // report shallow structure
393 //--------------------------------------------------------------------------
394
395 #if GB_DEVELOPER
396 if (pr_short || pr_complete)
397 {
398 GBPR (" ->h: %p shallow: %d\n", A->h, A->h_shallow) ;
399 GBPR (" ->p: %p shallow: %d\n", A->p, A->p_shallow) ;
400 GBPR (" ->i: %p shallow: %d\n", A->i, A->i_shallow) ;
401 GBPR (" ->b: %p shallow: %d\n", A->b, A->b_shallow) ;
402 GBPR (" ->x: %p shallow: %d\n", A->x, A->x_shallow) ;
403 }
404 #endif
405
406 //--------------------------------------------------------------------------
407 // check p
408 //--------------------------------------------------------------------------
409
410 if (is_hyper || is_sparse)
411 {
412 if (A->p == NULL)
413 {
414 GBPR0 (" ->p is NULL, invalid %s\n", kind) ;
415 return (GrB_INVALID_OBJECT) ;
416 }
417 }
418
419 //--------------------------------------------------------------------------
420 // check a non-empty matrix
421 //--------------------------------------------------------------------------
422
423 bool A_empty = (A->nzmax == 0) ;
424 if (is_hyper || is_sparse)
425 {
426 if (!A_empty && A->i == NULL)
427 {
428 GBPR0 (" ->i is NULL, invalid %s\n", kind) ;
429 return (GrB_INVALID_OBJECT) ;
430 }
431 }
432
433 //--------------------------------------------------------------------------
434 // check the content of p
435 //--------------------------------------------------------------------------
436
437 if (is_hyper || is_sparse)
438 {
439 if (A->p [0] != 0)
440 {
441 GBPR0 (" ->p [0] = " GBd " invalid\n", A->p [0]) ;
442 return (GrB_INVALID_OBJECT) ;
443 }
444
445 for (int64_t j = 0 ; j < A->nvec ; j++)
446 {
447 if (A->p [j+1] < A->p [j] || A->p [j+1] > A->nzmax)
448 {
449 GBPR0 (" ->p [" GBd "] = " GBd " invalid\n", j+1, A->p [j+1]) ;
450 return (GrB_INVALID_OBJECT) ;
451 }
452 }
453 }
454
455 //--------------------------------------------------------------------------
456 // check the content of h
457 //--------------------------------------------------------------------------
458
459 if (is_hyper)
460 {
461 int64_t jlast = -1 ;
462 for (int64_t k = 0 ; k < A->nvec ; k++)
463 {
464 int64_t j = A->h [k] ;
465 if (jlast >= j || j < 0 || j >= A->vdim)
466 {
467 GBPR0 (" ->h [" GBd "] = " GBd " invalid\n", k, j) ;
468 return (GrB_INVALID_OBJECT) ;
469 }
470 jlast = j ;
471 }
472 }
473
474 //--------------------------------------------------------------------------
475 // report name and number of entries
476 //--------------------------------------------------------------------------
477
478 GBPR0 (" ") ;
479 if (name != NULL && strlen (name) > 0)
480 {
481 GBPR0 ("%s, ", ((name != NULL) ? name : "")) ;
482 }
483
484 // # of entries cannot be computed until all the tests above are OK
485 int64_t anz = is_full ? GB_NNZ_FULL (A) : GB_NNZ (A) ;
486 if (anz == 0)
487 {
488 GBPR0 ("no entries\n") ;
489 }
490 else if (anz == 1)
491 {
492 GBPR0 ("1 entry\n") ;
493 }
494 else
495 {
496 GBPR0 ( GBd " entries\n", anz) ;
497 }
498
499 //--------------------------------------------------------------------------
500 // report the number of pending tuples and zombies
501 //--------------------------------------------------------------------------
502
503 if (Pending != NULL || A->nzombies != 0)
504 {
505 GBPR0 (" pending tuples: " GBd " max pending: " GBd
506 " zombies: " GBd "\n", GB_Pending_n (A),
507 (Pending == NULL) ? 0 : (Pending->nmax),
508 A->nzombies) ;
509 }
510
511 if (!ignore_zombies && (A->nzombies < 0 || A->nzombies > anz))
512 {
513 GBPR0 (" invalid number of zombies: " GBd " "
514 "must be >= 0 and <= # entries (" GBd ")\n", A->nzombies, anz) ;
515 return (GrB_INVALID_OBJECT) ;
516 }
517
518 if (is_full || is_bitmap)
519 {
520 if (A->nzombies != 0)
521 {
522 // full/bitmap cannot have zombies
523 GBPR0 (" %s %s cannot have zombies\n",
524 is_full ? "full" : "bitmap", kind) ;
525 return (GrB_INVALID_OBJECT) ;
526 }
527 if (Pending != NULL)
528 {
529 // full/bitmap cannot have pending tuples
530 GBPR0 (" %s %s cannot have pending tuples\n",
531 is_full ? "full" : "bitmap", kind) ;
532 return (GrB_INVALID_OBJECT) ;
533 }
534 if (A->jumbled)
535 {
536 // full/bitmap jumbled
537 GBPR0 (" %s %s cannot be jumbled\n",
538 is_full ? "full" : "bitmap", kind) ;
539 return (GrB_INVALID_OBJECT) ;
540 }
541 }
542
543 //--------------------------------------------------------------------------
544 // check and print the row indices and numerical values
545 //--------------------------------------------------------------------------
546
547 if (anz > 0 && !phantom) GBPR0 ("\n") ;
548
549 #define GB_NBRIEF 10
550 #define GB_NZBRIEF 30
551
552 int64_t nzombies = 0 ;
553 int64_t icount = 0 ;
554 bool truncated = false ;
555 int64_t anz_actual = 0 ;
556
557 // for each vector of A
558 for (int64_t k = 0 ; k < A->nvec ; k++)
559 {
560 if (phantom) break ;
561 int64_t ilast = -1 ;
562 int64_t j = GBH (A->h, k) ;
563 int64_t p = GBP (A->p, k, A->vlen) ;
564 int64_t pend = GBP (A->p, k+1, A->vlen) ;
565
566 // count the entries in A(:,j)
567 int64_t ajnz = pend - p ;
568 if (is_bitmap)
569 {
570 ajnz = 0 ;
571 for (int64_t p2 = p ; p2 < pend ; p2++)
572 {
573 int8_t ab = A->b [p2] ;
574 if (ab < 0 || ab > 1)
575 {
576 // bitmap with value other than 0, 1
577 GBPR0 (" invalid bitmap %d\n", ab) ;
578 return (GrB_INVALID_OBJECT) ;
579 }
580 ajnz += (ab != 0) ;
581 }
582 }
583
584 bool prcol = ((pr_short && !truncated) || pr_complete) ;
585 // print the header for vector j
586 if (prcol)
587 {
588 #if GB_DEVELOPER
589 GBPR (" %s: " GBd " : " GBd " entries [" GBd ":" GBd "]\n",
590 A->is_csc ? "column" : "row", j, ajnz, p, pend-1) ;
591 if (pr_short && k == GB_NBRIEF) truncated = true ;
592 #endif
593 }
594
595 // for each entry in A(:,j), the kth vector of A
596 for ( ; p < pend ; p++)
597 {
598 if (!GBB (A->b, p)) continue ;
599 anz_actual++ ;
600 icount++ ;
601
602 int64_t i = GBI (A->i, p, A->vlen) ;
603 bool is_zombie = GB_IS_ZOMBIE (i) ;
604 i = GB_UNFLIP (i) ;
605 if (is_zombie) nzombies++ ;
606 bool print_value = false ;
607 if (prcol)
608 {
609 if ((pr_short && icount < GB_NZBRIEF) || pr_complete)
610 {
611 print_value = true ;
612 #if GB_DEVELOPER
613 GBPR (" %s " GBd ": ", A->is_csc ? "row":"column", i) ;
614 #else
615 if (A->is_csc)
616 {
617 GBPR (" (" GBd "," GBd ") ", i+offset, j+offset) ;
618 }
619 else
620 {
621 GBPR (" (" GBd "," GBd ") ", j+offset, i+offset) ;
622 }
623 #endif
624 }
625 else if (pr_short && (ilast == -1 || icount == GB_NZBRIEF))
626 {
627 truncated = true ;
628 }
629 }
630 int64_t row = A->is_csc ? i : j ;
631 int64_t col = A->is_csc ? j : i ;
632 if (i < 0 || i >= A->vlen)
633 {
634 GBPR0 (" index (" GBd "," GBd ") out of range\n",
635 row+offset, col+offset) ;
636 return (GrB_INVALID_OBJECT) ;
637 }
638
639 // print the value
640 if (print_value)
641 {
642 if (is_zombie)
643 {
644 GBPR ("zombie") ;
645 }
646 else if (A->x != NULL)
647 {
648 GB_void *Ax = (GB_void *) A->x ;
649 info = GB_entry_check (A->type, Ax +(p * (A->type->size)),
650 pr, f) ;
651 if (info != GrB_SUCCESS) return (info) ;
652 }
653 }
654
655 // If the matrix is known to be jumbled, then out-of-order
656 // indices are OK (but duplicates are not OK). If the matrix is
657 // unjumbled, then all indices must appear in ascending order.
658 if (A->jumbled ? (i == ilast) : (i <= ilast))
659 {
660 // indices unsorted, or duplicates present
661 GBPR0 (" index (" GBd "," GBd ") invalid\n",
662 row+offset, col+offset) ;
663 return (GrB_INDEX_OUT_OF_BOUNDS) ;
664 }
665
666 if (print_value)
667 {
668 GBPR ("\n") ;
669 }
670 ilast = i ;
671 }
672 }
673
674 if (pr_short && truncated) GBPR (" ...\n") ;
675
676 //--------------------------------------------------------------------------
677 // check the entry count in the bitmap
678 //--------------------------------------------------------------------------
679
680 if (is_bitmap && anz != anz_actual)
681 {
682 // bitmap with invalid nvals
683 GBPR0 (" invalid bitmap count: " GBd " exist but"
684 " A->nvals = " GBd "\n", anz_actual, anz) ;
685 return (GrB_INVALID_OBJECT) ;
686 }
687
688 //--------------------------------------------------------------------------
689 // check the zombie count
690 //--------------------------------------------------------------------------
691
692 if (!ignore_zombies && nzombies != A->nzombies)
693 {
694 GBPR0 (" invalid zombie count: " GBd " exist but"
695 " A->nzombies = " GBd "\n", nzombies, A->nzombies) ;
696 return (GrB_INVALID_OBJECT) ;
697 }
698
699 //--------------------------------------------------------------------------
700 // check and print the pending tuples
701 //--------------------------------------------------------------------------
702
703 #if GB_DEVELOPER
704 if ((pr_short || pr_complete) && (is_sparse || is_hyper))
705 {
706 GBPR (" Pending %p\n", Pending) ;
707 }
708 #endif
709
710 if (Pending != NULL)
711 {
712
713 //---------------------------------------------------------------------
714 // A has pending tuples
715 //---------------------------------------------------------------------
716
717 #if GB_DEVELOPER
718 if (pr_short || pr_complete)
719 {
720 GBPR (" Pending->i %p\n", Pending->i) ;
721 GBPR (" Pending->j %p\n", Pending->j) ;
722 GBPR (" Pending->x %p\n", Pending->x) ;
723 }
724 #endif
725
726 if (Pending->n < 0 || Pending->n > Pending->nmax ||
727 Pending->nmax < 0)
728 {
729 GBPR0 (" invalid pending count\n") ;
730 return (GrB_INVALID_OBJECT) ;
731 }
732
733 // matrix has tuples, arrays and type must not be NULL
734 if (Pending->i == NULL || Pending->x == NULL ||
735 (A->vdim > 1 && Pending->j == NULL))
736 {
737 GBPR0 (" invalid pending tuples\n") ;
738 return (GrB_INVALID_OBJECT) ;
739 }
740
741 GBPR0 (" pending tuples:\n") ;
742
743 info = GB_Type_check (Pending->type, "", pr, f) ;
744 if (info != GrB_SUCCESS || (Pending->type->size != Pending->size))
745 {
746 // invalid Pending->type
747 GBPR0 (" %s has an invalid Pending->type\n", kind) ;
748 return (GrB_INVALID_OBJECT) ;
749 }
750
751 int64_t ilast = -1 ;
752 int64_t jlast = -1 ;
753 bool sorted = true ;
754
755 for (int64_t k = 0 ; k < Pending->n ; k++)
756 {
757 int64_t i = Pending->i [k] ;
758 int64_t j = (A->vdim <= 1) ? 0 : (Pending->j [k]) ;
759 int64_t row = A->is_csc ? i : j ;
760 int64_t col = A->is_csc ? j : i ;
761
762 // print the tuple
763 if ((pr_short && k < GB_NZBRIEF) || pr_complete)
764 {
765 GBPR (" row: " GBd " col: " GBd " ", row, col) ;
766 info = GB_entry_check (Pending->type,
767 Pending->x +(k * Pending->type->size), pr, f) ;
768 if (info != GrB_SUCCESS) return (info) ;
769 GBPR ("\n") ;
770 }
771
772 if (i < 0 || i >= A->vlen || j < 0 || j >= A->vdim)
773 {
774 GBPR0 (" tuple (" GBd "," GBd ") out of range\n", row, col) ;
775 return (GrB_INVALID_OBJECT) ;
776 }
777
778 sorted = sorted && ((jlast < j) || (jlast == j && ilast <= i)) ;
779 ilast = i ;
780 jlast = j ;
781 }
782
783 if (sorted != Pending->sorted)
784 {
785 GBPR0 (" invalid pending tuples: invalid sort\n") ;
786 return (GrB_INVALID_OBJECT) ;
787 }
788
789 if (Pending->op == NULL)
790 {
791 GBPR0 (" pending operator: implicit 2nd\n") ;
792 }
793 else
794 {
795 info = GB_BinaryOp_check (Pending->op, "pending operator:", pr, f) ;
796 if (info != GrB_SUCCESS)
797 {
798 GBPR0 (" invalid pending operator\n") ;
799 return (GrB_INVALID_OBJECT) ;
800 }
801 }
802 }
803
804 if (pr_complete)
805 {
806 GBPR ("\n") ;
807 }
808
809 //--------------------------------------------------------------------------
810 // check nvec_nonempty
811 //--------------------------------------------------------------------------
812
813 // A->nvec_nonempty == -1 denotes that the value has not been computed.
814 // This is valid, and can occur for imported matrices and in other cases
815 // when its computation is postponed or not needed. If not -1, however,
816 // the value must be correct.
817
818 int64_t actual_nvec_nonempty = GB_nvec_nonempty (A, NULL) ;
819
820 if (! ((A->nvec_nonempty == actual_nvec_nonempty) ||
821 (A->nvec_nonempty == -1)))
822 {
823 // invalid nvec_nonempty
824 GBPR0 (" invalid count of non-empty vectors\n") ;
825 return (GrB_INVALID_OBJECT) ;
826 }
827
828 //--------------------------------------------------------------------------
829 // return result
830 //--------------------------------------------------------------------------
831
832 return (GrB_SUCCESS) ;
833 }
834
835