質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

2回答

790閲覧

木構造で数式を表す際、指数関数と多項式の合成関数を作りたいです。

AI_engineer

総合スコア15

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

1クリップ

投稿2022/07/14 04:00

編集2022/07/14 06:15

前提

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は膨大な値になるためオーバーフローしたのだと考えていますが、改善の仕方がわかりません...

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

コード詳細は確認できていませんが、ぱっと見た感じexpを終端から非終端に扱いを変更するだけでよいように思います。

投稿2022/07/14 04:15

can110

総合スコア38262

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

AI_engineer

2022/07/14 06:07

ご回答ありがとうございます。ご指摘いただいた通り、expを非終端記号に変更しました。 expノードは子ノードを1つだけ持つようにし、expの子ノード部分によって生成された数式をexp(x)のxに代入するように変更したのですが、以下のようなエラーが出てしまいました。 a.py:23: RuntimeWarning: overflow encountered in exp a.py:156: RuntimeWarning: overflow encountered in double_scalars return sum([((individual.compute_tree(ds[0])*np.sqrt(2*np.pi)) - ds[1]) ** 2 for ds in dataset]) エラー文章を調べ、指数関数expは膨大な値になりやすいためオーバーフローしたと考えていますが、どのように対処すればよいでしょうか。
can110

2022/07/14 06:36

純粋にコンピュータで数値計算を行う場合の制限なので、逐次計算しているのであれば基本的にはどうしようもないかと思います。 ただ、せっかく構文木で表現されているのですから、 指数計算値は内部では式のままや負の値なり別表現で持っておき、最後に(可能であれば)実値に変換する といったことも可能かもしれません。もちろん簡単ではありませんが。 具体的な手法については「数値計算 指数 オーバーフロー 変形」なりで検索してみてください。
guest

0

pythonで木構造を用いて数式を生成するコードを書いています。その際、指数関数と多項式の合成関数をどのように生成すればよいか思いつかないのでアドバイスをいただきたいです。

提示されているコードに対するアドバイスではないのですが、実装しているコードとは別に数式(を表す文字列)の文法を作ってますでしょうか?もし作っていなければ今の時点のコードで処理可能な(はずと想定している)数式を定義するために必要十分な文法をBNF記法などで書いてみて、それを次にどのように拡張したいのかを文法として書いてみれば、現状のコードに何を追加、あるいはどこを修正すればいいかが明確になるかもしれません。

投稿2022/07/14 05:21

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問