Skip to content

Commit 48f771f

Browse files
authored
Convert to ReactiveBasics for Discrete variables (#75)
* Change Discretes to use ReactiveBasics
1 parent 200b35e commit 48f771f

File tree

9 files changed

+60
-81
lines changed

9 files changed

+60
-81
lines changed

REQUIRE

+1-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,5 @@ Documenter
44
Ipopt
55
JuMP
66
Plots
7-
Reactive
8-
Reexport
7+
ReactiveBasics
98
Sundials

docs/src/basics.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -259,18 +259,18 @@ end
259259
```
260260

261261
`Discrete` variables are based on `Signals` from the
262-
[Reactive.jl](http://julialang.org/Reactive.jl/) package. This
262+
[ReactiveBasics.jl](http://github.com/tshort/ReactiveBasics.jl/) package. This
263263
provides
264264
[Reactive Programming](http://en.wikipedia.org/wiki/Reactive_programming)
265265
capabilities where variables have data flow. This is similar to how
266-
spreadsheets dynamically update and how Simulink works. This `lift`
266+
spreadsheets dynamically update and how Simulink works. This `map`
267267
operator defines dependencies based on a function, and `reinit` is
268268
used to update inputs. Here is an example:
269269

270270
```julia
271271
a = Discrete(2.0)
272272
b = Discrete(4.0)
273-
c = lift((x,y) -> x * y, a, b) # 8.0
273+
c = map((x,y) -> x * y, a, b) # 8.0
274274
reinit(a, 4.0) # c becomes 16.0
275275
```
276276

examples/neural/lib.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ end
5858

5959
function MembranePotential(v,currents,c)
6060
@equations begin
61-
c * der(v) = - foldl((i,ax) -> i+ax, currents)
61+
c * der(v) = - foldp((i,ax) -> i+ax, currents)
6262
end
6363
end
6464

lib/electrical.jl

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import Reactive
21

32
########################################
43
## Electrical library ##
@@ -532,15 +531,16 @@ IdealThyristor(n1::ElectricalNode, n2::ElectricalNode, fire::Discrete;
532531
"""
533532
function IdealThyristor(n1::ElectricalNode, n2::ElectricalNode, fire,
534533
Vknee, Ron = 1e-5, Goff = 1e-5)
534+
fire = Parameter(fire)
535535
vals = compatible_values(n1, n2)
536536
i = Current(vals)
537537
v = Voltage(vals)
538538
s = Unknown(vals) # dummy variable
539539
spositive = Discrete(value(s) > 0.0)
540-
## off = @lift !spositive | (off & !fire) # on/off state of each switch
541-
off = lift(x -> x[1],
542-
foldl((off, spositive, fire) -> (!spositive | (off[1] & !fire), spositive, fire),
543-
(true, value(spositive), value(fire)), spositive, fire))
540+
## off = @map !spositive | (off & !fire) # on/off state of each switch
541+
off = map(x -> x[1],
542+
foldp((off, spositive, fire) -> (!spositive | (off[1] & !fire), spositive, fire),
543+
(true, value(spositive), value(fire)), spositive, fire))
544544
@equations begin
545545
Branch(n1, n2, v, i)
546546
BoolEvent(spositive, s)
@@ -553,7 +553,7 @@ function IdealThyristor(n1::ElectricalNode, n2::ElectricalNode, fire;
553553
IdealThyristor(n1, n2, fire, Vknee, Ron, Goff)
554554
end
555555

556-
556+
557557
"""
558558
This is an ideal GTO thyristor model which is **open** (off), if the
559559
voltage drop is less than 0 or `fire` is false **closed** (on), if the

src/Sims.jl

+5-3
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ __precompile__(false)
22

33
module Sims
44

5-
using Reexport
6-
@reexport using Reactive
5+
using ReactiveBasics
6+
import ReactiveBasics.value
77

88
import Base.ifelse,
99
Base.hcat,
@@ -29,7 +29,6 @@ export MTime, @unknown, @liftd, @comment
2929
## Methods
3030
export Equation, @equations, is_unknown, der, delay, mexpr, compatible_values, reinit, ifelse, pre,
3131
basetypeof, from_real, to_real,
32-
lift,
3332
gplot, plot,
3433
check, sim_verbose,
3534
elaborate, create_sim, create_simstate, sim, sunsim, dasslsim, solve,
@@ -38,6 +37,9 @@ export Equation, @equations, is_unknown, der, delay, mexpr, compatible_values, r
3837
## Model methods
3938
export Branch, BoolEvent
4039

40+
## ReactiveBasics
41+
export foldp, value, signal, flatmap
42+
4143

4244
using Documenter
4345
include("docutil.jl")

src/dassl.jl

-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ function dasslsim(ss::SimState, tstop::Float64, Nsteps::Int=500, reltol::Float64
6363
sm = ss.sm
6464
for x in sm.discrete_inputs
6565
push!(x.signal, x.initialvalue)
66-
Reactive.run_till_now()
6766
end
6867
ss.y[:] = ss.y0
6968
ss.yp[:] = ss.yp0

src/main.jl

+43-63
Original file line numberDiff line numberDiff line change
@@ -916,7 +916,7 @@ end
916916

917917

918918
"""
919-
An abstract type representing Unknowns that use the Reactive.jl
919+
An abstract type representing Unknowns that use the ReactiveBasics.jl
920920
package. The main types included are `Discrete` and
921921
`Parameter`. `Discrete` is normally used as inputs inside of models
922922
and includes an initial value that is reset at every simulation
@@ -927,10 +927,9 @@ variations.
927927
Because they are Unknowns, UnknownReactive types form MExpr's when
928928
used in expressions just like Unknowns.
929929
930-
Many of the methods from Reactive.jl are supported, including `lift`,
931-
`foldl`, `filter`, `dropif`, `droprepeats`, `keepwhen`, `dropwhen`,
932-
`sampleon`, and `merge`. Use `reinit` to reinitialize a Discrete or a
933-
Parameter (equivalent to `Reactive.push!`).
930+
Many of the methods from ReactiveBasics.jl are supported, including `map`,
931+
`foldp`, `filter`, and `merge`. Use `reinit` to reinitialize a Discrete or a
932+
Parameter (equivalent to `push!`).
934933
935934
"""
936935
abstract UnknownReactive{T} <: UnknownVariable
@@ -940,40 +939,40 @@ Discrete is a type for discrete variables. These are only changed
940939
during events. They are not used by the integrator. Because they are
941940
not used by the integrator, almost any type can be used as a discrete
942941
variable. Discrete variables wrap a Signal from the
943-
[Reactive.jl](http://julialang.org/Reactive.jl/) package.
942+
[ReactiveBasics.jl](http://github.org/tshort/ReactiveBasics.jl) package.
944943
945944
### Constructors
946945
947946
```julia
948947
Discrete(initialvalue = 0.0)
949-
Discrete(x::Reactive.Signal, initialvalue)
948+
Discrete(x::ReactiveBasics.Signal, initialvalue)
950949
```
951950
952951
Without arguments, `Discrete()` uses an initial value of 0.0.
953952
954953
### Arguments
955954
956955
* `initialvalue` : initial value and type information, defaults to 0.0
957-
* `x::Reactive.Signal` : a `Signal` from the Reactive.jl package.
956+
* `x::ReactiveBasics.Signal` : a `Signal` from the ReactiveBasics.jl package.
958957
959958
### Details
960959
961960
`Discrete` is the main input type for discrete variables. By default,
962-
it wraps a `Reactive.Signal` type. `Discrete` variables support data
963-
flow using Reactive.jl. Use `reinit` to update Discrete variables. Use
964-
`lift` to create additional `UnknownReactive` types that depend on the
965-
`Discrete` input. Use `foldl` for actions that remember state. For
961+
it wraps a `ReactiveBasics.Signal` type. `Discrete` variables support data
962+
flow using ReactiveBasics.jl. Use `reinit` to update Discrete variables. Use
963+
`map` to create additional `UnknownReactive` types that depend on the
964+
`Discrete` input. Use `foldp` for actions that remember state. For
966965
more information on *Reactive Programming*, see the
967-
[Reactive.jl](http://julialang.org/Reactive.jl/) package.
966+
[ReactiveBasics.jl](http://github.org/tshort/ReactiveBasics.jl) package.
968967
969968
"""
970-
type Discrete{T <: Reactive.Signal} <: UnknownReactive{T}
969+
type Discrete{T <: ReactiveBasics.Signal} <: UnknownReactive{T}
971970
signal::T
972971
initialvalue
973972
end
974-
# Discrete(x::Reactive.SignalSource) = Discrete(x, zero(x))
975-
Discrete(initialval) = Discrete(Reactive.Signal(initialval), initialval)
976-
Discrete() = Discrete(Reactive.Signal(0.0), 0.0)
973+
# Discrete(x::ReactiveBasics.SignalSource) = Discrete(x, zero(x))
974+
Discrete(initialval) = Discrete(ReactiveBasics.Signal(initialval), initialval)
975+
Discrete() = Discrete(ReactiveBasics.Signal(0.0), 0.0)
977976

978977
"""
979978
An `UnknownReactive` type that is useful for passing parameters at the
@@ -983,20 +982,20 @@ top level.
983982
984983
```julia
985984
Parameter(x = 0.0)
986-
Parameter(sig::Reactive.Signal}
985+
Parameter(sig::ReactiveBasics.Signal}
987986
```
988987
989988
### Arguments
990989
991990
* `x` : initial value and type information, defaults to 0.0
992-
* `sig` : A `Reactive.Signal
991+
* `sig` : A `ReactiveBasics.Signal`
993992
994993
### Details
995994
996995
Parameters can be reinitialized with `reinit`, either externally or
997996
inside models. If you want Parameters to be read-only, wrap them in
998997
another UnknownReactive before passing to models. For example, use
999-
`param_read_only = lift(x -> x, param)`.
998+
`param_read_only = map(x -> x, param)`.
1000999
10011000
### Examples
10021001
@@ -1014,17 +1013,18 @@ vwp3 = sim(ss, 10.0) # should be the same as vwp1
10141013
```
10151014
10161015
"""
1017-
type Parameter{T <: Reactive.Signal} <: UnknownReactive{T}
1016+
type Parameter{T <: ReactiveBasics.Signal} <: UnknownReactive{T}
10181017
signal::T
10191018
end
1020-
Parameter(x = 0.0) = Parameter(Reactive.Signal(x))
1019+
Parameter(x = 0.0) = Parameter(ReactiveBasics.Signal(x))
1020+
Parameter(x::UnknownReactive) = x
10211021

10221022
name(a::UnknownReactive) = "discrete"
1023-
value{T}(x::UnknownReactive{T}) = Reactive.value(x.signal)
1023+
value{T}(x::UnknownReactive{T}) = ReactiveBasics.value(x.signal)
10241024
signal(x::UnknownReactive) = x.signal
10251025

1026-
Reactive.push!{T}(x::Discrete{Reactive.Signal{T}}, y) = mexpr(:call, :(Reactive.push!), x.signal, y)
1027-
Reactive.push!{T}(x::Parameter{Reactive.Signal{T}}, y) = Reactive.push!(x.signal, y)
1026+
ReactiveBasics.push!{T}(x::Discrete{ReactiveBasics.Signal{T}}, y) = mexpr(:call, :(ReactiveBasics.push!), x.signal, y)
1027+
ReactiveBasics.push!{T}(x::Parameter{ReactiveBasics.Signal{T}}, y) = ReactiveBasics.push!(x.signal, y)
10281028

10291029

10301030
"""
@@ -1065,8 +1065,8 @@ end
10651065
See also [IdealThyristor](../../lib/electrical/#idealthyristor) in the standard library.
10661066
10671067
"""
1068-
reinit{T}(x::Discrete{Reactive.Signal{T}}, y) = MExpr(:( Reactive.push!($(x.signal), $y); Reactive.run_till_now() ))
1069-
reinit{T}(x::Parameter{Reactive.Signal{T}}, y) = Reactive.push!(x.signal, y)
1068+
reinit{T}(x::Discrete{ReactiveBasics.Signal{T}}, y) = MExpr(:( ReactiveBasics.push!($(x.signal), $y) ))
1069+
reinit{T}(x::Parameter{ReactiveBasics.Signal{T}}, y) = ReactiveBasics.push!(x.signal, y)
10701070

10711071
function reinit(x, y)
10721072
sim_info("reinit: $(x[]) to $y", 2)
@@ -1093,18 +1093,10 @@ Create a new UnknownReactive type that links to existing
10931093
UnknownReactive types (like Discrete and Parameter).
10941094
10951095
```julia
1096-
lift{T}(f::Function, inputs::UnknownReactive{T}...)
1097-
lift{T}(f::Function, t::Type, inputs::UnknownReactive{T}...)
10981096
map{T}(f::Function, inputs::UnknownReactive{T}...)
10991097
map{T}(f::Function, t::Type, inputs::UnknownReactive{T}...)
11001098
```
11011099
1102-
See also
1103-
[Reactive.lift](http://julialang.org/Reactive.jl/api.html#lift)] and
1104-
the [@liftd](#liftd) helper macro to ease writing expressions.
1105-
1106-
Note that `lift` is being transitioned to `Base.map`.
1107-
11081100
### Arguments
11091101
11101102
* `f::Function` : the transformation function; takes one argument for
@@ -1119,8 +1111,8 @@ function.
11191111
11201112
```julia
11211113
a = Discrete(1)
1122-
b = lift(x -> x + 1, a)
1123-
c = lift((x,y) -> x * y, a, b)
1114+
b = map(x -> x + 1, a)
1115+
c = map((x,y) -> x * y, a, b)
11241116
reinit(a, 3)
11251117
b # now 4
11261118
c # now 12
@@ -1131,11 +1123,11 @@ Note that you can use Discretes and Parameters in expressions that
11311123
create MExprs. Compare the following:
11321124
11331125
```julia
1134-
j = lift((x,y) = x * y, a, b)
1126+
j = map((x,y) = x * y, a, b)
11351127
k = a * b
11361128
```
11371129
1138-
In this example, `j` uses `lift` to immediately connect to `a` and
1130+
In this example, `j` uses `map` to immediately connect to `a` and
11391131
`b`. `k` is an MExpr with `a * b` embedded inside. When `j` is used in
11401132
a model, the `j` UnknownReactive object is embedded in the model, and it
11411133
is updated automatically. With `k`, `a * b` is inserted into the
@@ -1144,34 +1136,22 @@ in the residual calculation. The advantage of the `a * b` approach is
11441136
that the expression can include Unknowns.
11451137
11461138
"""
1147-
Reactive.lift{T}(f::Function, input::UnknownReactive{T}, inputs::UnknownReactive{T}...) = Parameter(map(f, input.signal, [input.signal for input in inputs]...))
1148-
1149-
Reactive.lift{T}(f::Function, t::Type, input::UnknownReactive{T}, inputs::UnknownReactive{T}...) = Parameter(map(f, t, input.signal, [input.signal for input in inputs]...))
1150-
11511139
Base.map{T}(f::Function, input::UnknownReactive{T}, inputs::UnknownReactive{T}...) = Parameter(map(f, input.signal, [input.signal for input in inputs]...))
11521140

11531141
Base.map{T}(f::Function, t::Type, input::UnknownReactive{T}, inputs::UnknownReactive{T}...) = Parameter(map(f, t, input.signal, [input.signal for input in inputs]...))
11541142

1155-
Reactive.filter{T}(pred::Function, v0, s::UnknownReactive{T}) = Parameter(filter(pred, v0, s.signal))
1156-
Reactive.dropwhen{T}(test::Signal{Bool}, v0, s::UnknownReactive{T}) = Parameter(dropwhen(pred, v0, s.signal))
1157-
Reactive.sampleon(s1::UnknownReactive, s2::UnknownReactive) = Parameter(sampleon(s1.signal, s2.signal))
1158-
# Reactive.merge() = nothing
1159-
Reactive.merge(signals::UnknownReactive...) = Parameter(merge(map(signal, signals)))
1160-
Reactive.droprepeats(s::UnknownReactive) = Parameter(droprepeats(signal(s)))
1161-
Reactive.dropif(pred::Function, v0, s::UnknownReactive) = Parameter(dropif(pred, v0, s.signal))
1162-
Reactive.keepwhen(test::UnknownReactive{Signal{Bool}}, v0, s::UnknownReactive) = Parameter(keepwhen(test.signal, v0, s.signal))
1143+
Base.filter{T}(pred::Function, v0, s::UnknownReactive{T}) = Parameter(filter(pred, v0, s.signal))
1144+
Base.merge(signals::UnknownReactive...) = Parameter(merge(map(signal, signals)))
1145+
ReactiveBasics.flatmap(f, inputs::UnknownReactive...) = Parameter(flatmap(f, [x.signal for x in inputs]...))
11631146

11641147

11651148

11661149
"""
1167-
"Fold over time" -- an UnknownReactive updated based on stored state
1150+
"Fold over past values" -- an UnknownReactive updated based on stored state
11681151
and additional inputs.
11691152
1170-
See also
1171-
[Reactive.foldl](http://julialang.org/Reactive.jl/api.html#foldl)].
1172-
11731153
```julia
1174-
foldl(f::Function, v0, inputs::UnknownReactive{T}...)
1154+
foldp(f::Function, v0, inputs::UnknownReactive{T}...)
11751155
```
11761156
11771157
### Arguments
@@ -1191,8 +1171,8 @@ foldl(f::Function, v0, inputs::UnknownReactive{T}...)
11911171
See the definition of [pre](#pre) for an example.
11921172
11931173
"""
1194-
Reactive.foldl{T,S}(f,v0::T, signal::UnknownReactive{S}, signals::UnknownReactive{S}...) =
1195-
Parameter(Reactive.foldl(f, v0, signal.signal, [s.signal for s in signals]...))
1174+
ReactiveBasics.foldp{T,S}(f,v0::T, signal::UnknownReactive{S}, signals::UnknownReactive{S}...) =
1175+
Parameter(ReactiveBasics.foldp(f, v0, signal.signal, [s.signal for s in signals]...))
11961176

11971177

11981178

@@ -1204,7 +1184,7 @@ A helper for an expression of UnknownReactive variables
12041184
```
12051185
12061186
Note that the expression should not contain Unknowns. To mark the
1207-
Discrete variables, enter them as Symbols. This uses `lift()`.
1187+
Discrete variables, enter them as Symbols. This uses `map()`.
12081188
12091189
### Arguments
12101190
@@ -1221,15 +1201,15 @@ x = Discrete(true)
12211201
y = Discrete(false)
12221202
z = @liftd :x & !:y
12231203
## equivalent to:
1224-
z2 = lift((x, y) -> x & !y, x, y)
1204+
z2 = map((x, y) -> x & !y, x, y)
12251205
```
12261206
12271207
"""
12281208
macro liftd(ex)
12291209
varnames = Any[]
12301210
body = replace_syms(ex, varnames)
12311211
front = Expr(:tuple, varnames...)
1232-
esc(:( Reactive.lift($front -> $body, $(varnames...)) ))
1212+
esc(:( map($front -> $body, $(varnames...)) ))
12331213
end
12341214
replace_syms(x, varnames) = x
12351215
function replace_syms(e::Expr, varnames)
@@ -1265,8 +1245,8 @@ pre(x::UnknownReactive)
12651245
12661246
"""
12671247
function pre{T}(x::UnknownReactive{T})
1268-
Reactive.lift(x -> x[1],
1269-
Reactive.foldl((a,b) -> (a[2], b), (zero(Sims.value(x)), Sims.value(x)), x))
1248+
map(x -> x[1],
1249+
ReactiveBasics.foldp((a,b) -> (a[2], b), (zero(Sims.value(x)), Sims.value(x)), x))
12701250
end
12711251

12721252

src/simcreation.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ function replace_unknowns(a::PassedUnknown, sm::Sim)
339339
a.ref
340340
## sm.unknown_idx_map[a.ref.sym]
341341
end
342-
function replace_unknowns{T}(a::Discrete{Reactive.Signal{T}}, sm::Sim)
342+
function replace_unknowns{T}(a::Discrete{ReactiveBasics.Signal{T}}, sm::Sim)
343343
push!(sm.discrete_inputs, a) # Discrete inputs
344344
:(value($a))
345345
end

src/sundials.jl

-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,6 @@ function sunsim(ss::SimState, tstop, Nsteps = 500, reltol = 1e-4, abstol = 1e-4,
119119
# fix up initial values
120120
for x in sm.discrete_inputs
121121
push!(x.signal, x.initialvalue)
122-
Reactive.run_till_now()
123122
end
124123
ss.y[:] = ss.y0
125124
ss.yp[:] = ss.yp0

0 commit comments

Comments
 (0)