Iteration utilities
Basic iteration
All time structures are iterable over their operational time periods
julia> using TimeStructjulia> function iterate_ex(periods::TimeStructure) for t in periods println(t) end enditerate_ex (generic function with 1 method)
Iteration with previous
In many settings, e.g. tracking of storage, it is convenient to have access to the previous time period. By using the custom iterator withprev it is possible to return both the previous and current time period as a tuple when iterating:
julia> using TimeStructjulia> periods = SimpleTimes(5, 1);julia> collect(withprev(periods))5-element Vector{Any}: (nothing, t1) (t1, t2) (t2, t3) (t3, t4) (t4, t5)
A variant of this is the withnext iterator that returns the current and next period (or nothing if none).
Iteration with chunks of time periods
Sometimes it is convenient to iterate through the time periods as chunks of a fixed number of periods or minimum duration, e.g. in production planning with minimum production runs. To simplify this process there are several iterator wrappers that allows this kind of iteration pattern.
The chunk function iterates through a time structure returning subsequences of length at most n starting at each time period.
julia> periods = SimpleTimes(5,1)SimpleTimes{Int64}(5, [1, 1, 1, 1, 1])julia> collect(collect(ts) for ts in chunk(periods, 3))5-element Vector{Vector{TimeStruct.SimplePeriod{Int64}}}: [t1, t2, t3] [t2, t3, t4] [t3, t4, t5] [t4, t5] [t5]
This wrapper can be used for e.g. modelling of startup modelling with a minimum uptime. The following example shows how this can be implemented as part of a JuMP model:
using JuMP, TimeStruct
periods = SimpleTimes(5,1)
m = Model()
@variable(m, startup[periods], Bin)
@variable(m, shutdown[periods], Bin)
for ts in chunk(periods, 3)
@constraint(m, sum(shutdown[t] for t in ts) <= 3 * (1 - startup[first(ts)]))
end3 startup[t1] + shutdown[t1] + shutdown[t2] + shutdown[t3] ≤ 3
3 startup[t2] + shutdown[t2] + shutdown[t3] + shutdown[t4] ≤ 3
3 startup[t3] + shutdown[t3] + shutdown[t4] + shutdown[t5] ≤ 3
3 startup[t4] + shutdown[t4] + shutdown[t5] ≤ 3
3 startup[t5] + shutdown[t5] ≤ 3Similarly, if modelling startup decisions with a minimum downtime, it is possible to reverse the original time periods and then chunk:
for ts in chunk(Iterators.reverse(periods), 3)
@constraint(m, sum(shutdown[t] for t in ts) <= 3 * (1 - startup[first(ts)]))
end3 startup[t5] + shutdown[t3] + shutdown[t4] + shutdown[t5] ≤ 3
3 startup[t4] + shutdown[t2] + shutdown[t3] + shutdown[t4] ≤ 3
3 startup[t3] + shutdown[t1] + shutdown[t2] + shutdown[t3] ≤ 3
3 startup[t2] + shutdown[t1] + shutdown[t2] ≤ 3
3 startup[t1] + shutdown[t1] ≤ 3It is also possible to get cyclic behaviour by setting the cyclic argument to true. If reaching the end before the required number of time periods, the chunk will continue from the first time period.
for ts in chunk(periods, 3; cyclic = true)
@constraint(m, sum(shutdown[t] for t in ts) <= 3 * (1 - startup[first(ts)]))
end3 startup[t1] + shutdown[t1] + shutdown[t2] + shutdown[t3] ≤ 3
3 startup[t2] + shutdown[t2] + shutdown[t3] + shutdown[t4] ≤ 3
3 startup[t3] + shutdown[t3] + shutdown[t4] + shutdown[t5] ≤ 3
3 startup[t4] + shutdown[t1] + shutdown[t4] + shutdown[t5] ≤ 3
3 startup[t5] + shutdown[t1] + shutdown[t2] + shutdown[t5] ≤ 3Chunks based on duration
If working with a time structure that has varying duration for its time periods, it can be more convenient with chunks based on their combined duration.
The chunk_duration function iterates through a time structure returning subsequences of duration at least dur starting at each time period.
julia> periods = SimpleTimes(5,[1, 2, 1, 1.5, 0.5, 2])SimpleTimes{Float64}(5, [1.0, 2.0, 1.0, 1.5, 0.5, 2.0])julia> collect(collect(ts) for ts in chunk_duration(periods, 3))5-element Vector{Vector{TimeStruct.SimplePeriod{Float64}}}: [t1, t2] [t2, t3] [t3, t4, t5] [t4, t5] [t5]
Indexing of operational time structures
It is possible to use indices for operational time structures, either directly using SimpleTimes or CalendarTimes or by accessing an operational scenario.
julia> periods = TwoLevel(3, 100, SimpleTimes(10,1));julia> scenario = first(opscenarios(periods))sp1-sc1julia> scenario[3]sp1-t3