1use crate::activity;
2use crate::activity::Activity;
3use crate::activity_builder::ActivityBuilder;
4use crate::{id, Error, Network, Result};
5use crate::{DurationType, StartType};
6use petgraph::graphmap::DiGraphMap;
7use petgraph::Direction;
8use std::collections::HashMap;
9
10#[derive(Default)]
11pub struct NetworkBuilder {
12 activities: HashMap<u64, ActivityBuilder>,
13 connections: DiGraphMap<u64, ()>,
14}
15
16impl NetworkBuilder {
17 pub(crate) fn new(
18 activities: HashMap<u64, ActivityBuilder>,
19 connections: DiGraphMap<u64, ()>,
20 ) -> NetworkBuilder {
21 NetworkBuilder {
22 activities,
23 connections,
24 }
25 }
26
27 pub fn add_activity(&mut self, reference: &str, duration: f64) -> Result<()> {
32 self.add_extended_activity(
33 reference,
34 reference,
35 duration,
36 duration,
37 duration,
38 StartType::Earliest,
39 DurationType::Expected,
40 )
41 }
42
43 pub fn remove_activity(&mut self, reference: &str) -> Result<()> {
45 self.activities
46 .remove(&id(&reference))
47 .ok_or_else(|| Error::UnknownReference(reference.to_string()))?;
48
49 if !self.connections.remove_node(id(&reference)) {
50 return Err(Error::UnknownReference(reference.to_string()));
51 };
52
53 Ok(())
54 }
55
56 pub fn remove_edge(&mut self, origin_reference: &str, target_reference: &str) -> Result<()> {
57 let origin = self.activity(id(&origin_reference))?;
58 let target = self.activity(id(&target_reference))?;
59
60 if self
61 .connections
62 .remove_edge(id(&origin), id(&target))
63 .is_none()
64 {
65 return Err(Error::UnknownEdge(
66 origin_reference.to_string(),
67 target_reference.to_string(),
68 ));
69 }
70
71 Ok(())
72 }
73
74 pub fn add_extended_activity(
87 &mut self,
88 reference: &str,
89 description: &str,
90 minimum_duration: f64,
91 expected_duration: f64,
92 maximum_duration: f64,
93 start_type: StartType,
94 duration_type: DurationType,
95 ) -> Result<()> {
96 let mut activity_builder = ActivityBuilder::new(
97 reference,
98 description,
99 expected_duration,
100 minimum_duration,
101 maximum_duration,
102 );
103 activity_builder.start_type = start_type;
104 activity_builder.duration_type = duration_type;
105
106 self.activities
107 .insert(id(&reference), activity_builder.clone());
108
109 self.connections.add_node(id(&activity_builder));
110
111 Ok(())
112 }
113
114 pub fn connect(&mut self, origin_reference: &str, target_reference: &str) -> Result<()> {
122 let origin = self
123 .activities
124 .get(&id(&origin_reference))
125 .ok_or_else(|| Error::UnknownReference(origin_reference.to_string()))?;
126
127 let target = self
128 .activities
129 .get(&id(&target_reference))
130 .ok_or_else(|| Error::UnknownReference(target_reference.to_string()))?;
131
132 self.connections.add_edge(id(&origin), id(&target), ());
133
134 Ok(())
135 }
136
137 fn mut_activity(&mut self, id: u64) -> Result<&mut ActivityBuilder> {
138 self.activities.get_mut(&id).ok_or(Error::UnknownId(id))
139 }
140
141 fn activity(&self, id: u64) -> Result<&ActivityBuilder> {
142 self.activities.get(&id).ok_or(Error::UnknownId(id))
143 }
144
145 fn previous_activities(&self, id: u64) -> Result<Vec<&ActivityBuilder>> {
146 self.connections
147 .neighbors_directed(id, Direction::Incoming)
148 .map(|ref id| self.activities.get(id).ok_or(Error::UnknownId(*id)))
149 .collect::<Result<Vec<&ActivityBuilder>>>()
150 }
151
152 fn next_activities(&self, id: u64) -> Result<Vec<&ActivityBuilder>> {
153 self.connections
154 .neighbors_directed(id, Direction::Outgoing)
155 .map(|ref id| self.activities.get(id).ok_or(Error::UnknownId(*id)))
156 .collect::<Result<Vec<&ActivityBuilder>>>()
157 }
158
159 fn forward_pass(&mut self) -> Result<()> {
160 let mut activity_ids: Vec<u64> = Vec::new();
161
162 for id in self
163 .connections
164 .neighbors_directed(id(&activity::START_REFERENCE), Direction::Outgoing)
165 {
166 activity_ids.push(id);
167 }
168
169 while !activity_ids.is_empty() {
170 let current_activity_id = activity_ids.remove(0);
171 let prev_activities = self.previous_activities(current_activity_id)?;
172 if prev_activities
173 .iter()
174 .all(|activity| activity.earliest_finish.is_some())
175 {
176 let earliest_start = prev_activities
177 .iter()
178 .map(|a| a.earliest_finish.ok_or(Error::FieldNotSet))
179 .collect::<Result<Vec<f64>>>()?
180 .iter()
181 .copied()
182 .fold(0.0, f64::max);
183
184 let depth = prev_activities
185 .iter()
186 .map(|a| a.depth)
187 .max()
188 .ok_or(Error::FieldNotSet)?;
189
190 let activity = self.mut_activity(current_activity_id)?;
191 activity.earliest_start(earliest_start);
192 activity.earliest_finish(earliest_start + activity.duration()?);
193 activity.depth = depth + 1;
194
195 for next_activity in self.next_activities(current_activity_id)?.iter() {
196 activity_ids.push(id(&next_activity.reference));
197 }
198 } else {
199 activity_ids.push(current_activity_id)
200 }
201 }
202 Ok(())
203 }
204
205 fn backward_pass(&mut self) -> Result<()> {
206 let mut activity_ids: Vec<u64> = Vec::new();
207
208 for id in self
209 .connections
210 .neighbors_directed(id(&activity::FINISH_REFERENCE), Direction::Incoming)
211 {
212 activity_ids.push(id);
213 }
214
215 while !activity_ids.is_empty() {
216 let current_activity_id = activity_ids.remove(0);
217 let next_activities = self.next_activities(current_activity_id)?;
218 if next_activities
219 .iter()
220 .all(|activity| activity.latest_start.is_some())
221 {
222 let latest_finish = next_activities
223 .iter()
224 .map(|a| a.latest_start.ok_or(Error::FieldNotSet))
225 .collect::<Result<Vec<f64>>>()?
226 .iter()
227 .copied()
228 .fold(f64::MAX, f64::min);
229
230 let activity = self.mut_activity(current_activity_id)?;
231 activity.latest_finish(latest_finish);
232 activity.latest_start(latest_finish - activity.duration()?);
233
234 for prev_activity in self.previous_activities(current_activity_id)?.iter() {
235 activity_ids.push(id(&prev_activity.reference));
236 }
237 } else {
238 activity_ids.push(current_activity_id)
239 }
240 }
241
242 Ok(())
243 }
244
245 pub(crate) fn build(&mut self) -> Result<Network> {
250 if petgraph::algo::is_cyclic_directed(&self.connections.clone().into_graph::<usize>()) {
251 return Err(Error::CycleDetected);
252 }
253
254 for activity in self.activities.values_mut() {
255 activity.earliest_start = None;
256 activity.latest_start = None;
257 activity.earliest_finish = None;
258 activity.latest_finish = None;
259 }
260
261 let mut start_activity = ActivityBuilder::new(
262 activity::START_REFERENCE,
263 activity::START_REFERENCE,
264 0.0,
265 0.0,
266 0.0,
267 );
268
269 start_activity.earliest_start(0.0);
270 start_activity.earliest_finish(0.0);
271 start_activity.latest_start(0.0);
272 start_activity.latest_finish(0.0);
273
274 let start_id = id(&activity::START_REFERENCE);
275
276 self.connections.add_node(start_id);
277
278 for &id in self.activities.keys() {
279 if self
280 .connections
281 .edges_directed(id, Direction::Incoming)
282 .count()
283 == 0
284 {
285 self.connections.add_edge(start_id, id, ());
286 }
287 }
288 self.activities.insert(start_id, start_activity);
289
290 let finish_id = id(&activity::FINISH_REFERENCE);
291 let finish_activity = ActivityBuilder::new(
292 activity::FINISH_REFERENCE,
293 activity::FINISH_REFERENCE,
294 0.0,
295 0.0,
296 0.0,
297 );
298
299 self.connections.add_node(finish_id);
300
301 for &id in self.activities.keys() {
302 if id == finish_id {
303 continue;
304 }
305 if self
306 .connections
307 .edges_directed(id, Direction::Outgoing)
308 .count()
309 == 0
310 {
311 self.connections.add_edge(id, finish_id, ());
312 }
313 }
314 self.activities.insert(finish_id, finish_activity);
315
316 self.forward_pass()?;
317
318 let finish_activity = self.mut_activity(id(&activity::FINISH_REFERENCE))?;
319 let latest_finish = finish_activity.earliest_finish.ok_or(Error::FieldNotSet)?;
320 let latest_start = latest_finish - finish_activity.duration()?;
321
322 finish_activity.latest_finish(latest_finish);
323 finish_activity.latest_start(latest_start);
324
325 self.backward_pass()?;
326
327 let mut activities = HashMap::<u64, Activity>::new();
328 let mut connections = DiGraphMap::<u64, ()>::new();
329
330 for &id in self.activities.keys() {
331 let activity = self.activity(id)?.try_into()?;
332 activities.insert(id, activity);
333
334 connections.add_node(id);
335 for next_neighboud_id in self.connections.neighbors_directed(id, Direction::Outgoing) {
336 connections.add_edge(id, next_neighboud_id, ());
337 }
338 }
339
340 activities.remove(&start_id);
341 activities.remove(&finish_id);
342
343 self.activities.remove(&start_id);
344 self.activities.remove(&finish_id);
345
346 connections.remove_node(start_id);
347 connections.remove_node(finish_id);
348
349 self.connections.remove_node(start_id);
350 self.connections.remove_node(finish_id);
351
352 let network = Network::new(activities, connections, latest_start);
353
354 Ok(network)
355 }
356
357 pub fn update_activity<F>(&mut self, reference: &str, with_activity_builder: F) -> Result<()>
358 where
359 F: FnOnce(&mut ActivityBuilder),
360 {
361 let activity_builder = self.mut_activity(id(&reference))?;
362 with_activity_builder(activity_builder);
363
364 Ok(())
365 }
366}
367
368impl From<Network> for NetworkBuilder {
369 fn from(network: Network) -> NetworkBuilder {
370 network.to_builder()
371 }
372}
373
374impl From<&Network> for NetworkBuilder {
375 fn from(network: &Network) -> NetworkBuilder {
376 network.to_builder()
377 }
378}