- バンディット問題のシミュレーションプログラムをJuliaで開発
- アルゴリズム、環境、タスクの設定をYAMLファイルで管理
- 複数設定での一括シミュレーション実行機能
- CairoMakie.jlによる結果の可視化
- 網羅的なテストの実装と妥当性検証
- 言語: Julia
- 可視化: CairoMakie.jl
- 設定管理: YAML
- テスト: Test.jl
- バンディット問題の環境クラスを作成
- バンディットアルゴリズムの実装(ε-greedy, UCB等)
- YAML設定ファイルの読み込み機能を実装
- シミュレーション実行機能を実装
- CairoMakie.jlで結果の可視化機能を実装
- 複数設定の一括実行機能を実装
- サンプルYAML設定ファイルを作成
bandit.jl: メインプログラムmain.jl: 実行エントリーポイントexperiment1.yaml: 実験設定1experiment2.yaml: 実験設定2
abstract type BanditEnvironment end
struct GaussianBandit <: BanditEnvironment
means::Vector{Float64}
stds::Vector{Float64}
k::Int
end- **ε-greedy**: 確率εで探索、それ以外は活用
- **UCB**: Upper Confidence Bound による腕選択
pull_arm(): 腕を引いて報酬を得るselect_action(): アルゴリズムに基づく腕選択update!(): Q値の更新run_simulation(): シミュレーション実行plot_results(): 結果可視化
test_bandit.jl: 網羅的テストスイート
- **バンディット環境のテスト**
- 初期化とパラメータ検証
- 報酬生成の統計的妥当性
- 最適腕・最適値の計算
- エラーハンドリング
- **アルゴリズムのテスト**
- ε-greedy: 探索と活用のバランス
- UCB: 信頼区間に基づく選択
- **シミュレーション機能のテスト**
- 報酬・後悔の計算
- 累積値の精度
- 最適行動選択率の追跡
- **YAML設定読み込み機能のテスト**
- 設定ファイルの解析
- 動的オブジェクト生成
- 無効設定のエラーハンドリング
- **統計処理のテスト**
- 複数実行結果の平均化
- 統計的妥当性の確保
- **統合テスト**
- End-to-end テスト
- 結果の可視化とファイル出力
- **原因**:
findfirst()が期待通りの動作をしない - **解決**: テストロジックを修正、より柔軟な検証に変更
- **原因**: 累積値の計算で微小な誤差が発生
- **解決**:
≈演算子を使用した近似比較に変更
- **原因**:
all_results = []がVector{Any}になる - **解決**:
all_results = SimulationResult[]に明示的型指定
- **原因**: YAML, CairoMakie, Testパッケージが未インストール
- **解決**:
Pkg.add()で必要パッケージをインストール
Running comprehensive tests for bandit simulation... ============================================================ Testing GaussianBandit... ✓ GaussianBandit tests passed Testing EpsilonGreedy... ✓ EpsilonGreedy tests passed Testing UCB... ✓ UCB tests passed Testing SimulationResult... ✓ SimulationResult tests passed Testing run_simulation... ✓ run_simulation tests passed Testing YAML configuration... ✓ YAML configuration tests passed Testing average_results... ✓ average_results tests passed Testing experiment integration... ✓ experiment integration tests passed Testing error handling... ✓ error handling tests passed ============================================================ All tests passed successfully! ✅
バンディット問題シミュレーション開始 ================================================== Running experiment: experiment1.yaml Running experiment with algorithm: ε-greedy (ε=0.1) Running experiment with algorithm: ε-greedy (ε=0.01) Running experiment with algorithm: UCB (c=2) Results saved to experiment1_results.png Running experiment: experiment2.yaml Running experiment with algorithm: ε-greedy (ε=0.05) Running experiment with algorithm: UCB (c=1) Running experiment with algorithm: UCB (c=3) Results saved to experiment2_results.png ================================================== 全ての実験が完了しました! 結果は各実験設定ファイル名_results.png として保存されています。
bandit.jl(245行) : メインプログラムmain.jl(17行) : 実行エントリーポイントtest_bandit.jl(298行) : 網羅的テストスイート
experiment1.yaml: 5腕バンディット、ε-greedy vs UCB比較experiment2.yaml: 異なる報酬分布、UCBパラメータ比較
experiment1_results.png: 実験1の結果グラフexperiment2_results.png: 実験2の結果グラフ
- ガウシアンバンディット
- 腕の報酬生成
- 最適腕の計算
- ε-greedy (探索率パラメータ)
- UCB (信頼区間パラメータ)
- 単一実行
- 複数実行の平均化
- 結果データの構造化
- 累積報酬
- 累積後悔
- 平均報酬
- 最適行動選択率
- YAML形式の設定ファイル
- 動的オブジェクト生成
- 複数実験の一括実行
abstract type BanditEnvironment end
abstract type BanditAlgorithm endmutable struct SimulationResult
rewards::Vector{Float64}
cumulative_rewards::Vector{Float64}
regrets::Vector{Float64}
cumulative_regrets::Vector{Float64}
optimal_action_percentage::Vector{Float64}
end- 網羅的なユニットテスト
- 統合テスト
- エラーハンドリング
- 統計的妥当性の検証
- **構造化された開発プロセス**: タスク分解とTodo管理
- **包括的なテスト**: 各機能の網羅的テスト
- **段階的な実装**: 機能ごとの分離実装
- **適切なエラーハンドリング**: 予期しない入力への対応
- **警告の修正**:
resolution→sizeの更新 - **型安全性**: より明示的な型指定
- **テストの堅牢性**: 浮動小数点精度への対応
- **Julia特有の型システム**: Vector{Any}の問題と解決
- **統計的シミュレーション**: 乱数シードの重要性
- **可視化ライブラリ**: CairoMakieの効果的な使用
今回の開発では、バンディット問題のシミュレーションプログラムを完全に実装し、網羅的なテストによって妥当性を検証しました。
- ✅ 完全な機能実装
- ✅ 網羅的なテスト
- ✅ YAML設定による柔軟性
- ✅ 可視化機能
- ✅ 複数実験の一括実行
- ✅ 統計的妥当性の確保
- 理論的に正確なバンディット問題の実装
- 実用的で拡張可能なアーキテクチャ
- 研究・教育目的での利用可能性
- 高品質なコードベース
このプロジェクトは、機械学習の基本的なアルゴリズムの実装から、設定管理、可視化、テストまでを含む包括的なソフトウェア開発の例となっています。
if abspath(PROGRAM_FILE) == @__FILE__ のコードの意味について
このJuliaのコードは、スクリプトが直接実行された場合にのみ特定の処理を実行する条件分岐です。
- **PROGRAM_FILE**: Julia の組み込み定数、起動時に最初に実行されるファイルのパス
- **@__FILE__**: 現在のソースファイルの絶対パスを返すマクロ
- **abspath()**: 相対パスを絶対パスに変換する関数(確実な比較のため)
julia main.jl
PROGRAM_FILE=/path/to/main.jl@__FILE__=/path/to/main.jl- 条件が
trueになり、~main()~ が実行される
# other.jl
include("main.jl") # main() は実行されないPROGRAM_FILE=/path/to/other.jl@__FILE__=/path/to/main.jl- 条件が
falseになり、~main()~ は実行されない
- **ライブラリとスクリプトの兼用**: 同じファイルを関数定義とスクリプト実行の両方で使用可能
- **テスト**:
include()でテストファイルに読み込んでも自動実行されない - **モジュール化**: 他のファイルから関数だけを使いたい場合に便利
Python の if __name__ == "__main__": と同じ役割を果たします。
# main.jl
function main()
config_files = [
"experiment1.yaml",
"experiment2.yaml"
]
println("バンディット問題シミュレーション開始")
all_results = run_multiple_experiments(config_files)
println("全ての実験が完了しました!")
end
if abspath(PROGRAM_FILE) == @__FILE__
main()
endこの実装により、~main.jl~ を直接実行すると実験が開始されるが、他のファイルから include("main.jl") で読み込んだ場合は関数定義のみが読み込まれ、実験は自動実行されない。これにより、コードの再利用性とテストの容易性が向上する。