assessment/valuation/unification/numeric.rs
1use crate::domain::{Qualitative, Quantitative, QuantitativeLimit};
2use crate::fuzzy::membership::Trapezoidal;
3use crate::valuation::{Interval, Numeric, NumericError, Unified, UnifiedError};
4use std::ops::{Add, Div, Mul, Sub};
5
6impl<'domain, T: QuantitativeLimit + Into<f64>> Numeric<'domain, T>
7where
8 T: Mul<Output = T>,
9 T: Add<Output = T>,
10 T: Sub<Output = T>,
11 T: Div<Output = T>,
12{
13 /// Unification of a Numeric valuation in a given domain.
14 ///
15 /// # Arguments
16 /// * `domain`: Domain in which perform the unification.
17 ///
18 /// # Examples
19 ///
20 /// ```
21 /// # use assessment::qualitative_symmetric_domain;
22 /// # use assessment::valuation::{Numeric, Unified, UnifiedError};
23 /// # use assessment::utilities;
24 /// # use assessment::domain::Quantitative;
25 /// let domain = Quantitative::new(0, 7).unwrap();
26 /// let unification_domain = qualitative_symmetric_domain!["a", "b", "c", "d", "e"].unwrap();
27 ///
28 /// let valuation = Numeric::new(&domain, 5).unwrap();
29 /// let unified = valuation.unification(&unification_domain).unwrap();
30 /// let measures = unified.measures();
31 /// let expected_measures = vec![0.0, 0.0, 0.14, 0.86, 0.0];
32 /// for i in 0..(expected_measures.len()) {
33 /// assert!(
34 /// utilities::math::approx_equal_f32(
35 /// measures[i],
36 /// expected_measures[i],
37 /// 2
38 /// ),
39 /// "({}) Value {:.2} vs. Expected {:.2}",
40 /// i,
41 /// measures[i],
42 /// expected_measures[i]
43 /// );
44 /// }
45 /// ```
46 ///
47 /// # Errors
48 ///
49 /// **UnifiedError::NonBLTSDomain**: If `domain` is a Non-BLTS domain.
50 ///
51 /// ```
52 /// # use assessment::qualitative_symmetric_domain;
53 /// # use assessment::valuation::{Numeric, Unified, UnifiedError};
54 /// # use assessment::utilities;
55 /// # use assessment::domain::Quantitative;
56 /// let domain = Quantitative::new(0, 7).unwrap();
57 /// let unification_domain = qualitative_symmetric_domain!["a", "b", "c", "d"].unwrap();
58 ///
59 /// let valuation = Numeric::new(&domain, 5).unwrap();
60 /// assert_eq!(
61 /// valuation.unification(&unification_domain),
62 /// Err(UnifiedError::NonBLTSDomain { domain: &unification_domain })
63 /// );
64 /// ```
65 ///
66 pub fn unification(
67 &self,
68 domain: &'domain Qualitative<Trapezoidal>,
69 ) -> Result<Unified, UnifiedError> {
70 let value = self.normalize().value() as f32;
71 let measures = (0..domain.cardinality())
72 .map(|i| {
73 domain
74 .get_label_by_index(i)
75 .unwrap()
76 .membership()
77 .membership_value(value)
78 })
79 .collect::<Vec<f32>>();
80 Unified::new(domain, measures)
81 }
82
83 /// Transform a Numeric valuation using a different domain.
84 ///
85 /// Note that domain type should be equal to valuation type.
86 ///
87 /// # Arguments
88 ///
89 /// * `domain`: Domain to be used.
90 ///
91 /// # Examples
92 ///
93 /// ```
94 /// # use assessment::qualitative_symmetric_domain;
95 /// # use assessment::valuation::{Numeric, Unified, UnifiedError};
96 /// # use assessment::utilities;
97 /// # use assessment::domain::Quantitative;
98 /// let domain = Quantitative::new(0, 7).unwrap();
99 /// let transform_domain = Quantitative::new(0, 3).unwrap();
100 ///
101 /// let valuation = Numeric::new(&domain, 5).unwrap();
102 /// let unified = valuation.transform_in_domain(&transform_domain);
103 /// assert_eq!(unified.value(), 2);
104 /// ```
105 ///
106 pub fn transform_in_domain(&self, domain: &'domain Quantitative<T>) -> Numeric<T> {
107 Numeric::new(
108 domain,
109 crate::utilities::math::transform_range(
110 self.value(),
111 self.domain().inf(),
112 self.domain().sup(),
113 domain.inf(),
114 domain.sup(),
115 ),
116 )
117 .unwrap()
118 }
119}
120
121/// Generates a Numeric<f32> valuation from an &Interval<f32> valuation.
122///
123/// # Examples
124///
125/// ```
126/// # use assessment::domain::Quantitative;
127/// # use assessment::utilities;
128/// # use assessment::valuation::{Numeric, Interval};
129/// let domain = Quantitative::new(0.5_f32, 1.0_f32).unwrap();
130/// let interval = Interval::new(&domain, 0.6, 0.8).unwrap();
131/// let numeric = Numeric::try_from(&interval).unwrap();
132/// let expected = 0.7;
133/// assert!((numeric.value() - expected).abs() < 0.01);
134/// ```
135///
136impl<'domain> TryFrom<&Interval<'domain, f32>> for Numeric<'domain, f32> {
137 type Error = NumericError<f32>;
138
139 fn try_from(value: &Interval<'domain, f32>) -> Result<Self, Self::Error> {
140 Numeric::new(value.domain(), value.resume())
141 }
142}
143
144/// Generates a Numeric<f64> valuation from an &Interval<f64> valuation.
145///
146/// # Examples
147///
148/// ```
149/// # use assessment::domain::Quantitative;
150/// # use assessment::utilities;
151/// # use assessment::valuation::{Numeric, Interval};
152/// let domain = Quantitative::new(0.5_f64, 1.0_f64).unwrap();
153/// let interval = Interval::new(&domain, 0.6, 0.8).unwrap();
154/// let numeric = Numeric::try_from(&interval).unwrap();
155/// let expected = 0.7;
156/// assert!((numeric.value() - expected).abs() < 0.01);
157/// ```
158///
159impl<'domain> TryFrom<&Interval<'domain, f64>> for Numeric<'domain, f64> {
160 type Error = NumericError<f64>;
161
162 fn try_from(value: &Interval<'domain, f64>) -> Result<Self, Self::Error> {
163 Numeric::new(value.domain(), value.resume())
164 }
165}
166
167/// Generates a Numeric<i32> valuation from an &Interval<i32> valuation.
168///
169/// # Examples
170///
171/// ```
172/// # use assessment::domain::Quantitative;
173/// # use assessment::utilities;
174/// # use assessment::valuation::{Numeric, Interval};
175/// let domain = Quantitative::new(5, 10).unwrap();
176/// let interval = Interval::new(&domain, 6, 8).unwrap();
177/// let numeric = Numeric::try_from(&interval).unwrap();
178/// let expected = 7;
179/// assert_eq!(numeric.value(), expected);
180/// ```
181///
182impl<'domain> TryFrom<&Interval<'domain, i32>> for Numeric<'domain, i32> {
183 type Error = NumericError<i32>;
184
185 fn try_from(value: &Interval<'domain, i32>) -> Result<Self, Self::Error> {
186 Numeric::new(value.domain(), value.resume())
187 }
188}
189
190/// Generates a Numeric<f32> valuation from an Interval<f32> valuation.
191///
192/// Wrapper of Numeric::try_from(&Interval<f32>).
193///
194impl<'domain> TryFrom<Interval<'domain, f32>> for Numeric<'domain, f32> {
195 type Error = NumericError<f32>;
196
197 fn try_from(value: Interval<'domain, f32>) -> Result<Self, Self::Error> {
198 Numeric::try_from(&value)
199 }
200}
201
202/// Generates a Numeric<f64> valuation from an Interval<f64> valuation.
203///
204/// Wrapper of Numeric::try_from(&Interval<f64>).
205///
206impl<'domain> TryFrom<Interval<'domain, f64>> for Numeric<'domain, f64> {
207 type Error = NumericError<f64>;
208
209 fn try_from(value: Interval<'domain, f64>) -> Result<Self, Self::Error> {
210 Numeric::try_from(&value)
211 }
212}
213
214/// Generates a Numeric<i32> valuation from an Interval<i32> valuation.
215///
216/// Wrapper of Numeric::try_from(&Interval<i32>).
217///
218/// ```
219/// # use assessment::domain::Quantitative;
220/// # use assessment::utilities;
221/// # use assessment::valuation::{Numeric, Interval};
222/// let domain = Quantitative::new(5, 10).unwrap();
223/// let interval = Interval::new(&domain, 6, 8).unwrap();
224/// let numeric = Numeric::try_from(&interval).unwrap();
225/// let expected = 7;
226/// assert_eq!(numeric.value(), expected);
227/// ```
228///
229impl<'domain> TryFrom<Interval<'domain, i32>> for Numeric<'domain, i32> {
230 type Error = NumericError<i32>;
231
232 fn try_from(value: Interval<'domain, i32>) -> Result<Self, Self::Error> {
233 Numeric::try_from(&value)
234 }
235}