2424#include " PetriNet/Algorithms.hpp"
2525#include " PetriNet/SparseMatrix.hpp"
2626#include " imgui/imgui.h"
27+ #include < iomanip>
28+ #include < set>
2729#include < sstream>
2830
2931namespace tpne {
3032
33+ namespace {
34+
35+ std::string formatTimeUnits (double const value)
36+ {
37+ std::ostringstream os;
38+ os << std::fixed << std::setprecision (2 ) << value;
39+ return os.str ();
40+ }
41+
42+ } // namespace
43+
3144// ------------------------------------------------------------------------------
3245void Editor::showStyleSelector ()
3346{
@@ -228,12 +241,13 @@ void Editor::showDynamicLinearSystem() const
228241}
229242
230243// ------------------------------------------------------------------------------
231- void Editor::showCriticalCycles ()
244+ void Editor::showCriticalCircuit ()
232245{
233- ImGui::OpenPopup (" Critical Cycle " );
246+ ImGui::OpenPopup (" Critical circuit analysis " );
234247 ImGui::SetNextWindowPos (m_states.viewport_center , ImGuiCond_Appearing,
235248 ImVec2 (0 .5f , 0 .5f ));
236- if (ImGui::BeginPopupModal (" Critical Cycle" , NULL , ImGuiWindowFlags_AlwaysAutoResize))
249+ if (ImGui::BeginPopupModal (" Critical circuit analysis" , NULL ,
250+ ImGuiWindowFlags_AlwaysAutoResize))
237251 {
238252 static CriticalCycleResult cached;
239253 static bool cached_valid = false ;
@@ -250,59 +264,109 @@ void Editor::showCriticalCycles()
250264 }
251265 else
252266 {
253- ImGui::Text (" Found %zu connected components of the optimal policy" , res.cycles );
267+ ImGui::TextWrapped (
268+ " Howard policy for this timed event graph. "
269+ " Highlighted arcs on the canvas form the critical circuit(s)." );
270+ ImGui::Spacing ();
271+ ImGui::Text (" Strongly connected components: %zu" , res.cycles );
272+
273+ std::set<double > const lambdas (res.durations .begin (), res.durations .end ());
274+ if (!lambdas.empty ())
275+ {
276+ if (lambdas.size () == 1u )
277+ {
278+ ImGui::Text (" Cycle time λ: %s time units." ,
279+ formatTimeUnits (*lambdas.begin ()).c_str ());
280+ }
281+ else
282+ {
283+ std::ostringstream os;
284+ auto it = lambdas.begin ();
285+ os << formatTimeUnits (*it++);
286+ for (; it != lambdas.end (); ++it)
287+ os << " , " << formatTimeUnits (*it);
288+ ImGui::Text (" Cycle times λ: %s time units." , os.str ().c_str ());
289+ }
290+ }
254291
255292 m_marked_arcs = res.arcs ;
256293 ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None;
257294 if (ImGui::BeginTabBar (" CriticalCycleResult" , tab_bar_flags))
258295 {
259- if (ImGui::BeginTabItem (" Critical cycle " ))
296+ if (ImGui::BeginTabItem (" Circuit arcs " ))
260297 {
261- std::stringstream txt;
262- if (net ().type () == TypeOfNet::TimedEventGraph)
298+ ImGuiTableFlags const flags =
299+ ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg |
300+ ImGuiTableFlags_SizingFixedFit;
301+ if (ImGui::BeginTable (" CriticalCircuitArcs" , 3 , flags))
263302 {
303+ ImGui::TableSetupColumn (" From" );
304+ ImGui::TableSetupColumn (" Place" );
305+ ImGui::TableSetupColumn (" To" );
306+ ImGui::TableHeadersRow ();
264307 for (size_t it = 0u ; it < res.arcs .size (); it += 2u )
265308 {
266- txt << res.arcs [it]->from .key << " -> "
267- << res.arcs [it + 1u ]->to .key
268- << std::endl;
309+ ImGui::TableNextRow ();
310+ ImGui::TableNextColumn ();
311+ ImGui::TextUnformatted (res.arcs [it]->from .key .c_str ());
312+ ImGui::TableNextColumn ();
313+ ImGui::TextUnformatted (res.arcs [it]->to .key .c_str ());
314+ ImGui::TableNextColumn ();
315+ ImGui::TextUnformatted (res.arcs [it + 1u ]->to .key .c_str ());
269316 }
317+ ImGui::EndTable ();
270318 }
271- else
272- {
273- for (size_t it = 0u ; it < res.arcs .size (); it += 2u )
274- {
275- txt << res.arcs [it]->from .key << " -> "
276- << res.arcs [it]->to .key << " -> "
277- << res.arcs [it + 1u ]->to .key
278- << std::endl;
279- }
280- }
281- ImGui::Text (" %s" , txt.str ().c_str ());
282319 ImGui::EndTabItem ();
283320 }
284- if (ImGui::BeginTabItem (" Cycle durations " ))
321+ if (ImGui::BeginTabItem (" Bias " ))
285322 {
286- const auto & tr = net ().transitions ();
287- std::stringstream txt;
288- for (size_t i = 0u ; i < res.durations .size (); ++i)
323+ auto const & transitions = net ().transitions ();
324+ ImGuiTableFlags const flags =
325+ ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg |
326+ ImGuiTableFlags_SizingFixedFit;
327+ if (ImGui::BeginTable (" CriticalCircuitBias" , 2 , flags))
289328 {
290- txt << " From " << tr[i].key << " : "
291- << res.durations [i]
292- << " units of time"
293- << std::endl;
329+ ImGui::TableSetupColumn (" Transition" );
330+ ImGui::TableSetupColumn (" Bias [time units]" );
331+ ImGui::TableHeadersRow ();
332+ size_t const n = std::min (transitions.size (),
333+ res.eigenvector .size ());
334+ for (size_t i = 0 ; i < n; ++i)
335+ {
336+ ImGui::TableNextRow ();
337+ ImGui::TableNextColumn ();
338+ ImGui::TextUnformatted (transitions[i].key .c_str ());
339+ ImGui::TableNextColumn ();
340+ ImGui::TextUnformatted (
341+ formatTimeUnits (res.eigenvector [i]).c_str ());
342+ }
343+ ImGui::EndTable ();
294344 }
295- ImGui::Text (" %s" , txt.str ().c_str ());
296345 ImGui::EndTabItem ();
297346 }
298- if (ImGui::BeginTabItem (" Eigenvector " ))
347+ if (ImGui::BeginTabItem (" Help " ))
299348 {
300- std::stringstream txt;
301- for (auto const & it : res.eigenvector )
302- {
303- txt << it << std::endl;
304- }
305- ImGui::Text (" %s" , txt.str ().c_str ());
349+ float const help_wrap = ImGui::GetCursorPos ().x + 420 .0f ;
350+ ImGui::PushTextWrapPos (help_wrap);
351+ ImGui::TextDisabled (" Cycle time λ" );
352+ ImGui::TextWrapped (
353+ " Max-plus eigenvalue of the timed event graph (same time "
354+ " units as arc durations). Average duration of one turn around "
355+ " a circuit in the optimal (Howard) policy—the bottleneck of "
356+ " the steady periodic regime." );
357+ ImGui::Spacing ();
358+ ImGui::TextDisabled (" Critical circuit" );
359+ ImGui::TextWrapped (
360+ " Arcs of the optimal policy that lie on a cycle and set λ. "
361+ " They are highlighted on the canvas (listed in the "
362+ " Circuit arcs tab)." );
363+ ImGui::Spacing ();
364+ ImGui::TextDisabled (" Bias" );
365+ ImGui::TextWrapped (
366+ " Initial time offset of each transition in the optimal "
367+ " policy, in the same time units. Transitions on the same "
368+ " circuit share the same λ but may have different biases." );
369+ ImGui::PopTextWrapPos ();
306370 ImGui::EndTabItem ();
307371 }
308372 ImGui::EndTabBar ();
@@ -313,7 +377,7 @@ void Editor::showCriticalCycles()
313377 if (ImGui::Button (" OK" , ImVec2 (120 , 0 )))
314378 {
315379 ImGui::CloseCurrentPopup ();
316- m_states.do_find_critical_cycle = false ;
380+ m_states.do_find_critical_circuit = false ;
317381 cached_valid = false ;
318382 }
319383 ImGui::EndPopup ();
0 commit comments