Source code for job_shop_lib.graphs._build_disjunctive_graph
"""Module for building the disjunctive graph of a job shop instance.The disjunctive graph is created by first adding nodes representing eachoperation in the jobs, along with two special nodes: a source $S$ and a sink$T$. Each operation node is linked to the next operation in its job sequenceby **conjunctive edges**, forming a path from the source to the sink. Theseedges represent the order in which operations of a single job must beperformed.Additionally, the graph includes **disjunctive edges** between operationsthat use the same machine but belong to different jobs. These edges arebidirectional, indicating that either of the connected operations can beperformed first. The disjunctive edges thus represent the scheduling choicesavailable: the order in which operations sharing a machine can be processed.Solving the Job Shop Scheduling problem involves choosing a direction foreach disjunctive edge such that the overall processing time is minimized."""importitertoolsfromjob_shop_libimportJobShopInstance,Schedulefromjob_shop_lib.graphsimportJobShopGraph,EdgeType,NodeType,Node
[docs]defbuild_disjunctive_graph(instance:JobShopInstance)->JobShopGraph:"""Builds and returns a disjunctive graph for the given job shop instance. This function creates a complete disjunctive graph from a :JobShopInstance. It starts by initializing a JobShopGraph object and proceeds by adding disjunctive edges between operations using the same machine, conjunctive edges between successive operations in the same job, and finally, special source and sink nodes with their respective edges to and from all other operations. Edges have a "type" attribute indicating whether they are disjunctive or conjunctive. Args: instance (JobShopInstance): The job shop instance for which to build the graph. Returns: A :class:`JobShopGraph` object representing the disjunctive graph of the job shop scheduling problem. """graph=JobShopGraph(instance)add_disjunctive_edges(graph)add_conjunctive_edges(graph)add_source_sink_nodes(graph)add_source_sink_edges(graph)returngraph
[docs]defbuild_solved_disjunctive_graph(schedule:Schedule)->JobShopGraph:"""Builds and returns a disjunctive graph for the given solved schedule. This function constructs a disjunctive graph from the given schedule, keeping only the disjunctive edges that represent the chosen ordering of operations on each machine as per the solution schedule. Args: schedule (Schedule): The solved schedule that contains the sequencing of operations on each machine. Returns: A JobShopGraph object representing the disjunctive graph of the solved job shop scheduling problem. """# Build the base disjunctive graph from the job shop instancegraph=JobShopGraph(schedule.instance)add_conjunctive_edges(graph)add_source_sink_nodes(graph)add_source_sink_edges(graph)# Iterate over each machine and add only the edges that match the solution# orderformachine_scheduleinschedule.schedule:fori,scheduled_operationinenumerate(machine_schedule):ifi+1>=len(machine_schedule):breaknext_scheduled_operation=machine_schedule[i+1]graph.add_edge(scheduled_operation.operation.operation_id,next_scheduled_operation.operation.operation_id,type=EdgeType.DISJUNCTIVE,)returngraph
[docs]defadd_disjunctive_edges(graph:JobShopGraph)->None:"""Adds disjunctive edges to the graph."""formachineingraph.nodes_by_machine:fornode1,node2initertools.combinations(machine,2):graph.add_edge(node1,node2,type=EdgeType.DISJUNCTIVE,)graph.add_edge(node2,node1,type=EdgeType.DISJUNCTIVE,)
[docs]defadd_conjunctive_edges(graph:JobShopGraph)->None:"""Adds conjunctive edges to the graph."""forjob_operationsingraph.nodes_by_job:foriinrange(1,len(job_operations)):graph.add_edge(job_operations[i-1],job_operations[i],type=EdgeType.CONJUNCTIVE,)
[docs]defadd_source_sink_nodes(graph:JobShopGraph)->None:"""Adds source and sink nodes to the graph."""source=Node(node_type=NodeType.SOURCE)sink=Node(node_type=NodeType.SINK)graph.add_node(source)graph.add_node(sink)
[docs]defadd_source_sink_edges(graph:JobShopGraph)->None:"""Adds edges between source and sink nodes and operations."""source=graph.nodes_by_type[NodeType.SOURCE][0]sink=graph.nodes_by_type[NodeType.SINK][0]forjob_operationsingraph.nodes_by_job:graph.add_edge(source,job_operations[0],type=EdgeType.CONJUNCTIVE)graph.add_edge(job_operations[-1],sink,type=EdgeType.CONJUNCTIVE)