Skip to content

Commit 0097578

Browse files
Merge pull request #79 from JuliaDiffEq/hg/fix/constant
Refactor Constant representation
2 parents bc7e230 + 9bff84f commit 0097578

12 files changed

+87
-120
lines changed

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -147,16 +147,12 @@ In this section we define the core pieces of the IR and what they mean.
147147

148148
### Variables
149149

150-
The simplest piece of the IR is the `Variable`. The `Variable` is the
150+
The most fundamental part of the IR is the `Variable`. The `Variable` is the
151151
context-aware single variable of the IR. Its fields are described as follows:
152152

153153
- `name`: the name of the `Variable`. Note that this is not necessarily
154154
the same as the name of the Julia variable. But this symbol itself is considered
155155
the core identifier of the `Variable` in the sense of equality.
156-
- `value`: the value of the `Variable`. The meaning of the value can be
157-
interpreted differently for different systems, but in most cases it's tied to
158-
whatever value information would be required for the system to be well-defined
159-
such as the initial condition of a differential equation.
160156
- `value_type`: the type that the values have to be. It's disconnected
161157
from the `value` because in many cases the `value` may not be able to be
162158
specified in advance even when we may already know the type. This can be used
@@ -179,6 +175,10 @@ context-aware single variable of the IR. Its fields are described as follows:
179175
- `context`: this is an open field for DSLs to carry along more context
180176
in the variables, but is not used in the systems themselves.
181177

178+
### Constants
179+
180+
`Constant` is a simple wrapper type to store numerical Julia constants.
181+
182182
### Operations
183183

184184
Operations are the basic composition of variables and puts together the pieces

src/ModelingToolkit.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ include("domains.jl")
1616
include("variables.jl")
1717

1818
Base.promote_rule(::Type{T},::Type{T2}) where {T<:Number,T2<:Expression} = Expression
19-
Base.one(::Type{T}) where T<:Expression = Constant(1)
20-
Base.zero(::Type{T}) where T<:Expression = Constant(0)
19+
Base.zero(::Type{<:Expression}) = Constant(0)
20+
Base.one(::Type{<:Expression}) = Constant(1)
2121
Base.convert(::Type{Variable},x::Int64) = Constant(x)
2222

2323
function caclulate_jacobian end

src/differentials.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ function (D::Differential)(x::Variable)
1616
end
1717
Base.:(==)(D1::Differential, D2::Differential) = D1.order == D2.order && D1.x == D2.x
1818

19-
Variable(x::Variable, D::Differential) = Variable(x.name,x.value,x.value_type,
19+
Variable(x::Variable, D::Differential) = Variable(x.name,x.value_type,
2020
x.subtype,D,x.dependents,x.description,x.flow,x.domain,
2121
x.size,x.context)
2222

@@ -31,7 +31,7 @@ function expand_derivatives(O::Operation)
3131

3232
return O
3333
end
34-
expand_derivatives(x::Variable) = x
34+
expand_derivatives(x) = x
3535

3636
# Don't specialize on the function here
3737
function Derivative(O::Operation,idx)

src/operations.jl

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ end
88
function Base.:(==)(x::Operation,y::Operation)
99
x.op == y.op && length(x.args) == length(y.args) && all(isequal.(x.args,y.args))
1010
end
11-
Base.:(==)(x::Operation,y::Number) = false
12-
Base.:(==)(x::Number,y::Operation) = false
13-
Base.:(==)(x::Operation,y::Nothing) = false
14-
Base.:(==)(x::Nothing,y::Operation) = false
15-
Base.:(==)(x::Variable,y::Operation) = false
16-
Base.:(==)(x::Operation,y::Variable) = false
11+
Base.:(==)(::Operation, ::Number ) = false
12+
Base.:(==)(::Number , ::Operation) = false
13+
Base.:(==)(::Operation, ::Variable ) = false
14+
Base.:(==)(::Variable , ::Operation) = false
15+
Base.:(==)(::Operation, ::Constant ) = false
16+
Base.:(==)(::Constant , ::Operation) = false
1717

1818
Base.convert(::Type{Expr}, O::Operation) =
1919
build_expr(:call, Any[Symbol(O.op); convert.(Expr, O.args)])
@@ -36,8 +36,7 @@ function find_replace!(O::Operation,x::Variable,y::Expression)
3636
end
3737

3838
# For inv
39-
Base.convert(::Type{Operation},x::Int) = Operation(identity,Expression[Constant(x)])
40-
Base.convert(::Type{Operation},x::Bool) = Operation(identity,Expression[Constant(x)])
41-
Base.convert(::Type{Operation},x::Variable) = Operation(identity,Expression[x])
42-
Operation(x) = convert(Operation,x)
43-
Operation(x::Operation) = x
39+
Base.convert(::Type{Operation}, x::Number) = Operation(identity, Expression[Constant(x)])
40+
Base.convert(::Type{Operation}, x::Operation) = x
41+
Base.convert(::Type{Operation}, x::Expression) = Operation(identity, Expression[x])
42+
Operation(x) = convert(Operation, x)

src/simplify.jl

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
function simplify_constants(O::Operation, shorten_tree = true)
1+
function simplify_constants(O::Operation, shorten_tree)
22
while true
33
O′ = _simplify_constants(O, shorten_tree)
44
if is_operation(O′)
@@ -8,10 +8,13 @@ function simplify_constants(O::Operation, shorten_tree = true)
88
O = O′
99
end
1010
end
11+
simplify_constants(x, shorten_tree) = x
12+
simplify_constants(x) = simplify_constants(x, true)
13+
1114

1215
const AC_OPERATORS = (*, +)
1316

14-
function _simplify_constants(O, shorten_tree = true)
17+
function _simplify_constants(O::Operation, shorten_tree)
1518
# Tree shrinking
1619
if shorten_tree && O.op AC_OPERATORS
1720
# Flatten tree
@@ -67,7 +70,7 @@ function _simplify_constants(O, shorten_tree = true)
6770

6871
return O
6972
end
70-
simplify_constants(x::Variable, y=false) = x
71-
_simplify_constants(x::Variable, y=false) = x
73+
_simplify_constants(x, shorten_tree) = x
74+
_simplify_constants(x) = _simplify_constants(x, true)
7275

7376
export simplify_constants

src/systems/diffeqs/first_order_transform.jl

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
function lower_varname(var::Variable, naming_scheme; lower=false)
22
D = var.diff
3-
D == nothing && return var
3+
D === nothing && return var
44
order = lower ? D.order-1 : D.order
55
lower_varname(var.name, D.x, order, var.subtype, naming_scheme)
66
end
77
function lower_varname(sym::Symbol, idv, order::Int, subtype::Symbol, naming_scheme)
8-
order == 0 && return Variable(sym, subtype)
9-
name = Symbol(String(sym)*naming_scheme*String(idv.name)^order)
10-
Variable(name, subtype=subtype)
8+
name = order == 0 ? sym : Symbol(sym, naming_scheme, string(idv.name)^order)
9+
return Variable(name, subtype=subtype)
1110
end
1211

1312
function ode_order_lowering(sys::DiffEqSystem; kwargs...)

src/utils.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ end
3333

3434
toexpr(ex) = MacroTools.postwalk(x -> isa(x, Expression) ? convert(Expr, x) : x, ex)
3535

36-
is_constant(x::Variable) = x.subtype === :Constant
36+
is_constant(::Constant) = true
3737
is_constant(::Any) = false
3838

3939
is_operation(::Operation) = true

src/variables.jl

Lines changed: 40 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
mutable struct Variable <: Expression
22
name::Symbol
3-
value
43
value_type::DataType
54
subtype::Symbol
65
diff::Union{Function,Nothing} # FIXME
@@ -13,26 +12,23 @@ mutable struct Variable <: Expression
1312
end
1413

1514
Variable(name,
16-
value = nothing,
17-
value_type = typeof(value);
15+
value_type = Any;
1816
subtype::Symbol=:Variable,
1917
dependents::Vector{Variable} = Variable[],
2018
flow::Bool = false,
2119
description::String = "",
2220
domain = Reals(),
2321
size = nothing,
2422
context = nothing) =
25-
Variable(name,value,value_type,subtype,nothing,
23+
Variable(name,value_type,subtype,nothing,
2624
dependents,description,flow,domain,size,context)
2725
Variable(name,args...;kwargs...) = Variable(name,args...;subtype=:Variable,kwargs...)
2826

29-
Variable(name,x::Variable) = Variable(name,x.value,x.value_type,
27+
Variable(name,x::Variable) = Variable(name,x.value_type,
3028
x.subtype,D,x.dependents,x.description,x.flow,x.domain,
3129
x.size,x.context)
3230

3331
Parameter(name,args...;kwargs...) = Variable(name,args...;subtype=:Parameter,kwargs...)
34-
Constant(value::Number) = Variable(Symbol(value),value,typeof(value);subtype=:Constant)
35-
Constant(name,args...;kwargs...) = Variable(name,args...;subtype=:Constant,kwargs...)
3632
IndependentVariable(name,args...;kwargs...) = Variable(name,args...;subtype=:IndependentVariable,kwargs...)
3733

3834
function DependentVariable(name,args...;dependents = [],kwargs...)
@@ -64,53 +60,38 @@ export Variable,Parameter,Constant,DependentVariable,IndependentVariable,JumpVar
6460
@Var, @DVar, @IVar, @Param, @Const
6561

6662

67-
Base.get(x::Variable) = x.value
63+
struct Constant <: Expression
64+
value::Number
65+
end
66+
Base.get(c::Constant) = c.value
67+
6868

69-
Base.iszero(::Expression) = false
70-
Base.iszero(c::Variable) = get(c) isa Number && iszero(get(c))
71-
Base.isone(::Expression) = false
72-
Base.isone(c::Variable) = get(c) isa Number && isone(get(c))
69+
Base.iszero(ex::Expression) = isa(ex, Constant) && iszero(ex.value)
70+
Base.isone(ex::Expression) = isa(ex, Constant) && isone(ex.value)
7371

7472

7573
# Variables use isequal for equality since == is an Operation
76-
function Base.:(==)(x::Variable,y::Variable)
77-
x.name == y.name && x.subtype == y.subtype && x.value == y.value &&
74+
function Base.:(==)(x::Variable, y::Variable)
75+
x.name == y.name && x.subtype == y.subtype &&
7876
x.value_type == y.value_type && x.diff == y.diff
7977
end
80-
81-
function Base.:(==)(x::Variable,y::Number)
82-
x == Constant(y)
83-
end
84-
85-
function Base.:(==)(x::Number,y::Variable)
86-
Constant(x) == y
87-
end
78+
Base.:(==)(::Variable, ::Number) = false
79+
Base.:(==)(::Number, ::Variable) = false
80+
Base.:(==)(::Variable, ::Constant) = false
81+
Base.:(==)(::Constant, ::Variable) = false
82+
Base.:(==)(c::Constant, n::Number) = c.value == n
83+
Base.:(==)(n::Number, c::Constant) = c.value == n
84+
Base.:(==)(a::Constant, b::Constant) = a.value == b.value
8885

8986
function Base.convert(::Type{Expr}, x::Variable)
90-
if x.subtype == :Constant
91-
return x.value
92-
elseif x.diff == nothing
93-
return :($(x.name))
94-
else
95-
return :($(Symbol("$(x.name)_$(x.diff.x.name)")))
96-
end
87+
x.diff === nothing && return x.name
88+
return Symbol("$(x.name)_$(x.diff.x.name)")
9789
end
90+
Base.convert(::Type{Expr}, c::Constant) = c.value
9891

99-
function Base.show(io::IO, A::Variable)
100-
if A.subtype == :Constant
101-
print(io,"Constant($(A.value))")
102-
else
103-
str = "$(A.subtype)($(A.name))"
104-
if A.value != nothing
105-
str *= ", value = " * string(A.value)
106-
end
107-
108-
if A.diff != nothing
109-
str *= ", diff = " * string(A.diff)
110-
end
111-
112-
print(io,str)
113-
end
92+
function Base.show(io::IO, x::Variable)
93+
print(io, x.subtype, '(', x.name, ')')
94+
x.diff === nothing || print(io, ", diff = ", x.diff)
11495
end
11596

11697
extract_idv(eq) = eq.args[1].diff.x
@@ -159,45 +140,29 @@ function _parse_vars(macroname, fun, x)
159140
# begin
160141
# x
161142
# y
162-
# z = exp(2)
143+
# z
163144
# end
164145
x = flatten_expr!(x)
165146
for _var in x
166147
iscall = typeof(_var) <: Expr && _var.head == :call
167148
issym = _var isa Symbol
168-
isassign = issym ? false : _var.head == :(=)
169-
@assert iscall || issym || isassign "@$macroname expects a tuple of expressions!\nE.g. `@$macroname x y z=1`"
170-
if iscall || issym
171-
if iscall
172-
dependents = :([$(_var.args[2:end]...)])
173-
var = _var.args[1]
174-
else
175-
dependents = Variable[]
176-
var = _var
177-
end
178-
lhs = var
179-
push!(lhss, lhs)
180-
expr = :( $lhs = $fun( Symbol($(String(lhs))) ,
181-
dependents = $dependents))
182-
end
183-
if isassign
184-
iscall = typeof(_var.args[1]) <: Expr && _var.args[1].head == :call
185-
if iscall
186-
dependents = :([$(_var.args[1].args[2:end]...)])
187-
lhs = _var.args[1].args[1]
188-
else
189-
dependents = Variable[]
190-
lhs = _var.args[1]
191-
end
192-
rhs = _var.args[2]
193-
push!(lhss, lhs)
194-
expr = :( $lhs = $fun( Symbol($(String(lhs))) , $rhs,
195-
dependents = $dependents))
149+
@assert iscall || issym "@$macroname expects a tuple of expressions!\nE.g. `@$macroname x y z`"
150+
151+
if iscall
152+
dependents = :([$(_var.args[2:end]...)])
153+
lhs = _var.args[1]
154+
else
155+
dependents = Variable[]
156+
lhs = _var
196157
end
158+
159+
push!(lhss, lhs)
160+
expr = :( $lhs = $fun( Symbol($(String(lhs))) ,
161+
dependents = $dependents))
197162
push!(ex.args, expr)
198163
end
199-
push!(ex.args, Expr(:tuple, lhss...))
200-
ex
164+
push!(ex.args, build_expr(:tuple, lhss))
165+
return ex
201166
end
202167

203168
for funs in ((:DVar, :DependentVariable), (:IVar, :IndependentVariable),

test/basic_variables_and_operations.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ using Test
1010
@Const c=0
1111

1212
# Default values
13-
p = Parameter(:p, 1)
14-
u = DependentVariable(:u, [1], dependents = [t])
13+
p = Parameter(:p)
14+
u = DependentVariable(:u, dependents = [t])
1515

16-
s = JumpVariable(:s,3,dependents=[t])
17-
n = NoiseVariable(:n,dependents=[t])
16+
s = JumpVariable(:s, dependents=[t])
17+
n = NoiseVariable(:n, dependents=[t])
1818

1919
σ*(y-x)
2020
D(x)

test/derivatives.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ expand_derivatives(dsin)
1111

1212
@test expand_derivatives(dsin) == cos(t)
1313
dcsch = D(csch(t))
14-
@test expand_derivatives(dcsch) == simplify_constants(Operation(coth(t)*csch(t)*-1))
14+
@test expand_derivatives(dcsch) == simplify_constants(coth(t) * csch(t) * -1)
1515

1616
# Chain rule
1717
dsinsin = D(sin(sin(t)))

0 commit comments

Comments
 (0)