Stefan Pabst

14 March 2022

2 min read

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.

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.

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:

In Rel in 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`

.

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}]
]
```

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

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

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}.

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, N_{circle}, and the total number of points placed, N_{total}, 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 N_{circle}/N_{total} 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!