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;
87 SparseVector(
const IndexT& t_index,
const ValueT& t_value) : m_map({ { t_index, t_value} }) {
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);
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 void reserve(
unsigned int t_capacity) {
125 m_map.reserve(t_capacity);
129 using iterator =
typename map_t::iterator;
130 using const_iterator =
typename map_t::const_iterator;
132 [[nodiscard]] iterator begin() {
return m_map.begin(); }
134 [[nodiscard]] iterator end() {
return m_map.end(); }
136 [[nodiscard]] const_iterator begin()
const {
return m_map.cbegin(); }
138 [[nodiscard]] const_iterator end()
const {
return m_map.cend(); }
140 [[nodiscard]] const_iterator cbegin()
const {
return m_map.cbegin(); }
142 [[nodiscard]] const_iterator cend()
const {
return m_map.cend(); }
149template<
class IndexT,
class ValueT>
154 for (
const auto& [var, val] : m_map) {
155 result.m_map.emplace(var, -val);
161template<
class IndexT,
class ValueT>
165 std::vector<IndexT> to_be_removed;
166 to_be_removed.reserve(m_map.size());
168 for (
auto it = m_map.begin(), end = m_map.end() ; it != end ; ++it) {
169 IDOL_REF_VALUE(it) /= t_scalar;
170 if (::idol::is_zero(it->second, Tolerance::Sparsity)) {
171 to_be_removed.emplace_back(it->first);
175 for (
const auto& index : to_be_removed) {
182template<
class IndexT,
class ValueT>
186 if (
this == &t_vector) {
191 for (
const auto& [var, val] : t_vector.m_map) {
194 auto [it, inserted] = m_map.emplace(var, minus_val);
196 IDOL_REF_VALUE(it) += std::move(minus_val);
197 if (::idol::is_zero(it->second, Tolerance::Sparsity)) {
206template<
class IndexT,
class ValueT>
210 std::vector<IndexT> to_be_removed;
211 to_be_removed.reserve(m_map.size());
213 for (
auto it = m_map.begin(), end = m_map.end() ; it != end ; ++it) {
214 IDOL_REF_VALUE(it) *= t_scalar;
215 if (::idol::is_zero(it->second, Tolerance::Sparsity)) {
216 to_be_removed.emplace_back(it->first);
220 for (
const auto& index : to_be_removed) {
227template<
class IndexT,
class ValueT>
229 for (
const auto& [var, val] : m_map) {
230 if (!::idol::is_zero(val, t_tolerance)) {
237template<
class IndexT,
class ValueT>
241 if (
this == &t_vector) {
242 return operator*=(2.);
245 for (
const auto& [var, val] : t_vector.m_map) {
246 auto [it, inserted] = m_map.emplace(var, val);
248 IDOL_REF_VALUE(it) += val;
249 if (::idol::is_zero(it->second, Tolerance::Sparsity)) {
258template<
class IndexT,
class ValueT>
262 for (
const auto& [var, val] : t_vec.m_map) {
263 auto [it, inserted] = m_map.emplace(var, val);
265 throw Exception(
"Found conflict when explicitly merging without conflict.");
272template<
class IndexT,
class ValueT>
275 const auto it = m_map.find(t_index1);
277 if (it == m_map.end()) {
284template<
class IndexT,
class ValueT>
287 if (::idol::is_zero(t_value, Tolerance::Sparsity)) {
292 auto [it, inserted] = m_map.emplace(t_index, t_value);
295 IDOL_REF_VALUE(it) = t_value;
302 template<
class IndexT,
class ValueT>
305 for (
const auto& [index, value] : t_vector) {
306 t_stream << index <<
": " << value <<
'\n';
312 template<
class IndexT,
class ValueT>
313 SparseVector<IndexT, ValueT> operator+(SparseVector<IndexT, ValueT>&& t_x,
const SparseVector<IndexT, ValueT>& t_y) {
314 return std::move(t_x) += t_y;
317 template<
class IndexT,
class ValueT>
318 SparseVector<IndexT, ValueT> operator+(
const SparseVector<IndexT, ValueT>& t_x, SparseVector<IndexT, ValueT>&& t_y) {
319 return std::move(t_y) += t_x;
322 template<
class IndexT,
class ValueT>
323 SparseVector<IndexT, ValueT> operator+(
const SparseVector<IndexT, ValueT>& t_x,
const SparseVector<IndexT, ValueT>& t_y) {
324 return SparseVector(t_x) += t_y;
327 template<
class IndexT,
class ValueT>
328 SparseVector<IndexT, ValueT> operator-(SparseVector<IndexT, ValueT> t_x,
const SparseVector<IndexT, ValueT>& t_y) {
329 return std::move(t_x) -= t_y;
332 template<
class IndexT,
class ValueT>
333 SparseVector<IndexT, ValueT> operator+(SparseVector<IndexT, ValueT> t_x,
double t_factor) {
334 return std::move(t_x) *= t_factor;
337 template<
class IndexT,
class ValueT>
338 SparseVector<IndexT, ValueT> operator+(
double t_factor, SparseVector<IndexT, ValueT> t_x) {
339 return std::move(t_x) *= t_factor;