contrib/gel/vsrl/vsrl_dynamic_program.cxx

Go to the documentation of this file.
00001 #include "vsrl_dynamic_program.h"
00002 #include <vcl_cstdlib.h>
00003 #include <vsrl/vsrl_token.h>
00004 #include <vsrl/vsrl_null_token.h>
00005 #include <vsrl/vsrl_parameters.h>
00006 #include <vcl_cassert.h>
00007 #include <vcl_iostream.h>
00008 
00009 // this class will perform a dynamic program
00010 
00011 // constructor
00012 vsrl_dynamic_program::vsrl_dynamic_program()
00013 {
00014   // get the global parameters
00015 
00016   search_range_= vsrl_parameters::instance()->correlation_range; // probably 10
00017   inner_cost_= vsrl_parameters::instance()->inner_cost; // probably 1.0
00018   outer_cost_= vsrl_parameters::instance()->outer_cost; // probably 0.5
00019   continuity_cost_= vsrl_parameters::instance()->continuity_cost; // probably 0.1
00020   num_row_=0;
00021   num_col_=0;
00022 
00023   inner_null_token_ = new vsrl_null_token();
00024   outer_null_token_ = new vsrl_null_token();
00025   inner_null_token_->set_cost(inner_cost_);
00026   outer_null_token_->set_cost(outer_cost_);
00027 
00028   cost_matrix_=0;
00029 }
00030 
00031 // destructor
00032 vsrl_dynamic_program::~vsrl_dynamic_program()
00033 {
00034   delete inner_null_token_;
00035   delete outer_null_token_;
00036 
00037   // deallocate the matrix
00038 
00039   deallocate_cost_matrix();
00040 }
00041 
00042 void vsrl_dynamic_program::set_tokens(token_list &l1,
00043                                       token_list &l2)
00044 {
00045   // set the tokens for the assignments
00046   if (l1.empty() || l2.empty())
00047   {
00048     vcl_cout << "warning empty list\n";
00049     return;
00050   }
00051 
00052   // the first list is a direct copy of l1
00053   list1_.clear();
00054   token_list::iterator ti;
00055 
00056   for (ti=l1.begin();ti!=l1.end();ti++)
00057   {
00058     list1_.push_back(*ti);
00059   }
00060 
00061   // the second list has alternating sets of tokens
00062   // from l2 and null tokens
00063 
00064   list2_.clear();
00065   // set the first token to an outer null token
00066 
00067   list2_.push_back(outer_null_token_);
00068   for (ti=l2.begin();ti!=l2.end();ti++)
00069   {
00070     // push the real token from l2
00071     list2_.push_back(*ti);
00072     // push an inner null token
00073     list2_.push_back(inner_null_token_);
00074   }
00075 
00076   // replace the last inner null token with an outer null token
00077   list2_[list2_.size()-1]=outer_null_token_;
00078 
00079   // set the number of rows and columns of the assignment matrix
00080   num_row_= list1_.size();
00081   num_col_= list2_.size();
00082 
00083   // set the search range for each token
00084 
00085   //define_search_range();
00086 }
00087 
00088 // define the search range for the tokens in list1
00089 
00090 void vsrl_dynamic_program::define_search_range()
00091 {
00092   for (unsigned int i=0;i<list1_.size();i++)
00093   {
00094     int low=i*2+1 - 2*search_range_;
00095     int high=i*2+1 + 2*search_range_;
00096 
00097     if (low<0)
00098       low=0;
00099     if ((unsigned int)low>=list2_.size())
00100       low=list2_.size()-1;
00101     if (high<0)
00102       high=0;
00103     if ((unsigned int)high>list2_.size())
00104       high=list2_.size();
00105 
00106     lower_search_range_.push_back(low);
00107     upper_search_range_.push_back(high);
00108   }
00109 }
00110 
00111 void vsrl_dynamic_program::define_search_range(vnl_vector<int > curr_row)
00112 {
00113   for (unsigned int i=0;i<list1_.size();i++)
00114   {
00115     int low=curr_row[i]*2+1 - 2*search_range_;
00116     int high=curr_row[i]*2+1 + 2*search_range_;
00117 
00118     if (low<0)
00119       low=0;
00120     if ((unsigned int)low>=list2_.size())
00121       low=list2_.size()-1;
00122     if (high<0)
00123       high=0;
00124     if ((unsigned int)high>list2_.size())
00125       high=list2_.size();
00126 
00127     lower_search_range_.push_back(low);
00128     upper_search_range_.push_back(high);
00129   }
00130 }
00131 
00132 
00133 // set the inner null cost
00134 void vsrl_dynamic_program::set_inner_cost(double cost)
00135 {
00136   inner_cost_ = cost;
00137   inner_null_token_->set_cost(cost);
00138 }
00139 
00140 // set the outer null cost
00141 void vsrl_dynamic_program::set_outer_cost(double cost)
00142 {
00143   outer_cost_ = cost;
00144   outer_null_token_->set_cost(cost);
00145 }
00146 
00147 
00148 // set the continuity cost
00149 void vsrl_dynamic_program::set_continuity_cost(double cost)
00150 {
00151   continuity_cost_ = cost;
00152 }
00153 
00154 // set the search range for each token
00155 void vsrl_dynamic_program::set_search_range(int range)
00156 {
00157   search_range_ = range;
00158 }
00159 
00160 // allocate the data matrix
00161 
00162 bool vsrl_dynamic_program::allocate_cost_matrix()
00163 {
00164   // we wish to make a two dimensional of assignment_nodes
00165   // to keep track of the assignment costs
00166 
00167   if (!num_row_ || !num_col_)
00168   {
00169     vcl_cout << "must set new token lists\n";
00170     cost_matrix_ = 0;
00171     return false;
00172   }
00173 
00174   cost_matrix_ = (assignment_node**)(vcl_malloc(num_row_ * sizeof(*cost_matrix_)));
00175 
00176   for (int i=0;i<num_row_;i++)
00177     cost_matrix_[i]=(assignment_node*)(vcl_malloc(num_col_ * sizeof(**cost_matrix_)));
00178 
00179   // initialize the matrix
00180 
00181   for (int i=0;i<num_row_;i++)
00182     for (int j=0;j<num_col_;j++)
00183     {
00184       cost_matrix_[i][j].index1=i;
00185       cost_matrix_[i][j].index2=j;
00186       cost_matrix_[i][j].prior_index1=0;
00187       cost_matrix_[i][j].prior_index2=0;
00188       cost_matrix_[i][j].cost=1000000;
00189       cost_matrix_[i][j].num_null1=0;
00190     }
00191   return true;
00192 }
00193 
00194 void vsrl_dynamic_program::deallocate_cost_matrix()
00195 {
00196   // free the memory associated with matrix
00197 
00198   for (int i=0;i<num_row_;i++)
00199     vcl_free((char*)(cost_matrix_[i]));
00200 
00201   vcl_free((char*)cost_matrix_);
00202 
00203   cost_matrix_=0;
00204   num_row_=0;
00205   num_col_=0;
00206 }
00207 
00208 double vsrl_dynamic_program::execute()
00209 {
00210   // we can now perform the dynamic program
00211 
00212   // allocate the cost matrix
00213 
00214   if (!allocate_cost_matrix())
00215     return 0.0;
00216 
00217 
00218   // compute the cost matrix that will allow us to
00219   // find the cheepest set of assignments
00220 
00221   for (int i=0;i<num_row_;i++)
00222     for (int j=lower_search_range_[i];j<upper_search_range_[i];j++)
00223       compute_cost(i,j);
00224 #ifdef DEBUG
00225   for (int i=0;i<num_row_;i++)
00226   {
00227     vcl_cout<<'\n';
00228     for (int j=lower_search_range_[i];j<upper_search_range_[i];j++)
00229       vcl_cout<<cost_matrix_[i][j].cost<<' ';
00230   }
00231 #endif
00232   // we can now set the optimum assignment
00233 
00234   double cost= optimum_assignment();
00235 
00236   // print_assignments();
00237 
00238    return cost;
00239 }
00240 
00241 void vsrl_dynamic_program::compute_cost(int i, int j)
00242 {
00243   // we wish to compute the cost between tokens i and j;
00244 
00245   // get these tokens
00246   vsrl_token *tok1 = list1_[i];
00247   vsrl_token *tok2 = list2_[j];
00248 
00249 
00250   // compute the direct cost of associating these tokens
00251 
00252   double direct_cost = tok1->cost(tok2);
00253 
00254   // special cases were token i is either the first or last token
00255 
00256   if (i==0)
00257   {
00258     // if j > 1 then we must consider all the unassigned tokens
00259     // in list2 that are below j;
00260 
00261     for (int k=0;k<j;k++)
00262     {
00263       if (!list2_[k]->null_token())
00264       {
00265         // this is a real token in list2 which must now
00266         // be allocated to the null assignment
00267         direct_cost = direct_cost + outer_cost_;
00268       }
00269     }
00270   }
00271 
00272 
00273   // this is the last token
00274   if (i+1==int(list1_.size()))
00275   {
00276     // this is the last token in list 1
00277     // so consider the rest of the tokens in list2 which
00278     // would now be doomed to a null assignment
00279 
00280     for (unsigned int k=j+1;k<list2_.size();k++)
00281     {
00282       if (!list2_[k]->null_token())
00283       {
00284         // this is a real token in list2 which must now
00285         // be allocated to the null assignment
00286         direct_cost = direct_cost + outer_cost_;
00287       }
00288     }
00289   }
00290 
00291   //  we can now compute the minimum prior cost
00292 
00293   double new_num_null1 = 0;
00294   double prior_cost = 0;
00295 
00296   int p_i =i-1;
00297   int p_j =0;
00298 
00299   if (i>0)
00300   {
00301     // determine the upper search limit on list 2
00302     // the key is that since the assignments must
00303     // be increasing, we must have an assignment below
00304     // j there for
00305 
00306     int upper_j = j;
00307     if (tok2->null_token())
00308     {
00309       // however it appears that token j is the null token
00310       // which can have mulltiple assignments so we will
00311       // increment upper_j;
00312 
00313       upper_j++;
00314     }
00315 
00316     // initiallly set the prior cost really high
00317     prior_cost = 100000;
00318 
00319     // the number of null assignments in a row
00320 
00321     double num_null1;
00322 
00323     // now compute the prior cost;
00324 
00325     for (int k=lower_search_range_[p_i];k<upper_j;k++)
00326     {
00327       // this is the cost of the prior assignmentt
00328 
00329       double cost = cost_matrix_[p_i][k].cost;
00330 
00331       // in some cases the geometry of the prior set of assignments
00332       // is important so we must consider this situation
00333 
00334       cost = cost + tok1->incremental_cost(tok2,list1_[p_i],list2_[k]);
00335 
00336 
00337       // compute the penalty for assigning too many tokens the same null assignment
00338 
00339       if (j==k)
00340       {
00341         // we have yet another null assignment so using the number of
00342         // consecuative null assignmens for the node p_i->k we can compute
00343         // how many consecuative null assignments now exist
00344 
00345         num_null1=cost_matrix_[p_i][k].num_null1 + 1;
00346       }
00347       else
00348       {
00349         // there is no continuity of null assignments but this
00350         // could be the start of a new gap
00351         //
00352         if (list2_[j]->null_token())
00353         {
00354           // this is the the start of a new gap
00355           num_null1=1;
00356         }
00357         else
00358         {
00359           // this is a valid token
00360           num_null1=0;
00361         }
00362       }
00363 
00364 
00365       // add the cost for this gap  - note that as the number of
00366       // consecuative null assignments increases, the penalty becomes more
00367       // and more severe
00368 
00369       cost = cost + num_null1 * continuity_cost_;
00370 
00371 
00372       // if there is a gap between k and j then all these
00373       // tokens in list will get the null assignment so  this
00374       // must be compensated for. We must also penalize the second
00375       // kind of gap
00376 
00377       double num_null2=0;
00378 
00379       for (int l=k+1;l<j;l++)
00380       {
00381         if (!list2_[l]->null_token())
00382         {
00383           // this is a real token in list2 which must now
00384           // be allocated to the null assignment
00385           cost = cost + inner_cost_;
00386           num_null2++;
00387           cost=cost+num_null2 * continuity_cost_;
00388         }
00389       }
00390 
00391       if (cost<prior_cost)
00392       {
00393         // we have a new prior cost
00394         prior_cost = cost;
00395         p_j=k;
00396         new_num_null1=num_null1;
00397       }
00398     }
00399   }
00400 
00401 
00402   // we can now determine the cost of assigning node i to node j
00403 
00404   cost_matrix_[i][j].cost= direct_cost + prior_cost;
00405   cost_matrix_[i][j].num_null1 = new_num_null1;
00406 
00407   // record the prior assignments used to compute cost
00408 
00409   cost_matrix_[i][j].prior_index1=p_i;
00410   cost_matrix_[i][j].prior_index2=p_j;
00411 }
00412 
00413 double vsrl_dynamic_program::optimum_assignment()
00414 {
00415   // we can now compute the optimum assignment
00416   // this is pretty easy we just find the lowest
00417   // cost assignment for the last token in list 2
00418   // and then follow the path back.
00419   // start by setting the assigned tokens of all lists to null;
00420 
00421   token_list::iterator ti;
00422   for (ti=list1_.begin();ti!=list1_.end();ti++)
00423     (*ti)->set_assigned_token(0);
00424 
00425   for (ti=list2_.begin();ti!=list2_.end();ti++)
00426     (*ti)->set_assigned_token(0);
00427 
00428   // now find the best assignment for token list1
00429   vsrl_token *tok1;
00430   vsrl_token *tok2;
00431 
00432   int i = num_row_-1;
00433   int j=0;
00434   double min_cost=1000000;
00435 
00436   for (int k=0;k<num_col_;k++)
00437   {
00438     if (cost_matrix_[i][k].cost < min_cost)
00439     {
00440       min_cost = cost_matrix_[i][k].cost;
00441       j=k;
00442     }
00443   }
00444 
00445   // Ok we know were to start so lets snake down the
00446   // optimal path
00447 
00448   double total_cost=0;
00449 
00450   while (i>=0)
00451   {
00452     // add the total cost
00453     total_cost = total_cost + cost_matrix_[i][j].cost;
00454     tok1= list1_[i];
00455     tok2= list2_[j];
00456 
00457     if (!tok2->null_token())
00458     {
00459       // this is a real assignment so assign it
00460       tok1->set_assigned_token(tok2);
00461       tok2->set_assigned_token(tok1);
00462     }
00463 
00464     // get the next j;
00465 
00466     j=cost_matrix_[i][j].prior_index2;
00467 
00468     i=i-1;
00469   }
00470 
00471   // ok we are done
00472 
00473   return total_cost;
00474 }
00475 
00476 
00477 // Some tools for diagnosis
00478 
00479 void vsrl_dynamic_program::print_direct_cost(int i, int j)
00480 {
00481   // we want to print the direct cost between matcjing token i and j
00482 
00483   assert(i>=0);
00484   assert(j>=0);
00485   if ((unsigned int)i < list1_.size() && (unsigned int)j< list2_.size())
00486   {
00487     vsrl_token *tok1 = list1_[i];
00488     vsrl_token *tok2 = list2_[j];
00489 
00490     double direct_cost = tok1->cost(tok2);
00491 
00492     vcl_cout << "Direct cost " << i << " -> " << j << ' ' << direct_cost <<'\n';
00493   }
00494 }
00495 
00496 
00497 void vsrl_dynamic_program::print_cost(int i, int j)
00498 {
00499   // we want to print the direct cost between matcjing token i and j
00500 
00501   assert(i>=0);
00502   assert(j>=0);
00503   if ((unsigned int)i < list1_.size() && (unsigned int)j< list2_.size())
00504     vcl_cout << "cost "<< i <<" -> "<< j <<' '<<cost_matrix_[i][j].cost <<'\n';
00505 }
00506 
00507 void vsrl_dynamic_program::print_direct_costs(int i)
00508 {
00509   // print all the direct costs for token i on list1
00510   vcl_cout << "Direct costs for token " << i << vcl_endl;
00511   for (int j=lower_search_range_[i];j<upper_search_range_[i];j++)
00512     print_direct_cost(i,j);
00513 }
00514 
00515 void vsrl_dynamic_program::print_costs(int i)
00516 {
00517   // print all the costs for token i on list1
00518   vcl_cout << "Printing the costs for token " << i << " in the range " << lower_search_range_[i]
00519            << " to " << upper_search_range_[i] << vcl_endl;
00520 
00521   for (int j=lower_search_range_[i];j<upper_search_range_[i];j++)
00522     print_cost(i,j);
00523 }
00524 
00525 void vsrl_dynamic_program::print_assignment_nodes(int i)
00526 {
00527   for (int j=lower_search_range_[i];j<upper_search_range_[i];j++)
00528     print_assignment_node(i,j);
00529 }
00530 
00531 
00532 void vsrl_dynamic_program::print_assignment_node(int i, int j)
00533 {
00534   vcl_cout << " assignment for node " << i << " -> " << j << vcl_endl
00535            << "   prior assignment: " << cost_matrix_[i][j].prior_index1 << " -> "
00536            << cost_matrix_[i][j].prior_index2 << vcl_endl
00537            << "   cost: " << cost_matrix_[i][j].cost << vcl_endl << vcl_endl;
00538 }
00539 
00540 void vsrl_dynamic_program::print_assignment(int i)
00541 {
00542   // we want to print the assignment for the i'th token
00543 
00544   vcl_cout << "Token " << i << " goes to ";
00545   vsrl_token *tok1 = (list1_[i]);
00546   vsrl_token *tok2 = tok1->get_assigned_token();
00547   if (tok2)
00548     vcl_cout << "token " << tok2->get_x() << vcl_endl;
00549   else
00550     vcl_cout << "the null token\n";
00551 }
00552 
00553 void vsrl_dynamic_program::print_assignments()
00554 {
00555   for (unsigned int j=0;j<list1_.size();j++)
00556     print_assignment(j);
00557 }

Generated on Mon Mar 8 05:24:39 2010 for contrib/gel/vsrl by  doxygen 1.5.1