def test_random_candidate_colour(tc): comp = mcts_tuners.Mcts_tuner('mctstest') config = default_config() config['candidate_colour'] = 'random' random.seed(1001) comp.initialise_from_control_file(config) comp.set_clean_status() tree = comp.tree job1 = comp.get_game() tc.assertIsInstance(job1, Game_job) tc.assertEqual(job1.player_b.code, '#0') tc.assertEqual(job1.player_w.code, 'opp') job2 = comp.get_game() tc.assertIsInstance(job2, Game_job) tc.assertEqual(job2.player_b.code, 'opp') tc.assertEqual(job2.player_w.code, '#1') result1 = Game_result.from_score('b', 7.5) result1.set_players({'b' : '#0', 'w' : 'opp'}) response1 = Game_job_result() response1.game_id = job1.game_id response1.game_result = result1 response1.engine_descriptions = { 'opp' : Engine_description("opp engine", None, None), '#0' : Engine_description("candidate engine", None, None), } response1.game_data = job1.game_data comp.process_game_result(response1) tc.assertEqual(tree.root.visits, 11) tc.assertEqual(tree.root.wins, 6)
def test_format_validation(tc): comp = mcts_tuners.Mcts_tuner('mctstest') config = default_config() config['parameters'].append( Parameter_config('bad', scale=str, split=10, format="bad: %.2f")) tc.assertRaisesRegexp(ControlFileError, "'format': invalid format string", comp.initialise_from_control_file, config)
def test_bad_komi(tc): comp = mcts_tuners.Mcts_tuner('mctstest') config = default_config() config['komi'] = 6 with tc.assertRaises(ControlFileError) as ar: comp.initialise_from_control_file(config) tc.assertEqual(str(ar.exception), "komi: must be fractional to prevent jigos")
def test_nocode_parameter_config(tc): comp = mcts_tuners.Mcts_tuner('mctstest') config = default_config() config['parameters'].append(Parameter_config()) with tc.assertRaises(ControlFileError) as ar: comp.initialise_from_control_file(config) tc.assertMultiLineEqual(str(ar.exception), dedent("""\ parameter 2: 'code' not specified"""))
def test_nonsense_parameter_config(tc): comp = mcts_tuners.Mcts_tuner('mctstest') config = default_config() config['parameters'].append(99) with tc.assertRaises(ControlFileError) as ar: comp.initialise_from_control_file(config) tc.assertMultiLineEqual(str(ar.exception), dedent("""\ 'parameters': item 2: not a Parameter"""))
def test_get_player_checks(tc): comp = mcts_tuners.Mcts_tuner('mctstest') config = default_config() comp.initialise_from_control_file(config) checks = comp.get_player_checks() tc.assertEqual(len(checks), 2) tc.assertEqual(checks[0].player.code, "candidate") tc.assertEqual(checks[0].player.cmd_args, ['cand', str(1 / 24), '5.0']) tc.assertEqual(checks[1].player.code, "opp") tc.assertEqual(checks[1].player.cmd_args, ['test'])
def test_bad_parameter_config(tc): comp = mcts_tuners.Mcts_tuner('mctstest') config = default_config() config['parameters'].append( Parameter_config('bad', scale=mcts_tuners.LOG(0.0, 1.0), split=10)) with tc.assertRaises(ControlFileError) as ar: comp.initialise_from_control_file(config) tc.assertMultiLineEqual( str(ar.exception), dedent("""\ parameter bad: 'scale': invalid parameters for LOG: lower bound is zero"""))
def test_integer_scale_example(tc): comp = mcts_tuners.Mcts_tuner('mctstest') config = default_config() config['parameters'] = [ Parameter_config('range', scale=mcts_tuners.LINEAR(-.5, 10.5, integer=True), split=11) ] comp.initialise_from_control_file(config) candidate_sees = [ comp.scale_parameters(comp.tree.parameters_for_path([i]))[0] for i in xrange(11) ] tc.assertEqual(candidate_sees, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
def test_make_candidate(tc): comp = mcts_tuners.Mcts_tuner('mctstest') config = default_config() comp.initialise_from_control_file(config) cand = comp.make_candidate('c#1', (0.5, 23)) tc.assertEqual(cand.code, 'c#1') tc.assertListEqual(cand.cmd_args, ['cand', '0.5', '23']) with tc.assertRaises(CompetitionError) as ar: comp.make_candidate('c#1', (-1, 23)) tc.assertTracebackStringEqual(str(ar.exception), dedent("""\ error from make_candidate() ValueError: oops traceback (most recent call last): mcts_tuner_tests|simple_make_candidate failing line: raise ValueError("oops") """))
def test_parameter_config(tc): comp = mcts_tuners.Mcts_tuner('mctstest') config = default_config() comp.initialise_from_control_file(config) tc.assertEqual(comp.tree.max_depth, 1) tc.assertEqual(comp.format_engine_parameters((0.5, 23)), "rsn@ 0.50; iwins 23") tc.assertEqual(comp.format_engine_parameters(('x', 23)), "[resign_at?x]; iwins 23") tc.assertEqual(comp.format_optimiser_parameters((0.5, 0.23)), "rsn@ 0.50; iwins 23") tc.assertEqual(comp.scale_parameters((0.5, 0.23)), (0.5, 23)) with tc.assertRaises(CompetitionError) as ar: comp.scale_parameters((0.5, None)) tc.assertTracebackStringEqual( str(ar.exception), dedent("""\ error from scale for initial_wins TypeError: unsupported operand type(s) for *: 'NoneType' and 'float' traceback (most recent call last): mcts_tuners|__call__ failing line: result = (f * self.range) + self.lower_bound """)) tc.assertRaisesRegexp(ValueError, "'code' not specified", comp.parameter_spec_from_config, Parameter_config()) tc.assertRaisesRegexp( ValueError, "code specified as both positional and keyword argument", comp.parameter_spec_from_config, Parameter_config('pa1', code='pa2', scale=float, split=2, format="%s")) tc.assertRaisesRegexp( ValueError, "too many positional arguments", comp.parameter_spec_from_config, Parameter_config('pa1', float, scale=float, split=2, format="%s")) tc.assertRaisesRegexp( ValueError, "'scale': invalid callable", comp.parameter_spec_from_config, Parameter_config('pa1', scale=None, split=2, format="%s")) pspec = comp.parameter_spec_from_config( Parameter_config('pa1', scale=float, split=2)) tc.assertRaisesRegexp( ControlFileError, "'format': invalid format string", comp.parameter_spec_from_config, Parameter_config('pa1', scale=float, split=2, format="nopct"))
def test_explicit_scale(tc): tc.assertRaises(ValueError, mcts_tuners.Explicit_scale_fn, []) pvalues = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'] comp = mcts_tuners.Mcts_tuner('mctstest') config = default_config() config['parameters'] = [ Parameter_config('range', scale=mcts_tuners.EXPLICIT(pvalues), split=len(pvalues)) ] comp.initialise_from_control_file(config) candidate_sees = [ comp.scale_parameters(comp.tree.parameters_for_path([i]))[0] for i, _ in enumerate(pvalues) ] tc.assertEqual(candidate_sees, pvalues)
def test_scale_check(tc): comp = mcts_tuners.Mcts_tuner('mctstest') config = default_config() config['parameters'].append( Parameter_config('bad', scale=str.split, split=10)) with tc.assertRaises(ControlFileError) as ar: comp.initialise_from_control_file(config) tc.assertTracebackStringEqual( str(ar.exception), dedent("""\ parameter bad: error from scale (applied to 0.05) TypeError: split-wants-float-not-str traceback (most recent call last): """), fixups=[ ("descriptor 'split' requires a 'str' object but received a 'float'", "split-wants-float-not-str"), ("unbound method split() must be called with str instance as " "first argument (got float instance instead)", "split-wants-float-not-str"), ])
def test_play(tc): comp = mcts_tuners.Mcts_tuner('mctstest') comp.initialise_from_control_file(default_config()) comp.set_clean_status() tree = comp.tree tc.assertEqual(comp.outstanding_simulations, {}) tc.assertEqual(tree.root.visits, 10) tc.assertEqual(tree.root.wins, 5) tc.assertEqual(sum(node.visits - 10 for node in tree.root.children), 0) tc.assertEqual(sum(node.wins - 5 for node in tree.root.children), 0) job1 = comp.get_game() tc.assertIsInstance(job1, Game_job) tc.assertEqual(job1.game_id, '0') tc.assertEqual(job1.player_b.code, 'opp') tc.assertEqual(job1.player_w.code, '#0') tc.assertEqual(job1.board_size, 13) tc.assertEqual(job1.komi, 7.5) tc.assertEqual(job1.move_limit, 1000) tc.assertIs(job1.use_internal_scorer, False) tc.assertEqual(job1.internal_scorer_handicap_compensation, 'full') tc.assertEqual(job1.game_data, 0) tc.assertEqual(job1.sgf_event, 'mctstest') tc.assertRegexpMatches(job1.sgf_note, '^Candidate parameters: rsn@ ') tc.assertItemsEqual(comp.outstanding_simulations.keys(), [0]) job2 = comp.get_game() tc.assertIsInstance(job2, Game_job) tc.assertEqual(job2.game_id, '1') tc.assertEqual(job2.player_b.code, 'opp') tc.assertEqual(job2.player_w.code, '#1') tc.assertItemsEqual(comp.outstanding_simulations.keys(), [0, 1]) result1 = Game_result.from_score('w', 8.5) result1.set_players({'b': 'opp', 'w': '#1'}) response1 = Game_job_result() response1.game_id = job1.game_id response1.game_result = result1 response1.engine_descriptions = { 'opp': Engine_description("opp engine", "v1.2.3", None), '#0': Engine_description("candidate engine", None, 'candidate engine description'), } response1.game_data = job1.game_data comp.process_game_result(response1) tc.assertItemsEqual(comp.outstanding_simulations.keys(), [1]) tc.assertEqual(tree.root.visits, 11) tc.assertEqual(tree.root.wins, 6) tc.assertEqual(sum(node.visits - 10 for node in tree.root.children), 1) tc.assertEqual(sum(node.wins - 5 for node in tree.root.children), 1) tc.assertRegexpMatches(competition_test_support.get_short_report(comp), r"(?m)^opponent \(opp\): opp engine:v1.2.3$") comp2 = mcts_tuners.Mcts_tuner('mctstest') comp2.initialise_from_control_file(default_config()) status = pickle.loads(pickle.dumps(comp.get_status())) comp2.set_status(status) tc.assertEqual(comp2.tree.root.visits, 11) tc.assertEqual(comp2.tree.root.wins, 6) tc.assertEqual(sum(node.visits - 10 for node in comp2.tree.root.children), 1) tc.assertEqual(sum(node.wins - 5 for node in comp2.tree.root.children), 1) config3 = default_config() # changed split config3['parameters'][0] = Parameter_config('resign_at', scale=float, split=11, format="rsn@ %.2f") comp3 = mcts_tuners.Mcts_tuner('mctstest') comp3.initialise_from_control_file(config3) status = pickle.loads(pickle.dumps(comp.get_status())) with tc.assertRaises(CompetitionError) as ar: comp3.set_status(status) tc.assertEqual(str(ar.exception), "status file is inconsistent with control file") config4 = default_config() # changed upper bound config4['parameters'][1] = Parameter_config('initial_wins', scale=mcts_tuners.LINEAR( 0, 200), split=10, format="iwins %d") comp4 = mcts_tuners.Mcts_tuner('mctstest') comp4.initialise_from_control_file(config4) status = pickle.loads(pickle.dumps(comp.get_status())) with tc.assertRaises(CompetitionError) as ar: comp4.set_status(status) tc.assertEqual(str(ar.exception), "status file is inconsistent with control file")