hydro2_network/
validate.rs1crate::ix!();
3
4impl<NetworkItem> Network<NetworkItem>
5where NetworkItem: Debug + Send + Sync
6{
7 pub fn validate(&self) -> NetResult<()> {
8 let node_count = self.nodes().len();
9
10 for (edge_idx, edge) in self.edges().iter().enumerate() {
12
13 let src = edge.source_index();
14 let so = edge.source_output_idx();
15 let dst = edge.dest_index();
16 let di = edge.dest_input_idx();
17
18 if *src >= node_count {
19 return Err(NetworkError::InvalidConfiguration {
20 details: format!("Edge #{} has invalid src node={}", edge_idx, src),
21 });
22 }
23 if *dst >= node_count {
24 return Err(NetworkError::InvalidConfiguration {
25 details: format!("Edge #{} has invalid dst node={}", edge_idx, dst),
26 });
27 }
28 if *so >= 4 {
29 return Err(NetworkError::InvalidConfiguration {
30 details: format!("Edge #{} has invalid src port={}", edge_idx, so),
31 });
32 }
33 if *di >= 4 {
34 return Err(NetworkError::InvalidConfiguration {
35 details: format!("Edge #{} has invalid dst port={}", edge_idx, di),
36 });
37 }
38 }
39
40 let mut in_degree = vec![0; node_count];
42 for edge in self.edges() {
43 in_degree[*edge.dest_index()] += 1;
44 }
45
46 let mut queue = std::collections::VecDeque::new();
47 for i in 0..node_count {
48 if in_degree[i] == 0 {
49 queue.push_back(i);
50 }
51 }
52 let mut processed = 0;
53 while let Some(n) = queue.pop_front() {
54 processed += 1;
55 for e in self.edges() {
57 if *e.source_index() == n {
58 let dst = e.dest_index();
59 in_degree[*dst] -= 1;
60 if in_degree[*dst] == 0 {
61 queue.push_back(*dst);
62 }
63 }
64 }
65 }
66 if processed < node_count {
67 return Err(NetworkError::InvalidConfiguration {
68 details: "Cycle detected in network graph".into()
69 });
70 }
71
72 Ok(())
73 }
74}
75
76#[cfg(test)]
77mod validate_network_tests {
78 use super::*;
79
80 #[test]
81 fn test_validate_empty_ok() -> Result<(), NetworkError> {
82 let net = NetworkBuilder::<TestWireIO<i32>>::default()
83 .nodes(vec![])
84 .edges(vec![])
85 .build()
86 .unwrap();
87 net.validate()?;
88 Ok(())
89 }
90
91 #[test]
92 fn test_validate_single_node_no_edges_ok() -> Result<(), NetworkError> {
93 let n0: NetworkNode<TestWireIO<i32>> = node!(0 => NoOpOperator::default());
95 let net = NetworkBuilder::<TestWireIO<i32>>::default()
96 .nodes(vec![n0])
97 .edges(vec![])
98 .build()
99 .unwrap();
100 net.validate()?;
101 Ok(())
102 }
103
104 #[test]
105 fn test_validate_cycle() {
106 let n0: NetworkNode<TestWireIO<i32>> = node!(0 => NoOpOperator::default());
108 let n1: NetworkNode<TestWireIO<i32>> = node!(1 => NoOpOperator::default());
109 let e0 = edge!(0:0 -> 1:0);
110 let e1 = edge!(1:0 -> 0:0); let net = NetworkBuilder::<TestWireIO<i32>>::default()
113 .nodes(vec![n0, n1])
114 .edges(vec![e0, e1])
115 .build()
116 .unwrap();
117
118 let res = net.validate();
119 assert!(res.is_err());
120 if let Err(NetworkError::InvalidConfiguration{details}) = res {
121 assert!(details.contains("Cycle detected"), "Expected cycle error, got: {}", details);
122 }
123 }
124
125 #[test]
126 fn test_validate_out_of_range_edge() {
127 let n0: NetworkNode<TestWireIO<i32>> = node!(0 => ConstantOp::new(42));
129 let n1: NetworkNode<TestWireIO<i32>> = node!(1 => AddOp::new(5));
130 let e_bad = edge!(0:0 -> 99:0);
132 let net = NetworkBuilder::<TestWireIO<i32>>::default()
133 .nodes(vec![n0, n1])
134 .edges(vec![e_bad])
135 .build()
136 .unwrap();
137
138 let res = net.validate();
139 assert!(res.is_err());
140 if let Err(NetworkError::InvalidConfiguration{details}) = res {
141 assert!(details.contains("invalid dst node=99"));
142 }
143 }
144
145 #[test]
146 fn test_validate_disconnected_multiple_nodes() -> Result<(), NetworkError> {
147 let n0: NetworkNode<TestWireIO<i32>> = node!(0 => ConstantOp::new(1));
150 let n1: NetworkNode<TestWireIO<i32>> = node!(1 => AddOp::new(5));
151 let n2: NetworkNode<TestWireIO<i32>> = node!(2 => MultiplyOp::new(2));
152
153 let net = NetworkBuilder::<TestWireIO<i32>>::default()
154 .nodes(vec![n0, n1, n2])
155 .edges(vec![])
156 .build()
157 .unwrap();
158
159 net.validate()?;
160 Ok(())
161 }
162
163 #[test]
164 fn test_validate_ok_chained() -> Result<(), NetworkError> {
165 let n0: NetworkNode<TestWireIO<i32>> = node!(0 => ConstantOp::new(1));
167 let n1: NetworkNode<TestWireIO<i32>> = node!(1 => MultiplyOp::new(5));
168 let n2: NetworkNode<TestWireIO<i32>> = node!(2 => AddOp::new(100));
169 let e0 = edge!(0:0 -> 1:0);
170 let e1 = edge!(1:0 -> 2:0);
171
172 let net = NetworkBuilder::<TestWireIO<i32>>::default()
173 .nodes(vec![n0, n1, n2])
174 .edges(vec![e0, e1])
175 .build()
176 .unwrap();
177
178 net.validate()?;
179 Ok(())
180 }
181}