GCC Code Coverage Report


Directory: ./
File: include/2geom/sbasis.h
Date: 2024-03-18 17:01:34
Exec Total Coverage
Lines: 81 140 57.9%
Functions: 32 50 64.0%
Branches: 42 124 33.9%

Line Branch Exec Source
1 /** @file
2 * @brief Polynomial in symmetric power basis (S-basis)
3 *//*
4 * Authors:
5 * Nathan Hurst <njh@mail.csse.monash.edu.au>
6 * Michael Sloan <mgsloan@gmail.com>
7 *
8 * Copyright (C) 2006-2007 authors
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it either under the terms of the GNU Lesser General Public
12 * License version 2.1 as published by the Free Software Foundation
13 * (the "LGPL") or, at your option, under the terms of the Mozilla
14 * Public License Version 1.1 (the "MPL"). If you do not alter this
15 * notice, a recipient may use your version of this file under either
16 * the MPL or the LGPL.
17 *
18 * You should have received a copy of the LGPL along with this library
19 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * You should have received a copy of the MPL along with this library
22 * in the file COPYING-MPL-1.1
23 *
24 * The contents of this file are subject to the Mozilla Public License
25 * Version 1.1 (the "License"); you may not use this file except in
26 * compliance with the License. You may obtain a copy of the License at
27 * http://www.mozilla.org/MPL/
28 *
29 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
30 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
31 * the specific language governing rights and limitations.
32 */
33
34 #ifndef LIB2GEOM_SEEN_SBASIS_H
35 #define LIB2GEOM_SEEN_SBASIS_H
36 #include <cassert>
37 #include <iostream>
38 #include <utility>
39 #include <vector>
40
41 #include <2geom/linear.h>
42 #include <2geom/interval.h>
43 #include <2geom/utils.h>
44 #include <2geom/exception.h>
45
46 //#define USE_SBASISN 1
47
48
49 #if defined(USE_SBASIS_OF)
50
51 #include "sbasis-of.h"
52
53 #elif defined(USE_SBASISN)
54
55 #include "sbasisN.h"
56 namespace Geom{
57
58 /*** An empty SBasis is identically 0. */
59 class SBasis : public SBasisN<1>;
60
61 };
62 #else
63
64 namespace Geom {
65
66 /**
67 * @brief Polynomial in symmetric power basis
68 * @ingroup Fragments
69 */
70 class SBasis {
71 std::vector<Linear> d;
72 void push_back(Linear const&l) { d.push_back(l); }
73
74 public:
75 // As part of our migration away from SBasis isa vector we provide this minimal set of vector interface methods.
76 43543782 size_t size() const {return d.size();}
77 typedef std::vector<Linear>::iterator iterator;
78 typedef std::vector<Linear>::const_iterator const_iterator;
79 43335298 Linear operator[](unsigned i) const {
80 43335298 return d[i];
81 }
82 19924174 Linear& operator[](unsigned i) { return d.at(i); }
83 const_iterator begin() const { return d.begin();}
84 const_iterator end() const { return d.end();}
85 47400 iterator begin() { return d.begin();}
86 47409 iterator end() { return d.end();}
87 bool empty() const { return d.size() == 1 && d[0][0] == 0 && d[0][1] == 0; }
88 1229284 Linear &back() {return d.back();}
89 Linear const &back() const {return d.back();}
90 521136 void pop_back() {
91
1/2
✓ Branch 1 taken 521136 times.
✗ Branch 2 not taken.
521136 if (d.size() > 1) {
92 521136 d.pop_back();
93 } else {
94 d[0][0] = 0;
95 d[0][1] = 0;
96 }
97 521136 }
98
1/2
✓ Branch 3 taken 133732 times.
✗ Branch 4 not taken.
133732 void resize(unsigned n) { d.resize(std::max<unsigned>(n, 1));}
99
1/2
✓ Branch 3 taken 1000673 times.
✗ Branch 4 not taken.
1000673 void resize(unsigned n, Linear const& l) { d.resize(std::max<unsigned>(n, 1), l);}
100 void reserve(unsigned n) { d.reserve(n);}
101 560 void clear() {
102 560 d.resize(1);
103 560 d[0][0] = 0;
104 560 d[0][1] = 0;
105 560 }
106 void insert(iterator before, const_iterator src_begin, const_iterator src_end) { d.insert(before, src_begin, src_end);}
107 280800 Linear& at(unsigned i) { return d.at(i);}
108 //void insert(Linear* before, int& n, Linear const &l) { d.insert(std::vector<Linear>::iterator(before), n, l);}
109 bool operator==(SBasis const&B) const { return d == B.d;}
110 bool operator!=(SBasis const&B) const { return d != B.d;}
111
112 768865 SBasis()
113
1/2
✓ Branch 4 taken 768865 times.
✗ Branch 5 not taken.
2306595 : d(1, Linear(0, 0))
114 768865 {}
115 explicit SBasis(double a)
116 : d(1, Linear(a, a))
117 {}
118 explicit SBasis(double a, double b)
119 : d(1, Linear(a, b))
120 {}
121 2411697 SBasis(SBasis const &a)
122 2411697 : d(a.d)
123 2411697 {}
124 SBasis(std::vector<Linear> ls)
125 : d(std::move(ls))
126 {}
127 783346 SBasis(Linear const &bo)
128
1/2
✓ Branch 2 taken 783346 times.
✗ Branch 3 not taken.
2350038 : d(1, bo)
129 783346 {}
130 SBasis(Linear* bo)
131 : d(1, bo ? *bo : Linear(0, 0))
132 {}
133
1/2
✓ Branch 2 taken 2748216 times.
✗ Branch 3 not taken.
8244648 explicit SBasis(size_t n, Linear const&l) : d(n, l) {}
134
135 SBasis(Coord c0, Coord c1, Coord c2, Coord c3)
136 : d(2)
137 {
138 d[0][0] = c0;
139 d[1][0] = c1;
140 d[1][1] = c2;
141 d[0][1] = c3;
142 }
143 SBasis(Coord c0, Coord c1, Coord c2, Coord c3, Coord c4, Coord c5)
144 : d(3)
145 {
146 d[0][0] = c0;
147 d[1][0] = c1;
148 d[2][0] = c2;
149 d[2][1] = c3;
150 d[1][1] = c4;
151 d[0][1] = c5;
152 }
153 SBasis(Coord c0, Coord c1, Coord c2, Coord c3, Coord c4, Coord c5,
154 Coord c6, Coord c7)
155 : d(4)
156 {
157 d[0][0] = c0;
158 d[1][0] = c1;
159 d[2][0] = c2;
160 d[3][0] = c3;
161 d[3][1] = c4;
162 d[2][1] = c5;
163 d[1][1] = c6;
164 d[0][1] = c7;
165 }
166 SBasis(Coord c0, Coord c1, Coord c2, Coord c3, Coord c4, Coord c5,
167 Coord c6, Coord c7, Coord c8, Coord c9)
168 : d(5)
169 {
170 d[0][0] = c0;
171 d[1][0] = c1;
172 d[2][0] = c2;
173 d[3][0] = c3;
174 d[4][0] = c4;
175 d[4][1] = c5;
176 d[3][1] = c6;
177 d[2][1] = c7;
178 d[1][1] = c8;
179 d[0][1] = c9;
180 }
181
182 // construct from a sequence of coefficients
183 template <typename Iter>
184 SBasis(Iter first, Iter last) {
185 assert(std::distance(first, last) % 2 == 0);
186 assert(std::distance(first, last) >= 2);
187 for (; first != last; ++first) {
188 --last;
189 push_back(Linear(*first, *last));
190 }
191 }
192
193 //IMPL: FragmentConcept
194 typedef double output_type;
195 2779799 inline bool isZero(double eps=EPSILON) const {
196
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2779799 times.
2779799 assert(size() > 0);
197
2/2
✓ Branch 1 taken 3263026 times.
✓ Branch 2 taken 229005 times.
3492031 for(unsigned i = 0; i < size(); i++) {
198
2/2
✓ Branch 4 taken 2550794 times.
✓ Branch 5 taken 712232 times.
3263026 if(!(*this)[i].isZero(eps)) return false;
199 }
200 229005 return true;
201 }
202 inline bool isConstant(double eps=EPSILON) const {
203 assert(size() > 0);
204 if(!(*this)[0].isConstant(eps)) return false;
205 for (unsigned i = 1; i < size(); i++) {
206 if(!(*this)[i].isZero(eps)) return false;
207 }
208 return true;
209 }
210
211 bool isFinite() const;
212 865975 inline Coord at0() const { return (*this)[0][0]; }
213 59766 inline Coord &at0() { return (*this)[0][0]; }
214 840775 inline Coord at1() const { return (*this)[0][1]; }
215 50166 inline Coord &at1() { return (*this)[0][1]; }
216
217 int degreesOfFreedom() const { return size()*2;}
218
219 300000 double valueAt(double t) const {
220
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 300000 times.
300000 assert(size() > 0);
221 300000 double s = t*(1-t);
222 300000 double p0 = 0, p1 = 0;
223
2/2
✓ Branch 1 taken 705300 times.
✓ Branch 2 taken 300000 times.
1005300 for(unsigned k = size(); k > 0; k--) {
224 705300 const Linear &lin = (*this)[k-1];
225 705300 p0 = p0*s + lin[0];
226 705300 p1 = p1*s + lin[1];
227 }
228 300000 return (1-t)*p0 + t*p1;
229 }
230 //double valueAndDerivative(double t, double &der) const {
231 //}
232 270000 double operator()(double t) const {
233 270000 return valueAt(t);
234 }
235
236 std::vector<double> valueAndDerivatives(double t, unsigned n) const;
237
238 SBasis toSBasis() const { return SBasis(*this); }
239
240 double tailError(unsigned tail) const;
241
242 // compute f(g)
243 SBasis operator()(SBasis const & g) const;
244
245 //MUTATOR PRISON
246 //remove extra zeros
247 708375 void normalize() {
248
6/6
✓ Branch 1 taken 1229284 times.
✓ Branch 2 taken 220 times.
✓ Branch 5 taken 521129 times.
✓ Branch 6 taken 708155 times.
✓ Branch 7 taken 521129 times.
✓ Branch 8 taken 708375 times.
1229504 while(size() > 1 && back().isZero(0))
249 521129 pop_back();
250 708375 }
251
252
3/4
✓ Branch 1 taken 72928 times.
✓ Branch 2 taken 15318 times.
✓ Branch 7 taken 72928 times.
✗ Branch 8 not taken.
88246 void truncate(unsigned k) { if(k < size()) resize(std::max<size_t>(k, 1)); }
253 private:
254 void derive(); // in place version
255 };
256
257 //TODO: figure out how to stick this in linear, while not adding an sbasis dep
258 inline SBasis Linear::toSBasis() const { return SBasis(*this); }
259
260 //implemented in sbasis-roots.cpp
261 OptInterval bounds_exact(SBasis const &a);
262 OptInterval bounds_fast(SBasis const &a, int order = 0);
263 OptInterval bounds_local(SBasis const &a, const OptInterval &t, int order = 0);
264
265 /** Returns a function which reverses the domain of a.
266 \param a sbasis function
267 \relates SBasis
268
269 useful for reversing a parameteric curve.
270 */
271 inline SBasis reverse(SBasis const &a) {
272 SBasis result(a.size(), Linear());
273
274 for(unsigned k = 0; k < a.size(); k++)
275 result[k] = reverse(a[k]);
276 return result;
277 }
278
279 //IMPL: ScalableConcept
280 11766 inline SBasis operator-(const SBasis& p) {
281
3/4
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 11757 times.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
11766 if(p.isZero()) return SBasis();
282
1/2
✓ Branch 5 taken 11757 times.
✗ Branch 6 not taken.
11757 SBasis result(p.size(), Linear());
283
284
2/2
✓ Branch 1 taken 23574 times.
✓ Branch 2 taken 11757 times.
35331 for(unsigned i = 0; i < p.size(); i++) {
285
1/2
✓ Branch 4 taken 23574 times.
✗ Branch 5 not taken.
23574 result[i] = -p[i];
286 }
287
1/2
✓ Branch 1 taken 11757 times.
✗ Branch 2 not taken.
11757 return result;
288 11757 }
289 SBasis operator*(SBasis const &a, double k);
290 46 inline SBasis operator*(double k, SBasis const &a) { return a*k; }
291 42600 inline SBasis operator/(SBasis const &a, double k) { return a*(1./k); }
292 SBasis& operator*=(SBasis& a, double b);
293 23409 inline SBasis& operator/=(SBasis& a, double b) { return (a*=(1./b)); }
294
295 //IMPL: AddableConcept
296 SBasis operator+(const SBasis& a, const SBasis& b);
297 SBasis operator-(const SBasis& a, const SBasis& b);
298 SBasis& operator+=(SBasis& a, const SBasis& b);
299 SBasis& operator-=(SBasis& a, const SBasis& b);
300
301 //TODO: remove?
302 /*inline SBasis operator+(const SBasis & a, Linear const & b) {
303 if(b.isZero()) return a;
304 if(a.isZero()) return b;
305 SBasis result(a);
306 result[0] += b;
307 return result;
308 }
309 inline SBasis operator-(const SBasis & a, Linear const & b) {
310 if(b.isZero()) return a;
311 SBasis result(a);
312 result[0] -= b;
313 return result;
314 }
315 inline SBasis& operator+=(SBasis& a, const Linear& b) {
316 if(a.isZero())
317 a.push_back(b);
318 else
319 a[0] += b;
320 return a;
321 }
322 inline SBasis& operator-=(SBasis& a, const Linear& b) {
323 if(a.isZero())
324 a.push_back(-b);
325 else
326 a[0] -= b;
327 return a;
328 }*/
329
330 //IMPL: OffsetableConcept
331 inline SBasis operator+(const SBasis & a, double b) {
332 if(a.isZero()) return Linear(b, b);
333 SBasis result(a);
334 result[0] += b;
335 return result;
336 }
337 inline SBasis operator-(const SBasis & a, double b) {
338 if(a.isZero()) return Linear(-b, -b);
339 SBasis result(a);
340 result[0] -= b;
341 return result;
342 }
343 11700 inline SBasis& operator+=(SBasis& a, double b) {
344
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 11700 times.
11700 if(a.isZero())
345 a = SBasis(Linear(b,b));
346 else
347 11700 a[0] += b;
348 11700 return a;
349 }
350 59111 inline SBasis& operator-=(SBasis& a, double b) {
351
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 59111 times.
59111 if(a.isZero())
352 a = SBasis(Linear(-b,-b));
353 else
354 59111 a[0] -= b;
355 59111 return a;
356 }
357
358 SBasis shift(SBasis const &a, int sh);
359 SBasis shift(Linear const &a, int sh);
360
361 inline SBasis truncate(SBasis const &a, unsigned terms) {
362 SBasis c;
363 c.insert(c.begin(), a.begin(), a.begin() + std::min(terms, (unsigned)a.size()));
364 return c;
365 }
366
367 SBasis multiply(SBasis const &a, SBasis const &b);
368 // This performs a multiply and accumulate operation in about the same time as multiply. return a*b + c
369 SBasis multiply_add(SBasis const &a, SBasis const &b, SBasis c);
370
371 SBasis integral(SBasis const &c);
372 SBasis derivative(SBasis const &a);
373
374 SBasis sqrt(SBasis const &a, int k);
375
376 // return a kth order approx to 1/a)
377 SBasis reciprocal(Linear const &a, int k);
378 SBasis divide(SBasis const &a, SBasis const &b, int k);
379
380 136332 inline SBasis operator*(SBasis const & a, SBasis const & b) {
381 136332 return multiply(a, b);
382 }
383
384 inline SBasis& operator*=(SBasis& a, SBasis const & b) {
385 a = multiply(a, b);
386 return a;
387 }
388
389 /** Returns the degree of the first non zero coefficient.
390 \param a sbasis function
391 \param tol largest abs val considered 0
392 \return first non zero coefficient
393 \relates SBasis
394 */
395 inline unsigned
396 23400 valuation(SBasis const &a, double tol=0){
397 23400 unsigned val=0;
398 70200 while( val<a.size() &&
399
6/8
✓ Branch 1 taken 46800 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 23400 times.
✓ Branch 6 taken 23400 times.
✓ Branch 8 taken 46800 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 23400 times.
✓ Branch 12 taken 23400 times.
163800 fabs(a[val][0])<tol &&
400
3/4
✓ Branch 2 taken 23400 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23400 times.
✓ Branch 5 taken 23400 times.
70200 fabs(a[val][1])<tol )
401 23400 val++;
402 23400 return val;
403 }
404
405 // a(b(t))
406 SBasis compose(SBasis const &a, SBasis const &b);
407 SBasis compose(SBasis const &a, SBasis const &b, unsigned k);
408 SBasis inverse(SBasis a, int k);
409 //compose_inverse(f,g)=compose(f,inverse(g)), but is numerically more stable in some good cases...
410 //TODO: requires g(0)=0 & g(1)=1 atm. generalization should be obvious.
411 SBasis compose_inverse(SBasis const &f, SBasis const &g, unsigned order=2, double tol=1e-3);
412
413 /** Returns the sbasis on domain [0,1] that was t on [from, to]
414 \param t sbasis function
415 \param from,to interval
416 \return sbasis
417 \relates SBasis
418 */
419 SBasis portion(const SBasis &t, double from, double to);
420 inline SBasis portion(const SBasis &t, Interval const &ivl) { return portion(t, ivl.min(), ivl.max()); }
421
422 // compute f(g)
423 inline SBasis
424 SBasis::operator()(SBasis const & g) const {
425 return compose(*this, g);
426 }
427
428 inline std::ostream &operator<< (std::ostream &out_file, const Linear &bo) {
429 out_file << "{" << bo[0] << ", " << bo[1] << "}";
430 return out_file;
431 }
432
433 inline std::ostream &operator<< (std::ostream &out_file, const SBasis & p) {
434 for(unsigned i = 0; i < p.size(); i++) {
435 if (i != 0) {
436 out_file << " + ";
437 }
438 out_file << p[i] << "s^" << i;
439 }
440 return out_file;
441 }
442
443 // These are deprecated, use sbasis-math.h versions if possible
444 SBasis sin(Linear bo, int k);
445 SBasis cos(Linear bo, int k);
446
447 std::vector<double> roots(SBasis const & s);
448 std::vector<double> roots(SBasis const & s, Interval const inside);
449 std::vector<std::vector<double> > multi_roots(SBasis const &f,
450 std::vector<double> const &levels,
451 double htol=1e-7,
452 double vtol=1e-7,
453 double a=0,
454 double b=1);
455
456 //--------- Levelset like functions -----------------------------------------------------
457
458 /** Solve f(t) = v +/- tolerance. The collection of intervals where
459 * v - vtol <= f(t) <= v+vtol
460 * is returned (with a precision tol on the boundaries).
461 \param f sbasis function
462 \param level the value of v.
463 \param vtol: error tolerance on v.
464 \param a, b limit search on domain [a,b]
465 \param tol: tolerance on the result bounds.
466 \returns a vector of intervals.
467 */
468 std::vector<Interval> level_set (SBasis const &f,
469 double level,
470 double vtol = 1e-5,
471 double a=0.,
472 double b=1.,
473 double tol = 1e-5);
474
475 /** Solve f(t)\in I=[u,v], which defines a collection of intervals (J_k). More precisely,
476 * a collection (J'_k) is returned with J'_k = J_k up to a given tolerance.
477 \param f sbasis function
478 \param level: the given interval of deisred values for f.
479 \param a, b limit search on domain [a,b]
480 \param tol: tolerance on the bounds of the result.
481 \returns a vector of intervals.
482 */
483 std::vector<Interval> level_set (SBasis const &f,
484 Interval const &level,
485 double a=0.,
486 double b=1.,
487 double tol = 1e-5);
488
489 /** 'Solve' f(t) = v +/- tolerance for several values of v at once.
490 \param f sbasis function
491 \param levels vector of values, that should be sorted.
492 \param vtol: error tolerance on v.
493 \param a, b limit search on domain [a,b]
494 \param tol: the bounds of the returned intervals are exact up to that tolerance.
495 \returns a vector of vectors of intervals.
496 */
497 std::vector<std::vector<Interval> > level_sets (SBasis const &f,
498 std::vector<double> const &levels,
499 double a=0.,
500 double b=1.,
501 double vtol = 1e-5,
502 double tol = 1e-5);
503
504 /** 'Solve' f(t)\in I=[u,v] for several intervals I at once.
505 \param f sbasis function
506 \param levels vector of 'y' intervals, that should be disjoints and sorted.
507 \param a, b limit search on domain [a,b]
508 \param tol: the bounds of the returned intervals are exact up to that tolerance.
509 \returns a vector of vectors of intervals.
510 */
511 std::vector<std::vector<Interval> > level_sets (SBasis const &f,
512 std::vector<Interval> const &levels,
513 double a=0.,
514 double b=1.,
515 double tol = 1e-5);
516
517 }
518 #endif
519
520 /*
521 Local Variables:
522 mode:c++
523 c-file-style:"stroustrup"
524 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
525 indent-tabs-mode:nil
526 fill-column:99
527 End:
528 */
529 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
530 #endif
531