delpi  0.0.1
DElta-complete LP solver
Loading...
Searching...
No Matches
VariableMap.h
1
7#pragma once
8
9#include <algorithm>
10#include <limits>
11#include <optional>
12#include <utility>
13#include <vector>
14
15#include "delpi/symbolic/Variable.h"
16#include "delpi/util/concepts.h"
17#include "delpi/util/exception.h"
18
19namespace delpi {
20
34template <class T>
35class VariableMap {
36 static_assert(std::is_copy_constructible_v<T>, "T must be copy constructible");
37
38 public:
39 using Id = Variable::Id;
40 using key_type = Variable;
41 using mapped_type = T;
42 using value_type = std::pair<const Variable, T>;
43
45 VariableMap() : min_id_{std::numeric_limits<Id>::max()} {}
51 template <TypedIterable<value_type> Items>
52 explicit VariableMap(const Items& items) : VariableMap{} {
53 Insert(items);
54 }
55
57 [[nodiscard]] Id min_id() const { return min_id_; }
59 [[nodiscard]] Id max_id() const { return vars_.size() + min_id_; }
61 [[nodiscard]] std::size_t size() const {
62 return std::ranges::count_if(vars_, [](const std::optional<mapped_type>& item) { return item.has_value(); });
63 }
65 [[nodiscard]] std::size_t capacity() const { return vars_.size(); }
67 [[nodiscard]] bool empty() const { return vars_.empty(); }
69 [[nodiscard]] std::vector<mapped_type> items() const {
70 std::vector<mapped_type> items;
71 items.reserve(vars_.size());
72 for (const std::optional<mapped_type>& item : vars_) {
73 if (item.has_value()) items.emplace_back(item.value());
74 }
75 return items;
76 }
77
84 [[nodiscard]] mapped_type At(const Variable var) const {
85 if (!Contains(var)) throw DelpiOutOfRangeException("Variable not in the map");
86 return vars_.at(var.id() - min_id_).value();
87 }
88
94 [[nodiscard]] bool Contains(const Variable& var) const { return Contains(var.id()); }
103 bool Insert(const Variable& var, const mapped_type& value) { return Insert(var.id(), value); }
110 template <TypedIterable<value_type> I>
111 void Insert(const I& items) {
112 const auto Comparator = [](const std::pair<Variable, T>& a, const std::pair<Variable, T>& b) {
113 return a.first.less(b.first);
114 };
115 // If the map is empty, initialise it with min_id_ = min(vars.id) and size m = max(vars.id) - min_id_ + 1
116 if (min_id_ == std::numeric_limits<Id>::max()) {
117 min_id_ = std::ranges::min_element(items, Comparator)->first.id();
118 vars_.resize(std::ranges::max_element(items, Comparator)->first.id() - min_id_ + 1, false);
119 for (const value_type& item : items) vars_.at(item.first.id() - min_id_) = item.second;
120 return;
121 }
122 // If the map is not empty, resize it to the new range and insert the variables
123 // First compute the new min_id and max_id comparing with the current min_id and max_id
124 // Then resize the vector to the new range m = new_max - new_min + 1
125 const Id new_min = std::min(std::ranges::min_element(items, Comparator)->first.id(), min_id_);
126 const Id new_max = std::max(std::ranges::max_element(items, Comparator)->first.id(), vars_.size() + min_id_ - 1);
127 const std::size_t max_diff = new_max - (vars_.size() + min_id_ - 1);
128 const std::size_t old_size = vars_.size();
129 vars_.resize(new_max - new_min + 1);
130 // If the lower bound of the new range is less than the current min_id, rotate the vector to the left by max_diff
131 if (new_min < min_id_) {
132 std::rotate(vars_.begin(), vars_.begin() + static_cast<std::int64_t>(old_size),
133 vars_.end() - static_cast<std::int64_t>(max_diff));
134 min_id_ = new_min;
135 }
136 for (const value_type& item : items) vars_.at(item.first.id() - min_id_) = item.second;
137 }
138
145 bool Remove(const Variable& var) { return Remove(var.id()); }
151 template <TypedIterable<Variable> V>
152 void Remove(const V& vars) {
153 for (const Variable& var : vars) Remove(var);
154 }
155
156 void Clear() {
157 vars_.clear();
158 min_id_ = std::numeric_limits<Id>::max();
159 }
160
161 private:
168 [[nodiscard]] bool Contains(const Id id) const {
169 return id >= min_id_ && id - min_id_ < vars_.size() && vars_.at(id - min_id_).has_value();
170 }
171
178 bool Insert(const Id id, const T& value) {
179 if (min_id_ == std::numeric_limits<Id>::max()) {
180 min_id_ = id;
181 vars_.emplace_back(value);
182 return true;
183 }
184 if (id < min_id_) {
185 vars_.resize(vars_.size() + min_id_ - id, std::nullopt);
186 std::ranges::rotate(vars_, vars_.begin() + static_cast<std::int64_t>(vars_.size() - (min_id_ - id)));
187 min_id_ = id;
188 vars_.front() = value;
189 return true;
190 }
191 if (id >= min_id_ + vars_.size()) {
192 vars_.resize(id - min_id_ + 1, std::nullopt);
193 vars_.back() = value;
194 return true;
195 }
196 vars_.at(id - min_id_) = value;
197 return false;
198 }
199
205 bool Remove(const Id id) {
206 if (!Contains(id)) return false;
207 const bool was_present = vars_.at(id - min_id_).has_value();
208 vars_.at(id - min_id_) = std::nullopt;
209 return was_present;
210 }
211
213 std::vector<std::optional<T>> vars_;
214};
215
216template <class T>
217std::ostream& operator<<(std::ostream& os, const VariableMap<T>& var_map);
218
219extern template class VariableMap<int>;
220
221} // namespace delpi
222
223#ifdef DELPI_INCLUDE_FMT
224
225#include "delpi/util/logging.h"
226
227OSTREAM_FORMATTER(delpi::VariableMap<int>)
228
229#endif
Exception for out of range errors.
Definition exception.h:69
Map from variables to an arbitrary type T optimised for fast access at the cost of memory.
Definition VariableMap.h:35
mapped_type At(const Variable var) const
Use the var to get the value it is mapped to, if it exists.
Definition VariableMap.h:84
bool Insert(const Id id, const T &value)
Insert a variable with the given id to the map and set it to the value.
VariableMap(const Items &items)
Construct a new variable map from a range of items.
Definition VariableMap.h:52
bool Contains(const Id id) const
Check if the variable with the given id is in the map.
bool Contains(const Variable &var) const
Check if the var is in the map.
Definition VariableMap.h:94
void Insert(const I &items)
Insert a range of key-value pairs to the map.
bool Remove(const Id id)
Remove a variable with the given id from the map.
bool empty() const
@checked{empty, variable map}
Definition VariableMap.h:67
std::vector< std::optional< T > > vars_
Vector tracking the value each variable is mapped to.
bool Remove(const Variable &var)
Remove a var from the map.
void Clear()
Clear the map of all variables.
bool Insert(const Variable &var, const mapped_type &value)
Insert a var to the map and set it to the value.
Id min_id_
Minimum id of the variables in the map.
void Remove(const V &vars)
Remove a range of vars from the map.
Real symbolic variable.
Definition Variable.h:20
Global namespace for the delpi library.