やること
次のような問題を見かけました。
どうしてちょうど3000倍を目指しているのかはわかりませんが、これをGAで解いてみましょう。
実行環境
WinPython3.6をおすすめしています。
WinPython - Browse /WinPython_3.6/3.6.7.0 at SourceForge.net
Portable Scientific Python 2/3 32/64bit Distribution for Windows
vcoptの使い方についてはチュートリアルをご参照ください。
vcoptの仕様については最新の仕様書をご参照ください。本記事執筆時とは仕様が異なる場合があります。
文字列として書かれた数式の評価
Pythonには、文字列として書かれた数式を評価する「eval」と、文字列として書かれたコマンドを実行する「exec」があります。
#文字列
print('1+1')
#それを評価したもの
print(eval('1+1'))
1+1
2
#文字列
print('a=1+1')
#それを実行する
exec('a=1+1')
#確認
print(a)
a=1+1
2
今回は「eval」を用います。
評価関数
0に対してクスリをparaの順番で作用させて、感度を返します。
‘(((((0’ という文字列に
- /2)
- -900)
- +2000)
- *5)
- +500)
を適当な順序で付け足し、それを「eval」します。
from vcopt import vcopt
#クスリの用意
drug = ['/2)', '-900)', '+2000)', '*5)', '+500)']
#評価関数、クスリの作用結果を返す
def calculate_sensitivity(para):
formula = '(((((0'
for i in para:
formula += drug[i]
#print(formula)
return eval(formula)
#テスト、順番に作用させてみる
print(calculate_sensitivity([0, 1, 2, 3, 4]))
6000.0
例えば、順序 [0, 1, 2, 3, 4] で作用させると、数式は ‘(((((0/2)-900)+2000)*5)+500)’ となります。これを「eval」すると6000になるわけです。
GAで解く
vcopt().tspGA() を用いてクスリの作用順を最適化します。評価関数の目標値は3000に設定します。
#GAで順序を最適化
para, score = vcopt().tspGA(range(5), #並べ替えたいもの
calculate_sensitivity, #評価関数
3000, #目標値
show_pool_func='print') #'bar', 'print', 'plot'
#結果の表示
formula = '(((((0'
for i in para:
formula += drug[i]
print(formula)
___________________ info ___________________
para_range : n=5
score_func : <class 'function'>
aim : 3000.0
show_pool_func : 'print'
seed : None
pool_num : 50
max_gen : None
core_num : 1 (*vcopt, vc-grendel)
___________________ start __________________
Scoring first gen 50/50
Mini 2-opting first gen 50/50
gen=0, best_score=3000.0, mean_score=3274.0, mean_gap=1156.0, time=0.0
gen=50, best_score=3000.0, mean_score=3036.0, mean_gap=188.0, time=0.1
__________________ results _________________
para : [2 1 3 4 0]
score : 3000.0
____________________ end ___________________
(((((0+2000)-900)*5)+500)/2)
結果、作用順は [2, 1, 3, 4, 0] となり、数式は ‘(((((0+2000)-900)*5)+500)/2)’ となりました。
感度を最大にしてみる
#GAで順序を最適化
para, score = vcopt().tspGA(range(5), #並べ替えたいもの
calculate_sensitivity, #評価関数
999999, #目標値
show_pool_func='print') #'bar', 'print', 'plot'
#結果の表示
formula = '(((((0'
for i in para:
formula += drug[i]
print(formula)
___________________ info ___________________
para_range : n=5
score_func : <class 'function'>
aim : 999999.0
show_pool_func : 'print'
seed : None
pool_num : 50
max_gen : None
core_num : 1 (*vcopt, vc-grendel)
___________________ start __________________
Scoring first gen 50/50
Mini 2-opting first gen 50/50
gen=0, best_score=11600.0, mean_score=5065.0, mean_gap=994934.0, time=0.0
gen=50, best_score=11600.0, mean_score=8874.0, mean_gap=991125.0, time=0.1
...
gen=400, best_score=11600.0, mean_score=11519.0, mean_gap=988480.0, time=0.8
gen=450, best_score=11600.0, mean_score=11519.0, mean_gap=988480.0, time=0.9
__________________ results _________________
para : [0 2 4 3 1]
score : 11600.0
____________________ end ___________________
(((((0/2)+2000)+500)*5)-900)
感度11600倍になりました!
同様に目標値を書き換えてやると、'(((((0/2)-900)+500)*5)+2000)’ で感度ゼロにもなるようです。