Core Concepts¶
FuzzyInfer extends classical rule-based inference with fuzzy logic, enabling reasoning with uncertainty and degrees of belief.
Facts¶
Facts represent knowledge with associated degrees of belief (certainty). Unlike classical logic where facts are either true or false, fuzzy facts have a degree of membership between 0.0 and 1.0.
Structure¶
A fact consists of three components:
- Predicate: The property or relationship (e.g.,
is-mammal,temperature) - Arguments: One or more values (e.g.,
["dog"],["room-1", "hot"]) - Degree: Confidence level from 0.0 (completely uncertain) to 1.0 (completely certain)
Examples¶
from fuzzy_infer import Fact
# Tweety is a bird with 90% certainty
Fact("is-bird", ["tweety"], 0.9)
# Room temperature is hot with 75% confidence
Fact("temperature", ["living-room", "hot"], 0.75)
# Alice is tall (100% certain by default)
Fact("is-tall", ["alice"], 1.0)
Why Degrees Matter¶
Real-world knowledge is rarely absolute:
- Sensor readings: Temperature sensor reads 78°F → "hot" with degree 0.6
- Classifications: A platypus is a mammal with degree 0.95 (it's unusual!)
- Predictions: It will rain tomorrow with confidence 0.7
- Subjective properties: Alice is tall with degree 0.8 (depends on context)
Rules¶
Rules define inference patterns that derive new facts from existing ones. They embody domain knowledge and reasoning strategies.
Structure¶
A rule contains:
- Name: Identifier for the rule (optional but recommended)
- Conditions: One or more patterns that must match existing facts
- Actions: Operations to perform when conditions are satisfied
- Priority: Execution order (higher priority rules fire first)
Pattern Variables¶
Rules use variables (prefixed with ?) to match multiple facts:
from fuzzy_infer import Rule
# If ?x is a bird, then ?x can fly
Rule(
name="birds-can-fly",
conditions=[
{"pred": "is-bird", "args": ["?x"]}
],
actions=[
{"action": "add", "fact": {"pred": "can-fly", "args": ["?x"], "deg": 0.9}}
]
)
This single rule applies to all birds: if is-bird(tweety), is-bird(robin), and is-bird(eagle) exist, it infers can-fly for each.
Degree Constraints¶
Add constraints on degrees for more precise rules:
# Only classify as mammal if certainty > 70%
Rule(
name="confident-mammals",
conditions=[
{
"pred": "is-mammal",
"args": ["?x"],
"deg": "?d",
"deg-pred": [">", "?d", 0.7] # Constraint: degree > 0.7
}
],
actions=[
{"action": "add", "fact": {"pred": "warm-blooded", "args": ["?x"], "deg": "?d"}}
]
)
Degree Calculations¶
Perform arithmetic on degrees:
# Multiply degrees (conjunction)
{"deg": ["*", "?d", 0.9]}
# Minimum of two degrees (fuzzy AND)
{"deg": ["min", "?d1", "?d2"]}
# Maximum (fuzzy OR)
{"deg": ["max", "?d1", "?d2"]}
# Arithmetic combinations
{"deg": ["+", ["*", "?d", 0.5], 0.3]}
Multiple Conditions¶
Rules can have multiple conditions (implicitly AND'ed):
Rule(
name="flying-birds",
conditions=[
{"pred": "is-bird", "args": ["?x"], "deg": "?d1"},
{"pred": "has-wings", "args": ["?x"], "deg": "?d2"},
{"deg-pred": [">", ["min", "?d1", "?d2"], 0.5]}
],
actions=[
{"action": "add", "fact": {"pred": "can-fly", "args": ["?x"],
"deg": ["*", ["min", "?d1", "?d2"], 0.85]}}
]
)
Inference Engine¶
The FuzzyInfer engine performs forward-chaining inference, automatically deriving new facts from rules.
Forward Chaining¶
The inference process:
- Match: Find all rule conditions that match current facts
- Fire: Execute actions for matched rules (respecting priority)
- Update: Add new facts to the knowledge base
- Repeat: Continue until no new facts are generated (fixpoint reached)
from fuzzy_infer import FuzzyInfer
# Create engine
inf = FuzzyInfer()
# Add initial facts
inf.add_fact(Fact("is-bird", ["tweety"], 0.9))
inf.add_fact(Fact("has-wings", ["tweety"], 1.0))
# Add rules
inf.add_rule(birds_fly_rule)
# Run inference
inf.run() # Derives: can-fly(tweety, 0.765)
# Query results
results = inf.query("can-fly", ["tweety"])
print(results)
Iteration Limits¶
To prevent infinite loops, inference stops after a maximum number of iterations (default: 100):
Fuzzy Logic Operations¶
Fuzzy AND (T-norms)¶
Combine multiple conditions using minimum (conservative):
Fuzzy OR (T-conorms)¶
When multiple rules derive the same fact, use maximum (optimistic):
# Rule 1 infers can-fly(tweety, 0.8)
# Rule 2 infers can-fly(tweety, 0.7)
# Result: can-fly(tweety, 0.8) ← maximum
FuzzyInfer automatically applies fuzzy OR when adding duplicate facts.
Fuzzy NOT¶
Negation is computed as complement:
Pattern Matching¶
Variables in conditions bind to concrete values:
# Pattern: parent(?x, ?y) AND parent(?y, ?z)
# Binds: ?x → "alice", ?y → "bob", ?z → "charlie"
# Infers: grandparent("alice", "charlie")
Example: Transitivity¶
Rule(
name="grandparent",
conditions=[
{"pred": "parent", "args": ["?x", "?y"]},
{"pred": "parent", "args": ["?y", "?z"]}
],
actions=[
{"action": "add", "fact": {"pred": "grandparent", "args": ["?x", "?z"]}}
]
)
# Given:
# parent(alice, bob)
# parent(bob, charlie)
# Infers:
# grandparent(alice, charlie)
Knowledge Base¶
The knowledge base stores all facts and rules:
inf = FuzzyInfer()
# Facts storage: {(predicate, tuple(args)) → Fact}
inf.add_fact(Fact("is-bird", ["robin"], 0.9))
# Rules storage: list sorted by priority
inf.add_rule(rule1) # priority=100
inf.add_rule(rule2) # priority=50
Fact Deduplication¶
When adding a fact that already exists, FuzzyInfer applies fuzzy OR (maximum):
inf.add_fact(Fact("is-bird", ["robin"], 0.8))
inf.add_fact(Fact("is-bird", ["robin"], 0.9))
# Result: is-bird(robin, 0.9) ← max(0.8, 0.9)
Querying¶
Retrieve facts from the knowledge base:
# Query all birds
birds = inf.query("is-bird")
# Query specific animal
robin_facts = inf.query("is-bird", ["robin"])
# Check if fact exists
if inf.query("can-fly", ["tweety"]):
print("Tweety can fly!")
Actions¶
Rules can perform three types of actions:
Add Facts¶
Most common action - add new derived facts:
Modify Facts¶
Update existing fact degrees:
Retract Facts¶
Remove facts from the knowledge base:
Practical Examples¶
Animal Classification¶
from fuzzy_infer import FuzzyInfer, Fact, Rule
inf = FuzzyInfer()
# Add observations
inf.add_fact(Fact("has-fur", ["dog"], 1.0))
inf.add_fact(Fact("barks", ["dog"], 0.95))
inf.add_fact(Fact("has-four-legs", ["dog"], 1.0))
# Add classification rules
inf.add_rule(Rule(
name="mammal-rule",
conditions=[
{"pred": "has-fur", "args": ["?x"]},
{"pred": "has-four-legs", "args": ["?x"]}
],
actions=[
{"action": "add", "fact": {"pred": "is-mammal", "args": ["?x"], "deg": 0.95}}
]
))
inf.add_rule(Rule(
name="dog-rule",
conditions=[
{"pred": "is-mammal", "args": ["?x"]},
{"pred": "barks", "args": ["?x"], "deg": "?d"},
{"deg-pred": [">", "?d", 0.7]}
],
actions=[
{"action": "add", "fact": {"pred": "is-dog", "args": ["?x"], "deg": 0.9}}
]
))
# Run inference
inf.run()
# Query results
print(inf.query("is-mammal", ["dog"])) # [Fact(is-mammal, [dog], 0.95)]
print(inf.query("is-dog", ["dog"])) # [Fact(is-dog, [dog], 0.855)]
Temperature Control¶
# Smart home temperature regulation
inf = FuzzyInfer()
# Sensor readings
inf.add_fact(Fact("temperature", ["living-room"], 0.85)) # 85% hot
inf.add_fact(Fact("occupancy", ["living-room"], 0.9)) # 90% occupied
# Control rule
inf.add_rule(Rule(
name="ac-control",
conditions=[
{"pred": "temperature", "args": ["?room"], "deg": "?temp"},
{"pred": "occupancy", "args": ["?room"], "deg": "?occ"},
{"deg-pred": [">", "?temp", 0.7]},
{"deg-pred": [">", "?occ", 0.5]}
],
actions=[
{"action": "add", "fact": {"pred": "ac-on", "args": ["?room"],
"deg": ["min", "?temp", "?occ"]}}
]
))
inf.run()
print(inf.query("ac-on")) # [Fact(ac-on, [living-room], 0.85)]
Best Practices¶
1. Use Meaningful Predicates¶
# Good: descriptive predicates
Fact("is-mammal", ["dog"], 0.9)
Fact("temperature-celsius", ["room-1", 25], 1.0)
# Avoid: cryptic names
Fact("m", ["d"], 0.9)
Fact("t1", ["r1", 25], 1.0)
2. Set Appropriate Degrees¶
# Good: reflects actual uncertainty
Fact("sensor-reading", ["temp-01"], 0.8) # Sensor confidence
Fact("prediction", ["rain-tomorrow"], 0.6) # Weather uncertainty
# Avoid: arbitrary degrees
Fact("is-dog", ["fido"], 0.567) # Too precise without reason
3. Use Rule Priorities¶
# Exception rules should have higher priority
Rule(name="general-rule", priority=50, ...) # General case
Rule(name="exception-rule", priority=100, ...) # Special case
4. Add Degree Constraints¶
# Good: only fire rule for high-confidence facts
{"deg-pred": [">", "?d", 0.7]}
# Avoid: processing low-confidence data unnecessarily
5. Name Your Rules¶
# Good: named rules are easier to debug
Rule(name="birds-fly", ...)
# Avoid: anonymous rules in complex systems
Rule(conditions=..., actions=...)
Summary¶
- Facts represent knowledge with degrees of belief (0.0 to 1.0)
- Rules define inference patterns with conditions and actions
- Variables (e.g.,
?x) enable pattern matching across multiple facts - Forward chaining automatically derives new knowledge
- Fuzzy operations handle uncertainty: AND (min), OR (max), NOT (1 - x)
- Degrees can be calculated using arithmetic expressions
- Priority controls rule execution order
Next: Inference Engine - Deep dive into how inference works