Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
al-vector.H
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
31
43# ifndef AL_VECTOR
44# define AL_VECTOR
45
46# include <memory>
47# include <sstream>
48# include <iostream>
49# include <string>
50# include <ah-errors.H>
51# include <ahFunctional.H>
52# include <ahDry.H>
53# include <ah-dry-mixin.H>
54# include <ahSort.H>
55# include <htlist.H>
56# include <ah-zip.H>
57# include <tpl_hash.H>
58# include <al-domain.H>
59
60namespace Aleph
61{
62 template <typename Trow, typename Tcol, typename NumType>
63 class Matrix;
64
80 template <typename T = int, typename NumType = double>
81 class Vector; // Forward declaration for CRTP
82
83 template <typename T, typename NumType>
84 class Vector : public TraverseMixin<Vector<T, NumType>, std::pair<T, NumType>>,
85 public LocateMixin<Vector<T, NumType>, std::pair<T, NumType>>,
86 public FunctionalMixin<Vector<T, NumType>, std::pair<T, NumType>>
87 {
88 public:
90 using DomainPtr = std::shared_ptr<Domain>;
92 using Item_Type = std::pair<T, NumType>; // Required by mixins
93
94 private:
96
100
101 static NumType abs(const NumType & val) noexcept
102 {
103 return val < 0 ? -val : val;
104 }
105
106 bool is_zero(const NumType & val) const noexcept
107 {
108 assert(epsilon >= 0);
109 return abs(val) <= epsilon;
110 }
111
112 static bool test_epsilon(const NumType & e) noexcept { return e >= 0; }
113
114 public:
120
126 void set_epsilon(const NumType & e) noexcept
127 {
128 epsilon = e;
129 }
130
131 using Pair = std::pair<T, NumType>;
132
138
141
149 {
150 //Empty
151 }
152
161 {
162 //Empty
163 }
164
169 Vector(const Vector & v)
171 {
172 // empty
173 }
174
180 : domain_ptr(v.domain_ptr), epsilon(v.epsilon),
181 entries(std::forward<Map>(v.entries))
182 {
183 // empty
184 }
185
194 const NumType & zero = default_epsilon)
196 {
197 ah_length_error_if(l.size() != domain_ptr->size())
198 << "Vector(DynList): list sizes does not match";
199
200 for (auto it = zip_it(domain_ptr->keys(), l); it.has_curr(); it.next_ne())
201 {
202 auto t = it.get_curr();
203 set_entry(get<0>(t), get<1>(t));
204 }
205 }
206
215 Vector(const Domain & d, const DynList<NumType> & l,
216 const NumType & zero = default_epsilon)
217 : Vector(DomainPtr(&const_cast<Domain &>(d), [](Domain *) {}), l, zero)
218 {}
219
228 {
229 if (this == &v)
230 return *this;
231
233 << "Vector assignment: domains must be the same";
234
235 epsilon = v.epsilon;
236 entries = v.entries;
237
238 return *this;
239 }
240
249 {
250 if (this == &v)
251 return *this;
252
253 ah_domain_error_if(domain_ptr.get() != v.domain_ptr.get())
254 << "Vector assignment: domains must be the same";
255
256 epsilon = v.epsilon;
257 entries.swap(v.entries);
258
259 return *this;
260 }
261
268 void set_entry(const T & i, const NumType & value)
269 {
270 assert(domain_ptr->has(i));
271
272 auto *ptr = const_cast<Pair *>(entries.search(i));
273 if (is_zero(value))
274 {
275 if (ptr != nullptr)
276 entries.remove_ptr(ptr);
277 return;
278 }
279
280 if (ptr == nullptr)
281 entries.insert(i, value);
282 else
283 ptr->second = value;
284 }
285
293 void set_entries(std::initializer_list<T> ld,
294 std::initializer_list<NumType> lr)
295 {
296 ah_range_error_if(ld.size() != lr.size())
297 << "size mismatch between domain and range";
298
299 auto itd = ld.begin();
300 auto itr = lr.begin();
301 for (; itd != ld.end(); ++itd, ++itr)
302 {
304 << "An item of first list doesn't belong to domain";
305 set_entry(*itd, *itr);
306 }
307 }
308
317 template <template <typename> class Container = DynList>
318 void set_entries(const Container<T> & c, std::initializer_list<NumType> lr)
319 {
320 ah_range_error_if(c.size() != lr.size())
321 << "size mismatch between domain and range";
322
323 auto itr = lr.begin();
324 c.for_each([this, &itr](const T & key)
325 {
327 << "Key does not belong to domain";
328
329 set_entry(key, *itr++);
330 });
331 }
332
340 NumType get_entry(const T & i)
341 {
342 assert(domain_ptr->has(i));
343
344 auto *ptr = entries.search(i);
345 if (ptr == nullptr)
346 return 0;
347
348 if (is_zero(ptr->second))
349 {
350 entries.remove_ptr(ptr);
351 return 0;
352 }
353
354 return ptr->second;
355 }
356
362 NumType get_entry(const T & i) const noexcept
363 {
364 assert(domain_ptr->has(i));
365
366 auto *ptr = entries.search(i);
367 if (ptr == nullptr)
368 return 0;
369
370 return ptr->second;
371 }
372
378 NumType * search_entry(const T & i) const noexcept
379 {
380 assert(domain_ptr->has(i));
381
382 auto *ptr = entries.search(i);
383 if (ptr == nullptr)
384 return nullptr;
385
386 return &ptr->second;
387 }
388
395 bool are_equal(const NumType & n1, const NumType & n2) const noexcept
396 {
397 return is_zero(n1 - n2);
398 }
399
405 bool equal_to(const Vector & other) const noexcept
406 {
407 assert(domain_ptr == other.domain_ptr);
408
409 return entries.all([&other, this](const Pair & p)
410 {
411 return are_equal(other.get_entry(p.first), p.second);
412 }) and
413 other.entries.all([this](const Pair & p)
414 {
415 return are_equal(get_entry(p.first), p.second);
416 });
417 }
418
419 bool operator ==(const Vector & v) const noexcept { return equal_to(v); }
420
421 bool operator !=(const Vector & v) const noexcept
422 {
423 return not equal_to(v);
424 }
425
427 {
429
430 v.entries.for_each([this](const Pair & p)
431 {
432 set_entry(p.first, get_entry(p.first) + p.second);
433 });
434 return *this;
435 }
436
438 {
440
441 v.entries.for_each([this](const Pair & p)
442 {
443 set_entry(p.first, get_entry(p.first) - p.second);
444 });
445 return *this;
446 }
447
448 Vector operator +(const Vector & r) const
449 {
450 Vector ret_val = *this;
451 ret_val += r;
452 return ret_val;
453 }
454
455 Vector operator -(const Vector & r) const
456 {
457 Vector ret_val = *this;
458 ret_val -= r;
459 return ret_val;
460 }
461
463 {
464 if (is_zero(scalar))
465 {
466 entries = Map(); // Clear by assigning empty map
467 return *this;
468 }
469
470 if (scalar == 1)
471 return *this;
472
473 entries.for_each([&scalar](const Pair & p)
474 {
475 const_cast<Pair &>(p).second *= scalar;
476 });
477 return *this;
478 }
479
481 {
482 Vector ret_val = *this;
484 }
485
487 {
489 << "Zero division";
490
491 if (scalar == 1)
492 return *this;
493
494 entries.for_each([&scalar](const Pair & p)
495 {
496 const_cast<Pair &>(p).second /= scalar;
497 });
498 return *this;
499 }
500
502 {
503 Vector ret_val = *this;
505 }
506
507 // negation
509 {
510 Vector ret_val = *this;
511 return ret_val.product_by_scalar(-1.0);
512 }
513
515 {
517 << "scalar_product: different domains";
518
519 if (entries.size() < v.entries.size())
520 return entries.
521 template foldl<NumType>(0, [&v](const NumType & acc, const Pair & p)
522 {
523 return acc + p.second * v.get_entry(p.first);
524 });
525
526 return v.entries.
527 template foldl<NumType>(0, [this](const NumType & acc, const Pair & p)
528 {
529 return acc + get_entry(p.first) * p.second;
530 });
531 }
532
533 NumType operator *(const Vector & v) const
534 {
535 return scalar_product(v);
536 }
537
539 {
540 return sort(domain_ptr->template maps<NumType>([this](const T & i)
541 {
542 return get_entry(i);
543 }));
544 }
545
546 void print() const
547 {
548 domain_ptr->for_each([&](const T & k)
549 {
550 if (entries.has(k) != 0)
551 std::cout << "(" << k << "," << entries(k) << ") ";
552 });
553 std::cout << '\n';
554 }
555
556 [[nodiscard]] std::string to_str() const
557 {
558 // Convert domain elements to strings
560 domain_ptr->keys().template maps<std::string>([](const T & k)
561 {
562 std::ostringstream s;
563 s << k;
564 return s.str();
565 });
566
567 // Convert range elements to strings
569 domain_ptr->keys().template maps<std::string>([this](const T & d)
570 {
571 return std::to_string(get_entry(d));
572 });
573
574 typedef std::pair<std::string, std::string> Pair;
576
577 const DynList<Pair> format = pairs.
578 template maps<Pair>([](const Pair & p)
579 {
580 const size_t fsz = p.first.size();
581 const size_t ssz = p.second.size();
582 if (fsz > ssz)
583 return Pair(" " + p.first, std::string(fsz - ssz + 1, ' ') + p.second);
584 return Pair(std::string(ssz - fsz + 1, ' ') + p.first, " " + p.second);
585 });
586
587 std::pair<DynList<std::string>, DynList<std::string>> ret = unzip(format);
588
589 auto concatenate = [](const std::string & s1, const std::string & s2)
590 {
591 return s1 + s2;
592 };
593
594 const std::string dstr = ret.first.template foldl<std::string>("", concatenate);
595
596 const std::string estr = ret.second.template foldl<std::string>("", concatenate);
597
598 return dstr + "\n" + std::string(dstr.size(), '-') + "\n" + estr;
599 }
600
601 class Proxy
602 {
603 Vector *v_ptr = nullptr;
604 T *key_ptr = nullptr;
605 NumType *entry_ptr = nullptr;
606
607 public:
608 Proxy(Vector & v, const T & k) noexcept
609 : v_ptr(&v), key_ptr(&const_cast<T &>(k))
610 {
611 auto *ptr = v_ptr->entries.search(k);
612 entry_ptr = ptr ? &ptr->second : nullptr;
613 }
614
616 {
617 if (this == &proxy)
618 return *this; // self-assignment
619
620 if (proxy.entry_ptr == nullptr)
621 return *this; // zero assigment
622
623 if (entry_ptr == nullptr)
624 v_ptr->entries.insert(*key_ptr, *proxy.entry_ptr);
625 else
626 *entry_ptr = *proxy.entry_ptr;
627
628 return *this;
629 }
630
631 Proxy &operator =(const NumType & item)
632 {
633 if (v_ptr->is_zero(item))
634 {
635 try { v_ptr->entries.remove(key_ptr); }
636 catch (...) { /* Key not found, already zero */ }
637 return *this;
638 }
639
640 if (entry_ptr == nullptr)
641 v_ptr->entries.insert(*key_ptr, item);
642 else
643 *entry_ptr = item;
644
645 return *this;
646 }
647
649 {
650 if (v_ptr->is_zero(item))
651 {
652 try { v_ptr->entries.remove(*key_ptr); }
653 catch (...) { /* Key not found, already zero */ }
654 return *this;
655 }
656
657 if (entry_ptr == nullptr)
658 v_ptr->entries.insert(*key_ptr, std::forward<NumType>(item));
659 else
660 std::swap(*entry_ptr, item);
661
662 return *this;
663 }
664
665 operator NumType() noexcept
666 {
667 if (entry_ptr == nullptr)
668 return 0;
669
670 return *entry_ptr;
671 }
672 };
673
674 Proxy operator [](const T & k) const noexcept
675 {
676 return Proxy(*this, k);
677 }
678
679 Proxy operator [](const T & k) noexcept
680 {
681 return Proxy(*this, k);
682 }
683
684 Proxy operator ()(const T & k) const noexcept
685 {
686 return Proxy(*this, k);
687 }
688
689 Proxy operator ()(const T & k) noexcept
690 {
691 return Proxy(*this, k);
692 }
693
694 struct Iterator : public Map::Iterator
695 {
697 };
698
700 Iterator get_it() const noexcept { return Iterator(*this); }
701
702 // Note: traverse(), for_each(), all(), exists(), maps(), filter(),
703 // foldl(), fold(), partition(), take(), drop(), rev(), length(),
704 // nth(), nth_ne(), find_ptr(), find_item() are now provided
705 // by the CRTP mixins: TraverseMixin, FunctionalMixin, LocateMixin
706 };
707
708 template <typename T, typename NumType>
710
711
712 template <typename T, typename NumType>
713 inline
715 const Vector<T, NumType> & v)
716 {
718 return ret_val.product_by_scalar(scalar);
719 }
720
721 template <typename T, typename NumType>
722 inline
723 std::ostream &operator <<(std::ostream & s, const Vector<T, NumType> & vec)
724 {
725 return s << vec.to_str();
726 }
727} // end namespace Aleph
728
729# endif // AL_VECTOR
CRTP Mixins for container functionality (DRY principle).
Exception handling system with formatted messages for Aleph-w.
#define ah_length_error_if(C)
Throws std::length_error if condition holds.
Definition ah-errors.H:698
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:522
#define ah_range_error_if(C)
Throws std::range_error if condition holds.
Definition ah-errors.H:207
Zip iterators and functional operations for multiple containers.
DRY (Don't Repeat Yourself) utilities and macros.
Functional programming utilities for Aleph-w containers.
High-level sorting functions for Aleph containers.
Integer domain classes for sparse data structures.
Generic domain class based on hash set.
Definition al-domain.H:85
Dynamic singly linked list with functional programming support.
Definition htlist.H:1423
CRTP Mixin providing functional programming operations.
Container< __Type > maps(Operation &operation) const
Transform elements using a mapping function.
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1319
CRTP Mixin providing element location operations.
Sparse matrix with generic row and column domains.
Definition al-matrix.H:66
CRTP Mixin providing traversal operations.
Proxy(Vector &v, const T &k) noexcept
Definition al-vector.H:608
Proxy & operator=(const Proxy &proxy)
Definition al-vector.H:615
Sparse vector implementation with domain-based indexing.
Definition al-vector.H:87
Vector(DomainPtr d, const NumType &zero=default_epsilon)
Construct a vector over a given domain (shared_ptr version)
Definition al-vector.H:147
Vector(const Domain &d, const DynList< NumType > &l, const NumType &zero=default_epsilon)
Construct vector from domain and list of values (reference version)
Definition al-vector.H:215
Vector operator-() const
Definition al-vector.H:508
std::pair< T, NumType > Item_Type
Definition al-vector.H:92
const Domain & get_domain() const noexcept
Get the domain over which this vector is defined.
Definition al-vector.H:137
std::pair< T, NumType > Pair
Definition al-vector.H:131
void set_entry(const T &i, const NumType &value)
Set a vector entry at given index.
Definition al-vector.H:268
bool equal_to(const Vector &other) const noexcept
Check if this vector equals another within epsilon tolerance.
Definition al-vector.H:405
const NumType & get_epsilon() const noexcept
Get the epsilon value used for zero comparisons.
Definition al-vector.H:119
Vector(const Domain &d, const NumType &zero=default_epsilon)
Construct a vector over a given domain (reference version)
Definition al-vector.H:159
Vector & operator=(const Vector &v)
Copy assignment operator.
Definition al-vector.H:227
Iterator get_it() const noexcept
Definition al-vector.H:700
NumType * search_entry(const T &i) const noexcept
Search for an entry and return pointer to its value.
Definition al-vector.H:378
Vector(const Vector &v)
Copy constructor.
Definition al-vector.H:169
Vector operator+(const Vector &r) const
Definition al-vector.H:448
static NumType abs(const NumType &val) noexcept
Definition al-vector.H:101
bool operator==(const Vector &v) const noexcept
Definition al-vector.H:419
bool are_equal(const NumType &n1, const NumType &n2) const noexcept
Check if two numeric values are equal within epsilon.
Definition al-vector.H:395
DynList< NumType > to_list() const
Definition al-vector.H:538
bool is_zero(const NumType &val) const noexcept
Definition al-vector.H:106
static bool test_epsilon(const NumType &e) noexcept
Definition al-vector.H:112
void print() const
Definition al-vector.H:546
void set_entries(const Container< T > &c, std::initializer_list< NumType > lr)
Set multiple entries using container and initializer list.
Definition al-vector.H:318
NumType get_entry(const T &i) const noexcept
Get vector entry at given index (const version)
Definition al-vector.H:362
void set_epsilon(const NumType &e) noexcept
Set the epsilon value for zero comparisons.
Definition al-vector.H:126
static const NumType default_epsilon
Definition al-vector.H:95
Proxy operator()(const T &k) const noexcept
Definition al-vector.H:684
Vector(Vector &&v) noexcept
Move constructor.
Definition al-vector.H:179
std::shared_ptr< Domain > DomainPtr
Definition al-vector.H:90
Vector(DomainPtr d, const DynList< NumType > &l, const NumType &zero=default_epsilon)
Construct vector from domain and list of values (shared_ptr version)
Definition al-vector.H:193
Proxy operator[](const T &k) const noexcept
Definition al-vector.H:674
NumType get_entry(const T &i)
Get vector entry at given index (non-const version)
Definition al-vector.H:340
void set_entries(std::initializer_list< T > ld, std::initializer_list< NumType > lr)
Set multiple entries using initializer lists.
Definition al-vector.H:293
const DomainPtr & get_domain_ptr() const noexcept
Return the shared pointer to the domain.
Definition al-vector.H:140
NumType epsilon
Definition al-vector.H:98
std::string to_str() const
Definition al-vector.H:556
Vector operator/(const NumType &scalar) const
Definition al-vector.H:501
NumType scalar_product(const Vector &v) const
Definition al-vector.H:514
Vector & operator+=(const Vector &v)
Definition al-vector.H:426
DomainPtr domain_ptr
Definition al-vector.H:97
Vector & divide_by_scalar(const NumType &scalar)
Definition al-vector.H:486
Vector & product_by_scalar(const NumType &scalar) noexcept
Definition al-vector.H:462
Vector & operator-=(const Vector &v)
Definition al-vector.H:437
Iterator get_itor() const noexcept
Definition al-vector.H:699
Aleph::HashMap< T, NumType, MapODhash > Map
Definition al-vector.H:91
Vector operator*(const NumType &scalar) const
Definition al-vector.H:480
bool operator!=(const Vector &v) const noexcept
Definition al-vector.H:421
Singly linked list implementations with head-tail access.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
auto unzip(const Container &l)
Separate a list of pairs into two lists.
DynList< std::pair< typename Container1::Item_Type, typename Container2::Item_Type > > zip(const Container1 &a, const Container2 &b)
Zip two containers into a list of pairs.
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:107
DynArray< T > sort(const DynArray< T > &a, Cmp &&cmp=Cmp())
Returns a sorted copy of a DynArray.
Definition ahSort.H:227
Matrix< Trow, Tcol, NumType > operator*(const NumType &scalar, const Matrix< Trow, Tcol, NumType > &m)
Scalar-matrix multiplication (scalar * matrix).
Definition al-matrix.H:995
std::ostream & operator<<(std::ostream &osObject, const Field< T > &rightOp)
Definition ahField.H:121
ZipIterator< Cs... > zip_it(const Cs &... cs)
Alias for get_zip_it.
Definition ah-zip.H:275
DynList< T > maps(const C &c, Op op)
Classic map operation.
STL namespace.
Iterator(const Vector &vec)
Definition al-vector.H:696
Aleph::DynList< T > keys() const
Definition ah-dry.H:1516
Unified hash table interface.
DynList< int > l