use crate::transducer::universal::position::{
MergeAndSplit, PositionVariant, Transposition, UniversalPosition,
};
#[cfg(test)]
use crate::transducer::universal::position::Standard;
#[inline(always)]
pub fn subsumes<V: PositionVariant>(
pos1: &UniversalPosition<V>,
pos2: &UniversalPosition<V>,
max_distance: u8,
) -> bool {
subsumes_impl(pos1, pos2, max_distance)
}
#[inline(always)]
fn subsumes_impl<V: PositionVariant>(
pos1: &UniversalPosition<V>,
pos2: &UniversalPosition<V>,
_max_distance: u8,
) -> bool {
use UniversalPosition::*;
match (pos1, pos2) {
(
INonFinal {
offset: i,
errors: e,
..
},
INonFinal {
offset: j,
errors: f,
..
},
) => {
if *f <= *e {
return false;
}
let error_diff = f - e;
let dist_raw = j - i;
let distance = if dist_raw >= 0 {
dist_raw as u8
} else {
(-dist_raw) as u8
};
distance <= error_diff
}
(
MFinal {
offset: i,
errors: e,
..
},
MFinal {
offset: j,
errors: f,
..
},
) => {
if *f <= *e {
return false;
}
let error_diff = f - e;
let dist_raw = j - i;
let distance = if dist_raw >= 0 {
dist_raw as u8
} else {
(-dist_raw) as u8
};
distance <= error_diff
}
_ => false,
}
}
#[allow(dead_code)]
fn subsumes_transposition(
pos1: &UniversalPosition<Transposition>,
pos2: &UniversalPosition<Transposition>,
_max_distance: u8,
) -> bool {
use crate::transducer::universal::position::TranspositionState;
use UniversalPosition::*;
match (pos1, pos2) {
(
INonFinal {
offset: i,
errors: e,
variant_state: v1,
},
INonFinal {
offset: j,
errors: f,
variant_state: v2,
},
) => {
if *f <= *e {
return false;
}
let distance = match (v1, v2) {
(TranspositionState::Usual, TranspositionState::Usual) => (j - i).abs() as u8,
(TranspositionState::Transposing, TranspositionState::Usual) => {
(j + 1 - i).abs() as u8
}
_ => return false,
};
let error_diff = f - e;
distance <= error_diff
}
(
MFinal {
offset: i,
errors: e,
variant_state: v1,
},
MFinal {
offset: j,
errors: f,
variant_state: v2,
},
) => {
if *f <= *e {
return false;
}
let distance = match (v1, v2) {
(TranspositionState::Usual, TranspositionState::Usual) => (j - i).abs() as u8,
(TranspositionState::Transposing, TranspositionState::Usual) => {
(j + 1 - i).abs() as u8
}
_ => return false,
};
let error_diff = f - e;
distance <= error_diff
}
_ => false,
}
}
#[allow(dead_code)]
fn subsumes_merge_split(
pos1: &UniversalPosition<MergeAndSplit>,
pos2: &UniversalPosition<MergeAndSplit>,
_max_distance: u8,
) -> bool {
use crate::transducer::universal::position::MergeSplitState;
use UniversalPosition::*;
match (pos1, pos2) {
(
INonFinal {
offset: i,
errors: e,
variant_state: v1,
},
INonFinal {
offset: j,
errors: f,
variant_state: v2,
},
) => {
if *f <= *e {
return false;
}
match (v1, v2) {
(MergeSplitState::Usual, MergeSplitState::Usual)
| (MergeSplitState::Splitting, MergeSplitState::Usual) => {
let error_diff = f - e;
let distance = (j - i).abs() as u8;
distance <= error_diff
}
_ => false,
}
}
(
MFinal {
offset: i,
errors: e,
variant_state: v1,
},
MFinal {
offset: j,
errors: f,
variant_state: v2,
},
) => {
if *f <= *e {
return false;
}
match (v1, v2) {
(MergeSplitState::Usual, MergeSplitState::Usual)
| (MergeSplitState::Splitting, MergeSplitState::Usual) => {
let error_diff = f - e;
let distance = (j - i).abs() as u8;
distance <= error_diff
}
_ => false,
}
}
_ => false,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_subsumption_basic_i_type() {
let pos1 = UniversalPosition::<Standard>::new_i(1, 1, 3)
.expect("test fixture: UniversalPosition::new_i with valid args");
let pos2 = UniversalPosition::<Standard>::new_i(2, 2, 3)
.expect("test fixture: UniversalPosition::new_i with valid args");
assert!(subsumes(&pos1, &pos2, 3));
}
#[test]
fn test_subsumption_fails_distance_too_large() {
let pos1 = UniversalPosition::<Standard>::new_i(0, 1, 3)
.expect("test fixture: UniversalPosition::new_i with valid args");
let pos2 = UniversalPosition::<Standard>::new_i(2, 2, 3)
.expect("test fixture: UniversalPosition::new_i with valid args");
assert!(!subsumes(&pos1, &pos2, 3));
}
#[test]
fn test_subsumption_fails_equal_errors() {
let pos1 = UniversalPosition::<Standard>::new_i(1, 1, 3)
.expect("test fixture: UniversalPosition::new_i with valid args");
let pos2 = UniversalPosition::<Standard>::new_i(1, 1, 3)
.expect("test fixture: UniversalPosition::new_i with valid args");
assert!(!subsumes(&pos1, &pos2, 3));
}
#[test]
fn test_subsumption_m_type() {
let pos1 = UniversalPosition::<Standard>::new_m(-2, 0, 2)
.expect("test fixture: UniversalPosition::new_m with valid args");
let pos2 = UniversalPosition::<Standard>::new_m(-1, 1, 2)
.expect("test fixture: UniversalPosition::new_m with valid args");
assert!(subsumes(&pos1, &pos2, 2));
}
#[test]
fn test_no_subsumption_across_types() {
let i_pos = UniversalPosition::<Standard>::new_i(0, 0, 2)
.expect("test fixture: UniversalPosition::new_i with valid args");
let m_pos = UniversalPosition::<Standard>::new_m(0, 0, 2)
.expect("test fixture: UniversalPosition::new_m with valid args");
assert!(!subsumes(&i_pos, &m_pos, 2));
assert!(!subsumes(&m_pos, &i_pos, 2));
}
#[test]
fn test_subsumption_i_exact_boundary() {
let pos1 = UniversalPosition::<Standard>::new_i(0, 1, 3)
.expect("test fixture: UniversalPosition::new_i with valid args");
let pos2 = UniversalPosition::<Standard>::new_i(1, 2, 3)
.expect("test fixture: UniversalPosition::new_i with valid args");
assert!(subsumes(&pos1, &pos2, 3));
}
#[test]
fn test_subsumption_i_negative_offsets() {
let pos1 = UniversalPosition::<Standard>::new_i(-1, 1, 3)
.expect("test fixture: UniversalPosition::new_i with valid args");
let pos2 = UniversalPosition::<Standard>::new_i(-2, 2, 3)
.expect("test fixture: UniversalPosition::new_i with valid args");
assert!(subsumes(&pos1, &pos2, 3));
}
#[test]
fn test_subsumption_i_zero_offset() {
let pos1 = UniversalPosition::<Standard>::new_i(0, 0, 2)
.expect("test fixture: UniversalPosition::new_i with valid args");
let pos2 = UniversalPosition::<Standard>::new_i(0, 1, 2)
.expect("test fixture: UniversalPosition::new_i with valid args");
assert!(subsumes(&pos1, &pos2, 2));
}
#[test]
fn test_subsumption_i_large_error_diff() {
let pos1 = UniversalPosition::<Standard>::new_i(0, 1, 3)
.expect("test fixture: UniversalPosition::new_i with valid args");
let pos2 = UniversalPosition::<Standard>::new_i(2, 3, 3)
.expect("test fixture: UniversalPosition::new_i with valid args");
assert!(subsumes(&pos1, &pos2, 3));
}
#[test]
fn test_no_subsumption_i_reverse_order() {
let pos1 = UniversalPosition::<Standard>::new_i(2, 2, 3)
.expect("test fixture: UniversalPosition::new_i with valid args");
let pos2 = UniversalPosition::<Standard>::new_i(1, 1, 3)
.expect("test fixture: UniversalPosition::new_i with valid args");
assert!(!subsumes(&pos1, &pos2, 3));
}
#[test]
fn test_subsumption_m_exact_boundary() {
let pos1 = UniversalPosition::<Standard>::new_m(-2, 0, 2)
.expect("test fixture: UniversalPosition::new_m with valid args");
let pos2 = UniversalPosition::<Standard>::new_m(-1, 1, 2)
.expect("test fixture: UniversalPosition::new_m with valid args");
assert!(subsumes(&pos1, &pos2, 2));
}
#[test]
fn test_subsumption_m_zero_offset_to_negative() {
let pos1 = UniversalPosition::<Standard>::new_m(0, 0, 2)
.expect("test fixture: UniversalPosition::new_m with valid args");
let pos2 = UniversalPosition::<Standard>::new_m(-1, 1, 2)
.expect("test fixture: UniversalPosition::new_m with valid args");
assert!(subsumes(&pos1, &pos2, 2));
}
#[test]
fn test_no_subsumption_m_distance_exceeds() {
let pos1 = UniversalPosition::<Standard>::new_m(-4, 1, 3)
.expect("test fixture: UniversalPosition::new_m with valid args");
let pos2 = UniversalPosition::<Standard>::new_m(-2, 2, 3)
.expect("test fixture: UniversalPosition::new_m with valid args");
assert!(!subsumes(&pos1, &pos2, 3));
}
#[test]
fn test_no_subsumption_m_equal_errors() {
let pos1 = UniversalPosition::<Standard>::new_m(-1, 1, 2)
.expect("test fixture: UniversalPosition::new_m with valid args");
let pos2 = UniversalPosition::<Standard>::new_m(-2, 1, 2)
.expect("test fixture: UniversalPosition::new_m with valid args");
assert!(!subsumes(&pos1, &pos2, 2));
}
#[test]
fn test_no_reflexive_subsumption() {
let pos = UniversalPosition::<Standard>::new_i(1, 1, 2)
.expect("test fixture: UniversalPosition::new_i with valid args");
assert!(!subsumes(&pos, &pos, 2));
}
#[test]
fn test_subsumption_not_symmetric() {
let pos1 = UniversalPosition::<Standard>::new_i(1, 1, 3)
.expect("test fixture: UniversalPosition::new_i with valid args");
let pos2 = UniversalPosition::<Standard>::new_i(2, 2, 3)
.expect("test fixture: UniversalPosition::new_i with valid args");
assert!(subsumes(&pos1, &pos2, 3)); assert!(!subsumes(&pos2, &pos1, 3)); }
#[test]
fn test_subsumption_with_transposition_variant() {
let pos1 = UniversalPosition::<Transposition>::new_i(1, 1, 3)
.expect("test fixture: UniversalPosition::new_i with valid args");
let pos2 = UniversalPosition::<Transposition>::new_i(2, 2, 3)
.expect("test fixture: UniversalPosition::new_i with valid args");
assert!(subsumes(&pos1, &pos2, 3));
}
#[test]
fn test_subsumption_with_merge_split_variant() {
let pos1 = UniversalPosition::<MergeAndSplit>::new_i(1, 1, 3)
.expect("test fixture: UniversalPosition::new_i with valid args");
let pos2 = UniversalPosition::<MergeAndSplit>::new_i(2, 2, 3)
.expect("test fixture: UniversalPosition::new_i with valid args");
assert!(subsumes(&pos1, &pos2, 3));
}
#[test]
fn test_subsumption_max_distance() {
let pos1 = UniversalPosition::<Standard>::new_i(2, 2, 3)
.expect("test fixture: UniversalPosition::new_i with valid args");
let pos2 = UniversalPosition::<Standard>::new_i(3, 3, 3)
.expect("test fixture: UniversalPosition::new_i with valid args");
assert!(subsumes(&pos1, &pos2, 3));
}
#[test]
fn test_subsumption_min_distance() {
let pos1 = UniversalPosition::<Standard>::new_i(0, 0, 1)
.expect("test fixture: UniversalPosition::new_i with valid args");
let pos2 = UniversalPosition::<Standard>::new_i(0, 1, 1)
.expect("test fixture: UniversalPosition::new_i with valid args");
assert!(subsumes(&pos1, &pos2, 1));
}
#[test]
fn test_subsumption_mixed_sign_offsets() {
let pos1 = UniversalPosition::<Standard>::new_i(-1, 2, 3)
.expect("test fixture: UniversalPosition::new_i with valid args");
let pos2 = UniversalPosition::<Standard>::new_i(1, 3, 3)
.expect("test fixture: UniversalPosition::new_i with valid args");
assert!(!subsumes(&pos1, &pos2, 3));
}
}