A simple question
Imagine you have a dictionary. A real one. 370,000 words, sorted from A to Z.
Someone asks you to find the word "love."
Most people would flip to somewhere in the middle, check the letter, and narrow it down from there. A programmer would write a binary search - a well-known trick that halves the remaining pages every step. Either way, you are searching.
One person asked something different.
Can I just calculate where the word is?
Not search for it. Not flip pages. Just - receive the word, do some math, and the math tells you the page number. Like a formula.
That question, which sounds almost too simple to be interesting, turns out to be one of the deepest questions in computer science.
Step 1: Letters are just numbers in disguise
The first idea was this. Letters already have an order. A comes before B, B before C, and so on. So give each letter a number.
a = 1,
b = 2,
c = 3,
...
z = 26
Now a word is just a sequence of numbers. "cat" is 3, 1, 20.
And just like how 3.14 means "3 ones, 1 tenth, 4 hundredths", a word means something similar - except instead of tens, we divide by 26 each time.
"cat" = 3/26 + 1/676 + 20/17576
"cat" ≈ 0.118
So "cat" lives at roughly 11.8% through the dictionary. Multiply by 370,000 words and you get an approximate page number.
It is not perfect. But it is a formula. A formula that takes a word and spits out a number. That is exactly what was asked for.
def word_to_index(word, dict_size=170_000):
score = 0
for i, ch in enumerate(word.lower(), start=1):
val = ord(ch) - ord('a') + 1
score += val / (26 ** i)
return round(score * dict_size)
word_to_index("cat") # → ~19,900
word_to_index("zebra") # → ~164,000
Most people who hear "it is not perfect" give up and look for a perfect method instead. This person accepted the approximation and kept going. That is a more mature response than it sounds.
Step 2: Gates that open and close
The next idea was sharper.
Scan the whole dictionary once. Write down where each letter's words start and end.
A words: position 0 to 18,000
B words: position 18,001 to 36,000
...
L words: position 165,448 to 175,449
...
Z words: position 368,718 to 370,104
Now here is the key part. Suppose someone asks for the word "love". You know it starts with L. So it must live between position 165,448 and 175,449. Any position outside that range is impossible. Dead. Blocked.
Now zoom in. Inside the L section, find where each two-letter combination lives.
LA words: 165,448 to 166,100
LB words: 166,101 to 166,900
...
LO words: 172,548 to 174,196
...
"love" starts with LO. So it must be between 172,548 and 174,196. Everything else is dead.
Keep going. LO → LOV → LOVE. Each step, the range gets smaller. Each step, impossible positions get eliminated. Until you arrive at exactly one position.
ranges = {
'l': (165448, 175449),
'lo': (172548, 174196),
'lov': (173992, 174066),
'love': (174000, 174000), # exact
}
def find(word):
prefix = ""
for ch in word:
prefix += ch
lo, hi = ranges[prefix]
if lo > hi:
return None # impossible - word does not exist
return lo # found
This is called a gate. Each letter either opens the gate (your index is in range - keep going) or closes it (impossible - stop). The word activates a chain of gates, one per letter, until it arrives at its exact location.
When this was built and tested against 370,000 words, the result was clean:
| Word | Length | Steps |
|---|---|---|
| cat | 3 | 4 |
| xylophone | 9 | 10 |
| antidisestablishmentarianism | 28 | 29 |
Steps = word length + 1. Always. Whether the word is 3 letters or 28. Whether it is near the start of the dictionary or the end. The position in the dictionary made zero difference. Only the length of the word mattered.
This is what computer scientists call O(n) - the time it takes grows only with the length of the word, nothing else.
What those gates actually are
Here is something remarkable.
Those gates - fire if inside the range, dead if outside - have a name in machine learning. They are called activation functions. They are the core building block of every neural network ever built. The idea of a unit that "fires" based on whether its input crosses a threshold is the same idea that runs inside ChatGPT, Gemini, and every other AI system today.
The hierarchical structure of gates - letter one narrows the range, letter two narrows it further, all the way down to the exact word - has a name in computer science. It is called a Trie (pronounced "try"). It was invented in 1959.
The idea of branching based on a condition to narrow down possibilities has another name. It is called a Decision Tree. It is the foundation of some of the most widely used machine learning algorithms today.
All three of these were described in one paragraph, without knowing the name of any of them.
Step 3: Can the computer learn the gates by itself?
This is where it became a machine learning idea.
The gates above were built by scanning the dictionary and writing down ranges manually. But what if the computer could learn those ranges on its own - and then compress the entire thing into a small formula that any other program could use?
The idea: feed the computer every word and its position. All 370,000 pairs. Let it find a mathematical formula that fits them all.
# turn every word into a list of numbers
def encode(word):
vec = [0] * 20
for i, ch in enumerate(word[:20]):
vec[i] = ord(ch) - ord('a') + 1
return vec
# "cat" → [3, 1, 20, 0, 0, 0, ...]
# "love" → [12, 15, 22, 5, 0, 0, ...]
# train: find the formula that maps every word to its position
model.fit(X, Y)
# save just the formula - a tiny file
json.dump({"coefficients": model.coef_.tolist()}, open("function.json", "w"))
Then any other program - a database, a search engine, anything - loads that tiny file and calls one line:
f = LearnedIndex("function.json")
f("love") # → 188596 (true answer: 174,000)
f("python") # → 256243 (true answer: 256,223)
f("zebra") # → 370105 (true answer: 368,970)
No word list. No gates. No searching. Just arithmetic. One calculation and you have the answer.
This is called O(1) - it takes the same amount of time regardless of how many words are in the dictionary. One word or a billion words - same speed.
For the curious: what is the learning algorithm?
The algorithm used here is called Ridge Regression. Here is how it works in plain English.
The formula looks like this:
index = (w1 × first_letter) + (w2 × second_letter) + (w3 × third_letter) + ...
The w values are called weights. The algorithm's only job is to find the best weights so the formula is as close as possible to correct for all 370,000 words at once.
It does this in three steps, repeated many times:
- Guess some weights
- Measure how wrong the formula is across every word
- Nudge the weights in the direction that makes it less wrong
The "Ridge" part adds one extra rule: weights are not allowed to grow too large. This prevents the formula from obsessing over a few words and doing badly on everything else. It keeps the formula honest.
The reason the error is still around 10,000 indexes is that this formula only draws straight lines through the data. Words do not follow a perfectly straight pattern, so there is always some leftover wrongness. A neural network adds more layers, which lets it draw curved lines, which fits closer. More layers, less error. When the error reaches zero, the formula is exact - and that is a perfect learned index.
Step 4: No surprises
Then came the final insight, stated in one sentence:
"There cannot be surprises if the function has the dictionary as its constraint."
This is the key. A normal formula has to work for any input - even words it has never seen. So it has to stay general. It cannot be perfectly tuned to one specific dictionary.
But this formula only needs to work for the words in the dictionary. Every word is a known training example. Every position is a known answer. So the formula can be fit perfectly to this exact dictionary and nothing else.
When the dictionary changes, you run the program again. New dictionary, new formula. The formula is always exactly right for the dictionary it was built from.
Computer scientists have a name for this too. It is called a perfect hash function - a formula that maps every known key to a unique position with no mistakes. But what was built here is something more interesting than a classic perfect hash. A classic perfect hash treats words as meaningless blobs and shuffles them into slots with clever math tricks. It does not understand the words.
This formula actually reads the word. It knows that L-words live near the middle of the dictionary and Z-words live near the end. It exploits the structure of the alphabet. A classic hash function ignores that structure entirely.
That distinction is exactly the argument Google made in a research paper in 2018, titled The Case for Learned Index Structures. Their argument: a model that understands the data will always beat a model that treats the data as meaningless. That paper was written by a team of PhDs and has been cited over a thousand times.
The same argument arrived here through curiosity alone.
What was actually built
Here is the full picture, without any jargon:
The tree (built once, offline):
Scan the dictionary. For every possible starting combination of letters - L, LO, LOV, LOVE - write down the range of positions those words occupy. Store all of this in a tree, like a family tree where each branch narrows the search.
Dictionary
├── A (positions 0 – 18,000)
│ ├── AA (positions 0 – 120)
│ ├── AB (positions 121 – 890)
│ └── ...
├── L (positions 165,448 – 175,449)
│ ├── LA (positions 165,448 – 166,100)
│ ├── LO (positions 172,548 – 174,196)
│ │ ├── LOV (positions 173,992 – 174,066)
│ │ │ └── LOVE (position 174,000) ← leaf
│ │ └── ...
│ └── ...
└── Z (positions 368,718 – 370,104)
The leaves of this tree - the tips of the branches - are exact positions. One leaf per word.
The formula (used forever after):
Take all those leaf positions. Feed them to a learning algorithm. The algorithm finds a formula that fits every single one. Save the formula as a small file.
Now any program can load that file and answer "where is this word?" with a single calculation. No dictionary needed. No tree traversal. Just math.
When the dictionary changes:
Run the program again. New tree, new formula, new file. The whole process takes a few minutes on a laptop. During that time the old formula still works. When the new one is ready, swap it in. Zero downtime.
The family tree of ideas
Every idea in this conversation already had a name. None of those names were known at the time.
| What was said | What it is called | When it was invented |
|---|---|---|
| Given a table of x and y, find f(x) = y | Machine learning (the entire field) | 1940s–present |
| Give each letter a number | Encoding / Embedding | 1950s |
| Treat a word like a decimal number | Base-n representation | Ancient |
| Write down ranges for each letter group | Trie (prefix tree) | 1959 |
| A gate that fires or stays dead | Activation function | 1958 |
| Narrowing by branching | Decision tree | 1986 |
| Let the computer find the formula | Machine learning / Regression | 1940s–present |
| Train on all known words as constraints | Perfect hash function | 1966 |
| Formula that understands data structure | Learned index structure | Google, 2018 |
Each row is years or decades of work by researchers, professors, and engineers. All of it was reconstructed in a single conversation, by following one question to its natural conclusion.
A childhood question that started it all
Before any of this conversation happened, there was an older question. One that arrived during a school mathematics lesson, somewhere in a chapter on Functions and Polynomials.
The teacher was explaining how a function takes an input and gives an output. How to find the inverse. How to identify the domain and range.
And a child sitting in that class thought something the teacher did not say:
For any large table of x and y values - can I find the actual function f where f(x) = y for every single row?
Not for two points. Not for three. For the entire table. No matter how big.
That question was not on the exam. There was no marks for it. It was just a thought that sat there quietly for years.
Neural networks are the answer to that question.
That is not a simplification. That is literally what they do. You give them a table - x on one side, y on the other - and they find the function f that connects every row. The table is called training data. The process of finding f is called training. The result is called a model.
And the same question works for any kind of x and y:
| x | y |
|---|---|
| A word | Its position in the dictionary |
| A photo | What is in it |
| A sentence in English | The same sentence in French |
| A voice recording | The words spoken |
| A patient's symptoms | The likely diagnosis |
Every single one of these is just a table. Every single one is solved by finding f. The inputs and outputs get more complex but the question stays exactly the same as the one asked in that childhood mathematics class.
The reason it took humanity until the 1980s to solve this well - despite the question being simple enough for a child to ask - is that three things needed to work together at the same time:
First, a function flexible enough to take any shape - that is the neural network with its layers and gates.
Second, a way to measure how wrong the current f is across the whole table - that is called the loss function.
Third, a way to automatically nudge f toward being less wrong - that is called backpropagation.
Without all three, you are stuck. The question was easy. The machinery to answer it took decades to build.
The entire field of machine learning is, at its core, that childhood question taken seriously.
Why any of this matters
There is a common way to learn computer science. You are taught the tools. Binary search. Hash tables. Tries. Decision trees. Neural networks. You learn what each tool is called, when to use it, how to implement it.
That is useful. But it is not the same as understanding why the tool exists.
The person in this conversation never learned the tools. They started from a question - can I calculate the position instead of searching for it? - and followed the logic forward. Each answer raised a new question. Each new question led somewhere real.
That is how the tools were invented in the first place.
Binary search is not interesting because it is a clever trick. It is interesting because someone once asked do I really need to check every page? The Trie is not interesting because it is a data structure. It is interesting because someone once asked what if each letter narrowed the search?
The questions came before the tools. The tools are just the questions, written in code.
This conversation was someone asking the questions again, from scratch, without knowing the answers already existed. And arriving at the same places.
That is rarer than it sounds.
The code in this essay is available at learned_index.zip. Every number is from an actual program running against 370,105 English words.
Median Formula for Continuous Grouped Data
Miscellaneous Real-World C