Newer
Older
module Alternatives
import JuMP: @constraint
import ..Abstract: ContainerBlock
import ...BuildSequences: global_model, fixed
import ...Variables: @defvar, make_generic
"""
AlternativeBlocks(name, blocks)
Represents a part of the sequence where there are multiple possible alternatives.
Variables can be matched across these alternatives using [`match_blocks!`](@ref).
The `name` is a symbol that is used to identify this `AlternativeBlocks` in the broader sequence.
"""
struct AlternativeBlocks <: ContainerBlock
name :: Symbol
options :: Dict{Any, <:ContainerBlock}
AlternativeBlocks(name::Symbol, options_vector::AbstractVector) = AlternativeBlocks(name, Dict(index => value for (index, value) in enumerate(options_vector)))
Base.getindex(alt::AlternativeBlocks, index) = alt.options[index]
Base.length(alt::AlternativeBlocks) = length(alt.options)
@defvar duration(alt::AlternativeBlocks) = maximum(duration.(values(alt.options)))
"""
match_blocks!(alternatives, function)
Matches the outcome of given `function` on each of the building blocks in [`AlternativeBlocks`](@ref).
For example, `match_blocks!(alternatives, duration)` will ensure that all the alternative building blocks have the same duration.
"""
function match_blocks!(alternatives::AlternativeBlocks, func)
options = [values(alternatives.options)...]
baseline = func(options[1])
for other_block in options[2:end]
if baseline isa AbstractVector
@constraint global_model() baseline == func(other_block)
else
@constraint global_model() baseline .== func(other_block)
end
end
end
fixed(alt::AlternativeBlocks) = AlternativeBlocks(alt.name, Dict(key=>fixed(value) for (key, value) in alt.options))
make_generic(alt::AlternativeBlocks) = AlternativeBlocks(alt.name, Dict(key=>make_generic(value) for (key, value) in alt.options))