00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include <labust/control/PNController.hpp>
00038 #include <boost/graph/graphviz.hpp>
00039 #include <boost/graph/visitors.hpp>
00040 #include <boost/graph/breadth_first_search.hpp>
00041
00042 #include <queue>
00043 #include <list>
00044 #include <algorithm>
00045 #include <sstream>
00046
00047 using namespace labust::control;
00048
00049 PNController::PNController():
00050 pnum(6),
00051 tnum(0),
00052 marking(pnum)
00053 {
00054
00055 std::string dofs[]={"X","Y","Z","K","M","N"};
00056
00057 for (int i=0; i<6;++i)
00058 {
00059 placeMap[i]=dofs[i];
00060 nameMap[dofs[i]].place_num = i;
00061 marking(i) = 1;
00062 }
00063 }
00064
00065 void PNController::addToGraph(const navcon_msgs::RegisterControllerRequest& info)
00066 {
00067 PlaceInfo& newcon=nameMap[info.name];
00068 newcon.place_num = pnum++;
00069
00070 marking.conservativeResize(pnum);
00071 marking(newcon.place_num) = 0;
00072 newcon.enable_t = tnum++;
00073 newcon.disable_t = tnum++;
00074
00075
00076 placeMap[newcon.place_num] = info.name;
00077 transitionMap[newcon.enable_t] = info.name+"_enable";
00078 transitionMap[newcon.disable_t] = info.name+"_disable";
00079
00080 Dm.conservativeResize(pnum, tnum);
00081 Dp.conservativeResize(pnum, tnum);
00082 Dm.row(newcon.place_num) = Eigen::VectorXi::Zero(tnum);
00083 Dp.row(newcon.place_num) = Eigen::VectorXi::Zero(tnum);
00084 Dm.col(newcon.enable_t)= Eigen::VectorXi::Zero(pnum);
00085 Dp.col(newcon.enable_t)= Eigen::VectorXi::Zero(pnum);
00086 Dm.col(newcon.disable_t)= Eigen::VectorXi::Zero(pnum);
00087 Dp.col(newcon.disable_t)= Eigen::VectorXi::Zero(pnum);
00088
00089
00090 Dm(newcon.place_num, newcon.disable_t) = 1;
00091 Dp(newcon.place_num, newcon.enable_t) = 1;
00092
00093 for (int i=0; i<info.used_dofs.size(); ++i)
00094 {
00095 if (info.used_dofs[i])
00096 {
00097 Dm(i, newcon.enable_t) = 1;
00098 Dp(i, newcon.disable_t) = 1;
00099 }
00100 }
00101
00102
00103 for (int i=0; i<info.used_cnt.size(); ++i)
00104 {
00105 int place_num = nameMap[info.used_cnt[i]].place_num;
00106 Dm(place_num, newcon.enable_t) = 1;
00107 Dp(place_num, newcon.disable_t) = 1;
00108 }
00109
00110 I=Dp-Dm;
00111 }
00112
00113 bool PNController::firing_rec(int des_place,
00114 std::set<int>& skip_transitions,
00115 std::set<int>& visited_places)
00116 {
00117
00118 visited_places.insert(des_place);
00119
00120
00121 Eigen::VectorXi transitions = Dp.row(des_place);
00122 std::vector<int> activators;
00123 for (int i=0; i<transitions.size(); ++i)
00124 {
00125
00126 if ((transitions(i) &&
00127 (skip_transitions.find(i) == skip_transitions.end())))
00128 {
00129 activators.push_back(i);
00130 }
00131 }
00132
00133
00134 if (activators.empty())
00135 {
00136 std::cout<<"Place "<<placeMap[des_place]<<" is a dead-end."<<std::endl;
00137 return false;
00138 }
00139
00140
00141 std::cout<<"Place "<<placeMap[des_place]<<" depends on transitions:";
00142 for (int i=0; i<activators.size(); ++i) std::cout<<transitionMap[activators[i]]<<", ";
00143 std::cout<<std::endl;
00144
00145
00146 bool trigerable = false;
00147 for (int i=0; i<activators.size(); ++i)
00148 {
00149 Eigen::VectorXi t_en = Dm.col(activators[i]);
00150 std::vector<int> places;
00151 for (int j=0; j<t_en.size(); ++j)
00152 {
00153
00154 if ((t_en(j) &&
00155 (visited_places.find(j) == visited_places.end())))
00156 {
00157 places.push_back(j);
00158 }
00159 }
00160
00161 if (places.size() == 0)
00162 {
00163 std::cout<<"Activator candidate transition "<<transitionMap[activators[i]];
00164 std::cout<<" is a dead-end."<<std::endl;
00165 continue;
00166 }
00167
00168
00169 std::cout<<"Activator candidate transition "<<transitionMap[activators[i]];
00170 std::cout<<" depends on:";
00171 for (int j=0; j<places.size(); ++j) std::cout<<placeMap[places[j]]<<", ";
00172 std::cout<<std::endl;
00173
00174 bool add_cur_seq=true;
00175
00176 for (int j=0; j<places.size(); ++j)
00177 if (marking(places[j])) visited_places.insert(places[j]);
00178
00179 for (int j=0; j<places.size(); ++j)
00180 {
00181
00182 if (!marking(places[j]))
00183 {
00184 if (!firing_rec(places[j], skip_transitions, visited_places))
00185 {
00186 add_cur_seq = false;
00187 break;
00188 }
00189 }
00190 }
00191
00192 if (add_cur_seq)
00193 {
00194 bool add = true;
00195 for (int j=0; j<firing_seq.size(); ++j)
00196 {
00197 if (firing_seq[j] == activators[i])
00198 {
00199 add = false;
00200 break;
00201 }
00202 }
00203
00204
00205 if (add)
00206 {
00207 std::cout<<"Adding to firing sequence:"<<transitionMap[activators[i]]<<std::endl;
00208 firing_seq.push_back(activators[i]);
00209 trigerable = true;
00210
00211
00212
00213 if (activators[i]%2 == 0)
00214 {
00215 std::cout<<"Adding to skip sequence:"<<transitionMap[activators[i]+1]<<std::endl;
00216 skip_transitions.insert(activators[i]+1);
00217 }
00218 else
00219 {
00220 std::cout<<"Adding to skip sequence:"<<transitionMap[activators[i]-1]<<std::endl;
00221 skip_transitions.insert(activators[i]-1);
00222 }
00223 }
00224 else
00225 {
00226 std::cout<<"Adding to skip sequence:"<<transitionMap[activators[i]]<<std::endl;
00227 skip_transitions.insert(activators[i]);
00228 }
00229 }
00230 }
00231 return trigerable;
00232 }
00233
00234 void PNController::get_firing(const std::string& name)
00235 {
00236
00237 int des_place = nameMap[name].place_num;
00238
00239 while (marking(des_place) != 1)
00240 {
00241 firing_seq.clear();
00242 std::set<int> skip_transitions;
00243 std::set<int> visited_places;
00244 firing_rec(des_place, skip_transitions, visited_places);
00245
00246 std::cout<<"The final firing sequence is:";
00247 for (int i=0; i<firing_seq.size(); ++i)
00248 {
00249 std::cout<<transitionMap[firing_seq[i]]<<" -> ";
00250 }
00251 std::cout<<"end"<<std::endl;
00252
00253
00254
00255
00256 for(int i=0; i<firing_seq.size(); ++i)
00257 {
00258 Eigen::VectorXi fire = Eigen::VectorXi::Zero(Dm.cols());
00259 fire(firing_seq[i]) = 1;
00260
00261 Eigen::VectorXi enabled_trans = marking.transpose()*Dm;
00262 if (enabled_trans(firing_seq[i]) == Dm.col(firing_seq[i]).sum())
00263 {
00264 std::cout<<"Transition "<<transitionMap[firing_seq[i]]<<" is enabled."<<std::endl;
00265 }
00266 else
00267 {
00268 std::cout<<"Transition "<<transitionMap[firing_seq[i]]<<" is not enabled."<<std::endl;
00269 std::cerr<<"Error - cannot fire transition."<<std::endl;
00270 break;
00271 }
00272
00273 marking = marking + I*fire;
00274 std::cout<<"Transition "<<transitionMap[firing_seq[i]]<<" fired, new marking:"<<marking<<std::endl;
00275 if (marking(des_place))
00276 {
00277 std::cout<<"Reached desired update in the marking."<<std::endl;
00278 break;
00279 }
00280 }
00281
00282 usleep(1000*1000);
00283 }
00284 }
00285
00286 template <class Vector>
00287 void print_vec(const Vector& vec)
00288 {
00289 std::cout<<"(";
00290 int i;
00291 for(i=0; i<vec.size()-1;++i)
00292 {
00293 std::cout<<vec(i)<<",";
00294 }
00295 std::cout<<vec(i)<<")";
00296 }
00297
00298 template <typename DistanceMap, typename PredecessorMap>
00299 class bacon_number_recorder : public boost::default_bfs_visitor
00300 {
00301 public:
00302 bacon_number_recorder(DistanceMap dist, PredecessorMap p) : d(dist), p(p) { }
00303
00304 template <typename Edge, typename Graph>
00305 void tree_edge(Edge e, const Graph& g) const
00306 {
00307 typename boost::graph_traits<Graph>::vertex_descriptor
00308 u = source(e, g), v = target(e, g);
00309 d[v] = d[u] + 1;
00310 p[v] = u;
00311 }
00312 private:
00313 DistanceMap d;
00314 PredecessorMap p;
00315 };
00316
00317 template <typename DistanceMap, typename PredecessorMap>
00318 bacon_number_recorder<DistanceMap, PredecessorMap>
00319 record_bacon_number(DistanceMap d, PredecessorMap p)
00320 {
00321 return bacon_number_recorder<DistanceMap, PredecessorMap>(d,p);
00322 }
00323
00324 void PNController::get_firing_r(const std::string& name)
00325 {
00326
00327 int des_place = nameMap[name].place_num;
00328
00329 std::cout<<"Desired place to activate is: "<<placeMap[des_place]<<" == "<<des_place<<std::endl;
00330
00331 std::vector<Eigen::VectorXi> av_markings;
00332 std::vector<int> av_diff, av_diff2;
00333 for(int i=0; i<all_markings.size(); ++i)
00334 {
00335 if (all_markings[i](des_place))
00336 {
00337 av_markings.push_back(all_markings[i]);
00338 Eigen::VectorXi diff = (all_markings[i] - marking);
00339 diff = diff.array().abs();
00340 av_diff.push_back(diff.sum());
00341 av_diff2.push_back(diff.sum());
00342 }
00343 }
00344
00345 std::sort(av_diff2.begin(),av_diff2.end());
00346 std::vector<int>::iterator it=std::find(av_diff.begin(), av_diff.end(),av_diff2[0]);
00347
00348 std::cout<<"From "<<all_markings.size();
00349 std::cout<<" markings, "<<av_markings.size()<<" have the needed place enabled."<<std::endl;
00350 std::cout<<"The smallest difference marking is:";
00351 print_vec(av_markings[it-av_diff.begin()]);
00352 std::cout<<std::endl;
00353 std::cout<<"The current marking is:";
00354 print_vec(marking);
00355 std::cout<<std::endl;
00356
00357
00358 std::vector<Eigen::VectorXi>::iterator it2 = std::find(all_markings.begin(), all_markings.end(),marking);
00359
00360 std::vector <int> bacon_number(boost::num_vertices(rgraph));
00361 std::vector <int> pred_map(boost::num_vertices(rgraph));
00362
00363 GraphType::vertex_descriptor curr_vx = all_idx[it2-all_markings.begin()];
00364 std::cout<<"The current marking index is: "<<it2-all_markings.begin()<<std::endl;
00365 boost::breadth_first_search(rgraph, all_idx[it2-all_markings.begin()],
00366 boost::visitor(record_bacon_number(&bacon_number[0],&pred_map[0])));
00367
00368 std::vector<int> av_idx;
00369 av_markings.clear();
00370 av_diff.clear();
00371 av_diff2.clear();
00372 for(int i=0; i<all_markings.size(); ++i)
00373 {
00374 if (all_markings[i](des_place))
00375 {
00376 av_markings.push_back(all_markings[i]);
00377 av_idx.push_back(all_idx[i]);
00378 av_diff.push_back(bacon_number[all_idx[i]]);
00379 av_diff2.push_back(bacon_number[all_idx[i]]);
00380 }
00381 }
00382
00383 std::sort(av_diff2.begin(),av_diff2.end());
00384 it=std::find(av_diff.begin(), av_diff.end(),av_diff2[0]);
00385
00386 std::cout<<"The closest marking(s) is(are):"<<std::endl;
00387 bool run=true;
00388 std::vector<int>::iterator it_h = av_diff.begin();
00389 while (it_h != av_diff.end())
00390 {
00391 it_h=std::find(it_h, av_diff.end(),av_diff2[0]);
00392 if (it_h != av_diff.end())
00393 {
00394 std::cout<<"\t";
00395 print_vec(av_markings[it_h-av_diff.begin()]);
00396 std::cout<<std::endl;
00397 ++it_h;
00398 }
00399 }
00400 std::cout<<std::endl;
00401 std::cout<<"The current marking is:";
00402 print_vec(marking);
00403 std::cout<<std::endl;
00404 Eigen::VectorXi m_new = av_markings[it-av_diff.begin()];
00405
00406 std::cout<<"Calculating firing seq."<<std::endl;
00407
00408 GraphType::vertex_descriptor closest_vx = av_idx[it-av_diff.begin()];
00409 GraphType::vertex_descriptor curr_pred = closest_vx;
00410
00411 boost::property_map<GraphType, boost::edge_name_t>::type edgeMap =
00412 boost::get(boost::edge_name_t(), rgraph);
00413 std::cout<<"Get the edge map."<<std::endl;
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424 std::cout<<"Loop across edges. The curr_pred = closest_vx = "<<closest_vx<<std::endl;
00425
00426 std::vector<int> firing_seq;
00427 while (curr_pred != curr_vx)
00428 {
00429 if (boost::edge(pred_map[curr_pred], curr_pred, rgraph).second)
00430 {
00431 std::cout<<"Get edge connection between "<<pred_map[curr_pred]<<" and "<<curr_pred<<std::endl;
00432 firing_seq.push_back(edgeMap[boost::edge(pred_map[curr_pred], curr_pred, rgraph).first]);
00433 }
00434 else
00435 {
00436 std::cout<<"No edge connection between "<<pred_map[curr_pred]<<" and "<<curr_pred<<std::endl;
00437 }
00438 curr_pred = pred_map[curr_pred];
00439 }
00440
00441 std::cout<<"Triggering the following sequence:";
00442 for (int i=firing_seq.size()-1; i>=0; --i)
00443 {
00444 std::cout<<transitionMap[firing_seq[i]]<<" -> ";
00445 }
00446 std::cout<<"end"<<std::endl;
00447
00448 marking = m_new;
00449 }
00450
00451 void PNController::reachability()
00452 {
00453 rgraph.clear();
00454 Eigen::VectorXi m0=Eigen::VectorXi::Zero(marking.size());
00455 for (int i=0; i<6;++i) m0(i) = 1;
00456
00457 typedef GraphType::vertex_descriptor IntType;
00458 std::queue<Eigen::VectorXi> new_markings;
00459 std::queue<IntType> new_idx;
00460
00461 std::vector<Eigen::VectorXi> visited;
00462 std::vector<Eigen::VectorXi> all_markings;
00463 std::vector<IntType> all_markings_idx;
00464 std::vector<IntType> visited_idx;
00465 std::list<Eigen::VectorXi> dead_end;
00466
00467 new_markings.push(m0);
00468 new_idx.push(boost::add_vertex(rgraph));
00469 rgraph[new_idx.back()].marking = m0;
00470
00471 std::cout<<"Building reachability graph:"<<std::endl<<std::endl;
00472
00473 while (!new_markings.empty())
00474 {
00475 Eigen::VectorXi m;
00476 IntType idx;
00477 bool foundNew = false;
00478 do
00479 {
00480 m = new_markings.front();
00481 idx = new_idx.front();
00482 new_markings.pop();
00483 new_idx.pop();
00484 foundNew = !(std::find(visited.begin(),visited.end(),m) != visited.end());
00485 }
00486 while ((!foundNew) && (!new_markings.empty()));
00487
00488 if (!foundNew) break;
00489 std::cout<<"Selected new marking:"<<m<<std::endl;
00490 visited.push_back(m);
00491 visited_idx.push_back(idx);
00492 if (std::find(all_markings.begin(),all_markings.end(),m) == all_markings.end())
00493 {
00494 all_markings.push_back(m);
00495 all_markings_idx.push_back(idx);
00496 }
00497
00498
00499 Eigen::VectorXi all_trans = m.transpose()*Dm;
00500 for (int i=0; i<all_trans.size(); ++i)
00501 {
00502 if (all_trans(i) == Dm.col(i).sum())
00503 {
00504 std::cout<<"Transition "<<transitionMap[i]<<" is enabled.";
00505 std::cout<<"("<<all_trans(i)<<", "<<Dm.col(i).sum()<<")"<<std::endl;
00506 Eigen::VectorXi fire = Eigen::VectorXi::Zero(Dm.cols());
00507 fire(i) = 1;
00508 Eigen::VectorXi newmarking = m + I*fire;
00509
00510
00511 std::vector<Eigen::VectorXi>::iterator it;
00512 it = std::find(all_markings.begin(),all_markings.end(),newmarking);
00513
00514 if (it == all_markings.end())
00515 {
00516
00517 IntType nidx = boost::add_vertex(rgraph);
00518 new_markings.push(newmarking);
00519 new_idx.push(nidx);
00520 all_markings.push_back(newmarking);
00521 all_markings_idx.push_back(nidx);
00522 rgraph[nidx].marking = newmarking;
00523 boost::add_edge(idx, nidx,
00524 i,rgraph);
00525 }
00526 else
00527 {
00528
00529
00530 int old_idx = it - all_markings.begin();
00531 boost::add_edge(idx, all_markings_idx[old_idx],
00532 i,rgraph);
00533 }
00534 }
00535 }
00536 }
00537
00538 std::cout<<"Finished building graph."<<std::endl;
00539 this->all_markings.swap(all_markings);
00540 this->all_idx.swap(all_markings_idx);
00541 }
00542
00543 void PNController::getDotDesc(std::string& desc)
00544 {
00545 using namespace boost;
00546
00547 std::ostringstream out;
00548 write_graphviz(out, rgraph,
00549 pn_writer(rgraph),
00550 make_edge_writer(
00551 boost::get(boost::edge_name_t(),rgraph),
00552 transitionMap));
00553 desc = out.str();
00554 }
00555