Skip to main content

Tensor Theorem Prover

ci Codecov PyPI Documentation Status

First-order logic theorem prover supporting unification with approximate vector similarity

Full docs: https://tensor-theorem-prover.readthedocs.io

Installation

pip install tensor-theorem-prover

Usage

tensor-theorem-prover can be used either as a standard symbolic first-order theorem prover, or it can be used with vector embeddings and fuzzy unification.

The basic setup requires listing out first-order formulae, and using the ResolutionProver class to generate proofs.

import numpy as np
from vector_theorem_prover import ResolutionProver, Constant, Predicate, Variable, Implies

X = Variable("X")
Y = Variable("Y")
Z = Variable("Z")
# predicates and constants can be given an embedding array for fuzzy unification
grandpa_of = Predicate("grandpa_of", np.array([1.0, 1.0, 0.0, 0.3, ...]))
grandfather_of = Predicate("grandfather_of", np.array([1.01, 0.95, 0.05, 0.33, ...]))
parent_of = Predicate("parent_of", np.array([ ... ]))
father_of = Predicate("father_of", np.array([ ... ]))
bart = Constant("bart", np.array([ ... ]))
homer = Constant("homer", np.array([ ... ]))
abe = Constant("abe", np.array([ ... ]))

knowledge = [
    parent_of(homer, bart),
    father_of(abe, homer),
    # father_of(X, Z) ^ parent_of(Z, Y) -> grandpa_of(X, Y)
    Implies(And(father_of(X, Z), parent_of(Z, Y)), grandpa_of(X, Y))
]

prover = ResolutionProver(knowledge=knowledge)

# query the prover to find who is bart's grandfather
proof = prover.prove(grandfather_of(X, bart))

# even though `grandpa_of` and `grandfather_of` are not identical symbols,
# their embedding is close enough that the prover can still find the answer
print(proof.substitutions[X]) # abe

# the prover will return `None` if a proof could not be found
failed_proof = prover.prove(grandfather_of(bart, homer))
print(failed_proof) # None

Working with proof results

The prover.prove() method will return a Proof object if a successful proof is found. This object contains a list of all the resolutions, substitutions, and similarity calculations that went into proving the goal.

proof = prover.prove(goal)

proof.substitutions # a map of all variables in the goal to their bound values
proof.similarity # the min similarity of all `unify` operations in this proof
proof.depth # the number of steps in this proof
proof.proof_steps # all the proof steps involved, including all resolutions and unifications along the way

The Proof object can be printed as a string to get a visual overview of the steps involved in the proof.

X = Variable("X")
Y = Variable("Y")
father_of = Predicate("father_of")
parent_of = Predicate("parent_of")
is_male = Predicate("is_male")
bart = Constant("bart")
homer = Constant("homer")

knowledge = [
    parent_of(homer, bart),
    is_male(homer),
    Implies(And(parent_of(X, Y), is_male(X)), father_of(X, Y)),
]

prover = ResolutionProver(knowledge=knowledge)

goal = father_of(homer, X)
proof = prover.prove(goal)

print(proof)
# Goal: [¬father_of(homer,X)]
# Subsitutions: {X -> bart}
# Similarity: 1.0
# Depth: 3
# Steps:
#   Similarity: 1.0
#   Source: [¬father_of(homer,X)]
#   Target: [father_of(X,Y) ∨ ¬is_male(X) ∨ ¬parent_of(X,Y)]
#   Unify: father_of(homer,X) = father_of(X,Y)
#   Subsitutions: {}, {X -> homer, Y -> X}
#   Resolvent: [¬is_male(homer) ∨ ¬parent_of(homer,X)]
#   ---
#   Similarity: 1.0
#   Source: [¬is_male(homer) ∨ ¬parent_of(homer,X)]
#   Target: [parent_of(homer,bart)]
#   Unify: parent_of(homer,X) = parent_of(homer,bart)
#   Subsitutions: {X -> bart}, {}
#   Resolvent: [¬is_male(homer)]
#   ---
#   Similarity: 1.0
#   Source: [¬is_male(homer)]
#   Target: [is_male(homer)]
#   Unify: is_male(homer) = is_male(homer)
#   Subsitutions: {}, {}
#   Resolvent: []

Finding all possible proofs

The prover.prove() method will return the proof with the highest similarity score among all possible proofs, if one exists. If you want to get a list of all the possible proofs in descending order of similarity score, you can call prover.prove_all() to return a list of all proofs.

Custom matching functions and similarity thresholds

By default, the prover will use cosine similarity for unification. If you'd like to use a different similarity function, you can pass in a function to the prover to perform the similarity calculation however you wish.

def fancy_similarity(item1, item2):
    norm = np.linalg.norm(item1.embedding) + np.linalg.norm(item2.embedding)
    return np.linalg.norm(item1.embedding - item2.embedding) / norm

prover = ResolutionProver(knowledge=knowledge, similarity_func=fancy_similarity)

By default, there is a minimum similarity threshold of 0.5 for a unification to success. You can customize this as well when creating a ResolutionProver instance

prover = ResolutionProver(knowledge=knowledge, min_similarity_threshold=0.9)

Working with Tensors (Pytorch, Tensorflow, etc...)

By default, the similarity calculation assumes that the embeddings supplied for constants and predicates are numpy arrays. If you want to use tensors instead, this will work as long as you provide a similarity_func which can work with the tensor types you're using and return a float.

For example, if you're using Pytorch, it might look like the following:

import torch

def torch_cosine_similarity(item1, item2):
    similarity = torch.nn.functional.cosine_similarity(
        item1.embedding,
        item2.embedding,
        0
    )
    return similarity.item()

prover = ResolutionProver(knowledge=knowledge, similarity_func=torch_cosine_similarity)

# for pytorch you may want to wrap the proving in torch.no_grad()
with torch.no_grad():
    proof = prover.prove(goal)

Max proof depth

By default, the ResolutionProver will abort proofs after a depth of 10. You can customize this behavior by passing max_proof_depth when creating the prover

prover = ResolutionProver(knowledge=knowledge, max_proof_depth=10)

Max resolvent width

By default, the ResolutionProver has no limit on how wide resolvents can get during the proving process. If the proofs are running too slowly, you can try to set max_resolvent_width to limit how many literals intermediate resolvents are allowed to contain. This should narrow the search tree, but has the trade-off of not finding proofs if the proof requires unifying together a lot of very wide clauses.

prover = ResolutionProver(knowledge=knowledge, max_resolvent_width=10)

Skipping seen resolvents

A major performance improvement when searching through a large proof space is to stop searching any branches that encounter a resolvent that's already been seen. Doing this is still guaranteed to find the proof with the highest similarity score, but it means the prover is no longer guaranteed to find every possible proof when running prover.prove_all(). Although, when dealing with anything beyond very small knowledge bases, finding every possible proof is likely not going to be computationally feasible anyway.

Searching for a proof using prover.prove() always enables this optimization, but you can enable it when using prover.prove_all() as well by passing the option skip_seen_resolvents=True when creating the ResolutionProver, like below:

prover = ResolutionProver(knowledge=knowledge, skip_seen_resolvents=True)

Max resolution attempts

As a final backstop against the search tree getting too large, you can set a maximum resolution attempts parameter to force the prover to give up after a finite amount of attempts. You can set this parameter when creating a ResolutionProver as shown below:

prover = ResolutionProver(knowledge=knowledge, max_resolution_attempts=100_000_000)

Multithreading

By default, the ResolutionProver will try to use available CPU cores up to a max of 6, though this may change in future releases. If you want to explicitly control the number of worker threads used for solving, pass num_workers when creating the ResolutionProver, like below:

prover = ResolutionProver(knowledge=knowledge, num_workers=1)

Acknowledgements

This library borrows code and ideas from the earier library fuzzy-reasoner. The main difference between these libraries is that tensor-theorem-prover supports full first-order logic using Resolution, whereas fuzzy-reasoner is restricted to Horn clauses and uses backwards chaining. This library is also much more optimized than the fuzzy-reasoner, as the core of tensor-theorem-prover is written in rust and supports multithreading, while fuzzy-reasoner is pure Python.

Like fuzzy-reasoner, this library also takes inspiration from the following papers for the idea of using vector similarity in theorem proving:

Contributing

Contributions are welcome! Please leave an issue in the Github repo if you find any bugs, and open a pull request with and fixes or improvements that you'd like to contribute.

Metadata

Release files for tensor-theorem-prover 0.14.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for tensor-theorem-prover 0.14.0
File Size Uploaded
tensor_theorem_prover-0.14.0.tar.gz 3.1 MB Details

Built distributions (wheels)

Table of built distributions (wheels) for tensor-theorem-prover 0.14.0
File
tensor_theorem_prover-0.14.0-cp38-none-win_amd64.whl CPython 3.8 none Windows x86-64 Details
tensor_theorem_prover-0.14.0-cp38-none-win32.whl CPython 3.8 none Windows x86-32 Details
tensor_theorem_prover-0.14.0-cp38-cp38-musllinux_1_2_x86_64.whl CPython 3.8 CPython 3.8 Linux musl 1.2+ x86-64 Details
tensor_theorem_prover-0.14.0-cp38-cp38-musllinux_1_2_i686.whl CPython 3.8 CPython 3.8 Linux musl 1.2+ x86-32 Details
tensor_theorem_prover-0.14.0-cp38-cp38-musllinux_1_2_armv7l.whl CPython 3.8 CPython 3.8 Linux musl 1.2+ ARMv7l Details
tensor_theorem_prover-0.14.0-cp38-cp38-musllinux_1_2_aarch64.whl CPython 3.8 CPython 3.8 Linux musl 1.2+ ARM64 Details
tensor_theorem_prover-0.14.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.8 CPython 3.8 Linux glibc 2.17+ x86-64 Details
tensor_theorem_prover-0.14.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl CPython 3.8 CPython 3.8 Linux glibc 2.12+ x86-32 Details
tensor_theorem_prover-0.14.0-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl CPython 3.8 CPython 3.8 macOS 10.9+ universal2 (ARM64, x86-64), macOS 10.9+ x86-64, macOS 11.0+ ARM64 Details
tensor_theorem_prover-0.14.0-cp38-cp38-macosx_10_7_x86_64.whl CPython 3.8 CPython 3.8 macOS 10.7+ x86-64 Details

Total release size: 18.6 MB

Release files / tensor_theorem_prover-0.14.0.tar.gz

Download URL tensor_theorem_prover-0.14.0.tar.gz
Size 3.1 MB
Tags Source
SHA-256 checksum
How to use checksums
aa5e121c235ac3d6b56961ff92721f8f5c25f7a8a9c0b8539f3e448a7f32d4a7
BLAKE2b-256 checksum
How to use checksums
cec016f418092bf56bf0fcbe1cdc4b30e7fca6dea77c2dc7f487da320941b3d5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.3.2 CPython/3.10.6 Linux/5.15.0-1031-azure

Release files / tensor_theorem_prover-0.14.0-cp38-none-win_amd64.whl

Download URL tensor_theorem_prover-0.14.0-cp38-none-win_amd64.whl
Size 694.1 kB
Tags CPython 3.8 Windows x86-64
SHA-256 checksum
How to use checksums
b34e79a1fe8cbf6301b32455cf15e694f9156268226e8b3e61bf6c476f1940ba
BLAKE2b-256 checksum
How to use checksums
e6b74c303c9f2165be7ed205446b605a95210d66ea882b13b0e145e9721aa9b5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.3.2 CPython/3.10.6 Linux/5.15.0-1031-azure

Release files / tensor_theorem_prover-0.14.0-cp38-none-win32.whl

Download URL tensor_theorem_prover-0.14.0-cp38-none-win32.whl
Size 626.3 kB
Tags CPython 3.8 Windows x86-32
SHA-256 checksum
How to use checksums
d2f2c586f8c0af5bc567be1306771dff3aec06336514e4b3432eaa4fee0d8338
BLAKE2b-256 checksum
How to use checksums
bc5a97d3039c17bcb67390e6e6ed08868c7b108b2db09173a22339983c3d55e6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.3.2 CPython/3.10.6 Linux/5.15.0-1031-azure

Release files / tensor_theorem_prover-0.14.0-cp38-cp38-musllinux_1_2_x86_64.whl

Download URL tensor_theorem_prover-0.14.0-cp38-cp38-musllinux_1_2_x86_64.whl
Size 2.0 MB
Tags CPython 3.8 Linux musl 1.2+ x86-64
SHA-256 checksum
How to use checksums
0c8407daaa90da7b91a43fa586f04ed4e48ad79f563ad1e88db58829d71d121f
BLAKE2b-256 checksum
How to use checksums
20eef455947b38139a5232e807050a462d3a7f9fd7d524119c362ff11ee57418
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.3.2 CPython/3.10.6 Linux/5.15.0-1031-azure

Release files / tensor_theorem_prover-0.14.0-cp38-cp38-musllinux_1_2_i686.whl

Download URL tensor_theorem_prover-0.14.0-cp38-cp38-musllinux_1_2_i686.whl
Size 2.0 MB
Tags CPython 3.8 Linux musl 1.2+ x86-32
SHA-256 checksum
How to use checksums
1b3f37a3772d532c1a231a18e5cf7857c2989aafd66f9b32aaf421f6430fee80
BLAKE2b-256 checksum
How to use checksums
1034236f779f29f1f6e639e5c3ae8999f77eed2a8b7fc31154d8fa3ec33408b9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.3.2 CPython/3.10.6 Linux/5.15.0-1031-azure

Release files / tensor_theorem_prover-0.14.0-cp38-cp38-musllinux_1_2_armv7l.whl

Download URL tensor_theorem_prover-0.14.0-cp38-cp38-musllinux_1_2_armv7l.whl
Size 2.0 MB
Tags CPython 3.8 Linux musl 1.2+ ARMv7l
SHA-256 checksum
How to use checksums
922b21f16d54ff585c3a3d5e486031be49036438b509163e9f7818cfd239e095
BLAKE2b-256 checksum
How to use checksums
352cc74acb14fb783a446594fbe2a5589a5e1b5aa979a676bd044f992e7e55af
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.3.2 CPython/3.10.6 Linux/5.15.0-1031-azure

Release files / tensor_theorem_prover-0.14.0-cp38-cp38-musllinux_1_2_aarch64.whl

Download URL tensor_theorem_prover-0.14.0-cp38-cp38-musllinux_1_2_aarch64.whl
Size 1.9 MB
Tags CPython 3.8 Linux musl 1.2+ ARM64
SHA-256 checksum
How to use checksums
8f8c589196579120e39d7642a879410cdfd34cbd4b836d5594b41755310a9c57
BLAKE2b-256 checksum
How to use checksums
81f8f0287201a15a0dc0d509559b50e33102ff188b9bc9e301587fe4456f0bee
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.3.2 CPython/3.10.6 Linux/5.15.0-1031-azure

Release files / tensor_theorem_prover-0.14.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL tensor_theorem_prover-0.14.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 1.8 MB
Tags CPython 3.8 Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
feeac8c591e8eebc9e542eca60f23c856049f4c20cf05a57343f2f49c656799b
BLAKE2b-256 checksum
How to use checksums
9393ed422925fcac337654b1c05de6a931ab8d890cb51a390d77fac45b584b77
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.3.2 CPython/3.10.6 Linux/5.15.0-1031-azure

Release files / tensor_theorem_prover-0.14.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl

Download URL tensor_theorem_prover-0.14.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl
Size 1.8 MB
Tags CPython 3.8 Linux glibc 2.12+ x86-32
SHA-256 checksum
How to use checksums
d6215ff770fa3bb580ad38d7cd0504c89827b560e0321bf8da104cd7f415afaf
BLAKE2b-256 checksum
How to use checksums
61ab2962eb257f44c7cc886c21ac1b90a45d4930e4adfd916e3d621b54c653a7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.3.2 CPython/3.10.6 Linux/5.15.0-1031-azure

Release files / tensor_theorem_prover-0.14.0-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl

Download URL tensor_theorem_prover-0.14.0-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl
Size 1.7 MB
Tags CPython 3.8 macOS 10.9+ universal2 (ARM64, x86-64) macOS 10.9+ x86-64 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
b29817d44332fc040618fea3b4c3b4c76d78adf53f787e45f619eb2e8ec7ea4a
BLAKE2b-256 checksum
How to use checksums
e20ca0e7339552c2553c82e6ed1a1c0409bff56df011c4b59ecbe327c20bf400
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.3.2 CPython/3.10.6 Linux/5.15.0-1031-azure

Release files / tensor_theorem_prover-0.14.0-cp38-cp38-macosx_10_7_x86_64.whl

Download URL tensor_theorem_prover-0.14.0-cp38-cp38-macosx_10_7_x86_64.whl
Size 902.7 kB
Tags CPython 3.8 macOS 10.7+ x86-64
SHA-256 checksum
How to use checksums
5f72b418d01580c61b31fd0c00bca757b41cb0d9cd71df4dbaf89b53b311b124
BLAKE2b-256 checksum
How to use checksums
8945a0c9a8a6151489b3873b3cf07fbf81b5b45b0dc60559c2a370f4792b065c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.3.2 CPython/3.10.6 Linux/5.15.0-1031-azure
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page