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

dance858 / PSLP / 21522825537

30 Jan 2026 04:26PM UTC coverage: 88.995% (+0.007%) from 88.988%
21522825537

Pull #34

github

web-flow
Merge 9dafbef89 into 8137ce2f7
Pull Request #34: fix-windows-build

1249 of 1400 branches covered (89.21%)

Branch coverage included in aggregate %.

226 of 243 new or added lines in 20 files covered. (93.0%)

1 existing line in 1 file now uncovered.

3854 of 4334 relevant lines covered (88.92%)

3375.4 hits per line

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

95.54
/src/core/Matrix.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 "Matrix.h"
20
#include "Debugger.h"
21
#include "Memory_wrapper.h"
22
#include "Numerics.h"
23
#include "PSLP_warnings.h"
24
#include "RowColViews.h"
25
#include "glbopts.h"
26
#include "stdlib.h"
27
#include "string.h"
28

29
Matrix *matrix_new(const double *Ax, const int *Ai, const int *Ap, PSLP_uint n_rows,
34✔
30
                   PSLP_uint n_cols, PSLP_uint nnz)
31
{
32
    DEBUG(ASSERT_NO_ZEROS_D(Ax, nnz));
34✔
33
    Matrix *A = matrix_alloc(n_rows, n_cols, nnz);
34✔
34
    RETURN_PTR_IF_NULL(A, NULL);
34✔
35
    PSLP_uint i, len;
36
    int offset, row_size, row_alloc;
37

38
    offset = 0;
34✔
39
    for (i = 0; i < n_rows; ++i)
2,189✔
40
    {
41
        A->p[i].start = Ap[i] + offset;
2,155✔
42
        len = (PSLP_uint) (Ap[i + 1] - Ap[i]);
2,155✔
43
        memcpy(A->x + A->p[i].start, Ax + Ap[i], len * sizeof(double));
2,155✔
44
        memcpy(A->i + A->p[i].start, Ai + Ap[i], len * sizeof(int));
2,155✔
45
        A->p[i].end = Ap[i + 1] + offset;
2,155✔
46
        row_size = A->p[i].end - A->p[i].start;
2,155✔
47
        row_alloc = calc_memory_row(row_size, EXTRA_ROW_SPACE, EXTRA_MEMORY_RATIO);
2,155✔
48
        offset += row_alloc - row_size;
2,155✔
49
    }
50

51
    A->p[n_rows].start = Ap[n_rows] + offset;
34✔
52
    A->p[n_rows].end = A->p[n_rows].start;
34✔
53

54
    return A;
34✔
55
}
56

57
// needed for the transpose function
58
Matrix *matrix_alloc(PSLP_uint n_rows, PSLP_uint n_cols, PSLP_uint nnz)
486✔
59
{
60
    Matrix *A = (Matrix *) ps_malloc(1, sizeof(Matrix));
486✔
61
    RETURN_PTR_IF_NULL(A, NULL);
486✔
62

63
    A->m = n_rows;
486✔
64
    A->n = n_cols;
486✔
65
    A->nnz = nnz;
486✔
66
    A->n_alloc = calc_memory(nnz, n_rows, EXTRA_ROW_SPACE, EXTRA_MEMORY_RATIO);
486✔
67

68
#ifdef TESTING
69
    A->i = (int *) ps_calloc(A->n_alloc, sizeof(int));
486✔
70
    A->p = (RowRange *) ps_calloc(n_rows + 1, sizeof(RowRange));
486✔
71
    A->x = (double *) ps_calloc(A->n_alloc, sizeof(double));
486✔
72
#else
73
    A->i = (int *) ps_malloc(A->n_alloc, sizeof(int));
74
    A->p = (RowRange *) ps_malloc(n_rows + 1, sizeof(RowRange));
75
    A->x = (double *) ps_malloc(A->n_alloc, sizeof(double));
76
#endif
77

78
    if (!A->i || !A->p || !A->x)
486✔
79
    {
80
        free_matrix(A);
×
81
        return NULL;
×
82
    }
83

84
    return A;
486✔
85
}
86

87
Matrix *matrix_new_no_extra_space(const double *Ax, const int *Ai, const int *Ap,
99✔
88
                                  PSLP_uint n_rows, PSLP_uint n_cols, PSLP_uint nnz)
89
{
90
    Matrix *A = (Matrix *) ps_malloc(1, sizeof(Matrix));
99✔
91
    RETURN_PTR_IF_NULL(A, NULL);
99✔
92

93
    A->m = n_rows;
99✔
94
    A->n = n_cols;
99✔
95
    A->nnz = nnz;
99✔
96
    A->n_alloc = nnz;
99✔
97
    A->i = (int *) ps_malloc(A->n_alloc, sizeof(int));
99✔
98
    A->p = (RowRange *) ps_malloc(n_rows + 1, sizeof(RowRange));
99✔
99
    A->x = (double *) ps_malloc(A->n_alloc, sizeof(double));
99✔
100

101
    if (!A->i || !A->p || !A->x)
99✔
102
    {
103
        free_matrix(A);
×
104
        return NULL;
×
105
    }
106

107
    memcpy(A->x, Ax, nnz * sizeof(double));
99✔
108
    memcpy(A->i, Ai, nnz * sizeof(int));
99✔
109

110
    for (int i = 0; i <= n_rows; ++i)
613✔
111
    {
112
        A->p[i].start = Ap[i];
514✔
113
        A->p[i].end = Ap[i + 1];
514✔
114
    }
115

116
    return A;
99✔
117
}
118

119
Matrix *transpose(const Matrix *A, int *work_n_cols)
452✔
120
{
121
    Matrix *AT = matrix_alloc(A->n, A->m, A->nnz);
452✔
122
    RETURN_PTR_IF_NULL(AT, NULL);
452✔
123
    int i, j, start;
124
    int *count = work_n_cols;
452✔
125
    memset(count, 0, A->n * sizeof(int));
452✔
126

127
    // -------------------------------------------------------------------
128
    //  compute nnz in each column of A
129
    // -------------------------------------------------------------------
130
    for (i = 0; i < A->m; ++i)
2,374✔
131
    {
132
        for (j = A->p[i].start; j < A->p[i].end; ++j)
8,088✔
133
        {
134
            count[A->i[j]]++;
6,166✔
135
        }
136
    }
137
    // ------------------------------------------------------------------
138
    //  compute row pointers, taking the extra space into account
139
    // ------------------------------------------------------------------
140
    AT->p[0].start = 0;
452✔
141
    for (i = 0; i < A->n; ++i)
2,724✔
142
    {
143
        start = AT->p[i].start;
2,272✔
144
        AT->p[i].end = start + count[i];
2,272✔
145
        AT->p[i + 1].start =
2,272✔
146
            start + calc_memory_row(count[i], EXTRA_ROW_SPACE, EXTRA_MEMORY_RATIO);
2,272✔
147
        count[i] = start;
2,272✔
148
    }
149

150
    AT->p[A->n].start = (int) AT->n_alloc;
452✔
151
    AT->p[A->n].end = (int) AT->n_alloc;
452✔
152

153
    // ------------------------------------------------------------------
154
    //  fill transposed matrix (this is a bottleneck)
155
    // ------------------------------------------------------------------
156
    for (i = 0; i < A->m; ++i)
2,374✔
157
    {
158
        for (j = A->p[i].start; j < A->p[i].end; j++)
8,088✔
159
        {
160
            AT->x[count[A->i[j]]] = A->x[j];
6,166✔
161
            AT->i[count[A->i[j]]] = i;
6,166✔
162
            count[A->i[j]]++;
6,166✔
163
        }
164
    }
165

166
    return AT;
452✔
167
}
168

169
PSLP_uint calc_memory(PSLP_uint nnz, PSLP_uint n_rows, PSLP_uint extra_row_space,
486✔
170
                      double memory_ratio)
171
{
172
    /* disable conversion compiler warning*/
173
    PSLP_DIAG_PUSH();
174
    PSLP_DIAG_IGNORE_CONVERSION();
175

176
    /* intentional truncation */
177
    PSLP_uint result = (PSLP_uint) (nnz * memory_ratio) + n_rows * extra_row_space;
486✔
178

179
    /* enable conversion compiler warnings */
180
    PSLP_DIAG_POP();
181
    return result;
486✔
182
}
183

184
int calc_memory_row(int size, int extra_row_space, double memory_ratio)
5,156✔
185
{
186
    return (int) (size * memory_ratio) + extra_row_space;
5,156✔
187
}
188

189
void free_matrix(Matrix *A)
585✔
190
{
191
    if (A)
585✔
192
    {
193
        PS_FREE(A->i);
585✔
194
        PS_FREE(A->p);
585✔
195
        PS_FREE(A->x);
585✔
196
    }
197

198
    PS_FREE(A);
585✔
199
}
585✔
200

201
void remove_extra_space(Matrix *A, const int *row_sizes, const int *col_sizes,
201✔
202
                        bool remove_all, int *col_idxs_map)
203
{
204
    int j, start, end, len, row_alloc, curr;
205
    int extra_row_space = (remove_all) ? 0 : EXTRA_ROW_SPACE;
201✔
206
    double extra_mem_ratio = (remove_all) ? 1.0 : EXTRA_MEMORY_RATIO;
201✔
207
    curr = 0;
201✔
208
    PSLP_uint i, n_deleted_rows, col_count;
209

210
    // --------------------------------------------------------------------------
211
    // loop through the rows and remove redundant space, including inactive
212
    // rows.
213
    // --------------------------------------------------------------------------
214
    n_deleted_rows = 0;
201✔
215
    for (i = 0; i < A->m; ++i)
1,123✔
216
    {
217
        if (row_sizes[i] == SIZE_INACTIVE_ROW)
922✔
218
        {
219
            n_deleted_rows++;
193✔
220
            continue;
193✔
221
        }
222

223
        start = A->p[i].start;
729✔
224
        end = A->p[i].end;
729✔
225
        len = end - start;
729✔
226
        memmove(A->x + curr, A->x + start, (PSLP_uint) (len) * sizeof(double));
729✔
227
        memmove(A->i + curr, A->i + start, (PSLP_uint) (len) * sizeof(int));
729✔
228
        A->p[i - n_deleted_rows].start = curr;
729✔
229
        A->p[i - n_deleted_rows].end = curr + len;
729✔
230
        row_alloc = calc_memory_row(len, extra_row_space, extra_mem_ratio);
729✔
231
        curr += row_alloc;
729✔
232
    }
233

234
    A->m -= n_deleted_rows;
201✔
235
    A->p[A->m].start = curr;
201✔
236
    A->p[A->m].end = curr;
201✔
237

238
    // shrink size
239
    A->x = (double *) ps_realloc(A->x, (PSLP_uint) MAX(curr, 1), sizeof(double));
201✔
240
    A->i = (int *) ps_realloc(A->i, (PSLP_uint) MAX(curr, 1), sizeof(int));
201✔
241
    A->p = (RowRange *) ps_realloc(A->p, (PSLP_uint) (A->m + 1), sizeof(RowRange));
201✔
242

243
    // -------------------------------------------------------------------------
244
    //                      compute new column indices
245
    // -------------------------------------------------------------------------
246
    col_count = 0;
201✔
247
    for (i = 0; i < A->n; ++i)
1,142✔
248
    {
249
        if (col_sizes[i] == SIZE_INACTIVE_COL)
941✔
250
        {
251
            col_idxs_map[i] = -1;
200✔
252
        }
253
        else
254
        {
255
            col_idxs_map[i] = (int) (col_count++);
741✔
256
        }
257
    }
258
    A->n = col_count;
201✔
259

260
    // -------------------------------------------------------------------------
261
    //                        update column indices
262
    // -------------------------------------------------------------------------
263
    for (i = 0; i < A->m; ++i)
930✔
264
    {
265
        for (j = A->p[i].start; j < A->p[i].end; ++j)
2,844✔
266
        {
267
            A->i[j] = col_idxs_map[A->i[j]];
2,115✔
268
        }
269
    }
270
}
201✔
271

272
bool shift_row(Matrix *A, int row, int extra_space, int max_shift)
28✔
273
{
274
    int left, right, missing_space, remaining_shifts, left_shifts;
275
    int right_shifts, space_left, space_right, n_move_right, n_move_left;
276
    int next_start, next_end;
277
    bool shift_left;
278
    RowRange *row_r = A->p;
28✔
279
    left = row;
28✔
280
    right = row + 1;
28✔
281
    remaining_shifts = max_shift;
28✔
282
    left_shifts = 0;
28✔
283
    right_shifts = 0;
28✔
284
    missing_space = extra_space - (row_r[right].start - row_r[row].end);
28✔
285

286
    if (missing_space <= 0)
28✔
287
    {
288
        return true;
2✔
289
    }
290

291
    // ------------------------------------------------------------------------
292
    // compute the new start index for row 'row' and a lower bound on the start
293
    // index for the the first active row following row 'row'.
294
    // ------------------------------------------------------------------------
295
    while (missing_space > 0)
84✔
296
    {
297
        if (left == 0 && right == A->m)
65✔
298
        {
299
            return false;
×
300
        }
301

302
        // space_left is the number of steps we can shift 'left' row to the
303
        // left without overwriting row 'left - 1'.
304
        // space_right is the number of steps we can shift 'right' row to
305
        // the right without overwriting row 'right + 1'.
306
        assert(left >= 0 && right <= A->m);
65✔
307
        space_left = (left == 0) ? 0 : row_r[left].start - row_r[left - 1].end;
65✔
308
        space_right =
65✔
309
            (right == A->m) ? 0 : row_r[right + 1].start - row_r[right].end;
65✔
310
        assert(space_left >= 0 && space_right >= 0);
65✔
311

312
        // number of elements that must be moved left resp. right if we shift
313
        // in a certain direction
314
        n_move_right = row_r[right].end - row_r[right].start;
65✔
315
        n_move_left = row_r[left].end - row_r[left].start;
65✔
316

317
        // decide which direction to shift
318
        if (left == 0)
65✔
319
        {
320
            if (right != A->m && n_move_right <= remaining_shifts)
7✔
321
            {
322
                shift_left = false;
5✔
323
            }
324
            else
325
            {
326
                return false;
2✔
327
            }
328
        }
329
        else if (right == A->m)
58✔
330
        {
331
            if (left != 0 && n_move_left <= remaining_shifts)
5✔
332
            {
333
                shift_left = true;
4✔
334
            }
335
            else
336
            {
337
                return false;
1✔
338
            }
339
        }
340
        else if (n_move_left == 0)
53✔
341
        {
342
            shift_left = true;
×
343
        }
344
        else if (n_move_right == 0)
53✔
345
        {
346
            shift_left = false;
11✔
347
        }
348
        else if (n_move_left <= remaining_shifts &&
42✔
349
                 (space_left / (double) (n_move_left) >=
37✔
350
                  space_right / (double) (n_move_right)))
37✔
351
        {
352
            shift_left = true;
16✔
353
        }
354
        else if (n_move_right <= remaining_shifts)
26✔
355
        {
356
            shift_left = false;
22✔
357
        }
358
        else
359
        {
360
            return false;
4✔
361
        }
362

363
        assert(!(shift_left && left == 0) && !(!shift_left && right == A->m));
58✔
364

365
        if (shift_left)
58✔
366
        {
367
            left_shifts = MIN(missing_space, space_left);
20✔
368
            missing_space -= left_shifts;
20✔
369
            remaining_shifts -= n_move_left;
20✔
370
            left -= 1;
20✔
371
        }
372
        else
373
        {
374
            right_shifts = MIN(missing_space, space_right);
38✔
375
            missing_space -= right_shifts;
38✔
376
            remaining_shifts -= n_move_right;
38✔
377
            right += 1;
38✔
378
        }
379
    }
380
    assert(remaining_shifts >= 0);
19✔
381

382
    // ------------------------------------------------------------------------
383
    //                 execute total left shift
384
    // ------------------------------------------------------------------------
385
    next_start = row_r[left + 1].start - left_shifts;
19✔
386
    for (; left < row; left++)
39✔
387
    {
388
        int len = row_r[left + 1].end - row_r[left + 1].start;
20✔
389
        if (len > 0)
20✔
390
        {
391
            memmove(A->x + next_start, A->x + row_r[left + 1].start,
20✔
392
                    ((PSLP_uint) len) * sizeof(double));
20✔
393
            memmove(A->i + next_start, A->i + row_r[left + 1].start,
20✔
394
                    ((PSLP_uint) len) * sizeof(int));
20✔
395
        }
396
        row_r[left + 1].start = next_start;
20✔
397
        row_r[left + 1].end = next_start + len;
20✔
398
        next_start += len;
20✔
399
    }
400

401
    // ------------------------------------------------------------------------
402
    //                 execute total right shift
403
    // ------------------------------------------------------------------------
404
    next_end = row_r[right - 1].end + right_shifts;
19✔
405
    for (; right > row + 1; right--)
56✔
406
    {
407
        int len = row_r[right - 1].end - row_r[right - 1].start;
37✔
408
        if (len > 0)
37✔
409
        {
410
            memmove(A->x + next_end - len, A->x + row_r[right - 1].start,
25✔
411
                    ((PSLP_uint) len) * sizeof(double));
25✔
412
            memmove(A->i + next_end - len, A->i + row_r[right - 1].start,
25✔
413
                    ((PSLP_uint) len) * sizeof(int));
25✔
414
        }
415
        row_r[right - 1].start = next_end - len;
37✔
416
        row_r[right - 1].end = next_end;
37✔
417
        next_end = row_r[right - 1].start;
37✔
418
    }
419

420
    assert(row_r[row + 1].start - row_r[row].end == extra_space);
19✔
421
    return true;
19✔
422
}
423

NEW
424
void print_row_starts(const RowRange *row_ranges, PSLP_uint len)
×
425
{
NEW
426
    for (PSLP_uint i = 0; i < len; ++i)
×
427
    {
428
        printf("%d ", row_ranges[i].start);
×
429
    }
430
    printf("\n");
×
431
}
×
432

433
double insert_or_update_coeff(Matrix *A, int row, int col, double val, int *row_size)
61✔
434
{
435
    int i, start, end, insertion;
436
    double old_val = 0.0;
61✔
437
    start = A->p[row].start;
61✔
438
    end = A->p[row].end;
61✔
439
    insertion = end;
61✔
440

441
    // -----------------------------------------------------------------
442
    //             find where it should be inserted
443
    // -----------------------------------------------------------------
444
    for (i = start; i < end; ++i)
133✔
445
    {
446
        if (A->i[i] >= col)
129✔
447
        {
448
            insertion = i;
57✔
449
            break;
57✔
450
        }
451
    }
452

453
    // -----------------------------------------------------------------
454
    // Insert the new value if it is nonzero. If it exists or should be
455
    // inserted in the end, we don't need to shift values.
456
    // -----------------------------------------------------------------
457
    if (ABS(val) > ZERO_TOL)
61✔
458
    {
459
        // assert(!IS_ZERO_FEAS_TOL(val));
460
        if (insertion == end)
51✔
461
        {
462
            A->x[insertion] = val;
4✔
463
            A->i[insertion] = col;
4✔
464
            A->p[row].end += 1;
4✔
465
            A->nnz += 1;
4✔
466
            *row_size += 1;
4✔
467
        }
468
        else if (A->i[insertion] == col)
47✔
469
        {
470
            old_val = A->x[insertion];
19✔
471
            A->x[insertion] = val;
19✔
472
        }
473
        else
474
        {
475
            PSLP_uint len = (PSLP_uint) (end - insertion);
28✔
476
            memmove(A->x + insertion + 1, A->x + insertion, len * sizeof(double));
28✔
477
            memmove(A->i + insertion + 1, A->i + insertion, len * sizeof(int));
28✔
478

479
            // insert new value
480
            A->x[insertion] = val;
28✔
481
            A->i[insertion] = col;
28✔
482
            A->p[row].end += 1;
28✔
483
            A->nnz += 1;
28✔
484
            *row_size += 1;
28✔
485
        }
486
    }
487
    // if the new value is zero, we just have to shift
488
    else
489
    {
490
        // we only expect that the new value is zero if the coefficient
491
        // already exists
492
        assert(A->i[insertion] == col);
10✔
493

494
        // we only have to shift values if the zero is not in the end
495
        if (insertion != end - 1)
10✔
496
        {
497
            PSLP_uint len = (PSLP_uint) (end - insertion - 1);
6✔
498
            memmove(A->x + insertion, A->x + insertion + 1, len * sizeof(double));
6✔
499
            memmove(A->i + insertion, A->i + insertion + 1, len * sizeof(int));
6✔
500
        }
501

502
        A->p[row].end -= 1;
10✔
503
        A->nnz -= 1;
10✔
504
        *row_size -= 1;
10✔
505
    }
506

507
    assert(A->p[row].end <= A->p[row + 1].start);
61✔
508
    return old_val;
61✔
509
}
510

511
void remove_coeff(RowView *row, int col)
35✔
512
{
513
    int shift = 0;
35✔
514
    int len = *row->len;
35✔
515
    for (int i = 0; i < len; ++i)
194✔
516
    {
517
        if (row->cols[i] == col)
159✔
518
        {
519
            shift = 1;
35✔
520
        }
521

522
        row->vals[i] = row->vals[i + shift];
159✔
523
        row->cols[i] = row->cols[i + shift];
159✔
524
    }
525

526
    assert(shift != 0);
35✔
527
    (*row->range).end -= 1;
35✔
528
    *row->len -= 1;
35✔
529
}
35✔
530

531
void count_rows(const Matrix *A, int *row_sizes)
198✔
532
{
533
    for (int i = 0; i < A->m; ++i)
1,087✔
534
    {
535
        row_sizes[i] = A->p[i].end - A->p[i].start;
889✔
536
    }
537
}
198✔
538

539
#ifdef TESTING
540
// Function to create a random CSR matrix
541
Matrix *random_matrix_new(PSLP_uint n_rows, PSLP_uint n_cols, double density)
2✔
542
{
543
    // allocate memory
544

545
    /* disable conversion compiler warning*/
546
    PSLP_DIAG_PUSH();
547
    PSLP_DIAG_IGNORE_CONVERSION();
548
    /* intentional truncation */
549
    PSLP_uint n_alloc_nnz = (PSLP_uint) (density * n_rows * n_cols);
2✔
550

551
    /* enable conversion compiler warnings */
552
    PSLP_DIAG_POP();
553
    double *Ax = (double *) ps_malloc(n_alloc_nnz, sizeof(double));
2✔
554
    int *Ai = (int *) ps_malloc(n_alloc_nnz, sizeof(int));
2✔
555
    int *Ap = (int *) ps_malloc(n_rows + 1, sizeof(int));
2✔
556
    if (!Ax || !Ai || !Ap)
2✔
557
    {
558
        PS_FREE(Ax);
×
559
        PS_FREE(Ai);
×
560
        PS_FREE(Ap);
×
561
        return NULL;
×
562
    }
563

564
    // Initialize random number generator
565
    srand(1);
2✔
566

567
    PSLP_uint nnz_count = 0; // Counter for nonzero elements
2✔
568
    Ap[0] = 0;
2✔
569

570
    for (PSLP_uint i = 0; i < n_rows; ++i)
2,002✔
571
    {
572
        PSLP_uint row_nnz = 0;
2,000✔
573

574
        // Randomly determine the number of nonzeros in this row
575
        for (PSLP_uint j = 0; j < n_cols; ++j)
3,999,508✔
576
        {
577
            if ((double) rand() / RAND_MAX < density)
3,997,510✔
578
            {
579
                if (nnz_count >= n_alloc_nnz)
400,002✔
580
                {
581
                    break;
2✔
582
                }
583

584
                Ax[nnz_count] = ((double) (rand() - rand()) / RAND_MAX) * 20.0;
400,000✔
585
                Ai[nnz_count] = (int) j;
400,000✔
586
                ++nnz_count;
400,000✔
587
                ++row_nnz;
400,000✔
588
            }
589
        }
590
        Ap[i + 1] = Ap[i] + (int) row_nnz;
2,000✔
591
    }
592

593
    // create matrix in modified CSR format
594
    Matrix *A = matrix_new(Ax, Ai, Ap, n_rows, n_cols, nnz_count);
2✔
595
    PS_FREE(Ax);
2✔
596
    PS_FREE(Ai);
2✔
597
    PS_FREE(Ap);
2✔
598

599
    return A;
2✔
600
}
601

602
void replace_row_A(Matrix *A, int row, double ratio, double *new_vals, int *cols_new,
42✔
603
                   int new_len)
604
{
605
    int i, len, start, n_new_elements;
606
    len = A->p[row].end - A->p[row].start;
42✔
607
    n_new_elements = new_len - len;
42✔
608

609
    // potentially shift row to get extra space
610
    if (n_new_elements > 0)
42✔
611
    {
612
        assert(shift_row(A, row, n_new_elements, 2000));
8✔
613
    }
614

615
    // replace the row
616
    start = A->p[row].start;
42✔
617
    for (i = 0; i < new_len; ++i)
8,078✔
618
    {
619
        A->x[start + i] = ratio * new_vals[i];
8,036✔
620
        A->i[start + i] = cols_new[i];
8,036✔
621
    }
622
    A->p[row].end = A->p[row].start + new_len;
42✔
623
    assert(A->p[row].end <= A->p[row + 1].start);
42✔
624
}
42✔
625

626
#endif
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