Example #1
0
def figure32():
    """
    Solves the reachability game from figure 3.2.
    """
    fig32_graph = io.load_from_file("assets/reachability/figure32.txt")
    (W0, sig0), (W1, sig1) = rs.reachability_solver(fig32_graph, [1], 0)
    return W0 == [1, 2, 3, 5] and sig0 == {
        1: 1,
        2: 1,
        5: 2
    } and W1 == [4, 6] and sig1 == {
        4: 6,
        6: 4
    }
Example #2
0
def example_1():
    """
    Solves a simple example.
    """
    fig51_graph = io.load_from_file("assets/reachability/fig51.txt")
    (W1, sig1), (W0, sig0) = rs.reachability_solver(fig51_graph, [8], 1)
    return W1 == [8, 7, 4] and sig1 == {
        8: 3,
        7: 8
    } and W0 == [1, 2, 3, 5, 6] and sig0 == {
        1: 5,
        3: 3,
        6: 5
    }
Example #3
0
def weak_parity_solver(g):
    """
    Weak parity games solver. This is an implementation of the algorithm presented in chapter 4 of the report.
    :param g: the game to solve.
    :return: the solution in the following format : (W_0, sigma_0), (W_1, sigma_1).
    """

    h = g  # the game we work on
    i = ops.max_priority(h)  # Maximum priority occurring in g

    W0 = []  # winning region for player 0
    W1 = []  # winning region for player 1
    sigma0 = defaultdict(lambda: -1)  # winning strategy for player 0
    sigma1 = defaultdict(lambda: -1)  # winning strategy for player 1

    # considering priorities from i to 0 in decreasing order
    for k in range(i, -1, -1):
        current_player = k % 2  # get current player

        # calling the reachability solver on the game h with target set "nodes of priority k" and for the current player
        (Ak, eta), (Bk, nu) = rs.reachability_solver(h,
                                                     ops.i_priority_node(h, k),
                                                     current_player)

        # depending on the current player, we add the nodes of Ak in a winning region and update strategies
        if current_player == 0:
            W0.extend(Ak)
            sigma0.update(eta)
            sigma1.update(nu)

        else:
            W1.extend(Ak)
            sigma1.update(eta)
            sigma0.update(nu)

        h = h.subgame(
            Bk)  # updates the current game (only keeping nodes in Bk)

    return (W0, sigma0), (W1, sigma1)
Example #4
0
def solver():
    """
    Takes appropriate actions according to the chosen options (using command_line_handler() output).
    """

    # Parsing the command line arguments
    args = command_line_handler()

    if args.mode == "solve":

        """ ----- Solving mode ----- """
        if args.gp:
            g = tools.load_generalized_from_file(args.inputFile)  # we have a generalized parity game arena
        else:
            g = tools.load_from_file(args.inputFile)  # loading game from the input file
        player = 0  # default player is 0, so solution comes as (W_0,sigma_0), (W_1,sigma_1) or (W_0, W_1)

        # Reachability (target and player is set)
        if args.target is not None:
            player = int(args.target[0])  # getting player (as int), replacing default player
            target = map(int, args.target[1].split(","))  # getting node ids in target (transforming them into int)
            solution = reachability.reachability_solver(g, target, player)  # calling reachability solver
            ops.print_solution(solution, player)  # printing the solution

        # Safety (safe set provided)
        if args.safe is not None:
            player = 1 # the player with the reachability objective (to write the solution later)
            safe_set = map(int, args.safe[0].split(","))  # getting node ids in safe set (transforming them into int)
            target_set = []
            # adds every node not in the safe set to the target set
            for node in g.get_nodes():
                if not (node in safe_set):
                    target_set.append(node)
            # the solution comes out as (W_1,sigma_1), (W_0,sigma_0)
            solution = reachability.reachability_solver(g, target_set, 1)  # calling reachability solver with target set for player 1 (2)
            ops.print_solution(solution, 1)  # printing the solution, player 1 (2) has the reachability objective

        # Weak parity
        elif args.wp:
            solution = weakparity.weak_parity_solver(g)  # calling weak parity solver on the game
            ops.print_solution(solution, player)  # printing the solution

        # Strong parity (an algorithm is chosen)
        elif args.parity_algorithm is not None:
            if (args.parity_algorithm == 'recursive'):
                solution = strongparity.strong_parity_solver(g)  # calling recursive algorithm for parity games
                ops.print_solution(solution, player)  # printing the solution (with strategy)
            elif (args.parity_algorithm == 'safety'):
                solution = strongparity.reduction_to_safety_parity_solver(g)  # calling reduction to safety algorithm
                ops.print_winning_regions(solution[0], solution[1]) # printing the solution (without strategy)
            elif (args.parity_algorithm == 'antichain'):
                # calling antichain-based algorithm, assumes indexes start with 1
                solution = strongparity.strong_parity_antichain_based(g,1)
                ops.print_winning_regions(solution[0], solution[1]) # printing the solution (without strategy)
            else:
                # this should not happen
                solution = None

        # Generalized parity
        elif args.gp:
            solution = generalizedparity.generalized_parity_solver(g)  # calling classical algorithm for generalized parity games
            ops.print_winning_regions(solution[0], solution[1])  # printing the solution (without strategy)

        # If output option is chosen and the algorithm is the classical algo for generalized parity games, use special
        # function dedicated to writing solution of generalized parity games (need to consider several priorities)
        if (args.outputFile is not None) and args.gp:
            tools.write_generalized_solution_to_file(g, solution[0], solution[1], args.outputFile)

        # If output option is chosen and the algorithm is the reduction to safety algorithm for parity games or the
        # antichain-based algorithm for parity games then the output is only the winning regions, not the strategies
        elif (args.outputFile is not None) and (args.parity_algorithm == 'safety' or args.parity_algorithm == 'antichain'):
            tools.write_solution_to_file_no_strategies(g, solution[0], solution[1], args.outputFile)

        # Else the regular regions + strategies are output
        elif args.outputFile is not None:
            tools.write_solution_to_file(g, solution, player, args.outputFile)

    elif args.mode == "bench":
        """ ----- Benchmark mode ----- """
        max = args.max
        step = args.step
        rep = args.repetitions
        plot = args.outputPlot is not None

        # Reachability
        if args.reachability_type is not None:
            if args.reachability_type == 'complete0':
                r_bench.benchmark(max, generators.complete_graph, [1], 0, iterations=rep, step=step, plot=plot,
                                  regression=True, order=2, path=args.outputPlot,
                                  title=u"Graphes complets de taille 1 à " + str(max))
            elif args.reachability_type == 'complete1':
                r_bench.benchmark(max, generators.complete_graph, [1], 1, iterations=rep, step=step, plot=plot,
                                  regression=True, order=2, path=args.outputPlot,
                                  title=u"Graphes complets de taille 1 à " + str(max))
            elif args.reachability_type == 'worstcase':
                r_bench.benchmark(max, generators.reachability_worst_case, [1], 0, iterations=rep, step=step,
                                  plot=plot, regression=True, order=2, path=args.outputPlot,
                                  title=u"Graphes 'pire cas' de taille 1 à " + str(max))

        # Weak parity
        elif args.weakparity_type is not None:
            if args.weakparity_type == 'complete':
                wp_bench.benchmark(max, generators.complete_graph_weakparity, iterations=rep, step=step, plot=plot,
                                   regression=True, order=2, path=args.outputPlot,
                                   title=u"Graphes complets de taille 1 à " + str(max))
            elif args.weakparity_type == 'worstcase':
                wp_bench.benchmark(max, generators.weak_parity_worst_case, iterations=rep, step=step, plot=plot,
                                   regression=True, order=3, path=args.outputPlot,
                                   title=u"Graphes 'pire cas' de taille 1 à " + str(max))

        # parity
        elif args.parity_type is not None:
            if args.parity_type == 'recursive-random':
                sp_bench.benchmark_random(max, iterations=rep, step=step, plot=plot,path=args.outputPlot)
            elif args.parity_type == 'safety-random':
                sp_bench.benchmark_random_reduction(max, iterations=rep, step=step, plot=plot,path=args.outputPlot)
            elif args.parity_type == 'antichain-random':
                sp_bench.benchmark_random_antichain_based(max, iterations=rep, step=step, plot=plot,path=args.outputPlot)
            elif args.parity_type == 'recursive-worstcase':
                sp_bench.benchmark_worst_case(max, iterations=rep, step=step, plot=plot, path=args.outputPlot)
            elif args.parity_type == 'safety-worstcase':
                sp_bench.benchmark_worst_case_reduction(max, iterations=rep, step=step, plot=plot,path=args.outputPlot)
            elif args.parity_type == 'antichain-worstcase':
                sp_bench.benchmark_worst_case_antichain_based(max, iterations=rep, step=step, plot=plot,path=args.outputPlot)

        # generalized parity
        else:
            gp_bench.benchmark_random_k_functions(max,3,iterations=rep, step=step, plot=plot, path=args.outputPlot)

    elif args.mode == "test":
        sp_test_result = sp_test.launch_tests()
        wp_test_result = wp_test.launch_tests()
        r_test_result = r_test.launch_tests()
        gp_test_result = gp_test.launch_tests()
        if (sp_test_result and wp_test_result and r_test_result and gp_test_result):
            print "All tests passed with success"
        else:
            print "Some tests failed"
Example #5
0
def benchmark(n,
              generator,
              t,
              p,
              iterations=3,
              step=10,
              plot=False,
              regression=False,
              order=1,
              path="",
              title=""):
    """
    General benchmarking function. Calls reachability solver on games generated using the provided generator function
    and for provided player and target set. Games of size 1 to n by a certain step are solved and a timer records the
    time taken to get the solution. The solver can be timed several times and the minimum value is selected using
    optional parameter iterations (to avoid recording time spikes and delays due to system load). The result as well as
    a regression can be plotted using matplotlib.
    :param n: number of nodes in generated graph.
    :param generator: graph generator function.
    :param iterations: number of times the algorithm is timed (default is 3).
    :param step: step to be taken in the generation.
    :param plot: if True, plots the data using matplotlib.
    :param regression: if True, plots a polynomial regression along with the data.
    :param order: order of that regression.
    :param path: path to the file in which to write the result.
    :param title: the title to be used in the plot.
    """

    y = []  # list for the time recordings
    n_ = []  # list for the x values (1 to n)

    total_time = 0  # accumulator to record total time

    nbr_generated = 0  # conserving the number of generated mesures (used to get the index of a mesure)

    chrono = timer.Timer(verbose=False)  # Timer object

    info = "Time to solve (s), player " + str(p) + ", target set " + str(
        t)  # info about the current benchmark

    # print first line of output
    print u"Generator".center(40) + "|" + u"Nodes (n)".center(12) + "|" + info.center(40) + "\n" + \
          "-" * 108

    # games generated are size 1 to n with a certain step
    for i in range(1, n + 1, step):
        temp = []  # temp list for #iterations recordings
        g = generator(i)  # generated game

        # #iterations calls to the solver are timed
        for j in range(iterations):
            with chrono:
                reachability_solver(g, t, p)  # solver call
            temp.append(chrono.interval)  # add time recording

        min_recording = min(temp)
        y.append(
            min_recording)  # get the minimum out of #iterations recordings
        n_.append(i)
        total_time += min_recording

        print generator.__name__.center(40) + "|" + str(i).center(12) + "|" \
              + str(y[nbr_generated]).center(40) + "\n" + "-" * 108

        nbr_generated += 1  # updating the number of generated mesures

    # at the end, print total time
    print "-" * 108 + "\n" + "Total (s)".center(40) + "|" + "#".center(12) + "|" + \
          str(total_time).center(40) + "\n" + "-" * 108 + "\n"

    # if we need to plot
    if plot:
        plt.grid(True)
        if title != "":
            plt.title(title)
        else:
            plt.title(u"Générateur : " +
                      str(generator.__name__).replace("_", " "))
        plt.xlabel(u'nombre de nœuds')
        plt.ylabel(u'temps (s)')
        if regression:
            coeficients = np.polyfit(n_, y, order)
            polynom = np.poly1d(coeficients)
            points, = plt.plot(n_,
                               y,
                               'g.',
                               label=u"Temps d'exécution, joueur " + str(p) +
                               u',\nensemble cible ' + str(t))
            fit, = plt.plot(n_,
                            polynom(n_),
                            'b--',
                            alpha=0.6,
                            label=u"Régression polynomiale de degré " +
                            str(order))
            plt.legend(loc='upper left', handles=[points, fit])
        else:
            points, = plt.plot(n_, y, 'g.', label=u"Temps d'exécution")
            plt.legend(loc='upper left', handles=[points])

        plt.savefig(path, bbox_inches='tight')
        plt.clf()
        plt.close()
Example #6
0
def benchmark_complete_targetset(n,
                                 iterations=3,
                                 step=10,
                                 plot=False,
                                 regression=False,
                                 path=""):
    """
    Unused. This was made to compare execution time between players on graphs where the target set is the set of nodes.
    Calls reachability solver for player 1 on complete graphs where the target set is the set of all nodes. This makes
    the algorithm add all nodes to the queue and all predecessor lists are iterated over.
    Games of size 1 to n by step of #step are solved and a timer records the time taken to get the solution. The solver
    can be timed several times and the minimum value is selected depending on the value of optional parameter iterations
    (to avoid recording time spikes and delays due to system load). Time to solve the game is recorded and printed to
    the console in a formatted way. The result can be plotted using matplotlib.
    :param n: number of nodes in generated graph.
    :param iterations: number of times the algorithm is timed (default is 3).
    :param step: step between two sizes of graphs generated.
    :param plot: if True, plots the data using matplotlib.
    :param regression: if True, plots a polynomial regression.
    :param path: path to the file in which to write the result.
    """
    y = []  # list for the time recordings
    n_ = []  # list for the x values (1 to n)

    total_time = 0  # accumulator to record total time

    nbr_generated = 0  # conserving the number of generated mesures (used to get the index of a mesure)

    chrono = timer.Timer(verbose=False)  # Timer object

    info = "Time to solve (s), player " + str(
        1) + ", target set : V"  # info about the current benchmark

    # print first line of output
    print u"Generator".center(40) + "|" + u"Nodes (n)".center(12) + "|" + info.center(40) + "\n" + \
          "-" * 108

    # games generated are size 1 to n
    for i in range(1, n + 1, step):
        temp = []  # temp list for #iterations recordings
        g = generators.complete_graph(i)  # generated game

        # #iterations calls to the solver are timed

        target = range(1, i + 1)  # target set is the set of all nodes

        for j in range(iterations):
            with chrono:
                reachability_solver(g, target, 1)  # solver call
            temp.append(chrono.interval)  # add time recording

        min_recording = min(temp)
        y.append(
            min_recording)  # get the minimum out of #iterations recordings
        n_.append(i)
        total_time += min_recording

        print "Complete graph".center(40) + "|" + str(i).center(12) + "|" \
              + str(y[nbr_generated]).center(40) + "\n" + "-" * 108

        nbr_generated += 1  # updating the number of generated mesures

        # at the end, print total time
    print "-" * 108 + "\n" + "Total time".center(40) + "|" + "#".center(12) + "|" + \
          str(total_time).center(40) + "\n" + "-" * 108 + "\n"

    if plot:
        plt.grid(True)
        plt.title(u"Graphes complets de taille 1 à " + str(n))
        plt.xlabel(u'nombre de nœuds')
        plt.ylabel(u'temps (s)')
        if regression:
            coeficients = np.polyfit(n_, y, 2)
            polynom = np.poly1d(coeficients)
            points, = plt.plot(n_,
                               y,
                               'g.',
                               label=u"Temps d'exécution,\nensemble cible : V")
            fit, = plt.plot(n_,
                            polynom(n_),
                            'b--',
                            label=u"Régression polynomiale de degré 2")
            plt.legend(loc='upper left', handles=[points, fit])
        else:
            points, = plt.plot(n_,
                               y,
                               'g.',
                               label=u"Temps d'exécution,\nensemble cible : V")
            plt.legend(loc='upper left', handles=[points])
        plt.savefig(path + "complete_graph" + "_" + str(n) +
                    "nodes_targetallnodes" + ".png",
                    bbox_inches='tight')
        plt.clf()
        plt.close()
Example #7
0
def benchmark_worst_case(n,
                         iterations=3,
                         step=10,
                         plot=False,
                         regression=False,
                         path=""):
    """
    Unused. This was made to compare execution time between players on worst case graphs.
    Calls reachability solver for both players and target set [1] on games generated using the worst case graph
    generator. Games of size 1 to n by step of #step are solved and a timer records the time taken to get the solution.
    The solver can be timed several times and the minimum value is selected depending on the value of optional parameter
    iterations (to avoid recording time spikes and delays due to system load). Time to solve the game for both players
    is recorded and printed to the console in a formatted way. Both results can be plotted using matplotlib.
    :param n: number of nodes in generated graph.
    :param iterations: number of times the algorithm is timed (default is 3).
    :param step: step between two sizes of graphs generated.
    :param plot: if True, plots the data using matplotlib.
    :param regression: if True, plots a polynomial regression.
    :param path: path to the file in which to write the result.
    """
    y_p0 = []  # list for the time recordings of player 0
    y_p1 = []  # list for the time recordings of player 1
    acc_p0 = 0  # accumulator for total time of player 0
    acc_p1 = 0  # accumulator for total time of player 1

    n_ = []  # list for the x values (1 to n)

    nbr_generated = 0  # conserving the number of generated mesures (used to get the index of a mesure)

    chrono = timer.Timer(verbose=False)  # Timer object

    # print first line of output
    print u"Generator".center(30) + "|" + u"Nodes (n)".center(12) + "|" + "Edges (m)".center(10) + "|" \
          + u"Time to solve, player 0".center(28) + "|" + u"Time to solve, player 1".center(28) + "\n" + \
          "-" * 108

    # games generated are size 1 to n
    for i in range(1, n + 1, step):
        temp_p0 = []  # temp list for #iterations recordings player 0
        temp_p1 = []  # temp list for #iterations recordings player 0

        g = generators.reachability_worst_case(i)  # generated game

        # #iterations calls to the solver are timed
        for j in range(iterations):
            with chrono:
                (W_0, sigma_0), (W_1, sigma_1) = reachability_solver(
                    g, [1], 0)  # solver call player 0
            temp_p0.append(chrono.interval)  # add time recording

        for j in range(iterations):
            with chrono:
                (W_1, sigma_1), (W_0, sigma_0) = reachability_solver(
                    g, [1], 1)  # solver call player 1
            temp_p1.append(chrono.interval)  # add time recording

        min_recording_p0 = min(temp_p0)
        y_p0.append(
            min_recording_p0
        )  # get the minimum out of #iterations recordings of player 0
        acc_p0 += min_recording_p0

        min_recording_p1 = min(temp_p1)
        y_p1.append(
            min_recording_p1
        )  # get the minimum out of #iterations recordings of player 1
        acc_p1 += min_recording_p1

        n_.append(i)

        print "Worst-case graph".center(30) + "|" + str(i).center(12) + "|" + str((i * (i + 1)) / 2).center(10) \
              + "|" + str(y_p0[nbr_generated]).center(28) + "|" + str(y_p1[nbr_generated]).center(28) + "\n" + "-" * 108

        nbr_generated += 1  # updating the number of generated mesures

    # at the end, print total time
    print "-" * 108 + "\n" + "Total time".center(30) + "|" + "#".center(12) + "|" + "#".center(10) + "|" + \
          str(acc_p0).center(28) + "|" + str(acc_p1).center(28) + "\n" + "-" * 108 + "\n"

    if plot:
        if regression:
            plt.grid(True)
            plt.title(u"Graphes 'pire cas' de taille 1 à " + str(n))
            plt.xlabel(u'nombre de nœuds')
            plt.ylabel(u'temps (s)')
            coeficients = np.polyfit(n_, y_p0, 2)
            polynom = np.poly1d(coeficients)
            points0, = plt.plot(
                n_,
                y_p0,
                'g.',
                label=u"Temps d'exécution, joueur 0,\nensemble cible {v1}")
            fit0, = plt.plot(n_,
                             polynom(n_),
                             'b--',
                             label=u"Régression polynomiale de degré 2")
            plt.legend(loc='upper left', handles=[points0, fit0])
            plt.savefig(path + "worstCase_" + str(n) + "nodes_player0.png",
                        bbox_inches='tight')
            plt.clf()
            plt.close()

            plt.grid(True)
            plt.title(u"Graphes 'pire cas' de taille 1 à " + str(n))
            plt.xlabel(u'nombre de nœuds')
            plt.ylabel(u'temps (s)')
            coeficients = np.polyfit(n_, y_p1, 1)
            polynom = np.poly1d(coeficients)
            points1, = plt.plot(
                n_,
                y_p1,
                'g.',
                label=u"Temps d'exécution, joueur 1,\nensemble cible {v1}")
            fit1, = plt.plot(
                n_, polynom(n_), 'b--', label=u"Régression linéaire"
            )  # \\\\"+str(coeficients[0])+u"$x^2 +$"+str(coeficients[1])+u"x +"+str(coeficients[2]))
            plt.legend(loc='upper left', handles=[points1, fit1])
            plt.savefig(path + "worstCase_" + str(n) + "nodes_player1.png",
                        bbox_inches='tight')
            plt.clf()
            plt.close()
        else:
            plt.grid(True)
            plt.title(u"Graphes pire cas de taille 1 à " + str(n))
            plt.xlabel(u'nombre de nœuds')
            plt.ylabel(u'temps (s)')
            points0, = plt.plot(
                n_,
                y_p0,
                'g.',
                label=u"Temps d'exécution, joueur 0,\nensemble cible {v1}")
            plt.legend(loc='upper left', handles=[points0])
            plt.savefig(path + "worstCase_" + str(n) + "nodes_player0.png",
                        bbox_inches='tight')
            plt.clf()
            plt.close()

            plt.grid(True)
            plt.title(u"Graphes pire cas de taille 1 à " + str(n))
            plt.xlabel(u'nombre de nœuds')
            plt.ylabel(u'temps (s)')
            points1, = plt.plot(
                n_,
                y_p1,
                'g.',
                label=u"Temps d'exécution, joueur 1,\nensemble cible {v1}")
            plt.legend(loc='upper left', handles=[points1])
            plt.savefig(path + "worstCase_" + str(n) + "nodes_player1.png",
                        bbox_inches='tight')
            plt.clf()
            plt.close()