A Discovery about Basic Logic
Logic is a foundation for many things. But what are the foundations of logic itself?
In symbolic logic, one introduces symbols like p and q
to stand for statements (or “propositions”) like “this is an
interesting essay”. Then one has certain “rules of logic”, like that,
for any p and any q, NOT (p AND q) is the same as (NOT p) OR (NOT q).
But where do these “rules of logic” come from? Well,
logic is a formal system. And, like Euclid’s geometry, it can be built
on axioms. But what are the axioms? We might start with things like p AND q = q AND p, or NOT NOT p = p. But how many axioms does one need? And how simple can they be?
It was a nagging question for a long time. But at
8:31pm on Saturday, January 29, 2000, out on my computer screen popped a
single axiom. I had already shown there couldn’t be anything simpler,
but I soon established that this one little axiom was enough to generate
all of logic:
✕
((p·q)·r)·(p·((p·r)·p))==r
|
But how did I know it was correct? Well, because I had a computer prove it. And here’s the proof, as I printed it in 4-point type in A New Kind of Science (and it’s now available in the Wolfram Data Repository):

With the latest version of the Wolfram Language, anyone can now generate this proof in under a minute. And given this proof, it’s straightforward to verify each step. But why is the result true? What’s the explanation?
That’s the same kind of question that’s increasingly
being asked about all sorts of computational systems, and all sorts of
applications of machine learning and AI. Yes, we can see what happens.
But can we understand it?
I think this is ultimately a deep question—that’s
actually critical to the future of science and technology, and in fact
to the future of our whole intellectual development.
But before we talk more about this, let’s talk about logic, and about the axiom I found for it.
The History
Logic as a formal discipline basically originated with Aristotle
in the 4th century BC. As part of his lifelong effort to catalog
things (animals, causes, etc.), Aristotle cataloged valid forms of
arguments, and created symbolic templates for them which basically
provided the main content of logic for two thousand years.
By the 1400s, however, algebra had been invented, and
with it came cleaner symbolic representations of things. But it was not
until 1847 that George Boole finally formulated logic in the same kind of way as algebra, with logical operations like AND and OR being thought of as operating according to algebra-like rules.
Within a few years, people were explicitly writing down axiom systems for logic. A typical example was:
✕
and[p,q]==and[q,p],or[p,q]==or[q,p],and[p,or[q,not[q]]]==p,or[p,and[q,not[q]]]==p,and[p,or[q,r]]==or[and[p,q],and[p,r]],or[p,and[q,r]]==and[or[p,q],or[p,r]]}
|
But does logic really need AND and OR and NOT? After the first decade of the 1900s several people had discovered that actually the single operation that we now call NAND is enough, with for example p OR q being computed as (p NAND p) NAND (q NAND q). (The “functional completeness” of NAND
could have remained forever a curiosity but for the development of
semiconductor technology—which implements all the billions of logic
operations in a modern microprocessor with combinations of transistors that perform none other than NAND or the related function NOR.)
But, OK, so what do the axioms of logic (or “Boolean algebra”) look like in terms of NAND? Here’s the first known version of them, from Henry Sheffer in 1913 (here dot · stands for NAND):
✕
{(p\[CenterDot]p)\[CenterDot](p\[CenterDot]p)==p,p\[CenterDot](q\[CenterDot](q\[CenterDot]q))==p\[CenterDot]p,(p\[CenterDot](q\[CenterDot]r))\[CenterDot](p\[CenterDot](q\[CenterDot]r))==((q\[CenterDot]q)\[CenterDot]p)\[CenterDot]((r\[CenterDot]r)\[CenterDot]p)}
|
Back in 1910 Whitehead and Russell’s Principia Mathematica
had popularized the idea that perhaps all of mathematics could be
derived from logic. And particularly with this in mind, there was
significant interest in seeing just how simple the axioms for logic
could be. Some of the most notable work on this was done in Lviv and
Warsaw (then both part of Poland), particularly by Jan Łukasiewicz (who, as a side effect of his work, invented in 1920 parenthesis-free Łukasiewicz or “Polish” notation). In 1944, at the age of 66, Łukasiewicz fled from the approaching Soviets—and in 1947 ended up in Ireland.
Meanwhile, the Irish-born Carew Meredith,
who had been educated at Winchester and Cambridge, and had become a
mathematics coach in Cambridge, had been forced by his pacifism to go
back to Ireland in 1939. And in 1947, Meredith went to lectures by
Łukasiewicz in Dublin, which inspired him to begin a search for simple
axioms, which would occupy most of the rest of his life.
Already by 1949, Meredith found the two-axiom system:
✕
{(p\[CenterDot](q\[CenterDot]r))\[CenterDot](p\[CenterDot](q\[CenterDot]r))==((r\[CenterDot]p)\[CenterDot]p)\[CenterDot]((q\[CenterDot]p)\[CenterDot]p),(p\[CenterDot]p)\[CenterDot](q\[CenterDot]p)==p}
|
After nearly 20 years of work, he had succeeded by 1967 in simplifying this to:
✕
{p\[CenterDot](q\[CenterDot](p\[CenterDot]r))==((r\[CenterDot]q)\[CenterDot]q)\[CenterDot]p,(p\[CenterDot]p)\[CenterDot](q\[CenterDot]p)==p}
|
But could it get any simpler? Meredith had been picking away for years trying to see how a NAND could be removed here or there. But after 1967 he apparently didn’t get any further (he died in 1976), though in 1969 he did find the three-axiom system:
✕
{p\[CenterDot](q\[CenterDot](p\[CenterDot]r))==p\[CenterDot](q\[CenterDot](q\[CenterDot]r)),(p\[CenterDot]p)\[CenterDot](q\[CenterDot]p)==p,p\[CenterDot]q==q\[CenterDot]p}
|
I actually didn’t know about Meredith’s work when I
started exploring axiom systems for logic. I’d gotten into the subject
as part of trying to understand what kinds of behavior simple rules
could produce. Back in the early 1980s I’d made the surprising discovery that even cellular automata with some of the simplest possible rules—like my favorite rule 30—could generate behavior of great complexity.
And having spent the 1990s basically trying to figure
out just how general this phenomenon was, I eventually wanted to see how
it might apply to mathematics. It’s an immediate observation that in
mathematics one’s basically starting from axioms (say for arithmetic, or geometry, or logic), and then trying to prove a whole collection of sophisticated theorems from them.
But just how simple can the axioms be? Well, that was
what I wanted to discover in 1999. And as my first example, I decided
to look at logic (or, equivalently, Boolean algebra). Contrary to what I
would ever have expected beforehand, my experience with cellular automata, Turing machines, and many other kinds of systems—including even partial differential equations—was
that one could just start enumerating the simplest possible cases, and
after not too long one would start seeing interesting things.
But could one “discover logic” this way? Well, there
was only one way to tell. And in late 1999 I set things up to start
exploring what amounts to the space of all possible axiom
systems—starting with the simplest ones.
In a sense any axiom system provides a set of constraints, say on p · q. It doesn’t say what p · q “is”; it just gives properties that p · q must satisfy (like, for example, it could say that p · q = q · p). Then the question is whether from these properties one can derive all the theorems of logic that hold when p · q is Nand[p, q]: no more and no less.
There’s a direct way to test some of this. Just take the axiom system, and see what explicit forms of p · q satisfy the axioms if p and q can, say, be True or False. If the axiom system were just p · q = q · p then, yes, p · q could be Nand[p, q]—but it doesn’t have to be. It could also be And[p, q] or Equal[p, q]—or lots of other things which won’t satisfy the same theorems as the NAND function in logic. But by the time one gets to the axiom system {((p · p) · q) · (q · p) = q} one’s reached the point where Nand[p, q] (and the basically equivalent Nor[p, q]) are the only “models” of p · q that work—at least assuming p and q have only two possible values.
So is this then an axiom system for logic? Well, no. Because it implies, for example, that there’s a possible form for p · q with 3 values for p and q,
whereas there’s no such thing for logic. But, OK, the fact that this
axiom system with just one axiom even gets close suggests it might be
worth looking for a single axiom that reproduces logic. And that’s what
I did back in January 2000 (it’s gotten a bit easier these days, thanks
notably to the handy, fairly new Wolfram Language function Groupings).
It was easy to see that no axioms with 3 or fewer “NANDs” (or, really, 3 or fewer “dot operators”) could work. And by 5am on Saturday, January 29 (yes, I was a night owl then), I’d found that none with 4 NANDs could work either. By the time I stopped working on it a little after 6am, I’d gotten 14 possible candidates with 5 NANDs. But when I started work again on Saturday evening and did more tests, every one of these candidates failed.
So, needless to say, the next step was to try cases with 6 NANDs.
There were 288,684 of these in all. But my code was efficient, and it
didn’t take long before out popped on my screen (yes, from Mathematica Version 4):

At first I didn’t know what I had. All I knew was that these were the 25 inequivalent 6-NAND axioms that got further than any of the 5-NAND
ones. But were any of them really an axiom system for logic? I had a
(rather computation-intensive) empirical method that could rule axioms
out. But the only way to know for sure whether any axiom was actually
correct was to prove that it could successfully reproduce, say, the
Sheffer axioms for logic.
It took a little software wrangling, but before many
days had gone by, I’d discovered that most of the 25 couldn’t work. And
in the end, just two survived:
✕
{((p\[CenterDot]q)\[CenterDot]r)\[CenterDot](p\[CenterDot]((p\[CenterDot]r)\[CenterDot]p))==r}
|
✕
{(p\[CenterDot]((r\[CenterDot]p)\[CenterDot]p))\[CenterDot](r\[CenterDot](q\[CenterDot]p))==r}
|
And to my great excitement, I was successfully able to
have my computer prove that both are axioms for logic. The procedure
I’d used ensured that there could be no simpler axioms for logic. So I
knew I’d come to the end of the road: after a century (or maybe even a
couple of millennia), we could finally say that the simplest possible
axiom for logic was known.
Not long after, I found two 2-axiom systems, also with 6 NANDs in total, that I proved could reproduce logic:
✕
{(p\[CenterDot]q)\[CenterDot](p\[CenterDot](q\[CenterDot]r))==p,p\[CenterDot]q==q\[CenterDot]p}
|
|
✕
{(p\[CenterDot]r)\[CenterDot](p\[CenterDot](q\[CenterDot]r))==p,p\[CenterDot]q==q\[CenterDot]p}
|
|
And if one chooses to take commutativity p · q = q · p for granted, then these show that all it takes to get logic is one tiny 4-NAND axiom.
Why It Matters
OK, so it’s neat to be able to say that one’s “finished
what Aristotle started” (or at least what Boole started) and found the
very simplest possible axiom system for logic. But is it just a
curiosity, or is there real significance to it?
Before the whole framework I developed in A New Kind of Science,
I think one would have been hard-pressed to view it as much more than a
curiosity. But now one can see that it’s actually tied into all sorts
of foundational questions, like whether one should consider mathematics
to be invented or discovered.
Mathematics as humans practice it is based on a handful of particular axiom systems—each
in effect defining a certain field of mathematics (say logic, or group
theory, or geometry, or set theory). But in the abstract, there are an
infinite number of possible axiom systems out there—in effect each defining a field of mathematics that could in principle be studied, even if we humans haven’t ever done it.
Before A New Kind of Science
I think I implicitly assumed that pretty much anything that’s just “out
there” in the computational universe must somehow be “less interesting”
than things we humans have explicitly built and studied. But my discoveries about simple programs
made it clear that at the very least there’s often lots of richness in
systems that are just “out there” than in ones that we carefully select.
So what about axiom systems for mathematics? Well, to
compare what’s just “out there” with what we humans have studied, we
have to know where the axiom systems for existing areas of mathematics
that we’ve studied—like logic—actually lie. And based on traditional
human-constructed axiom systems we’d conclude that they have to be far,
far out there—in effect only findable if one already knows where they
are.
But my axiom-system discovery basically answered the
question, “How far out is logic?” For something like cellular automata,
it’s particularly easy to assign a number (as I did in the early 1980s)
to each possible cellular automaton. It’s slightly harder to do this
with axiom systems, though not much. And in one approach, my axiom can
be labeled as 411;3;7;118—constructed in the Wolfram Language as:
✕
Groupings[{p, q, r}[[1 + IntegerDigits[411, 3, 7]]], CenterDot -> 2][[118]] == r
|
And at least in the space of possible functional forms
(not accounting for variable labeling), here’s a visual indication of
where the axiom lies:

Given how fundamental logic is to so many formal systems
we humans study, we might have thought that in any reasonable
representation, logic corresponds to one of the very simplest
conceivable axiom systems. But at least with the (NAND-based)
representation we’re using, that’s not true. There’s still by most
measures a very simple axiom system for it, but it’s perhaps the hundred
thousandth possible axiom system one would encounter if one just
started enumerating axiom systems starting from the simplest one.
So given this, the obvious next question is, what about
all the other axiom systems? What’s the story with those? Well, that’s
exactly the kind of investigation that A New Kind of Science
is all about. And indeed in the book I argue that things like the
systems we see in nature are often best captured precisely by those
“other rules” that we can find by enumerating possibilities.
In the case of axiom systems, I made a picture
that represents what happens in “fields of mathematics” corresponding
to different possible axiom systems. Each row shows the consequences of
a particular axiom system, with the boxes across the page indicating
whether a particular theorem is true in that axiom system. (Yes, at
some point Gödel’s Theorem
bites one, and it becomes irreducibly difficult to prove or disprove a
given theorem in a given axiom system; in practice, with my methods that
happened just a little further to the right than the picture shows…)

Is there something fundamentally special about “human-investigated” fields of mathematics?
From this picture, and other things I’ve studied, there doesn’t seem
to be anything obvious. And I suspect actually that the only thing
that’s really special about these fields of mathematics is the
historical fact that they are what have been studied. (One might make
claims like that they arise because they “describe the real world”, or
because they’re “related to how our brains work”, but the results in A New Kind of Science argue against these.)
Alright, well then what’s the significance of my axiom
system for logic? The size of it gives a sense of the ultimate
information content of logic as an axiomatic system. And it makes it
look like—at least for now—we should view logic as much more having been
“invented as a human construct” than having been “discovered” because
it was somehow “naturally exposed”.
If history had been different, and we’d routinely looked (in the manner of A New Kind of Science)
at lots of possible simple axiom systems, then perhaps we would have
“discovered” the axiom system for logic as one with particular
properties we happened to find interesting. But given that we have
explored so few of the possible simple axiom systems, I think we can
only reasonably view logic as something “invented”—by being constructed
in an essentially “discretionary” way.
In a sense this is how logic looked, say, back in the
Middle Ages—when the possible syllogisms (or valid forms of argument)
were represented by (Latin) mnemonics like bArbArA and cElErAnt. And to
mirror this, it’s fun to find mnemonics for what we now know is the
simplest possible axiom system for logic.
Starting with ((p · q) · r) · (p · ((p · r) · p)) = r, we can represent each p · q in prefix or Polish form (the reverse of the “reverse Polish” of an HP calculator) as Dpq—so the whole axiom can be written =DDDpqrDpDDprpr. Then (as Ed Pegg found for me) there’s an English mnemonic for this: FIGure OuT Queue, where p, q, r are u, r, e. Or, looking at first letters of words (with operator B, and p, q, r being a, p, c): “Bit by bit, a program computed Boolean algebra’s best binary axiom covering all cases”.
The Mechanics of Proof
OK, so how does one actually prove that my axiom system
is correct? Well, the most immediate thing to do is just to show that
from it one can derive a known axiom system for logic—like Sheffer’s
axiom system:
✕
{(p\[CenterDot]p)\[CenterDot](p\[CenterDot]p)==p,p\[CenterDot](q\[CenterDot](q\[CenterDot]q))==p\[CenterDot]p,(p\[CenterDot](q\[CenterDot]r))\[CenterDot](p\[CenterDot](q\[CenterDot]r))==((q\[CenterDot]q)\[CenterDot]p)\[CenterDot]((r\[CenterDot]r)\[CenterDot]p)}
|
There are three axioms here, and we’ve got to derive each of them. Well, with the latest version of the Wolfram Language, here’s what we do to derive, say, the second axiom:
✕
pf = FindEquationalProof[
p\[CenterDot](q\[CenterDot](q\[CenterDot]q)) ==
p\[CenterDot]p, \!\(
\*SubscriptBox[\(\[ForAll]\), \({p, q,
r}\)]\(\((\((p\[CenterDot]q)\)\[CenterDot]r)\)\[CenterDot]\((p\
\[CenterDot]\((\((p\[CenterDot]r)\)\[CenterDot]p)\))\) == r\)\)]
|
It’s pretty remarkable that it’s now possible to just do this. The “proof object”
records that 125 steps were used in the proof. And from this proof
object we can generate a notebook that describes each of those steps:
In outline, what happens is that a whole sequence of
intermediate lemmas are proved, which eventually allow the final result
to be derived. There’s a whole network of interdependencies between
lemmas, as this visualization shows:
✕
pf["ProofGraphWeighted"]
|
Here are the networks involved in deriving all three of
the axioms in the Sheffer axiom system—with the last one involving a
somewhat whopping 504 steps:

And, yes, it’s clear these are pretty complicated. But
before we discuss what that complexity means, let’s talk about what
actually goes on in the individual steps of these proofs.
The basic idea is straightforward. Let’s imagine we had an axiom that just said p · q = q · p. (Mathematically, this corresponds to the statement that · is commutative.) More precisely, what the axiom says is that for any expressions p and q, p · q is equivalent to q · p.
OK, so let’s say we wanted to derive from this axiom that (a · b) · (c · d) = (d · c) · (b · a). We could do this by using the axiom to transform d · c to c · d, b · a to a · b, and then finally (c · d) · (a · b) to (a · b) · (c · d).
FindEquationalProof
does essentially the same thing, though it chooses to do the steps in a
slightly different order, and modifies the left-hand side as well as
the right-hand side:
✕
pf = FindEquationalProof[(a\[CenterDot]b)\[CenterDot](c\[CenterDot]d) \
== (d\[CenterDot]c)\[CenterDot](b\[CenterDot]a), \!\(
\*SubscriptBox[\(\[ForAll]\), \({p, q}\)]\(p\[CenterDot]q ==
q\[CenterDot]p\)\)]["ProofNotebook"]
|
Once one’s got a proof like this, it’s straightforward
to just run through each of its steps, and check that they produce the
result that’s claimed. But how does one find the proof? There are lots
of different possible sequences of substitutions and transformations that one could do. So how does one find a sequence that successfully gets to the final result?
One might think: why not just try all possible
sequences, and if there is any sequence that works, one will eventually
find it? Well, the problem is that one quickly ends up with an
astronomical number of possible sequences to check. And indeed the main
art of automated theorem proving consists of finding ways to prune the number of sequences one has to check.
This quickly gets pretty technical, but the most
important idea is easy to talk about if one knows basic algebra. Let’s
say you’re trying to prove an algebraic result like:
✕
(-1 + x^2) (1 - x + x^2) (1 + x + x^2) == (-1 + x) (1 + x + x^2) (1 + x^3)
|
Well, there’s a guaranteed way to do this: just apply
the rules of algebra to expand out each side—and immediately one can see
they’re the same:
✕
{Expand[(-1 + x^2) (1 - x + x^2) (1 + x + x^2)],
Expand[(-1 + x) (1 + x + x^2) (1 + x^3)]}
|
Why does this work? Well, it’s because there’s a way of
taking algebraic expressions like this, and always systematically
reducing them so that eventually they get to a standard form. OK, but
so can one do the same thing for proofs with arbitrary axiom systems?
The answer is: not immediately. It works in algebra
because algebra has a special property that guarantees one can always
“make progress” in reducing expressions. But what was discovered
independently several times in the 1970s (under names like the Knuth–Bendix and the Gröbner Basis algorithm) is that even if an axiom system doesn’t intrinsically have the appropriate property, one can potentially find “completions” of it that do.
And that’s what’s going on in typical proofs produced by FindEquationalProof (which is based on the Waldmeister (“master of trees”) system).
There are so-called “critical pair lemmas” that don’t directly “make
progress” themselves, but make it possible to set up paths that do. And
the reason things get complicated is that even if the final expression
one’s trying to get to is fairly short, one may have to go through all
sorts of much longer intermediate expressions to get there. And so, for
example, for the proof of the first Sheffer axiom above, here are the
intermediate steps:

In this case, the largest intermediate form is about 4 times the size of the original axiom. Here it is:
✕
(p\[CenterDot]q)\[CenterDot](((p\[CenterDot]q)\[CenterDot](q\
\[CenterDot]((q\[CenterDot]q)\[CenterDot]q)))\[CenterDot](p\
\[CenterDot]q)) == (((q\[CenterDot](q\[CenterDot]((q\[CenterDot]q)\
\[CenterDot]q)))\[CenterDot]r)\[CenterDot]((p\[CenterDot]q)\
\[CenterDot](((p\[CenterDot]q)\[CenterDot](q\[CenterDot]((q\
\[CenterDot]q)\[CenterDot]q)))\[CenterDot](p\[CenterDot]q))))\
\[CenterDot](q\[CenterDot]((q\[CenterDot]q)\[CenterDot]q))
|
One can represent expressions like this as a tree. Here’s this one, compared to the original axiom:

And here’s how the sizes of intermediate steps evolve through the proofs found for each of the Sheffer axioms:

Why Is It So Hard?
Is it surprising that these proofs are so complicated?
In some ways, not really. Because, after all, we know perfectly well
that math can be hard. In principle it might have been that anything
that’s true in math would be easy to prove. But one of the side effects
of Gödel’s Theorem from 1931 was to establish that even things we can eventually prove can have proofs that are arbitrarily long.
And actually this is a symptom of the much more general phenomenon I call computational irreducibility. Consider a system governed, say, by the simple rule of a cellular automaton (and of course, every essay of mine must have a cellular automaton somewhere!). Now just run the system:
✕
ArrayPlot[CellularAutomaton[{2007,{3,1}},RandomInteger[2,3000],1500],Frame->False,ColorRules->{0->White,1->Hue[0.09, 1., 1.],2->Hue[0.03, 1., 0.76]}]
|
One might have thought that given that there’s a simple
rule that underlies the system, there’d always be a quick way to figure
out what the system will do. But that’s not the case. Because
according to my Principle of Computational Equivalence
the operation of the system will often correspond to a computation
that’s just as sophisticated as any computation that we could set up to
figure out the behavior of the system. And this means that the actual
behavior of the system in effect corresponds to an irreducible amount of
computational work that we can’t in general shortcut in any way.
In the picture above, let’s say we want to know whether
the pattern eventually dies out. Well, we could just keep running it,
and if we’re lucky it’ll eventually resolve to something whose outcome
is obvious. But in general there’s no upper bound to how far we’ll have
to go to, in effect, prove what happens.
When we do things like the logic proofs above, it’s a slightly different setup.
Instead of just running something according to definite rules, we’re
asking whether there exists a way to get to a particular result by
taking some series of steps that each follow a particular rule. And,
yes, as a practical computational problem, this is immediately more
difficult. But the core of the difficulty is still the same phenomenon
of computational irreducibility—and that this phenomenon implies that
there isn’t any general way to shortcut the process of working out what a
system will do.
Needless to say, there are plenty of things in the
world—especially in technology and scientific modeling, as well as in
areas where there are various forms of regulation—that have
traditionally been set up to implicitly avoid computational
irreducibility, and to operate in ways whose outcome can readily be
foreseen without an irreducible amount of computation.
But one of the implications of my Principle of Computational Equivalence
is that this is a rather singular and contrived situation—because it
says that computational irreducibility is in fact ubiquitous across
systems in the computational universe.
OK, but what about mathematics? Maybe somehow the rules
of mathematics are specially chosen to show computational reducibility.
And there are indeed some cases where that’s true (and in some sense
it even happens in logic). But for the most part it appears that the
axiom systems of mathematics are not untypical of the space of all
possible axiom systems—where computational irreducibility is inevitably
rampant.
What’s the Point of a Proof?
At some level, the point of a proof is to know that something is true. Of course, particularly in modern times, proof has very much taken a back seat
to pure computation. Because in practice it’s much more common to want
to generate things by explicit computation than it is to want to “go
back” and construct a proof that something is true.
In pure mathematics, though, it’s fairly common to deal with things that at least nominally involve an infinite number of cases
(“true for all primes”, etc.), for which at least direct computation
can’t work. And when it comes to questions of verification (“can this
program ever crash?” or “can this cryptocurrency ever get spent twice?”)
it’s often more reasonable to attempt a proof than to do something like
run all possible cases.
But in the actual practice of mathematics, there’s more
to proof than just establishing if things are true. Back when Euclid
first wrote his Elements, he just
gave results, and proofs were “left to the reader”. But for better or
worse, particularly over the past century, proof has become something
that doesn’t just happen behind the scenes, but is instead actually the
primary medium through which things are supposed to be communicated.
At some level I think it’s a quirk of history that
proofs are typically today presented for humans to understand, while
programs are usually just thought of as things for computers to run.
Why has this happened? Well, at least in the past, proofs could really
only be represented in essentially textual form—so if they were going to
be used, it would have to be by humans. But programs have essentially
always been written in some form of computer language. And for the
longest time, that language tended to be set up to map fairly directly
onto the low-level operations of the computer—which meant that it was
readily “understandable” by the computer, but not necessarily by humans.
But as it happens, one of the main goals of my own
efforts over the past several decades has been to change this—and to
develop in the Wolfram Language a true “computational communication language” in which computational ideas can be communicated in a way that is readily understandable to both computers and humans.
There are many consequences of having such a language.
But one of them is that it changes the role of proof. Let’s say one’s
looking at some mathematical result. Well, in the past the only
plausible way to communicate how one should understand it was to give a
proof that people could read. But now something different is possible:
one can give a Wolfram Language
program that computes the result. And in many ways this is a much more
powerful way to communicate why the result is true. Because every
piece of the program is something precise and unambiguous—that if one
wants to, one can actually run. There’s no issue of trying to divine
what some piece of text means, perhaps filling in some implicit
assumptions. Instead, everything is right there, in absolutely explicit
form.
OK, so what about proof? Are there in fact unambiguous
and precise ways to write proofs? Well, potentially yes, though it’s
not particularly easy. And even though the main Wolfram Language has
now existed for 30 years, it’s taken until pretty much now to figure out
a reasonable way to represent in it even such structurally
comparatively straightforward proofs as the one for my axiom system
above.
One can imagine authoring proofs in the Wolfram Language
much like one authors programs—and indeed we’re working on seeing how
to provide high-level versions of this kind of “proof assistant”
functionality. But the proof of my axiom system that I showed above is
not something anyone authored; it’s something that was found by the
computer. And as such, it’s more like the output of running a program
than like a program itself. (Like a program, though, the proof can in
some sense be “run” to verify the result.)
Generating Understandability
Most of the time when people use the Wolfram Language—or Wolfram|Alpha—they
just want to compute things. They’re interested in getting results,
not in understanding why they get the results they do. But in
Wolfram|Alpha, particularly in areas like math and chemistry, a popular
feature for students is “step-by-step solutions”:

When Wolfram|Alpha
does something like computing an integral, it’s using all sorts of
powerful systematic algorithmic techniques optimized for getting
answers. But when it’s asked to show steps it needs to do something
different: it needs instead to explain step by step why it gets the
result it does.
It wouldn’t be useful for it to explain how it actually
got the result; it’s a very non-human process. Instead, it basically
has to figure out how the kinds of operations humans learn can be used
to get the result. Often it’ll figure out some trick that can be used.
Yes, there’ll be a systematic way to do it that’ll always work. But it
involves too many “mechanical” steps. The “trick” (“trig
substitution”, “integration by parts”, whatever) won’t work in general,
but in this particular case it’ll provide a faster way to get to the
answer.
OK, but what about getting understandable versions of
other things? Like the operation of programs in general. Or like the
proof of my axiom system.
Let’s start by talking about programs. Let’s say one’s
written a program, and one wants to explain how it works. One
traditional approach is just to “include comments” in the code. Well,
if one’s writing in a traditional low-level language, that may be the
best one can do. But the whole point of the Wolfram Language
being a computational communication language is that the language
itself is supposed to allow you to communicate ideas, without needing
extra pieces of English text.
It takes effort to make a Wolfram Language
program be a good piece of exposition, just like it takes effort to
make English text a good piece of exposition. But one can end up with a
piece of Wolfram Language code that really explains very clearly how it
works just through the code itself.
Of course, it’s very common for the actual execution of
the code to do things that can’t readily be foreseen just from the
program. I’ll talk about extreme cases like cellular automata soon.
But for now let’s imagine that one’s constructed a program where there’s
some ability to foresee the broad outlines of what it does.
And in such a case, I’ve found that computational essays (presented as Wolfram Notebooks) are a great tool in explaining what’s going on. It’s crucial that the Wolfram Language
is symbolic, so it’s possible to run even the tiniest fragments of any
program on their own (with appropriate symbolic expressions as input or
output). And when one does this, one can present a succession of steps
in the program as a succession of elements in the dialog that forms the
core of a computational notebook.
In practice, it’s often critical to create
visualizations of inputs or outputs. Yes, everything can be represented
as an explicit symbolic expression. But we humans often have a much
easier time understanding things when they’re presented visually, rather
than as some kind of one-dimensional language-like string.
Of course, there’s something of an art to creating good visualizations. But in the Wolfram Language
we’ve managed to go a long way towards automating this art—often using
pretty sophisticated machine learning and other algorithms to do things
like lay out networks or graphics elements.
What about just starting from the raw execution trace
for a program? Well, it’s hard. I’ve done experiments on this for
decades, and never been very satisfied with the results. Yes, you can
zoom in to see lots of details of what’s going on. But when it comes to
knowing the “big picture” I’ve never found any particularly good
techniques for automatically producing things that are terribly useful.
At some level it’s similar to the general problem of
reverse engineering. You are shown some final machine code, chip
design, or whatever. But now you want to go backwards to reconstruct
the higher-level description that some human started from, that was
somehow “compiled” to what you see.
In the traditional approach to engineering, where one
builds things up incrementally, always somehow being able to foresee the
consequences of what one’s building, this approach can in principle
work. But if one does engineering by just searching the computational universe
to find an optimal program (much like I searched possible axiom systems
to find one for logic), then there’s no guarantee that there’s any
“human story” or explanation behind this program.
It’s a similar problem in natural science. You see some elaborate set of things happening in some biological system.
Can one “reverse engineer” these to find an “explanation” for them?
Sometimes one might be able to say, for example, that evolution by
natural selection would be likely to lead to something. Or that it’s
just common in the computational universe and so is likely to occur.
But there’s no guarantee that the natural world is set up in any way
that necessarily allows human explanation.
Needless to say, when one makes models for things,
one inevitably considers only the particular aspects that one’s
interested in, and idealizes everything else away. And particularly in
areas like medicine, it’s not uncommon to end up with some approximate
model that’s a fairly shallow decision tree that’s easy to explain, at
least as far as it goes.
The Nature of Explainability
What does it mean to say that something is explainable? Basically it’s that humans can understand it.
So what does it take for humans to understand something?
Well, somehow we have to be able to “wrap our brains around it”.
Let’s take a typical cellular automaton with complex behavior. A
computer has no problem following each step in the evolution. And with
immense effort a human could laboriously reproduce what a computer does.
But one wouldn’t say that means the human “understands”
what the cellular automaton is doing. To get to that point, the human
would have to be readily able to reason about how the cellular automaton
behaves, at some high level. Or put another way, the human would have
to be able to “tell a story” that other humans could readily understand,
about how the cellular automaton behaves.
Is there a general way to do this? Well, no, because of computational irreducibility.
But it can still be the case that certain features that humans choose
to care about can be explained in some reduced, higher-level way.
How does this work? Well, in a sense it requires that
some higher-level language be constructed that can describe the features
one’s interested in. Looking at a typical cellular automaton pattern,
one might try to talk not in terms of colors of huge numbers of
individual cells, but instead in terms of the higher-level structures
one can pick out. And the key point is that it’s possible to make at
least a partial catalog of these structures: even though there are lots
of details that don’t quite fit, there are still particular structures
that occur often.
And if we were going to start “explaining” the behavior of the cellular automaton,
we’d typically begin by giving the structures names, and then we’d
start talking about what’s going on in terms of these named things.

The case of a cellular automaton has an interesting
simplifying feature: because it operates according to simple
deterministic rules, there are structures that just repeat identically.
If we’re dealing with things in the natural world, for example, we
typically won’t see this kind of identical repetition. Instead, it’ll
just be that this tiger, say, is extremely similar to this other one, so
we can call them both “tigers”, even though their atoms are not
identical in their arrangement.
What’s the bigger picture of what’s going on? Well,
it’s basically that we’re using the idea of symbolic representation.
We’re saying that we can assign something—often a word—that we can use
to symbolically describe a whole class of things, without always having
to talk about all the detailed parts of each thing.
In effect it’s a kind of information compression: we’re
using symbolic constructs to find a shorter way to describe what we’re
interested in.
Let’s imagine we’ve generated a giant structure, say a mathematical one:
✕
Solve[a x^4 + b x^3 + c x^2 + d x + e == 0, x]
|
Well, a first step is to generate a kind of internal
higher-level representation. For example, we might find substructures
that appear repeatedly. And we might then assign names to them. And
then display a “skeleton” of the whole structure in terms of these
names:

And, yes, this kind of “dictionary compression”–like scheme is useful in bringing a first level of explainability.
But let’s go back to the proof of my axiom system. The
lemmas that were generated in this proof are precisely set up to be
elements that are used repeatedly (a bit like shared common
subexpressions). But even having in effect factored them out, we’re
still left with a proof that is not something that we humans can readily
understand.
So how can we go further? Well, basically we have to come up with some yet-higher-level description. But what might this be?
The Concept of Concepts
If you’re trying to explain something to somebody, it’s a
lot easier when there’s something similar that they’ve already
understood. Imagine trying to explain a modern drone
to someone from the Stone Age. It’d probably be pretty difficult. But
explaining it to someone from 50 years ago, who’d already seen
helicopters and model airplanes etc., would be a lot easier.
And ultimately the point is that when we explain
something, we do it in some language that both we and whoever we’re
explaining it to know. And the richer this language is, the fewer new
elements we have to introduce in order to communicate whatever it is
that we’re trying to explain.
There’s a pattern that’s been repeated throughout
intellectual history. Some particular collection of things gets seen a
bunch of times. And gradually it’s understood that these things are all
somehow abstractly similar. And they can all be described in terms of
some particular new concept, often referred to by some new word or
phrase.
Let’s say one had seen things like water and blood and
oil. Well, at some point one realizes that there’s a general concept of
“liquid”, and all of these can be described as liquids. And once one
has this concept, one can start reasoning in terms of it, and
identifying more concepts—like, say, viscosity—that build on it.
When does it makes sense to group things into a concept?
Well, that’s a difficult question, which can’t ultimately be answered
without foreseeing everything that might be done with that concept.
And in practice, in the evolution of human language and human ideas
there’s some kind of process of progressive approximation that goes on.
There’s a much more rapid recapitulation that happens in a modern machine learning system. Imagine taking all sorts of objects that one’s seen in the world, and just feeding them to FeatureSpacePlot
and seeing what comes out. Well, if one gets definite clusters in
feature space, then one might reasonably think that each of these
clusters should be identified as corresponding to a “concept”, that we
could for example label with a word.
Now, to be fair, what’s happening with FeatureSpacePlot—like in human intellectual development—is in some ways incremental. Because to lay the objects out in feature space, FeatureSpacePlot is using features that it’s learned how to extract from previous categorizations it knows about.
But, OK, given the world as it is, what are the best
categories—or best concepts—one can use to describe things? Well, it’s
an evolving story. And in fact breakthroughs—whether in science,
technology or elsewhere—are very often precisely associated with the
realization that some new category or concept can usefully be
identified.
But in the actual evolution of our civilization, there’s
a kind of spiral at work. First some particular concept is
identified—say the idea of a program. And once some concept has been
identified, people start using it, and thinking in terms of it. And
pretty soon all sorts of new things have been constructed on the basis
of that concept. But then another level of abstraction is identified,
and new concepts get constructed, building on top of the previous one.
It’s pretty much the same story for the technology stack
of modern civilization, and its “intellectual stack”. Both involve
towers of concepts, and successive levels of abstraction.
The Problem of Education
In order for people to be able to communicate using some
concept, they have to have learned about it. And, yes, there are some
concepts (like object permanence) that humans automatically learn by
themselves just by observing the natural world. But looking for example
at a list of common words
in modern English, it’s pretty clear that most of the concepts that we
now use in modern civilization aren’t ones that people can just learn
for themselves from the natural world.
Instead—much like a modern machine learning system—at
the very least they need some “specially curated” experience of the
world, organized to highlight particular concepts. And for more
abstract areas (like mathematics) they probably need explicit exposure
to the concepts themselves in their raw abstract forms.
But, OK, as the “intellectual stack” of civilization
advances, will we always have to learn progressively more? We might
worry that at some point our brains just won’t be able to keep up, and
we’d have to add some kind of augmentation. But perhaps fortunately, I
think it’s one of those cases where the problem can instead most likely
be “solved in software”.
The issue is this: At any given point in history,
there’s a certain set of concepts that are important in being able to
operate in the world as it is at that time. And, yes, as civilization
progresses new things are discovered, and new concepts are introduced.
But there’s another process at work as well: new concepts bring new
levels of abstraction, which typically subsume large numbers of earlier
concepts.
We often see this in technology. There was a time when
to operate a computer you needed to know all sorts of low-level details.
But over time those got abstracted away, so all you need to know is
some general concept. You click an icon and things start to happen—and
you don’t have to understand operating systems, or interrupt handlers or
schedulers, or any of those details.
Needless to say, the Wolfram Language provides a great example of all this. Because it goes to tremendous trouble to “automate out”
lots of low-level details (for example about what specific algorithm to
use) and let human users just think about things in terms of
higher-level concepts.
Yes, there still need to be some people who understand
the details “underneath” the abstraction (though I’m not sure how many
flint knappers modern society needs). But mostly education can
concentrate on teaching at a higher level.
There’s often an implicit assumption in education that
to reach higher-level concepts one has to somehow recapitulate the
history of how those concepts were historically arrived at. But
usually—and perhaps always—this doesn’t seem to be true. In an extreme
case, one might imagine that to teach about computers, one would have to
recapitulate the history of mathematical logic. But actually we know
that people can go straight to modern concepts of computing, without recapitulating any of the history.
But what is ultimately the understandability network of
concepts? Are there concepts that can only be understood if one already
understands other concepts? Given a particular ambient experience for a
human (or particular background training for a neural network) there is
presumably some ordering.
But I suspect that something analogous to computational
universality probably implies that if one’s just dealing with a “raw
brain” then one could start anywhere. So if some alien were exposed to
category theory and little else from the very beginning, they’d no doubt
build a network of concepts where this is at the root, and maybe what
for us is basic arithmetic would be something only reached in their
analog of math graduate school.
Of course, such an alien might form their technology
stack and their built environment in a quite different way from us—much
as the recent history of our own civilization might have been very
different if computers had successfully been developed in the 1800s rather than in the mid-1900s.
The Progress of Mathematics
I’ve often wondered to what extent the historical
trajectory of human mathematics is an “accident”, and to what extent
it’s somehow inexorable. As I mentioned earlier, at the level of formal
systems there are many possible axiom systems from which one could
construct something that is formally like mathematics.
But the actual history of mathematics did not start with
arbitrary axiom systems. It started—in Babylonian times—with efforts
to use arithmetic for commerce and geometry for land surveying. And
from these very practical origins, successive layers of abstraction have
been added that have led eventually to modern mathematics—with for
example numbers being generalized
from positive integers, to rationals, to roots, to all integers, to
decimals, to complex numbers, to algebraic numbers, to quaternions and
so on.
Is there an inexorability to this progression of
abstraction? I suspect to some extent there is. And probably it’s a
similar story as with other kinds of concept formation. Given some
stage that’s been reached, there are various things that can readily get
studied, and after a while groups of them are seen to be examples of
more general and abstract constructs—which then in turn define another
stage from which new things can be studied.
Are there ways to break out of this cycle? One
possibility would be through doing experiments in mathematics. Yes, one
can systematically prove things about particular mathematical systems.
But one can also just empirically notice mathematical facts—like Ramanujan’s observation that
is numerically close to an integer. And the question is: are things
like this just “random facts of mathematics” or do they somehow fit into
the whole “fabric of mathematics”?
One can ask the same kind of thing about questions in mathematics. Is the question of whether odd perfect numbers exist
(which has been unanswered since Pythagoras) a core question in
mathematics, or is it, in a sense, a random question that doesn’t
connect into the fabric of mathematics?
Just like one can enumerate things like axiom systems,
so also one can imagine enumerating possible questions in mathematics.
But if one does this, I suspect there’s immediately an issue. Gödel’s Theorem
establishes that in axiom systems like the one for arithmetic there are
“formally undecidable” propositions, that can’t be proved or disproved
from within the axiom system.
But the particular examples that Gödel constructed
seemed far from anything that would arise naturally in doing
mathematics. And for a long time it was assumed that somehow the
phenomenon of undecidability was something that, while in principle
present, wasn’t going to be relevant in “real mathematics”.
However, with my Principle of Computational Equivalence and my experience in the computational universe, I’ve come to the strong conclusion that this isn’t correct—and that instead undecidability is actually close at hand
even in typical mathematics as it’s been practiced. Indeed, I won’t be
surprised if a fair fraction of the current famous unsolved problems of
mathematics (Riemann Hypothesis, P=NP, etc.) actually turn out to be in effect undecidable.
But if there’s undecidability all around, how come
there’s so much mathematics that’s successfully been done? Well, I
think it’s because the things that have been done have implicitly been
chosen to avoid undecidability, basically just by virtue of the way
mathematics has been built up. Because if what one’s doing is basically
to form progressive levels of abstraction based on things one has shown
are true, one’s basically setting up a path that’s going to be able to
move forward without being forced into undecidability.
Of course, doing experimental mathematics
or asking “random questions” may immediately land one in some area
that’s full of undecidability. But at least so far in its history, this
hasn’t been the way the mainstream discipline of mathematics has
evolved.
So what about those “random facts of mathematics”?
Well, it’s pretty much like in other areas of intellectual endeavor.
“Random facts” don’t really get integrated into a line of intellectual
development until some structure—and typically some abstract
concepts—are built around them.
My own favorite discoveries about the origins of complexity in systems like the rule 30 cellular automaton are a good example. Yes, similar phenomena had been seen—even millennia earlier (think: randomness in the sequence of primes). But without a broader conceptual framework nobody really paid attention to them.
Nested patterns are another example. There are isolated examples of these in mosaics from the 1200s, but nobody really paid attention to them until the whole framework around nesting and fractals emerged in the 1980s.
It’s the same story over and over again: until abstract
concepts around them have been identified, it’s hard to really think
about new things, even when one encounters phenomena that exhibit them.
And so, I suspect, it is with mathematics: there’s a
certain inevitable layering of abstract concept on top of abstract
concept that defines the trajectory of mathematics. Is it a unique
path? Undoubtedly not. In the vast space of possible mathematical
facts, there are particular directions that get picked, and built along.
But others could have been picked instead.
So does this mean that the subject matter of mathematics
is inevitably dominated by historical accidents? Not as much as one
might think. Because—as mathematics has discovered over and over again,
starting with things like algebra and geometry—there’s a remarkable
tendency for different directions and different approaches to wind up
having equivalences or correspondences in the end.
And probably at some level this is a consequence of the Principle of Computational Equivalence,
and the phenomenon of computational universality: even though the
underlying rules (or underlying “language”) used in different areas of
mathematics are different, there ends up being some way to translate
between them—so that at the next level of abstraction the path that was
taken no longer critically matters.
The Logic Proof and the Automation of Abstraction
OK, so let’s go back to the logic proof. How does it
connect to typical mathematics? Well, right now, it basically doesn’t.
Yes, the proof has the same nominal form as a standard mathematical
proof. But it isn’t “human-mathematician friendly”. It’s all just
mechanical details. It doesn’t connect to higher-level abstract
concepts that a human mathematician can readily understand.
It would help a lot if we discovered that nontrivial lemmas in the proof already appeared in the mathematics literature.
(I don’t think any of them do, but our theorem-searching capabilities
haven’t gotten to the point where one can be sure.) But if they did
appear, then this would likely give us a way to connect these lemmas to
other things in mathematics, and in effect to identify a circle of
abstract concepts around them.
But without that, how can the proof become explainable?
Well, maybe there’s just a different way to do the proof
that’s fundamentally more connected to existing mathematics. But even
given the proof as we have it now, one could imagine “building out” new
concepts that would define a higher level of abstraction and put the
proof in a more general context.
I’m not sure how to do either of these things. I’ve considered sponsoring a prize (analogous to my 2007 Turing machine prize)
for “making the proof explainable”. But it’s not at all clear how one
could objectively judge “explainability”. (Maybe one could ask for a
1-hour video that would successfully explain the proof to a typical
mathematician—but this is definitely rather subjective.)
But just like we can automate things like finding aesthetic layouts for networks,
perhaps we can automate the process of making a proof explainable. The
proof as it is right now basically just says (without explanation),
“Consider these few hundred lemmas”. But let’s say we could identify a
modest number of “interesting” lemmas. Maybe we could somehow add these
to our canon of known mathematics and then be able to use them to
understand the proof.
There’s an analogy here with language design. In building up the Wolfram Language
what I’ve basically done is to try to identify “lumps of computational
work” that people will often want. Then we make these into built-in functions in the language, with particular names that people can use to refer to them.
A similar process goes on—though in a much less
organized way—in the evolution of human natural languages. “Lumps of
meaning” that turn out to be useful eventually get represented by words
in the language. Sometimes they start as phrases constructed out of a
few existing words. But the most impactful ones are typically
sufficiently far away from anything that has come before that they just
arrive as new words with potentially quite-hard-to-give definitions.
In the design of the Wolfram Language—with functions named with English words—I leverage
the “ambient understanding” that comes from the English words (and
sometimes from their meanings in common applications of computation).
One would want to do something similar in identifying
lemmas to add to our canon of mathematics. Not only would one want to
make sure that each lemma was somehow “intrinsically interesting”, but
one would also want when possible to select lemmas that are “easy to
reach” from existing known mathematical results and concepts.
But what does it mean for a lemma to be “intrinsically interesting”? I have to say that before I worked on A New Kind of Science,
I assumed that there was great arbitrariness and historical accident in
the choice of lemmas (or theorems) in any particular areas of
mathematics that get called out and given names in typical textbooks.
But when I looked in detail at theorems in basic logic, I was surprised to find something different. Let’s say one arranges all the true theorems of basic logic in order of their sizes (e.g. p = p might come first; p AND p = p
a bit later, and so on). When one goes through this list there’s lots
of redundancy. Indeed, most of the theorems end up being trivial
extensions of theorems that have already appeared in the list.
But just sometimes one gets to a theorem that
essentially gives new information—and that can’t be proved from the
theorems that have already appeared in the list. And here’s the
remarkable fact: there are 14 such theorems, and they essentially correspond exactly with the theorems that are typically given names in textbooks of logic. (Here AND is ∧, OR is ∨, and NOT is ¬.)

In other words, at least in this case, the named or
“interesting” theorems are the ones that give minimal statements of new
information. (Yes, after a while, by this definition there will be no
new information, because one will have encountered all the axioms needed
to prove anything that can be proved—though one can go a bit further
with this approach by starting to discuss limiting the complexity of
proofs that are allowed.)
What about with NAND theorems, like the ones in the proof? Once again, one can arrange all true NAND theorems in order—and then find which of them can’t be proved from any earlier in the list:
✕
{{a\[CenterDot]b==b\[CenterDot]a,a==(a\[CenterDot]a)\[CenterDot](a\[CenterDot]a),a==(a\[CenterDot]a)\[CenterDot](a\[CenterDot]b),(a\[CenterDot]a)\[CenterDot]a==(b\[CenterDot]b)\[CenterDot]b,(a\[CenterDot]a)\[CenterDot]b==(a\[CenterDot]b)\[CenterDot]b,a\[CenterDot]((a\[CenterDot]b)\[CenterDot]c)==a\[CenterDot]((b\[CenterDot]b)\[CenterDot]c)},{a\[CenterDot]b==b\[CenterDot]a,a==(a\[CenterDot]a)\[CenterDot](a\[CenterDot]a),a==(a\[CenterDot]a)\[CenterDot](a\[CenterDot]b),a==(a\[CenterDot]a)\[CenterDot](b\[CenterDot]a),a==(a\[CenterDot]b)\[CenterDot](a\[CenterDot]a),a==(b\[CenterDot]a)\[CenterDot](a\[CenterDot]a),(a\[CenterDot]a)\[CenterDot]a==a\[CenterDot](a\[CenterDot]a),(a\[CenterDot]a)\[CenterDot]a==(b\[CenterDot]b)\[CenterDot]b,a\[CenterDot](a\[CenterDot]a)==(b\[CenterDot]b)\[CenterDot]b,(a\[CenterDot]a)\[CenterDot]a==b\[CenterDot](b\[CenterDot]b),a\[CenterDot](a\[CenterDot]a)==b\[CenterDot](b\[CenterDot]b),a\[CenterDot](a\[CenterDot]b)==(a\[CenterDot]b)\[CenterDot]a,a\[CenterDot](a\[CenterDot]b)==a\[CenterDot](b\[CenterDot]a),(a\[CenterDot]a)\[CenterDot]b==(a\[CenterDot]b)\[CenterDot]b,a\[CenterDot](a\[CenterDot]b)==a\[CenterDot](b\[CenterDot]b),a\[CenterDot](a\[CenterDot]b)==(b\[CenterDot]a)\[CenterDot]a,(a\[CenterDot]a)\[CenterDot]b==b\[CenterDot](a\[CenterDot]a),(a\[CenterDot]a)\[CenterDot]b==(b\[CenterDot]a)\[CenterDot]b,(a\[CenterDot]a)\[CenterDot]b==b\[CenterDot](a\[CenterDot]b),a\[CenterDot](a\[CenterDot]b)==(b\[CenterDot]b)\[CenterDot]a,(a\[CenterDot]a)\[CenterDot]b==b\[CenterDot](b\[CenterDot]a),(a\[CenterDot]b)\[CenterDot]a==a\[CenterDot](b\[CenterDot]a),(a\[CenterDot]b)\[CenterDot]a==a\[CenterDot](b\[CenterDot]b),a\[CenterDot](b\[CenterDot]a)==a\[CenterDot](b\[CenterDot]b),(a\[CenterDot]b)\[CenterDot]a==(b\[CenterDot]a)\[CenterDot]a,a\[CenterDot](b\[CenterDot]a)==(b\[CenterDot]a)\[CenterDot]a,(a\[CenterDot]b)\[CenterDot]a==(b\[CenterDot]b)\[CenterDot]a,a\[CenterDot](b\[CenterDot]a)==(b\[CenterDot]b)\[CenterDot]a,a\[CenterDot](b\[CenterDot]b)==(b\[CenterDot]a)\[CenterDot]a,(a\[CenterDot]b)\[CenterDot]b==b\[CenterDot](a\[CenterDot]a),(a\[CenterDot]b)\[CenterDot]b==(b\[CenterDot]a)\[CenterDot]b,(a\[CenterDot]b)\[CenterDot]b==b\[CenterDot](a\[CenterDot]b),a\[CenterDot](b\[CenterDot]b)==(b\[CenterDot]b)\[CenterDot]a,(a\[CenterDot]b)\[CenterDot]b==b\[CenterDot](b\[CenterDot]a),a\[CenterDot](b\[CenterDot]c)==a\[CenterDot](c\[CenterDot]b),(a\[CenterDot]b)\[CenterDot]c==(b\[CenterDot]a)\[CenterDot]c,a\[CenterDot](b\[CenterDot]c)==(b\[CenterDot]c)\[CenterDot]a,(a\[CenterDot]b)\[CenterDot]c==c\[CenterDot](a\[CenterDot]b),a\[CenterDot](b\[CenterDot]c)==(c\[CenterDot]b)\[CenterDot]a,(a\[CenterDot]b)\[CenterDot]c==c\[CenterDot](b\[CenterDot]a),(a\[CenterDot]a)\[CenterDot](a\[CenterDot]a)==(a\[CenterDot]a)\[CenterDot](a\[CenterDot]b),(a\[CenterDot]a)\[CenterDot](a\[CenterDot]a)==(a\[CenterDot]a)\[CenterDot](b\[CenterDot]a),(a\[CenterDot]a)\[CenterDot](a\[CenterDot]a)==(a\[CenterDot]b)\[CenterDot](a\[CenterDot]a),(a\[CenterDot]a)\[CenterDot](a\[CenterDot]a)==(b\[CenterDot]a)\[CenterDot](a\[CenterDot]a),(a\[CenterDot]a)\[CenterDot](a\[CenterDot]b)==(a\[CenterDot]a)\[CenterDot](a\[CenterDot]c),(a\[CenterDot]a)\[CenterDot](a\[CenterDot]b)==(a\[CenterDot]a)\[CenterDot](b\[CenterDot]a),(a\[CenterDot]a)\[CenterDot](a\[CenterDot]b)==(a\[CenterDot]a)\[CenterDot](c\[CenterDot]a),(a\[CenterDot]a)\[CenterDot](a\[CenterDot]b)==(a\[CenterDot]b)\[CenterDot](a\[CenterDot]a)},{a\[CenterDot]((a\[CenterDot]b)\[CenterDot]b)==(c\[CenterDot](a\[CenterDot]a))\[CenterDot]a,a\[CenterDot]((a\[CenterDot]b)\[CenterDot]b)==((c\[CenterDot]a)\[CenterDot]c)\[CenterDot]a,a\[CenterDot]((a\[CenterDot]b)\[CenterDot]b)==(c\[CenterDot](a\[CenterDot]c))\[CenterDot]a,(a\[CenterDot](a\[CenterDot]b))\[CenterDot]b==(c\[CenterDot](b\[CenterDot]b))\[CenterDot]b,(a\[CenterDot](a\[CenterDot]b))\[CenterDot]b==((c\[CenterDot]b)\[CenterDot]c)\[CenterDot]b,(a\[CenterDot](a\[CenterDot]b))\[CenterDot]b==(c\[CenterDot](b\[CenterDot]c))\[CenterDot]b,a\[CenterDot]((a\[CenterDot]b)\[CenterDot]b)==(c\[CenterDot](c\[CenterDot]a))\[CenterDot]a,(a\[CenterDot](a\[CenterDot]b))\[CenterDot]b==(c\[CenterDot](c\[CenterDot]b))\[CenterDot]b,a\[CenterDot]((a\[CenterDot]b)\[CenterDot]b)==((c\[CenterDot]c)\[CenterDot]c)\[CenterDot]a,a\[CenterDot]((a\[CenterDot]b)\[CenterDot]b)==(c\[CenterDot](c\[CenterDot]c))\[CenterDot]a,(a\[CenterDot](a\[CenterDot]b))\[CenterDot]b==((c\[CenterDot]c)\[CenterDot]c)\[CenterDot]b,(a\[CenterDot](a\[CenterDot]b))\[CenterDot]b==(c\[CenterDot](c\[CenterDot]c))\[CenterDot]b,a\[CenterDot](a\[CenterDot](b\[CenterDot]c))==a\[CenterDot](a\[CenterDot](c\[CenterDot]b)),(a\[CenterDot](a\[CenterDot]b))\[CenterDot]c==((a\[CenterDot]b)\[CenterDot]a)\[CenterDot]c,(a\[CenterDot](a\[CenterDot]b))\[CenterDot]c==(a\[CenterDot](b\[CenterDot]a))\[CenterDot]c,a\[CenterDot]((a\[CenterDot]b)\[CenterDot]c)==a\[CenterDot]((b\[CenterDot]a)\[CenterDot]c),((a\[CenterDot]a)\[CenterDot]b)\[CenterDot]c==((a\[CenterDot]b)\[CenterDot]b)\[CenterDot]c,(a\[CenterDot](a\[CenterDot]b))\[CenterDot]c==(a\[CenterDot](b\[CenterDot]b))\[CenterDot]c,a\[CenterDot]((a\[CenterDot]b)\[CenterDot]c)==a\[CenterDot]((b\[CenterDot]b)\[CenterDot]c),a\[CenterDot]((a\[CenterDot]b)\[CenterDot]c)==((a\[CenterDot]b)\[CenterDot]c)\[CenterDot]a,a\[CenterDot](a\[CenterDot](b\[CenterDot]c))==(a\[CenterDot](b\[CenterDot]c))\[CenterDot]a,a\[CenterDot](a\[CenterDot](b\[CenterDot]c))==a\[CenterDot]((b\[CenterDot]c)\[CenterDot]a),a\[CenterDot](a\[CenterDot](b\[CenterDot]c))==((a\[CenterDot]b)\[CenterDot]c)\[CenterDot]c,(a\[CenterDot](a\[CenterDot]b))\[CenterDot]c==(a\[CenterDot](b\[CenterDot]c))\[CenterDot]c,a\[CenterDot]((a\[CenterDot]b)\[CenterDot]c)==a\[CenterDot]((b\[CenterDot]c)\[CenterDot]c),a\[CenterDot]((a\[CenterDot]b)\[CenterDot]c)==a\[CenterDot](c\[CenterDot](a\[CenterDot]b)),a\[CenterDot](a\[CenterDot](b\[CenterDot]c))==(a\[CenterDot](c\[CenterDot]b))\[CenterDot]a,a\[CenterDot](a\[CenterDot](b\[CenterDot]c))==a\[CenterDot]((c\[CenterDot]b)\[CenterDot]a),a\[CenterDot]((a\[CenterDot]b)\[CenterDot]c)==a\[CenterDot](c\[CenterDot](b\[CenterDot]a)),a\[CenterDot](a\[CenterDot](b\[CenterDot]c))==((a\[CenterDot]c)\[CenterDot]b)\[CenterDot]b,a\[CenterDot]((a\[CenterDot]b)\[CenterDot]c)==a\[CenterDot](c\[CenterDot](b\[CenterDot]b)),((a\[CenterDot]a)\[CenterDot]b)\[CenterDot]c==((a\[CenterDot]c)\[CenterDot]b)\[CenterDot]c,(a\[CenterDot](a\[CenterDot]b))\[CenterDot]c==(a\[CenterDot](c\[CenterDot]b))\[CenterDot]c,a\[CenterDot]((a\[CenterDot]b)\[CenterDot]c)==a\[CenterDot]((c\[CenterDot]b)\[CenterDot]c),a\[CenterDot]((a\[CenterDot]b)\[CenterDot]c)==a\[CenterDot](c\[CenterDot](b\[CenterDot]c)),a\[CenterDot]((a\[CenterDot]b)\[CenterDot]c)==a\[CenterDot](c\[CenterDot](c\[CenterDot]b))}}
|
NAND doesn’t have the same kind of historical tradition as AND, OR and NOT. (And there doesn’t seem to be any human language that, for example, has a single ordinary word for NAND.) But in the list of NAND theorems, the first highlighted one is easy to recognize as commutativity of NAND. After that, one really has to do a bit of translation to name the theorems: a = (a · a) · (a · a) is like the law of double negation, a = (a · a) · (a · b) is like the absorption law, (a · a) · b = (a · b) · b is like “weakening”, and so on.
But, OK, so if one’s going to learn just a few “key theorems” of NAND logic, which should they be? Perhaps they should be theorems that appear as “popular lemmas” in proofs.
Of course, there are many possible proofs of any given theorem. But let’s say we just use the particular proofs that FindEquationalProof generates. Then it turns out that in the proofs of the first thousand NAND theorems the single most popular lemma is a · a = a · ((a · a) · a), followed by such lemmas as (a · ((a · a) · a)) · (a · (a · ((a · a) · a))) = a.
What are these? Well, for the particular methods that FindEquationalProof uses, they’re useful. But for us humans they don’t seem terribly helpful.
But what about popular lemmas that happen to be short? a · b = b · a is definitely not the most popular lemma, but it is the shortest. (a · a) · (a · a) = a is more popular, but longer. And then there are lemmas like (a · a) · (b · a) = a.
But how useful are these lemmas? Here’s a way to test. Look at the first thousand NAND theorems, and see how much adding the lemmas shortens the proofs of these theorems (at least as found by FindEquationalProof):

a · b = b · a is very successful, often cutting down the proof by nearly 100 steps. (a · a) · (a · a) = a is much less successful; in fact, it actually sometimes seems to “confuse” FindEquationalProof, causing it to take more rather than fewer steps (visible as negative values in the plot). (a · a) · (b · a) = a is OK at shortening, but not as good as a · b = b · a. Though if one combines it with a · b = b · a, the result is more consistent shortening.
One could go on with this analysis, say including a
comparison of how much shortening is produced by a given lemma,
relative to how long its own proof was. But the problem is that if one
adds several “useful lemmas”, like a · b = b · a and (a · a) · (b · a) = a, there are still plenty of long proofs—and thus a lot left to “understand”:

What Can One Understand?
There are different ways to create models of things.
For a few hundred years, exact science was dominated by the idea of
finding mathematical equations that could be solved to say how things
should behave. But in pretty much the time since A New Kind of Science appeared, there’s been a strong shift to instead set up programs that can be run to say how things should behave.
Sometimes those programs are explicitly constructed for a
particular purpose; sometimes they’re exhaustively searched for. And
in modern times, at least one class of such programs is deduced using
machine learning, essentially by going backwards from examples of how
the system is known to behave.
OK, so with these different forms of modeling, how easy
is it to “understand what’s going on”? With mathematical equations,
it’s a big plus when it’s possible to find an “exact solution”—in which
the behavior of the system can be represented by something like an
explicit mathematical formula. And even when this doesn’t happen, it’s
fairly common to be able to make at least some mathematical statements
that are abstract enough to connect to other systems and other
behaviors.
As I discussed above, with a program—like a cellular
automaton—it can be a different story. Because it’s common to be thrust
immediately into computational irreducibility, which ultimately limits
how much one can ever hope to shortcut or “explain” what’s going on.
But what about with machine learning, and, say, with neural nets? At
some level, the training of a neural net is like recapitulating
inductive discovery in natural science. One’s trying to start from
examples and deduce a model for how a system behaves. But then can one
understand the model?
Again there are issues of computational irreducibility.
But let’s talk about a case where we can at least imagine what it would
look like to understand what’s going on.
Instead of using a neural net to model how some system behaves, let’s consider making a neural net that classifies some aspect of the world: say, takes images and classifies them
according to what they’re images of (“boat”, “giraffe”, etc.). When we
train the neural net, it’s learning to give correct final outputs.
But potentially one can think of the way it does this as being to
internally make a sequence of distinctions (a bit like playing a game of
Twenty Questions) that eventually determines the correct output.
But what are those distinctions? Sometimes we can recognize
some of them. “Is there a lot of blue in the image?”, for example. But
most of the time they’re essentially features of the world that we
humans don’t notice. Maybe there’s an alternative history of natural
science where some of them would have shown up. But they’re not things
that are part of our current canon of perception or analysis.
If we wanted to add them, we’d probably end up inventing
words for them. But the situation is very similar to the one with the
logic proof. An automated system has created things that it’s
effectively using as “waypoints” in generating a result. But they’re
not waypoints we recognize or relate to.
Once again, if we found that particular distinctions
were very common for neural nets, we might decide that those are
distinctions that are worth us humans learning, and adding to our
standard canon of ways to describe the world.
Can we expect that a modest number of such distinctions
would go a long way? It’s analogous to asking whether a modest number
of theorems would go a long way in understanding something like the
logic proof.
My guess is that the answer is fuzzy. If one looks, for example, at a large corpus of math papers, one can ask how common different theorems are. It turns out that the frequency of theorems follows an almost perfect Zipf law (with the Central Limit Theorem, the Implicit Function Theorem and Fubini’s Theorem
as the top three). And it’s probably the same with distinctions that
are “worth knowing”, or new theorems that are “worth knowing”.
Knowing a few will get one a certain distance, but there’ll be an infinite power-law tail, and one will never get to the end.
The Future of Knowledge
Whether one looks at mathematics, science or technology,
one sees the same basic qualitative progression of building a stack of
increasing abstraction. It would be nice to be able to quantify this
process. Perhaps one could look at how certain terms or descriptions
that are common at one time later get subsumed into higher levels of
abstraction, which then in turn have new terms or descriptions
associated with them.
Maybe one could create an idealized model of this process using some formal model of computation, like Turing machines.
Imagine that at the lowest level one has a basic Turing machine, with
no abstraction. Now imagine selecting programs for this Turing machine
according to some defined random process. Then run these programs and
analyze them to see what “higher-level” model of computation can
successfully reproduce the aggregate behavior of these programs without
having to run each step in each program.
One might have thought that computational irreducibility
would imply that this higher-level model of computation would
inevitably be more complicated in its construction. But the key point
is that we’re only trying to reproduce the aggregate behavior of the
programs, not their individual behavior.
OK, but so then what happens if you iterate this
process—essentially recapitulating idealized human intellectual history
and building a progressive tower of abstraction?
Conceivably there’s some analogy to critical phenomena in physics, and to the renormalization group.
And if so, one might imagine being able to identify a definite
trajectory in the space of what amount to concept representation
frameworks. What will the trajectory do?
Maybe it’ll have some kind of fixed-point behavior,
representing the guess that at any point in history there are about the
same number of abstract concepts that are worth learning—with new ones
slowly being invented, and old ones being subsumed.
What might any of this mean for mathematics? One guess
might be that any “random fact of mathematics”, say discovered
empirically, would eventually be covered when some level of abstraction
is reached. It’s not obvious how this process would work. After all,
at any given level of abstraction, there are always new empirical facts
to be “jumped to”. And it might very well be that the “rising tide of
abstraction” would move only slowly compared to the rate at which such
jumps could be made.
The Future of Understanding
OK, so what does all this mean for the future of understanding?
In the past, when humans looked, say, at the natural world, they had few pretensions to understand it. Sometimes they would personify
certain aspects of it in terms of spirits or deities. But they saw it
as just acting as it did, without any possibility for humans to
understand in detail why.
But with the rise of modern science—and especially as
more of our everyday existence came to be in built environments
dominated by technology (or regulatory structures) that we had
designed—these expectations changed. And as we look at computation or
AI today, it seems unsettling that we might not be able to understand
it.
But ultimately there’s always going to be a competition
between what the systems in our world do, and what our brains are
capable of computing about them. If we choose to interact only with
systems that are computationally much simpler than our brains, then,
yes, we can expect to use our brains to systematically understand what
the systems are doing.
But if we actually want to make full use of the
computational capabilities that our universe makes possible, then it’s
inevitable that the systems we’re dealing with will be equivalent in
their computational capabilities to our brains. And this means that—as
computational irreducibility implies—we’ll never be able to
systematically “outthink” or “understand” those systems.
But then how can we use them? Well, pretty much like
people have always used systems from the natural world. Yes, we don’t
know everything about how they work or what they might do. But at some
level of abstraction we know enough to be able to see how to get
purposes we care about achieved with them.
What about in an area like mathematics? In mathematics
we’re used to building our stack of knowledge so that each step is
something we can understand. But experimental mathematics—as well as
things like automated theorem proving—make it clear that there are
places to go that won’t have this feature.
Will we call this “mathematics”? I think we should.
But it’s a different tradition from what we’ve mostly used for the past
millennium. It’s one where we can still build abstractions, and we can
still construct new levels of understanding.
But somewhere underneath there will be all sorts of
computational irreducibility that we’ll never really be able to bring
into the realm of human understanding. And that’s basically what’s
going on in the proof of my little axiom for logic. It’s an early
example of what I think will be the dominant experience in
mathematics—and a lot else—in the future.