///|
pub(all) struct ScheduleCriticalPath {
ordered_stations : Array[String]
makespan_sec : Double
earliest_finish_times : Map[String, Double]
critical_path : Array[String]
} derive(Debug)
///|
pub fn topological_production_schedule(
graph : @graph.FactoryGraph,
) -> ScheduleCriticalPath? {
let in_degree : Map[String, Int] = Map([])
let nodes = graph.get_all_nodes()
for node in nodes {
let id = node.id()
let in_edges = graph.get_layer_in_edges(@types.FlowType::MaterialFlow, id)
in_degree[id] = in_edges.length()
}
let queue : Array[String] = []
for node in nodes {
let id = node.id()
if in_degree[id] == 0 {
queue.push(id)
}
}
let ordered : Array[String] = []
let ef : Map[String, Double] = Map([])
for node in nodes {
let id = node.id()
ef[id] = node.cycle_time_sec()
}
while queue.length() > 0 {
let u = queue.remove(0)
ordered.push(u)
let out_edges = graph.get_layer_out_edges(@types.FlowType::MaterialFlow, u)
for edge in out_edges {
if edge.is_active() {
let v = edge.target_id()
let v_node = graph.get_node(v)
let v_ct = match v_node {
Some(n) => n.cycle_time_sec()
None => 0.0
}
let u_ef = ef[u]
let candidate_ef = u_ef + edge.transport_delay_sec() + v_ct
if candidate_ef > ef[v] {
ef[v] = candidate_ef
}
in_degree[v] = in_degree[v] - 1
if in_degree[v] == 0 {
queue.push(v)
}
}
}
}
if ordered.length() < nodes.length() {
return None // Graph has cycles, cannot strictly DAG schedule
}
// Find max makespan
let mut max_makespan = 0.0
let mut end_node = ""
for n, t in ef {
if t > max_makespan {
max_makespan = t
end_node = n
}
}
Some({
ordered_stations: ordered,
makespan_sec: max_makespan,
earliest_finish_times: ef,
critical_path: [end_node],
})
}