def test_check_imperfect_solution(self): n = 4 cols = 10 rows = 5 dg = DataGenerator() some_instance_np_array = np.array( [[1, 10, 1], [2, 10, 2], [1, 10, 3], [5, 10, 4], [1, 10, 1]]) solution_checker = SolutionChecker(n, cols, rows) self.assertEqual( solution_checker.get_reward(some_instance_np_array), (10 * 5) / (cols * rows) )
def test_check_imperfect_solution_count_files_2(self): n = 4 cols = 10 rows = 5 dg = DataGenerator() some_instance_np_array = np.array( [[1, 10, 1], [6, 10, 2], [2, 10, 3], [1, 10, 4], [1, 10, 1]]) solution_checker = SolutionChecker(n, cols, rows) self.assertEqual( solution_checker.get_reward(some_instance_np_array, count_tiles=True), 1 / n )
def perform_simulation(self, state): ''' Performs the simulation until legal moves are available. If simulation ends by finding a solution, a root state starting from this simulation is returned ''' solution_tiles_order = [] depth = 0 simulation_root_state = state # in case simulation ends in solution; these states are the solution if len(state.tiles) == 0: print('perform_simulation called with empty tiles') return ALL_TILES_USED, simulation_root_state, solution_tiles_order val = self.val while True: val += 1 if len(state.tiles) == 0: print('solution found in simulation') return ALL_TILES_USED, simulation_root_state, solution_tiles_order valid_moves = SolutionChecker.get_valid_next_moves(state, state.tiles, val=val, colorful_states=self.colorful_states) if not valid_moves: return depth, simulation_root_state, solution_tiles_order next_random_tile_index = random.randint(0, len(valid_moves) -1) success, new_board = SolutionChecker.get_next_turn( state, valid_moves[next_random_tile_index], val, destroy_state=True, colorful_states=self.colorful_states ) self.n_tiles_placed += 1 solution_tiles_order.append(valid_moves[next_random_tile_index]) if success == ALL_TILES_USED: print('grid is full') # no LFB on grid; probably means grid is full solution_tiles_order.append(valid_moves[next_random_tile_index]) return ALL_TILES_USED, simulation_root_state, solution_tiles_order elif success == NO_NEXT_POSITION_TILES_UNUSED: print('no next position with unused tiles') return depth, simulation_root_state, solution_tiles_order elif success == TILE_CANNOT_BE_PLACED: # cannot place the tile. return depth reached return depth, simulation_root_state, solution_tiles_order else: new_tiles = SolutionChecker.eliminate_pair_tiles(state.tiles, valid_moves[next_random_tile_index]) new_state = State(board=new_board, tiles=new_tiles, parent=state) new_state.score = -1 # because no choice is performed for sequent actions state.children.append(new_state) state = new_state depth += 1 return depth, simulation_root_state, solution_tiles_order
def test_check_perfect_solution(self): n = 20 w = 40 h = 40 dg = DataGenerator() some_instance_visual = dg.gen_instance_visual(n, w, h) perfect_bin_configuration = sorted(some_instance_visual, key=lambda x: (x[2][0], x[2][1])) some_instance_np_array = dg._transform_instance_visual_to_np_array(some_instance_visual) solution_checker = SolutionChecker(n, h, w) self.assertEqual( solution_checker.get_reward(np.array(perfect_bin_configuration)), 0 )
def test_check_imperfect_solution_count_tiles(self): n = 4 cols = 10 rows = 5 dg = DataGenerator() some_instance_visual = dg.gen_instance_visual(n, cols, rows) # NOTE: first bin always repeated some_instance_np_array = np.array( [[1, 10, 1], [2, 10, 2], [1, 10, 3], [5, 10, 4], [1, 10, 1]]) solution_checker = SolutionChecker(n, cols, rows) self.assertEqual( solution_checker.get_reward(some_instance_np_array, count_tiles=True), 1 / n )
def test_get_next_turn_only_success(self): success, new_board, = SolutionChecker.get_next_turn( self.state, self.tile, val=1, get_only_success=True, destroy_state=True ) # assert board is destroyed i.e. equal to new_board self.assertIsNone(new_board)
def test_get_next_lfb_on_grid_5(self): state = np.array([ [1, 1, 1, 1], [1, 1, 1, 1], [0, 0, 0, 1] ]) res = SolutionChecker.get_next_lfb_on_grid(state) self.assertEqual(res, (2, 0))
def get_next_turn(self, state, tile, val=1): new_board = np.copy(state.board) next_position = SolutionChecker.get_next_lfb_on_grid(new_board) # one without the other should not be possible if not next_position and len(state.tiles) == 0: print('solution found!') return ALL_TILES_USED, None elif not next_position: return NO_NEXT_POSITION_TILES_UNUSED, None success, new_board = SolutionChecker.place_element_on_grid_given_grid( tile, SolutionChecker.get_next_lfb_on_grid(new_board), val, new_board, get_cols(new_board), get_rows(new_board)) if not success: # cannot place the tile. this branch will not be considered return TILE_CANNOT_BE_PLACED, None return True, new_board
def test_get_possible_tile_actions_given_grid(self): grid = np.array([ [1, 1, 1, 0, 0], [1, 1, 1, 0, 0], [1, 1, 1, 0, 0], ]) tiles = [[1, 2], [2, 1], [4, 5], [1, 1], [1, 1], [3, 2], [3, 3], [2, 3]] possible_tiles_to_place = SolutionChecker.get_possible_tile_actions_given_grid(grid, tiles) self.assertEqual(possible_tiles_to_place, [[1, 2], [2, 1], [1, 1], [1, 1], [3, 2]])
def test_get_valid_next_moves_1(self): self.board = np.array([ [1, 1, 1, 1], [1, 1, 1, 0], [0, 0, 0, 0] ]) self.tiles = [(2, 1), (1, 2)] self.state = State(self.board, self.tiles) next_moves = SolutionChecker.get_valid_next_moves(self.state, self.tiles) self.assertEqual(next_moves, [(2, 1)])
def __init__(self, tiles, board, strategy='max_depth'): self.initial_tiles, self.initial_board = tiles, board self.state = State(self.initial_board, self.initial_tiles) self.solution_checker = SolutionChecker(len(tiles), get_rows(board), get_cols(board)) self.strategy=strategy self.n_tiles_placed = 0 self.solution_tiles_order = [] # for MCTS vis purposes self.colorful_states = True
def test_get_next_turn_destroy_board(self): success, new_board, = SolutionChecker.get_next_turn( self.state, self.tile, val=1, get_only_success=False, destroy_state=True ) self.assertEqual(success, True) # assert board is destroyed i.e. equal to new_board np.testing.assert_array_equal( self.state.board, new_board )
def test_get_valid_actions_indexed_given_grid(self): grid = np.array([ [1, 1, 1, 0, 0], [1, 1, 1, 0, 0], [1, 1, 1, 0, 0], ]) tiles = [[1, 2], [2, 1], [0, 0], [4, 5], [1, 1], [1, 1], [3, 2], [3, 3], [2, 3]] possible_tiles_indexes = SolutionChecker.get_valid_tile_actions_indexes_given_grid( grid, tiles) self.assertEqual(possible_tiles_indexes, [1, 1, 0, 0, 1, 1, 1, 0, 0])
def test_get_valid_next_moves_2(self): self.board = np.array([ [1, 1, 1, 1], [1, 1, 1, 0], [0, 0, 0, 0] ]) tiles_list = [(2, 1), (1, 2), (3, 3), (4, 4), (1, 1)] self.tiles = sorted(tiles_list, key=lambda x: (x[1], x[0])) self.state = State(self.board, self.tiles) next_moves = SolutionChecker.get_valid_next_moves(self.state, self.tiles) self.assertEqual(next_moves, [(1, 1), (2, 1)])
def initialize(self, height, width, n_tiles): Game.__init__(self) self.height = height self.width = width self.n_tiles = n_tiles dg = DataGenerator() self.tiles, solution = dg.gen_instance(n_tiles, width, height) # print(self.tiles) _tiles_ints = SolutionChecker.get_tiles_with_orientation(self.tiles) self._base_board = Board(height, width, _tiles_ints, n_tiles)
def __init__(self, tiles, board): self.Qsa = {} # stores Q values for s,a (as defined in the paper) self.Nsa = {} # stores #times edge s,a was visited self.Ns = {} # stores #times board s was visited self.Ps = {} # stores initial policy (returned by neural net) self.Es = {} # stores game.getGameEnded ended for board s self.Vs = {} # stores game.getValidMoves for board s self.initial_tiles, self.initial_board = tiles, board self.state = State(self.initial_board, self.initial_tiles) self.solution_checker = SolutionChecker(len(tiles), get_rows(board), get_cols(board))
def test_bin_outside_border(self): n = 20 h = 50 w = 50 solution_checker = SolutionChecker(n, h, w) # # 11 ------------- # | | # | | | # | | | # -----------------------| # 40 solution_checker.LFBs = SortedKeyList([], key=lambda x: (x[1], x[0])) solution_checker.LFBs.add((40, 11)) _bin = (10, 10) self.assertFalse(solution_checker.is_bin_outside_borders(_bin)) _bin = (12, 10) self.assertTrue(solution_checker.is_bin_outside_borders(_bin))
def build_reward(self): # reorder input % tour and return tour length (euclidean distance) self.permutations = tf.stack( # this just creates a vectors with repeating idxs so we can gather later [ tf.tile(tf.expand_dims(tf.range(self.batch_size,dtype=tf.int32), 1), [1, self.n+1]), self.tour ], 2 ) if self.is_training==True: self.ordered_input_ = tf.gather_nd(self.input_,self.permutations) else: self.ordered_input_ = tf.gather_nd(tf.tile(self.input_,[self.batch_size,1,1]),self.permutations) solution_checker = SolutionChecker(self.n, self.w, self.h) sess = tf.Session() rewards = tf.py_func( solution_checker.get_rewards, [self.ordered_input_, self.count_non_placed_tiles, self.combinatorial_reward], tf.float32) self.reward = rewards tf.summary.scalar('reward_mean', tf.reduce_mean(rewards))
def get_only_random_predictions(examples): total_random_correct = 0 with open("tensorboard/random_predictions.csv", 'w') as f: for i in range(2755): total_count = 0 total_random_correct = 0 for example in examples: expected = np.argmax(example[2]) expected_tile = example[1][expected] random_prediction = random.randint( 0, SolutionChecker.get_n_nonplaced_tiles(example[1]) - 1) if np.array_equal(expected_tile, example[1][random_prediction]): total_random_correct += 1 total_count += 1 accuracy = (total_random_correct / total_count) * 100 f.write(f'{accuracy}\n') print(accuracy) return
def test_get_next_turn(self): success, new_board, = SolutionChecker.get_next_turn( self.state, self.tile, val=1, get_only_success=False, destroy_state=False ) self.assertEqual(success, True) np.testing.assert_array_equal( new_board, np.array([ [1, 1, 1, 1], [1, 1, 1, 1], [0, 0, 0, 1] ]) ) # assert board is not destroyed np.testing.assert_array_equal( self.state.board, np.array([ [1, 1, 1, 1], [1, 1, 1, 0], [0, 0, 0, 0] ]) )
def main(options): #N_TILES = 8 #HEIGHT = 8 #WIDTH = 8 HEIGHT = 25 WIDTH = 25 N_TILES = 50 for (WIDTH, HEIGHT) in [(30, 30)]: #for N_TILES in [50]: SCALAR_TILES = True predict_move_index = True g = Game(HEIGHT, WIDTH, N_TILES) dg = DataGenerator(WIDTH, HEIGHT) # from alpha.binpack.tensorflow.NNet import NNetWrapper as nn from alpha.binpack.keras.NNet import NNetWrapper as nn nnet = nn(g, scalar_tiles=SCALAR_TILES) n_tiles, height, width = N_TILES, HEIGHT, WIDTH if options['load_model']: nnet.load_checkpoint() else: # place tiles one by one # generate pair x and y where x is stack of state + tiles print('Preparing examples') N_EXAMPLES = 1000 examples = get_n_examples(N_EXAMPLES, width, height, n_tiles, dg, scalar_tiles=SCALAR_TILES) if options['load_examples']: with open( f'models/train_examples_{N_TILES}_{HEIGHT}_{WIDTH}.pickle', 'rb') as f: train_examples = pickle.load(f) else: train_examples = get_examples(examples, N_TILES, height, width, dg, return_binary_mask=True, predict_move_index=True, scalar_tiles=SCALAR_TILES) with open( f'models/train_examples_{N_TILES}_{HEIGHT}_{WIDTH}.pickle', 'wb') as f: pickle.dump(train_examples, f) if options['load_val_examples']: with open( f'models/validation_examples_{N_TILES}_{HEIGHT}_{WIDTH}.pickle', 'rb') as f: validation_examples = pickle.load(f) else: N_EXAMPLES = 100 validation_examples = get_n_examples(N_EXAMPLES, width, height, n_tiles, dg, scalar_tiles=SCALAR_TILES) validation_examples = get_examples(validation_examples, N_TILES, height, width, dg, from_file=False, return_binary_mask=True, predict_move_index=True, scalar_tiles=SCALAR_TILES, shuffle_tiles_times=1) validation_examples = get_val_examples_not_in_overlap( train_examples, validation_examples) with open( f'models/validation_examples_{N_TILES}_{HEIGHT}_{WIDTH}.pickle', 'wb') as f: pickle.dump(validation_examples, f) if not options['load_model']: print(f'In total: {len(train_examples)} train examples') print(f'In total: {len(validation_examples)} validation examples') if options['load_model']: nnet.load_checkpoint() else: nnet.train(train_examples, validation_examples) nnet.save_checkpoint() np.set_printoptions( formatter={'float': lambda x: "{0:0.2f}".format(x)}, linewidth=115) total_correct = 0 total_random_correct = 0 total_max_col_correct = 0 total_max_row_correct = 0 total_biggest_tile_correct = 0 total_smallest_tile_correct = 0 total_most_common_tile_correct = 0 total_count = 0 n_empty_tiles_with_fails = [0] * (N_TILES + 1) if False: # overlap was 39/1868 between val and train get_overlap_between_examples(train_examples, validation_examples) return if False: get_only_random_predictions(validation_examples) return for example in validation_examples: prediction = nnet.predict([example[0], example[1]]) random_prediction = random.randint( 0, SolutionChecker.get_n_nonplaced_tiles(example[1]) - 1) output_str = '' if VISUALIZE_PREDICTIONS: output_str += f'----------------------------------------------------------' output_str += '\n' if predict_move_index: _prediction = prediction if VISUALIZE_PREDICTIONS: output_str += f'{prediction}\n' max_index = np.argmax(prediction) _prediction_index = max_index if SCALAR_TILES: expected = np.argmax(example[2]) else: expected = np.argmax(example[1]) # if not scalar_tiles: # print('grid state') # print(example[0][:, :, 0]) # print(state_to_tiles_dims(example[0], dg)) # print('expected') if SCALAR_TILES: expected_tile = example[1][expected] prediction_tile = example[1][_prediction_index] if VISUALIZE_PREDICTIONS: output_str += f'{example[1].tolist()}\n' else: expected_tile = dg.get_matrix_tile_dims( example[0][:, :, expected + 1]) prediction_tile = dg.get_matrix_tile_dims( example[0][:, :, _prediction_index + 1]) # print(expected, expected_tile) #print('prediction') # print(_prediction) #print(_prediction_index, prediction_tile) if VISUALIZE_PREDICTIONS: output_str += f'{example[0]}\n' output_str += f'expected: {expected_tile}, got: {prediction_tile}' output_str += f'random: {example[1][random_prediction]}' if SCALAR_TILES: widest_tile = example[1][0] highest_tile = example[1][0] biggest_tile = example[1][0] smallest_tile = example[1][0] counter = Counter() for i, tile in enumerate(example[1]): if tile[1] > widest_tile[1]: widest_tile = tile elif tile[1] == widest_tile[1]: if tile[0] > widest_tile[0]: widest_tile = tile if tile[0] > highest_tile[0]: highest_tile = tile elif tile[0] == highest_tile[0]: if tile[1] > highest_tile[1]: highest_tile = tile if tile[1] * tile[0] > (biggest_tile[1] * biggest_tile[0]): biggest_tile = tile if tile[1] * tile[0] < (smallest_tile[1] * smallest_tile[0]): smallest_tile = tile counter[tuple(tile.tolist())] += 1 if np.array_equal(expected_tile, widest_tile): total_max_col_correct += 1 if np.array_equal(expected_tile, highest_tile): total_max_row_correct += 1 if np.array_equal(expected_tile, biggest_tile): total_biggest_tile_correct += 1 if np.array_equal(expected_tile, smallest_tile): total_smallest_tile_correct += 1 most_common_tile = np.array(counter.most_common(1)[0][0]) if np.array_equal(most_common_tile, np.array([0, 0])): most_common_tile = np.array( counter.most_common(2)[1][0]) if np.array_equal(expected_tile, most_common_tile): total_most_common_tile_correct += 1 if VISUALIZE_PREDICTIONS: output_str += f'max_tile: {widest_tile}\n' if np.array_equal(expected_tile, prediction_tile): total_correct += 1 # visualize predictions #if not np.array_equal(expected_tile, widest_tile) and VISUALIZE_PREDICTIONS: # print(output_str) if VISUALIZE_PREDICTIONS: print(output_str) else: n_empty_tiles_with_fails[count_n_of_non_placed_tiles( example[1]) // 2] += 1 # print(example[1][random_prediction]) if np.array_equal(expected_tile, example[1][random_prediction]): total_random_correct += 1 else: if expected_tile == prediction_tile: total_correct += 1 else: n_empty_tiles_with_fails[count_n_of_non_placed_tiles( state_to_tiles_dims(example[0], dg)) // 2] += 1 total_count += 1 else: _prediction = np.reshape(prediction, (width, height)) _prediction = get_prediction_masked(_prediction, example[0][:, :, 0]) expected = np.reshape(example[1], (width, height)) if VISUALIZE_PREDICTIONS: # visualize predictions # print('-' * 50) # print('grid state') # print(example[0][:, :, 0]) # print('expected') # print(expected) # print('prediction') # print(_prediction) pass if predict_move_index: with open(f"nn_results/custom_{N_TILES}_{width}_{height}.csv", 'w') as f: output_str = ( f'{width}-{height}\n' f'In total guessed;{100*(total_correct/ total_count)}; {total_correct}/{total_count}\n' f'Random baseline; {100*(total_random_correct/total_count)}\n' f'Max col tile baseline; {100*(total_max_col_correct/total_count)}\n' f'Max row tile baseline; {100*(total_max_row_correct/total_count)}\n' f'Most common tile baseline; {100*(total_most_common_tile_correct/total_count)}\n' f'Max area tile baseline; {100*(total_biggest_tile_correct/total_count)}\n' f'Min area tile baseline; {100*(total_smallest_tile_correct/total_count)}' ) f.write(output_str) print(output_str) print(n_empty_tiles_with_fails) print('-' * 100) if not PREDICT_FULL_EXAMPLES: # return continue tiles_left = [] for example in examples: if SCALAR_TILES: state, tiles, _ = example tiles = get_tiles_with_orientation(tiles.tolist()) else: tiles, _ = example # tiles = dg.get_matrix_tile_dims(tiles) grid = np.zeros((width, height)) tiles_left.append( play_using_prediction(nnet, width, height, tiles, grid, N_TILES, dg, predict_move_index, scalar_tiles=SCALAR_TILES)) # [0, 6, 4, 2, 2, 2, 0, 4, 4, 8, 6, 2, 2, 6, 6, 8, 6, 4, 4, 4] print(tiles_left) print(np.sum(tiles_left) / len(tiles_left))
def play_using_prediction(nnet, width, height, tiles, grid, n_tiles, dg, predict_move_index=False, verbose=False, scalar_tiles=False): if scalar_tiles: tiles = tiles else: tiles = state_to_tiles_dims(tiles, dg) while True: tiles_left = len(tiles) if tiles_left == 0: print( f"Success: game ended with {tiles_left / ORIENTATIONS} tiles left unplaced." ) return 0 _tiles_ints = SolutionChecker.get_possible_tile_actions_given_grid( grid, tiles) if len(_tiles_ints) == 0 and tiles_left: print( f"game ended with {tiles_left / ORIENTATIONS} tiles left unplaced." ) return tiles_left / ORIENTATIONS np.random.shuffle(_tiles_ints) if scalar_tiles: _tiles = tiles_to_np_array( SolutionChecker.pad_tiles_with_zero_scalars( _tiles_ints, ORIENTATIONS * n_tiles - len(_tiles_ints))) # state = state.squeeze() prediction = nnet.predict([grid, tiles_to_np_array(_tiles)]) else: tiles_in_matrix_shape = dg._transform_instance_to_matrix( _tiles_ints, only_one_orientation=True) tiles_in_matrix_shape = pad_tiles_with_zero_matrices( tiles_in_matrix_shape, n_tiles * ORIENTATIONS - tiles_in_matrix_shape.shape[2], width, height) state = np.dstack((np.expand_dims(grid, axis=2), tiles_in_matrix_shape)) prediction = nnet.predict(state) if not predict_move_index: if len(prediction) == 2: # if we are also predicting v prediction, v = prediction prediction = np.reshape(prediction, (width, height)) # get the probability matrix prediction = get_prediction_masked(prediction, state[:, :, 0]) if verbose: print('-' * 50) print(grid, prediction) print(tiles) if scalar_tiles: _ttiles = tiles else: _ttiles = state_to_tiles_dims(state, dg) solution_tile = get_best_tile_by_prediction( grid, _ttiles, prediction, dg, predict_move_index=predict_move_index) if verbose: print(solution_tile) if solution_tile is None: print( f"game ended with {tiles_left / ORIENTATIONS} tiles left unplaced." ) return tiles_left / ORIENTATIONS success, grid = SolutionChecker.place_element_on_grid_given_grid( solution_tile[0], solution_tile[1], val=1, grid=grid, cols=width, rows=height) if not success: print( f"game ended with {tiles_left / ORIENTATIONS} tiles left unplaced." ) return tiles_left / ORIENTATIONS if scalar_tiles: tiles = [tuple(x) for x in tiles] tiles = SolutionChecker.eliminate_pair_tiles(tiles, solution_tile[0]) return 0
def get_best_tile_by_prediction(grid, tiles, prediction, dg, predict_move_index=True): ''' 1. mask invalid moves 2. renormalize the probability distribution 3. for each tile sum up which would be the probability of placing that tile in LFB 4. return the new grid Returns the tile which is the best in format [(rows, cols), position_to_place] ''' next_lfb = SolutionChecker.get_next_lfb_on_grid(grid) max_probability = -math.inf max_index = 0 best_tile = None rows, cols = grid.shape tile_probabilities = defaultdict(int) tile_counts = defaultdict(int) tiles_to_iterate_on = tiles SOFTMAX = False best_tile_individual = None best_prediction = 0 for i, tile in enumerate(tiles_to_iterate_on): tile = tuple(tile) success, _ = SolutionChecker.place_element_on_grid_given_grid( tile, next_lfb, val=1, grid=grid, cols=cols, rows=rows, get_only_success=True) if not success: continue if predict_move_index and SOFTMAX: ''' The best tile is predicted by taking the sum of the tiles with the same (width, height) ''' if tuple(tile) == (0, 0): continue tile_probabilities[tile] += prediction[i] tile_counts[tile] += 1 elif predict_move_index: if tuple(tile) == (0, 0): continue if prediction[i] > best_prediction: best_tile_individual = tile best_prediction = prediction[i] # if tile[0] * tile[1] > best_prediction: # best_tile_individual = tile # best_prediction = tile[0] * tile[1] else: probability = np.sum(prediction[next_lfb[0]:next_lfb[0] + tile[0], next_lfb[1]:next_lfb[1] + tile[1]]) # scale with area # probability = probability / (tile[0] * tile[1]) if probability > max_probability: max_index = i max_probability = probability best_tile = [tile, next_lfb] if predict_move_index and SOFTMAX: max_tile = None max_val = -math.inf for k in tile_probabilities.keys(): v = tile_probabilities[k] / tile_counts[k] if True: if v > max_val: max_tile = k max_val = v else: if k[0] * k[1] > max_val: max_tile = k max_val = k[0] * k[1] if max_tile: best_tile = [max_tile, next_lfb] elif predict_move_index: best_tile = [best_tile_individual, next_lfb] # print(tile_probabilities) # print(tile_counts) if not best_tile: print('No valid tile placement found') return best_tile
def predict(self, temp=1, N=3000): initial_state = self.state state = self.state available_tiles = state.tiles prev_state = state solution_found = False depth = 0 self.val = 1 while len(state.tiles): tile_placed = False states = [] print(len(state.tiles)) best_score = 0 for i, tile in enumerate(state.tiles): success, new_board = SolutionChecker.get_next_turn(state, tile, self.val, destroy_state=False) self.n_tiles_placed += 1 if success == ALL_TILES_USED: print('solution found!') solution_found = True return initial_state, depth, solution_found if success == TILE_CANNOT_BE_PLACED: # cannot place the tile. this branch will not be considered states.append(None) continue else: tile_placed = True new_tiles = SolutionChecker.eliminate_pair_tiles(state.tiles, tile) new_state = State( board=new_board, tiles=new_tiles, parent=state) state.children.append(new_state) simulation_result, solution_tiles_order = self.perform_simulations(new_state, N=N, record_simulations=False) if simulation_result == ALL_TILES_USED: print('solution found in simulation!') print(tile) solution_found = True # update scores of states found in simulation new_state.score = len(state.tiles) / ORIENTATIONS - 1 _state = new_state.children[0] while _state.children: _state.score = (len(_state.tiles) / ORIENTATIONS) - 1 _state = _state.children[0] if state.tile_placed: self.solution_tiles_order.extend([state.tile_placed] + [tile] + solution_tiles_order) else: self.solution_tiles_order.extend([tile] + solution_tiles_order) return initial_state, depth, solution_found new_state.score = simulation_result if new_state.score > best_score: best_tile = tile best_score = new_state.score new_state.tile_placed = tile state.solution_tiles_order.append(tile) states.append(new_state) if not tile_placed: # no tile was placed, it's a dead end; end game return initial_state, depth, solution_found # PERFORMANCE: # for visualization this can be changed # all tiles will be 1 inside the frame for performance reasons self.val += 1 depth += 1 best_action = get_max_index(states) prev_state = state new_state = states[best_action] print(best_tile, prev_state.tile_placed) if prev_state.tile_placed: self.solution_tiles_order.append(prev_state.tile_placed) state = new_state print('Solution found!') solution_found = True return initial_state, depth, solution_found
def test_eliminate_pair_tiles_3(self): tiles_list = [(1, 1), (2, 1), (1, 1), (1, 1), (2, 1), (1, 1)] new_tiles = SolutionChecker.eliminate_pair_tiles(tiles_list, tile_to_remove=(1, 1)) self.assertEqual(new_tiles, [(2, 1), (1, 1), (2, 1), (1, 1)])
def test_eliminate_pair_tiles_when_pair_is_not_present(self): tiles_list = [(1, 8), (2, 1), (1, 1), (1, 1), (2, 1), (1, 1)] with self.assertRaises(ValueError): SolutionChecker.eliminate_pair_tiles(tiles_list, tile_to_remove=(1, 8))
def test_pad(self): tiles = [[1, 2], [2, 1], [4, 5]] padded_tiles = SolutionChecker.pad_tiles_with_zero_scalars(tiles, 2) self.assertEqual(len(padded_tiles), 5) self.assertEqual([[1, 2], [2, 1], [4, 5], [0, 0], [0, 0]], padded_tiles)
for i in tqdm(range(10)): # test instance seed_ = 1+random.randint(0, 10000) dg = DataGenerator() # Create Data Generator input_batch = dg.train_batch( 1, actor.n, actor.w, actor.h, actor.dimension, seed=i, freeze_first_batch=config.freeze_first_batch ) feed = {actor.input_: input_batch} # Get feed dict tour, reward = sess.run([actor.tour, actor.reward], feed_dict=feed) # sample tours j = np.argmin(reward) # find best solution best_permutation = tour[j][:-1] predictions_length.append(reward[j]) solution_checker = SolutionChecker(actor.n, actor.w, actor.h) # TODO: find how this is called in numpy (sort by index) bins = [] for el in best_permutation: bins.append(input_batch[0][el]) solution_checker.get_reward(bins) grid = solution_checker.grid print('reward',reward[j]) solution_checker.visualize_grid() #dataset.visualize_2D_trip(input_batch[0][best_permutation]) #dataset.visualize_sampling(tour) # dataset.visualize_2D_trip(opt_tour)
def get_examples(given_examples, n_tiles, height, width, dg, from_file=False, return_binary_mask=False, predict_v=False, predict_move_index=True, scalar_tiles=False, shuffle_tiles_times=20): examples = [] for i, _example in enumerate(given_examples): # print(f'{i}/{len(given_examples)}') if scalar_tiles: state, tiles, solution = _example state = state.squeeze() else: state, solution = _example grid = np.zeros([height, width]) for solution_index, solution_tile in enumerate(solution): solution_copy = np.copy(solution) solution_order = np.array(solution_copy[solution_index:]) solution_tile_dims = solution_tile[:2] orig_solution_order = solution_order for i in range(shuffle_tiles_times): # tile permutations solution_order = np.copy(orig_solution_order) _tiles_ints = [x[:ORIENTATIONS] for x in solution_order] _tiles_ints = get_tiles_with_orientation(_tiles_ints) _tiles_ints = SolutionChecker.get_possible_tile_actions_given_grid( grid, _tiles_ints) np.random.shuffle(_tiles_ints) if scalar_tiles: tiles = tiles_to_np_array( SolutionChecker.pad_tiles_with_zero_scalars( _tiles_ints, ORIENTATIONS * n_tiles - len(_tiles_ints))) else: tiles = dg._transform_instance_to_matrix( _tiles_ints, only_one_orientation=True) tiles = pad_tiles_with_zero_matrices( tiles, ORIENTATIONS * n_tiles - tiles.shape[2], width, height) state = np.dstack((np.expand_dims(grid, axis=2), tiles)) pi = solution_to_solution_matrix( solution_tile, cols=width, rows=height, return_binary_mask=False).flatten() # v = N_TILES - solution_index v = 1 if solution_index == len(solution) - 1: continue if predict_move_index: n_possible_tiles = SolutionChecker.get_n_nonplaced_tiles( _tiles_ints) if n_possible_tiles == 1: # if only one action-tile placement is possible pass else: _tiles_ints = SolutionChecker.np_array_to_tiles( _tiles_ints) solution_index = _tiles_ints.index(solution_tile_dims) if scalar_tiles: if INDIVIDUAL_TILES: split_tiles = np.array(tiles) split_tiles = np.split(split_tiles, split_tiles.shape[0]) else: split_tiles = tiles example = [ grid.copy(), split_tiles, one_hot_encode(_tiles_ints, solution_tile_dims, len(tiles)) ] else: example = [ state, one_hot_encode(_tiles_ints, solution_tile_dims, state.shape[2] - 1) ] examples.append(example) # print(_tiles_ints, solution_tile_dims, one_hot_encode(_tiles_ints, solution_tile_dims, state)) else: example = [state, pi] if predict_v: example.append(v) examples.append(example) success, grid = SolutionChecker.place_element_on_grid_given_grid( solution_tile[:ORIENTATIONS], solution_tile[2], val=1, grid=grid, cols=width, rows=height) return examples
def test_get_next_lfb_on_grid_3(self): state = np.array([[1, 1, 1], [1, 1, 1]]) res = SolutionChecker.get_next_lfb_on_grid(state) self.assertIsNone(res)