
Math-as-Code (2015) - yinso
https://github.com/Jam3/math-as-code
======
Koshkin
Mathematical notation is great at facilitating formal manipulations. This is
its critical feature, and without it we would get stuck at the level of
ancient mathematics. This is the reason it was invented a few hundred years
ago in the first place. That said, I find that notation is often abused in
texts as a mere substitute for the normal human language which, while allowing
to compress the text, does in fact nothing to help the reader better
understand what is being said but rather looks like a crazy mess of characters
and other marks in a multitude of fonts, styles and sizes the only purpose of
which seems to be to cause an eye strain.

~~~
rory_isAdonk
Anyone have a good resource on learning mathematical notation?

~~~
andrepd
There's no such thing as "learning mathematical notation". You learn whatever
field you are interested in, and the text you are reading will tell you what
the notation is, as "we'll denote multiplication of `a` and `b` by `ab`",
"we'll denote `A` implies `B` by `A => B`", "we'll denote derivation of `f`
wrt `x` with `df/dx`", etc.

------
BiteCode_dev
I hear regularly completly opposite opinions:

\- the ones that wish programming would be more elegant and expressive like
maths notations

\- the ones that wish paper would publish a Python algo instead because maths
notations are inconsistant and hard to read

I'm not a maths person, so can people with a lot of experience with it help me
decide which one is the more reasonable?

~~~
yodelshady
No question about it. Mathematical notation is _pure evil_ that should be cast
into mount doom and then some. Mathematical notation makes Javascript
operators look sane.

There is barely a single operation in the last few maths papers I've read that
doesn't have at least four possible interpretations at first glance, so the
only way to understand a single line is to understand the entire theory at
once. Needless to say, all variables are described with single letters.

The best defense for it is that it evolved from handwriting, where the
difference between `matmul(a,b)` and `a x b`, repeated a few dozen times, is
significant. These days, as I type, I define commands to turn the unambiguous
longhand into the shorthand.

("But yodel, a and b aren't bolded or uppercase so according to convention
they must be scalars!", I hear you say. Ha, ha, ha.)

I am genuinely angry about this. A great deal of practical mathematics is
__not hard __. Mathematical notation is hard, and everyone using it should be
a little bit ashamed at how needlessly difficult the field is.

~~~
Garlef
While I get your reasoning, I think it misses a few important points.

\-- 1. Having the same symbol for several things is the mathematicians way of
having polymorphism and is a very nice feature.

Take for example the plus sign. Everytime we encounter it, we will most likely
be dealing with some kind of abelian group. So just from seing the sign, we
can already tell a lot about the context.

Another example would be the sign for the tensor product. I we see it, we are
most likely dealing with some symmetric monoidal category . It might be vector
spaces, modules over some commutative ring, coherent sheaves, objects in some
derived category, etc. But still the important part is that all the stuff we
know about this context can be applied.

\-- 2. "so the only way to understand a single line is to understand the
entire theory at once."

What do you expect out of a single line? Just think of a codebase with 800k
lines. Would you expect to understand what the codebase is about by just
looking at a single line?

I guess not: You'd rely on the naming of the functions/classes/etc. and how
they are composed to understand what the codebase is doing. You'd also need a
lot of knowledge about the area the codebase is concerned with to tell what is
going on: Is it about a webserver providing a SPA? Is it a database? Is it a
compiler?

You also don't expect to understand the whole codebase and it's dependencies
(including low level abstractions)in its entirety: If you write a frontend
`<div>` tag as part of a frontend do you really need to know the exact way
this will end up as instructions on the chip of the computer that is running
running a specific version of a specific browser running a certain version
using drivers for a specific monitor, graphics card, etc...

All this is also true for mathematics.

\-- 3. "A great deal of practical mathematics is not hard. Mathematical
notation is hard ..."

Of course mathematics is hard. In fact: If anything related to human thought
is hard, it is mathematics.

And more explicit notation will not make it easier. Do you think the twin
prime conjecture is still unsolved because a layperson may misinterpret the
meaning of a plus sign?

~~~
roenxi
> Of course mathematics is hard.

That wasn't what was said. What was said was "A great deal of practical
mathematics is not hard.".

The notation "e^(i x pi)"is a crime in 2 languages against countless students.
Why E? No good reason. Why pi? Also no good reason. i? When they named it they
didn't even know if it was a real thing. They have many faces, and the
notation manages to avoid representing a single one of them. Even
"self_diff(rotate*half_turn)" would be an improvement; at least some of the
meanings are captured.

Naming things is hard, but this is literally 1-letter-naming applied to the 3
most common and important functions humanity has ever defined. The only excuse
for it was up until ~2,000AD the mathematicians were working by hand.

~~~
tsimionescu
But pi has lots of meanings. Sure, it represents a half-turn in geometry, but
that is in no way its only meaning (for example, it is also a transcendental
real number). The same is true for S. And the fact that that exponentiation
with complex exponents is isomorphic with geometric operations is a non-
trivial result that your notation losses. For example, log(e^i x pi) = i x pi.
Would that be as self-evident as log(self_diff(rotate x half_turn)) = rotate x
half_turn?

~~~
oalae5niMiel7qu
That "log(e^i x pi) = i x pi" is not self-evident at all. The only reason you
know it is because you attended a math class and your professor made you solve
60 problems from a $1,000 textbook until you memorized it.

I don't even know what "e^i x pi" means. How does that translate into C
notation? Is it pow(e, i) * pi, or is it pow(e, i) * x * pi, or is it
something else entirely?

~~~
tsimionescu
Unfortunately, the text inputs I have available are not good enough to
represent the actual maths notation, which is extremely clear in this respect:
it would have an e, and then in the superscript, i π. Since this is such a
well known formula (Euler's Identity), I didn't think it would be a problem.

In C notation, this would be pow(e, i * π). Or maybe pow(i*π, e), I don't
remember and the notation is pretty bad.

And the point about exponentiation is very simple, and I didn't need to do
hundreds of exercises to remember: the natural logarithm of e raised to some X
is X, whatever that X may be.

The other commenter's note was that raising some constant to an imaginary
number is a very obscure way of expressing the geometric operation that this
represents (multiplying by e^iπ is equivalent to rotating a complex number by
a half circle). I was pointing out that, while that is true, it loses the
algebraic interpretation, which also has value.

~~~
oalae5niMiel7qu
I agree with the other poster. If you can memorize log(e^N) = N, you could
have memorized other notations for expressing the same. Math notation doesn't
make Euler's Identity self-evident, and can be used to obscure the geometric
operations taking place.

To those who haven't memorized Euler's Identity (I'm aware of it due to your
comment, but will probably forget it in a day or two), this "self-evident"
truth is invisible no matter which notation is used.

C notation is bad, but has the advantage of being precisely representable in
ASCII. To post math notation you'd need to upload a PNG somewhere.

------
augustt
To be completely honest, I find it hard to believe when people claim that the
reason they never 'got' mathematics was because of the notation. Actually
understanding the concepts will almost always be significantly harder than
understanding notation.

~~~
doubleunplussed
There is a natural tendency to avoid learning the notation. Even though it
would be easy, it goes against our instincts to intentionally go out of our
way to look up notation we don't understand. With natural language one often
picks up the meaning of new words based on context, after a bit of repetition.
So it does not come naturally to people to do otherwise.

~~~
throwaway_pdp09
> to look up notation we don't understand

Not so easy. I was trying to find out which of NN and ZZ was what, try
searching for those. If you don't know what the signa (summing) sign means,
how are you going to find it?

~~~
doubleunplussed
A quick google revealed this easily. Ctrl-f'ing this article

[https://en.wikipedia.org/wiki/List_of_mathematical_symbols](https://en.wikipedia.org/wiki/List_of_mathematical_symbols)

for "Sigma" gets you that capital sigma is the summation symbol. ℤ etc are
there too though they are admittedly harder to Ctrl-f for.

Good luck googling for operators in a programming language as well though.

Like with a programming language, for which you might want to skim a tutorial,
if you are doing real analysis or whatever is talking about the sets of
integers or natural numbers, you might want to skim the opening pages of a
textbook or other course. The most common things are usually defined early on,
and the less common things are often defined in-text when they are used, e.g
"consider the bijective function f: ℤ→ℤ", now you know what f is and just need
to google "bijective function". And if you do you'll see the notation about
the domain and codomain (which you would also see in the opening chapters of
an analysis textbook or lecture notes).

I mean, learning how to use a programming language involves having to do some
reading too to get to grips with hard-to-google things. Maths is no different.

~~~
throwaway_pdp09
It's not so easy. I really was looking for those 2 (NN and ZZ) recently and
had a fight. Also bijective function, problem is I can read about it all day
but I need an intuitive understanding (which I do have now but wasn't born
with it).

> about the domain and codomain

I was taught these as domain and range. Another notational inconsistency.

I basically agree with you but maths is a lot harder for some reason than
programming. I don't think it's just me either. Perhaps if we could animate
maths... I don't know. It's simply not an easy thing.

~~~
doubleunplussed
Codomain and range are not the same - range is the set of numbers that
actually come out, codomain is like, some kind of set that those numbers are
drawn from like the integers (I'm not even sure, but it has never mattered
enough for me to find out). For the case of a bijection of course the codomain
and range are going to be the same, but not in general.

But, there are ocassional renamings of things that usually improve the overall
lingo. Some things I learned one way but they have now been renamed. E.g. I
learned about 'one-to-one and onto' functions instead of 'bijective'
functions. I think you'll agree 'bijective' is better than 'one-to-one and
onto'.

The same happens in programming languages and libraries when they rename
functions from time-to-time. For a while there are inconsistencies whilst both
are in use, sometimes permenently if the new name comes about by a creation of
a new programming language or dialects.

It's true that searching for a strange symbol you don't know the name of (or
even have the unicode character - if it exists - on hand) is hard. If you knew
they were called "blackboard-bold Z" you'd be able to find out via google what
it meant pretty easily.

(I am totally assuming you mean blackboard bold by writing ZZ and NN,
otherwise I also don't know what those mean)

~~~
throwaway_pdp09
"Codomain and range are not the same" \- Umm. Interesting. Not aware of this.

"I learned about 'one-to-one and onto' functions instead of 'bijective'
functions" \- For a beginner? The former. Past beginner? The latter. It's
context.

The "strange symbols" I only came across when searching for are described as
double-struck. I only found that recently. I only found out yesterday they
were also called Blackboard, while replying to others here. Difficulty in
finding symbol meanings are no way the hard part of maths, though.

------
_hardwaregeek
I highly recommend reading The Little Typer if you want a great book that
bridges math and code. It starts out describing Pi, a Lisp with some
interesting restrictions (limited recursion, types can have values, etc.).
They build up some cool stuff like vectors with the size encoded in the type.
All of a sudden, they explain that equality is a type, and any value of said
type is a proof! Turns out you can think of many proofs as manipulating data
structures to get a value of a certain type.

I wonder how long until we get a somewhat mainstream language with pi types. I
know Rust considered adding them. And I recently learned that Rust does allow
for quantification over lifetimes^[1]. I could certainly see a language that
implements dependently typed arrays. Midori for instance looked into eliding
bounds checks with compiler proofs^[2].

[1]: [https://doc.rust-lang.org/beta/nomicon/hrtb.html](https://doc.rust-
lang.org/beta/nomicon/hrtb.html) [2]: [http://joeduffyblog.com/2016/02/07/the-
error-model/](http://joeduffyblog.com/2016/02/07/the-error-model/)

~~~
gergoerdi
I think at this point, Haskell is the most likely to become the first
mainstream PL with Pi types:
[https://gitlab.haskell.org/ghc/ghc/-/wikis/dependent-
haskell](https://gitlab.haskell.org/ghc/ghc/-/wikis/dependent-haskell)

------
eterps
I also liked how the Fortress programming language enabled you to switch
between regular syntax and math notation:

[https://www.zdnet.com/article/guy-steeles-new-programming-
la...](https://www.zdnet.com/article/guy-steeles-new-programming-language/)

The language has faded into obscurity though.

~~~
zorked
Mathematica has that, though the math notation is more about display than
input.

~~~
henrikeh
Proper mathematical notation is absolutely for the input. Maybe not integrals
and sums (which are a bit unclear), but fractions, powers and the more
specialized notation is quite nice for readability.

------
thelazydogsback
I think the clear answer is that you want both -- maths notation, and at least
one implementation in a non-specialized programming language with clear
functional/procedural semantics. If you understand one or the other, you then
you can also learn the mapping between the two. This is also important to
remove ambiguities in notation, makes errors in each more obvious, and aids in
reproducible results. Of course, applicable input and output data also needs
to be supplied for verification. If the code is too long to publish in a paper
(usually there is at least some core idea that can be expressed) then it
should be in GitHub or elsewhere at a stable URI -- papers often refer to
academic sites that 404 soon after.

As a non-mathematician who has been recently been looking at papers in journal
back-issues from about 1970 to 2010, I certainly would have benefited from
this.

On a related note, another issue is that that maths must be implicitly ordered
in the context of the prose of the paper, while programs have actual entry-
points and (without nitpicking) explicit ordering. (It's possible that
ordering can be relaxed, but correctness preferred over runtime cost.)

I think "maths-as-data" is more important here -- use a parsable common
notation with enough meta-data that I can view it any way I want -- as math-
with-greeks, math-with-friendly-names('en-us'), as APL, as plain Python,
Python with numpy, etc.

------
Schiphol
I thought this was going to be about a math textbook (the ideas, not the
notation) that relied on previous proficiency with code. [Category Theory for
Programmers]([https://bartoszmilewski.com/2014/10/28/category-theory-
for-p...](https://bartoszmilewski.com/2014/10/28/category-theory-for-
programmers-the-preface/)) meets this description. Is anyone familiar with any
other good examples?

------
sohamsankaran
I would pay a fairly large chunk of my income to someone working on this kind
of alternate representation of mathematics full-time. Email me at soham [at]
soh.am if you're interested.

~~~
zozbot234
The closest thing to this kind of alternate representation is _formal_
mathematics, as seen in systems like Mizar, HOL Coq, Lean, Isabelle and the
like. The fact that it generally "looks like computer code" is often seen as a
drawback, but it does have its advantages. In fact, some of these systems
allow for constructive theories, which means that they _are_ programming
languages of a sort.

~~~
sohamsankaran
I think there's a place for alternate representations like these outside of
proofs that need to be exhaustively machine-checkable. I have, for what it's
worth, had far better experiences with Coq and the like than with mathematics
in general.

------
stared
I've found that PyTorch is the smoothest for math <-> programming (at least
when it comes to vector-like calculus).

See for example gradient descent in maths (LaTeX) and in PyTorch:
[https://colab.research.google.com/github/stared/thinking-
in-...](https://colab.research.google.com/github/stared/thinking-in-tensors-
writing-in-pytorch/blob/master/2%20Gradient%20Descent.ipynb)

For the smoothest math <-> programming

~~~
enriquto
I have the contrary impression. Fortran and matlab/octave are _great_ for
numeric math. Julia is also very good. The python math stuff (either torch or
numpy) is always an unreadable mess, you are always fighting against the
language. The matrix product and exponentiation operators look like a bad
joke. I do not understand how people can take this stuff seriously.

~~~
stared
To some extent, it is a matter of taste. Personally, I love functional
notation (technically, in PyTorch its chaining) e.g.:

x.matmul(y).pow(2).sum()

This way we can rite a lot of things, and we don't need to make up a new
combination of punctuation marks and special characters for an operation.

For example, while one can write in Python:

torch.sum((x @ y) __2)

I consider it less readable. I mean, here maybe it is fine, but once it gets
longer, more complicated, or we want to add new operations, it turns into a
mess.

Vide "style" section in: [https://github.com/stared/thinking-in-tensors-
writing-in-pyt...](https://github.com/stared/thinking-in-tensors-writing-in-
pytorch)

~~~
enriquto
Both of your examples are equally ugly and equally unreadable to me. Why
cannot it be something like Σ(x*y)^2 ? Why the extraneous words "torch",
"matmul" and the ridiculous operator @ ?

~~~
dunefox
I'm of the same opinion. In Julia it would be

sum(A * B) ^ 2

If you define sum as Σ then you can do

Σ(A * B) ^ 2

~~~
mkl
I think you mean sum((A*B)^2)? That's one character shorter than pytorch if
you import sum out of it, and Σ = torch.sum would be fine in Python too.

~~~
dunefox
No, the parent example was sum(A * B)^2.

I don't think you can use * if you want to backprop, for example in layer
regularisation. You'd need to use only PyTorch operations such as torch.mul(A,
B).pow(2).sum().

The point here isn't that PyTorch can't look similar to Julia in this small
example, rather that I can just use regular, concise Julia syntax - unlike in
Python + PyTorch where I need to use PyTorch constructs that are outside of
Python.

~~~
mkl
Well, there's the notational ambiguity!

In maths notation, Σ(x * y)^2 would mean Σ((x * y)^2), but in most programming
notation, treating Σ as a function, it would be as you say. I'm going with the
original formula in
[https://news.ycombinator.com/item?id=23508661](https://news.ycombinator.com/item?id=23508661).

I don't know PyTorch, but regular Python, Numpy, Sympy, etc. seem very similar
to Julia in this instance.

~~~
dunefox
You're right, that was my mistake - but I wouldn't say that it's extremely
ambiguous in this case, I just wasn't consequent enough in reading the
formula.

> I don't know PyTorch, but regular Python, Numpy, Sympy, etc. seem very
> similar to Julia in this instance.

If you need PyTorch to record the operations for the backward pass later on I
believe you need to use PyTorch versions of *, +, etc.: torch.mul, torch.sub,
torch.add, etc. In Julia you can just use built in functions and let Flux
handle the backward pass.

------
analbumcover
Homotopy type theory is a programming language whose original purpose was
"math-as-code". Gaining widespread adoption among mathematicians, let alone
programmers, seems unlikely as mathematicians dislike programming languages
for their perceived lack of elegance and are firmly set in their set theoretic
ways, while most programmers balk at the barest hint concision and rigor.

~~~
gergoerdi
HoTT isn't a programming language, because there are non-value normal forms.
That's the whole reason behind research into various formulations of Cubical
Type Theory, which is a programming language.

~~~
analbumcover
Intensional intuitionistic type theory is a programming language. Throw in
higher inductive types (still a programming language at this point) and
Voevodsky's univalence and you've got HoTT. Then sure, the simplicial model is
not constructive, whereas the cubical models give computational meaning to
univalence, but they're still just that, models of HoTT. So would you prefer I
had said HoTT has models that are programming languages?

------
ilaksh
This is really cool, but where I get really lost in not on the more basic
stuff covered here, but the more advanced math that shows up frequently in ML
papers for example.

It seems like there is a lot of stuff in math that is kind of like code
libraries or functions in programming, except you are supposed to just
remember exactly how it works rather than having the source code.

------
winrid
I love this kind of stuff. Following this thread for books.

Currently I'm doing Data Science From Scratch except in C++ instead of Python.

[https://github.com/winrid/data-science-from-scratch-
cpp](https://github.com/winrid/data-science-from-scratch-cpp)

------
vthommeret
I plan to create a Show HN shortly, but I created an interactive Python
tutorial to teach engineers how to read and implement math using the NumPy
library, called Math to Code:

[https://mathtocode.com](https://mathtocode.com)

It takes you from basic functions like square roots and absolute values, to
summations, matrix multiplication, to measures like standard deviation and the
Frobenius norm.

I was inspired to create it while taking the Fast.ai course and Jeremy Howard
showing what looked like a "complicated" Frobenius norm equation that could be
implemented in a single line of Python.

It's open source and should also work on mobile.

------
gnramires
If anyone is seriously interested in doing mathematics on the computer, give
Sage a try. It gets rid of many machine-particularities, like floats not being
real numbers (due to limited precision). You can easily represent and solve
equations, do calculus, integration, etc. And it supports a python-like
programming too.

So you can write a for loop which solves an equation with different parameters
at each iteration, for example. You can write logical proofs too, although
that's not the main purpose. (I think doing calculations on your computer and
generally being a superb Math assistant is where it's at).

~~~
dependenttypes
> It gets rid of many machine-particularities, like floats not being real
> numbers (due to limited precision).

I will have to doubt that for the simple fact that it is impossible to have a
real number type on a computer.

~~~
gnramires
Real numbers are represented as abstract data structures, not as infinite
series of digits (although that indeed fits in a Turing machine? :p)

So for example, '2' is recognized as an integer and is represented using
arbitrary size integers. You can also however write 'x = sqrt(2)' (or just
'sqrt(2)'), which has no finite digital (irrational), 'x' is a real number.
You can then ask for finitely many digits of x, with 'x.n(5)' (gives 5
digits), or write something like 'y=x^3+3x-4', which gives another real
number, represented as this polynomial data structure itself.

The only problem with this is irreducibility. You can compose arbitrarily many
operations on floats and still get a float of the same size. With this
approach, it may not be possible to simplify a series of operations so the
representation can grow unbounded.

edit: Fun fact, there are (real) numbers that indeed cannot be represented in
a finite computer no matter what -- but they cannot be represented in paper or
uniquely represented in any finite abstract form either! This follows from the
pigeonhole principle: finite expressions may represent numbers, but there are
uncountably infinite (2^(N0)) real numbers, and only countably infinitely many
expressions. So indeed almost every real cannot be represented. You can think
of those as not being identifiable with any property, so there's no finite
expression to describe them. They're more or less random.

~~~
dependenttypes
There are real numbers that can't be represented in an "infinite" computer
either.

~~~
gnramires
Every real number can be associated with an infinite series of digits, so a
theoretical infinite tape could hold any one (or countably infitely many).

~~~
dependenttypes
> so a theoretical infinite tape could hold any one (or countably infitely
> many).

I am not sure what you mean with that. You could have an infinite tape that
holds the number 1 and an "infinitely sized" irrational number at the same
time.

------
dang
See also:

2017 (a bit):
[https://news.ycombinator.com/item?id=15948326](https://news.ycombinator.com/item?id=15948326)

(another bit):
[https://news.ycombinator.com/item?id=15947744](https://news.ycombinator.com/item?id=15947744)

2015:
[https://news.ycombinator.com/item?id=9805071](https://news.ycombinator.com/item?id=9805071)

2015 (a bit):
[https://news.ycombinator.com/item?id=9801620](https://news.ycombinator.com/item?id=9801620)

------
xvilka
In the future, I hope, there will be more convergence between formal proofs
systems and the mathematical notation for learning, teaching, and storing
knowledge. Systems like Lean, Coq, Sage Math, Octave, etc should work together
on bringing more uniformity to the representation. Not for the actual code or
an engine but some uniform language/format/interface, bringing the way to read
and write it as a daily math, while preserving portability between those
systems.

------
iamthemalto
Am I missing something, or is the arrow operator (mathematical implication)
not quite right in the example code they give? What happens when a statement
is vacuously true?

------
percentcer
Weird that they left out the completely baffling yet for some reason
ubiquitous Leibniz notation

------
rdlecler1
I had a lot of trouble following mathematical (often analytical) notation
because you could never drill down. It wasn’t until I started looking at the
code making up math libraries that it all came together.

------
odc
Oh. I was expecting someone to post the original APL paper here.

------
29athrowaway
In JavaScript you should use Number.EPSILON rather than 1e-5

------
truth_seeker
Beautiful !

------
hntestacc
This is a test. If you see this, please pass through.

