furtif_core/traits/transforms/
mod.rs

1// This program is free software: you can redistribute it and/or modify
2// it under the terms of the Lesser GNU General Public License as published
3// by the Free Software Foundation, either version 3 of the License, or
4// (at your option) any later version.
5
6// This program is distributed in the hope that it will be useful,
7// but WITHOUT ANY WARRANTY; without even the implied warranty of
8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9// Lesser GNU General Public License for more details.
10
11// You should have received a copy of the Lesser GNU General Public License
12// along with this program.  If not, see <https://www.gnu.org/licenses/>.
13
14// Copyright 2024 Frederic Dambreville, Jean Dezert Developers.
15
16
17use std::{hash::Hash, collections::HashMap, };
18
19// #[cfg(not(feature = "silx-types"))] use crate::fake_slx::{f64slx, u32slx,  FakeSlx};
20// #[cfg(feature = "silx-types")] use silx_types::{ f64slx, u32slx, Float, IntoSlx, SlxInto};
21
22#[cfg(feature = "silx-types")] use silx_types::Float;
23
24use crate::{
25    types::{ u32slx, f64slx, SlxInto, IntoSlx, },
26    structs::{Assignment, SafeElement, ASSIGNMENT_EPSILON, one_f64slx, zero_f64slx}, 
27    traits::Lattice,
28};
29
30use super::ComplementedLattice;
31
32/// General trait for iterable lattices, ie. lattice with some useful iterators
33pub trait IterableLattice: Lattice {
34    /// Type of iterator for iterating lattice from bottom to top 
35    type IntoIterUp: Iterator<Item = Self::Item>;
36    /// Type of iterator for iterating lattice from top to bottom 
37    type IntoIterDown: Iterator<Item = Self::Item>;
38
39    /// Unsafe iterator of the full lattice, non decreasing with inference; 
40    /// * error means that the iterator cannot be iterated (e.g. lattice with too much elements)
41    /// * Output: iterator or error
42    unsafe fn unsafe_bottom_to_top(&self) -> Result<Self::IntoIterUp,String>;
43    
44    /// Unsafe iterator of the full lattice, non increasing with inference; 
45    /// * error means that the iterator cannot be iterated (e.g. lattice with too much elements)
46    /// * Output: iterator or error
47    unsafe fn unsafe_top_to_bottom(&self) -> Result<Self::IntoIterDown,String>;
48    
49    /// Safe iterator of the full lattice, non decreasing with inference; 
50    /// * error means that the iterator cannot be iterated (e.g. lattice with too much elements)
51    /// * Output: iterator or error
52    fn bottom_to_top(&self) -> Result<std::vec::IntoIter<SafeElement<Self::Item>>,String> {
53        let lattice_hash = self.lattice_hash();
54        Ok(unsafe{ self.unsafe_bottom_to_top() }?.map(
55            move |element| SafeElement { lattice_hash, code: element } 
56        ).collect::<Vec<_>>().into_iter())
57    }
58
59    /// Safe iterator of the full lattice, non increasing with inference; 
60    /// * error means that the iterator cannot be iterated (e.g. lattice with too much elements)
61    /// * Output: iterator or error
62    fn top_to_bottom(&self) -> Result<std::vec::IntoIter<SafeElement<Self::Item>>,String> {
63        let lattice_hash = self.lattice_hash();
64        Ok(unsafe{ self.unsafe_top_to_bottom() }?.map(
65            move |element| SafeElement { lattice_hash, code: element } 
66        ).collect::<Vec<_>>().into_iter())
67    }    
68}
69
70/// General trait for lattices with leaves.
71/// * Leaves are minimal non-empty elements which are generators for the lattice by means of the disjunction operator
72/// * Typically, Powerset and Taxonomy have leaves, but hyperpowerset (not implemented here) does not have leaves
73pub trait LatticeWithLeaves: Lattice where Self::Item: Ord + Hash, {
74    /// Type of leaves iterator
75    type IntoIterLeaves: Iterator<Item = (Self::Item,f64slx)>;
76
77    /// Get unsafe weighted leaf at rank `u`
78    /// * `u: usize` : leaf rank
79    /// * Output: unsafe weighted leaf or error
80    unsafe fn unsafe_weighted_leaf(&self, u: usize) -> Result<(&Self::Item,&f64slx),String>;
81
82    /// Unsafe iterator of the weighted leaves of the lattice
83    /// * Output: unsafe weighted leaf iterator or error
84    unsafe fn unsafe_leaves(&self) -> Result<Self::IntoIterLeaves,String>;
85
86    /// Get unsafe leaf at rank `u`
87    /// * `u: usize` : leaf rank
88    /// * Output: unsafe leaf or error
89    unsafe fn unsafe_leaf(&self, u: usize) -> Result<&Self::Item,String> {
90        Ok(&self.unsafe_weighted_leaf(u)?.0)
91    }
92
93    /// Get safe weighted leaf at rank `u`
94    /// * `u: usize` : leaf rank
95    /// * Output: safe weighted leaf or error
96    fn weighted_leaf(&self, u: usize) -> Result<(SafeElement<Self::Item>,f64slx),String> {
97        let (e,w) = unsafe { self.unsafe_weighted_leaf(u)? };
98        let lattice_hash = self.lattice_hash();
99        Ok((SafeElement { code: e.clone(), lattice_hash, },*w))
100    }
101
102    /// Get safe leaf at rank `u`
103    /// * `u: usize` : leaf rank
104    /// * Output: safe leaf or error
105    fn leaf(&self, u: usize) -> Result<SafeElement<Self::Item>,String> {
106        let e = unsafe { self.unsafe_leaf(u)? };
107        let lattice_hash = self.lattice_hash();
108        Ok(SafeElement { code: e.clone(), lattice_hash, })    
109    }
110
111    /// Iterator of the safe weighted leaves of the lattice
112    /// * Output: safe weighted leaf iterator or error
113    fn leaves(&self) -> Result<std::vec::IntoIter<(SafeElement<Self::Item>,f64slx)>,String> {
114        let lattice_hash = self.lattice_hash();
115        Ok(unsafe{ self.unsafe_leaves() }?.map(
116            move |(element,w)| (SafeElement { lattice_hash, code: element },w) 
117        ).collect::<Vec<_>>().into_iter())
118    }    
119
120    /// Transform mass to pignistic probability
121    /// * `mass: &Assignment<Self::Item>` : mass assignment
122    /// * Output: pignistic assignment or error
123    fn mass_to_pignistic(&self, mass: &Assignment<Self::Item>) -> Result<Assignment<Self::Item>,String> {
124        let Assignment { lattice_hash, elements, .. } = mass;
125        if lattice_hash == self.ref_lattice_hash() {
126            let leaves = unsafe { self.unsafe_leaves() }?.collect::<HashMap<_,_>>();
127            let loc_norm = elements.iter().map(|(x,wx)| {
128                let loc_leaves = leaves.iter().filter(
129                    |(y,_)|unsafe { self.unsafe_implied_join(x,*y) }
130                ).map(|(y,w)| (y,*w)).collect::<Vec<_>>();
131                let norm = loc_leaves.iter().map(|(_,w)| *w).sum::<f64slx>();
132                (*wx,loc_leaves,norm)
133            }).collect::<Vec<_>>();
134            let mut pign = self.assignment();
135            for (wx,ll,nx) in loc_norm {
136                for (l,w) in ll {
137                    unsafe { pign.unsafe_push(l.clone(), wx * w / nx)? };
138                }
139            }
140            pign.normalize()?; Ok(pign.into())
141        } else { Err("Mismatching lattice hash".to_string()) }
142    }
143}
144
145/// Trait implementing belief functions transforms
146pub trait BeliefTransform: IterableLattice where Self::Item: Ord + Hash, {
147    /// Transform mass to commonality
148    /// * `mass: &Assignment<Self::Item>` : mass assignment
149    /// * Output: commonality assignment or error
150    fn mass_to_commonality<>(&self, mass: &Assignment<Self::Item>) -> Result<Assignment<Self::Item>,String> {
151        let Assignment { lattice_hash, elements, .. } = mass;
152        if lattice_hash == self.ref_lattice_hash() {
153            let vec_com = unsafe{ self.unsafe_top_to_bottom() }?
154                            .map(|x| {
155                                let mut wx = *zero_f64slx();
156                                for (y,wy) in elements {
157                                    if unsafe{ self.unsafe_implies_join(&x, y) } { wx += *wy; }
158                                }
159                                (x, wx)
160                            }).filter(|(_,w)| w > &zero_f64slx()).collect::<Vec<_>>();
161            let elements = vec_com.clone().into_iter().collect();
162            Ok(Assignment { 
163                lattice_hash: *lattice_hash, elements,
164            })
165        } else { Err("Mismatching lattice hash".to_string()) }
166
167    }
168
169    /// Transform commonality to mass
170    /// * `commonality: &Assignment<Self::Item>` : commonality assignment
171    /// * Output: mass assignment or error
172    fn mass_from_commonality(&self, commonality: &Assignment<Self::Item>) -> Result<Assignment<Self::Item>,String> {
173        let Assignment { lattice_hash, elements, .. } = commonality;
174        if lattice_hash == self.ref_lattice_hash() {
175            let mut mass = self.assignment();
176            let zero = *zero_f64slx();
177            for x in unsafe{ self.unsafe_top_to_bottom() }? {
178                let mut wx = match elements.get(&x) {
179                    Some(w) => *w, None => zero,
180                };            
181                for (y,wy) in &mass.elements.elements {
182                    if unsafe{ self.unsafe_implies_join(&x, y) } { wx -= *wy; }
183                }
184                if wx.abs() > ASSIGNMENT_EPSILON.slx() { unsafe { mass.unsafe_push(x, wx) }?; }
185            }
186            mass.length_mid = (mass.elements.len() as u32).slx();
187            let slx2u32: u32slx = 2u32.slx();
188            mass.length_max = slx2u32 * mass.length_mid;
189            mass.normalize()?;
190            Ok(mass.into())
191        } else { Err("Mismatching lattice hash".to_string()) }
192    }
193
194    /// Transform mass to implicability
195    /// * `mass: &Assignment<Self::Item>` : mass assignment
196    /// * Output: implicability assignment or error
197    fn mass_to_implicability(&self, mass: &Assignment<Self::Item>) -> Result<Assignment<Self::Item>,String> {
198        let Assignment { lattice_hash, elements, .. } = mass;
199        if lattice_hash == self.ref_lattice_hash() {
200            let vec_com = unsafe{ self.unsafe_bottom_to_top() }?
201                            .map(|x| {
202                                let mut wx = *zero_f64slx();
203                                for (y,wy) in elements {
204                                    if unsafe{ self.unsafe_implied_join(&x, y) } { wx += *wy; }
205                                }
206                                (x, wx)
207                            }).filter(|(_,w)| w > zero_f64slx()).collect::<Vec<_>>();
208            let elements = vec_com.clone().into_iter().collect();
209            Ok(Assignment { lattice_hash: *lattice_hash, elements, })
210        } else { Err("Mismatching lattice hash".to_string()) }
211    }
212    
213    /// Transform implicability to mass
214    /// * `implicability: &Assignment<Self::Item>` : implicability assignment 
215    /// * Output: mass assignment or error
216    fn mass_from_implicability(&self, implicability: &Assignment<Self::Item>) -> Result<Assignment<Self::Item>,String> {
217        let Assignment { lattice_hash, elements, .. } = implicability;
218        if lattice_hash == self.ref_lattice_hash() {
219            let mut mass = self.assignment();
220            let zero = *zero_f64slx();
221            for x in unsafe{ self.unsafe_bottom_to_top() }? {
222                let mut wx = match elements.get(&x) {
223                    Some(w) => *w, None => zero,
224                };
225                for (y,wy) in &mass.elements.elements {
226                    if unsafe{ self.unsafe_implied_join(&x, y) } { wx -= *wy; }
227                }
228                if wx.abs() > ASSIGNMENT_EPSILON.slx() { unsafe { mass.unsafe_push(x, wx) }?; }
229            }
230            mass.length_mid = (mass.elements.len() as u32).slx();
231            let slx2u32: u32slx = 2u32.slx();
232            mass.length_max = slx2u32 * mass.length_mid;
233
234            mass.normalize()?;
235            Ok(mass.into())
236        } else { Err("Mismatching lattice hash".to_string()) }
237    }
238    
239    /// Transform mass to credibility
240    /// * `mass: &Assignment<Self::Item>` : mass assignment
241    /// * Output: credibility assignment or error
242    fn mass_to_credibility(&self, mass: &Assignment<Self::Item>) -> Result<Assignment<Self::Item>,String> {
243        let Assignment { lattice_hash, elements, .. } = mass;
244        if lattice_hash == self.ref_lattice_hash() {
245            let vec_com = unsafe{ self.unsafe_bottom_to_top() }?
246                            .map(|x| {
247                                let mut wx = *zero_f64slx();
248                                for (y,wy) in elements.iter()
249                                        .filter(|(x,_)| !unsafe { self.unsafe_is_bottom(*x) }) {
250                                    if unsafe{ self.unsafe_implied_join(&x, y) } { wx += *wy; }
251                                }
252                                (x, wx)
253                            }).filter(|(_,w)| w > zero_f64slx()).collect::<Vec<_>>();
254            let elements = vec_com.clone().into_iter().collect();
255            Ok(Assignment { lattice_hash: *lattice_hash, elements, })
256        } else { Err("Mismatching lattice hash".to_string()) }
257    }
258    
259    /// Transform credibility to mass
260    /// * `credibility: &Assignment<Self::Item>` : credibility assignment
261    /// * Output: mass assignment or error
262    fn mass_from_credibility(&self, credibility: &Assignment<Self::Item>) -> Result<Assignment<Self::Item>,String> {
263        let Assignment { lattice_hash, elements, .. } = credibility;
264        if lattice_hash == self.ref_lattice_hash() {
265            let mut mass = self.assignment();
266            let zero = *zero_f64slx();
267            let mut full_w = zero;
268            for x in unsafe{ self.unsafe_bottom_to_top() }? {
269                let mut wx = match elements.get(&x) {
270                    Some(w) => *w, None => zero,
271                };
272                for (y,wy) in &mass.elements.elements {
273                    if unsafe{ self.unsafe_implied_join(&x, y) } { wx -= *wy; }
274                }
275                if wx.abs() > ASSIGNMENT_EPSILON.slx() { 
276                    unsafe { mass.unsafe_push(x, wx) }?; 
277                    full_w += wx;
278                }
279
280            }
281            if full_w > *one_f64slx() { panic!("exceeding weights"); }
282            unsafe { mass.unsafe_push(self.bottom().code, *one_f64slx() - full_w)?;  }
283            mass.length_mid = (mass.elements.len() as u32).slx();
284            let slx2u32: u32slx = 2u32.slx();
285            mass.length_max = slx2u32 * mass.length_mid;
286            mass.normalize()?;
287            Ok(mass.into())
288        } else { Err("Mismatching lattice hash".to_string()) }
289    }
290    
291    /// Transform mass to plausibility
292    /// * `mass: &Assignment<Self::Item>` : mass assignment
293    /// * Output: plausibility assignment or error
294    fn mass_to_plausibility(&self, mass: &Assignment<Self::Item>) -> Result<Assignment<Self::Item>,String> {
295        let Assignment { lattice_hash, elements, .. } = mass;
296        if lattice_hash == self.ref_lattice_hash() {
297            let vec_com = unsafe{ self.unsafe_bottom_to_top() }?
298                            .map(|x| {
299                                let mut wx = *zero_f64slx();
300                                for (y,wy) in elements {
301                                    if !unsafe{ self.unsafe_disjoint(&x, y) } { wx += *wy; }
302                                }
303                                (x, wx)
304                            }).filter(|(_,w)| w > zero_f64slx()).collect::<Vec<_>>();
305            let elements = vec_com.clone().into_iter().collect();
306            Ok(Assignment { lattice_hash: *lattice_hash, elements, })
307        } else { Err("Mismatching lattice hash".to_string()) }
308    }
309
310
311    /// Transform implicability to credibility
312    /// * `implicability: &Assignment<Self::Item>` : implicability assignment
313    /// * Output: credibility assignment or error
314    fn implicability_to_credibility(&self, implicability: &Assignment<Self::Item>) -> Result<Assignment<Self::Item>,String> {
315        let Assignment { lattice_hash, elements, .. } = implicability;
316        let SafeElement { code: bottom, lattice_hash: ref_lattice_hash } = self.ref_bottom();
317        if lattice_hash == ref_lattice_hash { Ok( {
318            let zero = *zero_f64slx();
319            let neg_shift = match elements.get(&bottom) {
320                Some(w) => *w, None => zero,
321            };
322            let mapped = elements.iter()
323                .map(|(x,w)| (x.clone(), *w - neg_shift)).collect::<Vec<_>>();
324            for (_,w) in &mapped { 
325                let w = (*w).unslx();
326                if !w.is_finite() || w.is_sign_negative() {
327                    return Err(format!("mapped weight {w} is not finite or is sign negative"));
328                } 
329            }
330            let elements = mapped.into_iter().filter(|(_,w)| (*w).unslx() > ASSIGNMENT_EPSILON).collect();
331            Assignment { elements, lattice_hash: *lattice_hash }
332        } ) } else { Err("Mismatching lattice hash".to_string()) }
333    }
334
335    /// Transform credibility to implicability
336    /// * `credibility: &Assignment<Self::Item>` : credibility assignment
337    /// * Output: implicability assignment or error
338    fn implicability_from_credibility(&self, credibility: &Assignment<Self::Item>) -> Result<Assignment<Self::Item>,String> {
339        let Assignment { lattice_hash, elements, } = credibility;
340        let SafeElement { code: bottom, lattice_hash: ref_lattice_hash } = self.ref_bottom();
341        let SafeElement { code: top, .. } = self.ref_top();
342        let one = *one_f64slx();
343        let slx_assignment_epsilon: f64slx = ASSIGNMENT_EPSILON.slx();
344        if lattice_hash == ref_lattice_hash { Ok( {
345            let shift = match elements.get(&top) {
346                Some(w) => one - *w, None => one,
347            };
348            if shift <= - slx_assignment_epsilon { return Err("weight on top is greater than 1.0".to_string()) }
349            {
350                if let Some(w_bottom) = elements.get(&bottom) {
351                    return Err(format!("weight on bottom is {w_bottom} not 0.0")) 
352                }
353            }
354            // shifted prefix iterator
355            let zero_weighted = unsafe { self.unsafe_bottom_to_top() }?
356                .filter(|e| !elements.contains_key(e))
357                .map(|e|(e,shift));
358            // deep clone of elements shifted and prefixed
359            let weighted = zero_weighted.chain(
360                elements.clone().into_iter().map(|(x,w)| (x,w + shift))
361            ).collect::<Vec<_>>();
362            for (_,w) in &weighted { if !w.is_finite() || *w <= -slx_assignment_epsilon {
363                return Err(format!("mapped weight {w} is not finite or is sign negative"))
364            } }
365            let weighted_filtered = weighted.into_iter().filter(|(_,w)| w > &slx_assignment_epsilon).collect::<Vec<_>>();
366            // collect on light clone
367            let elements = weighted_filtered.clone().into_iter().collect::<HashMap<_,_>>();
368            Assignment { lattice_hash: *lattice_hash, elements, }
369        } ) } else { Err("Mismatching lattice hash".to_string()) }
370    }
371}
372
373/// Trait defining transformations based on the complementation
374pub trait ComplementedBeliefTransform: IterableLattice + ComplementedLattice where Self::Item: Eq + Ord + Hash + Clone, {    
375    /// Transform plausibility to mass
376    /// * `plausibility: &Assignment<Self::Item>` : plausibility assignment
377    /// * Output: mass assignment or error
378    fn mass_from_plausibility(&self, plausibility: &Assignment<Self::Item>) -> Result<Assignment<Self::Item>,String> {
379        let Assignment { lattice_hash, elements, .. } = plausibility;
380        if lattice_hash == self.ref_lattice_hash() {
381            let mut mass = self.assignment();
382            let one = *one_f64slx();
383            for x in unsafe{ self.unsafe_top_to_bottom() }? {
384                let neg_x = unsafe { self.unsafe_not(&x) };
385                let mut wx = match elements.get(&x) {
386                    Some(w) => one - *w, None => one,
387                }; //implicability of neg_x
388                for (y,wy) in &mass.elements.elements {
389                    if unsafe{ self.unsafe_implied_join(&neg_x, y) } { wx -= *wy; }
390                }
391                if wx.abs() > ASSIGNMENT_EPSILON.slx() { unsafe { mass.unsafe_push(neg_x, wx) }?; }
392            }
393            mass.length_mid = (mass.elements.len() as u32).slx();
394            let slx2u32: u32slx = 2u32.slx();
395            mass.length_max = slx2u32 * mass.length_mid;
396            mass.normalize()?;
397            Ok(mass.into())
398        } else { Err("Mismatching lattice hash".to_string()) }
399    }
400}
401
402impl<L> BeliefTransform for L where L: IterableLattice, Self::Item: Ord + Hash, { }
403
404impl<L> ComplementedBeliefTransform for L 
405            where L: IterableLattice + ComplementedLattice, Self::Item: Ord + Hash, { }
406
407
408pub mod experiment {
409    // #[cfg(not(feature = "silx-types"))] use crate::fake_slx::FakeSlx;
410    // #[cfg(feature = "silx-types")] use silx_types::IntoSlx;
411
412    use crate::{
413        types::IntoSlx,
414        structs::Powerset, 
415        traits::{ Lattice, BeliefTransform, ComplementedBeliefTransform, LatticeWithLeaves, }
416    };
417
418    /// Experimentation with assignment transforms
419    pub fn exp_transform() -> Result<(),String> {
420        println!("======================= transform =====");
421        let lattice = Powerset::new(3,1024)
422                .expect("unexpected powwerset initialisation failure")
423                .set_iterators();
424        let (mut m1,mut m2) = (
425            lattice.assignment(),
426            lattice.assignment(),
427        );
428        let (prop_a, m_a,) = (lattice.leaf(0)?, 0.1.slx());
429        let (prop_b, m_b) = (lattice.leaf(1)?, 0.15.slx(),);
430        let (prop_c, m_c) = (lattice.leaf(2)?, 0.2.slx());
431        let (prop_bc, m_bc) = (lattice.join(&prop_b,&prop_c)?,0.2.slx());
432        let (prop_ca, m_ca) = (lattice.join(&prop_c,&prop_a)?,0.1.slx());
433        let (prop_ab, m_ab) = (lattice.join(&prop_a,&prop_b)?,0.25.slx());
434        let (prop_abc, m_abc) = (lattice.join(&prop_bc,&prop_a)?,0.0.slx());
435        m1.push(prop_a,m_a)?;
436        m1.push(prop_b,m_b)?;
437        m1.push(prop_c,m_c)?;
438        m1.push(prop_bc,m_bc)?;
439        m1.push(prop_ca,m_ca)?;
440        m1.push(prop_ab,m_ab)?;
441        m1.push(prop_abc,m_abc)?;
442        let m1 = m1.into();
443        //
444        let (prop_bot, m_bot,) = (lattice.meet(&prop_a,&prop_b)?, 0.05.slx());
445        let m_bc = 0.15.slx();
446        let m_ab = 0.15.slx();
447        let m_abc = 0.1.slx();
448        m2.push(prop_bot,m_bot)?;
449        m2.push(prop_a,m_a)?;
450        m2.push(prop_b,m_b)?;
451        m2.push(prop_c,m_c)?;
452        m2.push(prop_bc,m_bc)?;
453        m2.push(prop_ca,m_ca)?;
454        m2.push(prop_ab,m_ab)?;
455        m2.push(prop_abc,m_abc)?;
456        let m2 = m2.into();
457        for (m,nm) in [(m1,"m1"),(m2,"m2")] {
458            println!("===================== transform {nm}=====");
459            println!("------------------- implicability -----");
460            println!("m: {:?}", m);
461            let implicability = lattice.mass_to_implicability(&m)?;
462            println!("implicability: {:?}",implicability);
463            let back_m = lattice.mass_from_implicability(&implicability)?;
464            println!("back_m -> {:?}",back_m);
465            println!("--------------------- commonality -----");
466            println!("m: {:?}", m);
467            let commonality = lattice.mass_to_commonality(&m)?;
468            println!("commonality: {:?}",commonality);
469            let back_m = lattice.mass_from_commonality(&commonality)?;
470            println!("back_m -> {:?}",back_m);
471            println!("--------------------- credibility -----");
472            println!("m: {:?}", m);
473            let credibility = lattice.mass_to_credibility(&m)?;
474            println!("credibility: {:?}",credibility);
475            let back_m = lattice.mass_from_credibility(&credibility)?;
476            println!("back_m -> {:?}",back_m);
477            let implicability = lattice.implicability_from_credibility(&credibility)?;
478            println!("implicability: {:?}",implicability);
479            let back_credibility = lattice.implicability_to_credibility(&implicability)?;
480            println!("back_credibility: {:?}",back_credibility);
481            println!("-------------------- plausibility -----");
482            println!("m: {:?}", m);
483            let plausibility = lattice.mass_to_plausibility(&m)?;
484            println!("plausibility: {:?}",plausibility);
485            // ComplementedLattice is necessary here:
486            let back_m = lattice.mass_from_plausibility(&plausibility)?;
487            println!("back_m -> {:?}",back_m);
488            println!("----------------------- pignistic -----");
489            println!("m: {:?}", m);
490            let pignistic = lattice.mass_to_pignistic(&m)?;
491            println!("pignistic: {:?}", pignistic);
492            println!();            
493        }
494        Ok(())
495    }
496}