65 state().verbose = level;
78 st.model_name.clear();
79 st.t0 = clock_type::now();
83 st.force_detail =
false;
84 st.compiling_own =
false;
85 st.header_pending =
false;
89 st.detail_last.clear();
90 st.detail_shapes.clear();
91 st.detail_shape_count.clear();
104 static bool wanted(
bool verbose =
true) {
113 const State& st = state();
114 return st.active && st.depth <= 1 && st.muted == 0;
123 const State& st = state();
124 if (st.muted > 0)
return false;
125 if (st.depth > 0)
return owns_log();
139 static bool begin_run(
const std::string& tag,
const std::string& model_name,
140 bool verbose =
true) {
142 if (st.depth == 0 && !
wanted(verbose)) {
149 if (st.depth > 1)
return false;
152 st.model_name = model_name;
153 st.t0 = clock_type::now();
155 st.last_loop.clear();
158 st.detail_last.clear();
159 st.detail_shapes.clear();
160 st.detail_shape_count.clear();
165 if (model_name.empty()) {
166 st.header_pending =
true;
176 if (st.active && st.depth == 1) st.tsetup = elapsed(st.t0);
183 if (st.muted > 0) st.muted--;
187 if (st.depth > 0 || !st.active)
return;
188 if (st.header_pending) {
189 st.header_pending =
false;
192 const double total = elapsed(st.t0);
193 if (st.tsetup < 0.0) {
194 step(
"DONE in %.4f s", total);
196 step(
"DONE in %.4f s (setup %.4f s, analysis %.4f s)", total, st.tsetup,
197 std::max(0.0, total - st.tsetup));
200 const int outer_mute = st.muted;
202 state().muted = outer_mute;
208 Run(
const std::string& tag,
const std::string& model_name,
bool verbose =
true) {
220 ~Quiet() { state().quiet = std::max(0, state().quiet - 1); }
228 static void step(
const char* fmt, ...) {
232 const std::string text = vformat(fmt, args);
242 const std::string text = vformat(fmt, args);
253 const State& st = state();
254 if (st.quiet > 0)
return;
255 if (st.depth > 0 && !st.force_detail && !st.compiling_own)
return;
259 const std::string text = vformat(fmt, args);
273 if (st.depth > 0 && st.model_name.empty()) {
274 st.model_name = name;
275 if (st.header_pending) {
276 st.header_pending =
false;
280 if (st.depth > 0 && name != st.model_name) {
283 st.compiling_own =
false;
284 detail(
"refreshing the auxiliary submodel '" + name +
"'");
286 st.compiling_own =
true;
288 st.clock = clock_type::now();
289 st.clock_started =
true;
291 step(
"compiling the network structure of model '%s'", name.c_str());
300 static void detail(
const std::string& raw) {
302 const std::string text =
trim(raw);
304 if (text.empty() || text == st.detail_last)
return;
305 const std::string shape = mask_numbers(text);
306 for (std::size_t i = 0; i < st.detail_shapes.size(); ++i) {
307 if (st.detail_shapes[i] == shape) {
308 if (++st.detail_shape_count[i] > kMaxPerShape)
return;
309 st.detail_last = text;
314 st.detail_shapes.push_back(shape);
315 st.detail_shape_count.push_back(1);
316 st.detail_last = text;
325 static void loop(
const char* fmt, ...) {
329 const std::string text = vformat(fmt, args);
332 if (text == st.last_loop)
return;
344 static void iter(
long k,
const char* fmt, ...) {
346 if (k > 20 && (k % 10) != 0)
return;
348 if (st.shown >= kMaxIterLines) {
351 emit(
" ",
"further iterations of this loop not reported");
357 const std::string text = vformat(fmt, args);
364 static std::string
plural(
long n,
const std::string& singular,
365 const std::string& plural_form) {
367 std::snprintf(buf,
sizeof(buf),
"%ld ", n);
368 return std::string(buf) + (n == 1 ? singular : plural_form);
381 typedef std::chrono::steady_clock clock_type;
383 static const int kMaxIterLines = 30;
384 static const int kMaxDetailLines = 200;
385 static const int kMaxPerShape = 3;
392 std::string model_name;
393 clock_type::time_point t0 = clock_type::now();
394 double tsetup = -1.0;
397 bool force_detail =
false;
398 bool compiling_own =
false;
399 bool header_pending =
false;
400 std::string last_loop;
403 std::string detail_last;
404 std::vector<std::string> detail_shapes;
405 std::vector<int> detail_shape_count;
406 int detail_total = 0;
407 clock_type::time_point clock = clock_type::now();
408 bool clock_started =
false;
411 static State& state() {
416 static void emit_header(
bool restart_clock =
true) {
419 st.clock = clock_type::now();
420 st.clock_started =
true;
425 step(
"LINE: Solver%s starting on model '%s' (lang cpp)", st.tag.c_str(),
426 st.model_name.empty() ?
"(unnamed)" : st.model_name.c_str());
429 static double elapsed(
const clock_type::time_point& from) {
430 return std::chrono::duration<double>(clock_type::now() - from).count();
433 static void emit(
const char* indent,
const std::string& text) {
435 if (!st.clock_started) {
436 st.clock = clock_type::now();
437 st.clock_started =
true;
440 std::string row = text;
441 if (indent[0] ==
'\0' && !row.empty()) {
442 row[0] =
static_cast<char>(std::toupper(
static_cast<unsigned char>(row[0])));
444 std::printf(
"[%8.3fs] %s%s\n", elapsed(st.clock), indent, row.c_str());
448 static void bump_and_emit(
const std::string& text) {
450 if (++st.detail_total > kMaxDetailLines) {
451 if (st.detail_total == kMaxDetailLines + 1)
452 emit(
" ",
"further solver detail not reported");
455 emit(
" ", lower_first(text));
458 static std::string vformat(
const char* fmt, va_list args) {
461 const int n = std::vsnprintf(
nullptr, 0, fmt, copy);
463 if (n <= 0)
return std::string(fmt);
464 std::vector<char> buf(
static_cast<std::size_t
>(n) + 1);
465 std::vsnprintf(buf.data(), buf.size(), fmt, args);
466 return std::string(buf.data(),
static_cast<std::size_t
>(n));
469 static std::string trim(
const std::string& s) {
470 std::size_t b = s.find_first_not_of(
" \t\r\n");
471 if (b == std::string::npos)
return std::string();
472 std::size_t e = s.find_last_not_of(
" \t\r\n");
473 return s.substr(b, e - b + 1);
477 static std::string mask_numbers(
const std::string& s) {
479 out.reserve(s.size());
480 bool in_number =
false;
481 for (std::size_t i = 0; i < s.size(); ++i) {
483 const bool digit = (c >=
'0' && c <=
'9');
484 const bool part = digit || (in_number && (c ==
'.' || c ==
'e' || c ==
'E' ||
485 ((c ==
'+' || c ==
'-') && i > 0 &&
486 (s[i - 1] ==
'e' || s[i - 1] ==
'E'))));
500 static std::string lower_first(
const std::string& s) {
502 const bool acronym = (s[0] >=
'A' && s[0] <=
'Z') && (s[1] >=
'A' && s[1] <=
'Z');
503 if (!acronym && s[0] >=
'A' && s[0] <=
'Z') {
505 out[0] =
static_cast<char>(s[0] -
'A' +
'a');
OwnModelCompile(const OwnModelCompile &)=delete
OwnModelCompile & operator=(const OwnModelCompile &)=delete
Quiet(const Quiet &)=delete
Quiet & operator=(const Quiet &)=delete
Run & operator=(const Run &)=delete
Run(const std::string &tag, const std::string &model_name, bool verbose=true)
static void reset()
Forget any open run (used after an interrupted solve).
static void set_verbose(VerboseLevel level)
Set the session verbosity.
static std::string plural(long n, const std::string &singular, const std::string &plural_form)
Count with an agreeing noun, e.g.
static void loop(const char *fmt,...)
Announce an iteration loop and reset its reporting budget.
static void substep(const char *fmt,...)
Write one indented progress line.
static VerboseLevel get_verbose()
The session verbosity.
static bool is_active()
True while a run is narrating; gates SUPPRESSION of legacy prints.
static bool wanted(bool verbose=true)
Resolve whether a run should narrate.
static void compiling(const std::string &name)
Announce the compilation of a model structure.
static void end_run()
Close the innermost open run, writing the closing line.
static void iter(long k, const char *fmt,...)
Report iteration k of the current loop.
static bool owns_log()
True only inside the OUTERMOST open run; gates EMISSION.
static void step(const char *fmt,...)
Write one progress line.
static bool writes()
True when a progress line should be printed: either the outermost run is narrating,...
static void setup_done()
Mark the end of the setup phase, so the closing line can split the time.
static bool begin_run(const std::string &tag, const std::string &model_name, bool verbose=true)
Open a console run.
static void compile_detail(const char *fmt,...)
One stage line of a structure compile: silenced inside a Quiet scope, and inside an open run,...
std::string trim(const std::string &s)
Trims ASCII whitespace from both ends, as Java's String.trim() does.
VerboseLevel
Session verbosity, the twin of MATLAB's VerboseLevel, jline.VerboseLevel and python's line_solver....