When the facts disagree, say so, instead of pretending they don’t.
paraconsistent-animals.py · output · proof · check · try it in the playground
Birds fly. Penguins don’t. Tweety is a bird and a penguin. Does Tweety fly?
Real data is often like this: two rules, or a rule and an observation, point in opposite directions. Ordinary logic breaks down here: from a contradiction it lets you conclude anything at all.
Paraconsistent reasoning is reasoning that keeps working when the data contains contradictions. It keeps the conflict contained and visible.
fact(bird('tweety'))
fact(penguin('tweety'))
fact(bird('falco'))
fact(penguin('opus'))
fact(mammal('batsy'))
fact(bat('batsy'))
fact(fish('nemo'))
fact(bird('mythic'))
fact(observed('mythic', 'flies', 'false'))
implies(bird(X), flies(X, 'true'))
implies(bird(X), wings(X, 'true'))
implies(penguin(X), flies(X, 'false'))
implies(mammal(X), wings(X, 'false'))
implies(bat(X), flies(X, 'true') & wings(X, 'true'))
# …
Conclusions are written as flies(X, 'true') or flies(X, 'false'), so both
can be recorded side by side without the program falling over.
Each property gets a local summary: true only, false only, or both.
implies(flies(X, 'true') & flies(X, 'false'), flight_status(X, 'both'))
implies(flies(X, 'true') & ~flies(X, 'false'), flight_status(X, 'true_only'))
# …
implies(flight_status(X, 'true_only'), flies_safely(X, 'true'))
implies(flight_status(X, 'both'), flies_safely(X, 'undecided'))
~ means “not found”: nothing peye knows says otherwise. Decisions read
only the summary, so a conflict leads to undecided, never to both answers.
50 conclusions in all. The interesting ones:
inconsistent('tweety', 'flies')
needs_review('tweety', 'flies')
inconsistent('mythic', 'flies')
inconsistent('batsy', 'wings')
flies_safely('tweety', 'undecided')
flies_safely('falco', 'true')
flies_safely('opus', 'false')
moves_by('opus', 'walking')
Tweety (bird and penguin) and Mythic (a bird seen not flying) are flagged for review. Batsy the bat has wings by one rule and none by the mammal rule. Falco, Opus and Nemo are clear-cut.
For Tweety:
bird('tweety').penguin('tweety').For Falco:
59 steps were verified against the program. Verdict: checked_with_obligations.
The 7 obligations are all of the kind called absent, one for each “not
found” the decisions rely on, such as:
obligation('absent', 'theory_scoped', ~flies('falco', 'false'))
peye concluded that nothing says Falco cannot fly because it searched everything it knows and found nothing. The checker records each such absence rather than proving it, and confirmed that no step in the proof contradicts any of them.
python -m peye examples/paraconsistent-animals.py # the answers
python -m peye --proof examples/paraconsistent-animals.py # answers with their proof
Or open it in the playground.
Delete the line fact(observed('mythic', 'flies', 'false')) and run again: the
conflict disappears, and you get flies_safely('mythic', 'true') and
moves_by('mythic', 'flying').
Contradictions in data are not a reason to give up or to guess. Kept local and labelled, they become a to-do list for a human, while everything that is clear-cut still gets decided.