コード例 #1
0
def psolB_modified_att(g, W1, W2):
    """
    Partial solver psolB for parity games using fatal attractors. Implementation using a variant of attractors.
    :param g: a game graph.
    :return: a partial solution g', W1', W2' in which g is an unsolved subgame of g and W1', W2' are included in the
    two respective winning regions of g.
    """

    for color in sort_colors_ascending(g):

        if DEBUG_PRINT: print("Computing for color " + str(color))

        target_set = ops.i_priority_node(g, color)  # set of nodes of color 'color'

        cache = set()

        # TODO check list comparison efficiency
        while cache != set(target_set) and target_set != []:

            cache = target_set

            MA, in_att, rest = monotone_attractor_including_target(g, target_set, color)

            if DEBUG_PRINT: print(" MA " + str(MA) + " Player " + str(g.get_node_player(target_set[0])) + "\n")

            # if the sum of values is the length of the target set, every node in target is in the attractor
            if sum(in_att.itervalues()) == len(target_set):

                if DEBUG_PRINT: print("Set " + str(target_set) + " in MA ")

                att, complement = attractor(g, MA, color % 2)

                if color % 2 == 0:
                    W1.extend(att)
                else:
                    W2.extend(att)

                return psolB_modified_att(g.subgame(complement), W1, W2)

            else:
                # only keep in target the target nodes that are included in the attractor
                target_set = filter(lambda x: in_att[x] == 1, in_att.iterkeys())

    return g, W1, W2
コード例 #2
0
def psolB_set(g, W1, W2):
    """
    Partial solver psolB for parity games using fatal attractors. Implementation using sets.
    :param g: a game graph.
    :return: a partial solution g', W1', W2' in which g is an unsolved subgame of g and W1', W2' are included in the
    two respective winning regions of g.
    """

    empty_set = set()

    for color in sort_colors_ascending(g):

        if DEBUG_PRINT: print("Computing for color " + str(color))

        target_set = set(ops.i_priority_node(g, color))  # set of nodes of color 'color'

        cache = set()

        while cache != target_set and target_set != empty_set:

            cache = target_set

            MA, rest = monotone_attractor(g, target_set, color)

            if DEBUG_PRINT: print(" MA " + str(MA) + " Player " + str(g.get_node_player(target_set[0])) + "\n")

            if target_set.issubset(MA):

                if DEBUG_PRINT: print("Set " + str(target_set) + " in MA ")

                att, complement = attractor(g, MA, color % 2)

                if color % 2 == 0:
                    W1.extend(att)
                else:
                    W2.extend(att)

                return psolB_set(g.subgame(complement), W1, W2)

            else:
                target_set = target_set.intersection(MA)

    return g, W1, W2
コード例 #3
0
def psolB_buchi_safety(g, W1, W2):
    """
    Partial solver psolB for parity games. This implementation uses buchi inter safety to find fatal attractors.
    :param g: a game graph.
    :return: a partial solution g', W1', W2' in which g is an unsolved subgame of g and W1', W2' are included in the
    two respective winning regions of g.
    """

    for color in sort_colors_ascending(g):

        if DEBUG_PRINT: print("Computing for color " + str(color))

        target_set = ops.i_priority_node(g, color)  # set of nodes of color 'color'

        # TODO here replace previous call by a call which goes through each node and add it to in/out set of color i
        # we only go trough every node once and add it to greater than color or of priority color

        # record the nodes we don't want to see infinitely often i.e. the ones with greater priority than color
        not_target_set_bigger = []
        for node in g.nodes.iterkeys():
            if g.get_node_priority(node) > color:
                not_target_set_bigger.append(node)

        # winning region of buchi inter safety for player color % 2
        w = safety.buchi_inter_safety_player(g, target_set, not_target_set_bigger, color % 2)

        if DEBUG_PRINT: print(" MA " + str(w) + " Player " + str(g.get_node_player(target_set[0])) + "\n")

        if w != []:

            if DEBUG_PRINT: print("Set " + str(target_set) + " in MA ")

            att, complement = attractor(g, w, color % 2)

            if color % 2 == 0:
                W1.extend(att)
            else:
                W2.extend(att)

            return psolB_buchi_safety(g.subgame(complement), W1, W2)

    return g, W1, W2
コード例 #4
0
def zielonka_with_partial(g, partial_solver):
    """
    This is an implementation of Zielonka's recursive algorithm used to solve parity games. This implementation uses a
    provided partial solver to speed up the solving process. This implementation does not compute the winning strategies
    (for comparison purpose with other algorithms which don't).

    :param g: the game to solve.
    :param partial_solver: a partial solver.
    :return: the solution in the following format : (W_0, W_1).
    """

    rest, partial_1, partial_2 = partial_solver(
        g, [], [])  # TODO this is the default input for the algorithms
    # a more general way is to use just g as input and add the [] [] in a wrapper function in PSOLB

    W1 = []  # Winning region of player 0
    W2 = []  # Winning region of player 1

    # add the partial solutions to the winning regions
    W1.extend(partial_1)
    W2.extend(partial_2)

    # if the game is empty, return the empty regions
    if len(rest.nodes) == 0:
        return W1, W2

    else:
        i = ops.max_priority(rest)  # get max priority occurring in g

        # determining which player we are considering, if i is even : player 0 and else player 1
        if i % 2 == 0:
            j = 0
        else:
            j = 1

        opponent = ops.opponent(j)  # getting the opponent of the player

        U = ops.i_priority_node(
            rest, i)  # target set for the attractor : nodes of priority i

        # getting the attractor A and discarding the region for the opponent
        A, discard1 = attractor(rest, U, j)

        # The subgame G\A is composed of the nodes not in the attractor, thus the nodes of the opposite player's region
        G_A = rest.subgame(discard1)

        # Recursively solving the subgame G\A, solution comes as (W_0, W_1)
        sol_player1, sol_player2 = zielonka_with_partial(G_A, partial_solver)

        # depending on which player we are considering, assign regions to the proper variables
        # W'_j is noted W_j, sigma'_j is noted sig_j; the same aplies for jbar
        if j == 0:
            W_j = sol_player1
            W_jbar = sol_player2
        else:
            W_j = sol_player2
            W_jbar = sol_player1

        # if W'_jbar is empty we update the regions depending on the current player
        # the region for the whole game for one of the players is empty
        if not W_jbar:
            if j == 0:
                W1.extend(A)
                W1.extend(W_j)
            else:
                W2.extend(A)
                W2.extend(W_j)
        else:
            # compute attractor B
            B, discard1 = attractor(rest, W_jbar, opponent)
            # The subgame G\B is composed of the nodes not in the attractor, so of the opposite player's winning region
            G_B = rest.subgame(discard1)

            # recursively solve subgame G\B, solution comes as (W_0, W_1)
            sol_player1_, sol_player2_ = zielonka_with_partial(
                G_B, partial_solver)

            # depending on which player we are considering, assign regions to the proper variables
            # W''_j is noted W__j, sigma''_j is noted sig__j; the same aplies for jbar
            if j == 0:
                W__j = sol_player1_
                W__jbar = sol_player2_
            else:
                W__j = sol_player2_
                W__jbar = sol_player1_

            # the last step is to update the winning regions depending on which player we consider
            if j == 0:
                W1 = W__j

                W2.extend(W__jbar)
                W2.extend(B)

            else:
                W2 = W__j

                W1.extend(W__jbar)
                W1.extend(B)

    return W1, W2
コード例 #5
0
def strong_parity_solver_no_strategies(g):
    """
    Strong parity games solver. This is an implementation of the recursive algorithm used to solve parity games.
    This implementation does not compute the winning strategies (for comparison purpose with other algorithms
    which don't)
    :param g: the game to solve.
    :return: the solution in the following format : (W_0, W_1).
    """
    W1 = []  # Winning region of player 0
    W2 = []  # Winning region of player 1

    # if the game is empty, return the empty regions
    if len(g.nodes) == 0:
        return W1, W2

    else:
        i = ops.max_priority(g)  # get max priority occurring in g

        # determining which player we are considering, if i is even : player 0 and else player 1
        if i % 2 == 0:
            j = 0
        else:
            j = 1

        opponent = ops.opponent(j)  # getting the opponent of the player

        U = ops.i_priority_node(
            g, i)  # target set for the attractor : nodes of priority i

        # getting the attractor A and discarding the region for the opponent
        A, discard1 = attractor(g, U, j)

        # The subgame G\A is composed of the nodes not in the attractor, thus the nodes of the opposite player's region
        G_A = g.subgame(discard1)

        # Recursively solving the subgame G\A, solution comes as (W_0, W_1)
        sol_player1, sol_player2 = strong_parity_solver_no_strategies(G_A)

        # depending on which player we are considering, assign regions to the proper variables
        # W'_j is noted W_j, sigma'_j is noted sig_j; the same aplies for jbar
        if j == 0:
            W_j = sol_player1
            W_jbar = sol_player2
        else:
            W_j = sol_player2
            W_jbar = sol_player1

        # if W'_jbar is empty we update the regions depending on the current player
        # the region for the whole game for one of the players is empty
        if not W_jbar:
            if j == 0:
                W1.extend(A)
                W1.extend(W_j)
            else:
                W2.extend(A)
                W2.extend(W_j)
        else:
            # compute attractor B
            B, discard1 = attractor(g, W_jbar, opponent)
            # The subgame G\B is composed of the nodes not in the attractor, so of the opposite player's winning region
            G_B = g.subgame(discard1)

            # recursively solve subgame G\B, solution comes as (W_0, W_1)
            sol_player1_, sol_player2_ = strong_parity_solver_no_strategies(
                G_B)

            # depending on which player we are considering, assign regions to the proper variables
            # W''_j is noted W__j, sigma''_j is noted sig__j; the same aplies for jbar
            if j == 0:
                W__j = sol_player1_
                W__jbar = sol_player2_
            else:
                W__j = sol_player2_
                W__jbar = sol_player1_

            # the last step is to update the winning regions depending on which player we consider
            if j == 0:
                W1 = W__j

                W2.extend(W__jbar)
                W2.extend(B)

            else:
                W2 = W__j

                W1.extend(W__jbar)
                W1.extend(B)

    return W1, W2
コード例 #6
0
def zielonka_with_single_psolB_iteration(g):
    """
    This is an implementation of Zielonka's recursive algorithm used to solve parity games. This implementation uses one
    iteration of psolB, for the set of nodes of maximum priority retrieved by the algorithm. This implementation does
    not compute the winning strategies (for comparison purpose with other algorithms which don't).
    :param g: the game to solve.
    :return: the solution in the following format : (W_0, W_1).
    """

    W1 = []  # Winning region of player 0
    W2 = []  # Winning region of player 1

    W1_partial = []
    W2_partial = []

    empty_set = set()

    # if the game is empty, return the empty regions
    if len(g.nodes) == 0:
        return W1, W2

    else:
        i = ops.max_priority(g)  # get max priority occurring in g

        # determining which player we are considering, if i is even : player 0 and else player 1
        if i % 2 == 0:
            j = 0
        else:
            j = 1

        opponent = ops.opponent(j)  # getting the opponent of the player

        U = ops.i_priority_node(
            g, i)  # target set for the attractor : nodes of priority i

        rest = g  # from now on we work on the game called rest which is g by default, but can be a sub-game of g

        target_set = set(U)  # set of nodes of color 'color'

        cache = set()

        flag = True

        while flag and cache != target_set and target_set != empty_set:

            cache = target_set

            MA, discard = psolB.monotone_attractor(rest, target_set, i)

            if target_set.issubset(MA):

                att, complement = attractor(rest, MA, i % 2)

                if i % 2 == 0:
                    W1_partial.extend(att)
                else:
                    W2_partial.extend(att)

                # we have updated winning regions, we also remove attractor to obtain a sub-game
                rest = g.subgame(complement)

                if rest.get_nodes() == []:
                    return W1_partial, W2_partial

                i = ops.max_priority(rest)  # get max priority occurring in g

                # determining which player we are considering, if i is even : player 0 and else player 1
                if i % 2 == 0:
                    j = 0
                else:
                    j = 1

                opponent = ops.opponent(
                    j)  # getting the opponent of the player

                U = ops.i_priority_node(
                    rest,
                    i)  # target set for the attractor : nodes of priority i

                flag = False

            else:
                target_set = target_set.intersection(MA)

        # getting the attractor A and discarding the region for the opponent
        A, discard1 = attractor(rest, U, j)

        # The subgame G\A is composed of the nodes not in the attractor, thus the nodes of the opposite player's region
        G_A = rest.subgame(discard1)

        # Recursively solving the subgame G\A, solution comes as (W_0, W_1)
        sol_player1, sol_player2 = zielonka_with_single_psolB_iteration(G_A)

        # depending on which player we are considering, assign regions to the proper variables
        # W'_j is noted W_j, sigma'_j is noted sig_j; the same aplies for jbar
        if j == 0:
            W_j = sol_player1
            W_jbar = sol_player2
        else:
            W_j = sol_player2
            W_jbar = sol_player1

        # if W'_jbar is empty we update the regions depending on the current player
        # the region for the whole game for one of the players is empty
        if not W_jbar:
            if j == 0:
                W1.extend(A)
                W1.extend(W_j)
            else:
                W2.extend(A)
                W2.extend(W_j)
        else:
            # compute attractor B
            B, discard1 = attractor(rest, W_jbar, opponent)
            # The subgame G\B is composed of the nodes not in the attractor, so of the opposite player's winning region
            G_B = rest.subgame(discard1)

            # recursively solve subgame G\B, solution comes as (W_0, W_1)
            sol_player1_, sol_player2_ = zielonka_with_single_psolB_iteration(
                G_B)

            # depending on which player we are considering, assign regions to the proper variables
            # W''_j is noted W__j, sigma''_j is noted sig__j; the same aplies for jbar
            if j == 0:
                W__j = sol_player1_
                W__jbar = sol_player2_
            else:
                W__j = sol_player2_
                W__jbar = sol_player1_

            # the last step is to update the winning regions depending on which player we consider
            if j == 0:
                W1 = W__j

                W2.extend(W__jbar)
                W2.extend(B)

            else:
                W2 = W__j

                W1.extend(W__jbar)
                W1.extend(B)

    if not flag:
        W1.extend(W1_partial)
        W2.extend(W2_partial)

    return W1, W2