fuzzy_logic_rs/
fuzzy_inference_systems.rs

1use crate::aggregations::Aggregations;
2use crate::defuzzifications::{Defuzzifiers, TSKDefuzzifiers};
3use crate::implications::Implications;
4use crate::rules::{self, Rule};
5use crate::s_norms::SNorms;
6use crate::t_norms::TNorms;
7use crate::variables::{InputVariable, OutputVariable, TSKOutputVariable};
8
9#[derive(Debug)]
10pub struct MamdaniFuzzyInferenceSystem {
11    s_norm: SNorms,
12    t_norm: TNorms,
13    implication: Implications,
14    aggregation: Aggregations,
15    defuzzifier: Defuzzifiers,
16    rules: Vec<Rule>,
17    inputs: Vec<InputVariable>,
18    outputs: Vec<OutputVariable>,
19}
20
21pub type MamdaniFIS = MamdaniFuzzyInferenceSystem;
22
23impl MamdaniFuzzyInferenceSystem {
24    pub fn new(
25        s_norm: SNorms,
26        t_norm: TNorms,
27        implication: Implications,
28        aggregation: Aggregations,
29        defuzzifier: Defuzzifiers,
30    ) -> Self {
31        Self {
32            s_norm,
33            t_norm,
34            implication,
35            aggregation,
36            defuzzifier,
37            rules: Vec::new(),
38            inputs: Vec::new(),
39            outputs: Vec::new(),
40        }
41    }
42
43    pub fn new_all(
44        s_norm: SNorms,
45        t_norm: TNorms,
46        implication: Implications,
47        aggregation: Aggregations,
48        defuzzifier: Defuzzifiers,
49        rules: Vec<Rule>,
50        inputs: Vec<InputVariable>,
51        outputs: Vec<OutputVariable>,
52    ) -> Self {
53        Self {
54            s_norm,
55            t_norm,
56            implication,
57            aggregation,
58            defuzzifier,
59            rules,
60            inputs,
61            outputs,
62        }
63    }
64
65    pub fn add_input(&mut self, input: InputVariable) {
66        self.inputs.push(input);
67    }
68
69    pub fn add_output(&mut self, output: OutputVariable) {
70        self.outputs.push(output);
71    }
72
73    pub fn add_rule(&mut self, rule: Rule) {
74        self.rules.push(rule);
75    }
76
77    pub fn get_s_norm(&self, fuzzified: &[f64]) -> f64 {
78        self.s_norm.s_norm(fuzzified)
79    }
80
81    pub fn get_t_norm(&self, fuzzified: &[f64]) -> f64 {
82        self.t_norm.t_norm(fuzzified)
83    }
84
85    pub fn get_rules(&self, rule_index: usize) -> &[i32] {
86        self.rules[rule_index].get_rules()
87    }
88
89    pub fn get_input_rules(&self, rule_index: usize) -> &[i32] {
90        self.rules[rule_index].get_input_rules(self.inputs.len())
91    }
92
93    pub fn get_output_rules(&self, rule_index: usize) -> &[i32] {
94        self.rules[rule_index].get_output_rules(self.inputs.len())
95    }
96
97    pub fn fuzzification(&self, input_vec: Vec<f64>) -> Vec<Vec<f64>> {
98        let mut fuzzified: Vec<Vec<f64>> = Vec::new();
99        for i in 0..self.rules.len() {
100            let input_rule: &[i32] = self.get_input_rules(i);
101            let mut temp_vec: Vec<f64> = Vec::new();
102            for ii in 0..self.inputs.len() {
103                let index;
104                let complement;
105                if input_rule[ii] < 0 {
106                    index = (-input_rule[ii]) as usize;
107                    complement = true;
108                } else {
109                    index = input_rule[ii] as usize;
110                    complement = false;
111                }
112                let fuzzed: f64 = self.inputs[ii].fuzzify(index, input_vec[ii]);
113                temp_vec.push(match complement {
114                    true => 1.0 - fuzzed,
115                    false => fuzzed,
116                });
117                //temp_vec.push(self.inputs[ii].fuzzify(input_rule[ii] as usize, input_vec[ii]));
118            }
119            fuzzified.push(temp_vec);
120        }
121        fuzzified
122    }
123
124    pub fn connect_inputs(&self, fuzzified: Vec<Vec<f64>>) -> Vec<f64> {
125        fuzzified
126            .into_iter()
127            .zip(&self.rules)
128            .map(|(fuzz, rule)| match rule.get_kind() {
129                rules::Kind::OR => self.get_s_norm(&fuzz),
130                rules::Kind::AND => self.get_t_norm(&fuzz),
131            })
132            .collect()
133    }
134
135    pub fn weighed_inputs(&self, connected_inputs: Vec<f64>) -> Vec<f64> {
136        connected_inputs
137            .into_iter()
138            .zip(&self.rules)
139            .map(|(mu, rule)| rule.get_weight() * mu)
140            .collect()
141    }
142
143    pub fn implication(&self, connected_inputs: Vec<f64>) -> Vec<Vec<Vec<f64>>> {
144        let mut implication_vec = Vec::new();
145        for i in 0..self.outputs.len() {
146            let mut temp_vec = Vec::new();
147            for ii in 0..self.rules.len() {
148                let output_rule = self.get_output_rules(ii);
149                let index;
150                let complement;
151                if output_rule[i] < 0 {
152                    index = (-output_rule[i]) as usize;
153                    complement = true;
154                } else {
155                    index = output_rule[i] as usize;
156                    complement = false;
157                }
158                let range: Vec<f64> = self.outputs[i]
159                    .get_mu(index)
160                    .into_iter()
161                    .map(|e| if complement { 1.0 - e } else { e.to_owned() })
162                    .collect();
163
164                temp_vec.push(self.implication.implication(connected_inputs[ii], &range));
165            }
166            implication_vec.push(temp_vec);
167        }
168        implication_vec
169    }
170
171    pub fn aggregation(&self, implication_vec: Vec<Vec<Vec<f64>>>) -> Vec<Vec<f64>> {
172        implication_vec
173            .into_iter()
174            .map(|vec| self.aggregation.aggregation(&vec))
175            .collect()
176    }
177
178    pub fn defuzzification(&self, aggregation_vec: Vec<Vec<f64>>) -> Vec<f64> {
179        aggregation_vec
180            .into_iter()
181            .enumerate()
182            .map(|(index, aggregated)| {
183                self.defuzzifier
184                    .defuzzify(aggregated, self.outputs[index].get_universe())
185            })
186            .collect()
187    }
188
189    pub fn compute_outputs(&self, input_vec: Vec<f64>) -> Vec<f64> {
190        assert!(self.inputs.len() != 0, "You must add at least one INPUT");
191        assert!(self.outputs.len() != 0, "You must add at least one OUTPUT");
192        assert!(self.rules.len() != 0, "You must add at least one RULE");
193
194        // 1. fuzzification
195        let fuzzified = self.fuzzification(input_vec);
196        let connected_inputs = self.connect_inputs(fuzzified);
197        let weighted_inputs = self.weighed_inputs(connected_inputs);
198        // 2. implication
199        let implication_vec = self.implication(weighted_inputs);
200        // 3. aggregation
201        let aggregation_vec = self.aggregation(implication_vec);
202        // 4. defuzzification
203        self.defuzzification(aggregation_vec)
204    }
205}
206
207#[derive(Debug)]
208pub struct TSKFuzzyInferenceSystem {
209    s_norm: SNorms,
210    t_norm: TNorms,
211    defuzzification: TSKDefuzzifiers,
212    rules: Vec<Rule>,
213    inputs: Vec<InputVariable>,
214    outputs: Vec<TSKOutputVariable>,
215}
216
217pub type TSKFIS = TSKFuzzyInferenceSystem;
218
219impl TSKFuzzyInferenceSystem {
220    pub fn new(s_norm: SNorms, t_norm: TNorms, defuzzification: TSKDefuzzifiers) -> Self {
221        Self {
222            s_norm,
223            t_norm,
224            defuzzification,
225            rules: Vec::new(),
226            inputs: Vec::new(),
227            outputs: Vec::new(),
228        }
229    }
230
231    pub fn add_input(&mut self, input: InputVariable) {
232        self.inputs.push(input);
233    }
234
235    pub fn add_output(&mut self, variable: TSKOutputVariable) {
236        self.outputs.push(variable);
237    }
238
239    pub fn add_rule(&mut self, rule: Rule) {
240        self.rules.push(rule);
241    }
242
243    pub fn get_s_norm(&self, fuzzified: &[f64]) -> f64 {
244        self.s_norm.s_norm(fuzzified)
245    }
246
247    pub fn get_t_norm(&self, fuzzified: &[f64]) -> f64 {
248        self.t_norm.t_norm(fuzzified)
249    }
250
251    pub fn get_rules(&self, rule_index: usize) -> &[i32] {
252        self.rules[rule_index].get_rules()
253    }
254
255    pub fn get_input_rules(&self, rule_index: usize) -> &[i32] {
256        self.rules[rule_index].get_input_rules(self.inputs.len())
257    }
258
259    pub fn get_output_rules(&self, rule_index: usize) -> &[i32] {
260        self.rules[rule_index].get_output_rules(self.inputs.len())
261    }
262
263    pub fn fuzzification(&self, input_vec: Vec<f64>) -> Vec<Vec<f64>> {
264        let mut fuzzified: Vec<Vec<f64>> = Vec::new();
265        for i in 0..self.rules.len() {
266            let input_rule = self.get_input_rules(i);
267            let mut temp_vec: Vec<f64> = Vec::new();
268            for ii in 0..self.inputs.len() {
269                let index;
270                let complement;
271                if input_rule[ii] < 0 {
272                    index = (-input_rule[ii]) as usize;
273                    complement = true;
274                } else {
275                    index = input_rule[ii] as usize;
276                    complement = false;
277                }
278                let fuzzed = self.inputs[ii].fuzzify(index, input_vec[ii]);
279                temp_vec.push(match complement {
280                    true => 1.0 - fuzzed,
281                    false => fuzzed,
282                });
283                //temp_vec.push(self.inputs[ii].fuzzify(input_rule[ii] as usize, input_vec[ii]));
284            }
285            fuzzified.push(temp_vec);
286        }
287        fuzzified
288    }
289
290    pub fn connect_inputs(&self, fuzzified: Vec<Vec<f64>>) -> Vec<f64> {
291        fuzzified
292            .into_iter()
293            .zip(&self.rules)
294            .map(|(fuzz, rule)| match rule.get_kind() {
295                rules::Kind::OR => self.get_s_norm(&fuzz),
296                rules::Kind::AND => self.get_t_norm(&fuzz),
297            })
298            .collect()
299    }
300
301    pub fn weighed_inputs(&self, connected_inputs: Vec<f64>) -> Vec<f64> {
302        connected_inputs
303            .into_iter()
304            .zip(&self.rules)
305            .map(|(mu, rule)| rule.get_weight() * mu)
306            .collect()
307    }
308
309    pub fn get_mu(&self, input_vec: &Vec<f64>) -> Vec<Vec<f64>> {
310        let mut output = Vec::new();
311        for i in 0..self.outputs.len() {
312            let mut temp_vec = Vec::new();
313            for ii in 0..self.rules.len() {
314                let output_rule = self.rules[ii].get_output_rules(self.inputs.len());
315                temp_vec.push(
316                    self.outputs[i].get_mu(output_rule[i as usize].try_into().unwrap(), &input_vec),
317                )
318            }
319            output.push(temp_vec);
320        }
321        output
322    }
323
324    pub fn compute_outputs(&self, input: Vec<f64>) -> Vec<f64> {
325        let mut output = Vec::new();
326
327        // 1 - fuzzification
328        let fuzzified = self.fuzzification(input.clone());
329        let connected_inputs = self.connect_inputs(fuzzified);
330        let weighted_input = self.weighed_inputs(connected_inputs);
331        // weighted_inputs
332
333        // 2 - implication
334        let mu_vec = self.get_mu(&input);
335        for i in 0..self.outputs.len() {
336            output.push(self.defuzzification.defuzzify(&mu_vec[i], &weighted_input));
337        }
338
339        output
340    }
341}