Beispiel #1
0
    def extract_mutex_rules(typeset: Typeset, output=None) -> Union[Atom, Tuple[List[str], Typeset]]:
        """Extract Mutex rules from the Formula"""

        rules_str = []
        rules_typeset = Typeset()

        for mutex_group in typeset.mutex_types:
            or_elements = []
            if len(mutex_group) > 1:
                for mutex_type in mutex_group:
                    neg_group = mutex_group.symmetric_difference({mutex_type})
                    and_elements = [mutex_type.name]
                    for elem in neg_group:
                        and_elements.append(Logic.not_(elem.name))
                    or_elements.append(Logic.and_(and_elements, brackets=True))
                rules_str.append(Logic.g_(Logic.or_(or_elements, brackets=False)))
                rules_typeset |= Typeset(mutex_group)

        if len(rules_str) == 0:
            return None

        if output is not None and output == FormulaOutput.ListCNF:
            return rules_str, rules_typeset

        return Atom(formula=(Logic.and_(rules_str, brackets=True), rules_typeset), kind=AtomKind.MUTEX_RULE)
Beispiel #2
0
    def context_active_rules(typeset: Typeset, output=None) -> Union[Atom, Tuple[List[str], Typeset]]:
        """Extract Liveness rules from the Formula"""

        rules_str = []
        rules_typeset = Typeset()

        inputs, outs = typeset.extract_inputs_outputs()

        active_context_types = []
        for t in inputs:
            if isinstance(t, Boolean):
                if t.kind == TypeKinds.ACTIVE or t.kind == TypeKinds.CONTEXT:
                    active_context_types.append(t.name)
                rules_typeset |= Typeset({t})

        if len(active_context_types) > 0:
            rules_str.append(Logic.g_(Logic.and_(active_context_types)))

        if len(rules_str) == 0:
            return None

        if output is not None and output == FormulaOutput.ListCNF:
            return rules_str, rules_typeset

        return Atom(formula=(Logic.and_(rules_str, brackets=True), rules_typeset), kind=AtomKind.LIVENESS_RULE)
Beispiel #3
0
    def and_(formulae: List[Tuple[str, Typeset]],
             brackets: bool = False) -> Tuple[str, Typeset]:
        """Returns an Tuple[str, Typeset] formula representing the logical AND of list_propoositions"""
        if len(formulae) > 1:

            propositions = [formula[0] for formula in formulae]
            typesets = [formula[1] for formula in formulae]

            if "FALSE" in propositions:
                return "FALSE", Typeset()
            """Remove all TRUE elements"""
            propositions = list(filter("TRUE".__ne__, propositions))
            if len(propositions) == 0:
                return "TRUE", Typeset()

            conj = ' & '.join(propositions)
            typeset = Typeset()
            for t in typesets:
                typeset |= t
            if brackets:
                return f"({conj})", typeset
            else:
                return conj, typeset

        elif len(formulae) == 1:
            return formulae[0]
        else:
            raise Exception("List of propositions is empty")
Beispiel #4
0
    def __init__(self,
                 actions: Set[Types] = None,
                 locations: Set[Types] = None,
                 sensors: Set[Types] = None,
                 contexts: Set[Types] = None):
        super().__init__()

        self.__typeset = Typeset(actions | locations | sensors | contexts
                                 | {Active()})

        for name, elem in self.__typeset.items():
            super(World, self).__setitem__(name, elem.to_atom())
            super(World, self).__setitem__(f"!{name}", ~elem.to_atom())

        self.__rules: Set[Rule] = set()
Beispiel #5
0
    def process_bin_input(
            pre: Union[Specification, Boolean],
            post: Union[Specification, Boolean]) -> Tuple[Typeset, str, str]:

        new_typeset = Typeset()

        if isinstance(pre, Boolean):
            new_typeset |= pre
            pre = pre.name
        elif isinstance(pre, Specification):
            new_typeset |= pre.typeset
            pre = pre.string
        else:
            raise AttributeError

        if isinstance(post, Boolean):
            new_typeset |= post
            post = post.name
        elif isinstance(post, Specification):
            new_typeset |= post.typeset
            post = post.string
        else:
            raise AttributeError

        return new_typeset, pre, post
Beispiel #6
0
    def __init__(self, ltl: LTL):
        variables = Typeset()
        variables |= ltl.variables

        pattern_formula = "G( F(" + ltl.formula() + "))"

        super().__init__(pattern_formula, variables)
Beispiel #7
0
    def or_(formulae: List[Tuple[str, Typeset]],
            brakets: bool = True) -> Tuple[str, Typeset]:
        """Returns an formula formula representing the logical OR of list_propoositions"""
        if len(formulae) > 1:

            propositions = [formula[0] for formula in formulae]
            typesets = [formula[1] for formula in formulae]

            typeset = Typeset()
            for t in typesets:
                typeset |= t

            if "TRUE" in propositions:
                return "TRUE", typeset
            """Remove all FALSE elements"""
            propositions = list(filter("FALSE".__ne__, propositions))

            res = " | ".join(propositions)

            if brakets:
                return f"({res})", typeset
            else:
                return res, typeset

        elif len(formulae) == 1:
            return formulae[0]
        else:
            raise Exception("List of propositions is empty")
Beispiel #8
0
 def __convert_to_nuxmv(typeset: Typeset) -> List[str]:
     tuple_vars = []
     for k, v in typeset.items():
         if isinstance(v, Boolean):
             tuple_vars.append(f"{k}: boolean")
         elif isinstance(v, BoundedInteger):
             tuple_vars.append(f"{k}: {k.min}..{k.max}")
     return tuple_vars
Beispiel #9
0
 def all_entry_locations(self, typeset: Typeset) -> Set[ReachLocation]:
     """List of all locations from where it is possible to reach any of the locations of the controller"""
     reachable_locations = set()
     for location in self.locations:
         """Extracting the locations from where 'first_location_to_visit' is reachable"""
         for class_name in location.adjacency_set:
             for t in typeset.values():
                 if type(t).__name__ == class_name:
                     reachable_locations.add(t)
     return reachable_locations
Beispiel #10
0
    def extract_refinement_rules(typeset: Typeset, output=None) -> Union[Atom, Tuple[List[str], Typeset]]:
        """Extract Refinement rules from the Formula"""

        rules_str = []
        rules_typeset = Typeset()

        for key_type, set_super_types in typeset.super_types.items():
            if isinstance(key_type, Boolean):
                for super_type in set_super_types:
                    rules_str.append(Logic.g_(Logic.implies_(key_type.name, super_type.name)))
                    rules_typeset |= Typeset({key_type})
                    rules_typeset |= Typeset(set_super_types)

        if len(rules_str) == 0:
            return None

        if output is not None and output == FormulaOutput.ListCNF:
            return rules_str, rules_typeset

        return Atom(formula=(Logic.and_(rules_str, brackets=True), rules_typeset), kind=AtomKind.MUTEX_RULE)
Beispiel #11
0
    def extract_adjacency_rules(typeset: Typeset, output=None) -> Union[Atom, Tuple[List[str], Typeset]]:
        """Extract Adjacency rules from the Formula"""

        rules_str = []
        rules_typeset = Typeset()

        for key_type, set_adjacent_types in typeset.adjacent_types.items():
            if isinstance(key_type, Boolean):
                """G(a -> X(b | c | d))"""
                rules_str.append(
                    Logic.g_(Logic.implies_(key_type.name, Logic.x_(Logic.or_([e.name for e in set_adjacent_types])))))
                rules_typeset |= Typeset({key_type})
                rules_typeset |= Typeset(set_adjacent_types)

        if len(rules_str) == 0:
            return None

        if output is not None and output == FormulaOutput.ListCNF:
            return rules_str, rules_typeset

        return Atom(formula=(Logic.and_(rules_str, brackets=True), rules_typeset), kind=AtomKind.ADJACENCY_RULE)
Beispiel #12
0
    def __init__(self, supertypes: Dict[AllTypes, Set[AllTypes]]):
        super().__init__(atom=Atom("TRUE"), kind=FormulaKind.REFINEMENT_RULES)

        for key_type, set_super_types in supertypes.items():
            if isinstance(key_type, Boolean):
                for super_type in set_super_types:
                    f = Logic.g_(Logic.implies_(key_type.name,
                                                super_type.name))
                    t = Typeset({key_type, super_type})
                    new_atom = Atom(formula=(f, t),
                                    kind=AtomKind.REFINEMENT_RULE)
                    self.__iand__(new_atom)
Beispiel #13
0
    def __init__(self,
                 formula: Union[str, Tuple[str, Typeset]] = None,
                 kind: AtomKind = None,
                 check: bool = True,
                 dontcare: bool = False):
        """Atomic Specification (can be an AP, but also an LTL_forced formula that cannot be broken down, e.g. a Pattern)"""

        if kind is None:
            self.__kind = AtomKind.UNDEFINED
        self.__kind = kind

        if self.__kind == AtomKind.REFINEMENT_RULE or \
                self.__kind == AtomKind.ADJACENCY_RULE or \
                self.__kind == AtomKind.MUTEX_RULE:
            self.__spec_kind = SpecKind.RULE
        else:
            self.__spec_kind = SpecKind.UNDEFINED

        """Indicates if the formula is negated"""
        self.__negation: bool = False

        """Indicates if the formula is a dontcare (weather is true or false)"""
        self.__dontcare: bool = dontcare

        """Used for linking guarantees to assumptions"""
        self.__saturation = None

        if formula is None:
            raise AttributeError
        if isinstance(formula, str):
            if formula == "TRUE":
                self.__base_formula: Tuple[str, Typeset] = "TRUE", Typeset()
            elif formula == "FALSE":
                self.__base_formula: Tuple[str, Typeset] = "FALSE", Typeset()
        else:
            self.__base_formula: Tuple[str, Typeset] = formula

            if check and kind != AtomKind.ADJACENCY_RULE and kind != AtomKind.MUTEX_RULE and kind != AtomKind.REFINEMENT_RULE:
                if not self.is_satisfiable():
                    raise AtomNotSatisfiableException(formula=self.__base_formula)
Beispiel #14
0
    def process_unary_input(element: Union[Specification, Boolean]) -> Tuple[str, Typeset]:

        typeset = Typeset()

        if isinstance(element, Boolean):
            input_str = element.name
            typeset |= element
        elif isinstance(element, Specification):
            input_str = element.string
            typeset |= element.typeset
        else:
            raise AttributeError

        return input_str, typeset
Beispiel #15
0
    def process_uni_input(l: Union[Atom, Boolean]) -> Tuple[Typeset, str]:

        new_typeset = Typeset()

        if isinstance(l, Boolean):
            new_typeset |= l
            l = l.name
        elif isinstance(l, Atom):
            new_typeset |= l.typeset
            l = l.string
        else:
            raise AttributeError

        return new_typeset, l
Beispiel #16
0
    def process_bin_contextual_input(
            pre: Union[Atom, Boolean], post: Union[Atom, Boolean],
            context: Union[Atom, Boolean],
            active: Union[Atom,
                          Boolean]) -> Tuple[Typeset, str, str, str, str]:

        new_typeset = Typeset()

        if isinstance(pre, Boolean):
            new_typeset |= pre
            pre = pre.name
        elif isinstance(pre, Atom):
            new_typeset |= pre.typeset
            pre = pre.string
        else:
            raise AttributeError

        if isinstance(post, Boolean):
            new_typeset |= post
            post = post.name
        elif isinstance(post, Atom):
            new_typeset |= post.typeset
            post = post.string
        else:
            raise AttributeError

        if context is not None:
            if isinstance(context, Boolean):
                new_typeset |= context
                context = context.name
            elif isinstance(context, Atom):
                new_typeset |= context.typeset
                context = context.string
            else:
                raise AttributeError
        else:
            context = "TRUE"

        if isinstance(active, Boolean):
            new_typeset |= active
            active = active.name
        elif isinstance(active, Atom):
            new_typeset |= active.typeset
            active = active.string
        else:
            raise AttributeError

        return new_typeset, pre, post, context, active
Beispiel #17
0
    def process_input(ls: Union[Atom, Boolean, List[Atom], List[Boolean]]) -> Tuple[Typeset, List[str]]:

        new_typeset = Typeset()
        formulae_str = []

        if not isinstance(ls, list):
            ls = [ls]
        for i, elem in enumerate(ls):
            if isinstance(elem, Boolean):
                new_typeset |= elem
                formulae_str.append(elem.name)
            elif isinstance(elem, Atom):
                new_typeset |= elem.typeset
                formulae_str.append(elem.string)
            else:
                raise AttributeError

        return new_typeset, formulae_str
Beispiel #18
0
    def create_transition_controller(self, start: Types, finish: Types, t_trans: int) -> Controller:

        t_controller_name = f"TRANS_{start.name}->{finish.name}"

        if self.session_name is None:
            folder_name = f"{self.t_controllers_folder_name}/{t_controller_name}"
        else:
            folder_name = f"{self.session_name}/{self.t_controllers_folder_name}/{t_controller_name}"

        typeset = Typeset({start, finish})
        realizable = False
        for n_steps in range(1, t_trans):
            trans_spec_str = Logic.and_([start.name, Logic.xn_(finish.name, n_steps)])
            trans_spec = Atom(formula=(trans_spec_str, typeset))
            trans_contract = Contract(guarantees=trans_spec)
            try:
                controller_info = trans_contract.get_controller_info(world_ts=self.world.typeset)
                a, g, i, o = controller_info.get_strix_inputs()
                controller_synthesis_input = StringMng.get_controller_synthesis_str(controller_info)
                Store.save_to_file(controller_synthesis_input,
                                   f"t_controller_{start.name}_{finish.name}_specs.txt", folder_name)
                realized, kiss_mealy, time = Strix.generate_controller(a, g, i, o)
                if realized:
                    realizable = True
                    break
            except ControllerException as e:
                raise TransSynthesisFail(self, e)
        if not realizable:
            raise Exception(
                f"Controller [{start.name}, {finish.name}] cannot be synthetized in {t_trans} steps")
        else:
            Store.save_to_file(kiss_mealy, f"{start.name}_{finish.name}_mealy",
                               folder_name)
            # Store.generate_eps_from_dot(dot_mealy, f"{start.name}_{finish.name}_dot",
            #                             folder_name)

            t_controller = Controller(mealy_machine=kiss_mealy, world=self.world, name=t_controller_name,
                                      synth_time=time)
            Store.save_to_file(str(t_controller), f"{start.name}_{finish.name}_table", folder_name)

            return t_controller
Beispiel #19
0
class World(dict):
    """"Instanciate atomic propositions (and their negation) for each Type"""
    def __init__(self,
                 actions: Set[Types] = None,
                 locations: Set[Types] = None,
                 sensors: Set[Types] = None,
                 contexts: Set[Types] = None):
        super().__init__()

        self.__typeset = Typeset(actions | locations | sensors | contexts
                                 | {Active()})

        for name, elem in self.__typeset.items():
            super(World, self).__setitem__(name, elem.to_atom())
            super(World, self).__setitem__(f"!{name}", ~elem.to_atom())

        self.__rules: Set[Rule] = set()

    @property
    def rules(self) -> Set[Rule]:
        return self.__rules

    @property
    def typeset(self) -> Typeset:
        return self.__typeset

    def add_rules(self, rules: Set[Rule]):
        self.__rules |= rules

    def adjacent_types(self, location: ReachLocation) -> Set[ReachLocation]:

        adjacent_types = set()
        for class_name in location.adjacency_set:
            for t in self.typeset.values():
                if type(t).__name__ == class_name:
                    adjacent_types.add(t)

        return adjacent_types
Beispiel #20
0
    def process_binary_input(pre: Union[Specification, Boolean], post: Union[Atom, Boolean]) -> Tuple[str, str, Typeset]:

        typeset = Typeset()

        if isinstance(pre, Boolean):
            pre_str = pre.name
            typeset |= pre
        elif isinstance(pre, Specification):
            pre_str = pre.string
            typeset |= pre.typeset
        else:
            raise AttributeError

        if isinstance(post, Boolean):
            post_str = post.name
            typeset |= post
        elif isinstance(post, Specification):
            post_str = post.string
            typeset |= post.typeset
        else:
            raise AttributeError

        return pre_str, post_str, typeset
Beispiel #21
0
    def __init__(self, name: str = "c"):
        super().__init__(name)


class GoD(ReachLocation):

    def __init__(self, name: str = "d"):
        super().__init__(name)


a = GoA()
b = GoB()
c = GoC()
d = GoD()

a = Atom((a.name, Typeset({a})))
b = Atom((b.name, Typeset({b})))

c = Atom((c.name, Typeset({c})))
d = Atom((d.name, Typeset({d})))

test = a >> ~ a

print(test.formula(FormulaOutput.CNF)[0])
print(test.formula(FormulaOutput.DNF)[0])

one = a & b

print("\none")
print(one.formula(FormulaOutput.CNF)[0])
print(one.formula(FormulaOutput.DNF)[0])
Beispiel #22
0
    def get_controller_info(self, world_ts: Typeset = None) -> SynthesisInfo:
        """Extract All Info Needed to Build a Controller from the Contract"""

        """Assumptions"""
        assumptions = []
        a_mutex = []
        a_liveness = []

        """Guarantees"""
        guarantees = []
        g_mutex = []
        g_adjacency = []

        a_typeset = Typeset()
        g_typeset = Typeset()

        list, typeset = self.assumptions.formula(FormulaOutput.ListCNF)
        assumptions.extend(list)
        a_typeset |= typeset

        list, typeset = self.guarantees.formula(FormulaOutput.ListCNF)
        guarantees.extend(list)
        g_typeset |= typeset

        if world_ts is not None:
            instance_ts = Typeset.get_instance_ts((a_typeset | g_typeset), world_ts)
        else:
            instance_ts = (a_typeset | g_typeset)

        """Extracting Inputs and Outputs Including the variables"""
        i_set, o_set = instance_ts.extract_inputs_outputs()

        i_typeset = Typeset(i_set)
        o_typeset = Typeset(o_set)

        """Mutex Rules"""
        ret = Atom.extract_mutex_rules(i_typeset, output=FormulaOutput.ListCNF)
        if ret is not None:
            rules, typeset = ret
            a_mutex.extend(rules)

        ret = Atom.extract_mutex_rules(o_typeset, output=FormulaOutput.ListCNF)
        if ret is not None:
            rules, typeset = ret
            g_mutex.extend(rules)

        """Adjacecy Rules"""
        ret = Atom.extract_adjacency_rules(o_typeset, output=FormulaOutput.ListCNF)
        if ret is not None:
            rules, typeset = ret
            g_adjacency.extend(rules)

        """Adding Liveness To Sensors (input)"""
        ret = Atom.extract_liveness_rules(i_typeset, output=FormulaOutput.ListCNF)
        if ret is not None:
            rules, typeset = ret
            a_liveness.extend(rules)

        """Adding context and active signal rules"""
        ret = Atom.context_active_rules(i_typeset, output=FormulaOutput.ListCNF)
        if ret is not None:
            rules, typeset = ret
            assumptions.extend(rules)

        """Extract Inputs and Outputs"""
        inputs = [t.name for t in i_set]
        outputs = [t.name for t in o_set]

        return SynthesisInfo(assumptions=assumptions,
                             a_liveness=a_liveness,
                             a_mutex=a_mutex,
                             guarantees=guarantees,
                             g_mutex=g_mutex,
                             g_adjacency=g_adjacency,
                             inputs=inputs,
                             outputs=outputs)
Beispiel #23
0
    def get_controller_info(self, world_ts: Typeset = None) -> SynthesisInfo:
        """Extract All Info Needed to Build a Controller from the Contract"""

        if world_ts is None:
            world_ts = Typeset()
        """Assumptions"""
        a_initial: List[str] = []
        a_fairness: List[str] = []
        a_safety: List[str] = []
        a_mutex: List[str] = []
        """Guarantees"""
        g_initial: List[str] = []
        g_safety: List[str] = []
        g_mutex: List[str] = []
        g_goal: List[str] = []

        a_typeset = Typeset()
        g_typeset = Typeset()

        list, typeset = self.assumptions.formula(FormulaOutput.ListCNF)
        a_initial.extend(list)
        a_typeset |= typeset

        list, typeset = self.guarantees.formula(FormulaOutput.ListCNF)
        g_goal.extend(list)
        g_typeset |= typeset

        all_typeset = a_typeset | g_typeset | world_ts
        """Inputs typeset"""
        i_typeset = Typeset(all_typeset.extract_inputs())
        """Output typeset"""
        o_typeset = Typeset(all_typeset.extract_outputs())

        actions_typeset = Typeset(all_typeset.ext())
        """Mutex"""
        ret = Atom.extract_mutex_rules(i_typeset, output=FormulaOutput.ListCNF)
        if ret is not None:
            rules, typeset = ret
            a_mutex.extend(rules)
        ret = Atom.extract_mutex_rules(o_typeset, output=FormulaOutput.ListCNF)
        if ret is not None:
            rules, typeset = ret
            g_mutex.extend(rules)
        """For the rules we extracts rules from the variables based on assumptions and inputs"""
        a_typeset = a_typeset | i_typeset
        """We remove the inputs typeset from the guarantees and we incorporate the variables ts"""
        g_typeset = g_typeset - i_typeset
        """Adding Mutex Rules"""
        ret = Atom.extract_mutex_rules(a_typeset, output=FormulaOutput.ListCNF)
        if ret is not None:
            rules, typeset = ret
            a_mutex.extend(rules)
            a_typeset |= typeset

        ret = Atom.extract_mutex_rules(g_typeset, output=FormulaOutput.ListCNF)
        if ret is not None:
            rules, typeset = ret
            g_mutex.extend(rules)
            g_typeset |= typeset
        """Adjacecy rules can include things that are in the world_ts"""
        if world_ts is not None:
            adjacency_ts = g_typeset | world_ts
        else:
            adjacency_ts = g_typeset

        ret = Atom.extract_adjacency_rules(adjacency_ts,
                                           output=FormulaOutput.ListCNF)
        if ret is not None:
            rules, typeset = ret
            g_adjacency.extend(rules)
            g_typeset |= typeset
        """Adding Liveness To Sensors (input)"""
        ret = Atom.extract_liveness_rules(i_typeset,
                                          output=FormulaOutput.ListCNF)
        if ret is not None:
            rules, typeset = ret
            a_liveness.extend(rules)
        """Extract Inputs and Outputs"""
        inputs = [t.name for t in (a_typeset | g_typeset).extract_inputs()]
        outputs = [t.name for t in (a_typeset | g_typeset).extract_outputs()]

        return SynthesisInfo(a_initial=assumptions,
                             a_fairness=a_liveness,
                             a_mutex=a_mutex,
                             guarantees=guarantees,
                             g_mutex=g_mutex,
                             g_safety=g_adjacency,
                             inputs=inputs,
                             outputs=outputs)
Beispiel #24
0
 def to_atom(self):
     from specification.atom import Atom
     from typeset import Typeset
     return Atom(formula=(self.name, Typeset({self})), check=False)
Beispiel #25
0
 def to_atom(self):
     from specification.atom import Atom, AtomKind
     from typeset import Typeset
     return Atom(formula=(self.name, Typeset({self})),
                 check=False,
                 kind=AtomKind.LOCATION)
Beispiel #26
0
night = Night().to_atom()
a1 = A1().to_atom()
a2 = A2().to_atom()
b1 = B1().to_atom()
b2 = B2().to_atom()
z = Z().to_atom()

"""Ordered Patrolling Location a1, a2 starting from a1"""
patrol_a = a1 & OrderedPatrolling([a1, a2])

"""Ordered Patrolling Location b1, b2"""
patrol_b = b1 & OrderedPatrolling([b1, b2])

"""Inputs and Outputs"""
i_set, o_set = (patrol_a.typeset | patrol_b.typeset | z.typeset).extract_inputs_outputs()
i_typeset = Typeset(i_set)
o_typeset = Typeset(o_set)

"""Mutex"""
mutex_context = Atom.extract_mutex_rules(i_typeset)
mutex_locs = Atom.extract_mutex_rules(o_typeset)

"""Liveness"""
live_day = Atom.extract_liveness_rules(day.typeset)
live_night = Atom.extract_liveness_rules(night.typeset)

"""Topology"""
topology = Atom.extract_adjacency_rules(o_typeset)

c1 = Contract(assumptions=live_day, guarantees=patrol_a & mutex_locs & topology)
c2 = Contract(assumptions=live_night, guarantees=patrol_b & mutex_locs & topology)