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