A Brief Flight of Morita's p-adic Gamma in Sonic Pi
I often like to think about the same mathematical object through different representations, e.g. musical, geometric, arithmetic, combinatorial, type-theoretic, and so on. One notion that has fascinated me ever since Emil Artin’s book, dedicated entirely to the Gamma function , keeps showing up in definitions across different contexts.
I’ll reproduce here some material from my earlier post. These formulas for the hypertetrahedral numbers will not be particularly useful for what follows, but they are what led me here.
Yes, there’s a bit of a joke in it, and also something of that trivial kind of orbit where you just look at the same object from every angle. To try out this river of equivalences, you can install my library
gem install figurate_numbers
and call
require "figurate_numbers"
gen = FigurateNumbers.k_dimensional_hypertetrahedron(57)
k_100_hypertetrahedron_num = gen.take(10)
# [1, 58, 1711, 34220, 521855, 6471002, 67945521, 621216192,
# 5047381560, 37014131440]
But I also think a lot about deformed objects built on top of these combinatorial geometries. That’s where we get to the second point.
On Gamma
figurate_numbers already has a module called ArithTransform, which includes p-adic methods you can call like this
ArithTransform.padic_val(n, p)
ArithTransform.ring_padic_val(seq, p)
ArithTransform.padic_norm(n, p)
ArithTransform.ring_padic_norm(seq, p)
ArithTransform.padic_expansion(n, p, precision = 11, reverse: false)
ArithTransform.ring_padic_expansion(seq, p, precision = 11, reverse: false)
And naturally, I’d been waiting a while to think about adding the p-adic Gamma function too.
Let’s set things up. Let denote the figurate sequence, where is the number of sides and is the dimension.
In simple words, what I’m after is simply
A bit of literature
The definition below comes from a number theory question posted on MathOverflow five and a half years ago about computing this. The question was answered by Henri Cohen, who points to his own book, specifically Chapter 11 of GTM 240.
As he mentions in the abstract, he thanks F. Rodriguez-Villegas for the script in GP used to compute this function.
That said, since this is just a sketch, I’ll leave optimization aside and think only about computing the first few values. The algorithm will be a naive one.
The p-adic side
The definition for integers (please use non-generalized figurate numbers; you’ve been warned, but do the opposite if you feel like it), and taking from here on (as if everything just happened to fit), is simply expressed as an arithmetic function with a product, going from , like this:
Finally, all that’s left is to bend the geometry of the figurate numbers to the p-adic Gamma.
Letting the Naive Algorithm Run
In the end, since I’m also fascinated by the question of iteration, I figure we could add some refinements with a magnifying glass.
For positive integer inputs, the product formula gives an ordinary integer value. This value is naturally regarded as an element of , and reducing it modulo gives a finite-precision approximation, which can then be expressed in base .
So here’s the algorithm, quite succinct and direct, without worrying about the cost of all those repeated multiplications:
def gamma_p_mod(n, p, r)
raise ArgumentError, "n must be >= 1" if n < 1
raise ArgumentError, "p must be >= 3" if p < 3
raise ArgumentError, "r must be >= 1" if r < 1
modulo = p ** r
product = 1
(1...n).each do |j|
if j % p != 0
product = (product * j) % modulo
end
end
sign = n.even? ? 1 : -1
(sign * product) % modulo
end
Yes, the argument checks are enough for this sketch. For the sake of simplicity, I’ll only require here and leave primality aside. Or better, get confused and see how it goes during your live coding session.
Sonic Pi of the Park Birds
Finally, Sonic Pi v5 just came out recently (you can check out my post on what’s new, and the fix I made).
First of all, make sure you find the PATH to the gem file in your system (see my example).
Well then, here’s the algorithm, introducing Euclidean rhythms. Let’s begin with the hypertetrahedral numbers .
require "<PATH>/lib/figurate_numbers.rb"
#require "C:/Ruby33-x64/lib/ruby/gems/3.3.0/gems/figurate_numbers-1.5.3/lib/figurate_numbers.rb"
hypertetra = FigurateNumbers.hypertetrahedral.take(50)
p = 3
r = 2
live_loop :padic_gamma do
use_synth :fm
n = hypertetra.ring.tick
play gamma_p_mod(n, p, r) + 60,
decay: 0.1,
release: 0.125,
divisor: 100 if (spread 3,5).look
sleep 0.125
end
If we bump p=7, we get a kind of Sunday dawn birdsong sound, it’s mostly just an effect. Also, be careful when changing take(N), for a relatively large value, you’ll see the algorithm start to fail.
Closure
When will I put this up? At some point I’ll add new functionality to the library. I think most of the interesting questions about will arrive in their own, non-computational time.
