-
Notifications
You must be signed in to change notification settings - Fork 1
/
powerseries.py
91 lines (60 loc) · 2.49 KB
/
powerseries.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
"""powerseries.py: This file is part of the feyncop/feyngen package.
Collection of subroutines for the manipulation of multivariable polynomials, which can be seen as truncated multivariable power series."""
# See also: https://github.com/michibo/feyncop
# Author: Michael Borinsky
# Python3 port: Frédéric Chapoton
# Bugreports, comments, or suggestions are always welcome.
# For instance, via github or email
from fractions import Fraction
from functools import reduce
from math import log
def unary_rec_list_op(op, A):
"""Apply an unary operation to a multivariable polynomial: op(A)"""
if isinstance(A, list):
return [unary_rec_list_op(op, a) for a in A]
return op(A)
def binary_rec_list_op(op, A, B):
"""Apply a binary operation to two multivariable polynomials: op(A,B)"""
if isinstance(A, list) and isinstance(B, list):
return [binary_rec_list_op(op, a, b) for a, b in zip(A, B)]
return op(A, B)
def lSum(A, B):
"""Sum two multivariable polynomials: A+B"""
def help_sum(a, b):
return a + b
return binary_rec_list_op(help_sum, A, B)
def lScalMult(m, A):
"""Scalar multiply a multivariable polynomials: m*A"""
def help_mul(a):
return m * a
return unary_rec_list_op(help_mul, A)
def lConvolute(A, B):
"""Multiply/Convolute two multivariable polynomials: A*B"""
if isinstance(A, list) and isinstance(B, list):
return [reduce(lSum, (lConvolute(A[k], B[n - k]) for k in range(n + 1)
if k < len(A) and (n - k) < len(B)))
for n in range(len(A) + len(B) - 1)]
return A * B
def lInvert(A):
"""Calculate reciprocal truncated power series: 1/A"""
if isinstance(A, list):
if len(A) > 1:
Ainv_s = lInvert(A[:-1])
Ap = [reduce(lSum, (lConvolute(Ainv_s[k], A[n - k]) for k in range(n))) for n in range(1, len(A))]
A0rec = lInvert(A[0])
A0rec_neg = lScalMult(-1, A0rec)
return [A0rec] + [lConvolute(A0rec_neg, a) for a in Ap]
return [lInvert(A[0])]
return Fraction(1, A)
def lLog(A):
"""Calculate the log of A: log(A)"""
if isinstance(A, list):
Ainv = lInvert(A)
Ap = [lScalMult(Fraction(1, n),
reduce(lSum, (lScalMult(k, lConvolute(A[k], Ainv[n - k]))
for k in range(1, n + 1))))
for n in range(1, len(A))]
return [lLog(A[0])] + Ap
if A == 1:
return 0
return log(A)