@@ -2,21 +2,108 @@ function partial_state_selection_graph!(sys::ODESystem)
2
2
s = get_structure (sys)
3
3
(s isa SystemStructure) || (sys = initialize_system_structure (sys))
4
4
s = structure (sys)
5
- find_solvables! (sys)
5
+ find_solvables! (sys; allow_symbolic = true )
6
6
@set! s. graph = complete (s. graph)
7
7
@set! sys. structure = s
8
- (sys, partial_state_selection_graph! (s. graph, s. solvable_graph, s. var_to_diff)... )
8
+ var_eq_matching, eq_to_diff = pantelides! (PantelidesSetup (sys, s. graph, s. var_to_diff))
9
+ (sys, partial_state_selection_graph! (s. graph, s. solvable_graph, s. var_to_diff, var_eq_matching, eq_to_diff)... )
10
+ end
11
+
12
+ function ascend_dg (xs, dg, level)
13
+ while level > 0
14
+ xs = Int[dg[x] for x in xs]
15
+ level -= 1
16
+ end
17
+ return xs
18
+ end
19
+
20
+ function ascend_dg_all (xs, dg, level, maxlevel)
21
+ r = Int[]
22
+ while true
23
+ if level <= 0
24
+ append! (r, xs)
25
+ end
26
+ maxlevel <= 0 && break
27
+ xs = Int[dg[x] for x in xs if dg[x] != = nothing ]
28
+ level -= 1
29
+ maxlevel -= 1
30
+ end
31
+ return r
32
+ end
33
+
34
+ function pss_graph_modia! (graph, solvable_graph, var_eq_matching, var_to_diff, eq_to_diff, varlevel, inv_varlevel, inv_eqlevel)
35
+ # var_eq_matching is a maximal matching on the top-differentiated variables.
36
+ # Find Strongly connected components. Note that after pantelides, we expect
37
+ # a balanced system, so a maximal matching should be possible.
38
+ var_sccs:: Vector{Union{Vector{Int}, Int}} = find_var_sccs (graph, var_eq_matching)
39
+ var_eq_matching = Matching {Union{Unassigned, SelectedState}} (var_eq_matching)
40
+ for vars in var_sccs
41
+ # TODO : We should have a way to not have the scc code look at unassigned vars.
42
+ if length (vars) == 1 && varlevel[vars[1 ]] != 0
43
+ continue
44
+ end
45
+
46
+ # Now proceed level by level from lowest to highest and tear the graph.
47
+ eqs = [var_eq_matching[var] for var in vars]
48
+ maxlevel = level = maximum (map (x-> inv_eqlevel[x], eqs))
49
+ old_level_vars = ()
50
+ ict = IncrementalCycleTracker (DiCMOBiGraph {true} (graph, complete (Matching (ndsts (graph)))); dir= :in )
51
+ while level >= 0
52
+ to_tear_eqs_toplevel = filter (eq-> inv_eqlevel[eq] >= level, eqs)
53
+ to_tear_eqs = ascend_dg (to_tear_eqs_toplevel, invview (eq_to_diff), level)
54
+
55
+ to_tear_vars_toplevel = filter (var-> inv_varlevel[var] >= level, vars)
56
+ to_tear_vars = ascend_dg_all (to_tear_vars_toplevel, invview (var_to_diff), level, maxlevel)
57
+
58
+ if old_level_vars != = ()
59
+ # Inherit constraints from previous level.
60
+ # TODO : Is this actually a good idea or do we want full freedom
61
+ # to tear differently on each level? Does it make a difference
62
+ # whether we're using heuristic or optimal tearing?
63
+ removed_eqs = Int[]
64
+ removed_vars = Int[]
65
+ for var in old_level_vars
66
+ old_assign = ict. graph. matching[var]
67
+ if ! isa (old_assign, Int) || ict. graph. matching[var_to_diff[var]] != = unassigned
68
+ continue
69
+ end
70
+ # Make sure the ict knows about this edge, so it doesn't accidentally introduce
71
+ # a cycle.
72
+ ok = try_assign_eq! (ict, var_to_diff[var], eq_to_diff[old_assign])
73
+ @assert ok
74
+ var_eq_matching[var_to_diff[var]] = eq_to_diff[old_assign]
75
+ push! (removed_eqs, eq_to_diff[ict. graph. matching[var]])
76
+ push! (removed_vars, var_to_diff[var])
77
+ end
78
+ to_tear_eqs = setdiff (to_tear_eqs, removed_eqs)
79
+ to_tear_vars = setdiff (to_tear_vars, removed_vars)
80
+ end
81
+ filter! (var-> ict. graph. matching[var] === unassigned, to_tear_vars)
82
+ filter! (eq-> invview (ict. graph. matching)[eq] === unassigned, to_tear_eqs)
83
+ tearEquations! (ict, solvable_graph. fadjlist, to_tear_eqs, to_tear_vars)
84
+ for var in to_tear_vars
85
+ var_eq_matching[var] = ict. graph. matching[var]
86
+ end
87
+ old_level_vars = to_tear_vars
88
+ level -= 1
89
+ end
90
+ for var in old_level_vars
91
+ if varlevel[var] != = 0 && var_eq_matching[var] === unassigned
92
+ var_eq_matching[var] = SelectedState ()
93
+ end
94
+ end
95
+ end
96
+ return var_eq_matching
9
97
end
10
98
11
99
struct SelectedState; end
12
- function partial_state_selection_graph! (graph, solvable_graph, var_to_diff)
13
- var_eq_matching, eq_to_diff = pantelides! (graph, solvable_graph, var_to_diff)
100
+ function partial_state_selection_graph! (graph, solvable_graph, var_to_diff, var_eq_matching, eq_to_diff)
14
101
eq_to_diff = complete (eq_to_diff)
15
102
16
- eqlevel = map (1 : nsrcs (graph)) do eq
103
+ inv_eqlevel = map (1 : nsrcs (graph)) do eq
17
104
level = 0
18
- while eq_to_diff[eq] != = nothing
19
- eq = eq_to_diff[eq]
105
+ while invview ( eq_to_diff) [eq] != = nothing
106
+ eq = invview ( eq_to_diff) [eq]
20
107
level += 1
21
108
end
22
109
level
@@ -31,45 +118,25 @@ function partial_state_selection_graph!(graph, solvable_graph, var_to_diff)
31
118
level
32
119
end
33
120
34
- all_selected_states = Int[]
35
-
36
- level = 0
37
- level_vars = [var for var in 1 : ndsts (graph) if varlevel[var] == 0 && invview (var_to_diff)[var] != = nothing ]
121
+ inv_varlevel = map (1 : ndsts (graph)) do var
122
+ level = 0
123
+ while invview (var_to_diff)[var] != = nothing
124
+ var = invview (var_to_diff)[var]
125
+ level += 1
126
+ end
127
+ level
128
+ end
38
129
39
- # TODO : Is this actually useful or should we just compute another maximal matching ?
130
+ # TODO : Should pantelides just return this ?
40
131
for var in 1 : ndsts (graph)
41
- if ! ( var in level_vars)
132
+ if var_to_diff[ var] != = nothing
42
133
var_eq_matching[var] = unassigned
43
134
end
44
135
end
45
136
46
- while level < maximum (eqlevel)
47
- var_eq_matching = tear_graph_modia (graph, solvable_graph;
48
- eqfilter = eq-> eqlevel[eq] == level && invview (eq_to_diff)[eq] != = nothing ,
49
- varfilter = var-> (var in level_vars && ! (var in all_selected_states)))
50
- for var in level_vars
51
- if var_eq_matching[var] === unassigned
52
- selected_state = invview (var_to_diff)[var]
53
- push! (all_selected_states, selected_state)
54
- #=
55
- # TODO : This is what the Matteson paper says, but it doesn't
56
- # quite seem to work.
57
- while selected_state !== nothing
58
- push!(all_selected_states, selected_state)
59
- selected_state = invview(var_to_diff)[selected_state]
60
- end
61
- =#
62
- end
63
- end
64
- level += 1
65
- level_vars = [var for var = 1 : ndsts (graph) if varlevel[var] == level && invview (var_to_diff)[var] != = nothing ]
66
- end
137
+ var_eq_matching = pss_graph_modia! (graph, solvable_graph,
138
+ complete (var_eq_matching), var_to_diff, eq_to_diff, varlevel, inv_varlevel,
139
+ inv_eqlevel)
67
140
68
- var_eq_matching = tear_graph_modia (graph, solvable_graph;
69
- varfilter = var-> ! (var in all_selected_states))
70
- var_eq_matching = Matching {Union{Unassigned, SelectedState}} (var_eq_matching)
71
- for var in all_selected_states
72
- var_eq_matching[var] = SelectedState ()
73
- end
74
- return var_eq_matching, eq_to_diff
141
+ var_eq_matching, eq_to_diff
75
142
end
0 commit comments