예제 #1
0
class Tree:
    def __init__(self, directed=False, weighted=False):

        self.directed = directed
        self.weighted = weighted
        self.tree = {}
        self.vertex_num = 0
        self.vertex = []
        self.components = UnionFind()

    def add_edge(self, origin, destiny, weight=0):
        def add_vertex(self, vertex):
            if not vertex in self.tree.keys():
                self.components.add(vertex)
                self.tree[vertex] = {}
                self.vertex_num += 1
                self.vertex.append(vertex)

        if not origin in self.tree.keys():
            add_vertex(self, origin)

        if not destiny in self.tree.keys():
            add_vertex(self, destiny)

        if self.components.connected(origin, destiny):
            raise Exception("Cannot add edge, would create a cicle")

        self.tree[origin][destiny] = weight
        if not self.directed:
            self.tree[destiny][origin] = weight

        self.components.union(origin, destiny)
예제 #2
0
	def kruskalMST(self):
		self.generatePQ()
		uf = UnionFind()
		uf.WeightedQuickUnionUF(self.N)
		self.mst = [None] * self.N 

		index = 0

		while len(self.PQ) != 0:
			edge = heapq.heappop(self.PQ)
			if (uf.connected(edge.u, edge.v)):
				continue
			uf.unify(edge.v, edge.u)
			self.mstCost += edge.cost
			self.mst[index] = edge
			index += 1
			if uf.size1(0) == self.N:
				break

		mstExists = (uf.size1(0) == self.N)
		solved = True

		if solved:
			return self.mstCost
		else:
			return None
예제 #3
0
def kruskal(g, w):
    uf = UnionFind(g.keys())
    w = sorted(w, key=lambda x: w[x])
    edges = list()
    for edge in w:
        a, b = edge
        if not uf.connected(a, b):
            uf.union(a, b)
            edges.append(edge)
        if len(edges) == len(g) - 1:
            break
    return edges
예제 #4
0
    def mspEdges(self, heuristicFn):
        A = []
        N = len(self.nodes)
        uf = UnionFind(N)
        weights = self.generate_weights(heuristicFn)

        order = argsort(weights)
        for i in order:
            (u, v) = self.edges[i]
            if not uf.connected(u, v):
                A.append((u, v))
                uf.union(u, v)
        return A
예제 #5
0
  def mspEdges(self, heuristicFn):
    A = []
    N = len(self.nodes)
    uf = UnionFind(N)
    weights = self.generate_weights(heuristicFn)

    order = argsort(weights)
    for i in order:
      (u,v) = self.edges[i]
      if not uf.connected(u,v):
        A.append((u,v))
        uf.union(u,v)
    return A
예제 #6
0
def cluster(edges, start_at):
    uf = UnionFind()

    sortede = sorted(edges, key=lambda x: x[3])

    for k in range(1, 501):
        uf.add(k)

    for _, u, v, w in sortede:

        if len(list(uf.components())) == 4:
            break
        elif not uf.connected(u, v):
            uf.union(u, v)

    find_minimal(uf, edges)
def Clustering(nodes):

    UnionNodes = UnionFind(nodes.keys())


    for node in tqdm(nodes):

        for neighbour in getNeiborhood(node):

            if neighbour not in nodes:
                continue
            
            if not UnionNodes.connected(node, neighbour):
                UnionNodes.union(node, neighbour)

    
    return UnionNodes
예제 #8
0
def prim(g, w, start):
    edges = list()
    uf = UnionFind(g.keys())
    q = list()

    for child in g[start]:
        heappush(q, [w[(start, child)], (start, child)])

    while len(edges) < len(g) - 1:
        weight, (a, b) = heappop(q)
        if not uf.connected(a, b):
            edges.append((a, b))
            uf.union(a, b)
            for child in g[b]:
                if child != a:
                    heappush(q, [w[(b, child)], (b, child)])

    return edges
예제 #9
0
def cluster(nodes):
    uf = UnionFind()
    one_diff, two_diff = one_two_away()

    for v in nodes:
        uf.add(v)

    for vindex, v in enumerate(nodes):

        # squash all the nodes with distance 1 away into me
        od = [(v ^ i) for i in one_diff]
        td = [(v ^ i) for i in two_diff]
        for d in od + td:
            if d in nodes and not uf.connected(v, d):
                uf.union(v, d)
                print("smashed", v, d)

    print(len(list(uf.components())))
예제 #10
0
    def _kruskal(self):

        graph = self.graph
        edge_list = sorted(self.edge_list)

        uf = UnionFind(list(graph.keys()))

        tree = Tree(weighted=True)
        minimum_cost = 0

        for cost, u, v in edge_list:

            if uf.n_comps == 1:
                break

            if not uf.connected(u, v):
                uf.union(u, v)
                minimum_cost += cost
                tree.add_edge(u, v, cost)

        return minimum_cost, tree
예제 #11
0
class GameState:
    """
    Stores information representing the current state of a game of hex, namely
    the board and the current turn. Also provides functions for playing game.
    """

    # dictionary associating numbers with players
    # PLAYERS = {"none": 0, "white": 1, "black": 2}

    # move value of -1 indicates the game has ended so no move is possible
    # GAME_OVER = -1

    # represent edges in the union find structure for detecting the connection
    # for player 1 Edge1 is high and EDGE2 is low
    # for player 2 Edge1 is left and EDGE2 is right

    # neighbor_patterns = ((-1, 0), (0, -1), (-1, 1), (0, 1), (1, 0), (1, -1))

    def __init__(self, size):
        """
        Initialize the game board and give white first turn.
        Also create our union find structures for win checking.

        Args:
            size (int): The board size
        """
        self.size = size
        self.to_play = GameMeta.PLAYERS['white']
        self.board = zeros((size, size))
        self.board = int_(self.board)
        self.white_played = 0
        self.black_played = 0
        self.white_groups = UnionFind()
        self.black_groups = UnionFind()
        self.white_groups.set_ignored_elements(
            [GameMeta.EDGE1, GameMeta.EDGE2])
        self.black_groups.set_ignored_elements(
            [GameMeta.EDGE1, GameMeta.EDGE2])

    def play(self, cell: tuple) -> None:
        """
        Play a stone of the player that owns the current turn in input cell.
        Args:
            cell (tuple): row and column of the cell
        """
        if self.to_play == GameMeta.PLAYERS['white']:
            self.place_white(cell)
            self.to_play = GameMeta.PLAYERS['black']
        elif self.to_play == GameMeta.PLAYERS['black']:
            self.place_black(cell)
            self.to_play = GameMeta.PLAYERS['white']

    def get_num_played(self) -> dict:
        return {'white': self.white_played, 'black': self.black_played}

    def get_white_groups(self) -> dict:
        """

        Returns (dict): group of white groups for unionfind check

        """
        return self.white_groups.get_groups()

    def get_black_groups(self) -> dict:
        """

        Returns (dict): group of white groups for unionfind check

        """
        return self.black_groups.get_groups()

    def place_white(self, cell: tuple) -> None:
        """
        Place a white stone regardless of whose turn it is.

        Args:
            cell (tuple): row and column of the cell
        """
        if self.board[cell] == GameMeta.PLAYERS['none']:
            self.board[cell] = GameMeta.PLAYERS['white']
            self.white_played += 1
        else:
            raise ValueError("Cell occupied")
        # if the placed cell touches a white edge connect it appropriately
        if cell[0] == 0:
            self.white_groups.join(GameMeta.EDGE1, cell)
        if cell[0] == self.size - 1:
            self.white_groups.join(GameMeta.EDGE2, cell)
        # join any groups connected by the new white stone
        for n in self.neighbors(cell):
            if self.board[n] == GameMeta.PLAYERS['white']:
                self.white_groups.join(n, cell)

    def place_black(self, cell: tuple) -> None:
        """
        Place a black stone regardless of whose turn it is.

        Args:
            cell (tuple): row and column of the cell
        """
        if self.board[cell] == GameMeta.PLAYERS['none']:
            self.board[cell] = GameMeta.PLAYERS['black']
            self.black_played += 1
        else:
            raise ValueError("Cell occupied")
        # if the placed cell touches a black edge connect it appropriately
        if cell[1] == 0:
            self.black_groups.join(GameMeta.EDGE1, cell)
        if cell[1] == self.size - 1:
            self.black_groups.join(GameMeta.EDGE2, cell)
        # join any groups connected by the new black stone
        for n in self.neighbors(cell):
            if self.board[n] == GameMeta.PLAYERS['black']:
                self.black_groups.join(n, cell)

    def would_lose(self, cell: tuple, color: int) -> bool:
        """
        Return True is the move indicated by cell and color would lose the game,
        False otherwise.
        """
        connect1 = False
        connect2 = False
        if color == GameMeta.PLAYERS['black']:
            if cell[1] == 0:
                connect1 = True
            elif cell[1] == self.size - 1:
                connect2 = True
            for n in self.neighbors(cell):
                if self.black_groups.connected(GameMeta.EDGE1, n):
                    connect1 = True
                elif self.black_groups.connected(GameMeta.EDGE2, n):
                    connect2 = True
        elif color == GameMeta.PLAYERS['white']:
            if cell[0] == 0:
                connect1 = True
            elif cell[0] == self.size - 1:
                connect2 = True
            for n in self.neighbors(cell):
                if self.white_groups.connected(GameMeta.EDGE1, n):
                    connect1 = True
                elif self.white_groups.connected(GameMeta.EDGE2, n):
                    connect2 = True

        return connect1 and connect2

    def turn(self) -> int:
        """
        Return the player with the next move.
        """
        return self.to_play

    def set_turn(self, player: int) -> None:
        """
        Set the player to take the next move.
        Raises:
            ValueError if player turn is not 1 or 2
        """
        if player in GameMeta.PLAYERS.values(
        ) and player != GameMeta.PLAYERS['none']:
            self.to_play = player
        else:
            raise ValueError('Invalid turn: ' + str(player))

    @property
    def winner(self) -> int:
        """
        Return a number corresponding to the winning player,
        or none if the game is not over.
        """
        if self.white_groups.connected(GameMeta.EDGE1, GameMeta.EDGE2):
            return GameMeta.PLAYERS['white']
        elif self.black_groups.connected(GameMeta.EDGE1, GameMeta.EDGE2):
            return GameMeta.PLAYERS['black']
        else:
            return GameMeta.PLAYERS['none']

    def neighbors(self, cell: tuple) -> list:
        """
        Return list of neighbors of the passed cell.

        Args:
            cell tuple):
        """
        x = cell[0]
        y = cell[1]
        return [(n[0] + x, n[1] + y) for n in GameMeta.NEIGHBOR_PATTERNS
                if (0 <= n[0] + x < self.size and 0 <= n[1] + y < self.size)]

    def moves(self) -> list:
        """
        Get a list of all moves possible on the current board.
        """
        moves = []
        for y in range(self.size):
            for x in range(self.size):
                if self.board[x, y] == GameMeta.PLAYERS['none']:
                    moves.append((x, y))
        return moves

    def __str__(self):
        """
        Print an ascii representation of the game board.
        Notes:
            Used for gtp interface
        """
        white = 'W'
        black = 'B'
        empty = '.'
        ret = '\n'
        coord_size = len(str(self.size))
        offset = 1
        ret += ' ' * (offset + 1)
        for x in range(self.size):
            ret += chr(ord('A') + x) + ' ' * offset * 2
        ret += '\n'
        for y in range(self.size):
            ret += str(y +
                       1) + ' ' * (offset * 2 + coord_size - len(str(y + 1)))
            for x in range(self.size):
                if self.board[x, y] == GameMeta.PLAYERS['white']:
                    ret += white
                elif self.board[x, y] == GameMeta.PLAYERS['black']:
                    ret += black
                else:
                    ret += empty
                ret += ' ' * offset * 2
            ret += white + "\n" + ' ' * offset * (y + 1)
        ret += ' ' * (offset * 2 + 1) + (black + ' ' * offset * 2) * self.size
        return ret
예제 #12
0
class Map:
    # cities = {}
    # _loops = []
    # _borders = []
    # loops = UnionFind()
    # _print: bool = False

    def __init__(self, cities_data, data_limit: int = 0, print: bool = False):
        self.cities = {}
        self._loops = []
        self._borders = []
        self.loops = UnionFind()
        limit = data_limit
        self._print = print
        df = pd.read_csv(cities_data)
        upper = len(df)
        if limit != 0:
            upper = limit
        df = df[0:upper]

        for row in df.iterrows():
            city = City(row[1].CityId, row[1].X, row[1].Y)
            self.cities[city.id] = city
        self._create_loops()

    def _create_loops(self):
        points = []
        g_cities = nx.DiGraph()

        for city in self.cities:
            city = self.cities.get(city)
            g_cities.add_node('f-' + str(city.id), bipartite=0)
            g_cities.add_node('t-' + str(city.id), bipartite=1)
            points.append([city.x, city.y])
        points = np.array(points)
        vor = Voronoi(points, incremental=True)

        for point in vor.ridge_points:
            self.cities[point[0]].add_neighbor(self.cities[point[1]])
            self.cities[point[1]].add_neighbor(self.cities[point[0]])
            g_cities.add_edge('f-' + str(self.cities[point[0]]),
                              't-' + str(self.cities[point[1]]))
            g_cities.add_edge('f-' + str(self.cities[point[1]]),
                              't-' + str(self.cities[point[0]]))

        temp = bipartite.maximum_matching(g_cities)
        print(temp)
        del g_cities
        islands = nx.DiGraph()
        i = 0
        for key, value in temp.items():
            # connect cities ...
            self.cities[int(key[2:])].connect_to(self.cities[int(value[2:])])
            islands.add_edge(self.cities[int(key[2:])],
                             self.cities[int(value[2:])])
            i += 1
            if (i >= temp.__len__() / 2):
                break
        for i, c in enumerate(nx.recursive_simple_cycles(islands)):
            # for i, c in enumerate(nx.simple_cycles(islands)):
            loop = Loop(c, i)
            self._loops.append(loop)
            self.loops.add(i)

        # plt.subplot(121)
        # nx.draw(islands, with_labels=True)
        # plt.savefig('temp_diagram.png')
        # plt.show()

    def loops_borders(self):
        temp_h = []
        n = len(self.loops)
        for i in range(n):
            for j in range(i + 1, n):
                temp_h = self._loops[i].find_border(self._loops[j], temp_h)
        return temp_h

    def merge_loops(self):
        city_pairs = self.loops_borders()
        while (city_pairs.__len__() > 0):
            cp = hq.heappop(city_pairs)
            if (not (self.loops.connected(cp[1].loop_id, cp[2].loop_id))):
                # connect loops
                if (self.merge_node(cp[1], cp[2])):
                    self.loops.union(cp[1].loop_id, cp[2].loop_id)

    def merge_node(self, c1: City, c2: City):
        p = c1
        q = c2
        if (self.is_revers(c1, c2)):
            p = c2
            q = c1
        self.connect(q.prev, p.next)
        self.connect(p, q)
        return True

    def connect(self, p: City, q: City) -> bool:
        p.next = q
        q.prev = p
        if (self._print):
            print(str(p.id) + ' --> ' + str(q.id))

    def is_revers(self, c1: City, c2: City):
        dist_12 = c2.prev.sqr_dist_to(c1.next)
        dist_21 = c1.prev.sqr_dist_to(c2.next)
        return dist_12 > dist_21

    def print_loops(self):
        print('loops ...')
        for loop in self._loops:
            print('------------')
            for vertex in loop.cities:
                print(
                    str(loop.cities.get(vertex)) + '\tEnergy: ' +
                    str(loop.cities.get(vertex).energy))

    def print_path(self):
        current_city = self.cities[0]
        current_energy = 10
        dist = 0
        min_enrg = 10
        while True:
            d = current_city.dist_to(current_city.next)
            if (min_enrg > current_energy):
                min_enrg = current_energy
            if (current_energy <= 0):
                d = d * 1.1
            dist += d
            print(str(current_city.id))
            # print(str(current_city.id)+'\tE: '+str(current_energy))
            current_city = current_city.next
            if (current_city.next == self.cities[0]):
                print(current_city.id)
                break
            current_energy += -1
            if (current_city.is_prime):
                current_energy = 10
        print('Distance: ' + str(dist))
        print('Minimum Energy:' + str(min_enrg))

    def save_path(self, file_name: str = "myFile.csv"):
        f = open(file_name, "w")
        f.write('Path\n')
        current_city = self.cities[0]
        while True:
            f.write(str(current_city.id) + '\n')
            current_city = current_city.next
            if (current_city.next == self.cities[0]):
                f.write(str(current_city.id) + '\n')
                break
        f.write('0\n')

    def save_paths(self, file_name: str = "myFile.csv"):
        f = open(file_name, "w")
        f.write('Path\n')
        current_city = self.cities[0]
        current_energy = 10
        dist = 0
        min_enrg = 10
        while True:
            d = current_city.dist_to(current_city.next)
            if (min_enrg > current_energy):
                min_enrg = current_energy
            if (current_energy <= 0):
                d = d * 1.1
            dist += d
            f.write(str(current_city.id) + '\n')
            current_city = current_city.next
            if (current_city.next == self.cities[0]):
                f.write(str(current_city.id) + '\n')
                break
            current_energy += -1
            if (current_city.is_prime):
                current_energy = 10
        f.write('0\n')
        print('Distance: ' + str(dist))
        return {'totalDist': dist, 'minEnergy': min_enrg}