def build_J(cells, spacing, r_max=R_MAX): '''Build the J matrix for the given circuit. Restricts the interaction distance to r_max but does not apply any adjacency contraints''' N = len(cells) # contruct connectivvity matrix J = np.zeros([N, N], dtype=float) DR = r_max*spacing for i,j in combinations(range(N), 2): Ek = getEk(cells[i], cells[j], DR=DR) if Ek: J[i,j] = J[j,i] = Ek # remove very weak interactions J = J*(np.abs(J) >= np.max(np.abs(J)*EK_THRESH)) return J
def zone_cells(cells, spacing, show=False): '''Split cells into clock zones. Distinguishes disjoint zones with the same zone index''' N = len(cells) # number of cells # construct connectivity matrix J = np.zeros([N, N], dtype=float) DR = R_MAX * spacing for i in xrange(N - 1): for j in xrange(i + 1, N): Ek = getEk(cells[i], cells[j], DR=DR) if Ek: J[i, j] = Ek J[j, i] = Ek # remove very weak interactions J = J * (np.abs(J) >= np.max(np.abs(J) * EK_THRESH)) # make full cell connectivity Graph G = nx.Graph(J) # if show: # plt.figure(0) # plt.clf() # nx.draw_graphviz(G) # plt.show() # get indices for each clock index clk = [cell['clk'] for cell in cells] clk_ind = list(set(clk)) # will sort by default inds = [[i for i, x in enumerate(clk) if x == ind] for ind in clk_ind] # split graph into sub-graphs with the same clock indices sub_G = {ind: G.subgraph(inds[ind]) for ind in clk_ind} # split disconnected components for each label graph sub_ind = { ind: list(nx.connected_components(sub_G[ind])) for ind in clk_ind } ## find zone order # create abstract zone connectivity graph G = nx.DiGraph() # nodes for clk in clk_ind: for i in xrange(len(sub_ind[clk])): key = (clk, i) G.add_node(key, inds=sub_ind[clk][i]) # edges for clk in clk_ind: adj_clk = 3 if clk == 0 else clk - 1 if not adj_clk in sub_ind: continue for i in xrange(len(sub_ind[clk])): k1 = (clk, i) for j in xrange(len(sub_ind[adj_clk])): k2 = (adj_clk, j) if np.any(J[G.node[k1]['inds'], :][:, G.node[k2]['inds']]): G.add_edge(k2, k1) # if show: # plt.figure(1) # plt.clf() # nx.draw_graphviz(G) # plt.show() # find input nodes, have no predecessors predecs = {n: len(G.predecessors(n)) for n in G.nodes_iter()} inputs = [ky for ky, val in predecs.iteritems() if val == 0] # expand from inputs visited = {key: False for key in G.nodes()} nodes = inputs order = [nodes] while nodes: new_nodes = set() for node in nodes: new_nodes.update(G.successors(node)) visited[node] = True # remove already visited nodes from new nodes new_nodes = [node for node in new_nodes if not visited[node]] nodes = new_nodes if nodes: order.append(nodes) # find feedback interactions feedback = {} for n in G.nodes_iter(): for p in G.predecessors(n): pshell = 0 nshell = 0 pzone = 0 nzone = 0 for shell in order: if p in shell: pshell = order.index(shell) pzone = shell.index(p) if n in shell: nshell = order.index(shell) nzone = shell.index(n) if pshell > nshell: if (pshell, pzone) in feedback: feedback[(pshell, pzone)].append((nshell, nzone)) else: feedback[(pshell, pzone)] = [(nshell, nzone)] # reformat order list to contain zone indices form_func = lambda n: sub_ind[n[0]][n[1]] order = [[form_func(zone) for zone in shell] for shell in order] return order, J, feedback
def zone_cells(cells, spacing): '''Split cells into clock zones. Distinguishes disjoint zones with the same zone index''' N = len(cells) # number of cells # construct connectivity matrix J = np.zeros([N, N], dtype=float) DR = R_MAX*spacing for i in range(N-1): for j in range(i+1, N): Ek = getEk(cells[i], cells[j], DR=DR) if Ek: J[i, j] = -Ek J[j, i] = -Ek # remove very weak interactions J = J * (np.abs(J) >= np.max(np.abs(J)*EK_THRESH)) # make full cell connectivity Graph G = nx.Graph(J) # get indices for each clock index clk = [cell['clk'] for cell in cells] clk_ind = list(set(clk)) # will sort by default inds = [[i for i, x in enumerate(clk) if x == ind] for ind in clk_ind] # split graph into sub-graphs with the same clock indices sub_G = {ind: G.subgraph(inds[ind]) for ind in clk_ind} # split disconnected components for each label graph sub_ind = {ind: list(nx.connected_components(sub_G[ind])) for ind in clk_ind} ## find zone order # create abstract zone connectivity graph G = nx.DiGraph() # nodes for clk in clk_ind: for i in range(len(sub_ind[clk])): key = (clk, i) G.add_node(key, inds=sub_ind[clk][i]) # edges for clk in clk_ind: adj_clk = 3 if clk == 0 else clk-1 if not adj_clk in sub_ind: continue for i in range(len(sub_ind[clk])): k1 = (clk, i) for j in range(len(sub_ind[adj_clk])): k2 = (adj_clk, j) if np.any(J[G.node[k1]['inds'], :][:, G.node[k2]['inds']]): G.add_edge(k2, k1) # find input nodes, have no predecessors predecs = {n: len(list(G.predecessors(n))) for n in G} inputs = [ky for ky, val in predecs.iteritems() if val == 0] # expand from inputs visited = {key: False for key in G.nodes()} nodes = inputs order = [nodes] while nodes: new_nodes = set() for node in nodes: new_nodes.update(G.successors(node)) visited[node] = True # remove already visited nodes from new nodes new_nodes = [node for node in new_nodes if not visited[node]] nodes = new_nodes if nodes: order.append(nodes) # find feedback interactions feedback = {} for n in G: for p in G.predecessors(n): pshell = 0 nshell = 0 pzone = 0 nzone = 0 for shell in order: if p in shell: pshell = order.index(shell) pzone = shell.index(p) if n in shell: nshell = order.index(shell) nzone = shell.index(n) if pshell > nshell: if (pshell,pzone) in feedback: feedback[(pshell,pzone)].append((nshell,nzone)) else: feedback[(pshell,pzone)] = [(nshell,nzone)] # reformat order list to contain zone indices form_func = lambda n: sub_ind[n[0]][n[1]] order = [[form_func(zone) for zone in shell] for shell in order] return order, J, feedback