Commit 21b3c639 authored by Vlad Golubev's avatar Vlad Golubev

Добавил презентацию графовой модели в виде словаря в GraphFactory

Данный функционал позволяет отправлять на клиент структурное описание графовой модели для последующей визуализации и интерактивной работы. Граф представляется в виде словаря со следующей структурой: graph: { 'init_state_name': { 'subgraph': None/{subgraph}, 'connect_to': [{'next': next_state_name, 'morph_f': morphism, 'pred_f': predicate}, ...] // здесь отобразаются связи вершины с другими вершинами }, 'state_name2': {...}, ... 'term_state_name': {...} } Данный словарь заполняется во время парсинга adot-файла. Не зависит от режима парсинга: c генарацией cpp или без.
parent b86dcefc
import collections import collections
import importlib as imp
import os import os
from enum import Enum, auto from enum import Enum, auto
from functools import partial from functools import partial
import importlib as imp
import pycomsdk.comsdk.comaux as aux import pycomsdk.comsdk.comaux as aux
ImplicitParallelizationInfo = collections.namedtuple('ImplicitParallelizationInfo', ['array_keys_mapping', 'branches_number', 'branch_i']) ImplicitParallelizationInfo = collections.namedtuple('ImplicitParallelizationInfo',
['array_keys_mapping', 'branches_number', 'branch_i'])
class Func(): class Func():
__slots__ = ( __slots__ = (
...@@ -16,42 +17,45 @@ class Func(): ...@@ -16,42 +17,45 @@ class Func():
'comment', 'comment',
'name' 'name'
) )
def __init__(self, module="", name="", dummy=False,func=None, comment=''):
def __init__(self, module="", name="", dummy=False, func=None, comment=''):
self.module = module self.module = module
self.name = name self.name = name
self.comment=comment.replace("\0", " ") if comment is not None else "" self.comment = comment.replace("\0", " ") if comment is not None else ""
if module =="" or name =="" or module is None or name is None: if module == "" or name == "" or module is None or name is None:
dummy = True dummy = True
if func is not None: if func is not None:
self.func = func self.func = func
elif dummy: elif dummy:
self.func = lambda data: data self.func = lambda data: data
else: else:
print("LOADING function {} from {} module".format(name, module) ) print("LOADING function {} from {} module".format(name, module))
try: try:
self.func = getattr(imp.import_module(module), name) self.func = getattr(imp.import_module(module), name)
except Exception: except Exception:
raise Exception("Could not load function {} from {} module".format(name, module)) raise Exception("Could not load function {} from {} module".format(name, module))
def __str__(self): def __str__(self):
if self.module =="" or self.name =="": if self.module == "" or self.name == "":
return '' return ''
return "{}_{}".format(self.module, self.name) return "{}_{}".format(self.module, self.name)
class Selector(Func): class Selector(Func):
def __init__(self, ntransf, module="", name="", dummy=False): def __init__(self, ntransf, module="", name="", dummy=False):
if module=="" and name =="": if module == "" and name == "":
dummy = True dummy = True
self.dummy = dummy self.dummy = dummy
super().__init__(module, name, func=(lambda x: [True for i in range(ntransf)]) if dummy else None) super().__init__(module, name, func=(lambda x: [True for i in range(ntransf)]) if dummy else None)
def __str__(self): def __str__(self):
if self.module =="" or self.name =="": if self.module == "" or self.name == "":
return '' return ''
return "{}_{}".format(self.module, self.name) return "{}_{}".format(self.module, self.name)
class Transfer: class Transfer:
def __init__(self, edge, output_state, order=0, comment = None): def __init__(self, edge, output_state, order=0, comment=None):
self.edge = edge self.edge = edge
self.output_state = output_state self.output_state = output_state
self.order = order self.order = order
...@@ -60,10 +64,12 @@ class Transfer: ...@@ -60,10 +64,12 @@ class Transfer:
self.edge.morph(data, dynamic_keys_mapping) self.edge.morph(data, dynamic_keys_mapping)
return self.output_state return self.output_state
class IdleRunType(Enum): class IdleRunType(Enum):
INIT = auto() INIT = auto()
CLEANUP = auto() CLEANUP = auto()
class PluralState: class PluralState:
def __init__(self, states): def __init__(self, states):
self.states = states self.states = states
...@@ -73,10 +79,12 @@ class PluralState: ...@@ -73,10 +79,12 @@ class PluralState:
for init_state, term_state in zip(self.states, term_states): for init_state, term_state in zip(self.states, term_states):
init_state.transfers.append(Transfer(edge, term_state)) init_state.transfers.append(Transfer(edge, term_state))
class Graph: class Graph:
''' '''
Class describing a graph-based computational method. Graph execution must start from this object. Class describing a graph-based computational method. Graph execution must start from this object.
''' '''
def __init__(self, init_state, def __init__(self, init_state,
term_state=None, term_state=None,
): ):
...@@ -100,15 +108,15 @@ class Graph: ...@@ -100,15 +108,15 @@ class Graph:
cur_state = self.init_state cur_state = self.init_state
implicit_parallelization_info = None implicit_parallelization_info = None
while cur_state is not None: while cur_state is not None:
# print('1) In main loop', implicit_parallelization_info) # print('1) In main loop', implicit_parallelization_info)
# morph = _run_state(cur_state, data, implicit_parallelization_info) # morph = _run_state(cur_state, data, implicit_parallelization_info)
transfer_f, 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) # print('2) In main loop', implicit_parallelization_info)
if '__EXCEPTION__' in data: if '__EXCEPTION__' in data:
return False return False
# cur_state, implicit_parallelization_info = morph(data) # cur_state, implicit_parallelization_info = morph(data)
cur_state = transfer_f(data) cur_state = transfer_f(data)
# print(morph) # print(morph)
if '__EXCEPTION__' in data: if '__EXCEPTION__' in data:
return False return False
return True return True
...@@ -124,12 +132,10 @@ class Graph: ...@@ -124,12 +132,10 @@ class Graph:
data['__WORKING_DIR__'] = data['__CURRENT_WORKING_DIR__'] data['__WORKING_DIR__'] = data['__CURRENT_WORKING_DIR__']
class State: class State:
__slots__ = [ __slots__ = [
'name', 'name',
'input_edges_number', #output_edges_number == len(transfers) 'input_edges_number', # output_edges_number == len(transfers)
'looped_edges_number', 'looped_edges_number',
'activated_input_edges_number', 'activated_input_edges_number',
'transfers', 'transfers',
...@@ -141,11 +147,13 @@ class State: ...@@ -141,11 +147,13 @@ class State:
'_proxy_state', '_proxy_state',
'possible_branches', 'possible_branches',
'comment' 'comment'
] ]
def __init__(self, name,
def __init__(self, name,
parallelization_policy=None, parallelization_policy=None,
selector=None, selector=None,
array_keys_mapping=None, # if array_keys_mapping is not None, we have implicit parallelization in this state array_keys_mapping=None,
# if array_keys_mapping is not None, we have implicit parallelization in this state
): ):
self.name = name self.name = name
self.parallelization_policy = SerialParallelizationPolicy() if parallelization_policy is None else parallelization_policy self.parallelization_policy = SerialParallelizationPolicy() if parallelization_policy is None else parallelization_policy
...@@ -155,19 +163,17 @@ class State: ...@@ -155,19 +163,17 @@ class State:
self.looped_edges_number = 0 self.looped_edges_number = 0
self.activated_input_edges_number = 0 self.activated_input_edges_number = 0
self.transfers = [] self.transfers = []
self.possible_branches=[] self.possible_branches = []
self.is_term_state=False self.is_term_state = False
self._branching_states_history = None self._branching_states_history = None
self._proxy_state=None self._proxy_state = None
self.comment = None self.comment = None
def idle_run(self, idle_run_type, branching_states_history): def idle_run(self, idle_run_type, branching_states_history):
def __sort_by_order(tr): def __sort_by_order(tr):
return tr.edge.order return tr.edge.order
self.transfers.sort(key = __sort_by_order)
# print(self.name) self.transfers.sort(key=__sort_by_order)
# 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: if self._proxy_state is not None:
return self._proxy_state.idle_run(idle_run_type, branching_states_history) return self._proxy_state.idle_run(idle_run_type, branching_states_history)
if idle_run_type == IdleRunType.INIT: if idle_run_type == IdleRunType.INIT:
...@@ -175,7 +181,7 @@ class State: ...@@ -175,7 +181,7 @@ class State:
if self.input_edges_number != 1: if self.input_edges_number != 1:
if self._is_looped_branch(branching_states_history): if self._is_looped_branch(branching_states_history):
self.looped_edges_number += 1 self.looped_edges_number += 1
return # no need to go further if we already were there return # no need to go further if we already were there
if self._branching_states_history is None: if self._branching_states_history is None:
self._branching_states_history = branching_states_history self._branching_states_history = branching_states_history
elif idle_run_type == IdleRunType.CLEANUP: elif idle_run_type == IdleRunType.CLEANUP:
...@@ -186,9 +192,7 @@ class State: ...@@ -186,9 +192,7 @@ class State:
if self._branching_states_history is None: if self._branching_states_history is None:
self._branching_states_history = branching_states_history self._branching_states_history = branching_states_history
else: else:
self.activated_input_edges_number += 1 # BUG: here we need to choose somehow whether we proceed or not self.activated_input_edges_number += 1 # BUG: here we need to choose somehow whether we proceed or not
# if len(self.transfers) == 0:
# print('Terminate state found')
if len(self.transfers) == 1: if len(self.transfers) == 1:
self.transfers[0].output_state.idle_run(idle_run_type, branching_states_history) self.transfers[0].output_state.idle_run(idle_run_type, branching_states_history)
else: else:
...@@ -201,26 +205,23 @@ class State: ...@@ -201,26 +205,23 @@ class State:
self.comment = comment self.comment = comment
self.transfers.append(Transfer(edge, term_state)) self.transfers.append(Transfer(edge, term_state))
self.selector = Selector(len(self.transfers)) self.selector = Selector(len(self.transfers))
# edge.set_output_state(term_state)
# self.output_edges.append(edge)
def replace_with_graph(self, graph): def replace_with_graph(self, graph):
self._proxy_state = graph.init_state self._proxy_state = graph.init_state
graph.term_state.transfers = self.transfers graph.term_state.transfers = self.transfers
graph.term_state.selector = self.selector graph.term_state.selector = self.selector
def run(self, data, implicit_parallelization_info=None): def run(self, data, implicit_parallelization_info=None):
print('STATE {}\n\tjust entered, implicit_parallelization_info: {}'.format(self.name, implicit_parallelization_info)) print('STATE {}\n\tjust entered, implicit_parallelization_info: {}'.format(self.name,
# print('\t{}'.format(data)) implicit_parallelization_info))
if self._proxy_state is not None: if self._proxy_state is not None:
return self._proxy_state.run(data, implicit_parallelization_info) return self._proxy_state.run(data, implicit_parallelization_info)
self._activate_input_edge(implicit_parallelization_info) self._activate_input_edge(implicit_parallelization_info)
#self.activated_input_edges_number += 1 print('\trequired input: {}, active: {}, looped: {}'.format(self.input_edges_number,
print('\trequired input: {}, active: {}, looped: {}'.format(self.input_edges_number, self.activated_input_edges_number, self.looped_edges_number)) self.activated_input_edges_number,
# print('qwer') self.looped_edges_number))
if not self._ready_to_transfer(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) 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) self._reset_activity(implicit_parallelization_info)
if self.is_term_state: if self.is_term_state:
implicit_parallelization_info = None implicit_parallelization_info = None
...@@ -231,16 +232,20 @@ class State: ...@@ -231,16 +232,20 @@ class State:
if not selected_edges: if not selected_edges:
raise GraphUnexpectedTermination( raise GraphUnexpectedTermination(
"STATE {}: error in selector: {} ".format(self.name, selected_edges)) "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] selected_transfers = [self.transfers[i] for i, _ in enumerate(selected_edges) if selected_edges[i] == True]
for transf in selected_transfers: for transf in selected_transfers:
if not transf.edge.predicate(data, dynamic_keys_mapping): 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)) 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, return self.parallelization_policy.make_transfer_func(selected_transfers,
array_keys_mapping=self.array_keys_mapping, array_keys_mapping=self.array_keys_mapping,
implicit_parallelization_info=implicit_parallelization_info, state=self), \ implicit_parallelization_info=implicit_parallelization_info,
state=self), \
implicit_parallelization_info implicit_parallelization_info
def _activate_input_edge(self, implicit_parallelization_info=None): def _activate_input_edge(self, implicit_parallelization_info=None):
if implicit_parallelization_info is None or self.is_term_state: if implicit_parallelization_info is None or self.is_term_state:
self.activated_input_edges_number += 1 self.activated_input_edges_number += 1
...@@ -255,16 +260,17 @@ class State: ...@@ -255,16 +260,17 @@ class State:
if self.is_term_state: if self.is_term_state:
required_activated_input_edges_number = implicit_parallelization_info.branches_number required_activated_input_edges_number = implicit_parallelization_info.branches_number
return self.activated_input_edges_number == required_activated_input_edges_number return self.activated_input_edges_number == required_activated_input_edges_number
return self.activated_input_edges_number[implicit_parallelization_info.branch_i] == required_activated_input_edges_number return self.activated_input_edges_number[
implicit_parallelization_info.branch_i] == required_activated_input_edges_number
else: else:
return self.activated_input_edges_number == required_activated_input_edges_number return self.activated_input_edges_number == required_activated_input_edges_number
# if implicit_parallelization_info is None or self.is_term_state: # if implicit_parallelization_info is None or self.is_term_state:
# if self.is_term_state: # if self.is_term_state:
# required_activated_input_edges_number = implicit_parallelization_info.branches_number # required_activated_input_edges_number = implicit_parallelization_info.branches_number
# return self.activated_input_edges_number == required_activated_input_edges_number # return self.activated_input_edges_number == required_activated_input_edges_number
# else: # else:
# return self.activated_input_edges_number[implicit_parallelization_info.branch_i] == required_activated_input_edges_number # return self.activated_input_edges_number[implicit_parallelization_info.branch_i] == required_activated_input_edges_number
def _reset_activity(self, implicit_parallelization_info=None): def _reset_activity(self, implicit_parallelization_info=None):
self._branching_states_history = None self._branching_states_history = None
...@@ -274,7 +280,7 @@ class State: ...@@ -274,7 +280,7 @@ class State:
else: else:
self.activated_input_edges_number[implicit_parallelization_info.branch_i] -= 1 self.activated_input_edges_number[implicit_parallelization_info.branch_i] -= 1
else: else:
# self.activated_input_edges_number = 0 # self.activated_input_edges_number = 0
if implicit_parallelization_info is None or self.is_term_state: if implicit_parallelization_info is None or self.is_term_state:
self.activated_input_edges_number = 0 self.activated_input_edges_number = 0
else: else:
...@@ -290,23 +296,25 @@ class State: ...@@ -290,23 +296,25 @@ class State:
def transfer_to_termination(data): def transfer_to_termination(data):
return None return None
class SerialParallelizationPolicy: class SerialParallelizationPolicy:
# def __init__(self, data): # def __init__(self, data):
# self.data = data # self.data = data
def __init__(self): def __init__(self):
pass pass
def make_transfer_func(self, morphisms, array_keys_mapping=None, implicit_parallelization_info=None, state=None): def make_transfer_func(self, morphisms, array_keys_mapping=None, implicit_parallelization_info=None, state=None):
def _morph(data): def _morph(data):
# print("MORPHING FROM {}".format(state.name))
if array_keys_mapping is None: if array_keys_mapping is None:
dynamic_keys_mapping = build_dynamic_keys_mapping(implicit_parallelization_info) dynamic_keys_mapping = build_dynamic_keys_mapping(implicit_parallelization_info)
next_morphs = [partial(morphism.transfer, 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] next_impl_para_infos = [implicit_parallelization_info for _ in morphisms]
# print('\t\t {}'.format(implicit_parallelization_infos))
else: else:
if len(morphisms) != 1: if len(morphisms) != 1:
raise BadGraphStructure('Impossible to create implicit paralleilzation in the state with {} output edges'.format(len(morphisms))) 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) dynamic_keys_mapping = build_dynamic_keys_mapping(implicit_parallelization_info)
proxy_data = aux.ProxyDict(data, keys_mappings=array_keys_mapping) proxy_data = aux.ProxyDict(data, keys_mappings=array_keys_mapping)
anykey = next(iter(array_keys_mapping.keys())) anykey = next(iter(array_keys_mapping.keys()))
...@@ -314,49 +322,53 @@ class SerialParallelizationPolicy: ...@@ -314,49 +322,53 @@ class SerialParallelizationPolicy:
next_morphs = [] next_morphs = []
next_impl_para_infos = [] next_impl_para_infos = []
for branch_i in range(implicit_branches_number): for branch_i in range(implicit_branches_number):
implicit_parallelization_info_ = ImplicitParallelizationInfo(array_keys_mapping, implicit_branches_number, branch_i) implicit_parallelization_info_ = ImplicitParallelizationInfo(array_keys_mapping,
implicit_branches_number, branch_i)
dynamic_keys_mapping = build_dynamic_keys_mapping(implicit_parallelization_info_) dynamic_keys_mapping = build_dynamic_keys_mapping(implicit_parallelization_info_)
# print(dynamic_keys_mapping)
next_morphs.append(partial(morphisms[0].morph, dynamic_keys_mapping=dynamic_keys_mapping)) next_morphs.append(partial(morphisms[0].morph, dynamic_keys_mapping=dynamic_keys_mapping))
next_impl_para_infos.append(implicit_parallelization_info_) next_impl_para_infos.append(implicit_parallelization_info_)
cur_morphs = [] cur_morphs = []
cur_impl_para_infos = [] cur_impl_para_infos = []
#while len(next_morphs) != 1 or _is_implicitly_parallelized(next_impl_para_infos): # 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): while len(next_morphs) != 1 or _requires_joint_of_implicit_parallelization(array_keys_mapping,
next_impl_para_infos):
if next_impl_para_infos == []: if next_impl_para_infos == []:
raise Exception("Morphs count on state {} is {}".format(state.name, 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) # print(array_keys_mapping, next_impl_para_infos)
cur_morphs[:] = next_morphs[:] cur_morphs[:] = next_morphs[:]
cur_impl_para_infos[:] = next_impl_para_infos[:] cur_impl_para_infos[:] = next_impl_para_infos[:]
del next_morphs[:] del next_morphs[:]
del next_impl_para_infos[:] del next_impl_para_infos[:]
for morph, impl_para_info in zip(cur_morphs, cur_impl_para_infos): for morph, impl_para_info in zip(cur_morphs, cur_impl_para_infos):
next_state = morph(data) next_state = morph(data)
# print('\t next_state: {}, with impl para info: {}'.format(next_state.name, impl_para_info)) # print('\t next_state: {}, with impl para info: {}'.format(next_state.name, impl_para_info))
if next_state is None: if next_state is None:
return None return None
next_morph, next_impl_para_info = _run_state(next_state, data, impl_para_info) next_morph, next_impl_para_info = _run_state(next_state, data, impl_para_info)
# print('\t next_morph: {}'.format(next_morph)) # print('\t next_morph: {}'.format(next_morph))
if '__EXCEPTION__' in data: if '__EXCEPTION__' in data:
return None return None
if next_morph is not None: if next_morph is not None:
next_morphs.append(next_morph) next_morphs.append(next_morph)
next_impl_para_infos.append(next_impl_para_info) next_impl_para_infos.append(next_impl_para_info)
# print(array_keys_mapping, next_impl_para_infos) # print(array_keys_mapping, next_impl_para_infos)
#print(len(next_morphs)) # print(len(next_morphs))
# print('\t last morph: {}'.format(next_morphs[0])) # print('\t last morph: {}'.format(next_morphs[0]))
next_state = next_morphs[0](data) next_state = next_morphs[0](data)
# print(next_state.name, next_impl_para_infos[0]) # print(next_state.name, next_impl_para_infos[0])
return next_state return next_state
return _morph return _morph
class BadGraphStructure(Exception): class BadGraphStructure(Exception):
pass pass
class GraphUnexpectedTermination(Exception): class GraphUnexpectedTermination(Exception):
pass pass
def _requires_joint_of_implicit_parallelization(array_keys_mapping, impl_para_infos): def _requires_joint_of_implicit_parallelization(array_keys_mapping, impl_para_infos):
if array_keys_mapping is None: if array_keys_mapping is None:
return False return False
...@@ -365,10 +377,12 @@ def _requires_joint_of_implicit_parallelization(array_keys_mapping, impl_para_in ...@@ -365,10 +377,12 @@ def _requires_joint_of_implicit_parallelization(array_keys_mapping, impl_para_in
return True return True
return False return False
def _get_trues(boolean_list): def _get_trues(boolean_list):
return [i for i, val in enumerate(boolean_list) if val == True] return [i for i, val in enumerate(boolean_list) if val == True]
#def _run_state(state, data, implicit_parallelization_info=None):
# def _run_state(state, data, implicit_parallelization_info=None):
# try: # try:
# next_morphism = state.run(data, implicit_parallelization_info) # next_morphism = state.run(data, implicit_parallelization_info)
# except GraphUnexpectedTermination as e: # except GraphUnexpectedTermination as e:
...@@ -391,4 +405,4 @@ def build_dynamic_keys_mapping(implicit_parallelization_info=None): ...@@ -391,4 +405,4 @@ def build_dynamic_keys_mapping(implicit_parallelization_info=None):
dynamic_keys_mapping = {} dynamic_keys_mapping = {}
for key, keys_path in implicit_parallelization_info.array_keys_mapping.items(): for key, keys_path in implicit_parallelization_info.array_keys_mapping.items():
dynamic_keys_mapping[key] = aux.ArrayItemGetter(keys_path, implicit_parallelization_info.branch_i) dynamic_keys_mapping[key] = aux.ArrayItemGetter(keys_path, implicit_parallelization_info.branch_i)
return dynamic_keys_mapping return dynamic_keys_mapping
\ No newline at end of file
...@@ -6,7 +6,7 @@ from pycomsdk.comsdk.edge import Edge ...@@ -6,7 +6,7 @@ from pycomsdk.comsdk.edge import Edge
from pycomsdk.comsdk.graph import Graph, Func, State, Selector from pycomsdk.comsdk.graph import Graph, Func, State, Selector
class Params(): class Params:
__slots__ = ( __slots__ = (
'module', 'module',
'entry_func', 'entry_func',
...@@ -33,28 +33,42 @@ class Params(): ...@@ -33,28 +33,42 @@ class Params():
# entities = {} # entities = {}
class GraphFactory(): class GraphFactory:
__slots__ = ( __slots__ = (
'name', 'name',
'states', 'states',
'graph', 'graph',
'issub', 'issub',
'tocpp', 'tocpp',
'entities' 'entities',
'graph_structure'
) )
def __init__(self, tocpp=False): def __init__(self, tocpp=False):
"""
Функция инициализации. Существует два режима конфигурации:
1) Без генерации cpp-кода
2) Генерация cpp-кода
:param tocpp: переключатель режима работы фабрики
"""
self.states = {} self.states = {}
self.entities = {} self.entities = {}
self.tocpp = tocpp self.tocpp = tocpp
self.name = None self.name = None
self.issub = False self.issub = False
self.graph_structure = {} # dict-representation of graph
def add_state(self, statename): def add_state(self, statename):
if statename not in self.states: if statename not in self.states:
self.states[statename] = State(statename) self.states[statename] = State(statename)
if statename in self.entities: if statename in self.entities:
self.states[statename].comment = self.entities[statename].comment self.states[statename].comment = self.entities[statename].comment
self.graph_structure.update({statename: {
'subgraph': None,
'connect_to': [],
'graph_name': self.name
}})
def _create_morphism(self, morphname=None): def _create_morphism(self, morphname=None):
comment = "" comment = ""
...@@ -91,6 +105,11 @@ class GraphFactory(): ...@@ -91,6 +105,11 @@ class GraphFactory():
def add_connection(self, st1, st2, morphism=None, ordr=0): def add_connection(self, st1, st2, morphism=None, ordr=0):
pred, entr, comm = self._create_morphism(morphism) pred, entr, comm = self._create_morphism(morphism)
self.states[st1].connect_to(self.states[st2], edge=Edge(pred, entr, order=ordr, comment=comm)) self.states[st1].connect_to(self.states[st2], edge=Edge(pred, entr, order=ordr, comment=comm))
self.graph_structure[st1]['connect_to'].append({
'next': st2,
'pred_f': str(pred),
'morph_f': str(entr),
})
print("{} -> {}".format(st1, st2)) print("{} -> {}".format(st1, st2))
def build(self, nsub): def build(self, nsub):
...@@ -123,15 +142,22 @@ class GraphFactory(): ...@@ -123,15 +142,22 @@ class GraphFactory():
else: else:
self.states[s].selector = Selector(len(self.states[s].transfers)) self.states[s].selector = Selector(len(self.states[s].transfers))
if s in self.entities and self.entities[s].subgraph is not None: if s in self.entities and self.entities[s].subgraph is not None:
# print(s + " is subgraph")
print("Replacing state {} with subgraph {}".format(s, self.entities[s].subgraph)) print("Replacing state {} with subgraph {}".format(s, self.entities[s].subgraph))
parsr = Parser(subgraph=True, tocpp=self.tocpp) parsr = Parser(subgraph=True, tocpp=self.tocpp)
subgr = parsr.parse_file(self.entities[s].subgraph) subgr = parsr.parse_file(self.entities[s].subgraph)
self.states[s].replace_with_graph(subgr) self.states[s].replace_with_graph(subgr)
self.graph_structure[s]['subgraph'] = {
'graph': parsr.fact.graph_structure,
'init_state': subgr.init_state.name,
'term_state': subgr.term_state.name,
'subgraph_name': parsr.fact.name
}
self.graph = Graph(self.graph.init_state, self.graph.term_state) self.graph = Graph(self.graph.init_state, self.graph.term_state)
return self.graph return self.graph
class Parser(): class Parser:
__slots__ = ( __slots__ = (
'fact', 'fact',
'issub' 'issub'
...@@ -462,7 +488,6 @@ class _Bush(): ...@@ -462,7 +488,6 @@ class _Bush():
res = "" res = ""
for tr in self.branches[i]: for tr in self.branches[i]:
edge = tr.edge edge = tr.edge
print(tr.output_state.name)
if edge.comment != "": if edge.comment != "":
res += "\t//{}\n".format(edge.comment) res += "\t//{}\n".format(edge.comment)
if edge.pred_f.name != "": if edge.pred_f.name != "":
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment