Thanks to visit codestin.com
Credit goes to lib.rs

#control #inference #logic #fuzzy #mamdani

velvetry

A type-safe fuzzy logic control library for Rust

1 unstable release

Uses new Rust 2024

new 0.1.0 Jan 5, 2026

#494 in Algorithms

MIT license

51KB
957 lines

Fuzzy Control

A type-safe, production-ready fuzzy logic control library for Rust.

Features

  • Type-safe membership degrees: Enforces the [0, 1] constraint at the type level
  • Generic numeric types: Use f64, f32, or custom numeric types for both domain and membership values
  • Comprehensive membership functions: Triangular, Trapezoidal, Gaussian, and extensible
  • Mamdani inference: Complete implementation with configurable operators
  • Multiple defuzzification methods: Centroid, Bisector, Mean/Smallest/Largest of Maximum, Weighted Average
  • Flexible rule system: Support for AND/OR operators and rule weights
  • SVG visualization: Built-in plotting for membership functions, fuzzification, aggregation, and control surfaces
  • No external dependencies: Only requires num-traits for numeric abstractions

Installation

Add this to your Cargo.toml:

[dependencies]
fuzzy_control = "0.1.0"

Quick Start

use fuzzy_control::*;
use fuzzy_control::membership_functions::*;
use fuzzy_control::defuzzification::*;
use std::collections::HashMap;

fn main() -> Result<(), MembershipError> {
    // Create input variable: Temperature (0-100°C)
    let mut temperature = LinguisticVariable::new("temperature", (0.0, 100.0));
    
    temperature.add_set(FuzzySet::new(
        "cold",
        Box::new(Triangular::new(0.0, 0.0, 50.0)?)
    ));
    temperature.add_set(FuzzySet::new(
        "hot",
        Box::new(Triangular::new(50.0, 100.0, 100.0)?)
    ));
    
    // Create output variable: Fan Speed (0-100%)
    let mut fan_speed = LinguisticVariable::new("fan_speed", (0.0, 100.0));
    
    fan_speed.add_set(FuzzySet::new(
        "low",
        Box::new(Triangular::new(0.0, 0.0, 50.0)?)
    ));
    fan_speed.add_set(FuzzySet::new(
        "high",
        Box::new(Triangular::new(50.0, 100.0, 100.0)?)
    ));
    
    // Create rules
    let rules = vec![
        FuzzyRule::new(
            vec![Condition::new("temperature", "cold")],
            RuleOperator::And,
            vec![Consequent::new("fan_speed", "low")],
        ),
        FuzzyRule::new(
            vec![Condition::new("temperature", "hot")],
            RuleOperator::And,
            vec![Consequent::new("fan_speed", "high")],
        ),
    ];
    
    // Build controller
    let controller = FuzzyController::builder()
        .add_input(temperature)
        .add_output(fan_speed)
        .add_rules(rules)
        .build();
    
    // Evaluate with input
    let inputs = HashMap::from([("temperature".to_string(), 75.0)]);
    let outputs = controller.evaluate_centroid(&inputs)?;
    
    println!("Temperature: 75°C → Fan Speed: {:.1}%", outputs["fan_speed"]);
    
    Ok(())
}

Core Concepts

Membership Functions

Define how crisp values map to fuzzy membership degrees:

// Triangular membership function
let cold = Triangular::new(0.0, 0.0, 50.0)?;

// Trapezoidal for flat peaks
let comfortable = Trapezoidal::new(15.0, 20.0, 25.0, 30.0)?;

// Gaussian for smooth transitions
let warm = Gaussian::new(25.0, 5.0)?;

Linguistic Variables

Group fuzzy sets under a named variable:

let mut temperature = LinguisticVariable::new("temperature", (0.0, 100.0));
temperature.add_set(cold_set);
temperature.add_set(warm_set);
temperature.add_set(hot_set);

Fuzzy Rules

Express control logic in IF-THEN format:

// Simple rule
let rule = FuzzyRule::new(
    vec![Condition::new("temperature", "hot")],
    RuleOperator::And,
    vec![Consequent::new("fan_speed", "high")],
);

// Rule with multiple conditions
let rule = FuzzyRule::new(
    vec![
        Condition::new("temperature", "hot"),
        Condition::new("humidity", "high"),
    ],
    RuleOperator::And,
    vec![Consequent::new("fan_speed", "max")],
);

// Rule with weight
let rule = rule.with_weight(MembershipDegree::new(0.8)?);

Defuzzification

Convert fuzzy outputs to crisp values:

// Centroid (most common)
let defuzz = Centroid::new(200)?;
let outputs = controller.evaluate(&inputs, &defuzz)?;

// Or use the convenience method
let outputs = controller.evaluate_centroid(&inputs)?;

// Other methods available:
// - Bisector
// - MeanOfMaximum
// - SmallestOfMaximum
// - LargestOfMaximum
// - WeightedAverage

Visualization

Generate SVG visualizations for analysis and debugging:

use fuzzy_control::visualization::*;

// Plot membership functions
let svg = plot_membership_functions(&temperature, None)?;
std::fs::write("membership.svg", svg)?;

// Visualize fuzzification
let svg = plot_fuzzification(&temperature, 35.0, None)?;
std::fs::write("fuzzification.svg", svg)?;

// Show rule firing strengths
let inputs = HashMap::from([("temperature".to_string(), 35.0)]);
let svg = plot_rule_evaluation(&controller, &inputs, None)?;
std::fs::write("rules.svg", svg)?;

// Visualize output aggregation
let defuzz = Centroid::new(200)?;
let svg = plot_output_aggregation(
    &controller,
    "fan_speed",
    &inputs,
    &defuzz,
    None
)?;
std::fs::write("aggregation.svg", svg)?;

// Generate control surface (2-input systems)
let svg = plot_control_surface(
    &controller,
    "temperature",
    "humidity",
    "fan_speed",
    &defuzz,
    30,
    None
)?;
std::fs::write("surface.svg", svg)?;

Advanced Usage

Custom Numeric Types

Use different numeric types for domain and membership:

// f32 for memory efficiency
let controller = FuzzyController::<f32, f32>::builder()
    .add_input(temp)
    .build();

// Mix types: f64 domain, f32 membership
let controller = FuzzyController::<f64, f32>::builder()
    .add_input(temp)
    .build();

Custom Operators

Provide custom T-norms and S-norms:

use fuzzy_control::operators::*;

let controller = FuzzyController::builder()
    .with_t_norm(Box::new(ProductTNorm))
    .with_s_norm(Box::new(ProbabilisticSumSNorm))
    .add_input(temp)
    .build();

Batch Operations

Add multiple variables and rules at once:

let controller = FuzzyController::builder()
    .add_inputs(vec![temp, humidity, pressure])
    .add_outputs(vec![fan, heater, ventilation])
    .add_rules(vec![rule1, rule2, rule3])
    .build();

Examples

See the examples/ directory for complete examples:

  • temperature_control.rs - Simple temperature control system
  • hvac_system.rs - Multi-input HVAC controller
  • visualizations.rs - Generate all visualization types

Run examples with:

cargo run --example temperature_control
cargo run --example hvac_system
cargo run --example visualizations

Testing

Run the comprehensive test suite:

cargo test

Run tests with output:

cargo test -- --nocapture

Architecture

The library is organized into several modules:

  • Core types: MembershipDegree, Float trait
  • Membership functions: membership_functions module
  • Fuzzy sets: FuzzySet, LinguisticVariable
  • Rules: FuzzyRule, Condition, Consequent
  • Operators: TNorm, SNorm traits and implementations
  • Controller: FuzzyController and builder
  • Defuzzification: Multiple defuzzification methods
  • Visualization: SVG plotting utilities

Contributing

Contributions are welcome! Please feel free to submit pull requests or open issues.

License

This project is dual-licensed under MIT or Apache-2.0. You may choose either license.

References

  • Zadeh, L.A. (1965). "Fuzzy Sets". Information and Control.
  • Mamdani, E.H. (1974). "Application of fuzzy algorithms for control of simple dynamic plant"
  • Takagi, T. and Sugeno, M. (1985). "Fuzzy identification of systems"

Roadmap

  • Sugeno-style inference
  • Additional membership function types (Sigmoid, Bell, etc.)
  • Performance optimizations
  • Serialization support
  • WASM support for web applications

Dependencies

~145KB