// <summary>ソースコード：ＨＹＭＣＯ演算モデルクラス</summary>
// <author>CommonMP</author>

using System;
using System.Collections.Generic;
using System.Text;

namespace CommonMP.HYMCO.OptionImple.GAModelSampleLIB.GACtlTools
{
    /// <summary><para>class outline:</para>
    /// <para>不均等ルーレット</para>
    /// </summary>
    /// <remarks><para>history:</para>
    /// <para>[CommonMP][ver 1.0.3][2010/10/01][新規作成]</para>
    /// </remarks>
    public class GARoulette
    {
        /// <summary>固体数 </summary>
        long m_lNum;
        /// <summary>ルーレットテーブル </summary>
        double[] m_dRouletteVal;
        /// <summary>ルーレットテーブル内の値の累積値 </summary>
        double m_dSum = 0.0;
        /// <summary>エリート</summary>
        long m_lElite = 0;
        /// <summary>乱数 </summary>
        public static Random m_csRnd = new System.Random(DateTime.Now.GetHashCode());

        /// <summary><para>method outline:</para>
        /// <para>コンストラクタ</para>
        /// </summary>
        /// <example>
        /// <para>usage:</para>
        /// <para>GARoulette csFitValueTable = new GARoulette(lNum)</para>
        /// </example>
        /// <param name="lNum">固体数</param>
        /// <returns>GARoulette 生成されたインスタンス</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public GARoulette(long lNum)
        {
            m_lNum = lNum;
            m_dRouletteVal = new double[m_lNum];
            for (long lLp = 0; lLp < m_lNum; lLp++)
            {
                m_dRouletteVal[lLp] = 0.0;
            }
            m_dSum = 0.0;
        }
        
        /// <summary><para>method outline:</para>
        /// <para>不均等ルーレットテーブルを内部に生成</para>
        /// </summary>
        /// <example>
        /// <para>usage:</para>
        /// <para> MakeRoulette(csTbl) </para>
        /// </example>
        /// <param name="csTbl">適合値管理表</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>適合値の大きいもの程選ばれやすいルーレットテーブルを作成する</para>
        /// </remarks>
        public void MakeRoulette(GAFitValueTable csTbl)
        {
            csTbl.Normalize();
            double[] dNormalizedVal = csTbl.GetNormalizedFitVal();
            double dMax = -1.0E10;
            m_lElite = 0;
            m_dSum = 0.0;
            for (long lLp = 0; lLp < m_lNum; lLp++)
            {
                if (dNormalizedVal[lLp] > dMax)
                {
                    dMax = dNormalizedVal[lLp];
                    m_lElite = lLp;
                }
                m_dSum += dNormalizedVal[lLp];
                m_dRouletteVal[lLp] = m_dSum;
            }
        }
        /// <summary><para>method outline:</para>
        /// <para>エリート取得</para>
        /// </summary>
        /// <example>
        /// <para>usage:</para>
        /// <para> GetElite( ) </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>テーブル上のエリートのアイテム番号（０相対）</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>最も適合値の大きい適合値配列のアイテム番号を取得する</para>
        /// </remarks>
        public long GetElite()
        {
            return m_lElite;
        }

        /// <summary><para>method outline:</para>
        /// <para>ルーレット動作</para>
        /// </summary>
        /// <example>
        /// <para>usage:</para>
        /// <para> Bet( ) </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>ヒットしたテーブル上のアイテム番号（０相対）</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>
        /// ルーレットを回し、ヒットしたテーブル上のアイテム番号を返す
        /// 適合値の高いものほど、ヒットしやすい
        /// </para>
        /// </remarks>
        public long Bet()
        {
            long lSlctNum = m_lNum-1;
            double dSlctVal = m_dSum * GARoulette.m_csRnd.NextDouble();
            for (long lLp = 0; lLp < m_lNum; lLp++)
            {
                if (dSlctVal < m_dRouletteVal[lLp])
                {
                    lSlctNum = lLp;
                    break;
                }
            }
            return lSlctNum;
        }
    }
}
