1 module scaling; 2 3 nothrow @nogc extern(C): 4 5 import glob_opts; 6 import types; 7 import lin_alg; 8 import constants; 9 10 11 version(EMBEDDED_1){} 12 else { 13 14 // Set values lower than threshold SCALING_REG to 1 15 void limit_scaling(c_float *D, c_int n) { 16 c_int i; 17 18 for (i = 0; i < n; i++) { 19 D[i] = D[i] < MIN_SCALING ? 1.0 : D[i]; 20 D[i] = D[i] > MAX_SCALING ? MAX_SCALING : D[i]; 21 } 22 } 23 24 /** 25 * Compute infinite norm of the columns of the KKT matrix without forming it 26 * 27 * The norm is stored in the vector v = (D, E) 28 * 29 * @param P Cost matrix 30 * @param A Constraints matrix 31 * @param D Norm of columns related to variables 32 * @param D_temp_A Temporary vector for norm of columns of A 33 * @param E Norm of columns related to constraints 34 * @param n Dimension of KKT matrix 35 */ 36 void compute_inf_norm_cols_KKT(const csc *P, const csc *A, 37 c_float *D, c_float *D_temp_A, 38 c_float *E, c_int n) { 39 // First half 40 // [ P ] 41 // [ A ] 42 mat_inf_norm_cols_sym_triu(P, D); 43 mat_inf_norm_cols(A, D_temp_A); 44 vec_ew_max_vec(D, D_temp_A, D, n); 45 46 // Second half 47 // [ A'] 48 // [ 0 ] 49 mat_inf_norm_rows(A, E); 50 } 51 52 c_int scale_data(OSQPWorkspace *work) { 53 // Scale KKT matrix 54 // 55 // [ P A'] 56 // [ A 0 ] 57 // 58 // with diagonal matrix 59 // 60 // S = [ D ] 61 // [ E ] 62 // 63 64 c_int i; // Iterations index 65 c_int n, m; // Number of constraints and variables 66 c_float c_temp; // Cost function scaling 67 c_float inf_norm_q; // Infinity norm of q 68 69 n = work.data.n; 70 m = work.data.m; 71 72 // Initialize scaling to 1 73 work.scaling.c = 1.0; 74 vec_set_scalar(work.scaling.D, 1., work.data.n); 75 vec_set_scalar(work.scaling.Dinv, 1., work.data.n); 76 vec_set_scalar(work.scaling.E, 1., work.data.m); 77 vec_set_scalar(work.scaling.Einv, 1., work.data.m); 78 79 80 for (i = 0; i < work.settings.scaling; i++) { 81 // 82 // First Ruiz step 83 // 84 85 // Compute norm of KKT columns 86 compute_inf_norm_cols_KKT(work.data.P, work.data.A, 87 work.D_temp, work.D_temp_A, 88 work.E_temp, n); 89 90 // Set to 1 values with 0 norms (avoid crazy scaling) 91 limit_scaling(work.D_temp, n); 92 limit_scaling(work.E_temp, m); 93 94 // Take square root of norms 95 vec_ew_sqrt(work.D_temp, n); 96 vec_ew_sqrt(work.E_temp, m); 97 98 // Divide scalings D and E by themselves 99 vec_ew_recipr(work.D_temp, work.D_temp, n); 100 vec_ew_recipr(work.E_temp, work.E_temp, m); 101 102 // Equilibrate matrices P and A and vector q 103 // P <- DPD 104 mat_premult_diag(work.data.P, work.D_temp); 105 mat_postmult_diag(work.data.P, work.D_temp); 106 107 // A <- EAD 108 mat_premult_diag(work.data.A, work.E_temp); 109 mat_postmult_diag(work.data.A, work.D_temp); 110 111 // q <- Dq 112 vec_ew_prod(work.D_temp, work.data.q, work.data.q, n); 113 114 // Update equilibration matrices D and E 115 vec_ew_prod(work.scaling.D, work.D_temp, work.scaling.D, n); 116 vec_ew_prod(work.scaling.E, work.E_temp, work.scaling.E, m); 117 118 // 119 // Cost normalization step 120 // 121 122 // Compute avg norm of cols of P 123 mat_inf_norm_cols_sym_triu(work.data.P, work.D_temp); 124 c_temp = vec_mean(work.D_temp, n); 125 126 // Compute inf norm of q 127 inf_norm_q = vec_norm_inf(work.data.q, n); 128 129 // If norm_q == 0, set it to 1 (ignore it in the scaling) 130 // NB: Using the same function as with vectors here 131 limit_scaling(&inf_norm_q, 1); 132 133 // Compute max between avg norm of cols of P and inf norm of q 134 c_temp = c_max(c_temp, inf_norm_q); 135 136 // Limit scaling (use same function as with vectors) 137 limit_scaling(&c_temp, 1); 138 139 // Invert scaling c = 1 / cost_measure 140 c_temp = 1. / c_temp; 141 142 // Scale P 143 mat_mult_scalar(work.data.P, c_temp); 144 145 // Scale q 146 vec_mult_scalar(work.data.q, c_temp, n); 147 148 // Update cost scaling 149 work.scaling.c *= c_temp; 150 } 151 152 153 // Store cinv, Dinv, Einv 154 work.scaling.cinv = 1. / work.scaling.c; 155 vec_ew_recipr(work.scaling.D, work.scaling.Dinv, work.data.n); 156 vec_ew_recipr(work.scaling.E, work.scaling.Einv, work.data.m); 157 158 159 // Scale problem vectors l, u 160 vec_ew_prod(work.scaling.E, work.data.l, work.data.l, work.data.m); 161 vec_ew_prod(work.scaling.E, work.data.u, work.data.u, work.data.m); 162 163 return 0; 164 } 165 166 } // EMBEDDED 167 168 c_int unscale_data(OSQPWorkspace *work) { 169 // Unscale cost 170 mat_mult_scalar(work.data.P, work.scaling.cinv); 171 mat_premult_diag(work.data.P, work.scaling.Dinv); 172 mat_postmult_diag(work.data.P, work.scaling.Dinv); 173 vec_mult_scalar(work.data.q, work.scaling.cinv, work.data.n); 174 vec_ew_prod(work.scaling.Dinv, work.data.q, work.data.q, work.data.n); 175 176 // Unscale constraints 177 mat_premult_diag(work.data.A, work.scaling.Einv); 178 mat_postmult_diag(work.data.A, work.scaling.Dinv); 179 vec_ew_prod(work.scaling.Einv, work.data.l, work.data.l, work.data.m); 180 vec_ew_prod(work.scaling.Einv, work.data.u, work.data.u, work.data.m); 181 182 return 0; 183 } 184 185 c_int unscale_solution(OSQPWorkspace *work) { 186 // primal 187 vec_ew_prod(work.scaling.D, 188 work.solution.x, 189 work.solution.x, 190 work.data.n); 191 192 // dual 193 vec_ew_prod(work.scaling.E, 194 work.solution.y, 195 work.solution.y, 196 work.data.m); 197 vec_mult_scalar(work.solution.y, work.scaling.cinv, work.data.m); 198 199 return 0; 200 }