QPALM 1.0.0
Proximal Augmented Lagrangian method for Quadratic Programs
termination.c
Go to the documentation of this file.
1/**
2 * @file termination.c
3 * @author Ben Hermans
4 * @brief Routines to check the termination and infeasibility criteria.
5 * @details The routines in this file compute the primal and dual residuals,
6 * the primal and dual tolerances, check whether the problem is solved
7 * completely, unscale and store the solution if that is the case, check
8 * whether the intermediate problem is solved and whether one of the
9 * infeasibility criteria hold. In other words, all routines related to
10 * the termination of the optimization algorithm are grouped in this file.
11 */
12#include "termination.h"
13#include "lin_alg.h"
14#include "constants.h"
15#include "global_opts.h"
16#include "util.h"
17#include "iteration.h"
18
24}
25
27 size_t m = work->data->m;
28 if (work->settings->scaling) {
29 vec_ew_prod(work->scaling->Einv, work->pri_res, work->temp_m, m);
30 work->info->pri_res_norm = vec_norm_inf(work->temp_m, m);
31 } else {
32 work->info->pri_res_norm = vec_norm_inf(work->pri_res, m);
33 }
34}
35
37 size_t n = work->data->n;
38 if (work->settings->scaling) {
39 if (work->settings->proximal) {
40 vec_add_scaled(work->x, work->x0, work->xx0, -1, n);
41 vec_add_scaled(work->dphi, work->xx0, work->temp_n, -1/work->gamma, n);
42 vec_ew_prod(work->scaling->Dinv, work->temp_n, work->temp_n, n);
43 work->info->dua_res_norm = vec_norm_inf(work->temp_n, n);
44 vec_ew_prod(work->scaling->Dinv, work->dphi, work->temp_n, n);
45 work->info->dua2_res_norm = vec_norm_inf(work->temp_n, n);
46 } else {
47 vec_ew_prod(work->scaling->Dinv, work->dphi, work->temp_n, n);
48 work->info->dua_res_norm = vec_norm_inf(work->temp_n, n);
49 work->info->dua2_res_norm = work->info->dua_res_norm;
50 }
51 work->info->dua_res_norm *= work->scaling->cinv;
52 work->info->dua2_res_norm *= work->scaling->cinv;
53
54 } else {
55 if (work->settings->proximal) {
56 vec_add_scaled(work->x, work->x0, work->xx0, -1, n);
57 vec_add_scaled(work->dphi, work->xx0, work->temp_n, -1/work->gamma, n);
58 work->info->dua_res_norm = vec_norm_inf(work->temp_n, n);
59 work->info->dua2_res_norm = vec_norm_inf(work->dphi, n);
60 } else {
61 work->info->dua_res_norm = vec_norm_inf(work->dphi, n);
62 work->info->dua2_res_norm = work->info->dua_res_norm;
63 }
64 }
65}
66
68 size_t m = work->data->m;
69 if (work->settings->scaling) {
70 /**NB Implementation detail: store Einv*Ax and Einv*z in temp_2m.
71 * The infinity norm of that vector is equal to the maximum
72 * of the infinity norms of Einv*Ax and Einv*z.*/
73 vec_ew_prod(work->scaling->Einv, work->Ax, work->temp_2m, m);
74 vec_ew_prod(work->scaling->Einv, work->z, work->temp_2m + m, m);
75 work->eps_pri = work->settings->eps_abs + work->settings->eps_rel*vec_norm_inf(work->temp_2m, m);
76 } else {
77 work->eps_pri = work->settings->eps_abs + work->settings->eps_rel*c_max(
78 vec_norm_inf(work->Ax, m),
79 vec_norm_inf(work->z, m));
80 }
81}
82
84 size_t n = work->data->n;
85 c_float norm_DinvQx, norm_Dinvq, norm_DinvAtyh, max_norm;
86 if (work->settings->scaling) {
87 vec_ew_prod(work->scaling->Dinv, work->Qx, work->temp_n, n);
88 norm_DinvQx = vec_norm_inf(work->temp_n, n);
89 vec_ew_prod(work->scaling->Dinv, work->data->q, work->temp_n, n);
90 norm_Dinvq = vec_norm_inf(work->temp_n, n);
91 vec_ew_prod(work->scaling->Dinv, work->Atyh, work->temp_n, n);
92 norm_DinvAtyh = vec_norm_inf(work->temp_n, n);
93 } else {
94 norm_DinvQx = vec_norm_inf(work->Qx, n);
95 norm_Dinvq = vec_norm_inf(work->data->q, n);
96 norm_DinvAtyh = vec_norm_inf(work->Atyh, n);
97 }
98
99 max_norm = c_max(norm_DinvQx, c_max(norm_Dinvq, norm_DinvAtyh));
100 if (work->settings->scaling) max_norm *= work->scaling->cinv;
101
102 work->eps_dua = work->settings->eps_abs + work->settings->eps_rel*max_norm;
103 work->eps_dua_in = work->eps_abs_in + work->eps_rel_in*max_norm;
104}
105
107 return (work->info->pri_res_norm < work->eps_pri) &&
108 (work->info->dua_res_norm < work->eps_dua);
109}
110
112 size_t n = work->data->n;
113 size_t m = work->data->m;
114 c_float eps_pinf_norm_Edy;
115
116 //dy = yh-y
117 vec_add_scaled(work->yh, work->y, work->delta_y, -1, m);
118 if (work->settings->scaling) {
119 //Edy = E.*dy
120 vec_ew_prod(work->scaling->E, work->delta_y, work->temp_m, m);
121 eps_pinf_norm_Edy = work->settings->eps_prim_inf*vec_norm_inf(work->temp_m, m);
122 } else {
123 eps_pinf_norm_Edy = work->settings->eps_prim_inf*vec_norm_inf(work->delta_y, m);
124 }
125
126 if (eps_pinf_norm_Edy == 0) { //dy == 0
127 return 0;
128 }
129
130 vec_add_scaled(work->Atyh, work->Aty, work->Atdelta_y, -1, n);
131 if (work->settings->scaling) {
132 vec_ew_prod(work->scaling->Dinv, work->Atdelta_y, work->Atdelta_y, n);
133 }
134
135 //out_of_bounds = bmax'*max(dy,0) + bmin'*min(dy,0)
136 c_float out_of_bounds = 0;
137 if (work->settings->scaling)
138 {
139 for(size_t i=0; i < m; i++)
140 {
141 out_of_bounds += (work->data->bmax[i] < work->scaling->E[i]*QPALM_INFTY) ? work->data->bmax[i]*c_max(work->delta_y[i], 0) : 0;
142 out_of_bounds += (work->data->bmin[i] > -work->scaling->E[i]*QPALM_INFTY) ? work->data->bmin[i]*c_min(work->delta_y[i], 0) : 0;
143 }
144 }
145 else
146 {
147 for(size_t i=0; i < m; i++)
148 {
149 out_of_bounds += (work->data->bmax[i] < QPALM_INFTY) ? work->data->bmax[i]*c_max(work->delta_y[i], 0) : 0;
150 out_of_bounds += (work->data->bmin[i] > -QPALM_INFTY) ? work->data->bmin[i]*c_min(work->delta_y[i], 0) : 0;
151 }
152 }
153
154 return (vec_norm_inf(work->Atdelta_y, n) <= eps_pinf_norm_Edy)
155 && (out_of_bounds <= -eps_pinf_norm_Edy);
156
157}
158
160 c_float eps_dinf_norm_Ddx, dxQdx, dxdx;
161 size_t n = work->data->n;
162 size_t m = work->data->m;
163
164 //dx = x-x_prev
165 vec_add_scaled(work->x, work->x_prev, work->delta_x, -1, n);
166 if (work->settings->scaling) {
167 //D*dx
168 vec_ew_prod(work->scaling->D, work->delta_x, work->temp_n, n);
169 eps_dinf_norm_Ddx = work->settings->eps_dual_inf*vec_norm_inf(work->temp_n, n);
170 dxdx = vec_prod(work->temp_n, work->temp_n, n);
171 } else {
172 eps_dinf_norm_Ddx = work->settings->eps_dual_inf*vec_norm_inf(work->delta_x, n);
173 dxdx = vec_prod(work->delta_x, work->delta_x, n);
174 }
175
176 if (eps_dinf_norm_Ddx == 0) { //dx == 0
177 return 0;
178 }
179
180 size_t k;
181 //NB Adx = work->Ad (= tau*Ad of the previous iteration)
182 if (work->settings->scaling) {
183 vec_ew_prod(work->scaling->Einv, work->Ad, work->Adelta_x, m);
184 for (k = 0; k < m; k++) {
185 if ((work->data->bmax[k] < work->scaling->E[k]*QPALM_INFTY && work->Adelta_x[k] >= eps_dinf_norm_Ddx)
186 || (work->data->bmin[k] > -work->scaling->E[k]*QPALM_INFTY && work->Adelta_x[k] <= -eps_dinf_norm_Ddx)) {
187 return 0;
188 }
189 }
190 } else {
191 for (k = 0; k < m; k++) {
192 if ((work->data->bmax[k] < QPALM_INFTY && work->Ad[k] >= eps_dinf_norm_Ddx)
193 || (work->data->bmin[k] > -QPALM_INFTY && work->Ad[k] <= -eps_dinf_norm_Ddx)) {
194 return 0;
195 }
196 }
197 }
198 //NB Qdx = work->Qd (= tau*Qd of the previous iteration)
199 //NB Qdx = work->Qd - tau/gamma*d (= tau*Qd of the previous iteration) if proximal is used
200 if (work->settings->proximal) {
201 vec_add_scaled(work->Qd, work->d, work->temp_n, -work->tau/work->gamma, n);
202 dxQdx = vec_prod(work->delta_x, work->temp_n, n);
203 } else {
204 dxQdx = vec_prod(work->Qd, work->delta_x, n);
205 }
206 if (work->settings->scaling) {
207 return (dxQdx <= -work->scaling->c*work->settings->eps_dual_inf*work->settings->eps_dual_inf*dxdx)
208 || ((dxQdx <= work->scaling->c*work->settings->eps_dual_inf*work->settings->eps_dual_inf*dxdx)
209 && (vec_prod(work->data->q, work->delta_x, n) <= -work->scaling->c*eps_dinf_norm_Ddx));
210 } else {
211 return (dxQdx <= -work->settings->eps_dual_inf*work->settings->eps_dual_inf*dxdx)
212 || ((dxQdx <= work->settings->eps_dual_inf*work->settings->eps_dual_inf*dxdx)
213 && (vec_prod(work->data->q, work->delta_x, n) <= -eps_dinf_norm_Ddx));
214 }
215}
216
218 if (work->settings->scaling) {
219 vec_ew_prod(work->x, work->scaling->D, work->solution->x, work->data->n);
220 vec_self_mult_scalar(work->yh, work->scaling->cinv, work->data->m);
221 vec_ew_prod(work->yh, work->scaling->E, work->solution->y, work->data->m);
222 } else {
223 prea_vec_copy(work->x, work->solution->x, work->data->n);
224 prea_vec_copy(work->yh, work->solution->y, work->data->m);
225 }
226 work->info->objective = compute_objective(work);
227}
228
230 return (work->info->dua2_res_norm <= work->eps_dua_in);
231}
Constants used in QPALM.
#define QPALM_INFTY
infinity, used to indicate one-sided constraints
Definition: constants.h:61
Custom memory allocation, print and utility functions, and data types for floats and ints.
ladel_int c_int
type for integer numbers
Definition: global_opts.h:42
ladel_double c_float
type for floating point numbers
Definition: global_opts.h:41
#define c_max(a, b)
maximum of two values
Definition: global_opts.h:92
#define c_min(a, b)
minimum of two values
Definition: global_opts.h:96
QPALM main solver routines.
c_float compute_objective(QPALMWorkspace *work)
Compute the (unscaled) primal objective value at the current iterate.
Definition: iteration.c:287
Linear algebra with vectors.
void vec_add_scaled(const c_float *a, const c_float *b, c_float *c, c_float sc, size_t n)
Scaled addition of one vector to another vector, .
Definition: lin_alg.c:110
void vec_self_mult_scalar(c_float *a, c_float sc, size_t n)
Mulitply vector with a constant scale factor.
Definition: lin_alg.c:56
void vec_ew_prod(const c_float *a, const c_float *b, c_float *c, size_t n)
Elementwise product, .
Definition: lin_alg.c:92
c_float vec_prod(const c_float *a, const c_float *b, size_t n)
Inner product between two vectors, .
Definition: lin_alg.c:72
void prea_vec_copy(const c_float *a, c_float *b, size_t n)
Copy vector a into preallocated vector b.
Definition: lin_alg.c:24
c_float vec_norm_inf(const c_float *a, size_t n)
Infinity norm of a vector, .
Definition: lin_alg.c:126
size_t m
number of constraints m
Definition: types.h:104
c_float * bmin
dense array for lower bounds (size m)
Definition: types.h:109
size_t n
number of variables n
Definition: types.h:103
c_float * q
dense array for linear part of cost function (size n)
Definition: types.h:107
c_float * bmax
dense array for upper bounds (size m)
Definition: types.h:110
c_float pri_res_norm
norm of primal residual
Definition: types.h:80
c_float dua2_res_norm
norm of intermediate dual residual (minus proximal term)
Definition: types.h:82
c_float objective
objective function value
Definition: types.h:84
c_float dua_res_norm
norm of dual residual
Definition: types.h:81
c_float * Dinv
primal variable rescaling
Definition: types.h:63
c_float c
objective scaling
Definition: types.h:66
c_float * E
dual variable scaling
Definition: types.h:64
c_float * Einv
dual variable rescaling
Definition: types.h:65
c_float cinv
objective rescaling
Definition: types.h:67
c_float * D
primal variable scaling
Definition: types.h:62
c_int proximal
boolean, use proximal method of multipliers or not
Definition: types.h:131
c_float eps_dual_inf
dual infeasibility tolerance
Definition: types.h:126
c_float eps_prim_inf
primal infeasibility tolerance
Definition: types.h:125
c_float eps_rel
relative convergence tolerance
Definition: types.h:121
c_int scaling
scaling iterations, if 0 then scaling is disabled
Definition: types.h:135
c_float eps_abs
absolute convergence tolerance
Definition: types.h:120
c_float * y
dual solution
Definition: types.h:45
c_float * x
primal solution
Definition: types.h:44
QPALM Workspace.
Definition: types.h:197
c_float * delta_y
difference of consecutive dual iterates
Definition: types.h:279
c_float * x
primal iterate
Definition: types.h:204
c_float * y
dual iterate
Definition: types.h:205
c_float * yh
candidate dual update
Definition: types.h:229
QPALMScaling * scaling
scaling vectors
Definition: types.h:306
c_float eps_pri
primal tolerance
Definition: types.h:268
c_float * Ax
scaled A * x
Definition: types.h:206
QPALMInfo * info
solver information
Definition: types.h:308
c_float * z
projection of Axys onto the constraint set [bmin, bmax]
Definition: types.h:226
c_float * temp_m
placeholder for vector of size m
Definition: types.h:217
QPALMSolution * solution
problem solution
Definition: types.h:307
c_float * pri_res
primal residual
Definition: types.h:227
c_float tau
stepsize
Definition: types.h:245
c_float eps_dua
dual tolerance
Definition: types.h:269
c_float * x_prev
previous primal iterate
Definition: types.h:209
c_float * Adelta_x
A * delta_x.
Definition: types.h:290
c_float * delta_x
difference of consecutive primal iterates
Definition: types.h:288
c_float * Qx
scaled Q * x
Definition: types.h:207
c_float eps_rel_in
intermediate relative tolerance
Definition: types.h:272
QPALMSettings * settings
problem settings
Definition: types.h:305
c_float * x0
record of the primal iterate during the last dual update
Definition: types.h:232
c_float eps_dua_in
intermediate dual tolerance
Definition: types.h:270
c_float gamma
proximal penalty factor
Definition: types.h:223
c_float * dphi
gradient of the Lagrangian
Definition: types.h:234
c_float * xx0
x - x0
Definition: types.h:233
c_float * Atdelta_y
A' * delta_y.
Definition: types.h:280
c_float * temp_2m
placeholder for vector of size 2m
Definition: types.h:254
c_float * Ad
A * d.
Definition: types.h:247
c_float * Aty
A' * y (useful for saving one mat_tpose_vec)
Definition: types.h:208
c_float eps_abs_in
intermediate absolute tolerance
Definition: types.h:271
QPALMData * data
problem data to work on (possibly scaled)
Definition: types.h:198
c_float * Qd
Q * d.
Definition: types.h:246
c_float * temp_n
placeholder for vector of size n
Definition: types.h:218
c_float * d
primal update step
Definition: types.h:237
c_float * Atyh
A' * yh.
Definition: types.h:230
c_int is_primal_infeasible(QPALMWorkspace *work)
Check whether the problem is primal infeasible.
Definition: termination.c:111
void calculate_residual_norms_and_tolerances(QPALMWorkspace *work)
Calls the routines that compute the norm of the residuals and the tolerances.
Definition: termination.c:19
void store_solution(QPALMWorkspace *work)
Helper function to store the (unscaled) solution in the solution struct.
Definition: termination.c:217
c_int is_solved(QPALMWorkspace *work)
Check whether the primal and dual residual norms are smaller than the primal and dual tolerances.
Definition: termination.c:106
c_int is_dual_infeasible(QPALMWorkspace *work)
Check whether the problem is dual infeasible.
Definition: termination.c:159
c_int check_subproblem_termination(QPALMWorkspace *work)
Check whether the subproblem is solved.
Definition: termination.c:229
void calculate_primal_tolerance(QPALMWorkspace *work)
Calculates the primal tolerance and stores it in work->eps_pri.
Definition: termination.c:67
void calculate_dual_tolerances(QPALMWorkspace *work)
Calculates the dual tolerance for the problem and current subproblem and stores them in work->eps_dua...
Definition: termination.c:83
void calculate_dual_residuals(QPALMWorkspace *work)
Calculates the infinity norm of the dual residual and the residual of the subproblem and stores them ...
Definition: termination.c:36
void calculate_primal_residual(QPALMWorkspace *work)
Calculates the infinity norm of the primal residual and stores it in work->info->pri_res_norm.
Definition: termination.c:26
Routines to check the termination and infeasibility criteria.
Utility functions.