Moved visitor inside parser unit.
							parent
							
								
									372ae8d092
								
							
						
					
					
						commit
						e6c1ad8d04
					
				|  | @ -17,64 +17,440 @@ | ||||||
| 
 | 
 | ||||||
| #define BOOST_SPIRIT_USE_PHOENIX_V3 1 | #define BOOST_SPIRIT_USE_PHOENIX_V3 1 | ||||||
| 
 | 
 | ||||||
|  | #include <gtsam/base/Matrix.h> | ||||||
|  | #include <gtsam/inference/Key.h> | ||||||
|  | #include <gtsam/inference/Symbol.h> | ||||||
|  | #include <gtsam_unstable/linear/QP.h> | ||||||
| #include <gtsam_unstable/linear/QPSParser.h> | #include <gtsam_unstable/linear/QPSParser.h> | ||||||
| #include <gtsam_unstable/linear/QPSParserException.h> | #include <gtsam_unstable/linear/QPSParserException.h> | ||||||
| #include <gtsam_unstable/linear/QPSVisitor.h> |  | ||||||
| 
 | 
 | ||||||
| #include <boost/spirit/include/qi.hpp> | #include <boost/fusion/include/vector.hpp> | ||||||
|  | #include <boost/fusion/sequence.hpp> | ||||||
| #include <boost/lambda/lambda.hpp> | #include <boost/lambda/lambda.hpp> | ||||||
| #include <boost/phoenix/bind.hpp> | #include <boost/phoenix/bind.hpp> | ||||||
| #include <boost/spirit/include/classic.hpp> | #include <boost/spirit/include/classic.hpp> | ||||||
|  | #include <boost/spirit/include/qi.hpp> | ||||||
|  | 
 | ||||||
|  | #include <algorithm> | ||||||
|  | #include <iostream> | ||||||
|  | #include <map> | ||||||
|  | #include <string> | ||||||
|  | #include <unordered_map> | ||||||
|  | #include <vector> | ||||||
|  | 
 | ||||||
|  | using boost::fusion::at_c; | ||||||
|  | using namespace std; | ||||||
| 
 | 
 | ||||||
| namespace bf = boost::fusion; | namespace bf = boost::fusion; | ||||||
| namespace qi = boost::spirit::qi; | namespace qi = boost::spirit::qi; | ||||||
| 
 | 
 | ||||||
|  | using Chars = std::vector<char>; | ||||||
|  | 
 | ||||||
|  | // Get a string from a fusion vector of Chars
 | ||||||
|  | template <size_t I, class FusionVector> | ||||||
|  | static string fromChars(const FusionVector &vars) { | ||||||
|  |   const Chars &chars = at_c<I>(vars); | ||||||
|  |   return string(chars.begin(), chars.end()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| namespace gtsam { | namespace gtsam { | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * As the parser reads a file, it call functions in this visitor. This visitor | ||||||
|  |  * in turn stores what the parser has read in a way that can be later used to | ||||||
|  |  * build the full QP problem in the file. | ||||||
|  |  */ | ||||||
|  | class QPSVisitor { | ||||||
|  |  private: | ||||||
|  |   typedef std::unordered_map<Key, Matrix11> coefficient_v; | ||||||
|  |   typedef std::unordered_map<std::string, coefficient_v> constraint_v; | ||||||
|  | 
 | ||||||
|  |   std::unordered_map<std::string, constraint_v *> | ||||||
|  |       row_to_constraint_v;  // Maps QPS ROWS to Variable-Matrix pairs
 | ||||||
|  |   constraint_v E;           // Equalities
 | ||||||
|  |   constraint_v IG;          // Inequalities >=
 | ||||||
|  |   constraint_v IL;          // Inequalities <=
 | ||||||
|  |   unsigned int numVariables; | ||||||
|  |   std::unordered_map<std::string, double> | ||||||
|  |       b;  // maps from constraint name to b value for Ax = b equality
 | ||||||
|  |           // constraints
 | ||||||
|  |   std::unordered_map<std::string, double> | ||||||
|  |       ranges;  // Inequalities can be specified as ranges on a variable
 | ||||||
|  |   std::unordered_map<Key, Vector1> g;  // linear term of quadratic cost
 | ||||||
|  |   std::unordered_map<std::string, Key> | ||||||
|  |       varname_to_key;  // Variable QPS string name to key
 | ||||||
|  |   std::unordered_map<Key, std::unordered_map<Key, Matrix11>> | ||||||
|  |       H;                 // H from hessian
 | ||||||
|  |   double f;              // Constant term of quadratic cost
 | ||||||
|  |   std::string obj_name;  // the objective function has a name in the QPS
 | ||||||
|  |   std::string name_;     // the quadratic program has a name in the QPS
 | ||||||
|  |   std::unordered_map<Key, double> | ||||||
|  |       up;  // Upper Bound constraints on variable where X < MAX
 | ||||||
|  |   std::unordered_map<Key, double> | ||||||
|  |       lo;  // Lower Bound constraints on variable where MIN < X
 | ||||||
|  |   std::unordered_map<Key, double> | ||||||
|  |       fx;          // Equalities specified as FX in BOUNDS part of QPS
 | ||||||
|  |   KeyVector free;  // Variables can be specified as free (to which no
 | ||||||
|  |                    // constraints apply)
 | ||||||
|  |   const bool debug = false; | ||||||
|  | 
 | ||||||
|  |  public: | ||||||
|  |   QPSVisitor() : numVariables(1) {} | ||||||
|  | 
 | ||||||
|  |   void setName(boost::fusion::vector<Chars, Chars, Chars> const &name) { | ||||||
|  |     name_ = fromChars<1>(name); | ||||||
|  |     if (debug) { | ||||||
|  |       cout << "Parsing file: " << name_ << endl; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   void addColumn(boost::fusion::vector<Chars, Chars, Chars, Chars, Chars, | ||||||
|  |                                        double, Chars> const &vars) { | ||||||
|  |     string var_ = fromChars<1>(vars); | ||||||
|  |     string row_ = fromChars<3>(vars); | ||||||
|  |     Matrix11 coefficient = at_c<5>(vars) * I_1x1; | ||||||
|  |     if (debug) { | ||||||
|  |       cout << "Added Column for Var: " << var_ << " Row: " << row_ | ||||||
|  |            << " Coefficient: " << coefficient << endl; | ||||||
|  |     } | ||||||
|  |     if (!varname_to_key.count(var_)) | ||||||
|  |       varname_to_key[var_] = Symbol('X', numVariables++); | ||||||
|  |     if (row_ == obj_name) { | ||||||
|  |       g[varname_to_key[var_]] = coefficient; | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     (*row_to_constraint_v[row_])[row_][varname_to_key[var_]] = coefficient; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   void addColumnDouble( | ||||||
|  |       boost::fusion::vector<Chars, Chars, Chars, Chars, double, Chars, Chars, | ||||||
|  |                             Chars, double> const &vars) { | ||||||
|  |     string var_ = fromChars<0>(vars); | ||||||
|  |     string row1_ = fromChars<2>(vars); | ||||||
|  |     string row2_ = fromChars<6>(vars); | ||||||
|  |     Matrix11 coefficient1 = at_c<4>(vars) * I_1x1; | ||||||
|  |     Matrix11 coefficient2 = at_c<8>(vars) * I_1x1; | ||||||
|  |     if (!varname_to_key.count(var_)) | ||||||
|  |       varname_to_key.insert({var_, Symbol('X', numVariables++)}); | ||||||
|  |     if (row1_ == obj_name) | ||||||
|  |       g[varname_to_key[var_]] = coefficient1; | ||||||
|  |     else | ||||||
|  |       (*row_to_constraint_v[row1_])[row1_][varname_to_key[var_]] = coefficient1; | ||||||
|  |     if (row2_ == obj_name) | ||||||
|  |       g[varname_to_key[var_]] = coefficient2; | ||||||
|  |     else | ||||||
|  |       (*row_to_constraint_v[row2_])[row2_][varname_to_key[var_]] = coefficient2; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   void addRangeSingle(boost::fusion::vector<Chars, Chars, Chars, Chars, Chars, | ||||||
|  |                                             double, Chars> const &vars) { | ||||||
|  |     string var_ = fromChars<1>(vars); | ||||||
|  |     string row_ = fromChars<3>(vars); | ||||||
|  |     double range = at_c<5>(vars); | ||||||
|  |     ranges[row_] = range; | ||||||
|  |     if (debug) { | ||||||
|  |       cout << "SINGLE RANGE ADDED" << endl; | ||||||
|  |       cout << "VAR:" << var_ << " ROW: " << row_ << " RANGE: " << range << endl; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   void addRangeDouble( | ||||||
|  |       boost::fusion::vector<Chars, Chars, Chars, Chars, Chars, double, Chars, | ||||||
|  |                             Chars, Chars, double> const &vars) { | ||||||
|  |     string var_ = fromChars<1>(vars); | ||||||
|  |     string row1_ = fromChars<3>(vars); | ||||||
|  |     string row2_ = fromChars<7>(vars); | ||||||
|  |     double range1 = at_c<5>(vars); | ||||||
|  |     double range2 = at_c<9>(vars); | ||||||
|  |     ranges[row1_] = range1; | ||||||
|  |     ranges[row2_] = range2; | ||||||
|  |     if (debug) { | ||||||
|  |       cout << "DOUBLE RANGE ADDED" << endl; | ||||||
|  |       cout << "VAR: " << var_ << " ROW1: " << row1_ << " RANGE1: " << range1 | ||||||
|  |            << " ROW2: " << row2_ << " RANGE2: " << range2 << endl; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   void addRHS(boost::fusion::vector<Chars, Chars, Chars, Chars, Chars, double, | ||||||
|  |                                     Chars> const &vars) { | ||||||
|  |     string var_ = fromChars<1>(vars); | ||||||
|  |     string row_ = fromChars<3>(vars); | ||||||
|  |     double coefficient = at_c<5>(vars); | ||||||
|  |     if (row_ == obj_name) | ||||||
|  |       f = -coefficient; | ||||||
|  |     else | ||||||
|  |       b[row_] = coefficient; | ||||||
|  | 
 | ||||||
|  |     if (debug) { | ||||||
|  |       cout << "Added RHS for Var: " << var_ << " Row: " << row_ | ||||||
|  |            << " Coefficient: " << coefficient << endl; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   void addRHSDouble( | ||||||
|  |       boost::fusion::vector<Chars, Chars, Chars, Chars, Chars, double, Chars, | ||||||
|  |                             Chars, Chars, double> const &vars) { | ||||||
|  |     string var_ = fromChars<1>(vars); | ||||||
|  |     string row1_ = fromChars<3>(vars); | ||||||
|  |     string row2_ = fromChars<7>(vars); | ||||||
|  |     double coefficient1 = at_c<5>(vars); | ||||||
|  |     double coefficient2 = at_c<9>(vars); | ||||||
|  |     if (row1_ == obj_name) | ||||||
|  |       f = -coefficient1; | ||||||
|  |     else | ||||||
|  |       b[row1_] = coefficient1; | ||||||
|  | 
 | ||||||
|  |     if (row2_ == obj_name) | ||||||
|  |       f = -coefficient2; | ||||||
|  |     else | ||||||
|  |       b[row2_] = coefficient2; | ||||||
|  | 
 | ||||||
|  |     if (debug) { | ||||||
|  |       cout << "Added RHS for Var: " << var_ << " Row: " << row1_ | ||||||
|  |            << " Coefficient: " << coefficient1 << endl; | ||||||
|  |       cout << "                      " | ||||||
|  |            << "Row: " << row2_ << " Coefficient: " << coefficient2 << endl; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   void addRow( | ||||||
|  |       boost::fusion::vector<Chars, char, Chars, Chars, Chars> const &vars) { | ||||||
|  |     string name_ = fromChars<3>(vars); | ||||||
|  |     char type = at_c<1>(vars); | ||||||
|  |     switch (type) { | ||||||
|  |       case 'N': | ||||||
|  |         obj_name = name_; | ||||||
|  |         break; | ||||||
|  |       case 'L': | ||||||
|  |         row_to_constraint_v[name_] = &IL; | ||||||
|  |         break; | ||||||
|  |       case 'G': | ||||||
|  |         row_to_constraint_v[name_] = &IG; | ||||||
|  |         break; | ||||||
|  |       case 'E': | ||||||
|  |         row_to_constraint_v[name_] = &E; | ||||||
|  |         break; | ||||||
|  |       default: | ||||||
|  |         cout << "invalid type: " << type << endl; | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |     if (debug) { | ||||||
|  |       cout << "Added Row Type: " << type << " Name: " << name_ << endl; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   void addBound(boost::fusion::vector<Chars, Chars, Chars, Chars, Chars, Chars, | ||||||
|  |                                       Chars, double> const &vars) { | ||||||
|  |     string type_ = fromChars<1>(vars); | ||||||
|  |     string var_ = fromChars<5>(vars); | ||||||
|  |     double number = at_c<7>(vars); | ||||||
|  |     if (type_.compare(string("UP")) == 0) | ||||||
|  |       up[varname_to_key[var_]] = number; | ||||||
|  |     else if (type_.compare(string("LO")) == 0) | ||||||
|  |       lo[varname_to_key[var_]] = number; | ||||||
|  |     else if (type_.compare(string("FX")) == 0) | ||||||
|  |       fx[varname_to_key[var_]] = number; | ||||||
|  |     else | ||||||
|  |       cout << "Invalid Bound Type: " << type_ << endl; | ||||||
|  | 
 | ||||||
|  |     if (debug) { | ||||||
|  |       cout << "Added Bound Type: " << type_ << " Var: " << var_ | ||||||
|  |            << " Amount: " << number << endl; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   void addFreeBound(boost::fusion::vector<Chars, Chars, Chars, Chars, Chars, | ||||||
|  |                                           Chars, Chars> const &vars) { | ||||||
|  |     string type_ = fromChars<1>(vars); | ||||||
|  |     string var_ = fromChars<5>(vars); | ||||||
|  |     free.push_back(varname_to_key[var_]); | ||||||
|  |     if (debug) { | ||||||
|  |       cout << "Added Free Bound Type: " << type_ << " Var: " << var_ | ||||||
|  |            << " Amount: " << endl; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   void addQuadTerm(boost::fusion::vector<Chars, Chars, Chars, Chars, Chars, | ||||||
|  |                                          double, Chars> const &vars) { | ||||||
|  |     string var1_ = fromChars<1>(vars); | ||||||
|  |     string var2_ = fromChars<3>(vars); | ||||||
|  |     Matrix11 coefficient = at_c<5>(vars) * I_1x1; | ||||||
|  | 
 | ||||||
|  |     H[varname_to_key[var1_]][varname_to_key[var2_]] = coefficient; | ||||||
|  |     H[varname_to_key[var2_]][varname_to_key[var1_]] = coefficient; | ||||||
|  |     if (debug) { | ||||||
|  |       cout << "Added QuadTerm for Var: " << var1_ << " Row: " << var2_ | ||||||
|  |            << " Coefficient: " << coefficient << endl; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   QP makeQP() { | ||||||
|  |     // Create the keys from the variable names
 | ||||||
|  |     KeyVector keys; | ||||||
|  |     for (auto kv : varname_to_key) { | ||||||
|  |       keys.push_back(kv.second); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Fill the G matrices and g vectors from
 | ||||||
|  |     vector<Matrix> Gs; | ||||||
|  |     vector<Vector> gs; | ||||||
|  |     sort(keys.begin(), keys.end()); | ||||||
|  |     for (size_t i = 0; i < keys.size(); ++i) { | ||||||
|  |       for (size_t j = i; j < keys.size(); ++j) { | ||||||
|  |         if (H.count(keys[i]) > 0 && H[keys[i]].count(keys[j]) > 0) { | ||||||
|  |           Gs.emplace_back(H[keys[i]][keys[j]]); | ||||||
|  |         } else { | ||||||
|  |           Gs.emplace_back(Z_1x1); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     for (Key key1 : keys) { | ||||||
|  |       if (g.count(key1) > 0) { | ||||||
|  |         gs.emplace_back(-g[key1]); | ||||||
|  |       } else { | ||||||
|  |         gs.emplace_back(Z_1x1); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Construct the quadratic program
 | ||||||
|  |     QP madeQP; | ||||||
|  |     auto obj = HessianFactor(keys, Gs, gs, 2 * f); | ||||||
|  |     madeQP.cost.push_back(obj); | ||||||
|  | 
 | ||||||
|  |     // Add equality and inequality constraints into the QP
 | ||||||
|  |     size_t dual_key_num = keys.size() + 1; | ||||||
|  |     for (auto kv : E) { | ||||||
|  |       map<Key, Matrix11> keyMatrixMapPos; | ||||||
|  |       map<Key, Matrix11> keyMatrixMapNeg; | ||||||
|  |       if (ranges.count(kv.first) == 1) { | ||||||
|  |         for (auto km : kv.second) { | ||||||
|  |           keyMatrixMapPos.insert(km); | ||||||
|  |           km.second = -km.second; | ||||||
|  |           keyMatrixMapNeg.insert(km); | ||||||
|  |         } | ||||||
|  |         if (ranges[kv.first] > 0) { | ||||||
|  |           madeQP.inequalities.push_back( | ||||||
|  |               LinearInequality(keyMatrixMapNeg, -b[kv.first], dual_key_num++)); | ||||||
|  |           madeQP.inequalities.push_back(LinearInequality( | ||||||
|  |               keyMatrixMapPos, b[kv.first] + ranges[kv.first], dual_key_num++)); | ||||||
|  |         } else if (ranges[kv.first] < 0) { | ||||||
|  |           madeQP.inequalities.push_back( | ||||||
|  |               LinearInequality(keyMatrixMapPos, b[kv.first], dual_key_num++)); | ||||||
|  |           madeQP.inequalities.push_back(LinearInequality( | ||||||
|  |               keyMatrixMapNeg, ranges[kv.first] - b[kv.first], dual_key_num++)); | ||||||
|  |         } else { | ||||||
|  |           cerr << "ERROR: CANNOT ADD A RANGE OF ZERO" << endl; | ||||||
|  |           throw; | ||||||
|  |         } | ||||||
|  |         continue; | ||||||
|  |       } | ||||||
|  |       map<Key, Matrix11> keyMatrixMap; | ||||||
|  |       for (auto km : kv.second) { | ||||||
|  |         keyMatrixMap.insert(km); | ||||||
|  |       } | ||||||
|  |       madeQP.equalities.push_back( | ||||||
|  |           LinearEquality(keyMatrixMap, b[kv.first] * I_1x1, dual_key_num++)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     for (auto kv : IG) { | ||||||
|  |       map<Key, Matrix11> keyMatrixMapNeg; | ||||||
|  |       map<Key, Matrix11> keyMatrixMapPos; | ||||||
|  |       for (auto km : kv.second) { | ||||||
|  |         keyMatrixMapPos.insert(km); | ||||||
|  |         km.second = -km.second; | ||||||
|  |         keyMatrixMapNeg.insert(km); | ||||||
|  |       } | ||||||
|  |       madeQP.inequalities.push_back( | ||||||
|  |           LinearInequality(keyMatrixMapNeg, -b[kv.first], dual_key_num++)); | ||||||
|  |       if (ranges.count(kv.first) == 1) { | ||||||
|  |         madeQP.inequalities.push_back(LinearInequality( | ||||||
|  |             keyMatrixMapPos, b[kv.first] + ranges[kv.first], dual_key_num++)); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     for (auto kv : IL) { | ||||||
|  |       map<Key, Matrix11> keyMatrixMapPos; | ||||||
|  |       map<Key, Matrix11> keyMatrixMapNeg; | ||||||
|  |       for (auto km : kv.second) { | ||||||
|  |         keyMatrixMapPos.insert(km); | ||||||
|  |         km.second = -km.second; | ||||||
|  |         keyMatrixMapNeg.insert(km); | ||||||
|  |       } | ||||||
|  |       madeQP.inequalities.push_back( | ||||||
|  |           LinearInequality(keyMatrixMapPos, b[kv.first], dual_key_num++)); | ||||||
|  |       if (ranges.count(kv.first) == 1) { | ||||||
|  |         madeQP.inequalities.push_back(LinearInequality( | ||||||
|  |             keyMatrixMapNeg, ranges[kv.first] - b[kv.first], dual_key_num++)); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     for (Key k : keys) { | ||||||
|  |       if (find(free.begin(), free.end(), k) != free.end()) continue; | ||||||
|  |       if (fx.count(k) == 1) | ||||||
|  |         madeQP.equalities.push_back( | ||||||
|  |             LinearEquality(k, I_1x1, fx[k] * I_1x1, dual_key_num++)); | ||||||
|  |       if (up.count(k) == 1) | ||||||
|  |         madeQP.inequalities.push_back( | ||||||
|  |             LinearInequality(k, I_1x1, up[k], dual_key_num++)); | ||||||
|  |       if (lo.count(k) == 1) | ||||||
|  |         madeQP.inequalities.push_back( | ||||||
|  |             LinearInequality(k, -I_1x1, -lo[k], dual_key_num++)); | ||||||
|  |       else | ||||||
|  |         madeQP.inequalities.push_back( | ||||||
|  |             LinearInequality(k, -I_1x1, 0, dual_key_num++)); | ||||||
|  |     } | ||||||
|  |     return madeQP; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| typedef qi::grammar<boost::spirit::basic_istream_iterator<char>> base_grammar; | typedef qi::grammar<boost::spirit::basic_istream_iterator<char>> base_grammar; | ||||||
| 
 | 
 | ||||||
| struct QPSParser::MPSGrammar: base_grammar { | struct QPSParser::MPSGrammar : base_grammar { | ||||||
|   typedef std::vector<char> Chars; |   typedef std::vector<char> Chars; | ||||||
|   QPSVisitor * rqp_; |   QPSVisitor *rqp_; | ||||||
|   boost::function<void(bf::vector<Chars, Chars, Chars> const&)> setName; |   boost::function<void(bf::vector<Chars, Chars, Chars> const &)> setName; | ||||||
|   boost::function<void(bf::vector<Chars, char, Chars, Chars, Chars> const &)> addRow; |   boost::function<void(bf::vector<Chars, char, Chars, Chars, Chars> const &)> | ||||||
|   boost::function< |       addRow; | ||||||
|       void(bf::vector<Chars, Chars, Chars, Chars, Chars, double, Chars> const &)> rhsSingle; |   boost::function<void( | ||||||
|   boost::function< |       bf::vector<Chars, Chars, Chars, Chars, Chars, double, Chars> const &)> | ||||||
|       void( |       rhsSingle; | ||||||
|           bf::vector<Chars, Chars, Chars, Chars, Chars, double, Chars, Chars, |   boost::function<void(bf::vector<Chars, Chars, Chars, Chars, Chars, double, | ||||||
|               Chars, double>)> rhsDouble; |                                   Chars, Chars, Chars, double>)> | ||||||
|   boost::function< |       rhsDouble; | ||||||
|       void(bf::vector<Chars, Chars, Chars, Chars, Chars, double, Chars> const &)> rangeSingle; |   boost::function<void( | ||||||
|   boost::function< |       bf::vector<Chars, Chars, Chars, Chars, Chars, double, Chars> const &)> | ||||||
|       void( |       rangeSingle; | ||||||
|           bf::vector<Chars, Chars, Chars, Chars, Chars, double, Chars, Chars, |   boost::function<void(bf::vector<Chars, Chars, Chars, Chars, Chars, double, | ||||||
|               Chars, double>)> rangeDouble; |                                   Chars, Chars, Chars, double>)> | ||||||
|   boost::function< |       rangeDouble; | ||||||
|       void(bf::vector<Chars, Chars, Chars, Chars, Chars, double, Chars>)> colSingle; |   boost::function<void( | ||||||
|   boost::function< |       bf::vector<Chars, Chars, Chars, Chars, Chars, double, Chars>)> | ||||||
|       void( |       colSingle; | ||||||
|           bf::vector<Chars, Chars, Chars, Chars, double, Chars, Chars, Chars, |   boost::function<void(bf::vector<Chars, Chars, Chars, Chars, double, Chars, | ||||||
|               double> const &)> colDouble; |                                   Chars, Chars, double> const &)> | ||||||
|   boost::function< |       colDouble; | ||||||
|       void(bf::vector<Chars, Chars, Chars, Chars, Chars, double, Chars> const &)> addQuadTerm; |   boost::function<void( | ||||||
|   boost::function< |       bf::vector<Chars, Chars, Chars, Chars, Chars, double, Chars> const &)> | ||||||
|       void( |       addQuadTerm; | ||||||
|           bf::vector<Chars, Chars, Chars, Chars, Chars, Chars, Chars, double> const &)> addBound; |   boost::function<void(bf::vector<Chars, Chars, Chars, Chars, Chars, Chars, | ||||||
|   boost::function< |                                   Chars, double> const &)> | ||||||
|       void(bf::vector<Chars, Chars, Chars, Chars, Chars, Chars, Chars> const &)> addFreeBound; |       addBound; | ||||||
|   MPSGrammar(QPSVisitor * rqp) : |   boost::function<void( | ||||||
|       base_grammar(start), rqp_(rqp), setName( |       bf::vector<Chars, Chars, Chars, Chars, Chars, Chars, Chars> const &)> | ||||||
|           boost::bind(&QPSVisitor::setName, rqp, ::_1)), addRow( |       addFreeBound; | ||||||
|           boost::bind(&QPSVisitor::addRow, rqp, ::_1)), rhsSingle( |   MPSGrammar(QPSVisitor *rqp) | ||||||
|           boost::bind(&QPSVisitor::addRHS, rqp, ::_1)), rhsDouble( |       : base_grammar(start), | ||||||
|           boost::bind(&QPSVisitor::addRHSDouble, rqp, ::_1)), rangeSingle( |         rqp_(rqp), | ||||||
|           boost::bind(&QPSVisitor::addRangeSingle, rqp, ::_1)), rangeDouble( |         setName(boost::bind(&QPSVisitor::setName, rqp, ::_1)), | ||||||
|           boost::bind(&QPSVisitor::addRangeDouble, rqp, ::_1)), colSingle( |         addRow(boost::bind(&QPSVisitor::addRow, rqp, ::_1)), | ||||||
|           boost::bind(&QPSVisitor::addColumn, rqp, ::_1)), colDouble( |         rhsSingle(boost::bind(&QPSVisitor::addRHS, rqp, ::_1)), | ||||||
|           boost::bind(&QPSVisitor::addColumnDouble, rqp, ::_1)), addQuadTerm( |         rhsDouble(boost::bind(&QPSVisitor::addRHSDouble, rqp, ::_1)), | ||||||
|           boost::bind(&QPSVisitor::addQuadTerm, rqp, ::_1)), addBound( |         rangeSingle(boost::bind(&QPSVisitor::addRangeSingle, rqp, ::_1)), | ||||||
|           boost::bind(&QPSVisitor::addBound, rqp, ::_1)), addFreeBound( |         rangeDouble(boost::bind(&QPSVisitor::addRangeDouble, rqp, ::_1)), | ||||||
|           boost::bind(&QPSVisitor::addFreeBound, rqp, ::_1)) { |         colSingle(boost::bind(&QPSVisitor::addColumn, rqp, ::_1)), | ||||||
|  |         colDouble(boost::bind(&QPSVisitor::addColumnDouble, rqp, ::_1)), | ||||||
|  |         addQuadTerm(boost::bind(&QPSVisitor::addQuadTerm, rqp, ::_1)), | ||||||
|  |         addBound(boost::bind(&QPSVisitor::addBound, rqp, ::_1)), | ||||||
|  |         addFreeBound(boost::bind(&QPSVisitor::addFreeBound, rqp, ::_1)) { | ||||||
|     using namespace boost::spirit; |     using namespace boost::spirit; | ||||||
|     using namespace boost::spirit::qi; |     using namespace boost::spirit::qi; | ||||||
|     character = lexeme[alnum | '_' | '-' | '.']; |     character = lexeme[alnum | '_' | '-' | '.']; | ||||||
|  | @ -82,42 +458,48 @@ struct QPSParser::MPSGrammar: base_grammar { | ||||||
|     word = lexeme[+character]; |     word = lexeme[+character]; | ||||||
|     name = lexeme[lit("NAME") >> *blank >> title >> +space][setName]; |     name = lexeme[lit("NAME") >> *blank >> title >> +space][setName]; | ||||||
|     row = lexeme[*blank >> character >> +blank >> word >> *blank][addRow]; |     row = lexeme[*blank >> character >> +blank >> word >> *blank][addRow]; | ||||||
|     rhs_single = lexeme[*blank >> word >> +blank >> word >> +blank >> double_ |     rhs_single = lexeme[*blank >> word >> +blank >> word >> +blank >> double_ >> | ||||||
|         >> *blank][rhsSingle]; |                         *blank][rhsSingle]; | ||||||
|     rhs_double = lexeme[(*blank >> word >> +blank >> word >> +blank >> double_ |     rhs_double = | ||||||
|         >> +blank >> word >> +blank >> double_)[rhsDouble] >> *blank]; |         lexeme[(*blank >> word >> +blank >> word >> +blank >> double_ >> | ||||||
|     range_single = lexeme[*blank >> word >> +blank >> word >> +blank >> double_ |                 +blank >> word >> +blank >> double_)[rhsDouble] >> | ||||||
|         >> *blank][rangeSingle]; |                *blank]; | ||||||
|     range_double = lexeme[(*blank >> word >> +blank >> word >> +blank >> double_ |     range_single = lexeme[*blank >> word >> +blank >> word >> +blank >> | ||||||
|         >> +blank >> word >> +blank >> double_)[rangeDouble] >> *blank]; |                           double_ >> *blank][rangeSingle]; | ||||||
|     col_single = lexeme[*blank >> word >> +blank >> word >> +blank >> double_ |     range_double = | ||||||
|         >> *blank][colSingle]; |         lexeme[(*blank >> word >> +blank >> word >> +blank >> double_ >> | ||||||
|     col_double = lexeme[*blank |                 +blank >> word >> +blank >> double_)[rangeDouble] >> | ||||||
|         >> (word >> +blank >> word >> +blank >> double_ >> +blank >> word |                *blank]; | ||||||
|             >> +blank >> double_)[colDouble] >> *blank]; |     col_single = lexeme[*blank >> word >> +blank >> word >> +blank >> double_ >> | ||||||
|     quad_l = lexeme[*blank >> word >> +blank >> word >> +blank >> double_ |                         *blank][colSingle]; | ||||||
|         >> *blank][addQuadTerm]; |     col_double = | ||||||
|     bound = lexeme[(*blank >> word >> +blank >> word >> +blank >> word >> +blank |         lexeme[*blank >> (word >> +blank >> word >> +blank >> double_ >> | ||||||
|         >> double_)[addBound] >> *blank]; |                           +blank >> word >> +blank >> double_)[colDouble] >> | ||||||
|     bound_fr = lexeme[*blank >> word >> +blank >> word >> +blank >> word |                *blank]; | ||||||
|         >> *blank][addFreeBound]; |     quad_l = lexeme[*blank >> word >> +blank >> word >> +blank >> double_ >> | ||||||
|  |                     *blank][addQuadTerm]; | ||||||
|  |     bound = lexeme[(*blank >> word >> +blank >> word >> +blank >> word >> | ||||||
|  |                     +blank >> double_)[addBound] >> | ||||||
|  |                    *blank]; | ||||||
|  |     bound_fr = lexeme[*blank >> word >> +blank >> word >> +blank >> word >> | ||||||
|  |                       *blank][addFreeBound]; | ||||||
|     rows = lexeme[lit("ROWS") >> *blank >> eol >> +(row >> eol)]; |     rows = lexeme[lit("ROWS") >> *blank >> eol >> +(row >> eol)]; | ||||||
|     rhs = lexeme[lit("RHS") >> *blank >> eol |     rhs = lexeme[lit("RHS") >> *blank >> eol >> | ||||||
|         >> +((rhs_double | rhs_single) >> eol)]; |                  +((rhs_double | rhs_single) >> eol)]; | ||||||
|     cols = lexeme[lit("COLUMNS") >> *blank >> eol |     cols = lexeme[lit("COLUMNS") >> *blank >> eol >> | ||||||
|         >> +((col_double | col_single) >> eol)]; |                   +((col_double | col_single) >> eol)]; | ||||||
|     quad = lexeme[lit("QUADOBJ") >> *blank >> eol >> +(quad_l >> eol)]; |     quad = lexeme[lit("QUADOBJ") >> *blank >> eol >> +(quad_l >> eol)]; | ||||||
|     bounds = lexeme[lit("BOUNDS") >> +space >> *((bound | bound_fr) >> eol)]; |     bounds = lexeme[lit("BOUNDS") >> +space >> *((bound | bound_fr) >> eol)]; | ||||||
|     ranges = lexeme[lit("RANGES") >> +space |     ranges = lexeme[lit("RANGES") >> +space >> | ||||||
|         >> *((range_double | range_single) >> eol)]; |                     *((range_double | range_single) >> eol)]; | ||||||
|     end = lexeme[lit("ENDATA") >> *space]; |     end = lexeme[lit("ENDATA") >> *space]; | ||||||
|     start = lexeme[name >> rows >> cols >> rhs >> -ranges >> bounds >> quad |     start = | ||||||
|         >> end]; |         lexeme[name >> rows >> cols >> rhs >> -ranges >> bounds >> quad >> end]; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   qi::rule<boost::spirit::basic_istream_iterator<char>, char()> character; |   qi::rule<boost::spirit::basic_istream_iterator<char>, char()> character; | ||||||
|   qi::rule<boost::spirit::basic_istream_iterator<char>, Chars()> word, title; |   qi::rule<boost::spirit::basic_istream_iterator<char>, Chars()> word, title; | ||||||
|   qi::rule<boost::spirit::basic_istream_iterator<char> > row, end, col_single, |   qi::rule<boost::spirit::basic_istream_iterator<char>> row, end, col_single, | ||||||
|       col_double, rhs_single, rhs_double, range_single, range_double, ranges, |       col_double, rhs_single, rhs_double, range_single, range_double, ranges, | ||||||
|       bound, bound_fr, bounds, quad, quad_l, rows, cols, rhs, name, start; |       bound, bound_fr, bounds, quad, quad_l, rows, cols, rhs, name, start; | ||||||
| }; | }; | ||||||
|  | @ -136,4 +518,4 @@ QP QPSParser::Parse() { | ||||||
|   return rawData.makeQP(); |   return rawData.makeQP(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } | }  // namespace gtsam
 | ||||||
|  |  | ||||||
|  | @ -1,353 +0,0 @@ | ||||||
| /* ----------------------------------------------------------------------------
 |  | ||||||
| 
 |  | ||||||
|  * GTSAM Copyright 2010, Georgia Tech Research Corporation, |  | ||||||
|  * Atlanta, Georgia 30332-0415 |  | ||||||
|  * All Rights Reserved |  | ||||||
|  * Authors: Frank Dellaert, et al. (see THANKS for the full author list) |  | ||||||
| 
 |  | ||||||
|  * See LICENSE for the license information |  | ||||||
| 
 |  | ||||||
|  * -------------------------------------------------------------------------- */ |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * @file     QPSVisitor.cpp |  | ||||||
|  * @brief    As the QPS parser reads a file, it call functions in QPSVistor. |  | ||||||
|  * This visitor in turn stores what the parser has read in a way that can be |  | ||||||
|  * later used to build the Factor Graph for the QP Constraints and cost. This |  | ||||||
|  * intermediate representation is required because an expression in the QPS file |  | ||||||
|  * doesn't necessarily correspond to a single constraint or term in the cost |  | ||||||
|  * function. |  | ||||||
|  * @author   Ivan Dario Jimenez |  | ||||||
|  * @date     3/5/16 |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| #include <gtsam_unstable/linear/QPSVisitor.h> |  | ||||||
| 
 |  | ||||||
| #include <algorithm> |  | ||||||
| #include <iostream> |  | ||||||
| #include <map> |  | ||||||
| 
 |  | ||||||
| using boost::fusion::at_c; |  | ||||||
| using namespace std; |  | ||||||
| 
 |  | ||||||
| using Chars = std::vector<char>; |  | ||||||
| 
 |  | ||||||
| // Get a string from a fusion vector of Chars
 |  | ||||||
| template <size_t I, class FusionVector> |  | ||||||
| static string fromChars(const FusionVector &vars) { |  | ||||||
|   const Chars &chars = at_c<I>(vars); |  | ||||||
|   return string(chars.begin(), chars.end()); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| namespace gtsam { |  | ||||||
| 
 |  | ||||||
| void QPSVisitor::setName( |  | ||||||
|     boost::fusion::vector<Chars, Chars, Chars> const &name) { |  | ||||||
|   name_ = fromChars<1>(name); |  | ||||||
|   if (debug) { |  | ||||||
|     cout << "Parsing file: " << name_ << endl; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void QPSVisitor::addColumn( |  | ||||||
|     boost::fusion::vector<Chars, Chars, Chars, Chars, Chars, double, |  | ||||||
|                           Chars> const &vars) { |  | ||||||
|   string var_ = fromChars<1>(vars); |  | ||||||
|   string row_ = fromChars<3>(vars); |  | ||||||
|   Matrix11 coefficient = at_c<5>(vars) * I_1x1; |  | ||||||
|   if (debug) { |  | ||||||
|     cout << "Added Column for Var: " << var_ << " Row: " << row_ |  | ||||||
|          << " Coefficient: " << coefficient << endl; |  | ||||||
|   } |  | ||||||
|   if (!varname_to_key.count(var_)) |  | ||||||
|     varname_to_key[var_] = Symbol('X', numVariables++); |  | ||||||
|   if (row_ == obj_name) { |  | ||||||
|     g[varname_to_key[var_]] = coefficient; |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   (*row_to_constraint_v[row_])[row_][varname_to_key[var_]] = coefficient; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void QPSVisitor::addColumnDouble( |  | ||||||
|     boost::fusion::vector<Chars, Chars, Chars, Chars, double, Chars, Chars, |  | ||||||
|                           Chars, double> const &vars) { |  | ||||||
|   string var_ = fromChars<0>(vars); |  | ||||||
|   string row1_ = fromChars<2>(vars); |  | ||||||
|   string row2_ = fromChars<6>(vars); |  | ||||||
|   Matrix11 coefficient1 = at_c<4>(vars) * I_1x1; |  | ||||||
|   Matrix11 coefficient2 = at_c<8>(vars) * I_1x1; |  | ||||||
|   if (!varname_to_key.count(var_)) |  | ||||||
|     varname_to_key.insert({var_, Symbol('X', numVariables++)}); |  | ||||||
|   if (row1_ == obj_name) |  | ||||||
|     g[varname_to_key[var_]] = coefficient1; |  | ||||||
|   else |  | ||||||
|     (*row_to_constraint_v[row1_])[row1_][varname_to_key[var_]] = coefficient1; |  | ||||||
|   if (row2_ == obj_name) |  | ||||||
|     g[varname_to_key[var_]] = coefficient2; |  | ||||||
|   else |  | ||||||
|     (*row_to_constraint_v[row2_])[row2_][varname_to_key[var_]] = coefficient2; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void QPSVisitor::addRangeSingle( |  | ||||||
|     boost::fusion::vector<Chars, Chars, Chars, Chars, Chars, double, |  | ||||||
|                           Chars> const &vars) { |  | ||||||
|   string var_ = fromChars<1>(vars); |  | ||||||
|   string row_ = fromChars<3>(vars); |  | ||||||
|   double range = at_c<5>(vars); |  | ||||||
|   ranges[row_] = range; |  | ||||||
|   if (debug) { |  | ||||||
|     cout << "SINGLE RANGE ADDED" << endl; |  | ||||||
|     cout << "VAR:" << var_ << " ROW: " << row_ << " RANGE: " << range << endl; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| void QPSVisitor::addRangeDouble( |  | ||||||
|     boost::fusion::vector<Chars, Chars, Chars, Chars, Chars, double, Chars, |  | ||||||
|                           Chars, Chars, double> const &vars) { |  | ||||||
|   string var_ = fromChars<1>(vars); |  | ||||||
|   string row1_ = fromChars<3>(vars); |  | ||||||
|   string row2_ = fromChars<7>(vars); |  | ||||||
|   double range1 = at_c<5>(vars); |  | ||||||
|   double range2 = at_c<9>(vars); |  | ||||||
|   ranges[row1_] = range1; |  | ||||||
|   ranges[row2_] = range2; |  | ||||||
|   if (debug) { |  | ||||||
|     cout << "DOUBLE RANGE ADDED" << endl; |  | ||||||
|     cout << "VAR: " << var_ << " ROW1: " << row1_ << " RANGE1: " << range1 |  | ||||||
|          << " ROW2: " << row2_ << " RANGE2: " << range2 << endl; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void QPSVisitor::addRHS(boost::fusion::vector<Chars, Chars, Chars, Chars, Chars, |  | ||||||
|                                               double, Chars> const &vars) { |  | ||||||
|   string var_ = fromChars<1>(vars); |  | ||||||
|   string row_ = fromChars<3>(vars); |  | ||||||
|   double coefficient = at_c<5>(vars); |  | ||||||
|   if (row_ == obj_name) |  | ||||||
|     f = -coefficient; |  | ||||||
|   else |  | ||||||
|     b[row_] = coefficient; |  | ||||||
| 
 |  | ||||||
|   if (debug) { |  | ||||||
|     cout << "Added RHS for Var: " << var_ << " Row: " << row_ |  | ||||||
|          << " Coefficient: " << coefficient << endl; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void QPSVisitor::addRHSDouble( |  | ||||||
|     boost::fusion::vector<Chars, Chars, Chars, Chars, Chars, double, Chars, |  | ||||||
|                           Chars, Chars, double> const &vars) { |  | ||||||
|   string var_ = fromChars<1>(vars); |  | ||||||
|   string row1_ = fromChars<3>(vars); |  | ||||||
|   string row2_ = fromChars<7>(vars); |  | ||||||
|   double coefficient1 = at_c<5>(vars); |  | ||||||
|   double coefficient2 = at_c<9>(vars); |  | ||||||
|   if (row1_ == obj_name) |  | ||||||
|     f = -coefficient1; |  | ||||||
|   else |  | ||||||
|     b[row1_] = coefficient1; |  | ||||||
| 
 |  | ||||||
|   if (row2_ == obj_name) |  | ||||||
|     f = -coefficient2; |  | ||||||
|   else |  | ||||||
|     b[row2_] = coefficient2; |  | ||||||
| 
 |  | ||||||
|   if (debug) { |  | ||||||
|     cout << "Added RHS for Var: " << var_ << " Row: " << row1_ |  | ||||||
|          << " Coefficient: " << coefficient1 << endl; |  | ||||||
|     cout << "                      " |  | ||||||
|          << "Row: " << row2_ << " Coefficient: " << coefficient2 << endl; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void QPSVisitor::addRow( |  | ||||||
|     boost::fusion::vector<Chars, char, Chars, Chars, Chars> const &vars) { |  | ||||||
|   string name_ = fromChars<3>(vars); |  | ||||||
|   char type = at_c<1>(vars); |  | ||||||
|   switch (type) { |  | ||||||
|     case 'N': |  | ||||||
|       obj_name = name_; |  | ||||||
|       break; |  | ||||||
|     case 'L': |  | ||||||
|       row_to_constraint_v[name_] = &IL; |  | ||||||
|       break; |  | ||||||
|     case 'G': |  | ||||||
|       row_to_constraint_v[name_] = &IG; |  | ||||||
|       break; |  | ||||||
|     case 'E': |  | ||||||
|       row_to_constraint_v[name_] = &E; |  | ||||||
|       break; |  | ||||||
|     default: |  | ||||||
|       cout << "invalid type: " << type << endl; |  | ||||||
|       break; |  | ||||||
|   } |  | ||||||
|   if (debug) { |  | ||||||
|     cout << "Added Row Type: " << type << " Name: " << name_ << endl; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void QPSVisitor::addBound( |  | ||||||
|     boost::fusion::vector<Chars, Chars, Chars, Chars, Chars, Chars, Chars, |  | ||||||
|                           double> const &vars) { |  | ||||||
|   string type_ = fromChars<1>(vars); |  | ||||||
|   string var_ = fromChars<5>(vars); |  | ||||||
|   double number = at_c<7>(vars); |  | ||||||
|   if (type_.compare(string("UP")) == 0) |  | ||||||
|     up[varname_to_key[var_]] = number; |  | ||||||
|   else if (type_.compare(string("LO")) == 0) |  | ||||||
|     lo[varname_to_key[var_]] = number; |  | ||||||
|   else if (type_.compare(string("FX")) == 0) |  | ||||||
|     fx[varname_to_key[var_]] = number; |  | ||||||
|   else |  | ||||||
|     cout << "Invalid Bound Type: " << type_ << endl; |  | ||||||
| 
 |  | ||||||
|   if (debug) { |  | ||||||
|     cout << "Added Bound Type: " << type_ << " Var: " << var_ |  | ||||||
|          << " Amount: " << number << endl; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void QPSVisitor::addFreeBound( |  | ||||||
|     boost::fusion::vector<Chars, Chars, Chars, Chars, Chars, Chars, Chars> const |  | ||||||
|         &vars) { |  | ||||||
|   string type_ = fromChars<1>(vars); |  | ||||||
|   string var_ = fromChars<5>(vars); |  | ||||||
|   free.push_back(varname_to_key[var_]); |  | ||||||
|   if (debug) { |  | ||||||
|     cout << "Added Free Bound Type: " << type_ << " Var: " << var_ |  | ||||||
|          << " Amount: " << endl; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void QPSVisitor::addQuadTerm( |  | ||||||
|     boost::fusion::vector<Chars, Chars, Chars, Chars, Chars, double, |  | ||||||
|                           Chars> const &vars) { |  | ||||||
|   string var1_ = fromChars<1>(vars); |  | ||||||
|   string var2_ = fromChars<3>(vars); |  | ||||||
|   Matrix11 coefficient = at_c<5>(vars) * I_1x1; |  | ||||||
| 
 |  | ||||||
|   H[varname_to_key[var1_]][varname_to_key[var2_]] = coefficient; |  | ||||||
|   H[varname_to_key[var2_]][varname_to_key[var1_]] = coefficient; |  | ||||||
|   if (debug) { |  | ||||||
|     cout << "Added QuadTerm for Var: " << var1_ << " Row: " << var2_ |  | ||||||
|          << " Coefficient: " << coefficient << endl; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| QP QPSVisitor::makeQP() { |  | ||||||
|   // Create the keys from the variable names
 |  | ||||||
|   KeyVector keys; |  | ||||||
|   for (auto kv : varname_to_key) { |  | ||||||
|     keys.push_back(kv.second); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   // Fill the G matrices and g vectors from
 |  | ||||||
|   vector<Matrix> Gs; |  | ||||||
|   vector<Vector> gs; |  | ||||||
|   sort(keys.begin(), keys.end()); |  | ||||||
|   for (size_t i = 0; i < keys.size(); ++i) { |  | ||||||
|     for (size_t j = i; j < keys.size(); ++j) { |  | ||||||
|       if (H.count(keys[i]) > 0 && H[keys[i]].count(keys[j]) > 0) { |  | ||||||
|         Gs.emplace_back(H[keys[i]][keys[j]]); |  | ||||||
|       } else { |  | ||||||
|         Gs.emplace_back(Z_1x1); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   for (Key key1 : keys) { |  | ||||||
|     if (g.count(key1) > 0) { |  | ||||||
|       gs.emplace_back(-g[key1]); |  | ||||||
|     } else { |  | ||||||
|       gs.emplace_back(Z_1x1); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   // Construct the quadratic program
 |  | ||||||
|   QP madeQP; |  | ||||||
|   auto obj = HessianFactor(keys, Gs, gs, 2 * f); |  | ||||||
|   madeQP.cost.push_back(obj); |  | ||||||
| 
 |  | ||||||
|   // Add equality and inequality constraints into the QP
 |  | ||||||
|   size_t dual_key_num = keys.size() + 1; |  | ||||||
|   for (auto kv : E) { |  | ||||||
|     map<Key, Matrix11> keyMatrixMapPos; |  | ||||||
|     map<Key, Matrix11> keyMatrixMapNeg; |  | ||||||
|     if (ranges.count(kv.first) == 1) { |  | ||||||
|       for (auto km : kv.second) { |  | ||||||
|         keyMatrixMapPos.insert(km); |  | ||||||
|         km.second = -km.second; |  | ||||||
|         keyMatrixMapNeg.insert(km); |  | ||||||
|       } |  | ||||||
|       if (ranges[kv.first] > 0) { |  | ||||||
|         madeQP.inequalities.push_back( |  | ||||||
|             LinearInequality(keyMatrixMapNeg, -b[kv.first], dual_key_num++)); |  | ||||||
|         madeQP.inequalities.push_back(LinearInequality( |  | ||||||
|             keyMatrixMapPos, b[kv.first] + ranges[kv.first], dual_key_num++)); |  | ||||||
|       } else if (ranges[kv.first] < 0) { |  | ||||||
|         madeQP.inequalities.push_back( |  | ||||||
|             LinearInequality(keyMatrixMapPos, b[kv.first], dual_key_num++)); |  | ||||||
|         madeQP.inequalities.push_back(LinearInequality( |  | ||||||
|             keyMatrixMapNeg, ranges[kv.first] - b[kv.first], dual_key_num++)); |  | ||||||
|       } else { |  | ||||||
|         cerr << "ERROR: CANNOT ADD A RANGE OF ZERO" << endl; |  | ||||||
|         throw; |  | ||||||
|       } |  | ||||||
|       continue; |  | ||||||
|     } |  | ||||||
|     map<Key, Matrix11> keyMatrixMap; |  | ||||||
|     for (auto km : kv.second) { |  | ||||||
|       keyMatrixMap.insert(km); |  | ||||||
|     } |  | ||||||
|     madeQP.equalities.push_back( |  | ||||||
|         LinearEquality(keyMatrixMap, b[kv.first] * I_1x1, dual_key_num++)); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   for (auto kv : IG) { |  | ||||||
|     map<Key, Matrix11> keyMatrixMapNeg; |  | ||||||
|     map<Key, Matrix11> keyMatrixMapPos; |  | ||||||
|     for (auto km : kv.second) { |  | ||||||
|       keyMatrixMapPos.insert(km); |  | ||||||
|       km.second = -km.second; |  | ||||||
|       keyMatrixMapNeg.insert(km); |  | ||||||
|     } |  | ||||||
|     madeQP.inequalities.push_back( |  | ||||||
|         LinearInequality(keyMatrixMapNeg, -b[kv.first], dual_key_num++)); |  | ||||||
|     if (ranges.count(kv.first) == 1) { |  | ||||||
|       madeQP.inequalities.push_back(LinearInequality( |  | ||||||
|           keyMatrixMapPos, b[kv.first] + ranges[kv.first], dual_key_num++)); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   for (auto kv : IL) { |  | ||||||
|     map<Key, Matrix11> keyMatrixMapPos; |  | ||||||
|     map<Key, Matrix11> keyMatrixMapNeg; |  | ||||||
|     for (auto km : kv.second) { |  | ||||||
|       keyMatrixMapPos.insert(km); |  | ||||||
|       km.second = -km.second; |  | ||||||
|       keyMatrixMapNeg.insert(km); |  | ||||||
|     } |  | ||||||
|     madeQP.inequalities.push_back( |  | ||||||
|         LinearInequality(keyMatrixMapPos, b[kv.first], dual_key_num++)); |  | ||||||
|     if (ranges.count(kv.first) == 1) { |  | ||||||
|       madeQP.inequalities.push_back(LinearInequality( |  | ||||||
|           keyMatrixMapNeg, ranges[kv.first] - b[kv.first], dual_key_num++)); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   for (Key k : keys) { |  | ||||||
|     if (find(free.begin(), free.end(), k) != free.end()) continue; |  | ||||||
|     if (fx.count(k) == 1) |  | ||||||
|       madeQP.equalities.push_back( |  | ||||||
|           LinearEquality(k, I_1x1, fx[k] * I_1x1, dual_key_num++)); |  | ||||||
|     if (up.count(k) == 1) |  | ||||||
|       madeQP.inequalities.push_back( |  | ||||||
|           LinearInequality(k, I_1x1, up[k], dual_key_num++)); |  | ||||||
|     if (lo.count(k) == 1) |  | ||||||
|       madeQP.inequalities.push_back( |  | ||||||
|           LinearInequality(k, -I_1x1, -lo[k], dual_key_num++)); |  | ||||||
|     else |  | ||||||
|       madeQP.inequalities.push_back( |  | ||||||
|           LinearInequality(k, -I_1x1, 0, dual_key_num++)); |  | ||||||
|   } |  | ||||||
|   return madeQP; |  | ||||||
| } |  | ||||||
| }  // namespace gtsam
 |  | ||||||
|  | @ -1,105 +0,0 @@ | ||||||
| /* ----------------------------------------------------------------------------
 |  | ||||||
| 
 |  | ||||||
|  * GTSAM Copyright 2010, Georgia Tech Research Corporation, |  | ||||||
|  * Atlanta, Georgia 30332-0415 |  | ||||||
|  * All Rights Reserved |  | ||||||
|  * Authors: Frank Dellaert, et al. (see THANKS for the full author list) |  | ||||||
| 
 |  | ||||||
|  * See LICENSE for the license information |  | ||||||
| 
 |  | ||||||
|  * -------------------------------------------------------------------------- */ |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * @file     QPSVisitor.h |  | ||||||
|  * @brief     |  | ||||||
|  * @author   Ivan Dario Jimenez |  | ||||||
|  * @date     3/5/16 |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| #pragma once |  | ||||||
| 
 |  | ||||||
| #include <gtsam/base/Matrix.h> |  | ||||||
| #include <gtsam/inference/Key.h> |  | ||||||
| #include <gtsam/inference/Symbol.h> |  | ||||||
| #include <gtsam_unstable/linear/QP.h> |  | ||||||
| 
 |  | ||||||
| #include <boost/fusion/include/vector.hpp> |  | ||||||
| #include <boost/fusion/sequence.hpp> |  | ||||||
| 
 |  | ||||||
| #include <string> |  | ||||||
| #include <unordered_map> |  | ||||||
| #include <vector> |  | ||||||
| 
 |  | ||||||
| namespace gtsam { |  | ||||||
| /**
 |  | ||||||
|  * As the parser reads a file, it call functions in this visitor. This visitor in turn stores what the parser has read |  | ||||||
|  * in a way that can be later used to build the full QP problem in the file. |  | ||||||
|  */ |  | ||||||
| class QPSVisitor { |  | ||||||
|  private: |  | ||||||
|   typedef std::unordered_map<Key, Matrix11> coefficient_v; |  | ||||||
|   typedef std::unordered_map<std::string, coefficient_v> constraint_v; |  | ||||||
| 
 |  | ||||||
|   std::unordered_map<std::string, constraint_v*> row_to_constraint_v;  // Maps QPS ROWS to Variable-Matrix pairs
 |  | ||||||
|   constraint_v E;   // Equalities
 |  | ||||||
|   constraint_v IG;  // Inequalities >=
 |  | ||||||
|   constraint_v IL;  // Inequalities <=
 |  | ||||||
|   unsigned int numVariables; |  | ||||||
|   std::unordered_map<std::string, double> b;  // maps from constraint name to b value for Ax = b equality constraints
 |  | ||||||
|   std::unordered_map<std::string, double> ranges;  // Inequalities can be specified as ranges on a variable
 |  | ||||||
|   std::unordered_map<Key, Vector1> g;  // linear term of quadratic cost
 |  | ||||||
|   std::unordered_map<std::string, Key> varname_to_key;  // Variable QPS string name to key
 |  | ||||||
|   std::unordered_map<Key, std::unordered_map<Key, Matrix11> > H;  // H from hessian
 |  | ||||||
|   double f;  // Constant term of quadratic cost
 |  | ||||||
|   std::string obj_name;  // the objective function has a name in the QPS
 |  | ||||||
|   std::string name_;  // the quadratic program has a name in the QPS
 |  | ||||||
|   std::unordered_map<Key, double> up;  // Upper Bound constraints on variable where X < MAX
 |  | ||||||
|   std::unordered_map<Key, double> lo;  // Lower Bound constraints on variable where MIN < X
 |  | ||||||
|   std::unordered_map<Key, double> fx;  // Equalities specified as FX in BOUNDS part of QPS
 |  | ||||||
|   KeyVector free;  // Variables can be specified as free (to which no constraints apply)
 |  | ||||||
|   const bool debug = false; |  | ||||||
| 
 |  | ||||||
|   using Chars = std::vector<char>; |  | ||||||
| 
 |  | ||||||
|  public: |  | ||||||
|   QPSVisitor() : numVariables(1) {} |  | ||||||
| 
 |  | ||||||
|   void setName(boost::fusion::vector<Chars, Chars, Chars> const& name); |  | ||||||
| 
 |  | ||||||
|   void addColumn(boost::fusion::vector<Chars, Chars, Chars, Chars, Chars, |  | ||||||
|                                        double, Chars> const& vars); |  | ||||||
| 
 |  | ||||||
|   void addColumnDouble( |  | ||||||
|       boost::fusion::vector<Chars, Chars, Chars, Chars, double, Chars, Chars, |  | ||||||
|                             Chars, double> const& vars); |  | ||||||
| 
 |  | ||||||
|   void addRHS(boost::fusion::vector<Chars, Chars, Chars, Chars, Chars, double, |  | ||||||
|                                     Chars> const& vars); |  | ||||||
| 
 |  | ||||||
|   void addRHSDouble( |  | ||||||
|       boost::fusion::vector<Chars, Chars, Chars, Chars, Chars, double, Chars, |  | ||||||
|                             Chars, Chars, double> const& vars); |  | ||||||
| 
 |  | ||||||
|   void addRangeSingle(boost::fusion::vector<Chars, Chars, Chars, Chars, Chars, |  | ||||||
|                                             double, Chars> const& vars); |  | ||||||
| 
 |  | ||||||
|   void addRangeDouble( |  | ||||||
|       boost::fusion::vector<Chars, Chars, Chars, Chars, Chars, double, Chars, |  | ||||||
|                             Chars, Chars, double> const& vars); |  | ||||||
| 
 |  | ||||||
|   void addRow( |  | ||||||
|       boost::fusion::vector<Chars, char, Chars, Chars, Chars> const& vars); |  | ||||||
| 
 |  | ||||||
|   void addBound(boost::fusion::vector<Chars, Chars, Chars, Chars, Chars, Chars, |  | ||||||
|                                       Chars, double> const& vars); |  | ||||||
| 
 |  | ||||||
|   void addFreeBound(boost::fusion::vector<Chars, Chars, Chars, Chars, Chars, |  | ||||||
|                                           Chars, Chars> const& vars); |  | ||||||
| 
 |  | ||||||
|   void addQuadTerm(boost::fusion::vector<Chars, Chars, Chars, Chars, Chars, |  | ||||||
|                                          double, Chars> const& vars); |  | ||||||
| 
 |  | ||||||
|   QP makeQP(); |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| }  // namespace gtsam
 |  | ||||||
		Loading…
	
		Reference in New Issue