/
indextypes.jl
167 lines (134 loc) · 5.03 KB
/
indextypes.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
# Copyright (c) 2017: Miles Lubin and contributors
# Copyright (c) 2017: Google Inc.
#
# Use of this source code is governed by an MIT-style license that can be found
# in the LICENSE.md file or at https://opensource.org/licenses/MIT.
"""
AbstractFunction
Abstract supertype for function objects.
## Required methods
All functions must implement:
* `Base.copy`
* `Base.isapprox`
* [`constant`](@ref)
Abstract subtypes of `AbstractFunction` may require additional methods to be
implemented.
"""
abstract type AbstractFunction <: MA.AbstractMutable end
"""
abstract type AbstractScalarFunction <: AbstractFunction
Abstract supertype for scalar-valued [`AbstractFunction`](@ref)s.
"""
abstract type AbstractScalarFunction <: AbstractFunction end
Base.broadcastable(f::AbstractScalarFunction) = Ref(f)
Base.ndims(::Type{<:AbstractScalarFunction}) = 0
Base.ndims(::AbstractScalarFunction) = 0
"""
VariableIndex
A type-safe wrapper for `Int64` for use in referencing variables in a model.
To allow for deletion, indices need not be consecutive.
"""
struct VariableIndex <: AbstractScalarFunction
value::Int64
end
"""
ConstraintIndex{F, S}
A type-safe wrapper for `Int64` for use in referencing `F`-in-`S` constraints in
a model.
The parameter `F` is the type of the function in the constraint, and the
parameter `S` is the type of set in the constraint. To allow for deletion,
indices need not be consecutive. Indices within a constraint type (that is, `F`-in-`S`)
must be unique, but non-unique indices across different constraint types are allowed.
If `F` is [`VariableIndex`](@ref) then the index is equal to the index of the
variable. That is for an `index::ConstraintIndex{VariableIndex}`, we always
have
```julia
index.value == MOI.get(model, MOI.ConstraintFunction(), index).value
```
"""
struct ConstraintIndex{F,S}
value::Int64
end
# The default hash is slow. It's important for the performance of dictionaries
# of VariableIndices to define our own.
# https://github.com/JuliaLang/julia/issues/10208
Base.hash(v::VariableIndex, h::UInt) = hash(v.value, h)
# No need to define isequal because the default matches our implementation of
# hash.
const Index = Union{ConstraintIndex,VariableIndex}
"""
struct InvalidIndex{IndexType<:Index} <: Exception
index::IndexType
end
An error indicating that the index `index` is invalid.
"""
struct InvalidIndex{IndexType<:Index} <: Exception
index::IndexType
end
function Base.showerror(io::IO, err::InvalidIndex)
return print(
"The index $(err.index) is invalid. Note that an index becomes invalid after it has been deleted.",
)
end
"""
is_valid(model::ModelLike, index::Index)::Bool
Return a `Bool` indicating whether this index refers to a valid object in the model `model`.
"""
is_valid(model::ModelLike, ref::Index) = false
"""
throw_if_not_valid(model::ModelLike, index::Index)
Throw an `InvalidIndex(index)` error if `MOI.is_valid(model, index)` returns
`false`.
"""
function throw_if_not_valid(model::ModelLike, index::Index)
if !is_valid(model, index)
throw(InvalidIndex(index))
end
end
"""
struct DeleteNotAllowed{IndexType <: Index} <: NotAllowedError
index::IndexType
message::String
end
An error indicating that the index `index` cannot be deleted.
"""
struct DeleteNotAllowed{IndexType<:Index} <: NotAllowedError
index::IndexType
message::String
end
DeleteNotAllowed(index::Index) = DeleteNotAllowed(index, "")
function operation_name(err::DeleteNotAllowed)
return "Deleting the index $(err.index)"
end
"""
delete(model::ModelLike, index::Index)
Delete the referenced object from the model. Throw [`DeleteNotAllowed`](@ref) if
if `index` cannot be deleted.
The following modifications also take effect if `Index` is [`VariableIndex`](@ref):
* If `index` used in the objective function, it is removed from the function,
that is, it is substituted for zero.
* For each `func`-in-`set` constraint of the model:
- If `func isa VariableIndex` and `func == index` then the
constraint is deleted.
- If `func isa VectorOfVariables` and `index in func.variables` then
* if `length(func.variables) == 1` is one, the constraint is deleted;
* if `length(func.variables) > 1` and `supports_dimension_update(set)` then
then the variable is removed from `func` and `set` is replaced by
`update_dimension(set, MOI.dimension(set) - 1)`.
* Otherwise, a [`DeleteNotAllowed`](@ref) error is thrown.
- Otherwise, the variable is removed from `func`, that is, it is substituted for
zero.
"""
delete(model::ModelLike, index::Index) = throw(DeleteNotAllowed(index))
"""
delete(model::ModelLike, indices::Vector{R<:Index}) where {R}
Delete the referenced objects in the vector `indices` from the model.
It may be assumed that `R` is a concrete type. The default fallback sequentially
deletes the individual items in `indices`, although specialized implementations
may be more efficient.
"""
function delete(model::ModelLike, indices::Vector{<:Index})
for index in indices
delete(model, index)
end
end