GiNaC 1.8.10
Gt_helpers.cpp
Go to the documentation of this file.
1
5/*
6 * GiNaC Copyright (C) 1999-2026 Johannes Gutenberg University Mainz, Germany
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#include "add.h"
24#include "mul.h"
25#include "power.h"
26#include "lst.h"
27#include "operators.h"
28#include "relational.h"
29#include "inifcns.h"
30#include "function.h"
31#include "Gt.h"
32#include "Gt_helpers.h"
33
34using namespace GiNaC;
35
36namespace GiNaC {
37namespace Gt_detail {
38
40//TransformExpressionWithCache//
42template<typename Type>
43template<typename T>
44typename std::enable_if<std::is_base_of<basic, T>::value, bool>::type
46{
47 return is_exactly_a<Type>(expr);
48}
49template<typename Type>
50template<typename T>
51typename std::enable_if<!std::is_base_of<basic, T>::value, bool>::type
53{
54 return is_the_function<Type>(expr);
55}
57template<typename Type>
59{
60 std::cout << "Cache" << std::endl;
61 for (const auto& n : cache)
62 std::cout << " " << n.first << " -> " << n.second << std::endl;
63}
64
65template<typename Type>
67{
68 // If the input is of the desired type, apply the transformation, update cache
69 if (check_type(expr)) {
70 const auto pos = cache.find(expr);
71 if (pos != cache.end())
72 return pos->second;
73 return cache.emplace(expr, func_obj(expr)).first->second;
74 }
75
76 // If the input is an addition, multiplication, exponentiation or list, run recurisvely over elements
77 if (is_exactly_a<add>(expr) || is_exactly_a<mul>(expr)) {
78 std::vector<ex> terms;
79 terms.reserve(expr.nops());
80 for (size_t i = 0; i < expr.nops(); i++)
81 terms.emplace_back(impl(expr.op(i)));
82 if (is_exactly_a<add>(expr))
83 return add(terms);
84 else
85 return mul(terms);
86 }
87 if (is_exactly_a<lst>(expr)) {
88 lst result;
89 for (size_t i = 0; i < expr.nops(); i++)
90 result.append(impl(expr.op(i)));
91 return result;
92 }
93 if (is_exactly_a<power>(expr))
94 return power(impl(expr.op(0)), expr.op(1));
95
96 // Otherwise, use default transformation function (e.g. for number, symbols, unrelated functions)
97 return func_default(expr);
98}
99
100// Instantiate template for elliptic and regular MPLs
103
104
105
107// Path deconcatenation tools //
109std::vector<std::vector<int>> integer_partition(const int n, const int m)
110{
111 std::vector<std::vector<int>> result;
112 std::vector<int> hlp(m, 0);
113 int k = 1;
114 hlp[1] = n;
115 while (k != 0) {
116 int x = hlp[k-1] + 1;
117 int y = hlp[k] - 1;
118 k -= 1;
119 while (x <= y && k < m-1) {
120 hlp[k] = x;
121 y -= x;
122 k += 1;
123 }
124 hlp[k] = x + y;
125
126 std::vector<int> decomposition(m, 0);
127 for (size_t i = 0; i < k+1; i++)
128 decomposition[i] = hlp[i];
129 std::sort(decomposition.begin(), decomposition.end());
130 do {
131 result.emplace_back(decomposition);
132 } while (next_permutation(decomposition.begin(), decomposition.end()));
133 }
134
135 return result;
136}
137
138template<typename Kernel>
140 const std::vector<Kernel>& args,
141 const std::vector<ex>& endpoints,
142 const std::function<ex(std::vector<Kernel>& new_args, const ex& start, const ex& end)>& construct
143)
144{
145 // Assemble partition information into iterated integrals
146 const size_t n_segments = endpoints.size()-1;
147 const std::vector<std::vector<int>> partitions = integer_partition(args.size(), n_segments);
148 std::vector<ex> terms;
149 terms.reserve(partitions.size());
150 for (const std::vector<int>& partition : partitions) { // loop over all partitions, each gives one term
151 size_t kernel_count = 0;
152 std::vector<ex> factors;
153 factors.reserve(n_segments);
154 for (size_t i = 0; i < n_segments; i++) { // loop over paths, each gives zero or one integral
155 if (partition[i] == 0)
156 continue;
157 // copy partition[i] consecutive kernels
158 std::vector<Kernel> new_args(args.begin()+kernel_count, args.begin()+kernel_count+partition[i]);
159 kernel_count += partition[i];
160 // Construct the shifted iterated integral, shift kernel arguments if necessary
161 factors.emplace_back(construct(new_args, endpoints[n_segments-1-i], endpoints[n_segments-i]));
162 }
163 terms.emplace_back(mul(factors));
164 }
165 return add(terms);
166}
167// Instantiate for regular and elliptic MPL kernels
169 const std::vector<ex>& args,
170 const std::vector<ex>& endpoints,
171 const std::function<ex(std::vector<ex>& new_args, const ex& start, const ex& end)>& construct
172);
174 const std::vector<Gt::kernel>& args,
175 const std::vector<ex>& endpoints,
176 const std::function<ex(std::vector<Gt::kernel>& new_args, const ex& start, const ex& end)>& construct
177);
178
179
180
182// pathintegral_term //
184
185pathintegral_term::pathintegral_term(const pathintegral_term& a, const pathintegral_term& b, int power_offset) // construct as product
186 : prefactor(a.prefactor * b.prefactor),
187 power(a.power + b.power + power_offset),
188 polylog(a.polylog.empty() ? b.polylog : a.polylog),
189 denom(a.denom.is_zero() ? b.denom : a.denom)
190{
191 if ((!a.polylog.empty() && !b.polylog.empty()) || (!a.denom.is_zero() && !b.denom.is_zero()))
192 throw std::logic_error("Gt: Cannot multiply these terms");
193}
194
196{
197 if (power != 0 && !denom.is_zero()) { // Power and denominator -> partial fractioning
198 for (int i = std::min(0, power); i < std::max(0, power); i++)
199 integrand.add((power > 0 ? 1 : -1) * prefactor * pow(denom, power-i-1), i, polylog);
200 integrand.add(prefactor * pow(denom, power), 0, polylog, denom);
201 return;
202 }
203
204 if (polylog.empty() && denom.is_zero()) { // only power of integration variable
205 if (power == -1)
206 result.add(prefactor, 0, std::vector<ex>(1,ex{0}));
207 else {
208 result.add( prefactor / (power + 1), power+1);
209 result.add(-prefactor / (power + 1)*pow(start,power+1), 0);
210 }
211 return;
212 }
213
214 if (!polylog.empty() && denom.is_zero()) { // (power and) polylog
215 std::vector<ex> args = polylog;
216 const ex& first = polylog[0];
217 if (power == -1) {
218 args.insert(args.begin(), ex{0});
219 result.add(prefactor, 0, args);
220 }
221 else {
222 result.add(prefactor / (power + 1), power+1, args);
223 args.erase(args.begin());
224 // If first==0 the denominator 1/([int.var.] - first) turns into [int.var]^(-1)
225 integrand.add(-prefactor / (power + 1), power+1 - first.is_zero(), args, first);
226 }
227 return;
228 }
229
230 if (polylog.empty() and power == 0) { // only denominator: 1/([int.var.] - C)
231 result.add(prefactor, 0, std::vector<ex>(1, denom));
232 return;
233 }
234
235 if (!polylog.empty() && power==0 && !denom.is_zero()) { // polylog and denominator
236 std::vector<ex> args = polylog;
237 args.insert(args.begin(), denom);
238 result.add(prefactor, 0, args);
239 return;
240 }
241
242 throw std::logic_error("Gt: Invalid integration");
243}
244
245ex pathintegral_term::evaluate(const ex& upper_bound, const std::vector<ex>& path) const
246{
247 ex result = prefactor * pow(upper_bound, power);
248 if (!denom.is_zero())
249 result /= denom - upper_bound;
250 if (!polylog.empty())
251 result *= G_path(polylog, path);
252 return result;
253}
254
255ex pathintegral_term::G_path(const std::vector<ex>& args, const std::vector<ex>& path)
256{
257 // Multiple segments -> deconcatenate path
258 if (path.size() > 2) {
259 return deconcatenate_path<ex>(args, path, [](std::vector<ex>& new_args, const ex& start, const ex& end) -> ex {
260 return G_path(new_args,start,end);
261 });
262 }
263 return G_path(args, path[0], path[1]);
264}
265ex pathintegral_term::G_path(const std::vector<ex>& args, const ex& start, const ex& end)
266{
267 // Optimisation in case all arguments are the same
268 bool all_args_same = args.size() >= 2;
269 for (size_t i = 1; i < args.size() && all_args_same; i++)
270 all_args_same = (args[i] == args[0]);
271 if (all_args_same)
272 return (pow(G((args[0] - start)/(end - start),1).hold(), args.size()) / factorial(args.size()));
273
274 // Shift arguments, such that integration path is 0 -> 1
275 lst new_args;
276 for (const ex& arg : args)
277 new_args.append((arg - start)/(end - start));
278 return G(new_args,1).hold();
279}
280
281std::ostream & operator<<(std::ostream & os, const pathintegral_term & term)
282{
283 os << "(" << term.prefactor << ")";
284 if (term.power)
285 os << "*[int.var.]^" << term.power;
286 if (!term.polylog.empty()) {
287 os << "*G({";
288 for (const ex& kern : term.polylog)
289 os << kern << ",";
290 os << "},[int.var.],[path])";
291 }
292 if (!term.denom.is_zero())
293 os << "/([int.var.]-(" << term.denom << "))";
294 return os;
295}
296
297// Terms are ordered such that more complicated terms (for integration) come first
299{
300 // 1) Sort decending by polylog order (integration-by-parts yields shorter polylogs)
301 if (a.polylog.size() > b.polylog.size()) return true;
302 if (a.polylog.size() < b.polylog.size()) return false;
303 // 2) Terms with denominator in beginning (partial fractioning yields terms without denominators)
304 if (!a.denom.is_zero() && b.denom.is_zero()) return true;
305 if (a.denom.is_zero() && !b.denom.is_zero()) return false;
306 // 3) Sort ascending by powers (integration-by-parts yields terms with higher power (if polylog present))
307 if (a.power < b.power) return true;
308 if (a.power > b.power) return false;
309
310 // Arbitrarily decide order based on remaining info
311 // Sort by denominator
312 int cmpval = a.denom.compare(b.denom);
313 if (cmpval < 0) return true;
314 if (cmpval > 0) return false;
315 // Sort by Polylog
316 for (size_t i = 0; i < a.polylog.size(); i++) {
317 cmpval = a.polylog[i].compare(b.polylog[i]);
318 if (cmpval < 0) return true;
319 if (cmpval > 0) return false;
320 }
321 // Terms which differ only in their prefactor are considered identical
322 // Calling find() on a container thus yields a term which is equivalent up to prefactor
323 // This means we can add a term to a container by calling find() and summing the prefactor
324 return false;
325}
326
328{
329 std::set<pathintegral_term>::iterator pos = terms.find(term);
330 if (pos == end())
331 terms.insert(std::move(term));
332 else {
333 pos->prefactor += term.prefactor;
334 if (pos->prefactor.is_zero())
335 terms.erase(pos);
336 }
337}
338
340{
341 // Cannot use terms.insert here, as we need to properly add prefacttors
342 for (const pathintegral_term& term : other)
343 add(pathintegral_term(term));
344}
345
347{
348 pathintegral_term term = *begin();
349 terms.erase(begin());
350 return term;
351}
352
353} // namespace Gt_detail
354} // namespace GiNaC
Interface to GiNaC's elliptic multiple polylogarithms.
Interface to helper functions for elliptic multiple polylogarithms.
Interface to GiNaC's sums of expressions.
static std::enable_if< std::is_base_of< basic, T >::value, bool >::type check_type(const ex &expr)
std::set< pathintegral_term >::const_iterator begin() const
Definition Gt_helpers.h:142
void add(pathintegral_term &&term)
std::set< pathintegral_term > terms
Definition Gt_helpers.h:139
std::set< pathintegral_term >::const_iterator end() const
Definition Gt_helpers.h:143
pathintegral_term(ex prefactor, int power, const std::vector< ex > &polylog={}, ex denom=0)
Definition Gt_helpers.h:107
void integrate(const ex &start, pathintegral_term_list &integrand, pathintegral_term_list &result) const
static ex G_path(const std::vector< ex > &args, const std::vector< ex > &path)
ex evaluate(const ex &upper_bound, const std::vector< ex > &path) const
Sum of expressions.
Definition add.h:31
const basic & hold() const
Stop further evaluation.
Definition basic.cpp:886
Wrapper template for making GiNaC classes out of STL containers.
Definition container.h:72
container & append(const ex &b)
Add element at back.
Definition container.h:390
Lightweight wrapper for GiNaC's symbolic objects.
Definition ex.h:72
bool find(const ex &pattern, exset &found) const
Find all occurrences of a pattern.
Definition ex.cpp:105
size_t nops() const
Definition ex.h:135
int compare(const ex &other) const
Definition ex.h:322
bool is_zero() const
Definition ex.h:213
ex op(size_t i) const
Definition ex.h:136
Product of expressions.
Definition mul.h:31
This class holds a two-component object, a basis and and exponent representing exponentiation.
Definition power.h:38
vector< vector< umodpoly > > cache
Definition factor.cpp:1428
upvec factors
Definition factor.cpp:1429
vector< int > k
Definition factor.cpp:1434
size_t n
Definition factor.cpp:1431
ex x
Definition factor.cpp:1609
mvec m
Definition factor.cpp:757
Interface to class of symbolic functions.
Interface to GiNaC's initially known functions.
Definition of GiNaC's lst.
Interface to GiNaC's products of expressions.
template ex deconcatenate_path< Gt::kernel >(const std::vector< Gt::kernel > &args, const std::vector< ex > &endpoints, const std::function< ex(std::vector< Gt::kernel > &new_args, const ex &start, const ex &end)> &construct)
template ex deconcatenate_path< ex >(const std::vector< ex > &args, const std::vector< ex > &endpoints, const std::function< ex(std::vector< ex > &new_args, const ex &start, const ex &end)> &construct)
ex deconcatenate_path(const std::vector< Kernel > &args, const std::vector< ex > &endpoints, const std::function< ex(std::vector< Kernel > &new_args, const ex &start, const ex &end)> &construct)
bool operator<(const pathintegral_term &a, const pathintegral_term &b)
std::ostream & operator<<(std::ostream &os, const pathintegral_term &term)
std::vector< std::vector< int > > integer_partition(const int n, const int m)
Definition add.cpp:35
bool is_zero(const ex &thisex)
Definition ex.h:835
ex denom(const ex &thisex)
Definition ex.h:763
const numeric pow(const numeric &x, const numeric &y)
Definition numeric.h:250
const numeric factorial(const numeric &n)
Factorial combinatorial function.
Definition numeric.cpp:2112
function G(const T1 &x, const T2 &y)
Definition inifcns.h:129
Interface to GiNaC's overloaded operators.
Interface to GiNaC's symbolic exponentiation (basis^exponent).
Interface to relations between expressions.

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