ukb
v1.2.1
Published
Equational reasoning based on the unfailing Knuth-Bendix completion procedure
Downloads
6
Maintainers
Readme
UKB
Search for proofs of equational theorems, or compute a set of convergent rules using the Unfailing Knuth-Bendix completion procedure.
Quick Run
The proof search can be run from the command line. Run
$ node run
for usage information.
Axioms and goals (i.e., theorems to be proved) are specified in a file.
Samples of such files can be found in directory samples
. Consult
in particular samples/group_prove.eqs
for details on the notation
used in such a file.
Axioms and goals can also be extracted from a TPTP problem file such as GRP136-1.p, for instance.
Note that package tptp facilitates downloading such TPTP problems.
Only pure equational problems in CNF can be processed. Supply options for such files in JSON format.
See samples/options.json
as an example.
Usage
const ukb = require('ukb');
ukb
exposes the functions createProver and createTptpProver:
createProver (axioms, options)
The function returns an object representing a prover. It has one mandatory parameter axioms
, the axioms given as an array of strings, or a string in case of a single axiom. Each axiom (string) is an equation, e.g. f(i(x),x) = a
. Note that a symbol starting with the letter
x, y, z, u, v, or w, optionally followed by one or more digits, is assumed to be a variable. Variables are
implicitly universally quantified. All other symbol names denote functions or constants.
For standard group axiomatization use, for instance,
['f(x,a) = x', 'f(x,i(x)) = a', 'f(f(x,y),z) = f(x,f(y,z))']
as a possible value of parameter axioms
.
The optional parameter options
should, if supplied, be an object with one or more of the following properties:
preorder
: see options of prover methodrun
described below; the value of this option will be used unless overwritten when starting or restarting a prover run.logger
: see options of prover methodrun
described below; the value of this option will be used unless overwritten when starting or resuming a prover run.logLevel
: see options of prover methodrun
described below; the value of this option will be used unless overwritten when starting or resuming a prover run.goals
: see options of prover methodrun
described below; the goals provided here will always be included in the set of goals to be proved.
The prover object returned has the following functions:
run(options)
: Starts or resumes a proof search or an attempt to produce a convergent set of rules (completion); the return value is the status at the time the run is terminated. It is the same value that is also returned bygetStatus
(see below). A run can be terminated before all proofs are found or completion succeeded using options described below. A run can be resumed by calling this function any number of times. The parameteroptions
is optional. If it is supplied it must be an object with properties described below. Note that propertiesordering
,preorder
,weighting
,indexingMatch
, andproofsEnabled
are taken into account only if a run starts from scratch (i.e., does not resume from where a previous run left off).ordering
: The ordering to be used. Currently there is only one ordering (Lexicographic Path Ordering or LPO) which makes using this option obsolete. As a matter of fact this option is currently ignored.preorder
: Defines the preorder employed by the chosen ordering (which can only be the LPO at this stage). The preorder is given as an array of symbol names where one symbol is greater than another if its array index is smaller (i.e., it occurs before the other in the array). The preorder may be partial or may be omitted altogether. If a symbol is encountered that is not in the preorder it is appended to the preorder as the (at that moment) smallest symbol.weighting
: A specification of the heuristic weighting function for selecting the next critical pair to become a rule or an equation; if omitted standard weighted symbol count is employed where variables count as 1 and all other symbols as 2. Otherwise the weighting function is specified through an object that must have propertyname
. Currently there is only one weighting function, namely weighted symbol count. Hence the value of propertyname
can only be"weightedSymbolCount"
or"WSC"
for short. Use additional propertiesfctWeights
andvarWeight
to specify the weights of functions and variables, respectively. (If omitted, the default weights will be used, which are 2 for function symbols and 1 for variables as mentioned above.) The value offctWeights
can either be a number or an object. If it is a number, then that weight applies to all (non-variable) symbols. If it is an object then symbol names are properties and weights (i.e., numbers) their values.indexingMatch
: A Boolean value that indicates whether an indexing technique should be employed for matching attempts (i.e., reductions); the default isfalse
. Setting the value totrue
in most cases leads to significant performance improvements. Deterioration can only be expected for problems requiring very little time to solve (i.e., when the overhead outweighs the gains). Note, however, that switching on indexing may change the search behavior on account of a different order in which rules or equations are used for reductions.logger
: A function accepting one (string) parameter (e.g.,console.log
); the function will be called with information that can be logged. The level of detail of that information depends on optionlogLevel
.logLevel
: An integer ranging from 0 to 6 that denotes the detail level of logging; higher values produce more logging information. The default is 0 which produces no logging information at all.goals
: The goals to be proved, given as a string (if there is but one goal) or an array of strings. Note that goals are added to the list of goals every timerun
is called. That is, previously given goals are not discarded. If you want a clean start, usererun
(see below). A goal can be negated, properly Skolemized, and presented as an inequality. For instance, commutativityf(x,y) = f(y,x)
(for allx
andy
) of a function symbolf
is given asf(c1,c2) != f(c2,c1)
, wherec1
andc2
are constants not occurring anywhere else. Alternatively the goal can be presented in a quantified, positive form, using!
and?
for universal and existential quantification, respectively. For instance, in group theory, the existence of a left-inverse element is given as!x?y: f(y,x) = a
, wherea
represents the neutral element. Commutativity is specified by!x,y: f(x,y) = f(y,x)
. In both cases the goals are properly Skolemized automatically.tptpMode
: a Boolean value that, if true, indicates that TPTP-style (or Prolog-style) variable names will be used; otherwise, which is the default, variable names follow the conventions outlined above.maxActivations
: The maximal number of activations after which the run terminates; each rule or equation generated as well as each goal activated counts as one activation. If omitted or not greater than 0 there will be no limit on the number of activations. Note that a run terminated this way can be resumed by callingrun(options)
again with the same or different options.reduceCpBeforeAdding
: A Boolean value that indicates whether or not a critical pair is reduced before adding it to the set of critical pairs; the default isfalse
. Note that a value oftrue
typically increases the total number of reductions, but reduces the number of critical pairs added. However, by reducing critical pairs beforehand their weight may change which may affect the search behavior one way or the other.cmpEqSidesForCpGen
: A Boolean value that indicates whether or not the two sides of an equation are to be compared before being used to create a critical pair. The default isfalse
. When set totrue
an (instance of an equation) will not be used if, as a result, a term would be replaced with a greater term (as per ordering). That way the generation of obsolete critical pairs is prevented. However, this leads to more comparison operations.timeout
: A timeout (in milliseconds) after which the run terminates; if omitted or not greater than 0 there will be no timeout. Note that a run terminated this way can be resumed by callingrun(options)
again with the same or different options.proofsEnabled
: A Boolean value that, if true, switches on proof recording. As a result, goals that can be proved offer the possibility to obtain a proof in standard mathematical (human-readable) form. SeegetGoals()
below for details. It should be noted that proof recording increases memory consumption and computation time, so it should not be switched on needlessly.
rerun(options)
: Discards all goals as well as all results from previous runs and restarts the prover; it is identical to callingrun
on a prover that was just created (i.e., has not yet run).getStatus()
: Returns the status of the proof procedure; if the prover has never been started throughrun
orrerun
the value returned isundefined
. Otherwise it can have one of the following string values:stopped
: A timeout occurred or the maximal number of activations was reached; resume the search by callingrun(options)
with the appropriate options.proved
: All goals were proved (but no convergent set of rules was computed)completed
: A convergent set of rules was computed; note that statuscompleted
implies that all goals were either proved or disproved.
getRules()
: Returns the current set of rules as an array of stringsgetEquations()
: Returns the current set of equations as an array of stringsgetGoals()
: Returns the current set of goals as an array of objects, where each such object has the following properties:goal
: The goal as a stringproved
: Boolean flag indicating whether the goal was proved (true
) or not (false
)proof
: The proof (if found) as an object that has two functionstoStringDetailed()
andtoString()
that present the proof in a detailed and simple form, respectively, as a string in both casesdsGoal
: The de-Skolemized goal as a string, generated by undoing Skolemization, which may not always be possible; if it is not possible then this property isnull
dsProof
: The proof (if found) of the de-Skolmized goal (if it was generated) as an object that has two functionstoStringDetailed()
andtoString()
that present the proof in a detailed and simple form, respectively, as a string in both cases
getPreorder()
: Returns the current preorder as an array of symbols in descending ordergetStatistics()
: Returns statistics for the current run (note that statistics are not reset when resuming a run usingrun(options)
); the value returned is an object with the following properties (all of which are non-negative integers):rulesAdded
: The number of rules addedequationsAdded
: The number of equations addedrulesDiscarded
: The number of rules removed from the set of rules and added to the set of critical pairs (on account of reducing the left side)equationsDiscarded
: The number of equations removed from the set of equations and added to the set of critical pairs (on account of reducing either side)reductions
: The total number of reductionscmpCount
: The total number of term comparisons (using the chosen term order)cpAdded
: The number of critical pairs added to the set of critical pairscpGenerated
: The number of critical pairs generated through overlapping; note that axioms also become critical pairs, but are not generated.obsoleteCp
: The number of critical pairs selected for processing, but discarded since one or both parents were not active rules or equations anymoretrivialCp
: The number of critical pairs selected for processing, but discarded since they could be reduced to a trivial equation (i.e., identity)fwdSubsumption
: The number of equations rejected since they were subsumed by an existing equationbwdSubsumption
: The number of equations discarded since they were subsumed by a newer equationgoalsActivated
: The number of goals activated (i.e., taking an active part in reductions and generation of further critical goals)critGoalsCreated
: The number of critical goals created (by overlapping rules or equations into activated goals)goalsFwdSubsumed
: The number of goals about to be activated, but rejected since they were subsumed by previously activated goalsgoalsBwdSubsumed
: The number of activated goals that were removed since they were subsumed by a new (active) goalobsoleteCritGoals
: The number of goals that were created, but not activated since one or both of the parents were not active goals anymore
getHrtimeElapsed()
: Returns the time elapsed since starting the most recent run inprocess.hrtime
formatgetTimeElapsed()
: Returns the time elapsed since starting the most recent run as a human-readable stringnormalize(t)
: Returns the term obtained by normalizingt
(i.e. computing the normal form oft
w.r.t. the completed set of axioms). Botht
and the term returned are strings. Note that an exception is thrown if the prover is not in statuscompleted
.testEquality(eq)
: Tests the given equalityeq
, i.e. an equations = t
(a string). The result istrue
if the normal forms ofs
andt
are identical,false
otherwise. Note that an exception is thrown if the prover is not in statuscompleted
. Note also that this simple test can only handle universally quantified variables. These variables have to be replaced with Skolem constants if there are equations after completing the set of axioms. Do not use this simple test in the presence of existentially quantified variables. Instead, run the prover and add the respective goal as described above. (See also the following examples.)
Examples
We assume that module or package ukb has been installed. A prover object for standard group axiomatization is created this way:
> const ukb = require('ukb');
undefined
> let prover = ukb.createProver(['f(x,0)=x', 'f(x,i(x))=0', 'f(f(x,y),z)=f(x,f(y,z))'], {preorder:['i','f','0']});
undefined
This prover can then be run to obtain a convergent set of rules:
> prover.run();
'completed'
> prover.getStatus();
'completed'
> prover.getRules();
[ 'f(x,0) --> x',
'f(x,i(x)) --> 0',
'f(f(x,y),z) --> f(x,f(y,z))',
'f(y,f(i(y),x)) --> x',
'f(0,x) --> x',
'i(0) --> 0',
'f(i(x),x) --> 0',
'i(i(x)) --> x',
'f(i(x),f(x,y)) --> y',
'i(f(y,x)) --> f(i(x),i(y))' ]
> prover.getEquations();
[]
You may re-use the convergent set of rules to prove one or more goals. In this example
we prove that there is an x
so that for all y
it is true that f(x,y) = y
.
After negation and Skolemization this goal is converted into the inequality
f(x,g(x)) != g(x)
:
> prover.run({goals:['f(x,g(x)) != g(x)']});
'completed'
> prover.getGoals();
[{
goal: 'f(x,g(x)) != g(x)',
proved: true,
proof: null,
dsGoal: '?v1!v2: f(v1,v2) = v2',
dsProof: null
}]
Note that the return value of the second run also is 'completed'
(which entails,
as explained above, that any goal can be either proved or disproved). Note also that there
are no proofs because proof recording was not switched on. There is, however, a de-Skolemized
version of the original goal.
If, on the other hand,
you rerun the prover with that goal, the return value is 'proved'
as the proof procedure
stops as soon as all goals (in this case just one) are proved, which happens before a convergent
set of rules was obtained. We switch on proof recording for this run so that we can have a look
at the proof found:
> prover.rerun({goals:['f(x,g(x)) != g(x)'], proofsEnabled:true});
'proved'
> prover.getStatus();
'proved'
> prover.getRules();
[ 'f(x,0) --> x',
'f(x,i(x)) --> 0',
'f(f(x,y),z) --> f(x,f(y,z))',
'f(x,i(0)) --> x',
'f(x,f(y,i(f(x,y)))) --> 0',
'f(y,f(i(y),x)) --> x',
'f(x,f(i(0),y)) --> f(x,y)',
'f(x,i(i(y))) --> f(x,y)',
'f(0,x) --> x' ]
> prover.getGoals();
[{
goal: 'f(x,g(x)) != g(x)',
proved: true,
proof: { ... },
dsGoal: '?v1!v2: f(v1,v2) = v2',
dsProof: { ... }
}]
The set of rules available at the time of proving the goal is not yet a convergent set of rules.
The set does, however, contain the rule that is essential for proving the goal, namely
the last (i.e., the most recently created) rule f(0,x) --> x
, which through overlapping
with the goal (unification of f(0,x)
and f(x,g(x))
)
produces the goal instance f(0,g(0)) != g(0)
. That goal instance leads to the so-called critical
goal g(0) != g(0)
which proves the goal by contradiction.
Since proof recording was switched on we can now have a look at the detailed proof of the de-Skolemized goal, for instance:
> console.log(prover.getGoals()[0].dsProof.toStringDetailed());
f(0,v2)
= f(0,f(v2,0)) : x = f(x,0) at position 2 with x <- v2
= f(0,f(v2,f(i(v2),i(i(v2))))) : 0 = f(x,i(x)) at position 2.2 with x <- i(v2)
= f(0,f(f(v2,i(v2)),i(i(v2)))) : f(x,f(y,z)) = f(f(x,y),z) at position 2 with x <- v2, y <- i(v2), z <- i(i(v2))
= f(0,f(0,i(i(v2)))) : f(x,i(x)) = 0 at position 2.1 with x <- v2
= f(f(0,0),i(i(v2))) : f(x,f(y,z)) = f(f(x,y),z) at position root with x <- 0, y <- 0, z <- i(i(v2))
= f(0,i(i(v2))) : f(x,0) = x at position 1 with x <- 0
= f(f(v2,i(v2)),i(i(v2))) : 0 = f(x,i(x)) at position 1 with x <- v2
= f(v2,f(i(v2),i(i(v2)))) : f(f(x,y),z) = f(x,f(y,z)) at position root with x <- v2, y <- i(v2), z <- i(i(v2))
= f(v2,0) : f(x,i(x)) = 0 at position 2 with x <- i(v2)
= v2 : f(x,0) = x at position root with x <- v2
undefined
The explanation or justification following the colon details the step taken to transform the term of the previous line into the term before the colon. Note that all justifications use only (instances of) axioms.
When adding a goal that cannot be proved, e.g. commutativity of f
, then a (re-)run
will only stop as soon as a convergent set of rules has been obtained, and therefore the return
value as well as the status of the proof run is 'completed'
:
> prover.run({goals:['f(a,b)!=f(b,a)']});
'completed'
> prover.getGoals();
[{
goal: 'f(x,g(x)) != g(x)',
proved: true,
proof: { ... },
dsGoal: '?v1!v2: f(v1,v2) = v2',
dsProof: { ... }
}, {
goal: 'f(a,b) != f(b,a)',
proved: false,
proof: null,
dsGoal: '!v1,v2: f(v2,v1) = f(v1,v2)',
dsProof: null
}]
> prover.getStatus();
'completed'
This example also demonstrates that calling run
does not discard previously
given goals, and that proof recording remains active because it was switched on through
rerun
and cannot be changed when resuming the procedure through run
.
The same result without proof recording can be achieved as follows:
> prover.rerun({goals:['f(x,g(x)) != g(x)', 'f(a,b)!=f(b,a)']});
'completed'
> prover.getGoals();
[{
goal: 'f(x,g(x)) != g(x)',
proved: true,
proof: null,
dsGoal: '?v1!v2: f(v1,v2) = v2',
dsProof: null
}, {
goal: 'f(a,b) != f(b,a)',
proved: false,
proof: null,
dsGoal: '!v1,v2: f(v2,v1) = f(v1,v2)',
dsProof: null
}]
> prover.getStatus();
'completed'
createTptpProver (tptpProblem, options)
The function returns an object representing a prover that extracts axioms and possibly goals from a TPTP problem.
Parameter tptpProblem
must be the contents of a TPTP problem (i.e., a string) with all include statements resolved.
Note that package tptp facilitates downloading such TPTP problems.
Only pure equational problems in CNF can be processed. Axioms and goal(s) are extracted from the TPTP problem.
For a description of parameter options
as well as the functions of the prover object returned consult
the documentation of createProver.