OPAL (Object Oriented Parallel Accelerator Library)  2.2.0
OPAL
FTps.hpp
Go to the documentation of this file.
1 #ifndef CLASSIC_FTps_CC
2 #define CLASSIC_FTps_CC
3 
4 // ------------------------------------------------------------------------
5 // $RCSfile: FTps.cpp,v $
6 // ------------------------------------------------------------------------
7 // $Revision: 1.5.2.15 $
8 // ------------------------------------------------------------------------
9 // Copyright: see Copyright.readme
10 // ------------------------------------------------------------------------
11 //
12 // Template class: FTps<T,N>
13 // Representation of a truncated power series
14 // with values of type T and a fixed number of variables N.
15 //
16 // ------------------------------------------------------------------------
17 // Class category: FixedAlgebra
18 // ------------------------------------------------------------------------
19 //
20 // $Date: 2003/11/07 18:06:20 $
21 // $Author: dbruhwil $
22 //
23 // ------------------------------------------------------------------------
24 
25 //#define DEBUG_FTps_CC
26 
27 #include "FixedAlgebra/FTps.h"
28 #include "FixedAlgebra/FTpsData.h"
29 #include "Algebra/Array1D.h"
30 #include "FixedAlgebra/FArray1D.h"
31 #include "FixedAlgebra/FMatrix.h"
32 #include "FixedAlgebra/FMonomial.h"
33 #include "FixedAlgebra/FVector.h"
35 #include "Utilities/DivideError.h"
36 #include "Utilities/FormatError.h"
37 #include "Utilities/LogicalError.h"
38 #include <climits>
39 #include <algorithm>
40 #include <iomanip>
41 #include <iostream>
42 #include <functional>
43 #include <string>
44 
45 
46 // Representation class FTpsRep<T,N>.
47 // The representation of an FTps<T,N> is based on a mechanism which avoids
48 // frequent memory allocations.
49 // This code contains various tweaks for speed.
50 // ------------------------------------------------------------------------
51 
52 template<class T, int N>
53 const int FTps<T, N> :: EXACT = INT_MAX;
54 
55 template <class T, int N>
56 class FTpsRep {
57 
58  // The only classes allowed access to the representation.
59  friend class FTps<T, N>;
60  friend class FVps<T, N>;
61 
62  // Constructor.
63  FTpsRep(int minOrder, int maxOrder, int trcOrder);
64 
65  // Destructor.
66  ~FTpsRep();
67 
68  // Clear FTpsRep<T,N> to zero.
69  void clear();
70 
71  // Clear FTpsRep<T,N> orders minOrder through maxOrder to zero.
72  void clear(int minOrder, int maxOrder);
73 
74  // Return beginning of monomial array.
75  T *begin() const
76  { return data; }
77 
78  // Return end of monomial array.
79  T *end() const
80  { return data + len; }
81 
82  // Return beginning of coefficient storage for given order.
83  T *begin(int order) const
84  { return data + FTpsData<N>::orderStart(order); }
85 
86  // Return end of coefficient storage for given order.
87  T *end(int order) const
88  { return data + FTpsData<N>::orderEnd(order); }
89 
90  // Pointer to next object in memory pool, when free.
92 
93  // Reference count.
94  int ref;
95 
96  // Orders of this object.
97  int minOrd; // The lowest order which contains non-zero coefficients.
98  int maxOrd; // The highest order which contains non-zero coefficients.
99  int trcOrd; // The truncation (precision) order, beyond which terms are truncated.
100  int allocOrd; // The allocation order: the maximum order for which this FTpsRep has memory.
101  // Note: We must have: 0 <= minOrd <= maxOrd <= allocOrd < EXACT,
102  // maxOrd <= trcOrd,
103  // and trcOrd _either_ <= allocOrd _or_ = EXACT.
104  // Also, if trcOrd == EXACT, then (initially) allocOrd == maxOrd.
105 
106  // Length of coefficient array.
107  int len;
108 
109  // Coefficient array.
110  T *data;
111 };
112 
113 
114 // Implementation of representation class FTpsRep<T,N>.
115 // ------------------------------------------------------------------------
116 
117 template <class T, int N>
118 FTpsRep<T, N>::FTpsRep(int minOrder, int maxOrder, int trcOrder):
119  next(0), ref(1), minOrd(minOrder), maxOrd(maxOrder), trcOrd(trcOrder) {
120  allocOrd = trcOrd;
124  data = new T[len];
125 }
126 
127 
128 template <class T, int N>
130  delete [] data;
131 }
132 
133 
134 template <class T, int N>
136  clear(minOrd, maxOrd);
137 }
138 
139 
140 template <class T, int N>
141 void FTpsRep<T, N>::clear(int minOrder, int maxOrder) {
142  std::fill(data + FTpsData<N>::orderStart(minOrder),
143  data + FTpsData<N>::orderEnd(maxOrder), T(0));
144 }
145 
146 
147 
148 // Implementation of template class FTps<T,N>.
149 // ------------------------------------------------------------------------
150 
151 template <class T, int N>
153 
154 template <class T, int N>
156 
157 
158 template <class T, int N>
160  itsRep = allocate(0, 0, EXACT);
161  itsRep->data[0] = T(0);
162 }
163 
164 
165 template <class T, int N>
167  itsRep = rhs.itsRep;
168  itsRep->ref++;
169 }
170 
171 
172 template <class T, int N>
173 FTps<T, N>::FTps(int minOrder, int maxOrder, int trcOrder) {
174  itsRep = allocate(minOrder, maxOrder, trcOrder);
175  itsRep->clear(minOrder, maxOrder);
176 }
177 
178 
179 template <class T, int N>
180 FTps<T, N>::FTps(const T &rhs) {
181  itsRep = allocate(0, 0, EXACT);
182  itsRep->data[0] = rhs;
183 }
184 
185 
186 template <class T, int N>
188  itsRep = allocate(0, 0, EXACT);
189  itsRep->data[0] = T(rhs);
190 }
191 
192 
193 template <class T, int N>
195  itsRep->ref--;
196  if(itsRep->ref == 0) deallocate(itsRep);
197 }
198 
199 
200 template <class T, int N>
202  if(itsRep != rhs.itsRep) {
203  itsRep->ref--;
204  if(itsRep->ref == 0) deallocate(itsRep);
205  itsRep = rhs.itsRep;
206  itsRep->ref++;
207  }
208  return *this;
209 }
210 
211 
212 template <class T, int N>
214  itsRep->ref--;
215  if(itsRep->ref == 0) deallocate(itsRep);
216  itsRep = allocate(0, 0, EXACT);
217  itsRep->data[0] = T(rhs);
218  return *this;
219 }
220 
221 
222 template <class T, int N>
223 const T FTps<T, N>::getCoefficient(int index) const {
224  if(index < 0) {
225  std::cerr << " <*** WARNING ***> from FTps<T,N>::getCoefficient(index):\n"
226  << " No coefficient has a negative index; returning 0." << std::endl;
227  return T(0);
228  }
229 
230  if(index < orderStart(itsRep->minOrd) || orderEnd(itsRep->maxOrd) <= index) return T(0);
231  return itsRep->data[index];
232 }
233 
234 
235 template <class T, int N>
236 void FTps<T, N>::setCoefficient(int index, const T &value) {
237  if(index < 0) {
238  std::cerr << " <*** WARNING ***> from FTps<T,N>::setCoefficient(index, value):\n"
239  << " Ignoring request because index < 0." << std::endl;
240  return;
241  }
242 
243  int order = FTpsData<N>::getOrder(index);
244 
245  // Ignore requests beyond truncation order.
246  if(order > itsRep->trcOrd) return;
247 
248  // If necessary, allocate more space.
249  // (This happens _only_ if itsRep->trcOrd == EXACT.)
250  if(order > itsRep->allocOrd) grow(order, EXACT);
251 
252  // Set coefficient.
253  unique();
254  if(order < itsRep->minOrd) setMinOrder(order);
255  else if(order > itsRep->maxOrd) setMaxOrder(order);
256  itsRep->data[index] = value;
257 }
258 
259 
260 template <class T, int N>
261 const T FTps<T, N>::getCoefficient(const FMonomial<N> &mono) const {
262  int index = FTpsData<N>::getIndex(mono);
263  return getCoefficient(index);
264 }
265 
266 
267 template <class T, int N>
268 void FTps<T, N>::setCoefficient(const FMonomial<N> &mono, const T &value) {
269  int index = FTpsData<N>::getIndex(mono);
270  setCoefficient(index, value);
271 }
272 
273 
274 template <class T, int N>
275 inline const T FTps<T, N>::operator[](int index) const {
276  return itsRep->data[index];
277 }
278 
279 
280 template <class T, int N>
281 inline T &FTps<T, N>::operator[](int index) {
282  unique();
283  return itsRep->data[index];
284 }
285 
286 
287 template <class T, int N>
288 const T FTps<T, N>::operator[](const FMonomial<N> &mono) const {
289  int index = FTpsData<N>::getIndex(mono);
290  return itsRep->data[index];
291 }
292 
293 
294 template <class T, int N>
296  unique();
297  int index = FTpsData<N>::getIndex(mono);
298  return itsRep->data[index];
299 }
300 
301 
302 template <class T, int N>
303 int FTps<T, N>::getSize(int order) {
304  return FTpsData<N>::getSize(order);
305 }
306 
307 
308 template <class T, int N>
310  return FTpsData<N>::getExponents(index);
311 }
312 
313 
314 template <class T, int N>
316  return FTpsData<N>::getIndex(mono);
317 }
318 
319 
320 template <class T, int N>
321 void FTps<T, N>::setMinOrder(int order) {
322  // Check sanity.
323  if(order == EXACT)
324  throw LogicalError("FTps<T,N>::setMinOrder(order)", "Cannot set minimum order to EXACT.");
325  if(order < 0)
326  throw LogicalError("FTps<T,N>::setMinOrder(order)", "Cannot set a negative minimum order.");
327  if(order > globalTruncOrder)
328  throw LogicalError("FTps<T,N>::setMinOrder(order)",
329  "Cannot set minimum order beyond globalTruncOrder.");
330 
331  unique();
332  // Ignore requests beyond truncation order, but issue a warning.
333  if(order > itsRep->trcOrd) {
334  std::cerr << " <*** WARNING ***> from FTps<T,N>::setMinOrder(order):\n"
335  << " Cannot set minimum order above truncation order;\n"
336  << " raising both minimum and maximum orders to truncation order." << std::endl;
337  order = itsRep->trcOrd;
338  }
339  // If necessary, allocate more space.
340  // (This can happen _only_ if itsRep->trcOrd == EXACT.)
341  else if(order > itsRep->allocOrd) grow(order, EXACT);
342 
343  // If raising minOrd above maxOrd, drag max with it and clear that order.
344  if(order > itsRep->maxOrd) {
345  itsRep->maxOrd = order;
346  itsRep->clear(order, order);
347  }
348  // If decreasing minOrd, stuff zeroes into new coefficients.
349  else if(order < itsRep->minOrd) itsRep->clear(order, itsRep->minOrd - 1);
350 
351  // Set new minimum order.
352  itsRep->minOrd = order;
353 }
354 
355 
356 template <class T, int N>
357 void FTps<T, N>::setMaxOrder(int order) {
358  // Check sanity.
359  if(order == EXACT)
360  throw LogicalError("FTps<T,N>::setMaxOrder(order)", "Cannot set maximum order to EXACT.");
361  if(order < 0)
362  throw LogicalError("FTps<T,N>::setMaxOrder(order)", "Cannot set a negative maximum order.");
363  if(order > globalTruncOrder)
364  throw LogicalError("FTps<T,N>::setMaxOrder(order)",
365  "Cannot set maximum order beyond globalTruncOrder.");
366 
367  unique();
368  // Ignore requests beyond truncation order, but issue a warning.
369  if(order > itsRep->trcOrd) {
370  std::cerr << " <*** WARNING ***> from FTps<T,N>::setMaxOrder(order):\n"
371  << " Cannot set maximum order above truncation order;\n"
372  << " raising maximum order to truncation order." << std::endl;
373  order = itsRep->trcOrd;
374  }
375  // If necessary, allocate more space.
376  // (This can happen _only_ if itsRep->trcOrd == EXACT.)
377  else if(order > itsRep->allocOrd) grow(order, EXACT);
378 
379  // If increasing maxOrd, stuff zeroes into new coefficients.
380  if(order > itsRep->maxOrd) itsRep->clear(itsRep->maxOrd + 1, order);
381  // If lowering maxOrd below minOrd, drag min with it and clear that order.
382  else if(order < itsRep->minOrd) {
383  itsRep->minOrd = order;
384  itsRep->clear(order, order);
385  }
386 
387  // Set new maximum order.
388  itsRep->maxOrd = order;
389 }
390 
391 
392 template <class T, int N>
393 void FTps<T, N>::setTruncOrder(int order) {
394  // Check sanity.
395  if(order != EXACT && order < 0)
396  throw LogicalError("FTps<T,N>::setTruncOrder(order)", "Cannot set a negative truncation order.");
397  if(order != EXACT && order > globalTruncOrder)
398  throw LogicalError("FTps<T,N>::setTruncOrder(order)",
399  "Cannot set truncation order beyond globalTruncOrder.");
400 
401  unique();
402  // If lowering trcOrd below minOrd, drag min and max with it, and clear that order.
403  if(order < itsRep->minOrd) {
404  itsRep->minOrd = order;
405  itsRep->maxOrd = order;
406  itsRep->clear(order, order);
407  }
408  // If lowering trcOrd below maxOrd, drag max with it.
409  else if(order < itsRep->maxOrd) itsRep->maxOrd = order;
410  // If necessary, allocate more space.
411  else if(order != EXACT && order > itsRep->allocOrd) grow(itsRep->maxOrd, order);
412 
413  // Set new truncation order.
414  itsRep->trcOrd = order;
415 }
416 
417 
418 template <class T, int N>
420  // Check sanity.
421  if(order == EXACT)
422  throw LogicalError("FTps<T,N>::setGlobalTruncOrder(order)", "Cannot make globalTruncOrder EXACT.");
423  if(order <= 0)
424  throw LogicalError("FTps<T,N>::setGlobalTruncOrder(order)",
425  "Cannot set a negative global truncation order.");
426 
427  globalTruncOrder = order;
428  FTpsData<N>::setup(order);
429 }
430 
431 
432 template <class T, int N>
434  return FTpsData<N>::getProductArray(index);
435 }
436 
437 
438 template <class T, int N>
440  return FTpsData<N>::getVariableList(index);
441 }
442 
443 
444 template <class T, int N>
446  return FTpsData<N>::getSubTable();
447 }
448 
449 
450 template <class T, int N>
451 FTps<T, N> FTps<T, N>::filter(int minOrder, int maxOrder, int trcOrder) const {
452  // Default: trcOrder = EXACT
453  checkOrders("filter(minOrder, maxOrder, trcOrder)", minOrder, maxOrder, trcOrder);
454 
455  // Compute order limits.
456  int myMin = std::max(minOrder, itsRep->minOrd);
457  int myMax = std::min(maxOrder, itsRep->maxOrd);
458  int myTrc = std::min(trcOrder, itsRep->trcOrd);
459 
460  bool OLflag = true;
461  if(myMin > myMax) { // no overlap exists
462  OLflag = false;
463  myMin = std::min(minOrder, myTrc);
464  myMax = std::min(maxOrder, myTrc);
465  }
466  // Construct filtered FTpsRep.
467  FTps<T, N> result(myMin, myMax, myTrc);
468  if(OLflag) std::copy(begin(myMin), end(myMax), result.begin(myMin));
469 
470  return result;
471 }
472 
473 
474 template <class T, int N> inline
476  return filter(0, trunc, trunc);
477 }
478 
479 
480 template <class T, int N>
482  FTps<T, N> result(1, 1, EXACT);
483  result[var + 1] = T(1);
484  return result;
485 }
486 
487 
488 template <class T, int N>
490  FMonomial<N> mono;
491  mono[var] = order;
492  FTps<T, N> result(order, order, EXACT);
493  result[mono] = T(1);
494  return result;
495 }
496 
497 
498 template <class T, int N>
499 FTps<T, N> FTps<T, N>::makeMonomial(int index, const T &val) {
500  int order = FTpsData<N>::getOrder(index);
501  FTps<T, N> result(order, order, EXACT);
502  result[index] = val;
503  return result;
504 }
505 
506 
507 template <class T, int N>
509  int order = mono.getOrder();
510  FTps<T, N> result(order, order, EXACT);
511  result[mono] = val;
512  return result;
513 }
514 
515 
516 template <class T, int N>
518  return *this;
519 }
520 
521 
522 template <class T, int N>
524  int minOrder = getMinOrder();
525  int maxOrder = getMaxOrder();
526  FTps<T, N> result(minOrder, maxOrder, getTruncOrder());
527  std::transform(begin(minOrder), end(maxOrder), result.begin(minOrder), std::negate<T>());
528  return result;
529 }
530 
531 
532 template <class T, int N>
534  return *this = *this + rhs;
535 }
536 
537 
538 template <class T, int N>
540  return *this = *this - rhs;
541 }
542 
543 
544 template <class T, int N>
546  return *this = multiply(rhs);
547 }
548 
549 
550 template <class T, int N>
552  return *this = divide(rhs);
553 }
554 
555 
556 template <class T, int N>
558  unique();
559  setMinOrder(0);
560  itsRep->data[0] += rhs;
561  return *this;
562 }
563 
564 
565 template <class T, int N>
567  unique();
568  setMinOrder(0);
569  itsRep->data[0] -= rhs;
570  return *this;
571 }
572 
573 
574 template <class T, int N>
576  unique();
577  std::transform(begin(getMinOrder()), end(getMaxOrder()), begin(getMinOrder()),
578  std::bind(std::multiplies<T>(), std::placeholders::_1, rhs));
579  return *this;
580 }
581 
582 template <class T, int N>
584  if(rhs == T(0)) throw DivideError("FTps::operator/=()");
585  return *this *= T(1) / rhs;
586 }
587 
588 template <class T, int N>
590  // Determine orders of result.
591  int f_min = getMinOrder();
592  int g_min = rhs.getMinOrder();
593  int f_max = getMaxOrder();
594  int g_max = rhs.getMaxOrder();
595  int trcOrder = std::min(getTruncOrder(), rhs.getTruncOrder());
596  int minOrder = std::max(f_min, g_min);
597  int maxOrder = std::min(f_max, g_max);
598 
599  if(minOrder <= maxOrder) { // overlap exists
600  FTps<T, N> result(minOrder, maxOrder, trcOrder);
601  std::transform(begin(minOrder), end(maxOrder), rhs.begin(minOrder),
602  result.begin(minOrder), std::multiplies<T>());
603  return result;
604  } else // no overlap ==> complain big time!
605  throw LogicalError("FTps<T,N>::scaleMonomials(rhs)", "No overlap exists.");
606 }
607 
608 
609 template <class T, int N>
610 FTps<T, N> FTps<T, N>::multiplyVariable(int var, int trunc) const {
611  // Default: trunc = EXACT
612 
613  int f_min = getMinOrder();
614  if(trunc <= f_min) {
615 #ifdef DEBUG_FTps_CC
616  std::cerr << " <*** WARNING ***> from FTps<T,N>::multiplyVariable(var, trunc):\n"
617  << " Result truncated out of existence; returning a zero polynomial."
618  << std::endl;
619 #endif
620  return FTps<T, N>(trunc, trunc, trunc);
621  } else {
622  // Determine orders of result.
623  int trcOrder = getTruncOrder();
624  if (trcOrder == EXACT) {
625  trcOrder = trunc;
626  } else {
627  ++ trcOrder;
628  trcOrder = std::min(trcOrder, trunc);
629  }
630  // trcOrder = (trcOrder == EXACT) ? trunc : std::min((++trcOrder), trunc);
631  int maxOrder = std::min(1 + getMaxOrder(), trcOrder);
632 
633  // Allocate result.
634  FTps<T, N> result(1 + f_min, maxOrder, trcOrder);
635  const T *f = begin();
636  T *g = result.begin();
637  const Array1D<int> &product = FTpsData<N>::getProductArray(var + 1);
638 
639  // Do multiplication.
640  int ie = orderStart(maxOrder);
641  for(int i = orderStart(f_min); i < ie; i++)
642  g[product[i]] = f[i];
643  return result;
644  }
645 
646 }
647 
648 
649 template <class T, int N>
650 FTps<T, N> FTps<T, N>::multiply(const FTps<T, N> &rhs, int trunc) const {
651  // Default: trunc = EXACT
652 
653  //Determine orders of result.
654  int trcOrder;
655  if(itsRep->trcOrd == EXACT) {
656  if(rhs.itsRep->trcOrd == EXACT) trcOrder = EXACT;
657  else trcOrder = itsRep->minOrd + rhs.itsRep->trcOrd;
658  } else if(rhs.itsRep->trcOrd == EXACT) trcOrder = itsRep->trcOrd + rhs.itsRep->minOrd;
659  else trcOrder = std::min(itsRep->trcOrd + rhs.itsRep->minOrd, itsRep->minOrd + rhs.itsRep->trcOrd);
660  trcOrder = std::min(trcOrder, trunc);
661  int maxOrder = std::min(itsRep->maxOrd + rhs.itsRep->maxOrd, trcOrder);
662  int minOrder = itsRep->minOrd + rhs.itsRep->minOrd;
663 
664  if(minOrder <= maxOrder) {
665  // Allocate result.
666  FTps<T, N> result(minOrder, maxOrder, trcOrder);
667 
668  // Assign data pointers and starting indices.
669  T *f = begin();
670  T *g = rhs.begin();
671  T *h = result.begin();
672  int first_f = orderStart(itsRep->minOrd);
673  int first_g = orderStart(rhs.itsRep->minOrd);
674 
675  int f_max = itsRep->maxOrd;
676  int g_max = std::min(rhs.itsRep->maxOrd, maxOrder);
677 
678  // Loop over orders in rhs.
679  for(int gOrd = rhs.itsRep->minOrd; gOrd <= g_max; gOrd++) {
680  // Set ending indices.
681  int last_f = orderEnd(std::min(f_max, maxOrder - gOrd));
682  int last_g = orderEnd(gOrd);
683  // Do multiplies for each entry (of order gOrd) in rhs.
684  for(int j = first_g; j < last_g; j++) {
685  T gj = g[j];
686  if(gj != T(0)) {
688  for(int i = first_f; i < last_f; i++) h[prod[i]] += f[i] * gj;
689  }
690  }
691  // Reset starting index for next order of rhs.
692  first_g = last_g;
693  }
694  return result;
695  } else {
696 #ifdef DEBUG_FTps_CC
697  std::cerr << " <*** WARNING ***> from FTps<T,N>::multiply(rhs, trunc):\n"
698  << " Result truncated out of existence; returning a zero polynomial."
699  << std::endl;
700 #endif
701  return FTps<T, N>(trcOrder, trcOrder, trcOrder);
702  }
703 }
704 
705 
706 template <class T, int N>
707 FTps<T, N> FTps<T, N>::inverse(int trunc) const {
708  // Default: trunc = EXACT
709 
710  // Check sanity.
711  T b0 = itsRep->data[0];
712  if(b0 == T(0) || itsRep->minOrd != 0) {
713  std::cerr << " <*** ERROR ***> in FTps::inverse():\n"
714  << " Cannot invert a polynomial with zero constant term." << std::endl;
715  throw DivideError("FTps::inverse()");
716  }
717 
718  // Get orders.
719  int trcOrder = std::min(itsRep->trcOrd, trunc);
720  int maxOrder = std::min(itsRep->maxOrd, trcOrder);
721  if(trcOrder > globalTruncOrder)
722  throw LogicalError("FTps::inverse(trunc)", "Truncation order exceeds globalTruncOrder!");
723 
724  // Allocate result.
725  FTps<T, N> result(0, trcOrder, trcOrder);
726 
727  // Initialisations.
728  const T *b = itsRep->data;
729  T *c = result.itsRep->data;
730  c[0] = T(1) / b0;
731  T neg_c0 = -c[0];
732 
733  // Return trivial result.
734  if(trcOrder == 0) return result;
735 
736  // Loop over orders to construct.
737  for(int m = 1; m <= trcOrder; ++m) {
738  // Use the c_k's from previous orders to build this order.
739  for(int mc = 0; mc < m; ++mc) {
740  int mb = m - mc;
741  if(mb > maxOrder) continue;
742  int start_c = orderStart(mc), end_c = orderEnd(mc);
743  int start_b = orderStart(mb), end_b = orderEnd(mb);
744  for(int k = start_c; k < end_c; ++k) {
745  T ck = c[k];
746  if(ck != T(0)) {
748  for(int i = end_b; i-- > start_b;) c[prod[i]] += b[i] * ck;
749  }
750  }
751  }
752  int je = orderEnd(m);
753  for(int j = orderStart(m); j < je; ++j) c[j] *= neg_c0;
754  }
755 
756  return result;
757 }
758 
759 
760 template <class T, int N>
761 FTps<T, N> FTps<T, N>::divide(const FTps<T, N> &rhs, int trunc) const {
762  // Default: trunc = EXACT
763 
764  // Algorithm: To compute C = A / B, we may form A = B * C and equate coefficients
765  // of like terms on each side. The resulting system of equations has a "triangular"
766  // nature and can be solved explicitly in an order-by-order fashion. The
767  // coefficients of C are given by
768  // c_0 = a_0 / b_0,
769  // and c_j = (a_j - \sum_{i+k=j, i!=0} b_i * c_k) / b_0, for j!=0.
770  // These formulae hold for multivariate polynomials if we interpret the subscripts
771  // j, i, and k as exponent vectors.
772 
773  // Check sanity.
774  T b0 = rhs.itsRep->data[0];
775  if(b0 == T(0) || rhs.itsRep->minOrd != 0) {
776  std::cerr << " <*** ERROR ***> in FTps::divide(rhs,trunc):\n"
777  << " Cannot divide by a polynomial with zero constant term." << std::endl;
778  throw DivideError("FTps::divide()");
779  }
780 
781  // Get orders.
782  int a_min = getMinOrder(), a_max = getMaxOrder(), a_trc = getTruncOrder();
783  int b_max = rhs.getMaxOrder(), b_trc = rhs.getTruncOrder();
784  int c_trc;
785  if(b_trc == EXACT) c_trc = std::min(a_trc, trunc);
786  else { c_trc = std::min(a_trc, b_trc + a_min); c_trc = std::min(c_trc, trunc); }
787  if(c_trc > globalTruncOrder)
788  throw LogicalError("FTps::divide(rhs,trunc)", "Truncation order exceeds globalTruncOrder!");
789  int c_max = c_trc, c_min = a_min;
790  int ac_max_min = std::min(a_max, c_max);
791 
792  // Allocate result.
793  FTps<T, N> result(c_min, c_max, c_trc);
794 
795  // Initialisations.
796  std::copy(begin(c_min), end(ac_max_min), result.begin(c_min)); // start w/ C = A
797  const T *b = rhs.itsRep->data;
798  T *c = result.itsRep->data;
799  T b0inv = T(1) / b0;
800  if(c_min == 0) c[0] *= b0inv;
801 
802  // Return trivial result.
803  if(c_trc == 0) return result;
804 
805  // Loop over orders to construct.
806  int mi = std::max(1, c_min);
807  for(int m = mi; m <= c_max; ++m) {
808  // Use the lower-order c_k's to build the present order.
809  for(int mc = c_min; mc < m; ++mc) {
810  int mb = m - mc;
811  if(mb > b_max) continue;
812  int start_c = orderStart(mc), end_c = orderEnd(mc);
813  int start_b = orderStart(mb), end_b = orderEnd(mb);
814  for(int k = start_c; k < end_c; ++k) {
815  T ck = c[k];
816  if(ck != T(0)) {
818  for(int i = end_b; i-- > start_b;) c[prod[i]] -= b[i] * ck;
819  }
820  }
821  }
822  int je = orderEnd(m);
823  for(int j = orderStart(m); j < je; ++j) c[j] *= b0inv;
824  }
825 
826  return result;
827 }
828 
829 
830 template <class T, int N>
831 bool FTps<T, N>::operator==(const FTps<T, N> &rhs) const {
832  if(itsRep == rhs.itsRep) return true;
833  // else ...
834 
835  // Determine ranges (of indices) to test.
836  int r_trc = std::min(getTruncOrder(), rhs.getTruncOrder());
837  int f_min = orderStart(getMinOrder()), f_max = orderEnd(std::min(getMaxOrder(), r_trc));
838  int g_min = orderStart(rhs.getMinOrder()), g_max = orderEnd(std::min(rhs.getMaxOrder(), r_trc));
839  int r_min = std::min(f_min, g_min), r_max = std::max(f_max, g_max);
840 
841  const T *f = begin();
842  const T *g = rhs.begin();
843 
844  // Test *this == rhs (f == g).
845  if(g_min < f_max && f_min < g_max) { // overlap exists
846  int i = r_min, fg_max_min = std::min(f_max, g_max);
847  for(; i < g_min; i++) if(f[i] != T(0)) return false; //: test below
848  for(; i < f_min; i++) if(g[i] != T(0)) return false; // overlap
849  for(; i < fg_max_min; i++) if(f[i] != g[i]) return false; //: test overlap
850  for(; i < f_max; i++) if(f[i] != T(0)) return false; //: test above
851  for(; i < g_max; i++) if(g[i] != T(0)) return false; // overlap
852  } else { // gap exists
853  if(f_max <= g_min) { // |f| < |g|
854  for(int i = r_min ; i < f_max; i++) if(f[i] != T(0)) return false;
855  for(int i = g_min ; i < r_max; i++) if(g[i] != T(0)) return false;
856  } else { // |g| < |f|
857  for(int i = r_min; i < g_max; i++) if(g[i] != T(0)) return false;
858  for(int i = f_min; i < r_max; i++) if(f[i] != T(0)) return false;
859  }
860  }
861 
862  return true;
863 }
864 
865 
866 template <class T, int N>
867 bool FTps<T, N>::operator==(const T &rhs) const {
868  int f_min = getMinOrder();
869  const T *f = begin();
870 
871  if(f_min == 0) {
872  if(*f != rhs) return false;
873  f_min++;
874  } else if(rhs != T(0)) return false;
875 
876  int i = orderStart(f_min);
877  int iend = orderEnd(getMaxOrder());
878  for(; i < iend; i++)
879  if(f[i] != T(0)) return false;
880 
881  return true;
882 }
883 
884 
885 template <class T, int N>
886 bool FTps<T, N>::operator!=(const FTps<T, N> &rhs) const {
887  return !(*this == rhs);
888 }
889 
890 
891 template <class T, int N>
892 bool FTps<T, N>::operator!=(const T &rhs) const {
893  return !(*this == rhs);
894 }
895 
896 
897 template <class T, int N>
899  int size = getSize(maxOrder);
900 
901  // Allocate result.
902  Array1D<T> result(size);
903 
904  // Initialize pointers to monomials and argument vector.
905  T *mon = result.begin();
906  const T *z = rhs.begin();
907 
908  // Constant term.
909  *mon++ = T(1);
910 
911  // Linear terms.
912  if(maxOrder > 0) std::copy(z, z + N, mon);
913 
914  // Higher-order terms.
915  if(maxOrder > 1) {
916  mon += N;
917  int N1 = N - 1;
918  int m = 2;
919  for(; m <= maxOrder; ++m) {
920  // Build monomials of order m from those of order m-1.
921  T *monx = mon; // Remember where to stop.
922  for(int k = 0, k1 = N1; k < N; k++, k1--) {
923  T zk = z[k]; // The zk times monomials
924  T *mona = monx - FTpsData<N>::orderStart(m, k1); // [mona..monx) yield the
925  while(mona != monx) *mon++ = zk * *mona++; // next ones of order m.
926  }
927  }
928  }
929 
930  return result;
931 }
932 
933 template <class T, int N>
935  // Note: We evaluate the linear part separately
936  // not out of necessity, but to speed execution.
937 
938  // Get coefficient array, f, argument vector, z, and orders.
939  const T *f = begin();
940  const T *z = rhs.begin();
941  int minOrder = getMinOrder();
942  int maxOrder = getMaxOrder();
943 
944  // Allocate array for monomials and pointer to run along it.
945  // Using static local variable to avoid fragmenting memory.
946  // Last allocated monoms array is never deleted, but OS
947  // will take care of this when program exits.
948  static T *monoms = 0;
949  static int myOrd = -1;
950  if(maxOrder > myOrd) {
951  if(monoms) delete [] monoms;
952  monoms = new T[getSize(maxOrder)];
953  myOrd = maxOrder;
954  }
955  T *mon = monoms;
956 
957  // Initialize monomials and result.
958  *mon++ = T(1);
959  T result = T(0);
960  if(minOrder == 0) {
961  result = *f++;
962  if(maxOrder == 0) return result;
963  } else f++;
964 
965  // Load order one monomials.
966  std::copy(z, z + N, mon);
967 
968  // Accumulate linear contribution.
969  T *monx = mon + N;
970  if(minOrder <= 1) while(mon != monx) result += *f++ * *mon++;
971  else { f += N; mon = monx; }
972 
973  // Evaluate higher-order contributions.
974  // First build monomials below minOrder.
975  int N1 = N - 1;
976  int m = 2;
977  for(; m < minOrder; m++) {
978  // Build monomials of order m from those of order m-1.
979  monx = mon; // Remember where to stop.
980  for(int k = 0, k1 = N1; k < N; k++, k1--) {
981  T zk = z[k]; // The zk times monomials
982  T *mona = monx - FTpsData<N>::orderStart(m, k1); // [mona..monx)
983  while(mona != monx) { // yield the next ones
984  *mon++ = zk * *mona++; // of order m.
985  f++; // Skip coefficient.
986  }
987  }
988  }
989  // Now add in the higher-order terms.
990  for(; m <= maxOrder; m++) {
991  // Build monomials of order m from those of order m-1.
992  monx = mon; // Remember where to stop.
993  for(int k = 0, k1 = N1; k < N; k++, k1--) {
994  T zk = z[k]; // The zk times monomials
995  T *mona = monx - FTpsData<N>::orderStart(m, k1); // [mona..monx)
996  while(mona != monx) { // yield the next ones
997  *mon = zk * *mona++; // of order m.
998  result += *f++ * *mon++; // Accumulate result.
999  }
1000  }
1001  }
1002 
1003  return result;
1004 }
1005 
1006 
1007 template <class T, int N>
1009  // Default: trunc = EXACT
1010 
1011  // Get orders.
1012  Array1D<int> ordersL(3), ordersR(3);
1013  ordersL[0] = getMinOrder(), ordersL[1] = getMaxOrder(), ordersL[2] = getTruncOrder();
1014  ordersR[0] = rhs.getMinOrder(), ordersR[1] = rhs.getMaxOrder(), ordersR[2] = rhs.getTruncOrder();
1015 
1016  Array1D<int> result = getSubstOrders(ordersL, ordersR, trunc);
1017  return result;
1018 }
1019 
1020 
1021 template <class T, int N>
1023  // Default: trunc = EXACT
1024 
1025  // Get orders.
1026  int f_min = ordersL[0], f_max = ordersL[1], f_trc = ordersL[2];
1027  int r_min = ordersR[0], r_max = ordersR[1], r_trc = ordersR[2];
1028  int g_min = f_min * r_min, g_max = f_max * r_max, g_trc;
1029  if(f_trc == EXACT) {
1030  if(r_trc == EXACT) {g_trc = (g_max <= trunc) ? EXACT : trunc;}
1031  else {
1032  if(f_max == 0) g_trc = EXACT;
1033  else {
1034  g_trc = r_trc;
1035  if(f_min != 0) g_trc += g_min - r_min;
1036  g_trc = std::min(g_trc, trunc);
1037  }
1038  }
1039  } else { // f_trc != EXACT
1040  if(r_min != 0) {
1041  g_trc = std::min((f_trc + 1) * r_min - 1, trunc);
1042  if(r_trc != EXACT && f_max != 0) {
1043  int t_trc = r_trc;
1044  if(f_min != 0) t_trc += g_min - r_min;
1045  g_trc = std::min(g_trc, t_trc);
1046  }
1047  } else { // r_min == 0
1048 #ifdef DEBUG_FTps_CC
1049  std::cerr << " <*** WARNING ***> from FTps<T,N>::getSubstOrders(ordersL,ordersR,trunc):\n"
1050  << " Incomplete computation of feed-down terms.\n" << std::endl;
1051 #endif
1052  if(f_max == 0) g_trc = 0;
1053  else {
1054  g_trc = std::min(f_trc, r_trc);
1055  g_trc = std::min(g_trc, trunc);
1056  }
1057  }
1058  }
1059 
1060  g_max = std::min(g_max, g_trc);
1061  // NB: If trunc is sufficiently small, it can happen that this last line sets
1062  // g_max (== g_trc) below g_min. This will mean that g = 0 + O(z^{g_trc+1}).
1063  // Any routine that calls this one MUST check for this possibility.
1064 
1065  Array1D<int> orders(3);
1066  orders[0] = g_min;
1067  orders[1] = g_max;
1068  orders[2] = g_trc;
1069 
1070  return orders;
1071 }
1072 
1073 
1074 template <class T, int N>
1076  // Check sanity.
1077  if(n < 0)
1078  throw LogicalError("FTps<T,N>::substitute(mat,n)",
1079  "Transformation order, n, is negative.");
1080  else if(n > globalTruncOrder)
1081  throw LogicalError("FTps<T,N>::substitute(mat,n)",
1082  "Transformation order, n, exceeds globalTruncOrder.");
1083 
1084  // Get orders.
1085  int minOrder = getMinOrder(), maxOrder = getMaxOrder(), trcOrder = getTruncOrder();
1086 
1087  //Allocate result.
1088  FTps<T, N> result(minOrder, maxOrder, trcOrder);
1089  std::copy(begin(minOrder), end(maxOrder), result.begin(minOrder));
1090 
1091  // Return trivial cases.
1092  if(n > trcOrder) {
1093 #ifdef DEBUG_FTps_CC
1094  std::cerr << " <*** WARNING ***> from FTps<T,N>::substitute(mat,n):\n"
1095  << " Transformation order exceeds truncation order;\n"
1096  << " returning polynomial unchanged." << std::endl;
1097 #endif
1098  return result;
1099  }
1100  if(n == 0 || n < minOrder || maxOrder < n) return result;
1101 
1102  // Allocate working array; use static
1103  // local memory to avoid fragmentation.
1104  // NB: Instead of static local memory, one could use the data storage of an FTps
1105  // ---it's the correct size, it's reference counted, and it's retained on a stack.
1106  static T *t = 0;
1107  static int max_n = -1;
1108  if(n > max_n) {
1109  if(t) delete [] t;
1110  t = new T[getSize(n)];
1111  max_n = n;
1112  }
1113 
1114  // Initialisations.
1115  const T *fj = begin(n);
1116  T *g = result.begin();
1117  T *t1 = t + 1;
1118  const Array1D<int> *oldvrbl = 0;
1119  int start_n = orderStart(n), end_n = orderEnd(n);
1120 
1121  // Clear order n.
1122  std::fill(g + start_n, g + end_n, T(0));
1123 
1124  // Loop over order n monomials.
1125  for(int j = start_n; j < end_n; ++j, ++fj) {
1126  // Skip monomials with coefficient zero.
1127  if(*fj == T(0)) continue;
1128 
1129  // Get current monomial's variable list; compare with old variable list.
1130  const Array1D<int> *vrbl = &FTpsData<N>::getVariableList(j);
1131  int vi = 0;
1132  if(oldvrbl)
1133  while((*vrbl)[vi] == (*oldvrbl)[vi]) ++vi;
1134 
1135  const T *mv;
1136  int ord;
1137  // If vi = 0, we must start at the beginning; otherwise,
1138  // we may re-use the first vi orders stored in t.
1139  if(vi == 0) {
1140  mv = mat[(*vrbl)[0]];
1141  std::copy(mv, mv + N, t1);
1142  ord = 2;
1143  } else ord = vi + 1;
1144 
1145  // In working array t, clear orders we can't use.
1146  std::fill(t + orderStart(ord), t + end_n, T(0));
1147  // Build the remainder.
1148  while(ord <= n) {
1149  // Build next order part of transformed monomial by multiplying
1150  // the part that is one order lower by the transformed version
1151  // of the next variable in the variable list.
1152  int ord1 = ord - 1;
1153  int start_l = orderStart(ord1), end_l = orderEnd(ord1);
1154  mv = mat[(*vrbl)[ord1]]; // transformed version of next variable
1155  for(int k = 0; k < N; k++) {
1156  T mvk = mv[k];
1157  if(mvk == T(0)) continue;
1159  for(int l = start_l; l < end_l; l++) t[prod[l]] += mvk * t[l];
1160  }
1161  ++ord;
1162  }
1163  //Increment g by f[j] * transformed monomial.
1164  for(int i = start_n; i < end_n; i++) g[i] += *fj * t[i];
1165  // Save variable list for comparison with the next one.
1166  oldvrbl = vrbl;
1167  }
1168 
1169  return result;
1170 }
1171 
1172 
1173 template <class T, int N>
1174 FTps<T, N> FTps<T, N>::substitute(const FMatrix<T, N, N> &mat, int nl, int nh) const {
1175  // Check sanity.
1176  if(nl > nh)
1177  throw LogicalError("FTps<T,N>::substitute(mat,nl,nh)",
1178  "Inconsistent transformation orders: nl > nh.");
1179  if(nl < 0)
1180  throw LogicalError("FTps<T,N>::substitute(mat,nl,nh)",
1181  "Transformation order nl is negative.");
1182  else if(nh > globalTruncOrder)
1183  throw LogicalError("FTps<T,N>::substitute(mat,nl,nh)",
1184  "Transformation order nh exceeds globalTruncOrder.");
1185 
1186  // Get orders.
1187  int minOrder = getMinOrder(), maxOrder = getMaxOrder(), trcOrder = getTruncOrder();
1188 
1189  //Allocate result.
1190  FTps<T, N> result(minOrder, maxOrder, trcOrder);
1191  std::copy(begin(minOrder), end(maxOrder), result.begin(minOrder));
1192 
1193  if(nh > trcOrder) {
1194 #ifdef DEBUG_FTps_CC
1195  std::cerr << " <*** WARNING ***> from FTps<T,N>::substitute(mat,nl,nh):\n"
1196  << " Transformation order nh exceeds truncation order;\n"
1197  << " truncation order unchanged." << std::endl;
1198 #endif
1199  }
1200 
1201  // Return trivial cases.
1202  if(nh == 0 || nh < minOrder || maxOrder < nl) return result;
1203 
1204  // Set and clear actual range of orders to transform.
1205  if(nl == 0) nl = 1;
1206  nl = std::max(nl, minOrder);
1207  nh = std::min(nh, maxOrder);
1208  std::fill(result.begin(nl), result.end(nh), T(0));
1209 
1210  // Allocate working arrays; use static
1211  // local memory to avoid fragmentation.
1212  static T *t = 0;
1213  static const T **fp;
1214  static int max_nh = -1;
1215  if(nh > max_nh) {
1216  if(t) {
1217  delete [] t;
1218  delete [] fp;
1219  }
1220  t = new T[getSize(nh)];
1221  fp = new const T*[nh+1];
1222  max_nh = nh;
1223  }
1224  T *t1 = t + 1;
1225 
1226  // Initialisations.
1227  // Array element fp[m] points to the next order m monomial to transform.
1228  for(int m = nl; m <= nh; ++m) fp[m] = begin(m);
1229  T *g = result.begin();
1230  const Array1D<int> *oldvrbl = 0;
1231  int start_nh = orderStart(nh), end_nh = orderEnd(nh), nh1 = nh - 1, nh2 = nh - 2;
1232 
1233  // Loop over order nh monomials; construct lower orders along the way.
1234  for(int j = start_nh; j < end_nh; ++j) {
1235  // Get current monomial's variable list; compare with old variable list.
1236  const Array1D<int> *vrbl = &FTpsData<N>::getVariableList(j);
1237  int vk = 0;
1238  if(oldvrbl)
1239  while((*vrbl)[vk] == (*oldvrbl)[vk]) ++vk;
1240 
1241  // Determine which monomial pointers we shall need to increment.
1242  int jl = (*vrbl)[nh1], ni = nh2;
1243  while(ni >= 0 && (*vrbl)[ni] == jl) --ni;
1244  ni += 2;
1245  ni = std::max(ni, nl);
1246  // Determine which monomials contribute this round.
1247  int n1 = std::max(nl, ni), n2 = nh;
1248  while(n1 <= n2 && *fp[n1] == 0) ++n1;
1249  while(n2 > n1 && *fp[n2] == 0) --n2;
1250  // Skip if all monomials have coefficient zero.
1251  if(n1 > n2) {
1252  for(int m = ni; m <= nh; ++m) ++fp[m];
1253  continue;
1254  }
1255 
1256  const T *mv;
1257  int ord;
1258  // If vk = 0, we must start at the beginning; otherwise,
1259  // we may keep the first vk orders stored in t.
1260  if(vk == 0) {
1261  mv = mat[(*vrbl)[0]];
1262  std::copy(mv, mv + N, t1);
1263  ord = 2;
1264  } else ord = vk + 1;
1265 
1266  // In working array t, clear orders we can't use.
1267  std::fill(t + orderStart(ord), t + end_nh, T(0));
1268 
1269  // Build the remainder.
1270  while(ord <= nh) {
1271  // Build next order part of transformed monomial by multiplying
1272  // the part that is one order lower by the transformed version
1273  // of the next variable in the variable list.
1274  int ord1 = ord - 1;
1275  int start_l = orderStart(ord1), end_l = orderEnd(ord1);
1276  mv = mat[(*vrbl)[ord1]]; // transformed version of next variable
1277  for(int k = 0; k < N; k++) {
1278  T mvk = mv[k];
1279  if(mvk == T(0)) continue;
1281  for(int l = start_l; l < end_l; ++l) t[prod[l]] += mvk * t[l];
1282  }
1283  ++ord;
1284  }
1285  //Increment g by f[j] * transformed monomial.
1286  for(int m = n1; m <= n2; ++m) {
1287  T fj = *fp[m];
1288  int start_m = orderStart(m), end_m = orderEnd(m);
1289  for(int i = start_m; i < end_m; i++) g[i] += fj * t[i];
1290  }
1291  // Increment pointers in fp[].
1292  for(int m = ni; m <= nh; ++m) ++fp[m];
1293  // Save variable list for comparison with the next one.
1294  oldvrbl = vrbl;
1295  }
1296 
1297  return result;
1298 }
1299 
1300 
1301 template <class T, int N>
1303  return substitute(mat, getMinOrder(), getMaxOrder());
1304 }
1305 
1306 
1307 template <class T, int N>
1308 FTps<T, N> FTps<T, N>::substitute(const FVps<T, N> &rhs, int trunc) const {
1309  // Default: trunc = EXACT
1310 
1311  // Get orders.
1312  int f_min = getMinOrder(), f_max = getMaxOrder();
1313  Array1D<int> orders = getSubstOrders(rhs, trunc);
1314  int g_min = orders[0], g_max = orders[1], g_trc = orders[2];
1315 
1316  // Make sure we don't trip over globalTruncOrder.
1317  if(g_trc != EXACT && g_trc > globalTruncOrder)
1318  throw LogicalError("FTps::substitute(FVps rhs, int trunc)",
1319  "Truncation order exceeds globalTruncOrder!");
1320 
1321  // Return trivial case.
1322  if(g_min > g_max) return FTps<T, N>(g_trc, g_trc, g_trc);
1323 
1324  //Allocate result.
1325  FTps<T, N> result(g_min, g_max, g_trc);
1326  if(f_min == 0) result[0] = *begin();
1327  if(f_max == 0) return result;
1328 
1329  // Set actual range of orders to transform.
1330  int nl = f_min, nh = f_max;
1331  if(nl == 0) nl = 1;
1332 
1333  // Allocate working arrays.
1334  const T *fp[nh+1];
1335  Array1D< FTps<T, N> > t(nh + 1);
1336 
1337  // Initialisations.
1338  // Array element fp[m] points to the next order m monomial to transform.
1339  for(int m = nl; m <= nh; ++m) fp[m] = begin(m);
1340  const Array1D<int> *oldvrbl = 0;
1341  int start_nh = orderStart(nh), end_nh = orderEnd(nh), nh1 = nh - 1, nh2 = nh - 2;
1342 
1343  // Loop over order nh monomials; construct lower orders along the way.
1344  for(int j = start_nh; j < end_nh; ++j) {
1345  // Get current monomial's variable list; compare with old variable list.
1346  const Array1D<int> *vrbl = &FTpsData<N>::getVariableList(j);
1347  int vk = 0;
1348  if(oldvrbl)
1349  while((*vrbl)[vk] == (*oldvrbl)[vk]) ++vk;
1350 
1351  // Determine which monomial pointers we shall need to increment.
1352  int jl = (*vrbl)[nh1], ni = nh2;
1353  while(ni >= 0 && (*vrbl)[ni] == jl) --ni;
1354  ni += 2;
1355  ni = std::max(ni, nl);
1356  // Determine which monomials contribute this round.
1357  int n1 = std::max(nl, ni), n2 = nh;
1358  while(n1 <= n2 && *fp[n1] == 0) ++n1;
1359  while(n2 > n1 && *fp[n2] == 0) --n2;
1360  // Skip if all monomials have coefficient zero.
1361  if(n1 > n2) {
1362  for(int m = ni; m <= nh; ++m) ++fp[m];
1363  continue;
1364  }
1365 
1366  int ord;
1367  // If vk = 0, we must start at the beginning; otherwise,
1368  // we may keep the first vk orders stored in t.
1369  if(vk == 0) {
1370  t[1] = rhs[(*vrbl)[0]];
1371  ord = 2;
1372  } else ord = vk + 1;
1373 
1374  // Build the remainder.
1375  while(ord <= nh) {
1376  // Build next order part of transformed monomial by multiplying
1377  // the part that is one order lower by the transformed version
1378  // of the next variable in the variable list.
1379  int ord1 = ord - 1;
1380  t[ord] = t[ord1].multiply(rhs[(*vrbl)[ord1]], g_trc);
1381  ++ord;
1382  }
1383  //Increment result by f[j] * transformed monomial.
1384  for(int m = n1; m <= n2; ++m) result += *fp[m] * t[m];
1385  // Increment pointers in fp[].
1386  for(int m = ni; m <= nh; ++m) ++fp[m];
1387  // Save variable list for comparison with the next one.
1388  oldvrbl = vrbl;
1389  }
1390 
1391  return result;
1392 }
1393 
1394 
1395 template <class T, int N>
1397  // Get orders.
1398  int f_min = getMinOrder(), f_max = getMaxOrder(), f_trc = getTruncOrder();
1399  int df_min = (f_min == 0) ? f_min : f_min - 1;
1400  int df_max = (f_max == 0) ? f_max : f_max - 1;
1401  int df_trc = (f_trc == 0 || f_trc == EXACT) ? f_trc : f_trc - 1;
1402  if(f_min == 0 && f_min < f_max) f_min = 1;
1403 
1404  //Allocate result.
1405  FTps<T, N> result(df_min, df_max, df_trc);
1406  // Return trivial case.
1407  if(f_max == 0) return result;
1408 
1409  // Initialisations.
1410  const int *product = FTpsData<N>::getProductArray(var + 1).begin();
1411  const T *f = begin();
1412  T *df = result.begin();
1413  T *dfe = df + orderEnd(df_max);
1414  int ks = orderStart(df_min);
1415  df += ks;
1416  product += ks;
1417 
1418  // Compute derivative.
1419  // For the contribution to the k-th monomial in the derivative, we look
1420  // at the monomial whose index is the k-th entry in the product array for
1421  // variable var. The var-th entry in that monomial's exponent array is
1422  // the power brought down by the differentiation.
1423  while(df != dfe) {
1424  int kp = *product++;
1425  *df++ = T(FTpsData<N>::getExponents(kp)[var]) * *(f + kp);
1426  }
1427 
1428  return result;
1429 }
1430 
1431 
1432 template <class T, int N>
1434  FVps<T, N> result;
1435  for(int i = 0; i < N; ++i) result[i] = derivative(i);
1436  return result;
1437 }
1438 
1439 
1440 template <class T, int N>
1441 FTps<T, N> FTps<T, N>::integral(int var, int trunc) const {
1442  // Default: trunc = EXACT
1443 
1444  // Get orders.
1445  int f_min = getMinOrder(), f_max = getMaxOrder(), f_trc = getTruncOrder();
1446  int minOrder = std::min(f_min + 1, trunc);
1447  int maxOrder = std::min(f_max + 1, trunc);
1448  int trcOrder;
1449  if(f_trc == EXACT) trcOrder = trunc;
1450  else trcOrder = std::min(f_trc + 1, trunc);
1451  if(maxOrder > globalTruncOrder || (trcOrder != EXACT && trcOrder > globalTruncOrder))
1452  throw LogicalError("FTps::integral(int var, int trunc)", "Some order exceeds globalTruncOrder!");
1453 
1454  // Allocate result.
1455  FTps<T, N> result(minOrder, maxOrder, trcOrder);
1456 
1457  // Return trivial result.
1458  if(f_min >= maxOrder) return result;
1459 
1460  // Initialisations.
1461  const T *f = begin();
1462  T *r = result.begin();
1463  int is = orderStart(f_min);
1464  int ie = orderEnd(maxOrder - 1);
1465 
1466  // Compute integral.
1467  // The contribution from the k-th monomial we insert into the integral
1468  // at the monomial whose index is the k-th entry in the product array
1469  // for variable var. The var-th entry in that (the result) monomial's
1470  // exponent array is the power kicked up by the integration.
1471  const Array1D<int> &product = FTpsData<N>::getProductArray(var + 1);
1472  for(int i = is; i < ie; ++i) {
1473  int k = product[i];
1474  r[k] = f[i] / double(FTpsData<N>::getExponents(k)[var]);
1475  }
1476  return result;
1477 }
1478 
1479 
1480 template <class T, int N>
1481 FTps<T, N> FTps<T, N>::taylor(const Array1D<T> &series, int order) const {
1482  FTps<T, N> x(*this);
1483  x.unique();
1484  x.itsRep->data[0] = T(0);
1485  FTps<T, N> result(series[order]);
1486 
1487  for(int m = 1; m <= order; ++m) {
1488  if(result.itsRep->trcOrd < m) result.setTruncOrder(m);
1489  result = x.multiply(result, m);
1490 
1491  /*
1492  * has to be set, otherwise if coefficient is zero --> next coefficient doesn't get
1493  * counted, e.g. with cos(x)
1494  */
1495  result.setMinOrder(0);
1496 
1497  result.itsRep->data[0] = series[order-m];
1498  }
1499 
1500  return result;
1501 }
1502 
1503 
1504 template <class T, int N> inline
1506  if(itsRep->ref > 1) {
1507  FTpsRep<T, N> *oldRep = itsRep;
1508  oldRep->ref--;
1509  itsRep = FTps<T, N>::allocate(itsRep->minOrd, itsRep->maxOrd, itsRep->trcOrd);
1510  std::copy(oldRep->begin(), oldRep->end(itsRep->maxOrd), itsRep->begin());
1511  }
1512 }
1513 
1514 template <class T, int N>
1516 
1517  // get total number of coefficients
1518  int size = getSize();
1519 
1520  // initialize list
1521  std::list<int> coeffs;
1522 
1523  // loop over all coefficients
1524  for (int i = 0; i < size; ++i) {
1525  // get index of non-zero coefficients
1526  if (getCoefficient(i) != 0) {
1527  coeffs.push_back(i);
1528  }
1529  }
1530 
1531  return coeffs;
1532 }
1533 
1534 template <class T, int N>
1536 
1537  // check index
1538  if ( index < 0 || getSize() - 1 < index)
1539  throw LogicalError("FVps<T,N>::extractExponents(var)","Index out of range.");
1540 
1541  // get exponents of monomial
1542  FMonomial<N> mono = FTps<T, N>::getExponents(index);
1543 
1544  // array of exponents
1545  FArray1D<int, N> expons;
1546 
1547  // copy monomials to array
1548  for (int i = 0; i < N; ++i)
1549  expons[i] = mono[i];
1550 
1551  return expons;
1552 }
1553 
1554 template <class T, int N>
1556 
1557  if (power < 0)
1558  throw LogicalError("FTps<T,N>::makePower(power)","Power is negative.");
1559 
1560  FTps<T, N> result = *this;
1561 
1562  // gets truncated in case of being bigger than global truncation order
1563  for (int i = 1; i < power; ++i) {
1564  //result *= *this;
1565  result = result.multiply(*this, globalTruncOrder);
1566  }
1567  return result;
1568 }
1569 
1570 template <class T, int N>
1571 std::istream &FTps<T, N>::get(std::istream &is) {
1572  // is.flags(std::ios::skipws);
1573  // char head[4];
1574  // is.get(head, 4);
1575  //
1576  // // Check for Tps.
1577  // if (strcmp(head, "Tps") != 0)
1578  // throw FormatError("FTps::get()", "Flag word \"Tps\" missing.");
1579 
1580  // Check for Tps.
1581  std::string head;
1582  is >> head;
1583  if(head != "Tps")
1584  throw FormatError("FTps::get()", "Flag word \"Tps\" missing.");
1585 
1586  // Read in order data.
1587  int minOrder, maxOrder, trcOrder, nVar;
1588  std::string trunc;
1589  is >> minOrder >> maxOrder >> trunc >> nVar;
1590  if(trunc == "EXACT") trcOrder = EXACT;
1591  else trcOrder = std::atoi(trunc.c_str());
1592 
1593  // Check sanity.
1594  if(nVar != N)
1595  throw FormatError("FTps::get()", "Invalid number of variables.");
1596 
1597  // Allocate result.
1598  FTps<T, N> result(minOrder, maxOrder, trcOrder);
1599  T coeff;
1600  FMonomial<N> mono(nVar);
1601  bool done = false;
1602  bool fail = false;
1603  bool first = true;
1604 
1605  while(true) {
1606  is >> coeff;
1607  fail = is.fail();
1608 
1609  int order = 0;
1610  for(int var = 0; var < nVar; var++) {
1611  int p;
1612  is >> p;
1613  fail |= is.fail();
1614  if(p < 0) done = true;
1615  mono[var] = p;
1616  order += mono[var];
1617  }
1618 
1619  if(fail) throw FormatError("FTps::get()", "File read error");
1620  if(done) break;
1621 
1622  if(coeff != T(0)) {
1623  if(first) {
1624  first = false;
1625  minOrder = maxOrder = order;
1626  } else {
1627  if(order < minOrder) minOrder = order;
1628  else if(order > maxOrder) maxOrder = order;
1629  }
1630  int index = FTpsData<N>::getIndex(mono);
1631  result[index] = coeff;
1632  }
1633  }
1634 
1635  if(minOrder < result.getMinOrder())
1636  throw FormatError("FTps::get()", "minOrder incorrect in file");
1637  if(maxOrder > result.getMaxOrder())
1638  throw FormatError("FTps::get()", "maxOrder incorrect in file");
1639  result.itsRep->minOrd = minOrder;
1640  result.itsRep->maxOrd = maxOrder;
1641 
1642  *this = result;
1643  return is;
1644 }
1645 
1646 
1647 template <class T, int N>
1648 std::ostream &FTps<T, N>::put(std::ostream &os) const {
1649  // Print out order data.
1650  os << "Tps " << itsRep->minOrd << ' ' << itsRep->maxOrd << ' ';
1651  if(itsRep->trcOrd == EXACT)
1652  os << "EXACT";
1653  else
1654  os << itsRep->trcOrd;
1655  os << " " << N << std::endl;
1656  // os << "<*** allocOrd = " << itsRep->allocOrd << " ***>" << std::endl;
1657 
1658  // Save old and set new formats.
1659  std::streamsize old_prec = os.precision(14);
1660  os.setf(std::ios::scientific, std::ios::floatfield);
1661 
1662  // Print out FTps coefficients and exponents.
1663  int i = orderStart(itsRep->minOrd);
1664  const T *f = begin(getMinOrder());
1665  const T *fe = end(getMaxOrder());
1666  for(; f != fe; f++, i++) {
1667  if(*f != T(0)) {
1668  os << std::setw(24) << *f;
1669  for(int var = 0; var < N; var++)
1670  os << std::setw(3) << FTpsData<N>::getExponents(i)[var];
1671  os << std::endl;
1672  }
1673  }
1674  // End FTps w/ "0.00 -1 .. -1".
1675  os << std::setw(24) << T(0);
1676  for(int var = 0; var < N; var++) os << std::setw(3) << (-1);
1677  os << std::endl;
1678 
1679  // Restore old formats.
1680  os.precision(old_prec);
1681  os.setf(std::ios::fixed, std::ios::floatfield);
1682 
1683  return os;
1684 }
1685 
1686 
1687 // Template class FTps<T,N>, private methods.
1688 // ------------------------------------------------------------------------
1689 
1690 template <class T, int N> inline
1691 FTpsRep<T, N> *
1692 FTps<T, N>::allocate(int minOrder, int maxOrder, int trcOrder) {
1693  checkOrders("FTps<T,N>::allocate(minOrder, maxOrder, trcOrder)", minOrder, maxOrder, trcOrder);
1694 
1695  // Determine allocation order.
1696  int allocOrder = trcOrder == EXACT ? maxOrder : trcOrder;
1697 
1698  // Do the allocating.
1699  FTpsRep<T, N> *rep = freeList[allocOrder];
1700  if(rep) {
1701  // There exists a free object of the correct order: take 'rep' off
1702  // the stack, point freeList to next element in the linked list, ...
1703  freeList[allocOrder] = rep->next;
1704  // ... and set the values of next, ref, and *Ord.
1705  rep->next = 0;
1706  rep->ref = 1;
1707  rep->minOrd = minOrder;
1708  rep->maxOrd = maxOrder;
1709  rep->trcOrd = trcOrder;
1710  //rep->allocOrd = allocOrder; // This should already be the case! (Don't alter rep->allocOrd!)
1711 #ifdef DEBUG_FTps_CC
1712  if(allocOrder != rep->allocOrd)
1713  std::cerr << " <*** allocOrder error ***> " << allocOrder << " != " << rep->allocOrd << std::endl;
1714 #endif
1715  } else {
1716  // We must allocate a new object.
1717  rep = new FTpsRep<T, N>(minOrder, maxOrder, trcOrder);
1718  }
1719 
1720  // The data array for the returned object is uninitialised.
1721  return rep;
1722 }
1723 
1724 
1725 template <class T, int N> inline
1727  int order = rep->allocOrd;
1728  rep->next = FTps<T, N>::freeList[order];
1729  FTps<T, N>::freeList[order] = rep;
1730 }
1731 
1732 
1733 template <class T, int N>
1734 void FTps<T, N>::grow(int maxOrder, int trcOrder) {
1735  int minOrder = itsRep->minOrd;
1736 
1737  // Allocate new representation.
1738  FTpsRep<T, N> *newRep = allocate(minOrder, maxOrder, trcOrder);
1739 
1740  // Copy old representation.
1741  T *f = itsRep->begin(minOrder);
1742  T *fe = itsRep->end(std::min(itsRep->maxOrd, maxOrder));
1743  T *g = newRep->begin(minOrder);
1744  T *ge = newRep->end(maxOrder);
1745  while(f < fe) *g++ = *f++;
1746  while(g < ge) *g++ = T(0);
1747 
1748  // Discard old representation and attach new one.
1749  itsRep->ref--;
1750  if(itsRep->ref == 0) deallocate(itsRep);
1751  itsRep = newRep;
1752 }
1753 
1754 
1755 template <class T, int N>
1757  Array1D<int> result(4);
1758  result[0] = itsRep->minOrd;
1759  result[1] = itsRep->maxOrd;
1760  result[2] = itsRep->trcOrd;
1761  result[3] = itsRep->allocOrd;
1762  return result;
1763 }
1764 
1765 
1766 template <class T, int N>
1767 void FTps<T, N>::checkOrders(const std::string &method, int minOrder, int maxOrder, int &trcOrder) {
1768  bool errF = false;
1769  std::string message;
1770 
1771  // Check that min-, max-, and trcOrder's have the correct relationships.
1772  if(!(0 <= minOrder && minOrder <= maxOrder && maxOrder <= trcOrder && maxOrder < EXACT)) {
1773  errF = true;
1774  message = "Invalid, or inconsistent, arguments.";
1775  }
1776  // Make sure we don't trip over globalTruncOrder.
1777  else if(maxOrder > globalTruncOrder) {
1778  errF = true;
1779  message = "The argument maxOrder exceeds globalTruncOrder.";
1780  } else if(trcOrder != EXACT && trcOrder > globalTruncOrder) {
1781  errF = true;
1782  message = "The argument trcOrder has a finite value that exceeds globalTruncOrder.";
1783  }
1784  if(errF) {
1785  std::cerr << "Method " << method << ", called with arguments (";
1786  if(minOrder == EXACT) std::cerr << "EXACT,";
1787  else std::cerr << minOrder << ",";
1788  if(maxOrder == EXACT) std::cerr << "EXACT,";
1789  else std::cerr << maxOrder << ",";
1790  if(trcOrder == EXACT) std::cerr << "EXACT";
1791  else std::cerr << trcOrder;
1792  std::cerr << ")." << std::endl;
1793  throw LogicalError(method, message);
1794  }
1795 }
1796 
1797 
1798 // Global functions acting on FTps<T> objects.
1799 // ------------------------------------------------------------------------
1800 
1801 template <class T, int N>
1802 FTps<T, N> operator+(const FTps<T, N> &lhs, const FTps<T, N> &rhs) {
1803  // Determine orders of result.
1804  int f_min = lhs.getMinOrder(), f_max = lhs.getMaxOrder();
1805  int g_min = rhs.getMinOrder(), g_max = rhs.getMaxOrder();
1806  int h_trc = std::min(lhs.getTruncOrder(), rhs.getTruncOrder());
1807  int h_min = std::min(f_min, g_min), h_max = std::min(std::max(f_max, g_max), h_trc);
1808  if(h_trc < f_min) h_max = g_max;
1809  else if(h_trc < g_min) h_max = f_max;
1810 
1811  // Allocate result.
1812  FTps<T, N> result(h_min, h_max, h_trc);
1813 
1814  // Change from orders to indices.
1815  f_min = FTps<T, N>::orderStart(f_min);
1816  f_max = FTps<T, N>::orderEnd(std::min(f_max, h_max));
1817  g_min = FTps<T, N>::orderStart(g_min);
1818  g_max = FTps<T, N>::orderEnd(std::min(g_max, h_max));
1819  h_min = std::min(f_min, g_min);
1820  h_max = std::max(f_max, g_max);
1821 
1822  const T *f = lhs.begin();
1823  const T *g = rhs.begin();
1824  T *h = result.begin();
1825 
1826  // Do the "addition" h = f + g.
1827  int i = h_min;
1828  if(g_min < f_max && f_min < g_max) { // overlap exists
1829  int fg_max_min = std::min(f_max, g_max);
1830  for(; i < g_min; i++) h[i] = f[i]; //: copy below
1831  for(; i < f_min; i++) h[i] = g[i]; // overlap
1832  for(; i < fg_max_min; i++) h[i] = f[i] + g[i]; //: do f + g
1833  for(; i < f_max; i++) h[i] = f[i]; //: copy above
1834  for(; i < g_max; i++) h[i] = g[i]; // overlap
1835  } else { // gap exists
1836  if(f_max <= g_min) { // |f| < |g|
1837  // Check for special case (corresponds to h_trc in gap).
1838  if(g_min > h_max) g_min = h_max;
1839  // Then load h.
1840  for(; i < f_max; i++) h[i] = f[i];
1841  for(; i < g_min; i++) h[i] = 0;
1842  for(; i < h_max; i++) h[i] = g[i];
1843  } else { // |g| < |f|
1844  // Check for special case (corresponds to h_trc in gap).
1845  if(f_min > h_max) f_min = h_max;
1846  // Then load h.
1847  for(; i < g_max; i++) h[i] = g[i];
1848  for(; i < f_min; i++) h[i] = 0;
1849  for(; i < h_max; i++) h[i] = f[i];
1850  }
1851  }
1852 
1853  return result;
1854 }
1855 
1856 
1857 template <class T, int N>
1858 FTps<T, N> operator-(const FTps<T, N> &lhs, const FTps<T, N> &rhs) {
1859  // Determine orders of result.
1860  int f_min = lhs.getMinOrder(), f_max = lhs.getMaxOrder();
1861  int g_min = rhs.getMinOrder(), g_max = rhs.getMaxOrder();
1862  int h_trc = std::min(lhs.getTruncOrder(), rhs.getTruncOrder());
1863  int h_min = std::min(f_min, g_min), h_max = std::min(std::max(f_max, g_max), h_trc);
1864  if(h_trc < f_min) h_max = g_max;
1865  else if(h_trc < g_min) h_max = f_max;
1866 
1867  // Allocate result.
1868  FTps<T, N> result(h_min, h_max, h_trc);
1869 
1870  // Change from orders to indices.
1871  f_min = FTps<T, N>::orderStart(f_min);
1872  f_max = FTps<T, N>::orderEnd(std::min(f_max, h_max));
1873  g_min = FTps<T, N>::orderStart(g_min);
1874  g_max = FTps<T, N>::orderEnd(std::min(g_max, h_max));
1875  h_min = std::min(f_min, g_min);
1876  h_max = std::max(f_max, g_max);
1877 
1878  const T *f = lhs.begin();
1879  const T *g = rhs.begin();
1880  T *h = result.begin();
1881 
1882  // Do the "subtraction" h = f - g.
1883  int i = h_min;
1884  if(g_min < f_max && f_min < g_max) { // overlap exists
1885  int fg_max_min = std::min(f_max, g_max);
1886  for(; i < g_min; i++) h[i] = f[i]; //: copy below
1887  for(; i < f_min; i++) h[i] = -g[i]; // overlap
1888  for(; i < fg_max_min; i++) h[i] = f[i] - g[i]; //: do f - g
1889  for(; i < f_max; i++) h[i] = f[i]; //: copy above
1890  for(; i < g_max; i++) h[i] = -g[i]; // overlap
1891  } else { // gap exists
1892  if(f_max <= g_min) { // |f| < |g|
1893  // Check for special case (corresponds to h_trc in gap).
1894  if(g_min > h_max) g_min = h_max;
1895  // Then load h.
1896  for(; i < f_max; i++) h[i] = f[i];
1897  for(; i < g_min; i++) h[i] = 0;
1898  for(; i < h_max; i++) h[i] = -g[i];
1899  } else { // |g| < |f|
1900  // Check for special case (corresponds to h_trc in gap).
1901  if(f_min > h_max) f_min = h_max;
1902  // Then load h.
1903  for(; i < g_max; i++) h[i] = -g[i];
1904  for(; i < f_min; i++) h[i] = 0;
1905  for(; i < h_max; i++) h[i] = f[i];
1906  }
1907  }
1908 
1909  return result;
1910 }
1911 
1912 
1913 template <class T, int N>
1914 FTps<T, N> operator+(const FTps<T, N> &lhs, const T &rhs) {
1915  FTps<T, N> result(lhs);
1916  return result += rhs;
1917 }
1918 
1919 
1920 template <class T, int N>
1921 FTps<T, N> operator-(const FTps<T, N> &lhs, const T &rhs) {
1922  FTps<T, N> result(lhs);
1923  return result -= rhs;
1924 }
1925 
1926 
1927 template <class T, int N>
1928 FTps<T, N> operator+(const T &lhs, const FTps<T, N> &rhs) {
1929  FTps<T, N> result(rhs);
1930  return result += lhs;
1931 }
1932 
1933 
1934 template <class T, int N>
1935 FTps<T, N> operator-(const T &lhs, const FTps<T, N> &rhs) {
1936  FTps<T, N> result(- rhs);
1937  return result += lhs;
1938 }
1939 
1940 
1941 template <class T, int N>
1942 FTps<T, N> operator*(const FTps<T, N> &lhs, const FTps<T, N> &rhs) {
1943  return lhs.multiply(rhs);
1944  // return lhs.multiply(rhs, FTps<T,N>::getGlobalTruncOrder());
1945 }
1946 
1947 
1948 template <class T, int N>
1949 FTps<T, N> operator/(const FTps<T, N> &lhs, const FTps<T, N> &rhs) {
1950  return lhs.divide(rhs);
1951 }
1952 
1953 
1954 template <class T, int N>
1955 FTps<T, N> operator*(const FTps<T, N> &lhs, const T &rhs) {
1956  FTps<T, N> result(lhs);
1957  return result *= rhs;
1958 }
1959 
1960 
1961 template <class T, int N>
1962 FTps<T, N> operator/(const FTps<T, N> &lhs, const T &rhs) {
1963  FTps<T, N> result(lhs);
1964  return result /= rhs;
1965 }
1966 
1967 
1968 template <class T, int N>
1969 FTps<T, N> operator*(const T &lhs, const FTps<T, N> &rhs) {
1970  FTps<T, N> result(rhs);
1971  return result *= lhs;
1972 }
1973 
1974 
1975 template <class T, int N>
1976 FTps<T, N> operator/(const T &lhs, const FTps<T, N> &rhs) {
1977  return rhs.inverse() * lhs;
1978 }
1979 
1980 
1981 template <class T, int N>
1982 bool operator==(const T &lhs, const FTps<T, N> &rhs) {
1983  return rhs == lhs;
1984 }
1985 
1986 
1987 template <class T, int N>
1988 bool operator!=(const T &lhs, const FTps<T, N> &rhs) {
1989  return rhs != lhs;
1990 }
1991 
1992 
1993 template <class T, int N> FVps<T, N>
1994 ExpMap(const FTps<T, N> &H, int trunc) {
1995  return ExpMap(H, FVps<T, N>(), trunc);
1996 }
1997 
1998 
1999 template <class T, int N> FTps<T, N>
2000 ExpMap(const FTps<T, N> &H, const FTps<T, N> &f, int trunc) {
2001  // Default: trunc = EXACT
2002 
2003  // Limit number of iterations.
2004  const int MAX_ITER = 100;
2005 
2006  // We really ought to throw an exception if H contains linear terms and is not exact,
2007  // but we're just going to complain!!
2008  bool FD = false;
2009  if(H.getTruncOrder() != FTps<T, N>::EXACT && H.getMinOrder() < 2) {
2010  FD = true;
2011 #ifdef DEBUG_FTps_CC
2012  std::cerr << " <*** WARNING ***> from ExpMap(H,f,trunc):\n"
2013  << " Incomplete computation of feed-down terms.\n" << std::endl;
2014 #endif
2015  }
2016  int fd_trc = std::min(H.getTruncOrder() - 1, f.getTruncOrder());
2017 
2018  // Construct dH = grad(H).J, s.t :H:f = dH.grad(f).
2019  FVps<T, N> dH;
2020  for(int i = 0; i < N; i += 2) {
2021  dH[i] = - H.derivative(i + 1);
2022  dH[i+1] = H.derivative(i);
2023  }
2024 
2025  // Allocate and initialize result.
2026  FTps<T, N> expHf = f;
2027 
2028  // Initialize variables.
2029  FTps<T, N> dHkf = f;
2030  FTps<T, N> old = T(0);
2031 
2032  // Compute series; quit computation if we added nothing last time through loop.
2033  for(int k = 1; expHf != old; ++k) {
2034  if(k > MAX_ITER)
2035  throw ConvergenceError("ExpMap(const FTps<T,N> &H, const FTps<T,N> &f)",
2036  "No convergence in ExpMap(H,f)");
2037 
2038  // Don't initialize dHk1f to 0, as that sets minOrder to 0!
2039  old = expHf;
2040  FTps<T, N> ddHkf = dHkf.derivative(0);
2041  if(FD) ddHkf.setTruncOrder(fd_trc);
2042  FTps<T, N> dHk1f = dH[0].multiply(ddHkf, trunc);
2043  for(int v = 1; v < N; ++v) {
2044  ddHkf = dHkf.derivative(v);
2045  if(FD) ddHkf.setTruncOrder(fd_trc);
2046  dHk1f += dH[v].multiply(ddHkf, trunc);
2047  //dHk1f += dH[v].multiply(dHkf.derivative(v),trunc);
2048  }
2049  dHkf = dHk1f / T(k); // :H:^{k}/(k!)
2050  expHf += dHkf;
2051  }
2052 
2053  return expHf;
2054 }
2055 
2056 
2057 template <class T, int N>
2058 FTps<T, N> PoissonBracket(const FTps<T, N> &f, const FTps<T, N> &g, int trunc) {
2059  // Default: trunc = EXACT
2060 
2061  // Determine orders of result.
2062  int f_min = f.getMinOrder(), f_max = f.getMaxOrder(), f_trc = f.getTruncOrder();
2063  int g_min = g.getMinOrder(), g_max = g.getMaxOrder(), g_trc = g.getTruncOrder();
2064  int h_min = std::max(f_min + g_min - 2, 0), h_max = std::max(f_max + g_max - 2, 0), h_trc;
2065  if(f_trc == FTps<T, N>::EXACT) {
2066  if(g_trc == FTps<T, N>::EXACT) {h_trc = (h_max <= trunc) ? FTps<T, N>::EXACT : trunc;}
2067  else h_trc = std::min(std::max(f_min + g_trc - 2, 0), trunc);
2068  } else if(g_trc == FTps<T, N>::EXACT) h_trc = std::min(std::max(f_trc + g_min - 2, 0), trunc);
2069  else {
2070  h_trc = std::min(f_trc + g_min - 2, f_min + g_trc - 2);
2071  h_trc = std::min(std::max(h_trc, 0), trunc);
2072  }
2073  h_max = std::min(h_max, h_trc);
2074 
2075  // Return trivial result.
2076  if(h_min > h_max) return FTps<T, N>();
2077 
2078  // Allocate result.
2079  FTps<T, N> h(h_min, h_max, h_trc);
2080 
2081  for(int q = 0; q < N; q += 2) {
2082  int p = q + 1;
2083  //h += f.derivative(q) * g.derivative(p) - f.derivative(p) * g.derivative(q);
2084  h += f.derivative(q).multiply(g.derivative(p), h_trc)
2085  - f.derivative(p).multiply(g.derivative(q), h_trc);
2086  }
2087  return h;
2088 }
2089 
2090 
2091 template <class T, int N>
2092 std::istream &operator>>(std::istream &is, FTps<T, N> &tps) {
2093  return tps.get(is);
2094 }
2095 
2096 
2097 template <class T, int N>
2098 std::ostream &operator<<(std::ostream &os, const FTps<T, N> &tps) {
2099  return tps.put(os);
2100 }
2101 
2102 #endif // CLASSIC_FTps_CC
static const Array1D< int > & getProductArray(int index)
Definition: FTpsData.h:239
Matrix< T > operator+(const Matrix< T > &, const Matrix< T > &)
Matrix addition.
Definition: Matrix.h:275
int trcOrd
Definition: FTps.hpp:99
FTps operator+() const
Unary plus.
Definition: FTps.hpp:517
static void checkOrders(const std::string &method, int minOrder, int maxOrder, int &trcOrder)
Definition: FTps.hpp:1767
T * end(int order) const
Definition: FTps.hpp:87
Array1D< int > getRepOrders() const
Definition: FTps.hpp:1756
Matrix< T > operator/(const Matrix< T > &, const T &)
Matrix divided by scalar.
Definition: Matrix.h:329
FTps truncate(int trunc)
Truncate.
Definition: FTps.hpp:475
void setMinOrder(int order)
Set minimum order.
Definition: FTps.hpp:321
FVps derivative(int var) const
Partial derivative.
Definition: FVps.hpp:524
int getMaxOrder() const
Get maximum order.
Definition: FTps.h:174
static const Array1D< TpsSubstitution > & getSubTable()
Definition: FTpsData.h:270
Definition: rbendmap.h:8
bool operator!=(const FTps &y) const
Inequality operator.
Definition: FTps.hpp:886
Array1D< int > getSubstOrders(const FVps< T, N > &rhs, int trunc=EXACT) const
Return orders {min, max, trc} of f(rhs(z)).
Definition: FTps.hpp:1008
FTpsRep(int minOrder, int maxOrder, int trcOrder)
Definition: FTps.hpp:118
A templated representation for vectors.
Definition: PartBunchBase.h:26
T::PETE_Expr_t::PETE_Return_t max(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:123
~FTpsRep()
Definition: FTps.hpp:129
int getMinOrder() const
Get minimum order.
Definition: FTps.h:165
FTps & operator+=(const FTps &y)
Add and assign.
Definition: FTps.hpp:533
Representation of the exponents for a monomial with fixed dimension.
Definition: FMonomial.h:32
int len
Definition: FTps.hpp:107
static int orderStart(int order)
Definition: FTpsData.h:196
static void setup(int order)
Definition: FTpsData.h:277
Matrix< T > operator*(const Matrix< T > &, const Matrix< T > &)
Matrix multiply.
Definition: Matrix.h:297
static const Array1D< int > & getVariableList(int index)
Definition: FTpsData.h:246
iterator begin()
Get iterator pointing to beginning of array.
Definition: FArray1D.h:192
Definition: FTps.h:33
FTps< T, N > makePower(int power) const
Multiply FTps with itself.
Definition: FTps.hpp:1555
std::list< int > getListOfNonzeroCoefficients() const
Get a list containing the indexes of non-zero coefficients of a FTps.
Definition: FTps.hpp:1515
FTpsRep< T, N > * next
Definition: FTps.hpp:91
FTps< T, N > data[N]
Definition: FVps.h:247
~FTps()
Destructor.
Definition: FTps.hpp:194
static FTps makeMonomial(int index, const T &t)
Make monomial.
Definition: FTps.hpp:499
Array1D< int > getSubstOrders(const FVps< T, N > &rhs, int trunc=(FTps< T, N >::EXACT)) const
Return orders {min, max, trc} of f(rhs(z)).
Definition: FVps.hpp:594
void clear()
Definition: FTps.hpp:135
int allocOrd
Definition: FTps.hpp:100
static int orderEnd(int order)
Definition: FTpsData.h:210
void setMaxOrder(int order)
Set maximum order.
Definition: FVps.hpp:191
PETE_TBTree< OpGE, Index::PETE_Expr_t, PETE_Scalar< double > > ge(const Index &idx, double x)
Definition: IndexInlines.h:355
FTpsRep< T, N > * itsRep
Definition: FTps.h:405
FTps multiplyVariable(int var, int trunc=EXACT) const
Multiply by variable [b]var[/b].
Definition: FTps.hpp:610
FTps multiply(const FTps &y, int trunc=EXACT) const
Multiplication.
Definition: FTps.hpp:650
static int orderStart(int order)
Get index at which [b]order[/b] starts.
Definition: FTps.h:143
FTps divide(const FTps &y, int trunc=EXACT) const
Division.
Definition: FTps.hpp:761
static int getSize(int order)
Definition: FTpsData.h:189
Tps< T > PoissonBracket(const Tps< T > &x, const Tps< T > &y)
Poisson bracket.
Definition: LieMap.h:154
int getTruncOrder() const
Get lowest truncation order in any component.
Definition: FVps.hpp:207
FTps()
Default constructor.
Definition: FTps.hpp:159
iterator begin()
Get beginning of data.
Definition: Array1D.h:204
static const Array1D< int > & getVariableList(int index)
List of variables contained in monomial &quot;index&quot;.
Definition: FTps.hpp:439
static const Array1D< int > & getProductArray(int index)
Index array for products of monomial &quot;index&quot;.
Definition: FTps.hpp:433
std::istream & get(std::istream &is)
Read FTps on the stream [b]is[/b].
Definition: FTps.hpp:1571
FVps< T, N > gradient() const
Gradient.
Definition: FTps.hpp:1433
int getSize() const
Get total number of coefficients.
Definition: FTps.h:136
const T operator[](int index) const
Get coefficient.
Definition: FTps.hpp:275
Internal utility class for FTps&lt;T,N&gt; class.
Definition: FTpsData.h:35
constexpr double c
The velocity of light in m/s.
Definition: Physics.h:52
Zero divide error.
Definition: DivideError.h:32
T * data
Definition: FTps.hpp:110
void setMaxOrder(int order)
Set maximum order.
Definition: FTps.hpp:357
bool operator==(const FTps &y) const
Equality operator.
Definition: FTps.hpp:831
Convergence error exception.
void unique()
Make representation unique.
Definition: FTps.hpp:1505
static int getOrder(int index)
Definition: FTpsData.h:182
FVps< T, N > ExpMap(const FTps< T, N > &H, int trunc=FTps< T, N >::EXACT)
Build the exponential series.
Definition: FTps.hpp:1994
FTps & operator-=(const FTps &y)
Subtract and assign.
Definition: FTps.hpp:539
const T getCoefficient(int index) const
Get coefficient.
Definition: FTps.hpp:223
int getTruncOrder() const
Get truncation order.
Definition: FTps.h:183
int ref
Definition: FTps.hpp:94
static int getIndex(const FMonomial< N > &)
Definition: FTpsData.h:167
FTps & operator=(const FTps &y)
Assign.
Definition: FTps.hpp:201
FTps substitute(const FMatrix< T, N, N > &M, int n) const
Substitute.
Definition: FTps.hpp:1075
static Array1D< T > evalMonoms(const FVector< T, N > &, int)
Evaluate monomials at point.
Definition: FTps.hpp:898
FVps filter(int minOrder, int maxOrder, int trcOrder=(FTps< T, N >::EXACT)) const
Extract given range of orders, with truncation.
Definition: FVps.hpp:223
T evaluate(const FVector< T, N > &) const
Evaluate FTps at point.
Definition: FTps.hpp:934
FTps scaleMonomials(const FTps &y) const
Scale monomial coefficients by coefficients in [b]y[/b].
Definition: FTps.hpp:589
std::ostream & put(std::ostream &os) const
Write FTps on the stream [b]os[/b].
Definition: FTps.hpp:1648
int precision() const
Definition: Inform.h:115
FArray1D< int, N > extractExponents(int index) const
Extract exponents of coefficient.
Definition: FTps.hpp:1535
T * end() const
Return end of monomial array.
Definition: FTps.h:121
static void deallocate(FTpsRep< T, N > *)
Definition: FTps.hpp:1726
FTps derivative(int var) const
Partial derivative.
Definition: FTps.hpp:1396
static const FMonomial< N > & getExponents(int index)
Definition: FTpsData.h:160
FTps taylor(const Array1D< T > &series, int order) const
Taylor series.
Definition: FTps.hpp:1481
bool operator!=(const Offset &off1, const Offset &off2)
Definition: Offset.cpp:225
int getMaxOrder() const
Get highest order contained in any component.
Definition: FVps.hpp:181
FTps filter(int minOrder, int maxOrder, int trcOrder=EXACT) const
Extract given range of orders, with truncation.
Definition: FTps.hpp:451
int getOrder() const
Compute the monomial&#39;s order.
Definition: FMonomial.h:124
void grow(int maxOrder, int trcOrder)
Definition: FTps.hpp:1734
FTps inverse(int trunc=EXACT) const
Reciprocal, 1/(*this).
Definition: FTps.hpp:707
int maxOrd
Definition: FTps.hpp:98
FTps operator-() const
Unary minus.
Definition: FTps.hpp:523
static const FMonomial< N > & getExponents(int index)
Get exponents for given index.
Definition: FTps.hpp:309
FTps & operator/=(const FTps &y)
Divide and assign.
Definition: FTps.hpp:551
static void setGlobalTruncOrder(int order)
Set the global truncation order.
Definition: FTps.hpp:419
static FTps makeVarPower(int var, int power)
Make power.
Definition: FTps.hpp:489
void setMinOrder(int order)
Set minimum order.
Definition: FVps.hpp:175
T::PETE_Expr_t::PETE_Return_t prod(const PETE_Expr< T > &expr)
Definition: PETE.h:1243
Format error exception.
Definition: FormatError.h:32
FTps integral(int var, int trunc=EXACT) const
Partial integral.
Definition: FTps.hpp:1441
T * end() const
Definition: FTps.hpp:79
static int orderEnd(int order)
Get one plus index at which [b]order[/b] ends.
Definition: FTps.h:147
void setTruncOrder(int order)
Set truncation order.
Definition: FTps.hpp:393
Truncated power series in N variables of type T.
Matrix< T > operator-(const Matrix< T > &, const Matrix< T > &)
Matrix subtraction.
Definition: Matrix.h:282
int minOrd
Definition: FTps.hpp:97
FVps substitute(const FMatrix< T, N, N > &M, int n) const
Substitute.
Definition: FVps.hpp:608
static int getIndex(const FMonomial< N > &mono)
Get Giorgilli index for monomial.
Definition: FTps.hpp:315
int getMinOrder() const
Get lowest order contained in any component.
Definition: FVps.hpp:165
Logical error exception.
Definition: LogicalError.h:33
T::PETE_Expr_t::PETE_Return_t min(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:95
static const Array1D< TpsSubstitution > & getSubTable()
Return the substitution table.
Definition: FTps.hpp:445
Vector truncated power series in n variables.
static FTps makeVariable(int var)
Make variable.
Definition: FTps.hpp:481
static FTpsRep< T, N > * allocate(int minOrder, int maxOrder, int trcOrder)
Definition: FTps.hpp:1692
std::istream & operator>>(std::istream &, LieMap< T > &x)
Extract LieMap&lt;T&gt; from stream.
Definition: LieMap.h:231
T * begin(int order) const
Definition: FTps.hpp:83
void setCoefficient(int index, const T &value)
Set coefficient.
Definition: FTps.hpp:236
T * begin() const
Definition: FTps.hpp:75
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
T * begin() const
Return beginning of monomial array.
Definition: FTps.h:118
bool operator==(const TwoPolynomial &left, const TwoPolynomial &right)
FTps & operator*=(const FTps &y)
Multiply and assign.
Definition: FTps.hpp:545