Skip to content

Commit a0fc653

Browse files
feat: add allow_algebraic, default allow_symbolic to false
1 parent cc8fa2b commit a0fc653

File tree

5 files changed

+63
-24
lines changed

5 files changed

+63
-24
lines changed

src/structural_transformation/partial_state_selection.jl

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -170,11 +170,13 @@ function partial_state_selection_graph!(structure::SystemStructure, var_eq_match
170170
end
171171

172172
function dummy_derivative_graph!(state::TransformationState, jac = nothing;
173-
state_priority = nothing, log = Val(false), kwargs...)
174-
state.structure.solvable_graph === nothing && find_solvables!(state; kwargs...)
173+
state_priority = nothing, log = Val(false), allow_symbolic = false, kwargs...)
174+
state.structure.solvable_graph === nothing &&
175+
find_solvables!(state; allow_symbolic, kwargs...)
175176
complete!(state.structure)
176-
var_eq_matching = complete(pantelides!(state; kwargs...))
177-
dummy_derivative_graph!(state.structure, var_eq_matching, jac, state_priority, log)
177+
var_eq_matching = complete(pantelides!(state; allow_symbolic, kwargs...))
178+
dummy_derivative_graph!(
179+
state.structure, var_eq_matching, jac, state_priority, log; allow_symbolic)
178180
end
179181

180182
struct DummyDerivativeSummary
@@ -184,7 +186,7 @@ end
184186

185187
function dummy_derivative_graph!(
186188
structure::SystemStructure, var_eq_matching, jac = nothing,
187-
state_priority = nothing, ::Val{log} = Val(false)) where {log}
189+
state_priority = nothing, ::Val{log} = Val(false); allow_symbolic = false) where {log}
188190
@unpack eq_to_diff, var_to_diff, graph = structure
189191
diff_to_eq = invview(eq_to_diff)
190192
diff_to_var = invview(var_to_diff)
@@ -342,7 +344,12 @@ function dummy_derivative_graph!(
342344
@warn "The number of dummy derivatives ($n_dummys) does not match the number of differentiated equations ($n_diff_eqs)."
343345
end
344346

345-
ret = tearing_with_dummy_derivatives(structure, BitSet(dummy_derivatives))
347+
dummy_derivatives_set = BitSet(dummy_derivatives)
348+
if !allow_symbolic
349+
make_differential_denominators_unsolvable!(structure, dummy_derivatives_set)
350+
end
351+
352+
ret = tearing_with_dummy_derivatives(structure, dummy_derivatives_set)
346353
if log
347354
(ret..., DummyDerivativeSummary(var_dummy_scc, var_state_priority))
348355
else

src/structural_transformation/symbolics_tearing.jl

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -992,8 +992,12 @@ end
992992
ndims = ndims(arr)
993993
end
994994

995-
function tearing(state::TearingState; kwargs...)
996-
state.structure.solvable_graph === nothing && find_solvables!(state; kwargs...)
995+
function tearing(state::TearingState; allow_symbolic = false, kwargs...)
996+
state.structure.solvable_graph === nothing &&
997+
find_solvables!(state; allow_symbolic, kwargs...)
998+
if !allow_symbolic
999+
make_differential_denominators_unsolvable!(state.structure)
1000+
end
9971001
complete!(state.structure)
9981002
tearing_with_dummy_derivatives(state.structure, ())
9991003
end

src/structural_transformation/utils.jl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,22 @@ function find_eq_solvables!(state::TearingState, ieq::Int, to_rm = Int[], coeffs
275275
all_int_vars, term
276276
end
277277

278+
"""
279+
$(TYPEDSIGNATURES)
280+
281+
Remove edges in `structure.solvable_graph` that require differential variables in the
282+
denominator to solve. `additional_algevars` is a collection of integers corresponding to
283+
differential variables that should be considered as algebraic for the purpose of this
284+
transformation.
285+
"""
286+
function make_differential_denominators_unsolvable!(
287+
structure::SystemStructure, additional_algevars = ())
288+
for ((eqi, vari), denoms) in structure.denominators
289+
all(i -> isalgvar(structure, i) || i in additional_algevars, denoms) && continue
290+
rem_edge!(structure.solvable_graph, eqi, vari)
291+
end
292+
end
293+
278294
function find_solvables!(state::TearingState; kwargs...)
279295
@assert state.structure.solvable_graph === nothing
280296
eqs = equations(state)

src/systems/systems.jl

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,30 @@ Structurally simplify algebraic equations in a system and compute the
1818
topological sort of the observed equations in `sys`.
1919
2020
### Optional Arguments:
21-
+ optional argument `io` may take a tuple `(inputs, outputs)`. This will convert all `inputs` to parameters and allow them to be unconnected, i.e., simplification will allow models where `n_unknowns = n_equations - n_inputs`.
21+
+ optional argument `io` may take a tuple `(inputs, outputs)`. This will convert all
22+
`inputs` to parameters and allow them to be unconnected, i.e., simplification will
23+
allow models where `n_unknowns = n_equations - n_inputs`.
2224
2325
### Optional Keyword Arguments:
24-
+ When `simplify=true`, the `simplify` function will be applied during the tearing process.
25-
+ `allow_symbolic=true`, `allow_parameter=true`, and `conservative=false` limit the coefficient types during tearing. In particular, `conservative=true` limits tearing to only solve for trivial linear systems where the coefficient has the absolute value of ``1``.
26-
+ `fully_determined=true` controls whether or not an error will be thrown if the number of equations don't match the number of inputs, outputs, and equations.
26+
+ When `simplify=true`, the `simplify` function will be applied during the tearing
27+
process.
28+
+ `allow_symbolic=false`, `allow_algebraic=true`, `allow_parameter=true`, and
29+
`conservative=false` limit the coefficient types during tearing. In particular,
30+
`conservative=true` limits tearing to only solve for trivial linear systems where
31+
the coefficient has the absolute value of ``1``. `allow_symbolic` allows arbitrary
32+
symbolic coefficients. If it is false, `allow_algebraic` allows symbolic coefficients
33+
involving only algebraic variables and parameters. Otherwise, `allow_parameter` only
34+
allows coefficients containing parameters.
35+
+ `fully_determined=true` controls whether or not an error will be thrown if the number
36+
of equations don't match the number of inputs, outputs, and equations.
2737
"""
2838
function structural_simplify(
2939
sys::AbstractSystem, io = nothing; additional_passes = [], simplify = false, split = true,
30-
allow_symbolic = true, allow_parameter = true, conservative = false, fully_determined = true,
31-
kwargs...)
40+
allow_symbolic = false, allow_algebraic = true, allow_parameter = true, conservative = false,
41+
fully_determined = true, kwargs...)
3242
isscheduled(sys) && throw(RepeatedStructuralSimplificationError())
33-
newsys′ = __structural_simplify(sys, io; simplify,
34-
allow_symbolic, allow_parameter, conservative, fully_determined,
35-
kwargs...)
43+
newsys′ = __structural_simplify(sys, io; simplify, allow_symbolic, allow_algebraic,
44+
allow_parameter, conservative, fully_determined, kwargs...)
3645
if newsys′ isa Tuple
3746
@assert length(newsys′) == 2
3847
newsys = newsys′[1]

src/systems/systemstructure.jl

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -693,7 +693,7 @@ end
693693

694694
function _structural_simplify!(state::TearingState, io; simplify = false,
695695
check_consistency = true, fully_determined = true, warn_initialize_determined = false,
696-
dummy_derivative = true,
696+
dummy_derivative = true, allow_symbolic = false,
697697
kwargs...)
698698
if fully_determined isa Bool
699699
check_consistency &= fully_determined
@@ -710,24 +710,27 @@ function _structural_simplify!(state::TearingState, io; simplify = false,
710710
else
711711
input_idxs = 0:-1 # Empty range
712712
end
713-
sys, mm = ModelingToolkit.alias_elimination!(state; kwargs...)
713+
sys, mm = ModelingToolkit.alias_elimination!(state; allow_symbolic, kwargs...)
714714
if check_consistency
715715
fully_determined = ModelingToolkit.check_consistency(
716716
state, orig_inputs; nothrow = fully_determined === nothing)
717717
end
718718
if fully_determined && dummy_derivative
719719
sys = ModelingToolkit.dummy_derivative(
720-
sys, state; simplify, mm, check_consistency, kwargs...)
720+
sys, state; simplify, mm, check_consistency, allow_symbolic, kwargs...)
721721
elseif fully_determined
722-
var_eq_matching = pantelides!(state; finalize = false, kwargs...)
722+
var_eq_matching = pantelides!(state; finalize = false, allow_symbolic, kwargs...)
723+
if !allow_symbolic
724+
StructuralTransformations.make_differential_denominators_unsolvable!(state.structure)
725+
end
723726
sys = pantelides_reassemble(state, var_eq_matching)
724727
state = TearingState(sys)
725-
sys, mm = ModelingToolkit.alias_elimination!(state; kwargs...)
728+
sys, mm = ModelingToolkit.alias_elimination!(state; allow_symbolic, kwargs...)
726729
sys = ModelingToolkit.dummy_derivative(
727-
sys, state; simplify, mm, check_consistency, kwargs...)
730+
sys, state; simplify, mm, check_consistency, allow_symbolic, kwargs...)
728731
else
729732
sys = ModelingToolkit.tearing(
730-
sys, state; simplify, mm, check_consistency, kwargs...)
733+
sys, state; simplify, mm, check_consistency, allow_symbolic, kwargs...)
731734
end
732735
fullunknowns = [map(eq -> eq.lhs, observed(sys)); unknowns(sys)]
733736
@set! sys.observed = ModelingToolkit.topsort_equations(observed(sys), fullunknowns)

0 commit comments

Comments
 (0)