Crocoddyl
callbacks.cpp
1 // BSD 3-Clause License
3 //
4 // Copyright (C) 2019-2025, LAAS-CNRS, University of Edinburgh,
5 // University of Oxford, Heriot-Watt University
6 // Copyright note valid unless otherwise stated in individual files.
7 // All rights reserved.
9 
10 #include "crocoddyl/core/utils/callbacks.hpp"
11 
12 namespace crocoddyl {
13 
14 CallbackVerbose::CallbackVerbose(VerboseLevel level, int precision)
15  : CallbackAbstract(),
16  level_(level),
17  separator_(" "),
18  separator_short_(" ") {
19  set_precision(precision);
20 }
21 
22 CallbackVerbose::~CallbackVerbose() {}
23 
24 VerboseLevel CallbackVerbose::get_level() const { return level_; }
25 
26 void CallbackVerbose::set_level(VerboseLevel level) {
27  level_ = level;
28  update_header();
29 }
30 
31 int CallbackVerbose::get_precision() const { return precision_; }
32 
33 void CallbackVerbose::set_precision(int precision) {
34  if (precision < 0) throw_pretty("The precision needs to be at least 0.");
35  precision_ = precision;
36  update_header();
37 }
38 
39 void CallbackVerbose::update_header() {
40  auto center_string = [](const std::string& str, int width,
41  bool right_padding = true) {
42  const int padding_size = width - static_cast<int>(str.length());
43  const int padding_left = padding_size > 0 ? padding_size / 2 : 0;
44  const int padding_right =
45  padding_size % 2 != 0
46  ? padding_left + 1
47  : padding_left; // If the padding is odd, add additional space
48  if (right_padding) {
49  return std::string(padding_left, ' ') + str +
50  std::string(padding_right, ' ');
51  } else {
52  return std::string(padding_left, ' ') + str;
53  }
54  };
55 
56  header_.clear();
57  // Scientific mode requires a column width of 6 + precision
58  const int columnwidth = 6 + precision_;
59  header_ += "iter" + separator_;
60  switch (level_) {
61  case _0: {
62  header_ += center_string("cost", columnwidth) + separator_;
63  header_ += center_string("stop", columnwidth) + separator_;
64  header_ += center_string("|grad|", columnwidth) + separator_;
65  header_ += center_string("preg", columnwidth) + separator_;
66  header_ += center_string("step", 6) + separator_;
67  header_ += center_string("dV-exp", columnwidth) + separator_;
68  header_ += center_string("dV", columnwidth, false);
69  break;
70  }
71  case _1: {
72  header_ += center_string("cost", columnwidth) + separator_;
73  header_ += center_string("merit", columnwidth) + separator_;
74  header_ += center_string("stop", columnwidth) + separator_;
75  header_ += center_string("|grad|", columnwidth) + separator_;
76  header_ += center_string("preg", columnwidth) + separator_;
77  header_ += center_string("step", 6) + separator_;
78  header_ += center_string("||ffeas||", columnwidth) + separator_;
79  header_ += center_string("dV-exp", columnwidth) + separator_;
80  header_ += center_string("dV", columnwidth, false);
81  break;
82  }
83  case _2: {
84  header_ += center_string("cost", columnwidth) + separator_;
85  header_ += center_string("merit", columnwidth) + separator_;
86  header_ += center_string("stop", columnwidth) + separator_;
87  header_ += center_string("|grad|", columnwidth) + separator_;
88  header_ += center_string("preg", columnwidth) + separator_;
89  header_ += center_string("dreg", columnwidth) + separator_;
90  header_ += center_string("step", 6) + separator_;
91  header_ += center_string("||ffeas||", columnwidth) + separator_;
92  header_ += center_string("dV-exp", columnwidth) + separator_;
93  header_ += center_string("dV", columnwidth, false);
94  break;
95  }
96  case _3: {
97  header_ += center_string("cost", columnwidth) + separator_;
98  header_ += center_string("merit", columnwidth) + separator_;
99  header_ += center_string("stop", columnwidth) + separator_;
100  header_ += center_string("|grad|", columnwidth) + separator_;
101  header_ += center_string("preg", columnwidth) + separator_;
102  header_ += center_string("dreg", columnwidth) + separator_;
103  header_ += center_string("step", 6) + separator_;
104  header_ += center_string("||ffeas||", columnwidth) + separator_;
105  header_ += center_string("||gfeas||", columnwidth) + separator_;
106  header_ += center_string("||hfeas||", columnwidth) + separator_;
107  header_ += center_string("dV-exp", columnwidth) + separator_;
108  header_ += center_string("dV", columnwidth, false);
109  break;
110  }
111  case _4: {
112  header_ += center_string("cost", columnwidth) + separator_;
113  header_ += center_string("merit", columnwidth) + separator_;
114  header_ += center_string("stop", columnwidth) + separator_;
115  header_ += center_string("|grad|", columnwidth) + separator_;
116  header_ += center_string("preg", columnwidth) + separator_;
117  header_ += center_string("dreg", columnwidth) + separator_;
118  header_ += center_string("step", 6) + separator_;
119  header_ += center_string("||ffeas||", columnwidth) + separator_;
120  header_ += center_string("||gfeas||", columnwidth) + separator_;
121  header_ += center_string("||hfeas||", columnwidth) + separator_;
122  header_ += center_string("dV-exp", columnwidth) + separator_;
123  header_ += center_string("dV", columnwidth) + separator_;
124  header_ += center_string("dPhi-exp", columnwidth) + separator_;
125  header_ += center_string("dPhi", columnwidth, false);
126  break;
127  }
128  default: {
129  }
130  }
131 }
132 
133 void CallbackVerbose::operator()(SolverAbstract& solver) {
134  if (solver.get_iter() % 10 == 0) {
135  std::cout << header_ << std::endl << std::flush;
136  }
137  auto space_sign = [this](const double value) {
138  std::stringstream stream;
139  if (value >= 0.) {
140  stream << " ";
141  } else {
142  stream << "-";
143  }
144  stream << std::scientific << std::setprecision(precision_) << abs(value);
145  return stream.str();
146  };
147 
148  std::cout << std::setw(4) << solver.get_iter() << separator_; // iter
149  switch (level_) {
150  case _0: {
151  std::cout << std::scientific << std::setprecision(precision_)
152  << solver.get_cost() << separator_; // cost
153  std::cout << solver.get_stop() << separator_; // stop
154  std::cout << abs(solver.get_d()[0]) << separator_; // grad
155  std::cout << solver.get_preg() << separator_; // preg
156  std::cout << std::fixed << std::setprecision(4) << solver.get_steplength()
157  << separator_short_; // step
158  std::cout << space_sign(solver.get_dVexp()) << separator_short_; // dVexp
159  std::cout << space_sign(solver.get_dV()); // dV
160  break;
161  }
162  case _1: {
163  std::cout << std::scientific << std::setprecision(precision_)
164  << solver.get_cost() << separator_short_; // cost
165  std::cout << space_sign(solver.get_merit()) << separator_; // merit
166  std::cout << solver.get_stop() << separator_; // stop
167  std::cout << abs(solver.get_d()[0]) << separator_; // grad
168  std::cout << solver.get_preg() << separator_; // preg
169  std::cout << std::fixed << std::setprecision(4) << solver.get_steplength()
170  << separator_; // step
171  std::cout << std::scientific << std::setprecision(precision_)
172  << solver.get_ffeas() << separator_short_; // ffeas
173  std::cout << space_sign(solver.get_dVexp()) << separator_short_; // dVexp
174  std::cout << space_sign(solver.get_dV()); // dV
175  break;
176  }
177  case _2: {
178  std::cout << std::scientific << std::setprecision(precision_)
179  << solver.get_cost() << separator_short_; // cost
180  std::cout << space_sign(solver.get_merit()) << separator_; // merit
181  std::cout << solver.get_stop() << separator_; // stop
182  std::cout << abs(solver.get_d()[0]) << separator_; // grad
183  std::cout << solver.get_preg() << separator_; // preg
184  std::cout << solver.get_dreg() << separator_; // dreg
185  std::cout << std::fixed << std::setprecision(4) << solver.get_steplength()
186  << separator_; // step
187  std::cout << std::scientific << std::setprecision(precision_)
188  << solver.get_ffeas() << separator_short_; // ffeas
189  std::cout << space_sign(solver.get_dVexp()) << separator_short_; // dVexp
190  std::cout << space_sign(solver.get_dV()); // dV
191  break;
192  }
193  case _3: {
194  std::cout << std::scientific << std::setprecision(precision_)
195  << solver.get_cost() << separator_short_; // cost
196  std::cout << space_sign(solver.get_merit()) << separator_; // merit
197  std::cout << solver.get_stop() << separator_; // stop
198  std::cout << abs(solver.get_d()[0]) << separator_; // grad
199  std::cout << solver.get_preg() << separator_; // preg
200  std::cout << solver.get_dreg() << separator_; // dreg
201  std::cout << std::fixed << std::setprecision(4) << solver.get_steplength()
202  << separator_; // step
203  std::cout << std::scientific << std::setprecision(precision_)
204  << solver.get_ffeas() << separator_; // ffeas
205  std::cout << solver.get_gfeas() << separator_; // gfeas
206  std::cout << solver.get_hfeas() << separator_short_; // hfeas
207  std::cout << space_sign(solver.get_dVexp()) << separator_short_; // dVexp
208  std::cout << space_sign(solver.get_dV()); // dV
209  break;
210  }
211  case _4: {
212  std::cout << std::scientific << std::setprecision(precision_)
213  << solver.get_cost() << separator_short_; // cost
214  std::cout << space_sign(solver.get_merit()) << separator_; // merit
215  std::cout << solver.get_stop() << separator_; // stop
216  std::cout << abs(solver.get_d()[0]) << separator_; // grad
217  std::cout << solver.get_preg() << separator_; // preg
218  std::cout << solver.get_dreg() << separator_; // dreg
219  std::cout << std::fixed << std::setprecision(4) << solver.get_steplength()
220  << separator_; // step
221  std::cout << std::scientific << std::setprecision(precision_)
222  << solver.get_ffeas() << separator_; // ffeas
223  std::cout << solver.get_gfeas() << separator_; // gfeas
224  std::cout << solver.get_hfeas() << separator_short_; // hfeas
225  std::cout << space_sign(solver.get_dVexp()) << separator_short_; // dVexp
226  std::cout << space_sign(solver.get_dV()) << separator_short_; // dV
227  std::cout << space_sign(solver.get_dPhiexp())
228  << separator_short_; // dPhiexp
229  std::cout << space_sign(solver.get_dPhi()); // dPhi
230  break;
231  }
232  default: {
233  }
234  }
235  std::cout << std::endl;
236  std::cout << std::flush;
237 }
238 
239 } // namespace crocoddyl
Abstract class for optimal control solvers.
Definition: solver-base.hpp:60
double get_cost() const
Return the cost for the current guess.
double get_dPhi() const
Return the reduction in the merit function .
std::size_t get_iter() const
Return the number of iterations performed by the solver.
double get_hfeas() const
Return the equality feasibility for the current guess.
double get_dVexp() const
Return the expected reduction in the cost function .
double get_dPhiexp() const
Return the expected reduction in the merit function .
double get_steplength() const
Return the step length .
double get_merit() const
Return the merit for the current guess.
double get_preg() const
Return the primal-variable regularization.
const Eigen::Vector2d & get_d() const
Return the linear and quadratic terms of the expected improvement.
double get_ffeas() const
Return the dynamic feasibility for the current guess.
double get_gfeas() const
Return the inequality feasibility for the current guess.
double get_stop() const
Return the stopping-criteria value computed by stoppingCriteria()
double get_dV() const
Return the reduction in the cost function .
double get_dreg() const
Return the dual-variable regularization.