Skip to content

Commit

Permalink
Format coloring package
Browse files Browse the repository at this point in the history
  • Loading branch information
ysitu committed Jun 7, 2014
1 parent aa02955 commit fb1b947
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 120 deletions.
221 changes: 116 additions & 105 deletions networkx/algorithms/coloring/greedy_coloring.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,41 +28,46 @@
'strategy_saturation_largest_first'
]


def min_degree_node(G):
return min(G, key=G.degree)


def max_degree_node(G):
return max(G, key=G.degree)

"""
Largest first (lf) ordering. Ordering the nodes by largest degree
first.
"""

def strategy_largest_first(G, colors):
"""
Largest first (lf) ordering. Ordering the nodes by largest degree
first.
"""
nodes = G.nodes()
nodes.sort(key=lambda node: -G.degree(node))

return nodes

"""
Random sequential (RS) ordering. Scrambles nodes into random ordering.
"""

def strategy_random_sequential(G, colors):
"""
Random sequential (RS) ordering. Scrambles nodes into random ordering.
"""
nodes = G.nodes()
random.shuffle(nodes)

return nodes

"""
Smallest last (sl). Picking the node with smallest degree first,
subtracting it from the graph, and starting over with the new smallest
degree node. When the graph is empty, the reverse ordering of the one
built is returned.
"""

def strategy_smallest_last(G, colors):
"""
Smallest last (sl). Picking the node with smallest degree first,
subtracting it from the graph, and starting over with the new smallest
degree node. When the graph is empty, the reverse ordering of the one
built is returned.
"""
len_g = len(G)
available_g = G.copy()
nodes = [None]*len_g
nodes = [None] * len_g

for i in range(len_g):
node = min_degree_node(available_g)
Expand All @@ -72,59 +77,63 @@ def strategy_smallest_last(G, colors):

return nodes

"""
Greedy independent set ordering (GIS). Generates a maximal independent
set of nodes, and assigns color C to all nodes in this set. This set
of nodes is now removed from the graph, and the algorithm runs again.
"""

def strategy_independent_set(G, colors):
"""
Greedy independent set ordering (GIS). Generates a maximal independent
set of nodes, and assigns color C to all nodes in this set. This set
of nodes is now removed from the graph, and the algorithm runs again.
"""
len_g = len(G)
no_colored = 0
k = 0

uncolored_g = G.copy()
while no_colored < len_g: # While there are uncolored nodes
while no_colored < len_g: # While there are uncolored nodes
available_g = uncolored_g.copy()

while len(available_g): # While there are still nodes available
while len(available_g): # While there are still nodes available
node = min_degree_node(available_g)
colors[node] = k # assign color to values
colors[node] = k # assign color to values

no_colored += 1
uncolored_g.remove_node(node)
# Remove node and its neighbors from available
# Remove node and its neighbors from available
available_g.remove_nodes_from(available_g.neighbors(node) + [node])
k += 1
return None

"""
Connected sequential ordering (CS). Yield nodes in such an order, that
each node, except the first one, has at least one neighbour in the
preceeding sequence. The sequence is generated using BFS)
"""

def strategy_connected_sequential_bfs(G, colors):
"""
Connected sequential ordering (CS). Yield nodes in such an order, that
each node, except the first one, has at least one neighbour in the
preceeding sequence. The sequence is generated using BFS)
"""
return strategy_connected_sequential(G, colors, 'bfs')

"""
Connected sequential ordering (CS). Yield nodes in such an order, that
each node, except the first one, has at least one neighbour in the
preceeding sequence. The sequence is generated using DFS)
"""

def strategy_connected_sequential_dfs(G, colors):
"""
Connected sequential ordering (CS). Yield nodes in such an order, that
each node, except the first one, has at least one neighbour in the
preceeding sequence. The sequence is generated using DFS)
"""
return strategy_connected_sequential(G, colors, 'dfs')

"""
Connected sequential ordering (CS). Yield nodes in such an order, that
each node, except the first one, has at least one neighbour in the
preceeding sequence. The sequence can be generated using both BFS and
DFS search (using the strategy_connected_sequential_bfs and
strategy_connected_sequential_dfs method). The default is bfs.
"""

def strategy_connected_sequential(G, colors, traversal='bfs'):
"""
Connected sequential ordering (CS). Yield nodes in such an order, that
each node, except the first one, has at least one neighbour in the
preceeding sequence. The sequence can be generated using both BFS and
DFS search (using the strategy_connected_sequential_bfs and
strategy_connected_sequential_dfs method). The default is bfs.
"""
for component_graph in nx.connected_component_subgraphs(G):
source = component_graph.nodes()[0]

yield source # Pick the first node as source
yield source # Pick the first node as source

if traversal == 'bfs':
tree = nx.bfs_edges(component_graph, source)
Expand All @@ -135,12 +144,14 @@ def strategy_connected_sequential(G, colors, traversal='bfs'):
'Please specify bfs or dfs for connected sequential ordering')

for (_, end) in tree:
yield end # Then yield nodes in the order traversed by either BFS or DFS
# Then yield nodes in the order traversed by either BFS or DFS
yield end


"""
Saturation largest first (SLF). Also known as degree saturation (DSATUR).
"""
def strategy_saturation_largest_first(G, colors):
"""
Saturation largest first (SLF). Also known as degree saturation (DSATUR).
"""
len_g = len(G)
no_colored = 0
distinct_colors = {}
Expand All @@ -161,7 +172,7 @@ def strategy_saturation_largest_first(G, colors):
highest_saturation_nodes = []

for node, distinct in distinct_colors.items():
if node not in colors: # If the node is not already colored
if node not in colors: # If the node is not already colored
saturation = len(distinct)
if saturation > highest_saturation:
highest_saturation = saturation
Expand Down Expand Up @@ -191,78 +202,78 @@ def strategy_saturation_largest_first(G, colors):
distinct_colors[neighbour].add(color)


"""Color a graph using various strategies of greedy graph coloring.
The strategies are described in [1].
Attempts to color a graph using as few colors as possible, where no
neighbours of a node can have same color as the node itself.
Parameters
----------
G : NetworkX graph
strategy : function(G, colors)
A function that provides the coloring strategy, by returning nodes
in the ordering they should be colored. G is the graph, and colors
is a dict of the currently assigned colors, keyed by nodes.
You can pass your own ordering function, or use one of the built in:
* strategy_largest_first
* strategy_random_sequential
* strategy_smallest_last
* strategy_independent_set
* strategy_connected_sequential (an alias of the BFS version)
* strategy_connected_sequential_bfs
* strategy_connected_sequential_dfs
* strategy_saturation_largest_first (also know as DSATUR)
interchange: boolean
Will use the color interchange algorithm described by [2] if set
to true.
Note that saturation largest first and independent set do not
work with interchange. Furthermore, if you use interchange with
your own strategy function, you cannot rely on the values in the
colors argument
Returns
-------
A dictionary with keys representing nodes and values representing
corresponding coloring.
Examples
--------
>>> G = nx.random_regular_graph(2, 4)
>>> d = nx.coloring.greedy_color(G, strategy=nx.coloring.strategy_largest_first)
>>> d
{0: 0, 1: 1, 2: 0, 3: 1}
References
----------
.. [1] Adrian Kosowski, and Krzysztof Manuszewski,
Classical Coloring of Graphs, Graph Colorings, 2-19, 2004,
ISBN 0-8218-3458-4.
[2] Maciej M. Syslo, Marsingh Deo, Janusz S. Kowalik,
Discrete Optimization Algorithms with Pascal Programs, 415-424, 1983
ISBN 0-486-45353-7
"""
def greedy_color(G, strategy=strategy_largest_first, interchange=False):
colors = dict() # dictionary to keep track of the colors of the nodes
"""Color a graph using various strategies of greedy graph coloring.
The strategies are described in [1]_.
Attempts to color a graph using as few colors as possible, where no
neighbours of a node can have same color as the node itself.
Parameters
----------
G : NetworkX graph
strategy : function(G, colors)
A function that provides the coloring strategy, by returning nodes
in the ordering they should be colored. G is the graph, and colors
is a dict of the currently assigned colors, keyed by nodes.
You can pass your own ordering function, or use one of the built in:
* strategy_largest_first
* strategy_random_sequential
* strategy_smallest_last
* strategy_independent_set
* strategy_connected_sequential (an alias of the BFS version)
* strategy_connected_sequential_bfs
* strategy_connected_sequential_dfs
* strategy_saturation_largest_first (also know as DSATUR)
interchange: boolean
Will use the color interchange algorithm described by [2] if set
to true.
Note that saturation largest first and independent set do not
work with interchange. Furthermore, if you use interchange with
your own strategy function, you cannot rely on the values in the
colors argument
Returns
-------
A dictionary with keys representing nodes and values representing
corresponding coloring.
Examples
--------
>>> G = nx.random_regular_graph(2, 4)
>>> d = nx.coloring.greedy_color(G, strategy=nx.coloring.strategy_largest_first)
>>> d
{0: 0, 1: 1, 2: 0, 3: 1}
References
----------
.. [1] Adrian Kosowski, and Krzysztof Manuszewski,
Classical Coloring of Graphs, Graph Colorings, 2-19, 2004,
ISBN 0-8218-3458-4.
[2] Maciej M. Syslo, Marsingh Deo, Janusz S. Kowalik,
Discrete Optimization Algorithms with Pascal Programs, 415-424, 1983
ISBN 0-486-45353-7
"""
colors = dict() # dictionary to keep track of the colors of the nodes

if len(G):
if interchange and (
strategy == strategy_independent_set or
strategy == strategy_saturation_largest_first):
raise nx.NetworkXPointlessConcept(
'Interchange is not applicable for GIS and SLF')
'Interchange is not applicable for GIS and SLF')

nodes = strategy(G, colors)

if nodes:
if interchange:
return (_interchange
.greedy_coloring_with_interchange(G, nodes))
.greedy_coloring_with_interchange(G, nodes))
else:
for node in nodes:
# set to keep track of colors of neighbours
Expand Down
34 changes: 19 additions & 15 deletions networkx/algorithms/coloring/greedy_coloring_with_interchange.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

__all__ = ['greedy_coloring_with_interchange']


class Node(object):

__slots__ = ['node_id', 'color', 'adj_list', 'adj_color']
Expand Down Expand Up @@ -45,6 +46,7 @@ def iter_neighbors_color(self, color):
yield adj_color_node.node_id
adj_color_node = adj_color_node.col_next


class AdjEntry(object):

__slots__ = ['node_id', 'next', 'mate', 'col_next', 'col_prev']
Expand All @@ -66,21 +68,22 @@ def __repr__(self):
None if self.col_prev == None else self.col_prev.node_id
)

"""
This procedure is an adaption of the algorithm described by [1],
and is an implementation of coloring with interchange. Please be
advised, that the datastructures used are rather complex because
they are optimized to minimize the time spent identifying sub-
components of the graph, which are possible candidates for color
interchange.
References
----------
... [1] Maciej M. Syslo, Marsingh Deo, Janusz S. Kowalik,
Discrete Optimization Algorithms with Pascal Programs, 415-424, 1983
ISBN 0-486-45353-7
"""

def greedy_coloring_with_interchange(original_graph, nodes):
"""
This procedure is an adaption of the algorithm described by [1]_,
and is an implementation of coloring with interchange. Please be
advised, that the datastructures used are rather complex because
they are optimized to minimize the time spent identifying
subcomponents of the graph, which are possible candidates for color
interchange.
References
----------
... [1] Maciej M. Syslo, Marsingh Deo, Janusz S. Kowalik,
Discrete Optimization Algorithms with Pascal Programs, 415-424, 1983
ISBN 0-486-45353-7
"""
n = len(original_graph)

graph = dict(
Expand Down Expand Up @@ -160,7 +163,8 @@ def greedy_coloring_with_interchange(original_graph, nodes):
col_opp = col1 if col == col2 else col2
for adj_node in graph[search_node].iter_neighbors():
if graph[adj_node.node_id].color != col_opp:
adj_mate = adj_node.mate # Direct reference to entry
# Direct reference to entry
adj_mate = adj_node.mate
graph[adj_node.node_id].clear_color(
adj_mate, col_opp)
graph[adj_node.node_id].assign_color(adj_mate, col)
Expand Down

0 comments on commit fb1b947

Please sign in to comment.