Quick start¶
mathema checks claims about code: it proves them where it can, and
where a claim is wrong it finds a real input that breaks it. Every claim
quantifies over a domain, and for a function of numbers that is R or
[0, 1]. This package supplies the domains for what most application
code actually takes: strings, records and the schemas that describe
them, each written L[...].
pip install "mathema[all]"
That is mathema with every extra this package included;
pip install mathema-language adds it to a mathema you already have.
mathema finds it through its entry points, so there is nothing to
configure. Three claims show the three kinds of data, each on
the shop in examples/shop, the example application these pages use
throughout.
A string¶
def display_name(username: str) -> str:
"""The username as shown in the header, upper-cased."""
return username.upper()
f = display_name
for username in L[unicode, len <= 32], len(f(username)) <= 32
falsified username = 'afifififififififififififififififi': 33 vs 32
L[unicode, len <= 32] is every string of at most 32 code points.
falsified means mathema ran the function on a member of the domain
and the claim did not hold, and the witness is that member, shrunk to
the smallest one that still fails: fi is one code point and upper-cases
to two.
A record¶
def order_total(order: Order) -> Decimal:
"""What the customer pays for the order."""
return order.quantity * order.unit_price
f = order_total
for order in L[shop.db.Order], f(order) >= 0
proven
L[shop.db.Order] is every row the SQLAlchemy orders table accepts.
proven means the claim holds for every one of them: the fields the
function reads were lifted to symbols bounded by the table's CHECK
constraints, and the proof went through.
A tree¶
def thread_size(comment: Comment) -> int:
"""How many comments the thread holds, this one included."""
return 1 + sum(thread_size(r) for r in comment.replies)
f = thread_size
for comment in L[shop.threads.Comment, depth <= 50], f(comment) >= 1
proven
for comment in L[shop.threads.Comment], f(comment) >= 1
falsified comment = <Comment tree 1050 records deep>: raised RecursionError
The first is proven by structural induction. The second is the same function on threads of any depth, where the recursion runs out: the mathematics is right and the code is not.
What the verdicts mean¶
| Verdict | Meaning |
|---|---|
proven |
true for every member of the domain, by a proof |
holds |
true on every input mathema tried, the language's hazards first |
falsified |
false, with a real input as the witness |
unknown |
mathema could not decide it, and says why |
skipped |
the claim could not be run, and the record says why |
Where next¶
- For text: Text, Formats and identifiers and JSON.
- For records: Records and schemas and Trees.
- Everything by name: Languages, Refinements, Relations and paths, Claim families, Vocabulary, and a page for each adaptor.
- The claims worth writing for a function, by what the function does: What to claim.