///|
/// Different comparisons answer different questions; none implies source identity.
pub(all) struct MapComparison {
same_source : Bool
same_topology : Bool
same_cut_geometry : Bool
same_size_bands : Bool
same_fragment_sequences : Bool
added_top_cuts : Array[Int]
removed_top_cuts : Array[Int]
} derive(Eq, Debug, ToJson)
///|
/// Sort literal oriented sequences; this ignores fragment order, NOT base rotation.
fn fragment_sequences(report : Digest) -> Array[String] {
let strings = report.fragments.map(f => f.sequence)
strings.sort()
strings
}
///|
/// Verify both reports then distinguish coordinate, size and sequence equivalence.
/// Rotated circular references may share size bands while their coordinates differ.
pub fn compare_maps(
left_dna : Dna,
left_enzymes : Array[Enzyme],
left : Digest,
right_dna : Dna,
right_enzymes : Array[Enzyme],
right : Digest,
) -> MapComparison raise RestrictError {
verify_digest(left_dna, left_enzymes, left)
verify_digest(right_dna, right_enzymes, right)
let lt = left.cuts.map(s => s.top)
let rt = right.cuts.map(s => s.top)
let lset : Map[Int, Bool] = Map([])
let rset : Map[Int, Bool] = Map([])
for x in lt {
lset[x] = true
}
for x in rt {
rset[x] = true
}
{
same_source: left_dna.bases == right_dna.bases,
same_topology: left.topology == right.topology,
same_cut_geometry: left.topology == right.topology &&
left.source_length == right.source_length &&
left.cuts.map(s => (s.top, s.stagger)) ==
right.cuts.map(s => (s.top, s.stagger)),
same_size_bands: size_bands(left.fragments) == size_bands(right.fragments),
same_fragment_sequences: fragment_sequences(left) ==
fragment_sequences(right),
added_top_cuts: rt.filter(x => !lset.contains(x)),
removed_top_cuts: lt.filter(x => !rset.contains(x)),
}
}