API Documentation#
Saturation Prover#
- class yapsap.yapsa_prover.YapsaProver(problem: str)#
Saturation algorithm defined in a Reinforcement Learning friendly way.
>>> import sys >>> if sys.version_info.major == 3 and sys.version_info.minor >= 9: ... from importlib.resources import files ... else: ... from importlib_resources import files >>> tptp_folder = files("yapsap").joinpath( ... os.path.join("resources", "TPTP-mock") ... ) >>> problem = os.path.join(tptp_folder, "Problems", "TST", "TST001-1.p") >>> from random import choice >>> class RandomProver(YapsaProver): ... def proof_attempt(self) -> None: ... while not self.proof_found: ... self._step(choice(list(self.state.keys()))) ... >>> prover = RandomProver(problem) >>> len(prover.state) 4
>>> from random import seed >>> seed(0) >>> prover.proof_attempt() >>> print(len(prover.state)) 161
- __init__(problem: str)#
Initialise spaces et al.
- Parameters:
problem – a list of the names of TPTP problem files
- proof_attempt() None#
Try finding a proof.
- property proof_found: bool#
Return whether there is an empty clause in the state.
Factoring#
- yapsap.factoring.all_possible_factors(given_clause: Clause) Tuple[Clause, ...]#
One of the four basic building blocks of the Given Clause algorithm.
>>> from tptp_lark_parser.tptp_parser import TPTPParser >>> parser = TPTPParser() >>> clause = parser.parse("cnf(one, axiom, p(c) | p(X) | q).")[0] >>> tuple(map( ... parser.cnf_parser.pretty_print, ... all_possible_factors(clause) ... )) ('cnf(x..., lemma, q() | p(c), inference(factoring, [], [one])).',)
- Parameters:
given_clause – a new clause which should be combined with all the processed ones
- Returns:
results of all possible factors with each one from
clausesand thegiven_clause
- yapsap.factoring.factoring(given_clause: Clause, literal_one: Literal, literal_two: Literal) Clause#
Apply positive factoring rule.
\[{\frac{C\vee A_1\vee A_2}{\sigma\left(C\vee L_1\right)}}\]where
\(C\) and is a clause
\(A_1\) and \(A_2\) are atomic formulae (positive literals)
\(\sigma\) is a most general unifier of \(A_1\) and \(A_2\)
>>> from tptp_lark_parser.grammar import Predicate, Variable, Function >>> from pprint import pprint >>> pprint(factoring( ... gram.Clause((gram.Literal(True, Predicate(8, (Variable(0),))),)), ... gram.Literal(False, Predicate(9, (Variable(0),))), ... gram.Literal(False, Predicate(9, (Function(0, ()),))) ... ).literals, width=75) (Literal(negated=True, atom=Predicate(index=8, arguments=(Function(index=0, arguments=()),))), Literal(negated=False, atom=Predicate(index=9, arguments=(Function(index=0, arguments=()),)))) >>> factoring( ... gram.Clause(()), gram.Literal(False, Predicate(8, ())), ... gram.Literal(True, Predicate(7, ())) ... ) Traceback (most recent call last): ... ValueError: factoring is not possible for Literal(negated=False, atom=P...
- Parameters:
given_clause – \(C\)
literal_one – \(A_1\)
literal_two – \(A_2\)
- Returns:
a new clause — the factoring result
- Raises:
ValueError – if
literal_oneorliteral_twois negated
Paramodulation#
- yapsap.paramodulation.all_paramodulants_from_clause(clause_one: Clause, literal_one: Literal, clause_two: Clause, literal_two: Literal) Tuple[Clause, ...]#
Apply
paramodulationwith varyingr_positionargument.Also varies for equality symmetry
- Parameters:
clause_one – \(C_1\)
literal_one – \(s\approx t\)
clause_two – \(C_2\)
literal_two – \(L\left[r\right]\)
- Returns:
a list of paramodulants for all possible values of
r_position- Raises:
ValueError – if
literal_oneis not an equality
- yapsap.paramodulation.all_paramodulants_from_list(clauses: Tuple[Clause, ...], given_clause: Clause) Tuple[Clause, ...]#
One of the four basic building block of the Given Clause algorithm.
>>> from tptp_lark_parser.grammar import Literal, Function, Predicate >>> all_paramodulants_from_list( ... (Clause( ... (Literal( ... False, ... Predicate(EQUALITY_SYMBOL_ID, (Function(1, ()),))), ... ), ... "one" ... ),), ... Clause((Literal(True, Predicate(3, ())),), "two") ... ) Traceback (most recent call last): ... ValueError: expected equality, but got Literal(negated=False, ...) >>> from tptp_lark_parser.tptp_parser import TPTPParser >>> parser = TPTPParser() >>> one = parser.parse("cnf(one, axiom, a=b | X=X).")[0] >>> two = parser.parse("cnf(two, axiom, b=c).")[0] >>> res = all_paramodulants_from_list((one,), two) >>> print(len(res)) 6
- Parameters:
clauses – a list of (processed) clauses
given_clause – a new clause which should be combined with all the processed ones
- Returns:
results of all possible paramodulants with each one from
clausesand thegiven_clause
- yapsap.paramodulation.paramodulation(clause_one: Clause, literal_one: Tuple[Variable | Function, Variable | Function], clause_two: Clause, literal_two: Literal, r_position: int) Clause#
Apply the binary paramodulation rule.
\[{\frac{C_1\vee s\approx t,C_2\vee L\left[r\right]}{\sigma\left(L\left[t\right]\vee C_1\vee C_2\right)}}\]where
\(C_1\) and \(C_2\) are clauses with no common variables
\(L\left[r\right]\) is a literal with a sub-term \(r\)
- only one instance of \(r\) in \(L\left[r\right]\) is considered,
even if there are many of them
- \(s\) and \(t\) are terms, \(\approx\) is a syntactic
equality symbol
\(\sigma\) is a most general unifier of \(s\) and \(r\)
>>> from tptp_lark_parser.grammar import Predicate, Variable, Function >>> res = paramodulation( ... Clause((Literal(False, Predicate(8, (Variable(0),))),)), ... (Variable(0), Function(7, ())), ... Clause((Literal(False, Predicate(9, (Variable(0),))),)), ... Literal(True, Predicate(10, (Function(0, ()),))), ... 1 ... ).literals >>> from pprint import pprint >>> pprint(list(sorted(map(str, res))), width=75) ['Literal(negated=False, atom=Predicate(index=8, ' 'arguments=(Function(index=0, arguments=()),)))', 'Literal(negated=False, atom=Predicate(index=9, ' 'arguments=(Function(index=0, arguments=()),)))', 'Literal(negated=True, atom=Predicate(index=10, ' 'arguments=(Function(index=7, arguments=()),)))']
- Parameters:
clause_one – \(C_1\)
literal_one – \(s\approx t\)
clause_two – \(C_2\)
literal_two – \(L\left[r\right]\)
r_position – index of \(r\) in the tree of sub-terms of \(L\left[r\right]\)
- Returns:
a new clause — the paramodulation result
Reflexivity Resolution#
- yapsap.reflexivity_resolution.all_possible_reflexivity_resolvents(given_clause: Clause) Tuple[Clause, ...]#
One of the four basic building blocks of the Given Clause algorithm.
>>> from tptp_lark_parser.tptp_parser import TPTPParser >>> parser = TPTPParser() >>> clause = parser.parse("cnf(test, axiom, p(X) | ~ X=a | b != a).")[0] >>> from pprint import pprint >>> pprint(tuple(map( ... parser.cnf_parser.pretty_print, ... all_possible_reflexivity_resolvents(clause) ... )), width=75) ('cnf(x..., lemma, p(a) | ~b = a, ' 'inference(reflexivity_resolution, [], [test])).',)
- Parameters:
given_clause – a new clause which should be combined with all the processed ones
- Returns:
results of all possible reflexivity resolvents with each one from
clausesand thegiven_clause
- yapsap.reflexivity_resolution.reflexivity_resolution(given_clause: Clause, a_literal: Tuple[Variable | Function, Variable | Function]) Clause#
Apply reflexivity resolution rule.
\[\frac{C\vee s\not\approx t}{\sigma\left(C\right)}\]where
\(C\) and is a clause
\(s\) and \(t\) are terms, \(\not\approx\) is a negation of equality
\(\sigma\) is a most general unifier of \(s\) and \(t\)
>>> from pprint import pprint >>> from tptp_lark_parser.grammar import Predicate, Variable, Function >>> pprint(reflexivity_resolution(grammar.Clause((grammar.Literal(True, ... Predicate(7, (Variable(0),))),)), (Variable(0), Function(0, ())) ... ).literals, width=75) (Literal(negated=True, atom=Predicate(index=7, arguments=(Function(index=0, arguments=()),))),)
- Parameters:
given_clause – \(C\)
a_literal – \(s\not\approx t\)
- Returns:
a new clause — the reflexivity resolution result
Resolution#
- yapsap.resolution.all_possible_resolvents(clauses: Tuple[Clause, ...], given_clause: Clause) Tuple[Clause, ...]#
One of the four basic building blocks of the Given Clause algorithm.
>>> from tptp_lark_parser.tptp_parser import TPTPParser >>> parser = TPTPParser() >>> one = parser.parse("cnf(one, axiom, q(X) | p(X)).")[0] >>> two = parser.parse("cnf(two, axiom, ~p(c)).")[0] >>> tuple(map( ... parser.cnf_parser.pretty_print, ... all_possible_resolvents((one,), two) ... )) ('cnf(x..., lemma, q(c), inference(resolution, [], [one, two])).',)
- Parameters:
clauses – a list of (processed) clauses
given_clause – a new clause which should be combined with all the processed ones
- Returns:
results of all possible resolvents with each one from
clausesand thegiven_clause
- yapsap.resolution.resolution(clause_one: Clause, literal_one: Literal, clause_two: Clause, literal_two: Literal) Clause#
Do inference according to the standard first-order resolution rule.
\[{\frac{C_1\vee L_1,C_2\vee L_2}{\sigma\left(C_1\vee C_2\right)}}\]where
\(C_1\) and \(C_2\) are clauses with no common variables
\(L_1\) and \(L_2\) are literals (one negated and one not)
- \(\sigma\) is a most general unifier of atoms from \(L_1\) and
\(L_2\)
>>> from tptp_lark_parser.grammar import Predicate, Variable, Function >>> from pprint import pprint >>> pprint(resolution( ... Clause((Literal(False, Predicate(4, (Variable(0),))),)), ... Literal(False, Predicate(3, (Variable(0),))), ... Clause((Literal(False, Predicate(5, (Variable(0),))),)), ... Literal(True, Predicate(3, (Function(1, ()),))) ... ).literals, width=75) (Literal(negated=False, atom=Predicate(index=4, arguments=(Function(index=1, arguments=()),))), Literal(negated=False, atom=Predicate(index=5, arguments=(Function(index=1, arguments=()),)))) >>> resolution( ... Clause(()), Literal(False, Predicate(8, ())), ... Clause(()), Literal(False, Predicate(7, ())) ... ) Traceback (most recent call last): ... ValueError: resolution is not possible for Literal(negated=False, atom=...
- Parameters:
clause_one – \(C_1\)
literal_one – \(L_1\)
clause_two – \(C_2\)
literal_two – \(L_2\)
- Returns:
a new clause — the resolution result
- Raises:
ValueError – if both
literal_oneandliteral_twoare negated or non-negated
Substitution#
- class yapsap.substitution.Substitution(variable: Variable, term: Variable | Function)#
A mapping from
VariabletoTerm.>>> substitution = Substitution( ... grammar.Variable(0), grammar.Function(2, ()) ... ) >>> from pprint import pprint >>> pprint(substitution( ... grammar.Clause(( ... grammar.Literal( ... False, ... grammar.Predicate( ... 3, ... (grammar.Function(1, (grammar.Variable(0),)),)) ... ), ... ), label="test") ... ).literals[0].atom, width=75) Predicate(index=3, arguments=(Function(index=1, arguments=(Function(index=2, arguments=()),)),)) >>> substitution(grammar.Variable(0)) Function(index=2, arguments=())
- __call__(target: Clause | Predicate | Variable | Function) Clause | Predicate | Variable | Function#
Apply a substitution to a given target clause.
- Parameters:
target – a clause to which to apply the substitution
- __init__(variable: Variable, term: Variable | Function) None#
- substitute_in_clause(clause: Clause) Clause#
Apply the substitution to something which is known to be a
Clause.- Parameters:
clause – a clause to apply substitution to
- Returns:
the result of the substitution
Unification#
- exception yapsap.unification.NonUnifiableError#
Exception raised when terms are not unifiable.
- yapsap.unification.most_general_unifier(propositions: Tuple[Predicate | Variable | Function, ...], substitutions: Tuple[Substitution, ...] | None = None) Tuple[Substitution, ...]#
Follow the Robinson’s 1965 unification algorithm.
>>> most_general_unifier((Variable(0), Variable(0))) () >>> most_general_unifier((Variable(0), Function(7, (Variable(0),)))) Traceback (most recent call last): ... yapsap.unification.NonUnifiableError: (Variable(index=... >>> from pprint import pprint >>> pprint(most_general_unifier(( ... Predicate( ... 8, (Variable(0), Variable(1), Function(0, (Variable(2),))) ... ), ... Predicate(8, ... ( ... Variable(4), ... Function(7, (Variable(5), Variable(5))), ... Variable(5) ... ) ... ) ... )), width=75) (Substitution(variable=Variable(index=0), term=Variable(index=4)), Substitution(variable=Variable(index=1), term=Function(index=7, arguments=(Variable(index=5), Variable(index=5)))), Substitution(variable=Variable(index=5), term=Function(index=0, arguments=(Variable(index=2),))))
- Parameters:
propositions – a set of propositions to unify
substitutions – this function is recursive and uses this param to accumulate its output
- Returns:
a map from variables to functions or other variables (aka substitution)
Logic Operations Utility Functions#
- exception yapsap.utils.NoSubtermFound#
Sometimes a sub-term index is larger than term length.
- exception yapsap.utils.TermSelfReplace#
An exception raised when trying to replace a sub-term with itself.
- yapsap.utils.clause_length(clause: dict) int#
Find the length of arguments of each predicate.
Negation adds one to each literal.
- Parameters:
clause – a clause in JSON representation
- Returns:
structural length of a clause
>>> from tptp_lark_parser.grammar import Literal >>> import orjson >>> clause_length(orjson.loads(orjson.dumps( ... Clause((Literal(True, Predicate("p", (Function("f", ()),))),)) ... ))) 3
- yapsap.utils.get_variable_list(clause: Clause | Predicate | Variable | Function) Tuple[Variable, ...]#
Find all variables present in a clause.
>>> from tptp_lark_parser.grammar import Literal >>> get_variable_list(Clause((Literal(False, ... Predicate(0, (Function(0, (Variable(0), Variable(0))),)) ... ),))) (Variable(index=0), Variable(index=0))
- Parameters:
clause – a clause
- Returns:
a list (with repetitions) of variables from there clause
- yapsap.utils.is_subproposition(one: Predicate | Variable | Function, two: Predicate | Variable | Function) bool#
Check whether proposition
oneis part of a propositiontwo.- Parameters:
one – presumably shorter proposition which is probably a part
two – presumably longer proposition which is probably the whole
- Returns:
whether
oneis a part oftwo
- yapsap.utils.is_tautology(clause: Clause) bool#
Check whether there are two literals (negated and not) with the same atom.
>>> from tptp_lark_parser.grammar import Literal >>> is_tautology(Clause((Literal(False, Predicate(7, ())),))) False >>> is_tautology(Clause( ... (Literal(False, Predicate(7, ())), Literal(True, Predicate(7, ()))) ... )) True >>> is_tautology(Clause( ... (Literal(False, Predicate(1, (Variable(0), Variable(0)))),) ... )) True
- Parameters:
clause – a clause to check
- Returns:
whether the clause is a primitive tautology or not
- yapsap.utils.proposition_length(proposition: Predicate | Variable | Function) int#
Find the number of functional, predicate and variable symbols.
- Parameters:
proposition – a function, a predicate or a variable
- Returns:
structural length of a proposition
>>> proposition_length(Predicate(7, (Function(0, (Variable(0),)),))) 3
- yapsap.utils.reindex_variables(clauses: Dict[str, Clause]) Dict[str, Clause]#
Rename variables so that each clause has its unique set of variables.
>>> from tptp_lark_parser.grammar import Literal >>> clause = Clause((Literal(False, ... Predicate(0, (Variable(2), Variable(1), Variable(0))) ... ),)) >>> sorted(map( ... attrgetter("index"), ... reindex_variables( ... {"this_is_a_test_case": clause} ... )["this_is_a_test_case"].literals[0].atom.arguments ... )) [0, 1, 2] >>> clause = Clause((Literal(False, ... Predicate(0, (Variable(5), Variable(10), Variable(5))) ... ),)) >>> sorted(map( ... attrgetter("index"), ... reindex_variables( ... {"this_is_a_test_case": clause} ... )["this_is_a_test_case"].literals[0].atom.arguments ... )) [0, 1, 1]
- Parameters:
clauses – a map of clause labels to clauses
- Returns:
the list of clauses with renamed variables
- yapsap.utils.replace_subterm_by_index(atom: Predicate | Variable | Function, index: int, term: Variable | Function) Predicate | Variable | Function#
Replace a sub-term with a given index (depth-first search) by a new term.
>>> atom = Predicate(7, ( ... Function(0, (Variable(0),)), Function(1, (Variable(2),)) ... )) >>> replace_subterm_by_index(atom, 0, Variable(3)) Traceback (most recent call last): ... yapsap.utils.NoSubtermFound: 5 >>> from pprint import pprint >>> pprint( ... replace_subterm_by_index(atom, 4, Function(2, (Variable(3),))), ... width=75 ... ) Predicate(index=7, arguments=(Function(index=0, arguments=(Variable(index=0),)), Function(index=1, arguments=(Function(index=2, arguments=(Variable(index=3),)),)))) >>> replace_subterm_by_index(Predicate(7, (Variable(0),)), 1, Variable(0)) Traceback (most recent call last): ... yapsap.utils.TermSelfReplace
- Parameters:
atom – a predicate or a term
index – an index of a sub-term to replace, must be greater than 0
term – replacement term for a given index
- Returns:
- Raises:
NoSubtermFound – if sub-term with a given index doesn’t exist
- yapsap.utils.subterm_by_index(atom: Predicate | Variable | Function, index: int) Variable | Function#
Extract a sub-term using depth-first search.
>>> atom = Predicate(7, ( ... Function(0, (Variable(0),)), Function(1, (Variable(1),)) ... )) >>> subterm_by_index(atom, 0) Traceback (most recent call last): ... ValueError: sub-term with index 0 exists only for terms, but got: ... >>> subterm_by_index(atom, 1) == atom.arguments[0] True >>> subterm_by_index(atom, 2) == atom.arguments[0].arguments[0] True >>> subterm_by_index(atom, 4) == atom.arguments[1].arguments[0] True
- Parameters:
atom – a predicate or a term
index – an index of a desired sub-term
- Returns:
a sub-term
- Raises:
ValueError – when trying to get a term with index 0 of a predicate
NoSubtermFound – if sub-term with a given index doesn’t exist