• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

dance858 / PSLP / 22279069886

22 Feb 2026 02:32PM UTC coverage: 89.311% (+0.3%) from 89.013%
22279069886

Pull #38

github

web-flow
Merge bae50547e into e13878911
Pull Request #38: [WIP] Speedup

1281 of 1432 branches covered (89.46%)

Branch coverage included in aggregate %.

181 of 193 new or added lines in 10 files covered. (93.78%)

67 existing lines in 7 files now uncovered.

3983 of 4462 relevant lines covered (89.26%)

6008.65 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.26
/src/core/Debugger.c
1
/*
2
 * Copyright 2025 Daniel Cederberg
3
 *
4
 * This file is part of the PSLP project (LP Presolver).
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 *     http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18

19
#include "Debugger.h"
20
#include "Activity.h"
21
#include "Bounds.h"
22
#include "Constraints.h"
23
#include "Locks.h"
24
#include "Matrix.h"
25
#include "Numerics.h"
26
#include "PSLP_stats.h"
27
#include "State.h"
28
#include "glbopts.h"
29
#include <assert.h>
30
#include <stdio.h>
31

32
#ifdef __has_include
33
#if __has_include(<valgrind/valgrind.h>)
34
#include <valgrind/valgrind.h>
35
#else
36
#define RUNNING_ON_VALGRIND 0
37
#endif
38
#else
39
#include <valgrind/valgrind.h> // fallback
40
#endif
41

42
void run_debugger(const Constraints *constraints, bool finished)
302✔
43
{
44
    verify_activities(constraints);
302✔
45
    verify_row_and_col_sizes(constraints);
302✔
46
    verify_empty_rows(constraints);
302✔
47
    verify_ston_rows(constraints);
302✔
48
    verify_doubleton_rows(constraints);
302✔
49
    verify_empty_cols(constraints);
302✔
50
    verify_ston_cols(constraints);
302✔
51
    verify_no_duplicates_lists(constraints->state);
302✔
52
    verify_A_and_AT(constraints, false);
302✔
53
    verify_locks(constraints->AT, constraints->state->col_locks,
302✔
54
                 constraints->col_tags, constraints->row_tags);
302✔
55
    verify_row_tags(constraints);
302✔
56

57
    if (finished)
302✔
58
    {
59
        verify_empty_when_finished(constraints);
20✔
60
        verify_A_and_AT(constraints, true);
20✔
61
    }
62
}
302✔
63

64
int ASSERT_NO_ZEROS_D(const double *x, size_t len)
104✔
65
{
66
    for (size_t i = 0; i < len; ++i)
400,752✔
67
    {
68
        assert(x[i] != 0);
400,648✔
69
    }
70

71
    return 0;
104✔
72
}
73

UNCOV
74
void print_int_array(const int *arr, size_t len)
×
75
{
UNCOV
76
    for (size_t i = 0; i < len; ++i)
×
77
    {
UNCOV
78
        printf("%d ", arr[i]);
×
79
    }
80
    printf("\n");
×
UNCOV
81
}
×
82

UNCOV
83
void print_double_array(const double *arr, size_t len)
×
84
{
UNCOV
85
    for (size_t i = 0; i < len; ++i)
×
86
    {
UNCOV
87
        printf("%f ", arr[i]);
×
88
    }
89
    printf("\n");
×
UNCOV
90
}
×
91

92
void verify_empty_rows(const Constraints *constraints)
302✔
93
{
94
    const iVec *empty_rows = constraints->state->empty_rows;
302✔
95
    const int *row_sizes = constraints->state->row_sizes;
302✔
96
    size_t n_rows = constraints->m;
302✔
97
    char *lookup = ps_calloc(n_rows, sizeof(char));
302✔
98

99
    // verify that all appended rows are empty rows
100
    for (size_t i = 0; i < empty_rows->len; ++i)
304✔
101
    {
102
        assert(row_sizes[empty_rows->data[i]] == 0);
2✔
103
        lookup[empty_rows->data[i]] = 1;
2✔
104
    }
105

106
    // verify that all empty rows have been appended using a look-up
107
    // table
108
    for (size_t i = 0; i < n_rows; i++)
1,590✔
109
    {
110
        if (row_sizes[i] == 0)
1,288✔
111
        {
112
            assert(lookup[i]);
2✔
113
        }
114
    }
115

116
    PS_FREE(lookup);
302✔
117
}
302✔
118

119
void verify_empty_cols(const Constraints *constraints)
302✔
120
{
121
    const iVec *empty_cols = constraints->state->empty_cols;
302✔
122
    const int *col_sizes = constraints->state->col_sizes;
302✔
123
    size_t n_cols = constraints->n;
302✔
124
    char *lookup = ps_calloc(n_cols, sizeof(char));
302✔
125

126
    // verify that all appended columns are empty columns
127
    for (size_t i = 0; i < empty_cols->len; ++i)
329✔
128
    {
129
        assert(col_sizes[empty_cols->data[i]] == 0);
27✔
130
        lookup[empty_cols->data[i]] = 1;
27✔
131
    }
132

133
    // verify that all empty rows have been appended using a look-up
134
    // table
135
    for (size_t i = 0; i < n_cols; i++)
1,868✔
136
    {
137
        if (col_sizes[i] == 0)
1,566✔
138
        {
139
            assert(lookup[i]);
27✔
140
        }
141
    }
142

143
    PS_FREE(lookup);
302✔
144
}
302✔
145

146
void verify_ston_cols(const Constraints *constraints)
302✔
147
{
148
    const iVec *ston_cols = constraints->state->ston_cols;
302✔
149
    const int *col_sizes = constraints->state->col_sizes;
302✔
150
    size_t n_cols = constraints->n;
302✔
151
    char *lookup = ps_calloc(n_cols, sizeof(char));
302✔
152

153
    // verify that all appended columns are ston columns or
154
    // empty/inactive
155
    for (size_t i = 0; i < ston_cols->len; ++i)
460✔
156
    {
157
        assert(col_sizes[ston_cols->data[i]] <= 1);
158✔
158
        lookup[ston_cols->data[i]] = 1;
158✔
159
    }
160

161
    // verify that all ston columns have been appended using a look-up
162
    // table
163
    for (size_t i = 0; i < constraints->n; i++)
1,868✔
164
    {
165
        if (col_sizes[i] == 1)
1,566✔
166
        {
167
            assert(lookup[i]);
156✔
168
        }
169
    }
170

171
    PS_FREE(lookup);
302✔
172
}
302✔
173

174
void verify_ston_rows(const Constraints *constraints)
302✔
175
{
176
    const iVec *ston_rows = constraints->state->ston_rows;
302✔
177
    const int *row_sizes = constraints->state->row_sizes;
302✔
178
    size_t n_rows = constraints->m;
302✔
179
    char *lookup = ps_calloc(n_rows, sizeof(char));
302✔
180

181
    // verify that all appended rows are empty rows
182
    for (size_t i = 0; i < ston_rows->len; ++i)
344✔
183
    {
184
        // if (!colTag.compare(ColTag::kFixed))??
185
        assert(row_sizes[ston_rows->data[i]] == 1);
42✔
186
        lookup[ston_rows->data[i]] = 1;
42✔
187
    }
188

189
    // verify that all ston rows have been appended using a look-up
190
    // table
191
    for (size_t i = 0; i < n_rows; i++)
1,590✔
192
    {
193
        if (row_sizes[i] == 1)
1,288✔
194
        {
195
            assert(lookup[i]);
42✔
196
        }
197
    }
198

199
    PS_FREE(lookup);
302✔
200
}
302✔
201

202
void verify_doubleton_rows(const Constraints *constraints)
302✔
203
{
204
    const iVec *doubleton_rows = constraints->state->dton_rows;
302✔
205
    const int *row_sizes = constraints->state->row_sizes;
302✔
206
    RowTag *row_tags = constraints->row_tags;
302✔
207
    size_t n_rows = constraints->m;
302✔
208
    char *lookup = ps_calloc(n_rows, sizeof(char));
302✔
209

210
    // verify that all appended rows have either size 2 and are equality rows,
211
    // or they have been reduced to size 1 or less
212
    for (size_t i = 0; i < doubleton_rows->len; ++i)
368✔
213
    {
214
        lookup[doubleton_rows->data[i]] = 1;
66✔
215
        assert(row_sizes[doubleton_rows->data[i]] <= 2);
66✔
216
        bool condition = HAS_TAG(row_tags[doubleton_rows->data[i]],
132✔
217
                                 (R_TAG_EQ | R_TAG_INACTIVE)) ||
66✔
UNCOV
218
                         row_sizes[doubleton_rows->data[i]] < 2;
×
219

220
        if (!condition)
66✔
221
        {
222
            printf("row_tags[%d] = %d\n", doubleton_rows->data[i],
×
223
                   row_tags[doubleton_rows->data[i]]);
×
224
            printf("row_sizes[%d] = %d\n", doubleton_rows->data[i],
×
UNCOV
225
                   row_sizes[doubleton_rows->data[i]]);
×
226
        }
227

228
        assert(condition);
66✔
229
    }
230

231
    // verify that all dton rows have been appended using a look-up
232
    // table
233
    for (size_t i = 0; i < n_rows; i++)
1,590✔
234
    {
235
        if (row_sizes[i] == 2 && HAS_TAG(row_tags[i], R_TAG_EQ))
1,288✔
236
        {
237
            assert(lookup[i]);
66✔
238
        }
239
    }
240

241
    PS_FREE(lookup);
302✔
242
}
302✔
243

244
// Comparison function for qsort
245
static int compare_ints(const void *a, const void *b)
1,404✔
246
{
247
    return (*(int *) a - *(int *) b);
1,404✔
248
}
249

UNCOV
250
void verify_no_duplicates(const iVec *vec)
×
251
{
UNCOV
252
    for (size_t i = 0; i < vec->len; ++i)
×
253
    {
UNCOV
254
        for (size_t j = i + 1; j < vec->len; ++j)
×
255
        {
UNCOV
256
            assert(vec->data[i] != vec->data[j]);
×
257
        }
258
    }
UNCOV
259
}
×
260

261
void verify_no_duplicates_sort_ptr(const int *data, size_t len)
2,226✔
262
{
263
    if (len == 0)
2,226✔
264
    {
265
        return;
1,734✔
266
    }
267

268
    int *temp = (int *) ps_malloc(len, sizeof(int));
492✔
269
    memcpy(temp, data, len * sizeof(int));
492✔
270
    qsort(temp, len, sizeof(int), compare_ints);
492✔
271

272
    for (size_t i = 0; i < len - 1; ++i)
1,323✔
273
    {
274
        assert(temp[i] >= 0);
831✔
275
        assert(temp[i] != temp[i + 1]);
831✔
276
    }
277

278
    PS_FREE(temp);
492✔
279
}
280

281
void verify_no_duplicates_sort(const iVec *vec)
2,197✔
282
{
283
    verify_no_duplicates_sort_ptr(vec->data, vec->len);
2,197✔
284
}
2,197✔
285

UNCOV
286
void verify_no_duplicates_ptr(const int *data, size_t len)
×
287
{
UNCOV
288
    for (size_t i = 0; i < len; ++i)
×
289
    {
UNCOV
290
        for (size_t j = i + 1; j < len; ++j)
×
291
        {
UNCOV
292
            assert(data[i] != data[j]);
×
293
        }
294
    }
UNCOV
295
}
×
296

297
void verify_nonnegative_iVec(const iVec *vec)
1,812✔
298
{
299
    for (size_t i = 0; i < vec->len; ++i)
2,733✔
300
    {
301
        assert(vec->data[i] >= 0);
921✔
302
    }
303
}
1,812✔
304

305
void verify_no_duplicates_lists(const State *data)
302✔
306
{
307
    verify_nonnegative_iVec(data->updated_activities);
302✔
308
    verify_nonnegative_iVec(data->dton_rows);
302✔
309
    verify_nonnegative_iVec(data->ston_rows);
302✔
310
    verify_nonnegative_iVec(data->fixed_cols_to_delete);
302✔
311
    verify_nonnegative_iVec(data->sub_cols_to_delete);
302✔
312
    verify_nonnegative_iVec(data->rows_to_delete);
302✔
313

314
    verify_no_duplicates_sort(data->updated_activities);
302✔
315
    verify_no_duplicates_sort(data->dton_rows);
302✔
316
    verify_no_duplicates_sort(data->ston_rows);
302✔
317
    verify_no_duplicates_sort(data->fixed_cols_to_delete);
302✔
318
    verify_no_duplicates_sort(data->sub_cols_to_delete);
302✔
319
    verify_no_duplicates_sort(data->rows_to_delete);
302✔
320
}
302✔
321

322
void verify_row_tags(const Constraints *constraints)
302✔
323
{
324
    const RowTag *row_tags = constraints->row_tags;
302✔
325
    const double *lhs = constraints->lhs;
302✔
326
    const double *rhs = constraints->rhs;
302✔
327

328
    for (int i = 0; i < constraints->m; ++i)
1,590✔
329
    {
330
        if (IS_NEG_INF(lhs[i]) && !HAS_TAG(row_tags[i], R_TAG_INACTIVE))
1,288✔
331
        {
332
            assert(HAS_TAG(row_tags[i], R_TAG_LHS_INF));
598✔
333
        }
334

335
        if (IS_POS_INF(rhs[i]) && !HAS_TAG(row_tags[i], R_TAG_INACTIVE))
1,288✔
336
        {
337
            assert(HAS_TAG(row_tags[i], R_TAG_RHS_INF));
136✔
338
        }
339

340
        if (HAS_TAG(row_tags[i], R_TAG_LHS_INF))
1,288✔
341
        {
342
            assert(IS_NEG_INF(lhs[i]));
646✔
343
        }
344

345
        if (HAS_TAG(row_tags[i], R_TAG_RHS_INF))
1,288✔
346
        {
347
            assert(IS_POS_INF(rhs[i]));
154✔
348
        }
349

350
        if (!HAS_TAG(row_tags[i], R_TAG_LHS_INF) &&
1,288✔
351
            !HAS_TAG(row_tags[i], R_TAG_RHS_INF) && lhs[i] == rhs[i])
642✔
352
        {
353
            assert(HAS_TAG(row_tags[i], (R_TAG_EQ | R_TAG_INACTIVE)));
435✔
354
        }
355
    }
356
}
302✔
357

358
static void verify_CSR_matrix(const Matrix *A, bool compressed)
644✔
359
{
360
    size_t i, nnz;
361
    int j;
362

363
    assert(A->n_alloc >= A->nnz);
644✔
364

365
    if (A->nnz > 0)
644✔
366
    {
367
        assert(A->i != NULL && A->x != NULL && A->p != NULL);
616✔
368
    }
369
    // verify that row ranges are ascending
370
    for (i = 0; i < A->m; ++i)
3,659✔
371
    {
372
        assert(A->p[i + 1].start >= A->p[i].end && A->p[i].end >= A->p[i].start);
3,015✔
373
    }
374

375
    // verify that columns within a row are sorted
376
    for (i = 0; i < A->m; ++i)
3,659✔
377
    {
378
        for (j = A->p[i].start + 1; j < A->p[i].end; ++j)
8,857✔
379
        {
380
            assert(A->i[j] > A->i[j - 1]);
5,842✔
381
        }
382
    }
383

384
    // verify that no explicit zeros are stored are that nnz count is correct
385
    nnz = 0;
644✔
386
    for (i = 0; i < A->m; ++i)
3,659✔
387
    {
388
        for (j = A->p[i].start; j < A->p[i].end; ++j)
11,603✔
389
        {
390
            assert(A->x[j] != 0);
8,588✔
391
        }
392

393
        nnz += (size_t) (A->p[i].end - A->p[i].start);
3,015✔
394
    }
395

396
    assert(nnz == A->nnz);
644✔
397

398
    if (compressed)
644✔
399
    {
400
        assert(A->p[A->m].start == A->nnz);
40✔
401
        assert(A->p[A->m].end == A->nnz);
40✔
402
        assert(A->p[0].start == 0);
40✔
403
    }
404
}
644✔
405

406
bool verify_A_and_AT_consistency(const Matrix *A, const Matrix *AT)
347✔
407
{
408
    int *work_n_cols = (int *) ps_malloc(A->n, sizeof(int));
347✔
409
    Matrix *real_AT = transpose(A, work_n_cols);
347✔
410

411
    // check that nnz and dimensions are consistent
412
    assert(real_AT->m == AT->m);
347✔
413
    assert(real_AT->n == AT->n);
347✔
414
    assert(real_AT->nnz == AT->nnz);
347✔
415

416
    size_t i;
417
    int j, k, start_AT, end_AT, start_real_AT, end_real_AT;
418

419
    // check that values are consistent
420
    for (i = 0; i < AT->m; ++i)
2,104✔
421
    {
422
        start_AT = AT->p[i].start;
1,757✔
423
        end_AT = AT->p[i].end;
1,757✔
424
        start_real_AT = real_AT->p[i].start;
1,757✔
425
        end_real_AT = real_AT->p[i].end;
1,757✔
426

427
        assert(end_AT - start_AT == end_real_AT - start_real_AT);
1,757✔
428

429
        for (j = start_AT, k = start_real_AT; j < end_AT; ++j, ++k)
6,390✔
430
        {
431
            assert(!IS_ABS_INF(AT->x[j]) && !IS_ABS_INF(real_AT->x[k]));
4,633✔
432
            if (AT->x[j] != real_AT->x[k] || AT->i[j] != real_AT->i[k])
4,633✔
433
            {
434
                PS_FREE(work_n_cols);
×
435
                free_matrix(real_AT);
×
436
                return false;
×
437
            }
438
        }
439
    }
440

441
    PS_FREE(work_n_cols);
347✔
442
    free_matrix(real_AT);
347✔
443
    return true;
347✔
444
}
445

446
static void verify_no_inactive_cols(const Matrix *A, ColTag *col_tags)
644✔
447
{
448
    int start, end, j;
449
    size_t i;
450
    for (i = 0; i < A->m; ++i)
3,659✔
451
    {
452
        start = A->p[i].start;
3,015✔
453
        end = A->p[i].end;
3,015✔
454

455
        for (j = start; j < end; ++j)
11,603✔
456
        {
457
            assert(!HAS_TAG(col_tags[A->i[j]], C_TAG_INACTIVE));
8,588✔
458
        }
459
    }
460
}
644✔
461

462
void verify_A_and_AT(const Constraints *constraints, bool compressed)
322✔
463
{
464
    const Matrix *A = constraints->A;
322✔
465
    const Matrix *AT = constraints->AT;
322✔
466

467
    // verify that both A and AT are valid CSR matrices
468
    verify_CSR_matrix(A, compressed);
322✔
469
    verify_CSR_matrix(AT, compressed);
322✔
470

471
    // verify that A and AT are consistent
472
    assert(verify_A_and_AT_consistency(A, AT));
322✔
473

474
    // verify that A does not store the coefficients of inactive columns
475
    verify_no_inactive_cols(A, constraints->col_tags);
322✔
476

477
    // verify that AT does not store the coefficients of inactive rows
478
    verify_no_inactive_cols(AT, constraints->row_tags);
322✔
479
}
322✔
480

481
void verify_locks(const Matrix *AT, const Lock *locks, const ColTag *col_tags,
302✔
482
                  const RowTag *row_tags)
483
{
484
    int up, down, i, row;
485
    size_t n_cols, col;
486
    n_cols = AT->m;
302✔
487
    double Aik;
488

489
    for (col = 0; col < n_cols; ++col)
1,868✔
490
    {
491
        if (HAS_TAG(col_tags[col], C_TAG_INACTIVE))
1,566✔
492
        {
493
            continue;
112✔
494
        }
495

496
        up = 0;
1,454✔
497
        down = 0;
1,454✔
498

499
        for (i = AT->p[col].start; i < AT->p[col].end; ++i)
5,513✔
500
        {
501
            row = AT->i[i];
4,059✔
502
            Aik = AT->x[i];
4,059✔
503

504
            if ((Aik > 0 && !HAS_TAG(row_tags[row], R_TAG_RHS_INF)) ||
4,059✔
505
                (Aik < 0 && !HAS_TAG(row_tags[row], R_TAG_LHS_INF)))
1,006✔
506
            {
507
                up++;
3,270✔
508
            }
509

510
            if ((Aik > 0 && !HAS_TAG(row_tags[row], R_TAG_LHS_INF)) ||
4,059✔
511
                (Aik < 0 && !HAS_TAG(row_tags[row], R_TAG_RHS_INF)))
1,006✔
512
            {
513
                down++;
2,554✔
514
            }
515
        }
516

517
        assert(up == locks[col].up);
1,454✔
518
        assert(down == locks[col].down);
1,454✔
519
    }
520
}
302✔
521

522
void verify_empty_when_finished(const Constraints *constraints)
20✔
523
{
524
    assert(constraints->state->empty_cols->len == 0);
20✔
525
    assert(constraints->state->empty_rows->len == 0);
20✔
526
    assert(constraints->state->rows_to_delete->len == 0);
20✔
527
    assert(constraints->state->fixed_cols_to_delete->len == 0);
20✔
528
    assert(constraints->state->sub_cols_to_delete->len == 0);
20✔
529

530
    for (int i = 0; i < constraints->A->m; ++i)
83✔
531
    {
532
        assert(!HAS_TAG(constraints->row_tags[i], R_TAG_INACTIVE));
63✔
533
    }
534

535
    for (int i = 0; i < constraints->A->n; ++i)
118✔
536
    {
537
        assert(!HAS_TAG(constraints->col_tags[i], C_TAG_INACTIVE));
98✔
538
    }
539
}
20✔
540

541
void verify_row_and_col_sizes(const Constraints *constraints)
302✔
542
{
543
    const int *row_sizes = constraints->state->row_sizes;
302✔
544
    const int *col_sizes = constraints->state->col_sizes;
302✔
545
    const Matrix *A = constraints->A;
302✔
546
    const Matrix *AT = constraints->AT;
302✔
547
    const ColTag *col_tags = constraints->col_tags;
302✔
548
    const RowTag *row_tags = constraints->row_tags;
302✔
549
    int i;
550

551
    // check that row sizes are correct
552
    for (i = 0; i < constraints->A->m; ++i)
1,590✔
553
    {
554
        if (HAS_TAG(row_tags[i], R_TAG_INACTIVE))
1,288✔
555
        {
556
            assert(row_sizes[i] == SIZE_INACTIVE_ROW);
128✔
557
            assert(A->p[i].start == A->p[i].end);
128✔
558
        }
559
        else
560
        {
561
            assert(row_sizes[i] == A->p[i].end - A->p[i].start);
1,160✔
562
        }
563

564
        if (row_sizes[i] == SIZE_INACTIVE_ROW)
1,288✔
565
        {
566
            assert(HAS_TAG(row_tags[i], R_TAG_INACTIVE));
128✔
567
        }
568
    }
569

570
    // check that column sizes are correct
571
    for (i = 0; i < constraints->A->n; ++i)
1,868✔
572
    {
573
        if (HAS_TAG(col_tags[i], C_TAG_INACTIVE))
1,566✔
574
        {
575
            if (col_sizes[i] != SIZE_INACTIVE_COL)
112✔
576
            {
577
                printf("col_sizes[%d] = %d\n", i, col_sizes[i]);
×
578
            }
579

580
            assert(col_sizes[i] == SIZE_INACTIVE_COL);
112✔
581
            if (AT->p[i].start != AT->p[i].end)
112✔
582
            {
583
                printf("AT->p[%d].start = %d\n", i, AT->p[i].start);
×
584
                printf("AT->p[%d].end = %d\n", i, AT->p[i].end);
×
585
            }
586
            assert(AT->p[i].start == AT->p[i].end);
112✔
587
        }
588
        else
589
        {
590
            assert(col_sizes[i] == AT->p[i].end - AT->p[i].start);
1,454✔
591
        }
592

593
        if (col_sizes[i] == SIZE_INACTIVE_COL)
1,566✔
594
        {
595
            assert(HAS_TAG(col_tags[i], C_TAG_INACTIVE));
112✔
596
        }
597
    }
598
}
302✔
599

600
void verify_activity(const ColTag *col_tags, const Bound *bounds, Activity activity,
1,486✔
601
                     RowTag row_tag, const int *cols, const double *vals, int len)
602
{
603
    int n_inf_min = 0;
1,486✔
604
    int n_inf_max = 0;
1,486✔
605
    double min = 0.0;
1,486✔
606
    double max = 0.0;
1,486✔
607
    int i, col;
608

609
    if (HAS_TAG(row_tag, R_TAG_INACTIVE))
1,486✔
610
    {
611
        return;
185✔
612
    }
613

614
    // count the infinite contributions
615
    for (i = 0; i < len; ++i)
5,909✔
616
    {
617
        col = cols[i];
4,608✔
618
        if (HAS_TAG(col_tags[col], C_TAG_INACTIVE))
4,608✔
619
        {
620
            continue;
×
621
        }
622

623
        if (vals[i] > 0)
4,608✔
624
        {
625
            if (HAS_TAG(col_tags[col], C_TAG_UB_INF))
3,443✔
626
            {
627
                n_inf_max++;
1,705✔
628
            }
629

630
            if (HAS_TAG(col_tags[col], C_TAG_LB_INF))
3,443✔
631
            {
632
                n_inf_min++;
193✔
633
            }
634
        }
635
        else
636
        {
637
            if (HAS_TAG(col_tags[col], C_TAG_LB_INF))
1,165✔
638
            {
639
                n_inf_max++;
56✔
640
            }
641

642
            if (HAS_TAG(col_tags[col], C_TAG_UB_INF))
1,165✔
643
            {
644
                n_inf_min++;
503✔
645
            }
646
        }
647
    }
648

649
    assert(n_inf_max == activity.n_inf_max);
1,301✔
650
    assert(n_inf_min == activity.n_inf_min);
1,301✔
651

652
    // if there is a max infinite contribution, the max activity should be
653
    // INVALID_ACT_DEBUG
654
    if (n_inf_max > 0)
1,301✔
655
    {
656
        if (activity.max != INVALID_ACT_DEBUG)
760✔
657
        {
658
            printf("n_inf_max = %d\n", n_inf_max);
×
659
            printf("activity.max = %f\n", activity.max);
×
660
        }
661
        assert(activity.max == INVALID_ACT_DEBUG);
760✔
662
    }
663
    else
664
    {
665
        // count max activity
666
        for (i = 0; i < len; ++i)
2,757✔
667
        {
668
            col = cols[i];
2,216✔
669
            if (HAS_TAG(col_tags[col], C_TAG_INACTIVE))
2,216✔
670
            {
671
                continue;
×
672
            }
673

674
            if (vals[i] > 0)
2,216✔
675
            {
676
                assert(!HAS_TAG(col_tags[col], C_TAG_UB_INF) &&
1,535✔
677
                       !IS_POS_INF(bounds[col].ub));
678
                max += vals[i] * bounds[col].ub;
1,535✔
679
            }
680
            else
681
            {
682
                assert(!HAS_TAG(col_tags[col], C_TAG_LB_INF) &&
681✔
683
                       !IS_NEG_INF(bounds[col].lb));
684
                max += vals[i] * bounds[col].lb;
681✔
685
            }
686
        }
687
        assert(ABS(activity.max - max) < 1e-6);
541✔
688
    }
689

690
    // if there is a min infinite contribution, the min activity should be
691
    // INVALID_ACT_DEBUG
692
    if (n_inf_min > 0)
1,301✔
693
    {
694
        assert(activity.min == INVALID_ACT_DEBUG);
431✔
695
    }
696
    else
697
    {
698
        // count min activity
699
        for (i = 0; i < len; ++i)
3,873✔
700
        {
701
            col = cols[i];
3,003✔
702
            if (HAS_TAG(col_tags[col], C_TAG_INACTIVE))
3,003✔
703
            {
704
                continue;
×
705
            }
706

707
            if (vals[i] > 0)
3,003✔
708
            {
709
                assert(!HAS_TAG(col_tags[col], C_TAG_LB_INF) &&
2,363✔
710
                       !IS_NEG_INF(bounds[col].lb));
711
                min += vals[i] * bounds[col].lb;
2,363✔
712
            }
713
            else
714
            {
715
                assert(!HAS_TAG(col_tags[col], C_TAG_UB_INF) &&
640✔
716
                       !IS_POS_INF(bounds[col].ub));
717
                min += vals[i] * bounds[col].ub;
640✔
718
            }
719
        }
720

721
        assert(ABS(activity.min - min) < 1e-6);
870✔
722
    }
723
}
724

725
void verify_activities(const Constraints *constraints)
345✔
726
{
727
    size_t n_rows = constraints->m;
345✔
728
    const Activity *activities = constraints->state->activities;
345✔
729
    const RowTag *row_tags = constraints->row_tags;
345✔
730
    const RowRange *row_ranges = constraints->A->p;
345✔
731
    const int *cols = constraints->A->i;
345✔
732
    const double *vals = constraints->A->x;
345✔
733

734
    for (size_t i = 0; i < n_rows; ++i)
1,831✔
735
    {
736
        verify_activity(constraints->col_tags, constraints->bounds, activities[i],
1,486✔
737
                        row_tags[i], cols + row_ranges[i].start,
1,486✔
738
                        vals + row_ranges[i].start,
1,486✔
739
                        row_ranges[i].end - row_ranges[i].start);
1,486✔
740
    }
741
}
345✔
742

743
void ASSERT_NO_ACTIVE_STON_ROWS(const Matrix *A, const RowTag *row_tags)
50✔
744
{
745
    for (int i = 0; i < A->m; ++i)
2,239✔
746
    {
747
        assert(A->p[i].end - A->p[i].start != 1 ||
2,189✔
748
               HAS_TAG(row_tags[i], R_TAG_INACTIVE));
749
    }
750
}
50✔
751

752
int ASSERT_INCREASING_I(const int *x, size_t len)
70✔
753
{
754
    for (size_t i = 1; i < len; ++i)
218✔
755
    {
756
        assert(x[i] > x[i - 1]);
148✔
757
    }
758

759
    return 0;
70✔
760
}
761

762
void print_matrix(const Matrix *A)
×
763
{
764
    for (int i = 0; i < A->m; i++)
×
765
    {
766
        int k = A->p[i].start;
×
767

768
        for (int j = 0; j < A->n; j++)
×
769
        {
770
            if (k < A->p[i].end && A->i[k] == j)
×
771
            {
772
                printf("%6.2f ", A->x[k]);
×
773
                k++;
×
774
            }
775
            else
776
            {
777
                printf("%6.2f ", 0.0);
×
778
            }
779
        }
780
        printf("\n");
×
781
    }
782
}
×
783

784
void verify_problem_up_to_date(const Constraints *constraints)
617✔
785
{
786
    assert(constraints->state->rows_to_delete->len == 0);
617✔
787
    assert(constraints->state->fixed_cols_to_delete->len == 0);
617✔
788
    assert(constraints->state->sub_cols_to_delete->len == 0);
617✔
789
}
617✔
790

791
void verify_row_states(const Activity *acts, const iVec *updated_activities)
25✔
792
{
793
    for (int i = 0; i < updated_activities->len; ++i)
94✔
794
    {
795
        int row = updated_activities->data[i];
69✔
796
        assert(acts[row].status == ADDED);
69✔
797
        assert(acts[row].n_inf_min == 0 || acts[row].n_inf_max == 0);
69✔
798
    }
799
}
25✔
800

801
void run_debugger_stats_consistency_check(const PresolveStats *stats)
20✔
802
{
803
    size_t total_removed = stats->nnz_removed_trivial + stats->nnz_removed_fast +
20✔
804
                           stats->nnz_removed_primal_propagation +
20✔
805
                           stats->nnz_removed_parallel_rows +
20✔
806
                           stats->nnz_removed_parallel_cols;
20✔
807

808
    assert(stats->nnz_original - stats->nnz_reduced == total_removed);
20✔
809

810
    // valgrind timing is not reliable
811
#ifndef RUNNING_ON_VALGRIND
812
    double time_medium = stats->ps_time_primal_propagation +
813
                         stats->ps_time_parallel_rows + stats->ps_time_parallel_cols;
814
    assert((stats->ps_time_medium - time_medium) / MAX(1e-2, time_medium) < 0.05);
815
#endif
816
}
20✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc