1use fabula::datasource::{DataSource, Edge, ValueConstraint};
7use fabula::interval::Interval;
8use petgraph::stable_graph::{NodeIndex, StableGraph};
9use petgraph::Direction;
10use std::collections::HashMap;
11use std::fmt::Debug;
12use std::hash::{Hash, Hasher};
13
14#[derive(Debug, Clone)]
17pub struct TemporalEdge<L, V, T> {
18 pub label: L,
19 pub value: V,
20 pub interval: Interval<T>,
21}
22
23pub struct PetTemporalGraph<N, L, V, T> {
29 graph: StableGraph<N, TemporalEdge<L, V, T>>,
30 node_index: HashMap<N, NodeIndex>,
31 current_time: T,
32}
33
34impl<N, L, V, T> PetTemporalGraph<N, L, V, T>
35where
36 N: Eq + Hash + Clone + Debug,
37 T: Clone,
38{
39 pub fn new(initial_time: T) -> Self {
41 Self {
42 graph: StableGraph::new(),
43 node_index: HashMap::new(),
44 current_time: initial_time,
45 }
46 }
47
48 pub fn set_time(&mut self, t: T) {
50 self.current_time = t;
51 }
52
53 pub fn add_node(&mut self, id: N) -> NodeIndex {
55 if let Some(&idx) = self.node_index.get(&id) {
56 idx
57 } else {
58 let idx = self.graph.add_node(id.clone());
59 self.node_index.insert(id, idx);
60 idx
61 }
62 }
63
64 pub fn add_edge(&mut self, from: N, label: L, value: V, interval: Interval<T>) {
66 let from_idx = self.add_node(from);
67 let edge = TemporalEdge {
68 label,
69 value,
70 interval,
71 };
72 self.graph.add_edge(from_idx, from_idx, edge);
77 }
78
79 pub fn add_edge_to_node(&mut self, from: N, label: L, to: N, interval: Interval<T>)
81 where
82 V: From<NodeRef<N>>,
83 {
84 self.add_node(to.clone());
85 let value = V::from(NodeRef(to));
86 self.add_edge(from, label, value, interval);
87 }
88
89 pub fn add_edge_bounded(&mut self, from: N, label: L, value: V, start: T, end: T)
91 where
92 T: Ord,
93 {
94 let from_idx = self.add_node(from);
95 let edge = TemporalEdge {
96 label,
97 value,
98 interval: Interval::new(start, end),
99 };
100 self.graph.add_edge(from_idx, from_idx, edge);
101 }
102
103 pub fn node_count(&self) -> usize {
105 self.graph.node_count()
106 }
107
108 pub fn edge_count(&self) -> usize {
110 self.graph.edge_count()
111 }
112}
113
114#[derive(Debug, Clone)]
117pub struct NodeRef<N>(pub N);
118
119#[derive(Debug, Clone, PartialEq, PartialOrd)]
121pub enum PetValue<N: Debug + Clone + PartialOrd> {
122 Node(N),
124 Str(String),
126 Num(f64),
128 Bool(bool),
130}
131
132impl<N: Debug + Clone + PartialOrd + Hash> Hash for PetValue<N> {
133 fn hash<H: Hasher>(&self, state: &mut H) {
134 std::mem::discriminant(self).hash(state);
135 match self {
136 PetValue::Node(n) => n.hash(state),
137 PetValue::Str(s) => s.hash(state),
138 PetValue::Num(n) => n.to_bits().hash(state),
139 PetValue::Bool(b) => b.hash(state),
140 }
141 }
142}
143
144impl<N: Debug + Clone + PartialOrd> From<NodeRef<N>> for PetValue<N> {
145 fn from(r: NodeRef<N>) -> Self {
146 PetValue::Node(r.0)
147 }
148}
149
150impl<N, L, T> DataSource for PetTemporalGraph<N, L, PetValue<N>, T>
151where
152 N: Eq + Hash + Clone + Debug + PartialOrd,
153 L: Eq + Hash + Clone + Debug,
154 T: Ord + Clone + Debug + Hash,
155{
156 type N = N;
157 type L = L;
158 type V = PetValue<N>;
159 type T = T;
160
161 fn edges_from(&self, node: &N, label: &L, at: &T) -> Vec<Edge<N, PetValue<N>, T>> {
162 let Some(&idx) = self.node_index.get(node) else {
163 return Vec::new();
164 };
165 self.graph
166 .edges_directed(idx, Direction::Outgoing)
167 .filter(|e| &e.weight().label == label && e.weight().interval.covers(at))
168 .map(|e| Edge {
169 source: node.clone(),
170 target: e.weight().value.clone(),
171 interval: e.weight().interval.clone(),
172 })
173 .collect()
174 }
175
176 fn scan(
177 &self,
178 label: &L,
179 constraint: &ValueConstraint<PetValue<N>>,
180 at: &T,
181 ) -> Vec<Edge<N, PetValue<N>, T>> {
182 let mut results = Vec::new();
183 for idx in self.graph.node_indices() {
184 let node_id = &self.graph[idx];
185 for e in self.graph.edges_directed(idx, Direction::Outgoing) {
186 let w = e.weight();
187 if &w.label == label && constraint.matches(&w.value) && w.interval.covers(at) {
188 results.push(Edge {
189 source: node_id.clone(),
190 target: w.value.clone(),
191 interval: w.interval.clone(),
192 });
193 }
194 }
195 }
196 results
197 }
198
199 fn edges_from_any_time(&self, node: &N, label: &L) -> Vec<Edge<N, PetValue<N>, T>> {
200 let Some(&idx) = self.node_index.get(node) else {
201 return Vec::new();
202 };
203 self.graph
204 .edges_directed(idx, Direction::Outgoing)
205 .filter(|e| &e.weight().label == label)
206 .map(|e| Edge {
207 source: node.clone(),
208 target: e.weight().value.clone(),
209 interval: e.weight().interval.clone(),
210 })
211 .collect()
212 }
213
214 fn scan_any_time(
215 &self,
216 label: &L,
217 constraint: &ValueConstraint<PetValue<N>>,
218 ) -> Vec<Edge<N, PetValue<N>, T>> {
219 let mut results = Vec::new();
220 for idx in self.graph.node_indices() {
221 let node_id = &self.graph[idx];
222 for e in self.graph.edges_directed(idx, Direction::Outgoing) {
223 let w = e.weight();
224 if &w.label == label && constraint.matches(&w.value) {
225 results.push(Edge {
226 source: node_id.clone(),
227 target: w.value.clone(),
228 interval: w.interval.clone(),
229 });
230 }
231 }
232 }
233 results
234 }
235
236 fn now(&self) -> T {
237 self.current_time.clone()
238 }
239
240 fn value_as_node(&self, value: &PetValue<N>) -> Option<N> {
241 match value {
242 PetValue::Node(n) => Some(n.clone()),
243 _ => None,
244 }
245 }
246}