diff --git a/rs/context_automaton.py b/rs/context_automaton.py index f99fb71..68277c3 100644 --- a/rs/context_automaton.py +++ b/rs/context_automaton.py @@ -9,7 +9,8 @@ class ContextAutomaton(object): self._init_state = None self._reaction_system = reaction_system self._name = "" - + self._prod_entities = set() + @property def states(self): return self._states @@ -18,6 +19,14 @@ class ContextAutomaton(object): def transitions(self): return self._transitions + @property + def prod_entities(self): + return self._prod_entities + + @property + def reaction_system(self): + return self._reaction_system + @property def name(self): return self._name @@ -101,6 +110,8 @@ class ContextAutomaton(object): new_context_set = set() for e in set(context_set): new_context_set.add(self._reaction_system.get_entity_id(e)) + + self._prod_entities |= new_context_set self._transitions.append((self.get_state_id(src),new_context_set,self.get_state_id(dst))) @@ -140,8 +151,14 @@ class ContextAutomaton(object): name_string = ": " + colour_str(C_BOLD, self.name) print(C_MARK_INFO + " Context automaton" + name_string) + def show_prod_entities(self): + print(C_MARK_INFO + " Context automaton possible products:") + for entity in self._prod_entities: + print(" - " + self._reaction_system.get_entity_name(entity)) + def show(self): self.show_header() self.show_states() self.show_transitions() + self.show_prod_entities() diff --git a/rs/extended_context_automaton.py b/rs/extended_context_automaton.py index 0fe1757..870226d 100644 --- a/rs/extended_context_automaton.py +++ b/rs/extended_context_automaton.py @@ -4,15 +4,52 @@ from colour import * from rs.context_automaton import ContextAutomaton class ExtendedContextAutomaton(ContextAutomaton): - """Extended Context Automaton""" + """Extended Context Automaton + + Supports transitions with actions. + + Each transitions is additionally guarded with + reactants and inhibitors. + + The provided context entities are the products + of the reactions labelling the transition taken. + """ + def __init__(self, reaction_system): - self._actions = [] super(ExtendedContextAutomaton, self).__init__(reaction_system) + self._actions = [] + self._transitions_for_products = dict() + self._actions_for_products = dict() @property def number_of_actions(self): return len(self._actions) + @property + def actions(self): + return self._actions + + def has_action(self, action): + """Checks if the automaton supports a given action""" + + return action in self._actions + + def get_transitions_producing_entity(self, entity): + """Returns the transitions that produce a given entity""" + + if entity in self._transitions_for_products: + return self._transitions_for_products[entity] + else: + return [] + + def get_actions_producing_entity(self, entity): + """Returns the actions that produce a given entity""" + + if entity in self._actions_for_products: + return self._actions_for_products[entity] + else: + return set() + def add_transition(self, src, actions, ctx_reaction, dst): """Adds a transition @@ -49,10 +86,21 @@ class ExtendedContextAutomaton(ContextAutomaton): i_ids = self.get_set_of_ids(ctx_inhibitors) p_ids = self.get_set_of_ids(ctx_products) - self._transitions.append((src_id, act_ids, (r_ids, i_ids, p_ids), dst_id)) + new_transition = (src_id, act_ids, (r_ids, i_ids, p_ids), dst_id) + + for product_id in p_ids: + self._transitions_for_products.setdefault(product_id, []) + self._transitions_for_products[product_id].append(new_transition) + self._actions_for_products.setdefault(product_id, set()) + self._actions_for_products[product_id] |= set(actions) + + self._prod_entities |= p_ids + + self._transitions.append(new_transition) def show_transitions(self): """Prints the set of registered transitions""" + print(C_MARK_INFO + " Context automaton transitions:") for src_id, act_id, reaction, dst_id in self._transitions: str_transition = self.get_state_name(src_id) + " --( " @@ -63,6 +111,7 @@ class ExtendedContextAutomaton(ContextAutomaton): def add_action(self, action_name): """Registers an action""" + if action_name not in self._actions: self._actions.append(action_name) else: @@ -70,6 +119,7 @@ class ExtendedContextAutomaton(ContextAutomaton): def get_action_id(self, action_name): """For an action name returns its id""" + try: return self._actions.index(action_name) except ValueError: @@ -81,6 +131,7 @@ class ExtendedContextAutomaton(ContextAutomaton): def get_set_of_action_ids(self, actions): """Converts a set of actions into the set of their ids""" + act_ids = set() for act in actions: act_ids.add(self.get_action_id(act)) @@ -88,6 +139,7 @@ class ExtendedContextAutomaton(ContextAutomaton): def get_actions_str(self, actions): """Returns the string for the set of action ids given by actions""" + s = "" for act in actions: s += self.get_action_name(act) + ", " @@ -96,6 +148,7 @@ class ExtendedContextAutomaton(ContextAutomaton): def show_actions(self): """Prints all the actions""" + print(C_MARK_INFO + " Context automaton actions:") for act in self._actions: print(" - " + act + " (id=" + str(self.get_action_id(act)) + ")") @@ -103,3 +156,4 @@ class ExtendedContextAutomaton(ContextAutomaton): def show(self): super(ExtendedContextAutomaton, self).show() self.show_actions() + diff --git a/rs/network_of_context_automata.py b/rs/network_of_context_automata.py index 51ab4ea..86b1931 100644 --- a/rs/network_of_context_automata.py +++ b/rs/network_of_context_automata.py @@ -1,18 +1,100 @@ from sys import exit +from colour import * class NetworkOfContextAutomata(object): - def __init__(self, context_automata): - self.automata = list(context_automata) + def __init__(self, reaction_system, context_automata): + self.automata = [] + self._reaction_system = reaction_system + self._actions = set() + self._prod_entities = set() + self._automata_for_actions = dict() + self._actions_for_products = dict() + + if len(context_automata) < 1: + print("Context automata network must contain at least one automaton!") + exit(1) + + for automaton in context_automata: + self.add(automaton) + + self.sanity_check() @property def number_of_automata(self): return len(self.automata) + @property + def reaction_system(self): + return self._reaction_system + + @property + def prod_entities(self): + """Returns the set of entities that can potentially be produced by the automata in the network""" + return self._prod_entities + + def sanity_check(self): + """Performs a sanity check of the network of automata""" + + for automaton in self.automata: + if automaton.reaction_system != self._reaction_system: + print_error("Mismatching reaction system used in \"" + str(automaton.name) + "\"!!!") + exit(1) + + def show_prod_entities(self): + print(C_MARK_INFO + " Possible context-products for the network of automata:") + for entity in self.prod_entities: + print(" - " + self._reaction_system.get_entity_name(entity)) + + def show_actions(self): + print(C_MARK_INFO + " Actions of the network:") + for action in self._actions: + print(" - " + action) + + def register_action(self, action, aut): + """Associates an action with an automaton""" + + self._automata_for_actions.setdefault(action, set()) + aut_index = self.automata.index(aut) + self._automata_for_actions[action].add(aut_index) + + def get_actions_producing_entity(self, entity): + """Returns the set of actions producing an entity""" + + if entity in self._actions_for_products: + return self._actions_for_products[entity] + else: + return set() + + def get_automata_with_action(self, action): + """Returns the set of automata that support an action""" + + if action in self._automata_for_actions: + return self._automata_for_actions[action] + else: + return set() + + def add(self, aut): + """Adds an automaton to the network""" + + self.automata.append(aut) + self._prod_entities |= aut.prod_entities + self._actions |= set(aut.actions) + + for action in aut.actions: + self.register_action(action, aut) + + for entity in aut.prod_entities: + self._actions_for_products.setdefault(entity, set()) + self._actions_for_products[entity] |= aut.get_actions_producing_entity(entity) + def show(self): + print() + print(C_MARK_INFO + " NETWORK OF CONTEXT AUTOMATA") for ca in self.automata: print() ca.show() - - def add(self, aut): - self.automata.append(aut) + print() + self.show_prod_entities() + self.show_actions() + \ No newline at end of file diff --git a/rs/reaction_system.py b/rs/reaction_system.py index 1ea8293..42c8bc9 100644 --- a/rs/reaction_system.py +++ b/rs/reaction_system.py @@ -15,6 +15,14 @@ class ReactionSystem(object): self.init_contexts = [] self.context_entities = [] + @property + def background_set_size(self): + return len(self.background_set) + + @property + def set_of_bgset_ids(self): + return set(range(self.background_set_size)) + def assume_not_in_bgset(self, name): if self.is_in_background_set(name): raise RuntimeError("The entity " + name + " is already on the list") diff --git a/rs_testing.py b/rs_testing.py index 929e61c..14d21c1 100644 --- a/rs_testing.py +++ b/rs_testing.py @@ -12,6 +12,8 @@ def test_extended_automaton(): r = ReactionSystem() r.add_bg_set_entity("inc") r.add_bg_set_entity("dec") + r.add_bg_set_entity("decx") + c1 = ExtendedContextAutomaton(r) c1.add_init_state("init") @@ -19,19 +21,44 @@ def test_extended_automaton(): c1.add_state("working") c1.add_action("act1") c1.add_action("act2") - c1.add_transition("init", ["act1", "act2"], ([],[],["inc"]), "working") + c1.add_transition("init", ["act1", "act2"], ([],[],["inc","dec"]), "working") c1.add_transition("working", ["act2"], ([],[],["inc"]), "working") c2 = ExtendedContextAutomaton(r) c2.add_init_state("init") - c2.name = "cxxxx" + c2.name = "c2" c2.add_state("working") c2.add_action("act1") c2.add_action("act2") c2.add_transition("init", ["act1", "act2"], ([],[],["inc"]), "working") c2.add_transition("working", ["act2"], ([],[],["inc"]), "working") + + c3 = ExtendedContextAutomaton(r) + c3.add_init_state("init") + c3.name = "c3" + c3.add_state("working") + c3.add_action("act1") + c3.add_transition("init", ["act1"], ([],[],["inc"]), "working") + # + # c4 = ExtendedContextAutomaton(r) + # c4.add_init_state("init") + # c4.name = "c4" + # c4.add_state("working") + # c4.add_action("act1") + # c4.add_action("act42") + # c4.add_transition("init", ["act1", "act42"], ([],[],["inc"]), "working") + # c4.add_transition("working", ["act42"], ([],[],["inc"]), "working") + # + # c5 = ExtendedContextAutomaton(r) + # c5.add_init_state("init") + # c5.name = "c5" + # c5.add_state("working") + # c5.add_action("act1") + # c5.add_action("act2") + # c5.add_transition("init", ["act1", "act2"], ([],[],["inc"]), "working") + # c5.add_transition("working", ["act2"], ([],[],["inc"]), "working") - na = NetworkOfContextAutomata([c1,c2]) + na = NetworkOfContextAutomata(r, [c1,c2,c3]) rna = ReactionSystemWithNetworkOfAutomata(r,na) diff --git a/rssmt.py b/rssmt.py index 735b0ac..d3b9a2d 100755 --- a/rssmt.py +++ b/rssmt.py @@ -24,8 +24,8 @@ version = "2016/12/28/00" rsmc_banner = """ Reaction Systems SMT-Based Model Checking -Version: """ + version + """ -Author: Artur Męski / +Version: """ + version + """ +Author: Artur Męski / """ ################################################################## diff --git a/smt/smt_checker_rs_na.py b/smt/smt_checker_rs_na.py index 55e1ff6..3905eb5 100644 --- a/smt/smt_checker_rs_na.py +++ b/smt/smt_checker_rs_na.py @@ -59,45 +59,26 @@ class SmtCheckerRSNA(SmtCheckerRS): def enc_transition_relation(self, level): return simplify(And(self.enc_rs_trans(level), self.enc_automaton_trans(level))) - - def enc_automaton_single_trans(self, level, transition): - src,actions,ctx_reaction,dst = transition - - src_enc = self.ca_state[level] == src - dst_enc = self.ca_state[level+1] == dst - - all_ent = set(range(len(self.rs.background_set))) - incl_ctx = ctx - excl_ctx = all_ent - incl_ctx - - ctx_enc = True - - for c in incl_ctx: - ctx_enc = simplify(And(ctx_enc, self.v_ctx[level][c])) - for c in excl_ctx: - ctx_enc = simplify(And(ctx_enc, Not(self.v_ctx[level][c]))) - - enc_single_trans = simplify(And(src_enc, ctx_enc, dst_enc)) - - return enc_single_trans - - def enc_single_automaton_trans(self, level, automaton): - - enc_aut_trans = False - for transition in automaton.transitions: - enc_aut_trans = simplify(Or(enc_aut_trans, self.enc_automaton_single_trans(level, transition))) - - return enc_aut_trans - def enc_automaton_trans(self, level): """Encodes the transition relation for the context automaton""" - enc_canet = True - for aut in self.canet: - enc_canet = simplify(And(enc_canet, self.enc_single_automaton_trans(level, aut))) + enc_trans = True + + prod_context = self.canet.prod_entities + never_produced_context = self.rs.set_of_bgset_ids - prod_context + + # producible entities: + for ent in prod_context: + actions_producing_ent = self.canet.get_actions_producing_entity(ent) + for act in actions_producing_ent: + automata_with_act = self.canet.get_automata_with_action(act) + for aut_id in automata_with_act: + aut = self.canet.automata[aut_id] - return enc_canet + # entities that are never produced: + + return enc_trans def check_reachability(self, state, print_witness=True, print_time=True, print_mem=True): @@ -108,4 +89,6 @@ class SmtCheckerRSNA(SmtCheckerRS): self.prepare_all_variables() self.prepare_all_variables() self.prepare_all_variables() + + print(self.enc_automaton_trans(0))