THIS POST IS ARCHIVED

Pi Day 2022 at RelationalAI

To celebrate Pi day, let's have some fun with π in our modeling language Rel.

We are excited to join the growing community of math lovers to celebrate International Pi Day. Pi Day is held on March 14 as its date, 3/14, resembles 3.14 --- the first three digits of π.

To celebrate Pi Day, we’re going to demonstrate how π can be approximated in various ways in our modeling language Rel, ranging from infinite series expressions to Monte-Carlo simulations. If you make it to the end, a little challenge awaits where you can test your Rel skills.

Using the Greek Letter π

Rel ships with a system-provided relation pi_float64 with the value of π as a Float64 number.

def output = pi_float64

Relation: 3.141592653589793

This is great, but the first thing we want to do is to refer to π using the Greek letter π, which is possible because Rel supports Unicode characters, which are a superset of ASCII.

def π = pi_float64

Now we have a relation named π that refers to our Float64 number of π. To test that it works, let’s query for this new relation.

Query: def output = π

Output: 3.141592653589793

It works! Now let’s get to work.

Best Approximation of π

First, let’s look which of the following approximations (3.14, 3.14159, 22/7, or 355/113) comes closest to the actual irrational value of π.

To do this, we define a relation pi that maps the name of the approximation to its actual value. We can think of pi as a dictionary in other languages that maps a String name to its Float64 value.

Then we are asking the system to give us the name of the best approximation. In mathematical terms, we perform the following task:

relation

In Rel it looks like this:

def pi["3.14"] = 3.14
def pi["22/7"] = 22/7
def pi["3.14159"] = 3.14159
def pi["355/113"] = 355/113

def best_approximation = argmin[abs[pi[i]-π] for i]

def output = best_approximation

Output: "355/113"

The most accurate approximation of the four options is 355/113. It’s not surprising that 3.14 and 22/7 are not the most accurate options, but it’s interesting to see that 3.14159 is only the second best. It means that if you want to remember only six digits for π\piπ, the best option is 355/113.

Computing π Using the Madhava-Leibniz Series

The Madhava-Leibniz series is one of the most famous infinite series that involves π. This series has a long history that goes back as far as the 14th century. It reads:

In Rel, we can express this series very naturally,

@inline
def leibniz_term[k] = (-1)^k/(2*k+1)

@inline
def leibniz_formula[n] =
    4*sum[leibniz_term[x]
    for x in range[0, n, 1]]

and plot its convergence behavior.

// collect convergence data
module leibniz_data
    def n_terms = 50
    def terms[i] = i, range(0, n_terms-1, 1, i)

    def pi_approx[i] = leibniz_formula[terms[i]]
    def error[i] = pi_approx[i] - π
end

// plot data
def output = vegalite:plot[
    vegalite:line[:terms, :error, {:data, leibniz_data}]
]
plot

From the plot, we can see that the Madhava-Leibniz series oscillates around π\piπ and converges slowly towards the exact value.

Calculate the Gaussian Integral

Another famous mathematical formula involving π\piπ is the Gaussian integral,

formula

which is ubiquitous in many STEM areas including probability theory, statistics, and physics.

We can express this integral in Rel by discretizing the x axis and turning the integral into a sum x∫dx→∑Δx. We then use Rel’s aggregation capabilities to perform this sum.

// discretization parameters
def n = 100
def x_max = 10.0
def dx = 2*x_max / n

// x points
def x = -x_max + dx * range[0, n-1, 1]

// Gaussian
@inline
def gaussian[x] = natural_exp[-x^2]

// Gaussian Integral
def integral = sum[gaussian[i] for i in x] * dx

def pi = integral^2

def output = pi

Output: 3.1415926535897913

By approximating the integral with 100 points, we can approximate π with a surprisingly high accuracy of around 10−15.

Sampling a Unit Circle with Monte Carlo

Our last example is another famous one. To estimate π, we can use a Monte Carlo simulation. The key idea is to approximate the area of a circle with a radius of 0.5 --- which is π/4 --- by placing random points in an enclosing unit square and counting the points that fall within the circle.

The ratio between the number of points within the circle, Ncircle, and the total number of points placed, Ntotal, approximates the circle area of π/4.

In Rel, we can build this simulation with just a few lines of code:

@inline
def rand = random_threefry_float64

module sample
   def size = 10^3
   def x[i] = rand[i, 1] - 0.5, range(1, size, 1, i)
   def y[i] = rand[i, 2] - 0.5, range(1, size, 1, i)
end

def points_in_circle(i) = sample:x[i]^2 + sample:y[i]^2 < 0.5^2

We’re using the Threefry pseudorandom number generator to place our random points. The module sample contains all the information about our samples from the sample size size to the x and y positions of the points. The relation points_in_circle holds all the sample IDs where the point falls within the circle.

The only thing left is the calculation of the ratio Ncircle/Ntotal​ which we multiply by four to get π.

Now it’s your turn! Complete the following query, and find the definition for ratio such that the relation pi holds the approximate value of π.

// def ratio = ???
def pi = 4*ratio

def output = pi

Output: 3.164

def ratio = count[points_in_circle] / sample:size

We hope you had fun playing around with π in Rel. Happy Pi Day from all of us at RelationalAI!