| 
						
						
							
								
							
						
						
					 | 
					 | 
					@ -134,10 +134,10 @@ class Node: | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        This is ok, because (name, kind) is unique within a circuit. | 
					 | 
					 | 
					 | 
					        This is ok, because (name, kind) is unique within a circuit. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        """ | 
					 | 
					 | 
					 | 
					        """ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        return self.name == other.name and self.kind == other.kind | 
					 | 
					 | 
					 | 
					        return self.name == other.name and self.kind == other.kind and self.circuit == other.circuit | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    def __hash__(self): | 
					 | 
					 | 
					 | 
					    def __hash__(self): | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        return hash((self.name, self.kind)) | 
					 | 
					 | 
					 | 
					        return hash((self.name, self.kind, id(self.circuit))) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					class Line: | 
					 | 
					 | 
					 | 
					class Line: | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					 | 
					@ -539,9 +539,6 @@ class Circuit: | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        for n in state['io_nodes']: | 
					 | 
					 | 
					 | 
					        for n in state['io_nodes']: | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            self.io_nodes.append(self.nodes[n]) | 
					 | 
					 | 
					 | 
					            self.io_nodes.append(self.nodes[n]) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    def __eq__(self, other): | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        return self.nodes == other.nodes and self.lines == other.lines and self.io_nodes == other.io_nodes | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    def __repr__(self): | 
					 | 
					 | 
					 | 
					    def __repr__(self): | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        return f'{{name: "{self.name}", cells: {len(self.cells)}, forks: {len(self.forks)}, lines: {len(self.lines)}, io_nodes: {len(self.io_nodes)}}}' | 
					 | 
					 | 
					 | 
					        return f'{{name: "{self.name}", cells: {len(self.cells)}, forks: {len(self.forks)}, lines: {len(self.lines)}, io_nodes: {len(self.io_nodes)}}}' | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					 | 
					@ -651,9 +648,9 @@ class Circuit: | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                region.append(n) | 
					 | 
					 | 
					 | 
					                region.append(n) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            yield stem, region | 
					 | 
					 | 
					 | 
					            yield stem, region | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    def dot(self, format='svg'): | 
					 | 
					 | 
					 | 
					    def dot(self, format='svg', graph_attr={}, line_labels={}): | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        from graphviz import Digraph | 
					 | 
					 | 
					 | 
					        from graphviz import Digraph | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        dot = Digraph(format=format, graph_attr={'rankdir': 'LR', 'splines': 'true'}) | 
					 | 
					 | 
					 | 
					        dot = Digraph(format=format, graph_attr={'rankdir': 'LR', 'splines': 'true', 'size': '10', 'ranksep': '0.1'} | graph_attr) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        s_dict = dict((n, i) for i, n in enumerate(self.s_nodes)) | 
					 | 
					 | 
					 | 
					        s_dict = dict((n, i) for i, n in enumerate(self.s_nodes)) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        node_level = np.zeros(len(self.nodes), dtype=np.uint32) | 
					 | 
					 | 
					 | 
					        node_level = np.zeros(len(self.nodes), dtype=np.uint32) | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -666,20 +663,24 @@ class Circuit: | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            with dot.subgraph() as s: | 
					 | 
					 | 
					 | 
					            with dot.subgraph() as s: | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                s.attr(rank='same') | 
					 | 
					 | 
					 | 
					                s.attr(rank='same') | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                for n in level_nodes[lv]: | 
					 | 
					 | 
					 | 
					                for n in level_nodes[lv]: | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                    ins = '|'.join([f'<i{i}>{i}' for i in range(len(n.ins))]) | 
					 | 
					 | 
					 | 
					                    ins = '{' + '|'.join([f'<i{i}>{i}' for i in range(len(n.ins))]) + '}|' if len(n.ins) > 1 else '' | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                    outs = '|'.join([f'<o{i}>{i}' for i in range(len(n.outs))]) | 
					 | 
					 | 
					 | 
					                    outs = '|{' + '|'.join([f'<o{i}>{i}' for i in range(len(n.outs))]) + '}' if len(n.outs) > 1 else '' | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                    io = f' [{s_dict[n]}]' if n in s_dict else '' | 
					 | 
					 | 
					 | 
					                    io = f' [{s_dict[n]}]' if n in s_dict else '' | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                    s.node(name=str(n.index), label = fr'{{{{{ins}}}|{n.index}{io}\n{n.kind}\n{n.name}|{{{outs}}}}}', shape='record') | 
					 | 
					 | 
					 | 
					                    color = '#f5f5f5' if n.kind == '__fork__' else '#cccccc' | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                    kind = '' if n.kind == '__fork__' else fr'\n{n.kind}' | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                    s.node(name=str(n.index), label = fr'{{{ins}{n.index}{io}{kind}\n{n.name}{outs}}}', shape='record', style='filled', fillcolor=color) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        for l in self.lines: | 
					 | 
					 | 
					 | 
					        for l in self.lines: | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            driver, reader = f'{l.driver.index}:o{l.driver_pin}', f'{l.reader.index}:i{l.reader_pin}' | 
					 | 
					 | 
					 | 
					            driver = f'{l.driver.index}:o{l.driver_pin}' if len(l.driver.outs)>1 else f'{l.driver.index}' | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            reader = f'{l.reader.index}:i{l.reader_pin}' if len(l.reader.ins)>1 else f'{l.reader.index}' | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            label = str(line_labels.get(l, l.index)) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            if node_level[l.driver] == node_level[l.reader]: | 
					 | 
					 | 
					 | 
					            if node_level[l.driver] == node_level[l.reader]: | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                s.node(f'_{l.index}_') | 
					 | 
					 | 
					 | 
					                s.node(f'_{l.index}_') | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                dot.edge(driver, f'_{l.index}_', style='dotted', label=str(l.index)) | 
					 | 
					 | 
					 | 
					                dot.edge(driver, f'_{l.index}_', style='dotted', label=label) | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                dot.edge(f'_{l.index}_', reader, style='dotted', label=str(l.index)) | 
					 | 
					 | 
					 | 
					                dot.edge(f'_{l.index}_', reader, style='dotted', label=label) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            elif node_level[l.driver] > node_level[l.reader]: | 
					 | 
					 | 
					 | 
					            elif node_level[l.driver] > node_level[l.reader]: | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                dot.edge(driver, reader, style='dotted', label=str(l.index)) | 
					 | 
					 | 
					 | 
					                dot.edge(driver, reader, style='dotted', label=label) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            else: | 
					 | 
					 | 
					 | 
					            else: | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                dot.edge(driver, reader, label=str(l.index)) | 
					 | 
					 | 
					 | 
					                dot.edge(driver, reader, label=label) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        return dot | 
					 | 
					 | 
					 | 
					        return dot | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
					 | 
					 | 
					
  |