1use crate::activity::Activity;
2use crate::activity_builder::ActivityBuilder;
3use crate::{id, Error, NetworkBuilder, Result};
4use petgraph::graphmap::DiGraphMap;
5use petgraph::Direction;
6
7use std::collections::HashMap;
8use std::fmt::Write;
9
10#[derive(Default, Clone, Debug)]
11pub struct Network {
12 activities: HashMap<u64, Activity>,
13 connections: DiGraphMap<u64, ()>,
14 finish_earliest_start: f64,
15}
16
17impl Network {
18 pub fn builder() -> NetworkBuilder {
19 NetworkBuilder::default()
20 }
21
22 pub(crate) fn new(
23 activities: HashMap<u64, Activity>,
24 connections: DiGraphMap<u64, ()>,
25 finish_earliest_start: f64,
26 ) -> Self {
27 Self {
28 activities,
29 connections,
30 finish_earliest_start,
31 }
32 }
33
34 fn id_activity(&self, id: u64) -> Result<&Activity> {
35 self.activities.get(&id).ok_or(Error::UnknownId(id))
36 }
37
38 fn activity(&self, reference: &str) -> Result<&Activity> {
39 self.activities
40 .get(&id(&reference))
41 .ok_or_else(|| Error::UnknownReference(reference.to_string()))
42 }
43
44 pub fn activities(&self) -> Result<Vec<&str>> {
46 let mut depth_and_references: Vec<(usize, &str)> = self
47 .activities
48 .values()
49 .map(|activity| (activity.depth, activity.reference.as_str()))
50 .collect();
51
52 depth_and_references.sort_by_key(|&(depth, _)| depth);
53 Ok(depth_and_references
54 .iter()
55 .map(|(_, reference)| *reference)
56 .collect())
57 }
58
59 pub fn edges(&self) -> Result<Vec<(&str, &str)>> {
61 self.connections
62 .all_edges()
63 .map(|(origin_id, target_id, _)| {
64 match (self.id_activity(origin_id), self.id_activity(target_id)) {
65 (Ok(origin), Ok(target)) => {
66 Ok((origin.reference.as_str(), target.reference.as_str()))
67 }
68 (Err(error), _) => Err(error),
69 (_, Err(error)) => Err(error),
70 }
71 })
72 .collect::<Result<Vec<(&str, &str)>>>()
73 }
74
75 pub fn connected(&self, origin_reference: &str, target_reference: &str) -> Result<bool> {
77 let origin = self.activity(origin_reference)?;
78 let target = self.activity(target_reference)?;
79
80 match self.connections.edge_weight(id(origin), id(target)) {
81 Some(_) => Ok(true),
82 None => Ok(false),
83 }
84 }
85
86 pub fn start_activities(&self) -> Result<Vec<&str>> {
90 let mut start_activities = Vec::new();
91 for id in self.activities.keys() {
92 if self
93 .connections
94 .edges_directed(*id, Direction::Incoming)
95 .count()
96 == 0
97 {
98 start_activities.push(self.id_activity(*id)?.reference.as_str());
99 }
100 }
101 Ok(start_activities)
102 }
103
104 pub fn finish_activities(&self) -> Result<Vec<&str>> {
108 let mut finish_activities = Vec::new();
109 for id in self.activities.keys() {
110 if self
111 .connections
112 .edges_directed(*id, Direction::Outgoing)
113 .count()
114 == 0
115 {
116 finish_activities.push(self.id_activity(*id)?.reference.as_str());
117 }
118 }
119 Ok(finish_activities)
120 }
121
122 fn ids_to_references(&self, ids: Vec<u64>) -> Result<Vec<&str>> {
123 Ok(ids
124 .iter()
125 .map(|id| self.id_activity(*id))
126 .collect::<Result<Vec<&Activity>>>()?
127 .iter()
128 .map(|activity| activity.reference.as_str())
129 .collect())
130 }
131
132 pub fn next_activities(&self, reference: &str) -> Result<Vec<&str>> {
134 self.ids_to_references(
135 self.connections
136 .neighbors_directed(id(&reference), Direction::Outgoing)
137 .collect(),
138 )
139 }
140
141 pub fn previous_activities(&self, reference: &str) -> Result<Vec<&str>> {
143 self.ids_to_references(
144 self.connections
145 .neighbors_directed(id(&reference), Direction::Incoming)
146 .collect(),
147 )
148 }
149
150 pub fn earliest_finish(&self, reference: &str) -> Result<f64> {
152 Ok(self.activity(reference)?.earliest_finish)
153 }
154
155 pub fn latest_finish(&self, reference: &str) -> Result<f64> {
157 Ok(self.activity(reference)?.latest_finish)
158 }
159
160 pub fn latest_start(&self, reference: &str) -> Result<f64> {
162 Ok(self.activity(reference)?.latest_start)
163 }
164
165 pub fn earliest_start(&self, reference: &str) -> Result<f64> {
167 Ok(self.activity(reference)?.earliest_start)
168 }
169
170 pub fn on_critical_path(&self, reference: &str) -> Result<bool> {
172 let activity = self.activity(reference)?;
173 Ok(activity.on_critical_path())
174 }
175
176 pub fn critical_path_activities(&self) -> Result<Vec<&str>> {
178 Ok(self
179 .activities
180 .values()
181 .filter(|activity| activity.on_critical_path())
182 .map(|activity| activity.reference.as_str())
183 .collect())
184 }
185
186 pub fn total_float(&self, reference: &str) -> Result<f64> {
191 Ok(self.activity(reference)?.total_float())
192 }
193
194 pub fn free_float(&self, reference: &str) -> Result<f64> {
199 let activity = self.activity(reference)?;
200 let min_earliest_start = self
201 .next_activities(reference)?
202 .iter()
203 .map(|reference| self.activity(reference))
204 .collect::<Result<Vec<&Activity>>>()?
205 .iter()
206 .map(|activity| activity.earliest_start)
207 .fold(self.finish_earliest_start, f64::min);
208
209 let max_earliest_finish = self
210 .previous_activities(reference)?
211 .iter()
212 .map(|reference| self.activity(reference))
213 .collect::<Result<Vec<&Activity>>>()?
214 .iter()
215 .map(|activity| activity.earliest_finish)
216 .fold(0.0, f64::max);
217
218 Ok(min_earliest_start - max_earliest_finish - activity.duration())
219 }
220
221 pub fn start(&self, reference: &str) -> Result<f64> {
223 Ok(self.activity(reference)?.start())
224 }
225
226 pub fn finish(&self, reference: &str) -> Result<f64> {
228 Ok(self.activity(reference)?.finish())
229 }
230
231 pub fn active_at(&self, reference: &str, time: f64) -> Result<bool> {
233 Ok(self.activity(reference)?.active_on(time))
234 }
235
236 pub fn active_during(&self, reference: &str, range: std::ops::Range<f64>) -> Result<bool> {
238 Ok(self.activity(reference)?.active_during(range))
239 }
240
241 pub fn mean_duration(&self, reference: &str) -> Result<f64> {
245 Ok(self.activity(reference)?.mean_duration())
246 }
247
248 pub fn variance(&self, reference: &str) -> Result<f64> {
252 Ok(self.activity(reference)?.variance())
253 }
254
255 pub fn standard_deviation(&self, reference: &str) -> Result<f64> {
259 Ok(self.activity(reference)?.standard_deviation())
260 }
261
262 pub fn depth(&self, reference: &str) -> Result<usize> {
267 Ok(self.activity(reference)?.depth)
268 }
269
270 pub fn to_dot(&self) -> Result<String> {
273 let mut s = String::new();
274
275 writeln!(&mut s, "digraph {{")?;
276 writeln!(&mut s, "rankdir=LR;")?;
277 writeln!(&mut s, "node [shape=Mrecord];")?;
278 for activity in self.activities.values() {
279 write!(&mut s, "\"{}\" ", activity.reference)?;
280 write!(&mut s, "[label=\"{}|", activity.description)?;
281 write!(&mut s, "{{")?;
282 write!(
283 &mut s,
284 "{{{}|{}}}",
285 activity.earliest_start, activity.latest_start,
286 )?;
287 write!(
288 &mut s,
289 "|{{{}|{{{}|{}}}}}",
290 activity.reference,
291 activity.total_float(),
292 self.free_float(&activity.reference)?
293 )?;
294 write!(
295 &mut s,
296 "|{{{}|{}}}}}",
297 activity.earliest_finish, activity.latest_finish
298 )?;
299 writeln!(&mut s, "|{}\"];", activity.duration())?;
300 }
301
302 for (from, to) in self.edges()?.iter() {
303 write!(&mut s, "\"{}\" -> \"{}\"", from, to)?;
304 if self.on_critical_path(from)? && self.on_critical_path(to)? {
305 write!(&mut s, "[style=bold]")?;
306 }
307 writeln!(&mut s, ";")?;
308 }
309 write!(&mut s, "}}")?;
310 Ok(s)
311 }
312
313 pub(crate) fn to_builder(&self) -> NetworkBuilder {
315 let mut activities = HashMap::<u64, ActivityBuilder>::new();
316 for (&id, activity) in self.activities.iter() {
317 activities.insert(id, activity.into());
318 }
319
320 NetworkBuilder::new(activities, self.connections.clone())
321 }
322
323 pub fn update_activity<F>(self, reference: &str, with_activity_builder: F) -> Result<Network>
324 where
325 F: FnOnce(&mut ActivityBuilder),
326 {
327 let mut network_builder = self.to_builder();
328 network_builder.update_activity(reference, with_activity_builder)?;
329
330 Self::try_from(network_builder)
331 }
332}
333
334impl TryFrom<NetworkBuilder> for Network {
335 type Error = crate::Error;
336
337 fn try_from(mut network_builder: NetworkBuilder) -> std::result::Result<Network, Self::Error> {
338 network_builder.build()
339 }
340}
341
342impl TryFrom<&mut NetworkBuilder> for Network {
343 type Error = crate::Error;
344
345 fn try_from(network_builder: &mut NetworkBuilder) -> std::result::Result<Network, Self::Error> {
346 network_builder.build()
347 }
348}