def get_incidence_graph(variables, constraints, include_fixed=True): """ This function gets the incidence graph of Pyomo variables and constraints. Arguments: ---------- variables: List of Pyomo VarData objects Variables that will appear in incidence graph constraints: List of Pyomo ConstraintData objects Constraints that will appear in incidence graph include_fixed: Bool Flag for whether fixed variable should be included in the incidence Returns: -------- NetworkX Graph """ _check_unindexed(variables+constraints) N, M = len(variables), len(constraints) graph = nx.Graph() graph.add_nodes_from(range(M), bipartite=0) graph.add_nodes_from(range(M, M+N), bipartite=1) var_node_map = ComponentMap((v, M+i) for i, v in enumerate(variables)) for i, con in enumerate(constraints): for var in identify_variables(con.expr, include_fixed=include_fixed): if var in var_node_map: graph.add_edge(i, var_node_map[var]) return graph
def test_not_directed(self): G = networkx.Graph() G.add_node("1") G.add_node("2") G.add_edge("1", "2") with self.assertRaises(TypeError): ScenarioTreeModelFromNetworkX(G)
def _construct_graph(self): bg = nx.Graph() n_l = 12 n_r = 11 left_nodes = list(range(n_l)) right_nodes = list(range(n_r)) bg.add_nodes_from(left_nodes, bipartite=0) bg.add_nodes_from([n_l + i for i in right_nodes], bipartite=1) paper_edges = [ (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (2, 4), (2, 5), (2, 7), (2, 8), (2, 10), (3, 1), (3, 3), (3, 5), (4, 6), (4, 7), (4, 11), (5, 6), (5, 7), (5, 9), (6, 8), (6, 9), (7, 8), (7, 9), (7, 10), (8, 10), (8, 11), (9, 11), (10, 10), (11, 10), (11, 11), (12, 11), ] edges = [(i - 1, j - 1 + n_l) for i, j in paper_edges] bg.add_edges_from(edges) return bg
def _construct_graph(self): """ Graph with the following incidence matrix: |x x x| |x x | | x x | | x x | | x x | | x| | x| """ N = 7 top_nodes = list(range(N)) bot_nodes = list(range(N, 2 * N)) graph = nx.Graph() graph.add_nodes_from(top_nodes, bipartite=0) graph.add_nodes_from(bot_nodes, bipartite=1) edges = [ (0, 0), (0, 1), (0, 6), (1, 0), (1, 2), (2, 3), (2, 5), (3, 4), (3, 5), (4, 3), (4, 4), (5, 6), (6, 6), ] edges = [(i, j + N) for i, j in edges] graph.add_edges_from(edges) return graph, top_nodes
def generate_model_graph(model, type_of_graph, with_objective=True, weighted_graph=True, use_only_active_components=True): """ Creates a networkX graph of nodes and edges based on a Pyomo optimization model This function takes in a Pyomo optimization model, then creates a graphical representation of the model with specific features of the graph determined by the user (see Parameters below). (This function is designed to be called by detect_communities, but can be used solely for the purpose of creating model graphs as well.) Parameters ---------- model: Block a Pyomo model or block to be used for community detection type_of_graph: str a string that specifies the type of graph that is created from the model 'constraint' creates a graph based on constraint nodes, 'variable' creates a graph based on variable nodes, 'bipartite' creates a graph based on constraint and variable nodes (bipartite graph). with_objective: bool, optional a Boolean argument that specifies whether or not the objective function is included in the graph; the default is True weighted_graph: bool, optional a Boolean argument that specifies whether a weighted or unweighted graph is to be created from the Pyomo model; the default is True (type_of_graph='bipartite' creates an unweighted graph regardless of this parameter) use_only_active_components: bool, optional a Boolean argument that specifies whether inactive constraints/objectives are included in the networkX graph Returns ------- bipartite_model_graph/projected_model_graph: nx.Graph a NetworkX graph with nodes and edges based on the given Pyomo optimization model number_component_map: dict a dictionary that (deterministically) maps a number to a component in the model constraint_variable_map: dict a dictionary that maps a numbered constraint to a list of (numbered) variables that appear in the constraint """ # Start off by making a bipartite graph (regardless of the value of type_of_graph), then if # type_of_graph = 'variable' or 'constraint', we will "collapse" this bipartite graph into a variable node # or constraint node graph # Initialize the data structure needed to keep track of edges in the graph (this graph will be made # without edge weights, because edge weights are not useful for this bipartite graph) edge_set = set() bipartite_model_graph = nx.Graph() # Initialize NetworkX graph for the bipartite graph constraint_variable_map = {} # Initialize map of the variables in constraint equations # Make a dict of all the components we need for the NetworkX graph (since we cannot use the components directly # in the NetworkX graph) if with_objective: component_number_map = ComponentMap((component, number) for number, component in enumerate( model.component_data_objects(ctype=(Constraint, Var, Objective), active=use_only_active_components, descend_into=True, sort=SortComponents.deterministic))) else: component_number_map = ComponentMap((component, number) for number, component in enumerate( model.component_data_objects(ctype=(Constraint, Var), active=use_only_active_components, descend_into=True, sort=SortComponents.deterministic))) # Create the reverse of component_number_map, which will be used in detect_communities to convert the node numbers # to their corresponding Pyomo modeling components number_component_map = dict((number, comp) for comp, number in component_number_map.items()) # Add the components as nodes to the bipartite graph bipartite_model_graph.add_nodes_from([node_number for node_number in range(len(component_number_map))]) # Loop through all constraints in the Pyomo model to determine what edges need to be created for model_constraint in model.component_data_objects(ctype=Constraint, active=use_only_active_components, descend_into=True): numbered_constraint = component_number_map[model_constraint] # Create a list of the variable numbers that occur in the given constraint equation numbered_variables_in_constraint_equation = [component_number_map[constraint_variable] for constraint_variable in identify_variables(model_constraint.body)] # Update constraint_variable_map constraint_variable_map[numbered_constraint] = numbered_variables_in_constraint_equation # Create a list of all the edges that need to be created based on the variables in this constraint equation edges_between_nodes = [(numbered_constraint, numbered_variable_in_constraint) for numbered_variable_in_constraint in numbered_variables_in_constraint_equation] # Update edge_set based on the determined edges between nodes edge_set.update(edges_between_nodes) # This if statement will be executed if the user chooses to include the objective function as a node in # the model graph if with_objective: # Use a loop to account for the possibility of multiple objective functions for objective_function in model.component_data_objects(ctype=Objective, active=use_only_active_components, descend_into=True): numbered_objective = component_number_map[objective_function] # Create a list of the variable numbers that occur in the given objective function numbered_variables_in_objective = [component_number_map[objective_variable] for objective_variable in identify_variables(objective_function)] # Update constraint_variable_map constraint_variable_map[numbered_objective] = numbered_variables_in_objective # Create a list of all the edges that need to be created based on the variables in the objective function edges_between_nodes = [(numbered_objective, numbered_variable_in_objective) for numbered_variable_in_objective in numbered_variables_in_objective] # Update edge_set based on the determined edges between nodes edge_set.update(edges_between_nodes) # Add edges to bipartite_model_graph (the order in which edges are added can affect community detection, so # sorting prevents any unpredictable changes) bipartite_model_graph.add_edges_from(sorted(edge_set)) if type_of_graph == 'bipartite': # This is the case where the user wants a bipartite graph, which we made above # Log important information with the following logger function _event_log(model, bipartite_model_graph, set(constraint_variable_map), type_of_graph, with_objective) # Return the bipartite NetworkX graph, the dictionary of node numbers mapped to their respective Pyomo # components, and the map of constraints to the variables they contain return bipartite_model_graph, number_component_map, constraint_variable_map # At this point of the code, we will create the projected version of the bipartite # model graph (based on the specific value of type_of_graph) constraint_nodes = set(constraint_variable_map) if type_of_graph == 'constraint': graph_nodes = constraint_nodes else: variable_nodes = set(number_component_map) - constraint_nodes graph_nodes = variable_nodes if weighted_graph: projected_model_graph = nx.bipartite.weighted_projected_graph(bipartite_model_graph, graph_nodes) else: projected_model_graph = nx.bipartite.projected_graph(bipartite_model_graph, graph_nodes) # Log important information with the following logger function _event_log(model, projected_model_graph, set(constraint_variable_map), type_of_graph, with_objective) # Return the projected NetworkX graph, the dictionary of node numbers mapped to their respective Pyomo # components, and the map of constraints to the variables they contain return projected_model_graph, number_component_map, constraint_variable_map