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

dance858 / PSLP / 22554559561

01 Mar 2026 10:42PM UTC coverage: 89.547% (+0.5%) from 89.013%
22554559561

Pull #38

github

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

1272 of 1418 branches covered (89.7%)

Branch coverage included in aggregate %.

274 of 294 new or added lines in 12 files covered. (93.2%)

2 existing lines in 1 file now uncovered.

3962 of 4427 relevant lines covered (89.5%)

6004.62 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 <stdio.h>
30

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

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

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

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

70
    return 0;
104✔
71
}
72

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

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

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

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

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

115
    PS_FREE(lookup);
301✔
116
}
301✔
117

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

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

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

142
    PS_FREE(lookup);
301✔
143
}
301✔
144

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

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

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

170
    PS_FREE(lookup);
301✔
171
}
301✔
172

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

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

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

198
    PS_FREE(lookup);
301✔
199
}
301✔
200

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

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

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

227
        PSLP_ASSERT(condition);
66✔
228
    }
229

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

240
    PS_FREE(lookup);
301✔
241
}
301✔
242

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

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

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

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

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

277
    PS_FREE(temp);
491✔
278
}
279

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

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

296
void verify_nonnegative_iVec(const iVec *vec)
1,806✔
297
{
298
    for (size_t i = 0; i < vec->len; ++i)
2,726✔
299
    {
300
        PSLP_ASSERT(vec->data[i] >= 0);
920✔
301
    }
302
}
1,806✔
303

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

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

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

327
    for (int i = 0; i < constraints->m; ++i)
1,586✔
328
    {
329
        if (IS_NEG_INF(lhs[i]) && !HAS_TAG(row_tags[i], R_TAG_INACTIVE))
1,285✔
330
        {
331
            PSLP_ASSERT(HAS_TAG(row_tags[i], R_TAG_LHS_INF));
596✔
332
        }
333

334
        if (IS_POS_INF(rhs[i]) && !HAS_TAG(row_tags[i], R_TAG_INACTIVE))
1,285✔
335
        {
336
            PSLP_ASSERT(HAS_TAG(row_tags[i], R_TAG_RHS_INF));
135✔
337
        }
338

339
        if (HAS_TAG(row_tags[i], R_TAG_LHS_INF))
1,285✔
340
        {
341
            PSLP_ASSERT(IS_NEG_INF(lhs[i]));
644✔
342
        }
343

344
        if (HAS_TAG(row_tags[i], R_TAG_RHS_INF))
1,285✔
345
        {
346
            PSLP_ASSERT(IS_POS_INF(rhs[i]));
153✔
347
        }
348

349
        if (!HAS_TAG(row_tags[i], R_TAG_LHS_INF) &&
1,285✔
350
            !HAS_TAG(row_tags[i], R_TAG_RHS_INF) && lhs[i] == rhs[i])
641✔
351
        {
352
            PSLP_ASSERT(HAS_TAG(row_tags[i], (R_TAG_EQ | R_TAG_INACTIVE)));
435✔
353
        }
354
    }
355
}
301✔
356

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

362
    PSLP_ASSERT(A->n_alloc >= A->nnz);
642✔
363

364
    if (A->nnz > 0)
642✔
365
    {
366
        PSLP_ASSERT(A->i != NULL && A->x != NULL && A->p != NULL);
614✔
367
    }
368
    // verify that row ranges are ascending
369
    for (i = 0; i < A->m; ++i)
3,650✔
370
    {
371
        PSLP_ASSERT(A->p[i + 1].start >= A->p[i].end && A->p[i].end >= A->p[i].start);
3,008✔
372
    }
373

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

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

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

395
    PSLP_ASSERT(nnz == A->nnz);
642✔
396

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

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

410
    // check that nnz and dimensions are consistent
411
    PSLP_ASSERT(real_AT->m == AT->m);
346✔
412
    PSLP_ASSERT(real_AT->n == AT->n);
346✔
413
    PSLP_ASSERT(real_AT->nnz == AT->nnz);
346✔
414

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

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

426
        PSLP_ASSERT(end_AT - start_AT == end_real_AT - start_real_AT);
1,753✔
427

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

440
    PS_FREE(work_n_cols);
346✔
441
    free_matrix(real_AT);
346✔
442
    return true;
346✔
443
}
444

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

454
        for (j = start; j < end; ++j)
11,576✔
455
        {
456
            PSLP_ASSERT(!HAS_TAG(col_tags[A->i[j]], C_TAG_INACTIVE));
8,568✔
457
        }
458
    }
459
}
642✔
460

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

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

470
    // verify that A and AT are consistent
471
    PSLP_ASSERT(verify_A_and_AT_consistency(A, AT));
321✔
472

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

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

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

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

495
        up = 0;
1,450✔
496
        down = 0;
1,450✔
497

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

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

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

516
        PSLP_ASSERT(up == locks[col].up);
1,450✔
517
        PSLP_ASSERT(down == locks[col].down);
1,450✔
518
    }
519
}
301✔
520

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

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

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

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

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

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

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

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

592
        if (col_sizes[i] == SIZE_INACTIVE_COL)
1,562✔
593
        {
594
            PSLP_ASSERT(HAS_TAG(col_tags[i], C_TAG_INACTIVE));
112✔
595
        }
596
    }
597
}
301✔
598

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

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

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

622
        if (vals[i] > 0)
4,598✔
623
        {
624
            if (HAS_TAG(col_tags[col], C_TAG_UB_INF))
3,437✔
625
            {
626
                n_inf_max++;
1,699✔
627
            }
628

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

641
            if (HAS_TAG(col_tags[col], C_TAG_UB_INF))
1,161✔
642
            {
643
                n_inf_min++;
499✔
644
            }
645
        }
646
    }
647

648
    PSLP_ASSERT(n_inf_max == activity.n_inf_max);
1,298✔
649
    PSLP_ASSERT(n_inf_min == activity.n_inf_min);
1,298✔
650

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

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

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

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

720
        PSLP_ASSERT(ABS(activity.min - min) < 1e-6);
869✔
721
    }
722
}
723

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

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

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

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

758
    return 0;
70✔
759
}
760

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

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

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

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

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

807
    PSLP_ASSERT(stats->nnz_original - stats->nnz_reduced == total_removed);
20✔
808

809
    // valgrind timing is not reliable
810
#ifndef RUNNING_ON_VALGRIND
811
    double time_medium = stats->ps_time_primal_propagation +
812
                         stats->ps_time_parallel_rows + stats->ps_time_parallel_cols;
813
    PSLP_ASSERT((stats->ps_time_medium - time_medium) / MAX(1e-2, time_medium) < 0.05);
814
#endif
815
}
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