-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathexamples.sage
More file actions
102 lines (93 loc) · 2.54 KB
/
examples.sage
File metadata and controls
102 lines (93 loc) · 2.54 KB
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
92
93
94
95
96
97
98
99
100
101
102
"""
Sage code to compute values associated to a list of coin denominations.
"""
from math import comb, perm, prod
from time import time
MAX_DEPTH = 7
def compute_gaps(coins):
if len(coins) < 2:
print(f"Error: must have at least two coin denominations. Given: {coins}.")
return
m,g,p = len(coins),coins[0],coins[0]
for c in coins[1:]:
g = gcd(g,c)
p *= c
if g == 1: break
else:
print(f"Error: must have gcd equal 1. Gcd found: {g}. Given denominations: {coins}.")
return
R.<t> = PowerSeriesRing(ZZ)
a = prod((1+O(t^p))/(1-t^c+O(t^p)) for c in coins).padded_list(p)
return [i for i in range(p) if a[i] == 0]
def compute_hilbert_num(coins, gaps):
R.<t> = PolynomialRing(ZZ)
p = prod(1-t^c for c in coins)
return p//(1-t) - p*sum(t^g for g in gaps)
def compute_C(hnum):
a = hnum.list()
return lambda r: sum(-a[i]*i**r for i in range(1,len(a)))
def compute_K(coins,C):
m = len(coins)
return lambda p: C(m + p) / ((-1) ** m * prod(coins) * perm(m + p, m))
def T(n, inputs):
_, p1, p2, _, p4, _, p6, _ = inputs # p0, p3, p5, p7 never used
if n > 7:
raise NotImplementedError
values=[
# n=0:
1,
# n=1:
p1 / 2,
# n=2:
(3 * p1**2 + p2) / 12,
# n=3:
(p1**3 + p1 * p2) / 8,
# n=4:
(15 * p1**4 + 30 * p1**2 * p2 + 5 * p2**2 - 2 * p4) / 240,
# n=5:
(3 * p1**5 + 10 * p1**3 * p2 + 5 * p1 * p2**2 - 2 * p1 * p4) / 96,
# n=6:
(63 * p1**6
+ 315 * p1**4 * p2
+ 315 * p1**2 * p2**2
- 126 * p1**2 * p4
+ 35 * p2**3
- 42 * p2 * p4
+ 16 * p6) / 4032,
# n=7:
(9 * p1**7
+ 63 * p1**5 * p2
+ 105 * p1**3 * p2**2
- 42 * p1**3 * p4
+ 35 * p1 * p2**3
- 42 * p1 * p2 * p4
+ 16 * p1 * p6) / 1152]
return values[n]
def compute(coins):
print(f"Input: {coins}")
gaps = compute_gaps(coins)
print(f"Gaps: {gaps}")
hnum = compute_hilbert_num(coins, gaps)
print(f"Hilbert numerator: {hnum}")
C = compute_C(hnum)
K = compute_K(coins,C)
G = lambda r: sum(g**r for g in gaps)
sigma = lambda k: sum(d**k for d in coins)
delta = lambda k: (sigma(k) - 1) / 2**k
Tsigma = lambda n: T(n, [sigma(k) for k in range(MAX_DEPTH + 1)])
Tdelta = lambda n: T(n, [delta(k) for k in range(MAX_DEPTH + 1)])
def FelRHS(p):
terms = [comb(p, r) * Tsigma(p - r) * G(r) for r in range(p + 1)]
terms.append(2 ** (p + 1) / (p + 1) * Tdelta(p + 1))
return sum(terms)
for p in range(0, MAX_DEPTH):
assert (Kp := K(p)) == FelRHS(p)
print(f"K_{p} = {Kp}")
print()
if __name__ == "__main__":
start_time = time()
compute([3,5])
compute([4,5,6])
compute([5,6,8,9])
end_time = time()
print(f"Time elapsed: {end_time-start_time} s.")