Fermat's Last Theorem in Sonic Pi: A Ruby Gem for Modular Forms

Fermat’s Last Theorem in Sonic Pi: A Ruby Gem for Modular Forms

I. Prelude

Modern number theory is often highly abstract and challenging to approach without advanced mathematical training. Among its most profound achievements is Fermat’s Last Theorem, proven by Andrew Wiles.

A few months ago, I began toying with the idea of bringing these deep mathematical concepts into Sonic Pi in a way that would be both intuitive and musically expressive (perhaps because I had them as a background image on my desktop, who knows?). What started as a fleeting thought quickly grew into a more serious reflection on how I could actually bring it to life.

A few weeks ago, I finally decided to take the plunge. Armed with my notebook, I sketched out some rough ideas and dived in. Inspired in part by tools like SageMath and the LMFDB database, and guided by literature on the subject, I set out to develop a Ruby gem called modular_forms.

II. Goals

This gem has two main goals:

  • To serve as a creative tool for generating music based on deep number theory structures in an intuitive way.
  • To provide an educational bridge for those starting their journey into number theory.

III. Getting Started

Install the gem with:

gem install modular_forms

Then, try this example, where we combine eta functions to construct a weight 2 modular form of level 144 associated with an elliptic curve, and use it to create a musical representation of one of the key ideas behind Fermat’s Last Theorem: the connection between them through its L-function.

Make sure to replace <PATH> with the actual path where modular_forms.rb is installed in your system:

require "<PATH>/modular_forms.rb"

# Set precision for Fourier q-expansion
prec = 20

# Build a weight 2 newform as an eta quotient
n = ModularForms.dedekind_eta_pow(12, prec, 12)
d1 = ModularForms.dedekind_eta_pow(4, prec, 6)
d2 = ModularForms.dedekind_eta_pow(4, prec, 24)
eta_prod = ModularForms.eta_product(d1, d2)
newform = ModularForms.eta_quotient(n, eta_prod, prec)

# Define elliptic curve E over F_p
p = 13
ellc = ModularForms.elliptic_curve_fp(p, [0, -1])  # y^2 = x^3 - 1
points = ModularForms.cardinality_fp(ellc)

# Modular coefficient a_p of L-function(E, s)
a_p = ModularForms.a_p(p, points)

# Sonify the modular relationship
live_loop :modularity_music do
  play (chord(:a3 + a_p, :m11)[newform.ring.tick]),
    amp: a_p, release: 0.125
  sleep 0.125
end

You can cross-check the mathematical data in the LMFDB.

IV. Status of modular_forms

The gem is still in its early stages. You can check out the GitHub repository for a list of limitations and the modules that have been implemented so far.
Some of the features currently supported include:

V. Collaboration

If you’re interested in trying it out, providing feedback, or contributing to development, feel free to reach out via email or here. I’d be happy to collaborate and create something together!


Best regards to all fellow live coders!
Edgar Delgado Vega

2 Likes

Had a brief play with this. In the simple example on github I found two problems.
First a typo

require "<PATH>/modular_forms.rb"

# Generate an Eisenstein series of weight k = 4
eisenstein_melody = ModularForms.eisenstein_serie(4)

# Play the melody in a loop with a mathematical transformation
120.times do
  play eisenstein_melody.next % 12 * 7
  sleep 0.5
end

should be eisenstein_series in third line
also all of the melody entries are divisible by 12 except the first one so it doesn’t sound anything much!
I got some sounds using the code below, also with some further embelishments using density and pan. Can also try other weights eg 2 and 8 with this, (not 6 unless you alter the% divider from 7)

require "<PATH>/modular_forms.rb"

# Generate an Eisenstein series of weight k = 4
eisenstein_melody = ModularForms.eisenstein_series(4)

# Play the melody in a loop with a mathematical transformation
120.times do
  nv= eisenstein_melody.next % 7
  #miss out zero notes, but leave gap for rest
  density dice(3) do
    if nv!=0
      play (nv+12) * 4,sustain: 0.5,release: 0.25,pan: 1-dice(2) #scale to a reasonable audio range
    end
    sleep 0.5
  end
  
end

Fun thing to play with.

1 Like

Thanks for trying it out, dear Robin Newman.
Yes, I’ll fix the typo. Also, great example! We’ll need to come up with several more like that.

When it comes to the topic, the most challenging part is considering concepts with meaningful musical or analytical significance. In fact, the idea of creating a mini-DSL would be one of the toughest parts.