Abduction is inference to the best explanation. Given an observation O, abduction finds hypotheses H such that if H were true, O would be explained. Unlike deduction (proving what must be true), abduction asks "what could explain this?"
The Three Modes of Inference:
| Deduction: | Rule + Case → Result | "All men are mortal. Socrates is a man. ∴ Socrates is mortal." |
| Induction: | Case + Result → Rule | "Socrates is mortal. Socrates is a man. ∴ All men are mortal." |
| Abduction: | Rule + Result → Case | "All men are mortal. Socrates is mortal. ∴ Socrates is a man." |
Formal Definition:
A hypothesis H is a valid explanation if:
Fallacy Warning: Abduction is not logically valid! "If it rains, the ground is wet" + "The ground is wet" does NOT prove it rained (sprinklers exist). Abduction finds possible explanations, not certain ones.
Bayesian Formulation:
The probability of hypothesis H given observation O depends on:
| Scoring Factor | Description | Weight |
|---|---|---|
| Rule confidence | Strength of the explanatory rule | 0.35 |
| Prior probability | Base rate of hypothesis being true | 0.25 |
| Explanatory coverage | Fraction of observations explained | 0.25 |
| Simplicity | Fewer assumptions preferred (Occam) | 0.15 |
Observation: isA Socrates Mortal
Rule: @r1 Implies (isA ?x Human) (isA ?x Mortal)
Hypothesis: isA Socrates Human
Observations:
- hasSymptom Patient123 Fever
- hasSymptom Patient123 Cough
- hasSymptom Patient123 Fatigue
Hypothesis: hasDiagnosis Patient123 Influenza
(Explains all three symptoms via known rules)
Observations:
- The grass is wet
- The sidewalk is dry
H₁ (rain) would wet both → Rejected
H₂ (sprinklers) only wet grass → Accepted
function abduceMultiple(observations, kb):
// Find hypotheses that explain ALL observations
candidateSets = []
for each H that could explain observations[0]:
remaining = observations.slice(1)
if all remaining are explained by H or derivable from kb ∪ {H}:
candidateSets.push({H})
else:
// Try combining hypotheses
for each H2 that could explain remaining[0]:
combined = {H, H2}
if all observations explained by kb ∪ combined:
if consistent(combined, kb):
candidateSets.push(combined)
// Rank by parsimony: prefer smaller sets
return sortBySize(candidateSets)
@r1 Implies (hasDiagnosis ?p Flu) (hasSymptom ?p Fever)
@r2 Implies (hasDiagnosis ?p Flu) (hasSymptom ?p Cough)
@r3 Implies (hasDiagnosis ?p Flu) (hasSymptom ?p Fatigue)
@r4 Implies (hasDiagnosis ?p Cold) (hasSymptom ?p Cough)
@r5 Implies (hasDiagnosis ?p Cold) (hasSymptom ?p Sneezing)
@r6 Implies (hasDiagnosis ?p Allergy) (hasSymptom ?p Sneezing)
Observations:
hasSymptom Patient1 Fever
hasSymptom Patient1 Cough
hasSymptom Patient1 Fatigue
Abduction Result:
Hypotheses:
1. hasDiagnosis Patient1 Flu
- Explains: Fever ✓, Cough ✓, Fatigue ✓
- Coverage: 100%
- Score: 0.92
2. And (hasDiagnosis Patient1 Cold) (unknown-cause Fever)
- Explains: Cough ✓ (partial)
- Coverage: 33%
- Score: 0.35
Confidence Propagation:
The confidence in a hypothesis depends on how well it explains observations, the strength of the rules used, and prior plausibility.
| Confidence Level | Interpretation | Action |
|---|---|---|
| 0.9 - 1.0 | Strong explanation | Accept hypothesis |
| 0.7 - 0.9 | Likely explanation | Consider accepting |
| 0.5 - 0.7 | Possible explanation | Seek more evidence |
| < 0.5 | Weak explanation | Explore alternatives |
import { AbductionEngine } from 'agisystem2/reasoning';
const engine = new AbductionEngine(session);
// Simple abduction
const hypotheses = await engine.abduce({
operator: 'hasSymptom',
args: ['Patient1', 'Fever']
});
// Multiple observations
const hypotheses = await engine.abduceMultiple([
{ operator: 'hasSymptom', args: ['Patient1', 'Fever'] },
{ operator: 'hasSymptom', args: ['Patient1', 'Cough'] }
]);
// With options
const hypotheses = await engine.abduce(observation, {
maxHypotheses: 5, // Limit results
minConfidence: 0.5, // Filter weak hypotheses
requireCoverage: 0.8, // Minimum explanation coverage
checkConsistency: true // Verify consistency with KB
});