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.1KB

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