Skip to content

Commit 8b7e739

Browse files
committed
update linalg
1 parent f059855 commit 8b7e739

File tree

2 files changed

+111
-169
lines changed

2 files changed

+111
-169
lines changed

highs/pdlp/hipdlp/linalg.cc

Lines changed: 110 additions & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -9,81 +9,46 @@
99
* @brief
1010
*/
1111
#include "linalg.hpp"
12-
1312
#include "Highs.h"
1413

1514
namespace linalg {
1615

1716
double project_box(double x, double l, double u) {
18-
if (x < l) {
19-
return l;
20-
} else if (x > u) {
21-
return u;
22-
} else {
23-
return x;
24-
}
17+
return std::max(l, std::min(x, u));
2518
}
2619

27-
double project_non_negative(double x) { return (x < 0.0) ? 0.0 : x; }
20+
double project_non_negative(double x) {
21+
return std::max(0.0, x);
22+
}
2823

2924
void Ax(const HighsLp& lp, const std::vector<double>& x,
3025
std::vector<double>& result) {
31-
for (HighsInt i = 0; i < lp.num_row_; ++i) {
32-
result[i] = 0.0;
33-
}
34-
for (HighsInt col = 0; col < lp.num_col_; ++col) { // Loop over columns
35-
for (HighsInt k_ptr = lp.a_matrix_.start_[col];
36-
k_ptr < lp.a_matrix_.start_[col + 1]; ++k_ptr) {
37-
HighsInt row = lp.a_matrix_.index_[k_ptr]; // row index
38-
double a_val = lp.a_matrix_.value_[k_ptr];
39-
result[row] += a_val * x[col]; // A[row][col] * x[col]
26+
std::fill(result.begin(), result.end(), 0.0);
27+
// Assumes column-wise matrix format
28+
for (HighsInt col = 0; col < lp.num_col_; ++col) {
29+
for (HighsInt i = lp.a_matrix_.start_[col]; i < lp.a_matrix_.start_[col + 1]; ++i) {
30+
const HighsInt row = lp.a_matrix_.index_[i];
31+
result[row] += lp.a_matrix_.value_[i] * x[col];
4032
}
4133
}
4234
}
4335

4436
void ATy(const HighsLp& lp, const std::vector<double>& y,
4537
std::vector<double>& result) {
46-
for (HighsInt i = 0; i < lp.num_col_; ++i) {
47-
result[i] = 0.0;
48-
}
49-
for (HighsInt col = 0; col < lp.num_col_; ++col) { // Loop over columns
50-
for (HighsInt k_ptr = lp.a_matrix_.start_[col];
51-
k_ptr < lp.a_matrix_.start_[col + 1]; ++k_ptr) {
52-
HighsInt row = lp.a_matrix_.index_[k_ptr]; // row index
53-
double a_val = lp.a_matrix_.value_[k_ptr]; // A[row][col]
54-
result[col] += a_val * y[row]; // A^T[col][row] * y[row]
38+
std::fill(result.begin(), result.end(), 0.0);
39+
// Assumes column-wise matrix format. For each column `col` of A,
40+
// this loop calculates dot(column_col, y) and adds it to result[col].
41+
for (HighsInt col = 0; col < lp.num_col_; ++col) {
42+
for (HighsInt i = lp.a_matrix_.start_[col]; i < lp.a_matrix_.start_[col + 1]; ++i) {
43+
const HighsInt row = lp.a_matrix_.index_[i];
44+
result[col] += lp.a_matrix_.value_[i] * y[row];
5545
}
5646
}
5747
}
5848

59-
double nrm2(const std::vector<double>& vec) {
60-
double sum_sq = 0.0;
61-
for (double val : vec) {
62-
sum_sq += val * val;
63-
}
64-
return std::sqrt(sum_sq);
65-
}
66-
67-
// ADD THE IMPLEMENTATION FOR scale:
68-
void scale(std::vector<double>& vec, double factor) {
69-
for (size_t i = 0; i < vec.size(); ++i) {
70-
vec[i] *= factor;
71-
}
72-
}
73-
74-
void normalize(std::vector<double>& vec) {
75-
double norm = nrm2(vec);
76-
if (norm > 0.0) {
77-
scale(vec, 1.0 / norm);
78-
} else {
79-
// If the vector is zero, we can choose to leave it as is or set it to a
80-
// default value Here we choose to leave it unchanged
81-
}
82-
}
83-
8449
double dot(const std::vector<double>& a, const std::vector<double>& b) {
8550
if (a.size() != b.size()) {
86-
throw std::invalid_argument("Vectors must be of the same size");
51+
throw std::invalid_argument("Vectors must be of the same size for dot product.");
8752
}
8853
double result = 0.0;
8954
for (size_t i = 0; i < a.size(); ++i) {
@@ -92,168 +57,144 @@ double dot(const std::vector<double>& a, const std::vector<double>& b) {
9257
return result;
9358
}
9459

95-
// Computes the L2 norm of the difference between two vectors (v1 - v2).
96-
double diffTwoNorm(const std::vector<double>& v1,
97-
const std::vector<double>& v2) {
98-
double norm_sq = 0.0;
99-
if (v1.size() != v2.size()) {
100-
// Handle error: vectors must have the same dimension.
101-
return -1.0;
102-
}
103-
for (size_t i = 0; i < v1.size(); ++i) {
104-
double diff = v1[i] - v2[i];
105-
norm_sq += diff * diff;
106-
}
107-
return std::sqrt(norm_sq);
60+
// =================================================================
61+
// Norm Functions
62+
// =================================================================
63+
64+
double nrm2(const std::vector<double>& vec) {
65+
return std::sqrt(dot(vec, vec));
10866
}
10967

110-
double vector_norm(const std::vector<double>& vec, double p) {
111-
if (std::isinf(p)) {
112-
// Infinity norm
113-
double max_val = 0.0;
114-
for (double val : vec) {
115-
max_val = std::max(max_val, std::abs(val));
116-
}
117-
return max_val;
118-
} else if (p == 2.0) {
119-
// L2 norm (use existing optimized function)
120-
return nrm2(vec);
121-
} else if (p == 1.0) {
122-
// L1 norm
123-
double sum = 0.0;
124-
for (double val : vec) {
125-
sum += std::abs(val);
126-
}
127-
return sum;
128-
} else {
129-
// General p-norm
130-
double sum = 0.0;
131-
for (double val : vec) {
132-
sum += std::pow(std::abs(val), p);
133-
}
134-
return std::pow(sum, 1.0 / p);
135-
}
68+
double vector_norm_squared(const std::vector<double>& vec) {
69+
return dot(vec, vec);
13670
}
13771

138-
// General vector norm (for raw array)
13972
double vector_norm(const double* values, size_t size, double p) {
140-
if (std::isinf(p)) {
141-
// Infinity norm
73+
if (std::isinf(p)) { // Infinity norm
14274
double max_val = 0.0;
14375
for (size_t i = 0; i < size; ++i) {
14476
max_val = std::max(max_val, std::abs(values[i]));
14577
}
14678
return max_val;
147-
} else if (p == 2.0) {
148-
// L2 norm
149-
double sum_sq = 0.0;
150-
for (size_t i = 0; i < size; ++i) {
151-
sum_sq += values[i] * values[i];
152-
}
153-
return std::sqrt(sum_sq);
154-
} else if (p == 1.0) {
155-
// L1 norm
79+
}
80+
if (p == 1.0) { // L1 norm
15681
double sum = 0.0;
15782
for (size_t i = 0; i < size; ++i) {
15883
sum += std::abs(values[i]);
15984
}
16085
return sum;
161-
} else {
162-
// General p-norm
163-
double sum = 0.0;
164-
for (size_t i = 0; i < size; ++i) {
165-
sum += std::pow(std::abs(values[i]), p);
166-
}
167-
return std::pow(sum, 1.0 / p);
16886
}
87+
// General p-norm (including L2)
88+
double sum = 0.0;
89+
for (size_t i = 0; i < size; ++i) {
90+
sum += std::pow(std::abs(values[i]), p);
91+
}
92+
return std::pow(sum, 1.0 / p);
16993
}
17094

95+
double vector_norm(const std::vector<double>& vec, double p) {
96+
// For L2 norm, call the optimized nrm2 to avoid pow()
97+
if (p == 2.0) {
98+
return nrm2(vec);
99+
}
100+
return vector_norm(vec.data(), vec.size(), p);
101+
}
102+
103+
// =================================================================
104+
// Vector Operations
105+
// =================================================================
106+
107+
void scale(std::vector<double>& vec, double factor) {
108+
for (double& val : vec) {
109+
val *= factor;
110+
}
111+
}
112+
113+
void normalize(std::vector<double>& vec) {
114+
double norm = nrm2(vec);
115+
if (norm > 1e-9) { // Use a small tolerance
116+
scale(vec, 1.0 / norm);
117+
}
118+
}
119+
120+
double diffTwoNorm(const std::vector<double>& v1, const std::vector<double>& v2) {
121+
if (v1.size() != v2.size()) {
122+
throw std::invalid_argument("Vectors must have the same dimension.");
123+
}
124+
double norm_sq = 0.0;
125+
for (size_t i = 0; i < v1.size(); ++i) {
126+
double diff = v1[i] - v2[i];
127+
norm_sq += diff * diff;
128+
}
129+
return std::sqrt(norm_sq);
130+
}
131+
132+
133+
// =================================================================
134+
// LP-related Norm Computations
135+
// =================================================================
136+
171137
double compute_cost_norm(const HighsLp& lp, double p) {
172138
return vector_norm(lp.col_cost_, p);
173139
}
174140

175-
// Compute norm of RHS vector (only for finite values)
176141
double compute_rhs_norm(const HighsLp& lp, double p) {
177-
std::vector<double> finite_rhs;
178-
finite_rhs.reserve(lp.num_row_);
179-
180-
for (HighsInt i = 0; i < lp.num_row_; ++i) {
181-
if (lp.row_lower_[i] > -kHighsInf && lp.row_lower_[i] < kHighsInf) {
182-
finite_rhs.push_back(lp.row_lower_[i]);
142+
if (std::isinf(p)) {
143+
double max_val = 0.0;
144+
for (double val : lp.row_lower_) {
145+
if (std::isfinite(val)) max_val = std::max(max_val, std::abs(val));
183146
}
147+
return max_val;
184148
}
185-
186-
return finite_rhs.empty() ? 0.0 : vector_norm(finite_rhs, p);
149+
150+
double sum = 0.0;
151+
for (double val : lp.row_lower_) {
152+
if (std::isfinite(val)) {
153+
if (p == 1.0) sum += std::abs(val);
154+
else sum += std::pow(std::abs(val), p);
155+
}
156+
}
157+
158+
if (p == 2.0) return std::sqrt(sum);
159+
if (p == 1.0) return sum;
160+
return std::pow(sum, 1.0 / p);
187161
}
188162

189-
// Compute column norms of the constraint matrix
190163
std::vector<double> compute_column_norms(const HighsLp& lp, double p) {
191164
std::vector<double> col_norms(lp.num_col_, 0.0);
192-
193165
for (HighsInt col = 0; col < lp.num_col_; ++col) {
194166
HighsInt start = lp.a_matrix_.start_[col];
195167
HighsInt end = lp.a_matrix_.start_[col + 1];
196-
197168
if (start < end) {
198169
col_norms[col] = vector_norm(&lp.a_matrix_.value_[start], end - start, p);
199170
}
200171
}
201-
202172
return col_norms;
203173
}
204174

205-
// Compute row norms of the constraint matrix
206175
std::vector<double> compute_row_norms(const HighsLp& lp, double p) {
207176
std::vector<double> row_norms(lp.num_row_, 0.0);
208-
209-
if (std::isinf(p)) {
210-
// Infinity norm - find max absolute value in each row
211-
for (HighsInt col = 0; col < lp.num_col_; ++col) {
212-
for (HighsInt el = lp.a_matrix_.start_[col];
213-
el < lp.a_matrix_.start_[col + 1]; ++el) {
214-
HighsInt row = lp.a_matrix_.index_[el];
215-
double abs_val = std::abs(lp.a_matrix_.value_[el]);
177+
for (HighsInt col = 0; col < lp.num_col_; ++col) {
178+
for (HighsInt i = lp.a_matrix_.start_[col]; i < lp.a_matrix_.start_[col + 1]; ++i) {
179+
const HighsInt row = lp.a_matrix_.index_[i];
180+
const double abs_val = std::abs(lp.a_matrix_.value_[i]);
181+
if (std::isinf(p)) {
216182
row_norms[row] = std::max(row_norms[row], abs_val);
183+
} else if (p == 1.0) {
184+
row_norms[row] += abs_val;
185+
} else {
186+
row_norms[row] += std::pow(abs_val, p);
217187
}
218188
}
219-
} else if (p == 2.0) {
220-
// L2 norm - sum of squares
221-
for (HighsInt col = 0; col < lp.num_col_; ++col) {
222-
for (HighsInt el = lp.a_matrix_.start_[col];
223-
el < lp.a_matrix_.start_[col + 1]; ++el) {
224-
HighsInt row = lp.a_matrix_.index_[el];
225-
double val = lp.a_matrix_.value_[el];
226-
row_norms[row] += val * val;
227-
}
228-
}
229-
for (HighsInt row = 0; row < lp.num_row_; ++row) {
230-
row_norms[row] = std::sqrt(row_norms[row]);
231-
}
232-
} else if (p == 1.0) {
233-
// L1 norm - sum of absolute values
234-
for (HighsInt col = 0; col < lp.num_col_; ++col) {
235-
for (HighsInt el = lp.a_matrix_.start_[col];
236-
el < lp.a_matrix_.start_[col + 1]; ++el) {
237-
HighsInt row = lp.a_matrix_.index_[el];
238-
row_norms[row] += std::abs(lp.a_matrix_.value_[el]);
239-
}
240-
}
241-
} else {
242-
// General p-norm
243-
for (HighsInt col = 0; col < lp.num_col_; ++col) {
244-
for (HighsInt el = lp.a_matrix_.start_[col];
245-
el < lp.a_matrix_.start_[col + 1]; ++el) {
246-
HighsInt row = lp.a_matrix_.index_[el];
247-
row_norms[row] += std::pow(std::abs(lp.a_matrix_.value_[el]), p);
248-
}
249-
}
189+
}
190+
191+
if (p != 1.0 && !std::isinf(p)) {
192+
const double p_inv = 1.0 / p;
250193
for (HighsInt row = 0; row < lp.num_row_; ++row) {
251-
if (row_norms[row] > 0.0) {
252-
row_norms[row] = std::pow(row_norms[row], 1.0 / p);
253-
}
194+
row_norms[row] = std::pow(row_norms[row], p_inv);
254195
}
255196
}
256-
257197
return row_norms;
258198
}
259-
} // namespace linalg
199+
200+
} // namespace linalg

highs/pdlp/hipdlp/linalg.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ double diffTwoNorm(const std::vector<double>& v1,
4040
// General norm functions
4141
double vector_norm(const std::vector<double>& vec, double p = 2.0);
4242
double vector_norm(const double* values, size_t size, double p = 2.0);
43+
double vector_norm_squared(const std::vector<double>& vec);
4344

4445
// LP-specific norm calculations
4546
double compute_cost_norm(const HighsLp& lp, double p = 2.0);

0 commit comments

Comments
 (0)