Fast IFS using RPN notation
python
c
x86-64
nasm
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.

expr.py 4.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. """ @namespace python_rpnifs.expr
  2. @brief Handles expression generation & mutation
  3. """
  4. import copy
  5. import random
  6. import pyrpn
  7. class RpnOp(object):
  8. def __init__(self, op=None):
  9. if op is None:
  10. op = self.random()
  11. elif op not in pyrpn.get_ops().values():
  12. raise ValueError('Invalid operation %r' % op)
  13. self.__op = op
  14. def __str__(self):
  15. return self.__op
  16. def __copy__(self):
  17. return type(self)(self.__op)
  18. @staticmethod
  19. def random():
  20. return random.choice(list(pyrpn.get_ops().values()))
  21. class RpnConst(object):
  22. def __init__(self, value=None):
  23. if value is None:
  24. value = random.randint(0, (1<<64)-1)
  25. elif value < 0 or value > (1<<64)-1:
  26. raise ValueError('Outof bound value %d' % value)
  27. self.__val = value
  28. def __copy__(self):
  29. return type(self)(self.__val)
  30. def __str__(self):
  31. return '0x%X' % self.__val
  32. class RpnVar(object):
  33. def __init__(self, varnum=None, nvar=1):
  34. if varnum is None:
  35. if nvar == 1:
  36. varnum = 0
  37. else:
  38. varnum = random.randint(0, nvar-1)
  39. elif varnum < 0 or varnum >= nvar:
  40. raise ValueError('Variable A%d do not exists' % varnum)
  41. self.__val = varnum
  42. self.__nvar = nvar
  43. @property
  44. def nvar(self):
  45. return self.__nvar
  46. def __copy__(self):
  47. return type(self)(self.__val, self.__nvar)
  48. def __str__(self):
  49. return 'A%d' % self.__val
  50. class RpnExpr(object):
  51. def __init__(self, sz=0, w_op=4, w_const=1, w_var=2, nvar=1):
  52. self.sz = 0
  53. self._weight = (w_op, w_const, w_var)
  54. choices = (RpnOp, RpnConst, lambda: RpnVar(nvar=nvar))
  55. self.expr = [random.choices(choices, self._weight)[0]()
  56. for _ in range(sz)]
  57. self.__nvar = nvar
  58. if sz > 0:
  59. self.refresh_expr()
  60. def refresh_expr(self):
  61. self.pyrpn = pyrpn.RPNExpr(str(self), self.__nvar)
  62. def __str__(self):
  63. return ' '.join([str(elt) for elt in self.expr])
  64. def __copy__(self):
  65. ret = RpnExpr(sz=0)
  66. ret.expr = [copy.copy(elt) for elt in self.expr]
  67. ret.refresh_expr()
  68. return ret
  69. def eval(self, *args):
  70. return self.pyrpn.eval(*args)
  71. def mutation(self, n=1, min_len=3, w_add=1.25, w_del=1, w_mut=2,
  72. w_mut_soft=4, w_add_elt=(1,1,1), w_mut_elt=(1,1,1)):
  73. for _ in range(n):
  74. if len(self.expr) <= min_len:
  75. self.add(*w_add_elt)
  76. return
  77. funs = ((self.add, w_add_elt),
  78. (self.delete, []),
  79. (self.mutate, w_mut_elt),
  80. (self.mutate_soft, []))
  81. choice = random.choices((0,1,2),
  82. (w_add, w_del, w_mut))[0]
  83. fun, args = funs[choice]
  84. fun(*args)
  85. self.refresh_expr()
  86. pass
  87. def add(self, w_op=1, w_const=1, w_var=1):
  88. idx = random.randint(0,len(self.expr))
  89. new = random.choices((RpnOp, RpnConst, RpnVar), self._weight)[0]
  90. new = new(nvar=self.__nvar) if new == RpnVar else new()
  91. self.expr.insert(idx, new)
  92. pass
  93. def delete(self, *args):
  94. idx = random.randint(0, len(self.expr)-1)
  95. self.expr.pop(idx)
  96. pass
  97. def mutate(self, w_op=1, w_const=1, w_var=1):
  98. idx = random.randint(0, len(self.expr)-1)
  99. new = random.choices((RpnOp, RpnConst, RpnVar), self._weight)[0]
  100. new = new(nvar=self.__nvar) if new == RpnVar else new()
  101. self.expr[idx] = new
  102. pass
  103. def mutate_soft(self):
  104. idx = random.randint(0, len(self.expr)-1)
  105. cur = self.expr[idx]
  106. cls = type(cur)
  107. if cls == RpnVar:
  108. new = cls(nvar=cur.nvar)
  109. else:
  110. new = cls()
  111. self.expr[idx] = new
  112. pass
  113. @classmethod
  114. def from_string(cls, expr, nvar=1):
  115. res = RpnExpr(sz=0)
  116. for spl in expr.split(' '):
  117. spl = spl.strip()
  118. if not spl:
  119. continue
  120. if spl[0] == 'A':
  121. try:
  122. argnum = int(spl[1:])
  123. except Exception:
  124. raise ValueError('Invalid argument %r' % spl)
  125. self.expr.append(RpnVar(argnum, nvar))
  126. elif spl in pyrpn.get_ops().values():
  127. self.expr.append(RpnOp(spl))
  128. else:
  129. try:
  130. val = int(spl)
  131. except Exception:
  132. raise ValueError('Invalid token %r' % spl)
  133. self.expr.append(RpnVal(spl))
  134. return res