Beispiel #1
0
class MockSimpleGraphDB\
(
    Generic[MockVertexData],
    PartiallyStatefulDirectedGraphInterface[SimpleGraphKey, MockVertexData]
):
    '''
    Type for mocking a simple database.
    '''

    data: DiGraph

    def __init__(self) -> None:
        self.data = DiGraph()

    def write_stateful_vertex_(self, label: SimpleGraphKey,
                               data: MockVertexData, *args: Any,
                               **kwargs: Any) -> None:
        self.data.add_node(node_for_adding=label,
                           memento=data)  # type: ignore unkonwn

    def write_stateless_directed_edge_(self, source: SimpleGraphKey,
                                       destination: SimpleGraphKey, *args: Any,
                                       **kwargs: Any) -> None:
        self.data.add_edge(
            u_of_edge=source,
            v_of_edge=destination)  # type: ignore unkonwn member
Beispiel #2
0
 def remove_low_frequency_label(
         community_label_list_for_nodes: multivalued_dict) -> DiGraph:
     from sklearn.ensemble import IsolationForest
     digraph_of_node_labels_and_frequencies = DiGraph()
     for graph_of_node, label_list_of_nodes in community_label_list_for_nodes.items(
     ):
         digraph_of_node_labels_and_frequencies.add_node(graph_of_node)
         label_set = set(label_list_of_nodes)
         dict_of_frequency_of_label = dict(
             sorted([(label_list_of_nodes.count(label_item), label_item)
                     for label_item in label_set],
                    key=lambda frequency_and_label: frequency_and_label[0],
                    reverse=True))
         dict_of_sn_and_frequency = dict([
             (sequence_number, frequency_of_label)
             for sequence_number, frequency_of_label in enumerate(
                 dict_of_frequency_of_label.keys(), 1)
         ])
         list_of_mapping_points = []
         for sequence_number, frequency_of_label in dict_of_sn_and_frequency.items(
         ):
             list_of_mapping_points.extend([[sequence_number]] *
                                           frequency_of_label)
         clf = IsolationForest(n_estimators=120, contamination='auto')
         clf.fit(list_of_mapping_points)
         for sequence_number, frequency_of_label in dict_of_sn_and_frequency.items(
         ):
             if clf.predict([[sequence_number]])[0] == 1:
                 label_item = dict_of_frequency_of_label.__getitem__(
                     frequency_of_label)
                 digraph_of_node_labels_and_frequencies.add_edge(
                     graph_of_node, label_item, weight=frequency_of_label)
     return digraph_of_node_labels_and_frequencies
Beispiel #3
0
class buchi_graph(object):
    """ construct buchi automaton graph
    Parameter:
        formula: LTL formula specifying task
    """
    def __init__(self, formula):
        self.formula = formula

    def formulaParser(self):
        """replace letter with symbol
        """
        indicator = 'FG'

        if [True for i in indicator if i in self.formula]:
            self.formula.replace('F', '<>').replace('G', '[]')

    def execLtl2ba(self):
        """ given formula, exectute the ltl2ba
        Parameter:
            buchi_str: output string of program ltl2ba  (utf-8 format)
        """

        dirname = os.path.dirname(__file__)
        self.buchi_str = subprocess.check_output(dirname + "/./ltl2ba -f \"" +
                                                 self.formula + "\"",
                                                 shell=True).decode("utf-8")

    def buchiGraph(self):
        """parse the output of ltl2ba
        Parameter:
            buchi_graph: Graph of buchi automaton
        """
        # find all states
        state_re = re.compile(r'\n(\w+):\n\t')
        state_group = re.findall(state_re, self.buchi_str)

        # find initial and accepting states
        init = [s for s in state_group if 'init' in s]
        accep = [s for s in state_group if 'accept' in s]
        """
        Format:
            buchi_graph.node = NodeView(('T0_init', 'T1_S1', 'accept_S1'))
            buchi_graph.edges = OutEdgeView([('T0_init', 'T0_init'), ('T0_init', 'T1_S1'),....])
            buchi_graph.succ = AdjacencyView({'T0_init': {'T0_init': {'label': '1'}, 'T1_S1': {'label': 'r3'}}})
        """
        self.buchi_graph = DiGraph(type='buchi', init=init, accept=accep)
        for state in state_group:
            # for each state, find transition relation
            # add node
            self.buchi_graph.add_node(state)
            state_if_fi = re.findall(state + r':\n\tif(.*?)fi', self.buchi_str,
                                     re.DOTALL)
            if state_if_fi:
                relation_group = re.findall(r':: \((.*?)\) -> goto (\w+)\n\t',
                                            state_if_fi[0])
                for (label, state_dest) in relation_group:
                    # add edge
                    self.buchi_graph.add_edge(state, state_dest, label=label)

        return self.buchi_graph
Beispiel #4
0
def build_crm(roadmap_dir='./build_roadmap/roadmap_2D.p',
              wsn_rate_dir='./wsn_routing/rate_map.p',
              ws_img_dir='./build_roadmap/ws_img.p'):
    '''
    build combined roadmap, crm
    via load roadmap and merge in wsn_rate info
    '''
    roadmap_edges = pickle.load(open(roadmap_dir, 'rb'))
    wsn_rate, wifis_loc, sink_loc = pickle.load(open(wsn_rate_dir, 'rb'))
    img = pickle.load(open(ws_img_dir, 'rb'))
    crm = DiGraph(name='combined_model',
                  ws_img=img,
                  wifis=wifis_loc,
                  sink=sink_loc)
    for e in roadmap_edges:
        (f_node, t_node) = e
        near_f_node = min(wsn_rate.keys(), key=lambda p: dist_2D(p, f_node))
        f_node_rate = wsn_rate[near_f_node]
        crm.add_node(f_node, rate=f_node_rate)
        near_t_node = min(wsn_rate.keys(), key=lambda p: dist_2D(p, t_node))
        t_node_rate = wsn_rate[near_t_node]
        crm.add_node(t_node, rate=t_node_rate)
        # interpolation
        dist_e = dist_2D(f_node, t_node)
        f_t_rate = intp_rate(f_node_rate, t_node_rate)
        crm.add_edge(f_node, t_node, rate=f_t_rate, dist=dist_e)
        t_f_rate = intp_rate(t_node_rate, f_node_rate)
        crm.add_edge(t_node, f_node, rate=t_f_rate, dist=dist_e)
    print '---crm constructed from %s and %s, %d nodes, %d edges---' % (
        roadmap_dir, wsn_rate_dir, len(crm.nodes()), len(crm.edges()))
    return crm
Beispiel #5
0
 def _digraph(self, index):
     g = DiGraph()
     g.add_node(index[self])
     for _, (fun, _) in self.calls:
         g.add_node(index[fun])
         g.add_edge(index[fun], index[self])
         g = networkx.compose(g, fun._digraph(index))
     return g
Beispiel #6
0
def load_graph(file_or_path:FileOrPath, ext:str=None) -> DiGraph:
  graph = DiGraph()
  for adj in load_jsonl(text_file_for(file_or_path)):
    src = adj[0]
    graph.add_node(src)
    for dst in adj[1:]:
      graph.add_edge(src, dst)
  return graph
Beispiel #7
0
def hoftask(init, buchi_graph, regions):
    h_task = DiGraph(type='subtask')
    try:
        label = to_dnf(
            buchi_graph.edges[(buchi_graph.graph['init'][0],
                               buchi_graph.graph['init'][0])]['label'], True)
    except KeyError:
        # no self loop
        label = to_dnf('0')
    init_node = State((init, buchi_graph.graph['init'][0]), label)
    h_task.add_node(init_node)
    open_set = list()
    open_set.append(init_node)
    explore_set = list()

    while open_set:
        curr = open_set.pop(0)

        # assume co-safe
        # if curr.q in buchi_graph.graph['accept']:
        #     continue
        # print(curr)
        for q_b in buchi_graph.succ[curr.q]:

            try:
                label = to_dnf(buchi_graph.edges[(q_b, q_b)]['label'], True)
            except KeyError:
                # no self loop
                label = to_dnf('0')
            if q_b != curr.q:  # and q_b not in buchi_graph.graph['accept']:
                # region corresponding to the label/word
                edge_label = (buchi_graph.edges[(curr.q, q_b)]['label'])
                if edge_label == '(1)':
                    x_set = [curr.x]
                else:
                    x_set = target(to_dnf(edge_label), regions)
                if x_set:
                    for x in x_set:
                        cand = State((x, q_b), label)
                        # print(cand)
                        if cand not in open_set and cand not in explore_set:
                            open_set.append(cand)
                            # check the match with each subtask in h_task
                            if not match(h_task, curr, cand):
                                # print(cand)
                                h_task.add_node(cand)
                                h_task.add_edge(curr, cand)
                                # continue
                            # roots for accepting states
                            # if q_b in buchi_graph.graph['accept']:
                            #     h_task.add_edge(curr, cand)

        explore_set.append(curr)
    # for x in h_task.nodes:
    #     print(x)
    return h_task
Beispiel #8
0
class SimpleGraphDB\
(
    Generic[SimpleVertexLabel, VertexData], 
    PartiallyStatefulDirectedGraphInterface[SimpleVertexLabel, VertexData],
    StatefulVertexGraphLoaderInterface[SimpleVertexLabel, VertexData]
):
    '''
    Class that can write stateful vertices and stateless directed edges into a graph-like structure.
    '''

    __graph: DiGraph

    '''
    Property and dunder methods
    '''

    def __init__(self, *args: Any, **kwargs: Any) -> None:
        '''
        Sets up a `networkx.DiGraph` structure for writing stateful vertices and stateless direWcted edges.
        '''
        self.__graph = DiGraph()

        return None

    @property
    def _graph(self) -> DiGraph: return self.__graph

    '''
    ABC extensions.
    '''

    def write_stateful_vertex_(self, label: SimpleVertexLabel, data: VertexData, *args: Any, **kwargs: Any) -> None:
        '''
        Writes a vertex with this `label` associated with this `data` into a `networkx.DiGraph` object.
        '''
        self.__graph.add_node(node_for_adding = label, data = data)

        return None

    def write_stateless_directed_edge_(self, source: SimpleVertexLabel, destination: SimpleVertexLabel, *args: Any, **kwargs: Any) -> None:
        '''
        Writes an unlabelled edge between a vertex with this `source` label and one with this `destination` label into a `networkx.DiGraph` object.
        '''
        self.__graph.add_edge(u_of_edge = source, v_of_edge = destination)

        return None

    def load_stateful_vertex(self, label: SimpleVertexLabel, *args: Any, **kwargs: Any) -> VertexData:
        '''
        Loads the `VertexData` associated with this `label` from a `networkx.DiGraph` object.
        '''
        return self.__graph.nodes[label].get('data')
Beispiel #9
0
def buchi_from_ltl(formula,Type):
    promela_string = run_ltl2ba(formula)
    symbols = find_symbols(formula)
    edges = parse_ltl(promela_string)
    (states, initials, accepts) = find_states(edges)
    buchi = DiGraph(type=Type, initial=initials, accept=accepts, symbols=symbols)
    for state in states:
        buchi.add_node(state)
    for (ef,et) in edges.keys():
        guard_formula = edges[(ef,et)]
        guard_expr = parse_guard(guard_formula)
        buchi.add_edge(ef, et, guard=guard_expr, guard_formula=guard_formula)
    return buchi
Beispiel #10
0
class BoardGraph(object):
    def walk(self, board, size_limit=maxint):
        pending_nodes = []
        self.graph = DiGraph()
        self.start = board.display(cropped=True)
        self.graph.add_node(self.start)
        pending_nodes.append(self.start)
        self.min_domino_count = len(board.dominoes)
        while pending_nodes:
            if len(self.graph) >= size_limit:
                raise GraphLimitExceeded(size_limit)
            state = pending_nodes.pop()
            board = Board.create(state, border=1)
            dominoes = set(board.dominoes)
            self.min_domino_count = min(self.min_domino_count, len(dominoes))
            for domino in dominoes:
                dx, dy = domino.direction
                self.try_move(state, domino, dx, dy, pending_nodes)
                self.try_move(state, domino, -dx, -dy, pending_nodes)
        self.last = state
        return set(self.graph.nodes())

    def try_move(self, old_state, domino, dx, dy, pending_states):
        try:
            new_state = self.move(domino, dx, dy)
            move = domino.describe_move(dx, dy)
            if not self.graph.has_node(new_state):
                # new node
                self.graph.add_node(new_state)
                pending_states.append(new_state)
            self.graph.add_edge(old_state, new_state, move=move)
        except BoardError:
            pass

    def move(self, domino, dx, dy):
        """ Move a domino and calculate the new board state.

        Afterward, put the board back in its original state.
        @return: the new board state
        @raise BoardError: if the move is illegal
        """
        domino.move(dx, dy)
        try:
            board = domino.head.board
            if not board.isConnected():
                raise BoardError('Board is not connected.')
            if board.hasLoner():
                raise BoardError('Board has a lonely domino.')
            return board.display(cropped=True)
        finally:
            domino.move(-dx, -dy)
Beispiel #11
0
    def load_from_graphml(path):
        """
        :type path: str
        :rtype: networkx.classes.graph.Graph
        """
        #: :type : networkx.classes.graph.Graph
        g1 = nx.read_graphml(path)
        #: :type graph: networkx.classes.digraph.DiGraph
        g2 = DiGraph()

        typetest = re.compile(r"([a-zA-z]+)(\d*)")

        max_qualifiers = dict(crossing=0, poi=0, plcs=0)
        node_mapping = dict()

        for node, data in g1.nodes_iter(data=True):

            m = typetest.match(data["label"])
            if m is None:
                raise(SALMAException("Wrong label format for node {}!".format(node)))

            loctype = m.group(1)
            if loctype in ["c"]:
                loctype = "crossing"
            elif loctype in ["p"]:
                loctype = "poi"
            elif loctype in ["pl"]:
                loctype = "plcs"
            if loctype not in ["poi", "plcs", "crossing"]:
                raise(SALMAException("Wrong loctype for node {}: {}".format(node, loctype)))
            qualifier = m.group(2)
            if len(qualifier) == 0:
                qualifier = max_qualifiers[loctype] + 1
                nid = data["label"] + str(qualifier)
            else:
                nid = data["label"]
            max_qualifiers[loctype] = max(max_qualifiers[loctype], qualifier)

            pos = (round(float(data["x"])), round(float(data["y"])))

            g2.add_node(nid, pos=pos, scaled_pos=pos, loctype=loctype)
            node_mapping[node] = nid

        for u, v in g1.edges_iter():
            n1 = node_mapping[u]
            n2 = node_mapping[v]
            g2.add_edge(n1, n2)
            g2.add_edge(n2, n1)

        MapGenerator.__add_roadlengths(g2)
        return g2
Beispiel #12
0
 def construct_arg_crm(self):
     arg_crm = DiGraph()
     for wp_f in self.crm.nodes_iter():
         for d_f in iter(self.data_set):
             s_f = (wp_f, d_f)
             arg_crm.add_node(s_f)
             for wp_t in self.crm.neighbors(wp_f):
                 d_evolve = d_f - self.crm.edge[wp_f][wp_t][
                     'rate'] * self.sample_time - 2 * self.quant_size
                 d_t = [d for d in self.data_set if d >= d_evolve][0]
                 s_t = (wp_t, d_t)
                 arg_crm.add_edge(s_f, s_t, weight=1.0)
     print '---static argumented crm constructed: %d nodes, %d edges----' % (
         len(arg_crm.nodes()), len(arg_crm.edges()))
     self.arg_crm = arg_crm
Beispiel #13
0
    def setUp(self):
        graph = DiGraph()
        graph.add_cycle([1, 2, 3, 4])
        graph.add_cycle([5, 6, 7, 8])
        graph.add_node(0)
        graph.add_edge(9, 10)
        self.graph_1 = graph

        graph = DiGraph()
        graph.add_cycle([1, 2, 3, 4])
        graph.add_cycle([5, 6, 7, 8])
        graph.add_node(0)
        graph.add_edge(9, 10)
        graph.add_edge(3, 9)
        graph.add_edge(10, 7)
        self.graph_2 = graph
Beispiel #14
0
def DuoBA_from_ltls(hard_spec, soft_spec):
    hard_buchi = buchi_from_ltl(hard_spec, 'hard_buchi')
    soft_buchi = buchi_from_ltl(soft_spec, 'soft_buchi')
    hard_symbols = hard_buchi.graph['symbols']
    soft_symbols = soft_buchi.graph['symbols']
    symbols = set(hard_symbols).union(set(soft_symbols))
    DuoBA = DiGraph(type='safe_buchi',
                    hard=hard_buchi,
                    soft=soft_buchi,
                    symols=symbols)
    initial = set()
    accept = set()
    for (h_node, s_node, l) in cartesian_product(hard_buchi.nodes(),
                                                 soft_buchi.nodes(), [1, 2]):
        DuoNode = (h_node, s_node, l)
        DuoBA.add_node(DuoNode, hard=h_node, soft=s_node, level=l)
        if (h_node in hard_buchi.graph['initial']
                and s_node in soft_buchi.graph['initial'] and l == 1):
            initial.add(DuoNode)
        if (h_node in hard_buchi.graph['accept'] and l == 1):
            accept.add(DuoNode)
    DuoBA.graph['accept'] = accept
    DuoBA.graph['initial'] = initial
    for f_duonode in DuoBA.nodes_iter():
        for t_duonode in DuoBA.nodes_iter():
            f_h_node, f_s_node, f_level = check_duo_attr(DuoBA, f_duonode)
            t_h_node, t_s_node, t_level = check_duo_attr(DuoBA, t_duonode)
            if (t_h_node not in DuoBA.graph['hard'].neighbors(f_h_node) or
                    t_s_node not in DuoBA.graph['soft'].neighbors(f_s_node)):
                continue
                # relaxed because no common input alphabets are enabled
            hardguard = DuoBA.graph['hard'].edge[f_h_node][t_h_node]['guard']
            softguard = DuoBA.graph['soft'].edge[f_s_node][t_s_node]['guard']
            if ((f_h_node not in DuoBA.graph['hard'].graph['accept']
                 and f_level == 1 and t_level == 1)
                    or (f_h_node in DuoBA.graph['hard'].graph['accept']
                        and f_level == 1 and t_level == 2)
                    or (f_s_node not in DuoBA.graph['soft'].graph['accept']
                        and f_level == 2 and t_level == 2)
                    or (f_s_node in DuoBA.graph['soft'].graph['accept']
                        and f_level == 2 and t_level == 1)):
                DuoBA.add_edge(f_duonode,
                               t_duonode,
                               hardguard=hardguard,
                               softguard=softguard)
    return DuoBA
def buchi_from_ltl(formula, Type1):
    promela_string = "never { /* G(goods->Xdepot)&&G(depot->Xgoods)&&(G(!b)&&G(!door||open)) */    accept_init :    /* init */    if	:: (!goods && !depot && !b && !door) || (!goods && !depot && !b && open) -> goto accept_init	:: (!goods && !b && !door) || (!goods && !b && open) -> goto accept_S2	:: (!depot && !b && !door) || (!depot && !b && open) -> goto accept_S3	:: (!b && !door) || (!b && open) -> goto accept_S4	fi;accept_S2 :    /* 1 */	if	:: (goods && !depot && !b && !door) || (goods && !depot && !b && open) -> goto accept_S3	:: (goods && !b && !door) || (goods && !b && open) -> goto accept_S4	fi;accept_S3 :    /* 2 */	if	:: (!goods && depot && !b && !door) || (!goods && depot && !b && open) -> goto accept_S2	:: (depot && !b && !door) || (depot && !b && open) -> goto accept_S4	fi;accept_S4 :    /* 3 */	if	:: (goods && depot && !b && !door) || (goods && depot && !b && open) -> goto accept_S4	fi;}"
    #promela_string = run_ltl2ba(formula)
    symbols = find_symbols(formula)
    edges = parse_ltl(promela_string)
    (states, initials, accepts) = find_states(edges)
    buchi = DiGraph(type=Type,
                    initial=initials,
                    accept=accepts,
                    symbols=symbols)
    for state in states:
        buchi.add_node(state)
    for (ef, et) in edges.keys():
        guard_formula = edges[(ef, et)]
        guard_expr = parse_guard(guard_formula)
        buchi.add_edge(ef, et, guard=guard_expr, guard_formula=guard_formula)
    return buchi
Beispiel #16
0
    def _build_ast(cls, rpn_expression):
        """build an AST from an Excel formula

        :param rpn_expression: a string formula or the result of parse_to_rpn()
        :return: AST which can be used to generate code
        """

        # use a directed graph to store the syntax tree
        tree = DiGraph()

        # production stack
        stack = []

        for node in rpn_expression:
            # The graph does not maintain the order of adding nodes/edges, so
            # add an attribute 'pos' so we can always sort to the correct order

            node.ast = tree
            if isinstance(node, OperatorNode):
                if node.token.type == node.token.OP_IN:
                    try:
                        arg2 = stack.pop()
                        arg1 = stack.pop()
                    except IndexError:
                        raise FormulaParserError(
                            "'{}' operator missing operand".format(
                                node.token.value))
                    tree.add_node(arg1, pos=0)
                    tree.add_node(arg2, pos=1)
                    tree.add_edge(arg1, node)
                    tree.add_edge(arg2, node)
                else:
                    try:
                        arg1 = stack.pop()
                    except IndexError:
                        raise FormulaParserError(
                            "'{}' operator missing operand".format(
                                node.token.value))
                    tree.add_node(arg1, pos=1)
                    tree.add_edge(arg1, node)

            elif isinstance(node, FunctionNode):
                if node.num_args:
                    args = stack[-node.num_args:]
                    del stack[-node.num_args:]
                    for i, a in enumerate(args):
                        tree.add_node(a, pos=i)
                        tree.add_edge(a, node)
            else:
                tree.add_node(node, pos=0)

            stack.append(node)

        assert 1 == len(stack)
        return stack[0]
Beispiel #17
0
    def _build_ast(cls, rpn_expression):
        """build an AST from an Excel formula

        :param rpn_expression: a string formula or the result of parse_to_rpn()
        :return: AST which can be used to generate code
        """

        # use a directed graph to store the syntax tree
        tree = DiGraph()

        # production stack
        stack = []

        for node in rpn_expression:
            # The graph does not maintain the order of adding nodes/edges, so
            # add an attribute 'pos' so we can always sort to the correct order

            node.ast = tree
            if isinstance(node, OperatorNode):
                if node.token.type == node.token.OP_IN:
                    try:
                        arg2 = stack.pop()
                        arg1 = stack.pop()
                    except IndexError:
                        raise FormulaParserError(
                            "'{}' operator missing operand".format(
                                node.token.value))
                    tree.add_node(arg1, pos=0)
                    tree.add_node(arg2, pos=1)
                    tree.add_edge(arg1, node)
                    tree.add_edge(arg2, node)
                else:
                    try:
                        arg1 = stack.pop()
                    except IndexError:
                        raise FormulaParserError(
                            "'{}' operator missing operand".format(
                                node.token.value))
                    tree.add_node(arg1, pos=1)
                    tree.add_edge(arg1, node)

            elif isinstance(node, FunctionNode):
                if node.num_args:
                    args = stack[-node.num_args:]
                    del stack[-node.num_args:]
                    for i, a in enumerate(args):
                        tree.add_node(a, pos=i)
                        tree.add_edge(a, node)
            else:
                tree.add_node(node, pos=0)

            stack.append(node)

        assert 1 == len(stack)
        return stack[0]
Beispiel #18
0
def hoftask_no_simplified(init, buchi_graph, regions):
    try:
        label = to_dnf(
            buchi_graph.edges[(buchi_graph.graph['init'][0],
                               buchi_graph.graph['init'][0])]['label'], True)
    except KeyError:
        # no self loop
        label = to_dnf('0')
    init_node = State((init, buchi_graph.graph['init'][0]), label)
    h_task = DiGraph(type='subtask', init=init_node)
    h_task.add_node(init_node)
    open_set = list()
    open_set.append(init_node)
    explore_set = list()

    while open_set:
        curr = open_set.pop(0)
        for q_b in buchi_graph.succ[curr.q]:
            try:
                label = to_dnf(buchi_graph.edges[(q_b, q_b)]['label'], True)
            except KeyError:
                # no self loop
                label = to_dnf('0')
            if q_b != curr.q:
                # region corresponding to the label/word
                edge_label = (buchi_graph.edges[(curr.q, q_b)]['label'])
                if edge_label == '(1)':
                    x_set = [curr.x]
                elif '~' in edge_label and to_dnf(edge_label).nargs == {
                        1
                }:  # ~l3_1
                    x_set = [curr.x]  # !!!!!!!
                else:
                    x_set = target(to_dnf(edge_label), regions)
                if x_set:
                    for x in x_set:
                        cand = State((x, q_b), label)
                        #  whether cand is already in the h_task
                        # cand = find_node(cand, h_task)
                        h_task.add_edge(curr, cand)
                        if cand not in open_set and cand not in explore_set:
                            open_set.append(cand)

        explore_set.append(curr)
    return h_task
Beispiel #19
0
 def add_node(self, n, attr_dict=None, dHdS=(0, 0), **attr):
     """ Add state node n to reaction graph. """
     assert n not in self.adj   # edge-attrs dict, {src: {tgt1: {edge1_attrs}, ...}}
     # print("ReactionGraph.add_node(%s, %s, %s, %s)" % (n, attr_dict, dHdS, attr))
     if attr_dict is None:
         attr_dict = attr
     elif attr:
         attr_dict.update(attr)
     # First dispatch
     attr_dict['dHdS'] = dHdS
     attr_dict['encounters'] = 1
     for dispatcher in self.dispatchers:
         dispatcher.add_node(n, attr_dict)
     attr_dict['dHdS_count'] = {dHdS: 1}
     # MultiGraph, with edges keyed by (reacted_spec_pair, reaction_attr):
     # reaction_graph.adj[source][target][(reacted_spec_pair, reaction_attr)] = eattr
     #self.reaction_graph.add_node(target_state, node_attrs)
     DiGraph.add_node(self, n, attr_dict)
def build_txs_graph(datadir: str) -> DiGraph:
    """
    read all block and transaction files in the given datadir and construct
    a full transaction graph.
    
    Each node represents a transaction. the node's id is the txid and it has
    the following attributes:
        - "tx" - the full tx json, as returned by bitcoind
        - "fee" - the tx fee
        - "height" - the block height in which the tx was included
    
    Each edge has the following attributes:
        - "value" the value in BTC of the output represented by this edge
        
    """
    blocks = load_blocks(datadir)
    txs = load_txs(datadir)

    txid_to_fee = {txid: find_tx_fee(txid, txs) for txid in txs.keys()}
    txid_to_height = {
        txid: block["height"]
        for block in blocks.values() for txid in block["tx"]
    }

    graph = DiGraph()

    # add all transactions
    for txid in txs.keys():
        graph.add_node(txid,
                       tx=txs[txid],
                       fee=txid_to_fee[txid],
                       height=txid_to_height[txid])

    # add edges between transactions
    for dest_txid, dest_tx in txs.items():
        for entry in dest_tx["vin"]:
            if "coinbase" in entry:
                continue  # coinbase transaction. no src
            src_txid = entry["txid"]
            index = entry["vout"]
            value = txs[src_txid]["vout"][index]["value"]
            graph.add_edge(src_txid, dest_txid, value=value)

    return graph
Beispiel #21
0
def find_SCCs(mdp, Sneg):
    #----simply find strongly connected components----
    print 'Remaining states size', len(Sneg)
    SCC  = set()
    simple_digraph = DiGraph()
    A = dict()
    for s in mdp.nodes():
        A[s] = mdp.node[s]['act'].copy()
    for s_f in Sneg:
        if s_f not in simple_digraph:
            simple_digraph.add_node(s_f)
        for s_t in mdp.successors_iter(s_f):
            if s_t in Sneg:
                simple_digraph.add_edge(s_f,s_t)
    print "SubGraph of one Sf: %s states and %s edges" %(str(len(simple_digraph.nodes())), str(len(simple_digraph.edges())))
    sccs = strongly_connected_component_subgraphs(simple_digraph)
    for scc in sccs:
        SCC.add(frozenset(scc.nodes()))    
    return SCC, A
Beispiel #22
0
def build_graph(num_grid, t):
    env = DiGraph(name='Environment')

    open_set = set()
    explore_set = set()
    r = round(1 / num_grid, 10)
    open_set.add((round(r / 2, 10), round(r / 2, 10)))
    while open_set:
        point = open_set.pop()
        env.add_node(point)
        fea_point = direction(point, r, t)
        for p in fea_point:
            env.add_edge(point, p)
            env.add_edge(p, point)
            if point not in explore_set:
                open_set.add(p)
        explore_set.add(point)

    return env
Beispiel #23
0
def create_graph_with_new_data():
    '''
    A DiGraph object holds directed edges
    - Parallel edges still aren't allowed
        - For a Digraph, two edges are parallel if they connect the same ordered pair of vertices
            - Thus, two edges that connect the same vertices but go in different directions are not parallel
    '''
    # Create with edge list
    g = DiGraph([(1, 5), (5, 1)]) 
    #g = Graph([(1, 5), (5, 1)]) 
    g.add_node(6)
    print(g.nodes()) # [1, 5, 6]
    # These are two distinct edges
    print(g.edges()) # [(1, 5), (5, 1)]
    print(g.neighbors(1)) # [5]
    print(g.neighbors(5)) # [1]
    g.edge[1][5]['foo'] = 'bar'
    print(g.edge[1][5]) # {'foo': 'bar'}
    print(g.edge[5][1]) # {}
Beispiel #24
0
def build_ast(expression, debug = False):
    """build an AST from an Excel formula expression in reverse polish notation"""
    #use a directed graph to store the tree
    G = DiGraph()
    stack = []


    for n in expression:
        # Since the graph does not maintain the order of adding nodes/edges
        # add an extra attribute 'pos' so we can always sort to the correct order
        if isinstance(n,OperatorNode):
            if n.ttype == "operator-infix":
                arg2 = stack.pop()
                arg1 = stack.pop()
                # Hack to write the name of sheet in 2argument address
                if(n.tvalue == ':'):
                    if '!' in arg1.tvalue and arg2.ttype == 'operand' and '!' not in arg2.tvalue:
                        arg2.tvalue = arg1.tvalue.split('!')[0] + '!' + arg2.tvalue
                    
                G.add_node(arg1,{'pos':1})
                G.add_node(arg2,{'pos':2})
                G.add_edge(arg1, n)
                G.add_edge(arg2, n)
            else:
                arg1 = stack.pop()
                G.add_node(arg1,{'pos':1})
                G.add_edge(arg1, n)
                
        elif isinstance(n,FunctionNode):
            args = []
            for _ in range(n.num_args):
                try:
                    args.append(stack.pop())
                except:
                    raise Exception()
            #try:
                # args = [stack.pop() for _ in range(n.num_args)]
            #except:
            #        print 'STACK', stack, type(n)
            #        raise Exception('prut')
            args.reverse()
            for i,a in enumerate(args):
                G.add_node(a,{'pos':i})
                G.add_edge(a,n)

        else:
            G.add_node(n,{'pos':0})

        stack.append(n)

    return G,stack.pop()
Beispiel #25
0
def build_ast(expression, debug=False):
    """build an AST from an Excel formula expression in reverse polish notation"""
    #use a directed graph to store the tree
    G = DiGraph()
    stack = []

    for n in expression:
        # Since the graph does not maintain the order of adding nodes/edges
        # add an extra attribute 'pos' so we can always sort to the correct order
        if isinstance(n, OperatorNode):
            if n.ttype == "operator-infix":
                arg2 = stack.pop()
                arg1 = stack.pop()
                # Hack to write the name of sheet in 2argument address
                if (n.tvalue == ':'):
                    if '!' in arg1.tvalue and arg2.ttype == 'operand' and '!' not in arg2.tvalue:
                        arg2.tvalue = arg1.tvalue.split(
                            '!')[0] + '!' + arg2.tvalue

                G.add_node(arg1, {'pos': 1})
                G.add_node(arg2, {'pos': 2})
                G.add_edge(arg1, n)
                G.add_edge(arg2, n)
            else:
                arg1 = stack.pop()
                G.add_node(arg1, {'pos': 1})
                G.add_edge(arg1, n)

        elif isinstance(n, FunctionNode):
            args = []
            for _ in range(n.num_args):
                try:
                    args.append(stack.pop())
                except:
                    raise Exception()
            #try:
            # args = [stack.pop() for _ in range(n.num_args)]
            #except:
            #        print 'STACK', stack, type(n)
            #        raise Exception('prut')
            args.reverse()
            for i, a in enumerate(args):
                G.add_node(a, {'pos': i})
                G.add_edge(a, n)

        else:
            G.add_node(n, {'pos': 0})

        stack.append(n)

    return G, stack.pop()
Beispiel #26
0
def DuoBA_from_ltls(hard_spec, soft_spec):
    hard_buchi = buchi_from_ltl(hard_spec, 'hard_buchi')
    soft_buchi = buchi_from_ltl(soft_spec, 'soft_buchi')
    hard_symbols = hard_buchi.graph['symbols']
    soft_symbols = soft_buchi.graph['symbols']
    symbols = set(hard_symbols).union(set(soft_symbols))
    DuoBA = DiGraph(type='safe_buchi', hard=hard_buchi, soft=soft_buchi, symols=symbols)
    initial = set()
    accept = set()
    for (h_node, s_node, l) in cartesian_product(hard_buchi.nodes(), soft_buchi.nodes(), [1, 2]):
        DuoNode = (h_node, s_node, l)
        DuoBA.add_node(DuoNode,hard=h_node, soft=s_node, level=l)
        if (h_node in hard_buchi.graph['initial'] and 
            s_node in soft_buchi.graph['initial'] and l == 1):
            initial.add(DuoNode)
        if (h_node in hard_buchi.graph['accept'] and l == 1):
            accept.add(DuoNode)
    DuoBA.graph['accept'] = accept
    DuoBA.graph['initial'] = initial
    for f_duonode in DuoBA.nodes():
        for t_duonode in DuoBA.nodes():
            f_h_node, f_s_node, f_level = check_duo_attr(DuoBA, f_duonode)
            t_h_node, t_s_node, t_level = check_duo_attr(DuoBA, t_duonode)
            if (t_h_node not in DuoBA.graph['hard'].neighbors(f_h_node) or 
                t_s_node not in DuoBA.graph['soft'].neighbors(f_s_node)):
                continue
                # relaxed because no common input alphabets are enabled
            hardguard = DuoBA.graph['hard'].edges[f_h_node,t_h_node]['guard']
            softguard = DuoBA.graph['soft'].edges[f_s_node,t_s_node]['guard']
            if ((f_h_node not in DuoBA.graph['hard'].graph['accept'] and 
                f_level == 1 and t_level == 1) or 
                (f_h_node in DuoBA.graph['hard'].graph['accept'] and 
                f_level == 1 and t_level == 2) or 
                (f_s_node not in DuoBA.graph['soft'].graph['accept'] and 
                f_level == 2 and t_level == 2) or 
                (f_s_node in DuoBA.graph['soft'].graph['accept'] and 
                f_level == 2 and t_level == 1)):
                DuoBA.add_edge(f_duonode, t_duonode, hardguard=hardguard, softguard=softguard)
    return DuoBA
def buchi_from_ltl(formula, Type):
    promela_string = run_ltl2ba(formula)
    symbols = find_symbols(formula)
    # print "Output from symbols"
    # print symbols
    edges = parse_ltl(promela_string)
    (states, initials, accepts) = find_states(edges)
    # print "Output from find_states"
    # print states
    # print initials
    # print accepts
    buchi = DiGraph(type=Type,
                    initial=initials,
                    accept=accepts,
                    symbols=symbols)
    for state in states:
        buchi.add_node(state)
    for (ef, et) in edges.keys():
        guard_formula = edges[(ef, et)]
        guard_expr = parse_guard(guard_formula)
        buchi.add_edge(ef, et, guard=guard_expr, guard_formula=guard_formula)
    # write_dot(buchi, "./result.dot")
    return buchi
Beispiel #28
0
def build_ast(expression):

    """build an AST from an Excel formula expression in reverse polish notation"""
    
    #use a directed graph to store the tree
    G = DiGraph()
    
    stack = []
    
    for n in expression:
        # Since the graph does not maintain the order of adding nodes/edges
        # add an extra attribute 'pos' so we can always sort to the correct order
        if isinstance(n,OperatorNode):
            if n.ttype == "operator-infix":
                arg2 = stack.pop()
                arg1 = stack.pop()
                G.add_node(arg1,{'pos':1})
                G.add_node(arg2,{'pos':2})
                G.add_edge(arg1, n)
                G.add_edge(arg2, n)
            else:
                arg1 = stack.pop()
                G.add_node(arg1,{'pos':1})
                G.add_edge(arg1, n)
                
        elif isinstance(n,FunctionNode):
            args = [stack.pop() for _ in range(n.num_args)]
            args.reverse()
            for i,a in enumerate(args):
                G.add_node(a,{'pos':i})
                G.add_edge(a,n)
            #for i in range(n.num_args):
            #    G.add_edge(stack.pop(),n)
        else:
            G.add_node(n,{'pos':0})

        stack.append(n)
        
    return G,stack.pop()
Beispiel #29
0
def build_ast(expression):
    """build an AST from an Excel formula expression in reverse polish notation"""

    #use a directed graph to store the tree
    G = DiGraph()

    stack = []

    for n in expression:
        # Since the graph does not maintain the order of adding nodes/edges
        # add an extra attribute 'pos' so we can always sort to the correct order
        if isinstance(n, OperatorNode):
            if n.ttype == "operator-infix":
                arg2 = stack.pop()
                arg1 = stack.pop()
                G.add_node(arg1, {'pos': 1})
                G.add_node(arg2, {'pos': 2})
                G.add_edge(arg1, n)
                G.add_edge(arg2, n)
            else:
                arg1 = stack.pop()
                G.add_node(arg1, {'pos': 1})
                G.add_edge(arg1, n)

        elif isinstance(n, FunctionNode):
            args = [stack.pop() for _ in range(n.num_args)]
            args.reverse()
            for i, a in enumerate(args):
                G.add_node(a, {'pos': i})
                G.add_edge(a, n)
            #for i in range(n.num_args):
            #    G.add_edge(stack.pop(),n)
        else:
            G.add_node(n, {'pos': 0})

        stack.append(n)

    return G, stack.pop()
Beispiel #30
0
def lst_dag(G, r, U,
            node_reward_key='r',
            edge_cost_key='c',
            edge_weight_decimal_point=None,
            fixed_point_func=round,
            debug=False):
    """
    Param:
    -------------
    binary_dag: a DAG in networkx format. Each node can have at most 2 child
    r: root node in dag
    U: the maximum threshold of edge weight sum

    Return:
    maximum-sum subtree rooted at r whose sum of edge weights <= A
    ------------
    """
    # round edge weight to fixed decimal point if necessary

    if edge_weight_decimal_point is not None:
        G = G.copy()
        G, U = round_edge_weights_by_multiplying(
            G,
            U,
            edge_weight_decimal_point,
            edge_cost_key=edge_cost_key,
            fixed_point_func=fixed_point_func
        )

    if debug:
        print('U => {}'.format(U))

    ns = G.nodes()
    if debug:
        print("total #nodes {}".format(len(ns)))
    
    A, D, BP = {}, {}, {}
    for n in ns:
        A[n] = {}  # maximum sum of node u at a cost i
        A[n][0] = G.node[n][node_reward_key]

        D[n] = {}  # set of nodes included corresponding to A[u][i]
        D[n][0] = {n}

        BP[n] = defaultdict(list)  # backpointer corresponding to A[u][i]

    for n_i, n in enumerate(
            topological_sort(G, reverse=True)):  # leaves come first

        if debug:
            print("#nodes processed {}".format(n_i))
        
        children = G.neighbors(n)
        reward = G.node[n][node_reward_key]
        if len(children) == 1:
            child = children[0]
            w = G[n][child][edge_cost_key]
            for i in xrange(U, w - 1, -1):
                if (i-w) in A[child]:
                    A[n][i] = A[child][i-w] + reward
                    D[n][i] = D[child][i-w] | {n}
                    BP[n][i] = [(child, i-w)]
        elif len(children) > 1:
            lchild, rchild = children
            lw = G[n][lchild][edge_cost_key]
            rw = G[n][rchild][edge_cost_key]

            for i in A[lchild]:
                c = lw + i
                if debug:
                    print('n={}, D={}, cost_child_tuples={}'.format(
                        n, D, [(i, lchild)])
                    )
                    print('c={}'.format(c))
                if c <= U:
                    if A[n].get(c) is None or A[lchild][i] + reward > A[n][c]:
                        A[n][c] = A[lchild][i] + reward
                        D[n][c] = D[lchild][i] | {n}
                        BP[n][c] = [(lchild, i)]

            for i in A[rchild]:
                c = rw + i
                if c <= U:
                    if A[n].get(c) is None or A[rchild][i] + reward > A[n][c]:
                        A[n][c] = A[rchild][i] + reward
                        D[n][c] = D[rchild][i] | {n}
                        BP[n][c] = [(rchild, i)]
            
            for i in A[lchild]:
                for j in A[rchild]:
                    c = lw + rw + i + j
                    if c <= U:
                        if (A[n].get(c) is None or
                            A[lchild][i] + A[rchild][j] + reward > A[n][c]) and \
                           len(D[lchild][i] & D[rchild][j]) == 0:
                            A[n][c] = A[lchild][i] + A[rchild][j] + reward
                            D[n][c] = D[lchild][i] | D[rchild][j] | {n}
                            BP[n][c] = [(lchild, i), (rchild, j)]
            
            # if n == r:  # no need to continue once we processed root
            #     break
                
    if debug:
        print('A[r]', A[r])

    best_cost = max(xrange(U + 1),
                    key=lambda i: A[r][i] if i in A[r] else float('-inf'))
    if debug:
        print("best_cost", best_cost)

    tree = DiGraph()
    tree.add_node(r)
    stack = []
    for n, cost in BP[r][best_cost]:
        stack.append((r, n, cost))
    while len(stack) > 0:
        # if debug:
        #     print('stack size: {}'.format(len(stack)))
        #     print('stack: {}'.format(stack))
        
        parent, child, cost = stack.pop(0)
        tree.add_edge(parent, child)

        # copy the attributes
        tree[parent][child] = G[parent][child]
        tree.node[parent] = G.node[parent]
        tree.node[child] = G.node[child]

        for grandchild, cost2 in BP[child][cost]:
            # if debug:
            #     print(grandchild, cost2)
            stack.append((child, grandchild, cost2))

    return tree
Beispiel #31
0
        #     continue

        print(f'Processing log file {filepath}...')
        log = xes_import_factory.apply(filepath)

        print(f'Running Heuristic miner on {label}...')
        net, _i, _f = run_heuristic(log, label,
                                    'dest_class_func',
                                    parameters=heuristic_b_params)

        print(f'Creating graph for petri net...')
        graph = DiGraph()
        all_nodes = set()

        for place in net.places:
            graph.add_node(str(place), label=str(place))
            all_nodes.add(str(place))
        for transition in net.transitions:
            graph.add_node(str(transition), label=str(transition))
            all_nodes.add(str(transition))
        for arc in net.arcs:
            graph.add_edge(str(arc.source), str(arc.target))

        sp_nodes = set([label for label in nodes_in_shortest_path(graph)
                       if heuristic_filter(label)])

        filtered_nodes = set([label for label in all_nodes
                             if heuristic_filter(label)])

        # print("Filtered Nodes")
        # print(filtered_nodes)
Beispiel #32
0
class tree(object):
    """ construction of prefix and suffix tree
    """
    def __init__(self, ts, buchi_graph, init, step_size, base=1e3):
        """
        :param ts: transition system
        :param buchi_graph:  Buchi graph
        :param init: product initial state
        """
        self.robot = 1
        self.goals = []
        self.ts = ts
        self.buchi_graph = buchi_graph
        self.init = init
        self.step_size = step_size
        self.dim = len(self.ts['workspace'])
        uni_v = np.power(np.pi, self.robot * self.dim /
                         2) / math.gamma(self.robot * self.dim / 2 + 1)
        self.gamma = np.ceil(
            4 * np.power(1 / uni_v, 1. /
                         (self.dim * self.robot)))  # unit workspace
        self.tree = DiGraph(type='PBA', init=init)
        label = self.label(init[0])
        if label != '':
            label = label + '_' + str(1)
        # accepting state before current node
        acc = set()
        if 'accept' in init[1]:
            acc.add(init)
        self.tree.add_node(init, cost=0, label=label, acc=acc)
        self.search_goal(init, label, acc)

        # already used skilles
        self.used = set()
        self.base = base

    def sample(self):
        """
        sample point from the workspace
        :return: sampled point, tuple
        """
        x_rand = []
        for i in range(self.dim):
            x_rand.append(uniform(0, self.ts['workspace'][i]))

        return tuple(x_rand)

    def nearest(self, x_rand):
        """
        find the nearest class of vertices in the tree
        :param: x_rand randomly sampled point form: single point ()
        :return: nearest class of vertices form: single point ()
        """
        min_dis = math.inf
        q_nearest = []
        for vertex in self.tree.nodes:
            x_vertex = vertex[0]
            dis = np.linalg.norm(np.subtract(x_rand, x_vertex))
            if dis < min_dis:
                q_nearest = list()
                q_nearest.append(vertex)
                min_dis = dis
            elif dis == min_dis:
                q_nearest.append(vertex)
        return q_nearest

    def steer(self, x_rand, x_nearest):
        """
        steer
        :param: x_rand randomly sampled point form: single point ()
        :param: x_nearest nearest point in the tree form: single point ()
        :return: new point single point ()
        """
        if np.linalg.norm(np.subtract(x_rand, x_nearest)) <= self.step_size:
            return x_rand
        else:
            return tuple(
                np.asarray(x_nearest) + self.step_size *
                (np.subtract(x_rand, x_nearest)) /
                np.linalg.norm(np.subtract(x_rand, x_nearest)))

    def acpt_check(self, q_min, q_new):
        """
        check the accepting state in the patg leading to q_new
        :param q_min:
        :param q_new:
        :return:
        """
        changed = False
        acc = set(self.tree.nodes[q_min]['acc'])  # copy
        if 'accept' in q_new[1]:
            acc.add(q_new)
            # print(acc)
            changed = True
        return acc, changed

    def search_goal(self, q_new, label_new, acc):
        """
        whether q_new can connect to point before acc
        :param q_new:
        :param label_new:
        :param acc:
        :return:
        """
        for ac in acc:
            # connect to path leading to accepting state, including accepting state
            path = self.findpath([ac])[0][1]
            for point in path:
                if list(self.obs_check([q_new], point[0], self.tree.nodes[point]['label']).values())[0] \
                        and self.checkTranB(q_new[1], label_new, point[1]):
                    self.goals.append(
                        (q_new, point,
                         ac))  # endpoint, middle point, accepting point

    def extend(self, q_new, near_v, label, obs_check, succ_list):
        """
        :param: q_new: new state form: tuple (mulp, buchi)
        :param: near_v: near state form: tuple (mulp, buchi)
        :param: obs_check: check obstacle free  form: dict { (mulp, mulp): True }
        :param: succ: list of successor of the root
        :return: extending the tree
        """
        added = 0
        cost = np.inf
        q_min = ()
        for near_vertex in near_v:
            if near_vertex in succ_list:  # do not extend if there is a corresponding root
                continue
            if q_new != near_vertex and obs_check[(q_new[0], near_vertex[0])] \
                    and self.checkTranB(near_vertex[1], self.tree.nodes[near_vertex]['label'], q_new[1]):
                c = self.tree.nodes[near_vertex]['cost'] + \
                    np.linalg.norm(np.subtract(q_new[0], near_vertex[0]))
                if c < cost:
                    added = 1
                    q_min = near_vertex
                    cost = c
        if added == 1:
            self.tree.add_node(q_new, cost=cost, label=label)
            self.tree.nodes[q_new]['acc'] = set(
                self.acpt_check(q_min, q_new)[0])
            self.tree.add_edge(q_min, q_new)
            # self.search_goal(q_new, label, self.tree.nodes[q_new]['acc'])
        return added

    def rewire(self, q_new, near_v, obs_check):
        """
        :param: q_new: new state form: tuple (mul, buchi)
        :param: near_v: near state form: tuple (mul, buchi)
        :param: obs_check: check obstacle free form: dict { (mulp, mulp): True }
        :return: rewiring the tree
        """
        for near_vertex in near_v:
            if obs_check[(q_new[0], near_vertex[0])] \
                    and self.checkTranB(q_new[1], self.tree.nodes[q_new]['label'], near_vertex[1]):
                c = self.tree.nodes[q_new]['cost'] \
                    + np.linalg.norm(np.subtract(q_new[0], near_vertex[0]))
                delta_c = self.tree.nodes[near_vertex]['cost'] - c
                # update the cost of node in the subtree rooted at near_vertex
                if delta_c > 0:
                    # self.tree.nodes[near_vertex]['cost'] = c
                    self.tree.remove_edge(
                        list(self.tree.pred[near_vertex].keys())[0],
                        near_vertex)
                    self.tree.add_edge(q_new, near_vertex)
                    edges = dfs_labeled_edges(self.tree, source=near_vertex)
                    acc, changed = self.acpt_check(q_new, near_vertex)
                    self.tree.nodes[near_vertex]['acc'] = set(acc)
                    for u, v, d in edges:
                        if d == 'forward':
                            self.tree.nodes[v][
                                'cost'] = self.tree.nodes[v]['cost'] - delta_c
                            if changed:
                                self.tree.nodes[v]['acc'] = set(
                                    self.acpt_check(u, v)[0])  # copy
        # better to research the goal but abandon the implementation

    def near(self, x_new):
        """
        find the states in the near ball
        :param x_new: new point form: single point
        :return: p_near: near state, form: tuple (mulp, buchi)
        """
        p_near = []
        r = min(
            self.gamma * np.power(
                np.log(self.tree.number_of_nodes() + 1) /
                self.tree.number_of_nodes(), 1. / (self.dim * self.robot)),
            self.step_size)
        # r = self.step_size
        for vertex in self.tree.nodes:
            if np.linalg.norm(np.subtract(x_new, vertex[0])) <= r:
                p_near.append(vertex)
        return p_near

    def obs_check(self, q_near, x_new, label):
        """
        check whether obstacle free along the line from x_near to x_new
        :param q_near: states in the near ball, tuple (mulp, buchi)
        :param x_new: new state form: multiple point
        :param label: label of x_new
        :param stage: regular stage or final stage, deciding whether it's goal state
        :return: dict (x_near, x_new): true (obs_free)
        """

        obs_check_dict = {}
        checked = set()

        for x in q_near:
            if x[0] in checked:
                continue
            checked.add(x[0])
            obs_check_dict[(x_new, x[0])] = True

            # the line connecting two points crosses an obstacle
            for (obs, boundary) in iter(self.ts['obs'].items()):
                if LineString([Point(x[0]),
                               Point(x_new)]).intersects(boundary):
                    obs_check_dict[(x_new, x[0])] = False
                    break

            for (region, boundary) in iter(self.ts['region'].items()):
                if LineString([Point(x[0]), Point(x_new)]).intersects(boundary) \
                        and region + '_' + str(1) != label \
                        and region + '_' + str(1) != self.tree.nodes[x]['label']:
                    # if stage == 'reg' or (stage == 'final' and region in self.no):
                    obs_check_dict[(x_new, x[0])] = False
                    break

        return obs_check_dict

    def label(self, x):
        """
        generating the label of position state
        :param x: position
        :return: label
        """

        point = Point(x)
        # whether x lies within obstacle
        for (obs, boundary) in iter(self.ts['obs'].items()):
            if point.within(boundary):
                return obs

        # whether x lies within regions
        for (region, boundary) in iter(self.ts['region'].items()):
            if point.within(boundary):
                return region
        # x lies within unlabeled region
        return ''

    def checkTranB(self, b_state, x_label, q_b_new):
        """ decide valid transition, whether b_state --L(x)---> q_b_new
             Algorithm2 in Chapter 2 Motion and Task Planning
             :param b_state: buchi state
             :param x_label: label of x
             :param q_b_new buchi state
             :return True satisfied
        """
        b_state_succ = self.buchi_graph.succ[b_state]
        # q_b_new is not the successor of b_state
        if q_b_new not in b_state_succ:
            return False

        truth = self.buchi_graph.edges[(b_state, q_b_new)]['truth']
        if self.t_satisfy_b_truth(x_label, truth):
            return True

        return False

    def t_satisfy_b_truth(self, x_label, truth):
        """
        check whether transition enabled under current label
        :param x_label: current label
        :param truth: truth value making transition enabled
        :return: true or false
        """
        if truth == '1':
            return True

        true_label = [
            truelabel for truelabel in truth.keys() if truth[truelabel]
        ]
        for label in true_label:
            if label not in x_label:
                return False

        false_label = [
            falselabel for falselabel in truth.keys() if not truth[falselabel]
        ]
        for label in false_label:
            if label in x_label:
                return False

        return True

    def findpath(self, goals):
        """
        find the path backwards
        :param goals: goal state
        :return: dict path : cost
        """
        paths = OrderedDict()
        for i in range(len(goals)):
            goal = goals[i]
            path = [goal]
            s = goal
            while s != self.init:
                s = list(self.tree.pred[s].keys())[0]
                if s == path[0]:
                    print("loop")
                path.insert(0, s)

            paths[i] = [self.tree.nodes[goal]['cost'], path]
        return paths
Beispiel #33
0
class BoardGraph(object):
    def __init__(self, board_class=Board):
        self.graph = self.start = self.last = self.closest = None
        self.min_domino_count = None
        self.board_class = board_class

    def walk(self, board, size_limit=maxsize):
        pending_nodes = []
        self.graph = DiGraph()
        self.start = board.display(cropped=True)
        self.graph.add_node(self.start)
        pending_nodes.append(self.start)
        self.last = self.start
        while pending_nodes:
            if len(self.graph) >= size_limit:
                raise GraphLimitExceeded(size_limit)
            state = pending_nodes.pop()
            board = self.board_class.create(state, border=1)
            for move, new_state in self.generate_moves(board):
                if not self.graph.has_node(new_state):
                    # new node
                    self.graph.add_node(new_state)
                    pending_nodes.append(new_state)
                self.graph.add_edge(state, new_state, move=move)
        return set(self.graph.nodes())

    def generate_moves(self, board):
        """ Generate all moves from the board's current state.

        :param Board board: the current state
        :return: a generator of (state, move_description) tuples
        """
        dominoes = set(board.dominoes)
        domino_count = len(dominoes)
        if self.min_domino_count is None or domino_count < self.min_domino_count:
            self.min_domino_count = domino_count
            self.last = board.display(cropped=True)
        for domino in dominoes:
            dx, dy = domino.direction
            yield from self.try_move(domino, dx, dy)
            yield from self.try_move(domino, -dx, -dy)

    def try_move(self, domino, dx, dy):
        try:
            new_state = self.move(domino, dx, dy)
            move = domino.describe_move(dx, dy)
            yield move, new_state
        except BadPositionError:
            pass

    def move(self, domino, dx, dy):
        """ Move a domino and calculate the new board state.

        Afterward, put the board back in its original state.
        @return: the new board state
        @raise BadPositionError: if the move is illegal
        """
        domino.move(dx, dy)
        try:
            board = domino.head.board
            if not board.isConnected():
                raise BadPositionError('Board is not connected.')
            if board.hasLoner():
                raise BadPositionError('Board has a lonely domino.')
            return board.display(cropped=True)
        finally:
            domino.move(-dx, -dy)

    def get_solution(self, return_partial=False):
        """ Find a solution from the graph of moves.

        @param return_partial: If True, a partial solution will be returned if no
        solution exists.
        @return: a list of strings describing each move. Each string is two
        digits describing the domino that moved plus a letter to show the
        direction.
        """
        solution = []
        goal = self.closest if return_partial else self.last or ''
        solution_nodes = shortest_path(self.graph, self.start, goal)
        for i in range(len(solution_nodes) - 1):
            source, target = solution_nodes[i:i + 2]
            solution.append(self.graph[source][target]['move'])
        return solution

    def get_choice_counts(self):
        solution_nodes = shortest_path(self.graph, self.start, self.last)
        return [len(self.graph[node]) for node in solution_nodes[:-1]]

    def get_average_choices(self):
        choices = self.get_choice_counts()
        return sum(choices) / float(len(choices)) if choices else maxsize

    def get_max_choices(self):
        choices = self.get_choice_counts()
        return max(choices) if choices else maxsize
Beispiel #34
0
def find_MECs(mdp, Sneg):
    #----implementation of Alg.47 P866 of Baier08----
    print 'Remaining states size', len(Sneg)
    U = mdp.graph['U']
    A = dict()
    for s in Sneg:
        A[s] = mdp.node[s]['act'].copy()
        if not A[s]:
            print "Isolated state"
    MEC = set()
    MECnew = set()
    MECnew.add(frozenset(Sneg))
    #----
    k = 0
    while MEC != MECnew:
        print "<============iteration %s============>" %k
        k +=1
        MEC = MECnew
        MECnew = set()
        print "MEC size: %s" %len(MEC)
        print "MECnew size: %s" %len(MECnew)
        for T in MEC:
            R = set()
            T_temp = set(T)
            simple_digraph = DiGraph()
            for s_f in T_temp:
                if s_f not in simple_digraph:
                    simple_digraph.add_node(s_f)
                for s_t in mdp.successors_iter(s_f):
                    if s_t in T_temp:
                        simple_digraph.add_edge(s_f,s_t)
            print "SubGraph of one MEC: %s states and %s edges" %(str(len(simple_digraph.nodes())), str(len(simple_digraph.edges())))
            Sccs = strongly_connected_component_subgraphs(simple_digraph)
            i = 0
            for Scc in Sccs:
                i += 1
                if (len(Scc.edges())>=1):
                    for s in Scc.nodes():
                        U_to_remove = set() 
                        for u in A[s]:
                            for t in mdp.successors_iter(s):
                                if ((u  in mdp.edge[s][t]['prop'].keys()) and (t not in Scc.nodes())):
                                    U_to_remove.add(u)
                        A[s].difference_update(U_to_remove)
                        if not A[s]:                            
                            R.add(s)
            while R:
                s = R.pop()
                T_temp.remove(s)
                for f in mdp.predecessors(s):
                    if f in T_temp:
                        A[f].difference_update(set(mdp.edge[f][s]['prop'].keys()))
                        if not A[f]:
                            R.add(f)
            New_Sccs = strongly_connected_component_subgraphs(simple_digraph)
            j = 0
            for Scc in New_Sccs:
                j += 1
                if (len(Scc.edges()) >= 1):
                    common = set(Scc.nodes()).intersection(T_temp)
                    if common:
                        MECnew.add(frozenset(common))
    #---------------
    print 'Final MEC and MECnew size:', len(MEC)
    return MEC, A
Beispiel #35
0
class StadynaMcgAnalysis:
    def __init__(self):
        self.androGuardObjects = []
        
        self.nodes = {}
        self.nodes_id = {}
        self.entry_nodes = []
        self.G = DiGraph()
        
#         self.internal_methods = []
        #self.GI = DiGraph()
        
        
    def analyseFile(self, vmx, apk):
        vm = vmx.get_vm()
        self.androGuardObjects.append((apk, vm, vmx))

#         self.internal_methods.extend(vm.get_methods())
        
        #creating real internal nodes
        internal_called_methods = vmx.get_tainted_packages().stadyna_get_internal_called_methods()
        for method in internal_called_methods:
            class_name, method_name, descriptor = method
            
            nodeType = None
            if method_name == "<clinit>":
                nodeType = NODE_STATIC_INIT
            elif method_name == "<init>":
                nodeType = NODE_CONSTRUCTOR
            else:
                nodeType = NODE_METHOD
            n = self._get_node(nodeType, (class_name, method_name, descriptor))
            n.set_attribute(ATTR_CLASS_NAME, class_name)
            n.set_attribute(ATTR_METHOD_NAME, method_name)
            n.set_attribute(ATTR_DESCRIPTOR, descriptor)
            self.G.add_node(n.id)
            
        
        
        
        #creating real edges (nodes are already there)
        #currently we are working only with internal packages.
        for j in vmx.get_tainted_packages().get_internal_packages():
            src_class_name, src_method_name, src_descriptor = j.get_src(vm.get_class_manager())
            dst_class_name, dst_method_name, dst_descriptor = j.get_dst(vm.get_class_manager())
             
            n1 = self._get_existed_node((src_class_name, src_method_name, src_descriptor))
#             n1.set_attribute(ATTR_CLASS_NAME, src_class_name)
#             n1.set_attribute(ATTR_METHOD_NAME, src_method_name)
#             n1.set_attribute(ATTR_DESCRIPTOR, src_descriptor)
             
            n2 = self._get_existed_node((dst_class_name, dst_method_name, dst_descriptor))
#             n2.set_attribute(ATTR_CLASS_NAME, dst_class_name)
#             n2.set_attribute(ATTR_METHOD_NAME, dst_method_name)
#             n2.set_attribute(ATTR_DESCRIPTOR, dst_descriptor)
            self.G.add_edge(n1.id, n2.id)
        
        
        
        #adding fake class nodes    
        for method in internal_called_methods:
            src_class_name, src_method_name, src_descriptor = method
            if src_method_name == "<init>" or src_method_name == "<clinit>":
                n1 = self._get_existed_node((src_class_name, src_method_name, src_descriptor))
                n2 = self._get_node(NODE_FAKE_CLASS, src_class_name, None, False)
                n2.set_attribute(ATTR_CLASS_NAME, src_class_name)
                if src_method_name == "<clinit>":
                    self.G.add_edge(n1.id, n2.id)
                elif src_method_name == "<init>":
                    self.G.add_edge(n2.id, n1.id)
                
        
        #real (external) reflection invoke nodes    
        reflection_invoke_paths = analysis.seccon_get_invoke_method_paths(vmx)
        for j in reflection_invoke_paths:
            src_class_name, src_method_name, src_descriptor = j.get_src( vm.get_class_manager() )
            dst_class_name, dst_method_name, dst_descriptor = j.get_dst( vm.get_class_manager() )
            
            n1 = self._get_existed_node((src_class_name, src_method_name, src_descriptor))
            if n1 == None:
                logger.warning("Cannot find the node [%s], where reflection invoke is called!" % (src_class_name, src_method_name, src_descriptor))
                continue
            
            key = "%s %s %s %s %s %s %s" % (src_class_name, src_method_name, src_descriptor, dst_class_name, dst_method_name, dst_descriptor, POSTFIX_REFL_INVOKE)
            n2 = self._get_node(NODE_REFL_INVOKE, key, LABEL_REFL_INVOKE, True)
            n2.set_attribute(ATTR_CLASS_NAME, src_class_name)
            n2.set_attribute(ATTR_METHOD_NAME, src_method_name)
            n2.set_attribute(ATTR_DESCRIPTOR, src_descriptor)
            
            self.G.add_edge( n1.id, n2.id )
            
        
        #real (external) reflection new instance nodes   
        reflection_newInstance_paths = analysis.seccon_get_newInstance_method_paths(vmx)
        for j in reflection_newInstance_paths:
            src_class_name, src_method_name, src_descriptor = j.get_src( vm.get_class_manager() )
            dst_class_name, dst_method_name, dst_descriptor = j.get_dst( vm.get_class_manager() )
            
            n1 = self._get_existed_node((src_class_name, src_method_name, src_descriptor))
            if n1 == None:
                logger.warning("Cannot find the node [%s], where reflection new instance is called!" % (src_class_name, src_method_name, src_descriptor))
                continue
            
            key = "%s %s %s %s %s %s %s" % (src_class_name, src_method_name, src_descriptor, dst_class_name, dst_method_name, dst_descriptor, POSTFIX_REFL_NEWINSTANCE)
            n2 = self._get_node(NODE_REFL_NEWINSTANCE, key, LABEL_REFL_NEWINSTANCE, True)
            n2.set_attribute(ATTR_CLASS_NAME, src_class_name)
            n2.set_attribute(ATTR_METHOD_NAME, src_method_name)
            n2.set_attribute(ATTR_DESCRIPTOR, src_descriptor)
            
            self.G.add_edge( n1.id, n2.id )
        
        
        #adding fake entry points
        if apk != None:
            for i in apk.get_activities() :
                j = bytecode.FormatClassToJava(i)
                n1 = self._get_existed_node((j, "onCreate", "(Landroid/os/Bundle;)V"))
                if n1 != None: 
                    key = "%s %s %s %s" % (j, "onCreate", "(Landroid/os/Bundle;)V", POSTFIX_ACTIVITY)
                    n2 = self._get_node(NODE_FAKE_ACTIVITY, key, LABEL_ACTIVITY, False)
                    self.G.add_edge( n2.id, n1.id )
                    self.entry_nodes.append( n1.id )
                    
            for i in apk.get_services() :
                j = bytecode.FormatClassToJava(i)
                n1 = self._get_existed_node( (j, "onCreate", "()V") )
                if n1 != None : 
                    key = "%s %s %s %s" % (j, "onCreate", "()V", POSTFIX_SERVICE)
                    n2 = self._get_node(NODE_FAKE_SERVICE, key, LABEL_SERVICE, False)
                    self.G.add_edge( n2.id, n1.id )
                    self.entry_nodes.append( n1.id )
            
            for i in apk.get_receivers() :
                j = bytecode.FormatClassToJava(i)
                n1 = self._get_existed_node( (j, "onReceive", "(Landroid/content/Context;Landroid/content/Intent;)V") )
                if n1 != None : 
                    key = "%s %s %s %s" % (j, "onReceive", "(Landroid/content/Context;Landroid/content/Intent;)V", POSTFIX_RECEIVER)
                    n2 = self._get_node(NODE_FAKE_SERVICE, key, LABEL_RECEIVER, False)
                    self.G.add_edge( n2.id, n1.id )
                    self.entry_nodes.append( n1.id )

        
        #fake permissions
        list_permissions = vmx.stadyna_get_permissions([])
        for x in list_permissions:
            for j in list_permissions[x]:
                if isinstance(j, PathVar):
                    continue

                src_class_name, src_method_name, src_descriptor = j.get_src( vm.get_class_manager() )
                dst_class_name, dst_method_name, dst_descriptor = j.get_dst( vm.get_class_manager() )
                
                n1 = self._get_existed_node((src_class_name, src_method_name, src_descriptor))
                if n1 == None:
                    logger.warning("Cannot find node [%s %s %s] for permission [%s]!" % (src_class_name, src_method_name, src_descriptor, x))
                    continue
                
                #SOURCE, DEST, POSTFIX, PERMISSION_NAME
                key = "%s %s %s %s %s %s %s %s" %  (src_class_name, src_method_name, src_descriptor, dst_class_name, dst_method_name, dst_descriptor, POSTFIX_PERM, x)
                n2 = self._get_node(NODE_FAKE_PERMISSION, key, x, False)
                n2.set_attribute(ATTR_CLASS_NAME, dst_class_name)
                n2.set_attribute(ATTR_METHOD_NAME, dst_method_name)
                n2.set_attribute(ATTR_DESCRIPTOR, dst_descriptor)
                n2.set_attribute(ATTR_PERM_NAME, x)
                n2.set_attribute(ATTR_PERM_LEVEL, MANIFEST_PERMISSIONS[ x ][0])
                
                self.G.add_edge(n1.id, n2.id)
                                

        #fake DexClassLoader nodes
        dyn_code_loading = analysis.seccon_get_dyncode_loading_paths(vmx)
        for j in dyn_code_loading:
            src_class_name, src_method_name, src_descriptor = j.get_src( vm.get_class_manager() )
            dst_class_name, dst_method_name, dst_descriptor = j.get_dst( vm.get_class_manager() )
            
            n1 = self._get_existed_node((src_class_name, src_method_name, src_descriptor))
            if n1 == None:
                logger.warning("Cannot find dexload node [%s]!" % (src_class_name, src_method_name, src_descriptor))
                continue
            
            key = "%s %s %s %s %s %s %s" % (src_class_name, src_method_name, src_descriptor, dst_class_name, dst_method_name, dst_descriptor, POSTFIX_DEXLOAD)
            n2 = self._get_node(NODE_FAKE_DEXLOAD, key, LABEL_DEXLOAD, False)
            n2.set_attribute(ATTR_CLASS_NAME, src_class_name)
            n2.set_attribute(ATTR_METHOD_NAME, src_method_name)
            n2.set_attribute(ATTR_DESCRIPTOR, src_descriptor)
            
            self.G.add_edge( n1.id, n2.id )
        
        
        
        # Specific Java/Android library
        for c in vm.get_classes():
            #if c.get_superclassname() == "Landroid/app/Service;" :
            #    n1 = self._get_node( c.get_name(), "<init>", "()V" )
            #    n2 = self._get_node( c.get_name(), "onCreate", "()V" )

            #    self.G.add_edge( n1.id, n2.id )
            if c.get_superclassname() == "Ljava/lang/Thread;" or c.get_superclassname() == "Ljava/util/TimerTask;" :
                for i in vm.get_method("run") :
                    if i.get_class_name() == c.get_name() :
                        n1 = self._get_node(NODE_METHOD, (i.get_class_name(), i.get_name(), i.get_descriptor()))
                        n2 = self._get_node(NODE_METHOD, (i.get_class_name(), "start", i.get_descriptor())) 
                       
                        # link from start to run
                        self.G.add_edge( n2.id, n1.id )
                        #n2.add_edge( n1, {} )

                        # link from init to start
                        for init in vm.get_method("<init>") :
                            if init.get_class_name() == c.get_name():
                                #TODO: Leaving _get_existed_node to check if all the nodes are included
                                #It is possible that internal_packages does not contain this node. Leaving _get_existed_node to check this
                                n3 = self._get_node(NODE_CONSTRUCTOR, (init.get_class_name(), "<init>", init.get_descriptor()))
                                self.G.add_edge( n3.id, n2.id )
                                #n3.add_edge( n2, {} )
        
                        
                        
    def addInvokePath(self, src, through, dst):
        src_class_name, src_method_name, src_descriptor = src
        dst_class_name, dst_method_name, dst_descriptor = dst
        through_class_name, through_method_name, through_descriptor = through
        key = "%s %s %s %s %s %s %s" % (src_class_name, src_method_name, src_descriptor, through_class_name, through_method_name, through_descriptor, POSTFIX_REFL_INVOKE)
        n1 = self._get_existed_node(key)
        if n1 == None:
            logger.warning("Something wrong has happened! Could not find invoke Node in Graph with key [%s]" % str(key))
            return
        
        n2 = self._get_node(NODE_METHOD, (dst_class_name, dst_method_name, dst_descriptor))
        n2.set_attribute(ATTR_CLASS_NAME, dst_class_name)
        n2.set_attribute(ATTR_METHOD_NAME, dst_method_name)
        n2.set_attribute(ATTR_DESCRIPTOR, dst_descriptor)
        
        self.G.add_edge(n1.id, n2.id)
        
        #check if called method calls protected feature
        data = "%s-%s-%s" % (dst_class_name, dst_method_name, dst_descriptor)
        if data in DVM_PERMISSIONS_BY_API_CALLS:
            logger.info("BINGOOOOOOO! The protected method is called through reflection!")
            perm = DVM_PERMISSIONS_BY_API_CALLS[ data ]
            key1 = "%s %s %s %s %s %s %s %s" %  (through_class_name, through_method_name, through_descriptor, dst_class_name, dst_method_name, dst_descriptor, POSTFIX_PERM, perm)
            n3 = self._get_node(NODE_FAKE_PERMISSION, key1, perm, False)
            n3.set_attribute(ATTR_CLASS_NAME, dst_class_name)
            n3.set_attribute(ATTR_METHOD_NAME, dst_method_name)
            n3.set_attribute(ATTR_DESCRIPTOR, dst_descriptor)
            n3.set_attribute(ATTR_PERM_NAME, perm)
            n3.set_attribute(ATTR_PERM_LEVEL, MANIFEST_PERMISSIONS[ perm ][0])
            self.G.add_edge(n2.id, n3.id)
            

        
            
    def addNewInstancePath(self, src, through, dst):
        src_class_name, src_method_name, src_descriptor = src
        dst_class_name, dst_method_name, dst_descriptor = dst
        through_class_name, through_method_name, through_descriptor = through
        key = "%s %s %s %s %s %s %s" % (src_class_name, src_method_name, src_descriptor, through_class_name, through_method_name, through_descriptor, POSTFIX_REFL_NEWINSTANCE)
        n1 = self._get_existed_node(key)
        if n1 == None:
            logger.error("Something wrong has happened! Could not find Node in Graph with key [%s]" % str(key))
            return
        
        n2 = self._get_node(NODE_CONSTRUCTOR, (dst_class_name, dst_method_name, dst_descriptor))
        n2.set_attribute(ATTR_CLASS_NAME, dst_class_name)
        n2.set_attribute(ATTR_METHOD_NAME, dst_method_name)
        n2.set_attribute(ATTR_DESCRIPTOR, dst_descriptor) 
        
        self.G.add_edge(n1.id, n2.id)
        
        #we also need to add link to the class node
        #TODO: Think in the future what to do with this
        n_class = self._get_node(NODE_FAKE_CLASS, dst_class_name, None, False)
        n_class.set_attribute(ATTR_CLASS_NAME, dst_class_name)
        self.G.add_edge(n_class.id, n2.id)
        
        #checking if we need to add additional permission nodes
        data = "%s-%s-%s" % (dst_class_name, dst_method_name, dst_descriptor)
        if data in DVM_PERMISSIONS_BY_API_CALLS:
            logger.info("BINGOOOOOOO! The protected method is called through reflection!")
            perm = DVM_PERMISSIONS_BY_API_CALLS[ data ]
            key1 = "%s %s %s %s %s %s %s %s" %  (through_class_name, through_method_name, through_descriptor, dst_class_name, dst_method_name, dst_descriptor, POSTFIX_PERM, perm)
            n3 = self._get_node(NODE_FAKE_PERMISSION, key1, perm, False)
            n3.set_attribute(ATTR_CLASS_NAME, dst_class_name)
            n3.set_attribute(ATTR_METHOD_NAME, dst_method_name)
            n3.set_attribute(ATTR_DESCRIPTOR, dst_descriptor)
            n3.set_attribute(ATTR_PERM_NAME, perm)
            n3.set_attribute(ATTR_PERM_LEVEL, MANIFEST_PERMISSIONS[ perm ][0])
            self.G.add_edge(n2.id, n3.id)
        
            
    def addDexloadPath(self, src, through, filename):
        src_class_name, src_method_name, src_descriptor = src
        through_class_name, through_method_name, through_descriptor = through
        key = "%s %s %s %s %s %s %s" % (src_class_name, src_method_name, src_descriptor,  through_class_name, through_method_name, through_descriptor, POSTFIX_DEXLOAD)
        n1 = self._get_existed_node(key)
        if n1 == None:
            logger.error("Something wrong has happened! Could not find Node in Graph with key [%s]" % str(key))
            return
        
        n2 = self._get_node(NODE_FAKE_DEXLOAD_FILE, filename, filename, False)
        n2.set_attribute(ATTR_DEXLOAD_FILENAME, filename)
        
        self.G.add_edge(n1.id, n2.id)
        
    

    def _get_node(self, nType, key, label=None, real=True):
        node_key = None
        if isinstance(key, basestring):
            node_key = key
        elif isinstance(key, tuple):
            node_key = "%s %s %s" % key
        else:
            logger.error("Unknown instance type of key!!!")
        
        if node_key not in self.nodes.keys():
            new_node = NodeS(len(self.nodes), nType, node_key, label, real)
            self.nodes[node_key] = new_node
            self.nodes_id[new_node.id] = new_node
        
        return self.nodes[node_key]
    
    
    def _get_existed_node(self, key):
        node_key = None
        if isinstance(key, basestring):
            node_key = key
        elif isinstance(key, tuple):
            node_key = "%s %s %s" % key
        else:
            logger.error("Unknown instance type of key!!!")
        
        try:
            return self.nodes[node_key]
        except KeyError:
            logger.error("Could not find existed node [%s]!" % node_key)
            return None

    def export_to_gexf(self) :
        buff = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
        buff += "<gexf xmlns=\"http://www.gephi.org/gexf\" xmlns:viz=\"http://www.gephi.org/gexf/viz\">\n"
        buff += "<graph type=\"static\">\n"

        buff += "<attributes class=\"node\" type=\"static\">\n"
        buff += "<attribute title=\"%s\" id=\"%d\" type=\"string\"/>\n" % (ATTR_TYPE,              ID_ATTRIBUTES[ ATTR_TYPE ])
        buff += "<attribute title=\"%s\" id=\"%d\" type=\"string\"/>\n" % (ATTR_CLASS_NAME,        ID_ATTRIBUTES[ ATTR_CLASS_NAME ])
        buff += "<attribute title=\"%s\" id=\"%d\" type=\"string\"/>\n" % (ATTR_METHOD_NAME,       ID_ATTRIBUTES[ ATTR_METHOD_NAME ])
        buff += "<attribute title=\"%s\" id=\"%d\" type=\"string\"/>\n" % (ATTR_DESCRIPTOR,        ID_ATTRIBUTES[ ATTR_DESCRIPTOR ])
        buff += "<attribute title=\"%s\" id=\"%d\" type=\"string\"/>\n" % (ATTR_REAL,              ID_ATTRIBUTES[ ATTR_REAL ])
        buff += "<attribute title=\"%s\" id=\"%d\" type=\"string\"/>\n" % (ATTR_PERM_NAME,         ID_ATTRIBUTES[ ATTR_PERM_NAME ])
        buff += "<attribute title=\"%s\" id=\"%d\" type=\"string\"/>\n" % (ATTR_PERM_LEVEL,        ID_ATTRIBUTES[ ATTR_PERM_LEVEL ])
        buff += "<attribute title=\"%s\" id=\"%d\" type=\"string\"/>\n" % (ATTR_DEXLOAD_FILENAME,  ID_ATTRIBUTES[ ATTR_DEXLOAD_FILENAME ])
        buff += "</attributes>\n"

#         buff += "<attributes class=\"node\" type=\"static\">\n" 
#         buff += "<attribute id=\"%d\" title=\"type\" type=\"string\" default=\"normal\"/>\n" % ID_ATTRIBUTES[ "type"]
#         buff += "<attribute id=\"%d\" title=\"class_name\" type=\"string\"/>\n" % ID_ATTRIBUTES[ "class_name"]
#         buff += "<attribute id=\"%d\" title=\"method_name\" type=\"string\"/>\n" % ID_ATTRIBUTES[ "method_name"]
#         buff += "<attribute id=\"%d\" title=\"descriptor\" type=\"string\"/>\n" % ID_ATTRIBUTES[ "descriptor"]
# 
# 
#         buff += "<attribute id=\"%d\" title=\"permissions\" type=\"integer\" default=\"0\"/>\n" % ID_ATTRIBUTES[ "permissions"]
#         buff += "<attribute id=\"%d\" title=\"permissions_level\" type=\"string\" default=\"normal\"/>\n" % ID_ATTRIBUTES[ "permissions_level"]
#         
#         buff += "<attribute id=\"%d\" title=\"dynamic_code\" type=\"boolean\" default=\"false\"/>\n" % ID_ATTRIBUTES[ "dynamic_code"]
#         
#         buff += "</attributes>\n"   

        buff += "<nodes>\n"
        for node in self.G.nodes() :
            buff += "<node id=\"%d\" label=\"%s\">\n" % (node, escape(self.nodes_id[ node ].label))
            buff += self.nodes_id[ node ].get_attributes_gexf()
            buff += "</node>\n"
        buff += "</nodes>\n"


        buff += "<edges>\n"
        nb = 0
        for edge in self.G.edges() :
            buff += "<edge id=\"%d\" source=\"%d\" target=\"%d\"/>\n" % (nb, edge[0], edge[1])
            nb += 1
        buff += "</edges>\n"


        buff += "</graph>\n"
        buff += "</gexf>\n"

        return buff
  
    
    def get_current_real_node_count(self):
        count = 0
        for node in self.nodes_id.keys():
            if self.nodes_id[node].get_attribute(ATTR_REAL) == "True":
                count += 1
        return count

    def get_current_node_count(self):
        return len(self.G.nodes())
    
    def get_current_edge_count(self):
        return len(self.G.edges())
    
    def get_current_permission_level_node_count(self, permission_level):
        count = 0
        for node in self.nodes_id.keys():
            if self.nodes_id[node].get_attribute(ATTR_PERM_LEVEL) == permission_level:
                count += 1
        return count
    
    def get_current_protected_node_count(self):
        count = 0
        for node in self.nodes_id.keys():
            if self.nodes_id[node].get_attribute(ATTR_PERM_LEVEL) != None:
                count += 1
        return count
Beispiel #36
0
class tree(object):
    """ construction of prefix and suffix tree
    """
    def __init__(self, n_robot, acpt, ts, buchi_graph, init, seg, step_size,
                 no):
        """
        :param acpt:  accepting state
        :param ts: transition system
        :param buchi_graph:  Buchi graph
        :param init: product initial state
        """
        self.robot = n_robot
        self.acpt = acpt
        self.goals = []
        self.ts = ts
        self.buchi_graph = buchi_graph
        self.init = init
        self.seg = seg
        self.step_size = step_size
        self.dim = len(self.ts['workspace'])
        uni_ball = [
            1, 2, 3.142, 4.189, 4.935, 5.264, 5.168, 4.725, 4.059, 3.299, 2.550
        ]
        # uni_v = uni_ball[self.robot*self.dim]
        uni_v = np.power(np.pi, self.robot * self.dim /
                         2) / math.gamma(self.robot * self.dim / 2 + 1)
        self.gamma = np.ceil(
            4 * np.power(1 / uni_v, 1. /
                         (self.dim * self.robot)))  # unit workspace
        self.tree = DiGraph(type='PBA', init=init)
        self.group = dict()
        label = []
        for i in range(self.robot):
            l = self.label(init[0][i])
            # exists one sampled point lies within obstacles
            if l != '':
                l = l + '_' + str(i + 1)
            label.append(l)

        self.tree.add_node(init, cost=0, label=label)
        self.add_group(init)
        # probability
        self.p = 0.9
        # threshold for collision avoidance
        self.threshold = 0.02
        # polygon obstacle
        polys = [[
            vg.Point(0.4, 1.0),
            vg.Point(0.4, 0.7),
            vg.Point(0.6, 0.7),
            vg.Point(0.6, 1.0)
        ],
                 [
                     vg.Point(0.3, 0.2),
                     vg.Point(0.3, 0.0),
                     vg.Point(0.7, 0.0),
                     vg.Point(0.7, 0.2)
                 ]]
        self.g = vg.VisGraph()
        self.g.build(polys, status=False)
        # region that has ! preceding it
        self.no = no

    def add_group(self, q_state):
        """
        group nodes with same buchi state
        :param q_state: new state added to the tree
        """
        try:
            self.group[q_state[1]].append(q_state)
        except KeyError:
            self.group[q_state[1]] = [q_state]

    def min2final(self, min_qb_dict, b_final, cand):
        """
         collects the buchi state in the tree with minimum distance to the final state
        :param min_qb_dict: dict
        :param b_final: feasible final state
        :return: list of buchi states in the tree with minimum distance to the final state
        """
        l_min = np.inf
        b_min = []
        for b_state in cand:
            if min_qb_dict[(b_state, b_final)] < l_min:
                l_min = min_qb_dict[(b_state, b_final)]
                b_min = [b_state]
            elif min_qb_dict[(b_state, b_final)] == l_min:
                b_min.append(b_state)
        return b_min

    def all2one(self, b_min):
        """
        partition nodes into 2 groups
        :param b_min: buchi states with minimum distance to the finals state
        :return: 2 groups
        """
        q_min2final = []
        q_minNot2final = []
        for b_state in self.group.keys():
            if b_state in b_min:
                q_min2final = q_min2final + self.group[b_state]
            else:
                q_minNot2final = q_minNot2final + self.group[b_state]
        return q_min2final, q_minNot2final

    def get_truncated_normal(self, mean=0, sd=1, low=0, upp=10):
        return truncnorm((low - mean) / sd, (upp - mean) / sd,
                         loc=mean,
                         scale=sd)

    def trunc(self, value):
        if value < 0:
            return 0
        elif value > 1:
            return 1
        else:
            return value

    def collision_avoidance(self, x, index):
        """
        check whether any robots are collision-free from index-th robot
        :param x: all robots
        :param index: index-th robot
        :return: true collision free
        """
        for i in range(len(x)):
            if i != index and np.linalg.norm(np.subtract(
                    x[i], x[index])) <= self.threshold:
                return False
        return True

    def target(self, init, target, regions):
        """
        find the closest vertex in the short path from init to target
        :param init: inital point
        :param target: target labeled region
        :param regions: regions
        :return: closest vertex
        """
        tg = regions[((target, 'b'))][:2]
        shortest = self.g.shortest_path(vg.Point(init[0], init[1]),
                                        vg.Point(tg[0], tg[1]))
        return (shortest[1].x, shortest[1].y)

    def gaussian_guided(self, x, target):
        """
        calculate new point following gaussian dist guided by the target
        :param x: mean point
        :param target: target point
        :return: new point
        """
        # print(min(self.gamma * np.power(np.log(self.tree.number_of_nodes()+1)/self.tree.number_of_nodes(),1./(self.dim*self.robot)), self.step_size)/3)
        # d = self.get_truncated_normal(0, min(self.gamma * np.power(np.log(self.tree.number_of_nodes()+1)/self.tree.number_of_nodes(),1./(self.dim*self.robot)), self.step_size)/3, 0, np.inf)
        # d = self.get_truncated_normal(0, self.step_size/3, 0, np.inf)
        d = self.get_truncated_normal(0, 1 / 3, 0, np.inf)
        # d = self.get_truncated_normal(0, 1, 0, np.inf)
        d = d.rvs()
        # # print('d=',d)
        # if np.random.uniform(0,1,1) <= self.p:
        #     angle = np.random.uniform(-np.pi/2, np.pi/2, 1) + np.arctan2(center[1]-x[1], center[0]-x[0])
        # else:
        #     angle = np.random.uniform(np.pi/2, 3*np.pi/2, 1) + np.arctan2(center[1]-x[1], center[0]-x[0])
        angle = np.random.normal(0, np.pi / 12 / 3 / 3, 1) + np.arctan2(
            target[1] - x[1], target[0] - x[0])
        # angle = np.arctan2(target[1] - x[1], target[0] - x[0])
        x_rand = np.add(x, np.append(d * np.cos(angle), d * np.sin(angle)))
        x_rand = [self.trunc(x) for x in x_rand]
        return tuple(x_rand)

    def gaussian_unguided(self, x):
        """

        :param x:
        :return:
        """
        d = self.get_truncated_normal(
            0,
            min(
                self.gamma * np.power(
                    np.log(self.tree.number_of_nodes() + 1) /
                    self.tree.number_of_nodes(), 1. /
                    (self.dim * self.robot)), self.step_size) / 3, 0)
        d = d.rvs()
        angle = np.random.uniform(-np.pi, np.pi, 1)
        x_rand = np.add(x, np.append(d * np.cos(angle), d * np.sin(angle)))
        return tuple([self.trunc(x) for x in x_rand])

    def buchi_guided_sample_by_label(self, x_rand, b_label, x_label, regions):

        if b_label.strip().strip('(').strip(')') == '1':
            return []
        # not or be in some place
        else:
            # label of current position
            blabel = b_label.split('||')[0]
            # blabel = random.choice(b_label.split('||'))
            atomic_label = blabel.split('&&')
            for a in atomic_label:
                # a = a.strip().strip('(').strip(')')
                a = a.strip().strip('(').strip(')').split('or')[0].strip()
                # if in wrong position, sample randomly
                if '!' in a:
                    if a[1:] in x_label:
                        xi_rand = []
                        for i in range(self.dim):
                            xi_rand.append(uniform(0, self.ts['workspace'][i]))
                        ind = int(a[1:].split('_')[1]) - 1
                        x_rand[ind] = tuple(xi_rand)
                else:
                    # move towards target position
                    if not a in x_label:
                        ind = a.split('_')
                        weight = 0.8
                        if np.random.uniform(0, 1, 1) <= weight:
                            tg = self.target(x_rand[int(ind[1]) - 1], ind[0],
                                             regions)
                            x_rand[int(ind[1]) - 1] = self.gaussian_guided(
                                x_rand[int(ind[1]) - 1], tg)
                        else:
                            xi_rand = []
                            for i in range(self.dim):
                                xi_rand.append(
                                    uniform(0, self.ts['workspace'][i]))
                            x_rand[int(ind[1]) - 1] = tuple(xi_rand)

        return x_rand

    def buchi_guided_sample_by_truthvalue(self, truth, x_rand, q_rand, x_label,
                                          regions):
        """
        sample guided by truth value
        :param truth: the value making transition occur
        :param x_rand: random selected node
        :param x_label: label of x_rand
        :param regions: regions
        :return: new sampled point
        """
        if truth == '1':
            return [], []
        # not or be in some place
        else:
            for key in truth:
                # if in wrong position, sample randomly
                # if not truth[key] and key in x_label:
                #     xi_rand = []
                #     for i in range(self.dim):
                #         xi_rand.append(uniform(0, self.ts['workspace'][i]))
                #     ind = key.split('_')
                #     x_rand[int(ind[1]) - 1] = tuple(xi_rand)
                # elif truth[key]:
                #     # move towards target position
                #     if not key in x_label:
                #         ind = key.split('_')
                #         weight = 1
                #         if np.random.uniform(0, 1, 1) <= weight:
                #             tg = self.target(x_rand[int(ind[1]) - 1], ind[0], regions)
                #             # tg = self.target(orig_x_rand, ind[0], regions)
                #             x_rand[int(ind[1]) - 1] = self.gaussian_guided(x_rand[int(ind[1]) - 1], tg)
                #         else:
                #             xi_rand = []
                #             for i in range(self.dim):
                #                 xi_rand.append(uniform(0, self.ts['workspace'][i]))
                #             x_rand[int(ind[1]) - 1] = tuple(xi_rand)
                ind = key.split('_')
                orig_x_rand = x_rand[int(ind[1]) - 1]  # save
                while 1:
                    x_rand[int(ind[1]) - 1] = orig_x_rand  # recover
                    # if in wrong position, sample randomly
                    if not truth[key] and key in x_label:
                        xi_rand = []
                        for i in range(self.dim):
                            xi_rand.append(uniform(0, self.ts['workspace'][i]))
                        # ind = key.split('_')
                        x_rand[int(ind[1]) - 1] = tuple(xi_rand)
                    elif truth[key]:
                        # move towards target position
                        if not key in x_label:
                            # ind = key.split('_')
                            weight = 0.8
                            if np.random.uniform(0, 1, 1) <= weight:
                                # tg = self.target(x_rand[int(ind[1]) - 1], ind[0], regions)
                                tg = self.target(orig_x_rand, ind[0], regions)
                                x_rand[int(ind[1]) - 1] = self.gaussian_guided(
                                    orig_x_rand, tg)
                            else:
                                xi_rand = []
                                for i in range(self.dim):
                                    xi_rand.append(
                                        uniform(0, self.ts['workspace'][i]))
                                x_rand[int(ind[1]) - 1] = tuple(xi_rand)
                    else:
                        break
                    if self.collision_avoidance(x_rand, int(ind[1]) - 1):
                        break

            #   x_rand                  x_nearest
        return self.mulp2sglp(x_rand), q_rand
        # return x_rand

    def sample(self, buchi_graph, min_qb_dict, regions):
        """
        sample point from the workspace
        :return: sampled point, tuple
        """
        if self.seg == 'pre':
            b_final = buchi_graph.graph['accept'][np.random.randint(
                0, len(buchi_graph.graph['accept'])
            )]  # feasible final buchi state
        else:
            b_final = buchi_graph.graph['accept']
        # collects the buchi state in the tree with minimum distance to the final state
        b_min = self.min2final(min_qb_dict, b_final, self.group.keys())
        # partition of nodes
        q_min2final, q_minNot2final = self.all2one(b_min)
        # sample random nodes
        p_rand = np.random.uniform(0, 1, 1)
        if (p_rand <= self.p and len(q_min2final) > 0) or not q_minNot2final:
            q_rand = q_min2final[np.random.randint(0, len(q_min2final))]
        elif p_rand > self.p or not q_min2final:
            q_rand = q_minNot2final[np.random.randint(0, len(q_minNot2final))]
        # find feasible succssor of buchi state in q_rand
        Rb_q_rand = []
        x_label = []
        for i in range(self.robot):
            l = self.label(q_rand[0][i])
            if l != '':
                l = l + '_' + str(i + 1)
            x_label.append(l)

        for b_state in buchi_graph.succ[q_rand[1]]:
            # if self.t_satisfy_b(x_label, buchi_graph.edges[(q_rand[1], b_state)]['label']):
            if self.t_satisfy_b_truth(
                    x_label, buchi_graph.edges[(q_rand[1], b_state)]['truth']):
                Rb_q_rand.append(b_state)
        # if empty
        if not Rb_q_rand:
            return Rb_q_rand, Rb_q_rand
        # collects the buchi state in the reachable set of qb_rand with minimum distance to the final state
        b_min = self.min2final(min_qb_dict, b_final, Rb_q_rand)

        # collects the buchi state in the reachable set of b_min with distance to the final state equal to that of b_min - 1
        decr_dict = dict()
        for b_state in b_min:
            decr = []
            for succ in buchi_graph.succ[b_state]:
                if min_qb_dict[(b_state, b_final)] - 1 == min_qb_dict[(
                        succ, b_final)] or succ in buchi_graph.graph['accept']:
                    decr.append(succ)
            decr_dict[b_state] = decr
        M_cand = [
            b_state for b_state in decr_dict.keys() if decr_dict[b_state]
        ]
        # if empty
        if not M_cand:
            return M_cand, M_cand
        # sample b_min and b_decr
        b_min = M_cand[np.random.randint(0, len(M_cand))]
        b_decr = decr_dict[b_min][np.random.randint(0, len(decr_dict[b_min]))]

        # b_label = buchi_graph.edges[(b_min, b_decr)]['label']
        # x_rand = list(q_rand[0])
        #
        # return self.buchi_guided_sample_by_label(x_rand, b_label, x_label, regions)

        truth = buchi_graph.edges[(b_min, b_decr)]['truth']
        x_rand = list(q_rand[0])
        return self.buchi_guided_sample_by_truthvalue(truth, x_rand, q_rand,
                                                      x_label, regions)

        #   x_rand                  x_nearest
        # return self.mulp2sglp(x_rand), self.mulp2sglp(q_rand[0])

        # return x_rand

    # def nearest(self, x_rand):
    #     """
    #     find the nearest vertex in the tree
    #     :param: x_rand randomly sampled point form: single point ()
    #     :return: nearest vertex form: single point ()
    #     """
    #     min_dis = math.inf
    #     x_nearest = x_rand
    #     for vertex in self.tree.nodes:
    #         x_vertex = self.mulp2sglp(vertex[0])
    #         dis = np.linalg.norm(np.subtract(x_rand, x_vertex))
    #         if dis < min_dis:
    #             x_nearest = x_vertex
    #             min_dis = dis
    #     return x_nearest

    def nearest(self, x_rand):
        """
        find the nearest class of vertices in the tree
        :param: x_rand randomly sampled point form: single point ()
        :return: nearest class of vertices form: single point ()
        """
        min_dis = math.inf
        q_nearest = []
        for vertex in self.tree.nodes:
            x_vertex = self.mulp2sglp(vertex[0])
            dis = np.linalg.norm(np.subtract(x_rand, x_vertex))
            if dis < min_dis:
                q_nearest = list()
                q_nearest.append(vertex)
                min_dis = dis
            elif dis == min_dis:
                q_nearest.append(vertex)
        return q_nearest

    def steer(self, x_rand, x_nearest):
        """
        steer
        :param: x_rand randomly sampled point form: single point ()
        :param: x_nearest nearest point in the tree form: single point ()
        :return: new point single point ()
        """
        #return np.asarray([0.8,0.4])
        if np.linalg.norm(np.subtract(x_rand, x_nearest)) <= self.step_size:
            return x_rand
        else:
            return tuple(
                np.asarray(x_nearest) + self.step_size *
                (np.subtract(x_rand, x_nearest)) /
                np.linalg.norm(np.subtract(x_rand, x_nearest)))

    def extend(self, q_new, near_v, label, obs_check):
        """
        :param: q_new: new state form: tuple (mulp, buchi)
        :param: near_v: near state form: tuple (mulp, buchi)
        :param: obs_check: check obstacle free  form: dict { (mulp, mulp): True }
        :return: extending the tree
        """
        added = 0
        cost = np.inf
        q_min = ()
        for near_vertex in near_v:
            if q_new != near_vertex and obs_check[(
                    q_new[0], near_vertex[0])] and self.checkTranB(
                        near_vertex[1], self.tree.nodes[near_vertex]['label'],
                        q_new[1]):
                c = self.tree.nodes[near_vertex]['cost'] + np.linalg.norm(
                    np.subtract(self.mulp2sglp(q_new[0]),
                                self.mulp2sglp(
                                    near_vertex[0])))  # don't consider control
                if c < cost:
                    added = 1
                    q_min = near_vertex
                    cost = c
        if added == 1:
            self.tree.add_node(q_new, cost=cost, label=label)
            self.tree.add_edge(q_min, q_new)
            self.add_group(q_new)
            if self.seg == 'pre' and q_new[1] in self.acpt:
                q_n = list(list(self.tree.pred[q_new].keys())[0])
                cost = self.tree.nodes[tuple(q_n)]['cost']
                label = self.tree.nodes[tuple(q_n)]['label']
                q_n[1] = q_new[1]
                q_n = tuple(q_n)
                self.tree.add_node(q_n, cost=cost, label=label)
                self.tree.add_edge(q_min, q_n)
                self.add_group(q_n)
                self.goals.append(q_n)

            if self.seg == 'suf' and self.checkTranB(q_new[1], label,
                                                     self.init[1]):
                print('final')

            if self.seg == 'suf' and self.obs_check(
                [self.init], q_new[0], label,
                    'final')[(q_new[0], self.init[0])] and self.checkTranB(
                        q_new[1], label, self.init[1]):
                # if self.seg == 'suf' and self.init in near_v and obs_check[(q_new[0], self.init[0])] and self.checkTranB(q_new[1], label, self.init[1]):
                self.goals.append(q_new)
        return added

    def rewire(self, q_new, near_v, obs_check):
        """
        :param: q_new: new state form: tuple (mul, buchi)
        :param: near_v: near state form: tuple (mul, buchi)
        :param: obs_check: check obstacle free form: dict { (mulp, mulp): True }
        :return: rewiring the tree
        """
        for near_vertex in near_v:
            if obs_check[(q_new[0], near_vertex[0])] and self.checkTranB(
                    q_new[1], self.tree.nodes[q_new]['label'], near_vertex[1]):
                c = self.tree.nodes[q_new]['cost'] + np.linalg.norm(
                    np.subtract(self.mulp2sglp(
                        q_new[0]), self.mulp2sglp(
                            near_vertex[0])))  # without considering control
                delta_c = self.tree.nodes[near_vertex]['cost'] - c
                # update the cost of node in the subtree rooted at near_vertex
                if delta_c > 0:
                    # self.tree.nodes[near_vertex]['cost'] = c
                    if not list(self.tree.pred[near_vertex].keys()):
                        print('empty')
                    self.tree.remove_edge(
                        list(self.tree.pred[near_vertex].keys())[0],
                        near_vertex)
                    self.tree.add_edge(q_new, near_vertex)
                    edges = dfs_labeled_edges(self.tree, source=near_vertex)
                    for _, v, d in edges:
                        if d == 'forward':
                            self.tree.nodes[v][
                                'cost'] = self.tree.nodes[v]['cost'] - delta_c

    def near(self, x_new):
        """
        find the states in the near ball
        :param x_new: new point form: single point
        :return: p_near: near state, form: tuple (mulp, buchi)
        """
        p_near = []
        r = min(
            self.gamma * np.power(
                np.log(self.tree.number_of_nodes() + 1) /
                self.tree.number_of_nodes(), 1. / (self.dim * self.robot)),
            self.step_size)
        for vertex in self.tree.nodes:
            if np.linalg.norm(np.subtract(x_new, self.mulp2sglp(
                    vertex[0]))) <= r:
                p_near.append(vertex)
        return p_near

    def obs_check(self, q_near, x_new, label, stage):
        """
        check whether obstacle free along the line from x_near to x_new
        :param q_near: states in the near ball, tuple (mulp, buchi)
        :param x_new: new state form: multiple point
        :param label: label of x_new
        :param stage: regular stage or final stage, deciding whether it's goal state
        :return: dict (x_near, x_new): true (obs_free)
        """
        # x_new =  ((0.8944144022556246, 0.33267910821176216),)
        # label = ['l3_1']
        # q_near = [(((0.8, 0.1),), 'T0_init'), (((0.9115062737314963, 0.10325925485437781),), 'T0_init')]

        obs_check_dict = {}
        for x in q_near:
            obs_check_dict[(x_new, x[0])] = True
            flag = True  # indicate whether break and jump to outer loop
            for r in range(self.robot):
                for i in range(1, 11):
                    mid = tuple(
                        np.asarray(x[0][r]) +
                        i / 10. * np.subtract(x_new[r], x[0][r]))
                    mid_label = self.label(mid)
                    if mid_label != '':
                        mid_label = mid_label + '_' + str(r + 1)
                    if stage == 'reg' and (
                            'o' in mid_label or
                        (mid_label != self.tree.nodes[x]['label'][r]
                         and mid_label != label[r])):
                        #                      obstacle             pass through one region more than once
                        obs_check_dict[(x_new, x[0])] = False
                        flag = False
                        break
                    # elif stage == 'final' and ('o' in mid_label or (mid_label != self.tree.nodes[x]['label'][r] and mid_label != label[r] and mid_label != '')):
                    #                             obstacle             cannot pass through one region more than once expcet unlabeled region
                    elif stage == 'final' and (
                            'o' in mid_label or
                        (mid_label != self.tree.nodes[x]['label'][r]
                         and mid_label != label[r] and mid_label in self.no)):
                        obs_check_dict[(x_new, x[0])] = False
                        flag = False
                        break
                if not flag:
                    break

        return obs_check_dict

    def label(self, x):
        """
        generating the label of position state
        :param x: position
        :return: label
        """
        # whether x lies within obstacle
        for (obs, boundary) in iter(self.ts['obs'].items()):
            if obs[1] == 'b' and np.linalg.norm(np.subtract(
                    x, boundary[0:-1])) <= boundary[-1]:
                return obs[0]
            elif obs[1] == 'p':
                dictator = True
                for i in range(len(boundary)):
                    if np.dot(x, boundary[i][0:-1]) + boundary[i][-1] > 0:
                        dictator = False
                        break
                if dictator == True:
                    return obs[0]

        # whether x lies within regions
        for (regions, boundary) in iter(self.ts['region'].items()):
            if regions[1] == 'b' and np.linalg.norm(
                    x - np.asarray(boundary[0:-1])) <= boundary[-1]:
                return regions[0]
            elif regions[1] == 'p':
                dictator = True
                for i in range(len(boundary)):
                    if np.dot(x, np.asarray(
                            boundary[i][0:-1])) + boundary[i][-1] > 0:
                        dictator = False
                        break
                if dictator == True:
                    return regions[0]

        return ''

    def checkTranB(self, b_state, x_label, q_b_new):
        """ decide valid transition, whether b_state --L(x)---> q_b_new
             Algorithm2 in Chapter 2 Motion and Task Planning
             :param b_state: buchi state
             :param x_label: label of x
             :param q_b_new buchi state
             :return True satisfied
        """
        b_state_succ = self.buchi_graph.succ[b_state]
        # q_b_new is not the successor of b_state
        if q_b_new not in b_state_succ:
            return False

        # b_label = self.buchi_graph.edges[(b_state, q_b_new)]['label']
        # if self.t_satisfy_b(x_label, b_label):
        #     return True

        truth = self.buchi_graph.edges[(b_state, q_b_new)]['truth']
        if self.t_satisfy_b_truth(x_label, truth):
            return True

    def t_satisfy_b(self, x_label, b_label):
        """ decide whether label of self.ts_graph can satisfy label of self.buchi_graph
            :param x_label: label of x
            :param b_label: label of buchi state
            :return t_s_b: true if satisfied
        """
        t_s_b = True
        # split label with ||
        b_label = b_label.split('||')
        for label in b_label:
            t_s_b = True
            # spit label with &&
            atomic_label = label.split('&&')
            for a in atomic_label:
                a = a.strip()
                a = a.strip('(')
                a = a.strip(')')
                if a == '1':
                    continue
                # whether ! in an atomic proposition
                if '!' in a:
                    if a[1:] in x_label:
                        t_s_b = False
                        break
                else:
                    if not a in x_label:
                        t_s_b = False
                        break
            # either one of || holds
            if t_s_b:
                return t_s_b
        return t_s_b

    def t_satisfy_b_truth(self, x_label, truth):
        """
        check whether transition enabled under current label
        :param x_label: current label
        :param truth: truth value making transition enabled
        :return: true or false
        """
        if truth == '1':
            return True

        true_label = [
            truelabel for truelabel in truth.keys() if truth[truelabel]
        ]
        for label in true_label:
            if label not in x_label:
                return False

        false_label = [
            falselabel for falselabel in truth.keys() if not truth[falselabel]
        ]
        for label in false_label:
            if label in x_label:
                return False

        return True

    def findpath(self, goals):
        """
        find the path backwards
        :param goal: goal state
        :return: dict path : cost
        """
        paths = OrderedDict()
        for i in range(len(goals)):
            goal = goals[i]
            path = [goal]
            s = goal
            while s != self.init:
                s = list(self.tree.pred[s].keys())[0]
                if s == path[0]:
                    print("loop")
                path.insert(0, s)

            if self.seg == 'pre':
                paths[i] = [self.tree.nodes[goal]['cost'], path]
            elif self.seg == 'suf':
                # path.append(self.init)
                paths[i] = [
                    self.tree.nodes[goal]['cost'] +
                    np.linalg.norm(np.subtract(goal[0], self.init[0])), path
                ]
        return paths

    def mulp2sglp(self, point):
        """
        convert multiple form point ((),(),(),...) to single form point ()
        :param point: multiple points ((),(),(),...)
        :return: signle point ()
        """
        sp = []
        for p in point:
            sp = sp + list(p)
        return tuple(sp)

    def sglp2mulp(self, point):
        """
        convert single form point () to multiple form point ((), (), (), ...)
        :param point: single form point ()
        :return:  multiple form point ((), (), (), ...)
        """
        mp = []
        for i in range(self.robot):
            mp.append(point[i * self.dim:(i + 1) * self.dim])
        return tuple(mp)
Beispiel #37
0
class tree(object):
    """ construction of prefix and suffix tree
    """
    def __init__(self, n_robot, acpt, ts, buchi_graph, init, seg, step_size,
                 no):
        """
        :param acpt:  accepting state
        :param ts: transition system
        :param buchi_graph:  Buchi graph
        :param init: product initial state
        """
        self.robot = n_robot
        self.acpt = acpt
        self.goals = []
        self.ts = ts
        self.buchi_graph = buchi_graph
        self.init = init
        self.seg = seg
        self.step_size = step_size
        self.dim = len(self.ts['workspace'])
        uni_ball = [
            1, 2, 3.142, 4.189, 4.935, 5.264, 5.168, 4.725, 4.059, 3.299, 2.550
        ]
        self.gamma = np.ceil(
            4 * np.power(1 / uni_ball[self.robot * self.dim], 1. /
                         (self.dim * self.robot)))  # unit workspace
        self.tree = DiGraph(type='PBA', init=init)

        label = []
        for i in range(self.robot):
            l = self.label(init[0][i])
            # exists one sampled point lies within obstacles
            if l != '':
                l = l + '_' + str(i + 1)
            label.append(l)

        self.tree.add_node(init, cost=0, label=label)
        self.no = no

    def sample(self):
        """
        sample point from the workspace
        :return: sampled point, tuple
        """
        x_rand = []
        for i in range(self.dim):
            x_rand.append(uniform(0, self.ts['workspace'][i]))

        return tuple(x_rand)

    def nearest(self, x_rand):
        """
        find the nearest vertex in the tree
        :param: x_rand randomly sampled point form: single point ()
        :return: nearest vertex form: single point ()
        """
        # min_dis = math.inf
        # x_nearest = x_rand
        # for vertex in self.tree.nodes:
        #     x_vertex = self.mulp2sglp(vertex[0])
        #     dis = np.linalg.norm(np.subtract(x_rand, x_vertex))
        #     if dis < min_dis:
        #         x_nearest = x_vertex
        #         min_dis = dis
        # return x_nearest

        min_dis = math.inf
        q_nearest = []
        for vertex in self.tree.nodes:
            x_vertex = self.mulp2sglp(vertex[0])
            dis = np.linalg.norm(np.subtract(x_rand, x_vertex))
            if dis < min_dis:
                q_nearest = list()
                q_nearest.append(vertex)
                min_dis = dis
            elif dis == min_dis:
                q_nearest.append(vertex)
        return q_nearest

    def steer(self, x_rand, x_nearest):
        """
        steer
        :param: x_rand randomly sampled point form: single point ()
        :param: x_nearest nearest point in the tree form: single point ()
        :return: new point single point ()
        """
        #return np.asarray([0.8,0.4])
        if np.linalg.norm(np.subtract(x_rand, x_nearest)) <= self.step_size:
            return x_rand
        else:
            return tuple(
                np.asarray(x_nearest) + self.step_size *
                (np.subtract(x_rand, x_nearest)) /
                np.linalg.norm(np.subtract(x_rand, x_nearest)))

    def extend(self, q_new, q_nearest, label, obs_check):
        for v_nearest in q_nearest:
            # print(v_nearest)
            if obs_check[(q_new[0], v_nearest[0])] and self.checkTranB(
                    v_nearest[1], self.tree.nodes[v_nearest]['label'],
                    q_new[1]):
                if 'T1_S4' in v_nearest:
                    print(self.tree.nodes[v_nearest]['label'])
                    if 'l3_1' in self.tree.nodes[v_nearest]['label']:
                        print(2)
                cost = self.tree.nodes[v_nearest]['cost'] + np.linalg.norm(
                    np.subtract(self.mulp2sglp(q_new[0]),
                                self.mulp2sglp(v_nearest[0])))

                self.tree.add_node(q_new, cost=cost, label=label)
                self.tree.add_edge(v_nearest, q_new)
                if self.seg == 'pre' and q_new[1] in self.acpt:
                    q_n = list(list(self.tree.pred[q_new].keys())[0])
                    cost = self.tree.nodes[tuple(q_n)]['cost']
                    label = self.tree.nodes[tuple(q_n)]['label']
                    q_n[1] = q_new[1]
                    q_n = tuple(q_n)
                    self.tree.add_node(q_n, cost=cost, label=label)
                    self.tree.add_edge(v_nearest, q_n)
                    self.goals.append(q_n)
                    # self.goals.append(q_new)
                # if self.seg == 'suf' and self.init in near_v and obs_check[(q_new[0], self.init[0])]  and  self.checkTranB(q_new[1], label, self.init[1]):
                if self.seg == 'suf' and self.obs_check(
                    [self.init], q_new[0], label,
                        'final')[(q_new[0], self.init[0])] and self.checkTranB(
                            q_new[1], label, self.init[1]):
                    self.goals.append(q_new)
                break

    def obs_check(self, q_near, x_new, label, stage):
        """
        check whether obstacle free along the line from x_near to x_new
        :param q_near: states in the near ball, tuple (mulp, buchi)
        :param x_new: new state form: multiple point
        :return: dict (x_near, x_new): true (obs_free)
        """

        obs_check_dict = {}
        for x in q_near:
            obs_check_dict[(x_new, x[0])] = True
            flag = True  # indicate whether break and jump to outer loop
            for r in range(self.robot):
                for i in range(1, 11):
                    mid = tuple(
                        np.asarray(x[0][r]) +
                        i / 10. * np.subtract(x_new[r], x[0][r]))
                    mid_label = self.label(mid)
                    if mid_label != '':
                        mid_label = mid_label + '_' + str(r + 1)
                    if stage == 'reg' and (
                            'o' in mid_label or
                        (mid_label != self.tree.nodes[x]['label'][r]
                         and mid_label != label[r])):
                        # obstacle             pass through one region more than once
                        obs_check_dict[(x_new, x[0])] = False
                        flag = False
                        break
                    elif stage == 'final' and (
                            'o' in mid_label or
                        (mid_label != self.tree.nodes[x]['label'][r]
                         and mid_label != label[r] and mid_label in self.no)):
                        obs_check_dict[(x_new, x[0])] = False
                        flag = False
                        break
                if not flag:
                    break

        return obs_check_dict

    def label(self, x):
        """
        generating the label of position state
        :param x: position
        :return: label
        """
        # whether x lies within obstacle
        for (obs, boundary) in iter(self.ts['obs'].items()):
            if obs[1] == 'b' and np.linalg.norm(np.subtract(
                    x, boundary[0:-1])) <= boundary[-1]:
                return obs[0]
            elif obs[1] == 'p':
                dictator = True
                for i in range(len(boundary)):
                    if np.dot(x, boundary[i][0:-1]) + boundary[i][-1] > 0:
                        dictator = False
                        break
                if dictator == True:
                    return obs[0]

        # whether x lies within regions
        for (regions, boundary) in iter(self.ts['region'].items()):
            if regions[1] == 'b' and np.linalg.norm(
                    x - np.asarray(boundary[0:-1])) <= boundary[-1]:
                return regions[0]
            elif regions[1] == 'p':
                dictator = True
                for i in range(len(boundary)):
                    if np.dot(x, np.asarray(
                            boundary[i][0:-1])) + boundary[i][-1] > 0:
                        dictator = False
                        break
                if dictator == True:
                    return regions[0]

        return ''

    def checkTranB(self, b_state, x_label, q_b_new):
        """ decide valid transition, whether b_state --L(x)---> q_b_new
             Algorithm2 in Chapter 2 Motion and Task Planning
             :param b_state: buchi state
             :param x_label: label of x
             :param q_b_new buchi state
             :return True satisfied
        """
        b_state_succ = self.buchi_graph.succ[b_state]
        # q_b_new is not the successor of b_state
        if q_b_new not in b_state_succ:
            return False

        b_label = self.buchi_graph.edges[(b_state, q_b_new)]['label']
        if self.t_satisfy_b(x_label, b_label):
            return True

    def t_satisfy_b(self, x_label, b_label):
        """ decide whether label of self.ts_graph can satisfy label of self.buchi_graph
            :param x_label: label of x
            :param b_label: label of buchi state
            :return t_s_b: true if satisfied
        """
        t_s_b = True
        # split label with ||
        b_label = b_label.split('||')
        for label in b_label:
            t_s_b = True
            # spit label with &&
            atomic_label = label.split('&&')
            for a in atomic_label:
                a = a.strip()
                a = a.strip('(')
                a = a.strip(')')
                if a == '1':
                    continue
                # whether ! in an atomic proposition
                if '!' in a:
                    if a[1:] in x_label:
                        t_s_b = False
                        break
                else:
                    if not a in x_label:
                        t_s_b = False
                        break
            # either one of || holds
            if t_s_b:
                return t_s_b
        return t_s_b

    def findpath(self, goals):
        """
        find the path backwards
        :param goal: goal state
        :return: dict path : cost
        """
        paths = OrderedDict()
        for i in range(len(goals)):
            goal = goals[i]
            path = [goal]
            s = goal
            while s != self.init:
                s = list(self.tree.pred[s].keys())[0]
                path.insert(0, s)
            if self.seg == 'pre':
                paths[i] = [self.tree.nodes[goal]['cost'], path]
            elif self.seg == 'suf':
                # path.append(self.init)
                paths[i] = [
                    self.tree.nodes[goal]['cost'] +
                    np.linalg.norm(np.subtract(goal[0], self.init[0])), path
                ]
        return paths

    def mulp2sglp(self, point):
        """
        convert multiple form point ((),(),(),...) to single form point ()
        :param point: multiple points ((),(),(),...)
        :return: signle point ()
        """
        sp = []
        for p in point:
            sp = sp + list(p)
        return tuple(sp)

    def sglp2mulp(self, point):
        """
        convert single form point () to multiple form point ((), (), (), ...)
        :param point: single form point ()
        :return:  multiple form point ((), (), (), ...)
        """
        mp = []
        for i in range(self.robot):
            mp.append(point[i * self.dim:(i + 1) * self.dim])
        return tuple(mp)
Beispiel #38
0
def dp_dag_general(G, r, U,
                   cost_func,
                   node_reward_key='r',
                   debug=False):
    """
    cost_func(node, D table, graph, [(cost at child , child)])

    It should return cost as integer type(fixed point is used when appropriate)
    """
    ns = G.nodes()
    if debug:
        print("total #nodes {}".format(len(ns)))
    
    A, D, BP = {}, {}, {}
    for n in ns:
        A[n] = {}  # maximum sum of node u at a cost i
        A[n][0] = G.node[n][node_reward_key]

        D[n] = {}  # set of nodes included corresponding to A[u][i]
        D[n][0] = {n}

        BP[n] = defaultdict(list)  # backpointer corresponding to A[u][i]

    for n_i, n in enumerate(
            topological_sort(G, reverse=True)):  # leaves come first

        if debug:
            print("#nodes processed {}".format(n_i))

        children = G.neighbors(n)
        if debug:
                print('{}\'s children={}'.format(n, children))
        reward = G.node[n][node_reward_key]
        if len(children) == 1:
            child = children[0]
            if debug:
                print('child={}'.format(child))
            for i in A[child]:
                c = cost_func(n, D, G,
                              [(i, child)])
                assert isinstance(c, int)
                if c <= U:
                    A[n][c] = A[child][i] + reward
                    D[n][c] = D[child][i] | {n}
                    BP[n][c] = [(child, i)]
        elif len(children) > 1:
            assert len(children) == 2
            lchild, rchild = children

            for i in A[lchild]:
                c = cost_func(n, D, G,
                              [(i, lchild)])
                assert isinstance(c, int)
                if debug:
                    print('n={}, D={}, cost_child_tuples={}'.format(
                        n, D, [(i, lchild)])
                    )
                    print('c={}'.format(c))
                if c <= U:
                    if A[n].get(c) is None or A[lchild][i] + reward > A[n][c]:
                        A[n][c] = A[lchild][i] + reward
                        D[n][c] = D[lchild][i] | {n}
                        BP[n][c] = [(lchild, i)]

            for i in A[rchild]:
                c = cost_func(n, D, G,
                              [(i, rchild)])
                assert isinstance(c, int)
                if c <= U:
                    if A[n].get(c) is None or A[rchild][i] + reward > A[n][c]:
                        A[n][c] = A[rchild][i] + reward
                        D[n][c] = D[rchild][i] | {n}
                        BP[n][c] = [(rchild, i)]
            
            for i in A[lchild]:
                for j in A[rchild]:
                    c = cost_func(n, D, G,
                                  [(i, lchild), (j, rchild)])
                    assert isinstance(c, int)
                    lset, rset = D[lchild][i], D[rchild][j]
                    if c <= U:
                        if (A[n].get(c) is None or
                            A[lchild][i] + A[rchild][j] + reward > A[n][c]) and \
                           len(lset & rset) == 0:
                            A[n][c] = A[lchild][i] + A[rchild][j] + reward
                            D[n][c] = D[lchild][i] | D[rchild][j] | {n}
                            BP[n][c] = [(lchild, i), (rchild, j)]

            if n == r:  # no need to continue once we processed root
                break
                
    best_cost = max(xrange(U + 1),
                    key=lambda i: A[r][i] if i in A[r] else float('-inf'))
    tree = DiGraph()
    tree.add_node(r)
    stack = []
    if debug and len(stack) == 0:
        print('stack empty')
        print(A)
    for n, cost in BP[r][best_cost]:
        stack.append((r, n, cost))
    while len(stack) > 0:
        if debug:
            print('stack size: {}'.format(len(stack)))
            print('stack: {}'.format(stack))
        
        parent, child, cost = stack.pop(0)
        tree.add_edge(parent, child)

        # copy the attributes
        tree[parent][child] = G[parent][child]
        tree.node[parent] = G.node[parent]
        tree.node[child] = G.node[child]

        for grandchild, cost2 in BP[child][cost]:
            if debug:
                print(grandchild, cost2)
            stack.append((child, grandchild, cost2))

    return tree
Beispiel #39
0
class unbiasedTree(object):
    """
    unbiased tree for prefix and suffix parts
    """
    def __init__(self, workspace, buchi, init_state, init_label, segment,
                 para):
        """
        initialization of the tree
        :param workspace: workspace
        :param buchi: buchi automaton
        :param init_state: initial location of the robots
        :param init_label: label generated by the initial location
        :param segment: prefix or suffix part
        :param para: parameters regarding unbiased-sampling method
        """
        # parameters regarding workspace
        self.workspace = workspace.workspace
        self.dim = len(self.workspace)
        self.regions = workspace.regions
        self.obstacles = workspace.obs
        self.robot = buchi.number_of_robots
        # parameters regarding task
        self.buchi = buchi
        self.accept = self.buchi.buchi_graph.graph['accept']
        self.init = init_state

        # initlizing the tree
        self.unbiased_tree = DiGraph(type='PBA', init=self.init)
        self.unbiased_tree.add_node(self.init, cost=0, label=init_label)

        # parameters regarding TL-RRT* algorithm
        self.goals = set()
        self.step_size = para['step_size']
        self.segment = segment
        self.lite = para['is_lite']
        # size of the ball used in function near
        uni_v = np.power(np.pi, self.robot * self.dim /
                         2) / math.gamma(self.robot * self.dim / 2 + 1)
        # self.gamma = np.ceil(4 * np.power(1 / uni_v, 1. / (self.dim * self.robot)))  # unit workspace
        self.gamma = (2 + 1 / 4) * np.power(
            (1 + 0.0 / 4) * 2.5 / (self.dim * self.robot + 1) / (1 / 4) /
            (1 - 0.0) * 0.84 / uni_v, 1. / (self.dim * self.robot + 1))

        # select final buchi states
        if self.segment == 'prefix':
            self.b_final = self.buchi.buchi_graph.graph['accept'][0]
        else:
            self.b_final = self.buchi.buchi_graph.graph['accept']

        # threshold for collision avoidance
        self.threshold = para['threshold']

    def sample(self):
        """
        sample point from the workspace
        :return: sampled point, tuple
        """
        x_rand = []
        for i in range(self.dim):
            x_rand.append(uniform(0, self.workspace[i]))

        return tuple(x_rand)

    def collision_avoidance(self, x, robot_index):
        """
        check whether robots with smaller index than robot_index collide with the robot of index robot_index
        :param x: position of robots
        :param robot_index: index of the specific robot
        :return: true if collision free
        """
        for i in range(len(x)):
            if i != robot_index and np.fabs(x[i][0] - x[robot_index][0]) <= self.threshold and \
                            np.fabs(x[i][1] - x[robot_index][1]) <= self.threshold:
                return False
        return True

    def nearest(self, x_rand):
        """
        find the nearest class of vertices in the tree
        :param: x_rand randomly sampled point form: single point ()
        :return: nearest class of vertices form: single point ()
        """
        min_dis = math.inf
        q_p_nearest = []
        for node in self.unbiased_tree.nodes:
            x = self.mulp2single(node[0])
            dis = np.linalg.norm(np.subtract(x_rand, x))
            if dis < min_dis:
                q_p_nearest = [node]
                min_dis = dis
            elif dis == min_dis:
                q_p_nearest.append(node)
        return q_p_nearest

    def steer(self, x_rand, x_nearest):
        """
        steer
        :param: x_rand randomly sampled point form: single point ()
        :param: x_nearest nearest point in the tree form: single point ()
        :return: new point single point ()
        """
        if np.linalg.norm(np.subtract(x_rand, x_nearest)) <= self.step_size:
            return x_rand
        else:
            return tuple(
                map(
                    tuple,
                    np.asarray(x_nearest) + self.step_size *
                    (np.subtract(x_rand, x_nearest)) /
                    np.linalg.norm(np.subtract(x_rand, x_nearest))))

    def extend(self, q_new, near_nodes, label, obs_check):
        """
        add the new sate q_new to the tree
        :param: q_new: new state
        :param: near_nodes: near state
        :param: obs_check: check the line connecting two points are inside the freespace
        :return: the tree after extension
        """
        added = False
        cost = np.inf
        q_min = ()
        # loop over all nodes in near_nodes
        for node in near_nodes:
            if q_new != node and obs_check[(q_new[0], node[0])] and \
                    self.check_transition_b(node[1], self.unbiased_tree.nodes[node]['label'], q_new[1]):
                c = self.unbiased_tree.nodes[node]['cost'] \
                    + np.linalg.norm(np.subtract(self.mulp2single(q_new[0]), self.mulp2single(node[0])))
                if c < cost:
                    added = True
                    q_min = node
                    cost = c
        if added:
            self.unbiased_tree.add_node(q_new, cost=cost, label=label)
            self.unbiased_tree.add_edge(q_min, q_new)
            if self.segment == 'prefix' and q_new[1] in self.accept:
                q_n = list(list(self.unbiased_tree.pred[q_new].keys())[0])
                cost = self.unbiased_tree.nodes[tuple(q_n)]['cost']
                label = self.unbiased_tree.nodes[tuple(q_n)]['label']
                q_n[1] = q_new[1]
                q_n = tuple(q_n)
                if q_n != q_min:
                    self.unbiased_tree.add_node(q_n, cost=cost, label=label)
                    self.unbiased_tree.add_edge(q_min, q_n)
                    self.goals.add(q_n)
            # if self.segment == 'suffix' and \
            #         self.obstacle_check([self.init], q_new[0], label)[(q_new[0], self.init[0])] \
            #         and self.check_transition_b(q_new[1], label, self.init[1]):
            #     self.goals.add(q_new)

            elif self.segment == 'suffix' and self.init[1] == q_new[1]:
                self.goals.add(q_new)
        return added

    def rewire(self, q_new, near_nodes, obs_check):
        """
        :param: q_new: new state
        :param: near_nodes: states returned near
        :param: obs_check: check whether obstacle-free
        :return: the tree after rewiring
        """
        for node in near_nodes:
            if obs_check[(q_new[0], node[0])] \
                    and self.check_transition_b(q_new[1], self.unbiased_tree.nodes[q_new]['label'], node[1]):
                c = self.unbiased_tree.nodes[q_new]['cost'] \
                    + np.linalg.norm(np.subtract(self.mulp2single(q_new[0]), self.mulp2single(node[0])))
                delta_c = self.unbiased_tree.nodes[node]['cost'] - c
                # update the cost of node in the subtree rooted at the rewired node
                if delta_c > 0:
                    self.unbiased_tree.remove_edge(
                        list(self.unbiased_tree.pred[node].keys())[0], node)
                    self.unbiased_tree.add_edge(q_new, node)
                    edges = dfs_labeled_edges(self.unbiased_tree, source=node)
                    for _, v, d in edges:
                        if d == 'forward':
                            self.unbiased_tree.nodes[v][
                                'cost'] = self.unbiased_tree.nodes[v][
                                    'cost'] - delta_c

    def near(self, x_new):
        """
        find the states in the near ball
        :param x_new: new point form: single point
        :return: p_near: near state, form: tuple (mulp, buchi)
        """
        near_nodes = []
        radius = min(
            self.gamma * np.power(
                np.log(self.unbiased_tree.number_of_nodes() + 1) /
                self.unbiased_tree.number_of_nodes(), 1. /
                (self.dim * self.robot)), self.step_size)
        for node in self.unbiased_tree.nodes:
            if np.linalg.norm(np.subtract(x_new, self.mulp2single(
                    node[0]))) <= radius:
                near_nodes.append(node)
        return near_nodes

    def obstacle_check(self, near_node, x_new, label):
        """
        check whether line from x_near to x_new is obstacle-free
        :param near_node: nodes returned by near function
        :param x_new: new position component
        :param label: label of x_new
        :return: a dictionary indicating whether the line connecting two points are obstacle-free
        """

        obs_check = {}
        checked = set()

        for node in near_node:
            # whether the position component of nodes has been checked
            if node[0] in checked:
                continue
            checked.add(node[0])
            obs_check[(x_new, node[0])] = True
            flag = True  # indicate whether break and jump to outer loop
            for r in range(self.robot):
                # the line connecting two points crosses an obstacle
                for (obs, boundary) in iter(self.obstacles.items()):
                    if LineString([Point(node[0][r]),
                                   Point(x_new[r])]).intersects(boundary):
                        obs_check[(x_new, node[0])] = False
                        flag = False
                        break
                # no need to check further
                if not flag:
                    break

                for (region, boundary) in iter(self.regions.items()):
                    if LineString([Point(node[0][r]), Point(x_new[r])]).intersects(boundary) \
                            and region + '_' + str(r + 1) != label[r] \
                            and region + '_' + str(r + 1) != self.unbiased_tree.nodes[node]['label'][r]:
                        obs_check[(x_new, node[0])] = False
                        flag = False
                        break
                # no need to check further
                if not flag:
                    break

        return obs_check

    def get_label(self, x):
        """
        generating the label of position component
        :param x: position
        :return: label
        """
        point = Point(x)
        # whether x lies within obstacle
        for (obs, boundary) in iter(self.obstacles.items()):
            if point.within(boundary):
                return obs

        # whether x lies within regions
        for (region, boundary) in iter(self.regions.items()):
            if point.within(boundary):
                return region
        # x lies within unlabeled region
        return ''

    def check_transition_b(self, q_b, x_label, q_b_new):
        """
        check whether q_b -- x_label ---> q_b_new
        :param q_b: buchi state
        :param x_label: label of x
        :param q_b_new: buchi state
        :return True if satisfied
        """
        b_state_succ = self.buchi.buchi_graph.succ[q_b]
        # q_b_new is not the successor of b_state
        if q_b_new not in b_state_succ:
            return False
        # check whether label of x enables the transition
        truth = self.buchi.buchi_graph.edges[(q_b, q_b_new)]['truth']
        if self.check_transition_b_helper(x_label, truth):
            return True

        return False

    def check_transition_b_helper(self, x_label, truth):
        """
        check whether transition enabled with current generated label
        :param x_label: label of the current position
        :param truth: symbol enabling the transition
        :return: true or false
        """
        if truth == '1':
            return True
        # all true propositions should be satisdied
        true_label = [
            true_label for true_label in truth.keys() if truth[true_label]
        ]
        for label in true_label:
            if label not in x_label: return False

        # all fasle propositions should not be satisfied
        false_label = [
            false_label for false_label in truth.keys()
            if not truth[false_label]
        ]
        for label in false_label:
            if label in x_label: return False

        return True

    def find_path(self, goals):
        """
        find the path backwards
        :param goals: found all goal states
        :return: the path leading to the goal state and the corresponding cost
        """
        paths = OrderedDict()
        for i in range(len(goals)):
            goals = list(goals)
            goal = goals[i]
            path = [goal]
            s = goal
            while s != self.init:
                s = list(self.unbiased_tree.pred[s].keys())[0]
                path.insert(0, s)
            if self.segment == 'prefix':
                paths[i] = [self.unbiased_tree.nodes[goal]['cost'], path]
            elif self.segment == 'suffix':
                path.append(self.init)
                paths[i] = [
                    self.unbiased_tree.nodes[goal]['cost'] + np.linalg.norm(
                        np.subtract(self.mulp2single(goal[0]),
                                    self.mulp2single(self.init[0]))), path
                ]

        return paths

    def mulp2single(self, point):
        """
        convert a point, which in the form of a tuple of tuple ((),(),(),...) to point in the form of a flat tuple
        :param point: point((position of robot 1), (position of robot2), (), ...)
        :return: point (position of robot1, position of robot2, ...)
        """
        return tuple([p for r in point for p in r])

    def single2mulp(self, point):
        """
        convert a point in the form of flat tuple to point in the form of a tuple of tuple ((),(),(),...)
        :param point: point (position of robot1, position of robot2, ...)
        :return:  point((position of robot 1), (position of robot2), (), ...)
        """
        mp = [
            point[i * self.dim:(i + 1) * self.dim] for i in range(self.robot)
        ]
        return tuple(mp)
Beispiel #40
0
def hoftask(init, buchi_graph, regions, r):

    h_task = DiGraph(type='subtask')
    try:
        label = to_dnf(
            buchi_graph.edges[(buchi_graph.graph['init'][0],
                               buchi_graph.graph['init'][0])]['label'], True)
    except KeyError:
        # no self loop
        label = to_dnf('0')
    init_node = State((init, buchi_graph.graph['init'][0]), label)
    h_task.add_node(init_node)
    open_set = list()
    open_set.append((init_node, '0'))
    explore_set = list()
    # if  q1 --label--> q2, [target(label), q1]:q2
    succ_dict = dict()
    succ_dict[(init_node, '0')] = {buchi_graph.graph['init'][0]}

    task_group = dict()
    while open_set:
        curr = open_set.pop(0)
        # buchi state that curr corresponds to
        for q_target in succ_dict[curr]:
            try:
                label = to_dnf(
                    buchi_graph.edges[(q_target, q_target)]['label'], True)
            except KeyError:
                # no self loop
                label = to_dnf('0')
            for q_b in buchi_graph.succ[q_target]:

                if q_b != q_target:

                    # region corresponding to the label/word
                    edge_label = (buchi_graph.edges[(q_target, q_b)]['label'])
                    if edge_label == '(1)':
                        x_set = [curr[0].x]
                    elif '~' in edge_label and to_dnf(edge_label).nargs == {
                            1
                    }:  # ~l3_1
                        if curr[0].x == regions[to_dnf(
                                edge_label).args[0].name.split('_')[0]]:
                            x_set = [(curr[0].x[0], curr[0].x[1] - r)]
                        else:
                            x_set = [curr[0].x]
                    else:
                        x_set = target(to_dnf(edge_label), regions)
                    if x_set:
                        for x in x_set:
                            cand = State((x, q_target), label)
                            # seems no need to check
                            # if curr[0] != cand and not match(h_task, curr[0], cand):
                            if not match(h_task, curr[0], cand):
                                h_task.add_edge(curr[0], cand)
                                try:
                                    task_group[curr[0].x].add((curr[0], cand))
                                except KeyError:
                                    task_group[curr[0].x] = {(curr[0], cand)}
                            try:
                                succ_dict[(cand, edge_label)].add(q_b)
                            except KeyError:
                                succ_dict[(cand, edge_label)] = {q_b}

                            if (cand, edge_label) not in open_set and (
                                    cand, edge_label) not in explore_set:
                                open_set.append((cand, edge_label))
                                h_task.add_node(cand)

            explore_set.append(curr)

    return h_task, task_group