def example_1(): """ Solves a simple example. """ g = io.load_from_file("assets/strong parity/example_1.txt") (a, b), (c, d) = sp.strong_parity_solver(g) return (a == [1, 3, 2]) and b == {1: 1, 3: 3} and c == [] and d == {}
def worstcase1(): """ Solves a worst case graph G_n for n = 1. """ g = io.load_from_file("assets/strong parity/worstcase_1.txt") (a, b), (c, d) = sp.strong_parity_solver(g) return a == [1, 3, 4, 2, 0] and b == {1: 2, 3: 1} and c == [] and d == {}
def figure56(): """ Solves the strong parity game from figure 5.6. """ fig56_graph = io.load_from_file("assets/strong parity/figure56.txt") (a, b), (c, d) = sp.strong_parity_solver(fig56_graph) return (a == [2, 4, 1, 6]) and b == { 2: 2, 4: 1 } and c == [5, 3] and d == { 5: 5 }
def worstcase2(): """ Solves a worst case graph G_n for n = 2. """ g = io.load_from_file("assets/strong parity/worstcase_2.txt") (a, b), (c, d) = sp.strong_parity_solver(g) return a == [] and b == {} and c == [6, 8, 9, 7, 5, 4, 0, 2, 1, 3 ] and d == { 0: 4, 2: 4, 4: 5, 6: 7, 8: 6 }
def example_5(): """ Solves a simple example. """ g = io.load_from_file("assets/strong parity/example_5.txt") (a, b), (c, d) = sp.strong_parity_solver(g) return a == [2, 1, 5] and b == { 1: 2, 2: 2, 5: 5 } and c == [7, 6, 3, 4] and d == { 3: 6, 4: 3, 6: 6 }
def example_3(): """ Solves a simple example. """ g = io.load_from_file("assets/strong parity/example_3.txt") (a, b), (c, d) = sp.strong_parity_solver(g) return (a == [2, 1, 3, 4]) and b == { 4: 4, 2: 4, 1: 2 } and c == [6, 7, 5] and d == { 7: 6, 6: 6, 5: 6 }
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"
def benchmark_worst_case(n, iterations=3, step=10, plot=False, path=""): """ Benchmarks the recursive algorithm for strong parity games using the worst case generator which yields an exponential complexity. Calls strong parity solver on games generated using the worst case generator function. Games of size 5 to 5*n 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 can be plotted using matplotlib. :param n: number of nodes in generated graph (nodes is 5*n due to construction). :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 path: path to the file in which to write the result. """ y = [] # list for the time recordings n_ = [] # list for the x values (5 to 5n) 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)" # 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.strong_parity_worst_case(i) # generated game # #iterations calls to the solver are timed for j in range(iterations): with chrono: strong_parity_solver(g) # 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(5 * i) total_time += min_recording print "Worst-case graph".center(40) + "|" + str(i * 5).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 plot: plt.grid(True) plt.title(u"Graphes 'pire cas' de taille 5 à " + str(5 * n)) plt.xlabel(u'nombre de nœuds') plt.ylabel(u'temps (s)') # plt.yscale("log") allows logatithmic y-axis 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()
def benchmark_worst_case_removed_optimization(n, iterations=3, step=10, plot=False, path=""): """ Analyzes the influence of the removed list optimization on the recursive algorithm for worst-case graphs. :param n: number of nodes in generated graph (nodes is 5*n due to construction). :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 path: path to the file in which to write the result. """ y = [] # list for the time recordings n_ = [] # list for the x values (5 to 5n) y2 = [] # list for the time recordings n_2 = [] # list for the x values (5 to 5n) 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)" # 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.strong_parity_worst_case(i) # generated game # #iterations calls to the solver are timed for j in range(iterations): with chrono: strong_parity_solver(g) # 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(5 * i) total_time += min_recording temp = [] # #iterations calls to the solver are timed for j in range(iterations): removed = bitarray([False] + ([False] * len(g.nodes))) with chrono: strong_parity_solver_non_removed(g, removed) # solver call temp.append(chrono.interval) # add time recording min_recording = min(temp) y2.append( min_recording) # get the minimum out of #iterations recordings n_2.append(5 * i) min_recording = min(temp) print "Worst-case graph".center(40) + "|" + str(i * 5).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 plot: plt.grid(True) plt.title( u"Recursive algorithm runtime comparison : worst-case graphs of size 1 to " + str(5 * n)) plt.xlabel(u'number of nodes') plt.ylabel(u'time (s)') # plt.yscale("log") allows logatithmic y-axis points, = plt.plot(n_, y, 'g.', label=u"Regular") points2, = plt.plot(n_2, y2, 'r.', label=u"Without sub-game construction") plt.legend(loc='upper left', handles=[points, points2]) plt.savefig(path, bbox_inches='tight') plt.clf() plt.close()
def benchmark_random(n, iterations=3, step=10, plot=False, path=""): """ This function is unfinished. Benchmarks the recursive algorithm for strong parity games using a random generator. Calls strong parity solver on games generated using the random generator function. Games of 1 to n 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 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 to be taken in the generation. :param plot: if True, plots the data using matplotlib. :param path: path to the file in which to write the result. """ y = [] # list for the time recordings n_ = [] # list for the x values 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" # 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 prio = randint(0, i) # number of priorities min_out = randint(1, i) max_out = randint(min_out, i) g = generators.random(i, prio, min_out, max_out) # generated game # #iterations calls to the solver are timed for j in range(iterations): with chrono: strong_parity_solver(g) # 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 "Random 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 aléatoires de taille 1 à " + str(n)) plt.xlabel(u'nombre de nœuds') plt.ylabel(u'temps (s)') points, = plt.plot(n_, y, 'g.', label=u"Temps d'exécution") plt.legend(loc='upper left', handles=[points]) plt.savefig(path + "sp_random_" + str(n) + ".png", bbox_inches='tight') plt.clf() plt.close()