/// <summary> /// This method can be executed several times, it returns the same if the probability has not been updated between the calls /// </summary> public void RecalculateProbForEachAnswer() { if (ProbChange != -1) { //UncertainFact provided only with ProbChange (not fixed list of probabilities) probabilitiesForEachPossibleAnswer[0] = SharedHelper.IncreaseProb(ProbVariable.RefValue.ProbOf(e => e == true), -ProbChange); probabilitiesForEachPossibleAnswer[1] = ProbVariable.RefValue.ProbOf(e => e == true).Value; //get the current value probabilitiesForEachPossibleAnswer[2] = SharedHelper.IncreaseProb(ProbVariable.RefValue.ProbOf(e => e == true), ProbChange); //UnityEngine.Debug.LogWarning("Recalculate answers probabilities for " + this.Name + ": " + probabilitiesForEachPossibleAnswer[0] + " " + probabilitiesForEachPossibleAnswer[1] + " " + probabilitiesForEachPossibleAnswer[2]); } else { SharedHelper.LogWarning("Prob change requested for " + Name + ", but this question is with fixed probabilities"); } #region debug if (probabilitiesForEachPossibleAnswer.Sum() == 0) { SharedHelper.LogError("Probabilities are all 0!!! for " + Name); } #endregion }
public bool AdjustProbVariablesDuringPlanning(int bufferedInteractionsCount) { bool regenerate = false; //1. About bot //exclude this action because there are no items for it if (ProbVariables.Bot.PrSharePureFactInfoAboutBot[(int)PV.Current].Value != 0 && KorraModelHelper.GetItemsLeftForSubCategory(ActionsEnum.SharePureFactInfoAboutBot, ItemProviders) == 0) { //adjust pure facts probabilities: disable AboutBot and boost AboutUser ProbVariables.Bot.PrSharePureFactInfoAboutBot[(int)PV.Current] = Prob(0); SharedHelper.LogWarning("Disabled all pure facts about bot, because there were no items."); //we re-inforce AboutUser so that it is stronger than Suggestion action if (ProbVariables.Bot.PrAskPureFactQuestionAboutUser[(int)PV.Current].Value > 0) { ProbVariables.Bot.PrAskPureFactQuestionAboutUser[(int)PV.Current] = ProbVariables.Bot.PrAskPureFactQuestionAboutUser[(int)PV.Increased]; } regenerate = true; } //2. About User //exclude this action because there are no items for it if (ProbVariables.Bot.PrAskPureFactQuestionAboutUser[(int)PV.Current].Value != 0 && KorraModelHelper.GetItemsLeftForSubCategory(ActionsEnum.AskPureFactQuestionAboutUser, ItemProviders) == 0) { //adjust pure facts probabilities: disable AboutUser and boost AboutBot ProbVariables.Bot.PrAskPureFactQuestionAboutUser[(int)PV.Current] = Prob(0); SharedHelper.Log("Disabled all pure facts about user, because there were no items."); //we re-inforce AboutBot so that it is stronger than Suggestion action if (ProbVariables.Bot.PrSharePureFactInfoAboutBot[(int)PV.Current].Value > 0) { ProbVariables.Bot.PrSharePureFactInfoAboutBot[(int)PV.Current] = ProbVariables.Bot.PrSharePureFactInfoAboutBot[(int)PV.Increased]; } regenerate = true; } //3. Suggestions //if there are no Pure or Uncertain facts left then we boost suggestions bool noFactsLeft = (ProbVariables.Bot.PrAskPureFactQuestionAboutUser[(int)PV.Current].Value == 0 && ProbVariables.Bot.PrSharePureFactInfoAboutBot[(int)PV.Current].Value == 0); if (noFactsLeft && ProbVariables.Bot.PrMakeSuggestion[(int)PV.Current] != ProbVariables.Bot.PrMakeSuggestion[(int)PV.Default]) { ProbVariables.Bot.PrMakeSuggestion[(int)PV.Current] = ProbVariables.Bot.PrMakeSuggestion[(int)PV.Default]; SharedHelper.Log("All pure facts used. PrMakeSuggestion changed to: " + ProbVariables.Bot.PrMakeSuggestion[(int)PV.Current]); } //Keep suggestions decreased if there are more pure facts if (!noFactsLeft && ProbVariables.Bot.PrMakeSuggestion[(int)PV.Current] != ProbVariables.Bot.PrMakeSuggestion[(int)PV.Descreased]) { SharedHelper.Log("PrMakeSuggestion changed decreased."); ProbVariables.Bot.PrMakeSuggestion[(int)PV.Current] = ProbVariables.Bot.PrMakeSuggestion[(int)PV.Descreased]; } return(regenerate); }
public bool Process(bool isPureFactUpdated, TimeSpan timeSinceStart, IKorraAIModel model) { //SharedHelper.LogWarning("Inside music trigger"); // We increase the music suggestions after a fixed amount of time if (timeSinceStart.TotalMinutes > MinutesIncreaseMusic) // && !IncreaseDistributionSuggestMusicDone) { executedCount = executedCount + 1; ProbVariables.Bot.PrSuggestListenToSong = Prob(0.35); SharedHelper.LogWarning("PrSuggestListenToSong updated to: " + ProbVariables.Bot.PrSuggestListenToSong.Value); } return(false); //no re-sampling }
//public static void SetAsPlanned(string name) //{ // for (int i = 0; i < list.Count; i++) // { // if (list[i].Name == name) // { // //UnityEngine.Debug.Log("Set to used true: " + list[i].Name); // list[i].IsPlanned = true; // return; // } // } // SharedHelper.LogError("Pure Fact Name not found in SetAsUsed!"); //} public void SetValue(string Name, string Value) { foreach (var item in items) { PureFact f = (PureFact)item; if (f.Name == Name) { SharedHelper.LogWarning("Set as answered: " + f.Name + " with value: '" + Value + "'"); f.Value = Value; f.IsAnswered = true; return; } } }
//public static PureFact GetByName(string name) //{ // foreach (var q in list) // { // if (q.Name == name) // { // return q; // } // } // SharedHelper.LogError("GetFacfByName: Pure Fact Name '" + name + "'not found"); // return null; //} //public static void RemovePlannedFlagForAllPureFacts() //{ // for (int i = 0; i < list.Count; i++) // { // list[i].IsPlanned = false; // } //} /// <summary> /// Used to delete answers that are invalid after validation: ex. age is not a valid number /// </summary> public void DropAnswer(string Name) { foreach (var item in items) { PureFact f = (PureFact)item; if (f.Name == Name) { SharedHelper.LogWarning("DropAnswer: " + f.Name); f.Value = ""; f.IsAnswered = false; f.IsUsed = false; return; } } }
public static void PrintSummary() { string result = ""; int i = 0; foreach (var key in CategoryNInter.Keys) { i++; result += "|" + key + ": " + CategoryNInter[key] + Environment.NewLine; } SharedHelper.LogWarning("Interactions statistics: " + Environment.NewLine + result); TimeSpan time = TimeSpan.FromSeconds(TimeForecast()); SharedHelper.Log("Time (hh:mm) forecast scheduled interactions will take: " + time.ToString(@"hh\:mm")); }
public Item GetItem() { Item[] q; q = items.Where(j => j.IsUsed == false && j.IsPlanned == false).ToArray(); if (q.Length > 0) { Item s = q.ElementAt(r.Next(0, q.Count())); return(s); } else { //SharedHelper.LogError("No items for category: " + example.Category + example.SubCategory); if (IsAllowedResetUsageOnEmptyCategory()) { SharedHelper.LogWarning("No items for category: " + example.Category + example.SubCategory + " have been reset. They are all set to unused now."); foreach (Item item in items) { if (item.IsUsed == true) { item.IsUsed = false; item.IsPlanned = false; } } //after adding items, choose one q = items.Where(j => j.IsUsed == false && j.IsPlanned == false).ToArray(); if (q.Length > 0) { Item s = q.ElementAt(r.Next(0, q.Count())); return(s); } } return(null); } }
public CommItem?Process(IKorraAIModel model) { #region Get Fact Manager PureFacts pfManager = (PureFacts)model.ItemProviders.SingleOrDefault(x => x is PureFacts); if (pfManager == null) { SharedHelper.LogError("No manager in Facts Manager in MoviesModelUpdateTrigger."); return(null); } #endregion var context = model.GetContext(); string text = ""; PureFact factLikesVideoGames = (PureFact)pfManager.GetByName("UserLikesVideoGames"); PureFact factThinksVideoGameIsGoodPresent = (PureFact)pfManager.GetByName("UserThinksVideoGameIsGoodPresent"); PureFact userAge = (PureFact)pfManager.GetByName("UserAge"); PureFact userSex = (PureFact)pfManager.GetByName("UserSex"); if (factLikesVideoGames == null || factThinksVideoGameIsGoodPresent == null || userAge == null || userSex == null) { SharedHelper.LogError("factJob or factWatchedMovieYesterday is NULL in MoviesModelUpdateTrigger."); } bool UserLikesVideoGamesAnswered = factLikesVideoGames.IsAnswered; bool UserThinksVideoGameIsGoodPresentAnswered = factThinksVideoGameIsGoodPresent.IsAnswered; bool userAgeAnswered = userAge.IsAnswered; bool userSexAnswered = userSex.IsAnswered; if (!UserLikesVideoGamesAnswered) { return(null); } bool UserLikesVideoGamesAnsweredYES = context.BasePhrases.IsYes(factLikesVideoGames.Value); //only if answered //Calcualte 3 differerent surprises: //1. surprise because statistically people from this sex and age like computer games //Should like Video Games, but user answered No if (userAgeAnswered && userSexAnswered && factLikesVideoGames.IsAnswered && !UserLikesVideoGamesAnsweredYES //DOES NOT LIKE VIDEO GAMES ) { int Age = Convert.ToInt32(userAge.Value); bool IsMale = userSex.Value.ToLower() == phrases.Male().ToLower(); var likesVideoGamesInferred = BernoulliF(ProbVariables.User.playsGames(Age, IsMale)); //our estimation based on Age and Sex //Threshold check if (likesVideoGamesInferred.ProbOf(e => e == true).Value > 0.8) { SharedHelper.LogWarning("VG S1 surprise inferred."); text = phrases.SurpriseVideoGames(1, false); //second parameter is not used executedCount = executedCount + 1; return(new CommItem { Category = ActionsEnum.MakeGeneralStatement, Name = "ExpressVideoGamesSurprise", TextToSay = text, FacialExpression = FaceExp.SurpriseOnStartTalking, }); } else { SharedHelper.LogWarning("No VG S1 surprise, because it is below threshold."); } } if (!UserThinksVideoGameIsGoodPresentAnswered) { return(null); } bool UserThinksVideoGameIsGoodPresentYES = context.BasePhrases.IsYes(factThinksVideoGameIsGoodPresent.Value); //only if answered //2. Surprise //Thinks games are good present - YES //Likes games in general - NO //surprise: LikesGames rendered more than 70% positive, but still answered NO by user //backward inference if (UserLikesVideoGamesAnswered && !UserLikesVideoGamesAnsweredYES && //DOES NOT LIKE VIDEO GAMES UserThinksVideoGameIsGoodPresentAnswered && UserThinksVideoGameIsGoodPresentYES //LIKES VG AS PRESENT ) { var conditionThinksVideogameIsGoodPresent = ProbVariables.User.VideoGameModel.ConditionHard(e => e.ThinksVideogameIsGoodPresent); //for this query we are not using Age and Sex, because we already know that the user LikesVideoGames (answered by the user) double probLikesGamesConditionedOnThinksGamesAreGoodPresentInferred = conditionThinksVideogameIsGoodPresent.ProbOf(e => e.LikesVideoGames).Value; SharedHelper.LogWarning("S2 probLikesGamesConditionedOnThinksGamesAreGoodPresent: " + probLikesGamesConditionedOnThinksGamesAreGoodPresentInferred); //Threshold check if (probLikesGamesConditionedOnThinksGamesAreGoodPresentInferred > 0.6) { SharedHelper.LogWarning("VG S2 surprise inferred."); bool IsLikesGamesFirstAnswered = factLikesVideoGames.LastUpdated < factThinksVideoGameIsGoodPresent.LastUpdated; text = phrases.SurpriseVideoGames(2, IsLikesGamesFirstAnswered); executedCount = executedCount + 1; return(new CommItem { Category = ActionsEnum.MakeGeneralStatement, Name = "ExpressVideoGamesSurprise", TextToSay = text, IsReactionToUser = true, FacialExpression = FaceExp.SurpriseOnStartTalking, }); } else { SharedHelper.LogWarning("No VG S2 surprise, because it is below threshold."); } } // 3. Surprise //Thinks games are a good present - NO //Likes games in general - YES //surprise: ThinkGamesGoodPresent rendered more than 70% positive, but still answered NO by user if (UserLikesVideoGamesAnswered && UserThinksVideoGameIsGoodPresentAnswered && UserLikesVideoGamesAnsweredYES && //LIKES VIDEO GAMES !UserThinksVideoGameIsGoodPresentYES) //DOES NOT LIKE VG AS PRESENT { //TODO: it should not be here, but attached to the item //THIS IS NEEDED FOR THE INFERRENCE BELOW ON: probThinksVideoGameIsGoodPresentInferred if (UserLikesVideoGamesAnsweredYES) { ProbVariables.User.LikesVideoGames = BernoulliF(Prob(0.98)); } var probThinksVideoGameIsGoodPresentInferred = ProbVariables.User.VideoGameModel.ProbOf(e => e.ThinksVideogameIsGoodPresent).Value; SharedHelper.LogWarning("S3 probThinksVideoGameIsGoodPresent: " + probThinksVideoGameIsGoodPresentInferred); //Threshold check if (probThinksVideoGameIsGoodPresentInferred >= 0.7) { SharedHelper.LogWarning("VG S3 surprise inferred."); bool IsLikesGamesFirstAnswered = factLikesVideoGames.LastUpdated < factThinksVideoGameIsGoodPresent.LastUpdated; text = phrases.SurpriseVideoGames(3, IsLikesGamesFirstAnswered); executedCount = executedCount + 1; return(new CommItem { Category = ActionsEnum.MakeGeneralStatement, Name = "ExpressVideoGamesSurprise", TextToSay = text, FacialExpression = FaceExp.SurpriseOnStartTalking, }); } else { SharedHelper.LogWarning("No VG S3 surprise, because it is below threshold."); } } return(null); }
public void ReGenerateMainSequence(ref Queue <CommItem> Interactions, ItemManager[] p_providers) { this.providers = p_providers; #region debug planned string availableItems = "Available items before sampling:\n"; foreach (var manager in providers) { availableItems += "Available items for : " + manager.ToString() + " (" + manager.AvailableItems() + ")\n"; if (!manager.AreAllUnPlanned()) { SharedHelper.LogError("Flag planned not removed for: " + manager.ToString()); } } if ((JokesProvider.GetAll().Where(x => x.IsPlanned == false)).Count() != JokesProvider.GetAll().Count()) { SharedHelper.LogError("Flag planned not removed for: JokeProvider "); } int availableJokes = JokesProvider.GetAll().Where(x => x.IsPlanned == false && x.IsUsed == false).Count(); availableItems += "Available items for : " + "JokeProvider" + " (" + availableJokes + ")\n"; SharedHelper.LogWarning(availableItems); #endregion PureFacts pfManager = (PureFacts)providers.SingleOrDefault(x => x is PureFacts); if (pfManager == null) { SharedHelper.LogError("No PureFact manager in ReGenerateMainSequence."); } //Creates a distribution over "EasilyOffended", IsRomanticJoke dists.InitJokesDistribution((PureFact)pfManager.GetByName("EasilyOffended"), false, true); //Interactions are built newely generated suggestions and actions allSuggestions = GenerateSuggestions(); allActions = GenerateActions(); while (allActions.Count > 0 && allSuggestions.Count > 0) { if (this.AdjFunc(Interactions.Count)) { allActions = GenerateActions(); } //================================================================================================== CommItem citem = new CommItem(); citem.Category = allActions.Dequeue(); //SharedHelper.Log("action: " + action); string suggestion = ""; if (citem.Category == ActionsEnum.MakeSuggestion) { suggestion = allSuggestions.Dequeue(); } citem.SubCategory = suggestion; //Correction if (citem.Category == ActionsEnum.AskPureFactQuestionAboutUser) { citem.Category = ActionsEnum.PureFact; citem.SubCategory = ActionsEnum.AskPureFactQuestionAboutUser; } if (citem.Category == ActionsEnum.SharePureFactInfoAboutBot) { citem.Category = ActionsEnum.PureFact; citem.SubCategory = ActionsEnum.SharePureFactInfoAboutBot; } #region Process All ItemManager manager = providers.SingleOrDefault(x => x.Is(citem)); if (manager != null && !(manager is PureFacts)) //TODO: to be improved { Item item = manager.GetItem(); if (item != null) { manager.SetAsPlanned(item.Name); citem = new CommItem(item); if (manager is SongsProvider) { citem.TextToSay = ((Song)item).Name; } if (manager is MoviesProvider) { citem.TextToSay = phrases.MovieAnnouncement((Movie)item); } //if (manager is SportsProvider) // SharedHelper.Log("Sport item added in Joi sampler: " + citem.TextToSay); InteractionsStat.AddScheduledInteraction(citem.Category + citem.SubCategory); //SharedHelper.LogWarning("Added " + citem.Category + citem.SubCategory + " with text: " + citem.TextToSay); } else { InteractionsStat.AddMissingInteraction(citem.Category + citem.SubCategory); SharedHelper.LogWarning("Not enough " + citem.Category + citem.SubCategory + " during planning."); } } #endregion else { #region Set Suggestion if (citem.Category == ActionsEnum.MakeSuggestion) { //string suggestion = allSuggestions.Dequeue(); //SharedHelper.Log("suggestion: " + suggestion); #region set joke if (suggestion == SuggestionsEnum.TellJoke) { //the fact that joke has bee planned, does not mean it has been executed Joke joke = dists.NextJoke(); if (joke != null) { citem = new CommItem(joke); //Planned is handled by "dists" //It gives a distribution from all unplanned and unused JokesProvider.SetJokeAsPlanned(joke.Name); //joke.IsPlanned = true; //citem.Name = joke.Name; //citem.TextToSay = joke.Text; //citem.SubCategory = suggestion; citem.IsJokePureFact = joke.IsPureFact; //these jokes come from the PureFacts collection citem.UIAnswer = joke.PureFactUI; citem.FacialExpression = joke.FaceExpression; InteractionsStat.AddScheduledInteraction(SuggestionsEnum.TellJoke); } else { citem.TextToSay = "__nointeraction__"; //UnityEngine.Debug.LogWarning("Not enough jokes during planning."); InteractionsStat.AddMissingInteraction(SuggestionsEnum.TellJoke); } } #endregion #region set Go Out if (suggestion == SuggestionsEnum.GoOut) { citem.TextToSay = phrases.GoOutAnnoucement(); InteractionsStat.AddScheduledInteraction(SuggestionsEnum.GoOut); } #endregion //#region set Watch movie //if (suggestion == SuggestionsEnum.WatchMovie) //{ // Movie movie = MoviesProvider.Get(); // if (movie != null) // { // movie.IsPlanned = true; // //citem.Name = movie.Name; // //citem.TextToSay = phrases.MovieAnnouncement(movie); // citem = new CommItem(movie); // //UnityEngine.Debug.LogWarning("Movie scheduled: " + citem.TextToSay); // InteractionsStat.AddScheduledInteraction(SuggestionsEnum.WatchMovie); // } // else // { // citem.TextToSay = "__nointeraction__"; // SharedHelper.LogWarning("Not enough movies during planning."); // InteractionsStat.AddMissingInteraction(SuggestionsEnum.WatchMovie); // } //} //#endregion #region set Weather forecast if (suggestion == SuggestionsEnum.TellWeatherForecast) { citem.TextToSay = "The weather forecast should be good."; //TODO not translated } #endregion //#region set Song //if (suggestion == SuggestionsEnum.ListenToSong) //{ // //the fact that song has bee planned, does not mean it has been executed // Song song = SongsProvider.GetSong(); // if (song != null) // { // song.IsPlanned = true; // citem.Name = song.Name; // citem.TextToSay = song.Name; // InteractionsStat.AddScheduledInteraction(SuggestionsEnum.ListenToSong); // } // else // { // citem.TextToSay = "__nointeraction__"; // SharedHelper.LogWarning("Not enough songs during planning."); // InteractionsStat.AddMissingInteraction(SuggestionsEnum.ListenToSong); // } //} //#endregion //else //#region set Go to gym //if (suggestion == SuggestionsEnum.DoSport) //{ // ItemManager manager = providers.Single(x => x.Is(citem)); // if (manager == null) SharedHelper.LogWarning("Manager is null"); // Sport sport = (Sport)manager.GetItem(); // if (sport != null) // { // manager.SetAsPlanned(sport.Name); // citem = new CommItem(sport); // InteractionsStat.AddScheduledInteraction(SuggestionsEnum.DoSport); // } // else // { // citem.TextToSay = "__nointeraction__"; // SharedHelper.LogWarning("Not enough sports during planning."); // InteractionsStat.AddMissingInteraction(SuggestionsEnum.DoSport); // } //} //#endregion } //end action suggestions #endregion else if (citem.Category == ActionsEnum.AskUncertanFactQuestion) { //the actual question is selected at run time citem.TextToSay = "###place holder for UncertanFactQuestion"; citem.IsPureFact = false; InteractionsStat.AddScheduledInteraction(ActionsEnum.AskUncertanFactQuestion); } else if (citem.SubCategory == ActionsEnum.AskPureFactQuestionAboutUser) //ABOUT USER { int pfabul = PureFactsAboutUserLeftCount(); if (pfabul > 0) { PureFact sf = pfManager.GetPureFactAbouUser(); if (sf == null) { SharedHelper.LogError("There are pure facts about the user left, but no pure fact has been selected."); } else { citem.TextToSay = sf.Question; //SharedHelper.Log("q name: " + q [0].Name); citem.Name = sf.Name; citem.IsPureFact = true; pfManager.SetAsPlanned(sf.Name); citem.UIAnswer = sf.UI; } InteractionsStat.AddScheduledInteraction(citem.Category + citem.SubCategory); } else { InteractionsStat.AddMissingInteraction(citem.Category + citem.SubCategory); } } else if (citem.SubCategory == ActionsEnum.SharePureFactInfoAboutBot) //ABOUT BOT { int pfabbl = PureFactsAboutBotLeftCount(); if (pfabbl > 0) { PureFact sf = GetPureFactAbouBot(); if (sf == null) { SharedHelper.LogError("There are pure facts about the bot left, but no pure fact has been selected."); } else { //SharedHelper.Log("Found " + Actions.SharePureFactInfoAboutBot + ": " + q.Length.ToString()); citem.TextToSay = sf.Acknowledgement; citem.IsPureFact = true; citem.Name = sf.Name; pfManager.SetAsPlanned(sf.Name); } InteractionsStat.AddScheduledInteraction(citem.Category + citem.SubCategory); } else { InteractionsStat.AddMissingInteraction(citem.Category + citem.SubCategory); } } else if (citem.Category == ActionsEnum.ChangeVisualAppearance) { citem.TextToSay = context.BasePhrases.ChangeClothesAnnouncement(); InteractionsStat.AddScheduledInteraction(ActionsEnum.ChangeVisualAppearance); } else if (citem.Category == ActionsEnum.ExpressMentalState) { //choose mental state to share using a distribution (uniform?) //currently only one state is processed string selectedMentalState = "InAGoodMood"; if (selectedMentalState == "InAGoodMood") { //Take into account the: ProbVariables.Bot.InAGoodMood; //class Statement where the constructor takes prob variable as or UncertainFact //or just phrase that internally takes into account current values of the prob variable and other normal variables citem.TextToSay = "###place holder for InAGoodMood"; } InteractionsStat.AddScheduledInteraction(ActionsEnum.ExpressMentalState); } else { SharedHelper.LogError("Unknown action: " + citem.Category); } } #region Add interaction item to queue if (string.IsNullOrEmpty(citem.TextToSay)) { SharedHelper.LogError("Text is empty! Action was: " + citem.Category + "|" + citem.SubCategory); } else { Interactions.Enqueue(citem); } #endregion #region debug PureFact[] LeftPureFacts = (from item in pfManager.GetAll() let pf = (PureFact)item where (pf.Type == PureFactType.AboutBot || pf.Type != PureFactType.AboutUser) && pf.IsPlanned == false && pf.IsUsed == false select pf).ToArray(); //if (!Flags.DecreaseDistributionOfAskPureFactQuestionAboutUserDone && Interactions.Count > 45 && (LeftPureFacts.Length - PersistentData.PureFactsLoadedOnStartup()) > 0) // KorraBaseHelper.LogError("All pure facts should have been already planned. Left not used pure facts: " + LeftPureFacts.Length); #endregion } }