@@ -983,6 +983,12 @@ function observed2graph(sys::AbstractSystem, eqs::Vector{Equation}, unknowns::Ve
983983 return graph, assigns
984984end
985985
986+ """
987+ Toggle to control whether `topsort_equations` prints the equations in the
988+ cycle, if present.
989+ """
990+ TOPSORT_EQS_PRINT_CYCLE:: Bool = false
991+
986992"""
987993 $(TYPEDSIGNATURES)
988994
@@ -1054,7 +1060,37 @@ function topsort_equations(sys::AbstractSystem, eqs::Vector{Equation}, unknowns:
10541060 end
10551061 end
10561062
1057- (check && idx != neqs) && throw (ArgumentError (" The equations have at least one cycle." ))
1063+ if check && idx != neqs
1064+ # Build a directed eq→eq subgraph over unsorted equations, find smallest SCC.
1065+ if TOPSORT_EQS_PRINT_CYCLE
1066+ unsorted = findall (> (0 ), degrees)
1067+ unsorted_set = Set (unsorted)
1068+ n_unsorted = length (unsorted)
1069+ old_to_new = Dict (old => new for (new, old) in enumerate (unsorted))
1070+
1071+ g = SimpleDiGraph (n_unsorted)
1072+ for src_old in unsorted
1073+ for dst_old in 𝑑neighbors (graph, assigns[src_old])
1074+ dst_old in unsorted_set || continue
1075+ add_edge! (g, old_to_new[src_old], old_to_new[dst_old])
1076+ end
1077+ end
1078+
1079+ sccs = strongly_connected_components (g)
1080+ nontrivial = filter (scc -> length (scc) >= 2 , sccs)
1081+ smallest_new = isempty (nontrivial) ? collect (1 : n_unsorted) :
1082+ nontrivial[argmin (length .(nontrivial))]
1083+
1084+ println (" === topsort_equations: CYCLE DETECTED ===" )
1085+ println (" Smallest cycle ($(length (smallest_new)) equations):" )
1086+ for new_idx in smallest_new
1087+ old_idx = unsorted[new_idx]
1088+ println (" LHS = $(unknowns[assigns[old_idx]]) " )
1089+ println (" EQ = $(eqs[old_idx]) " )
1090+ end
1091+ end
1092+ throw (ArgumentError (" The equations have at least one cycle." ))
1093+ end
10581094
10591095 return ordered_eqs
10601096end
0 commit comments