4/14(日) 足・靴・木型研究会「第2回研究集会」を開催します☆彡

8-10. 遺伝的アルゴリズム(vcopt)で女騎士の感度を3000倍にする

やること

次のような問題を見かけました。

予備

どうしてちょうど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)’ で感度ゼロにもなるようです。

タイトルとURLをコピーしました