gameboy superoptimizer
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

60 lines
1.7 KiB

2 years ago
2 years ago
  1. from math import exp, log
  2. from random import random
  3. from typing import List
  4. from gbso.program.test_case import Output, TestCase, eq_on_testcase
  5. from gbso.program.mutate import mutate_program
  6. from gbso.program.program import Program
  7. EPSILON = 0.00001
  8. DEFAULT_NUM_ITERS = 1_000_000
  9. DEFAULT_PROB_OPCODE = 0.25
  10. DEFAULT_PROB_OPERAND = 0.25
  11. DEFAULT_PROB_SWAP = 0.25
  12. DEFAULT_PROB_INSN = 0.25
  13. DEFAULT_PROB_INSN_UNUSED = 0.1
  14. def cost(orig_prgm, test_cases, outputs, prgm) -> int:
  15. c = prgm.perf() - orig_prgm.perf()
  16. # print(f"init cost: {c}")
  17. for test_case in test_cases:
  18. c += eq_on_testcase(orig_prgm, prgm, test_case, outputs)
  19. # print(f"cost after testcase: {c}")
  20. return c
  21. def optimize(
  22. prgm: Program,
  23. max_size: int,
  24. test_cases: List[TestCase],
  25. outputs: List[Output],
  26. beta: int = 0.75, # How far away in cost you are allowed to search
  27. num_iters: int = DEFAULT_NUM_ITERS,
  28. prob_opcode: float = DEFAULT_PROB_OPCODE,
  29. prob_operand: float = DEFAULT_PROB_OPERAND,
  30. prob_swap: float = DEFAULT_PROB_SWAP,
  31. prob_insn: float = DEFAULT_PROB_INSN,
  32. prob_insn_unused: float = DEFAULT_PROB_INSN_UNUSED,
  33. ) -> Program:
  34. padded_prgm = prgm.pad(max_size)
  35. last_prgm = padded_prgm
  36. last_cost = cost(padded_prgm, test_cases, outputs, last_prgm)
  37. for _ in range(num_iters):
  38. candidate_prgm = mutate_program(
  39. last_prgm, prob_opcode, prob_operand, prob_swap, prob_insn, prob_insn_unused
  40. )
  41. candidate_cost = cost(padded_prgm, test_cases, outputs, candidate_prgm)
  42. if candidate_cost < last_cost - log(random()) / beta:
  43. last_prgm = candidate_prgm
  44. last_cost = candidate_cost
  45. return last_prgm