ilqgames
A new real-time solver for large-scale differential games.
cost_inspector.cpp
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 // Utility for plotting different costs for each player over time. Integrates
40 // with DearImGui.
41 //
42 ///////////////////////////////////////////////////////////////////////////////
43 
44 #include <ilqgames/gui/control_sliders.h>
45 #include <ilqgames/gui/cost_inspector.h>
46 #include <ilqgames/utils/operating_point.h>
47 #include <ilqgames/utils/player_cost_cache.h>
48 #include <ilqgames/utils/solver_log.h>
49 #include <ilqgames/utils/types.h>
50 
51 #include <glog/logging.h>
52 #include <imgui/imgui.h>
53 #include <string>
54 #include <vector>
55 
56 namespace ilqgames {
57 
58 void CostInspector::Render() const {
59  // Extract player costs.
60  // NOTE: need to redo this all the time to ensure that we're always using the
61  // most up to date log for each GUI widget.
62  const auto& costs1 =
63  player_costs_[selected_problem_][sliders_->LogIndex(selected_problem_)];
64 
65  // Do nothing if log is empty.
66  if (costs1.Log().NumIterates() == 0) return;
67 
68  // Set up main window.
69  ImGui::Begin("Cost Inspector");
70 
71  // Combo box to select problem.
72  if (ImGui::BeginCombo("Problem",
73  std::to_string(selected_problem_ + 1).c_str())) {
74  for (size_t problem_idx = 0; problem_idx < sliders_->NumProblems();
75  problem_idx++) {
76  const bool is_selected = (selected_problem_ == problem_idx);
77  if (ImGui::Selectable(std::to_string(problem_idx + 1).c_str(),
78  is_selected))
79  selected_problem_ = problem_idx;
80  if (is_selected) ImGui::SetItemDefaultFocus();
81  }
82 
83  ImGui::EndCombo();
84  }
85 
86  // Combo box to select player.
87  const auto& costs2 =
88  player_costs_[selected_problem_][sliders_->LogIndex(selected_problem_)];
89 
90  if (ImGui::BeginCombo("Player",
91  std::to_string(selected_player_ + 1).c_str())) {
92  for (PlayerIndex ii = 0; ii < costs2.NumPlayers(); ii++) {
93  const bool is_selected = (selected_player_ == ii);
94  if (ImGui::Selectable(std::to_string(ii + 1).c_str(), is_selected))
95  selected_player_ = ii;
96  if (is_selected) ImGui::SetItemDefaultFocus();
97  }
98 
99  ImGui::EndCombo();
100  }
101 
102  // Combo box to select cost.
103  const auto& costs3 =
104  player_costs_[selected_problem_][sliders_->LogIndex(selected_problem_)];
105 
106  if (ImGui::BeginCombo("Cost", selected_cost_name_.c_str())) {
107  for (const auto& entry : costs3.EvaluatedCosts(selected_player_)) {
108  const std::string& cost_name = entry.first;
109  const bool is_selected = (selected_cost_name_ == cost_name);
110  if (ImGui::Selectable(cost_name.c_str(), is_selected))
111  selected_cost_name_ = cost_name;
112  if (is_selected) ImGui::SetItemDefaultFocus();
113  }
114 
115  ImGui::EndCombo();
116  }
117 
118  // Plot the given cost.
119  const auto& costs4 =
120  player_costs_[selected_problem_][sliders_->LogIndex(selected_problem_)];
121  if (ImGui::BeginChild("Cost over time", ImVec2(0, 0), false)) {
122  const std::string label = "Player " + std::to_string(selected_player_ + 1) +
123  ": " + selected_cost_name_;
124  if (costs4.PlayerHasCost(selected_player_, selected_cost_name_)) {
125  const std::vector<float>& values =
126  costs4.EvaluatedCost(sliders_->SolverIterate(selected_problem_),
127  selected_player_, selected_cost_name_);
128  ImGui::PlotLines(label.c_str(), values.data(), values.size(), 0,
129  label.c_str(), FLT_MAX, FLT_MAX,
130  ImGui::GetWindowContentRegionMax());
131 
132  // Show a vertical line at the current time.
133  const float time = sliders_->InterpolationTime(selected_problem_);
134  const ImU32 color =
135  ImColor(ImVec4(234.0 / 255.0, 110.0 / 255.0, 110.0 / 255.0, 0.5));
136  constexpr float kLineThickness = 2.0;
137 
138  const ImVec2 window_top_left = ImGui::GetWindowPos();
139  const float line_y_lower = window_top_left.y + ImGui::GetWindowHeight();
140  const float line_y_upper = window_top_left.y;
141  const float line_x = window_top_left.x + ImGui::GetWindowWidth() * time /
142  costs4.Log().FinalTime();
143 
144  ImDrawList* draw_list = ImGui::GetWindowDrawList();
145  draw_list->AddLine(ImVec2(line_x, line_y_lower),
146  ImVec2(line_x, line_y_upper), color, kLineThickness);
147  }
148  }
149 
150  ImGui::EndChild();
151 
152  // End this window.
153  ImGui::End();
154 }
155 
156 } // namespace ilqgames