前提
pythonで木構造を用いて数式を生成するコードを書いています。その際、指数関数と多項式の合成関数をどのように生成すればよいか思いつかないのでアドバイスをいただきたいです。
実現したいこと
木構造を使って、
(ex1) x^2 + 2 * (x+1) * exp(x)
などという数式を生成することはできたのですが、
(ex2) x^2 + 2 * (x+1) * exp(x^2+1)
の太字の部分のように指数関数exp(x)のx部分に多項式が来るような数式を生成できるようにしたいです。
該当のソースコード
python
1import numpy as np 2from random import random, randint, seed 3 4def add(x, y): return x + y 5def sub(x, y): return x - y 6def mul(x, y): return x * y 7def div(x, y): return 1 if y == 0 else x / y 8 9FUNCTIONS = [add, sub, mul, div] # 木構造の非終端ノード(四則演算) 10TERMINALS = ['x', 'exp', -2, -1, 0, 1, 2] # 木構造の終端ノード(定数or入力変数x or exp(x)) 11 12class GPTree: 13 def __init__(self, data = None, left = None, right = None): 14 self.data = data 15 self.left = left 16 self.right = right 17 18 def node_label(self): 19 if (self.data in FUNCTIONS): 20 return self.data.__name__ 21 else: 22 return str(self.data) 23 24 def random_tree(self, grow, max_depth, depth = 0): # 木構造(数式)を生成 25 26 if depth < 2 or (depth < max_depth and not grow): 27 self.data = FUNCTIONS[randint(0, len(FUNCTIONS)-1)] 28 elif depth >= max_depth: 29 self.data = TERMINALS[randint(0, len(TERMINALS)-1)] 30 else: # intermediate depth, grow 31 if random () > 0.5: 32 self.data = TERMINALS[randint(0, len(TERMINALS)-1)] 33 else: 34 self.data = FUNCTIONS[randint(0, len(FUNCTIONS)-1)] 35 # 右と左の木を生成 36 if self.data in FUNCTIONS: 37 self.left = GPTree() 38 self.left.random_tree(grow, max_depth, depth = depth + 1) 39 self.right = GPTree() 40 self.right.random_tree(grow, max_depth, depth = depth + 1) 41 42 # 数式を生成する関数(x:入力変数) 43 def compute_tree(self, x): 44 if (self.data in FUNCTIONS): 45 return self.data(self.left.compute_tree(x), self.right.compute_tree(x)) 46 elif self.data == 'x': return x 47 elif self.data == 'exp': return np.exp(x) 48 else: return self.data 49 50 def print_tree(self, prefix = ""): # 生成した木構造を出力する関数 51 print("%s%s" % (prefix, self.node_label())) 52 if self.left: self.left.print_tree (prefix + " ") 53 if self.right: self.right.print_tree(prefix + " ") 54 55t = GPTree() 56t.random_tree(grow=True, max_depth=5) 57t.print_tree()
コードの補足説明
random_treeメソッド
木構造を初期化しています。grow変数の真偽によって処理を分岐していますが、実現したいこととはあまり関係がないので今は無視していただいて構いません。
compute_treeメソッド
木構造から数式を生成する関数です。ここのexpの処理を変えるべきだと思っています。
現段階ではexp(x)をそのままreturnするとなっているため、最終的に生成される数式で指数関数と多項式の合成形を作れないのだろうと考えています。ですが、実装力の問題でどのようにコードを書けばよいか思い浮かばず困っています。
修正後のコード
expを終端記号から非終端記号に変更するとよいとのアドバイスをいただいたので、自分なりにコードを修正してみました。
python
1# exp()を非終端記号に変更 2def add(x, y): return x + y 3def sub(x, y): return x - y 4def mul(x, y): return x * y 5def div(x, y): return 1 if y == 0 else x / y 6def exp(x): return np.exp(x) 7 8FUNCTIONS = [add, sub, mul, div, exp] 9TERMINALS = ['x', -2, -1, 0, 1, 2] 10 11 12# exp(x)の子ノードの部分木をxに代入するように変更 13def random_tree(self, grow, max_depth, depth = 0): # create random tree using either grow or full method 14 """初期集団の生成 15 16 Args: 17 grow (_type_): FUNCTIONから選ぶかを操作 18 max_depth (_type_): 木の深さの上限 19 depth (int, optional): 現在の木の深さ. Defaults to 0. 20 """ 21 if depth < MIN_DEPTH or (depth < max_depth and not grow): 22 self.data = FUNCTIONS[randint(0, len(FUNCTIONS)-1)] 23 elif depth >= max_depth: 24 self.data = TERMINALS[randint(0, len(TERMINALS)-1)] 25 else: # intermediate depth, grow # grow=True且つdepth < max_depth 26 if random () > 0.5: 27 self.data = TERMINALS[randint(0, len(TERMINALS)-1)] 28 else: 29 self.data = FUNCTIONS[randint(0, len(FUNCTIONS)-1)] 30 # 右と左の木を生成 31 if self.data == exp: 32 self.left = GPTree() 33 self.left.random_tree(grow, max_depth, depth = depth + 1) 34 elif self.data in FUNCTIONS: 35 self.left = GPTree() 36 self.left.random_tree(grow, max_depth, depth = depth + 1) # 木の深さを更新 37 self.right = GPTree() 38 self.right.random_tree(grow, max_depth, depth = depth + 1)
これを実行すると、
RuntimeWarning: overflow encountered in exp
def exp(x): return np.exp(x)
a.py:156: RuntimeWarning: overflow encountered in double_scalars
return sum([((individual.compute_tree(ds[0])np.sqrt(2np.pi)) - ds[1]) ** 2 for ds in dataset])
などのエラーがでてしまい、解決方法がわからず困っています。
エラー文について調べて、指数関数expは膨大な値になるためオーバーフローしたのだと考えていますが、改善の仕方がわかりません...

回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2022/07/14 06:07
2022/07/14 06:36