/// <summary> /// Add to list of values corresponding to chain key /// If list does not exist create it /// </summary> /// <param name="key"></param> /// <param name="value"></param> public void AddToChain(ChainKey key, string value) { if (!_chains.ContainsKey(key)) { _chains.Add(key, new List <string>()); } _chains[key].Add(value); }
/// <summary> /// Add to list of values corresponding to chain key /// If list does not exist create it /// </summary> /// <param name="key"></param> /// <param name="value"></param> public void AddToChain(ChainKey key, string value) { if(!_chains.ContainsKey(key)) { _chains.Add(key, new List<string>()) ; } _chains[key].Add(value) ; }
/// <summary> /// Get copy of List of values corresponding to passed in key /// </summary> /// <param name="key"></param> /// <returns>copy of values corresponding to passed in key</returns> public List<string> GetValues(ChainKey key) { List<string> retVals ; if(!_chains.TryGetValue(key, out retVals)) { throw new Exceptions.InvalidKey("Invalid key") ; } return retVals; }
/// <summary> /// Get copy of List of values corresponding to passed in key /// </summary> /// <param name="key"></param> /// <returns>copy of values corresponding to passed in key</returns> public List <string> GetValues(ChainKey key) { List <string> retVals; if (!_chains.TryGetValue(key, out retVals)) { throw new Exceptions.InvalidKey("Invalid key"); } return(retVals); }
public void T_GetValues() { ChainMap cm = InitSimpleChainMapp() ; ChainKey keyNull = new ChainKey(new string[]{null, "word1"}) ; ChainKey key1 = new ChainKey(new string[]{"word1", "word2"}) ; ChainKey key2 = new ChainKey(new string[]{"word2", "word3"}) ; ChainKey keyIncorrect = new ChainKey(new string[]{"word2", "word1"}) ; CollectionAssert.AreEquivalent(cm.GetValues(keyNull), new List<string>{"valnull"}) ; CollectionAssert.AreEquivalent(cm.GetValues(key1), new List<string>{"val1", "val3"}) ; CollectionAssert.AreEquivalent(cm.GetValues(key2), new List<string>{"val2"}) ; Assert.Throws(typeof(Exceptions.InvalidKey), delegate { cm.GetValues(keyIncorrect);}); }
/// <summary> /// Get next word. If the next natural word does not obey given predicate, throw exception /// If we reach the end of the list get random key matching end condition passed in Reset /// </summary> /// <param name="condition"> Predicate next word must obey </param> /// <returns></returns> public string GetNextWord(Predicate <string> condition) { //If word generator has never been reset, reset with default values if (!SubchainsInitialized) { ResetSubchains(); } Predicate <string> realCondition = condition; if (realCondition == null) { realCondition = _alwaysTrueCondition.WordCondition; } ChainKey currKey = _currKey; string currWord = CurrentWord; string[] newChainKeyVals = new string[currKey.Words.Length]; for (int i = 0; i < currKey.Words.Length - 1; i++) { newChainKeyVals[i] = currKey.Words[i + 1]; } newChainKeyVals[currKey.Words.Length - 1] = currWord; currKey = new ChainKey(newChainKeyVals); List <string> potentialWords = null; try { potentialWords = _chains.GetValues(currKey); } catch (Exceptions.InvalidKey) { //if we get here that means we hit the end of the list newChainKeyVals = GetRandomKey(_onEndSubChains, ck => !ck.Equals(currKey)).Words; currKey = new ChainKey(newChainKeyVals); potentialWords = _chains.GetValues(currKey); } bool candidateFound = GetCandidate(potentialWords, condition, out currWord); if (!candidateFound) { throw new Exceptions.NoPossibleElements("Unable to find a state matching given conditions"); } _currKey = currKey; CurrentWord = currWord; return(currWord); }
/// <summary> /// Generate markov chains using input text /// </summary> public void GenerateChains() { //Split text string[] splits = _text.Split(); List <string> advancedSplits = new List <string>(); foreach (string baseSplit in splits) { advancedSplits.AddRange(StringUtils.SplitAndKeep(baseSplit.ToLower(), _delims)); } Chains = new ChainMap(); if (advancedSplits.Count < _chainSize * 2) { throw new Exceptions.InvalidArguments(string.Format("Chain size: {0} to small relative to text split {1}", _chainSize, advancedSplits.Count)); } //Insert null elements in the beginning so chains are created for the first _chainSize elements for (int i = 0; i < _chainSize; i++) { advancedSplits.Insert(0, null); } List <string> .Enumerator listEnum = advancedSplits.GetEnumerator(); string[] chainWords = new string[_chainSize]; for (int i = 0; i < _chainSize; i++) { listEnum.MoveNext(); chainWords[i] = listEnum.Current; } while (listEnum.MoveNext()) { string current = listEnum.Current; ChainKey currKey = new ChainKey(chainWords); Chains.AddToChain(currKey, current); for (int i = 0; i < _chainSize - 1; i++) { chainWords[i] = chainWords[i + 1]; } chainWords[_chainSize - 1] = current; } }
/// <summary> /// Reset using currently existing initialCondition and onEndCondition /// This should be a low cpu usage operation /// </summary> public void ResetReadOnly() { //verify if reset has never been called if (!SubchainsInitialized) { throw new Exceptions.InitializationRequired("ResetReadOnly should be called after a regular reset"); } //All chains and words should match condition so we can just get random ChainKey currKey = GetRandomKey(_initialConditionSubKeys); string currWord; GetCandidate(_initialConditionSubChains.GetValues(currKey), null, out currWord); CurrentWord = currWord; _currKey = currKey; }
public override bool Equals(object obj) { ChainKey other = obj as ChainKey; if (other == null) { return(false); } if (other.Words.Length != Words.Length) { return(false); } //Ensure all words are equal for (int i = 0; i < Words.Length; i++) { if (Words[i] != other.Words[i]) { return(false); } } return(true); }
/// <summary> /// Generate markov chains using input text /// </summary> public void GenerateChains() { //Split text string[] splits = _text.Split() ; List<string> advancedSplits = new List<string>() ; foreach(string baseSplit in splits) { advancedSplits.AddRange(StringUtils.SplitAndKeep(baseSplit.ToLower(), _delims)) ; } Chains = new ChainMap() ; if(advancedSplits.Count < _chainSize * 2) { throw new Exceptions.InvalidArguments(string.Format("Chain size: {0} to small relative to text split {1}", _chainSize, advancedSplits.Count)) ; } //Insert null elements in the beginning so chains are created for the first _chainSize elements for(int i = 0 ; i < _chainSize ; i++) { advancedSplits.Insert(0, null) ; } List<string>.Enumerator listEnum = advancedSplits.GetEnumerator() ; string[] chainWords = new string[_chainSize] ; for(int i = 0 ; i < _chainSize ; i++) { listEnum.MoveNext(); chainWords[i] = listEnum.Current ; } while(listEnum.MoveNext()) { string current = listEnum.Current; ChainKey currKey = new ChainKey(chainWords) ; Chains.AddToChain(currKey, current) ; for(int i = 0 ; i < _chainSize - 1 ; i++) { chainWords[i] = chainWords[i+1] ; } chainWords[_chainSize - 1] = current ; } }
public void T_GetRandomKey_WithParams() { WordGenerator gen = InitSimpleWordGen() ; ChainMap subMap = new ChainMap() ; ChainKey key1 = new ChainKey(new string[]{"key1", "key2", "key3"}) ; ChainKey key2 = new ChainKey(new string[]{"key1", "key2", "key4"}) ; subMap.AddToChain(key1, "val1") ; subMap.AddToChain(key2, "val2") ; bool key1Found, key2Found ; key1Found = key2Found = false ; for(int i = 0 ; i < 10 ; i++) { ChainKey currKey = gen.GetRandomKey(subMap); if(key1.Equals(currKey)) { key1Found = true ; } else if(key2.Equals(currKey)) { key2Found = true ; } else { Assert.Fail("Invalid key returned") ; } } if(!(key1Found && key2Found)) { Assert.Fail("GetRandomKey is not random") ; } }
/// <summary> /// Reset CurrentWord based on conditions /// </summary> /// <param name="keyCondition"> Condition for key of first word </param> /// <param name="onEndCondition"> Condition for new word after there are no more chains /// By default this is the same as @keyCondition </param> private void Reset(ChainCondition initialCondition, ChainCondition onEndCondition) { ChainCondition realInitialConditions = initialCondition; //Set null conditions to always true conditions to simplify our code if (realInitialConditions == null) { realInitialConditions = _alwaysTrueCondition; } else { if (realInitialConditions.KeyCondition == null) { realInitialConditions.KeyCondition = _alwaysTrueCondition.KeyCondition; } if (realInitialConditions.WordCondition == null) { realInitialConditions.WordCondition = _alwaysTrueCondition.WordCondition; } } ChainCondition realOnEndCondition = onEndCondition; //Set on end condition to start condition if it is null if (realOnEndCondition == null) { realOnEndCondition = realInitialConditions; } else { if (realOnEndCondition.KeyCondition == null) { realOnEndCondition.KeyCondition = _alwaysTrueCondition.KeyCondition; } if (realOnEndCondition.WordCondition == null) { realOnEndCondition.WordCondition = _alwaysTrueCondition.WordCondition; } } ChainMap initialConditionMap; //Only generate subchains if we need to if (realInitialConditions != _alwaysTrueCondition) { initialConditionMap = GetSubChain(realInitialConditions); } else { initialConditionMap = Chains; } ChainKey[] initialConditionSubKeys = CreateKeysArray(initialConditionMap, _alwaysTrueCondition.KeyCondition); //All chains and words should match condition so we can just get random ChainKey currKey = GetRandomKey(initialConditionSubKeys); string currWord; GetCandidate(initialConditionMap.GetValues(currKey), null, out currWord); if (realOnEndCondition != _alwaysTrueCondition) { //Verify on end map has valid elements. If no exception is thrown we are good to go _onEndSubChains = GetSubChain(realOnEndCondition); } else { _onEndSubChains = initialConditionMap; } CurrentWord = currWord; _currKey = currKey; _initialConditionSubChains = initialConditionMap; _initialConditionSubKeys = initialConditionSubKeys; _currentOnEndCondition = realOnEndCondition; SubchainsInitialized = true; }
/// <summary> /// Reset CurrentWord based on conditions /// </summary> /// <param name="keyCondition"> Condition for key of first word </param> /// <param name="onEndCondition"> Condition for new word after there are no more chains /// By default this is the same as @keyCondition </param> private void Reset(ChainCondition initialCondition, ChainCondition onEndCondition) { ChainCondition realInitialConditions = initialCondition; //Set null conditions to always true conditions to simplify our code if(realInitialConditions == null) { realInitialConditions = _alwaysTrueCondition; } else { if (realInitialConditions.KeyCondition == null) { realInitialConditions.KeyCondition = _alwaysTrueCondition.KeyCondition; } if (realInitialConditions.WordCondition == null) { realInitialConditions.WordCondition = _alwaysTrueCondition.WordCondition; } } ChainCondition realOnEndCondition = onEndCondition ; //Set on end condition to start condition if it is null if(realOnEndCondition == null) { realOnEndCondition = realInitialConditions ; } else { if (realOnEndCondition.KeyCondition == null) { realOnEndCondition.KeyCondition = _alwaysTrueCondition.KeyCondition; } if (realOnEndCondition.WordCondition == null) { realOnEndCondition.WordCondition = _alwaysTrueCondition.WordCondition; } } ChainMap initialConditionMap ; //Only generate subchains if we need to if(realInitialConditions != _alwaysTrueCondition) { initialConditionMap = GetSubChain(realInitialConditions) ; } else { initialConditionMap = Chains; } ChainKey[] initialConditionSubKeys = CreateKeysArray(initialConditionMap, _alwaysTrueCondition.KeyCondition) ; //All chains and words should match condition so we can just get random ChainKey currKey = GetRandomKey(initialConditionSubKeys) ; string currWord ; GetCandidate(initialConditionMap.GetValues(currKey), null, out currWord) ; if(realOnEndCondition != _alwaysTrueCondition) { //Verify on end map has valid elements. If no exception is thrown we are good to go _onEndSubChains = GetSubChain(realOnEndCondition) ; } else { _onEndSubChains = initialConditionMap; } CurrentWord = currWord; _currKey = currKey; _initialConditionSubChains = initialConditionMap ; _initialConditionSubKeys = initialConditionSubKeys; _currentOnEndCondition = realOnEndCondition; SubchainsInitialized = true ; }
/// <summary> /// Get a random key from passed in chain array /// </summary> /// <returns></returns> internal ChainKey GetRandomKey(ChainKey[] ckList) { return ckList[_rand.Next(ckList.Length)]; }
/// <summary> /// Reset using currently existing initialCondition and onEndCondition /// This should be a low cpu usage operation /// </summary> public void ResetReadOnly() { //verify if reset has never been called if(!SubchainsInitialized) { throw new Exceptions.InitializationRequired("ResetReadOnly should be called after a regular reset") ; } //All chains and words should match condition so we can just get random ChainKey currKey = GetRandomKey(_initialConditionSubKeys) ; string currWord ; GetCandidate(_initialConditionSubChains.GetValues(currKey), null, out currWord) ; CurrentWord = currWord; _currKey = currKey; }
/// <summary> /// Get next word. If the next natural word does not obey given predicate, throw exception /// If we reach the end of the list get random key matching end condition passed in Reset /// </summary> /// <param name="condition"> Predicate next word must obey </param> /// <returns></returns> public string GetNextWord(Predicate<string> condition) { //If word generator has never been reset, reset with default values if(!SubchainsInitialized) { ResetSubchains() ; } Predicate<string> realCondition = condition ; if(realCondition == null) { realCondition = _alwaysTrueCondition.WordCondition; } ChainKey currKey = _currKey; string currWord = CurrentWord; string[] newChainKeyVals = new string[currKey.Words.Length] ; for(int i = 0 ; i < currKey.Words.Length - 1 ; i++) { newChainKeyVals[i] = currKey.Words[i+1] ; } newChainKeyVals[currKey.Words.Length - 1] = currWord ; currKey = new ChainKey(newChainKeyVals) ; List<string> potentialWords = null ; try { potentialWords = _chains.GetValues(currKey) ; } catch(Exceptions.InvalidKey) { //if we get here that means we hit the end of the list newChainKeyVals = GetRandomKey(_onEndSubChains, ck => !ck.Equals(currKey)).Words; currKey = new ChainKey(newChainKeyVals) ; potentialWords = _chains.GetValues(currKey) ; } bool candidateFound = GetCandidate(potentialWords, condition, out currWord) ; if(!candidateFound) { throw new Exceptions.NoPossibleElements("Unable to find a state matching given conditions") ; } _currKey = currKey; CurrentWord = currWord; return currWord; }