THORN (Theorem prover based on HORN clause logic) is a program designed for solving problems in first-order logic
with equality. Download THORN and test problems here. The standard library is required to
run THORN.
THORN Itself
THORN is derived from Stickel’s PTTP and uses logic programming technology to achieve high inferencing
rates. The latest version is version 18. THORNt extends the PTTP from first-order logic to embrace first-order
logic with equality. THORN is not equivalent in problem-solving capability to systems with a larger code base
like Vampire and Prover9. Stickel’s observations apply to THORN.
Caveat: PTTP's high inference rate is achieved at the cost of not allowing more flexible search strategies or
elimination of redundancy in the search space by subsumption. Although PTTP is one of the fastest theorem provers
available when evaluated by its inference rate and performance on easy problems and it has been used to solve
reasoning problems in planning and natural-language-understanding systems effectively, its high inference rate
can be overwhelmed by its exponential search space and it is unsuitable for many difficult theorems.
Nevertheless THORN has solved some humanly unprovable theorems in equivalential calculus as well as Schubert's
Steamroller in 1 second under Shen/Scheme. The latter problem was unsolved by any ATP until 1984. It is also a small
program of around 530 lines of Shen, unlike Vampire (195,000 lines of OCAML and C++) and Prover9 (75,000 lines of C).
Unlike the PTTP, THORN uses a style of proof closer to natural deduction and the proofs are rather easier to read
than those from Vampire or Prover9.
THORN consists of two elements; a precursor program that is sound, complete and terminating for propositional calculus
and the main program which is based on logic programming technology. The precursor program can solve problems
independently of the logic programming component. If it fails to solve a problem, the decomposed problem is
handed to the logic programming component. A short paper on THORN is available on
Academia.
Trying It Out
The system is remarkably simple to use. Simply download,
enter Shen, type (load "THORN 19.shen") w.o. type checking enabled and
(load "datatypes.shen") and switch on the type checker. Go to the folder
Problems and load any of the files there. There's lots of examples of
THORN propositions in that folder. BTW prop is a type in THORN. For any
successful run there is a file prf.txt in your home directory containing a proof.
Important Functions
The two important functions are kb-> (insert into the knowledge base) and <-kb (ask of the knowledge base).
The first takes a list of propositions (objects of the type prop) and compiles them into efficient code returning
compiled. The type of kb-> is (list prop) --> symbol.
<-kb receives a prop and tries to prove it returning either true (proved) or false (unproved) and placing a proof
in the file prf.txt in the home directory. The type of <-kb is prop --> boolean.
Loading the file loadme.shen in the THORN directory will load both THORN and the datatype definition of prop.
The Type prop
The sample files in the Problems directory contain numerous examples of propositions (props).
Here are the rules formally.
1. The logical constants are all, exists, =>, ~, <=>, &, v, =.
2. Any symbol which is not a logical constant is an (atomic) prop.
3. If P and Q are props, so is [~ P], [P => Q], [P v Q], [P <=> Q], [P & Q].
4. Any string, number, boolean, or symbol that is not a logical constant is a term.
5. A function symbol is any lowercase symbol that is not a logical constant.
6. A predicate is any lowercase symbol that is not a logical constant.
7. If f is a function symbol and t1 ...tn are terms then [f t1 ...tn] is a term.
8. If F is a predicate symbol and t1 ... tn are terms then [F t1 ...tn] is an (atomic) prop.
9. If t1 and t2 are terms [t1 = t2] is a prop.
10. If t1 and t2 are terms then [t1 : t2] is a prop.
10. If X is a lowercase symbol that is not a logical constant and P is a prop then [all X P] is a prop
and so is [exists X P].
11. If X is a lowercase symbol that is not a logical constant and t is a term and P is a prop
then [all X : t P] is a prop and so is [exists X : t P].
The expression [t1 : t2] is read as 't1 is of type t2' and [all X : T P] is a
sugared form of [all X [[X : T] => P]]. Remember to use lowercase symbols for functions
and predicates.
Prolog Notation
THORN accepts Prolog notation treating capitalised terms as universally quantified
variables; [all x [f x]] and [f X] are equivalent.
Procedural Attachment
Procedural attachment is a feature in theorem-provers going way back. For example, given as the goal 3 < 10, it is obvious
that the native arithmetic engine needs to be called to prove this, not the inference engine itself. Procedural attachment is also
a feature of Prolog.
After THORN 20, the higher-order call predicate in Shen Prolog can be invoked. For example in my Tarski-flavoured semantics
I had an axiom.
[all x [all y [all z [[[name x] & [[copEng y] & [adjEng z]]]
<=> [[istrueEng [cn x [cn y z]]] <=> [sat [den x] z]]]]]]
and
[adjEng "bald"]
But if I were to expand this system to incorporate thousands of English adjectives, I 'd have thousands of atomic statements in
my axiom base. It would probably not compile; imagine a function def of adjEng with > 1 million loc!!
The solution is procedural attachment; I replace the axioms for adjectives by
[all x [[call [adjEng? x]] => [adjEng x]]]
and add
(defprolog adjEng?
X <-- (when (element? X (value *EngAdj*)));)
(set *EngAdj* ["bald" ....])
call, as you might know, figures in Shen Prolog. It calls a Prolog goal.
(prolog? (call (is X a)))
true
In THORN it is embedded in a way to preserve the syntax of the type prop.
The called procedure has access to resources from THORN; they are kept in the variables Prf, Max, Depth, Hyp.
The most useful is the variable Hyp, which codes the hypotheses available at that stage of the proof. We can
do stuff like this.
(define mytypechecking
-> [[all x [all type [[call [typecheck! x type (protect Hyp)]]
=> [x : type]]]]])
(defprolog typecheck!
X Type Hyp <-- (shen.system-S-h X Type Hyp);)
(kb-> (mytypechecking))
compiled
(<-kb [4 : number])
run time: 0.015625 secs
44 inferences, equality = false
depth = 20, complexity = -1, timeout = 60 secs
true
So you can link the type system into THORN. And that means, should you want to explore some exotic verification system
or type theory, run under first-order logic and call on the Shen type system, you can do it.
One last caveat, call expects to know the arity of what it is calling. This is the higher-order magic behind the totally
laconic definition of call in the kernel (the magic for this is in the kernel).
(define call
Call Bindings Lock Key Continuation
-> (Call Bindings Lock Key Continuation))
So I use typecheck! to meet that need..
Some Proofs
There are some stored proofs returned by THORN
here.
Settings
Like the PTTP, THORN uses incrementally bounded depth first search up to a given maximum to seek solutions. The
maximum is set by the user. (thorn.depth n) will set the depth which is by default 20. There is also a timeout
which by default is 60 seconds. (thorn.timeout n) will set this to any desired number. There a figure for
controlling the complexity of the terms generated which means that any goal (an atomic prop which THORN is attempting to prove)
whose terms collectively exceed this complexity will be axed from the search. (thorn.complex n) sets this. By default
it is set to -1, which means there is no bound to complexity.
THORN handles equality as two-way rewriting (see Academia again on this. By default it is disabled and is enabled under the following conditions.
1. The user enters (thorn.equality true).
2. The user enters a prop to kb-> containing the equality sign.
3. The user enter a prop to <-kb containing an equality sign.
(thorn.defaults) will reset all these settings to the default values. (thorn.wipe-kb) will wipe the knowledge base.
Stuff in the Problems Folder
Simply loading any of the files in the Problems directory will run the problems in that file.
File | Contents |
ec.shen | Equivalential calculus axioms. These problems are impossible for humans. |
group.shen | Group theory which requires equality. The same problem is submitted with unbounded and
differing levels of complexity. |
L.shen | A first-order formalisation of classical propositional calculus incorporating modus ponens and
three axiom schemas taken from Eliot Mendelson. The axiomatisation is in Prolog notation. |
pelletier.shen | A selection of propositional problems from Pelletier. |
schubert.shen | Schubert’s steamroller. |
set.shen | Basic set theory |
meaning.shen | Tarsi-style truth semantics of natural language |
Some of the problems are commented out as too hard.
Issues
Beware that the predicates you use will be compiled into functions of the same name overwriting any defs
of them which pre-exist. kb-> overwrites
earlier axiom sets in that any any prop which uses a predicate F will overwrite the information about F in
an earlier invocation of kb->. The timeout option seems a little liberal in its interpretation of time, giving
the program more time to execute than allowed for.
Using the same predicate with a different arity in different contexts will cause problems. In case there
is doubt whether a previous use of kb-> has done this (thorn.wipe-kb) will initialise the knowledge base.
THORN is not good at doing stand alone problems which do not require precompiled axioms. For instance,
entering (<-kb p) where p is a first-order theorem, may not issue in a proof in all cases.
If p is propositional, it will be proved. However if not, it may not be. The reason for this is that the
precursor program is a weak but terminating ATP that acts as a preprocessor for handing the problem to the
main program which works with compiled information. If this compiled information is absent, and the problem
is not solvable within propositional calculus, then the precursor
program will act alone and may fail to provide a proof.
As of June 2025, there is an odd bug about trying to perform an arithmetic operation on an unbound Prolog
variable which is hard to track down. It has occurred twice on different problems.
|