use crate::domain::niseci::lessclone::{
CampionamentoNISECI, ClassiEtaAlieniNISECI, ClassiEtaSpecieNISECI, InfoPopolazioniAlieneNISECI,
};
use crate::domain::niseci::{IdSpecieNISECI, RiferimentoNISECI};
use std::collections::hash_map::Entry;
use std::collections::HashMap;
#[derive(Clone)]
pub struct SubmetricheX3 {
classi_eta: ClassiEtaSpecieNISECI,
rapporto_ad_juv: Option<f32>,
criterio_a: u8,
criterio_b: u8,
}
impl SubmetricheX3 {
pub fn new(
classi_eta: ClassiEtaSpecieNISECI,
rapporto_ad_juv: Option<f32>,
criterio_a: u8,
criterio_b: u8,
) -> Self {
Self {
classi_eta,
rapporto_ad_juv,
criterio_a,
criterio_b,
}
}
#[inline(always)]
pub fn get_ref_classi_eta(&self) -> &ClassiEtaSpecieNISECI {
&self.classi_eta
}
#[inline(always)]
pub fn get_rapporto_ad_juv(&self) -> Option<f32> {
self.rapporto_ad_juv
}
#[inline(always)]
pub fn get_criterio_a(&self) -> u8 {
self.criterio_a
}
#[inline(always)]
pub fn get_criterio_b(&self) -> u8 {
self.criterio_b
}
}
pub struct MetricheX3 {
criterio_a: f32,
criterio_b: f32,
submetriche_map: HashMap<IdSpecieNISECI, SubmetricheX3>,
}
impl MetricheX3 {
pub fn new(
criterio_a: f32,
criterio_b: f32,
submetriche_map: HashMap<IdSpecieNISECI, SubmetricheX3>,
) -> Self {
Self {
criterio_a,
criterio_b,
submetriche_map,
}
}
#[inline(always)]
pub fn get_criterio_a(&self) -> f32 {
self.criterio_a
}
#[inline(always)]
pub fn get_criterio_b(&self) -> f32 {
self.criterio_b
}
#[inline(always)]
pub fn get_ref_submetriche_map(&self) -> &HashMap<IdSpecieNISECI, SubmetricheX3> {
&self.submetriche_map
}
}
pub fn calculate_x3(
c: &CampionamentoNISECI,
r: &RiferimentoNISECI,
) -> Result<(f32, Option<MetricheX3>), Vec<String>> {
let alieni_indigeni = c.get_numero_pesci_alieni_e_indigeni(r);
if alieni_indigeni.alieni() == 0 {
return Ok((1.0, None));
}
if alieni_indigeni.alieni() >= alieni_indigeni.indigeni() {
return Ok((0.0, None));
}
let classi_eta = calculate_classi_eta_alieni(c, r);
let info_pop_aliene = InfoPopolazioniAlieneNISECI::get_info_pop_aliene(&classi_eta, r)?;
let epsilon: f32 = 1e-6;
if (info_pop_aliene.tipo_1().popolazione_piu_strutt() - 1.0).abs() < epsilon {
return Ok((0.0, None));
}
let a = calculate_a(&info_pop_aliene);
let b = calculate_b(&info_pop_aliene);
let x3 = 0.5 * (a + b);
let rounded_x3 = (1000.0 * x3).round() / 1000.0;
let mut errors = Vec::<String>::new();
let mut submetriche = HashMap::<IdSpecieNISECI, SubmetricheX3>::new();
for (key, val) in info_pop_aliene.tipo_1().intermediates_map() {
match submetriche.entry(*key) {
Entry::Occupied(_) => {}
Entry::Vacant(vacant_entry) => {
vacant_entry.insert(
SubmetricheX3::new(
ClassiEtaSpecieNISECI::new_empty(),
val.get_rapporto_ad_juv(),
val.get_criterio_a(),
val.get_criterio_b(),
),
);
}
}
}
for (key, val) in classi_eta.map_tipo_1() {
match submetriche.entry(*key) {
Entry::Occupied(mut entry) => {
let submetr = entry.get_mut();
*submetr = SubmetricheX3::new(
val.clone(),
submetr.get_rapporto_ad_juv(),
submetr.get_criterio_a(),
submetr.get_criterio_b(),
);
}
Entry::Vacant(_) => {
errors.push(format!(
"Errore: specie {} ha classi eta ma manca degli altri valori intermedi",
key
));
}
}
}
for (key, val) in info_pop_aliene.tipo_2().intermediates_map() {
match submetriche.entry(*key) {
Entry::Occupied(_) => {}
Entry::Vacant(vacant_entry) => {
vacant_entry.insert(
SubmetricheX3::new(
ClassiEtaSpecieNISECI::new_empty(),
val.get_rapporto_ad_juv(),
val.get_criterio_a(),
val.get_criterio_b(),
),
);
}
}
}
for (key, val) in classi_eta.map_tipo_2() {
match submetriche.entry(*key) {
Entry::Occupied(mut entry) => {
let submetr = entry.get_mut();
*submetr = SubmetricheX3::new(
val.clone(),
submetr.get_rapporto_ad_juv(),
submetr.get_criterio_a(),
submetr.get_criterio_b(),
);
}
Entry::Vacant(_) => {
errors.push(format!(
"Errore: specie {} ha classi eta ma manca degli altri valori intermedi",
key
));
}
}
}
for (key, val) in info_pop_aliene.tipo_3().intermediates_map() {
match submetriche.entry(*key) {
Entry::Occupied(_) => {}
Entry::Vacant(vacant_entry) => {
vacant_entry.insert(
SubmetricheX3::new(
ClassiEtaSpecieNISECI::new_empty(),
val.get_rapporto_ad_juv(),
val.get_criterio_a(),
val.get_criterio_b(),
),
);
}
}
}
for (key, val) in classi_eta.map_tipo_3() {
match submetriche.entry(*key) {
Entry::Occupied(mut entry) => {
let submetr = entry.get_mut();
*submetr = SubmetricheX3::new(
val.clone(),
submetr.get_rapporto_ad_juv(),
submetr.get_criterio_a(),
submetr.get_criterio_b(),
);
}
Entry::Vacant(_) => {
errors.push(format!(
"Errore: specie {} ha classi eta ma manca degli altri valori intermedi",
key
));
}
}
}
if !errors.is_empty() {
return Err(errors);
}
Ok((rounded_x3, Some(MetricheX3::new(a, b, submetriche))))
}
fn calculate_classi_eta_alieni(
c: &CampionamentoNISECI,
r: &RiferimentoNISECI,
) -> ClassiEtaAlieniNISECI {
let mut classi_eta = ClassiEtaAlieniNISECI::new();
for cattura in c {
let id = cattura.id();
debug_assert!(r.contains_plain_id(id));
let specie = r
.get_ref_by_plain_id(id)
.expect("Riferimento should contain this id");
if specie.tipo_alloctono() == 1 {
match classi_eta.map_tipo_1.entry(id) {
Entry::Occupied(mut entry) => {
let v: &mut ClassiEtaSpecieNISECI = entry.get_mut();
v.update_classi_eta(cattura, r);
}
Entry::Vacant(entry) => {
ClassiEtaSpecieNISECI::new_cl_prevalorizzata(cattura, r)
.and_then(|c| Some(entry.insert(c)));
}
};
} else if specie.tipo_alloctono() == 2 {
match classi_eta.map_tipo_2.entry(id) {
Entry::Occupied(mut entry) => {
let v: &mut ClassiEtaSpecieNISECI = entry.get_mut();
v.update_classi_eta(cattura, r);
}
Entry::Vacant(entry) => {
ClassiEtaSpecieNISECI::new_cl_prevalorizzata(cattura, r)
.and_then(|c| Some(entry.insert(c)));
}
};
} else if specie.tipo_alloctono() == 3 {
match classi_eta.map_tipo_3.entry(id) {
Entry::Occupied(mut entry) => {
let v: &mut ClassiEtaSpecieNISECI = entry.get_mut();
v.update_classi_eta(cattura, r);
}
Entry::Vacant(entry) => {
ClassiEtaSpecieNISECI::new_cl_prevalorizzata(cattura, r)
.and_then(|c| Some(entry.insert(c)));
}
};
}
classi_eta.set_tot_specie_autoctone(c.get_tot_specie_autoctone_attese(r));
}
classi_eta.set_tot_specie_aliene(
classi_eta.map_tipo_1().len()
+ classi_eta.map_tipo_2().len()
+ classi_eta.map_tipo_3().len(),
);
classi_eta
}
fn calculate_a(info: &InfoPopolazioniAlieneNISECI) -> f32 {
if info.tipo_1().tot_species() > 0 && info.tipo_1().popolazione_piu_strutt() < 1.0 {
return 0.5;
}
if info.tipo_2().tot_species() != 0
&& info.tipo_2().tot_species() >= info.tot_specie_autoctone()
{
return 0.5;
}
if info.tipo_2().tot_species() != 0 && info.tipo_2().tot_species() < info.tot_specie_autoctone()
{
return 0.75;
}
if info.tipo_3().tot_species() >= info.tot_specie_autoctone() {
return 0.75;
}
if info.tipo_3().tot_species() != 0 && info.tipo_3().tot_species() < info.tot_specie_autoctone()
{
return 0.85;
}
1.0
}
fn calculate_b(info: &InfoPopolazioniAlieneNISECI) -> f32 {
let specie_mediamente_strutt = info.get_species_mediamente_strutt();
let species_destrutt = info.get_species_destrutt();
let i2 = 0.5 * (specie_mediamente_strutt as f32 / info.tot_specie_aliene() as f32);
let i3 = species_destrutt as f32 / info.tot_specie_aliene() as f32;
i2 + i3
}
#[cfg(test)]
pub mod tests {
use super::*;
#[test]
fn calculate_b_tutte_destrutt() {
let mut info_aliene = InfoPopolazioniAlieneNISECI::new();
info_aliene.tipo_3.species_destrutt = 10;
info_aliene.tipo_2.species_destrutt = 20;
info_aliene.tipo_3.species_strutt = 20;
info_aliene.tot_specie_aliene = 50;
let b = calculate_b(&info_aliene);
assert_eq!(b, 0.6);
info_aliene.tipo_3.species_strutt = 0;
info_aliene.tot_specie_aliene = 30;
let b = calculate_b(&info_aliene);
assert_eq!(b, 1.0);
}
#[test]
fn calculate_b_tutte_mediam_strutt() {
let mut info_aliene = InfoPopolazioniAlieneNISECI::new();
info_aliene.tipo_3.species_mediamente_strutt = 10;
info_aliene.tipo_2.species_mediamente_strutt = 20;
info_aliene.tipo_3.species_strutt = 20;
info_aliene.tot_specie_aliene = 50;
let b = calculate_b(&info_aliene);
assert_eq!(b, 0.3);
info_aliene.tipo_3.species_strutt = 0;
info_aliene.tot_specie_aliene = 30;
let b = calculate_b(&info_aliene);
assert_eq!(b, 0.5);
}
#[test]
fn calculate_b_miscellaneous() {
let mut info_aliene = InfoPopolazioniAlieneNISECI::new();
info_aliene.tipo_3.species_mediamente_strutt = 10;
info_aliene.tipo_2.species_mediamente_strutt = 20;
info_aliene.tipo_3.species_destrutt = 10;
info_aliene.tipo_2.species_destrutt = 20;
info_aliene.tipo_3.species_strutt = 20;
info_aliene.tot_specie_aliene = 80;
let b = calculate_b(&info_aliene);
assert_eq!(b, 0.5625);
}
#[test]
fn calculate_a_tipo_1_presente_ma_no_strutt() {
let mut info = InfoPopolazioniAlieneNISECI::new();
info.tipo_1.tot_species = 2;
info.tipo_1.species_mediamente_strutt = 2;
info.tipo_1.popolazione_piu_strutt = 0.5;
let a = calculate_a(&info);
assert_eq!(a, 0.5);
info.tipo_1.species_destrutt = 1;
info.tipo_1.tot_species = 3;
let a = calculate_a(&info);
assert_eq!(a, 0.5);
}
#[test]
fn calculate_a_tipo_2_magg_autoctone() {
let mut info = InfoPopolazioniAlieneNISECI::new();
info.tipo_2.tot_species = 3;
info.tot_specie_autoctone = 2;
let a = calculate_a(&info);
assert_eq!(a, 0.5);
}
#[test]
fn calculate_a_tipo_2_min_autoctone() {
let mut info = InfoPopolazioniAlieneNISECI::new();
info.tipo_2.tot_species = 2;
info.tot_specie_autoctone = 3;
let a = calculate_a(&info);
assert_eq!(a, 0.75);
}
#[test]
fn calculate_a_tipo_3_magg_autoctone() {
let mut info = InfoPopolazioniAlieneNISECI::new();
info.tipo_3.tot_species = 3;
info.tot_specie_autoctone = 2;
let a = calculate_a(&info);
assert_eq!(a, 0.75);
}
#[test]
fn calculate_a_tipo_3_min_autoctone() {
let mut info = InfoPopolazioniAlieneNISECI::new();
info.tipo_3.tot_species = 2;
info.tot_specie_autoctone = 3;
let a = calculate_a(&info);
assert_eq!(a, 0.85);
}
#[test]
fn calculate_a_progressive_scaling() {
let mut info = InfoPopolazioniAlieneNISECI::new();
info.tipo_3.tot_species = 2;
info.tot_specie_autoctone = 3;
let a = calculate_a(&info);
assert_eq!(a, 0.85);
info.tipo_2.tot_species = 2;
let a = calculate_a(&info);
assert_eq!(a, 0.75);
info.tipo_1.tot_species = 2;
info.tipo_1.species_mediamente_strutt = 2;
info.tipo_1.popolazione_piu_strutt = 0.5;
let a = calculate_a(&info);
assert_eq!(a, 0.5);
info.tipo_1.species_destrutt = 1;
info.tipo_1.tot_species = 3;
let a = calculate_a(&info);
assert_eq!(a, 0.5);
}
}