diff --git a/adot_to_cpp.py b/adot_to_cpp.py new file mode 100644 index 0000000000000000000000000000000000000000..9f185b2bdcadd912617e36f0a1b7399641b0a869 --- /dev/null +++ b/adot_to_cpp.py @@ -0,0 +1,18 @@ +import unittest +from copy import deepcopy +import subprocess +import os +import random +import sys +from test_funcs.simplest import * +import comsdk.parser as pars +from comsdk.graph import * +from comsdk.edge import Edge + +prsr = pars.Parser(tocpp=True) +data = {"a":10, "b":0} +gr = prsr.parse_file(sys.argv[1]) +if sys.argv[2] !="": + prsr.generate_cpp(sys.argv[2]) +else: + prsr.generate_cpp() diff --git a/templates/.gitignore b/comsdk/__init__.py similarity index 100% rename from templates/.gitignore rename to comsdk/__init__.py diff --git a/comsdk/__pycache__/__init__.cpython-37.pyc b/comsdk/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f9404d7651af084fa1904c30f3f2177d136df94d Binary files /dev/null and b/comsdk/__pycache__/__init__.cpython-37.pyc differ diff --git a/comsdk/__pycache__/comaux.cpython-37.pyc b/comsdk/__pycache__/comaux.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4542f51de64a0b77ce8e354a8bd8e1474687a982 Binary files /dev/null and b/comsdk/__pycache__/comaux.cpython-37.pyc differ diff --git a/comsdk/__pycache__/communication.cpython-37.pyc b/comsdk/__pycache__/communication.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4d27064eec3908f8312c68db10e8c3e042a0505e Binary files /dev/null and b/comsdk/__pycache__/communication.cpython-37.pyc differ diff --git a/comsdk/__pycache__/edge.cpython-37.pyc b/comsdk/__pycache__/edge.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9fc9d7bc448ba0ff4d69489503373000e4f03660 Binary files /dev/null and b/comsdk/__pycache__/edge.cpython-37.pyc differ diff --git a/comsdk/__pycache__/graph.cpython-37.pyc b/comsdk/__pycache__/graph.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d26ff4d7ad63377bfc86d9c384514df6ae83d68d Binary files /dev/null and b/comsdk/__pycache__/graph.cpython-37.pyc differ diff --git a/comsdk/__pycache__/parser.cpython-37.pyc b/comsdk/__pycache__/parser.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2af755407ceeea4d4b4325fc67d619ef32e898c6 Binary files /dev/null and b/comsdk/__pycache__/parser.cpython-37.pyc differ diff --git a/comsdk/aux.py b/comsdk/comaux.py similarity index 100% rename from comsdk/aux.py rename to comsdk/comaux.py diff --git a/comsdk/communication.py b/comsdk/communication.py index a25dd50b238fb2580d0ec18b8bf54f1d11bb2949..1c45001ba28b168e82ed42c20928f8b3f43cb036 100644 --- a/comsdk/communication.py +++ b/comsdk/communication.py @@ -8,7 +8,7 @@ import json from stat import S_ISDIR from abc import ABCMeta, abstractmethod -from comsdk.aux import load_function_from_module +from comsdk.comaux import load_function_from_module class Host(object): ''' diff --git a/comsdk/distributed_storage.py b/comsdk/distributed_storage.py index f2fec11624bf29521f5dd5a9939e4214266457dd..0d7667dc33d067f551b92ae33ad2bd203064b5ad 100644 --- a/comsdk/distributed_storage.py +++ b/comsdk/distributed_storage.py @@ -1,4 +1,4 @@ -from comsdk.aux import find_dir_by_named_regexp +from comsdk.comaux import find_dir_by_named_regexp from functools import partial import os diff --git a/comsdk/edge.py b/comsdk/edge.py index 36cbe9a3fcad5416fc14a6d2ee75579849f8d35e..66a9b0f74592320ff1ff83e6cc71598ab2898df5 100644 --- a/comsdk/edge.py +++ b/comsdk/edge.py @@ -1,5 +1,6 @@ -import comsdk.aux as aux +import comsdk.comaux as aux from comsdk.communication import CommunicationError +from comsdk.graph import Func from mako.template import Template import os @@ -26,43 +27,53 @@ class InOutMapping(object): class Edge(object): __slots__ = [ - '_predicate', - '_morphism', + 'pred_f', + 'morph_f', '_io_mapping', 'preprocess', 'postprocess', - ] + 'order', + 'comment' + ] def __init__(self, predicate, morphism, io_mapping=InOutMapping(), + order=0, + comment="" ): - self._predicate = predicate - self._morphism = morphism + self.pred_f = predicate + self.morph_f = morphism self._io_mapping = io_mapping self.preprocess = lambda pd: None self.postprocess = lambda pd: None + self.order = int(0 if order is None else order) + self.comment = comment def predicate(self, data, dynamic_keys_mapping={}): proxy_data = self._io_mapping.build_proxy_data(data, dynamic_keys_mapping) - return self._predicate(proxy_data) + return self.pred_f.func(proxy_data) def morph(self, data, dynamic_keys_mapping={}): - #print(dynamic_keys_mapping) + # print(self.pred_name, self.morph_name, self.order) proxy_data = self._io_mapping.build_proxy_data(data, dynamic_keys_mapping) - #print(proxy_data) + # print(proxy_data) self.preprocess(data) - self._morphism(proxy_data) + self.morph_f.func(proxy_data) self.postprocess(data) + -class DummyEdge(Edge): - def __init__(self): - super().__init__(None, None) +# class DummyEdge(Edge): + # def __init__(self): + # super().__init__(None, None) +# + # def predicate(self, data, dynamic_keys_mapping={}): + # return True +# + # def morph(self, data, dynamic_keys_mapping={}): + # self.preprocess(data) + # self.postprocess(data) - def predicate(self, data, dynamic_keys_mapping={}): - return True - - def morph(self, data, dynamic_keys_mapping={}): - self.preprocess(data) - self.postprocess(data) +def DummyEdge(): + return Edge(Func(), Func()) class ExecutableProgramEdge(Edge): ''' diff --git a/comsdk/graph.py b/comsdk/graph.py index 08c2369a3733a4b9042e5b1cec897913ee5a5df2..c850991a54ff2b57c73e342ba49747f1e0e6c26b 100644 --- a/comsdk/graph.py +++ b/comsdk/graph.py @@ -2,59 +2,68 @@ import collections import os from enum import Enum, auto from functools import partial +import importlib as imp -import comsdk.aux as aux + +import comsdk.comaux as aux ImplicitParallelizationInfo = collections.namedtuple('ImplicitParallelizationInfo', ['array_keys_mapping', 'branches_number', 'branch_i']) -class Morphism: - def __init__(self, edge, output_state): +class Func(): + __slots__ = ( + 'module', + 'func', + 'comment', + 'name' + ) + def __init__(self, module="", name="", dummy=False,func=None, comment=''): + self.module = module + self.name = name + self.comment=comment.replace("\0", " ") if comment is not None else "" + if module =="" or name =="" or module is None or name is None: + dummy = True + if func is not None: + self.func = func + elif dummy: + self.func = lambda data: data + else: + print("LOADING function {} from {} module".format(name, module) ) + try: + self.func = getattr(imp.import_module(module), name) + except Exception: + raise Exception("Could not load function {} from {} module".format(name, module)) + + def __str__(self): + if self.module =="" or self.name =="": + return '' + return "{}_{}".format(self.module, self.name) + +class Selector(Func): + def __init__(self, ntransf, module="", name="", dummy=False): + if module=="" and name =="": + dummy = True + self.dummy = dummy + super().__init__(module, name, func=(lambda x: [True for i in range(ntransf)]) if dummy else None) + def __str__(self): + if self.module =="" or self.name =="": + return '' + return "{}_{}".format(self.module, self.name) + + +class Transfer: + def __init__(self, edge, output_state, order=0, comment = None): self.edge = edge self.output_state = output_state + self.order = order - def morph(self, data, dynamic_keys_mapping={}): - #print(dynamic_keys_mapping) + def transfer(self, data, dynamic_keys_mapping={}): self.edge.morph(data, dynamic_keys_mapping) - #return self.output_state, None return self.output_state class IdleRunType(Enum): INIT = auto() CLEANUP = auto() -class GraphFactory: - def __init__(self): - pass - - def create_state(): - pass - - def create_edge(): - # Here we should somehow pass the argument for "special" edges - # Essentially, we change only io_mapping - pass - - def make_graph(): - pass - -class PluralGraphFactory: - def __init__(self, plural_keys_mappings, parallel_graphs_number): - self.plural_keys_mappings = plural_keys_mappings - self.parallel_graphs_number = parallel_graphs_number - self.init_state = None - - def create_state(state): - if self.init_state == None: - self.init_state = state - - def create_edge(): - # Here we should somehow pass the argument for "special" edges - # Essentially, we change only io_mapping - pass - - def make_graph(): - pass - class PluralState: def __init__(self, states): self.states = states @@ -62,7 +71,7 @@ class PluralState: def connect_to(self, term_states, edge): for init_state, term_state in zip(self.states, term_states): - init_state.output_morphisms.append(Morphism(edge, term_state)) + init_state.transfers.append(Transfer(edge, term_state)) class Graph: ''' @@ -93,18 +102,18 @@ class Graph: while cur_state is not None: # print('1) In main loop', implicit_parallelization_info) # morph = _run_state(cur_state, data, implicit_parallelization_info) - morph, implicit_parallelization_info = _run_state(cur_state, data, implicit_parallelization_info) + transfer_f, implicit_parallelization_info = _run_state(cur_state, data, implicit_parallelization_info) # print('2) In main loop', implicit_parallelization_info) if '__EXCEPTION__' in data: return False # cur_state, implicit_parallelization_info = morph(data) - cur_state = morph(data) + cur_state = transfer_f(data) # print(morph) if '__EXCEPTION__' in data: return False return True - def init_graph(self, data): + def init_graph(self, data={}): if not self._initialized: self.init_state.idle_run(IdleRunType.INIT, [self.init_state.name]) self._initialized = True @@ -114,41 +123,53 @@ class Graph: if not '__WORKING_DIR__' in data: data['__WORKING_DIR__'] = data['__CURRENT_WORKING_DIR__'] + + + class State: __slots__ = [ 'name', - 'input_edges_number', + 'input_edges_number', #output_edges_number == len(transfers) 'looped_edges_number', 'activated_input_edges_number', - 'output_morphisms', + 'transfers', 'parallelization_policy', - 'selection_policy', + 'selector', 'is_term_state', 'array_keys_mapping', '_branching_states_history', '_proxy_state', + 'possible_branches', + 'comment' ] def __init__(self, name, parallelization_policy=None, - selection_policy=None, + selector=None, array_keys_mapping=None, # if array_keys_mapping is not None, we have implicit parallelization in this state ): self.name = name self.parallelization_policy = SerialParallelizationPolicy() if parallelization_policy is None else parallelization_policy - self.selection_policy = OnlyOneSelectionPolicy() if selection_policy is None else selection_policy + self.selector = Selector(1) if selector is None else selector self.array_keys_mapping = array_keys_mapping self.input_edges_number = 0 self.looped_edges_number = 0 self.activated_input_edges_number = 0 - self.output_morphisms = [] + self.transfers = [] + self.possible_branches=[] self.is_term_state=False self._branching_states_history = None self._proxy_state=None + self.comment = None def idle_run(self, idle_run_type, branching_states_history): + def __sort_by_order(tr): + return tr.edge.order + self.transfers.sort(key = __sort_by_order) + # print(self.name) + # for t in self.transfers: + # print("\t", t.edge.order, t.edge.pred_name, t.edge.morph_name) if self._proxy_state is not None: return self._proxy_state.idle_run(idle_run_type, branching_states_history) -# print('{} {} -> '.format(self.name, branching_states_history), end='') if idle_run_type == IdleRunType.INIT: self.input_edges_number += 1 if self.input_edges_number != 1: @@ -159,66 +180,66 @@ class State: self._branching_states_history = branching_states_history elif idle_run_type == IdleRunType.CLEANUP: self.activated_input_edges_number = 0 -# print('\tCLEANUP STATE {}, active: {}, branches_story: {}'.format(self.name, self.activated_input_edges_number, self._branching_states_history)) if self._branching_states_history is not None and self._is_looped_branch(branching_states_history): -# print('\tqwer') self._branching_states_history = None return if self._branching_states_history is None: self._branching_states_history = branching_states_history else: self.activated_input_edges_number += 1 # BUG: here we need to choose somehow whether we proceed or not -# if len(self.output_edges) == 0: -# print('Terminate state found') - if len(self.output_morphisms) == 1: - self.output_morphisms[0].output_state.idle_run(idle_run_type, branching_states_history) + # if len(self.transfers) == 0: + # print('Terminate state found') + if len(self.transfers) == 1: + self.transfers[0].output_state.idle_run(idle_run_type, branching_states_history) else: - for i, morphism in enumerate(self.output_morphisms): - next_state = morphism.output_state + for i, transfer in enumerate(self.transfers): + next_state = transfer.output_state next_state.idle_run(idle_run_type, branching_states_history + [next_state.name]) - def connect_to(self, term_state, edge): - self.output_morphisms.append(Morphism(edge, term_state)) + def connect_to(self, term_state, edge=None, comment=None): + if comment is not None or comment != "": + self.comment = comment + self.transfers.append(Transfer(edge, term_state)) + self.selector = Selector(len(self.transfers)) # edge.set_output_state(term_state) # self.output_edges.append(edge) def replace_with_graph(self, graph): self._proxy_state = graph.init_state - graph.term_state.output_morphisms = self.output_morphisms + graph.term_state.transfers = self.transfers + graph.term_state.selector = self.selector + def run(self, data, implicit_parallelization_info=None): - print('STATE {}, just entered, implicit_parallelization_info: {}'.format(self.name, implicit_parallelization_info)) + print('STATE {}\n\tjust entered, implicit_parallelization_info: {}'.format(self.name, implicit_parallelization_info)) + # print('\t{}'.format(data)) if self._proxy_state is not None: return self._proxy_state.run(data, implicit_parallelization_info) self._activate_input_edge(implicit_parallelization_info) #self.activated_input_edges_number += 1 - print('STATE {}, required input: {}, active: {}, looped: {}'.format(self.name, self.input_edges_number, self.activated_input_edges_number, self.looped_edges_number)) + print('\trequired input: {}, active: {}, looped: {}'.format(self.input_edges_number, self.activated_input_edges_number, self.looped_edges_number)) # print('qwer') - if not self._ready_to_morph(implicit_parallelization_info): + if not self._ready_to_transfer(implicit_parallelization_info): return None, None # it means that this state waits for some incoming edges (it is a point of collision of several edges) self._reset_activity(implicit_parallelization_info) if self.is_term_state: implicit_parallelization_info = None - #print(self.name) - if len(self.output_morphisms) == 0: - return morphism_to_termination, None - predicate_values = [] + if len(self.transfers) == 0: + return transfer_to_termination, None dynamic_keys_mapping = build_dynamic_keys_mapping(implicit_parallelization_info) - for morphism in self.output_morphisms: - predicate_values.append(morphism.edge.predicate(data, dynamic_keys_mapping)) - selected_edge_indices = self.selection_policy.select(predicate_values) - if not selected_edge_indices: + selected_edges = self.selector.func(data) + if not selected_edges: raise GraphUnexpectedTermination( - 'State {}: Predicate values {} do not conform selection policy'.format(self.name, predicate_values)) - selected_morphisms = [self.output_morphisms[i] for i in selected_edge_indices] - return self.parallelization_policy.make_morphism(selected_morphisms, + "STATE {}: error in selector: {} ".format(self.name, selected_edges)) + selected_transfers = [self.transfers[i] for i, _ in enumerate(selected_edges) if selected_edges[i]==True] + for transf in selected_transfers: + if not transf.edge.predicate(data, dynamic_keys_mapping): + raise Exception("\tERROR: predicate {} returns {} running from state {}\n data{}".format(transf.edge.pred_f.name,transf.edge.predicate(data, dynamic_keys_mapping), self.name, data)) + return self.parallelization_policy.make_transfer_func(selected_transfers, array_keys_mapping=self.array_keys_mapping, - implicit_parallelization_info=implicit_parallelization_info,), \ + implicit_parallelization_info=implicit_parallelization_info, state=self), \ implicit_parallelization_info -# return self.parallelization_policy.make_morphism(selected_morphisms, -# array_keys_mapping=self.array_keys_mapping, -# implicit_parallelization_info=implicit_parallelization_info,) def _activate_input_edge(self, implicit_parallelization_info=None): if implicit_parallelization_info is None or self.is_term_state: @@ -228,7 +249,7 @@ class State: self.activated_input_edges_number = [0 for i in range(implicit_parallelization_info.branches_number)] self.activated_input_edges_number[implicit_parallelization_info.branch_i] += 1 - def _ready_to_morph(self, implicit_parallelization_info=None): + def _ready_to_transfer(self, implicit_parallelization_info=None): required_activated_input_edges_number = self.input_edges_number - self.looped_edges_number if implicit_parallelization_info is not None: if self.is_term_state: @@ -247,7 +268,7 @@ class State: def _reset_activity(self, implicit_parallelization_info=None): self._branching_states_history = None - if self._ready_to_morph(implicit_parallelization_info) and self._has_loop(): + if self._ready_to_transfer(implicit_parallelization_info) and self._has_loop(): if implicit_parallelization_info is None or self.is_term_state: self.activated_input_edges_number -= 1 else: @@ -265,7 +286,8 @@ class State: def _has_loop(self): return self.looped_edges_number != 0 -def morphism_to_termination(data): + +def transfer_to_termination(data): return None class SerialParallelizationPolicy: @@ -274,59 +296,12 @@ class SerialParallelizationPolicy: def __init__(self): pass -# def make_morphism(self, morphisms, array_keys_mapping=None, implicit_parallelization_info=None): -# def _morph(data): -# if array_keys_mapping is None: -# dynamic_keys_mapping = build_dynamic_keys_mapping(implicit_parallelization_info) -# next_morphs = [partial(morphism.morph, dynamic_keys_mapping=dynamic_keys_mapping) for morphism in morphisms] -# next_impl_para_infos = [implicit_parallelization_info for _ in morphisms] -# # print('\t\t {}'.format(implicit_parallelization_infos)) -# else: -# if len(morphisms) != 1: -# raise BadGraphStructure('Impossible to create implicit paralleilzation in the state with {} output edges'.format(len(morphisms))) -# dynamic_keys_mapping = build_dynamic_keys_mapping(implicit_parallelization_info) -# proxy_data = aux.ProxyDict(data, keys_mappings=array_keys_mapping) -# anykey = next(iter(array_keys_mapping.keys())) -# implicit_branches_number = len(proxy_data[anykey]) -# next_morphs = [] -# next_impl_para_infos = [] -# for branch_i in range(implicit_branches_number): -# implicit_parallelization_info_ = ImplicitParallelizationInfo(array_keys_mapping, implicit_branches_number, branch_i) -# dynamic_keys_mapping = build_dynamic_keys_mapping(implicit_parallelization_info_) -# next_morphs.append(partial(morphisms[0].morph, dynamic_keys_mapping=dynamic_keys_mapping)) -# next_impl_para_infos.append(implicit_parallelization_info_) -# cur_morphs = [] -# cur_impl_para_infos = [] -# while len(next_morphs) != 1: -# cur_morphs[:] = next_morphs[:] -# cur_impl_para_infos[:] = next_impl_para_infos[:] -# del next_morphs[:] -# del next_impl_para_infos[:] -# # WE DO NOT UPDATE implicit_parallelization_infos !!! -# for morph, impl_para_info in zip(cur_morphs, cur_impl_para_infos): -# next_state, _ = morph(data) -## print('\t next_state: {}, with impl para info: {}'.format(next_state.name, impl_para_info)) -# if next_state is None: -# return None, None -# next_morph = _run_state(next_state, data, impl_para_info) -## print('\t next_morph: {}'.format(next_morph)) -# if '__EXCEPTION__' in data: -# return None, None -# if next_morph is not None: -# next_morphs.append(next_morph) -# next_impl_para_infos.append(impl_para_info) -# #print(len(next_morphs)) -## print('\t last morph: {}'.format(next_morphs[0])) -# next_state, _ = next_morphs[0](data) -# print(next_state.name, next_impl_para_infos[0]) -# return next_state, next_impl_para_infos[0] -# return _morph - - def make_morphism(self, morphisms, array_keys_mapping=None, implicit_parallelization_info=None): + def make_transfer_func(self, morphisms, array_keys_mapping=None, implicit_parallelization_info=None, state=None): def _morph(data): + # print("MORPHING FROM {}".format(state.name)) if array_keys_mapping is None: dynamic_keys_mapping = build_dynamic_keys_mapping(implicit_parallelization_info) - next_morphs = [partial(morphism.morph, dynamic_keys_mapping=dynamic_keys_mapping) for morphism in morphisms] + next_morphs = [partial(morphism.transfer, dynamic_keys_mapping=dynamic_keys_mapping) for morphism in morphisms] next_impl_para_infos = [implicit_parallelization_info for _ in morphisms] # print('\t\t {}'.format(implicit_parallelization_infos)) else: @@ -349,7 +324,7 @@ class SerialParallelizationPolicy: #while len(next_morphs) != 1 or _is_implicitly_parallelized(next_impl_para_infos): while len(next_morphs) != 1 or _requires_joint_of_implicit_parallelization(array_keys_mapping, next_impl_para_infos): if next_impl_para_infos == []: - raise Exception(str(len(next_morphs))) + raise Exception("Morphs count on state {} is {}".format(state.name, str(len(next_morphs)))) # print(array_keys_mapping, next_impl_para_infos) cur_morphs[:] = next_morphs[:] cur_impl_para_infos[:] = next_impl_para_infos[:] @@ -376,26 +351,6 @@ class SerialParallelizationPolicy: return _morph -class OnlyOneSelectionPolicy: - def __init__(self): - pass - - def select(self, predicate_values): - trues_indices = _get_trues(predicate_values) - if len(trues_indices) != 1: - return None - return trues_indices - -class AllSelectionPolicy: - def __init__(self): - pass - - def select(self, predicate_values): - trues_indices = _get_trues(predicate_values) - if len(trues_indices) != len(predicate_values): - return None - return trues_indices - class BadGraphStructure(Exception): pass diff --git a/comsdk/parser.py b/comsdk/parser.py new file mode 100644 index 0000000000000000000000000000000000000000..f264ac0cfa19d097e9cbae3440504c26f124a2ab --- /dev/null +++ b/comsdk/parser.py @@ -0,0 +1,455 @@ +import re +import copy +import importlib as imp + +from comsdk.graph import Graph, Func, State, Selector +from comsdk.edge import Edge + + +class Params(): + __slots__=( + 'module', + 'entry_func', + 'predicate', + 'selector', + 'function', + 'morphism', + 'parallelism', + 'comment', + 'order', + 'subgraph' + ) + def __init__(self): + for slot in self.__slots__: + setattr(self, slot, None) + + def __str__(self): + stri = "" + for s in self.__slots__: + stri += ((s+": {}, ".format(getattr(self, s))) if getattr(self, s) is not None else "") + return stri + +# entities = {} + +class GraphFactory(): + __slots__ = ( + 'name', + 'states', + 'graph', + 'issub', + 'tocpp', + 'entities' + ) + def __init__(self, tocpp=False): + self.states = {} + self.entities = {} + self.tocpp = tocpp + self.name = None + self.issub = False + + def add_state(self, statename): + if statename not in self.states: + self.states[statename] = State(statename) + if statename in self.entities: + self.states[statename].comment = self.entities[statename].comment + + def _create_morphism(self, morphname=None): + comment = "" + if morphname is None: + return Func(), Func(), comment + pred_f, func_f = Func(), Func() + morph = self.entities[morphname] + for m in morph.__slots__: + if getattr(morph,m) is not None: + if m!="predicate" and m!="function" and m!="comment": + raise Exception("ERROR: Morphisms could not have any params exept comment, predicate and function!\n{}".format(morphname)) + if m=="comment": + comment=getattr(morph, m).replace("\0", " ") + if m=="predicate": + if getattr(morph,m) not in self.entities: + raise Exception("\tERROR: Predicate {} is not defined!".format(getattr(morph, m))) + pred = self.entities[getattr(morph, m)] + if self.tocpp: + pred_f = Func(pred.module, pred.entry_func, dummy=True, comment=pred.comment) + else: + pred_f = Func(pred.module, pred.entry_func, comment=pred.comment) + if m=="function": + if getattr(morph,m) not in self.entities: + raise Exception("\tERROR: Function: {} is not defined!".format(getattr(morph, m))) + fu = self.entities[getattr(morph, m)] + if self.tocpp: + func_f = Func(fu.module, fu.entry_func, dummy=True, comment=fu.comment) + else: + func_f = Func(fu.module, fu.entry_func,comment=fu.comment) + return pred_f, func_f, comment + + + def add_connection(self, st1, st2, morphism=None, ordr=0): + pred, entr, comm = self._create_morphism(morphism) + self.states[st1].connect_to(self.states[st2], edge=Edge(pred, entr, order=ordr, comment=comm)) + print("{} -> {}".format(st1, st2)) + + def build(self, nsub): + print("BUILDING {}\nStates:".format(self.name)) + for s in self.states: + print("\t"+ s) + if self.issub: + self.graph = Graph(self.states[self.name+str(nsub)+"_"+"__BEGIN__"], self.states[self.name+str(nsub)+"_"+"__END__"]) + else: + self.graph = Graph(self.states["__BEGIN__"], self.states["__END__"]) + self.graph.init_graph() + if self.issub: + oldkeys = [] + for e in self.entities: + oldkeys.append(e) + for old in oldkeys: + if self.entities[old].selector is not None or self.entities[old].subgraph is not None: + self.entities[self.name + str(Parser.subgr_count)+"_"+old] = self.entities[old] + del self.entities[old] + for s in self.states: + if s in self.entities and self.entities[s].selector is not None: + selname = self.entities[s].selector + if self.tocpp: + self.states[s].selector = Selector(len(self.states[s].transfers), self.entities[selname].module, self.entities[selname].entry_func, dummy=True) + else: + self.states[s].selector = Selector(len(self.states[s].transfers), self.entities[selname].module, self.entities[selname].entry_func) + else: + self.states[s].selector = Selector(len(self.states[s].transfers)) + if s in self.entities and self.entities[s].subgraph is not None: + print("Replacing state {} with subgraph {}".format(s,self.entities[s].subgraph)) + parsr = Parser(subgraph=True, tocpp= self.tocpp) + subgr = parsr.parse_file(self.entities[s].subgraph) + self.states[s].replace_with_graph(subgr) + self.graph = Graph(self.graph.init_state, self.graph.term_state) + return self.graph + + +class Parser(): + __slots__ = ( + 'fact', + 'issub' + ) + subgr_count = 0 + def __init__(self, tocpp=False, subgraph=False): + self.fact = GraphFactory(tocpp=tocpp) + self.fact.issub = subgraph + self.issub = subgraph + if subgraph: + Parser.subgr_count+=1 + + def _check_brackets(self, rawfile): + br = { "[":{"line":0, "count":0}, "(":{"line":0, "count":0}, "{":{"line":0, "count":0}, "\"":{"line":0, "count":0}} + line = 1 + qu = 0 + for char in rawfile: + if char == "[": + br["["]["line"] = line + br["["]["count"] +=1 + elif char == "{": + br["{"]["line"] = line + br["{"]["count"] +=1 + elif char == "(": + br["("]["line"] = line + br["("]["count"] +=1 + elif char == "]": + br["["]["count"] -=1 + elif char == "}": + br["{"]["count"] -=1 + elif char == ")": + br["("]["count"] -=1 + elif char =="\"": + br["\""]["line"] = line + br["\""]["count"] += 1 if br["\""]["count"]==0 else -1 + elif char == "\n": + line+=1 + expstr= "Brackets or quotes do not match! Missing closing brackets on lines: " + fl = False + for c in br: + if br[c]["count"] != 0: + fl= True + expstr+=str(br[c]["line"])+" " + if fl: + raise Exception(expstr) + + def _split_multiple(self,param): + vals = {} + first=True + for s in param.__slots__: + attr = getattr(param,s) + if attr is not None and '\0' in attr: + vals[s] = attr.split('\0') + l=0 + for sl in vals: + if l==0: + l=len(vals[sl]) + elif l!=len(vals[sl]): + raise Exception("\tERROR: Number of multiple params do not match", l) + res = [copy.copy(param) for i in range(l)] + for sl in vals: + for i, _ in enumerate(res): + setattr(res[i], sl, vals[sl][i]) + return res + + #Props is line "[proFp=smth, ...]" + def _param_from_props(self,props): + parm = Params() + comment = "" + if props =="": + return parm + props = props.replace("]", '') + if '\"' in props: + m = [m for m in re.finditer(r'\".*\"', props)][0] + comment = props[m.span()[0]+1:m.span()[1]-1] + props=props[:m.span()[0]]+props[m.span()[1]:] + if '(' in props: + mchs = [m for m in re.finditer(r'\((\w+,)*\w+\)', props)] + for m in mchs: + props=props[:m.span()[0]]+(props[m.span()[0]:m.span()[1]]).replace(',','\0')+props[m.span()[1]:] + props = props.replace("(","") + props = props.replace(")","") + rs =props.split(r",") #.split(r", ") + for r in rs: + r=r.split(r"=", 1) + if r[0] in parm.__slots__: + setattr(parm, r[0], r[1]) + else: + raise Exception("\tERROR:Unknown parameter: "+ r[0]) + if comment != "": + setattr(parm, "comment", comment.replace("\0", " ")) + return parm + + def _param_from_entln(self, raw): + res = re.split(r"\[", raw, 1) + return res[0], self._param_from_props(res[1]) + + def _multiple_morphs(self,props, n): + p = self._param_from_props(props) + if p.morphism is None: + return [copy.copy(p) for i in range(n)] + else: + return self._split_multiple(p) + + def _topology(self,raw): + spl = re.split(r"\s*(=>|->|\[|\])\s*", raw) + spl = list(filter(lambda x: x!="[" and x!="]" and x!="", spl)) + left = spl[0].split(",") + right = spl[2].split(",") + if self.issub: + for i in range(len(left)): + left[i] = self.fact.name + str(Parser.subgr_count) + "_" + left[i] + for i in range(len(right)): + right[i] = self.fact.name + str(Parser.subgr_count) + "_" + right[i] + if (len(left)>1) and (len(right)>1): + raise Exception("ERROR: Ambigious multiple connection in line:\n\t{}".format(raw)) + # many to one conection + elif len(left)>1: + if len(spl) < 4: + spl.append("") + morphs = self._multiple_morphs(spl[3], len(left)) + if len(morphs)!=len(left): + raise Exception("\tERROR: Count of edges do not match to count of states in many to one connection!\n\t\t{}".format(raw)) + self.fact.add_state(right[0]) + for i, st in enumerate(left): + self.fact.add_state(st) + self.fact.add_connection(st, right[0], morphs[i].morphism) + # one to many connection, here could be selector + elif len(right)>1: + if len(spl) < 4: + spl.append("") + morphs = self._multiple_morphs(spl[3], len(right)) + self.fact.add_state(left[0]) + if len(morphs)!=len(right): + raise Exception("\tERROR: Count of edges do not match to count of states in one to many connection!\n\t\t{}".format(raw)) + for i, st in enumerate(right): + self.fact.add_state(st) + self.fact.add_connection(left[0], st, morphs[i].morphism, morphs[i].order) + # one to one connection + else: + self.fact.add_state(left[0]) + self.fact.add_state(right[0]) + if len(spl)==4: + pr =self._param_from_props(spl[3]) + self.fact.add_connection(left[0], right[0], pr.morphism, ordr=pr.order if pr.order is not None else 0) + elif len(spl)==3: + self.fact.add_connection(left[0], right[0], None) + + def parse_file(self, filename): + # @todo В случае, если на вход будет подан файл в отличной от UTF-8 кодировке программа работать не будет + file = open(filename, encoding='utf-8')# "r") + dot = file.read() + self._check_brackets(dot) + + comments = [m for m in re.finditer(r'\".*\"', dot)] + for m in comments: + dot=dot[:m.span()[0]]+(dot[m.span()[0]:m.span()[1]]).replace(' ','\0')+dot[m.span()[1]:] + dot = re.sub(r"[ \t\r]", "", dot) #deleting all spaces + dot = re.sub(r"((digraph)|}|{)", "", dot) + dot = re.sub(r"\/\/.*", "", dot) + dot = re.sub(r"^\n$", "", dot) + dotlines = dot.splitlines() + dotlines = list(filter(None, dotlines)) + self.fact.name = dotlines[0] + dotlines = dotlines[1:] + # ent_re - regular expr for edges, states, functions properties + ent_re = re.compile(r"^\w+\[.*\]$") + # top_re - regular expr for topology properties, most time consuming one + top_re = re.compile(r"^(\w+,?)+(->|=>)(\w+,?)+(\[(\w+=(\(?\w+,?\)?)+,?)+\])?") + # (r"^\w[\w\s,]*(->|=>)\s*\w[\w\s,=\[\]()]*$") + for i, ln in enumerate(dotlines): + if ent_re.match(ln): + name, parm = self._param_from_entln(ln) + self.fact.entities[name] = parm + elif top_re.match(ln): + self._topology(ln) + return self.fact.build(Parser.subgr_count) + + checked=[] + bushes = {} + selectorends = {} + def generate_cpp(self, filename=None): + self.fact.graph.init_state.input_edges_number =0 + states_to_check = [self.fact.graph.init_state] + while len(states_to_check)!=0: + for st in states_to_check: + self.checked.append(st) + states_to_check.remove(st) + bush = _Bush(st) + bush.grow_bush() + self.bushes[st] = bush + for outs in bush.outstates: + if outs not in states_to_check and outs not in self.checked: + states_to_check.append(outs) + send_token(self.fact.graph.init_state, self.bushes, []) + preds, morphs, sels, st, body = print_graph(self.fact.graph.init_state, self.fact.entities, self.bushes) + from mako.template import Template + if filename is not None: + f = open(filename, "w") + else: + f= open(self.fact.name + ".cpp", "w") + print(Template(filename="./cpp/template.cpp").render(preds=preds, morphs = morphs, sels = sels, states=st, body=body), file=f) + +def print_graph(cur_state, entities, bushes): + checked = [] + toloadpred = [] + toloadmorph = [] + toloadsel =[] + tocheck = [cur_state] + body = "" + while len(tocheck) !=0: + cur_state=tocheck[0] + cur_b = bushes[cur_state] + cur_b.token+=1 + if cur_b.token < cur_b.state.input_edges_number - cur_b.state.looped_edges_number: + tocheck.remove(cur_state) + tocheck.append(cur_state) + continue + if cur_state in checked: + tocheck.remove(cur_state) + continue + if len(cur_b.branches)>1 or len(cur_b.incomes)>1: + body+="{}:\n".format(cur_state.name) + if len(cur_b.incomes)!=0: + if cur_b.state.comment!="" and cur_b.state.comment is not None: + print("STcomm:", cur_b.state.comment) + body+="//"+cur_b.state.comment+"\n" + stri = "false " + for inc in cur_b.incomes: + stri += "|| SEL_{}[{}] ".format(inc["st"].name, inc["i"]) + body+="if (!({}))".format(stri) + body+="{\n\tfor (int seli = 0;"+" seli < {};".format(len(cur_state.transfers))+" seli++)\n"+ "\t\tSEL_{}[seli]=false;".format(cur_state.name)+"\n}" + if cur_state.selector.name != "": + # print(cur_state.name, cur_state.selector) + if cur_state.selector not in toloadsel: + toloadsel.append(cur_state.selector) + body+="else {\n"+ "\tSEL_{} = {}(&data);//{}\n".format(cur_state.name, cur_state.selector, cur_state.selector.comment )+"}\n" + else: + body+="else {\n\tfor (int seli = 0;"+" seli < {};".format(len(cur_state.transfers))+" seli++)\n"+"\t\tSEL_{}[seli]=true;".format(cur_state.name)+"\n}\n" + for i, br in enumerate(cur_b.branches): + body+="if (SEL_{}[{}])".format(cur_state.name, i)+"{\n" + if br[len(br)-1].output_state not in tocheck: + tocheck.append(br[len(br)-1].output_state) + if br[len(br)-1].output_state in checked or br[len(br)-1].output_state is cur_state: + stri, toloadpred, toloadmorph = cur_b.cpp_branch(i, toloadpred, toloadmorph) + body+=stri+"\tgoto {};\n".format(br[len(br)-1].output_state.name)+"}\n" + else: + stri, toloadpred, toloadmorph = cur_b.cpp_branch(i, toloadpred, toloadmorph) + body+=stri+"}\n" + tocheck.remove(cur_state) + checked.append(cur_state) + return _unique(toloadpred), _unique(toloadmorph), _unique(toloadsel), checked, body + +def _unique(lst): + for i, el in enumerate(lst): + for el2 in lst[i+1:]: + if el2.module == el.module and el2.name == el.name: + lst.remove(el2) + return lst + +def send_token(cur_state, bushes, checked): + cur_b = bushes[cur_state] + if cur_state in checked: + return + if len(cur_b.outstates)==0: + return + if len(cur_b.incomes) == cur_b.state.input_edges_number - cur_b.state.looped_edges_number: + checked.append(cur_state) + for i,br in enumerate(cur_b.branches): + bushes[br[len(br)-1].output_state].incomes.append({"st":cur_state, "i":i}) + send_token(br[len(br)-1].output_state,bushes, checked) + +class _Bush(): + __slots__=( + 'state', + 'selector', + 'branches', + 'outstates', + 'token', + 'incomes', + 'selectorfin' + ) + + def __init__(self, state): + self.state = state + self.selector = state.selector + self.branches = [] + self.outstates = [] + self.token = 0 + self.incomes = [] + + def grow_bush(self): + for t in self.state.transfers: + branch = [t] + self._gen_branch(t.output_state, branch) + + def _gen_branch(self, cur_state, branch): + while len(cur_state.transfers)==1 and cur_state.input_edges_number==1: + if cur_state._proxy_state is not None: + cur_state=cur_state._proxy_state + tr = cur_state.transfers[0] + branch.append(tr) + cur_state = tr.output_state + self.branches.append(branch) + if cur_state not in self.outstates: + self.outstates.append(cur_state) + + def cpp_branch(self, i, toloadpred, toloadmorph): + res = "" + for tr in self.branches[i]: + edge = tr.edge + if edge.comment!="": + res+="\t//{}\n".format(edge.comment) + if edge.pred_f.name != "": + if edge.pred_f not in toloadpred: + toloadpred.append(edge.pred_f) + res+="\tcheck_pred({}(&data), \"{}\");".format(edge.pred_f, edge.pred_f) + res+="//{}\n".format(edge.pred_f.comment) if edge.pred_f.comment != "" else "\n" + if edge.morph_f.name != "": + if edge.morph_f not in toloadmorph: + toloadmorph.append(edge.morph_f) + res+="\t{}(&data);".format(edge.morph_f) + res+="//{}\n".format(edge.morph_f.comment) if edge.morph_f.comment != "" else "\n" + return res, toloadpred, toloadmorph + + + + diff --git a/comsdk/research.py b/comsdk/research.py index 9c1e1f1a32d529bb5a3e04238a6d1cc98ebaf30f..ca45e3d597afdf44ae1cff715c2588e3523cb663 100644 --- a/comsdk/research.py +++ b/comsdk/research.py @@ -2,7 +2,7 @@ import os import pickle import shutil from datetime import datetime, date -from comsdk.aux import * +from comsdk.comaux import * from comsdk.communication import * from comsdk.distributed_storage import * from comsdk.edge import Edge, dummy_predicate diff --git a/comsdk/test.adot b/comsdk/test.adot new file mode 100644 index 0000000000000000000000000000000000000000..bc95ee3f52f4157cfdf31bb911e88c64fff57db7 --- /dev/null +++ b/comsdk/test.adot @@ -0,0 +1,40 @@ +digraph CODEOBJECT_GENERATOR +{ +// ??????????? ???????-???????????? + FUNC_1 [module=case_gen_funcs, entry_func=function_1] + FUNC_2 [module=case_gen_funcs, entry_func=function_2] + FUNC_3 [module=case_gen_funcs, entry_func=function_3] + SAVE_TO_DB [module=case_gen_funcs, entry_func=save_to_db] + SAVE_TO_FILE [module=case_gen_funcs, entry_func=save_to_file] + REPEAT [module=case_gen_funcs, entry_func=repeat] + EXIT [module=case_gen_funcs, entry_func=exit] + CREATE_DUMP [module=case_gen_funcs, entry_func=create_dump] +// ??????????? ???????-?????????? + PREDICATE_X [module=predicate_funcs, entry_func=predicate_x] + PREDICATE_Y [module=predicate_funcs, entry_func=predicate_y] + SELECTOR [module=predicate_funcs, entry_func=selector] +// ??????????? ??????? ???????? (????????) + EDGE_1 [predicate=PREDICATE_X, function=FUNC_1] + EDGE_2 [predicate=PREDICATE_Y, function=FUNC_2] + EDGE_3 [predicate=PREDICATE_X, function=FUNC_3] + EDGE_4 [predicate=PREDICATE_Y, function=SAVE_TO_DB] + EDGE_5 [predicate=PREDICATE_X, function=SAVE_TO_FILE] + EDGE_6 [predicate=PREDICATE_Y, function=REPEAT] + EDGE_7 [predicate=PREDICATE_X, function=EXIT] + EDGE_8 [function=EXIT] + EDGE_9 [predicate=CHECK_DUMP, function=EXIT] + EDGE_10 [function=CREATE_DUMP] +// ? ???? ??????? ????????? ????????????????? + CONTENT_SUBSTITUTED [parallelism=threading] +// ??????????? ???????? ?????? + __BEGIN__ -> INPUT_READY + INPUT_READY -> TEPMLATE_COPIED [morphism=EDGE_1] + TEPMLATE_COPIED -> NAMES_SUBSTITUTED [morphism=EDGE_2] + NAMES_SUBSTITUTED -> CONTENT_SUBSTITUTED [morphism=EDGE_3] + CONTENT_SUBSTITUTED => DUMP_CREATED [morphism=EDGE_10] + CONTENT_SUBSTITUTED -> RESULT_SAVED [morphism=EDGE_4] + CONTENT_SUBSTITUTED -> RESULT_SAVED [morphism=EDGE_5] +// ? ??????????? ?? ?????? ?????????? SELECTOR ?????????????? ??????? ?? ??????? ??? ??????? ????? + RESULT_SAVED -> INPUT_READY, __END__ [selector=SELECTOR, morphism=(EDGE_6, EDGE_7)] + RESULT_SAVED, DUMP_CREATED -> __END__ [morphism=(EDGE_8, EDGE_9)] +} \ No newline at end of file diff --git a/cpp/printers.cpp b/cpp/printers.cpp new file mode 100644 index 0000000000000000000000000000000000000000..52f6cd0353bcda8ea48f042ccf41287e89d351b5 --- /dev/null +++ b/cpp/printers.cpp @@ -0,0 +1,36 @@ +#include <iostream> +#include <anymap.h> + +extern "C" { + int PrintHello(com::Anymap) { + std::cout<<"Hello!" << std::endl; + return 0; + } + + int PrintBye(com::Anymap) { + std::cout<<"Bye!" << std::endl; + return 0; + } + + int PrintA(com::Anymap) { + std::cout<<"A" << std::endl; + return 0; + } + + int PrintB(com::Anymap) { + std::cout<<"B" << std::endl; + return 0; + } + + bool ReturnTrue(){ + return true; + } + + bool ReturnFalse(){ + return false; + } + + std::list<bool> ThreeTrue(){ + return false; + } +} \ No newline at end of file diff --git a/cpp/run.sh b/cpp/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..f7d40f63826e8e5463530cdc240ed4dec5c50d38 --- /dev/null +++ b/cpp/run.sh @@ -0,0 +1,9 @@ +g++ -c -fPIC ./dev/core/anymap.cpp -o anymap.o -I./dev; +g++ -c -fPIC tests.cpp -o tests.o -I./dev; +# g++ -c -fPIC ./dev/iniparser/iniparser.cpp -o iniparser.o -I./dev; +g++ tests.o anymap.o -shared -o libtest.so; rm tests.o anymap.o; +if g++ $1 -o graph.out -I./dev ./dev/core/anymap.cpp -ldl; then +./graph.out; +else + echo "Not Compiled!"; +fi; \ No newline at end of file diff --git a/cpp/template.cpp b/cpp/template.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9aa7bba0e17baef44092c3cbd0a008521d8c7b75 --- /dev/null +++ b/cpp/template.cpp @@ -0,0 +1,59 @@ +#include <libtools.h> +#include <anymap.h> +#include <iniparser.h> + +typedef std::function<int(com::Anymap*)> IntFunc; +typedef std::function<bool(com::Anymap*)> BoolFunc; +typedef std::function<bool*(com::Anymap*)> BoolArrFunc; + +IntFunc LoadEntry(std::string lib, std::string func) { + DllHandle handler; + return com::lib::loadFunction<int (com::Anymap*), DllHandle>(lib.c_str(), func.c_str(), handler); +} + +BoolFunc LoadPred(std::string lib, std::string func) { + DllHandle handler; + return com::lib::loadFunction<int (com::Anymap*), DllHandle>(lib.c_str(), func.c_str(), handler); +} + +BoolArrFunc LoadSelector(std::string lib, std::string func){ + DllHandle handler; + return com::lib::loadFunction<bool* (com::Anymap*), DllHandle>(lib.c_str(), func.c_str(), handler); +} + +void check_pred(bool predval, std::string predname) { + if (!predval) { + std::cout<<"Predicate "<<predname<<" returned FALSE!"<<std::endl; + exit(-1); + } +} + +int main(int argc, char const *argv[]) +{ + auto data = com::Anymap(); + //Predicates +% for pred in preds: + auto ${pred} = LoadPred("${pred.module}", "${pred.name}"); +% endfor + //Entry functions +% for morph in morphs: + auto ${str(morph)} = LoadEntry("${morph.module}", "${morph.name}"); +% endfor + //Selectors +% for sel in sels: + auto ${str(sel)} = LoadSelector("${sel.module}", "${sel.name}"); +% endfor + //Branch tokens + bool* SEL_${states[0].name} = new bool[${len(states[0].transfers)}]; + std::fill_n(SEL_${states[0].name}, ${len(states[0].transfers)}, true); +% for st in states[1:]: + bool* SEL_${st.name} = new bool[${len(st.transfers)}]; + std::fill_n(SEL_${st.name}, ${len(st.transfers)}, false); +% endfor + +${body} + +TERM: + std::cout<<"Termination!\n"; + return 0; +} \ No newline at end of file diff --git a/test_funcs/__init__.py b/test_funcs/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test_funcs/__pycache__/__init__.cpython-37.pyc b/test_funcs/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8300123196cdd46044f029b6d36d2d032e00c2d0 Binary files /dev/null and b/test_funcs/__pycache__/__init__.cpython-37.pyc differ diff --git a/test_funcs/__pycache__/simplest.cpython-37.pyc b/test_funcs/__pycache__/simplest.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9325caa8e4bb079839e61965e3f86352010caf45 Binary files /dev/null and b/test_funcs/__pycache__/simplest.cpython-37.pyc differ diff --git a/test_funcs/simplest.py b/test_funcs/simplest.py new file mode 100644 index 0000000000000000000000000000000000000000..2d357c28fa3f6c2f0641985e35cc082534a4e71e --- /dev/null +++ b/test_funcs/simplest.py @@ -0,0 +1,34 @@ +def dummy_edge(data): + pass + +def increment_a_edge(data): + data['a'] += 1 + +def increment_a_array_edge(data): + for i in range(len(data['a'])): + data['a'][i] += 1 + +def increment_b_edge(data): + data['b'] += 1 + +def decrement_a_edge(data): + data['a'] -= 1 + +def nonzero_predicate(data): + return data['a'] != 0 + +def positiveness_predicate(data): + return data['a'] > 0 + +def nonpositiveness_predicate(data): + return data['a'] <= 0 + +def copy_to_c(data): + data['c'] = data['a'] + +def selector_a_nonpositive(data): + res = data['a'] <= 0 + return [res, not res] + +def true_predicate(data): + return True diff --git a/tests/__pycache__/test_graph.cpython-37.pyc b/tests/__pycache__/test_graph.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..210eeb9df598a9e610767e642839d77107d9e0cf Binary files /dev/null and b/tests/__pycache__/test_graph.cpython-37.pyc differ diff --git a/tests/__pycache__/test_parser.cpython-37.pyc b/tests/__pycache__/test_parser.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6507451d786bb069e2d5db775d48ded878be3a21 Binary files /dev/null and b/tests/__pycache__/test_parser.cpython-37.pyc differ diff --git a/tests/adot/add.adot b/tests/adot/add.adot new file mode 100644 index 0000000000000000000000000000000000000000..e12c29ededc85084b136af109d2796fe67211c07 --- /dev/null +++ b/tests/adot/add.adot @@ -0,0 +1,8 @@ +digraph ADD { + FUNC [module=test_funcs.simplest, entry_func=increment_b_edge] + PRED [module=test_funcs.simplest, entry_func=positiveness_predicate] + MORPH [predicate=PRED, function=FUNC, comment="ADD"] + + __BEGIN__ -> ST [morphism = MORPH] + ST -> __END__ +} \ No newline at end of file diff --git a/tests/adot/branching.adot b/tests/adot/branching.adot new file mode 100644 index 0000000000000000000000000000000000000000..e8c14dea2182d4a8629053871a326872f4fddb07 --- /dev/null +++ b/tests/adot/branching.adot @@ -0,0 +1,15 @@ +digraph SIMPLEST { + FUNCA [module=test_funcs.simplest, entry_func=increment_a_edge] + FUNCB [module=test_funcs.simplest, entry_func=increment_b_edge] + PRED [module=test_funcs.simplest, entry_func=true_predicate] + + INCR_A [predicate=PRED, function=FUNCA] + INCR_B [predicate=PRED, function=FUNCB] + + __BEGIN__ -> ROOT + ROOT -> BR1, BR2 [morphism=(INCR_A, INCR_B)] + BR1 -> BR1_ST [morphism=INCR_A] + BR2 -> BR2_ST [morphism=INCR_B] + BR1_ST, BR2_ST -> MERGE [morphism=(INCR_A, INCR_B)] + MERGE -> __END__ +} \ No newline at end of file diff --git a/tests/adot/complex.adot b/tests/adot/complex.adot new file mode 100644 index 0000000000000000000000000000000000000000..3ea224c98daaee0aa0069957b4af5e4b07a8ed76 --- /dev/null +++ b/tests/adot/complex.adot @@ -0,0 +1,15 @@ +digraph SIMPLEST { + FUNCA [module=test_funcs.simplest, entry_func=increment_a_edge] + PRED [module=test_funcs.simplest, entry_func=true_predicate] + + INCR_A [predicate=PRED, function=FUNCA] + + ST1 [subgraph=tests/adot/trivial.adot] + ST2 [subgraph=tests/adot/cycled.adot] + ST3 [subgraph=tests/adot/branching.adot] + + __BEGIN__ -> ST1 + ST1 -> ST2 [morphism=INCR_A] + ST2 -> ST3 [morphism=INCR_A] + ST3 -> __END__ +} \ No newline at end of file diff --git a/tests/adot/cppbranching.adot b/tests/adot/cppbranching.adot new file mode 100644 index 0000000000000000000000000000000000000000..3b5a0a549585628c591168103da43e93cb0c7772 --- /dev/null +++ b/tests/adot/cppbranching.adot @@ -0,0 +1,28 @@ +digraph SIMPLEST { + FUNCA [module=libtest, entry_func=IncA] + FUNCB [module=libtest, entry_func=IncB] + + CHECKA [module=libtest, entry_func=CheckAEq4] + CHECKB [module=libtest, entry_func=CheckBEq4] + + SETA [module=libtest, entry_func=SetAEq1] + SETB [module=libtest, entry_func=SetBEq1] + + PASS [module=libtest, entry_func=PassFunc] + PRED [module=libtest, entry_func=PassPred] + + INCR_A [predicate=PRED, function=FUNCA] + INCR_B [predicate=PRED, function=FUNCB] + CH_A [predicate=CHECKA, function = PASS] + SET_A [predicate=PRED, function=SETA] + SET_B [predicate=PRED, function=SETB] + CH_B [predicate=CHECKB, function = PASS] + + __BEGIN__ -> ROT [morphism=SET_A] + ROT -> ROOT[morphism=SET_B] + ROOT -> BR1, BR2 [morphism=(INCR_A, INCR_B)] + BR1 -> BR1_ST [morphism=INCR_A] + BR2 -> BR2_ST [morphism=INCR_B] + BR1_ST, BR2_ST -> MERGE [morphism=(INCR_A, INCR_B)] + MERGE -> __END__, __END__ [morphism=(CH_A, CH_B)] +} \ No newline at end of file diff --git a/tests/adot/cppcomplex.adot b/tests/adot/cppcomplex.adot new file mode 100644 index 0000000000000000000000000000000000000000..c93c09ec2a9aacd7abde6c5f23a2072437f16839 --- /dev/null +++ b/tests/adot/cppcomplex.adot @@ -0,0 +1,15 @@ +digraph SIMPLEST { + FUNCA [module=test_funcs.simplest, entry_func=increment_a_edge] + PRED [module=test_funcs.simplest, entry_func=true_predicate] + + INCR_A [predicate=PRED, function=FUNCA] + + ST1 [subgraph=tests/adot/cpptrivial.adot] + ST2 [subgraph=tests/adot/cppcycled.adot] + ST3 [subgraph=tests/adot/cppbranching.adot] + + __BEGIN__ -> ST1 + ST1 -> ST2 + ST2 -> ST3 + ST3 -> __END__ +} \ No newline at end of file diff --git a/tests/adot/cppcycled.adot b/tests/adot/cppcycled.adot new file mode 100644 index 0000000000000000000000000000000000000000..ed3209bc780cf9eaa2b7ffef94c5bbde7ab83120 --- /dev/null +++ b/tests/adot/cppcycled.adot @@ -0,0 +1,18 @@ +digraph CYCLED { + + SETA [module=libtest, entry_func=SetAEq10] + FUNC [module=libtest, entry_func=DecA] + PRED [module=libtest, entry_func=PassPred] + + SET [predicate=PRED, function=SETA] + MORPH [predicate=PRED, function=FUNC] + + SEL [module = libtest, entry_func=SelectorA] + + ST2 [selector = SEL] + + __BEGIN__ -> ST1 [morphism=SET] + ST1 -> ST2 [morphism=MORPH] + ST2 -> ST1 [order=1] + ST2 -> __END__ [order = 2] +} \ No newline at end of file diff --git a/tests/adot/cpptrivial.adot b/tests/adot/cpptrivial.adot new file mode 100644 index 0000000000000000000000000000000000000000..c37cb9c1fe8393522e05dc62288d8b052f7424b0 --- /dev/null +++ b/tests/adot/cpptrivial.adot @@ -0,0 +1,9 @@ +digraph SIMPLE { + FUNC [module=libtest, entry_func=IncA] + PRED [module=libtest, entry_func=PassPred] + MORPH [predicate=PRED, function=FUNC] + + __BEGIN__ -> ST1 [morphism = MORPH] + ST1 -> ST2 [morphism = MORPH] + ST2 -> __END__ [morphism = MORPH] +} \ No newline at end of file diff --git a/tests/adot/cycled.adot b/tests/adot/cycled.adot new file mode 100644 index 0000000000000000000000000000000000000000..4b37cbcb3a5306edae2c41a651252f0e05627d4d --- /dev/null +++ b/tests/adot/cycled.adot @@ -0,0 +1,14 @@ +digraph CYCLED { + FUNC [module=test_funcs.simplest, entry_func=decrement_a_edge] + PRED [module=test_funcs.simplest, entry_func=true_predicate] + MORPH [predicate=PRED, function=FUNC] + + SEL [module = test_funcs.simplest, entry_func = selector_a_nonpositive] + + ST2 [selector = SEL] + + __BEGIN__ -> ST1 + ST1 -> ST2 [morphism=MORPH] + ST2 -> ST1 [order=2] + ST2 -> __END__ [order = 1] +} \ No newline at end of file diff --git a/tests/adot/file.adot b/tests/adot/file.adot new file mode 100644 index 0000000000000000000000000000000000000000..6076637bf3e355453552ce2e62238b6c39ce1bed --- /dev/null +++ b/tests/adot/file.adot @@ -0,0 +1,54 @@ +digraph gcdhom_inverted_model_pso +{ +// Определение функций-обработчиков + PASS_PROCESSOR [module=libcomsdk, entry_func=pass_processor] + CHECK_PSO_AGENT_REINIT [module=libgcdfes, entry_func=check_pso_agent_reinit, comment="Проверка о необходимости реинициализации отдельной частицы (смещение частицы) в рое в рамках метода роя частиц."] + CHECK_PSO_SWARM_REINIT [module=libgcdfes, entry_func=check_pso_swarm_reinit, comment="Проверка о необходимости реинициализации всего роя частиц в рамках метода роя частиц."] + + PSO_AGENT_REINIT [module=libgcdfes, entry_func=pso_agent_reinit, comment="Реинициализация отдельной частицы (смещение частицы) в рое в рамках метода роя частиц."] + PSO_SWARM_REINIT [module=libgcdfes, entry_func=pso_swarm_reinit, comment="Реинициализация всего роя частиц в рамках метода роя частиц."] + + PSO_SWARM_ANALYSING [module=libgcdfes, entry_func=pso_swarm_analysing, comment="Анализ всего роя частиц в рамках метода роя частиц."] + + PSO_HOM_AGENT_POSTPROC [module=libgcdfes, entry_func=pso_hom_agent_postproc, comment="Постпроцессинг после решения отдельной задачи методом асимптотического осреднения."] + + PSO_TASK_DATA_REINIT [module=libgcdfes, entry_func=pso_task_data_reinit, comment="Реинициализация постановки задачи анализа эффективных характеристик КМ методом асимптотического осреднения."] + + PSO_AGENT_INIT [module=libgcdfes, entry_func=pso_agent_init, comment="Инициализация отдельной частицы в рамках метода роя частиц."] + + PSO_SWARM_INIT [module=libgcdfes, entry_func=pso_swarm_init, comment="Инициализация роя частиц."] + + PSO_INIT [module=libgcdfes, entry_func=pso_swarm_init, comment="Инициализация метода роя частиц."] + +// Определение функций-предикатов + PASS_PREDICATE [module=libcomsdk, entry_func=pass_predicate] + +// Определение морфизмов + PASS_MORPHISM [predicate=PASS_PREDICATE, function=PASS_PROCESSOR, comment="ПАСС, морфизм."] + + PSO_AGENT_REINIT_MORPHISM [predicate=PASS_PREDICATE, function=PSO_AGENT_REINIT] + PSO_SWARM_REINIT_MORPHISM [predicate=PASS_PREDICATE, function=PSO_SWARM_REINIT] + PSO_SWARM_ANALYSING_MORPHISM [predicate=PASS_PREDICATE, function=PSO_SWARM_ANALYSING] + PSO_HOM_AGENT_POSTPROC_MORPHISM [predicate=PASS_PREDICATE, function=PSO_HOM_AGENT_POSTPROC] + PSO_TASK_DATA_REINIT_MORPHISM [predicate=PASS_PREDICATE, function=PSO_TASK_DATA_REINIT] + PSO_AGENT_INIT_MORPHISM [predicate=PASS_PREDICATE, function=PSO_AGENT_INIT] + PSO_SWARM_INIT_MORPHISM [predicate=PASS_PREDICATE, function=PSO_SWARM_INIT] + PSO_INIT_MORPHISM [predicate=PASS_PREDICATE, function=PSO_INIT] + +// Определение атрибутов узлов + S_1 [subgraph=gcdhom_preprocessor.adot] + S_5 [subgraph=gcdhom_processor.adot] + S_6 [selector=CHECK_PSO_AGENT_REINIT] + S_7 [selector=CHECK_PSO_SWARM_REINIT] + +// Определение топологии графовой модели метода конечных элементов + __BEGIN__ -> S_1 + S_1 -> S_2 [morphism=PSO_INIT_MORPHISM] + S_2 -> S_3 [morphism=PSO_SWARM_INIT_MORPHISM] + S_3 -> S_4 [morphism=PSO_AGENT_INIT_MORPHISM] + S_4 -> S_5 [morphism=PSO_TASK_DATA_REINIT_MORPHISM] + S_5 -> S_6 [morphism=PSO_HOM_AGENT_POSTPROC_MORPHISM] + S_6 -> S_4, S_7 [morphism=(PSO_AGENT_REINIT_MORPHISM, PSO_SWARM_ANALYSING_MORPHISM), order=(10,20)] + S_7 -> S_4, S_8 [morphism=(PSO_SWARM_REINIT_MORPHISM, PASS_MORPHISM), order=(30,40)] + S_8 -> __END__ [comment = "Расчет завершён."] +} diff --git a/tests/adot/testparal.adot b/tests/adot/testparal.adot new file mode 100644 index 0000000000000000000000000000000000000000..4f275f0e79fceeac99b50037343e96bd51a17088 --- /dev/null +++ b/tests/adot/testparal.adot @@ -0,0 +1,17 @@ +digraph SIMPLEST { + FUNCA [module=test_funcs.simplest, entry_func=increment_a_edge] + FUNCB [module=test_funcs.simplest, entry_func=increment_b_edge] + PRED [module=test_funcs.simplest, entry_func=positiveness_predicate] + INCR_A [predicate=PRED, function=FUNCA] + INCR_B [predicate=PRED, function=FUNCB] + + + __BEGIN__ -> ROOT + ROOT -> BR1, BR2, BR3 [morphism=(INCR_A, INCR_A, INCR_A)] + //BR3 -> SIBL3_BR1, SIBL3_BR2 [morphism=(INCR_A, INCR_A)] + //BR2 -> SIBL2_BR1, SIBL2_BR2 [morphism=(INCR_A, INCR_A)] + //SIBL3_BR1 -> SIBL3_BR1_1, SIBL3_BR1_2 [morphism=(INCR_A, INCR_A)] + //SIBL3_BR1_1, SIBL3_BR1_2 -> TERM [morphism=(INCR_A, INCR_A)] + //BR1, SIBL2_BR1, SIBL2_BR2, TERM, SIBL3_BR2 -> __END__ [morphism=(INCR_A, INCR_A, INCR_A, INCR_A, INCR_A)] + BR1, BR2, BR3 -> __END__ [morphism=(INCR_A, INCR_A, INCR_A)] +} \ No newline at end of file diff --git a/tests/adot/testsub.adot b/tests/adot/testsub.adot new file mode 100644 index 0000000000000000000000000000000000000000..42391b8e86484ace7e8d443394991f28b626bae1 --- /dev/null +++ b/tests/adot/testsub.adot @@ -0,0 +1,14 @@ +digraph TEST_SUB { + FUNC [module=test_funcs.simplest, entry_func=increment_a_edge] + PRED [module=test_funcs.simplest, entry_func=positiveness_predicate] + MORPH [predicate=PRED, function=FUNC] + SEL [module=test_funcs.simplest, entry_func=selector_a_nonpositive] + + ST2 [subgraph = tests/adot/file.adot] + ST3 [selector = SEL] + + __BEGIN__ -> ST1 [morphism = MORPH] + ST1 -> ST2 + ST2 -> ST3 + ST3 -> __END__ +} \ No newline at end of file diff --git a/tests/adot/trivial.adot b/tests/adot/trivial.adot new file mode 100644 index 0000000000000000000000000000000000000000..26a06b741eefec6c26dc5d8a6ec048c4d384f324 --- /dev/null +++ b/tests/adot/trivial.adot @@ -0,0 +1,9 @@ +digraph TRIVIAL { + FUNC [module=test_funcs.simplest, entry_func=increment_a_edge] + PRED [module=test_funcs.simplest, entry_func=true_predicate] + MORPH [predicate=PRED, function=FUNC, comment="ADD"] + + __BEGIN__ -> ST1 [morphism = MORPH] + ST1 -> ST2 [morphism = MORPH] + ST2 -> __END__ [morphism = MORPH] +} \ No newline at end of file diff --git a/tests/square/square b/tests/square/square new file mode 100755 index 0000000000000000000000000000000000000000..ad02987631f2c4cdb69d2b659e8a2cc39cfd5cb8 Binary files /dev/null and b/tests/square/square differ diff --git a/tests/test_graph.py b/tests/test_graph.py index ab2a5df23f6d94050b8d4318f8fc202afb4e5a6f..160e2348a891f64149e5c13fd9c381e432c2c209 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -230,24 +230,30 @@ class GraphGoodCheck(unittest.TestCase): def _get_trivial_parallel_graph(self, initial_conditions): ''' - s_1 -> s_2 -> s_3 -> s_6 - -> s_4 -> s_5 -> + s_1 -> s_2 -> s_3 ---------> s6s + -> s_4 -> s_4_1 -> s_5 + -> s_4_2 p_12 = p_24 = p_13 = p_34 := a not 0 f_12 = f_24 := a + 1 f_13 = f_34 := b + 1 ''' - s_1 = State('nonparallel_s_1', selection_policy=AllSelectionPolicy()) + s_1 = State('nonparallel_s_1') s_2 = State('parallel_s_2') s_3 = State('parallel_s_3') s_4 = State('parallel_s_4') + s_4_1 = State('parallel_s_4_1') + s_4_2 = State('parallel_s_4_2') s_5 = State('parallel_s_5') s_6 = State('nonparallel_s_6') s_1.connect_to(s_2, edge=Edge(nonzero_predicate, increment_a_edge)) s_2.connect_to(s_3, edge=Edge(nonzero_predicate, increment_a_edge)) s_3.connect_to(s_6, edge=Edge(nonzero_predicate, increment_a_edge)) s_1.connect_to(s_4, edge=Edge(nonzero_predicate, increment_b_edge)) - s_4.connect_to(s_5, edge=Edge(nonzero_predicate, increment_b_edge)) + s_4.connect_to(s_4_1, edge=Edge(nonzero_predicate, increment_b_edge)) + s_4.connect_to(s_4_2, edge=Edge(nonzero_predicate, increment_b_edge)) + s_4_1.connect_to(s_5, edge=Edge(nonzero_predicate, increment_b_edge)) + s_4_2.connect_to(s_6, edge=Edge(nonzero_predicate, increment_b_edge)) s_5.connect_to(s_6, edge=Edge(nonzero_predicate, increment_b_edge)) correct_outputs = [] for ic in initial_conditions: @@ -433,15 +439,17 @@ class GraphGoodCheck(unittest.TestCase): p_12 = p_23 := dummy f_12 := a + 1 ''' - + + pred = Func(func=dummy_predicate) + morph = Func(func=increment_a_edge) s_1 = State('s_1') s_2 = State('s_2') s_3 = State('s_3') - s_1.connect_to(s_2, edge=Edge(dummy_predicate, increment_a_edge)) - s_2.connect_to(s_3, edge=Edge(dummy_predicate, increment_a_edge)) + s_1.connect_to(s_2, edge=Edge(pred, morph)) + s_2.connect_to(s_3, edge=Edge(pred, morph)) sub_s_1 = State('sub_s_1') sub_s_2 = State('sub_s_2') - sub_s_1.connect_to(sub_s_2, edge=Edge(dummy_predicate, increment_a_edge)) + sub_s_1.connect_to(sub_s_2, edge=Edge(pred, morph)) s_2.replace_with_graph(Graph(sub_s_1, sub_s_2)) correct_outputs = [] for ic in initial_conditions: diff --git a/tests/test_parser.py b/tests/test_parser.py new file mode 100644 index 0000000000000000000000000000000000000000..cadf7ad55faa1d80d09f1362660772746ec308f8 --- /dev/null +++ b/tests/test_parser.py @@ -0,0 +1,72 @@ +import unittest +import subprocess + +from comsdk.graph import * +from comsdk.parser import Parser + +path_to_comsdk = "/home/lbstr/bmstu/comsdk" +path_to_pycomsdk = "/home/lbstr/bmstu/pycomsdk" + +class ParserGoodCheck(unittest.TestCase): + + def test_trivial_graph(self): + parsr = Parser() + gr = parsr.parse_file("./tests/adot/trivial.adot") + data = {"a": 1} + gr.run(data) + self.assertEqual(data["a"], 4) + + def test_branching_graph(self): + parsr = Parser() + gr = parsr.parse_file("./tests/adot/branching.adot") + data = {"a": 1, "b": 1} + gr.run(data) + self.assertEqual(data["a"], 4) + self.assertEqual(data["b"], 4) + + def test_cycled_graph(self): + parsr = Parser() + gr = parsr.parse_file("./tests/adot/cycled.adot") + data = {"a": 10} + gr.run(data) + self.assertEqual(data["a"], 0) + + def test_complex_graph(self): + parsr = Parser() + gr = parsr.parse_file("./tests/adot/complex.adot") + data = {"a": 1, "b": 1} + gr.run(data) + self.assertEqual(data["a"], 4) + self.assertEqual(data["b"], 4) + + def test_cpp_trivial_graph(self): + parsr = Parser(tocpp=True) + gr = parsr.parse_file("./tests/adot/cpptrivial.adot") + parsr.generate_cpp(path_to_comsdk+"res.cpp") + command = "cd "+path_to_comsdk+"; "+path_to_pycomsdk+"/cpp/run.sh "+path_to_comsdk+"res.cpp" + subprocess.check_output(["bash", "-c", command]) + + def test_cpp_branching_graph(self): + parsr = Parser(tocpp=True) + gr = parsr.parse_file("./tests/adot/cppbranching.adot") + parsr.generate_cpp(path_to_comsdk+"res.cpp") + command = "cd "+path_to_comsdk+"; "+path_to_pycomsdk+"/cpp/run.sh "+path_to_comsdk+"res.cpp" + subprocess.check_output(["bash", "-c", command]) + + def test_cpp_cycled_graph(self): + parsr = Parser(tocpp=True) + gr = parsr.parse_file("./tests/adot/cppcycled.adot") + parsr.generate_cpp(path_to_comsdk+"res.cpp") + command = "cd "+path_to_comsdk+"; "+path_to_pycomsdk+"/cpp/run.sh "+path_to_comsdk+"res.cpp" + subprocess.check_output(["bash", "-c", command]) + + def test_cpp_complex_graph(self): + parsr = Parser(tocpp=True) + gr = parsr.parse_file("./tests/adot/cppcomplex.adot") + parsr.generate_cpp(path_to_comsdk+"res.cpp") + command = "cd "+path_to_comsdk+"; "+path_to_pycomsdk+"/cpp/run.sh "+path_to_comsdk+"res.cpp" + subprocess.check_output(["bash", "-c", command]) + +if __name__ == '__main__': + unittest.main() +