This is part of [**Furtif**](https://crates.io/crates/furtif) project `furtif-core` contains core components for implementing furtif application ## Notes: About version 0.1.2: * `CombiLattice` is deprecated and replaced by `EnumLattice` * Dependencies are updated Documentation is generated under the hypothesis that feature `silx` is enabled, which is default configuration By default, feature `silx` is enabled, which means: * Serialization/deserialization (`serde` and `rkyv`) and archive (`rkyv`) features are enabled * `silx-types` is enabled, so that `f64slx`, `u128slx`, `u32slx` replace the native types `f64`, `u128`, `u32` Type aliasing and casting are implemented in the `types` module and depend on whether or not the `silx-types` feature is enabled # Purpose Furtif offers a generic implementation in Rust of functionalities for manipulating belief functions and merging them. This crate includes: * Traits defining the notion of lattice and its variants * Two types of lattices are implemented * Powerset * Taxonomy * Tools for transforming between different forms of belief functions * The notion of referee functions is implemented, thus enabling: * the ability to generically define fusion rules * the design of generic engines for computing fused assignments * Presently, an exact computation method with pruning is proposed Furtif is designed from the outset to work asynchronously, interacting with the Silx library. This feature is enabled by default, but can be deselected in Cargo.toml by applying option `default-features = false` on `furtif-core` Main features of `furtif-core` are: * `default` : feature `silx` is enabled * `silx` : makes `furtif-core` compatible with `silx`: * Features `silx-types`, `serde` and `rkyv` are enabled * `serde` : implements serde serialization/deserialization for some types * `rkyv` : implements rkyv serialization/zero-copy deserialization for some types * `silx-types` : builds implementations with silx types * Silx types `f64slx`, `u128slx`, `u32slx` are used instead of native types `f64`, `u128`, `u32`, in order to implement lattices, elements and assignments Furtif remains a project under development. The current version can work as silx-independent (by applying option `default-features = false` on `furtif-core`) or as silx-integrated crate, the latter allowing it to operate in the asynchronous silx environment. Further enhancements are envisaged, such as the implementation of Mex modules for Matlab or Octave. In addition, we have some developments in view concerning belief functions. To start with, the following silx-independent example gives a minimalist overview of the library's features. Other examples, especially silx-integrated, are also available on the project's github. # Minimalist example (Dempster-Shafer fusion) ## Cargo.toml ```toml [package] name = "silx_furtif_dst" version = "0.1.2" edition = "2021" [dependencies] furtif-core = { version = "0.1.2", default-features = false } ``` ## main.rs ```rust use furtif_core::{ structs::{DiscountedFuser, EnumRule, Powerset}, traits::{ComplementedLattice, DiscountedFusion, IterableLattice, Lattice}, }; /// Furtif: a simple fusion of 2 masses by Dempster-Shafer rule pub fn main() -> Result<(),String> { // build a powerset generated by `A` `B` and `C` let powerset = Powerset::new_with_label( &["A".to_string(), "B".to_string(), "C".to_string()], 128 )?; // List of elements in the powerset (non-decreasing for the inclusion ordering) println!("==== Elements -------------"); let powerset = powerset.set_iterators(); for e in powerset.bottom_to_top()? { println!("{e} -> {}", powerset.to_string(&e)?); } // Some boolean operations and results // * `powerset.join(...)` is the disjunction operator // * `powerset.not(...)` is the boolean negation // * `powerset.meet(...)` is the conjunction operator println!("\n==== operators -------------"); let a = powerset.from_str("A")?; let b = powerset.from_str("B")?; let aub = powerset.join(&a,&b)?; let not_a = powerset.not(&a)?; let aub_n_not_a = powerset.meet(&aub, ¬_a)?; println!("aub: {} -> {}", aub, powerset.to_string(&aub)?); println!("not_a: {} -> {}", not_a, powerset.to_string(¬_a)?); println!("aub_n_not_a: {} -> {}", aub_n_not_a, powerset.to_string(&aub_n_not_a)?); println!("\n==== assignments -------------"); // Construction of two basic belief assignments let c = powerset.from_str("C")?; let buc = not_a; let cua = powerset.not(&b)?; let m1 = powerset.assignment() + (a, 3.0) + (aub, 3.0) + (buc, 4.0) + (); let m2 = powerset.assignment() + (c, 2.0) + (aub, 3.0) + (cua, 5.0) + (); println!("m1 -> {m1}"); println!("m2 -> {m2}"); // Computation of Dempster-Shafer fusion let engine = DiscountedFuser::new(512..=1024); let (fused,z) = engine.fuse(&powerset, &EnumRule::DempsterShafer,&[&m1,&m2])?; println!("fused / DS -> {fused}"); println!("z -> {z:.3}"); Ok(()) } ``` ## Typical output ``` ==== Elements ------------- 0 -> ⊥ 4 -> C 1 -> A 2 -> B 5 -> A | C 6 -> B | C 3 -> A | B 7 -> ⊤ ==== operators ------------- aub: 3 -> A | B not_a: 6 -> B | C aub_n_not_a: 2 -> B ==== assignments ------------- m1 -> [ 6 -> 0.4000, 3 -> 0.3000, 1 -> 0.3000, ] m2 -> [ 3 -> 0.3000, 5 -> 0.5000, 4 -> 0.2000, ] fused / DS -> [ 3 -> 0.1023, 4 -> 0.3182, 1 -> 0.4432, 2 -> 0.1364, ] z -> 0.120 ```