Go to the documentation of this file.00001 #include <boost/algorithm/string/join.hpp>
00002 #include <boost/filesystem.hpp>
00003 #include <boost/foreach.hpp>
00004 #include <boost/lexical_cast.hpp>
00005 #include <fstream>
00006 #include <ros/ros.h>
00007 #include <stdexcept>
00008 #include <yaml-cpp/yaml.h>
00009
00010 #include <bwi_planning/cost_learner.h>
00011
00012 #ifdef HAVE_NEW_YAMLCPP
00013 namespace YAML {
00014
00015
00016 template<typename T>
00017 void operator >> (const YAML::Node& node, T& i)
00018 {
00019 i = node.as<T>();
00020 }
00021 }
00022 #endif
00023
00024 namespace bwi_planning {
00025
00026 CostLearner::CostLearner () {
00027
00028 ros::NodeHandle nh, private_nh("~");
00029
00030 std::vector<std::string> unavailable_parameters;
00031 std::string door_file;
00032 if (!(private_nh.getParam("door_file", door_file))) {
00033 unavailable_parameters.push_back("door_file");
00034 }
00035 if (!(private_nh.getParam("values_file", values_file_))) {
00036 unavailable_parameters.push_back("values_file");
00037 }
00038 if (!(private_nh.getParam("lua_file", lua_file_))) {
00039 unavailable_parameters.push_back("lua_file");
00040 }
00041 private_nh.param("alpha", alpha_, 0.5);
00042 private_nh.param("use_exponential_weighting",
00043 use_exponential_weighting_, true);
00044
00045 if (unavailable_parameters.size() != 0) {
00046 std::string message = "Following neccessary params not available: " +
00047 boost::algorithm::join(unavailable_parameters, ", ");
00048 ROS_INFO_STREAM(message);
00049 throw std::runtime_error(message);
00050 }
00051
00052 readDoorFile(door_file, doors_);
00053 prepareInputData();
00054 }
00055
00056 void CostLearner::prepareInputData() {
00057
00058 iteration_ = 1;
00059 while (boost::filesystem::exists(values_file_ +
00060 boost::lexical_cast<std::string>(iteration_))) {
00061 ++iteration_;
00062 }
00063
00064 ROS_INFO_STREAM("Starting at iteration #" << iteration_);
00065
00066 if (iteration_ == 1) {
00067
00068 for (int idx = 0; idx < doors_.size(); ++idx) {
00069 for (int j = 0; j < doors_.size(); ++j) {
00070 if (j == idx) {
00071 continue;
00072 }
00073 if (doors_[j].approach_names[0] == doors_[idx].approach_names[0]) {
00074 std::string loc = doors_[j].approach_names[0];
00075 distance_estimates_[loc][idx][j] = 1.0f;
00076 distance_samples_[loc][idx][j] = 0;
00077 }
00078 if (doors_[j].approach_names[0] == doors_[idx].approach_names[1]) {
00079 std::string loc = doors_[j].approach_names[0];
00080 distance_estimates_[loc][idx][j] = 1.0f;
00081 distance_samples_[loc][idx][j] = 0;
00082 }
00083 if (doors_[j].approach_names[1] == doors_[idx].approach_names[0]) {
00084 std::string loc = doors_[j].approach_names[1];
00085 distance_estimates_[loc][idx][j] = 1.0f;
00086 distance_samples_[loc][idx][j] = 0;
00087 }
00088 if (doors_[j].approach_names[1] == doors_[idx].approach_names[1]) {
00089 std::string loc = doors_[j].approach_names[1];
00090 distance_estimates_[loc][idx][j] = 1.0f;
00091 distance_samples_[loc][idx][j] = 0;
00092 }
00093 }
00094 }
00095
00096
00097 writeValuesFile(0);
00098 } else {
00099 readValuesFile(iteration_ - 1);
00100 }
00101 writeLuaFile();
00102 }
00103
00104 void CostLearner::writeLuaFile(std::string lua_file) {
00105 if (lua_file.empty()) {
00106 lua_file = lua_file_;
00107 }
00108 std::ofstream fout(lua_file.c_str());
00109 fout << "#begin_lua" << std::endl << std::endl;
00110 fout << "loc_table={}" << std::endl;
00111 int count = 0;
00112 BOOST_FOREACH(SIIFPair const& kv, distance_estimates_) {
00113 fout << "loc_table[\"" << kv.first << "\"] = " << count << std::endl;
00114 count++;
00115 }
00116 fout << "door_table={}" << std::endl;
00117 for (unsigned int i = 0; i < doors_.size(); ++i) {
00118 fout << "door_table[\"" << doors_[i].name << "\"] = " << i << std::endl;
00119 }
00120 fout << "function dis(a,b,c)" << std::endl;
00121 fout << "\td1 = door_table[tostring(a)]" << std::endl;
00122 fout << "\td2 = door_table[tostring(b)]" << std::endl;
00123 fout << "\tif d1==d2 then return 1 end" << std::endl;
00124 fout << "\tloc = loc_table[tostring(c)]" << std::endl;
00125 count = 0;
00126 BOOST_FOREACH(SIIFPair const& kv, distance_estimates_) {
00127 fout << "\tif loc==" << count << " then" << std::endl;
00128 BOOST_FOREACH(IIFPair const& kv2, kv.second) {
00129 fout << "\t\tif d1==" << kv2.first << " then" << std::endl;
00130 BOOST_FOREACH(IFPair const& kv3, kv2.second) {
00131 fout << "\t\t\tif d2==" << kv3.first << " then return " <<
00132 lrint(kv3.second) << " end" << std::endl;
00133 }
00134 fout << "\t\tend" << std::endl;
00135 }
00136 fout << "\tend" << std::endl;
00137 count++;
00138 }
00139 fout << "\treturn 1" << std::endl;
00140 fout << "end" << std::endl << std::endl;
00141 fout << "#end_lua." << std::endl;
00142 fout.close();
00143 }
00144
00145 void CostLearner::writeValuesFile(int episode) {
00146 if (episode == -1) {
00147 episode = iteration_;
00148 }
00149 std::string out_file_name = values_file_ +
00150 boost::lexical_cast<std::string>(episode);
00151 std::ofstream fout(out_file_name.c_str());
00152 BOOST_FOREACH(SIIIPair const& kv, distance_samples_) {
00153 fout << " - name: " << kv.first << std::endl;
00154 fout << " costs: " << std::endl;
00155 BOOST_FOREACH(IIIPair const& kv2, kv.second) {
00156 BOOST_FOREACH(IIPair const& kv3, kv2.second) {
00157 fout << " - from: " << kv2.first << std::endl;
00158 fout << " to: " << kv3.first << std::endl;
00159 fout << " cost: " <<
00160 distance_estimates_[kv.first][kv2.first][kv3.first] << std::endl;
00161 fout << " samples: " << kv3.second << std::endl;
00162 }
00163 }
00164 }
00165 fout.close();
00166 std::string lua_file_name = values_file_ + "_distances" +
00167 boost::lexical_cast<std::string>(episode) + ".lua";
00168 writeLuaFile(lua_file_name);
00169 }
00170
00171 void CostLearner::readValuesFile(int episode) {
00172 if (episode == -1) {
00173 episode = iteration_;
00174 }
00175 std::string in_file_name = values_file_ +
00176 boost::lexical_cast<std::string>(episode);
00177 std::ifstream fin(in_file_name.c_str());
00178
00179 YAML::Node doc;
00180 #ifdef HAVE_NEW_YAMLCPP
00181 doc = YAML::Load(fin);
00182 #else
00183 YAML::Parser parser(fin);
00184 parser.GetNextDocument(doc);
00185 #endif
00186
00187 for (size_t i = 0; i < doc.size(); ++i) {
00188 std::string loc;
00189 doc[i]["name"] >> loc;
00190 const YAML::Node &costs = doc[i]["costs"];
00191 for (size_t j = 0; j < costs.size(); ++j) {
00192 int from, to;
00193 costs[j]["from"] >> from;
00194 costs[j]["to"] >> to;
00195 costs[j]["cost"] >> distance_estimates_[loc][from][to];
00196 costs[j]["samples"] >> distance_samples_[loc][from][to];
00197 }
00198 }
00199 }
00200
00201 bool CostLearner::addSample(const std::string& loc, int door_from,
00202 int door_to, float cost) {
00203
00204 if (door_from >= (int) doors_.size() || door_from < 0 ||
00205 door_to >= (int) doors_.size() || door_to < 0) {
00206 return false;
00207 }
00208
00209 ROS_INFO_STREAM(std::string("Adding sample ") <<
00210 doors_[door_from].name << "->" <<
00211 doors_[door_to].name << ": " << cost);
00212 int samples = distance_samples_[loc][door_from][door_to];
00213 float old_cost = distance_estimates_[loc][door_from][door_to];
00214 float final_cost = 0;
00215 if (use_exponential_weighting_) {
00216 final_cost = (1.0f - alpha_) * old_cost + alpha_ * cost;
00217 } else {
00218 if (samples != 0) {
00219 final_cost = (old_cost * samples + cost) / (samples + 1);
00220 } else {
00221
00222 final_cost = cost;
00223 }
00224 }
00225 distance_estimates_[loc][door_from][door_to] = final_cost;
00226 distance_estimates_[loc][door_to][door_from] = final_cost;
00227 distance_samples_[loc][door_from][door_to] = samples + 1;
00228 distance_samples_[loc][door_to][door_from] = samples + 1;
00229 }
00230
00231 bool CostLearner::addSample(const std::string& loc,
00232 const std::string& door_from, const std::string& door_to,
00233 float cost) {
00234
00235 size_t door_from_idx = bwi_planning_common::resolveDoor(door_from, doors_);
00236 size_t door_to_idx = bwi_planning_common::resolveDoor(door_to, doors_);
00237
00238 if (door_from_idx == bwi_planning_common::NO_DOOR_IDX ||
00239 door_to_idx == bwi_planning_common::NO_DOOR_IDX) {
00240 return false;
00241 }
00242
00243 return addSample(loc, door_from_idx, door_to_idx, cost);
00244 }
00245
00246 void CostLearner::finalizeEpisode() {
00247 writeLuaFile();
00248 writeValuesFile();
00249 ++iteration_;
00250 ROS_INFO_STREAM("Bumping cost learner to iteration #" << iteration_);
00251 }
00252
00253 }