Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
mvpoly-tools.h
Go to the documentation of this file.
1/*
2 * Routines that extend univariate polynomial functions
3 * to multi-variate polynomial exploiting recursion at compile time
4 *
5 * Authors:
6 * Marco Cecchetti <mrcekets at gmail.com>
7 *
8 * Copyright 2008 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 _GEOM_SL_MVPOLY_TOOLS_H_
35#define _GEOM_SL_MVPOLY_TOOLS_H_
36
37
38#include <2geom/exception.h>
39
43
44#include <array>
45#include <functional>
46#include <iostream>
47#include <type_traits>
48
49
50namespace Geom { namespace SL {
51
52/*
53 * rank<PolyT>::value == total amount of indeterminates
54 * x_(0),x_(1),...,x_(rank-1) that belong to type PolyT
55 */
56
57template <typename T>
58struct rank
59{
60 static const size_t value = 0;
61};
62
63template <typename CoeffT>
64struct rank< Polynomial<CoeffT> >
65{
66 static const size_t value = rank<CoeffT>::value + 1;
67};
68
69
70/*
71 * mvpoly<N, CoeffT> creates a multi-variate polynomial type
72 * by nesting N-1 Polynomial class template and setting
73 * the coefficient type of the most nested Polynomial to CoeffT
74 * example: mvpoly<3, double>::type is the same than
75 * Polynomial< Polynomial< Polynomial<double> > >
76 */
77
78template <size_t N, typename CoeffT>
79struct mvpoly
80{
81 typedef Polynomial<typename mvpoly<N-1, CoeffT>::type> type;
82 typedef CoeffT coeff_type;
83 static const size_t rank = N;
84
85 /*
86 * computes the lexicographic degree of the mv polynomial p
87 */
88 static
90 {
92 lex_degree_impl<0>(p, D);
93 return D;
94 }
95
96 /*
97 * Returns in the out-parameter D an N-sequence where each entry value
98 * represents the max degree of the polynomial related to the passed
99 * index I, if one index value in I is greater than the related max degree
100 * the routine returns false otherwise it returns true.
101 * This routine can be used to test if a given multi-index I is related
102 * to an actual initialized coefficient.
103 */
104 static
105 bool max_degree (type const& p,
107 multi_index_type const& I)
108 {
109 if (I.size() != N)
110 THROW_RANGEERROR ("multi-index with wrong length");
111 D.resize(N);
112 return max_degree_impl<0>(p, D, I);
113 }
114
115 /*
116 * Returns in the out-parameter D an N-sequence where each entry value
117 * represents the real degree of the polynomial related to the passed
118 * index I, if one index value in I is greater than the related real degree
119 * the routine returns false otherwise it returns true.
120 * This routine can be used to test if a given multi-index I is related
121 * to an actual initialized and non-zero coefficient.
122 */
123
124 static
125 bool real_degree (type const& p,
127 multi_index_type const& I)
128 {
129 if (I.size() != N)
130 THROW_RANGEERROR ("multi-index with wrong length");
131 D.resize(N);
132 return real_degree_impl<0>(p, D, I);
133 }
134
135 /*
136 * Multiplies p by X^I
137 */
138 static
139 void shift(type & p, multi_index_type const& I)
140 {
141 if (I.size() != N)
142 THROW_RANGEERROR ("multi-index with wrong length");
143 shift_impl<0>(p, I);
144 }
145
146 /*
147 * mv poly evaluation:
148 * T can be any type that is able to be += with the coefficient type
149 * and that can be *= with the same type T moreover a specialization
150 * of zero struct for the type T is needed
151 */
152 template <typename T>
153 static
154 T evaluate(type const& p, std::array<T, N> const& X)
155 {
156 return evaluate_impl<T, 0>(p, X);
157 }
158
159 /*
160 * trim leading zero coefficients
161 */
162 static
163 void normalize(type & p)
164 {
165 p.normalize();
166 for (size_t k = 0; k < p.size(); ++k)
168 }
169
170 /*
171 * Applies the unary operator "op" to each coefficient of p with rank M.
172 * For instance when M = 0 op is applied to each coefficient
173 * of the multi-variate polynomial p.
174 * When M < N the function call recursively the for_each routine
175 * for p.real_degree() times, when M == N the operator "op" is invoked on p;
176 */
177 template <size_t M>
178 static
180 (type & p,
181 std::function<void (typename mvpoly<M, CoeffT>::type &)> const& op,
182 typename std::enable_if_t<(M < N)>* = 0)
183 {
184 for (size_t k = 0; k <= p.real_degree(); ++k)
185 {
186 mvpoly<N-1, CoeffT>::template for_each<M>(p[k], op);
187 }
188 }
189
190 template <size_t M>
191 static
193 (type & p,
194 std::function<void (typename mvpoly<M, CoeffT>::type &)> const& op,
195 typename std::enable_if_t<(M == N)>* = 0)
196 {
197 op(p);
198 }
199
200 // this is only an helper function to be passed to the for_each routine
201 static
202 void multiply_to (type& p, type const& q)
203 {
204 p *= q;
205 }
206
207 private:
208 template <size_t i>
209 static
211 {
212 D[i] = p.real_degree();
213 mvpoly<N-1, CoeffT>::template lex_degree_impl<i+1>(p[D[i]], D);
214 }
215
216 template <size_t i>
217 static
218 bool max_degree_impl (type const& p,
220 multi_index_type const& I)
221 {
222 D[i] = p.max_degree();
223 if (I[i] > D[i]) return false;
224 return
225 mvpoly<N-1, CoeffT>::template max_degree_impl<i+1>(p[I[i]], D, I);
226 }
227
228 template <size_t i>
229 static
230 bool real_degree_impl (type const& p,
232 multi_index_type const& I)
233 {
234 D[i] = p.real_degree();
235 if (I[i] > D[i]) return false;
236 return
237 mvpoly<N-1, CoeffT>::template real_degree_impl<i+1>(p[I[i]], D, I);
238 }
239
240 template <size_t i>
241 static
243 {
244 p <<= I[i];
245 for (size_t k = 0; k < p.size(); ++k)
246 {
247 mvpoly<N-1, CoeffT>::template shift_impl<i+1>(p[k], I);
248 }
249 }
250
251 template <typename T, size_t i>
252 static
253 T evaluate_impl(type const& p, std::array<T, N+i> const& X)
254 {
255// T r = zero<T>()();
256// for (size_t k = p.max_degree(); k > 0; --k)
257// {
258// r += mvpoly<N-1, CoeffT>::template evaluate_impl<T, i+1>(p[k], X);
259// r *= X[i];
260// }
261// r += mvpoly<N-1, CoeffT>::template evaluate_impl<T, i+1>(p[0], X);
262
263 int n = p.max_degree();
264 T r = mvpoly<N-1, CoeffT>::template evaluate_impl<T, i+1>(p[n], X);
265 for (int k = n - 1; k >= 0; --k)
266 {
267 r *= X[i];
268 r += mvpoly<N-1, CoeffT>::template evaluate_impl<T, i+1>(p[k], X);
269 }
270 return r;
271 }
272
273 template <size_t M, typename C>
274 friend struct mvpoly;
275};
276
277/*
278 * rank 0 mv poly, that is a scalar value (usually a numeric value),
279 * the routines implemented here are used only to stop recursion
280 * (but for_each)
281 */
282template< typename CoeffT >
283struct mvpoly<0, CoeffT>
284{
285 typedef CoeffT type;
286 typedef CoeffT coeff_type;
287 static const size_t rank = 0;
288
289 template <size_t M>
290 static
292 (type & p,
293 std::function<void (typename mvpoly<M, CoeffT>::type &)> const& op,
294 typename std::enable_if_t<(M == 0)>* = 0)
295 {
296 op(p);
297 }
298
299 // multiply_to and divide_to are only helper functions
300 // to be passed to the for_each routine
301 static
302 void multiply_to (type& p, type const& q)
303 {
304 p *= q;
305 }
306
307 static
308 void divide_to (type& p, type const& c)
309 {
310 p /= c;
311 }
312
313 private:
314 template <size_t i>
315 static
316 void lex_degree_impl (type const &/*p*/, multi_index_type&/*D*/)
317 {
318 return;
319 }
320
321 template <size_t i>
322 static
323 bool max_degree_impl (type const &/*p*/,
324 multi_index_type &/*D*/,
325 multi_index_type const &/*I*/)
326 {
327 return true;
328 }
329
330 template <size_t i>
331 static
332 bool real_degree_impl (type const &/*p*/,
333 multi_index_type &/*D*/,
334 multi_index_type const &/*I*/)
335 {
336 return true;
337 }
338
339 template <size_t i>
340 static
341 void shift_impl(type &/*p*/, multi_index_type const &/*I*/)
342 {}
343
344 template <typename T, size_t i>
345 static
346 T evaluate_impl(type const &p, std::array<T, i> const &/*X*/)
347 {
348 return p;
349 }
350
351 static
352 void normalize(type &/*p*/)
353 {}
354
355
356 template <size_t M, typename C>
357 friend struct mvpoly;
358};
359
360
361/*
362 * monomial::make generate a mv-poly made up by a single term:
363 * monomial::make<N>(I,c) == c*X^I, where X=(x_(0), .., x_(N-1))
364 */
365
366template <size_t N, typename CoeffT>
368{
370
371 static inline
373 {
374 if (I.size() != N) // an exponent for each indeterminate
375 THROW_RANGEERROR ("multi-index with wrong length");
376
377 return make_impl<0>(I, c);
378 }
379
380 private:
381 // at i-th level of recursion I need to pick up the i-th exponent in "I"
382 // so I pass i as a template parameter, this trick is needed to avoid
383 // to create a new multi-index at each recursion level:
384 // (J = I[std::slice[1, I.size()-1, 1)]) that will be more expensive
385 template <size_t i>
386 static
388 {
389 poly_type p(monomial<N-1,CoeffT>::template make_impl<i+1>(I, c), I[i]);
390 return p;
391 }
392
393 // make_impl private require that monomial classes to be each other friend
394 template <size_t M, typename C>
395 friend struct monomial;
396};
397
398
399// case N = 0 for stopping recursion
400template <typename CoeffT>
401struct monomial<0, CoeffT>
402{
403 private:
404 template <size_t i>
405 static
406 CoeffT make_impl(multi_index_type const &/*I*/, CoeffT c)
407 {
408 return c;
409 }
410
411 template<size_t N, typename C>
412 friend struct monomial;
413};
414
415
416/*
417 * coefficient<N, PolyT>
418 *
419 * N should be in the range [0, rank<PolyT>-1]
420 *
421 * "type" == the type of the coefficient of the polynomial with
422 * rank = rank<PolyT> - N - 1, that is it is the type of the object returned
423 * by applying the operator[] of a Polynomial object N+1 times;
424 *
425 * "zero" represents the zero element (in the group theory meaning)
426 * for the coefficient type "type"; having it as a static class member
427 * allows to return always a (const) reference by the "get_safe" method
428 *
429 * get(p, I) returns the coefficient of the monomial X^I
430 * this method doesn't check if such a coefficient really exists,
431 * so it's up to the user checking that the passed multi-index I is
432 * not out of range
433 *
434 * get_safe(p, I) returns the coefficient of the monomial X^I
435 * in case such a coefficient doesn't really exist "zero" is returned
436 *
437 * set_safe(p, I, c) set the coefficient of the monomial X^I to "c"
438 * in case such a coefficient doesn't really exist this method creates it
439 * and creates all monomials X^J with J < I that don't exist yet, setting
440 * their coefficients to "zero";
441 * (with J < I we mean "<" wrt the lexicographic order)
442 *
443 */
444
445template <size_t N, typename T>
447{
448};
449
450
451template <size_t N, typename CoeffT>
452struct coefficient< N, Polynomial<CoeffT> >
453{
454 typedef typename coefficient<N-1, CoeffT>::type type;
456
457 static const type zero;
458
459 static
460 type const& get(poly_type const& p, multi_index_type const& I)
461 {
462 if (I.size() != N+1)
463 THROW_RANGEERROR ("multi-index with wrong length");
464
465 return get_impl<0>(p, I);
466 }
467
468 static
470 {
471 if (I.size() != N+1)
472 THROW_RANGEERROR ("multi-index with wrong length");
473
474 return get_impl<0>(p, I);
475 }
476
477 static
478 type const& get_safe(poly_type const& p, multi_index_type const& I)
479 {
480 if (I.size() != N+1)
481 THROW_RANGEERROR ("multi-index with wrong length");
482
483 return get_safe_impl<0>(p, I);
484 }
485
486 static
487 void set_safe(poly_type & p, multi_index_type const& I, type const& c)
488 {
489 if (I.size() != N+1)
490 THROW_RANGEERROR ("multi-index with wrong length");
491
492 return set_safe_impl<0>(p, I, c);
493 }
494
495 private:
496 template <size_t i>
497 static
498 type const& get_impl(poly_type const& p, multi_index_type const& I)
499 {
500 return coefficient<N-1, CoeffT>::template get_impl<i+1>(p[I[i]], I);
501 }
502
503 template <size_t i>
504 static
506 {
507 return coefficient<N-1, CoeffT>::template get_impl<i+1>(p[I[i]], I);
508 }
509
510 template <size_t i>
511 static
513 {
514 if (I[i] > p.max_degree())
515 {
516 return zero;
517 }
518 else
519 {
520 return
521 coefficient<N-1, CoeffT>::template get_safe_impl<i+1>(p[I[i]], I);
522 }
523 }
524
525 template <size_t i>
526 static
527 void set_safe_impl(poly_type & p, multi_index_type const& I, type const& c)
528 {
529 if (I[i] > p.max_degree())
530 {
531 multi_index_type J = shift(I, i+1);
532 CoeffT m = monomial<N, type>::make(J, c);
533 p.coefficient(I[i], m);
534 }
535 else
536 {
537 coefficient<N-1, CoeffT>::template set_safe_impl<i+1>(p[I[i]], I, c);
538 }
539 }
540
541 template<size_t M, typename T>
542 friend struct coefficient;
543
544};
545
546// initialization of static member zero
547template <size_t N, typename CoeffT>
548const typename coefficient< N, Polynomial<CoeffT> >::type
551
552
553// case N = 0 for stopping recursion
554template <typename CoeffT>
555struct coefficient< 0, Polynomial<CoeffT> >
556{
557 typedef CoeffT type;
559
560 static const type zero;
561
562 static
563 type const& get(poly_type const& p, multi_index_type const& I)
564 {
565 if (I.size() != 1)
566 THROW_RANGEERROR ("multi-index with wrong length");
567
568 return p[I[0]];
569 }
570
571 static
573 {
574 if (I.size() != 1)
575 THROW_RANGEERROR ("multi-index with wrong length");
576
577 return p[I[0]];
578 }
579
580 static
581 type const& get_safe(poly_type const& p, multi_index_type const& I)
582 {
583 if (I.size() != 1)
584 THROW_RANGEERROR ("multi-index with wrong length");
585
586 return p.coefficient(I[0]);
587 }
588
589 static
590 void set_safe(poly_type & p, multi_index_type const& I, type const& c)
591 {
592 if (I.size() != 1)
593 THROW_RANGEERROR ("multi-index with wrong length");
594
595 p.coefficient(I[0], c);
596 }
597
598 private:
599 template <size_t i>
600 static
601 type const& get_impl(poly_type const& p, multi_index_type const& I)
602 {
603 return p[I[i]];
604 }
605
606 template <size_t i>
607 static
609 {
610 return p[I[i]];
611 }
612
613 template <size_t i>
614 static
616 {
617 return p.coefficient(I[i]);
618 }
619
620 template <size_t i>
621 static
622 void set_safe_impl(poly_type & p, multi_index_type const& I, type const& c)
623 {
624 p.coefficient(I[i], c);
625 }
626
627 template<size_t M, typename T>
628 friend struct coefficient;
629};
630
631// initialization of static member zero
632template <typename CoeffT>
633const typename coefficient< 0, Polynomial<CoeffT> >::type
636
637
638/*
639 * ordering types:
640 * lex : lexicographic ordering
641 * ilex : inverse lexicographic ordering
642 * max_lex : max degree + lexicographic ordering for disambiguation
643 *
644 */
645
646namespace ordering
647{
648 struct lex; // WARNING: at present only lex ordering is supported
649 struct ilex;
650 struct max_lex;
651}
652
653
654/*
655 * degree of a mv poly wrt a given ordering
656 */
657
658template <size_t N, typename CoeffT, typename OrderT = ordering::lex>
660{};
661
662template <size_t N, typename CoeffT>
663struct mvdegree<N, CoeffT, ordering::lex>
664{
666 typedef ordering::lex ordering;
667
668 static
673};
674
675} /*end namespace Geom*/ } /*end namespace SL*/
676
677
678#endif // _GEOM_SL_MVPOLY_TOOLS_H_
679
680
681/*
682 Local Variables:
683 mode:c++
684 c-file-style:"stroustrup"
685 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
686 indent-tabs-mode:nil
687 fill-column:99
688 End:
689*/
690// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
Defines the different types of exceptions that 2geom can throw.
size_t size() const
Definition polynomial.h:87
size_t real_degree() const
Definition polynomial.h:143
size_t max_degree() const
Definition polynomial.h:126
coeff_type const & coefficient(size_t i) const
Definition polynomial.h:191
double c[8][4]
@ X
Definition coord.h:48
std::valarray< size_t > multi_index_type
Definition multi-index.h:85
multi_index_type shift(multi_index_type const &I, size_t i=1)
Various utility functions.
Definition affine.h:22
size_t N
static void set_safe(poly_type &p, multi_index_type const &I, type const &c)
static type & get_impl(poly_type &p, multi_index_type const &I)
static type const & get_safe_impl(poly_type const &p, multi_index_type const &I)
static type const & get(poly_type const &p, multi_index_type const &I)
static void set_safe_impl(poly_type &p, multi_index_type const &I, type const &c)
static type const & get_impl(poly_type const &p, multi_index_type const &I)
static type const & get_safe(poly_type const &p, multi_index_type const &I)
static type & get(poly_type &p, multi_index_type const &I)
static type const & get(poly_type const &p, multi_index_type const &I)
static type & get_impl(poly_type &p, multi_index_type const &I)
static type const & get_safe_impl(poly_type const &p, multi_index_type const &I)
static void set_safe_impl(poly_type &p, multi_index_type const &I, type const &c)
coefficient< N-1, CoeffT >::type type
static type const & get_impl(poly_type const &p, multi_index_type const &I)
static type const & get_safe(poly_type const &p, multi_index_type const &I)
static type & get(poly_type &p, multi_index_type const &I)
static void set_safe(poly_type &p, multi_index_type const &I, type const &c)
static CoeffT make_impl(multi_index_type const &, CoeffT c)
static poly_type make_impl(multi_index_type const &I, CoeffT c)
mvpoly< N, CoeffT >::type poly_type
static poly_type make(multi_index_type const &I, CoeffT c)
static multi_index_type value(poly_type const &p)
static void lex_degree_impl(type const &, multi_index_type &)
static bool real_degree_impl(type const &, multi_index_type &, multi_index_type const &)
static void shift_impl(type &, multi_index_type const &)
static void normalize(type &)
static void multiply_to(type &p, type const &q)
static bool max_degree_impl(type const &, multi_index_type &, multi_index_type const &)
static T evaluate_impl(type const &p, std::array< T, i > const &)
static void divide_to(type &p, type const &c)
static void for_each(type &p, std::function< void(typename mvpoly< M, CoeffT >::type &)> const &op, typename std::enable_if_t<(M==0)> *=0)
static void for_each(type &p, std::function< void(typename mvpoly< M, CoeffT >::type &)> const &op, typename std::enable_if_t<(M< N)> *=0)
static bool real_degree_impl(type const &p, multi_index_type &D, multi_index_type const &I)
static void lex_degree_impl(type const &p, multi_index_type &D)
static bool real_degree(type const &p, multi_index_type &D, multi_index_type const &I)
static void normalize(type &p)
static T evaluate_impl(type const &p, std::array< T, N+i > const &X)
static multi_index_type lex_degree(type const &p)
static void shift_impl(type &p, multi_index_type const &I)
static T evaluate(type const &p, std::array< T, N > const &X)
static void multiply_to(type &p, type const &q)
static bool max_degree(type const &p, multi_index_type &D, multi_index_type const &I)
static bool max_degree_impl(type const &p, multi_index_type &D, multi_index_type const &I)
static void shift(type &p, multi_index_type const &I)
Polynomial< typename mvpoly< N-1, CoeffT >::type > type
static void for_each(type &p, std::function< void(typename mvpoly< M, CoeffT >::type &)> const &op, typename std::enable_if_t<(M==N)> *=0)
static const size_t value