rstmt_nrt/transform/types/
path.rs

1/*
2    Appellation: path <module>
3    Contrib: @FL03
4*/
5use crate::transform::SearchNode;
6use crate::{LPR, Triad};
7use rshyper::EdgeId;
8use std::collections::HashMap;
9
10/// Represents a sequence of transformations from one triad to another
11#[derive(Clone, Debug, Default, Eq, PartialEq)]
12#[cfg_attr(
13    feature = "serde",
14    derive(serde_derive::Deserialize, serde_derive::Serialize)
15)]
16pub struct Path {
17    /// Musical cost or distance metric (lower is better)
18    pub(crate) cost: usize,
19    /// Edge IDs in the tonnetz (if available)
20    pub(crate) edge_ids: Vec<Option<EdgeId>>,
21    /// Path features for musical analysis
22    pub(crate) features: PathFeatures,
23    /// The sequence of transformations to apply
24    pub(crate) transforms: Vec<LPR>,
25    /// The sequence of triads visited
26    pub(crate) triads: Vec<Triad>,
27}
28
29/// Features describing musical characteristics of a transformation path
30#[derive(Clone, Debug, Default, Eq, PartialEq)]
31#[cfg_attr(
32    feature = "serde",
33    derive(serde_derive::Deserialize, serde_derive::Serialize)
34)]
35pub struct PathFeatures {
36    /// Smoothness of voice leading (sum of semitone movements)
37    pub(crate) distance: usize,
38    /// Changes in modality (i.e. major/minor or any other changes in classification)
39    pub(crate) modality_changes: usize,
40    /// Count of each transformation type in the path
41    pub(crate) transform_counts: HashMap<LPR, usize>,
42}
43
44impl Path {
45    pub fn new(transforms: Vec<LPR>, triads: Vec<Triad>, edge_ids: Vec<Option<EdgeId>>) -> Self {
46        Path {
47            transforms,
48            triads,
49            edge_ids,
50            cost: 0,
51            features: PathFeatures::default(),
52        }
53    }
54
55    pub fn from_triads(triads: Vec<Triad>) -> Self {
56        Path {
57            transforms: Vec::new(),
58            triads,
59            edge_ids: Vec::new(),
60            cost: 0,
61            features: PathFeatures::default(),
62        }
63    }
64
65    pub fn from_node_with_features(node: SearchNode, features: PathFeatures) -> Self {
66        let SearchNode {
67            cost,
68            edges: edge_ids,
69            transforms,
70            visited: triads,
71            ..
72        } = node;
73        Path {
74            transforms,
75            triads,
76            edge_ids,
77            cost,
78            features,
79        }
80    }
81    /// returns a copy of the path's cost
82    pub const fn cost(&self) -> usize {
83        self.cost
84    }
85    #[inline]
86    pub fn cost_mut(&mut self) -> &mut usize {
87        &mut self.cost
88    }
89    /// returns a reference to the path's edge IDs
90    pub const fn edges(&self) -> &Vec<Option<EdgeId>> {
91        &self.edge_ids
92    }
93    #[inline]
94    pub fn edges_mut(&mut self) -> &mut Vec<Option<EdgeId>> {
95        &mut self.edge_ids
96    }
97    /// returns a reference to the path's features
98    pub const fn features(&self) -> &PathFeatures {
99        &self.features
100    }
101    #[inline]
102    pub fn features_mut(&mut self) -> &mut PathFeatures {
103        &mut self.features
104    }
105
106    pub const fn transforms(&self) -> &Vec<LPR> {
107        &self.transforms
108    }
109    #[inline]
110    pub fn transforms_mut(&mut self) -> &mut Vec<LPR> {
111        &mut self.transforms
112    }
113
114    pub const fn triads(&self) -> &Vec<Triad> {
115        &self.triads
116    }
117
118    #[inline]
119    pub fn triads_mut(&mut self) -> &mut Vec<Triad> {
120        &mut self.triads
121    }
122
123    pub fn get_edge(&self, index: usize) -> Option<EdgeId> {
124        self.edge_ids.get(index).cloned().flatten()
125    }
126
127    pub fn push_transform(&mut self, transform: LPR) {
128        self.transforms.push(transform);
129    }
130
131    pub fn push_triad(&mut self, triad: Triad) {
132        self.triads.push(triad);
133    }
134}