mod build;
mod optimise;
use std::{
collections::HashMap,
fmt::{Debug, Display, Formatter},
ops::Deref,
sync::Arc,
};
use bellframe::{music::AtRowPositions, Row};
use datasize::DataSize;
use crate::{
group::PhRotation,
parameters::{CallIdx, MethodIdx, MusicTypeVec},
utils::{
counts::Counts,
lengths::{PerPartLength, TotalLength},
},
};
#[derive(Debug, Clone)]
pub struct Graph {
pub(crate) chunks: HashMap<ChunkId, Chunk>,
pub(crate) links: LinkSet,
pub(crate) starts: Vec<(LinkId, ChunkId)>,
pub(crate) ends: Vec<(LinkId, ChunkId)>,
}
#[derive(Debug, Clone)]
pub(crate) struct Chunk {
pub(crate) predecessors: Vec<LinkId>,
pub(crate) successors: Vec<LinkId>,
pub(crate) false_chunks: Vec<ChunkId>,
pub(crate) per_part_length: PerPartLength,
pub(crate) total_length: TotalLength,
pub(crate) method_counts: Counts,
pub(crate) score: f32,
pub(crate) music_counts: MusicTypeVec<AtRowPositions<usize>>,
pub(crate) required: bool,
pub(crate) lb_distance_from_rounds: TotalLength,
pub(crate) lb_distance_to_rounds: TotalLength,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub(crate) struct Link {
pub from: LinkSide<ChunkId>,
pub to: LinkSide<ChunkId>,
pub call: Option<CallIdx>,
pub ph_rotation: PhRotation,
pub ph_rotation_back: PhRotation,
}
impl Link {
pub fn is_start(&self) -> bool {
self.from.is_start_or_end()
}
pub fn is_end(&self) -> bool {
self.to.is_start_or_end()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, DataSize)]
pub(crate) enum LinkSide<Id> {
StartOrEnd,
Chunk(Id),
}
impl<Id> LinkSide<Id> {
pub fn is_start_or_end(&self) -> bool {
matches!(self, Self::StartOrEnd)
}
pub fn as_ref(&self) -> LinkSide<&Id> {
match self {
Self::StartOrEnd => LinkSide::StartOrEnd,
Self::Chunk(c) => LinkSide::Chunk(c),
}
}
}
impl Chunk {
pub(crate) fn pred_links<'g>(
&'g self,
graph: &'g Graph,
) -> impl Iterator<Item = (LinkId, &'g Link)> {
self.predecessors
.iter()
.filter_map(|&id| graph.links.get(id).map(|l| (id, l)))
}
pub(crate) fn succ_links<'g>(
&'g self,
graph: &'g Graph,
) -> impl Iterator<Item = (LinkId, &'g Link)> {
self.successors
.iter()
.filter_map(|&id| graph.links.get(id).map(|l| (id, l)))
}
}
#[derive(Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
pub(crate) struct ChunkId {
pub lead_head: Arc<Row>, pub row_idx: RowIdx,
}
impl ChunkId {
pub fn new(lead_head: Arc<Row>, row_idx: RowIdx) -> Self {
Self { lead_head, row_idx }
}
}
impl Deref for ChunkId {
type Target = RowIdx;
fn deref(&self) -> &Self::Target {
&self.row_idx
}
}
impl Debug for ChunkId {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "ChunkId({})", self)
}
}
impl Display for ChunkId {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{},{:?}:{}",
self.lead_head, self.method, self.sub_lead_idx,
)?;
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) struct RowIdx {
pub method: MethodIdx,
pub sub_lead_idx: usize,
}
impl RowIdx {
pub fn new(method_idx: MethodIdx, sub_lead_idx: usize) -> Self {
Self {
method: method_idx,
sub_lead_idx,
}
}
}
pub(crate) use link_set::{LinkId, LinkSet};
mod link_set {
use std::collections::HashMap;
use super::Link;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) struct LinkId(usize);
#[derive(Debug, Clone, Default)]
pub(crate) struct LinkSet {
next_id: usize,
map: HashMap<LinkId, Link>,
}
impl LinkSet {
pub fn new() -> Self {
Self::default()
}
pub fn add(&mut self, link: Link) -> LinkId {
let id = self.next_id();
self.map.insert(id, link);
id
}
pub fn len(&self) -> usize {
self.map.len()
}
pub fn get(&self, id: LinkId) -> Option<&Link> {
self.map.get(&id)
}
pub fn contains(&self, id: LinkId) -> bool {
self.map.contains_key(&id)
}
pub fn iter(&self) -> std::collections::hash_map::Iter<LinkId, Link> {
self.map.iter()
}
#[allow(dead_code)] pub fn keys(&self) -> std::iter::Copied<std::collections::hash_map::Keys<LinkId, Link>> {
self.map.keys().copied()
}
pub fn values(&self) -> std::collections::hash_map::Values<LinkId, Link> {
self.map.values()
}
pub fn retain(&mut self, mut pred: impl FnMut(LinkId, &mut Link) -> bool) {
self.map.retain(|id, link| pred(*id, link))
}
fn next_id(&mut self) -> LinkId {
let id = LinkId(self.next_id);
self.next_id += 1;
id
}
}
impl std::ops::Index<LinkId> for LinkSet {
type Output = Link;
#[track_caller]
fn index(&self, index: LinkId) -> &Self::Output {
&self.map[&index]
}
}
}