def is_k_forcing_set(G, nodes, k): """Return whether or not the nodes in `nodes` comprise a *k*-forcing set in *G*. Parameters ---------- G : NetworkX graph An undirected graph. nodes : list, set An iterable container of nodes in G. k : int A positive integer. Returns ------- boolean True if the nodes in `nodes` comprise a *k*-forcing set in *G*. False otherwise. """ Z = set(n for n in nodes if n in G) while is_k_forcing_active_set(G, Z, k): Z_temp = Z.copy() for v in Z: if is_k_forcing_vertex(G, v, Z, k): Z_temp |= set(neighborhood(G, v)) Z = Z_temp return Z == set(G.nodes())
def is_total_zero_forcing_set(G, nodes): """Return whether or not the nodes in `nodes` comprise a total zero forcing set in *G*. A *total zero forcing set* in a graph *G* is a zero forcing set that does not induce any isolated vertices. Parameters ---------- G : NetworkX graph An undirected graph. nodes : list, set An iterable container of nodes in G. Returns ------- boolean True if the nodes in `nodes` comprise a total zero forcing set in *G*. False otherwise. """ S = set(n for n in nodes if n in G) for v in S: if set(neighborhood(G, v)).intersection(S) == set(): return False return is_zero_forcing_set(G, S)
def is_k_forcing_vertex(G, v, nodes, k): """Return whether or not *v* can *k*-force relative to the set of nodes in `nodes`. Parameters ---------- G : NetworkX graph An undirected graph. v : node A single node in *G*. nodes : list, set An iterable container of nodes in G. k : int A positive integer. Returns ------- boolean True if *v* can *k*-force relative to the nodes in `nodes`. False otherwise. """ # check that k is a positive integer if not float(k).is_integer(): raise TypeError("Expected k to be an integer.") k = int(k) if k < 1: raise ValueError("Expected k to be a positive integer.") S = set(n for n in nodes if n in G) n = len(set(neighborhood(G, v)).difference(S)) return v in S and n >= 1 and n <= k
def is_k_independent_set(G, nodes, k): """Return whether or not `nodes` is a k-independent set in G. A set *S* of nodes in *G* is called a *k-independent set* it every node in S has at most *k*-1 neighbors in S. Notice that a 1-independent set is equivalent to an independent set. Parameters ---------- G : NetworkX graph An undirected graph. nodes : list, set An iterable container of nodes in G. k : int A positive integer. Returns ------- bool True if the nodes in *nodes* comprise a k-independent set, False otherwise. See Also -------- is_independent_set """ if k == 1: return is_independent_set(G, nodes) else: S = set(n for n in nodes if n in G) for v in S: N = set(neighborhood(G, v)) if len(N.intersection(S)) >= k: return False return True
def is_total_dominating_set(G, nbunch): # TODO: Add documentation # check if nbunch is an iterable; if not, convert to a list try: _ = (v for v in nbunch) except: nbunch = [nbunch] return set(neighborhood(G, nbunch)) == set(nodes(G))
def is_independent_set(G, nbunch): # TODO: Add documentation # check if nbunch is an iterable; if not, convert to a list try: _ = (v for v in nbunch) except: nbunch = [nbunch] S = set(nbunch) return set(neighborhood(G, S)).intersection(S) == set()
def min_total_dominating_set_ilp(G): """Return a smallest total dominating set in the graph. This method solves an integer linear program in order to find a smallest total dominating set. It solves the following integer program: minimize .. math:: \\sum_{v \\in V} x_v subject to ... math:: \\sum_{u \\in N(v)} x_u \\geq 1 \\mathrm{ for all } v \\in V where *V* is the set of nodes of G and *N(v)* is the set of neighbors of the vertex *v*. Parameters ---------- G: NetworkX graph An undirected graph. Returns ------- set A set of nodes in a smallest total dominating set in the graph. References ---------- R. Davila, A note on sub-total domination in graphs. *arXiv preprint arXiv: 1701.07811*, (2017) """ prob = LpProblem('min_total_dominating_set', LpMinimize) variables = { node: LpVariable('x{}'.format(i+1), 0, 1, LpBinary) for i, node in enumerate(G.nodes()) } # Set the total domination number objective function prob += lpSum([variables[n] for n in variables]) # Set constraints for node in G.nodes(): combination = [ variables[n] for n in variables if n in neighborhood(G, node) ] prob += lpSum(combination) >= 1 prob.solve() solution_set = {node for node in variables if variables[node].value() == 1} return solution_set
def is_k_forcing_vertex(G, v, nbunch, k): # TODO: Add documentation # TODO: add check that k >= 1 # check if nbunch is an iterable; if not, convert to a list try: _ = (v for v in nbunch) except: nbunch = [nbunch] S = set(nbunch) n = len(set(neighborhood(G, v)).difference(S)) return v in S and n >= 1 and n <= k
def is_k_forcing_set(G, nbunch, k): # TODO: Add documentation # check if nbunch is an iterable; if not, convert to a list try: _ = (v for v in nbunch) except: nbunch = [nbunch] Z = set(nbunch) while is_k_forcing_active_set(G, Z, k): Z_temp = Z.copy() for v in Z: if is_k_forcing_vertex(G, v, Z, k): Z_temp |= set(neighborhood(G, v)) Z = Z_temp return Z == set(nodes(G))
def is_k_independent_set(G, nbunch, k): # TODO: Add documentation # check if nbunch is an iterable; if not, convert to a list try: _ = (v for v in nbunch) except: nbunch = [nbunch] if k == 1: return is_independent_set(G, nbunch) else: for v in nbunch: N = set(neighborhood(G, v)) if len(N.intersection(nbunch)) >= k: return False return True
def is_k_dominating_set(G, nodes, k): """Return whether or not nodes comprises a k-dominating set. A *k-dominating set* is a set of nodes with the property that every node in the graph is either in the set or adjacent at least 1 and at most k nodes in the set. This is a generalization of the well known concept of a dominating set (take k = 1). Parameters ---------- G : NetworkX graph An undirected graph. nodes : list, set An iterable container of nodes in G. k : int A positive integer. Returns ------- boolean True if the nodes in nbunch comprise a k-dominating set, and False otherwise. """ # check that k is a positive integer if not float(k).is_integer(): raise TypeError("Expected k to be an integer.") k = int(k) if k < 1: raise ValueError("Expected k to be a positive integer.") # check if nbunch is an iterable; if not, convert to a list S = set(n for n in nodes if n in G) if k == 1: return is_dominating_set(G, S) else: # loop through the nodes in the complement of S and determine # if they are adjacent to atleast k nodes in S others = set(G.nodes()).difference(S) for v in others: if len(set(neighborhood(G, v)).intersection(S)) < k: return False # if the above loop completes, nbunch is a k-dominating set return True
def is_k_dominating_set(G, nbunch, k): # TODO: Add documentation # TODO: add check that k >= 1 and throw error if not # check if nbunch is an iterable; if not, convert to a list try: _ = (v for v in nbunch) except: nbunch = [nbunch] if k == 1: return is_dominating_set(G, nbunch) else: S = set(nbunch) # loop through the nodes in the complement of S and determine if they are adjacent to atleast k nodes in S others = set(nodes(G)).difference(S) for v in others: if len(set(neighborhood(G, v)).intersection(S)) < k: return False # if the above loop completes, nbunch is a k-dominating set return True
def test_neighborhood(self): G = self.G N0 = gp.neighborhood(G, 0) N1 = gp.neighborhood(G, 1) N2 = gp.neighborhood(G, 2) N3 = gp.neighborhood(G, 3) N4 = gp.neighborhood(G, 4) N5 = gp.neighborhood(G, 5) assert N0 == [1, 2, 3] assert N1 == [0, 2] assert N2 == [0, 1] assert N3 == [0, 4, 5] assert N4 == [3] assert N5 == [3]
def degree(G, x): return len(neighborhood(G, x))