public void WriteRLMSettings(RlmSettings settings)
        {
            var           collection = settings.GetType().GetProperties();
            List <string> headers    = new List <string>();
            List <string> data       = new List <string>();

            foreach (PropertyInfo pi in collection)
            {
                headers.Add(pi.Name);
                data.Add(pi.GetValue(settings).ToString());
            }

            Sr.WriteLine(String.Join(",", headers));
            Sr.WriteLine(String.Join(",", data));
        }
        private bool UpdateScoreHit(ref int currentHits, RlmSettings settings)
        {
            bool retVal = false;

            if (TrainingVariables["SessionScore"].Value >= settings.SimulationTarget && settings.SimulationType == RlmSimulationType.Score)
            {
                currentHits++;
                if (currentHits >= settings.NumScoreHits)
                {
                    retVal = true;
                }
            }
            else
            {
                currentHits = 0;
            }

            return(retVal);
        }
        static void Main(string[] args)
        {
            IRlmDbData rlmDbData = new RlmDbDataSQLServer("BasketballPrototype");

            RlmOptimizer opt = new RlmOptimizer(rlmDbData);
            Dictionary <string, Resource> resources = new Dictionary <string, Resource>();

            Resource r1 = new Resource
            {
                Name             = "Position",
                Type             = Category.Range,
                RLMObject        = RLMObject.Input,
                Min              = 1,
                Max              = 5,
                DataType         = "System.Int32",
                RlmInputDataType = RlmInputDataType.Int,
                RlmInputType     = RlmInputType.Distinct
            };

            opt.Resources.Add(r1.Name, r1);

            Resource r2 = new Resource
            {
                Name             = "Player",
                Type             = Category.Data,
                RLMObject        = RLMObject.Output,
                DataType         = "System.Int32",
                RlmInputDataType = RlmInputDataType.Int
            };

            r2.UploadDataResource("PlayerDetails2.csv");
            opt.Resources.Add(r2.Name, r2);

            //PG
            var pgMetric = new Resource();

            pgMetric.Name    = "PGMetric";
            pgMetric.Type    = Category.Computed;
            pgMetric.Formula = new string[]
            {
                @"([Player.Playmaking] * .3) + 
                ([Player.OutsideScoring] * .3) + 
                ([Player.PerimeterDefense] * .3) + 
                ([Player.Speed] * .1)"
                //([Player.Rebounding] * .05) +
                //([Player.LowPostDefense] * .05) +
                //([Player.Strength] * .05) +
                //([Player.InsideScoring] * .05)"
            };
            opt.Resources.Add(pgMetric.Name, pgMetric);

            //SG
            var sgMetric = new Resource()
            {
                Name    = "SGMetric",
                Type    = Category.Computed,
                Formula = new string[]
                {
                    @"([Player.Playmaking] * .1) + 
                    ([Player.OutsideScoring] * .5) + 
                    ([Player.PerimeterDefense] * .3) + 
                    ([Player.Speed] * .1)"
                    //([Player.Rebounding] * .07) +
                    //([Player.LowPostDefense] * .07) +
                    //([Player.Strength] * .06) +
                    //([Player.InsideScoring] * .1)"
                }
            };

            opt.Resources.Add(sgMetric.Name, sgMetric);

            //SF
            var sfMetric = new Resource()
            {
                Name    = "SFMetric",
                Type    = Category.Computed,
                Formula = new string[]
                {
                    @"([Player.OutsideScoring] * .3) + 
                    ([Player.PerimeterDefense] * .3) +                     
                    ([Player.Speed] * .1) + 
                    ([Player.LowPostDefense] * .15) +                     
                    ([Player.InsideScoring] * .15)"
                }
            };

            opt.Resources.Add(sfMetric.Name, sfMetric);

            //PF
            var pfMetric = new Resource()
            {
                Name    = "PFMetric",
                Type    = Category.Computed,
                Formula = new string[]
                {
                    //@"([Player.Playmaking] * .05) +
                    //([Player.OutsideScoring] * .05) +
                    //([Player.PerimeterDefense] * .05) +
                    //([Player.Speed] * .05) +
                    @"([Player.Rebounding] * .2) + 
                    ([Player.LowPostDefense] * .15) +  
                    ([Player.Strength] * .15) + 
                    ([Player.InsideScoring] * .5)"
                }
            };

            opt.Resources.Add(pfMetric.Name, pfMetric);

            //CENTER
            var centerMetric = new Resource()
            {
                Name    = "CenterMetric",
                Type    = Category.Computed,
                Formula = new string[]
                {
                    //@"([Player.Playmaking] * .05) +
                    //([Player.OutsideScoring] * .05) +
                    //([Player.PerimeterDefense] * .05) +
                    //([Player.Speed] * .05) +
                    @"([Player.Rebounding] * .4) + 
                    ([Player.LowPostDefense] * .3) + 
                    ([Player.Strength] * .2) + 
                    ([Player.InsideScoring] * .1)"
                }
            };

            opt.Resources.Add(centerMetric.Name, centerMetric);

            var totalMetric = new Resource();

            totalMetric.Name  = "Total";
            totalMetric.Type  = Category.Variable;
            totalMetric.Value = 0;
            opt.Resources.Add(totalMetric.Name, totalMetric);

            //PG
            Constraint pgConst = new Constraint()
            {
                Name    = "PGConstraint",
                Formula = new List <string> {
                    "[CycleInputs.Position] == 1 && [Player.Height] <= 194"
                },
                FailScore = new ConstraintScore()
                {
                    Name = "FailScore", Formula = new string[] { "0" }
                },
                SuccessScore = new ConstraintScore()
                {
                    Name = "SucessScore", Formula = new string[] { "[PGMetric]" }
                }
            };

            //SG
            Constraint sgConst = new Constraint()
            {
                Name    = "SGConstraint",
                Formula = new List <string> {
                    "[CycleInputs.Position] == 2 && [Player.Height] > 194 && [Player.Height] <= 200"
                },
                FailScore = new ConstraintScore()
                {
                    Name = "FailScore", Formula = new string[] { "0" }
                },
                SuccessScore = new ConstraintScore()
                {
                    Name = "SucessScore", Formula = new string[] { "[SGMetric]" }
                }
            };

            //SF
            Constraint sfConst = new Constraint()
            {
                Name    = "SFConstraint",
                Formula = new List <string> {
                    "[CycleInputs.Position] == 3 && [Player.Height] > 200 && [Player.Height] <= 208"
                },
                FailScore = new ConstraintScore()
                {
                    Name = "FailScore", Formula = new string[] { "0" }
                },
                SuccessScore = new ConstraintScore()
                {
                    Name = "SucessScore", Formula = new string[] { "[SFMetric]" }
                }
            };

            //PF
            Constraint pfConst = new Constraint()
            {
                Name    = "PFConstraint",
                Formula = new List <string> {
                    "[CycleInputs.Position] == 4 && [Player.Height] > 208 && [Player.Height] <= 212"
                },
                FailScore = new ConstraintScore()
                {
                    Name = "FailScore", Formula = new string[] { "0" }
                },
                SuccessScore = new ConstraintScore()
                {
                    Name = "SucessScore", Formula = new string[] { "[PFMetric]" }
                }
            };

            //CENTER
            Constraint centerConst = new Constraint()
            {
                Name    = "CenterConstraint",
                Formula = new List <string> {
                    "[CycleInputs.Position] == 5 && [Player.Height] > 212"
                },
                FailScore = new ConstraintScore()
                {
                    Name = "FailScore", Formula = new string[] { "0" }
                },
                SuccessScore = new ConstraintScore()
                {
                    Name = "SucessScore", Formula = new string[] { "[CenterMetric]" }
                }
            };

            var cyclePhase = new ScoringPhase();

            cyclePhase.Name    = "CycleScore";
            cyclePhase.Formula = new string[]
            {
                "[CycleScore] = [PGConstraint] + [SGConstraint] + [SFConstraint] + [PFConstraint] + [CenterConstraint]",
                "[SessionScore] = [SessionScore] + [CycleScore]",
            };
            //cyclePhase.Constraints.Add(cons1);
            opt.Constraints[pgConst.Name]     = pgConst;     //PG
            opt.Constraints[sgConst.Name]     = sgConst;     //SG
            opt.Constraints[sfConst.Name]     = sfConst;     //SF
            opt.Constraints[pfConst.Name]     = pfConst;     //PF
            opt.Constraints[centerConst.Name] = centerConst; //CENTER

            opt.CyclePhase = cyclePhase;

            var sessionPhase = new ScoringPhase();

            sessionPhase.Name    = "SessionScore";
            sessionPhase.Formula = new string[]
            {
                "[SessionScore]",
                //"[Total] = 0"
            };

            opt.SessionPhase = sessionPhase;

            RlmSettings settings = new RlmSettings()
            {
                Name               = "BasketballOptimizer",
                StartRandomness    = 50,
                EndRandomness      = 0,
                MaxLinearBracket   = 15,
                MinLinearBracket   = 3,
                NumOfSessionsReset = 100,
                SimulationTarget   = TargetForThisRun,
                NumScoreHits       = 10,
                SimulationType     = RlmSimulationType.Score,
                Time               = new TimeSpan(0, 5, 0),
                DatabaseName       = "BasketballPrototype"
            };

            opt.StartTraining(settings);

            //Save to CSV Code
            SaveToCSV saveToCSV = new SaveToCSV(FileNameForThisTest);

            saveToCSV.WriteRLMSettings(settings);
            //saveToCSV.WriteData(opt.SessionData, "Session,SessionScore");
            //saveToCSV.WriteData(opt.PredictData, "Position,Score");
            saveToCSV.WriteSpace();

            for (int i = 1; i <= r1.Max; i++)
            {
                int    output = Convert.ToInt32(opt.SessionOutputs["Player"].ElementAt(i - 1));
                string line   = $"Position: {i}, Player: {opt.Resources["Player"].DataObjDictionary.ElementAt(output).Value.AttributeDictionary["PlayerName"]}";
                Console.WriteLine(line);
                saveToCSV.WriteLine(line);
            }

            saveToCSV.WriteSpace();
            //saveToCSV.WriteLine("Total Elapsed Time: " + opt.Elapsed);

            //Console.WriteLine(compiler.Parse(cyclePhase));
            Console.ReadLine();
        }
        public IDictionary <int, RlmCyclecompleteArgs> StartTraining(RlmSettings settings, CancellationToken?token = null)
        {
            dataPersistEvent.Reset();
            //stopTraining = false;
            //settings = this.Settings;
            this.Settings = settings;

            //Get RLM Settings from user
            int startRandomness       = settings.StartRandomness;
            int endRandomness         = settings.EndRandomness;
            int maxBracket            = settings.MaxLinearBracket;
            int minBracket            = settings.MinLinearBracket;
            RlmSimulationType simType = settings.SimulationType;
            TimeSpan          time    = settings.Time;
            double            target  = settings.SimulationTarget;

            // clear previous network, if any
            ClearNetwork();

            IDictionary <int, RlmCyclecompleteArgs> cycleOutputDic = null;

            network = (string.IsNullOrEmpty(DatabaseName) ? new RlmNetwork() : new RlmNetwork(RlmDbData, true));

            network.DataPersistenceComplete += Network_DataPersistenceComplete;

            network.StartRandomness  = startRandomness;
            network.EndRandomness    = endRandomness;
            network.MaxLinearBracket = maxBracket;
            network.MinLinearBracket = minBracket;

            List <RlmIO> inputs  = new List <RlmIO>();
            List <RlmIO> outputs = new List <RlmIO>();

            //get inputs/outputs from resources
            var resourceInputs  = Resources.Where(a => a.Value.RLMObject == RLMObject.Input);
            var resourceOutputs = Resources.Where(a => a.Value.RLMObject == RLMObject.Output);

            //set rlm inputs/outputs
            inputs  = GetRlmIOFromResource(resourceInputs);
            outputs = GetRlmIOFromResource(resourceOutputs);

            //create network
            if (!network.LoadNetwork())
            {
                network.NewNetwork("RlmOptimizer", inputs, outputs);
            }

            //start training
            int      sessions = settings.SimulationType == RlmSimulationType.Sessions ? Convert.ToInt32(settings.SimulationTarget) : settings.NumOfSessionsReset;
            double   hours    = settings.SimulationType == RlmSimulationType.Time ? settings.Time.TotalHours : 0;
            DateTime endsOn   = DateTime.Now.AddHours(hours);

            TraceLog($"RLM Settings: \n\n" +
                     $"Randomness: Max = {startRandomness}, End = {endRandomness}\nLinear Bracket: Max = {maxBracket}, Min = {minBracket}\n" +
                     $"Simulation Type: {simType}\nTarget: {target}\nTime: {hours}\n" +
                     $"Cycle Score Formula: {string.Join(" | ", CyclePhase.Formula)}\n" +
                     $"Session Score Formula: {string.Join(" | ", SessionPhase.Formula)}");
            TraceLog();

            int  scoreHits = 0;
            bool timesUp   = false;

            //for (var trial = 1; trial <= 5; trial++)
            //{
            //TrainingLog($"\nTrial #{trial}");

            do
            {
                //settings
                network.NumSessions      = sessions;
                network.StartRandomness  = startRandomness;
                network.EndRandomness    = endRandomness;
                network.MaxLinearBracket = maxBracket;
                network.MinLinearBracket = minBracket;

                network.ResetRandomizationCounter();

                if ((simType == RlmSimulationType.Time && DateTime.Compare(DateTime.Now, endsOn) == 1) || token?.IsCancellationRequested == true)
                {
                    timesUp = true;
                }

                if (!timesUp)
                {
                    TraceLog("\nTraining...\n");
                    for (int i = 1; i <= sessions; i++)
                    {
                        cycleOutputDic = RunOneSession(network, resourceInputs, true);
                        if (settings.SimulationType == RlmSimulationType.Score)
                        {
                            if (UpdateScoreHit(ref scoreHits, settings) || token?.IsCancellationRequested == true)
                            {
                                break;
                            }
                        }

                        if ((simType == RlmSimulationType.Time && DateTime.Compare(DateTime.Now, endsOn) == 1) || token?.IsCancellationRequested == true)
                        {
                            timesUp = true;
                            break;
                        }

                        if (stopTraining || token?.IsCancellationRequested == true)
                        {
                            break;
                        }
                    }
                }

                //predict
                TraceLog("\nPredicting...\n");
                if (settings.SimulationType == RlmSimulationType.Score)
                {
                    for (int i = 1; i <= settings.NumScoreHits; i++)
                    {
                        cycleOutputDic = RunOneSession(network, resourceInputs, false, (i == settings.NumScoreHits));
                        if (UpdateScoreHit(ref scoreHits, settings) || token?.IsCancellationRequested == true)
                        {
                            break;
                        }
                    }
                }
                else
                {
                    cycleOutputDic = RunOneSession(network, resourceInputs, false, true);
                }

                if (stopTraining || token?.IsCancellationRequested == true)
                {
                    break;
                }
            } while ((!timesUp && simType == RlmSimulationType.Time) ||
                     (simType == RlmSimulationType.Score && settings.NumScoreHits > scoreHits));
            //}

            //end training
            network.TrainingDone();

            if (simType == RlmSimulationType.Score)
            {
                TraceLog($"Score Hits: {scoreHits}");
            }

            TraceLog("Optimization Done");

            return(cycleOutputDic);
        }
        public static RlmOptimizer GetOptimizer()
        {
            RlmDbDataSQLServer            rlmDb        = new RlmDbDataSQLServer("BasketballOptimizer");
            RlmOptimizer                  rlmOptimizer = new RlmOptimizer(rlmDb);
            Dictionary <string, Resource> resources    = new Dictionary <string, Resource>();

            //input resource
            Resource input1 = new Resource
            {
                Name             = "Position",
                Type             = Category.Range,
                RLMObject        = RLMObject.Input,
                Min              = 1,
                Max              = 5,
                DataType         = "System.Int32",
                RlmInputDataType = RlmInputDataType.Int,
                RlmInputType     = RlmInputType.Distinct
            };

            rlmOptimizer.Resources.Add(input1.Name, input1);

            //output resource
            Resource output1 = new Resource
            {
                Name             = "Player",
                Type             = Category.Data,
                RLMObject        = RLMObject.Output,
                DataType         = "System.Int32",
                RlmInputDataType = RlmInputDataType.Int
            };

            output1.UploadDataResource("PlayerDetails2.csv");
            rlmOptimizer.Resources.Add(output1.Name, output1);

            #region Metrics
            //PG
            var pgMetric = new Resource();
            pgMetric.Name    = "PGMetric";
            pgMetric.Type    = Category.Computed;
            pgMetric.Formula = new string[]
            {
                @"([Player.Playmaking] * .3) + 
                ([Player.OutsideScoring] * .3) + 
                ([Player.PerimeterDefense] * .3) + 
                ([Player.Speed] * .1)"
            };
            rlmOptimizer.Resources.Add(pgMetric.Name, pgMetric);

            //SG
            var sgMetric = new Resource()
            {
                Name    = "SGMetric",
                Type    = Category.Computed,
                Formula = new string[]
                {
                    @"([Player.Playmaking] * .1) + 
                    ([Player.OutsideScoring] * .1) + 
                    ([Player.PerimeterDefense] * .2) + 
                    ([Player.Speed] * .6)"
                }
            };
            rlmOptimizer.Resources.Add(sgMetric.Name, sgMetric);

            //SF
            var sfMetric = new Resource()
            {
                Name    = "SFMetric",
                Type    = Category.Computed,
                Formula = new string[]
                {
                    @"([Player.OutsideScoring] * .1) + 
                    ([Player.PerimeterDefense] * .45) +                     
                    ([Player.Speed] * .1) + 
                    ([Player.LowPostDefense] * .15) +                     
                    ([Player.InsideScoring] * .25)"
                }
            };
            rlmOptimizer.Resources.Add(sfMetric.Name, sfMetric);

            //PF
            var pfMetric = new Resource()
            {
                Name    = "PFMetric",
                Type    = Category.Computed,
                Formula = new string[]
                {
                    @"([Player.Playmaking] * .05) + 
                    ([Player.OutsideScoring] * .35) + 
                    ([Player.PerimeterDefense] * .05) + 
                    ([Player.Speed] * .05) + 
                    ([Player.Rebounding] * .2) + 
                    ([Player.LowPostDefense] * .15) +  
                    ([Player.Strength] * .1) + 
                    ([Player.InsideScoring] * .05)"
                }
            };
            rlmOptimizer.Resources.Add(pfMetric.Name, pfMetric);

            //CENTER
            var centerMetric = new Resource()
            {
                Name    = "CenterMetric",
                Type    = Category.Computed,
                Formula = new string[]
                {
                    @"([Player.Playmaking] * .05) + 
                    ([Player.OutsideScoring] * .50) + 
                    ([Player.PerimeterDefense] * .05) + 
                    ([Player.Speed] * .1) + 
                    ([Player.Rebounding] * .1) + 
                    ([Player.LowPostDefense] * .1) + 
                    ([Player.Strength] * .1) + 
                    ([Player.InsideScoring] * .1)"
                }
            };
            rlmOptimizer.Resources.Add(centerMetric.Name, centerMetric);
            #endregion

            #region Constraints
            //PG
            Constraint pgConst = new Constraint()
            {
                Name    = "PGConstraint",
                Formula = new List <string> {
                    "[CycleInputs.Position] == 1 && [Player.Height] > 195 && [Player.Height] <= 198"
                },
                FailScore = new ConstraintScore()
                {
                    Name = "FailScore", Formula = new string[] { "0" }
                },
                SuccessScore = new ConstraintScore()
                {
                    Name = "SucessScore", Formula = new string[] { "[PGMetric]" }
                }
            };

            //SG
            Constraint sgConst = new Constraint()
            {
                Name    = "SGConstraint",
                Formula = new List <string> {
                    "[CycleInputs.Position] == 2 && [Player.Height] > 198 && [Player.Height] <= 203"
                },
                FailScore = new ConstraintScore()
                {
                    Name = "FailScore", Formula = new string[] { "0" }
                },
                SuccessScore = new ConstraintScore()
                {
                    Name = "SucessScore", Formula = new string[] { "[SGMetric]" }
                }
            };

            //SF
            Constraint sfConst = new Constraint()
            {
                Name    = "SFConstraint",
                Formula = new List <string> {
                    "[CycleInputs.Position] == 3 && [Player.Height] == 200"
                },
                FailScore = new ConstraintScore()
                {
                    Name = "FailScore", Formula = new string[] { "0" }
                },
                SuccessScore = new ConstraintScore()
                {
                    Name = "SucessScore", Formula = new string[] { "[SFMetric]" }
                }
            };

            //PF
            Constraint pfConst = new Constraint()
            {
                Name    = "PFConstraint",
                Formula = new List <string> {
                    "[CycleInputs.Position] == 4 && [Player.Height] > 205 && [Player.Height] <= 213"
                },
                FailScore = new ConstraintScore()
                {
                    Name = "FailScore", Formula = new string[] { "0" }
                },
                SuccessScore = new ConstraintScore()
                {
                    Name = "SucessScore", Formula = new string[] { "[PFMetric]" }
                }
            };

            //CENTER
            Constraint centerConst = new Constraint()
            {
                Name    = "CenterConstraint",
                Formula = new List <string> {
                    "[CycleInputs.Position] == 5 && [Player.Height] > 205"
                },
                FailScore = new ConstraintScore()
                {
                    Name = "FailScore", Formula = new string[] { "0" }
                },
                SuccessScore = new ConstraintScore()
                {
                    Name = "SucessScore", Formula = new string[] { "[CenterMetric]" }
                }
            };

            rlmOptimizer.Constraints[pgConst.Name]     = pgConst;     //PG
            rlmOptimizer.Constraints[sgConst.Name]     = sgConst;     //SG
            rlmOptimizer.Constraints[sfConst.Name]     = sfConst;     //SF
            rlmOptimizer.Constraints[pfConst.Name]     = pfConst;     //PF
            rlmOptimizer.Constraints[centerConst.Name] = centerConst; //CENTER
            #endregion

            //Cycle scoring formula
            var cyclePhase = new ScoringPhase();
            cyclePhase.Name    = "CycleScore";
            cyclePhase.Formula = new string[]
            {
                "[CycleScore] = [PGConstraint] + [SGConstraint] + [SFConstraint] + [PFConstraint] + [CenterConstraint]",
                "[SessionScore] = [SessionScore] + [CycleScore]",
            };
            rlmOptimizer.CyclePhase = cyclePhase;

            //Session scoring formula
            var sessionPhase = new ScoringPhase();
            sessionPhase.Name    = "SessionScore";
            sessionPhase.Formula = new string[]
            {
                "[SessionScore]"
            };
            rlmOptimizer.SessionPhase = sessionPhase;

            //Settings
            RlmSettings settings = new RlmSettings()
            {
                StartRandomness    = 30,
                EndRandomness      = 0,
                MaxLinearBracket   = 15,
                MinLinearBracket   = 3,
                NumOfSessionsReset = 100,
                SimulationTarget   = 500,
                NumScoreHits       = 10,
                SimulationType     = RlmSimulationType.Sessions,
                Time = new TimeSpan(0, 0, 10)
            };

            rlmOptimizer.Settings = settings;

            var resourceIn = rlmOptimizer.Resources.Where(a => a.Value.RLMObject == RLMObject.Input).First();
            rlmOptimizer.CycleInputs[resourceIn.Value.Name] = 0;

            var resourceOut = rlmOptimizer.Resources.Where(a => a.Value.RLMObject == RLMObject.Output).First();
            rlmOptimizer.CycleOutputs[resourceOut.Value.Name] = 0;

            rlmOptimizer.SessionOutputs["Player"] = new List <object> {
            };

            return(rlmOptimizer);
        }