DuQuad  v1.0
Quadratic Programming Optimizations
 All Data Structures Files Functions Variables Typedefs Macros
alm.c
Go to the documentation of this file.
1 /*
2  * alm.c
3  *
4  * Created on: Nov 3, 2014
5  * Author: sverre
6  */
7 
8 #include "alm.h"
9 
10 /* static functions declaration */
11 
12 static int32_t solve_ALM();
13 static real_t dual_obj();
14 static void clean_up_inner_problem();
15 static void init_inner_problem();
16 
17 
18 /* public functions definition */
19 
21 {
22  // Make z0 feasible
23  if(!s->info->ub_is_inf)
24  vector_min(s->prob->ub,s->prob->z0,s->prob->z0,N);
25  if(!s->info->lb_is_inf)
26  vector_max(s->prob->lb,s->prob->z0,s->prob->z0,N);
27 
28  // Initialize the "inner" problem
29  struct Struct_FGM p_in;
30  init_inner_problem(s, &p_in);
31  if (solve_ALM(s,&p_in) == -1){
32  ERROR("Error in solving solveALM()\n");
33  clean_up_inner_problem(&p_in);
34  return -1;
35  };
36 
37  clean_up_inner_problem(&p_in);
38  _SDEBUG("End of ALM()\n");
39  return 0;
40 }
41 
42 static int32_t solve_ALM(struct Struct_ALM *s, struct Struct_FGM *p_in)
43 {
44 
45  // calculating alpha
46  real_t alpha = s->opt->rho;
47 
48  // Dynamc Arrays for ds and pf
49  struct Array ds_array, pf_array;
50  initArray(&ds_array, 100);
51  initArray(&pf_array, 100);
52 
53  // Declaration and initialization of other necessary variables
54  real_t pf = s->opt->eps_pf + 1;
55  uint32_t niter_feasible_ds = 0;
56  uint32_t niter_feasible_pf = 0;
57  uint32_t last_eps_ds;
58  uint32_t niter = 1;
59  real_t dual_value_new = 0.0;
60  real_t dual_value_diff = s->opt->eps_ds + 1;
61  s->res->exitflag = 1;
62  s->res->out->exitflag_inner = 1;
64 
65  // Clock
66  clock_t tic, toc, tic_in, toc_in;
67  tic = clock();
68 
69  // solve inner problem first time
70  // with: c_in = c + A'*lambda - rho*Atb
71  // NOTE: As long as lambda = 0, c_in = c - rho*A'*b
72  vector_sub(s->prob->c,s->rho_At_b,p_in->c,N);
73  vector_copy(s->prob->z0,p_in->z0,N); // Initialize z0
74  uint32_t niter_inner = 0;
75 
76  tic_in = clock();
77  niter_inner += FGM(p_in);
78  toc_in = clock();
79 
80  s->res->out->time_tot_inner = (real_t)(toc_in-tic_in);
81  if(p_in->exitflag == 2){
82  s->res->out->exitflag_inner = 2;
84  }
85 
86  vector_copy(p_in->zopt,s->z,N);
87  mtx_vec_mul(s->prob->A,s->z,s->A_z,M,N); // used in dual_obj
88  vector_copy(s->z,s->summ,N);
89 
90 
91  // find the value of the Dual Function (Lagrangian) first time
92  real_t dual_value = dual_obj(s);
93 
94  /* ##################################################################################
95  START WHILE-LOOP
96  ################################################################################## */
97 
98  while (dual_value_diff > s->opt->eps_ds || pf > s->opt->eps_pf)
99  {
100 
101  if (niter > s->opt->maxiter_outer){
102  //printf("reached maximum number of iterations in ALM\n");
103  s->res->exitflag = 2;
104  niter_feasible_ds--;
105  niter_feasible_pf--;
106  break;
107  }
108 
109  if (dual_value_diff < s->opt->eps_ds){
110  niter_feasible_ds++;
111  last_eps_ds = 1;
112  }
113  else
114  last_eps_ds = 0;
115 
116  if (pf < s->opt->eps_pf)
117  niter_feasible_pf++;
118 
119  /* *********************************************************************
120  Finding the next lambda
121  ********************************************************************* */
122 
123  // lambda += alpha * (A*z - b_lb_hat)
124  // NOTE: re-use the 'lambda' vector instead of creating 'lambda_new'
125 
126  // lambda += alpha * (A*z - b)
127  vector_sub(s->A_z,s->prob->b,s->temp3_dim_M,M); // ANS - b
128  vector_scalar_mul(s->temp3_dim_M,alpha,s->temp3_dim_M,M); // ANS * alpha
129  vector_add(s->temp3_dim_M,s->lambda,s->lambda,M); // lambda += ANS
130  // NOTE: No projection
131 
132 
133  /* *********************************************************************
134  Solving the inner problem
135  ********************************************************************* */
136 
137  // First calculate the new c (c_hat) for the inner problem,
138  // c_hat = p_in->c = c + A' * lambda - rho*A'*b
139  vector_copy(s->prob->c,p_in->c,N);
140 
141  // p_in->c = c + A' * lambda - rho*a'*b
142  mtx_vec_mul(s->prob->A_t,s->lambda,s->temp1_dim_N,N,M); // A' * lambda
143  vector_add(p_in->c,s->temp1_dim_N,p_in->c,N); // p_in->c = ANS + c
144  vector_sub(p_in->c,s->rho_At_b,p_in->c,N);
145 
146  // Compute the new optimal z (s->z) from the inner problem
147  vector_copy(s->z, p_in->z0, N); // Warm start
148 
149  tic_in = clock();
150  niter_inner += FGM(p_in);
151  toc_in = clock();
152  s->res->out->time_tot_inner += (real_t)(toc_in-tic_in);
153  if(p_in->exitflag == 2){
154  s->res->out->exitflag_inner = 2;
156  }
157 
158  vector_copy(p_in->zopt,s->z,N);
159  mtx_vec_mul(s->prob->A,s->z,s->A_z,M,N); // used in dual_obj. Only solved here in the while loop
160 
161  /* *********************************************************************
162  Finding dual_value_diff
163  ********************************************************************* */
164 
165  // calculate the difference between the new and previous Lagrangian value
166  dual_value_new = dual_obj(s);
167  dual_value_diff = abs_2(dual_value_new - dual_value);
168  dual_value = dual_value_new;
169 
170  /* *********************************************************************
171  Finding pf
172  ********************************************************************* */
173 
174  // pf = norm2( max([A*z_pf - b_ub_hat ; -A*z_pf + b_lb_hat]) , 0) )
175  // NOTE: Algorithm 1 (last) => we use z_pf = z
176  // Algorithm 2 (average) => we use z_pf = z_avg = summ_k / (niter+1)
177 
178  if (s->opt->algorithm == 5) {
179  // *** LAST z in stopping criteria ***
180 
181  vector_sub(s->A_z,s->prob->b,s->pf_vec,M); // (A*z) - b
182  // NOTE: No projection
183 
184  }
185  else if (s->opt->algorithm == 6) {
186  // *** AVERAGE z in pf stopping criteria ***
187 
188  vector_add(s->summ,s->z,s->summ,N); // summ += z
189  vector_scalar_mul(s->summ,1.0/(1+niter),s->z_avg,N); // z_avg = summ / (niter+1)
190  mtx_vec_mul(s->prob->A,s->z_avg,s->temp2_dim_M,M,N); // A * z_avg
191 
192  vector_sub(s->temp2_dim_M,s->prob->b,s->pf_vec,M); // (A*z) - b
193  // NOTE: No projection
194  }
195  else {
196  ERROR("Choose algorithm 5 or 6 when running ALM()\n");
197  return -1;
198  }
199 
200  // Take the norm
201  pf = vector_norm_2(s->pf_vec, s->info->pf_vec_length); // norm2
202 
203  // store the result of the stopping criterias
204  insertArray(&ds_array, dual_value_diff);
205  insertArray(&pf_array, pf);
206 
207  /* *********************************************************************
208  Update the variables
209  ********************************************************************* */
210  niter++;
211 
212  } /* #### END WHILE-LOOP #### */
213 
214 
215  /* *********************************************************************
216  Setting the result
217  ********************************************************************* */
218 
219  // Clock
220  toc = clock();
221  s->res->out->time = (real_t)(toc - tic) / CLOCKS_PER_SEC;
222  s->res->out->time_tot_inner /= CLOCKS_PER_SEC;
223 
224  if (s->opt->algorithm == 5) {
225  s->res->zopt = s->z;
226  s->res->fopt = obj(s->z, s->prob->H, s->prob->c, s->temp1_dim_N);
227  }
228  else if (s->opt->algorithm == 6) {
229  s->res->zopt = s->z_avg;
230  s->res->fopt = obj(s->z_avg, s->prob->H, s->prob->c, s->temp1_dim_N);
231  }
232  else {
233  ERROR("Choose algorithm 5 or 6 when running ALM()\n");
234  return -1;
235  }
236 
237  s->res->lambda1 = s->lambda;
238  //s->res->lambda2 = s->lambda2; hva skjer her ????????????+
239  s->res->out->iterations = --niter;
240  s->res->out->iterations_inner_tot = niter_inner;
241  s->res->out->niter_feasible_ds = ++niter_feasible_ds;
242  s->res->out->niter_feasible_pf = ++niter_feasible_pf;
243 
244  if (last_eps_ds == 1)
245  s->res->out->flag_last_satisfied = 2;
246  else
247  s->res->out->flag_last_satisfied = 1;
248 
249  // Copy ds_vector and pf_vector
250  s->res->out->ds_vector = (real_t *)realloc(s->res->out->ds_vector, (niter) * sizeof(real_t));
251  s->res->out->pf_vector = (real_t *)realloc(s->res->out->pf_vector, (niter) * sizeof(real_t));
252  vector_copy(ds_array.array,s->res->out->ds_vector,niter);
253  vector_copy(pf_array.array,s->res->out->pf_vector,niter);
254  freeArray(&ds_array);
255  freeArray(&pf_array);
256 
257  return 0;
258 }
259 
260 
261 /* Definition of static functions */
262 
263 static real_t dual_obj(struct Struct_ALM *s, const uint32_t prob_case)
264 {
265  /*return: 0.5z'Hz + c'z + lambda'*(A*z - b) + 0.5*rho*norm(A*z-b) */
266 
267  // f_value = 0.5*z'Hz + c'z;
268  real_t f_value = obj(s->z, s->prob->H, s->prob->c, s->temp1_dim_N);
269 
270  // f_value += lambda'*(A*z-b)
271 
272  vector_sub(s->A_z,s->prob->b,s->temp3_dim_M,M); // (A*z) - b
273  f_value += vector_mul(s->lambda,s->temp3_dim_M,M);
274 
275  real_t nor = vector_norm_2(s->temp3_dim_M,M);
276  f_value += 0.5 * s->opt->rho * (nor*nor);
277 
278  return f_value;
279 }
280 
281 static void init_inner_problem(const struct Struct_ALM *s, struct Struct_FGM *p_in)
282 {
283  // Setting the inner problem to point to the outer problem except for c and z0
284  // Setting the inner problem to point to the same as the outer saves some memory
285  p_in->H = s->H_hat;
286  p_in->lb = s->prob->lb;
287  p_in->ub = s->prob->ub;
288  p_in->lb_is_inf = s->info->lb_is_inf;
289  p_in->ub_is_inf = s->info->ub_is_inf;
290  p_in->eigH_max = s->info->eigH_max;
291  p_in->eigH_min = s->info->eigH_min;
292 
293  // Make own allocation for c (This is changing for each outer iteration)
294  p_in->c = vector_alloc(N);
295  // Copy z0
296  p_in->z0 = vector_alloc(N);
297 
298  // Allocate other necessary vectors
299  p_in->zopt = vector_alloc(N);
300  p_in->z = vector_alloc(N);
301  p_in->y = vector_alloc(N);
302  p_in->znew = vector_alloc(N);
303  p_in->ynew = vector_alloc(N);
304  p_in->temp1_dim_N = vector_alloc(N);
305 
306  // Initialize options
307  //p_in->opt = malloc(sizeof * p_in->opt);
308  p_in->maxiter = s->opt->maxiter_inner;
309  p_in->eps = s->opt->eps_inner;
310 }
311 
312 static void clean_up_inner_problem(struct Struct_FGM *s)
313 {
314  free_pointer(s->c);
315  free_pointer(s->z0);
316  free_pointer(s->zopt);
317  free_pointer(s->z);
318  free_pointer(s->y);
319  free_pointer(s->znew);
320  free_pointer(s->ynew);
322 }
void vector_add(const real_t *v1, const real_t *v2, real_t *res, const uint32_t length)
struct Info * info
Definition: alm.h:25
void free_pointer(real_t *pointer)
real_t time_tot_inner
Definition: qp_structs.h:54
void insertArray(struct Array *a, real_t element)
real_t abs_2(const real_t a)
unsigned int uint32_t
Definition: typedefs.h:19
real_t time
Definition: qp_structs.h:53
real_t * A_t
Definition: qp_structs.h:19
uint32_t algorithm
Definition: qp_structs.h:34
struct Result * res
Definition: alm.h:26
real_t eigH_min
Definition: fgm.h:37
real_t * A_z
Definition: alm.h:37
real_t obj(const real_t *z, const real_t *H, const real_t *c, real_t *temp)
boolean ub_is_inf
Definition: fgm.h:35
void vector_min(const real_t *v1, const real_t *v2, real_t *res, const uint32_t length)
void initArray(struct Array *a, uint32_t initialSize)
real_t * vector_alloc(uint32_t size)
struct Output * out
Definition: qp_structs.h:70
real_t * temp2_dim_M
Definition: alm.h:32
boolean ub_is_inf
Definition: qp_structs.h:40
Definition: alm.h:21
real_t * zopt
Definition: qp_structs.h:65
uint32_t iterations_inner_tot
Definition: qp_structs.h:52
real_t * summ
Definition: alm.h:35
real_t * ub
Definition: fgm.h:25
real_t * z_avg
Definition: alm.h:34
real_t * lb
Definition: qp_structs.h:23
real_t * temp1_dim_N
Definition: fgm.h:44
real_t * znew
Definition: fgm.h:42
real_t * ds_vector
Definition: qp_structs.h:60
uint32_t exitflag
Definition: qp_structs.h:67
uint32_t flag_last_satisfied
Definition: qp_structs.h:55
real_t eps
Definition: fgm.h:48
real_t * pf_vec
Definition: alm.h:36
real_t * lb
Definition: fgm.h:24
real_t * y
Definition: fgm.h:41
real_t eigH_max
Definition: fgm.h:36
uint32_t pf_vec_length
Definition: qp_structs.h:47
real_t eps_ds
Definition: qp_structs.h:31
real_t * H
Definition: qp_structs.h:16
real_t fopt
Definition: qp_structs.h:66
uint32_t iterations
Definition: qp_structs.h:51
real_t * H
Definition: fgm.h:22
boolean lb_is_inf
Definition: fgm.h:34
uint32_t exitflag
Definition: fgm.h:31
real_t * A
Definition: qp_structs.h:18
real_t * z
Definition: alm.h:29
struct Options * opt
Definition: alm.h:24
real_t * ub
Definition: qp_structs.h:24
uint32_t maxiter_outer
Definition: qp_structs.h:29
void vector_sub(const real_t *v1, const real_t *v2, real_t *res, const uint32_t length)
real_t * H_hat
Definition: alm.h:40
uint32_t FGM(struct Struct_FGM *s)
Definition: fgm.c:12
signed int int32_t
Definition: typedefs.h:15
uint32_t niter_feasible_pf
Definition: qp_structs.h:57
real_t * lambda1
Definition: qp_structs.h:68
real_t vector_norm_2(real_t *v, const uint32_t length)
uint32_t M
Definition: head.h:34
real_t * lambda
Definition: alm.h:30
uint32_t num_exceeded_max_niter_inner
Definition: qp_structs.h:59
real_t * temp3_dim_M
Definition: alm.h:33
real_t * rho_At_b
Definition: alm.h:42
void vector_copy(const real_t *v1, real_t *v2, const uint32_t length)
real_t eps_inner
Definition: qp_structs.h:33
real_t * z
Definition: fgm.h:40
float64_t real_t
Definition: typedefs.h:25
uint32_t exitflag_inner
Definition: qp_structs.h:58
boolean lb_is_inf
Definition: qp_structs.h:39
struct Problem * prob
Definition: alm.h:23
void vector_scalar_mul(const real_t *v1, const real_t scalar, real_t *res, const uint32_t length)
void mtx_vec_mul(const real_t *mtx, const real_t *v, real_t *res, const uint32_t rows, const uint32_t cols)
real_t * ynew
Definition: fgm.h:43
#define _SDEBUG(fmt)
Definition: head.h:60
real_t * z0
Definition: fgm.h:26
real_t * temp1_dim_N
Definition: alm.h:31
uint32_t maxiter_inner
Definition: qp_structs.h:30
real_t rho
Definition: qp_structs.h:35
real_t * z0
Definition: qp_structs.h:25
real_t * c
Definition: fgm.h:23
void vector_max(const real_t *v1, const real_t *v2, real_t *res, const uint32_t length)
real_t eigH_min
Definition: qp_structs.h:44
#define ERROR(fmt)
Definition: head.h:54
real_t * pf_vector
Definition: qp_structs.h:61
real_t eps_pf
Definition: qp_structs.h:32
real_t eigH_max
Definition: qp_structs.h:43
uint32_t maxiter
Definition: fgm.h:47
uint32_t niter_feasible_ds
Definition: qp_structs.h:56
Definition: fgm.h:20
void freeArray(struct Array *a)
real_t vector_mul(const real_t *v1, const real_t *v2, const uint32_t length)
int32_t ALM(struct Struct_ALM *s)
Definition: alm.c:20
real_t * zopt
Definition: fgm.h:29
real_t * b
Definition: qp_structs.h:20
uint32_t N
Definition: head.h:33
real_t * c
Definition: qp_structs.h:17