Skip to content

Commit 2ca56e7

Browse files
authored
refactor: promote shared primitives to mathematical_optimization (#1481)
Moves linear algebra primitives and other shared utilities into the optimization namespace to reduce the need for `using` statements or namespace qualification introduced by #1446. Linear algebra goes into a new directory named `cpp/src/linear_algebra` and other utilities go into the pre-existing `cpp/src/math_optimization` directory. No behavioral or API change; pure relocation. Authors: - Miles Lubin (https://github.com/mlubin) Approvers: - Ramakrishna Prabhu (https://github.com/ramakrishnap-nv) - Akif ÇÖRDÜK (https://github.com/akifcorduk) URL: #1481
1 parent 90e424e commit 2ca56e7

86 files changed

Lines changed: 381 additions & 404 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cpp/src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ set(UTIL_SRC_FILES ${CMAKE_CURRENT_SOURCE_DIR}/utilities/seed_generator.cu
99
${CMAKE_CURRENT_SOURCE_DIR}/utilities/timestamp_utils.cpp
1010
${CMAKE_CURRENT_SOURCE_DIR}/utilities/work_unit_scheduler.cpp)
1111

12+
add_subdirectory(linear_algebra)
1213
add_subdirectory(pdlp)
1314
add_subdirectory(math_optimization)
1415
add_subdirectory(mip_heuristics)

cpp/src/barrier/barrier.cu

Lines changed: 38 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,23 @@
1010
#include <barrier/conjugate_gradient.hpp>
1111
#include <barrier/cusparse_info.hpp>
1212
#include <barrier/cusparse_view.hpp>
13-
#include <barrier/dense_matrix.hpp>
14-
#include <barrier/dense_vector.hpp>
1513
#include <barrier/device_sparse_matrix.cuh>
1614
#include <barrier/iterative_refinement.hpp>
1715
#include <barrier/pinned_host_allocator.hpp>
1816
#include <barrier/second_order_cone_kernels.cuh>
1917
#include <barrier/sparse_cholesky.cuh>
2018
#include <barrier/sparse_matrix_kernels.cuh>
19+
#include <linear_algebra/dense_matrix.hpp>
20+
#include <linear_algebra/dense_vector.hpp>
2121

2222
#include <dual_simplex/presolve.hpp>
2323
#include <dual_simplex/solve.hpp>
2424

25-
#include <dual_simplex/sparse_matrix.hpp>
26-
#include <dual_simplex/tic_toc.hpp>
27-
#include <dual_simplex/types.hpp>
25+
#include <linear_algebra/sparse_matrix.hpp>
26+
#include <math_optimization/tic_toc.hpp>
27+
#include <math_optimization/types.hpp>
2828

29-
#include <dual_simplex/vector_math.cuh>
29+
#include <linear_algebra/vector_math.cuh>
3030

3131
#include <rmm/device_scalar.hpp>
3232
#include <rmm/device_uvector.hpp>
@@ -53,20 +53,10 @@
5353
namespace cuopt::mathematical_optimization::barrier {
5454

5555
using simplex::compute_user_objective;
56-
using simplex::csc_matrix_t;
57-
using simplex::csr_matrix_t;
58-
using simplex::device_vector_norm_inf;
59-
using simplex::float64_t;
60-
using simplex::inf;
6156
using simplex::lp_problem_t;
6257
using simplex::lp_solution_t;
6358
using simplex::lp_status_t;
64-
using simplex::matrix_vector_multiply;
65-
using simplex::multiply;
6659
using simplex::simplex_solver_settings_t;
67-
using simplex::tic;
68-
using simplex::toc;
69-
using simplex::vector_norm1;
7060

7161
template <typename i_t, typename f_t>
7262
bool validate_barrier_cone_layout(const lp_problem_t<i_t, f_t>& problem,
@@ -1024,9 +1014,9 @@ class iteration_data_t {
10241014
{
10251015
if (n_dense_columns == 0) {
10261016
// Solve ADAT * x = b
1027-
if (debug) { settings_.log.printf("||b|| = %.16e\n", simplex::vector_norm2<i_t, f_t>(b)); }
1017+
if (debug) { settings_.log.printf("||b|| = %.16e\n", vector_norm2<i_t, f_t>(b)); }
10281018
i_t solve_status = chol->solve(b, x);
1029-
if (debug) { settings_.log.printf("||x|| = %.16e\n", simplex::vector_norm2<i_t, f_t>(x)); }
1019+
if (debug) { settings_.log.printf("||x|| = %.16e\n", vector_norm2<i_t, f_t>(x)); }
10301020
return solve_status;
10311021
} else {
10321022
// Use Sherman Morrison followed by PCG
@@ -1062,9 +1052,9 @@ class iteration_data_t {
10621052
dense_vector_t<i_t, f_t> w(AD.m);
10631053
const bool debug = false;
10641054
const bool full_debug = false;
1065-
if (debug) { settings_.log.printf("||b|| = %.16e\n", simplex::vector_norm2<i_t, f_t>(b)); }
1055+
if (debug) { settings_.log.printf("||b|| = %.16e\n", vector_norm2<i_t, f_t>(b)); }
10661056
i_t solve_status = chol->solve(b, w);
1067-
if (debug) { settings_.log.printf("||w|| = %.16e\n", simplex::vector_norm2<i_t, f_t>(w)); }
1057+
if (debug) { settings_.log.printf("||w|| = %.16e\n", vector_norm2<i_t, f_t>(w)); }
10681058
if (solve_status != 0) {
10691059
settings_.log.printf("Linear solve failed in Sherman Morrison after ADAT solve\n");
10701060
return solve_status;
@@ -1102,7 +1092,7 @@ class iteration_data_t {
11021092
matrix_vector_multiply(ADAT, 1.0, M_col, -1.0, M_residual);
11031093
settings_.log.printf(
11041094
"|| A_sparse * D_sparse * A_sparse^T * M(:, k) - AD_dense(:, k) ||_2 = %e\n",
1105-
simplex::vector_norm2<i_t, f_t>(M_residual));
1095+
vector_norm2<i_t, f_t>(M_residual));
11061096
}
11071097
}
11081098
// A_sparse * D_sparse * A_sparse^T * M = U = AD_dense
@@ -1154,8 +1144,7 @@ class iteration_data_t {
11541144
if (debug) {
11551145
dense_vector_t<i_t, f_t> H_residual = g;
11561146
H.matrix_vector_multiply(1.0, y, -1.0, H_residual);
1157-
settings_.log.printf("|| H * y - g ||_2 = %e\n",
1158-
simplex::vector_norm2<i_t, f_t>(H_residual));
1147+
settings_.log.printf("|| H * y - g ||_2 = %e\n", vector_norm2<i_t, f_t>(H_residual));
11591148
}
11601149

11611150
// x = (A_sparse * D_sparse * A_sparse^T)^{-1} * (b - U * y)
@@ -1174,15 +1163,14 @@ class iteration_data_t {
11741163
dense_vector_t<i_t, f_t> solve_residual = v;
11751164
matrix_vector_multiply(ADAT, 1.0, x, -1.0, solve_residual);
11761165
settings_.log.printf("|| A_sparse * D * A_sparse^T * x - v ||_2 = %e\n",
1177-
simplex::vector_norm2<i_t, f_t>(solve_residual));
1166+
vector_norm2<i_t, f_t>(solve_residual));
11781167
}
11791168

11801169
if (debug) {
11811170
// Check U^T * x - y = 0;
11821171
dense_vector_t<i_t, f_t> residual_2 = y;
11831172
AD_dense.transpose_multiply(1.0, x, -1.0, residual_2);
1184-
settings_.log.printf("|| U^T * x - y ||_2 = %e\n",
1185-
simplex::vector_norm2<i_t, f_t>(residual_2));
1173+
settings_.log.printf("|| U^T * x - y ||_2 = %e\n", vector_norm2<i_t, f_t>(residual_2));
11861174
}
11871175

11881176
if (debug) {
@@ -1191,7 +1179,7 @@ class iteration_data_t {
11911179
AD_dense.matrix_vector_multiply(1.0, y, -1.0, residual_1);
11921180
matrix_vector_multiply(ADAT, 1.0, x, 1.0, residual_1);
11931181
settings_.log.printf("|| A_sparse * D_sparse * A_sparse^T * x + U * y - b ||_2 = %e\n",
1194-
simplex::vector_norm2<i_t, f_t>(residual_1));
1182+
vector_norm2<i_t, f_t>(residual_1));
11951183
}
11961184

11971185
if (full_debug && debug) {
@@ -1216,7 +1204,7 @@ class iteration_data_t {
12161204

12171205
adat_multiply(-1.0, ei, 1.0, u);
12181206

1219-
max_error = std::max(max_error, simplex::vector_norm2<i_t, f_t>(u));
1207+
max_error = std::max(max_error, vector_norm2<i_t, f_t>(u));
12201208
}
12211209
settings_.log.printf("|| ADAT(e_i) - ADA^T * e_i ||_2 = %e\n", max_error);
12221210
}
@@ -1356,7 +1344,7 @@ class iteration_data_t {
13561344

13571345
adat_multiply(-1.0, ei, 1.0, u);
13581346

1359-
max_error = std::max(max_error, simplex::vector_norm2<i_t, f_t>(u));
1347+
max_error = std::max(max_error, vector_norm2<i_t, f_t>(u));
13601348
}
13611349
settings_.log.printf(
13621350
"|| (A_sparse * D_sparse * A_sparse^T + U * V^T) * e_i - ADA^T * e_i ||_2 = %e\n",
@@ -1367,7 +1355,7 @@ class iteration_data_t {
13671355
dense_vector_t<i_t, f_t> total_residual = b;
13681356
adat_multiply(1.0, x, -1.0, total_residual);
13691357
settings_.log.printf("|| A * D * A^T * x - b ||_2 = %e\n",
1370-
simplex::vector_norm2<i_t, f_t>(total_residual));
1358+
vector_norm2<i_t, f_t>(total_residual));
13711359
}
13721360

13731361
// Now do some rounds of PCG
@@ -1436,7 +1424,7 @@ class iteration_data_t {
14361424
dense_vector_t<i_t, f_t> dual_res = z_tilde;
14371425
dual_res.axpy(-1.0, lp.objective, 1.0);
14381426
cusparse_view.transpose_spmv(1.0, solution.y, 1.0, dual_res);
1439-
f_t dual_residual_norm = simplex::vector_norm_inf<i_t, f_t>(dual_res, stream_view_);
1427+
f_t dual_residual_norm = vector_norm_inf<i_t, f_t>(dual_res, stream_view_);
14401428
#ifdef PRINT_INFO
14411429
settings_.log.printf("Solution Dual residual: %e\n", dual_residual_norm);
14421430
#endif
@@ -1794,20 +1782,20 @@ class iteration_data_t {
17941782

17951783
// u = A^T * y
17961784
dense_vector_t<i_t, f_t> u(n);
1797-
simplex::matrix_transpose_vector_multiply(A, 1.0, y, 0.0, u);
1798-
if (debug) { printf("||u|| = %.16e\n", simplex::vector_norm2<i_t, f_t>(u)); }
1785+
matrix_transpose_vector_multiply(A, 1.0, y, 0.0, u);
1786+
if (debug) { printf("||u|| = %.16e\n", vector_norm2<i_t, f_t>(u)); }
17991787

18001788
// w = Dinv * u
18011789
dense_vector_t<i_t, f_t> w(n);
18021790
inv_diag.pairwise_product(u, w);
1803-
if (debug) { printf("||inv_diag|| = %.16e\n", simplex::vector_norm2<i_t, f_t>(inv_diag)); }
1791+
if (debug) { printf("||inv_diag|| = %.16e\n", vector_norm2<i_t, f_t>(inv_diag)); }
18041792

18051793
// v = alpha * A * w + beta * v = alpha * A * Dinv * A^T * y + beta * v
18061794
matrix_vector_multiply(A, alpha, w, beta, v);
18071795
if (debug) {
1808-
printf("||A|| = %.16e\n", simplex::vector_norm2<i_t, f_t>(A.x));
1809-
printf("||w|| = %.16e\n", simplex::vector_norm2<i_t, f_t>(w));
1810-
printf("||v|| = %.16e\n", simplex::vector_norm2<i_t, f_t>(v));
1796+
printf("||A|| = %.16e\n", vector_norm2<i_t, f_t>(A.x));
1797+
printf("||w|| = %.16e\n", vector_norm2<i_t, f_t>(w));
1798+
printf("||v|| = %.16e\n", vector_norm2<i_t, f_t>(v));
18111799
}
18121800
}
18131801

@@ -2174,8 +2162,8 @@ int barrier_solver_t<i_t, f_t>::initial_point(iteration_data_t<i_t, f_t>& data)
21742162
// LP block: e = 1, SOC block: e = (sqrt(2), 0, ..., 0)
21752163
if (data.has_cones()) {
21762164
const i_t cs = data.cone_start();
2177-
const f_t norm_b = simplex::vector_norm_inf<i_t, f_t>(lp.rhs);
2178-
const f_t norm_c = simplex::vector_norm_inf<i_t, f_t>(lp.objective);
2165+
const f_t norm_b = vector_norm_inf<i_t, f_t>(lp.rhs);
2166+
const f_t norm_c = vector_norm_inf<i_t, f_t>(lp.objective);
21792167
const f_t mu = std::sqrt((1.0 + norm_b) * (1.0 + norm_c));
21802168
const f_t sqrt2 = std::sqrt(2.0);
21812169
const f_t x_soc = mu * sqrt2;
@@ -2281,27 +2269,27 @@ int barrier_solver_t<i_t, f_t>::initial_point(iteration_data_t<i_t, f_t>& data)
22812269
// rhs_x <- A * Dinv * F * u - b
22822270
data.cusparse_view_.spmv(1.0, DinvFu, -1.0, rhs_x);
22832271
#ifdef PRINT_INFO
2284-
settings.log.printf("||DinvFu|| = %e\n", simplex::vector_norm2<i_t, f_t>(DinvFu));
2272+
settings.log.printf("||DinvFu|| = %e\n", vector_norm2<i_t, f_t>(DinvFu));
22852273
#endif
22862274

22872275
// Solve A*Dinv*A'*q = A*Dinv*F*u - b
22882276
#ifdef PRINT_INFO
2289-
settings.log.printf("||rhs_x|| = %.16e\n", simplex::vector_norm2<i_t, f_t>(rhs_x));
2277+
settings.log.printf("||rhs_x|| = %.16e\n", vector_norm2<i_t, f_t>(rhs_x));
22902278
#endif
22912279
// i_t solve_status = data.chol->solve(rhs_x, q);
22922280
i_t solve_status = data.solve_adat(rhs_x, q);
22932281
if (solve_status != 0) { return status; }
22942282
#ifdef PRINT_INFO
22952283
settings.log.printf("Initial solve status %d\n", solve_status);
2296-
settings.log.printf("||q|| = %.16e\n", simplex::vector_norm2<i_t, f_t>(q));
2284+
settings.log.printf("||q|| = %.16e\n", vector_norm2<i_t, f_t>(q));
22972285
#endif
22982286

22992287
// rhs_x <- A*Dinv*A'*q - rhs_x
23002288
data.adat_multiply(1.0, q, -1.0, rhs_x);
23012289
// matrix_vector_multiply(data.ADAT, 1.0, q, -1.0, rhs_x);
23022290
#ifdef PRINT_INFO
23032291
settings.log.printf("|| A*Dinv*A'*q - (A*Dinv*F*u - b) || = %.16e\n",
2304-
simplex::vector_norm2<i_t, f_t>(rhs_x));
2292+
vector_norm2<i_t, f_t>(rhs_x));
23052293
#endif
23062294

23072295
// x = Dinv*(F*u - A'*q)
@@ -2327,8 +2315,7 @@ int barrier_solver_t<i_t, f_t>::initial_point(iteration_data_t<i_t, f_t>& data)
23272315
data.cusparse_view_.spmv(1.0, data.x, -1.0, init_primal_residual);
23282316
data.handle_ptr->get_stream().synchronize();
23292317
#ifdef PRINT_INFO
2330-
settings.log.printf("||b - A * x||: %.16e\n",
2331-
simplex::vector_norm2<i_t, f_t>(init_primal_residual));
2318+
settings.log.printf("||b - A * x||: %.16e\n", vector_norm2<i_t, f_t>(init_primal_residual));
23322319
#endif
23332320

23342321
if (data.n_upper_bounds > 0) {
@@ -2338,8 +2325,7 @@ int barrier_solver_t<i_t, f_t>::initial_point(iteration_data_t<i_t, f_t>& data)
23382325
init_bound_residual[k] = lp.upper[j] - data.w[k] - data.x[j];
23392326
}
23402327
#ifdef PRINT_INFO
2341-
settings.log.printf("|| u - w - x||: %e\n",
2342-
simplex::vector_norm2<i_t, f_t>(init_bound_residual));
2328+
settings.log.printf("|| u - w - x||: %e\n", vector_norm2<i_t, f_t>(init_bound_residual));
23432329
#endif
23442330
}
23452331

@@ -2453,7 +2439,7 @@ int barrier_solver_t<i_t, f_t>::initial_point(iteration_data_t<i_t, f_t>& data)
24532439
}
24542440
#ifdef PRINT_INFO
24552441
settings.log.printf("||A^T y + z - E*v - Q*x - c ||: %e\n",
2456-
simplex::vector_norm2<i_t, f_t>(init_dual_residual));
2442+
vector_norm2<i_t, f_t>(init_dual_residual));
24572443
#endif
24582444
// Make sure (w, x, v, z) > 0. Skip free variables being handled directly.
24592445
data.w.ensure_positive(epsilon_adjust);
@@ -3017,7 +3003,7 @@ i_t barrier_solver_t<i_t, f_t>::gpu_compute_search_direction(iteration_data_t<i_
30173003
raft::common::nvtx::range fun_scope("Barrier: dx_residual_2 GPU");
30183004

30193005
// norm_inf(D^-1 * (A'*dy - r1) - dx)
3020-
const f_t dx_residual_2_norm = simplex::device_custom_vector_norm_inf<i_t, f_t>(
3006+
const f_t dx_residual_2_norm = device_custom_vector_norm_inf<i_t, f_t>(
30213007
thrust::make_transform_iterator(
30223008
thrust::make_zip_iterator(data.d_inv_diag.data(), data.d_r1_.data(), data.d_dx_.data()),
30233009
[] HD(thrust::tuple<f_t, f_t, f_t> t) -> f_t {
@@ -3096,7 +3082,7 @@ i_t barrier_solver_t<i_t, f_t>::gpu_compute_search_direction(iteration_data_t<i_
30963082
lp.A.transpose(Atranspose);
30973083
multiply(ADinv, Atranspose, ADinvAT);
30983084
matrix_vector_multiply(ADinvAT, 1.0, dy, -1.0, dx_residual_4);
3099-
const f_t dx_residual_4_norm = simplex::vector_norm_inf<i_t, f_t>(dx_residual_4, stream_view_);
3085+
const f_t dx_residual_4_norm = vector_norm_inf<i_t, f_t>(dx_residual_4, stream_view_);
31003086
max_residual = std::max(max_residual, dx_residual_4_norm);
31013087
if (dx_residual_4_norm > 1e-2) {
31023088
settings.log.printf("|| ADAT * dy - A * D^-1 * r1 - A * dx || = %.2e\n", dx_residual_4_norm);
@@ -4127,8 +4113,8 @@ lp_status_t barrier_solver_t<i_t, f_t>::solve(f_t start_time, lp_solution_t<i_t,
41274113
f_t mu;
41284114
compute_mu(data, mu);
41294115

4130-
f_t norm_b = simplex::vector_norm_inf<i_t, f_t>(data.b, stream_view_);
4131-
f_t norm_c = simplex::vector_norm_inf<i_t, f_t>(data.c, stream_view_);
4116+
f_t norm_b = vector_norm_inf<i_t, f_t>(data.b, stream_view_);
4117+
f_t norm_c = vector_norm_inf<i_t, f_t>(data.c, stream_view_);
41324118

41334119
f_t quad_objective = 0.0;
41344120
if (data.Q.n > 0) {

cpp/src/barrier/barrier.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66
/* clang-format on */
77
#pragma once
88

9-
#include <barrier/dense_vector.hpp>
9+
#include <linear_algebra/dense_vector.hpp>
1010

1111
#include <dual_simplex/presolve.hpp>
1212
#include <dual_simplex/simplex_solver_settings.hpp>
1313
#include <dual_simplex/solution.hpp>
1414
#include <dual_simplex/solve.hpp>
15-
#include <dual_simplex/sparse_matrix.hpp>
16-
#include <dual_simplex/tic_toc.hpp>
15+
#include <linear_algebra/sparse_matrix.hpp>
16+
#include <math_optimization/tic_toc.hpp>
1717

1818
#include <rmm/device_uvector.hpp>
1919
namespace cuopt::mathematical_optimization::barrier {
@@ -36,7 +36,7 @@ class barrier_solver_t {
3636

3737
private:
3838
void my_pop_range(bool debug) const;
39-
void create_Q(const simplex::lp_problem_t<i_t, f_t>& lp, simplex::csc_matrix_t<i_t, f_t>& Q);
39+
void create_Q(const simplex::lp_problem_t<i_t, f_t>& lp, csc_matrix_t<i_t, f_t>& Q);
4040
int initial_point(iteration_data_t<i_t, f_t>& data);
4141
void compute_residual_norms(const dense_vector_t<i_t, f_t>& w,
4242
const dense_vector_t<i_t, f_t>& x,

cpp/src/barrier/conjugate_gradient.hpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66
/* clang-format on */
77
#pragma once
88

9-
#include <barrier/dense_vector.hpp>
9+
#include <linear_algebra/dense_vector.hpp>
1010

1111
#include <dual_simplex/simplex_solver_settings.hpp>
12-
#include <dual_simplex/types.hpp>
13-
#include <dual_simplex/vector_math.hpp>
12+
#include <linear_algebra/vector_math.hpp>
13+
#include <math_optimization/types.hpp>
1414

1515
#include <cmath>
1616
#include <cstdio>
@@ -42,12 +42,12 @@ i_t preconditioned_conjugate_gradient(const T& op,
4242

4343
dense_vector_t<i_t, f_t> Ap(b.size());
4444
i_t iter = 0;
45-
f_t norm_residual = simplex::vector_norm2<i_t, f_t>(residual);
45+
f_t norm_residual = vector_norm2<i_t, f_t>(residual);
4646
f_t initial_norm_residual = norm_residual;
4747
if (show_pcg_info) {
4848
settings.log.printf("PCG initial residual 2-norm %e inf-norm %e\n",
4949
norm_residual,
50-
simplex::vector_norm_inf<i_t, f_t>(residual));
50+
vector_norm_inf<i_t, f_t>(residual));
5151
}
5252

5353
f_t rTy = residual.inner_product(y);
@@ -62,7 +62,7 @@ i_t preconditioned_conjugate_gradient(const T& op,
6262
// Update residual = residual + alpha * Ap
6363
residual.axpy(alpha, Ap, 1.0);
6464

65-
f_t new_residual = simplex::vector_norm2<i_t, f_t>(residual);
65+
f_t new_residual = vector_norm2<i_t, f_t>(residual);
6666
if (new_residual > 1.1 * norm_residual || new_residual > 1.1 * initial_norm_residual) {
6767
if (show_pcg_info) {
6868
settings.log.printf(
@@ -78,7 +78,7 @@ i_t preconditioned_conjugate_gradient(const T& op,
7878
// residual = A*x - b
7979
residual = b;
8080
op.a_multiply(1.0, x, -1.0, residual);
81-
norm_residual = simplex::vector_norm2<i_t, f_t>(residual);
81+
norm_residual = vector_norm2<i_t, f_t>(residual);
8282

8383
// Solve M y = r for y
8484
op.m_solve(residual, y);
@@ -98,13 +98,13 @@ i_t preconditioned_conjugate_gradient(const T& op,
9898
settings.log.printf("PCG iter %3d 2-norm_residual %.2e inf-norm_residual %.2e\n",
9999
iter,
100100
norm_residual,
101-
simplex::vector_norm_inf<i_t, f_t>(residual));
101+
vector_norm_inf<i_t, f_t>(residual));
102102
}
103103
}
104104

105105
residual = b;
106106
op.a_multiply(1.0, x, -1.0, residual);
107-
norm_residual = simplex::vector_norm2<i_t, f_t>(residual);
107+
norm_residual = vector_norm2<i_t, f_t>(residual);
108108
if (norm_residual < initial_norm_residual) {
109109
if (show_pcg_info) {
110110
settings.log.printf("PCG improved residual 2-norm %.2e/%.2e in %d iterations\n",

0 commit comments

Comments
 (0)