I’ve put a very clever horse on the internet. He’s called Hans and I’ve made a little video about him.

You can ask Clever Hans your own questions! Go to christianp.github.io/clever-hans and make sure your microphone is turned on. Another proviso: I think only Google Chrome supports the special technology I used to make Hans work. Sorry!

I’ll explain how Hans does his horsey magic below the fold.

The real Clever Hans has always fascinated me. He was a horse owned by a German maths teacher, who discovered that Hans could count, do calculations with fractions and dates, and perform all sorts of other clever tricks. A New York Times article from the time titled “Berlin’s Wonderful Horse” is rather breathless in its praise of Clever Hans.

A while ago, I had the idea of making a new Clever Hans, not by training a real horse (too expensive; have to muck out too regularly) but by making a robot (very cheap; fewer ethical quandaries) that can listen for questions and answer them using a computery brain.

My long term plan is to stick a Raspberry Pi and a motor or two inside a model horse, but for now I’ve encased a pixelated horse in the web page I linked to above. Here’s how it works:

I use the experimental Web Speech API, which currently only works in Google Chrome, to do speech recognition. I pass the transcript of the speech recognition to a grammar written using PEG.js, which at the moment looks like this:

Expression = ("clever hans "/"") question:question { return question } question = question:("what is"/"what's"/"can you tell me"/"") " "? terms:terms { return {question: "calculate", terms: terms} } terms = n:atom ops:(space op:op space {return op})* { return [n].concat(ops)} op = "all "? "squared" { return {op:"squared"} } / op:binaryop " "? n:atom { return {op:op, n:n} } atom = n:number space op:("squared"/"cubed"/"factorial") { return {op:op,n:n} } / ("the square root of"/"root"/"route"/"√") " "? n:number {return {op:"sqrt", n:n } } / op:(gcd/lcm) space a:terms space "and" space b:terms { return {op:op, a:a, b:b} } / number binaryop = add / multiply / subtract / divide / power add = ("+"/"add"/"plus") {return "+"} multiply = ("×"/"x"/"times"/"multiplied by") {return "*"} subtract = ("-"/"minus"/"take away"/"takeaway"/"take-away") {return "-"} divide = ("÷"/"divided by"/"over") {return "/"} power = ("^"/"to the"/"to the power of") {return "^"} gcd = ("the greatest common factor of"/"the greatest common divisor of"/"the gcd of"/"the gcf of"/"the biggest number that divides") { return "gcd" } lcm = ("the least common multiple of"/"the lcm of"/"the smallest multiple of both") { return "lcm" } space = " "* number = digits:([0-9]+) { return {number: parseInt(digits.join(''))} } / "one" {return {number: 1}} / ("two"/"to"/"too") {return {number: 2}} / "three" {return {number: 3}} / ("four"/"for") {return {number: 4}} / "five" {return {number: 5}} / "six" {return {number: 6}} / "seven" {return {number: 7}} / ("eight"/"ate") {return {number: 8}} / "nine" {return {number: 9}} / "zero" {return {number: 0}}

After I run the transcript through that, I get a data structure which I can evaluate to a number, and then make Hans count it out by playing some sounds and animations.

Note that the grammar for arithmetic operations doesn’t follow the normal order of operations – it just works left-to-right (or earliest to latest, since this is speech), accumulating a single value. Spoken maths is a very interesting topic – Katie and I had a very interesting conversation with Edmund Harriss about it in the first episode of our All Squared podcast.

It’s difficult to specify exactly what you want an operation to apply to, in speech. For example, “five plus two squared” could either mean $5 + 2^2$ or $(5+2)^2$. you can do stuff like saying “all squared” to mean the second option, but even that isn’t enough, and it turns out we use rhythm and pauses to define grouping, which I don’t think I can pick up using the Web Speech API.

A few years ago, I met some people at Kingston University who were looking into a “speech user interface for mathematics”, called TalkMaths. They were trying out all sorts of complicated grammars and parsing schemes, which I’m not willing to do for a weekend project!

Anyway, I reckon the amount my Clever Hans can understand is pretty darn good for a horse.

At the moment, Hans can only perform arithmetic calculations in the integers. In the future, I’d like to replicate the other tricks the original Hans could do – calendar calculations and so on – as well as get him to answer questions like “what comes next in the sequence 1,2,3,5,8,…” by querying the OEIS.

*PS: Years and years ago, when I wanted to be a computer game developer, I found this horse sprite and used it to make this. It was the pinnacle of my game-making career, and I decided I couldn’t do any better so I should become a mathematician instead. I’m glad I finally found a way of making the horsey even nicer.*