<jupyter_start><jupyter_text>Convert Single Graph to function  Preliminaries  Imports<jupyter_code>import os
import sys
import networkx as nx

from os.path import dirname
from networkx.drawing.nx_pydot import to_pydot

note_dir = os.getcwd()

root_dir = dirname(note_dir)
src_dir = os.path.join(root_dir, "src")

sys.path.append(src_dir)

import morpheus
from morpheus.tests import default_chain, default_ensemble
from morpheus.graph import (model_to_graph,
                            model_graph_traces,
                            model_graph_layout, 
                            convert_positions_to_dot_format,
                            add_merge_nodes)<jupyter_output><empty_output><jupyter_text>Methods<jupyter_code>def fix_layout(G):
    
    for n in G.nodes():
        node = G.nodes(data=True)[n]
        if node['bipartite'] == 'func':
            node['shape'] = "\"square\""
            node['width'] = "2"
        elif node['bipartite'] == 'data':
            node['shape'] = "\"circle\""
        else:
            pass
    
    return G<jupyter_output><empty_output><jupyter_text>Demo graph<jupyter_code>ens = default_ensemble()
ens.pretty_print()
model_one = ens.estimators_[0]
model_two = ens.estimators_[1]
G = model_to_graph(model_one, idx=1)
G = fix_layout(G)
G.nodes(data=True)

    

X = to_pydot(G)
X.set('rankdir', 'BT')
X.set('splines', 'ortho')

with open("tmp/test.dot", "w") as text_file:
    print(X.to_string(), file=text_file)

!dot -T png ./tmp/test.dot > ./tmp/test.png  # Bash command

from IPython.display import Image, display
from IPython.core.display import HTML 

display(Image('tmp/test.png', unconfined=True))<jupyter_output><empty_output><jupyter_text>Parse graph<jupyter_code>G.in_degree()
source_nodes = [node for node, in_degree in G.in_degree() if in_degree == 0]
target_nodes = [node for node, out_degree in G.out_degree() if out_degree == 0]

for n in source_nodes:
    G.nodes()[n]['stage'] = 0
target_nodes
nx.ancestors(G, 'd-01')
list(nx.topological_sort(G))
def select(idx):
    
    def select(X):
        return X[:, idx]
    return select
import numpy as np
X = np.random.randint(0,10, (20, 5))
X
select(4)(X)
from functools import reduce
def f1(x):
    return x*2

def f2(x):
    return x+2

def f3(x):
    return x+6
def x(*functions):
    
    def parallel_comp(*function_inputs):
        if len(function_inputs) == 1:
            res = tuple([f(function_inputs[0]) for f in functions])
            return res
        elif len(function_inputs) == len(functions):
            res = tuple([f(x) for f, x in zip(functions, function_inputs)])
            return res
            
    return parallel_comp
px = reduce(x, [f1,f2,f3])
px = x(f1,f2,f3)
px(4)
px(4,4,4)
px(4,10,10)
px(4)
select(2)(X).shape
def o(f1, f2):
    def sequential_composition(*function_arguments):
        return f1(f2(*function_arguments))

    return sequential_composition


def x(*functions, return_type=tuple):
    def parallel_composition(*function_arguments):
        if len(function_arguments) == 1:
            res = return_type([f(function_arguments[0]) for f in functions])
            return res
        elif len(function_arguments) == len(functions):
            res = return_type([f(x) for f, x in zip(functions, function_arguments)])
            return res

    return parallel_composition
pc = o(np.transpose, x(select(1), select(2), select(3), return_type=np.array))
pc(X)
np.array(pc(X))
def build_array(array_tuple):
    n_rows = np.unique([t.shape[0] for t in array_tuple])
    return n_rows
build_array(pc(X))
sorted_list = list(nx.topological_sort(G))
print(sorted_list)
functions = {}
for node_name in sorted_list:
    node = G.nodes(data=True)[node_name]
    
    if node['bipartite'] == 'data': 
        if len(nx.ancestors(G, node_name)) == 0:
            functions[node_name] = select(node['idx'])
        elif len(nx.descendants(G, node_name)) == 0:
            functions[node_name] = 'end'
            
    elif node['bipartite'] == 'func':
        inputs = [functions[n] for n in nx.ancestors(G, node_name)]
        inputs = o(np.transpose, x(*inputs, return_type=np.array))
        f = node['function']
        functions[node_name] = o(f, inputs)
        
        
        
functions
X[:, 0:3]
functions['f-01'](X)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1331629095979549, 'fraction_numerical': 0.013246572158958867, 'mean_word_length': 3.17458777885548, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 18, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '302405', 'license': 'MIT', 'n_tokens_mistral': 1542, 'n_tokens_neox': 1504, 'n_words': 325, 'path': 'note/dev-1905/190424 - Convert Single Graph to function.ipynb', 'repo_name': 'eliavw/morpheus', 'size': '4303'}