Some say you must know math to truly know programming, while others claim that's false.
In the modern world, many mathematicians also have to know how to code (e.g. using Sage) to test hypothesis or avoid doing a lot of manual work.
One thing that I found surprising is a deep connection between mathematical formulae and programming, in a sense that a math formula is essentially a deterministic algorithm - given some input - get an output.
This blogpost is heavily inspired by Willan's formula but I will show you how I got to alternative formulae for primes, and much more.
If scary math equations scare you, you are not alone - together I hope we get to build-up some sort of "programming building blocks" that would help us undertake this task.
That's a tough question - generally mathematical formulae are algorithmic in nature, but some of them might actually be very hard to be useful.
For example,
On the other hand, we must be very careful - formulae that have division by zero or infinite sums that do not converge are nonsensical (in most "normal" situations, anyway).
Therefore, I try to stick to the following rules:
- All formulae that I consider must avoid doing anything nonsensical (such as division by zero and others).
- I use LaTeX type of formulae, which is easy to turn into human-readable text.
- I avoid infinities (even when it does make sense, e.g. avoid this:
$\max_{k\in\mathbb{N^+}}{\frac{1}{k}}$ . - Formulaes can be highly inefficient in terms of time-complexity, which is acceptible.
With that, let's get started!
For conditions, our goal is using Indicators. An indicator is a function that gets a single input and outputs either 0 or 1 - indicating whether some conditions is true for the number. That is very helpful as 0 and 1 have special roles in mathematics:
- Adding
0to any sum does not change it. - Multiplying by
0makes the entire product0. - Adding
1helps us count - if we added the number1five times to itself - we get a5. - Multiplying by
1des not change the product.
-
Logical not(negation) is easy - assuming our input is also an indicatorI, we apply$1-I\left(n\right)$ , which will turn a0into a1and vice-versa. -
Logical andconditions are also easy, as we are working with indicators, we simply multiply conditions:a and bis really$ab$ - as it only takes one of the inputs to be0in order for the entire result to be0. -
Logical oris a bit more complicated, we could address it in several ways. One approach is adding all terms and test if the result is positive - we could implement that (see later aboutnon-negativity), but at this point, since we haveandandnot, we could apply De Morgan's laws:a or bis equivalent tonot((not a) and (not b)), which simply turns into this:a or bis$1-\left(1-a\right)\left(1-b\right)$ . To convince yourself this is true - feel free to assign all0and1combinations (there are only 4 such combinations) and see how the result yields the logical result of anorcondition.
-
Inequalityhas one main idea - using thearctanfunction, which turns a0into a0and all other inputs into non-zero values in the range$\left(-\frac{\pi}{2},\frac{\pi}{2}\right)$ . We turn all negative values to positive ones by squaring, and then normalize by$\frac{\pi^2}{4}$ due to the squaring.
This gives us a number between 0 and 1, where0is only yielded for the input0. Then, we simply use the ceiling function, which means all input turn into1except for the input0. Therefore, the conditiona != bcan turn into$\left\lceil\frac{4\arctan^2{\left(a-b\right)}}{\pi^2}\right\rceil$ . Again - to convince yourself, noticearcsinyields0only when the input is0, which can happen only ifa == b. -
Equalityis easy given inequality - obviously we can now combine negation with inequality to test for equality:a == bis implemented as:$1-\left\lceil\frac{4\arctan^2{\left(a-b\right)}}{\pi^2}\right\rceil$ .
-
Non-negativitycould compare the absolute value of a number with that number. This can be implemented by calling the equality test on$\sqrt{x^2}$ (which is the absolute value of a number) andx:$1-\left\lceil\frac{4\arctan^2{\left(\sqrt{x^2}-x\right)}}{\pi^2}\right\rceil$ . -
Less-than-or-equal-toindicator is now quite trivial: to check ifa <= b, we could check non-negativity onb-a:$1-\left\lceil\frac{4\arctan^2{\left(\sqrt{\left(b-a\right)^2}-\left(b-a\right)\right)}}{\pi^2}\right\rceil$ . -
Strictly-less-thanis also obvious, asa < bis equivalent tonot (b <= a). -
Strictly-bigger-thancan be implemented trivially:a > bis justb < awhich we have already done. -
Bigger-than-or-equal-tois similarly implemented:a >= bis justb <= a.
-
Integer testcould be done very similarly to what we have done before with trigonometry. Given the inputx, we could use thecosinefunction on$x\pi$ - which yields-1and1if and only ifxis an integer, and a number between those otherwise. Therefore, squaring the result gives us a number in the range$\left[0,1\right]$ and yields1only whenxis an integer. We use thefloorfunction on the result to make all non-1 numbers yield0. To summarize,$x\in\mathbb{Z}$ can be implemented as$\left\lfloor\cos^2\left(\pi x\right)\right\rfloor$ . -
Natural number testingcan now be implemented easily:$x\in\mathbb{N}$ (xis a Natural number) can be implemented by adding the integer test withx>0(orx>=0if you insist that$0\in\mathbb{N}$ ).
Obviously the "usual" operations of addition, substruction, multipication, division, square roots and powers are free.
However, there are some cool mathematical tricks we could use for our benefit.
- Assuming
ais not0, we can check ifadividesbby testing if$\frac{b}{a}$ is an integer. - To get
a % b(the remainder) we could use the floor function:$a - b\left\lfloor\frac{a}{b}\right\rfloor$ .
- The easiest (yet very inefficient) primality test relies on Wilson's theorem, in essence,
nis prime ifn > 1and$\frac{\left(n-1\right)!+1}{n}$ is an integer. - One more idea would just be iterating all numbers between
2andn-1and performing divisibility tests on all of them, which can be done with summation of$\sum_{k=2}^{n-1}$ . - Lastly, instead of a summation we could use the multiplication of
$\prod_{k=2}^{n-1}$ and making sure none of them dividen.
- We could use the floor function to get the decimal digits of a number after the decimal point:
$\left\lfloor10^n x\right\rfloor - 10\left\lfloor10^{n-1} x\right\rfloor$ .
Loops are an essential part of programming, and do not exist in "traditional" math formulae as simply as they appear in programming.
However, we could still use sums and products to "iterate" through a loop.
- This is where our indicators really pay off - given an indicator
Iwe simply sum them. For example, to count how many numbers yield1from the indicatorIin the range of integers between1and10, we yield:$\sum_{k=1}^{10}\left(I\left(k\right)\right)$ . - To ensure all numbers in a range yield
1for the given indicatorI, we can multiply them all:$\prod_{k=1}^{10}\left(I\left(k\right)\right)$ . - Given an indicator, we can now check if at least
nelements yield true. This was originally done by Willans by using the function$\left\lfloor\sqrt[n]{\frac{n}{k}}\right\rfloor$ which yields1if and only ifn >= k. However, we already have the comparison for>=so we can use either.
I built a Python script that gets a JSON, parses everything there and outputs the formula.
Here's an example:
{
"compose":
{
"a": "f\\left(n\\right)=\\sum_{i=1}^{2^n}",
"b": {
"is_range_at_least_exp": {
"lo": 1,
"hi": "i",
"n": "n",
"index_letter": "j",
"indicator": {
"is_prime_divisors": {
"a": "j"
}
}
}
}
}
}I run ./prog2math.py -j examples/prime_gen_divisors.json I get:
f\left(n\right)=\sum_{i=1}^{2^n}\left(\left\lfloor\sqrt[{n}]{\frac{n}{\sum_{j=1}^{i}\left(\left(\left(\left\lfloor\left(\cos\left(\pi j\right)\right)^2\right\rfloor\right)\left(1-\left(1-\left(\left\lceil\frac{4\arctan^2{\left(\sqrt{\left(0-j\right)^2}-0-j\right)}}{\pi^2}\right\rceil\right)\right)\right)\right)\left(\left(\left\lfloor\left(\cos\left(\pi \prod_{i=2}^{j-1}\left(1-\left(\left\lfloor\left(\cos\left(\pi \frac{j}{i}\right)\right)^2\right\rfloor\right)\right)\right)\right)^2\right\rfloor\right)\left(1-\left(1-\left(\left\lceil\frac{4\arctan^2{\left(\sqrt{\left(0-\prod_{i=2}^{j-1}\left(1-\left(\left\lfloor\left(\cos\left(\pi \frac{j}{i}\right)\right)^2\right\rfloor\right)\right)\right)^2}-0-\prod_{i=2}^{j-1}\left(1-\left(\left\lfloor\left(\cos\left(\pi \frac{j}{i}\right)\right)^2\right\rfloor\right)\right)\right)}}{\pi^2}\right\rceil\right)\right)\right)\right)\right)}}\right\rfloor\right)
We can easily present that - this is my forumula for the n-th prime!
Woah. A bit less elegant than Willan's formula, but works well.
I also added some other things to the examples directory, including Willan's formula (slightly changed):
I hope this quite odd blogpost was informative.
There's more work to be done - e.g. there's no concept of "memory" in formulae - can we come up with such a concept?
I'd love to see more cool ideas of generating interesting formulae - feel free to add a pull request :)
Stay tuned!
Jonathan Bar Or
