Core Concepts¶
Understanding the fundamentals of fuzzy logic and inference.
Fuzzy Logic Basics¶
Degrees of Truth¶
Unlike classical logic where statements are either true (1) or false (0), fuzzy logic allows degrees of truth between 0.0 and 1.0:
Real-World Example¶
Consider classifying someone's height:
from fuzzy_infer import fuzzy
kb = fuzzy()
# John is 5'10" (178cm)
kb.fact("height", ["john", 178])
# Fuzzy classification rules
kb.rule(
when=("height", "?person", "?h"),
then=("is-tall", "?person", degree="(?h - 150) / 50"),
where=lambda b: b["?h"] > 175
)
kb.rule(
when=("height", "?person", "?h"),
then=("is-medium", "?person", degree="1.0 - abs(?h - 170) / 20"),
where=lambda b: 160 <= b["?h"] <= 180
)
Facts¶
Facts are the building blocks of knowledge:
from fuzzy_infer import Fact
# Creating facts
fact1 = Fact("is-bird", ["robin"], degree=0.9)
fact2 = Fact("can-fly", ["robin"], degree=0.8)
# Facts have three components:
# 1. Predicate: what we're asserting ("is-bird")
# 2. Arguments: what it applies to (["robin"])
# 3. Degree: how true it is (0.9)
Rules¶
Rules encode if-then relationships:
from fuzzy_infer import Rule, Condition, Action
# Simple rule: birds can fly
rule = Rule(
conditions=[Condition("is-bird", ["?x"])],
actions=[Action("add", {"pred": "can-fly", "args": ["?x"], "degree": 0.85})],
name="bird-flight"
)
# Using fluent API (much cleaner!)
kb.rule(
when=("is-bird", "?x"),
then=("can-fly", "?x", 0.85),
name="bird-flight"
)
Pattern Variables¶
Variables (prefixed with ?) match any value:
# ?x matches any animal
kb.rule(
when=("is-mammal", "?x"),
then=("is-warm-blooded", "?x")
)
# Multiple variables
kb.rule(
when=[("parent", "?x", "?y"), ("parent", "?y", "?z")],
then=("grandparent", "?x", "?z")
)
# Constraints on variables
kb.rule(
when=("age", "?person", "?age"),
then=("is-adult", "?person"),
where=lambda b: b["?age"] >= 18
)
Forward Chaining¶
FuzzyInfer uses forward chaining (data-driven inference):
graph LR
A[Initial Facts] --> B[Apply Rules]
B --> C[Generate New Facts]
C --> D{New Facts?}
D -->|Yes| B
D -->|No| E[Complete]
Inference Process¶
- Start with initial facts
- Find rules whose conditions match
- Execute rule actions (add new facts)
- Repeat until no new facts generated
# Initial facts
kb.fact("is-bird", ["robin"])
kb.fact("is-bird", ["eagle"])
# Rule
kb.rule(
when=("is-bird", "?x"),
then=("can-fly", "?x")
)
# Before inference
print(kb.query("can-fly")) # []
# Run inference
kb.infer()
# After inference
print(kb.query("can-fly")) # [robin, eagle]
Fuzzy Operations¶
Fuzzy AND (T-norms)¶
When multiple conditions must be met:
# Minimum (default)
kb.rule(
when=[
("condition-a", "?x", degree=0.8),
("condition-b", "?x", degree=0.6)
],
then=("result", "?x"), # degree = min(0.8, 0.6) = 0.6
fuzzy_and="min"
)
# Product
kb.rule(
when=[("a", "?x"), ("b", "?x")],
then=("result", "?x"), # degree = 0.8 * 0.6 = 0.48
fuzzy_and="product"
)
Fuzzy OR (T-conorms)¶
When any condition is sufficient:
# Maximum (default)
kb.rule(
when_any=[
("option-a", "?x", degree=0.7),
("option-b", "?x", degree=0.9)
],
then=("selected", "?x"), # degree = max(0.7, 0.9) = 0.9
fuzzy_or="max"
)
Fuzzy NOT¶
Negation in fuzzy logic:
# Standard negation
kb.rule(
when=("is-cold", "?x", degree="?d"),
then=("is-warm", "?x", degree="1.0 - ?d")
)
Degree Arithmetic¶
Compute degrees dynamically:
# Degree variables
kb.rule(
when=("probability", "?event", degree="?p"),
then=("unlikely", "?event", degree="1.0 - ?p")
)
# Complex calculations
kb.rule(
when=[
("feature-a", "?x", degree="?a"),
("feature-b", "?x", degree="?b")
],
then=("combined", "?x", degree="(?a + ?b) / 2") # Average
)
# Hedges (linguistic modifiers)
kb.rule(
when=("tall", "?x", degree="?d"),
then=("very-tall", "?x", degree="?d * ?d") # Square for "very"
)
Conflict Resolution¶
When multiple rules could fire:
Priority-Based¶
# Higher priority rules fire first
kb.rule(
when=("emergency", "?x"),
then=("handle", "?x"),
priority=10 # High priority
)
kb.rule(
when=("request", "?x"),
then=("handle", "?x"),
priority=1 # Low priority
)
Specificity-Based¶
More specific rules override general ones:
# General rule
kb.rule(
when=("is-bird", "?x"),
then=("can-fly", "?x", 0.9)
)
# Specific exception
kb.rule(
when=[("is-bird", "?x"), ("is-penguin", "?x")],
then=("can-fly", "?x", 0.0), # Penguins can't fly
priority=5 # Higher priority
)
Knowledge Base¶
The knowledge base stores facts and rules:
from fuzzy_infer import FuzzyInfer
# Create knowledge base
kb = FuzzyInfer()
# Add facts
kb.add_fact(Fact("is-mammal", ["dog"]))
kb.add_facts([
Fact("is-mammal", ["cat"]),
Fact("is-bird", ["robin"])
])
# Add rules
kb.add_rule(rule)
# Query facts
mammals = kb.query("is-mammal") # Returns all mammals
specific = kb.query("is-mammal", ["dog"]) # Check specific
# Run inference
result = kb.run() # Returns InferenceResult
print(f"Generated {result.facts_added} new facts")
JSONL Serialization¶
FuzzyInfer uses JSON Lines for interoperability:
{"type": "fact", "pred": "is-bird", "args": ["robin"], "degree": 0.9}
{"type": "rule", "name": "fly", "when": [{"pred": "is-bird", "args": ["?x"]}], "then": [{"action": "add", "pred": "can-fly", "args": ["?x"]}]}
This enables Unix-style pipelines:
# Chain with other tools
cat facts.jsonl |
fuzzy-infer run rules.jsonl |
jq 'select(.pred == "can-fly")' |
sort -t'"' -k8 -rn # Sort by degree
Performance Considerations¶
Fact Storage¶
- Facts indexed by
(predicate, arguments) - O(1) lookup for specific facts
- O(n) for pattern matching
Rule Matching¶
- Forward chaining is exhaustive
- Each iteration checks all rules
- Complexity: O(rules × facts)
Optimization Tips¶
- Use specific patterns: More constraints = faster matching
- Order rules by frequency: Common rules first
- Limit inference depth: Set max iterations
- Stream processing: Process in chunks for large datasets
Next Steps¶
- Explore the Fluent API for elegant rule composition
- Learn about Unix CLI for pipeline integration
- See practical Examples