use std::collections::HashMap;
use crate::{
graph::LinkSide,
group::{PartHead, PhRotation},
parameters::{CallIdx, Parameters},
utils::{
counts::Counts,
lengths::{PerPartLength, TotalLength},
},
};
use bit_vec::BitVec;
use super::atw::{AtwBitmap, AtwTable};
#[derive(Debug, Clone)]
pub(super) struct Graph {
pub starts: StartVec<(ChunkIdx, crate::graph::LinkId, PartHead)>,
pub chunks: ChunkVec<Chunk>,
}
#[derive(Debug, Clone)]
pub(super) struct Chunk {
pub id: crate::graph::ChunkId,
pub score: f32,
pub per_part_length: PerPartLength, pub total_length: TotalLength,
pub method_counts: Counts,
pub min_len_to_rounds: TotalLength,
pub succs: SuccVec<SuccLink>,
pub falseness: BitVec,
pub atw_bitmap: AtwBitmap,
}
#[derive(Debug, Clone)]
pub(super) struct SuccLink {
pub call: Option<CallIdx>,
pub next: LinkSide<ChunkIdx>,
pub score: f32,
pub ph_rotation: PhRotation,
}
impl Graph {
pub fn new(
source_graph: &crate::graph::Graph,
params: &Parameters,
atw_table: &AtwTable,
) -> Self {
let num_chunks = source_graph.chunks.len();
let mut index_to_id = ChunkVec::<(crate::graph::ChunkId, &crate::graph::Chunk)>::new();
let mut id_to_index = HashMap::<crate::graph::ChunkId, ChunkIdx>::new();
for (id, chunk) in &source_graph.chunks {
let index = index_to_id.push((id.to_owned(), chunk));
id_to_index.insert(id.to_owned(), index);
}
let chunks: ChunkVec<_> = (0..num_chunks)
.map(|index| {
let index = ChunkIdx::new(index);
let (id, source_chunk) = index_to_id[index].clone();
let mut falseness = BitVec::from_elem(num_chunks, false);
for false_id in &source_chunk.false_chunks {
let false_chunk_idx = id_to_index[false_id];
falseness.set(false_chunk_idx.index(), true);
}
let atw_bitmap =
atw_table.bitmap_for_chunk(params, &id, source_chunk.per_part_length);
let succs = source_chunk
.successors
.iter()
.filter_map(|link_id| {
let link = source_graph.links.get(*link_id)?;
let next = match &link.to {
LinkSide::Chunk(ch_id) => LinkSide::Chunk(*id_to_index.get(ch_id)?),
LinkSide::StartOrEnd => LinkSide::StartOrEnd,
};
Some(SuccLink {
call: link.call,
score: link_score(source_chunk, link, params),
next,
ph_rotation: link.ph_rotation,
})
})
.collect();
Chunk {
per_part_length: source_chunk.per_part_length,
total_length: source_chunk.total_length,
method_counts: source_chunk.method_counts.clone(),
min_len_to_rounds: source_chunk.lb_distance_to_rounds,
score: source_chunk.score,
succs,
falseness,
atw_bitmap,
id,
}
})
.collect();
let mut starts = StartVec::new();
for (start_link_id, start_chunk_id) in &source_graph.starts {
let start_link = match source_graph.links.get(*start_link_id) {
Some(l) => l,
None => continue, };
if source_graph.chunks.contains_key(start_chunk_id) {
starts.push((
id_to_index[start_chunk_id],
*start_link_id,
PartHead::rounds() * start_link.ph_rotation,
));
}
}
Graph { starts, chunks }
}
}
fn link_score(
source_chunk: &crate::graph::Chunk,
link: &crate::graph::Link,
params: &Parameters,
) -> f32 {
let is_splice = match (&link.from, &link.to) {
(LinkSide::Chunk(c1), LinkSide::Chunk(c2)) => {
let sub_lead_idx_after_prev_chunk = params.methods[c1.method]
.add_sub_lead_idx(c1.sub_lead_idx, source_chunk.per_part_length);
let is_continuation =
c1.method == c2.method && sub_lead_idx_after_prev_chunk == c2.sub_lead_idx;
!is_continuation
}
_ => false,
};
let call_weight = match link.call {
Some(idx) => params.calls[idx].weight,
None => 0.0, };
let splice_weight = if is_splice { params.splice_weight } else { 0.0 };
(call_weight + splice_weight) * params.num_parts() as f32
}
index_vec::define_index_type! { pub struct ChunkIdx = usize; }
index_vec::define_index_type! { pub struct StartIdx = u32; }
index_vec::define_index_type! { pub struct SuccIdx = u32; }
type ChunkVec<T> = index_vec::IndexVec<ChunkIdx, T>;
type StartVec<T> = index_vec::IndexVec<StartIdx, T>;
type SuccVec<T> = index_vec::IndexVec<SuccIdx, T>;