99 * @brief
1010 */
1111#include " linalg.hpp"
12-
1312#include " Highs.h"
1413
1514namespace linalg {
1615
1716double 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
2924void 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
4436void 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-
8449double 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)
13972double 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+
171137double 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)
176141double 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
190163std::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
206175std::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
0 commit comments