MeshLib C++ Docs
Loading...
Searching...
No Matches
MRSparsePolynomial.h
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4#include <cassert>
5#include <utility>
6#include <vector>
7
8namespace MR
9{
12
13
14template <typename C, typename D, D M>
16
18template <typename T, typename D, D M>
20
23template <typename T, typename C, typename D, D M>
25
27template <typename C, typename D, D M>
29
34template <typename T, typename C, typename D, D M>
35[[nodiscard]] int signOfProductsDiff( const SparsePolynomial<C,D,M>& a, const SparsePolynomial<C,D,M>& b,
36 const SparsePolynomial<C,D,M>& c, const SparsePolynomial<C,D,M>& d );
37
43template <typename C, typename D, D M>
45{
46 static_assert( M > 0 );
47public:
49 using Term = std::pair<D, C>;
50
52 SparsePolynomial() = default;
53
56 SparsePolynomial( std::vector<Term> && );
57
59 SparsePolynomial( C c0, D d1, C c1 );
60
62 SparsePolynomial( C c0, D d1, C c1, D d2, C c2 );
63
65 [[nodiscard]] static SparsePolynomial fromUnsortedTerms( std::vector<Term> && terms );
66
68 void setZeroCoeff( D d )
69 {
70 auto it = std::lower_bound( terms_.begin(), terms_.end(), d,
71 []( const Term & t, D d ) { return t.first < d; } );
72 if ( it != terms_.end() && it->first == d )
73 terms_.erase( it );
74 }
75
77 [[nodiscard]] bool empty() const { return terms_.empty(); }
78
80 [[nodiscard]] bool isPositive() const;
81
83 [[nodiscard]] const std::vector<Term> & get() const { return terms_; }
84
87 [[nodiscard]] friend SparsePolynomial operator +( SparsePolynomial a, const SparsePolynomial& b ) { a += b; return a; }
88 [[nodiscard]] friend SparsePolynomial operator -( SparsePolynomial a, const SparsePolynomial& b ) { a -= b; return a; }
89 template <typename T, typename C2, typename D2, D2 M2>
91
92private:
94 void mergeTerms_();
95
96 std::vector<Term> terms_;
97};
98
99template <typename C, typename D, D M>
100SparsePolynomial<C,D,M>::SparsePolynomial( std::vector<Term> && terms ) : terms_( std::move( terms ) )
101{
102#ifndef NDEBUG
103 for ( size_t i = 0; i < terms_.size(); ++i )
104 {
105 assert( terms_[i].first <= M );
106 assert( terms_[i].second != 0 );
107 assert( i == 0 || terms_[i - 1].first < terms_[i].first );
108 }
109#endif
110}
111
112template <typename C, typename D, D M>
114{
115 assert( c1 != 0 );
116 assert( d1 != 0 );
117 if ( c0 != 0 )
118 terms_.emplace_back( D(0), c0 );
119 if ( d1 <= M )
120 terms_.emplace_back( d1, c1 );
121}
122
123template <typename C, typename D, D M>
124SparsePolynomial<C,D,M>::SparsePolynomial( C c0, D d1, C c1, D d2, C c2 )
125{
126 assert( c1 != 0 );
127 assert( d1 != 0 );
128 assert( c2 != 0 );
129 assert( d2 != 0 );
130 assert( d1 != d2 );
131 if ( c0 != 0 )
132 terms_.emplace_back( D(0), c0 );
133 if ( d1 > d2 )
134 {
135 std::swap( d1, d2 );
136 std::swap( c1, c2 );
137 }
138 if ( d1 <= M )
139 terms_.emplace_back( d1, c1 );
140 if ( d2 <= M )
141 terms_.emplace_back( d2, c2 );
142}
143
144template <typename C, typename D, D M>
146{
147 std::sort( terms.begin(), terms.end(), []( const Term & x, const Term & y ) { return x.first < y.first; } );
148 assert( terms.empty() || terms.back().first <= M );
150 res.terms_ = std::move( terms );
151 res.mergeTerms_();
152 return res;
153}
154
155template <typename C, typename D, D M>
157{
158 if ( !terms_.empty() )
159 return terms_.front().second > 0;
160
161 assert (false);
162 return false;
163}
164
165template <typename C, typename D, D M>
166void SparsePolynomial<C,D,M>::mergeTerms_()
167{
168 size_t out = 0;
169 for ( size_t i = 0; i < terms_.size(); )
170 {
171 auto deg = terms_[i].first;
172 auto cf = std::move( terms_[i].second );
173 for ( ++i; i < terms_.size() && terms_[i].first == deg; ++i )
174 cf += terms_[i].second;
175 if ( cf != 0 )
176 terms_[out++] = { deg, std::move( cf ) };
177 }
178 terms_.resize( out );
179}
180
181template <typename C, typename D, D M>
183{
184 std::vector<Term> res;
185 res.reserve( terms_.size() + b.terms_.size() );
186 std::merge( std::make_move_iterator( terms_.begin() ), std::make_move_iterator( terms_.end() ),
187 b.terms_.begin(), b.terms_.end(), std::back_inserter( res ),
188 []( const Term & x, const Term & y ) { return x.first < y.first; } );
189 terms_ = std::move( res );
190 mergeTerms_();
191 return * this;
192}
193
194template <typename C, typename D, D M>
196{
197 std::vector<Term> res;
198 res.reserve( terms_.size() + b.terms_.size() );
199 auto itA = terms_.begin();
200 auto itB = b.terms_.begin();
201 while ( itA != terms_.end() && itB != b.terms_.end() )
202 {
203 if ( itB->first < itA->first )
204 {
205 res.emplace_back( itB->first, -itB->second );
206 ++itB;
207 }
208 else
209 {
210 res.push_back( std::move( *itA ) );
211 ++itA;
212 }
213 }
214 for ( ; itA != terms_.end(); ++itA )
215 res.push_back( std::move( *itA ) );
216 for ( ; itB != b.terms_.end(); ++itB )
217 res.emplace_back( itB->first, -itB->second );
218 terms_ = std::move( res );
219 mergeTerms_();
220 return * this;
221}
222
223template <typename T, typename C, typename D, D M>
225{
227 using Term = typename Res::Term;
228 std::vector<Term> res;
229 res.reserve( a.terms_.size() * b.terms_.size() );
230 for ( const auto & [degA, cfA] : a.terms_ )
231 {
232 assert( cfA != 0 );
233 for ( const auto & [degB, cfB] : b.terms_ )
234 {
235 assert( cfB != 0 );
236 const auto deg = degA + degB;
237 if ( deg > M )
238 break;
239 res.emplace_back( deg, T( cfA ) * T( cfB ) );
240 }
241 }
242 return Res::fromUnsortedTerms( std::move( res ) );
243}
244
245template <typename T, typename C, typename D, D M>
248{
251 struct RowTerm
252 {
253 D deg;
254 int i, j;
255 bool neg;
256 };
257 auto greater = []( const RowTerm & x, const RowTerm & y ) { return x.deg > y.deg; };
258 std::vector<RowTerm> heap;
259 heap.reserve( a.get().size() + c.get().size() );
261 if ( !b.get().empty() )
262 for ( int i = 0; i < (int)a.get().size() && a.get()[i].first + b.get()[0].first <= M; ++i )
263 heap.push_back( { a.get()[i].first + b.get()[0].first, i, 0, false } );
264 if ( !d.get().empty() )
265 for ( int i = 0; i < (int)c.get().size() && c.get()[i].first + d.get()[0].first <= M; ++i )
266 heap.push_back( { c.get()[i].first + d.get()[0].first, i, 0, true } );
267 std::make_heap( heap.begin(), heap.end(), greater );
268
269 while ( !heap.empty() )
270 {
271 const auto deg = heap.front().deg;
272 decltype( std::declval<T>() * std::declval<T>() ) coeff{};
273 do
274 {
275 std::pop_heap( heap.begin(), heap.end(), greater );
276 auto r = heap.back();
277 heap.pop_back();
278 const auto & f = ( r.neg ? c : a ).get();
279 const auto & g = ( r.neg ? d : b ).get();
280 const auto prod = T( f[r.i].second ) * T( g[r.j].second );
281 if ( r.neg )
282 coeff -= prod;
283 else
284 coeff += prod;
285 if ( ++r.j < (int)g.size() && ( r.deg = f[r.i].first + g[r.j].first ) <= M )
286 {
287 heap.push_back( r );
288 std::push_heap( heap.begin(), heap.end(), greater );
289 }
290 }
291 while ( !heap.empty() && heap.front().deg == deg );
292 if ( coeff > 0 )
293 return 1;
294 if ( coeff < 0 )
295 return -1;
296 }
297 return 0;
298}
299
300}
#define M(T)
Definition MRSparsePolynomial.h:45
constexpr const V & get(const Box< V > &box) noexcept
get<0> returns min, get<1> returns max
Definition MRBox.h:400
SparsePolynomialProduct< T, D, M > mulAs(const SparsePolynomial< C, D, M > &a, const SparsePolynomial< C, D, M > &b)
Definition MRSparsePolynomial.h:224
ImVec2 size(const ViewportRectangle &rect)
Definition MRViewport.h:32
bool empty() const
returns true if no single polynomial coefficient is defined
Definition MRSparsePolynomial.h:77
SparsePolynomial & operator-=(const SparsePolynomial &b)
Definition MRSparsePolynomial.h:195
SparsePolynomial()=default
constructs zero polynomial
std::pair< D, C > Term
a not-zero coefficient with its degree
Definition MRSparsePolynomial.h:49
const std::vector< Term > & get() const
gets read-only access to all not-zero coefficients
Definition MRSparsePolynomial.h:83
bool isPositive() const
returns true if the coefficient for the smallest not-zero degress is positive
Definition MRSparsePolynomial.h:156
friend SparsePolynomialProduct< T, D2, M2 > mulAs(const SparsePolynomial< C2, D2, M2 > &a, const SparsePolynomial< C2, D2, M2 > &b)
int signOfProductsDiff(const SparsePolynomial< C, D, M > &a, const SparsePolynomial< C, D, M > &b, const SparsePolynomial< C, D, M > &c, const SparsePolynomial< C, D, M > &d)
Definition MRSparsePolynomial.h:246
void setZeroCoeff(D d)
sets coefficient for given degree to zero
Definition MRSparsePolynomial.h:68
Color operator*(float a, const Color &b)
Definition MRColor.h:119
SparsePolynomial & operator+=(const SparsePolynomial &b)
Definition MRSparsePolynomial.h:182
friend SparsePolynomial operator+(SparsePolynomial a, const SparsePolynomial &b)
Definition MRSparsePolynomial.h:87
friend SparsePolynomial operator-(SparsePolynomial a, const SparsePolynomial &b)
Definition MRSparsePolynomial.h:88
static SparsePolynomial fromUnsortedTerms(std::vector< Term > &&terms)
constructs polynomial from arbitrary terms with degrees not above M: sorts them by degree,...
Definition MRSparsePolynomial.h:145
SparsePolynomial< decltype(std::declval< T >() *std::declval< T >()), D, M > SparsePolynomialProduct
the type of the polynomial with coefficients of the type of the product of two values of type T
Definition MRSparsePolynomial.h:19
only for bindings generation
Definition MRCameraOrientationPlugin.h:8