GiNaC 1.8.10
utils.h
Go to the documentation of this file.
1
6/*
7 * GiNaC Copyright (C) 1999-2026 Johannes Gutenberg University Mainz, Germany
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
23#ifndef GINAC_UTILS_H
24#define GINAC_UTILS_H
25
26#include "assertion.h"
27
28#include <functional>
29#include <cstdint> // for uintptr_t
30#include <string>
31
32namespace GiNaC {
33
36class dunno {};
37
38// some compilers (e.g. cygwin) define a macro log2, causing confusion
39#ifdef log2
40#undef log2
41#endif
42
43unsigned log2(unsigned n);
44
47inline unsigned rotate_left(unsigned n)
48{
49 return (n & 0x80000000U) ? (n << 1 | 0x00000001U) : (n << 1);
50}
51
54template <class T>
55inline int compare_pointers(const T * a, const T * b)
56{
57 // '<' is not defined for pointers that don't point to the same array,
58 // but std::less is.
59 if (std::less<const T *>()(a, b))
60 return -1;
61 else if (std::less<const T *>()(b, a))
62 return 1;
63 return 0;
64}
65
67inline unsigned golden_ratio_hash(uintptr_t n)
68{
69 return n * UINT64_C(0x4f1bbcdd);
70}
71
72/* Compute the sign of a permutation of a container, with and without an
73 explicitly supplied comparison function. If the sign returned is 1 or -1,
74 the container is sorted after the operation. */
75template <class It>
76int permutation_sign(It first, It last)
77{
78 using std::swap;
79 if (first == last)
80 return 0;
81 --last;
82 if (first == last)
83 return 0;
84 It flag = first;
85 int sign = 1;
86
87 do {
88 It i = last, other = last;
89 --other;
90 bool swapped = false;
91 while (i != first) {
92 if (*i < *other) {
93 swap(*other, *i);
94 flag = other;
95 swapped = true;
96 sign = -sign;
97 } else if (!(*other < *i))
98 return 0;
99 --i;
100 if (i != first)
101 --other;
102 }
103 if (!swapped)
104 return sign;
105 ++flag;
106 if (flag == last)
107 return sign;
108 first = flag;
109 i = first; other = first;
110 ++other;
111 swapped = false;
112 while (i != last) {
113 if (*other < *i) {
114 swap(*i, *other);
115 flag = other;
116 swapped = true;
117 sign = -sign;
118 } else if (!(*i < *other))
119 return 0;
120 ++i;
121 if (i != last)
122 ++other;
123 }
124 if (!swapped)
125 return sign;
126 last = flag;
127 --last;
128 } while (first != last);
129
130 return sign;
131}
132
133template <class It, class Cmp, class Swap>
134int permutation_sign(It first, It last, Cmp comp, Swap swapit)
135{
136 if (first == last)
137 return 0;
138 --last;
139 if (first == last)
140 return 0;
141 It flag = first;
142 int sign = 1;
143
144 do {
145 It i = last, other = last;
146 --other;
147 bool swapped = false;
148 while (i != first) {
149 if (comp(*i, *other)) {
150 swapit(*other, *i);
151 flag = other;
152 swapped = true;
153 sign = -sign;
154 } else if (!comp(*other, *i))
155 return 0;
156 --i;
157 if (i != first)
158 --other;
159 }
160 if (!swapped)
161 return sign;
162 ++flag;
163 if (flag == last)
164 return sign;
165 first = flag;
166 i = first; other = first;
167 ++other;
168 swapped = false;
169 while (i != last) {
170 if (comp(*other, *i)) {
171 swapit(*i, *other);
172 flag = other;
173 swapped = true;
174 sign = -sign;
175 } else if (!comp(*i, *other))
176 return 0;
177 ++i;
178 if (i != last)
179 ++other;
180 }
181 if (!swapped)
182 return sign;
183 last = flag;
184 --last;
185 } while (first != last);
186
187 return sign;
188}
189
190/* Implementation of shaker sort, only compares adjacent elements. */
191template <class It, class Cmp, class Swap>
192void shaker_sort(It first, It last, Cmp comp, Swap swapit)
193{
194 if (first == last)
195 return;
196 --last;
197 if (first == last)
198 return;
199 It flag = first;
200
201 do {
202 It i = last, other = last;
203 --other;
204 bool swapped = false;
205 while (i != first) {
206 if (comp(*i, *other)) {
207 swapit(*other, *i);
208 flag = other;
209 swapped = true;
210 }
211 --i;
212 if (i != first)
213 --other;
214 }
215 if (!swapped)
216 return;
217 ++flag;
218 if (flag == last)
219 return;
220 first = flag;
221 i = first; other = first;
222 ++other;
223 swapped = false;
224 while (i != last) {
225 if (comp(*other, *i)) {
226 swapit(*i, *other);
227 flag = other;
228 swapped = true;
229 }
230 ++i;
231 if (i != last)
232 ++other;
233 }
234 if (!swapped)
235 return;
236 last = flag;
237 --last;
238 } while (first != last);
239}
240
241/* In-place cyclic permutation of a container (no copying, only swapping). */
242template <class It, class Swap>
243void cyclic_permutation(It first, It last, It new_first, Swap swapit)
244{
245 unsigned num = last - first;
246again:
247 if (first == new_first || num < 2)
248 return;
249
250 unsigned num1 = new_first - first, num2 = last - new_first;
251 if (num1 >= num2) {
252 It a = first, b = new_first;
253 while (b != last) {
254 swapit(*a, *b);
255 ++a; ++b;
256 }
257 if (num1 > num2) {
258 first += num2;
259 num = num1;
260 goto again;
261 }
262 } else {
263 It a = new_first, b = last;
264 do {
265 --a; --b;
266 swapit(*a, *b);
267 } while (a != first);
268 last -= num1;
269 num = num2;
270 goto again;
271 }
272}
273
278protected:
279 // Partitions n into m parts, not including zero parts.
280 // (Cf. OEIS sequence A008284; implementation adapted from Jörg Arndt's
281 // FXT library)
283 {
284 // partition: x[1] + x[2] + ... + x[m] = n and sentinel x[0] == 0
285 std::vector<unsigned> x;
286 unsigned n; // n>0
287 unsigned m; // 0<m<=n
288 mpartition2(unsigned n_, unsigned m_)
289 : x(m_+1), n(n_), m(m_)
290 {
291 for (unsigned k=1; k<m; ++k)
292 x[k] = 1;
293 x[m] = n - m + 1;
294 }
296 {
297 unsigned u = x[m]; // last element
298 unsigned k = m;
299 unsigned s = u;
300 while (--k) {
301 s += x[k];
302 if (x[k] + 2 <= u)
303 break;
304 }
305 if (k==0)
306 return false; // current is last
307 unsigned f = x[k] + 1;
308 while (k < m) {
309 x[k] = f;
310 s -= f;
311 ++k;
312 }
313 x[m] = s;
314 return true;
315 }
316 };
318 basic_partition_generator(unsigned n_, unsigned m_)
319 : mpgen(n_, m_)
320 { }
321};
322
327private:
328 unsigned m; // number of parts 0<m
329 mutable std::vector<unsigned> partition; // current partition
330 mutable bool current_updated; // whether partition vector has been updated
331public:
332 partition_with_zero_parts_generator(unsigned n_, unsigned m_)
333 : basic_partition_generator(n_, 1), m(m_), partition(m_), current_updated(false)
334 { }
335 // returns current partition in non-decreasing order, padded with zeros
336 const std::vector<unsigned>& get() const
337 {
338 if (!current_updated) {
339 for (unsigned i = 0; i < m - mpgen.m; ++i)
340 partition[i] = 0; // pad with zeros
341
342 for (unsigned i = m - mpgen.m; i < m; ++i)
343 partition[i] = mpgen.x[i - m + mpgen.m + 1];
344
345 current_updated = true;
346 }
347 return partition;
348 }
349 bool next()
350 {
351 current_updated = false;
352 if (!mpgen.next_partition()) {
353 if (mpgen.m == m || mpgen.m == mpgen.n)
354 return false; // current is last
355 // increment number of parts
356 mpgen = mpartition2(mpgen.n, mpgen.m + 1);
357 }
358 return true;
359 }
360};
361
366private:
367 mutable std::vector<unsigned> partition; // current partition
368 mutable bool current_updated; // whether partition vector has been updated
369public:
370 partition_generator(unsigned n_, unsigned m_)
372 { }
373 // returns current partition in non-decreasing order, padded with zeros
374 const std::vector<unsigned>& get() const
375 {
376 if (!current_updated) {
377 for (unsigned i = 0; i < mpgen.m; ++i)
378 partition[i] = mpgen.x[i + 1];
379
380 current_updated = true;
381 }
382 return partition;
383 }
384 bool next()
385 {
386 current_updated = false;
387 return mpgen.next_partition();
388 }
389};
390
395private:
396 // Generates all distinct permutations of a multiset.
397 // (Based on Aaron Williams' algorithm 1 from "Loopless Generation of
398 // Multiset Permutations using a Constant Number of Variables by Prefix
399 // Shifts." <https://dl.acm.org/doi/pdf/10.5555/1496770.1496877>)
400 struct coolmulti {
401 // element of singly linked list
402 struct element {
403 unsigned value;
405 element(unsigned val, element* n)
406 : value(val), next(n) {}
408 { // recurses down to the end of the singly linked list
409 delete next;
410 }
411 };
413 // NB: Partition must be sorted in non-decreasing order.
414 explicit coolmulti(const std::vector<unsigned>& partition)
415 : head(nullptr), i(nullptr), after_i(nullptr)
416 {
417 for (unsigned n = 0; n < partition.size(); ++n) {
418 head = new element(partition[n], head);
419 if (n <= 1)
420 i = head;
421 }
422 after_i = i->next;
423 }
425 { // deletes singly linked list
426 delete head;
427 }
429 {
430 element *before_k;
431 if (after_i->next != nullptr && i->value >= after_i->next->value)
432 before_k = after_i;
433 else
434 before_k = i;
435 element *k = before_k->next;
436 before_k->next = k->next;
437 k->next = head;
438 if (k->value < head->value)
439 i = k;
440 after_i = i->next;
441 head = k;
442 }
443 bool finished() const
444 {
445 return after_i->next == nullptr && after_i->value >= head->value;
446 }
448 bool atend; // needed for simplifying iteration over permutations
449 bool trivial; // likewise, true if all elements are equal
450 mutable std::vector<unsigned> composition; // current compositions
451 mutable bool current_updated; // whether composition vector has been updated
452public:
453 explicit composition_generator(const std::vector<unsigned>& partition)
454 : cmgen(partition), atend(false), trivial(true), composition(partition.size()), current_updated(false)
455 {
456 for (unsigned i=1; i<partition.size(); ++i)
457 trivial = trivial && (partition[0] == partition[i]);
458 }
459 const std::vector<unsigned>& get() const
460 {
461 if (!current_updated) {
463 size_t i = 0;
464 while (it != nullptr) {
465 composition[i] = it->value;
466 it = it->next;
467 ++i;
468 }
469 current_updated = true;
470 }
471 return composition;
472 }
473 bool next()
474 {
475 // This ugly contortion is needed because the original coolmulti
476 // algorithm requires code duplication of the payload procedure,
477 // one before the loop and one inside it.
478 if (trivial || atend)
479 return false;
481 current_updated = false;
482 atend = cmgen.finished();
483 return true;
484 }
485};
486
490const numeric
491multinomial_coefficient(const std::vector<unsigned> & p);
492
493
494// Collection of `construct on first use' wrappers for safely avoiding
495// internal object replication without running into the `static
496// initialization order fiasco'. This chest of numbers helps speed up
497// the library but should not be used outside it since it is
498// potentially confusing.
499
500class ex;
501
502extern const numeric *_num_120_p;
503extern const ex _ex_120;
504extern const numeric *_num_60_p;
505extern const ex _ex_60;
506extern const numeric *_num_48_p;
507extern const ex _ex_48;
508extern const numeric *_num_30_p;
509extern const ex _ex_30;
510extern const numeric *_num_25_p;
511extern const ex _ex_25;
512extern const numeric *_num_24_p;
513extern const ex _ex_24;
514extern const numeric *_num_20_p;
515extern const ex _ex_20;
516extern const numeric *_num_18_p;
517extern const ex _ex_18;
518extern const numeric *_num_15_p;
519extern const ex _ex_15;
520extern const numeric *_num_12_p;
521extern const ex _ex_12;
522extern const numeric *_num_11_p;
523extern const ex _ex_11;
524extern const numeric *_num_10_p;
525extern const ex _ex_10;
526extern const numeric *_num_9_p;
527extern const ex _ex_9;
528extern const numeric *_num_8_p;
529extern const ex _ex_8;
530extern const numeric *_num_7_p;
531extern const ex _ex_7;
532extern const numeric *_num_6_p;
533extern const ex _ex_6;
534extern const numeric *_num_5_p;
535extern const ex _ex_5;
536extern const numeric *_num_4_p;
537extern const ex _ex_4;
538extern const numeric *_num_3_p;
539extern const ex _ex_3;
540extern const numeric *_num_2_p;
541extern const ex _ex_2;
542extern const numeric *_num_1_p;
543extern const ex _ex_1;
544extern const numeric *_num_1_2_p;
545extern const ex _ex_1_2;
546extern const numeric *_num_1_3_p;
547extern const ex _ex_1_3;
548extern const numeric *_num_1_4_p;
549extern const ex _ex_1_4;
550extern const numeric *_num0_p;
551extern const basic *_num0_bp;
552extern const ex _ex0;
553extern const numeric *_num1_4_p;
554extern const ex _ex1_4;
555extern const numeric *_num1_3_p;
556extern const ex _ex1_3;
557extern const numeric *_num1_2_p;
558extern const ex _ex1_2;
559extern const numeric *_num1_p;
560extern const ex _ex1;
561extern const numeric *_num2_p;
562extern const ex _ex2;
563extern const numeric *_num3_p;
564extern const ex _ex3;
565extern const numeric *_num4_p;
566extern const ex _ex4;
567extern const numeric *_num5_p;
568extern const ex _ex5;
569extern const numeric *_num6_p;
570extern const ex _ex6;
571extern const numeric *_num7_p;
572extern const ex _ex7;
573extern const numeric *_num8_p;
574extern const ex _ex8;
575extern const numeric *_num9_p;
576extern const ex _ex9;
577extern const numeric *_num10_p;
578extern const ex _ex10;
579extern const numeric *_num11_p;
580extern const ex _ex11;
581extern const numeric *_num12_p;
582extern const ex _ex12;
583extern const numeric *_num15_p;
584extern const ex _ex15;
585extern const numeric *_num18_p;
586extern const ex _ex18;
587extern const numeric *_num20_p;
588extern const ex _ex20;
589extern const numeric *_num24_p;
590extern const ex _ex24;
591extern const numeric *_num25_p;
592extern const ex _ex25;
593extern const numeric *_num30_p;
594extern const ex _ex30;
595extern const numeric *_num48_p;
596extern const ex _ex48;
597extern const numeric *_num60_p;
598extern const ex _ex60;
599extern const numeric *_num120_p;
600extern const ex _ex120;
601
602
603// Helper macros for class implementations (mostly useful for trivial classes)
604
605#define DEFAULT_CTOR(classname) \
606classname::classname() { setflag(status_flags::evaluated | status_flags::expanded); }
607
608#define DEFAULT_COMPARE(classname) \
609int classname::compare_same_type(const basic & other) const \
610{ \
611 /* by default, the objects are always identical */ \
612 return 0; \
613}
614
615#define DEFAULT_PRINT(classname, text) \
616void classname::do_print(const print_context & c, unsigned level) const \
617{ \
618 c.s << text; \
619}
620
621#define DEFAULT_PRINT_LATEX(classname, text, latex) \
622DEFAULT_PRINT(classname, text) \
623void classname::do_print_latex(const print_latex & c, unsigned level) const \
624{ \
625 c.s << latex; \
626}
627
628} // namespace GiNaC
629
630#endif // ndef GINAC_UTILS_H
Assertion macro definition.
Base class for generating all bounded combinatorial partitions of an integer n with exactly m parts i...
Definition utils.h:277
basic_partition_generator(unsigned n_, unsigned m_)
Definition utils.h:318
Generate all compositions of a partition of an integer n, starting with the compositions which has no...
Definition utils.h:394
std::vector< unsigned > composition
Definition utils.h:450
struct GiNaC::composition_generator::coolmulti cmgen
composition_generator(const std::vector< unsigned > &partition)
Definition utils.h:453
const std::vector< unsigned > & get() const
Definition utils.h:459
Exception class thrown by functions to signal unimplemented functionality so the expression may just ...
Definition utils.h:36
Generate all bounded combinatorial partitions of an integer n with exactly m parts (not including zer...
Definition utils.h:365
const std::vector< unsigned > & get() const
Definition utils.h:374
partition_generator(unsigned n_, unsigned m_)
Definition utils.h:370
std::vector< unsigned > partition
Definition utils.h:367
Generate all bounded combinatorial partitions of an integer n with exactly m parts (including zero pa...
Definition utils.h:326
partition_with_zero_parts_generator(unsigned n_, unsigned m_)
Definition utils.h:332
const std::vector< unsigned > & get() const
Definition utils.h:336
std::vector< unsigned > partition
Definition utils.h:329
vector< int > k
Definition factor.cpp:1434
size_t n
Definition factor.cpp:1431
size_t last
Definition factor.cpp:1433
Definition add.cpp:35
const ex _ex_20
Definition utils.cpp:295
const numeric * _num_3_p
Definition utils.cpp:342
const numeric * _num_24_p
Definition utils.cpp:290
const ex _ex_12
Definition utils.cpp:307
const numeric * _num1_3_p
Definition utils.cpp:375
const ex _ex9
Definition utils.cpp:416
const numeric * _num_1_p
Definition utils.cpp:350
const ex _ex_120
Definition utils.cpp:271
const ex _ex2
Definition utils.cpp:388
const numeric * _num_120_p
Definition utils.cpp:270
const ex _ex_1_2
Definition utils.cpp:355
const numeric * _num_30_p
Definition utils.cpp:282
const numeric * _num6_p
Definition utils.cpp:403
unsigned golden_ratio_hash(uintptr_t n)
Truncated multiplication with golden ratio, for computing hash values.
Definition utils.h:67
const numeric * _num_1_3_p
Definition utils.cpp:358
const ex _ex1_2
Definition utils.cpp:380
const numeric * _num_1_2_p
Definition utils.cpp:354
const numeric * _num3_p
Definition utils.cpp:391
const ex _ex7
Definition utils.cpp:408
const numeric * _num_1_4_p
Definition utils.cpp:362
const numeric * _num1_2_p
Definition utils.cpp:379
const ex _ex24
Definition utils.cpp:444
const numeric * _num25_p
Definition utils.cpp:447
const ex _ex12
Definition utils.cpp:428
const ex _ex1
Definition utils.cpp:384
const numeric * _num_10_p
Definition utils.cpp:314
const ex _ex_60
Definition utils.cpp:275
const numeric * _num_8_p
Definition utils.cpp:322
const numeric * _num1_4_p
Definition utils.cpp:371
const numeric * _num_5_p
Definition utils.cpp:334
int compare_pointers(const T *a, const T *b)
Compare two pointers (just to establish some sort of canonical order).
Definition utils.h:55
const numeric * _num24_p
Definition utils.cpp:443
const ex _ex15
Definition utils.cpp:432
const numeric * _num_11_p
Definition utils.cpp:310
const numeric * _num30_p
Definition utils.cpp:451
const ex _ex3
Definition utils.cpp:392
const numeric * _num10_p
Definition utils.cpp:419
const ex _ex6
Definition utils.cpp:404
const numeric * _num4_p
Definition utils.cpp:395
const numeric * _num_12_p
Definition utils.cpp:306
const numeric * _num_2_p
Definition utils.cpp:346
const numeric * _num_9_p
Definition utils.cpp:318
const numeric * _num2_p
Definition utils.cpp:387
const ex _ex11
Definition utils.cpp:424
const ex _ex_4
Definition utils.cpp:339
const ex _ex_24
Definition utils.cpp:291
const ex _ex_25
Definition utils.cpp:287
const ex _ex120
Definition utils.cpp:464
const numeric * _num11_p
Definition utils.cpp:423
const numeric * _num_48_p
Definition utils.cpp:278
const numeric * _num7_p
Definition utils.cpp:407
const ex _ex_5
Definition utils.cpp:335
const ex _ex_1
Definition utils.cpp:351
const ex _ex_3
Definition utils.cpp:343
const numeric * _num12_p
Definition utils.cpp:427
const ex _ex20
Definition utils.cpp:440
const numeric * _num48_p
Definition utils.cpp:455
unsigned log2(unsigned n)
Integer binary logarithm.
Definition utils.cpp:47
const ex _ex30
Definition utils.cpp:452
const numeric * _num_6_p
Definition utils.cpp:330
const ex _ex_6
Definition utils.cpp:331
const numeric * _num9_p
Definition utils.cpp:415
const basic * _num0_bp
Definition utils.cpp:367
const numeric * _num_18_p
Definition utils.cpp:298
const ex _ex_2
Definition utils.cpp:347
const ex _ex_10
Definition utils.cpp:315
const ex _ex4
Definition utils.cpp:396
const ex _ex_15
Definition utils.cpp:303
const ex _ex5
Definition utils.cpp:400
unsigned rotate_left(unsigned n)
Rotate bits of unsigned value by one bit to the left.
Definition utils.h:47
const ex _ex_7
Definition utils.cpp:327
const numeric * _num_60_p
Definition utils.cpp:274
const ex _ex25
Definition utils.cpp:448
const numeric * _num_7_p
Definition utils.cpp:326
const numeric * _num1_p
Definition utils.cpp:383
const numeric * _num8_p
Definition utils.cpp:411
const ex _ex10
Definition utils.cpp:420
void shaker_sort(It first, It last, Cmp comp, Swap swapit)
Definition utils.h:192
const ex _ex48
Definition utils.cpp:456
const numeric * _num_15_p
Definition utils.cpp:302
const ex _ex18
Definition utils.cpp:436
void cyclic_permutation(It first, It last, It new_first, Swap swapit)
Definition utils.h:243
void swap(ex &e1, ex &e2)
Definition ex.h:838
const ex _ex_11
Definition utils.cpp:311
const numeric * _num60_p
Definition utils.cpp:459
const ex _ex_1_4
Definition utils.cpp:363
const ex _ex60
Definition utils.cpp:460
const ex _ex1_4
Definition utils.cpp:372
const ex _ex_48
Definition utils.cpp:279
int permutation_sign(It first, It last)
Definition utils.h:76
const numeric * _num_4_p
Definition utils.cpp:338
const numeric * _num15_p
Definition utils.cpp:431
const ex _ex_8
Definition utils.cpp:323
const ex _ex_1_3
Definition utils.cpp:359
const ex _ex0
Definition utils.cpp:368
const numeric * _num120_p
Definition utils.cpp:463
const ex _ex_18
Definition utils.cpp:299
const numeric * _num_20_p
Definition utils.cpp:294
const ex _ex_30
Definition utils.cpp:283
const numeric * _num_25_p
Definition utils.cpp:286
const numeric multinomial_coefficient(const std::vector< unsigned > &p)
Compute the multinomial coefficient n!/(p1!*p2!*...*pk!) where n = p1+p2+...+pk, i....
Definition utils.cpp:59
const numeric * _num20_p
Definition utils.cpp:439
const numeric * _num18_p
Definition utils.cpp:435
const ex _ex8
Definition utils.cpp:412
const ex _ex_9
Definition utils.cpp:319
const numeric * _num0_p
Definition utils.cpp:366
const numeric * _num5_p
Definition utils.cpp:399
const ex _ex1_3
Definition utils.cpp:376
void swap(GiNaC::ex &a, GiNaC::ex &b)
Specialization of std::swap() for ex objects.
Definition ex.h:991
mpartition2(unsigned n_, unsigned m_)
Definition utils.h:288
coolmulti(const std::vector< unsigned > &partition)
Definition utils.h:414

This page is part of the GiNaC developer's reference. It was generated automatically by doxygen. For an introduction, see the tutorial.