1use super::{DEVStoneAtomic, DEVStoneSeeder};
2#[cfg(test)]
3use super::{SharedProbe, TestProbe};
4use crate::modeling::Coupled;
5
6pub struct HOmod {
7 pub coupled: Coupled,
8}
9
10impl HOmod {
11 pub fn create(
12 width: usize,
13 depth: usize,
14 int_delay: u64,
15 ext_delay: u64,
16 #[cfg(test)] probe: SharedProbe,
17 ) -> Coupled {
18 let mut coupled = Coupled::new("HOmod");
19 let seeder = DEVStoneSeeder::new("seeder");
20 let homod = Self::new(
21 width,
22 depth,
23 int_delay,
24 ext_delay,
25 #[cfg(test)]
26 probe,
27 );
28 let homod_name = homod.coupled.component.get_name().to_string();
29 coupled.add_component(Box::new(seeder));
30 coupled.add_component(Box::new(homod.coupled));
31 coupled.add_ic("seeder", "output", &homod_name, "input_1");
32 coupled.add_ic("seeder", "output", &homod_name, "input_2");
33 coupled
34 }
35
36 fn new(
37 width: usize,
38 depth: usize,
39 int_delay: u64,
40 ext_delay: u64,
41 #[cfg(test)] probe: SharedProbe,
42 ) -> Self {
43 if width < 1 {
45 panic!("width must be greater than 1")
46 }
47 if depth < 1 {
48 panic!("depth must be greater than 1")
49 }
50 let name = format!("coupled_{depth}");
52 let mut coupled = Coupled::new(&name);
53 coupled.add_in_port::<usize>("input_1");
54 coupled.add_in_port::<usize>("input_2");
55 coupled.add_out_port::<usize>("output");
56 if depth == 1 {
58 let atomic = DEVStoneAtomic::new(
59 "inner_atomic",
60 int_delay,
61 ext_delay,
62 #[cfg(test)]
63 probe.clone(),
64 );
65 coupled.add_component(Box::new(atomic));
66 coupled.add_eic("input_1", "inner_atomic", "input");
67 coupled.add_eoc("inner_atomic", "output", "output");
68 } else {
70 let subcoupled = Self::new(
71 width,
72 depth - 1,
73 int_delay,
74 ext_delay,
75 #[cfg(test)]
76 probe.clone(),
77 );
78 let subcoupled_name = subcoupled.coupled.component.get_name().to_string();
79 coupled.add_component(Box::new(subcoupled.coupled));
80 coupled.add_eic("input_1", &subcoupled_name, "input_1");
81 coupled.add_eoc(&subcoupled_name, "output", "output");
82 let mut prev_row: Vec<String> = Vec::new();
83 let mut current_row: Vec<String> = Vec::new();
84 for i in 1..width {
86 let atomic_name = format!("atomic(1,{i}");
87 prev_row.push(atomic_name.clone());
88 let atomic = DEVStoneAtomic::new(
89 &atomic_name,
90 int_delay,
91 ext_delay,
92 #[cfg(test)]
93 probe.clone(),
94 );
95 coupled.add_component(Box::new(atomic));
96 coupled.add_eic("input_2", &atomic_name, "input");
97 coupled.add_ic(&atomic_name, "output", &subcoupled_name, "input_2");
98 }
99 for i in 1..width {
101 let atomic_name = format!("atomic(2,{i}");
102 current_row.push(atomic_name.clone());
103 let atomic = DEVStoneAtomic::new(
104 &atomic_name,
105 int_delay,
106 ext_delay,
107 #[cfg(test)]
108 probe.clone(),
109 );
110 coupled.add_component(Box::new(atomic));
111 if i == 1 {
112 coupled.add_eic("input_2", &atomic_name, "input");
113 }
114 for prev_name in &prev_row {
115 coupled.add_ic(&atomic_name, "output", prev_name, "input");
116 }
117 }
118 for layer in 3..(width + 1) {
120 prev_row = current_row;
121 current_row = Vec::new();
122 for i in 1..prev_row.len() {
123 let atomic_name = format!("atomic({layer},{i}");
124 current_row.push(atomic_name.clone());
125 let atomic = DEVStoneAtomic::new(
126 &atomic_name,
127 int_delay,
128 ext_delay,
129 #[cfg(test)]
130 probe.clone(),
131 );
132 coupled.add_component(Box::new(atomic));
133 if i == 1 {
134 coupled.add_eic("input_2", &atomic_name, "input");
135 }
136 coupled.add_ic(&atomic_name, "output", prev_row.get(i).unwrap(), "input");
137 }
138 }
139 }
140 #[cfg(test)]
142 {
143 let mut x = probe.lock().unwrap();
144 x.n_eics += coupled.n_eics();
145 x.n_ics += coupled.n_ics();
146 x.n_eocs += coupled.n_eocs();
147 }
148 Self { coupled }
149 }
150}
151
152#[cfg(test)]
153mod tests {
154 use super::*;
155 use crate::simulation::*;
156 use std::sync::{Arc, Mutex};
157
158 fn expected_atomics(width: usize, depth: usize) -> usize {
159 (width - 1 + (width - 1) * width / 2) * (depth - 1) + 1
160 }
161
162 fn expected_eics(width: usize, depth: usize) -> usize {
163 (2 * (width - 1) + 1) * (depth - 1) + 1
164 }
165
166 fn expected_ics(width: usize, depth: usize) -> usize {
167 ((width - 1) * (width - 1) + (width - 1) * width / 2) * (depth - 1)
168 }
169
170 fn expected_eocs(_width: usize, depth: usize) -> usize {
171 depth
172 }
173
174 fn expected_internals(width: usize, depth: usize) -> usize {
175 let mut n = 1;
176 for d in 1..depth {
177 n += (1 + (d - 1) * (width - 1)) * (width - 1) * width / 2
178 + (width - 1) * (width + (d - 1) * (width - 1));
179 }
180 n
181 }
182
183 fn expected_events(width: usize, depth: usize) -> usize {
184 let mut n = 1;
185 if width > 1 && depth > 1 {
186 n += 2 * (width - 1);
187 let mut aux = 0;
188 for i in 2..depth {
189 aux += 1 + (i - 1) * (width - 1);
190 }
191 n += aux * 2 * (width - 1) * (width - 1);
192 n += (aux + 1) * ((width - 1) * (width - 1) + (width - 2) * (width - 1) / 2);
193 }
194 n
195 }
196
197 #[test]
198 fn test_homod() {
199 for width in (1..10).step_by(1) {
200 for depth in (1..10).step_by(1) {
201 let probe = Arc::new(Mutex::new(TestProbe::default()));
202 let coupled = HOmod::create(width, depth, 0, 0, probe.clone());
203 let mut simulator = RootCoordinator::new(coupled);
204 simulator.simulate(f64::INFINITY);
205
206 let x = probe.lock().unwrap();
207 assert_eq!(expected_atomics(width, depth), x.n_atomics);
208 assert_eq!(expected_eics(width, depth), x.n_eics);
209 assert_eq!(expected_ics(width, depth), x.n_ics);
210 assert_eq!(expected_eocs(width, depth), x.n_eocs);
211 assert_eq!(expected_internals(width, depth), x.n_internals);
212 assert_eq!(expected_internals(width, depth), x.n_externals);
213 assert_eq!(expected_events(width, depth), x.n_events);
214 }
215 }
216 }
217}