Skip to content

Commit

Permalink
improve transpiler python to Crop2ML
Browse files Browse the repository at this point in the history
  • Loading branch information
cyrillemidingoyi committed Sep 14, 2024
1 parent 18908c9 commit 41199d2
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 35 deletions.
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ path
six
nbformat
numpy==1.16.6
Cython
Cython==0.29.21
nbsphinx
networkx
graphviz
Expand Down
1 change: 0 additions & 1 deletion src/pycropml/transpiler/antlr_py/createXml.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ def run_unit(self):
for inp in md.inputs:
if "variablecategory" in dir(inp):
if inp.datatype.endswith("ARRAY"):
print(inp)
inputs.append(ns.Input(name=inp.name, description=inp.description, inputtype=inp.inputtype, variablecategory=inp.variablecategory, datatype=inp.datatype, len=inp.len, max=inp.max, min = inp.min, default=inp.default, unit=inp.unit))
else: inputs.append(ns.Input(name=inp.name, description=inp.description, inputtype=inp.inputtype, variablecategory=inp.variablecategory, datatype=inp.datatype, max=inp.max, min = inp.min, default=inp.default, unit=inp.unit))
else:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,6 @@ def extract_compo(comment):
head[keywords[i]] = re.search(p, comment).group(keywords[i])
i = i + 1
m = ModelComposition(head)

# description element of modelUnit (Title, Authors, Reference, Institution, Abstract)
pat_description = r'-\s*Description:\s*(.*?)(?=\n\s*[#!/]*\s*-\s*inputs|\n\s*[#!/]*\s*-\s*outputs|$)'
text_description = re.search(pat_description, comment, re.DOTALL).group(1)
Expand Down
1 change: 0 additions & 1 deletion src/pycropml/transpiler/antlr_py/python/api_transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ def float_expander(type, message, args):
def len_expander(type, message, args):
receiver_type = args[0]['pseudo_type']
if isinstance(receiver_type, list):
print(receiver_type, "ioooo")
a = receiver_type[0]
else:
a = receiver_type
Expand Down
105 changes: 78 additions & 27 deletions src/pycropml/transpiler/antlr_py/python/pythonExtraction.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,18 @@
from openalea.core.pkgmanager import PackageManager
from pycropml.transpiler.antlr_py.codeExtraction import extraction
import re
import copy

def listdictvalues(dictlist:list) -> list:
"""Extract the values of a list of dictionnaries
Args:
dictlist (list): list of dictionnaries
Returns:
list: list of values
"""
return [v for d in dictlist for v in d.values()]

class PythonExtraction(MetaExtraction):
def __init__(self):
Expand All @@ -26,51 +37,91 @@ def modelunit(self, file, tree):
def getMethod(self, tree):
self.getTypeNode(tree, "function_definition")
return self.getTree

def orderedvar(self, mdata, tree):
mu_inputs = [m.name for m in tree.params]
mu_outputs = [m.name for m in tree.block[-1].value.elements]
inps = []
outs = []
for n in mu_inputs:
for inp in mdata.inputs:
if inp.name == n:
inps.append(inp)
for n in mu_outputs:
for out in mdata.outputs:
if out.name == n:
outs.append(out)
mdata.inputs = inps
mdata.outputs = outs
return mdata


def modelcomposition(self, file, models, tree):
self.mc = extract_compo(file)
self.getTypeNode(tree, "function_definition")
mc_def_tree = self.getTree
mc_inputs = [m.name for m in mc_def_tree[0].params]
mc_outputs = [m.name for m in mc_def_tree[0].block[-1].value.elements]
self.getTypeNode(mc_def_tree[0].block, "assignment")
list_assign = self.getTree
inputlink = []
outputlink = []
internallink = []
inp = {}
#name = re.findall(r'(def\s+.+\()', py_unit)[0].replace("def", "").replace("(", "").strip()
funcs = self.getMethod(tree)
print(funcs)
algo = [f for f in funcs if f.name.startswith("model")]
self.getTypeNode(algo[0].block,"custom_call")
call = self.getTree
self.mc.model = [c.function.split("model_")[-1] for c in call]
print(self.mc.model)
print([n.name for n in models])
inps, outs = [], []
md = [n for m in self.mc.model for n in models if m.lower() == n.name.split("model_")[-1].lower()]
self.mc.model = [n.name for n in md]
inps = [n.name for m in md for n in m.inputs ]
outs = [n.name for m in md for n in m.outputs ]
m_in = set(inps) - set(outs)
z = {}
internallink= []
for m in md:
vi = list(set([n.name for n in m.inputs ]).intersection(m_in))
vo = [n.name for n in m.outputs]
for v in vi:
inputlink.append({"target": m.name + "." + v, "source":v})
for v in vo: z.update({v:m.name})

for k, v in z.items():
outputlink.append({"source": v + "." + k, "target":k})

for i in range(0, len(md)-1):
inps = {m.name:[n.name for n in m.inputs] for m in md}
outs = {m.name:[n.name for n in m.outputs] for m in md}
var_int = []
var_out = [] # variables that are outputs of model units
len_r = len(md) - 1 if len(md) > 1 else len(md)
res_in = {}
res_out = {}
for i in range(0, len_r):
mi = md[i]
for j in range(i+1, len(md)):
mj = md[j]
vi = list(set([n.name for n in mi.outputs ]).intersection(set([n.name for n in mj.inputs ])))
if vi:
for k in vi:
internallink.append({"source": mi.name + "." + k, "target":mj.name + "." + k})
mi_inp = inps[mi.name]
mi_out = outs[mi.name]
mi_inp_p = set(mi_inp).intersection(set(mc_inputs)) # inputs of mi that are also inputs of the model composition
mi_out_p = set(mi_out).intersection(set(mc_outputs)) # outputs of mi that are also outputs ...
mi_inp_f = mi_inp_p - set(var_out) # inputs of mi that are not outputs of the previous model units
if len(md) > 1:
for j in range(i+1, len_r+1):
mj = md[j]
mj_inp = inps[mj.name]
zi = list(mi_out.intersection(set(mj_inp)))
var_int.extend(list(zi))
for k in zi:
internallink.append({"source": mi.name + "." + k, "target":mj.name + "." + k})
var_out.extend(mi_out)
mi_out_f = mi_out_p - set(var_int) # outputs of mi that are not used as intermediate variables are considered as outputs of the model composition
res_in.update({mi.name:mi_inp_f})
res_out.update({mi.name:mi_out_f})

for k in mc_inputs:
for m in md:
if k in res_in[m.name]:
inputlink.append({"target": m.name + "." + k, "source":k})
for k in mc_outputs:
for m in md:
if k in res_out[m.name]:
outputlink.append({"source": m.name + "." + k, "target":k})

ilink = {}
for a in list_assign:
if "name" in dir(a.value) and a.value.name in mc_inputs:
for m in md:
if a.target.name in inps[m.name]:
if a.value.name not in ilink: ilink[a.value.name] = []
ilink[a.value.name].append({m.name: a.target.name})

self.mc.inputlink = inputlink
self.mc.outputlink = outputlink
self.mc.internallink = internallink
print(self.mc.model)
return self.mc

5 changes: 2 additions & 3 deletions src/pycropml/transpiler/antlr_py/python/pythonTransformer.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,9 +251,9 @@ def transformer(self):
body = self.visit(self.tree)
self.type_env.top['__name__'] = "str"
self.q=None

#'definition':self.signature,
#print(self.type_env.values)
return {'type': 'module','definition':self.signature, 'iterators':self.iterators, 'body': body if isinstance(body, list) else [body]}
return {'type': 'module', 'iterators':self.iterators, 'body': body if isinstance(body, list) else [body]}

def visit_definitions(self):
definitions = []
Expand Down Expand Up @@ -655,7 +655,6 @@ def visit_expr(self, node, AWAIT,expr, atom, trailer,POWER,ADD,MINUS,NOT_OP,STA
self.accessReturn(x[0])
q = self.q["pseudo_type"]
else:

x = [f for f in self.signature if f.name.NAME == message]
argx = [a["pseudo_type"] for a in self.visit(x[0].typedargslist)]
#self._definition_index["functions"][message] = self.visit(x[0])
Expand Down
4 changes: 4 additions & 0 deletions src/pycropml/transpiler/antlr_py/python/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ def translate(inout, meth):
inittag_begin = "#"+init_tags[0]
inittag_end = "#"+init_tags[1]



def run_python(components, package):

create_repo(package)
Expand Down Expand Up @@ -171,10 +173,12 @@ def run_python(components, package):
fi.write(extcode + '\n')

models.append(mdata)
mdata = z.orderedvar(mdata,meth)
generate_unitfile(package, mdata, package_name)

break
else:
mdata = z.orderedvar(mdata,meth)
models.append(mdata)
generate_unitfile(package, mdata, package_name)

Expand Down
1 change: 0 additions & 1 deletion src/pycropml/transpiler/ast_transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,6 @@ def visit_singleassignmentnode(self, node, lhs, rhs, location):
e, value_node['pseudo_type'], "can't change the type of variable %s in %s " % (name, self.function_name))
else:
#if value_node["type"] =="custom_call" and value_node["pseudo_type"] is None: value_node["pseudo_type"] = e
print(value_node)
if value_node["type"] != "none":
a = self._compatible_types(e, value_node['pseudo_type'], "can't change the type of variable %s in %s at %s " % (
name, self.function_name, location[0]))
Expand Down

0 comments on commit 41199d2

Please sign in to comment.