sigma  1.0.0
Loading...
Searching...
No Matches
affine.hpp
Go to the documentation of this file.
1#pragma once
2#include <memory>
3#include <optional>
5#include <sstream>
6#include <unordered_map>
7
11
12namespace sigma {
13
47template<typename ValueType>
48class Affine {
49public:
51 using size_type = std::size_t;
52
54 using value_t = ValueType;
55
57 using error_term_t = std::shared_ptr<size_type>;
58
60 using error_terms_t = std::unordered_map<error_term_t, value_t>;
61
64
65 // --- Constructors and Assignment ----------------------------------------
66
73 Affine() = default;
74
85
99 Affine(value_t lo, value_t hi) : Affine(interval_t(lo, hi)) {}
100
113 explicit Affine(const interval_t& interval) {
114 if(interval.empty()) { return; }
115 m_center_ = interval.median();
116 if(interval.radius() > 0) {
117 m_error_terms_[make_error_term()] = interval.radius();
118 }
119 }
120
134 m_center_(center), m_error_terms_(std::move(radii)) {}
135
143 Affine(const Affine& other) = default;
144
151 Affine(Affine&& other) noexcept = default;
152
162 Affine& operator=(const Affine& other) = default;
163
172 Affine& operator=(Affine&& other) noexcept = default;
173
174 // -- State Accessors -----------------------------------------------------
175
186
194 value_t center() const {
195 assert_not_empty_();
196 return *m_center_;
197 }
198
213 const error_terms_t& error_terms() const { return m_error_terms_; }
214
225
236 void set_center(value_t center) { m_center_ = center; }
237
252 if(empty()) set_center(value_t{0});
253 m_error_terms_[error_term] = radius;
254 }
255
268 bool contains(value_t value) const;
269
284 bool contains(const interval_t& interval) const;
285
299 bool contains(const Affine& affine) const {
300 return contains(affine.range());
301 }
302
313 bool empty() const noexcept { return !m_center_; }
314
327 std::string print_affine_form() const;
328
343 std::string print_interval_form() const {
344 return range().print_interval_form();
345 }
346
347 // -- Arithmetic Operators ------------------------------------------------
348
362
376 if(empty()) { return *this = Affine(value); }
377 (*m_center_) += value;
378 return *this;
379 }
380
398 Affine& operator+=(const Affine& other);
399
413 Affine operator+(value_t value) const { return Affine(*this) += value; }
414
428 Affine operator+(const Affine& other) const {
429 return Affine(*this) += other;
430 }
431
445 if(empty()) { return *this = Affine(-value); }
446 (*m_center_) -= value;
447 return *this;
448 }
449
467 Affine& operator-=(const Affine& other);
468
482 Affine operator-(value_t value) const { return Affine(*this) -= value; }
483
497 Affine operator-(const Affine& other) const {
498 return Affine(*this) -= other;
499 }
500
516 if(empty()) { return *this; }
517 (*m_center_) *= value;
518 for(auto&& [error_symbol, error_term_i] : m_error_terms_) {
519 error_term_i *= value;
520 }
521 return *this;
522 }
523
546 Affine& operator*=(const Affine& other);
547
561 Affine operator*(value_t value) const { return Affine(*this) *= value; }
562
576 Affine operator*(const Affine& other) const {
577 return Affine(*this) *= other;
578 }
579
596 if(value == 0) { throw std::domain_error("Division by zero"); }
597 return *this *= value_t(1.0 / value);
598 }
599
616 Affine& operator/=(const Affine& other);
617
630 Affine operator/(value_t value) const { return Affine(*this) /= value; }
631
647 Affine operator/(const Affine& other) const {
648 return Affine(*this) /= other;
649 }
650
674 value_t delta) const {
675 value_t new_center = empty() ? zeta : alpha * center() + zeta;
676 error_terms_t new_error_terms;
677 for(auto&& [error_symbol, error_term_i] : m_error_terms_) {
678 new_error_terms[error_symbol] = alpha * error_term_i;
679 }
680 new_error_terms[make_error_term()] = delta;
681 return Affine(new_center, std::move(new_error_terms));
682 }
683
708
709 // -- Comparison Operators ------------------------------------------------
710
726 bool operator==(const Affine& other) const {
727 if(empty() != other.empty()) { return false; }
728 if(empty()) { return true; }
729 if(m_center_ != other.m_center_) { return false; }
730 return m_error_terms_ == other.m_error_terms_;
731 }
732
748 bool operator!=(const Affine& other) const { return !(*this == other); }
749
750private:
752 void assert_not_empty_() const {
753 if(empty()) { throw std::domain_error("Affine form is empty"); }
754 }
755
758 // could switch to a hash or uuid.
759 error_term_t make_error_term() const {
760 return std::make_shared<size_type>(m_error_terms_.size());
761 }
762
765 std::optional<value_t> m_center_;
766
769 error_terms_t m_error_terms_;
770};
771
772// -- Non-member functions
773// ---------------------------------------------------
774
791template<typename ValueType>
792std::ostream& operator<<(std::ostream& os, const Affine<ValueType>& a) {
793 os << a.range();
794 return os;
795}
796
815template<typename ValueType>
817 return a * value;
818}
819
820// -- Out-of-line definitions
821// ------------------------------------------------
822
823template<typename ValueType>
825 if(empty()) { return interval_t(); }
826 auto r = radius();
827 return interval_t(center() - r, center() + r);
828}
829
830template<typename ValueType>
832 assert_not_empty_();
833 value_t r = 0;
834 for(auto&& [error_symbol, error_term_i] : m_error_terms_) {
835 r += std::fabs(error_term_i);
836 }
837 return r;
838}
839
840template<typename ValueType>
841auto Affine<ValueType>::contains(value_t value) const -> bool {
842 if(empty()) { return false; }
843 return range().contains(value);
844}
845
846template<typename ValueType>
847auto Affine<ValueType>::contains(const interval_t& interval) const -> bool {
848 if(interval.empty()) { return true; }
849 if(empty()) { return false; }
850 return range().contains(interval);
851}
852
853template<typename ValueType>
855 if(empty()) { return "∅"; }
856 std::stringstream ss;
857 ss << center();
858 for(auto&& [error_symbol, error_term_i] : m_error_terms_) {
859 ss << " +/- " << error_term_i;
860 }
861 return ss.str();
862}
863
864template<typename ValueType>
866 if(empty()) { return *this; }
867 value_t new_center = -center();
868 error_terms_t new_error_terms;
869 for(auto&& [error_symbol, error_term_i] : m_error_terms_) {
870 new_error_terms[error_symbol] = -error_term_i;
871 }
872 return Affine(new_center, new_error_terms);
873}
874
875template<typename ValueType>
877 if(empty()) { return *this = other; }
878 if(other.empty()) { return *this; }
879 value_t new_center = center() + other.center();
880 error_terms_t new_error_terms = m_error_terms_;
881 for(auto&& [error_symbol, error_term_i] : other.m_error_terms_) {
882 new_error_terms[error_symbol] += error_term_i;
883 }
884 return *this = Affine(new_center, new_error_terms);
885}
886
887template<typename ValueType>
889 return *this += -other;
890}
891
892template<typename ValueType>
894 if(empty() || other.empty()) { return *this = Affine(); }
895 value_t new_center = center() * other.center();
896 error_terms_t new_error_terms;
897 value_t new_radius = 0;
898 for(auto&& [error_symbol, error_term_i] : m_error_terms_) {
899 new_error_terms[error_symbol] = error_term_i * other.center();
900 new_radius += std::fabs(new_error_terms[error_symbol]);
901 }
902 for(auto&& [error_symbol, error_term_j] : other.m_error_terms_) {
903 new_error_terms[error_symbol] += error_term_j * center();
904 new_radius += std::fabs(new_error_terms[error_symbol]);
905 }
906 auto correction = radius() * other.radius();
907 new_error_terms[make_error_term()] = correction;
908 return *this = Affine(new_center, new_error_terms);
909}
910
911template<typename ValueType>
913 // Multiply by this by 1 / other
914 return *this *= other.multiplicative_inverse();
915}
916
917template<typename ValueType>
919 assert_not_empty_();
920 if(contains(0)) { throw std::domain_error("Division by zero"); }
921 // Compute the affine transformation which transforms other to 1 / other
922 auto other_range = range();
923 auto abs_inf = std::fabs(other_range.lower());
924 auto abs_sup = std::fabs(other_range.upper());
925 auto a = std::min(abs_inf, abs_sup);
926 auto b = std::max(abs_inf, abs_sup);
927 auto alpha = value_t(-1.0) / (b * b);
928 auto lo = value_t(1.0) / a - alpha * a;
929 auto hi = value_t(2.0) / b;
930 interval_t interval(std::min(lo, hi), std::max(lo, hi));
931 auto zeta = std::fabs(interval.median());
932 auto delta = interval.radius();
933 return apply_affine_transform(alpha, zeta, delta);
934}
935
938
941
942} // namespace sigma
943
Components for compatibility with Eigen.
Convenience header for affine form operations.
Implements affine arithmetic.
Definition affine.hpp:48
Affine operator+(const Affine &other) const
Returns the sum of *this and other.
Definition affine.hpp:428
Affine & operator/=(value_t value)
Overwrites *this with the quotient of *this and value.
Definition affine.hpp:595
Affine & operator-=(value_t value)
Overwrites *this with the difference of *this and value.
Definition affine.hpp:444
bool contains(const Affine &affine) const
Checks if affine is contained within *this.
Definition affine.hpp:299
Affine< ValueType > operator*(ValueType value, const Affine< ValueType > &a)
Multiplies a scalar by an affine form.
Definition affine.hpp:816
Affine & operator-=(const Affine &other)
Overwrites *this with the difference of *this and other.
Definition affine.hpp:888
Affine & operator+=(value_t value)
Overwrites *this with the sum of *this and value.
Definition affine.hpp:375
Affine(value_t center, error_terms_t radii)
Construct an affine form from a center value and a map of errors.
Definition affine.hpp:133
bool operator==(const Affine &other) const
Checks if *this and other represent the same affine form.
Definition affine.hpp:726
Affine operator+(value_t value) const
Returns the sum of *this and value.
Definition affine.hpp:413
Affine apply_affine_transform(value_t alpha, value_t zeta, value_t delta) const
Applies an affine transformation to *this.
Definition affine.hpp:673
Affine operator/(value_t value) const
Returns the quotient of *this and value.
Definition affine.hpp:630
bool contains(const interval_t &interval) const
Checks if interval is contained within *this.
Definition affine.hpp:847
Affine()=default
Constructs an empty affine form.
ValueType value_t
Type used for storing floating point values.
Definition affine.hpp:54
Affine(Affine &&other) noexcept=default
Constructs an affine form by moving other.
std::unordered_map< error_term_t, value_t > error_terms_t
Type used to map error terms to their radii.
Definition affine.hpp:60
std::string print_interval_form() const
Creates a string of the interval form of *this.
Definition affine.hpp:343
Affine(value_t lo, value_t hi)
Constructs an affine form from a lower and upper bound.
Definition affine.hpp:99
const error_terms_t & error_terms() const
Returns the error terms of the affine form.
Definition affine.hpp:213
Affine multiplicative_inverse() const
Returns the multiplicative inverse of *this.
Definition affine.hpp:918
Affine(value_t center)
Constructs an affine form from a center value.
Definition affine.hpp:84
std::string print_affine_form() const
Creates a string of the affine form of *this.
Definition affine.hpp:854
value_t center() const
Definition affine.hpp:194
Affine(const Affine &other)=default
Makes a deep copy of other.
Affine operator-(value_t value) const
Returns the difference of *this and value.
Definition affine.hpp:482
void set_center(value_t center)
Sets the center of the affine form.
Definition affine.hpp:236
Interval< value_t > interval_t
Type of an interval.
Definition affine.hpp:63
Affine operator*(const Affine &other) const
Returns the product of *this and other.
Definition affine.hpp:576
Affine & operator*=(value_t value)
Overwrites *this with the product of *this and value.
Definition affine.hpp:515
bool operator!=(const Affine &other) const
Checks if *this and other represent different affine forms.
Definition affine.hpp:748
Affine & operator*=(const Affine &other)
Overwrites *this with the product of *this and other.
Definition affine.hpp:893
Affine & operator=(Affine &&other) noexcept=default
Moves the value of other to this affine form.
std::size_t size_type
Type used for indexing and offsets.
Definition affine.hpp:51
Affine operator-(const Affine &other) const
Returns the difference of *this and other.
Definition affine.hpp:497
void add_error_term(error_term_t error_term, value_t radius)
Adds an error term to the affine form.
Definition affine.hpp:251
Affine operator*(value_t value) const
Returns the product of *this and value.
Definition affine.hpp:561
bool empty() const noexcept
Checks if this affine form is representing an empty interval.
Definition affine.hpp:313
std::ostream & operator<<(std::ostream &os, const Affine< ValueType > &a)
Outputs the range of an affine form to an output stream.
Definition affine.hpp:792
std::shared_ptr< size_type > error_term_t
Opaque type used to store error term information.
Definition affine.hpp:57
Affine & operator/=(const Affine &other)
Overwrites *this with the quotient of *this and other.
Definition affine.hpp:912
interval_t range() const
Returns the interval represented by the affine form.
Definition affine.hpp:824
bool contains(value_t value) const
Checks if the interval represented by *this contains value.
Definition affine.hpp:841
Affine operator/(const Affine &other) const
Returns the quotient of *this and other.
Definition affine.hpp:647
Affine & operator+=(const Affine &other)
Overwrites *this with the sum of *this and other.
Definition affine.hpp:876
Affine(const interval_t &interval)
Constructs an affine form from an interval.
Definition affine.hpp:113
Affine operator-() const
Returns the additive inverse of *this.
Definition affine.hpp:865
Affine & operator=(const Affine &other)=default
Assigns the value of other to this affine form.
value_t radius() const
Returns the radius of the affine form.
Definition affine.hpp:831
Models a numeric interval.
Definition interval.hpp:23
value_t median() const
Returns the midpoint of the interval.
Definition interval.hpp:82
std::string print_interval_form() const
Print the interval in interval form.
Definition interval.hpp:604
value_t radius() const
Returns the half-width of the interval.
Definition interval.hpp:96
bool empty() const
Is *this the empty interval?
Definition interval.hpp:106
Defines the Interval class.
The primary namespace for the sigma library.
Definition affine.hpp:12
Affine< double > ADouble
Typedef for an affine form of doubles.
Definition affine.hpp:940
Affine< float > AFloat
Typedef for an affine form of floats.
Definition affine.hpp:937