ilqgames
A new real-time solver for large-scale differential games.
lq_open_loop_solver.h
1 /*
2  * Copyright (c) 2020, 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 // Core open-loop LQ game solver based on Basar and Olsder, Chapter 6. All
40 // notation matches the text, though we shall assume that `c` (additive drift in
41 // dynamics) is always `0`, which holds because these dynamics are for delta x,
42 // delta us. Also, we have modified terms slightly to account for linear terms
43 // in the stage cost for control, i.e.
44 // control penalty i = 0.5 \sum_j du_j^T R_ij (du_j + 2 r_ij)
45 //
46 // Solve a time-varying, finite horizon LQ game (finds open-loop Nash
47 // feedback strategies for both players).
48 //
49 // Assumes that dynamics are given by
50 // ``` dx_{k+1} = A_k dx_k + \sum_i Bs[i]_k du[i]_k ```
51 //
52 // Returns strategies Ps, alphas. Here, all the Ps are zero (by default), and
53 // only the alphas are nonzero.
54 //
55 // Notation is based on derivation which may be found in the PDF included in
56 // this repository named "open_loop_lq_derivation.pdf".
57 //
58 ///////////////////////////////////////////////////////////////////////////////
59 
60 #ifndef ILQGAMES_SOLVER_LQ_OPEN_LOOP_SOLVER_H
61 #define ILQGAMES_SOLVER_LQ_OPEN_LOOP_SOLVER_H
62 
63 #include <ilqgames/dynamics/multi_player_integrable_system.h>
64 #include <ilqgames/solver/lq_solver.h>
65 #include <ilqgames/utils/linear_dynamics_approximation.h>
66 #include <ilqgames/utils/quadratic_cost_approximation.h>
67 #include <ilqgames/utils/strategy.h>
68 #include <vector>
69 
70 namespace ilqgames {
71 
72 class LQOpenLoopSolver : public LQSolver {
73  public:
74  ~LQOpenLoopSolver() {}
76  const std::shared_ptr<const MultiPlayerIntegrableSystem>& dynamics,
77  size_t num_time_steps)
78  : LQSolver(dynamics, num_time_steps) {
79  // Initialize Ms and ms.
80  Ms_.resize(num_time_steps_);
81  ms_.resize(num_time_steps_);
82  for (size_t kk = 0; kk < num_time_steps_; kk++) {
83  Ms_[kk].resize(dynamics_->NumPlayers(),
84  MatrixXf::Zero(dynamics_->XDim(), dynamics_->XDim()));
85  ms_[kk].resize(dynamics_->NumPlayers(),
86  VectorXf::Zero(dynamics_->XDim()));
87  }
88 
89  // Initialize other "special" terms and decompositions.
90  intermediate_terms_.resize(num_time_steps_ - 1,
91  VectorXf::Zero(dynamics_->XDim()));
92  capital_lambdas_.resize(
93  num_time_steps_ - 1,
94  MatrixXf::Zero(dynamics_->XDim(), dynamics_->XDim()));
95  qr_capital_lambdas_.resize(
96  num_time_steps_ - 1,
97  Eigen::HouseholderQR<MatrixXf>(dynamics_->XDim(), dynamics_->XDim()));
98 
99  std::vector<Eigen::LDLT<MatrixXf>> chol_Rs_element;
100  std::vector<MatrixXf> warped_Bs_element;
101  std::vector<VectorXf> warped_rs_element;
102  for (PlayerIndex ii = 0; ii < dynamics_->NumPlayers(); ii++) {
103  chol_Rs_element.emplace_back(dynamics_->UDim(ii));
104  warped_Bs_element.emplace_back(dynamics_->UDim(ii), dynamics_->XDim());
105  warped_rs_element.emplace_back(dynamics_->UDim(ii));
106  }
107 
108  chol_Rs_.resize(num_time_steps_ - 1, chol_Rs_element);
109  warped_Bs_.resize(num_time_steps_ - 1, warped_Bs_element);
110  warped_rs_.resize(num_time_steps_ - 1, warped_rs_element);
111  }
112 
113  // Solve underlying LQ game to a open-loop Nash equilibrium.
114  // Optionally return delta xs and costates.
115  std::vector<Strategy> Solve(
116  const std::vector<LinearDynamicsApproximation>& linearization,
117  const std::vector<std::vector<QuadraticCostApproximation>>&
118  quadraticization,
119  const VectorXf& x0, std::vector<VectorXf>* delta_xs = nullptr,
120  std::vector<std::vector<VectorXf>>* costates = nullptr);
121 
122  private:
123  // Initialize Ms and ms.
124  std::vector<std::vector<VectorXf>> ms_;
125  std::vector<std::vector<MatrixXf>> Ms_;
126 
127  // Instantiate the rest of the "special" terms and decompositions.
128  std::vector<VectorXf> intermediate_terms_;
129  std::vector<MatrixXf> capital_lambdas_;
130  std::vector<Eigen::HouseholderQR<MatrixXf>> qr_capital_lambdas_;
131  std::vector<std::vector<Eigen::LDLT<MatrixXf>>> chol_Rs_;
132  std::vector<std::vector<MatrixXf>> warped_Bs_;
133  std::vector<std::vector<VectorXf>> warped_rs_;
134 
135 }; // LQOpenLoopSolver
136 
137 } // namespace ilqgames
138 
139 #endif