Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dependency graph entry and test files. #3

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion core_collection/varia_collection/data_axs.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"sysinfo": "sysinfo",
"rule_matching_demonstrator": "rule_matching_demonstrator",
"rule_matching_producer": "rule_matching_producer",
"rule_matching_advertiser": "rule_matching_advertiser"
"rule_matching_advertiser": "rule_matching_advertiser",
"graph" : "graph"
}
}
82 changes: 82 additions & 0 deletions core_collection/varia_collection/graph/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
## Generating Hierarchy Graph
`AXS` command:
elimkwan marked this conversation as resolved.
Show resolved Hide resolved
```
axs byname graph , draw <entry_name>
elimkwan marked this conversation as resolved.
Show resolved Hide resolved
```
Eg.
```
axs byname graph , draw image_classification_using_tf_py
elimkwan marked this conversation as resolved.
Show resolved Hide resolved
```

![Alt text](image.png)
elimkwan marked this conversation as resolved.
Show resolved Hide resolved

The figure shows a dependency graph generated for `image_classification_using_tf_py` entry.

- Red : target entry
- Coral: Parents of the target entry
- Blue: output node
- Lightblue: Parents of the output node

If the run is successful, it should print `Graph is generated!`

```
saved to '/home/saheli/work_collection/generated_by_graph_on_draw_a579763d98044530962cc967ac659b28/data_axs.json'
byname_entries: ['base_imagenet_experiment']
Graph is generated!
['^', 'byname', 'generated_by_graph_on_draw_generated_by_graph_on_draw_a579763d98044530962cc967ac659b28']
```
The image of the graph rendered in vector graphics, `image.svg` and `.dot` file are generated under `~/work_collection/generated_by_graph_on_draw_a579763d98044530962cc967ac659b28/` folder.
elimkwan marked this conversation as resolved.
Show resolved Hide resolved

The structure of the `.dot` file will look something like this: `image`. It can be interpreted as a normal text file.
```
digraph {
node [shape=ellipse]
dpi=400
subgraph cluster_0 {
style=dotted
label="Entry and Its Parent(s)"
image_classification_using_tf_py [color=red style=filled]
python_script -> image_classification_using_tf_py
base_benchmark_program -> image_classification_using_tf_py
base_benchmark_program [color=lightcoral style=filled]
python_script [color=lightcoral style=filled]
python_in_shell -> python_script
python_in_shell [color=lightcoral style=filled]
shell -> python_in_shell
shell [color=lightcoral style=filled]
}
output [color=blue style=filled]
image_classification_using_tf_py -> output
base_imagenet_experiment -> output
subgraph cluster_1 {
style=dotted
label="Parent(s) of the Output Entry"
base_imagenet_experiment [color=lightblue style=filled]
base_experiment -> base_imagenet_experiment
base_experiment [color=lightblue style=filled]
}
}
```
## Running tests
elimkwan marked this conversation as resolved.
Show resolved Hide resolved
The next step is to run the tests.

### Step 1:
The first step is to run the `create_json.py` to generate two json files containing dictionaries containing all the contained entries obtained as keys from `bert`, `image_classification`, `object_detection` folders and corresponding values as the `_parent_entries` and `output_parent_entries` for each entry.
```
python create_json.py
```
<Details><Pre>
output_parent_entries_dict.json parent_entries_dict.json </Details></Pre>

### Step 2:
Next, to run the `test_parent_and_output_entries.py` file
```
pytest test_parent_and_output_entries.py
```
<Details><Pre>
==================================================================================== 2 passed in 0.01s =====================================================================================
collected 2 items

test_parent_and_output_entries.py::test_compare_dot_and_json_for_target PASSED
test_parent_and_output_entries.py::test_compare_dot_and_json_for_target_output PASSED
</Details></Pre>
185 changes: 185 additions & 0 deletions core_collection/varia_collection/graph/code_axs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
import re
import graphviz
import json
from kernel import default_kernel as ak

initial_root_visited = False

def dfs(root, f, __entry__, is_output=False):

""" Depth First Search(DFS) for a given node.
"""

global initial_root_visited
stack = []
visited = set()

cur_target_entry = __entry__.get_kernel().byname(root)
if not cur_target_entry:
print("ERROR!")
return

stack.append((cur_target_entry, True)) # Using True to signify that this is the initial root node

while stack:
cur_target_entry, is_initial_root = stack.pop()
cur_target = cur_target_entry.get_name()

if cur_target in visited:
continue

if not initial_root_visited:
color = 'red'
initial_root_visited = True
elif is_output:
color = 'lightblue'
else:
color = 'lightcoral'

f.node(cur_target, color=color, style='filled')
visited.add(cur_target)

parents = cur_target_entry.get("_parent_entries")
if parents:
for parent in parents:
if isinstance(parent, str):
p = __entry__.get_kernel().byname(parent)
else:
p = parent
if not p:
continue
stack.append((p, False)) # Using False to signify that this is not the initial root node
f.edge(p.get_name(), cur_target)

return f

def draw(target, return_this_entry=None, __entry__=None):
elimkwan marked this conversation as resolved.
Show resolved Hide resolved

""" Generate Dependency Graph for a given entry.

Usage examples:
axs byname graph , draw bert_using_onnxrt_py
axs byname graph , draw image_classification_using_tf_py
elimkwan marked this conversation as resolved.
Show resolved Hide resolved
"""

global initial_root_visited
initial_root_visited = False
output = False
output_parents_data = ""
dest_dir = return_this_entry.get_path()

target_entry = __entry__.get_kernel().byname(target)
if target_entry:
get_path = target_entry.get_path()
file_path = f'{get_path}/data_axs.json'
target_data = target_entry.own_data()
output_entries = target_entry.get("output_entry_parents")

if output_entries:
# Extract all 'byname' entries from "output_entry_parents" as objects to byname as key
byname_entries = extract_byname_entries(output_entries)
print("byname_entries:", byname_entries)

for key, val in target_data.items():
if "_parent_entries" in str(val):
output = True
output_parents_data = val
elif "tags" in str(val):
output = True
elif output_entries:
output = True

f = graphviz.Digraph(format='svg')
f.attr('node', shape='ellipse')
f.attr(dpi='400')
f.engine = 'dot'


with f.subgraph(name='cluster_0') as c:
c.attr(style='dotted')
c.attr(label='Entry and Its Parent(s)')
dfs(target, c, __entry__, is_output=False)


if output:
f.node("output", style='filled', color='blue')
f.edge(target, "output")

if output_parents_data:
info = find_parent(output_parents_data)
output_parents = find_byname(file_path,obj=info)
print("output_parents", output_parents)
for output_parent in output_parents:
with f.subgraph(name='cluster_1') as c:
c.attr(style='dotted')
c.attr(label='Parent(s) of the Output Entry')
dfs(output_parent, c, __entry__, is_output=True)
f.edge(output_parent, "output")
target_entry = output_parent
else:
target_entry = None

elif output_entries and byname_entries:
for byname_entry in byname_entries:
with f.subgraph(name=f'cluster_1') as c:
c.attr(style='dotted')
c.attr(label=f'Parent(s) of the Output Entry')
dfs(byname_entry, c, __entry__, is_output=True)
f.edge(byname_entry, "output")


f.render(filename=f"{dest_dir}/image", view=False, cleanup=False)
print("Graph is generated!")

return return_this_entry
else:
print("ERROR! Provide correct entry name!")


def find_parent(obj):
items = find_key(obj, "_parent_entries")
return items

def find_byname(file_path, obj=None):
obj=process_json(file_path)
items = find_key(obj, "byname")
print("items",items)
return [list(item)[2] for item in items]

def find_key(obj, key):
matches = []
if isinstance(obj, dict):
for k, v in obj.items():
if k == key:
return v
matches.extend(find_key(v, key))
result = find_key(v, key)
if result is not None:
return result
elif isinstance(obj, list):
if key == "_parent_entries" and re.search(r"^\[(?:'|\")_parent_entries(.*)", str(obj)):
matches.append(obj)
if key == "byname" and re.search(r"^\[(?:'|\")\^(?:'|\")(?:\s*),(?:\s*)(?:'|\")byname(.*)", str(obj)):
matches.append(obj)
for item in obj:
matches.extend(find_key(item, key))

return matches

def process_json(file_path):
with open(file_path) as f:
obj = json.load(f)
required_data = {key: obj[key] for key in ['output_file_path', 'output_entry'] if key in obj}
parents = find_parent(required_data)
return parents


def extract_byname_entries(output_entries):
byname_entries = []
for item in output_entries:
if isinstance(item, list) and 'byname' in item:
index = item.index('byname') + 1
if index < len(item):
byname_entries.append(item[index])
return byname_entries

88 changes: 88 additions & 0 deletions core_collection/varia_collection/graph/create_json.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import json
import os

base_directory = os.path.expanduser('~/axs/core_collection/workflows_collection')

def get_contained_entries_keys_from_multiple_locations():
folders = ['bert', 'image_classification', 'object_detection']
keys_dict = {}
workflows_directory = os.path.expanduser('~/axs/core_collection/workflows_collection')

for folder in folders:
for root, dirs, files in os.walk(os.path.join(workflows_directory, folder)):
if 'data_axs.json' in files:
json_file_path = os.path.join(root, 'data_axs.json')

print(f"Checking existence of {json_file_path}") # Debug line

with open(json_file_path, 'r') as f:
data = json.load(f)
keys = list(data.get('contained_entries', {}).keys())

if folder in keys_dict:
keys_dict[folder].extend(keys)
else:
keys_dict[folder] = keys
else:
print(f"The JSON file at {os.path.join(root, 'data_axs.json')} doesn't exist.")

return keys_dict

contained_entries_keys_dict = get_contained_entries_keys_from_multiple_locations()

key_json_paths = []

for folder, keys in contained_entries_keys_dict.items():
for key in keys:
key_json_path = os.path.join(base_directory,folder, key, 'data_axs.json')
key_json_paths.append(key_json_path)

def read_entries(key_json_paths, entry_key):
entries_dict = {}
for key_json_path in key_json_paths:
if os.path.exists(key_json_path):
with open(key_json_path, 'r') as f:
data = json.load(f)
key_name = os.path.basename(os.path.dirname(key_json_path))
entries_dict[key_name] = [entry[-1] for entry in data.get('_parent_entries', [])]
else:
print(f"The JSON file at {key_json_path} doesn't exist.")
return entries_dict

# Read parent entries
parent_entries_dict = read_entries(key_json_paths, '_parent_entries')

def read_output_parent_entries(key_json_paths):
output_parent_entries_dict = {}
for key_json_path in key_json_paths:
if os.path.exists(key_json_path):
with open(key_json_path, 'r') as f:
data = json.load(f)
output_key_name = os.path.basename(os.path.dirname(key_json_path))

final_entries = []
for entry in data.get('output_entry_parents', []):
if isinstance(entry, list) and 'byname' in entry:
index = entry.index('byname') + 1
if index < len(entry):
final_entries.append(entry[index])

if final_entries:
output_parent_entries_dict[output_key_name] = final_entries
else:
output_parent_entries_dict[output_key_name] = data.get('output_entry_parents', [])

else:
print(f"The JSON file at {key_json_path} doesn't exist.")

return output_parent_entries_dict

# Read output parent entries
output_parent_entries_dict = read_output_parent_entries(key_json_paths)

# Save to a JSON file
with open('parent_entries_dict.json', 'w') as f:
json.dump(parent_entries_dict, f, indent=4)

with open('output_parent_entries_dict.json', 'w') as f:
json.dump(output_parent_entries_dict, f, indent=4)
15 changes: 15 additions & 0 deletions core_collection/varia_collection/graph/data_axs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"_producer_rules": [
[ [ "graph_output" ], [["draw"]], { }, [ "target"]]],
"target" : "shell",
"return_this_entry": [ "^^", "execute", [[
[ "get", "__record_entry__" ],
[ "attach", [ "^", "work_collection" ] ],
[ "plant", [ "^^", "substitute", [[
"tags", [ "graph_output"],
"target", "#{target}#"
]] ] ],
[ "save" ]
]] ]

}
Binary file added core_collection/varia_collection/graph/image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading