use crate::tonnetz::{EdgeMap, HyperTonnetz, LprMap, NoteGraph};
use crate::traits::{TriadRepr, TriadType};
use crate::triad::TriadBase;
use core::hash::Hash;
use hashbrown::HashMap;
use num_traits::FromPrimitive;
use rshyper::{AddStep, EdgeId, RawIndex, VertexId, Weight};
use rstmt_core::Octave;
impl<S, K, T, Ix> HyperTonnetz<S, K, T, Ix>
where
K: TriadType,
S: TriadRepr<Elem = T>,
Ix: RawIndex,
{
pub fn new() -> Self
where
Ix: Default,
{
HyperTonnetz {
graph: NoteGraph::new(),
triads: EdgeMap::new(),
transformations: LprMap::new(),
}
}
pub fn with_capacity(capacity: usize) -> Self
where
Ix: Default,
{
HyperTonnetz {
graph: NoteGraph::with_capacity(capacity * capacity, capacity),
triads: HashMap::with_capacity(capacity),
transformations: HashMap::new(),
}
}
pub const fn graph(&self) -> &NoteGraph<T, (), Ix> {
&self.graph
}
pub const fn graph_mut(&mut self) -> &mut NoteGraph<T, (), Ix> {
&mut self.graph
}
pub const fn triads(&self) -> &EdgeMap<S, K, T, Ix> {
&self.triads
}
pub const fn triads_mut(&mut self) -> &mut EdgeMap<S, K, T, Ix> {
&mut self.triads
}
pub const fn transformations(&self) -> &LprMap<Ix> {
&self.transformations
}
pub const fn transformations_mut(&mut self) -> &mut LprMap<Ix> {
&mut self.transformations
}
#[inline]
pub fn clear(&mut self)
where
Ix: Default + Eq + Hash,
{
self.graph_mut().clear();
self.triads_mut().clear();
self.transformations_mut().clear();
}
pub fn set_graph(&mut self, graph: NoteGraph<T, (), Ix>) {
self.graph = graph
}
#[inline]
pub fn set_triads(&mut self, triads: EdgeMap<S, K, T, Ix>) {
self.triads = triads
}
#[inline]
pub fn set_transformations(&mut self, transformations: LprMap<Ix>) {
self.transformations = transformations
}
pub fn add_note(&mut self, note: T) -> crate::Result<VertexId<Ix>>
where
Ix: Copy + Eq + Hash + AddStep<Output = Ix>,
{
self.graph_mut()
.add_node(Weight(note))
.map_err(|e| e.into())
}
pub fn add_notes<I>(&mut self, notes: I) -> Vec<VertexId<Ix>>
where
I: IntoIterator<Item = T>,
Ix: Copy + Eq + Hash + AddStep<Output = Ix>,
{
notes
.into_iter()
.filter_map(|note| self.add_note(note).ok())
.collect::<Vec<_>>()
}
pub fn get_triad<Q>(&self, key: &Q) -> Option<&TriadBase<S, K, T>>
where
Q: Eq + Hash,
Ix: Eq + Hash,
EdgeId<Ix>: core::borrow::Borrow<Q>,
{
self.triads().get(key)
}
pub fn get_triad_mut<Q>(&mut self, key: &Q) -> Option<&mut TriadBase<S, K, T>>
where
Q: Eq + Hash,
Ix: Eq + Hash,
EdgeId<Ix>: core::borrow::Borrow<Q>,
{
self.triads_mut().get_mut(key)
}
}
impl<S, K, T, Ix> HyperTonnetz<S, K, T, Ix>
where
K: TriadType,
S: TriadRepr<Elem = T>,
T: Eq + Hash,
Ix: Copy + Eq + Hash + RawIndex,
{
pub fn scaffold_layer(&mut self, octave: Octave) -> crate::Result<Vec<VertexId<Ix>>>
where
Ix: AddStep<Output = Ix>,
T: Copy + FromPrimitive + core::ops::Add<Output = T>,
{
let octave = T::from_isize(octave.value()).unwrap();
let iter = (0..12).map(|i| T::from_usize(i).unwrap() + octave);
Ok(self.add_notes(iter))
}
pub fn add_triad(&mut self, triad: TriadBase<S, K, T>) -> crate::Result<EdgeId<Ix>>
where
Ix: AddStep<Output = Ix>,
T: Copy,
S: Clone + IntoIterator<Item = T>,
{
let vertices: Vec<VertexId<Ix>> = triad
.chord()
.clone()
.into_iter()
.map(|p| {
if let Some(v) = self.find_vertex_by_note(p) {
v
} else {
self.add_note(p).expect("Failed to add note")
}
})
.collect();
let edge_id = self
.graph_mut()
.add_link(vertices)
.expect("Failed to add hyperedge");
self.triads.insert(edge_id, triad);
Ok(edge_id)
}
pub(crate) fn find_vertex_by_note<Q>(&self, note: Q) -> Option<VertexId<Ix>>
where
Weight<T>: PartialEq<Q>,
{
self.graph
.nodes()
.iter()
.find(|(_, node)| *node.weight() == note)
.map(|(id, _)| *id)
}
}
impl HyperTonnetz {
pub fn compute_transformations(&mut self) {
self.transformations.clear();
let edges: Vec<EdgeId> = self.triads.keys().cloned().collect();
for &edge1 in &edges {
self.transformations.insert(edge1, HashMap::new());
if let Some(a) = self.triads.get(&edge1) {
for &edge2 in &edges {
if edge1 == edge2 {
continue;
}
if let Some(b) = self.triads().get(&edge2) {
if let Some(transform) = a.is_neighbor(b) {
self.transformations
.get_mut(&edge1)
.unwrap()
.insert(transform, edge2);
}
}
}
}
}
}
}
impl HyperTonnetz {}
impl Default for HyperTonnetz {
fn default() -> Self {
Self::new()
}
}