123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- """ @namespace python_rpnifs.expr
- @brief Handles expression generation & mutation
- """
- import copy
- import random
-
- import pyrpn
-
-
- class RpnOp(object):
-
- def __init__(self, op=None):
- if op is None:
- op = self.random()
- elif op not in pyrpn.get_ops().values():
- raise ValueError('Invalid operation %r' % op)
- self.__op = op
-
- def __str__(self):
- return self.__op
-
- def __copy__(self):
- return type(self)(self.__op)
-
- @staticmethod
- def random():
- return random.choice(list(pyrpn.get_ops().values()))
-
-
- class RpnConst(object):
-
- def __init__(self, value=None):
- if value is None:
- value = random.randint(0, (1<<64)-1)
- elif value < 0 or value > (1<<64)-1:
- raise ValueError('Outof bound value %d' % value)
- self.__val = value
-
- def __copy__(self):
- return type(self)(self.__val)
-
- def __str__(self):
- return '0x%X' % self.__val
-
-
- class RpnVar(object):
-
- def __init__(self, varnum=None, nvar=1):
- if varnum is None:
- if nvar == 1:
- varnum = 0
- else:
- varnum = random.randint(0, nvar-1)
- elif varnum < 0 or varnum >= nvar:
- raise ValueError('Variable A%d do not exists' % varnum)
- self.__val = varnum
- self.__nvar = nvar
-
- @property
- def nvar(self):
- return self.__nvar
-
- def __copy__(self):
- return type(self)(self.__val, self.__nvar)
-
- def __str__(self):
- return 'A%d' % self.__val
-
- class RpnExpr(object):
-
- def __init__(self, sz=0, w_op=4, w_const=1, w_var=2, nvar=1):
- self.sz = 0
- self._weight = (w_op, w_const, w_var)
- choices = (RpnOp, RpnConst, lambda: RpnVar(nvar=nvar))
- self.expr = [random.choices(choices, self._weight)[0]()
- for _ in range(sz)]
- self.__nvar = nvar
- if sz > 0:
- self.refresh_expr()
-
- def refresh_expr(self):
- self.pyrpn = pyrpn.RPNExpr(str(self), self.__nvar)
-
- def __str__(self):
- return ' '.join([str(elt) for elt in self.expr])
-
- def __copy__(self):
- ret = RpnExpr(sz=0)
- ret.expr = [copy.copy(elt) for elt in self.expr]
- ret.refresh_expr()
- return ret
-
- def eval(self, *args):
- return self.pyrpn.eval(*args)
-
- def mutation(self, n=1, min_len=3, w_add=1.25, w_del=1, w_mut=2,
- w_mut_soft=4, w_add_elt=(1,1,1), w_mut_elt=(1,1,1)):
- for _ in range(n):
- if len(self.expr) <= min_len:
- self.add(*w_add_elt)
- return
- funs = ((self.add, w_add_elt),
- (self.delete, []),
- (self.mutate, w_mut_elt),
- (self.mutate_soft, []))
- choice = random.choices((0,1,2),
- (w_add, w_del, w_mut))[0]
- fun, args = funs[choice]
- fun(*args)
- self.refresh_expr()
- pass
-
- def add(self, w_op=1, w_const=1, w_var=1):
- idx = random.randint(0,len(self.expr))
- new = random.choices((RpnOp, RpnConst, RpnVar), self._weight)[0]
- new = new(nvar=self.__nvar) if new == RpnVar else new()
- self.expr.insert(idx, new)
- pass
-
- def delete(self, *args):
- idx = random.randint(0, len(self.expr)-1)
- self.expr.pop(idx)
- pass
-
- def mutate(self, w_op=1, w_const=1, w_var=1):
- idx = random.randint(0, len(self.expr)-1)
- new = random.choices((RpnOp, RpnConst, RpnVar), self._weight)[0]
- new = new(nvar=self.__nvar) if new == RpnVar else new()
- self.expr[idx] = new
- pass
-
- def mutate_soft(self):
- idx = random.randint(0, len(self.expr)-1)
- cur = self.expr[idx]
- cls = type(cur)
- if cls == RpnVar:
- new = cls(nvar=cur.nvar)
- else:
- new = cls()
- self.expr[idx] = new
- pass
-
- @classmethod
- def from_string(cls, expr, nvar=1):
- res = RpnExpr(sz=0)
-
- for spl in expr.split(' '):
- spl = spl.strip()
- if not spl:
- continue
- if spl[0] == 'A':
- try:
- argnum = int(spl[1:])
- except Exception:
- raise ValueError('Invalid argument %r' % spl)
- self.expr.append(RpnVar(argnum, nvar))
- elif spl in pyrpn.get_ops().values():
- self.expr.append(RpnOp(spl))
- else:
- try:
- val = int(spl)
- except Exception:
- raise ValueError('Invalid token %r' % spl)
- self.expr.append(RpnVal(spl))
- return res
-
|