// <summary>ソースコード：ＨＹＭＣＯモデルファクトリクラス</summary>
// <author>CommonMP</author>

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

using CommonMP.HYSSOP.Interface.HSData;
using CommonMP.HYSSOP.Interface.HSViewer;
using CommonMP.HYSSOP.CoreImpl.HSData;
using CommonMP.HYSSOP.CoreImpl.HSTools;

using CommonMP.HYMCO.Interface;
using CommonMP.HYMCO.Interface.Model;
using CommonMP.HYMCO.Interface.Data;
using CommonMP.HYMCO.Interface.Controller;

using CommonMP.HYSSOP.CoreImpl;
using CommonMP.HYMCO.CoreImpl.Model;
using CommonMP.HYMCO.CoreImpl.Data;

using CommonMP.HYMCO._SYSTEM_;
namespace CommonMP.HYMCO._SYSTEM_
{
    /// <summary><para>class outline:</para>
    /// <para>ＨＹＭＣＯモデルファクトリ生成</para>
    /// </summary>
    /// <remarks><para>history:</para>
    /// <para>[CommonMP][ver 1.0.0][2009/10/01][新規作成]</para>
    /// </remarks>
    public class HYMCO_MODEL_FACTORY_CREATOR_IMPLE : HYMCO_MODEL_FACTORY_CREATOR
    {
        /// <summary><para>method outline:</para>
        /// <para>コンストラクター</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> HYMCO_MODEL_FACTORY_CREATOR_IMPLE csFactCrt = new HYMCO_MODEL_FACTORY_CREATOR_IMPLE( ) </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>生成インスタンス</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public HYMCO_MODEL_FACTORY_CREATOR_IMPLE()
        {
        }
        /// <summary><para>method outline:</para>
        /// <para>演算モデルファクトリクラス生成</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> McModelFactory csCalModelFactory = CreateFactory( ) </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>演算モデルファクトリクラス</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public CommonMP.HYMCO.Interface.Model.McModelFactory CreateFactory()
        {
            return new CommonMP.HYMCO.OptionImpl.NeuralNetworkSample.NeuralNetworkSampleFactory();
        }
    }
}

// ToDo namespace は　モデル開発者が変更して、ユニークな名称にして下さい
namespace CommonMP.HYMCO.OptionImpl.NeuralNetworkSample
{
    /// <summary><para>class outline:</para>
    /// <para>モデルファクトリクラス</para>
    /// </summary>
    /// <remarks><para>history:</para>
    /// <para>[CommonMP][ver 1.0.0][2008/10/01][新規作成]</para>
    /// </remarks>
    public class NeuralNetworkSampleFactory : McBasicModelFactoryBase
    {
        /// <summary><para>method outline:</para>
        /// <para>ファクトリ識別子を生成</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> HySID csFactID = CreateFactoryID( ) </para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>ファクトリ識別子</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override HySID CreateFactoryID()
        {
            // ToDo 本ファクトリクラスにユニークな識別子を生成して返してください
            return NeuralNetworkSampleDefine.MODEL_FACTORY_LIB_ID;
        }

        /// <summary><para>method outline:</para>
        /// <para>演算モデルクラス生成</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> McCalModel csCalModel = CreateCalModel(csModelKind) </para>
        /// </example>
        /// <param name="csModelKind">モデル種別識別子</param>
        /// <returns>演算モデルクラス</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override McCalModel CreateCalModel(HySObjectKind csModelKind)
        {
            McBasicCalculateModelBase csCalModel = null;

            if (csModelKind.Equals(NeuralNetworkSampleDefine.NEURALNET_MODEL_KIND) == true)
            {
                csCalModel = new NeuralNetworkModel();
            }
            if (csModelKind.Equals(NeuralNetworkSampleDefine.NEURALNET_MODEL_TEST_KIND) == true)
            {
                csCalModel = new DmyDataModel();
            }
            else
            {
                // Do Nothing
            }
            
            return csCalModel;
        }

        /// <summary><para>method outline:</para>
        /// <para>要素内演算中データクラス生成</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> McCalInfo csCalModel = CreateCalInfo( csModelKind ) </para>
        /// </example>
        /// <param name="csModelKind">モデル種別識別子</param>
        /// <returns>要素内演算中データクラス</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override McCalInfo CreateCalInfo(HySObjectKind csModelKind)
        {
            McCalInfo csCalInfoData = null;

            if (csModelKind.Equals(NeuralNetworkSampleDefine.NEURALNET_MODEL_KIND) == true)
            {
                csCalInfoData = new NeuralNetworkCalInfo();
            }
            if (csModelKind.Equals(NeuralNetworkSampleDefine.NEURALNET_MODEL_TEST_KIND) == true)
            {
                csCalInfoData = new DmyDataCalInfo();
            }
            else
            {
                // Do Nothing
            }

            return csCalInfoData;
        }

        /// <summary><para>method outline:</para>
        /// <para>モデルプロパティ表示／設定情報クラス生成</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> McPropertyInfoRoot csPropertyInf = CreateModelPropertyInfo(csLibraryID, csModelKind ) </para>
        /// </example>
        /// <param name="csLibraryID">ライブラリー識別子</param>
        /// <param name="csModelKind">モデル種別識別子</param>
        /// <returns>モデルプロパティ表示／設定情報クラス</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override McCellModelPropertyIF CreateModelProperty(HySID csLibraryID, HySObjectKind csModelKind)
        {
            if (this.EqualFactory(csLibraryID) == false)
            {
                return null;
            }

            McCellModelPropertyInfo csRtnCellPrptyDt = null;

            if (csModelKind.Equals(NeuralNetworkSampleDefine.NEURALNET_MODEL_KIND) == true)
            {
                csRtnCellPrptyDt = new McCellModelPropertyInfo(csLibraryID, csModelKind);
                csRtnCellPrptyDt.SetStepTime(600); // δT設定 600秒  // 時間設定はダミー

                // 層の数
                csRtnCellPrptyDt.AddInfoType("m_lLayerNum", "層の数（３　or ４）", McDefine.ValKind.LONG);
                csRtnCellPrptyDt.SetInfo("m_lLayerNum", 3);
                // 層内のニューロン数設定
                csRtnCellPrptyDt.AddInfoType("m_iNeuronNumber[0]", "入力層のニューロン数", McDefine.ValKind.LONG);
                csRtnCellPrptyDt.SetInfo("m_iNeuronNumber[0]", 2);
                csRtnCellPrptyDt.AddInfoType("m_iNeuronNumber[Top]", "出力層のニューロン数", McDefine.ValKind.LONG);
                csRtnCellPrptyDt.SetInfo("m_iNeuronNumber[Top]", 1);
                csRtnCellPrptyDt.AddInfoType("m_iNeuronNumber[1]", "第１隠れ層のニューロン数", McDefine.ValKind.LONG);
                csRtnCellPrptyDt.SetInfo("m_iNeuronNumber[1]", 2);
                csRtnCellPrptyDt.AddInfoType("m_iNeuronNumber[2]", "第２隠れ層のニューロン数", McDefine.ValKind.LONG);
                csRtnCellPrptyDt.SetInfo("m_iNeuronNumber[2]", 0);


                // 受信可能なパターン
                {
                    // 受信パターンその１
                    McTranInfoPattern csTrnPtn = csRtnCellPrptyDt.CreateTranInforPattern(
                        NeuralNetworkSampleDefine.LEARN_INPUT_PATTERN_ID,
                        McTranInfoDefine.D1_CELL_SERIAL,
                        "学習用：入力パターン") as McTranInfoPattern;
                    {
                        // セル内変数設定
                        HySDataCharacteristicInCell csCellChara = csTrnPtn.CreateCellDataCharacteristic(16); // セル内の情報は１個のみ
                        {
                            for (long lP = 0; lP < 16; lP++)
                            {
                                csCellChara.SetDataKind(lP, "学習用入力:NO=" + lP.ToString(),
                                    HySDataCharacteristicInCell.DATA_KIND.ANY_VALUE, "任意単位");
                            }
                        }
                        csTrnPtn.SetCellDataCharacteristic(csCellChara);
                        csTrnPtn.SetInterpolateType(HySDefine.InterpolateType.NO_INTERPOLATE); // 内挿方法設定
                    }
                    csRtnCellPrptyDt.AddReceivePattern(csTrnPtn);
                    // 受信パターンその２
                    csTrnPtn = csRtnCellPrptyDt.CreateTranInforPattern(
                        NeuralNetworkSampleDefine.LEARN_TEACH_PATTERN_ID,
                        McTranInfoDefine.D1_CELL_SERIAL,
                        "学習用：教師パターン") as McTranInfoPattern;
                    {
                        // セル内変数設定
                        HySDataCharacteristicInCell csCellChara = csTrnPtn.CreateCellDataCharacteristic(16); // セル内の情報は１個のみ
                        {
                            for (long lP = 0; lP < 16; lP++)
                            {
                                csCellChara.SetDataKind(lP, "学習用教師:NO=" + lP.ToString(),
                                    HySDataCharacteristicInCell.DATA_KIND.ANY_VALUE, "任意単位");
                            }
                        }
                        csTrnPtn.SetCellDataCharacteristic(csCellChara);
                        csTrnPtn.SetInterpolateType(HySDefine.InterpolateType.NO_INTERPOLATE); // 内挿方法設定
                    }
                    csRtnCellPrptyDt.AddReceivePattern(csTrnPtn);
                    // 受信パターンその３
                    csTrnPtn = csRtnCellPrptyDt.CreateTranInforPattern(
                        NeuralNetworkSampleDefine.RECOG_INPUT_PATTERN_ID,
                        McTranInfoDefine.D1_CELL_SERIAL,
                        "連想用入力パターン") as McTranInfoPattern;
                    {
                        // セル内変数設定
                        HySDataCharacteristicInCell csCellChara = csTrnPtn.CreateCellDataCharacteristic(16); // セル内の情報は１個のみ
                        {
                            for (long lP = 0; lP < 16; lP++)
                            {
                                csCellChara.SetDataKind(lP, "連想用入力:NO=" + lP.ToString(),
                                    HySDataCharacteristicInCell.DATA_KIND.ANY_VALUE, "任意単位");
                            }
                        }
                        csTrnPtn.SetCellDataCharacteristic(csCellChara);
                        csTrnPtn.SetInterpolateType(HySDefine.InterpolateType.NO_INTERPOLATE); // 内挿方法設定
                    }
                    csRtnCellPrptyDt.AddReceivePattern(csTrnPtn);
                }
                // 送信パターンの設定
                {
                    // 送信パターンその１
                    McTranInfoPattern csTrnPtn = csRtnCellPrptyDt.CreateTranInforPattern(
                            NeuralNetworkSampleDefine.RECOG_OUTPUT_PATTERN_ID,
                            McTranInfoDefine.D1_CELL_SERIAL,
                            "連想結果") as McTranInfoPattern;
                    {
                        // セル内変数設定
                        HySDataCharacteristicInCell csCellChara = csTrnPtn.CreateCellDataCharacteristic(16); // セル内の情報は１個のみ
                        {
                            for (long lP = 0; lP < 16; lP++)
                            {
                                csCellChara.SetDataKind(lP, "連想用出力:NO=" + lP.ToString(),
                                    HySDataCharacteristicInCell.DATA_KIND.ANY_VALUE, "任意単位");
                            }
                        }
                        csTrnPtn.SetCellDataCharacteristic(csCellChara);
                    }
                    csRtnCellPrptyDt.AddSendPattern(csTrnPtn);

                    // 送信パターンその２
                    csTrnPtn = csRtnCellPrptyDt.CreateTranInforPattern(
                            NeuralNetworkSampleDefine.LEARN_ERROR_OUT_PATTERN_ID,
                            McTranInfoDefine.SINGLE_CELL_SERIAL,
                            "学習中の誤差") as McTranInfoPattern;
                    {
                        // セル内変数設定
                        HySDataCharacteristicInCell csCellChara = csTrnPtn.CreateCellDataCharacteristic(1); // セル内の情報は１個のみ
                        {
                            csCellChara.SetDataKind(0, "学習中誤差", HySDataCharacteristicInCell.DATA_KIND.ANY_VALUE, "任意単位");
                        }
                        csTrnPtn.SetCellDataCharacteristic(csCellChara);
                    }
                    csRtnCellPrptyDt.AddSendPattern(csTrnPtn);
                }
            }
            else if (csModelKind.Equals(NeuralNetworkSampleDefine.NEURALNET_MODEL_TEST_KIND) == true)
            {
                csRtnCellPrptyDt = new McCellModelPropertyInfo(csLibraryID, csModelKind);
                csRtnCellPrptyDt.SetStepTime(1000000); // δT設定   // 時間設定はダミー

                // 受信可能なパターン
                {

                }
                // 送信パターンの設定
                {
                    McTranInfoPattern csTrnPtn = csRtnCellPrptyDt.CreateTranInforPattern(
                                NeuralNetworkSampleDefine.LEARN_INPUT_PATTERN_ID,
                                McTranInfoDefine.D1_CELL_SERIAL,
                                "学習用：入力パターン") as McTranInfoPattern;
                    {
                        // セル内変数設定
                        HySDataCharacteristicInCell csCellChara = csTrnPtn.CreateCellDataCharacteristic(16); // セル内の情報は１個のみ
                        {
                            for (long lP = 0; lP < 16; lP++)
                            {
                                csCellChara.SetDataKind(lP, "学習用入力:NO=" + lP.ToString(),
                                    HySDataCharacteristicInCell.DATA_KIND.ANY_VALUE, "任意単位");
                            }
                        }
                        csTrnPtn.SetCellDataCharacteristic(csCellChara);
                    }
                    csRtnCellPrptyDt.AddSendPattern(csTrnPtn);

                    csTrnPtn = csRtnCellPrptyDt.CreateTranInforPattern(
                        NeuralNetworkSampleDefine.LEARN_TEACH_PATTERN_ID,
                        McTranInfoDefine.D1_CELL_SERIAL,
                        "学習用：教師パターン") as McTranInfoPattern;
                    {
                        // セル内変数設定
                        HySDataCharacteristicInCell csCellChara = csTrnPtn.CreateCellDataCharacteristic(16); // セル内の情報は１個のみ
                        {
                            for (long lP = 0; lP < 16; lP++)
                            {
                                csCellChara.SetDataKind(lP, "学習用教師:NO=" + lP.ToString(),
                                    HySDataCharacteristicInCell.DATA_KIND.ANY_VALUE, "任意単位");
                            }
                        }
                        csTrnPtn.SetCellDataCharacteristic(csCellChara);
                    }
                    csRtnCellPrptyDt.AddSendPattern(csTrnPtn);

                    csTrnPtn = csRtnCellPrptyDt.CreateTranInforPattern(
                            NeuralNetworkSampleDefine.RECOG_INPUT_PATTERN_ID,
                            McTranInfoDefine.D1_CELL_SERIAL,
                            "連想用入力パターン") as McTranInfoPattern;
                    {
                        // セル内変数設定
                        HySDataCharacteristicInCell csCellChara = csTrnPtn.CreateCellDataCharacteristic(16); // セル内の情報は１個のみ
                        {
                            for (long lP = 0; lP < 16; lP++)
                            {
                                csCellChara.SetDataKind(lP, "連想用入力:NO=" + lP.ToString(),
                                    HySDataCharacteristicInCell.DATA_KIND.ANY_VALUE, "任意単位");
                            }
                        }
                        csTrnPtn.SetCellDataCharacteristic(csCellChara);
                    }
                    csRtnCellPrptyDt.AddSendPattern(csTrnPtn);
                }
            }
            else
            {
                // Do Noghing
            }

            return csRtnCellPrptyDt;
        }
        /// <summary><para>method outline:</para>
        /// <para>モデル初期化表示／設定情報生成</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> McPropertyInfoRoot csInitialInf = CreateModelInitialInfo(csLibraryID, csModelKind ) </para>
        /// </example>
        /// <param name="csLibraryID">ライブラリー識別子</param>
        /// <param name="csModelKind">モデル種別識別子</param>
        /// <returns>初期情報情報クラス</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override McPropertyInfoRoot CreateModelInitialInfo(HySID csLibraryID, HySObjectKind csModelKind)
        {
            if (this.EqualFactory(csLibraryID) == false)
            {
                return null;
            }

            McInitialInfo csRtnDt = null;

            if (csModelKind.Equals(NeuralNetworkSampleDefine.NEURALNET_MODEL_KIND) == true)
            {
                csRtnDt = new McInitialInfo(csLibraryID, csModelKind);


                csRtnDt.AddInfoType("m_lMode", "学習(=0)／連想モード(=1)", McDefine.ValKind.LONG);
                csRtnDt.SetInfo("m_lMode", 0);

                csRtnDt.AddInfoType("m_csLearnedResultStockFile", "学習結果保存ファイル", McDefine.ValKind.STRING);
                // >> Ver1.0 → Ver1.1 により、モデル用データ格納場所を変更（プログラムによる相対パス化）
                //csRtnDt.SetInfo("m_csLearnedResultStockFile", "..\\temp\\LearndResult.dat");
                csRtnDt.SetInfo("m_csLearnedResultStockFile", "OutputData\\NNSample\\LearndResult.dat");
                // Ver1.0 → Ver1.1 により、モデル用データ格納場所を変更（プログラムによる相対パス化） <<

                csRtnDt.AddInfoType("m_iLearnPtnNum", "学習パターン数(本サンプルでは最大１６としておく)", McDefine.ValKind.LONG);
                csRtnDt.SetInfo("m_iLearnPtnNum", 4);
                
                csRtnDt.AddInfoType("m_dE2Limit", "学習打ち切り判定誤差", McDefine.ValKind.DOUBLE);
                csRtnDt.SetInfo("m_dE2Limit", 0.001);
                
                csRtnDt.AddInfoType("m_dSlope", "シグモイド関数の傾き", McDefine.ValKind.DOUBLE);
                csRtnDt.SetInfo("m_dSlope", 3.0);
                csRtnDt.AddInfoType("m_dAlpha", "学習係数", McDefine.ValKind.DOUBLE);
                csRtnDt.SetInfo("m_dAlpha", 0.1);
                csRtnDt.AddInfoType("m_dInertia", "学習慣性係数", McDefine.ValKind.DOUBLE);
                csRtnDt.SetInfo("m_dInertia", 0.75);

                csRtnDt.AddInfoType("m_iMaxLearnNum", "最大学習回数", McDefine.ValKind.LONG);
                csRtnDt.SetInfo("m_iMaxLearnNum", 10000);


                // 学習係数、慣性項
                // 打ち切りエラー限界
                // あきらめ学習回数打ち切り限界
                // シグモイド関数の傾き
                // コーディング例

                // csRtnDt.AddInfoType("m_dData", "初期値", McDefine.ValKind.DOUBLE);
                // csRtnDt.SetInfo("m_dData", 1.0); 
            }
            if (csModelKind.Equals(NeuralNetworkSampleDefine.NEURALNET_MODEL_TEST_KIND) == true)
            {
                csRtnDt = new McInitialInfo(csLibraryID, csModelKind);
            }
            else
            {
                // Do Nothing
            }

            return csRtnDt;
        }

        /// <summary>
        /// <para>method outline:</para>
        /// <para>モデル情報提供</para>
        /// </summary>
        /// <example>
        /// <para>usage:</para>
        /// <para>HySDataLinkedList csModelInfoList = GetCalModelInfoList();</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>モデル情報のリスト</returns>
        /// <exception cref="">無し</exception>
        /// <remarks>
        /// <para>remarks:</para>
        /// <para>モデル情報(McModelInfo)をリスト形式で返却する</para>
        /// </remarks>
        public override HySDataLinkedList GetCalModelInfoList()
        {
            McModelInfo csModelInfo=null;

            csModelInfo = new McModelInfo(
                    (HySID)this.GetFactoryID(),
                    McModelLibraryDefine.DIVISION_CALCULATION_MODEL,    // <-- 演算モデルは、必ずこの値にして下さい（LibraryCategoryXML.xmlに記述されている）
                    new HySObjectKind("CAL_SAMPLE_MODELS"), // <-- LibraryCategoryXML.xmlに定義されている値を使用する
                    NeuralNetworkSampleDefine.NEURALNET_MODEL_KIND, // モデルの識別子
                    NeuralNetworkSampleDefine.NEURALNET_MODEL_NAME  // モデルの名称
                                          );
            csModelInfo.SetVersionInf("Ver1.0 ");
            csModelInfo.SetSummaryInf("ニューラルネットワークモデルのサンプルです。学習方法は、バックプロパゲーションを用いています");
            csModelInfo.SetCreatorInf("CommonMP　モデル開発者");
            csModelInfo.SetIconName(new HySString("DefaultModel"));
            csModelInfo.SetManualFileName(".\\Sample\\NeuralNetworkSampleModelExplanation.pdf"); // <-- モデル解説書

            m_csCalModelInforList.AddLast(csModelInfo); // 演算モデル情報の追加

            csModelInfo = new McModelInfo(
                (HySID)this.GetFactoryID(),
                McModelLibraryDefine.DIVISION_CALCULATION_MODEL,    // <-- 演算モデルは、必ずこの値にして下さい（LibraryCategoryXML.xmlに記述されている）
                new HySObjectKind("CAL_SAMPLE_MODELS"), // <-- LibraryCategoryXML.xmlに定義されている値を使用する
                NeuralNetworkSampleDefine.NEURALNET_MODEL_TEST_KIND, // モデルの識別子
                NeuralNetworkSampleDefine.NEURALNET_MODEL_NAME_TEST  // モデルの名称
                              );
            csModelInfo.SetVersionInf("Ver1.0 ");
            csModelInfo.SetSummaryInf("サンプルニューラルネットワークモデルへの学習情報・連想入力情報を生成します。本例では、XORパターンを学習させます");
            csModelInfo.SetCreatorInf("CommonMP　モデル開発者");
            csModelInfo.SetIconName(new HySString("DefaultModel"));
            csModelInfo.SetManualFileName(".\\Sample\\NeuralNetworkSampleModelExplanation.pdf"); // <-- モデル解説書
            m_csCalModelInforList.AddLast(csModelInfo); // 演算モデル情報の追加

            return m_csCalModelInforList;
        }

    }
}
