-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathinputs.jl
216 lines (155 loc) · 5.11 KB
/
inputs.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
"""
AbstractInput
Abstract supertype for all input types.
### Notes
The input types defined here implement an iterator interface, such that other methods
can build upon the behavior of inputs which are either constant or varying.
Iteration is supported with an index number called *iterator state*.
The iteration function `Base.iterate` takes and returns a tuple (`input`, `state`),
where `input` represents the value of the input, and `state` is an index which
counts the number of times this iterator was called.
A convenience function `nextinput(input, n)` is also provided and it returns the
first `n` elements of `input`.
"""
abstract type AbstractInput end
"""
ConstantInput{UT} <: AbstractInput
Type representing an input that remains constant in time.
### Fields
- `U` -- input set
### Examples
The constant input holds a single element and its length is infinite.
To access the field `U`, you can use Base's `iterate` given a state, or the method
`nextinput` given the number of desired input elements:
```jldoctest constant_input
julia> c = ConstantInput(-1//2)
ConstantInput{Rational{Int64}}(-1//2)
julia> iterate(c, 1)
(-1//2, nothing)
julia> iterate(c, 2)
(-1//2, nothing)
julia> collect(nextinput(c, 4))
4-element Array{Rational{Int64},1}:
-1//2
-1//2
-1//2
-1//2
```
The elements of this input are rational numbers:
```jldoctest constant_input
julia> eltype(c)
Rational{Int64}
```
To transform a constant input, you can use `map` as in:
```jldoctest constant_input
julia> map(x->2*x, c)
ConstantInput{Rational{Int64}}(-1//1)
```
"""
struct ConstantInput{UT} <: AbstractInput
U::UT
end
Base.eltype(::Type{ConstantInput{UT}}) where {UT} = UT
Base.iterate(input::ConstantInput, state::Union{Int, Nothing}=nothing) = (input.U, nothing)
Base.IteratorSize(::Type{<:ConstantInput}) = Base.IsInfinite()
Base.IteratorEltype(::Type{<:ConstantInput}) = Base.HasEltype()
Base.map(f::Function, c::ConstantInput) = ConstantInput(f(c.U))
"""
nextinput(input::ConstantInput, n::Int=1)
Returns the first `n` elements of this input.
### Input
- `input` -- a constant input
- `n` -- (optional, default: `1`) the number of desired elements
### Output
A repeated iterator that generates `n` equal samples of this input.
"""
nextinput(input::ConstantInput, n::Int=1) = Base.Iterators.repeated(input.U, n)
"""
VaryingInput{UT, VUT<:AbstractVector{UT}} <: AbstractInput
Type representing an input that may vary with time.
### Fields
- `U` -- vector of input sets
### Examples
The varying input holds a vector and its length equals the number
of elements in the vector. Consider an input given by a vector of rational numbers:
```jldoctest varying_input
julia> v = VaryingInput([-1//2, 1//2])
VaryingInput{Rational{Int64},Array{Rational{Int64},1}}(Rational{Int64}[-1//2, 1//2])
julia> length(v)
2
julia> eltype(v)
Rational{Int64}
```
Base's `iterate` method receives the input and an integer state and returns the
input element and the next iteration state:
```jldoctest varying_input
julia> iterate(v, 1)
(-1//2, 2)
julia> iterate(v, 2)
(1//2, 3)
```
The method `nextinput` receives a varying input and an integer `n` and returns
an iterator over the first `n` elements of this input (where `n=1` by default):
```jldoctest varying_input
julia> typeof(nextinput(v))
Base.Iterators.Take{VaryingInput{Rational{Int64},Array{Rational{Int64},1}}}
julia> collect(nextinput(v, 1))
1-element Array{Rational{Int64},1}:
-1//2
julia> collect(nextinput(v, 2))
2-element Array{Rational{Int64},1}:
-1//2
1//2
```
You can collect the inputs in an array, or equivalently use list comprehension,
(or use a `for` loop):
```jldoctest varying_input
julia> collect(v)
2-element Array{Rational{Int64},1}:
-1//2
1//2
julia> [2*vi for vi in v]
2-element Array{Rational{Int64},1}:
-1//1
1//1
```
Since this input type is finite, querying more elements than its length returns
the full vector:
```jldoctest varying_input
julia> collect(nextinput(v, 4))
2-element Array{Rational{Int64},1}:
-1//2
1//2
```
To transform a varying input, you can use `map` as in:
```jldoctest varying_input
julia> map(x->2*x, v)
VaryingInput{Rational{Int64},Array{Rational{Int64},1}}(Rational{Int64}[-1//1, 1//1])
```
"""
struct VaryingInput{UT, VUT<:AbstractVector{UT}} <: AbstractInput
U::VUT # input sequence
end
Base.eltype(::Type{VaryingInput{UT, VUT}}) where {UT, VUT} = UT
function Base.iterate(input::VaryingInput, state::Int=1)
if state > length(input.U)
return nothing
else
return (input.U[state], state + 1)
end
end
Base.length(input::VaryingInput) = length(input.U)
Base.IteratorSize(::Type{<:VaryingInput}) = Base.HasLength()
Base.IteratorEltype(::Type{<:VaryingInput}) = Base.HasEltype()
Base.map(f::Function, v::VaryingInput) = VaryingInput(f.(v.U))
"""
nextinput(input::VaryingInput, n::Int=1)
Returns the first `n` elements of this input.
### Input
- `input` -- varying input
- `n` -- (optional, default: `1`) number of desired elements
### Output
An iterator of type `Base.Iterators.Take` that represents at most the first
`n` elements of this input.
"""
nextinput(input::VaryingInput, n::Int=1) = Base.Iterators.take(input, n)