rust_fuzzylogic/rulespace.rs
1#![deprecated(since = "0.2.0", note = "Use system::System and SystemBuilder instead")]
2//! Deprecated: RuleSpace has been superseded by `system::System` and
3//! `system::SystemBuilder`.
4//!
5//! As of 0.2.0, prefer building fuzzy inference systems via the `System`
6//! API, which validates rules on construction and provides a cohesive
7//! builder for variables, terms, and rules.
8//!
9//! This module remains for backward compatibility and will be removed in a
10//! future release.
11//!
12
13//! RuleSpace: orchestrate aggregation and defuzzification for a rule base.
14//!
15//! `RuleSpace` bundles the fuzzy variables, rule set, and the intermediate
16//! aggregated membership values produced during inference. It provides a
17//! convenience API to:
18//! - construct a rule space from variables and rules (`new`),
19//! - append additional rules (`add_rules`),
20//! - run aggregation only (`aggregate`), and
21//! - run aggregation followed by defuzzification in one call (`defuzzify`).
22//!
23//! Typical flow
24//! 1) Define input/output variables and their terms.
25//! 2) Build rules from antecedents and consequents.
26//! 3) Create a `RuleSpace` and call `defuzzify` with crisp inputs and a sampler.
27//!
28//! Example
29//! ```rust
30//! use std::collections::HashMap;
31//! use rust_fuzzylogic::prelude::*;
32//! use rust_fuzzylogic::membership::triangular::Triangular;
33//! use rust_fuzzylogic::term::Term;
34//! use rust_fuzzylogic::variable::Variable;
35//! use rust_fuzzylogic::antecedent::Antecedent;
36//! use rust_fuzzylogic::mamdani::{Rule, Consequent};
37//! use rust_fuzzylogic::rulespace::RuleSpace;
38//!
39//! // Variables
40//! let mut temp = Variable::new(-10.0, 10.0).unwrap();
41//! temp.insert_term("hot", Term::new("hot", Triangular::new(0.0, 5.0, 10.0).unwrap())).unwrap();
42//! let mut fan = Variable::new(0.0, 10.0).unwrap();
43//! fan.insert_term("high", Term::new("high", Triangular::new(5.0, 7.5, 10.0).unwrap())).unwrap();
44//!
45//! let mut vars: HashMap<String, Variable> = HashMap::new();
46//! vars.insert("temp".into(), temp);
47//! vars.insert("fan".into(), fan);
48//!
49//! // Rule: IF temp IS hot THEN fan IS high
50//! let rules = vec![Rule{
51//! antecedent: Antecedent::Atom{ var: "temp".into(), term: "hot".into() },
52//! consequent: vec![Consequent{ var: "fan".into(), term: "high".into() }],
53//! }];
54//!
55//! let sampler = UniformSampler::default();
56//! let mut rs = RuleSpace::new(vars, rules).unwrap();
57//! let mut input: HashMap<&str, Float> = HashMap::new();
58//! input.insert("temp", 7.5);
59//!
60//! // One-shot aggregate + defuzzify
61//! let crisp = rs.defuzzify(&input, &sampler).unwrap();
62//! assert!(crisp["fan"] >= 0.0 && crisp["fan"] <= 10.0);
63//! ```
64use std::{borrow::Borrow, collections::HashMap, hash::Hash};
65
66use crate::{
67 aggregate::aggregation,
68 defuzz::defuzzification,
69 error::{self, FuzzyError},
70 mamdani::Rule,
71 sampler::UniformSampler,
72 variable::Variable,
73 Float,
74};
75
76/// Container for fuzzy variables, rules, and intermediate membership data.
77///
78/// Internally, `RuleSpace` stores:
79/// - `vars`: the set of named input/output variables.
80/// - `rules`: the rule base defining inference behavior.
81/// - `agg_memberships`: aggregated membership samples per output variable from
82/// the most recent call to `aggregate`/`defuzzify`.
83#[deprecated(since = "0.2.0", note = "Use system::System and SystemBuilder instead")]
84pub struct RuleSpace {
85 vars: HashMap<String, Variable>,
86 agg_memberships: HashMap<String, Vec<Float>>,
87 rules: Vec<Rule>,
88}
89
90impl RuleSpace {
91 /// Create a rule space with the supplied variables and rules.
92 ///
93 /// Errors
94 /// - `FuzzyError::EmptyInput` if `vars` or `rules` is empty.
95 #[deprecated(since = "0.2.0", note = "Use system::System and SystemBuilder instead")]
96 pub fn new(vars: HashMap<String, Variable>, rules: Vec<Rule>) -> error::Result<Self> {
97 if vars.is_empty() || rules.is_empty() {
98 return Err(FuzzyError::EmptyInput);
99 } else {
100 return Ok(Self {
101 vars: vars,
102 agg_memberships: HashMap::new(),
103 rules: rules,
104 });
105 }
106 }
107
108 /// Append additional rules to the existing rule set.
109 ///
110 /// Returns a mutable reference to `self` upon success.
111 ///
112 /// Errors
113 /// - `FuzzyError::EmptyInput` if `rules` is empty.
114 #[deprecated(since = "0.2.0", note = "Use system::System and SystemBuilder instead")]
115 pub fn add_rules(&mut self, rules: &mut Vec<Rule>) -> error::Result<&mut Self> {
116 if rules.is_empty() {
117 Err(FuzzyError::EmptyInput)
118 } else {
119 let _ = &mut self.rules.append(rules);
120 return Ok(self);
121 }
122 }
123
124 /// Run the aggregation step for all rules with the provided crisp inputs.
125 ///
126 /// This populates `agg_memberships` with a sample vector for each output
127 /// variable. Use `defuzzify` if you want crisp outputs in a single call.
128 ///
129 /// Type parameters
130 /// - `KI`: key type for `input`, must borrow as `str`.
131 ///
132 /// Errors
133 /// - Propagates errors from rule activation/implication and aggregation.
134 #[deprecated(since = "0.2.0", note = "Use system::System and SystemBuilder instead")]
135 pub fn aggregate<KI>(
136 &mut self,
137 input: &HashMap<KI, Float>,
138 sampler: &UniformSampler,
139 ) -> error::Result<()>
140 where
141 KI: Eq + Hash + Borrow<str>,
142 {
143 //let rules = std::mem::take(&mut self.rules);
144 let agg_memberships = aggregation(&self.rules, input, &self.vars, sampler)?;
145 self.agg_memberships = agg_memberships;
146
147 Ok(())
148 }
149
150 /// Aggregate and then defuzzify each output variable using the supplied sampler.
151 ///
152 /// Combines `aggregate` and `defuzzification` to return crisp values for
153 /// all output variables in a single call.
154 ///
155 /// Type parameters
156 /// - `KI`: key type for `input`, must borrow as `str`.
157 ///
158 /// Errors
159 /// - Propagates any error from aggregation or defuzzification.
160 #[deprecated(since = "0.2.0", note = "Use system::System and SystemBuilder instead")]
161 pub fn defuzzify<KI>(
162 &mut self,
163 input: &HashMap<KI, Float>,
164 sampler: &UniformSampler,
165 ) -> error::Result<HashMap<String, Float>>
166 where
167 KI: Eq + Hash + Borrow<str>,
168 {
169 let _ = self.aggregate(input, sampler)?;
170 //let agg_memberships = std::mem::take(&mut self.agg_memberships);
171 Ok(defuzzification(&self.agg_memberships, &self.vars)?)
172 }
173 //is there a nessecity?
174 //pub fn consequent_keys() {}
175}