A comprehensive Python library for designing and implementing fuzzy logic inference systems with support for both Mamdani and Sugeno methods.
- Multiple Membership Functions: Triangular, trapezoidal, Gaussian, and sigmoid functions for defining fuzzy sets
- Fuzzy Sets with Logical Operations: Support for AND, OR, and NOT operations on fuzzy sets
- Linguistic Variables: Define fuzzy variables with multiple fuzzy sets and automatic fuzzification
- Flexible Rule System: IF-THEN rules with support for multiple antecedents and consequents
- Dual Inference Engines:
- Mamdani: Traditional fuzzy logic with fuzzy consequents and full defuzzification
- Sugeno: Efficient inference with crisp consequents (constants or linear functions)
- Multiple Defuzzification Methods: Centroid, bisector, mean/smallest/largest of maximum (for Mamdani)
- Sugeno System Support: Both Order-0 (constant) and Order-1 (linear) consequent functions
- NumPy Integration: Efficient computation using NumPy arrays
pip install numpyThen copy the fuzzy_inference/ directory to your project.
from fuzzy_inference import FuzzyVariable, FuzzySet, FuzzyRule, FuzzySystem
from fuzzy_inference import triangular
# Create input variable
temperature = FuzzyVariable("temperature", 0, 100)
temperature.add_set(FuzzySet("cold", lambda x: triangular(x, 0, 0, 50)))
temperature.add_set(FuzzySet("hot", lambda x: triangular(x, 50, 100, 100)))
# Create output variable
fan_speed = FuzzyVariable("fan_speed", 0, 100)
fan_speed.add_set(FuzzySet("slow", lambda x: triangular(x, 0, 0, 50)))
fan_speed.add_set(FuzzySet("fast", lambda x: triangular(x, 50, 100, 100)))
# Create Mamdani system and add rules
system = FuzzySystem(system_type="mamdani") # or just FuzzySystem() - mamdani is default
system.add_input_variable(temperature)
system.add_output_variable(fan_speed)
system.add_rule(FuzzyRule(
{"temperature": temperature["cold"]},
{"fan_speed": fan_speed["slow"]}
))
system.add_rule(FuzzyRule(
{"temperature": temperature["hot"]},
{"fan_speed": fan_speed["fast"]}
))
# Perform inference
result = system.infer({"temperature": 75})
print(f"Fan speed: {result['fan_speed']:.2f}")from fuzzy_inference import FuzzyVariable, FuzzySet, SugenoRule, FuzzySystem
from fuzzy_inference import triangular
# Create input variable (same as Mamdani)
temperature = FuzzyVariable("temperature", 0, 100)
temperature.add_set(FuzzySet("cold", lambda x: triangular(x, 0, 0, 50)))
temperature.add_set(FuzzySet("hot", lambda x: triangular(x, 50, 100, 100)))
# Create output variable (only universe range needed)
fan_speed = FuzzyVariable("fan_speed", 0, 100)
# Create Sugeno system
system = FuzzySystem(system_type="sugeno")
system.add_input_variable(temperature)
system.add_output_variable(fan_speed)
# Order-0 Sugeno (constant consequents)
system.add_rule(SugenoRule(
{"temperature": temperature["cold"]},
{"fan_speed": 20} # Constant value
))
# Order-1 Sugeno (linear consequents)
system.add_rule(SugenoRule(
{"temperature": temperature["hot"]},
{"fan_speed": lambda inputs: 0.8 * inputs["temperature"] + 10} # Linear function
))
# Perform inference (uses weighted average, no defuzzification method needed)
result = system.infer({"temperature": 75})
print(f"Fan speed: {result['fan_speed']:.2f}")The fuzzy_inference library is organized into several key modules:
Membership functions define the degree to which a value belongs to a fuzzy set. All functions return values between 0 and 1.
Triangular membership function with linear slopes.
- Parameters:
x: Input value or NumPy arraya: Left foot (membership = 0)b: Peak (membership = 1)c: Right foot (membership = 0)
- Use case: General-purpose fuzzy sets, simple and intuitive
Trapezoidal membership function with a flat top region.
- Parameters:
x: Input value or NumPy arraya: Left foot (membership = 0)b: Left shoulder (membership = 1 starts)c: Right shoulder (membership = 1 ends)d: Right foot (membership = 0)
- Use case: Representing ranges where membership is fully true across a region
Gaussian (bell-shaped) membership function.
- Parameters:
x: Input value or NumPy arraymean: Center of the curvesigma: Standard deviation (controls width)
- Use case: Smooth, continuous membership with natural uncertainty representation
S-shaped sigmoid membership function.
- Parameters:
x: Input value or NumPy arraya: Slope parameter (positive for rising, negative for falling)c: Center point (inflection point)
- Use case: Representing gradual transitions, often used for "high" or "low" concepts
A FuzzySet represents a fuzzy set with a name and a membership function. It encapsulates the concept of partial membership.
from fuzzy_inference import FuzzySet, triangular
# Create a fuzzy set with a membership function
cold = FuzzySet("cold", lambda x: triangular(x, 0, 0, 50))# Get membership degree for a single value
degree = cold.membership(25) # Returns a value between 0 and 1
# Get membership for an array of values
import numpy as np
values = np.array([0, 10, 25, 40, 50])
degrees = cold.membership(values)Fuzzy sets support standard fuzzy logic operations:
cold = FuzzySet("cold", lambda x: triangular(x, 0, 0, 50))
warm = FuzzySet("warm", lambda x: triangular(x, 25, 50, 75))
# NOT operation (fuzzy complement)
not_cold = ~cold # membership(x) = 1 - cold.membership(x)
# OR operation (fuzzy union, uses max)
cold_or_warm = cold | warm # membership(x) = max(cold.membership(x), warm.membership(x))
# AND operation (fuzzy intersection, uses min)
# Note: Typically used implicitly in rule antecedentsA FuzzyVariable represents a linguistic variable—a variable that can take on fuzzy values described by linguistic terms (e.g., "cold", "warm", "hot" for temperature).
from fuzzy_inference import FuzzyVariable, FuzzySet, triangular
# Define the universe of discourse (min and max values)
temperature = FuzzyVariable("temperature", universe_min=0, universe_max=100)
# Add fuzzy sets (linguistic terms) to the variable
temperature.add_set(FuzzySet("cold", lambda x: triangular(x, 0, 0, 50)))
temperature.add_set(FuzzySet("warm", lambda x: triangular(x, 25, 50, 75)))
temperature.add_set(FuzzySet("hot", lambda x: triangular(x, 50, 100, 100)))Fuzzification converts a crisp (numeric) value into fuzzy membership degrees:
# Fuzzify a crisp value
memberships = temperature.fuzzify(60)
# Returns: {"cold": 0.0, "warm": 0.4, "hot": 0.6}
# Interpretation: The value 60 is 0% cold, 40% warm, and 60% hot# Access a specific fuzzy set by name
hot_set = temperature["hot"]
# Get the universe of discourse (array of values)
universe = temperature.universe # NumPy array from 0 to 100Rules define the IF-THEN logic of the fuzzy system. The antecedent (IF part) is always fuzzy, but the consequent (THEN part) differs between Mamdani and Sugeno systems.
Mamdani rules have fuzzy consequents:
from fuzzy_inference import FuzzyRule
# Single input, single output
rule = FuzzyRule(
antecedent={"temperature": temp["hot"]},
consequent={"fan_speed": speed["fast"]} # FuzzySet
)
# Multiple inputs (uses min for AND operation)
rule = FuzzyRule(
antecedent={"temperature": temp["hot"], "humidity": humid["high"]},
consequent={"fan_speed": speed["fast"]}
)Rule Evaluation Process:
- Fuzzification: Crisp inputs are converted to membership degrees
- Antecedent evaluation: Multiple antecedents are combined using min (AND)
- Implication: The output fuzzy set is clipped at the activation level
- Aggregation: Multiple rules are combined using max (OR)
- Defuzzification: The aggregated fuzzy output is converted to a crisp value
Sugeno rules have crisp function consequents (constants or linear functions):
from fuzzy_inference import SugenoRule
# Order-0 Sugeno (constant consequent)
rule = SugenoRule(
antecedent={"temperature": temp["hot"]},
consequent={"fan_speed": 80} # Constant value
)
# Order-1 Sugeno (linear function consequent)
rule = SugenoRule(
antecedent={"temperature": temp["hot"], "humidity": humid["high"]},
consequent={"fan_speed": lambda inputs: 0.5 * inputs["temperature"] + 0.3 * inputs["humidity"] + 10}
)Rule Evaluation Process:
- Fuzzification: Crisp inputs are converted to membership degrees
- Antecedent evaluation: Multiple antecedents are combined using min (AND)
- Consequent evaluation: The crisp function is evaluated with the inputs
- Weighted average: Output is the weighted average of all consequents, weighted by activation strengths
The FuzzySystem class is the main inference engine that coordinates the entire fuzzy logic process. It supports both Mamdani and Sugeno inference methods.
from fuzzy_inference import FuzzySystem
# Create a Mamdani system (default)
system = FuzzySystem(system_type="mamdani")
# Or create a Sugeno system
system = FuzzySystem(system_type="sugeno")# Add input variables
system.add_input_variable(temperature)
system.add_input_variable(humidity)
# Add output variables
system.add_output_variable(fan_speed)
# Add rules
system.add_rule(rule1)
system.add_rule(rule2)
# ... more rules
# Method chaining is supported
system.add_input_variable(temperature)\
.add_output_variable(fan_speed)\
.add_rule(rule1)\
.add_rule(rule2)Mamdani Inference:
# Perform inference with defuzzification method
output = system.infer(
inputs={"temperature": 75, "humidity": 60},
method="centroid" # or "bisector", "mom", "som", "lom"
)
# Returns: {"fan_speed": 65.3}Sugeno Inference:
# Perform inference (weighted average automatically used)
output = system.infer(
inputs={"temperature": 75, "humidity": 60}
)
# Returns: {"fan_speed": 67.8}# Get system representation
print(system)
# Output:
# FuzzySystem(
# type='mamdani',
# inputs=['temperature', 'humidity'],
# outputs=['fan_speed'],
# rules=9
# )Defuzzification converts the fuzzy output of a Mamdani system back into a crisp value. Different methods can produce different results depending on the shape of the aggregated output.
Calculates the center of area under the membership function curve.
- Formula:
Σ(x * μ(x)) / Σ(μ(x)) - Best for: Most applications; provides smooth, balanced output
- Characteristics: Computationally moderate, intuitive results
Finds the value that divides the area under the curve into two equal parts.
- Best for: When you need the median value
- Characteristics: Computationally moderate, less common
Returns the average of all values with maximum membership.
- Best for: When multiple peaks exist and you want a compromise
- Characteristics: Fast computation, can be unstable with flat tops
Returns the smallest value among those with maximum membership.
- Best for: Conservative control (prefer lower values)
- Characteristics: Very fast, biased toward lower values
Returns the largest value among those with maximum membership.
- Best for: Aggressive control (prefer higher values)
- Characteristics: Very fast, biased toward higher values
For Sugeno systems, defuzzification uses a weighted average of rule consequents:
- Formula:
Σ(activation_i * consequent_i) / Σ(activation_i) - Automatic: No method parameter needed
- Advantages: Computationally efficient, guaranteed continuity, well-suited for optimization
Understanding the differences between these two inference methods helps you choose the right approach for your application.
| Aspect | Mamdani | Sugeno |
|---|---|---|
| Consequent Type | Fuzzy sets (linguistic) | Constants (Order-0) or linear functions (Order-1) |
| Defuzzification | Required (centroid, bisector, etc.) | Weighted average (automatic) |
| Computational Cost | Higher (more operations) | Lower (simpler calculations) |
| Interpretability | Highly intuitive, human-readable | More mathematical, less intuitive |
| Output Surface | Complex, non-linear surfaces | Piecewise constant (Order-0) or linear (Order-1) |
| Rule Consequents | {"output": fuzzy_set} |
{"output": constant} or {"output": lambda ...} |
| Memory Usage | Higher (stores membership functions) | Lower (stores numbers/functions) |
| Best For | Expert systems, control, decision support | Optimization, adaptive learning, ANFIS |
| Learning Capability | Difficult to optimize | Easy to optimize (linear parameters) |
Choose Mamdani when:
- You need intuitive, human-interpretable rules ("IF temp is HOT THEN fan is FAST")
- Working with expert knowledge from domain experts
- Output requires complex, non-linear surfaces
- Interpretability is more important than computational speed
- Building control systems where operators need to understand the logic
Choose Sugeno when:
- Computational efficiency is critical (real-time systems)
- Working with mathematical models or data-driven approaches
- Using adaptive techniques (ANFIS, neuro-fuzzy, optimization)
- Need guaranteed continuity and smoothness in output
- Integrating with machine learning or optimization algorithms
- Working with embedded systems or resource-constrained environments
You can also combine both methods in a single application:
- Use Mamdani for high-level decision making (interpretability)
- Use Sugeno for low-level control (efficiency)
Understanding the inference process helps you design better fuzzy systems.
The Mamdani method follows these steps:
-
Fuzzification
- Convert crisp inputs to fuzzy membership degrees
- Example: Temperature 75°C → {cold: 0.0, warm: 0.5, hot: 0.5}
-
Rule Evaluation
- For each rule, evaluate the antecedent (IF part)
- Multiple antecedents are combined using min (AND operation)
- Example: IF temp is HOT (0.5) AND humidity is HIGH (0.7) → activation = min(0.5, 0.7) = 0.5
-
Implication
- Apply the activation strength to the consequent fuzzy set
- Uses clipping: membership is limited to the activation level
- Example: If activation = 0.5, "fan is FAST" membership is clipped at 0.5
-
Aggregation
- Combine outputs from all rules using max (OR operation)
- Creates a single aggregated fuzzy set for each output variable
- Example: max(rule1_output, rule2_output, rule3_output)
-
Defuzzification
- Convert the aggregated fuzzy output to a crisp value
- Uses methods like centroid, bisector, etc.
- Example: Aggregated fuzzy set → crisp value 65.3%
The Sugeno method is more streamlined:
-
Fuzzification
- Same as Mamdani: convert crisp inputs to membership degrees
-
Rule Evaluation
- Same as Mamdani: evaluate antecedents using min for AND
-
Consequent Evaluation
- Evaluate the crisp consequent function
- Order-0: Use constant value
- Order-1: Evaluate linear function with inputs
- Example: consequent = 0.5 * temp + 0.3 * humidity + 10
-
Weighted Average
- Combine all rule outputs using weighted average
- Weights are the rule activation strengths
- Formula:
output = Σ(activation_i * consequent_i) / Σ(activation_i) - Example: (0.5 * 80 + 0.7 * 65 + 0.3 * 50) / (0.5 + 0.7 + 0.3) = 67.8
- AND operation: Uses
min()for combining antecedents - OR operation: Uses
max()for aggregating rules (Mamdani only) - Universe of discourse: Automatically discretized to 1000 points for Mamdani
- No rule fires: Returns midpoint of output universe range
- NumPy arrays: All computations vectorized for performance
See the example files for complete demonstrations:
- example.py: Mamdani system for a tipping calculator
- example_sugeno.py: Sugeno systems (both Order-0 and Order-1) for fan speed control
- example_comparison.py: Side-by-side comparison of Mamdani and Sugeno systems
Run them with:
python example.py
python example_sugeno.py
python example_comparison.pyfuzzy_inference/
├── __init__.py # Package initialization
├── membership.py # Membership functions
├── fuzzyset.py # FuzzySet class
├── variable.py # FuzzyVariable class
├── rule.py # FuzzyRule and SugenoRule classes
└── system.py # FuzzySystem (Mamdani & Sugeno inference engines)
The fuzzy_inference library is suitable for a wide range of applications:
- HVAC control: Temperature and humidity regulation
- Motor speed control: Adaptive speed based on load and conditions
- Traffic light control: Dynamic timing based on traffic flow
- Home automation: Smart lighting, climate control
- Credit risk assessment: Evaluating loan applications
- Medical diagnosis: Assisting in disease identification
- Investment analysis: Portfolio management recommendations
- Tipping calculators: Service quality evaluation
- Quality control: Product classification and grading
- Process optimization: Manufacturing parameter tuning
- Fault diagnosis: Equipment health monitoring
- Energy management: Power distribution optimization
- Robot navigation: Obstacle avoidance and path planning
- Behavior arbitration: Multi-objective decision making
- Sensor fusion: Combining multiple sensor inputs
- Autonomous vehicles: Adaptive cruise control
- Pattern recognition: Image and signal classification
- Natural language processing: Sentiment analysis
- Game AI: Adaptive difficulty and NPC behavior
- Financial trading: Market analysis and strategy selection
-
Overlap is good: Adjacent fuzzy sets should overlap (typically 25-50%)
- Provides smooth transitions between linguistic terms
- Prevents discontinuities in the output
-
Cover the universe: Ensure the entire input range is covered
- Every possible input should have non-zero membership in at least one set
- Gaps can lead to unexpected behavior
-
Keep it simple: Start with 3-7 fuzzy sets per variable
- Too few: Loss of granularity
- Too many: Complexity without significant benefit
-
Use appropriate shapes:
- Triangular: General purpose, fast computation
- Trapezoidal: When a range should be "fully true"
- Gaussian: Smooth, natural uncertainty
- Sigmoid: Monotonic transitions (e.g., "low" to "high")
-
Completeness: Cover all important input combinations
- Missing rules can lead to poor performance
- Use domain knowledge to identify critical scenarios
-
Consistency: Avoid contradictory rules
- Rules with same antecedent should have compatible consequents
- Test edge cases to verify behavior
-
Start simple: Begin with a minimal rule set
- Add rules incrementally based on testing
- Every rule should serve a clear purpose
-
Choose the right inference method:
- Mamdani: When interpretability matters
- Sugeno: When efficiency and optimization matter
-
Normalize inputs: Keep inputs in reasonable ranges (e.g., 0-100)
- Makes rule design more intuitive
- Improves numerical stability
-
Test thoroughly: Validate with:
- Edge cases (min/max values)
- Typical operating conditions
- Boundary regions between fuzzy sets
-
Iterate and refine:
- Start with expert knowledge
- Refine based on real-world testing
- Consider tuning with data if available
-
For Mamdani systems:
- Use fewer universe discretization points if precision allows
- Prefer centroid defuzzification for most applications
- Consider Sugeno if speed is critical
-
For Sugeno systems:
- Use Order-0 (constants) when linear functions aren't needed
- Order-1 provides better approximation but is slightly slower
-
Rule optimization:
- Minimize the number of rules while maintaining performance
- Group similar rules when possible
from fuzzy_inference import (
# Membership functions
triangular, trapezoidal, gaussian, sigmoid,
# Core classes
FuzzySet, FuzzyVariable, FuzzyRule, SugenoRule, FuzzySystem
)# Membership function
mf = lambda x: triangular(x, 0, 50, 100)
# Fuzzy set
fs = FuzzySet("hot", lambda x: triangular(x, 50, 100, 100))
# Fuzzy variable
temp = FuzzyVariable("temperature", 0, 100)
temp.add_set(FuzzySet("cold", lambda x: triangular(x, 0, 0, 50)))
# Mamdani rule
rule = FuzzyRule(
{"temperature": temp["hot"]},
{"fan_speed": speed["fast"]}
)
# Sugeno rule (Order-0)
rule = SugenoRule(
{"temperature": temp["hot"]},
{"fan_speed": 80}
)
# Sugeno rule (Order-1)
rule = SugenoRule(
{"temperature": temp["hot"]},
{"fan_speed": lambda inputs: 0.8 * inputs["temperature"] + 10}
)
# Fuzzy system
system = FuzzySystem(system_type="mamdani") # or "sugeno"
system.add_input_variable(temp)
system.add_output_variable(speed)
system.add_rule(rule)
# Inference
result = system.infer({"temperature": 75}, method="centroid")# Fuzzify a value
memberships = temperature.fuzzify(65) # Returns dict of memberships
# Get membership degree
degree = fuzzy_set.membership(50) # Returns float
# Logical operations on sets
not_cold = ~cold_set
cold_or_warm = cold_set | warm_set
# Access fuzzy set by name
hot_set = temperature["hot"]Issue: System returns unexpected values
- Check: Ensure all input ranges are covered by fuzzy sets
- Check: Verify rules are complete and consistent
- Check: Test fuzzification:
variable.fuzzify(test_value)
Issue: Output always returns the midpoint
- Cause: No rules are firing (all activations are 0)
- Solution: Check that input values are within variable universe ranges
- Solution: Verify fuzzy sets overlap and cover the input range
Issue: Sugeno system gives different results than Mamdani
- This is normal: The two methods use different inference approaches
- Tip: Sugeno outputs are typically smoother and more continuous
- Tip: You can tune Sugeno consequents to approximate Mamdani behavior
Issue: Performance is slow with Mamdani
- Solution: Reduce the number of rules if possible
- Solution: Use simpler membership functions (triangular vs gaussian)
- Solution: Consider switching to Sugeno for better performance
- Solution: Cache repeated calculations if using the same inputs
Issue: TypeError when creating membership functions
- Check: Ensure you're passing a callable (lambda or function)
- Example:
FuzzySet("hot", lambda x: triangular(x, 50, 100, 100)) - Not:
FuzzySet("hot", triangular(x, 50, 100, 100))❌
Issue: Output is too sensitive to small input changes
- Solution: Increase overlap between fuzzy sets
- Solution: Use smoother membership functions (gaussian instead of triangular)
- Solution: For Mamdani, try different defuzzification methods
Contributions are welcome! Areas for enhancement:
- Additional membership functions (generalized bell, trapezoidal variants)
- Visualization tools for membership functions and inference
- Type-2 fuzzy logic support
- Additional defuzzification methods
- Performance optimizations
- More example applications
v0.1.0 - Initial release
- Mamdani and Sugeno inference engines
- Four membership functions
- Five defuzzification methods
- Complete rule system
MIT License