eryon_rt/frag/
fragment.rs

1/*
2    Appellation: fragment <module>
3    Contrib: @FL03
4*/
5use core::hash::Hash;
6use eryon_actors::prelude::{Driver, VNode};
7use rshyper::{EdgeId, HyperMap, VertexId, Weight};
8use rstmt::Aspn;
9use rstmt::nrt::{LPR, Triad};
10use std::collections::HashMap;
11
12/// [`FragTonnetz`] represents a fragment of the tonal space that can be managed by a local
13/// runtime. Each partition is a VNode that contains a plant and associated memory system.
14#[derive(Clone, Debug)]
15pub struct FragTonnetz<D>
16where
17    D: Driver<Triad>,
18{
19    /// The underlying hypergraph structure
20    pub(crate) graph: HyperMap<Aspn, VNode<D>>,
21    /// Maps EdgeIds to VNodes for efficient access
22    pub(crate) partitions: HashMap<EdgeId, VNode<D>>,
23    /// Tracks adjacency between triads via transformations
24    pub(crate) transformations: HashMap<EdgeId, HashMap<LPR, EdgeId>>,
25}
26
27impl<D> Default for FragTonnetz<D>
28where
29    D: Driver<Triad>,
30{
31    fn default() -> Self {
32        Self::new()
33    }
34}
35
36impl<D> FragTonnetz<D>
37where
38    D: Driver<Triad>,
39{
40    /// Create a new Tonnetz structure
41    pub fn new() -> Self {
42        FragTonnetz {
43            graph: HyperMap::new(),
44            partitions: HashMap::new(),
45            transformations: HashMap::new(),
46        }
47    }
48    /// returns an immutable reference to the graph
49    pub const fn graph(&self) -> &HyperMap<Aspn, VNode<D>> {
50        &self.graph
51    }
52    /// returns a mutable reference to the graph
53    pub const fn graph_mut(&mut self) -> &mut HyperMap<Aspn, VNode<D>> {
54        &mut self.graph
55    }
56    /// returns an immutable reference to the partitions
57    pub const fn partitions(&self) -> &HashMap<EdgeId, VNode<D>> {
58        &self.partitions
59    }
60    /// returns a mutable reference to the partitions
61    pub const fn partitions_mut(&mut self) -> &mut HashMap<EdgeId, VNode<D>> {
62        &mut self.partitions
63    }
64    /// returns an immutable reference to the transformations
65    pub const fn transformations(&self) -> &HashMap<EdgeId, HashMap<LPR, EdgeId>> {
66        &self.transformations
67    }
68    /// returns a mutable reference to the transformations
69    pub const fn transformations_mut(&mut self) -> &mut HashMap<EdgeId, HashMap<LPR, EdgeId>> {
70        &mut self.transformations
71    }
72    /// Add a hyperedge to the graph and return its edge ID
73    pub fn add_edge<I>(&mut self, vertices: I) -> eryon::Result<EdgeId>
74    where
75        I: IntoIterator<Item = VertexId>,
76    {
77        let id = self.graph_mut().add_link(vertices)?;
78        Ok(id)
79    }
80    /// Add a note to the graph and return its vertex ID
81    pub fn add_note(&mut self, note: Aspn) -> eryon::Result<VertexId> {
82        let id = self.graph_mut().add_node(Weight(note))?;
83        Ok(id)
84    }
85    /// register a [`VNode`] with the system
86    pub fn add_vnode(&mut self, key: EdgeId, vnode: VNode<D>) -> Option<VNode<D>> {
87        // insert the partition
88        self.partitions_mut().insert(key, vnode)
89    }
90    /// returns true if the edge exists
91    pub fn contains_edge(&self, id: &EdgeId) -> bool {
92        self.graph().contains_edge(id)
93    }
94    /// returns true if the node exists
95    pub fn contains_node(&self, id: &VertexId) -> bool {
96        self.graph().contains_node(id)
97    }
98    /// returns true if the given node is a child of the edge
99    pub fn contains_node_in_edge<Q>(&self, edge: &EdgeId, key: &Q) -> bool
100    where
101        Q: Hash + Eq,
102        VertexId: core::borrow::Borrow<Q>,
103    {
104        self.graph().is_node_in_domain(edge, key)
105    }
106    /// returns true if the partition exists
107    pub fn contains_partition<Q>(&self, key: &Q) -> bool
108    where
109        Q: Hash + Eq + ?Sized,
110        EdgeId: core::borrow::Borrow<Q>,
111    {
112        self.partitions().contains_key(key)
113    }
114    /// returns a reference to the node if it exists
115    pub fn get_note<Q>(&self, key: &Q) -> Option<&Weight<Aspn>>
116    where
117        Q: Hash + Eq,
118        VertexId: core::borrow::Borrow<Q>,
119    {
120        self.graph().get_node_weight(key).ok()
121    }
122    /// returns a mutable reference to the node if it exists
123    pub fn get_note_mut<Q>(&mut self, key: &Q) -> Option<&mut Weight<Aspn>>
124    where
125        Q: Hash + Eq,
126        VertexId: core::borrow::Borrow<Q>,
127    {
128        self.graph_mut().get_node_weight_mut(key).ok()
129    }
130    /// returns a reference to the partition if it exists
131    pub fn get_partition<Q>(&self, key: &Q) -> Option<&VNode<D>>
132    where
133        Q: Hash + Eq + ?Sized,
134        EdgeId: core::borrow::Borrow<Q>,
135    {
136        self.partitions().get(key)
137    }
138    /// returns a mutable reference to the partition if it exists
139    pub fn get_partition_mut<Q>(&mut self, key: &Q) -> Option<&mut VNode<D>>
140    where
141        Q: Hash + Eq + ?Sized,
142        EdgeId: core::borrow::Borrow<Q>,
143    {
144        self.partitions_mut().get_mut(key)
145    }
146    /// returns the total number of edges
147    pub fn total_edges(&self) -> usize {
148        self.graph().size()
149    }
150    /// returns the total number of vertices
151    pub fn total_nodes(&self) -> usize {
152        self.graph().order()
153    }
154    /// returns the number of partitions
155    pub fn total_partitions(&self) -> usize {
156        self.partitions().len()
157    }
158}
159
160#[allow(deprecated)]
161impl<D> FragTonnetz<D>
162where
163    D: Driver<Triad>,
164{
165    #[deprecated(
166        since = "0.0.3",
167        note = "use `get_note` instead; this will be removed in the next major release"
168    )]
169    pub fn get_node<Q>(&self, key: &Q) -> Option<&Weight<Aspn>>
170    where
171        Q: Hash + Eq,
172        VertexId: core::borrow::Borrow<Q>,
173    {
174        self.get_note(key)
175    }
176    #[deprecated(
177        since = "0.0.3",
178        note = "use `total_partitions` instead; this will be removed in the next major release"
179    )]
180    pub fn partition_count(&self) -> usize {
181        self.partitions().len()
182    }
183    #[deprecated(
184        since = "0.0.3",
185        note = "use `total_edges` instead; this will be removed in the next major release"
186    )]
187    pub fn edge_count(&self) -> usize {
188        self.graph().total_edges()
189    }
190    #[deprecated(
191        since = "0.0.3",
192        note = "use `total_nodes` instead; this will be removed in the next major release"
193    )]
194    pub fn vertex_count(&self) -> usize {
195        self.graph().total_nodes()
196    }
197    #[deprecated(
198        since = "0.0.3",
199        note = "use `add_vnode` instead; this will be removed in the next major release"
200    )]
201    pub fn add_partition(&mut self, key: EdgeId, vnode: VNode<D>) -> Option<VNode<D>> {
202        // insert the partition
203        self.partitions_mut().insert(key, vnode)
204    }
205}