rust_fuzzylogic/
mamdani.rs1use std::{borrow::Borrow, collections::HashMap, hash::Hash};
4
5#[cfg(feature = "inference-mamdani")]
6use crate::{
7 antecedent::{eval_antecedent, Antecedent},
8 error::{FuzzyError, MissingSpace},
9 prelude::*,
10 sampler::UniformSampler,
11 variable::Variable,
12};
13
14pub enum Implication {
16 Clip,
17 Product,
18}
19
20pub struct Consequent {
22 pub var: String,
23 pub term: String,
24 }
27
28pub struct Rule {
30 pub antecedent: Antecedent,
31 pub consequent: Vec<Consequent>,
32}
33
34#[cfg(feature = "inference-mamdani")]
36impl Rule {
37 pub fn activation<KI, KV>(
39 &self,
40 input: &HashMap<KI, Float>,
41 vars: &HashMap<KV, Variable>,
42 ) -> Result<Float>
43 where
44 KI: Eq + Hash + Borrow<str>,
45 KV: Eq + Hash + Borrow<str>,
46 {
47 eval_antecedent(&self.antecedent, input, vars)
48 }
49
50 pub fn implicate<KV>(
52 &self,
53 alpha: Float,
54 vers: &HashMap<KV, Variable>,
55 sampler: &UniformSampler,
56 ) -> Result<HashMap<String, Vec<Float>>>
57 where
58 KV: Eq + Hash + Borrow<str>,
59 {
60 let mut result_map: HashMap<String, Vec<Float>> = HashMap::new();
61
62 for i in 0..self.consequent.len() {
63 let mut result_vec = vec![0.0; sampler.n];
64
65 let (dom_min, dom_max) = vers
66 .get(&self.consequent[i].var.as_str())
67 .ok_or(FuzzyError::NotFound {
68 space: MissingSpace::Var,
69 key: self.consequent[i].term.clone(),
70 })?
71 .domain();
72
73 let step = (dom_max - dom_min) / sampler.n as Float;
74
75 for k in 0..sampler.n {
76 let x = dom_min + (k as Float * step);
77 result_vec[k] = vers
78 .get(&self.consequent[i].var.as_str())
79 .ok_or(FuzzyError::NotFound {
80 space: MissingSpace::Var,
81 key: self.consequent[i].term.clone(),
82 })?
83 .eval(&self.consequent[i].term, x)?
84 .min(alpha);
85 }
86
87 result_map.insert(self.consequent[i].var.to_string(), result_vec);
88 }
89 return Ok(result_map);
90 }
92}