ilqgames
A new real-time solver for large-scale differential games.
solver_log.h
1 /*
2  * Copyright (c) 2019, 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 
37 ///////////////////////////////////////////////////////////////////////////////
38 //
39 // Container to store solver logs.
40 //
41 ///////////////////////////////////////////////////////////////////////////////
42 
43 #ifndef ILQGAMES_UTILS_LOG_H
44 #define ILQGAMES_UTILS_LOG_H
45 
46 #include <ilqgames/utils/operating_point.h>
47 #include <ilqgames/utils/strategy.h>
48 #include <ilqgames/utils/types.h>
49 #include <ilqgames/utils/uncopyable.h>
50 
51 #include <math.h>
52 #include <vector>
53 
54 namespace ilqgames {
55 
56 // Default experiment name to use.
57 std::string DefaultExperimentName();
58 
59 class SolverLog : private Uncopyable {
60  public:
61  ~SolverLog() {}
62  SolverLog() {}
63 
64  // Add a new solver iterate.
65  void AddSolverIterate(const OperatingPoint& operating_point,
66  const std::vector<Strategy>& strategies,
67  const std::vector<float>& total_costs,
68  Time cumulative_runtime, bool was_converged) {
69  operating_points_.push_back(operating_point);
70  strategies_.push_back(strategies);
71  total_player_costs_.push_back(total_costs);
72  cumulative_runtimes_.push_back(cumulative_runtime);
73  was_converged_.push_back(was_converged);
74  }
75 
76  // Add a whole other log.
77  void AddLog(const SolverLog& log) {
78  for (size_t ii = 0; ii < log.NumIterates(); ii++) {
79  AddSolverIterate(log.operating_points_[ii], log.strategies_[ii],
80  log.total_player_costs_[ii],
81  log.cumulative_runtimes_[ii], log.was_converged_[ii]);
82  }
83  }
84 
85  // Clear all but first entry. Used by the solver to return initial conditions
86  // upon failure.
87  void ClearAllButFirstIterate() {
88  constexpr size_t kOneIterate = 1;
89 
90  CHECK_GE(operating_points_.size(), kOneIterate);
91  operating_points_.resize(kOneIterate, operating_points_.front());
92  strategies_.resize(kOneIterate);
93  total_player_costs_.resize(kOneIterate);
94  cumulative_runtimes_.resize(kOneIterate);
95  was_converged_.resize(kOneIterate);
96  }
97 
98  // Accessors.
99  bool WasConverged() const { return was_converged_.back(); }
100  bool WasConverged(size_t idx) const { return was_converged_[idx]; }
101  Time InitialTime() const {
102  return (NumIterates() > 0) ? operating_points_[0].t0 : 0.0;
103  }
104  Time FinalTime() const {
105  return (NumIterates() > 0) ? IndexToTime(operating_points_[0].xs.size() - 1)
106  : 0.0;
107  }
108  PlayerIndex NumPlayers() const { return strategies_[0].size(); }
109  size_t NumIterates() const { return operating_points_.size(); }
110  std::vector<float> TotalCosts() const { return total_player_costs_.back(); }
111 
112  const std::vector<Strategy>& InitialStrategies() const {
113  return strategies_.front();
114  }
115  const OperatingPoint& InitialOperatingPoint() const {
116  return operating_points_.front();
117  }
118  const std::vector<Strategy>& FinalStrategies() const {
119  return strategies_.back();
120  }
121  const OperatingPoint& FinalOperatingPoint() const {
122  return operating_points_.back();
123  }
124 
125  VectorXf InterpolateState(size_t iterate, Time t) const;
126  float InterpolateState(size_t iterate, Time t, Dimension dim) const;
127  VectorXf InterpolateControl(size_t iterate, Time t, PlayerIndex player) const;
128  float InterpolateControl(size_t iterate, Time t, PlayerIndex player,
129  Dimension dim) const;
130 
131  std::vector<MatrixXf> Ps(size_t iterate, size_t time_index) const;
132  std::vector<VectorXf> alphas(size_t iterate, size_t time_index) const;
133  MatrixXf P(size_t iterate, size_t time_index, PlayerIndex player) const;
134  VectorXf alpha(size_t iterate, size_t time_index, PlayerIndex player) const;
135 
136  VectorXf State(size_t iterate, size_t time_index) const {
137  return operating_points_[iterate].xs[time_index];
138  }
139  float State(size_t iterate, size_t time_index, Dimension dim) const {
140  return operating_points_[iterate].xs[time_index](dim);
141  }
142  VectorXf Control(size_t iterate, size_t time_index,
143  PlayerIndex player) const {
144  return operating_points_[iterate].us[time_index][player];
145  }
146  float Control(size_t iterate, size_t time_index, PlayerIndex player,
147  Dimension dim) const {
148  return operating_points_[iterate].us[time_index][player](dim);
149  }
150 
151  std::vector<MatrixXf> Ps(size_t iterate, Time t) const {
152  return Ps(iterate, TimeToIndex(t));
153  }
154  std::vector<VectorXf> alphas(size_t iterate, Time t) const {
155  return alphas(iterate, TimeToIndex(t));
156  }
157  MatrixXf P(size_t iterate, Time t, PlayerIndex player) const {
158  return P(iterate, TimeToIndex(t), player);
159  }
160  VectorXf alpha(size_t iterate, Time t, PlayerIndex player) const {
161  return alpha(iterate, TimeToIndex(t), player);
162  }
163 
164  // Get index corresponding to the time step immediately before the given time.
165  size_t TimeToIndex(Time t) const {
166  return static_cast<size_t>(
167  std::max<Time>(constants::kSmallNumber, t - InitialTime()) /
168  time::kTimeStep);
169  }
170 
171  // Get time stamp corresponding to a particular index.
172  Time IndexToTime(size_t idx) const {
173  return InitialTime() + time::kTimeStep * static_cast<Time>(idx);
174  }
175 
176  // Save to disk.
177  bool Save(bool only_last_trajectory = false,
178  const std::string& experiment_name = DefaultExperimentName()) const;
179 
180  private:
181  // Operating points, strategies, total costs, and cumulative runtime indexed
182  // by solver iterate.
183  std::vector<OperatingPoint> operating_points_;
184  std::vector<std::vector<Strategy>> strategies_;
185  std::vector<std::vector<float>> total_player_costs_;
186  std::vector<Time> cumulative_runtimes_;
187  std::vector<bool> was_converged_;
188 }; // class SolverLog
189 
190 // Utility to save a list of logs.
191 bool SaveLogs(const std::vector<SolverLog>& logs,
192  bool only_last_trajectory = true,
193  const std::string& experiment_name = DefaultExperimentName());
194 bool SaveLogs(const std::vector<std::shared_ptr<const SolverLog>>& logs,
195  bool only_last_trajectory = true,
196  const std::string& experiment_name = DefaultExperimentName());
197 
198 } // namespace ilqgames
199 
200 #endif