/// <summary>
        /// Selects the best group of queries, then compares them to the appropriate label.
        /// If the query's expected reward is better than the label, it returns the query.
        /// If the label's expected reward is better, than it returns null, to indicate querying is not the recommended action.
        /// </summary>
        /// <param name="dataVector"></param>
        /// <returns></returns>
        public Query GetBestQuery(DataVector dataVector)
        {
            //Try to add new details
            if (dataVector.GetType() == typeof(DataVectorTraining))
            {
                AddMissingQueriesAndLabels((DataVectorTraining)dataVector);
            }

            //Get best queries (general)
            var bestQueriesGroup = GetAverageGroupQueries();

            //Build list of possible queries, that match datavector
            var possibleQueries = bestQueriesGroup.Where(q =>
                                                         dataVector.Features.Find(f => q.Key.Feature.Equals(f))
                                                         != null
                                                         ).ToList();

            //If no possibilities
            if (possibleQueries.Count == 0)
            {
                return(null);
            }

            //Result variable
            Query bestQueryResult = null; //Default: don't query, because the labels provide the best reward.

            #region Find best query, Version 1
            //Find best query for each label by expected reward
            List <KeyValuePair <Query, double> > bestQueries = new List <KeyValuePair <Query, double> >();

            foreach (var labelPair in Labels.ToList())
            {
                //Get label details
                FeatureValuePair theLabel = labelPair.Key;
                double           theLabelExpectedReward = labelPair.Value;

                //Filter list by label
                var bestQueriesByLabel = possibleQueries.Where(q => q.Key.Label.Equals(theLabel)).ToList();
                if (bestQueriesByLabel.Count == 0)
                {
                    continue;
                }

                //Get best query details
                var    bestQueryPair           = bestQueriesByLabel.OrderByDescending(p => p.Value).First();
                Query  bestQuery               = bestQueryPair.Key;
                double bestQueryExpectedReward = bestQueryPair.Value;

                //Is query better than label
                if (bestQueryExpectedReward > theLabelExpectedReward)
                {
                    bestQueries.Add(bestQueryPair);
                }
            }

            //Pick final answer
            if (bestQueries.Count > 0)
            {
                bestQueryResult = bestQueries.OrderByDescending(q => q.Value).First().Key;
            }
            #endregion

            #region Find best query, Version 2 -- this may work, and would be faster.
            ////Find best query pair
            //var bestQueryPair2 = possibleQueries.OrderByDescending(p => p.Value).First();
            //Query bestQuery2 = bestQueryPair2.Key;
            //double bestQuery2ExpectedReward = bestQueryPair2.Value;

            ////Find label
            //var labelPair2 = Labels.ToList().Find(p => p.Key.Equals(bestQuery2.Label));
            //Feature theLabel2 = labelPair2.Key;
            //double theLabel2ExpectedReward = labelPair2.Value;

            ////If query has higher expected reward, select it as the option.
            //Query bestQueryResult2 = null;
            //if (bestQuery2ExpectedReward > theLabel2ExpectedReward)
            //    bestQueryResult2 = bestQuery2;
            #endregion

            return(bestQueryResult);
        }
        public object Classify_ByPolicy(DataVector dataVector, bool byProbability)
        {
            //Start with root state
            State rootState = StateSpace[0]; // 0 is the hashcode for a state with no features.
            var   labels    = rootState.Labels;

            State currentState = rootState;

            while (true)
            {
                //Set current state's labels
                labels = currentState.Labels;

                //Find best query
                Query recommendedQuery = currentState.GetBestQuery(dataVector);

                //If no query, then end search. Use current labels.
                if (recommendedQuery == null)
                {
                    break;
                }

                //Search for next state
                State nextState    = null;
                int   nextHashCode = currentState.GetHashCodeWith(recommendedQuery.Feature);
                if (StateSpace.ContainsKey(nextHashCode))
                {
                    nextState = StateSpace[nextHashCode];
                }
                else
                {
                    break;
                }

                //Go to next state
                currentState = nextState;
            }

            //Select method for using the labels
            if (byProbability)
            {
                //Select best label, by percentage probabilty
                double r              = rand.NextDouble() * labels.Sum(p => p.Value); // Random value between 0 and the sum of expected rewards
                double runningTotal   = 0;
                object bestLabelValue = null;
                foreach (var label in labels.OrderBy(p => p.Value))
                {
                    runningTotal += label.Value;
                    if (r < runningTotal)
                    {
                        bestLabelValue = label.Key.Value;
                        break;
                    }
                }
                return(bestLabelValue);
            }
            else
            {
                //By highest expected reward
                return(labels.OrderByDescending(p => p.Value).First().Key.Value);
            }
        }
 public object Classify_ByTree(DataVector dataVector, bool byProbability)
 {
     return(DecisionTree.Classify(dataVector, byProbability));
 }
 /// <summary>
 /// Uses the current policy to classify a datavector and return the best classification label.
 /// </summary>
 /// <param name="dataVector"></param>
 /// <returns>Classification label</returns>
 public object Classify_ByPolicy(DataVector dataVector)
 {
     return(Classify_ByPolicy(dataVector, true));
 }
 /// <summary>
 /// Uses the resulting "DecisionTree", summarized from the policy, to quickly classify a given datavector.
 /// </summary>
 /// <param name="dataVector"></param>
 /// <returns>Classification label</returns>
 public object Classify_ByTree(DataVector dataVector)
 {
     return(DecisionTree.Classify(dataVector));
 }