Пример #1
0
def gen_Entity(obj, name="", parent=None, **kwargs):
    islogical = issubclass(obj.__class__, Model.LogicalEntity)
    hide_behaviour = kwargs["interface_only"] or kwargs["no_behaviour"] or \
        (islogical and kwargs["logical_interface_only"])

    style = "dashed" if islogical else "solid"

    inputs = ""
    outputs = ""
    centre = ""
    body = ""
    """ Inputs """
    for name_, input_ in Model.get_inputs(obj, as_dict=True).items():
        inputs += "\n" + generate(input_, name_, obj, **kwargs)
    """ Centre """
    if not hide_behaviour:
        for name_, state in Model.get_states(obj, as_dict=True).items():
            if not name_ == CURRENT_IDENTIFIER:
                centre += "\n" + generate(state, name_, obj, **kwargs)

    if not hide_behaviour:
        for name_, local in Model.get_locals(obj, as_dict=True).items():
            centre += "\n" + generate(local, name_, obj, **kwargs)
    """ Outputs """
    for name_, output in Model.get_outputs(obj, as_dict=True).items():
        outputs += "\n" + generate(output, name_, obj, **kwargs)
    """ Body """
    if not hide_behaviour:
        if kwargs["transitions"]:
            for name_, trans in Model.get_transitions(obj,
                                                      as_dict=True).items():
                body += "\n" + "\n".join(generate(trans, name_, obj, **kwargs))

    if not kwargs["interface_only"] and not (islogical and
                                             kwargs["logical_interface_only"]):
        for name_, entity in Model.get_entities(obj, as_dict=True).items():
            if name_ != PARENT_IDENTIFIER:
                centre += "\n" + generate(entity, name_, obj, **kwargs)

    if not kwargs["interface_only"] and not (islogical and
                                             kwargs["logical_interface_only"]):
        for name_, influence in Model.get_influences(obj,
                                                     as_dict=True).items():
            body += "\n" + generate(influence, name_, obj, **kwargs)

    if not hide_behaviour:
        if kwargs["updates"]:
            for name_, update in Model.get_updates(obj, as_dict=True).items():
                body += "\n" + "\n".join(generate(update, name_, obj, **
                                                  kwargs))

    if not hide_behaviour:
        if kwargs["actions"]:
            for name_, action in Model.get_actions(obj, as_dict=True).items():
                body += "\n" + "\n".join(generate(action, name_, obj, **
                                                  kwargs))

    typename = obj.__class__.__name__ if isinstance(
        obj, CrestObject) else obj.__name__
    return f"""
Пример #2
0
def gen_Entity(obj, name="", parent=None, **kwargs):
    parentinfo = "" if parent is None else parent._name
    logger.debug(
        f"Adding entity '{name}' of type {type(obj)} with parent (id={id(parent)})"
    )
    typename = obj.__class__.__name__ if isinstance(
        obj, CrestObject) else obj.__name__
    node = {
        'id': str(id(obj)),
        'label': {
            'label': f'{name} | {typename}',
            'text': name
        },
        'children': [],
        'ports': [],
        'edges': [],
        'cresttype': 'entity',
        'width': 300,
        'height': 200
    }
    """ Inputs """
    for name_, input_ in Model.get_inputs(obj, as_dict=True).items():
        node["ports"].append(generate(input_, name_, obj, **kwargs))
    """ Centre """
    for name_, state in Model.get_states(obj, as_dict=True).items():
        if not name_ == CURRENT_IDENTIFIER:
            node["children"].append(generate(state, name_, obj, **kwargs))

    for name_, local in Model.get_locals(obj, as_dict=True).items():
        node["children"].append(generate(local, name_, obj, **kwargs))
    """ Outputs """
    for name_, output in Model.get_outputs(obj, as_dict=True).items():
        node["ports"].append(generate(output, name_, obj, **kwargs))

    for name_, entity in Model.get_entities(obj, as_dict=True).items():
        if name_ != PARENT_IDENTIFIER:
            node["children"].append(generate(entity, name_, obj, **kwargs))

    for name_, trans in Model.get_transitions(obj, as_dict=True).items():
        node["edges"].extend(generate(trans, name_, obj, **kwargs))
        node["children"].append(generate_midpoint(trans, name_, obj, **kwargs))

    for name_, influence in Model.get_influences(obj, as_dict=True).items():
        node["edges"].extend(generate(influence, name_, obj, **kwargs))

    for name_, update in Model.get_updates(obj, as_dict=True).items():
        node["edges"].extend(generate(update, name_, obj, **kwargs))
        pass

    for name_, action in Model.get_actions(obj, as_dict=True).items():
        node["edges"].extend(generate(action, name_, obj, **kwargs))

    return node
Пример #3
0
    def calculate_entity_hook(self, entity):
        all_dts = []
        logger.debug(
            f"Calculating behaviour change for entity {entity._name} ({entity.__class__.__name__})"
        )
        for influence in get_influences(entity):
            if self.contains_if_condition(influence):
                inf_dts = self.get_condition_change_enablers(influence)
                if inf_dts is not None:
                    all_dts.append(inf_dts)

        # updates = [up for up in get_updates(self.entity) if up.state == up._parent.current]
        for update in get_updates(entity):
            if update.state is update._parent.current:  # only the currently active updates
                if self.contains_if_condition(update):
                    up_dts = self.get_condition_change_enablers(update)
                    if up_dts is not None:
                        all_dts.append(up_dts)

        # TODO: check for transitions whether they can be done by time only
        for name, trans in get_transitions(entity, as_dict=True).items():
            if entity.current is trans.source:
                trans_dts = self.get_transition_time(trans)
                if trans_dts is not None:
                    all_dts.append(trans_dts)

        if logger.getEffectiveLevel() <= logging.DEBUG:
            if len(all_dts) == 0:
                logger.debug(
                    "There were no change times in entity {entity._name} ({entity.__class__.__name__})."
                )
                return []

            min_dt_eps = min(all_dts, key=(lambda x: x[0]))
            # min_dt = get_minimum_dt_of_several(all_dts, self.timeunit)
            if min_dt_eps is not None:
                logger.debug(
                    f"Minimum behaviour change time for entity {entity._name} ({entity.__class__.__name__}) is {min_dt_eps}"
                )
            return [min_dt_eps]  # return a list

            # min_dt = get_minimum_dt_of_several(all_dts, self.timeunit)
            # if min_dt is not None:
            #     logger.debug(f"Minimum behaviour change time for entity {entity._name} ({entity.__class__.__name__}) is {min_dt}")
            # return [min_dt]  # return a list
        else:
            # XXX This is the faster one that we run when we're not debugging !!
            return all_dts
Пример #4
0
    def transition(self, entity, transition=None):
        logger.debug("transitions in entity %s (%s)", entity._name,
                     entity.__class__.__name__)
        if transition is None:
            transition = self.select_transition_to_trigger(entity)

        if transition is None:  # there are no enabled transitions ! (exit early)
            return False

        # in case it was passed as parameter
        assert self._get_transition_guard_value(
            transition
        ), "It seems that the transition that was chosen to be fired is not enabled."

        entity.current = transition.target
        logger.info(
            f"Time: {self.global_time} | Firing transition <<{transition._name}>> in {entity._name} ({entity.__class__.__name__}) : {transition.source._name} -> {transition.target._name}  | current global time: {self.global_time}"
        )

        transition_updates = [
            up for up in get_updates(transition._parent)
            if up.state is transition
        ]  # FIXME: until we completely switched to only allowing actions...
        actions = [
            a for a in get_actions(transition._parent)
            if a.transition is transition
        ]
        for act in actions + transition_updates:
            logger.debug(
                f"Triggering action {act._name} in entity {entity._name} ({entity.__class__.__name__})"
            )
            newval = self._get_action_function_value(act)
            if newval != act.target.value:
                logger.info(
                    f"Port value changed: {act.target._name} ({act.target._parent._name}) {act.target.value} -> {newval}"
                )
                act.target.value = newval

        # return if a transition was fired
        return (transition is not None)
Пример #5
0
    def transition(self, entity):
        # logger.debug(f"transitions in entity {entity._name} ({entity.__class__.__name__})")
        transitions_from_current_state = [
            t for t in model.get_transitions(entity)
            if t.source is entity.current
        ]
        enabled_transitions = [
            t for t in transitions_from_current_state
            if self._get_transition_guard_value(t)
        ]

        state_before = SystemState(self.system).save()  # backup the state

        states_after = []
        for transition in enabled_transitions:
            state_before.apply()  # reset to original state
            entity.current = transition.target
            # logger.info(f"Time: {self.global_time} | Firing transition <<{transition._name}>> in {entity._name} ({entity.__class__.__name__}) : {transition.source._name} -> {transition.target._name}  | current global time: {self.global_time}")

            transition_updates = [
                up for up in model.get_updates(transition._parent)
                if up.state is transition
            ]  # FIXME: until we completely switched to only allowing actions...
            actions = [
                a for a in model.get_actions(transition._parent)
                if a.transition is transition
            ]
            for act in actions + transition_updates:
                newval = self._get_action_function_value(act)
                if newval != act.target.value:
                    act.target.value = newval

            state_after = SystemState(self.system).save()
            states_after.append((state_after, [transition]))

        # return the new states if there are any (this means that empty list means no transitions were fired)
        # logger.debug(f"finished transitions in entity {entity._name} ({entity.__class__.__name__}): Created {len(states_after)} new states!")
        return states_after
Пример #6
0
    def _update(self,
                entity,
                time,
                original_states,
                original_port_values,
                first=False):
        logger.debug(
            f"entity <<{entity._name}>> ({entity.__class__.__name__}) with dt of {time}"
        )

        # set pre's
        for port in get_sources(entity):
            port.pre = original_port_values[port]

        current_port_values = {t: t.value for t in get_all_ports(entity)}
        updates_from_current_state = [
            up for up in get_updates(entity) if up.state is entity.current
        ]
        """ apply updates """
        values_to_update = {}
        for update in updates_from_current_state:
            logger.debug(
                f"Executing update <<{update._name}>> (target: {update.target._name}) in entity {entity._name} ({entity.__class__.__name__})"
            )
            update_func_value = self._calculate_update_value(
                entity, time, original_states, original_port_values, update)
            if not bool(current_port_values[update.target] ==
                        update_func_value):  # this means something changed
                values_to_update[update.target] = update_func_value
                logger.debug(
                    f"Update <<{update._name}>> in entity {entity._name} ({entity.__class__.__name__}) TEMP changing value of port {update.target._name} (type: {update.target.resource.unit}) to {update_func_value} (from {current_port_values[update.target]}) | global time {self.global_time}"
                )
        self._value_change(values_to_update)
        self.propagate_influences(
            entity)  # propagate through influences and to children

        logger.debug(f"executing subentity updates")
        subentity_changes = []
        for subentity in get_entities(entity):
            # only do it if the inputs values changed, otherwise we'll stay like this...
            # also do it if it's the first time we execute
            if first or any(i.value != current_port_values[i]
                            for i in get_inputs(subentity)):
                logger.debug(
                    f"Applying update to subentity {subentity._name} ({subentity.__class__.__name__})"
                )
                self.reset_subentity(
                    subentity, original_states,
                    original_port_values)  # resets all except inputs
                self.update_system(subentity, time)
                self.stabilise(subentity)
                sub_changes = [
                    o.value != current_port_values[o]
                    for o in get_outputs(subentity)
                ]
                logger.debug(
                    f"Applying update to subentity {subentity._name} ({subentity.__class__.__name__}) changed values: {any(sub_changes)}"
                )
                subentity_changes.append(any(sub_changes))
                logger.debug(
                    f"Finished update of subentity {subentity._name} ({subentity.__class__.__name__})"
                )
        logger.debug(f"finished executing subentity updates")
        self.propagate_influences(entity)  # forward all influences

        logger.debug(
            f"finished entity <<{entity._name}>> ({entity.__class__.__name__}) with dt of {time}"
        )
        # either port values changed or subentity interfaces changed
        return len(values_to_update) > 0 or any(subentity_changes)
Пример #7
0
def _replacability_checks(entity, name, obj, existing):
    # TODO: clean me up ? These are lots of checks, maybe we need to make them look nice

    if isinstance(obj, crest.Entity):
        for update in crest.get_updates(
                entity
        ):  # check if an update already writes to one of the entity's ports
            if update.target in crest.get_inputs(existing):
                raise AttributeError(
                    f"Cannot reassign SubEntity '{name}' since one of its Input ports was used as target of Update '{get_name(update)}'."
                )
        for influence in crest.get_influences(
                entity
        ):  # check if an influence already reads from or writes to the entity's ports
            if influence.source in crest.get_outputs(existing):
                raise AttributeError(
                    f"Cannot reassign SubEntity '{name}' since one of its Output ports was used as source of Influence '{get_name(influence)}'."
                )
            if influence.target in crest.get_inputs(existing):
                raise AttributeError(
                    f"Cannot reassign SubEntity '{name}' since one of its Input ports was used as target of Influence '{get_name(influence)}'."
                )
        for action in crest.get_actions(
                entity
        ):  # check if an action already writes to the entity's ports
            if action.target in crest.get_inputs(existing):
                raise AttributeError(
                    f"Cannot reassign SubEntity '{name}' since one of its Input ports was used as target of Action '{get_name(action)}'."
                )

    elif isinstance(obj, crest.Port):
        for update in crest.get_updates(
                entity
        ):  # check if an update already writes to the port that we want to override
            if update.target == existing:
                raise AttributeError(
                    f"Cannot reassign {obj.__class__.__name__} port '{name}' after it was used as target of Update '{get_name(update)}'."
                )
        for influence in crest.get_influences(
                entity
        ):  # check if an influence already reads from or writes to the port that we want to override
            if influence.source == existing:
                raise AttributeError(
                    f"Cannot reassign {obj.__class__.__name__} port '{name}' after it was used as source of Influence '{get_name(influence)}'."
                )
            if influence.target == existing:
                raise AttributeError(
                    f"Cannot reassign {obj.__class__.__name__} port '{name}' after it was used as target of Influence '{get_name(influence)}'."
                )
        for action in crest.get_actions(
                entity
        ):  # check if an action already writes to the port that we want to override
            if action.target == existing:
                raise AttributeError(
                    f"Cannot reassign {obj.__class__.__name__} port '{name}' after it was used as target of Action '{get_name(action)}'."
                )

    elif isinstance(obj, crest.State):
        for update in crest.get_updates(
                entity
        ):  # check if an update is already linked to the state that we want to override
            if update.state == existing:
                raise AttributeError(
                    f"Cannot reassign {obj.__class__.__name__} '{name}' after it was used in Update '{get_name(update)}'."
                )
        for transition in crest.get_transitions(
                entity
        ):  # check if a transition already starts from or goes to the state that we want to override
            if transition.source == existing:
                raise AttributeError(
                    f"Cannot reassign {obj.__class__.__name__} '{name}' after it was used as source of Transition '{get_name(transition)}'."
                )
            if transition.target == existing:
                raise AttributeError(
                    f"Cannot reassign {obj.__class__.__name__} '{name}' after it was used as target of Transition '{get_name(transition)}'."
                )

    elif isinstance(obj, crest.Transition):
        # TODO: check here for any action uses the transition already
        # this is non-trivial however
        pass