5#ifndef IDOL_SPARSEVECTOR_H
6#define IDOL_SPARSEVECTOR_H
9#include "idol/general/utils/exceptions/Exception.h"
10#include "idol/general/numericals.h"
11#include <idol/mixed-integer/modeling/variables/Var.h>
12#include <idol/general/utils/Map.h>
22 auto operator()(
const T& t_obj)
const {
return std::hash<unsigned int>()(t_obj.id()); }
26 struct equal_to_object {
27 auto operator()(
const T& t_a,
const T& t_b)
const {
return t_a.
id() == t_b.id(); }
32 auto operator()(
const T& t_a,
const T& t_b)
const {
return t_a.id() < t_b.id(); }
38template<>
struct std::hash<idol::Var> :
public idol::impl::hash_object<idol::Var> {};
39template<>
struct std::equal_to<idol::Var> :
public idol::impl::equal_to_object<idol::Var> {};
40template<>
struct std::less<idol::Var> :
public idol::impl::less_object<idol::Var> {};
42template<>
struct std::hash<idol::Ctr> :
public idol::impl::hash_object<idol::Ctr> {};
43template<>
struct std::equal_to<idol::Ctr> :
public idol::impl::equal_to_object<idol::Ctr> {};
44template<>
struct std::less<idol::Ctr> :
public idol::impl::less_object<idol::Ctr> {};
47 template<
class,
class>
52#include <tsl/sparse_map.h>
53#include <tsl/ordered_map.h>
54#define IDOL_REF_VALUE(t_iterator) t_iterator.value()
56#ifdef IDOL_USE_ROBINHOOD
57#include <robin_hood.h>
58#define IDOL_REF_VALUE(t_iterator) t_iterator->second
61#define IDOL_REF_VALUE(t_iterator) t_iterator->second
65template<
class IndexT,
class ValueT>
69 using map_t = std::conditional_t<
71 tsl::sparse_map<IndexT, ValueT>,
72 tsl::ordered_map<IndexT, ValueT>
75 #ifdef IDOL_USE_ROBINHOOD
76 using map_t = robin_hood::unordered_map<IndexT, ValueT>;
78 using map_t = std::unordered_map<IndexT, ValueT>;
83 static ValueT s_zero_value;
85 SparseVector() =
default;
87 SparseVector(
const IndexT& t_index,
const ValueT& t_value) : m_map({ { t_index, t_value} }) {
93 SparseVector(
const SparseVector&) =
default;
94 SparseVector(SparseVector&&) =
default;
96 virtual ~SparseVector() =
default;
98 SparseVector& operator=(
const SparseVector&) =
default;
99 SparseVector& operator=(SparseVector&&)
noexcept =
default;
101 virtual SparseVector& operator+=(
const SparseVector& t_vector);
102 virtual SparseVector& operator-=(
const SparseVector& t_vector);
103 virtual SparseVector& operator*=(std::conditional_t<std::is_arithmetic_v<ValueT>, ValueT,
double> t_scalar);
104 virtual SparseVector& operator/=(std::conditional_t<std::is_arithmetic_v<ValueT>, ValueT,
double> t_scalar);
105 SparseVector operator-()
const;
107 [[nodiscard]]
unsigned int size()
const {
return m_map.size(); }
109 [[nodiscard]]
bool empty()
const {
return m_map.empty(); }
111 [[nodiscard]]
bool has_index(
const IndexT& t_index)
const {
return m_map.find(t_index) != m_map.end(); }
113 [[nodiscard]]
const ValueT& get(
const IndexT& t_index1)
const;
115 void set(
const IndexT& t_index,
const ValueT& t_value);
117 [[nodiscard]]
virtual bool is_zero(
double t_tolerance)
const;
119 void remove(
const IndexT& t_index) { m_map.erase(t_index); }
121 void clear() { m_map.clear(); }
123 std::pair<double, double> range()
const;
125 void reserve(
unsigned int t_capacity) {
127 m_map.reserve(t_capacity);
131 using iterator =
typename map_t::iterator;
132 using const_iterator =
typename map_t::const_iterator;
134 [[nodiscard]] iterator begin() {
return m_map.begin(); }
136 [[nodiscard]] iterator end() {
return m_map.end(); }
138 [[nodiscard]] const_iterator begin()
const {
return m_map.cbegin(); }
140 [[nodiscard]] const_iterator end()
const {
return m_map.cend(); }
142 [[nodiscard]] const_iterator cbegin()
const {
return m_map.cbegin(); }
144 [[nodiscard]] const_iterator cend()
const {
return m_map.cend(); }
146 SparseVector& merge_without_conflict(
const SparseVector& t_vec);
149template<
class IndexT,
class ValueT> ValueT idol::SparseVector<IndexT, ValueT>::s_zero_value {};
151template<
class IndexT,
class ValueT>
153idol::SparseVector<IndexT, ValueT>::operator-()
const {
156 for (
const auto& [var, val] : m_map) {
157 result.m_map.emplace(var, -val);
163template<
class IndexT,
class ValueT>
165idol::SparseVector<IndexT, ValueT>::operator/=(std::conditional_t<std::is_arithmetic_v<ValueT>, ValueT,
double> t_scalar) {
167 std::vector<IndexT> to_be_removed;
168 to_be_removed.reserve(m_map.size());
170 for (
auto it = m_map.begin(), end = m_map.end() ; it != end ; ++it) {
171 IDOL_REF_VALUE(it) /= t_scalar;
172 if (::idol::is_zero(it->second, Tolerance::Sparsity)) {
173 to_be_removed.emplace_back(it->first);
177 for (
const auto& index : to_be_removed) {
184template<
class IndexT,
class ValueT>
186idol::SparseVector<IndexT, ValueT>::operator-=(
const SparseVector &t_vector) {
188 if (
this == &t_vector) {
193 for (
const auto& [var, val] : t_vector.m_map) {
196 auto [it, inserted] = m_map.emplace(var, minus_val);
198 IDOL_REF_VALUE(it) += std::move(minus_val);
199 if (::idol::is_zero(it->second, Tolerance::Sparsity)) {
208template<
class IndexT,
class ValueT>
210idol::SparseVector<IndexT, ValueT>::operator*=(std::conditional_t<std::is_arithmetic_v<ValueT>, ValueT,
double> t_scalar) {
212 std::vector<IndexT> to_be_removed;
213 to_be_removed.reserve(m_map.size());
215 for (
auto it = m_map.begin(), end = m_map.end() ; it != end ; ++it) {
216 IDOL_REF_VALUE(it) *= t_scalar;
217 if (::idol::is_zero(it->second, Tolerance::Sparsity)) {
218 to_be_removed.emplace_back(it->first);
222 for (
const auto& index : to_be_removed) {
229template<
class IndexT,
class ValueT>
230bool idol::SparseVector<IndexT, ValueT>::is_zero(
double t_tolerance)
const {
231 for (
const auto& [var, val] : m_map) {
232 if (!::idol::is_zero(val, t_tolerance)) {
239template <
class IndexT,
class ValueT>
240std::pair<double, double> idol::SparseVector<IndexT, ValueT>::range()
const {
241 double min = Inf, max = -Inf;
242 for (
const auto& [var, val] : m_map) {
243 const double abs_val = std::abs(val);
244 min = std::min(min, abs_val);
245 max = std::max(max, abs_val);
247 return std::make_pair(min, max);
250template<
class IndexT,
class ValueT>
252idol::SparseVector<IndexT, ValueT>::operator+=(
const SparseVector &t_vector) {
254 if (
this == &t_vector) {
255 return operator*=(2.);
258 for (
const auto& [var, val] : t_vector.m_map) {
259 auto [it, inserted] = m_map.emplace(var, val);
261 IDOL_REF_VALUE(it) += val;
262 if (::idol::is_zero(it->second, Tolerance::Sparsity)) {
271template<
class IndexT,
class ValueT>
273idol::SparseVector<IndexT, ValueT>::merge_without_conflict(
const SparseVector &t_vec) {
275 for (
const auto& [var, val] : t_vec.m_map) {
276 auto [it, inserted] = m_map.emplace(var, val);
278 throw Exception(
"Found conflict when explicitly merging without conflict.");
285template<
class IndexT,
class ValueT>
286const ValueT& idol::SparseVector<IndexT, ValueT>::get(
const IndexT &t_index1)
const {
288 const auto it = m_map.find(t_index1);
290 if (it == m_map.end()) {
297template<
class IndexT,
class ValueT>
298void idol::SparseVector<IndexT, ValueT>::set(
const IndexT &t_index,
const ValueT &t_value) {
300 if (::idol::is_zero(t_value, Tolerance::Sparsity)) {
305 auto [it, inserted] = m_map.emplace(t_index, t_value);
308 IDOL_REF_VALUE(it) = t_value;
315 template<
class IndexT,
class ValueT>
316 static std::ostream & operator<<(std::ostream &t_stream,
const idol::SparseVector<IndexT, ValueT> &t_vector) {
318 for (
const auto& [index, value] : t_vector) {
319 t_stream << index <<
": " << value <<
'\n';
325 template<
class IndexT,
class ValueT>
327 return std::move(t_x) += t_y;
330 template<
class IndexT,
class ValueT>
332 return std::move(t_y) += t_x;
335 template<
class IndexT,
class ValueT>
340 template<
class IndexT,
class ValueT>
342 return std::move(t_x) -= t_y;
345 template<
class IndexT,
class ValueT>
347 return std::move(t_x) *= t_factor;
350 template<
class IndexT,
class ValueT>
352 return std::move(t_x) *= t_factor;