matlab_value_function.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018, The Regents of the University of California (Regents).
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above
13  * copyright notice, this list of conditions and the following
14  * disclaimer in the documentation and/or other materials provided
15  * with the distribution.
16  *
17  * 3. Neither the name of the copyright holder nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Please contact the author(s) of this library if you have any questions.
34  * Authors: David Fridovich-Keil ( dfk@eecs.berkeley.edu )
35  */
36 
38 //
39 // Defines the MatlabValueFunction class, which derives from the base class
40 // ValueFunction and is templated on the tracker/planner state
41 // (TS/PS), tracker/planner control (TC/PC), tracker/planner dynamics (TD/PC),
42 // relative state (RS), relative dynamics (RD) and bound (B).
43 //
44 // NOTE: this class is templated on relative state (RS) and dynamics (RD)
45 // whereas the base class ValueFunction is NOT.
46 //
48 
49 #ifndef FASTRACK_VALUE_MATLAB_VALUE_FUNCTION_H
50 #define FASTRACK_VALUE_MATLAB_VALUE_FUNCTION_H
51 
56 #include <fastrack/utils/types.h>
58 
59 #include <ros/assert.h>
60 #include <ros/ros.h>
61 #include <functional>
62 
63 namespace fastrack {
64 namespace value {
65 
66 template <typename TS, typename TC, typename TD, typename PS, typename PC,
67  typename PD, typename RS, typename RD, typename B>
68 class MatlabValueFunction : public ValueFunction<TS, TC, TD, PS, PC, PD, B> {
69  public:
71  explicit MatlabValueFunction() : ValueFunction<TS, TC, TD, PS, PC, PD, B>() {}
72 
73  // Initialize from file. Returns whether or not loading was successful.
74  // Can be used as an alternative to intialization from a NodeHandle.
75  bool InitializeFromMatFile(const std::string& file_name);
76 
77  // Value and gradient at particular relative states.
78  double Value(const TS& tracker_x, const PS& planner_x) const;
79  std::unique_ptr<RelativeState<TS, PS>> Gradient(const TS& tracker_x,
80  const PS& planner_x) const;
81 
82  // Priority of the optimal control at the given tracker and planner states.
83  // This is a number between 0 and 1, where 1 means the final control signal
84  // should be exactly the optimal control signal computed by this
85  // value function.
86  double Priority(const TS& tracker_x, const PS& planner_x) const;
87 
88  private:
89  // Load parameters.
90  bool LoadParameters(const ros::NodeHandle& n) {
91  ros::NodeHandle nl(n);
92 
93  std::string file_name;
94  if (!nl.getParam("file_name", file_name)) return false;
95 
96  std::cout << "---------------------" << std::endl;
97  std::cout << file_name << std::endl;
98 
99  return InitializeFromMatFile(file_name);
100  }
101 
102  // Convert a (relative) state to an index into 'data_'.
103  size_t StateToIndex(const VectorXd& x) const;
104 
105  // Compute the difference vector between this (relative) state and the center
106  // of the nearest cell (i.e. cell center minus state).
107  VectorXd DirectionToCenter(const VectorXd& x) const;
108 
109  // Accessor for precomputed gradient at the given state.
110  VectorXd GradientAccessor(const VectorXd& x) const;
111 
112  // Compute the grid point below a given state in dimension idx.
113  double LowerGridPoint(const VectorXd& x, size_t idx) const;
114 
115  // Compute center of nearest grid cell to the given state.
116  VectorXd NearestCenterPoint(const VectorXd& x) const;
117 
118  // Recursive helper function for gradient multilinear interpolation.
119  // Takes in a state and index along which to interpolate.
120  VectorXd RecursiveGradientInterpolator(const VectorXd& x, size_t idx) const;
121 
122  // Lower and upper bounds for the value function. Used for computing the
123  // 'priority' of the optimal control signal.
126 
127  // Number of cells and upper/lower bounds in each dimension.
128  std::vector<size_t> num_cells_;
129  std::vector<double> cell_size_;
130  std::vector<double> lower_;
131  std::vector<double> upper_;
132 
133  // Value function itself is stored in row-major order.
134  std::vector<double> data_;
135 
136  // Gradient information at each cell. One list per dimension, each in the
137  // same order as 'data_'.
138  std::vector<std::vector<double>> gradient_;
139 }; //\class MatlabValueFunction
140 
141 // ---------------------------- IMPLEMENTATION ---------------------------- //
142 
143 // Value at the given relative state.
144 template <typename TS, typename TC, typename TD, typename PS, typename PC,
145  typename PD, typename RS, typename RD, typename B>
147  const TS& tracker_x, const PS& planner_x) const {
148  const VectorXd relative_x = RS(tracker_x, planner_x).ToVector();
149 
150  // Get distance from cell center in each dimension.
151  const VectorXd center_distance = DirectionToCenter(relative_x);
152 
153  // Interpolate.
154  const double nn_value = data_[StateToIndex(relative_x)];
155  double approx_value = nn_value;
156 
157  VectorXd neighbor = relative_x;
158  for (size_t ii = 0; ii < relative_x.size(); ii++) {
159  // Get neighboring value.
160  if (center_distance(ii) >= 0.0)
161  neighbor(ii) += cell_size_[ii];
162  else
163  neighbor(ii) -= cell_size_[ii];
164 
165  const double neighbor_value = data_[StateToIndex(neighbor)];
166  neighbor(ii) = relative_x(ii);
167 
168  // Compute forward difference.
169  const double slope = (center_distance(ii) >= 0.0)
170  ? (neighbor_value - nn_value) / cell_size_[ii]
171  : (nn_value - neighbor_value) / cell_size_[ii];
172 
173  // Add to the Taylor approximation.
174  approx_value += slope * center_distance(ii);
175  }
176 
177  return approx_value;
178 }
179 
180 // Gradient at the given relative state.
181 template <typename TS, typename TC, typename TD, typename PS, typename PC,
182  typename PD, typename RS, typename RD, typename B>
183 std::unique_ptr<RelativeState<TS, PS>>
185  const TS& tracker_x, const PS& planner_x) const {
186  const VectorXd relative_x = RS(tracker_x, planner_x).ToVector();
187 
188  // std::cout << "tracker_x: " << tracker_x.ToVector().transpose() << std::endl;
189  // std::cout << "planner_x: " << planner_x.ToVector().transpose() << std::endl;
190  // std::cout << "relative_x: " << relative_x.transpose() << std::endl;
191  // std::cout << "gradient: " << RecursiveGradientInterpolator(relative_x, 0).transpose() << std::endl;
192 
193  return std::unique_ptr<RS>(
194  new RS(RecursiveGradientInterpolator(relative_x, 0)));
195 }
196 
197 // Priority of the optimal control at the given tracker and planner states.
198 // This is a number between 0 and 1, where 1 means the final control signal
199 // should be exactly the optimal control signal computed by this
200 // value function.
201 template <typename TS, typename TC, typename TD, typename PS, typename PC,
202  typename PD, typename RS, typename RD, typename B>
204  const TS& tracker_x, const PS& planner_x) const {
205  const double value = Value(tracker_x, planner_x);
206 
207  if (value < priority_lower_) return 0.0;
208 
209  // HACK! If value is too high, just use LQR instead.
210  if (value > priority_upper_) return 0.0;
211  return (value - priority_lower_) / (priority_upper_ - priority_lower_);
212 }
213 
214 // Convert a (relative) state to an index into 'data_'.
215 template <typename TS, typename TC, typename TD, typename PS, typename PC,
216  typename PD, typename RS, typename RD, typename B>
218  const VectorXd& x) const {
219  // Quantize each dimension of the state.
220  std::vector<size_t> quantized;
221  for (size_t ii = 0; ii < x.size(); ii++) {
222  if (x(ii) < lower_[ii]) {
223  ROS_WARN_THROTTLE(1.0,
224  "%s: State is too small in dimension %zu: %f vs %f",
225  this->name_.c_str(), ii, x(ii), lower_[ii]);
226  quantized.push_back(0);
227  } else if (x(ii) > upper_[ii]) {
228  ROS_WARN_THROTTLE(1.0,
229  "%s: State is too large in dimension %zu: %f vs %f",
230  this->name_.c_str(), ii, x(ii), upper_[ii]);
231  quantized.push_back(num_cells_[ii] - 1);
232  } else {
233  // In bounds, so quantize. This works because of 0-indexing and casting.
234  quantized.push_back(
235  static_cast<size_t>((x(ii) - lower_[ii]) / cell_size_[ii]));
236  }
237  }
238 
239  // Convert to row-major order.
240  size_t idx = quantized[0];
241  for (size_t ii = 1; ii < quantized.size(); ii++) {
242  idx *= num_cells_[ii];
243  idx += quantized[ii];
244  }
245 
246  return idx;
247 }
248 
249 // Accessor for precomputed gradient at the given state.
250 template <typename TS, typename TC, typename TD, typename PS, typename PC,
251  typename PD, typename RS, typename RD, typename B>
252 VectorXd MatlabValueFunction<TS, TC, TD, PS, PC, PD, RS, RD,
253  B>::GradientAccessor(const VectorXd& x) const {
254  // Convert to index and read gradient one dimension at a time.
255  const size_t idx = StateToIndex(x);
256 
257  VectorXd gradient(x.size());
258  for (size_t ii = 0; ii < gradient.size(); ii++)
259  gradient(ii) = gradient_[ii][idx];
260 
261  return gradient;
262 }
263 
264 // Compute the difference vector between this (relative) state and the center
265 // of the nearest cell (i.e. cell center minus state).
266 template <typename TS, typename TC, typename TD, typename PS, typename PC,
267  typename PD, typename RS, typename RD, typename B>
268 VectorXd MatlabValueFunction<TS, TC, TD, PS, PC, PD, RS, RD,
269  B>::DirectionToCenter(const VectorXd& x) const {
270  return NearestCenterPoint(x) - x;
271 }
272 
273 // Compute the grid point below a given state in dimension idx.
274 template <typename TS, typename TC, typename TD, typename PS, typename PC,
275  typename PD, typename RS, typename RD, typename B>
277  const VectorXd& x, size_t idx) const {
278  // Get center of nearest cell.
279  const double center =
280  0.5 * cell_size_[idx] + lower_[idx] +
281  cell_size_[idx] * std::floor((x(idx) - lower_[idx]) / cell_size_[idx]);
282 
283  // Check if center is above us. If so, the lower bound is the cell below.
284  return (center > x(idx)) ? center - cell_size_[idx] : center;
285 }
286 
287 // Compute the center of the cell nearest to the given state.
288 template <typename TS, typename TC, typename TD, typename PS, typename PC,
289  typename PD, typename RS, typename RD, typename B>
290 VectorXd MatlabValueFunction<TS, TC, TD, PS, PC, PD, RS, RD,
291  B>::NearestCenterPoint(const VectorXd& x) const {
292  VectorXd center(x.size());
293 
294  for (size_t ii = 0; ii < center.size(); ii++)
295  center[ii] =
296  0.5 * cell_size_[ii] + lower_[ii] +
297  cell_size_[ii] * std::floor((x(ii) - lower_[ii]) / cell_size_[ii]);
298 
299  return center;
300 }
301 
302 // Recursive helper function for gradient multilinear interpolation.
303 // Takes in a state and index along which to interpolate.
304 template <typename TS, typename TC, typename TD, typename PS, typename PC,
305  typename PD, typename RS, typename RD, typename B>
306 VectorXd
307 MatlabValueFunction<TS, TC, TD, PS, PC, PD, RS, RD,
308  B>::RecursiveGradientInterpolator(const VectorXd& x,
309  size_t idx) const {
310  // Assume x's entries prior to idx are equal to the upper/lower bounds of
311  // the cell containing x.
312  // Begin by computing the lower and upper bounds of the cell containing x
313  // in dimension idx.
314  const double lower = LowerGridPoint(x, idx);
315  const double upper = lower + cell_size_[idx];
316 
317  // Compute the fractional distance between lower and upper.
318  const double fractional_dist = (x(idx) - lower) / cell_size_[idx];
319 
320  // Split x along dimension idx.
321  VectorXd x_lower = x;
322  x_lower(idx) = lower;
323 
324  VectorXd x_upper = x;
325  x_upper(idx) = upper;
326 
327  // Base case.
328  if (idx == x.size() - 1) {
329  return GradientAccessor(x_upper) * fractional_dist +
330  GradientAccessor(x_lower) * (1.0 - fractional_dist);
331  }
332 
333  // Recursive step.
334  return RecursiveGradientInterpolator(x_upper, idx + 1) * fractional_dist +
335  RecursiveGradientInterpolator(x_lower, idx + 1) *
336  (1.0 - fractional_dist);
337 }
338 
339 // Initialize from file. Returns whether or not loading was successful.
340 // Can be used as an alternative to intialization from a NodeHandle.
341 template <typename TS, typename TC, typename TD, typename PS, typename PC,
342  typename PD, typename RS, typename RD, typename B>
343 bool MatlabValueFunction<TS, TC, TD, PS, PC, PD, RS, RD,
344  B>::InitializeFromMatFile(const std::string&
345  file_name) {
346  // Open up this file.
347  MatlabFileReader reader(file_name);
348  if (!reader.IsOpen()) return false;
349 
350  // Load each class variable.
351  if (!reader.ReadScalar("priority_lower", &priority_lower_)) return false;
352  if (!reader.ReadScalar("priority_upper", &priority_upper_)) return false;
353  if (!reader.ReadVector("num_cells", &num_cells_)) return false;
354  if (!reader.ReadVector("lower", &lower_)) return false;
355  if (!reader.ReadVector("upper", &upper_)) return false;
356  if (!reader.ReadVector("data", &data_)) return false;
357 
358  // Check loaded variables.
360  ROS_ERROR("%s: Priority lower bound above upper bound.",
361  this->name_.c_str());
362  return false;
363  }
364 
365  if (num_cells_.size() != lower_.size() || lower_.size() != upper_.size()) {
366  ROS_ERROR("%s: Dimensions do not match.", this->name_.c_str());
367  return false;
368  }
369 
370  const double total_num_cells = std::accumulate(
371  num_cells_.begin(), num_cells_.end(), 1, std::multiplies<size_t>());
372  if (total_num_cells == 0) {
373  ROS_ERROR("%s: 0 total cells.", this->name_.c_str());
374  return false;
375  }
376 
377  if (data_.size() != total_num_cells) {
378  ROS_ERROR("%s: Grid data was of the wrong size.", this->name_.c_str());
379  return false;
380  }
381 
382  // Compute cell size.
383  for (size_t ii = 0; ii < num_cells_.size(); ii++)
384  cell_size_.emplace_back((upper_[ii] - lower_[ii]) /
385  static_cast<double>(num_cells_[ii]));
386 
387  // Load gradients.
388  for (size_t ii = 0; ii < num_cells_.size(); ii++) {
389  gradient_.emplace_back();
390  auto& partial = gradient_.back();
391  if (!reader.ReadVector("deriv_" + std::to_string(ii), &partial)) {
392  ROS_ERROR("%s: Could not read deriv_%zu.", this->name_.c_str(), ii);
393  return false;
394  }
395 
396  if (partial.size() != total_num_cells) {
397  ROS_ERROR("%s: Partial derivative in dimension %zu had incorrect size.",
398  this->name_.c_str(), ii);
399  return false;
400  }
401  }
402 
403  // Load dynamics and bound parameters.
404  std::vector<double> params;
405  if (!reader.ReadVector("tracker_params", &params)) return false;
406  this->tracker_dynamics_.Initialize(params);
407  if (!reader.ReadVector("planner_params", &params)) return false;
408  this->planner_dynamics_.Initialize(params);
409  this->relative_dynamics_.reset(new RD);
410 
411  if (!reader.ReadVector("bound_params", &params)) return false;
412  if (!this->bound_.Initialize(params)) return false;
413 
414  return true;
415 }
416 
417 } // namespace value
418 } // namespace fastrack
419 
420 #endif
bool InitializeFromMatFile(const std::string &file_name)
VectorXd NearestCenterPoint(const VectorXd &x) const
double LowerGridPoint(const VectorXd &x, size_t idx) const
std::unique_ptr< RelativeState< TS, PS > > Gradient(const TS &tracker_x, const PS &planner_x) const
bool ReadVector(const std::string &field_name, std::vector< double > *values)
size_t StateToIndex(const VectorXd &x) const
bool ReadScalar(const std::string &field_name, double *value)
VectorXd RecursiveGradientInterpolator(const VectorXd &x, size_t idx) const
VectorXd DirectionToCenter(const VectorXd &x) const
VectorXd GradientAccessor(const VectorXd &x) const
Definition: box.h:53
std::vector< std::vector< double > > gradient_
double Priority(const TS &tracker_x, const PS &planner_x) const
double Value(const TS &tracker_x, const PS &planner_x) const
std::unique_ptr< RelativeDynamics< TS, TC, PS, PC > > relative_dynamics_
bool LoadParameters(const ros::NodeHandle &n)


fastrack
Author(s): David Fridovich-Keil
autogenerated on Mon Aug 3 2020 21:28:37