예제 #1
0
    def add_node(self, n, attr_dict=None, check=True, **attr):
        """Use a L{TypedDict} as attribute dict.

        Overrides C{networkx.MultiDiGraph.add_node},
        see that for details.

        Log warning if node already exists.
        All other functionality remains the same.

        @param check: if True and untyped keys are passed,
            then raise C{AttributeError}.
        """
        # avoid multiple additions
        if n in self:
            logger.debug('Graph already has node: ' + str(n))
        attr_dict = self._update_attr_dict_with_attr(attr_dict, attr)
        # define typed dict
        typed_attr = TypedDict()
        typed_attr.set_types(self._node_label_types)
        typed_attr.update(copy.deepcopy(self._node_label_defaults))
        # type checking happens here
        typed_attr.update(attr_dict)
        logger.debug('node typed_attr: ' + str(typed_attr))
        self._check_for_untyped_keys(typed_attr,
                                     self._node_label_types,
                                     check)
        nx.MultiDiGraph.add_node(self, n, attr_dict=typed_attr)
예제 #2
0
    def add_node(self, n, attr_dict=None, check=True, **attr):
        """Use a L{TypedDict} as attribute dict.

        Overrides C{networkx.MultiDiGraph.add_node},
        see that for details.

        Log warning if node already exists.
        All other functionality remains the same.

        @param check: if True and untyped keys are passed,
            then raise C{AttributeError}.
        """
        # avoid multiple additions
        if n in self:
            logger.debug('Graph already has node: ' + str(n))
        attr_dict = self._update_attr_dict_with_attr(attr_dict, attr)
        # define typed dict
        typed_attr = TypedDict()
        typed_attr.set_types(self._node_label_types)
        typed_attr.update(copy.deepcopy(self._node_label_defaults))
        # type checking happens here
        typed_attr.update(attr_dict)
        logger.debug('node typed_attr: ' + str(typed_attr))
        self._check_for_untyped_keys(typed_attr,
                                     self._node_label_types,
                                     check)
        nx.MultiDiGraph.add_node(self, n, attr_dict=typed_attr)
예제 #3
0
    def add_edge(self, u, v, key=None, attr_dict=None, check=True, **attr):
        """Use a L{TypedDict} as attribute dict.

        Overrides C{networkx.MultiDiGraph.add_edge},
        see that for details.

          - Raise ValueError if C{u} or C{v} are not already nodes.
          - Raise Exception if edge (u, v, {}) exists.
          - Log warning if edge (u, v, attr_dict) exists.
          - Raise ValueError if C{attr_dict} contains
            typed key with invalid value.
          - Raise AttributeError if C{attr_dict} contains untyped keys,
            unless C{check=False}.

        Each label defines a different labeled edge.
        So to "change" the label, either:

            - remove the edge with this label, then add a new one, or
            - find the edge key, then use subscript notation:

                C{G[i][j][key]['attr_name'] = attr_value}

        Notes
        =====
        1. Argument C{key} has been removed compared to
           C{networkx.MultiDiGraph.add_edge}, because edges are defined
           by their labeling, i.e., multiple edges with same labeling
           are not allowed.

        @param check: raise C{AttributeError} if C{attr_dict}
            has untyped attribute keys, otherwise warn
        """
        # legacy
        if 'check_states' in attr:
            msg = 'saw keyword argument: check_states ' +\
                  'which is no longer available, ' +\
                  'firstly add the new nodes.'
            logger.warning(msg)
        # check nodes exist
        if u not in self.succ:
            raise ValueError('Graph does not have node u: ' + str(u))
        if v not in self.succ:
            raise ValueError('Graph does not have node v: ' + str(v))
        attr_dict = self._update_attr_dict_with_attr(attr_dict, attr)
        # define typed dict
        typed_attr = TypedDict()
        typed_attr.set_types(self._edge_label_types)
        typed_attr.update(copy.deepcopy(self._edge_label_defaults))
        # type checking happens here
        typed_attr.update(attr_dict)
        logger.debug('Given: attr_dict = ' + str(attr_dict))
        logger.debug('Stored in: typed_attr = ' + str(typed_attr))
        # may be possible to speedup using .succ
        existing_u_v = self.get_edge_data(u, v, default={})
        if dict() in existing_u_v.values():
            msg = (
                'Unlabeled transition: '
                'from_state-> to_state already exists,\n'
                'where:\t from_state = ' + str(u) + '\n'
                'and:\t to_state = ' + str(v) + '\n')
            raise Exception(msg)
        # check if same labeled transition exists
        if attr_dict in existing_u_v.values():
            msg = (
                'Same labeled transition:\n'
                'from_state---[label]---> to_state\n'
                'already exists, where:\n'
                '\t from_state = ' + str(u) + '\n'
                '\t to_state = ' + str(v) + '\n'
                '\t label = ' + str(typed_attr) + '\n')
            warnings.warn(msg)
            logger.warning(msg)
            return
        # self._breaks_determinism(from_state, labels)
        self._check_for_untyped_keys(typed_attr,
                                     self._edge_label_types,
                                     check)
        # the only change from nx in this clause is using TypedDict
        logger.debug('adding edge: ' + str(u) + ' ---> ' + str(v))
        if v in self.succ[u]:
            msg = 'there already exist directed edges with ' +\
                  'same end-points'
            logger.debug(msg)
            keydict = self.adj[u][v]
            # find a unique integer key
            if key is None:
                key = len(keydict)
                while key in keydict:
                    key -= 1
            datadict = keydict.get(key, typed_attr)
            datadict.update(typed_attr)
            keydict[key] = datadict
        else:
            logger.debug('first directed edge between these nodes')
            # selfloops work this way without special treatment
            key = 0
            keydict = {key: typed_attr}
            self.succ[u][v] = keydict
            self.pred[v][u] = keydict
예제 #4
0
    def add_edge(self, u, v, key=None, attr_dict=None, check=True, **attr):
        """Use a L{TypedDict} as attribute dict.

        Overrides C{networkx.MultiDiGraph.add_edge},
        see that for details.

          - Raise ValueError if C{u} or C{v} are not already nodes.
          - Raise Exception if edge (u, v, {}) exists.
          - Log warning if edge (u, v, attr_dict) exists.
          - Raise ValueError if C{attr_dict} contains
            typed key with invalid value.
          - Raise AttributeError if C{attr_dict} contains untyped keys,
            unless C{check=False}.

        Each label defines a different labeled edge.
        So to "change" the label, either:

            - remove the edge with this label, then add a new one, or
            - find the edge key, then use subscript notation:

                C{G[i][j][key]['attr_name'] = attr_value}

        Notes
        =====

        @param check: raise C{AttributeError} if C{attr_dict}
            has untyped attribute keys, otherwise warn
        """
        # legacy
        if 'check_states' in attr:
            msg = 'saw keyword argument: check_states ' +\
                  'which is no longer available, ' +\
                  'firstly add the new nodes.'
            logger.warning(msg)
        # check nodes exist
        if u not in self._succ:
            raise ValueError('Graph does not have node u: ' + str(u))
        if v not in self._succ:
            raise ValueError('Graph does not have node v: ' + str(v))
        attr_dict = self._update_attr_dict_with_attr(attr_dict, attr)
        # define typed dict
        typed_attr = TypedDict()
        typed_attr.set_types(self._edge_label_types)
        typed_attr.update(copy.deepcopy(self._edge_label_defaults))
        # type checking happens here
        typed_attr.update(attr_dict)
        existing_u_v = self.get_edge_data(u, v, default={})
        if dict() in existing_u_v.values():
            msg = (
                'Unlabeled transition: '
                'from_state-> to_state already exists,\n'
                'where:\t from_state = ' + str(u) + '\n'
                'and:\t to_state = ' + str(v) + '\n')
            raise Exception(msg)
        # check if same labeled transition exists
        if attr_dict in existing_u_v.values():
            msg = (
                'Same labeled transition:\n'
                'from_state---[label]---> to_state\n'
                'already exists, where:\n'
                '\t from_state = ' + str(u) + '\n'
                '\t to_state = ' + str(v) + '\n'
                '\t label = ' + str(typed_attr) + '\n')
            logger.warning(msg)
            return
        # self._breaks_determinism(from_state, labels)
        self._check_for_untyped_keys(typed_attr,
                                     self._edge_label_types,
                                     check)
        # the only change from nx in this clause is using TypedDict
        logger.debug('adding edge: ' + str(u) + ' ---> ' + str(v))
        if key is None:
            key = self.new_edge_key(u, v)
        if v in self._succ[u]:
            keydict = self._adj[u][v]
            datadict = keydict.get(key, typed_attr)
            datadict.update(typed_attr)
            nx.MultiDiGraph.add_edge(self, u, v, key, **datadict)
        else:
            # selfloops work this way without special treatment
            nx.MultiDiGraph.add_edge(self, u, v, **typed_attr)
예제 #5
0
    def find(self, from_states=None, to_states=None,
             with_attr_dict=None, typed_only=False, **with_attr):
        """Find all edges between given states with given labels.

        Instead of having two separate methods to:

          - find all labels of edges between given states (s1, s2)

          - find all transitions (s1, s2, L) with given label L,
                possibly from some given state s1,
                i.e., the edges leading to the successor states
                Post(s1, a) = Post(s1) restricted by action a

        this method provides both functionalities.

        Preimage under edge labeling function L of given label,
        intersected with given subset of edges::
            L^{-1}(desired_label) \\cap (from_states x to_states)

        See Also
        ========
        L{add}, L{add_adj}

        @param from_states: edges must start from this subset of states
        @type from_states:
            - iterable of existing states, or
            - None (no constraint, default)

        @param to_states: edges must end in this subset of states
        @type to_states:
            - iterable of existing states, or
            - None (no constraint, default)

        @param with_attr_dict: edges must be annotated with these labels
        @type with_attr_dict:
            - {label_type : desired_label_value, ...}, or
            - None (no constraint, default)

        @param with_attr: label type-value pairs,
            take precedence over C{desired_label}.

        @return: set of transitions = labeled edges::
                (from_state, to_state, label)
        such that::
                (from_state, to_state )
                in from_states x to_states

        @rtype: list of transitions::
                = list of labeled edges
                = [(from_state, to_state, label),...]
        where:
          - C{from_state} in C{from_states}
          - C{to_state} in C{to_states}
          - C{label}: dict
        """
        if with_attr_dict is None:
            with_attr_dict = with_attr
        try:
            with_attr_dict.update(with_attr)
        except:
            raise TypeError('with_attr_dict must be a dict')
        found_transitions = []
        u_v_edges = self.graph.edges(nbunch=from_states, data=True)
        if to_states is not None:
            u_v_edges = [(u, v, d)
                         for u, v, d in u_v_edges
                         if v in to_states]
        for u, v, attr_dict in u_v_edges:
            ok = True
            if not with_attr_dict:
                logger.debug('Any label is allowed.')
            elif not attr_dict:
                logger.debug('No labels defined.')
            else:
                logger.debug('Checking guard.')
                typed_attr = TypedDict()
                typed_attr.set_types(self.graph._edge_label_types)
                typed_attr.update(attr_dict)
                ok = label_is_desired(typed_attr, with_attr_dict)
            if ok:
                logger.debug('Transition label matched desired label.')
                transition = (u, v, dict(attr_dict))
                found_transitions.append(transition)
        return found_transitions
예제 #6
0
    def find(self, states=None, with_attr_dict=None, **with_attr):
        """Filter by desired states and by desired state labels.

        Examples
        ========
        Assume that the system is:

        >>> import transys as trs
        >>> ts = trs.FTS()
        >>> ts.atomic_propositions.add('p')
        >>> ts.states.add('s0', ap={'p'})

          - To find the label of a single state C{'s0'}:

              >>> a = ts.states.find(['s0'] )
              >>> (s0_, label) = a[0]
              >>> print(label)
              {'ap': set(['p'])}

          - To find all states with a specific label C{{'p'}}:

              >>> ts.states.add('s1', ap={'p'})
              >>> b = ts.states.find(with_attr_dict={'ap':{'p'} } )
              >>> states = [state for (state, label_) in b]
              >>> print(set(states) )
              {'s0', 's1'}

          - To find all states in subset C{M} labeled with C{{'p'}}:

              >>> ts.states.add('s2', ap={'p'})
              >>> M = {'s0', 's2'}
              >>> b = ts.states.find(M, {'ap': {'p'} } )
              >>> states = [state for (state, label_) in b]
              >>> print(set(states) )
              {'s0', 's2'}

        @param states: subset of states over which to search
        @type states: 'any' (default)
            | iterable of valid states
            | single valid state

        @param with_attr_dict: label with which to filter the states
        @type with_attr_dict: {sublabel_type : desired_sublabel_value, ...}
            | leave empty, to allow any state label (default)

        @param with_attr: label key-value pairs which take
            precedence over C{with_attr_dict}.

        @rtype: list of labeled states
        @return: [(C{state}, C{label}),...]
            where:
                - C{state} \\in C{states}
                - C{label}: dict
        """
        if with_attr_dict is None:
            with_attr_dict = with_attr
        else:
            try:
                with_attr_dict.update(with_attr)
            except AttributeError:
                raise Exception('with_attr_dict must be a dict')
        if states is not None:
            # singleton check
            if states in self:
                state = states
                msg = (
                    'LabeledStates.find got single state: ' +
                    str(state) + '\n'
                    'instead of Iterable of states.\n')
                states = [state]
                msg += 'Replaced given states = ' + str(state)
                msg += ' with states = ' + str(states)
                logger.debug(msg)
        found_state_label_pairs = []
        for state, attr_dict in self.graph.nodes(data=True):
            logger.debug('Checking state_id = ' + str(state) +
                         ', with attr_dict = ' + str(attr_dict))
            if states is not None:
                if state not in states:
                    logger.debug('state_id = ' + str(state) + ', not desired.')
                    continue
            msg = (
                'Checking state label:\n\t attr_dict = ' +
                str(attr_dict) +
                '\n vs:\n\t desired_label = ' + str(with_attr_dict))
            logger.debug(msg)
            if not with_attr_dict:
                logger.debug('Any label acceptable.')
                ok = True
            else:
                typed_attr = TypedDict()
                typed_attr.set_types(self.graph._node_label_types)
                typed_attr.update(attr_dict)
                ok = label_is_desired(typed_attr, with_attr_dict)
            if ok:
                logger.debug('Label Matched:\n\t' + str(attr_dict) +
                             ' == ' + str(with_attr_dict))
                state_label_pair = (state, dict(attr_dict))
                found_state_label_pairs.append(state_label_pair)
            else:
                logger.debug('No match for label---> state discarded.')
        return found_state_label_pairs
예제 #7
0
 def setUp(self):
     d = TypedDict()
     d.set_types({'animal': {'dog', 'cat'}})
     self.d = d
 def setUp(self):
     d = TypedDict()
     d.set_types({"animal": {"dog", "cat"}})
     self.d = d
예제 #9
0
    def add_edge(self, u, v, key=None, attr_dict=None, check=True, **attr):
        """Use a L{TypedDict} as attribute dict.

        Overrides C{networkx.MultiDiGraph.add_edge},
        see that for details.

          - Raise ValueError if C{u} or C{v} are not already nodes.
          - Raise Exception if edge (u, v, {}) exists.
          - Log warning if edge (u, v, attr_dict) exists.
          - Raise ValueError if C{attr_dict} contains
            typed key with invalid value.
          - Raise AttributeError if C{attr_dict} contains untyped keys,
            unless C{check=False}.

        Each label defines a different labeled edge.
        So to "change" the label, either:

            - remove the edge with this label, then add a new one, or
            - find the edge key, then use subscript notation:

                C{G[i][j][key]['attr_name'] = attr_value}

        Notes
        =====
        1. Argument C{key} has been removed compared to
           C{networkx.MultiDiGraph.add_edge}, because edges are defined
           by their labeling, i.e., multiple edges with same labeling
           are not allowed.

        @param check: raise C{AttributeError} if C{attr_dict}
            has untyped attribute keys, otherwise warn
        """
        # legacy
        if 'check_states' in attr:
            msg = 'saw keyword argument: check_states ' +\
                  'which is no longer available, ' +\
                  'firstly add the new nodes.'
            logger.warning(msg)
        # check nodes exist
        if u not in self.succ:
            raise ValueError('Graph does not have node u: ' + str(u))
        if v not in self.succ:
            raise ValueError('Graph does not have node v: ' + str(v))
        attr_dict = self._update_attr_dict_with_attr(attr_dict, attr)
        # define typed dict
        typed_attr = TypedDict()
        typed_attr.set_types(self._edge_label_types)
        typed_attr.update(copy.deepcopy(self._edge_label_defaults))
        # type checking happens here
        typed_attr.update(attr_dict)
        logger.debug('Given: attr_dict = ' + str(attr_dict))
        logger.debug('Stored in: typed_attr = ' + str(typed_attr))
        # may be possible to speedup using .succ
        existing_u_v = self.get_edge_data(u, v, default={})
        if dict() in existing_u_v.values():
            msg = (
                'Unlabeled transition: '
                'from_state-> to_state already exists,\n'
                'where:\t from_state = ' + str(u) + '\n'
                'and:\t to_state = ' + str(v) + '\n')
            raise Exception(msg)
        # check if same labeled transition exists
        if attr_dict in existing_u_v.values():
            msg = (
                'Same labeled transition:\n'
                'from_state---[label]---> to_state\n'
                'already exists, where:\n'
                '\t from_state = ' + str(u) + '\n'
                '\t to_state = ' + str(v) + '\n'
                '\t label = ' + str(typed_attr) + '\n')
            warnings.warn(msg)
            logger.warning(msg)
            return
        # self._breaks_determinism(from_state, labels)
        self._check_for_untyped_keys(typed_attr,
                                     self._edge_label_types,
                                     check)
        # the only change from nx in this clause is using TypedDict
        logger.debug('adding edge: ' + str(u) + ' ---> ' + str(v))
        if v in self.succ[u]:
            msg = 'there already exist directed edges with ' +\
                  'same end-points'
            logger.debug(msg)
            keydict = self.adj[u][v]
            # find a unique integer key
            if key is None:
                key = len(keydict)
                while key in keydict:
                    key -= 1
            datadict = keydict.get(key, typed_attr)
            datadict.update(typed_attr)
            keydict[key] = datadict
        else:
            logger.debug('first directed edge between these nodes')
            # selfloops work this way without special treatment
            key = 0
            keydict = {key: typed_attr}
            self.succ[u][v] = keydict
            self.pred[v][u] = keydict