Artificial Intelligence (A.I.) is implemented using a collection of statistical, probabilistic and heuristic machine learning algorithms. They can be shallow, that is, they have one or a few hidden layers, or they are deep, that is, they have as many hidden layers as you can practically compute on the resources you have. Often, you need suitable performance to get a reasonable runtime so languages such as C, C++, Fortran do the tight loops and GPGPU libraries such as CUDA, MKL and OpenCL assist with parallelizing your code. Just as frequently, you need the right level of abstraction so that you are less focused on pointers, shuffling between registers and compilers and more focused on which approach fits your problem, regression, Random Forest, SVM … for that, Python, Java and JVM languages stand at the front of the pack; they use high-level abstractions such as objects and classes, have REPLs for interactive prototyping, are fast enough and can call ultra-fast routines in other languages when the need arises.
I struggle to name a single complex A.I. that doesn’t use more than one programming language. AlphaGo is likely to have been written using Torch, a framework that itself comprises of C, Lua and uses CUDA for GPU processing. IBM’s Watson was mostly written in Java with chunks of the codebase written in C++ and Prolog .
Logic programming languages are a niche programming paradigm you’ve probably not heard of. They provide a very high level of abstraction and concern themselves with providing a programmatic way to express formal logic. They excel at non-numerical analysis, they make interesting and outstanding lexical parsers and they are the kings of expert systems; solving a very specific problem where the solution is dependent on a large number of rules and facts. This was why early attempts at computational AI in the 1960s and early 1970s, undertaken at Stanford and the University of Edinburgh, turned to using logic languages as the means to express pure logic in computable syntax.
Logic languages, however, have fallen by the way side – else you’d probably have heard of them. Some attribute their decline as collateral damage from the Fifth Generation Computer Systems (FGCS) boondoggle, a massive $400 million Japanese project stretching from 1982 to 1992 to stimulate research and development into a new supercomputer that was to be the platform for Artificial Intelligence. When that project collapsed, Prolog was considered part of the wreckage. Others argue that, it lost is way trying simply to be a declarative language for searching and querying data, a battle that it lost to SQL, but perhaps lives on in Datalog. There are also basic reasons why the champion of logic languages, Prolog, failed; it introduced the imperative ‘cut’ function that wrecked the declarative nature of the program. At the same time, Prolog’s procedural semantics mandate backtracking, which can cause problems when it affects things like I/O.
Computing power is now cheaper and the burden is now more firmly shifted on how do we make developers most productive. Expressing complex ideas in their simplest form so that we can use that as a platform to build evermore complex things.
It’s time to revisit logic languages.
Why would I want to use a logic language?
That’s blunt, but to the point. Programming languages are just tools and if the tool doesn’t have utility then there is no point. The key utility of logic languages is that they express a problem as a series of facts and rules; not as a series of function, nor procedures, but quite literally as logical statements. The facts set what is true and rules that govern how these facts interact. It leads to a simple, deductive process. For instance, consider these facts:
- Nemo can swim
- Pingu can swim
- Nemo has gills.
Then consider some rules,
- If X can swim and X has gills then X is a fish.
- If X can swim, but does not have gills then X is a penguin.
From this, we can deduce that Nemo is a fish and Pingu is a penguin. Further, if we propose a new fact, “Dorey can swim and has gills”, then our system will deduce that another new fact, Dorey, is a fish. This is referred to as forward-chaining, inferring a fact from a system of facts and rules.
You may be asking, why do this in a logic language? I can compute this in any programming language! All you need is some variables or objects to represent the “facts” and some if statements to build rules. However, perhaps you will consider that just because you can, doesn’t mean you should.
Here is how a logic language would represent the above:
swims(X), has_gills(X) => fish(X);
swims(X), not has_gills(X) => penguin(X);
The syntax is terse, the meaning is nice and clear, if perhaps a little unfamiliar. Those parentheses? They’re not function calls, but rather a fact “swims” and it’s predicate i.e. “Nemo”. The => represents an implication. Fact retrieval and logic in two lines of code is not possible in most languages. Further, logic languages are declarative similar to SQL yet instead of selecting data you make logic inferences. Lastly, rules expressed as logical implications are provable; consider a traffic light system, signals for cars and pedestrians can never change to green at the same time if these rules are used:
button(T-1) => walk(T);
walk(T) => pedestrians(green,T), cars(red,T);
not walk(T), cars( ,T-1) => pedestrians(red,T), cars(green,T);
Proof by contradiction. Assume that cars(green,T) and pedestrians(green,T) are both true for some T. Stable model semantics require that both facts are either initial facts or consequences of true antecedent conditions in the rules. Disregarding the initial facts possibility, this means that walk(T), not walk(T), and cars( ,T-1) are also true for this T. But having both walk(T) and not walk(T) true is a contradiction, so our original assumption must be false. End of proof.
Rules that are provable are especially welcome in mission-critical systems where the cost of failure is high.
Interested in logic languages? Come find us at rubble.tech
We’re bringing logic languages back and if it’s good enough for Watson then it’s good enough for you!
We’ve build Rubble; a modern logic language available immediately as a cloud service or available on-premise on request. Rubble has a raft of operational and scalable features to make it simple to adopt in your system. It’s pedigree is well matched as our founder and CTO had been writing Prolog compilers for some 10 years before he created Rubble. Rubble is the logic language for modern applications.