Genetic Turmit Evolver
python
c
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.

rpnlib.py 7.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. import collections
  2. import inspect
  3. import random
  4. _op_list = collections.OrderedDict()
  5. _var_list = collections.OrderedDict()
  6. _op_alias = collections.OrderedDict()
  7. _op_alias['add'] = '+'
  8. _op_alias['sub'] = '-'
  9. _op_alias['mul'] = '*'
  10. _op_alias['div'] = '/'
  11. _op_alias['mod'] = '%'
  12. _op_alias['bin_and'] = '&'
  13. _op_alias['bin_or'] = '|'
  14. _op_alias['bin_xor'] = '^'
  15. _op_alias['lshift'] = '<<'
  16. _op_alias['rshift'] = '>>'
  17. _op_alias['pow'] = '**'
  18. _var_list['x'] = 0
  19. _var_list['y'] = 0
  20. _var_list['r'] = 0
  21. _var_list['g'] = 0
  22. _var_list['b'] = 0
  23. def RpnOpNoMod(method):
  24. return RpnOp(method, True)
  25. def RpnOp(method, nomod = False):
  26. ''' @brief Decorator for RPN operation that autodetect argument count
  27. Autodetect argument count and pop them from the stack. Then attempt
  28. to push values from result as an array. If it fails result is push
  29. as it.
  30. @warning if result is None nothing is push
  31. '''
  32. narg = len(inspect.signature(method).parameters)-1
  33. def wrapped(self):
  34. args = [ self._pop() for _ in range(narg) ]
  35. determinist = True
  36. if not nomod:
  37. for arg in args:
  38. if isinstance(arg, IntVar):
  39. determinist = False
  40. break
  41. args.reverse()
  42. try:
  43. res = method(self, *args)
  44. except ZeroDivisionError:
  45. res = None
  46. if res is None:
  47. return determinist
  48. try:
  49. for topush in res:
  50. if not isinstance(topush, int):
  51. raise ValueError('Turmit.%s() returned a list containing a\
  52. %s : %s' % (method.__name__, type(topush), topush))
  53. topush = self._cast_int(topush)
  54. self._push(topush)
  55. except TypeError:
  56. if not isinstance(res, int):
  57. raise ValueError('Turmit.%s() returned a list containing a\
  58. %s : %s' % (method.__name__, type(res), res))
  59. self._push(res)
  60. return determinist
  61. _op_list[method.__name__] = (method, wrapped)
  62. return wrapped
  63. class RpnExpr(list):
  64. ''' @brief Extended list that only contains RpnSymbol '''
  65. def __init__(self, *args, **kwargs):
  66. super().__init__(*args, **kwargs)
  67. for i, item in enumerate(self):
  68. if not isinstance(item, RpnSymbol):
  69. raise TypeError('Item %d is %s but RpnSymbol expected' % (i,
  70. item))
  71. def __setitem__(self, idx, val):
  72. if not isinstance(val, RpnSymbol):
  73. raise TypeError('RpnSymbol expected but got %s' % type(val))
  74. super().__setitem__(idx, val)
  75. def __str__(self, small=True):
  76. if small:
  77. return ' '.join([_op_alias[str(sym).lower()]
  78. if str(sym).lower() in _op_alias
  79. else str(sym)
  80. for sym in self])
  81. return ' '.join([str(sym) for sym in self])
  82. def __eq__(self, b):
  83. if len(self) != len(b):
  84. return False
  85. for i in range(len(self)):
  86. if self[i] != b[i]:
  87. return False
  88. return True
  89. @classmethod
  90. def random(cls, sz):
  91. return cls([RpnSymbol.random() for _ in range(sz)])
  92. @classmethod
  93. def from_string(cls, val):
  94. ''' @brief generate an expr from a string
  95. @param val str : expression
  96. @return RpnExpr
  97. '''
  98. return cls([RpnSymbol.from_string(s.strip())
  99. for s in val.split()
  100. if len(s.strip()) > 0])
  101. class RpnSymbol(object):
  102. ''' @brief Designed to handle operation and operand for Turmit expr '''
  103. OPERATION = 0x0
  104. VALUE = 0x1
  105. VARIABLE = 0x3
  106. def __init__(self, value, optype = VALUE):
  107. ''' @brief RpnSymbol constructor
  108. @param value int : positiv integer moded given optype
  109. @param optype int : one of @ref OPERATION @ref VALUE @ref VARIABLE
  110. '''
  111. self.optype = optype
  112. self.value = value
  113. err = False
  114. err_type = 'Unknown'
  115. if optype == self.OPERATION:
  116. if isinstance(value, str):
  117. if self.value.lower() in _op_alias.values():
  118. idx = list(_op_alias.values()).index(self.value.lower())
  119. self.value = list(_op_alias.keys())[idx]
  120. if not value in _op_list:
  121. err = True
  122. err_type = 'operation'
  123. else:
  124. self.value = value
  125. else:
  126. self.value = list(_op_list.keys())[value % len(_op_list)]
  127. self.value = self.value.lower()
  128. elif optype == self.VARIABLE:
  129. if isinstance(value, str):
  130. if not value in _var_list:
  131. err = True
  132. err_type = 'variable'
  133. else:
  134. self.value = value
  135. else:
  136. self.value = list(_var_list.keys())[value % len(_var_list)]
  137. self.value = self.value.lower()
  138. if err:
  139. msg = 'Invalid %s : "%s"' % (err_type, value.upper())
  140. def __str__(self, small=True):
  141. ''' @brief Return a string representation of current symbol '''
  142. if self.optype == self.OPERATION:
  143. return _op_list[self.value][0].__name__.upper()
  144. elif self.optype == self.VALUE:
  145. if small:
  146. return '0x%X' % self.value
  147. else:
  148. return '0x%04X' % self.value
  149. else:
  150. return self.value.upper()
  151. def __repr__(self):
  152. if self.optype == self.OPERATION:
  153. optype = 'OPE'
  154. elif self.optype == self.VALUE:
  155. optype = 'VAL'
  156. elif self.optype == self.VARIABLE:
  157. optype = 'VAR'
  158. name = '%s.%s' % (self.__class__.__module__,
  159. self.__class__.__name__)
  160. return '<%s %s(%s)>' % (name, optype, self.value)
  161. def __eq__(self, b):
  162. if not isinstance(b, RpnSymbol):
  163. return False
  164. return b.optype == self.optype and b.value == self.value
  165. def __copy__(self):
  166. return self.__class__(self.value, self.optype)
  167. @classmethod
  168. def from_string(cls, val):
  169. try:
  170. val = int(val, base=0)
  171. return cls(val, cls.VALUE)
  172. except Exception:
  173. pass
  174. if val.lower() in _op_list.keys() or val.lower() in _op_alias.values():
  175. return cls(val, cls.OPERATION)
  176. elif val.lower() in _var_list.keys():
  177. return cls(val, cls.VARIABLE)
  178. raise ValueError('Unrecognized symbol "%s"' % val)
  179. @classmethod
  180. def random(cls, optype=None):
  181. ''' @brief Return a randomly generated symbol '''
  182. if optype is None:
  183. optype = [cls.OPERATION, cls.VALUE, cls.VARIABLE]
  184. optype = optype[random.randint(0,2)]
  185. if optype == cls.VALUE:
  186. vals = [(0,0xF), (0, 0xFF), (0,0xFFFF)]
  187. return cls(random.randint(*vals[random.randint(0,2)]), optype)
  188. else:
  189. return cls(random.randint(0, 0xFFFF), optype)
  190. @classmethod
  191. def rand_op(cls):
  192. ''' @return Random operation '''
  193. return cls.random(cls.OPERATION)
  194. @classmethod
  195. def rand_var(cls):
  196. ''' @retrun Random variable '''
  197. return cls.random(cls.VARIABLE)
  198. @classmethod
  199. def rand_value(cls):
  200. ''' @return Random value '''
  201. return cls.random(cls.VALUE)
  202. class IntVar(int):
  203. pass