use super::position::GeneralizedPosition;
#[inline(always)]
pub fn subsumes(pos1: &GeneralizedPosition, pos2: &GeneralizedPosition, max_distance: u8) -> bool {
subsumes_standard(pos1, pos2, max_distance)
}
fn subsumes_standard(
pos1: &GeneralizedPosition,
pos2: &GeneralizedPosition,
_max_distance: u8,
) -> bool {
use GeneralizedPosition::*;
fn check_subsumption(i: i32, e: u8, j: i32, f: u8) -> bool {
if f <= e {
return false;
}
let error_diff = (f - e) as i32;
let offset_diff = (j - i).abs();
offset_diff <= error_diff
}
match (pos1, pos2) {
(
INonFinal {
offset: i,
errors: e,
},
INonFinal {
offset: j,
errors: f,
},
) => check_subsumption(*i, *e, *j, *f),
(
MFinal {
offset: i,
errors: e,
},
MFinal {
offset: j,
errors: f,
},
) => check_subsumption(*i, *e, *j, *f),
(
ITransposing {
offset: i,
errors: e,
},
ITransposing {
offset: j,
errors: f,
},
) => check_subsumption(*i, *e, *j, *f),
(
MTransposing {
offset: i,
errors: e,
},
MTransposing {
offset: j,
errors: f,
},
) => check_subsumption(*i, *e, *j, *f),
(
ISplitting {
offset: i,
errors: e,
..
},
ISplitting {
offset: j,
errors: f,
..
},
) => check_subsumption(*i, *e, *j, *f),
(
MSplitting {
offset: i,
errors: e,
..
},
MSplitting {
offset: j,
errors: f,
..
},
) => check_subsumption(*i, *e, *j, *f),
_ => false,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_subsumes_i_type_standard() {
let pos1 = GeneralizedPosition::new_i(1, 2, 3)
.expect("test fixture: GeneralizedPosition::new_i with valid args");
let pos2 = GeneralizedPosition::new_i(2, 3, 3)
.expect("test fixture: GeneralizedPosition::new_i with valid args");
assert!(subsumes(&pos1, &pos2, 3));
}
#[test]
fn test_not_subsumes_too_far() {
let pos1 = GeneralizedPosition::new_i(0, 2, 3)
.expect("test fixture: GeneralizedPosition::new_i with valid args");
let pos2 = GeneralizedPosition::new_i(-2, 3, 3)
.expect("test fixture: GeneralizedPosition::new_i with valid args");
assert!(!subsumes(&pos1, &pos2, 3));
}
#[test]
fn test_not_subsumes_same_errors() {
let pos1 = GeneralizedPosition::new_i(0, 1, 3)
.expect("test fixture: GeneralizedPosition::new_i with valid args");
let pos2 = GeneralizedPosition::new_i(1, 1, 3)
.expect("test fixture: GeneralizedPosition::new_i with valid args");
assert!(!subsumes(&pos1, &pos2, 3));
}
#[test]
fn test_subsumes_m_type_standard() {
let pos1 = GeneralizedPosition::new_m(-1, 0, 2)
.expect("test fixture: GeneralizedPosition::new_m with valid args");
let pos2 = GeneralizedPosition::new_m(-2, 1, 2)
.expect("test fixture: GeneralizedPosition::new_m with valid args");
assert!(subsumes(&pos1, &pos2, 2));
}
#[test]
fn test_not_subsumes_different_types() {
let i_pos = GeneralizedPosition::new_i(0, 0, 2)
.expect("test fixture: GeneralizedPosition::new_i with valid args");
let m_pos = GeneralizedPosition::new_m(0, 0, 2)
.expect("test fixture: GeneralizedPosition::new_m with valid args");
assert!(!subsumes(&i_pos, &m_pos, 2));
assert!(!subsumes(&m_pos, &i_pos, 2));
}
#[test]
fn test_subsumes_reflexive_false() {
let pos = GeneralizedPosition::new_i(0, 1, 3)
.expect("test fixture: GeneralizedPosition::new_i with valid args");
assert!(!subsumes(&pos, &pos, 3));
}
#[test]
fn test_subsumes_boundary_case() {
let pos1 = GeneralizedPosition::new_i(0, 0, 3)
.expect("test fixture: GeneralizedPosition::new_i with valid args");
let pos2 = GeneralizedPosition::new_i(2, 2, 3)
.expect("test fixture: GeneralizedPosition::new_i with valid args");
assert!(subsumes(&pos1, &pos2, 3));
}
#[test]
fn test_subsumes_negative_offsets() {
let pos1 = GeneralizedPosition::new_i(-1, 2, 3)
.expect("test fixture: GeneralizedPosition::new_i with valid args");
let pos2 = GeneralizedPosition::new_i(0, 3, 3)
.expect("test fixture: GeneralizedPosition::new_i with valid args");
assert!(subsumes(&pos1, &pos2, 3));
}
#[test]
fn test_same_variant_subsumption_transposing() {
let pos1 = GeneralizedPosition::new_i_transposing(-1, 1, 2)
.expect("test fixture: GeneralizedPosition::new_i_transposing with valid args");
let pos2 = GeneralizedPosition::new_i_transposing(0, 2, 2)
.expect("test fixture: GeneralizedPosition::new_i_transposing with valid args");
assert!(subsumes(&pos1, &pos2, 2));
}
#[test]
fn test_same_variant_subsumption_splitting() {
let pos1 = GeneralizedPosition::new_i_splitting(-1, 1, 2, 'a')
.expect("test fixture: GeneralizedPosition::new_i_splitting with valid args");
let pos2 = GeneralizedPosition::new_i_splitting(0, 2, 2, 'a')
.expect("test fixture: GeneralizedPosition::new_i_splitting with valid args");
assert!(subsumes(&pos1, &pos2, 2));
}
#[test]
fn test_same_variant_subsumption_m_transposing() {
let pos1 = GeneralizedPosition::new_m_transposing(-1, 1, 2)
.expect("test fixture: GeneralizedPosition::new_m_transposing with valid args");
let pos2 = GeneralizedPosition::new_m_transposing(-2, 2, 2)
.expect("test fixture: GeneralizedPosition::new_m_transposing with valid args");
assert!(subsumes(&pos1, &pos2, 2));
}
#[test]
fn test_same_variant_subsumption_m_splitting() {
let pos1 = GeneralizedPosition::new_m_splitting(-1, 1, 2, 'a')
.expect("test fixture: GeneralizedPosition::new_m_splitting with valid args");
let pos2 = GeneralizedPosition::new_m_splitting(-2, 2, 2, 'a')
.expect("test fixture: GeneralizedPosition::new_m_splitting with valid args");
assert!(subsumes(&pos1, &pos2, 2));
}
#[test]
fn test_different_variant_no_subsumption_usual_vs_transposing() {
let pos1 = GeneralizedPosition::new_i(0, 1, 2)
.expect("test fixture: GeneralizedPosition::new_i with valid args");
let pos2 = GeneralizedPosition::new_i_transposing(0, 2, 2)
.expect("test fixture: GeneralizedPosition::new_i_transposing with valid args");
assert!(!subsumes(&pos1, &pos2, 2));
assert!(!subsumes(&pos2, &pos1, 2));
}
#[test]
fn test_different_variant_no_subsumption_transposing_vs_splitting() {
let pos1 = GeneralizedPosition::new_i_transposing(0, 1, 2)
.expect("test fixture: GeneralizedPosition::new_i_transposing with valid args");
let pos2 = GeneralizedPosition::new_i_splitting(0, 2, 2, 'a')
.expect("test fixture: GeneralizedPosition::new_i_splitting with valid args");
assert!(!subsumes(&pos1, &pos2, 2));
assert!(!subsumes(&pos2, &pos1, 2));
}
#[test]
fn test_different_variant_no_subsumption_usual_vs_splitting() {
let pos1 = GeneralizedPosition::new_i(0, 1, 2)
.expect("test fixture: GeneralizedPosition::new_i with valid args");
let pos2 = GeneralizedPosition::new_i_splitting(0, 2, 2, 'a')
.expect("test fixture: GeneralizedPosition::new_i_splitting with valid args");
assert!(!subsumes(&pos1, &pos2, 2));
assert!(!subsumes(&pos2, &pos1, 2));
}
#[test]
fn test_different_variant_same_offset_errors() {
let i_usual = GeneralizedPosition::new_i(0, 1, 2)
.expect("test fixture: GeneralizedPosition::new_i with valid args");
let i_trans = GeneralizedPosition::new_i_transposing(0, 1, 2)
.expect("test fixture: GeneralizedPosition::new_i_transposing with valid args");
let i_split = GeneralizedPosition::new_i_splitting(0, 1, 2, 'a')
.expect("test fixture: GeneralizedPosition::new_i_splitting with valid args");
assert!(!subsumes(&i_usual, &i_trans, 2));
assert!(!subsumes(&i_usual, &i_split, 2));
assert!(!subsumes(&i_trans, &i_usual, 2));
assert!(!subsumes(&i_trans, &i_split, 2));
assert!(!subsumes(&i_split, &i_usual, 2));
assert!(!subsumes(&i_split, &i_trans, 2));
}
#[test]
fn test_m_type_variants_no_cross_subsumption() {
let m_usual = GeneralizedPosition::new_m(0, 1, 2)
.expect("test fixture: GeneralizedPosition::new_m with valid args");
let m_trans = GeneralizedPosition::new_m_transposing(0, 1, 2)
.expect("test fixture: GeneralizedPosition::new_m_transposing with valid args");
let m_split = GeneralizedPosition::new_m_splitting(0, 1, 2, 'a')
.expect("test fixture: GeneralizedPosition::new_m_splitting with valid args");
assert!(!subsumes(&m_usual, &m_trans, 2));
assert!(!subsumes(&m_usual, &m_split, 2));
assert!(!subsumes(&m_trans, &m_usual, 2));
assert!(!subsumes(&m_trans, &m_split, 2));
assert!(!subsumes(&m_split, &m_usual, 2));
assert!(!subsumes(&m_split, &m_trans, 2));
}
}