use crate::{ENDMARKER, SOURCE_KEY, SOURCE_VALUE, REF_SAMPLE, REFERENCE_SAMPLES_KEY};
use crate::{Segment, GBWT, BidirectionalState, Orientation, Pos};
use crate::bwt::Record;
use crate::gbwt::{SequenceIter, Metadata};
use crate::graph::Graph;
use crate::graph::SegmentIter as GraphSegmentIter;
use crate::headers::{Header, GBZPayload};
use crate::support::{DisjointSets, Tags};
use crate::support;
use simple_sds::bit_vector::{BitVector, OneIter, Identity};
use simple_sds::ops::{BitVec, Select};
use simple_sds::raw_vector::{RawVector, AccessRaw};
use simple_sds::serialize::Serialize;
use std::collections::BTreeSet;
use std::io::{Error, ErrorKind};
use std::iter::FusedIterator;
use std::ops::Range;
use std::path::Path;
use std::io;
#[cfg(test)]
mod tests;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct GBZ {
header: Header<GBZPayload>,
tags: Tags,
index: GBWT,
graph: Graph,
real_nodes: BitVector,
}
impl GBZ {
pub fn tags(&self) -> &Tags {
&self.tags
}
pub fn tags_mut(&mut self) -> &mut Tags {
&mut self.tags
}
fn reference_samples_impl(&self, also_generic: bool) -> Vec<String> {
let mut result: Vec<String> = Vec::new();
let ref_samples = self.index.tags().get(REFERENCE_SAMPLES_KEY);
if let Some(samples) = ref_samples {
for sample in samples.split(' ') {
result.push(String::from(sample));
}
}
if also_generic {
result.push(String::from(REF_SAMPLE));
}
result
}
pub fn reference_sample_ids(&self, also_generic: bool) -> Vec<usize> {
let metadata = self.metadata();
if metadata.is_none() {
return Vec::new();
}
let metadata = metadata.unwrap();
self.reference_samples_impl(also_generic).iter().filter_map(|sample| {
metadata.sample_id(sample)
}).collect()
}
pub fn reference_sample_names(&self, also_generic: bool) -> Vec<String> {
let metadata = self.metadata();
if metadata.is_none() {
return Vec::new();
}
let metadata = metadata.unwrap();
self.reference_samples_impl(also_generic).into_iter().filter_map(|sample| {
if metadata.sample_id(&sample).is_some() {
Some(sample)
} else {
None
}
}).collect()
}
pub fn set_reference_samples(&mut self, samples: &[String]) -> usize {
let metadata = self.metadata();
if metadata.is_none() {
return 0;
}
let metadata = metadata.unwrap();
let mut ref_samples: BTreeSet<String> = BTreeSet::new();
for sample in samples {
if metadata.sample_id(sample).is_some() && sample != REF_SAMPLE {
ref_samples.insert(sample.clone());
}
}
let mut value = String::new();
let mut count = 0;
for sample in ref_samples {
if count > 0 {
value.push(' ');
}
value.push_str(&sample);
count += 1;
}
if count > 0 {
self.index.tags_mut().insert(REFERENCE_SAMPLES_KEY, &value);
} else {
self.index.tags_mut().remove(REFERENCE_SAMPLES_KEY);
}
count
}
pub fn is_gbz<P: AsRef<Path>>(filename: P) -> bool {
Header::<GBZPayload>::found_in(filename)
}
#[inline]
fn graph_node_to_sequence(&self, node_id: usize) -> usize {
let gbwt_node = support::encode_node(node_id, Orientation::Forward);
Self::gbwt_node_to_sequence(&self.index, gbwt_node)
}
#[inline]
fn gbwt_node_to_sequence(index: &GBWT, gbwt_node: usize) -> usize {
(gbwt_node - index.first_node()) / 2
}
#[inline]
fn sequence_to_graph_node(&self, sequence_id: usize) -> usize {
support::node_id(sequence_id * 2 + self.index.first_node())
}
}
impl GBZ {
#[inline]
pub fn nodes(&self) -> usize {
self.graph.nodes()
}
#[inline]
pub fn min_node(&self) -> usize {
support::node_id(self.index.first_node())
}
#[inline]
pub fn max_node(&self) -> usize {
support::node_id(self.index.alphabet_size()) - 1
}
#[inline]
pub fn has_node(&self, node_id: usize) -> bool {
let gbwt_node = support::encode_node(node_id, Orientation::Forward);
self.index.has_node(gbwt_node) && self.real_nodes.get(Self::gbwt_node_to_sequence(&self.index, gbwt_node))
}
pub fn sequence(&self, node_id: usize) -> Option<&[u8]> {
if !self.has_node(node_id) {
return None;
}
let sequence_id = self.graph_node_to_sequence(node_id);
Some(self.graph.sequence(sequence_id))
}
pub fn sequence_len(&self, node_id: usize) -> Option<usize> {
if !self.has_node(node_id) {
return None;
}
let sequence_id = self.graph_node_to_sequence(node_id);
Some(self.graph.sequence_len(sequence_id))
}
pub fn node_iter(&self) -> NodeIter {
NodeIter {
parent: self,
iter: self.real_nodes.one_iter()
}
}
pub fn successors(&self, node_id: usize, orientation: Orientation) -> Option<EdgeIter> {
if !self.has_node(node_id) {
return None;
}
let gbwt_node = support::encode_node(node_id, orientation);
let record_id = self.index.node_to_record(gbwt_node);
let record = self.index.as_ref().record(record_id)?;
let next = if record.outdegree() > 0 && record.successor(0) == ENDMARKER { 1 } else { 0 };
let limit = record.outdegree();
Some(EdgeIter {
record,
next,
limit,
flip: false,
})
}
pub fn predecessors(&self, node_id: usize, orientation: Orientation) -> Option<EdgeIter> {
if !self.has_node(node_id) {
return None;
}
let gbwt_node = support::encode_node(node_id, orientation.flip());
let record_id = self.index.node_to_record(gbwt_node);
let record = self.index.as_ref().record(record_id)?;
let next = if record.outdegree() > 0 && record.successor(0) == ENDMARKER { 1 } else { 0 };
let limit = record.outdegree();
Some(EdgeIter {
record,
next,
limit,
flip: true,
})
}
}
impl GBZ {
#[inline]
pub fn has_translation(&self) -> bool {
self.graph.has_translation()
}
pub fn node_to_segment(&self, node_id: usize) -> Option<Segment> {
if self.has_translation() && self.has_node(node_id) {
Some(self.graph.node_to_segment(node_id))
} else {
None
}
}
pub fn segment_iter(&self) -> Option<SegmentIter> {
if self.has_translation() {
Some(SegmentIter {
parent: self,
iter: self.graph.segment_iter(),
})
} else {
None
}
}
pub fn segment_successors(&self, segment: &Segment, orientation: Orientation) -> Option<LinkIter> {
if segment.nodes.is_empty() || !self.has_translation() {
return None;
}
let node_id = match orientation {
Orientation::Forward => segment.nodes.end - 1,
Orientation::Reverse => segment.nodes.start,
};
let iter = self.successors(node_id, orientation)?;
Some(LinkIter {
parent: self,
iter,
})
}
pub fn segment_predecessors(&self, segment: &Segment, orientation: Orientation) -> Option<LinkIter> {
if segment.nodes.is_empty() || !self.has_translation() {
return None;
}
let node_id = match orientation {
Orientation::Forward => segment.nodes.start,
Orientation::Reverse => segment.nodes.end - 1,
};
let iter = self.predecessors(node_id, orientation)?;
Some(LinkIter {
parent: self,
iter,
})
}
}
impl GBZ {
#[inline]
pub fn paths(&self) -> usize {
self.index.sequences() / 2
}
pub fn path(&self, path_id: usize, orientation: Orientation) -> Option<PathIter> {
let iter = self.index.sequence(support::encode_path(path_id, orientation))?;
Some(PathIter {
iter,
})
}
pub fn segment_path(&self, path_id: usize, orientation: Orientation) -> Option<SegmentPathIter> {
if !self.has_translation() {
return None;
}
let iter = self.index.sequence(support::encode_path(path_id, orientation))?;
Some(SegmentPathIter {
parent: self,
iter,
next: None,
nodes: 0..0,
fail: false,
})
}
pub fn has_metadata(&self) -> bool {
self.index.has_metadata()
}
pub fn metadata(&self) -> Option<&Metadata> {
self.index.metadata()
}
pub fn search_state(&self, node_id: usize, orientation: Orientation) -> Option<BidirectionalState> {
self.index.bd_find(support::encode_node(node_id, orientation))
}
pub fn follow_forward(&self, state: &BidirectionalState) -> Option<StateIter> {
let (node_id, orientation) = support::decode_node(state.forward.node);
let iter = self.successors(node_id, orientation)?;
Some(StateIter {
iter,
state: state.clone(),
flip: false,
})
}
pub fn follow_backward(&self, state: &BidirectionalState) -> Option<StateIter> {
let state = state.flip();
let (node_id, orientation) = support::decode_node(state.forward.node);
let iter = self.successors(node_id, orientation)?;
Some(StateIter {
iter,
state,
flip: true,
})
}
}
impl GBZ {
pub fn weakly_connected_components(&self) -> Vec<Vec<usize>> {
let min_id = self.min_node();
let max_id = self.max_node();
let mut found = RawVector::with_len(max_id + 1 - min_id, false);
let mut sets = DisjointSets::new(max_id + 1 - min_id, min_id);
for start_id in self.node_iter() {
if found.bit(start_id - min_id) {
continue;
}
let mut stack: Vec<(usize, Orientation)> = vec![(start_id, Orientation::Forward)];
while let Some((node_id, orientation)) = stack.pop() {
if found.bit(node_id - min_id) {
continue;
}
found.set_bit(node_id - min_id, true);
for (next_id, next_o) in self.successors(node_id, orientation).unwrap() {
sets.union(node_id, next_id);
stack.push((next_id, next_o));
}
for (prev_id, prev_o) in self.predecessors(node_id, orientation).unwrap() {
sets.union(node_id, prev_id);
stack.push((prev_id, prev_o));
}
}
}
sets.extract(|node_id| self.has_node(node_id))
}
pub fn reference_positions(&self, interval: usize, verbose: bool) -> Vec<ReferencePath> {
if verbose {
eprintln!("Extracting reference path positions");
}
let metadata = self.metadata().unwrap();
let ref_samples: BTreeSet<usize> = self.reference_sample_ids(true).into_iter().collect();
if ref_samples.is_empty() {
eprintln!("No reference samples to index");
return Vec::new();
}
if verbose {
eprint!("Reference samples:");
for id in ref_samples.iter() {
eprint!(" {}", metadata.sample_name(*id));
}
eprintln!();
}
let mut indexed_paths: usize = 0;
let mut indexed_positions: usize = 0;
let mut result = Vec::new();
for (path_handle, name) in metadata.path_iter().enumerate() {
if ref_samples.contains(&name.sample()) {
let mut indexed_positions_for_path = Vec::new();
let mut path_offset = 0;
let mut next = 0;
let sequence_id = support::encode_path(path_handle, Orientation::Forward);
let mut pos = self.index.start(sequence_id);
while let Some(p) = pos {
if path_offset >= next {
indexed_positions_for_path.push((path_offset, p));
indexed_positions += 1;
next = path_offset + interval;
}
path_offset += self.sequence_len(support::node_id(p.node)).unwrap();
pos = self.index.forward(p);
}
result.push(ReferencePath {
id: path_handle,
len: path_offset,
positions: indexed_positions_for_path
});
indexed_paths += 1;
}
}
if verbose {
eprintln!("Found {} positions on {} reference paths", indexed_positions, indexed_paths);
}
result
}
}
impl Serialize for GBZ {
fn serialize_header<T: io::Write>(&self, writer: &mut T) -> io::Result<()> {
self.header.serialize(writer)
}
fn serialize_body<T: io::Write>(&self, writer: &mut T) -> io::Result<()> {
self.tags.serialize(writer)?;
self.index.serialize(writer)?;
self.graph.serialize(writer)?;
Ok(())
}
fn load<T: io::Read>(reader: &mut T) -> io::Result<Self> {
let header = Header::<GBZPayload>::load(reader)?;
if let Err(msg) = header.validate() {
return Err(Error::new(ErrorKind::InvalidData, msg));
}
let mut tags = Tags::load(reader)?;
tags.insert(SOURCE_KEY, SOURCE_VALUE);
let index = GBWT::load(reader)?;
if !index.is_bidirectional() {
return Err(Error::new(ErrorKind::InvalidData, "GBZ: The GBWT index is not bidirectional"));
}
let potential_nodes = (index.alphabet_size() - index.first_node()) / 2;
let graph = Graph::load(reader)?;
if graph.sequences() != potential_nodes {
return Err(Error::new(ErrorKind::InvalidData, "GBZ: Mismatch between GBWT alphabet size and Graph sequence count"));
}
let mut real_nodes = RawVector::with_len(potential_nodes, false);
for record_id in index.as_ref().id_iter() {
if record_id == ENDMARKER {
continue;
}
let gbwt_node = index.record_to_node(record_id);
if support::node_orientation(gbwt_node) == Orientation::Forward {
real_nodes.set_bit(Self::gbwt_node_to_sequence(&index, gbwt_node), true);
}
}
Ok(GBZ {
header,
tags,
index,
graph,
real_nodes: BitVector::from(real_nodes),
})
}
fn size_in_elements(&self) -> usize {
self.header.size_in_elements() + self.tags.size_in_elements() + self.index.size_in_elements() + self.graph.size_in_elements()
}
}
impl AsRef<GBWT> for GBZ {
fn as_ref(&self) -> &GBWT {
&self.index
}
}
impl AsRef<Graph> for GBZ {
fn as_ref(&self) -> &Graph {
&self.graph
}
}
#[derive(Clone, Debug)]
pub struct NodeIter<'a> {
parent: &'a GBZ,
iter: OneIter<'a, Identity>,
}
impl<'a> Iterator for NodeIter<'a> {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|(_, id)| self.parent.sequence_to_graph_node(id))
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<'a> DoubleEndedIterator for NodeIter<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back().map(|(_, id)| self.parent.sequence_to_graph_node(id))
}
}
impl<'a> ExactSizeIterator for NodeIter<'a> {}
impl<'a> FusedIterator for NodeIter<'a> {}
#[derive(Clone, Debug)]
pub struct EdgeIter<'a> {
record: Record<'a>,
next: usize,
limit: usize,
flip: bool,
}
impl<'a> Iterator for EdgeIter<'a> {
type Item = (usize, Orientation);
fn next(&mut self) -> Option<Self::Item> {
if self.next >= self.limit {
None
} else {
let gbwt_node = self.record.successor(self.next);
self.next += 1;
let mut orientation = support::node_orientation(gbwt_node);
if self.flip {
orientation = orientation.flip();
}
Some((support::node_id(gbwt_node), orientation))
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = self.limit - self.next;
(remaining, Some(remaining))
}
}
impl<'a> DoubleEndedIterator for EdgeIter<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.next >= self.limit {
None
} else {
self.limit -= 1;
let gbwt_node = self.record.successor(self.limit);
let mut orientation = support::node_orientation(gbwt_node);
if self.flip {
orientation = orientation.flip();
}
Some((support::node_id(gbwt_node), orientation))
}
}
}
impl<'a> ExactSizeIterator for EdgeIter<'a> {}
impl<'a> FusedIterator for EdgeIter<'a> {}
#[derive(Clone, Debug)]
pub struct SegmentIter<'a> {
parent: &'a GBZ,
iter: GraphSegmentIter<'a>,
}
impl<'a> Iterator for SegmentIter<'a> {
type Item = Segment<'a>;
fn next(&mut self) -> Option<Self::Item> {
for segment in self.iter.by_ref() {
if self.parent.has_node(segment.nodes.start) {
return Some(segment);
}
}
None
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(self.iter.len()))
}
}
impl<'a> DoubleEndedIterator for SegmentIter<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
while let Some(segment) = self.iter.next_back() {
if self.parent.has_node(segment.nodes.start) {
return Some(segment);
}
}
None
}
}
impl<'a> FusedIterator for SegmentIter<'a> {}
#[derive(Clone, Debug)]
pub struct LinkIter<'a> {
parent: &'a GBZ,
iter: EdgeIter<'a>,
}
impl<'a> Iterator for LinkIter<'a> {
type Item = (Segment<'a>, Orientation);
fn next(&mut self) -> Option<Self::Item> {
let (node_id, orientation) = self.iter.next()?;
self.parent.node_to_segment(node_id).map(|s| (s, orientation))
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<'a> DoubleEndedIterator for LinkIter<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
let (node_id, orientation) = self.iter.next_back()?;
self.parent.node_to_segment(node_id).map(|s| (s, orientation))
}
}
impl<'a> ExactSizeIterator for LinkIter<'a> {}
impl<'a> FusedIterator for LinkIter<'a> {}
#[derive(Clone, Debug)]
pub struct PathIter<'a> {
iter: SequenceIter<'a>,
}
impl<'a> Iterator for PathIter<'a> {
type Item = (usize, Orientation);
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(support::decode_node)
}
}
impl<'a> FusedIterator for PathIter<'a> {}
#[derive(Clone, Debug)]
pub struct SegmentPathIter<'a> {
parent: &'a GBZ,
iter: SequenceIter<'a>,
next: Option<(usize, Orientation)>,
nodes: Range<usize>,
fail: bool,
}
impl<'a> SegmentPathIter<'a> {
fn visit(&mut self, nodes: Range<usize>, orientation: Orientation) {
match orientation {
Orientation::Forward => self.next = Some((nodes.start, orientation)),
Orientation::Reverse => self.next = Some((nodes.end - 1, orientation)),
}
self.nodes = nodes;
self.advance();
}
fn advance(&mut self) {
let (node_id, orientation) = self.next.unwrap();
match orientation {
Orientation::Forward => {
if node_id + 1 < self.nodes.end {
self.next = Some((node_id + 1, orientation));
} else {
self.next = None;
}
},
Orientation::Reverse => {
if node_id > self.nodes.start {
self.next = Some((node_id - 1, orientation));
} else {
self.next = None;
}
},
}
}
}
impl<'a> Iterator for SegmentPathIter<'a> {
type Item = (Segment<'a>, Orientation);
fn next(&mut self) -> Option<Self::Item> {
if self.fail {
return None;
}
while let Some(gbwt_node) = self.iter.next() {
let (node_id, orientation) = support::decode_node(gbwt_node);
if let Some(expected) = self.next {
if (node_id, orientation) != expected {
self.fail = true;
return None;
}
self.advance();
} else if let Some(segment) = self.parent.node_to_segment(node_id) {
self.visit(segment.nodes.clone(), orientation);
return Some((segment, orientation));
} else {
self.fail = true;
return None;
}
}
None
}
}
impl<'a> FusedIterator for SegmentPathIter<'a> {}
#[derive(Clone, Debug)]
pub struct StateIter<'a> {
iter: EdgeIter<'a>,
state: BidirectionalState,
flip: bool,
}
impl<'a> Iterator for StateIter<'a> {
type Item = BidirectionalState;
fn next(&mut self) -> Option<Self::Item> {
while let Some((node_id, orientation)) = self.iter.next() {
let gbwt_node = support::encode_node(node_id, orientation);
if let Some(state) = GBWT::bd_internal(&self.iter.record, &self.state, gbwt_node) {
return if self.flip { Some(state.flip()) } else { Some(state) };
}
}
None
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(self.iter.len()))
}
}
impl<'a> DoubleEndedIterator for StateIter<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
while let Some((node_id, orientation)) = self.iter.next_back() {
let gbwt_node = support::encode_node(node_id, orientation);
if let Some(state) = GBWT::bd_internal(&self.iter.record, &self.state, gbwt_node) {
return if self.flip { Some(state.flip()) } else { Some(state) };
}
}
None
}
}
impl<'a> FusedIterator for StateIter<'a> {}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ReferencePath {
pub id: usize,
pub len: usize,
pub positions: Vec<(usize, Pos)>,
}