Case studies: real formulae, real verdicts¶
Two worked examples on formulae you can look up, taken from openly licensed references. Every claim on this page is in the claim lexicon and is executed by the test suite, so what follows is what mathema actually returns, including where it declines.
The point of both is the same: the interesting result is rarely one claim. It is what a small set of claims says together, and what the disagreements between them tell you.
Put-call parity and the Greeks¶
An option's price is not a simple formula. The Black-Scholes call involves a logarithm, a square root, an exponential and the normal CDF, which is itself an error function. Put-call parity says that however complicated each leg is, the difference between a call and a put on the same strike collapses to something elementary:
C - P = S - K*exp(-r*T)
No volatility term survives. That is a strong statement about a function whose body mentions volatility five times, and it is exactly the kind of claim worth checking against the implementation rather than against a textbook.
for s in [50,150], k in [50,150], r in [0.0,0.1], t in [0.1,2], sigma in [0.05,0.8], f(s,k,r,t,sigma) == s - k*exp(-r*t)
On put_call_parity_gap that is proven, not sampled. The two
legs, with all their error functions, cancel symbolically.
The Greeks are partial derivatives, so state them as partial derivatives¶
Delta is the sensitivity of the price to the spot, which is to say it
is the partial derivative of the price in s. The grammar says that
directly:
for s in [50,150], k in [50,150], r in [0.0,0.1], t in [0.1,2], sigma in [0.05,0.8], ∂(f(s,k,r,t,sigma), s) >= 0
for s in [50,150], k in [50,150], r in [0.0,0.1], t in [0.1,2], sigma in [0.05,0.8], ∂(f(s,k,r,t,sigma), s) <= 1
Both are proven against black_scholes_call. Together they
establish the textbook fact that a call's delta lies in [0, 1], and
they establish it from the code you are shipping rather than from the
paper the code was meant to implement. Nothing was differentiated by
hand: the claim names the partial derivative and the derive route
takes it.
Both spellings work, so d(f(...), s) and ∂(f(...), s) are the same
claim. Use whichever your readers will check.
The sigmoid: calculus as a specification¶
The logistic function is one line of code and a great deal of mathematics:
def logistic_standard(x: float) -> float:
return 1.0 / (1.0 + math.exp(-x))
Its defining properties are calculus facts, and each is a claim.
Its derivative is expressible in the function itself. This is the identity backpropagation is built on:
for x in [-700, 700], d(f(x), x) == f(x)*(1 - f(x))
It is symmetric about the origin:
for x in [-700, 700], f(-x) == 1 - f(x)
It saturates, which limits state:
lim(f(x), x -> oo) == 1
lim(f(x), x -> -oo) == 0
Its derivative is a probability density, which an integral over the whole line states exactly:
∫(d(f(x), x), x, -oo, oo) == 1
All five are proven. The derivative identity, the limits and the
integral are settled symbolically, which is the difference between
knowing a property and having sampled it. The two identities carry a
range because this code cannot evaluate the whole line: below about
x = -709.78, math.exp(-x) raises OverflowError, so stated over
the whole line both are falsified (witnesses x = -1420 and
x = 1420), for the reason the next section spells out.
Where it gets interesting: a true claim that falsifies¶
The sigmoid is bounded strictly between zero and one. Every textbook says so, and it is true of the mathematics. State it unquantified and mathema disagrees:
| claim | verdict | witness |
|---|---|---|
f(x) > 0 |
falsified | x = -1420 raised OverflowError |
f(x) < 1 |
falsified | x = -1420 raised OverflowError |
for x in [0, 1e6], f(x) < 1 |
falsified | x = 1e6 returned exactly 1.0 |
None of these is a mathematical error. At x = -1420, math.exp(1420)
overflows before any division happens, and a claim has no value where
the code raises. Past the overflow the upper bound fails a second
way: at x = 1e6, exp(-x) underflows to zero and the result
saturates to exactly 1.0, so the strict inequality fails in f64
while remaining true in the reals.
This is the distinction the record is built to preserve: the mathematics is sound and the implementation is not total over the inputs the claim quantified. The fix is to say where you meant, which is usually what you meant anyway:
for x in [-30, 30], f(x) > 0
for x in [-30, 30], f(x) < 1
Both proven. A bounded domain is not a weaker claim, it is an honest one, and the record now states the range over which the bound was established rather than implying the whole line.
Gradient descent, and a claim that composes¶
Fixed-step gradient descent on the quadratic bowl 0.5*q*t^2
multiplies the iterate by r = 1 - alpha*q each step, so it converges
exactly when |r| < 1. That condition is a claim about the step size:
for alpha in [0.01,1.9], q in [0.5,1.0], |f(alpha,q)| < 1
Proven on gd_convergence_factor. The claim is more useful than
the sentence it encodes, because it is attached to the code: change
the step-size policy and the claim is re-adjudicated.
Composing: lemmas over case studies¶
Each claim above stands alone, which is the weakest way to use them. A
claim can rest on another through an assuming premise, and then the
evidence composes:
from mathema.claims import check_conjectures, claim
from mathema.lexicon import logistic_standard
check_conjectures(logistic_standard, [
claim("for x in [-30, 30], f(x) > 0", name="positive", route="derive"),
claim("assuming positive is proven, for x in [-30, 30], f(x)*(1 - f(x)) >= 0",
name="derivative_nonneg"),
])
derivative_nonneg is not re-deriving positivity; it is resting on it,
and the record says so. If positive were only sampled, a premise
that demands is proven would have nothing to rest on and
derivative_nonneg would come back unknown; written
assuming positive holds, the conclusion would be capped at holds
and meta["mathema.capped_by"] would name it. That is the property that
makes a chain trustworthy: evidence never gets stronger as it
propagates. See Lemmas for the full behaviour.
Finding a spelling¶
Every claim here is a lexicon entry, and the lexicon is browsable, so you do not have to remember the grammar:
from mathema import lexicon
lexicon.show("sigmoid_derivative") # one entry, both renderings
lexicon.get("parity_identity") # just the claim text
The entries are grouped by what they demonstrate (calculus, assuming, domains, case studies), which makes the lexicon a reasonable first stop when you know what you want to say but not how to spell it.
Sources¶
The formulae are standard and the implementations here are mathema's own. The references are openly licensed:
- Put-call parity, Black-Scholes model, Greeks (finance), and Logistic function: Wikipedia, CC BY-SA 4.0.
- Fixed-step gradient descent on a quadratic: Scientific Python Lectures, CC BY 4.0, "Mathematical optimization: finding minima of functions".