Skip to content

Commit 3cba8b7

Browse files
authored
Merge pull request #757 from SciML/myb/conservative_alias
Add a conservative option in alias elimination
2 parents 5ed420e + d67fe45 commit 3cba8b7

File tree

2 files changed

+47
-24
lines changed

2 files changed

+47
-24
lines changed

src/systems/reduction.jl

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ end
3232

3333
# Note that we reduce parameters, too
3434
# i.e. `2param = 3` will be reduced away
35-
isvar(s::Sym) = true
36-
isvar(s::Term) = isvar(operation(s))
37-
isvar(s::Any) = false
35+
isvar(s) = s isa Sym ? true :
36+
istree(s) ? isvar(operation(s)) :
37+
false
3838

3939
function get_α_x(αx)
4040
if isvar(αx)
@@ -55,7 +55,37 @@ function get_α_x(αx)
5555
end
5656
end
5757

58-
function alias_elimination(sys::ODESystem)
58+
function is_univariate_expr(ex, iv)
59+
count = 0
60+
for var in vars(ex)
61+
if !isequal(iv, var) && !isparameter(var)
62+
count += 1
63+
count > 1 && return false
64+
end
65+
end
66+
return count <= 1
67+
end
68+
69+
function is_sub_candidate(ex, iv, conservative)
70+
conservative || return true
71+
isvar(ex) || ex isa Number || is_univariate_expr(ex, iv)
72+
end
73+
74+
function maybe_alias(lhs, rhs, diff_vars, iv, conservative)
75+
is_sub_candidate(rhs, iv, conservative) || return false, nothing
76+
77+
res_left = get_α_x(lhs)
78+
if res_left !== nothing && !(res_left[2] in diff_vars)
79+
α, x = res_left
80+
sub = x => _isone(α) ? rhs : rhs / α
81+
return true, sub
82+
else
83+
return false, nothing
84+
end
85+
end
86+
87+
function alias_elimination(sys::ODESystem; conservative=true)
88+
iv = independent_variable(sys)
5989
eqs = vcat(equations(sys), observed(sys))
6090
diff_vars = filter(!isnothing, map(eqs) do eq
6191
if isdiffeq(eq)
@@ -76,24 +106,15 @@ function alias_elimination(sys::ODESystem)
76106
continue
77107
end
78108

79-
maybe_alias = isalias = false
80-
res_left = get_α_x(eq.lhs)
81-
if !isnothing(res_left) && !(res_left[2] in diff_vars)
82-
# `α x = rhs` => `x = rhs / α`
83-
α, x = res_left
84-
sub = x => _isone(α) ? eq.rhs : eq.rhs / α
85-
maybe_alias = true
86-
else
87-
res_right = get_α_x(eq.rhs)
88-
if !isnothing(res_right) && !(res_right[2] in diff_vars)
89-
# `lhs = β y` => `y = lhs / β`
90-
β, y = res_right
91-
sub = y => _isone(β) ? eq.lhs : β * eq.lhs
92-
maybe_alias = true
93-
end
109+
# `α x = rhs` => `x = rhs / α`
110+
ma, sub = maybe_alias(eq.lhs, eq.rhs, diff_vars, iv, conservative)
111+
if !ma
112+
# `lhs = β y` => `y = lhs / β`
113+
ma, sub = maybe_alias(eq.rhs, eq.lhs, diff_vars, iv, conservative)
94114
end
95115

96-
if maybe_alias
116+
isalias = false
117+
if ma
97118
l, r = sub
98119
# alias equations shouldn't introduce cycles
99120
if !(l in deps) && isempty(intersect(deps, vars(r)))

test/reduction.jl

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ eqs = [
3434
D(y) ~ x*-z)-y + β
3535
0 ~ sin(z) - x + y
3636
sin(u) ~ x + y
37-
x ~ a
37+
2x ~ 3a
38+
2u ~ 3x
3839
]
3940

4041
lorenz1 = ODESystem(eqs,t,name=:lorenz1)
@@ -49,8 +50,9 @@ reduced_eqs = [
4950
test_equal.(equations(lorenz1_aliased), reduced_eqs)
5051
@test isempty(setdiff(states(lorenz1_aliased), [u, x, y, z]))
5152
test_equal.(observed(lorenz1_aliased), [
52-
a ~ x,
53-
])
53+
a ~ 2/3 * x,
54+
u ~ 3/2 * x,
55+
])
5456

5557
# Multi-System Reduction
5658

@@ -75,7 +77,7 @@ connected = ODESystem([s ~ a + lorenz1.x
7577

7678
flattened_system = ModelingToolkit.flatten(connected)
7779

78-
aliased_flattened_system = alias_elimination(flattened_system)
80+
aliased_flattened_system = alias_elimination(flattened_system; conservative=false)
7981

8082
@test setdiff(states(aliased_flattened_system), [
8183
a

0 commit comments

Comments
 (0)