bazar  1.3.1
ls_minimizer2.cpp
Go to the documentation of this file.
1 /*
2 Copyright 2005, 2006 Computer Vision Lab,
3 Ecole Polytechnique Federale de Lausanne (EPFL), Switzerland.
4 All rights reserved.
5 
6 This file is part of BazAR.
7 
8 BazAR is free software; you can redistribute it and/or modify it under the
9 terms of the GNU General Public License as published by the Free Software
10 Foundation; either version 2 of the License, or (at your option) any later
11 version.
12 
13 BazAR is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
15 PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License along with
18 BazAR; if not, write to the Free Software Foundation, Inc., 51 Franklin
19 Street, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21 #include <iostream>
22 #include <iomanip>
23 #include <algorithm>
24 
25 #include <math/mcvm.h>
26 #include <math/polynom_solver.h>
27 #include "ls_minimizer2.h"
28 
29 using namespace std;
30 
31 #define msg(level, M) (level <= verbose_level) ? (cout << M) : (cout << "")
32 
34 {
35  state=0;
36  new_state=0;
37  best_state=0;
38  scales=0;
39  step_solver=0;
40  ground_truth_state=0;
41  J=0;
42  use_user_scaling = false;
43  use_automated_scaling = true;
44  new_iteration_callback = 0;
45  state_change_callback = 0;
46  set_default_values();
47  set_state_size(state_size);
48 }
49 
50 void ls_minimizer2::set_state_size(int state_size)
51 {
52  free_all();
53  if (state_size<=0) return;
54 
55  this->state_size = state_size;
56  state = new flt_t[state_size];
57  new_state = new flt_t[state_size];
58  best_state = new flt_t[state_size];
59  scales = new flt_t[state_size];
60  for(int i = 0; i < state_size; i++)
61  scales[i] = 1.;
62 }
63 
64 void ls_minimizer2::alloc_matrices(int maximum_scalar_measure_number)
65 {
66  assert(state_size>0);
67  assert(maximum_scalar_measure_number>0);
68 
69  if (J && real_J_size>=maximum_scalar_measure_number) {
70  step_solver->resize(state_size, maximum_scalar_measure_number);
71  return;
72  }
73 
74  free_matrices();
75  step_solver = new ls_step_solver(state_size, maximum_scalar_measure_number);
76  real_J_size = maximum_scalar_measure_number;
77  J = cvCreateMat(maximum_scalar_measure_number, state_size, CV_64F);
78  newJ = cvCreateMat(maximum_scalar_measure_number, state_size, CV_64F);
79  eps = cvCreateMat(maximum_scalar_measure_number, 1, CV_64F);
80  eps_previous = cvCreateMat(maximum_scalar_measure_number, 1, CV_64F);
81  //Jt = cvCreateMat(state_size, maximum_scalar_measure_number, CV_64F);
82  JtJ = cvCreateMat(state_size, state_size, CV_64F);
83  Jteps = cvCreateMat(state_size, 1, CV_64F);
84  ds = cvCreateMat(state_size, 1, CV_64F);
85  Jds = cvCreateMat(maximum_scalar_measure_number, 1, CV_64F);
86 
87  // For Levenberg-Marquardt:
88  aug_JtJ = cvCreateMat(state_size, state_size, CV_64F);
89 
90  // For Dog Leg:
91  dl_delta_sd = cvCreateMat(state_size, 1, CV_64F);
92  dl_delta_gn = cvCreateMat(state_size, 1, CV_64F);
93  dl_delta_dl = cvCreateMat(state_size, 1, CV_64F);
94  dl_delta_diff = cvCreateMat(state_size, 1, CV_64F);
95  JtJdelta = cvCreateMat(state_size, 1, CV_64F);
96  JJteps = cvCreateMat(maximum_scalar_measure_number, 1, CV_64F);
97 
98  // For Cat Tail:
99  ct_delta_gn = cvCreateMat(state_size, 1, CV_64F);
100  ct_delta_sd = cvCreateMat(state_size, 1, CV_64F);
101 
102 }
103 
105  free_all();
106 }
107 
108 void ls_minimizer2::free_all()
109 {
110  if (state) {
111  delete[] state;
112  delete[] new_state;
113  delete[] best_state;
114  delete[] scales;
115  delete[] ground_truth_state;
116  }
117  free_matrices();
118 }
119 
120 void ls_minimizer2::free_matrices()
121 {
122  if (step_solver) delete step_solver;
123  step_solver=0;
124 
125  if (J==0) return;
126 
127  cvReleaseMat(&J);
128  cvReleaseMat(&newJ);
129  cvReleaseMat(&eps);
130  cvReleaseMat(&eps_previous);
131  //cvReleaseMat(&Jt);
132  cvReleaseMat(&JtJ);
133  cvReleaseMat(&Jteps);
134  cvReleaseMat(&ds);
135  cvReleaseMat(&Jds);
136 
137  cvReleaseMat(&aug_JtJ);
138  cvReleaseMat(&dl_delta_sd);
139  cvReleaseMat(&dl_delta_gn);
140  cvReleaseMat(&dl_delta_dl);
141  cvReleaseMat(&dl_delta_diff);
142  cvReleaseMat(&JtJdelta);
143  cvReleaseMat(&JJteps);
144 
145  cvReleaseMat(&ct_delta_gn);
146  cvReleaseMat(&ct_delta_sd);
147 }
148 
149 void ls_minimizer2::set_user_data(int slot_index, void * ptr)
150 {
151  assert((unsigned)slot_index< 10);
152  user_data[slot_index] = ptr;
153 }
154 
155 
157 {
158  flt_t norm = 0;
159  for(int i = 0; i < state_size; i++)
160  norm += scales[i] * scales[i];
161  norm = sqrt(norm);
162 
163  for(int i = 0; i < state_size; i++)
164  this->scales[i] = scales[i] / (state_size * norm);
165 
166  use_user_scaling = true;
167 }
168 
169 void ls_minimizer2::set_default_values(void)
170 {
171  set_verbose_level(0);
172 
173  default_squared_c = numeric_limits<flt_t>::max();
174 
175  lm_set_initial_lambda(0);
176  lm_set_max_iterations(50);
177  lm_set_max_failures_in_a_row(10);
178  lm_set_tol_cos(1e-5);
179 
180  ct_set_max_iterations(50);
181  set_line_search_parameters(1e-3, 5, 1.2);
182 
183  inside_julien_method = false;
184 }
185 
187 {
188  verbose_level = vl;
189 }
190 
192 {
193  lm_max_iterations = it;
194 }
195 
197 {
198  lm_max_failures_in_a_row = f;
199 }
200 
202 {
203  lm_tol_cos = t;
204 }
205 
207 {
208  lm_initial_lambda = l;
209 }
210 
212 {
213  ct_lambda0 = lambda0;
214  ct_k_rough = k_rough;
215  ct_k_fine = k_fine;
216 }
217 
218 
220 {
221  // For debugging:
222  if(ground_truth_state) delete[] ground_truth_state;
223  ground_truth_state = new flt_t[state_size];
224  for(int i = 0; i < state_size; i++)
225  ground_truth_state[i] = state[i];
226 }
227 
229 {
230  new_iteration_callback = callback;
231 }
232 
234 {
235  state_change_callback = callback;
236 }
237 
239  erase_observations(0);
240 }
241 
243 {
244  assert(b<0 || (a<=b));
245  if (a >= (signed)observations.size()) return;
246  observation_vector::iterator first = observations.begin()+a;
247  observation_vector::iterator last = (b<0 ? observations.end() : observations.begin()+b);
248  for (observation_vector::iterator it = first; it != last; ++it)
249  {
250  if ((*it)->delete_me) delete *it;
251  else if ((*it)->array_delete_me) delete[] *it;
252  }
253  observations.erase(first,last);
254  assert(a == (signed)observations.size());
255 }
256 
258 {
259  default_squared_c = c * c;
260 }
261 
262 void ls_minimizer2::add_observation(observation *obs, bool to_delete, bool to_array_delete)
263 {
264  assert(!(to_delete && to_array_delete));
265 
266  //if (obs->weight <=0) return;
267 
268  obs->sqrt_weight = obs->weight*obs->weight;
269  obs->delete_me = to_delete;
270  obs->array_delete_me = to_array_delete;
271  observations.push_back(obs);
272 }
273 
275 {
276  observation *o = observations.back();
277  assert(o!=0);
278 
279  o->squared_c = c*c;
280 }
281 
283 {
284  observation *o = observations.back();
285  assert(o!=0);
286  o->c_min = c_min;
287  o->c_max = c_max;
288 }
289 
291 {
292  observation *o = observations.back();
293  assert(o!=0);
294  o->weight = weight;
295  o->sqrt_weight = sqrt(weight);
296 }
297 
299 {
300  observation *o = observations.back();
301  assert(o!=0);
302  o->confidence = confidence;
303 }
304 
306 {
307  observation *o = observations.back();
308  assert(o!=0);
309  o->outlier = true;
310 }
311 
313 {
314  int n = get_nb_measures();
315  flt_t r=0;
316  for (int i=0; i<n; i++) {
317  flt_t d = computed_b[i] - b[i];
318  r += d*d;
319  }
320  return r;
321 }
322 
323 ls_minimizer2::flt_t ls_minimizer2::residual(flt_t * state)
324 {
325  flt_t result = 0.;
326 
327  flt_t b[MAX_B_SIZE];
328 
329  for (observation_vector::iterator it = observations.begin();
330  it != observations.end(); ++it)
331  {
332  observation *obs = *it;
333  obs->eval_func(state, b, 0, user_data);
334  result += obs->weight*rho(obs->residual(b), obs->squared_c);
335  }
336  return result;
337 }
338 
340 {
341  if (ground_truth_state==0) return;
342  cout << endl;
343  cout << "FOUND: ";
344  compute_residual(state, true);
345  cout << "GROUND TRUTH: ";
346  compute_residual(ground_truth_state, true);
347 
348  if (new_iteration_callback != 0) new_iteration_callback(state, user_data);
349 }
350 
352 {
353  int correct_inlier_number = 0, correct_outlier_number = 0;
354 
355  flt_t b[MAX_B_SIZE];
356 
357  int gt_inliers = 0;
358 
359  int observation_number = 0;
360  for (observation_vector::iterator it = observations.begin();
361  it != observations.end(); ++it)
362  {
363  observation *o = *it;
364  o->eval_func(state, b, 0, user_data);
365  flt_t diff = o->residual(b);
366 
367  if (diff < o->squared_c && !o->ground_truth_outlier)
368  correct_inlier_number++;
369  else if (diff >= o->squared_c && o->ground_truth_outlier)
370  correct_outlier_number++;
371 
372  if (!o->ground_truth_outlier) gt_inliers++;
373  ++observation_number;
374  }
375 
376 
377  cout << endl;
378  cout << (100.0 * correct_inlier_number) / gt_inliers << "% inliers and ";
379  cout << (100.0 * correct_outlier_number) / (observation_number - gt_inliers) << "% outliers correctly found.";
380  cout << endl;
381 }
382 
383 ls_minimizer2::flt_t ls_minimizer2::build_eps(flt_t * state, flt_t current_best_residual, bool outliers_in_residual)
384 {
385  int im_n = 0;
386  flt_t residual = 0;
387 
388  if (new_iteration_callback != 0) new_iteration_callback(state, user_data);
389 
390  flt_t b[MAX_B_SIZE];
391  /*flt_t diff[MAX_B_SIZE];*/
392  nb_inliers = 0;
393  for (observation_vector::iterator it = observations.begin();
394  it != observations.end(); ++it)
395  {
396  observation *o = *it;
397  o->eval_func(state, b, newJ->data.db + im_n*state_size, user_data);
398 
399  flt_t res = o->residual(b);
400  assert(res >= 0);
401  assert(o->squared_c>=0);
402  int n = o->get_nb_measures();
403  if (res < o->squared_c)
404  {
405  o->outlier = false;
406  nb_inliers++;
407  if (o->weight != 1.) {
408  for(int j = 0; j < n*state_size; j++)
409  (newJ->data.db + im_n * state_size)[j] *= o->sqrt_weight;
410  }
411  for (int i=0; i<n; ++i)
412  eps->data.db[im_n+i] = o->sqrt_weight * (o->b[i] - b[i]);
413  im_n+=n;
414  residual += o->weight * res;
415  assert(o->weight >=0);
416  }
417  else
418  {
419  o->outlier = true;
420  if (outliers_in_residual)
421  residual += o->weight * o->squared_c;
422  }
423 
424  if (residual > current_best_residual) {
425  eps->rows = 0;
426  newJ->rows = 0;
427  return numeric_limits<flt_t>::max();
428  }
429  }
430 
431  eps->rows = im_n;
432  newJ->rows = im_n;
433  return residual;
434 }
435 
436 ls_minimizer2::flt_t ls_minimizer2::build_eps_return_inlier_residual(flt_t * state, flt_t current_best_residual)
437 {
438  return build_eps(state, current_best_residual, false);
439 }
440 
441 ls_minimizer2::flt_t ls_minimizer2::inlier_residual(flt_t * state, flt_t current_best_residual)
442 {
443  flt_t residual = 0;
444 
445  if (new_iteration_callback != 0) new_iteration_callback(state, user_data);
446 
447  flt_t b[MAX_B_SIZE];
448 
449  for (observation_vector::iterator it = observations.begin();
450  it != observations.end(); ++it)
451  {
452  observation *obs = *it;
453  if (!obs->outlier) {
454  obs->eval_func(state, b, 0, user_data);
455  residual += obs->weight * obs->residual(b);
456  if (residual > current_best_residual) return numeric_limits<flt_t>::max();
457  }
458  }
459 
460  return residual;
461 }
462 
463 bool ls_minimizer2::build_J(flt_t * state)
464 {
465  int im_n = 0;
466 
467  flt_t b[MAX_B_SIZE];
468  for (observation_vector::iterator it = observations.begin();
469  it != observations.end(); ++it)
470  {
471  observation *obs = *it;
472  if (!obs->outlier) {
473  int n = obs->get_nb_measures();
474  assert(im_n+n <= real_J_size);
475  obs->eval_func(state, b, J->data.db + im_n*state_size, user_data);
476  if (obs->weight != 1.) for(int j = 0; j < n*state_size; j++)
477  (J->data.db + im_n * state_size)[j] *= obs->sqrt_weight;
478  im_n += n;
479  }
480  }
481 
482  J->rows = im_n;
483 
484  return true;
485 }
486 
487 ls_minimizer2::flt_t ls_minimizer2::compute_residual(flt_t * state, bool display)
488 {
489  if (display)
490  for(int i = 0; i < state_size; i++)
491  cout << state[i] << " " << flush;
492 
493  if (new_iteration_callback != 0) new_iteration_callback(state, user_data);
494 
495  flt_t result = residual(state);
496  if (display)
497  cout << " -> " << result << endl;
498 
499  return result;
500 }
501 
502 void ls_minimizer2::show_state(int vl, flt_t * state, flt_t r)
503 {
504  for(int i = 0; i < state_size; i++) {
505  msg(vl, state[i]);
506  if (i < state_size - 1)
507  msg(vl, ", ");
508  }
509  msg(vl, " --> " << setprecision(20) << r << setprecision(6) << endl);
510 }
511 
512 bool ls_minimizer2::build_J_and_stuff(flt_t * state)
513 {
514  //build_J(state);
515  // Julien: build_eps computed newJ
516  CvMat *tmp = J;
517  J = newJ;
518  newJ = tmp;
519 
520  if (J->rows == 0)
521  {
522  msg(0, "**: No inliers found" << endl);
523  return false;
524  }
525  //Jt->cols = J->rows;
526  // Jteps = Jt * eps
527  cvGEMM(J, eps, 1, 0, 1, Jteps, CV_GEMM_A_T);
528  cvMulTransposed(J, JtJ, 1);
529 
530  return true;
531 }
532 
533 void ls_minimizer2::set_current_c_s(flt_t k)
534 {
535  if (k < 0)
536  {
537  if (inside_julien_method) return;
538  for (observation_vector::iterator it = observations.begin();
539  it != observations.end(); ++it)
540  {
541  observation *o = *it;
543  }
544  }
545  else
546  {
547  for (observation_vector::iterator it = observations.begin();
548  it != observations.end(); ++it)
549  {
550  observation *o = *it;
551  flt_t c = exp(k * log(o->c_max) + (1. - k) * log(o->c_min));
552  o->squared_c_current = c * c;
553  }
554  }
555 }
556 
558 {
559  int n=0;
560  int nobs=0;
561  if (observations.size()==0) return 0;
562 
563  for (observation_vector::iterator it = observations.begin();
564  it != observations.end(); ++it)
565  {
566  n += (*it)->get_nb_measures();
567  nobs++;
568  }
569  msg(2,nobs << " obs, " << n << " measures"<<endl);
570  return n;
571 }
572 
580 {
581  msg(1, "LM: Beginning optimization using Levenberg-Marquardt:" << endl);
582 
583  alloc_matrices(count_measures());
584 
585  assert(step_solver!=0);
586  set_new_state(initial_state);
587  assert(step_solver!=0);
588 
589  double *state = new flt_t[state_size];
590  memcpy(state, initial_state, state_size*sizeof(flt_t));
591 
592  set_current_c_s();
593 
594  flt_t lambda = lm_initial_lambda, rho = 0., cosinus = 0.;
595  int iter_nb = 0, failures_in_a_row = 0;
596  int reason = 0;
597  flt_t r_previous = build_eps(state), r=0.;
598 
599  eps_previous->rows = eps->rows; cvCopy(eps, eps_previous);
600  build_J_and_stuff(state);
601  cvCopy(JtJ, aug_JtJ);
602 
603  msg(1, "LM: "); show_state(1, state, r_previous);
604 
605  while(iter_nb < lm_max_iterations)
606  {
607  iter_nb++;
608  msg(2, "LM: iteration # " << iter_nb << " --------------------------------------------" << endl);
609 
610  do {
611  for(int i = 0; i < state_size; i++)
612  if (use_user_scaling)
613  aug_JtJ->data.db[i * state_size + i] = JtJ->data.db[i * state_size + i] + lambda * scales[i];
614  else if (use_automated_scaling)
615  aug_JtJ->data.db[i * state_size + i] = JtJ->data.db[i * state_size + i] +
616  lambda * (1 + JtJ->data.db[i * state_size + i] * JtJ->data.db[i * state_size + i]);
617  else
618  aug_JtJ->data.db[i * state_size + i] = JtJ->data.db[i * state_size + i] + lambda;
619 
620  assert(aug_JtJ->cols == state_size && state_size == aug_JtJ->rows);
621 
622  if (!step_solver->qr_solve(aug_JtJ, Jteps, ds)) {
623  reason = -1;
624  goto lm_end;
625  }
626 
627  assert(aug_JtJ->cols == state_size && state_size == aug_JtJ->rows);
628 
630  for(int i = 0; i < state_size; i++) {
631  new_state[i] = state[i];
632  state[i] = state[i] + ds->data.db[i];
633  }
634 
635  set_new_state(state);
636  r = build_eps(state);
637  rho = r_previous - r;
638  if (rho > 0) {
639  rho /= lambda * cvDotProduct(ds, ds) + cvDotProduct(ds, Jteps);
640 
641  Jds->rows = J->rows;
642  cvMatMul(J, ds, Jds);
643  cosinus = cvDotProduct(eps_previous, Jds) / (sqrt(r_previous) * sqrt(cvDotProduct(Jds, Jds)));
644  msg(2, "LM: cosinus = " << cosinus << endl);
645  if (cosinus < lm_tol_cos) {
646  reason = 3;
647  goto lm_end;
648  }
649  eps_previous->rows = eps->rows; cvCopy(eps, eps_previous);
650 
651  build_J_and_stuff(state);
652  cvCopy(JtJ, aug_JtJ);
653  r_previous = r;
654  lambda = lambda / 10;
655 
656  failures_in_a_row = 0;
657  msg(2, "LM: iteration succeeded: new lambda = " << lambda << endl);
658  msg(2, "LM: "); show_state(2, state, r);
659  if (verbose_level >= 3) { compare_outliers_with_ground_truth(); compare_state_with_ground_truth(); }
660  }
661  else {
662  memcpy(state, new_state, state_size*sizeof(flt_t));
663  failures_in_a_row++;
664  if (failures_in_a_row > lm_max_failures_in_a_row) {
665  reason = 2;
666  goto lm_end;
667  }
668  if (lambda == 0) lambda = 1e-3; else lambda *= 10;
669 
670  msg(2, "LM: iteration failed --> " << r << " new lambda = " << lambda << endl);
671  }
672  } while(rho < 0);
673  }
674 lm_end:
675  if (iter_nb >= lm_max_iterations)
676  reason = 4;
677 
678  switch(reason) {
679  case 2: msg(1, "LM: " << failures_in_a_row << " failures in a row." << endl); break;
680  case 3: msg(1, "LM: Termination criterion satisfied: cosinus = " << cosinus << " < " << lm_tol_cos << endl);
681  break;
682  case 4: msg(1, "LM: Too many iterations." << endl); break;
683  case -1: msg(1, "LM: qr_solve failed\n"); break;
684  default:
685  msg(1, "LM: unkown termination reason" << endl);
686  }
687 
688  msg(1, "LM: ");
689  for(int i = 0; i < state_size; i++)
690  {
691  msg(1, state[i]);
692  if (i < state_size - 1)
693  msg(1, ", ");
694  }
695  msg(1, " --> " << r << endl);
696  msg(1, "LM: End of minimization." << endl);
697 
698  if (new_iteration_callback != 0) new_iteration_callback(state, user_data);
699 
700  delete[] state;
701  return reason;
702 }
703 
704 void ls_minimizer2::set_new_state(const flt_t *new_state)
705 {
706  if (memcmp(new_state, state, sizeof(flt_t)*state_size)==0) return;
707  for(int i = 0; i < state_size; i++) state[i] = new_state[i];
708  if (state_change_callback) state_change_callback(state, user_data);
709 }
710 
711 ls_minimizer2::flt_t ls_minimizer2::dl_update_Delta(flt_t rho, flt_t Delta, flt_t rho_min, flt_t rho_max)
712 {
713  if (rho < rho_min) return Delta / 2;
714  if (rho > rho_max) return Delta * 2;
715  return rho;
716 }
717 
719 {
720  msg(1, "DL: Beginning optimization using Dog Leg algorithm:" << endl);
721 
722  alloc_matrices(count_measures());
723 
724  set_new_state(initial_state);
725 
726  set_current_c_s();
727 
728  flt_t Delta = 10000., rho = 0., cosinus = 0.;
729  flt_t dl_delta_gn_computed = false;
730  int iter_nb = 0, failures_in_a_row = 0;
731  int reason = 0;
732 
733  flt_t r_previous = build_eps(state), r = 0.;
734  eps_previous->rows = eps->rows; cvCopy(eps, eps_previous);
735  build_J_and_stuff(state);
736 
737  msg(1, "DL: "); show_state(1, state, r_previous);
738 
739  while(iter_nb < lm_max_iterations)
740  {
741  iter_nb++;
742  msg(2, "DL: iteration # " << iter_nb << " --------------------------------------------" << endl);
743 
744  JJteps->rows = J->rows;
745  cvMatMul(J, Jteps, JJteps);
746  cvScale(Jteps, dl_delta_sd, cvDotProduct(Jteps, Jteps) / cvDotProduct(JJteps, JJteps));
747 
748  dl_delta_gn_computed = false;
749 
750  do {
751  msg(2, "DL: Delta = " << Delta << endl);
752  if (cvDotProduct(dl_delta_sd, dl_delta_sd) > Delta * Delta)
753  {
754  cvScale(dl_delta_sd, dl_delta_dl, Delta / cvDotProduct(dl_delta_sd, dl_delta_sd));
755  msg(2, "DL: Trying truncated steepest descent step" << endl);
756  }
757  else {
758  if (!dl_delta_gn_computed) {
759  step_solver->qr_solve(JtJ, Jteps, dl_delta_gn);
760  // step_solver->qr_solve(J, eps, dl_delta_gn);
761  dl_delta_gn_computed = true;
762  }
763  if (cvDotProduct(dl_delta_gn, dl_delta_gn) <= Delta * Delta)
764  {
765  cvCopy(dl_delta_gn, dl_delta_dl);
766 
767  msg(2, "DL: Trying gauss-newton step" << endl);
768  }
769  else {
770  cvSub(dl_delta_gn, dl_delta_sd, dl_delta_diff);
771  flt_t beta1, beta2, beta;
772  solve_deg2(cvDotProduct(dl_delta_diff, dl_delta_diff),
773  2 * cvDotProduct(dl_delta_sd, dl_delta_diff),
774  cvDotProduct(dl_delta_sd, dl_delta_sd) - Delta * Delta,
775  beta1, beta2);
776  beta = (beta1 > 0) ? beta1 : beta2;
777  cvScaleAdd(dl_delta_diff, cvScalar(beta), dl_delta_sd, dl_delta_dl);
778 
779  msg(2, "DL: Trying truncated gauss-newton step" << endl);
780  }
781  }
782  for(int i = 0; i < state_size; i++) new_state[i] = state[i] + dl_delta_dl->data.db[i];
784  r = build_eps(new_state);
785  cvMatMul(JtJ, dl_delta_dl, JtJdelta);
786  flt_t L_delta = 2 * ( 0.5 * r_previous - cvDotProduct(Jteps, dl_delta_dl) + 0.5 * cvDotProduct(dl_delta_dl, JtJdelta));
787  rho = (r_previous - r) / (r_previous - L_delta);
788  if (rho > 0) {
789  set_new_state(new_state);
790  Jds->rows = J->rows;
791  cvMatMul(J, dl_delta_dl, Jds);
792  cosinus = cvDotProduct(eps_previous, Jds) / (sqrt(r_previous) * sqrt(cvDotProduct(Jds, Jds)));
793  msg(2, "DL: cosinus = " << cosinus << endl);
794  if (cosinus < dl_tol_cos) {
795  reason = 3;
796  goto dl_end;
797  }
798  eps_previous->rows = eps->rows; cvCopy(eps, eps_previous);
799  r_previous = r;
800  build_J_and_stuff(state);
801 
802  failures_in_a_row = 0;
803  msg(2, "DL: "); show_state(2, state, r);
804  if (verbose_level >= 3) { compare_outliers_with_ground_truth(); compare_state_with_ground_truth(); }
805  }
806  else {
807  msg(2, "DL: -> failure." << endl);
808 
809  failures_in_a_row++;
810  if (failures_in_a_row > lm_max_failures_in_a_row) {
811  reason = 2;
812  goto dl_end;
813  }
814  }
815  Delta = dl_update_Delta(rho, Delta, 0.25, 0.75);
816  } while(rho < 0);
817  }
818 dl_end:
819  if (iter_nb >= lm_max_iterations)
820  reason = 4;
821 
822  if (reason == 2) msg(1, "DL: " << failures_in_a_row << " failures in a row." << endl);
823  if (reason == 3) msg(1, "DL: Termination criterion satisfied: cosinus = " << cosinus << " < " << lm_tol_cos << endl);
824  if (reason == 4) msg(1, "DL: Too many iterations." << endl);
825 
826  msg(1, "DL: ");
827  for(int i = 0; i < state_size; i++)
828  {
829  msg(1, state[i]);
830  if (i < state_size - 1)
831  msg(1, ", ");
832  }
833  msg(1, " --> " << r << endl);
834  msg(1, "DL: End of minimization." << endl);
835 
836  if (new_iteration_callback != 0) new_iteration_callback(state, user_data);
837 
838  return reason;
839 }
840 
841 bool ls_minimizer2::line_search(CvMat * dir,
842  flt_t lambda_min, flt_t lambda_max,
843  flt_t residual0, flt_t & new_residual, flt_t & new_lambda)
844 {
845  lambda_min = lambda_max = 0.; //
846 
847  alloc_matrices(count_measures());
848 
849  static flt_t lambda = ct_lambda0;
850  for(int i = 0; i < state_size; i++) new_state[i] = state[i] + lambda * dir->data.db[i];
851  flt_t residual_lambda = inlier_residual(new_state, residual0);
852  flt_t old_residual = residual_lambda;
853 
854  while(residual_lambda > residual0)
855  {
856  msg(2, " LS: rough search lambda = " << lambda << endl);
857  lambda /= ct_k_rough;
858  for(int i = 0; i < state_size; i++) new_state[i] = state[i] + lambda * dir->data.db[i];
859  old_residual = residual_lambda;
860  residual_lambda = inlier_residual(new_state, residual0);
861  }
862 
863  while(residual_lambda < residual0)
864  {
865  msg(2, " LS: rough search lambda = " << lambda << endl);
866  residual0 = residual_lambda;
867  lambda *= ct_k_rough;
868  for(int i = 0; i < state_size; i++) new_state[i] = state[i] + lambda * dir->data.db[i];
869  old_residual = residual_lambda;
870  residual_lambda = inlier_residual(new_state, old_residual);
871  }
872  lambda /= ct_k_rough;
873  residual_lambda = old_residual;
874  for(int i = 0; i < state_size; i++) new_state[i] = state[i] + lambda * dir->data.db[i];
875 
876  bool found = false;
877  while(residual_lambda < new_residual)
878  {
879  msg(2, " LS: fine search lambda = " << lambda << endl);
880  new_residual = residual_lambda;
881  memcpy(best_state, new_state, state_size * sizeof(flt_t));
882  new_lambda = lambda;
883  found = true;
884 
885  lambda *= ct_k_fine;
886  for(int i = 0; i < state_size; i++) new_state[i] = state[i] + lambda * dir->data.db[i];
887  residual_lambda = build_eps(new_state, new_residual);
888  }
889 
890  return found;
891 }
892 
894 {
895  return a->confidence > b->confidence;
896 }
897 
899 {
900  msg(1, "CT: Beginning optimization using Cat Tail algorithm:" << endl);
901 
902  alloc_matrices(count_measures());
903 
904  sort(observations.begin(), observations.end(), confidence_cmp);
905  //observations.sort();
906 
907  memcpy(state, initial_state, state_size * sizeof(flt_t));
908 
909  set_current_c_s();
910 
911  flt_t r;
912  int iter_nb = 0;
913  int reason;
914  do
915  {
916  if (verbose_level >= 3) { msg(3, "CT: "); compare_state_with_ground_truth(); }
917 
918  r = build_eps_return_inlier_residual(state);
919  flt_t best_r = r;
920  build_J_and_stuff(state);
921 
922  msg(2, "CT " << nb_inliers << " inliers." << endl);
923 
924  int method = -1;
925  flt_t best_lambda, gain = 0.;
926 
927  step_solver->qr_solve(J, eps, ct_delta_gn);
928  for(int i = 0; i < state_size; i++) best_state[i] = state[i] + ct_delta_gn->data.db[i];
929  flt_t r_gn = inlier_residual(best_state, best_r);
930  if (r_gn < best_r)
931  {
932  gain = r - r_gn;
933  best_r = r_gn;
934  method = 1;
935  }
936 
937  for(int i = 0; i < state_size; i++) ct_delta_sd->data.db[i] = Jteps->data.db[i] / JtJ->data.db[i * state_size + i];
938  if (line_search(ct_delta_sd, 0.0001, 1, r, best_r, best_lambda))
939  {
940  gain = r - best_r;
941  method = 2;
942  }
943 
944  if (method == -1)
945  {
946  reason = 2;
947  goto ct_end;
948  }
949  else if (method == 1)
950  msg(2, "CT: Taking the gauss-newton step." << endl);
951  else if (method == 2)
952  msg(2, "CT: Taking the corrected linear model step (lambda = " << best_lambda << ")." << endl);
953  else
954  {
955  cerr << "bug in ls_minimizer2::minimize_using_cattail_from" << endl;
956  exit(0);
957  }
958 
959  msg(2, "CT: Gain = " << gain << " --> residual = " << best_r << endl);
960  memcpy(state, best_state, state_size * sizeof(flt_t));
961 
962  r = best_r;
963  iter_nb++;
965  } while(iter_nb < ct_max_iterations);
966  reason = 4;
967 
968 ct_end:
969  if (reason == 2) msg(2, "CT: no improvement found." << endl);
970  if (reason == 4) msg(2, "CT: Too many iterations (" << ct_max_iterations << ")." << endl);
971 
972  msg(1, "CT: ");
973  for(int i = 0; i < state_size; i++)
974  {
975  msg(1, state[i]);
976  if (i < state_size - 1)
977  msg(1, ", ");
978  }
979  msg(1, " --> " << r << endl);
980  msg(1, "CT: End of minimization." << endl);
981 
982  if (new_iteration_callback != 0) new_iteration_callback(state, user_data);
983 
984  return 4;
985 }
986 
987 bool ls_minimizer2::pick_random_indices(int *idx, int n, int max_index)
988 {
989 
990  if ( n > max_index ) return false;
991 
992  for (int i=0; i<n; i++) {
993  idx[i] = rand()%max_index;
994 
995  for (int j=0; j<i; j++)
996  if (idx[i]==idx[j]) {
997  --i;
998  break;
999  }
1000  }
1001  return true;
1002 }
1003 
1004 static inline unsigned mymin(unsigned a, unsigned b) {
1005  return (a>b? b : a);
1006 }
1007 
1009  int nb_samples,
1010  int min_number_of_inliers, int max_number_of_iterations)
1011 {
1012  alloc_matrices(count_measures());
1013 
1014  sort(observations.begin(), observations.end(), confidence_cmp);
1015  //observations.sort();
1016 
1017  /*flt_t b[MAX_B_SIZE];*/
1018  flt_t best_residual = numeric_limits<flt_t>::max();
1019  int *idx = new int[nb_samples];
1020  observation **o = new observation *[nb_samples];
1021  for(int iter = 0; iter < max_number_of_iterations; iter++)
1022  {
1023  if (!pick_random_indices(idx, nb_samples, mymin(iter + nb_samples, observations.size())))
1024  {
1025  cerr << "PR: not enough observations." << endl;
1026  return false;
1027  }
1028 
1029  for (int i=0; i<nb_samples; i++) {
1030  //o[i] = observations[idx[i]];
1031  observation_vector::iterator it=observations.begin();
1032  for (int j=0; j<idx[i]; ++i) ++it;
1033  o[i] = *it;
1034  }
1035 
1037  if (f(new_state, o, nb_samples, user_data))
1038  {
1039  set_new_state(new_state);
1040  flt_t new_residual = build_eps(state, best_residual);
1041  if (new_residual < best_residual)
1042  {
1043  best_residual = new_residual;
1044  memcpy(best_state, state, state_size * sizeof(flt_t));
1045  int nb_inliers = 0;
1046  for (observation_vector::iterator it = observations.begin();
1047  it != observations.end(); ++it)
1048  {
1049  if (!(*it)->outlier)
1050  nb_inliers++;
1051  }
1052  if (nb_inliers > min_number_of_inliers)
1053  break;
1054  }
1055  }
1056  }
1057 
1058  delete[] o;
1059  delete[] idx;
1060 
1061  memcpy(state, best_state, state_size * sizeof(flt_t));
1062  return best_residual;
1063 }
1064 
1065 ls_minimizer2::flt_t ls_minimizer2::minimize_using_julien_method_from(const flt_t * initial_state, int nb_steps, int nb_iterations_per_step)
1066 {
1067  alloc_matrices(count_measures());
1068  inside_julien_method = true;
1069  ct_set_max_iterations(nb_iterations_per_step);
1070 
1071  memcpy(state, initial_state, state_size * sizeof(flt_t));
1072 
1073  for(int i = 0; i < nb_steps; i++)
1074  {
1075  msg(2, endl);
1076  msg(2, "-----------------------------------------------------------------" << endl);
1077  msg(2, " STEP # " << i << " / " << nb_steps << endl);
1078  msg(2, "-----------------------------------------------------------------" << endl);
1079  set_current_c_s(1. - flt_t(i) / (nb_steps - 1));
1080  minimize_using_cattail_from(state);
1081  }
1082 
1083  ct_set_max_iterations(50);
1084  minimize_using_cattail_from(state);
1085 
1086  inside_julien_method = false;
1087 
1088  return 0;
1089 }
1090 
1092 {
1093  alloc_matrices(count_measures());
1094  flt_t b0[MAX_B_SIZE];
1095  flt_t b[MAX_B_SIZE];
1096 
1097  int obsnb=0;
1098 
1099  for (observation_vector::iterator it = observations.begin();
1100  it != observations.end(); ++it)
1101  {
1102  cout << "OBS #" << obsnb++ << endl;
1103 
1104  observation *o = *it;
1105  int n = o->get_nb_measures();
1106  flt_t * J = new flt_t[n * state_size];
1107  set_new_state(state0);
1108  o->eval_func(state, b0, J, user_data);
1109 
1110  for(int j = 0; j < state_size; j++)
1111  {
1112  for(int k = 0; k < state_size; k++)
1113  new_state[k] = state0[k];
1114  new_state[j] += state_step;
1115 
1116  set_new_state(new_state);
1117 
1118  o->eval_func(state, b, 0, user_data);
1119  for (int i=0; i<n; i++) {
1120  flt_t analytic = J[i*state_size + j];
1121  flt_t numeric = (b[i] - b0[i])/state_step;
1122 
1123  cout << " (df" << i << "/ds" << j << ") = "
1124  << analytic << " = " << numeric << endl;
1125  }
1126  }
1127 
1128  delete [] J;
1129  }
1130 }
1131 
1132 void ls_minimizer2::add_observation_2data_1measure(func_nn_ptr f, const flt_t data[2], const flt_t goal)
1133 {
1134  observation_nn<2,1> *o = new observation_nn<2,1>(f, data, &goal);
1135  o->set_default_values();
1136  add_observation(o, true, false);
1137 }
1138 
1139 void ls_minimizer2::add_observation_3data_1measure(func_nn_ptr f, const flt_t data[3], const flt_t goal)
1140 {
1141  observation_nn<3,1> *o = new observation_nn<3,1>(f, data, &goal);
1142  o->set_default_values();
1143  add_observation(o, true, false);
1144 }
1145 
1146 void ls_minimizer2::add_observation_2data_2measures(func_nn_ptr f, const flt_t data[2], const flt_t goal[2])
1147 {
1148  observation_nn<2,2> *o = new observation_nn<2,2>(f, data, goal);
1149  o->set_default_values();
1150  add_observation(o, true, false);
1151 }
1152 
1153 void ls_minimizer2::add_observation_3data_2measures(func_nn_ptr f, const flt_t data[3], const flt_t goal[2])
1154 {
1155  observation_nn<3,2> *o = new observation_nn<3,2>(f, data, goal);
1156  o->set_default_values();
1157  add_observation(o, true, false);
1158 }