From e212edb8084adfc6a08aa1de9e70bd8eb1fcd42b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Slabber?= Date: Wed, 8 Jul 2026 08:33:00 +0200 Subject: [PATCH 1/9] Various fixes for problems identified by Grok This fork contains the first set of fixes to BrainSimThought code for errors that were found by Grok --- BrainSimMAC/BrainSimMACMain.cs | 21 +- BrainSimulator/BrainSim Thought.csproj | 22 +- BrainSimulator/GlobalUsings.cs | 1 + BrainSimulator/MainWindowFiles.cs | 4 +- BrainSimulator/ModuleHandler.cs | 14 +- BrainSimulator/ModuleViewMenu.cs | 32 +- .../Modules/Agents/ModuleAttributeBubble.cs | 15 +- ...lg.xml.cs => ModuleBalanceTreeDlg.xaml.cs} | 2 +- BrainSimulator/Modules/ModuleGPTInfo.cs | 2 + BrainSimulator/Modules/ModuleLearnMelody.cs | 16 +- BrainSimulator/Modules/ModuleOnlineInfo.cs | 186 +- .../Modules/ModuleUKSQueryDlg.xaml.cs | 3 +- .../Vision/ModuleMentalModelDlg.xaml.cs | 5 +- BrainSimulator/Modules/Vision/ModuleVision.cs | 4 +- .../Modules/Vision/ModuleVisionDlg.xaml.cs | 6 +- BrainSimulator/Modules/Vision/README.md | 12 + BrainSimulator/Network.cs | 14 +- BrainSimulator/Resources/wordlist.txt | 30 + BrainSimulator/UKSContent/NatureAnimals.xml | 1995 +++++++++++++++++ BrainSimulator/Utils.cs | 23 +- .../archive/legacy/MainWindowPythonModules.cs | 173 ++ BrainSimulator/archive/legacy/README.md | 10 + .../{ => archive/legacy}/XmlFile.cs | 0 PythonProj/MainWindow.py | 28 +- PythonProj/module_uks_tree.py | 8 +- PythonProj/utils.py | 29 +- Tests/ModuleAlgorithm.Tests.cs | 2 +- Tests/NatureAnimalsXmlTests.cs | 87 + Tests/NonUksP0FixesRegressionTests.cs | 38 + Tests/NonUksP1FixesRegressionTests.cs | 39 + Tests/NonUksP2FixesRegressionTests.cs | 52 + Tests/NonUksRemainingFixesRegressionTests.cs | 56 + Tests/UKSFixesRegressionTests.cs | 117 + Tests/VisionCompatRegressionTests.cs | 52 + ...xtensiion.cs => IReadOnlyListExtension.cs} | 0 UKS/Relationship.cs | 33 + UKS/Thought.BrainSim3Compat.cs | 104 + UKS/Thought.cs | 76 +- UKS/UKS .Initialize.cs | 2 +- UKS/UKS.BrainSim3Compat.cs | 102 + UKS/UKS.Exclusivity.cs | 8 +- UKS/UKS.Sequence.cs | 33 +- UKS/UKS.Statement.cs | 45 +- UKS/UKS.TextFile.cs | 31 +- UKS/UKS.XMLFile.cs | 31 +- tools/generate_nature_animals_xml.py | 359 +++ 46 files changed, 3636 insertions(+), 286 deletions(-) create mode 100644 BrainSimulator/GlobalUsings.cs rename BrainSimulator/Modules/Agents/{ModuleBalanceTreeDlg.xml.cs => ModuleBalanceTreeDlg.xaml.cs} (99%) create mode 100644 BrainSimulator/Modules/Vision/README.md create mode 100644 BrainSimulator/Resources/wordlist.txt create mode 100644 BrainSimulator/UKSContent/NatureAnimals.xml create mode 100644 BrainSimulator/archive/legacy/MainWindowPythonModules.cs create mode 100644 BrainSimulator/archive/legacy/README.md rename BrainSimulator/{ => archive/legacy}/XmlFile.cs (100%) create mode 100644 Tests/NatureAnimalsXmlTests.cs create mode 100644 Tests/NonUksP0FixesRegressionTests.cs create mode 100644 Tests/NonUksP1FixesRegressionTests.cs create mode 100644 Tests/NonUksP2FixesRegressionTests.cs create mode 100644 Tests/NonUksRemainingFixesRegressionTests.cs create mode 100644 Tests/UKSFixesRegressionTests.cs create mode 100644 Tests/VisionCompatRegressionTests.cs rename UKS/{IReadOnlyListExtensiion.cs => IReadOnlyListExtension.cs} (100%) create mode 100644 UKS/Relationship.cs create mode 100644 UKS/Thought.BrainSim3Compat.cs create mode 100644 UKS/UKS.BrainSim3Compat.cs create mode 100644 tools/generate_nature_animals_xml.py diff --git a/BrainSimMAC/BrainSimMACMain.cs b/BrainSimMAC/BrainSimMACMain.cs index f7f1655..0d3d04e 100644 --- a/BrainSimMAC/BrainSimMACMain.cs +++ b/BrainSimMAC/BrainSimMACMain.cs @@ -5,12 +5,13 @@ * * This file is part of Brain Simulator Thought and is licensed under * the MIT License. You may use, copy, modify, merge, publish, distribute, - * sublicense, and/or sell copies of this software under the terms of + * sublicense, and/or sell copies of the software under the terms of * the MIT License. * * See the LICENSE file in the project root for full license information. */ using BrainSimulator; +using System.Diagnostics; using UKS; @@ -67,15 +68,22 @@ //force the MainWindow to always be activated moduleHandler.ActivateModule("MainWindow.py"); +const int loopDelayMs = 50; while (true) { + activeModulesRoot = moduleHandler.theUKS.Labeled("ActiveModule"); + if (activeModulesRoot is null) + { + Thread.Sleep(loopDelayMs); + continue; + } + foreach (var module in activeModulesRoot.Children) { if (module.Label.Contains(".py")) moduleHandler.RunScript(module.Label); } - activeModulesRoot = moduleHandler.theUKS.Labeled("ActiveModule"); for (int i = 0; i < moduleHandler.activePythonModules.Count; i++) { @@ -88,7 +96,12 @@ moduleHandler.activePythonModules.RemoveAt(i); i--; } - catch { } + catch (Exception ex) + { + Debug.WriteLine($"BrainSimMAC: Close failed for {module.Item1}: {ex.Message}"); + } } } -} + + Thread.Sleep(loopDelayMs); +} \ No newline at end of file diff --git a/BrainSimulator/BrainSim Thought.csproj b/BrainSimulator/BrainSim Thought.csproj index 94e72b8..676960f 100644 --- a/BrainSimulator/BrainSim Thought.csproj +++ b/BrainSimulator/BrainSim Thought.csproj @@ -25,9 +25,10 @@ preview + - + @@ -49,7 +50,11 @@ - + + + + + @@ -74,6 +79,7 @@ + @@ -123,6 +129,11 @@ PreserveNewest + + + PreserveNewest + + PreserveNewest @@ -131,11 +142,6 @@ PreserveNewest - - - - - - + \ No newline at end of file diff --git a/BrainSimulator/GlobalUsings.cs b/BrainSimulator/GlobalUsings.cs new file mode 100644 index 0000000..c48ada4 --- /dev/null +++ b/BrainSimulator/GlobalUsings.cs @@ -0,0 +1 @@ +global using Thing = UKS.Thought; \ No newline at end of file diff --git a/BrainSimulator/MainWindowFiles.cs b/BrainSimulator/MainWindowFiles.cs index 4e7b79a..50aea99 100644 --- a/BrainSimulator/MainWindowFiles.cs +++ b/BrainSimulator/MainWindowFiles.cs @@ -63,10 +63,10 @@ public void ReloadActiveModulesSP() ActiveModuleSP.Children.Clear(); Thought activeModuleParent = theUKS.Labeled("ActiveModule"); + if (activeModuleParent is null) { return; } + //TODO: Remove activeModuleParent.AddParent("BrainSim"); - - if (activeModuleParent is null) { return; } var activeModules1 = activeModuleParent.Children; activeModules1 = activeModules1.OrderBy(x => x.Label).ToList(); diff --git a/BrainSimulator/ModuleHandler.cs b/BrainSimulator/ModuleHandler.cs index f0cf3ef..7585b94 100644 --- a/BrainSimulator/ModuleHandler.cs +++ b/BrainSimulator/ModuleHandler.cs @@ -69,14 +69,7 @@ public void DeactivateModule(string moduleLabel) { Thought t = theUKS.Labeled(moduleLabel); if (t is null) return; - for (int i = 0; i < t.LinksTo.Count; i++) - { - Link r = t.LinksTo[i]; - r.To.Delete(); - } t.Delete(); - - return; } @@ -141,7 +134,7 @@ public void Close(string moduleLabel) { theModuleEntry.Item2.Close(); } - catch { } + catch (Exception ex) { Debug.WriteLine($"Python Close failed for {theModuleEntry.Item1}: {ex.Message}"); } } } } @@ -221,9 +214,10 @@ public void RunScript(string moduleLabel) catch (Exception ex) { activePythonModules.Remove(theModuleEntry); - DeactivateModule(moduleLabel); #if !CONSOLE_APP - MainWindow.theWindow.ReloadActiveModulesSP(); + MainWindow.theWindow?.DeactivateModule(moduleLabel); +#else + DeactivateModule(moduleLabel); #endif Console.WriteLine("Fire method call failed for module: " + moduleLabel + " Reason: " + ex.Message); } diff --git a/BrainSimulator/ModuleViewMenu.cs b/BrainSimulator/ModuleViewMenu.cs index 20ded0d..5103beb 100644 --- a/BrainSimulator/ModuleViewMenu.cs +++ b/BrainSimulator/ModuleViewMenu.cs @@ -100,17 +100,16 @@ private void Mi_Click(object sender, RoutedEventArgs e) if ((string)mi.Header == "View Dialog Source") theModuleType += "Dlg.xaml"; - string cwd = System.IO.Directory.GetCurrentDirectory(); - if (cwd.Contains("bin\\")) - cwd = cwd.ToLower().Substring(0, cwd.IndexOf("bin\\")); - string fileName = cwd + @"modules\" + theModuleType + ".cs"; + string cwd = Directory.GetCurrentDirectory(); + string binSegment = "bin" + Path.DirectorySeparatorChar; + int binIndex = cwd.IndexOf(binSegment, StringComparison.OrdinalIgnoreCase); + if (binIndex >= 0) + cwd = cwd.Substring(0, binIndex); + string fileName = Path.Combine(cwd, "modules", theModuleType + ".cs"); + if (!File.Exists(fileName)) + fileName = Path.Combine(cwd, "BrainSim2modules", theModuleType + ".cs"); if (File.Exists(fileName)) OpenSource(fileName); - else - { - fileName = cwd + @"BrainSim2modules\" + theModuleType + ".cs"; - OpenSource(fileName); - } } if ((string)mi.Header == "Delete") { @@ -176,5 +175,20 @@ public void DeleteModule(string moduleName) ReloadActiveModulesSP(); } + + public void DeactivateModule(string moduleLabel) + { + ModuleBase mb = activeModules.FindFirst(x => x.Label == moduleLabel); + if (mb is not null) + { + mb.CloseDlg(); + mb.Closing(); + activeModules.Remove(mb); + } + pythonModules.Remove(moduleLabel); + moduleHandler.pythonModules.Remove(moduleLabel); + moduleHandler.DeactivateModule(moduleLabel); + ReloadActiveModulesSP(); + } } } diff --git a/BrainSimulator/Modules/Agents/ModuleAttributeBubble.cs b/BrainSimulator/Modules/Agents/ModuleAttributeBubble.cs index d0f782b..c293f63 100644 --- a/BrainSimulator/Modules/Agents/ModuleAttributeBubble.cs +++ b/BrainSimulator/Modules/Agents/ModuleAttributeBubble.cs @@ -155,15 +155,16 @@ void BubbleChildAttributes(Thought t) } - //calculate the new weight - //If there is an existing weight, it is increased/decreased by a small amound and removed if it drops below .5 - //If there is no existing weight, it is assumed to start at 0.5. - //TODO, replace this hardcoded "lookup table" with a formula + // Weight delta ladder: maps (positiveWeight - negativeWeight) to a small adjustment. + // Thresholds tuned empirically; initial weight defaults to 0.5 when absent; links below 0.5 are removed. float targetWeight = 0; float deltaWeight = positiveWeight - negativeWeight; - if (deltaWeight < .8) targetWeight = -.1f; - else if (deltaWeight < 1.7) targetWeight = .01f; - else if (deltaWeight < 2.7) targetWeight = .2f; + const float weakDeltaThreshold = 0.8f; + const float moderateDeltaThreshold = 1.7f; + const float strongDeltaThreshold = 2.7f; + if (deltaWeight < weakDeltaThreshold) targetWeight = -.1f; + else if (deltaWeight < moderateDeltaThreshold) targetWeight = .01f; + else if (deltaWeight < strongDeltaThreshold) targetWeight = .2f; else targetWeight = .3f; if (currentWeight == 0) currentWeight = 0.5f; float newWeight = currentWeight + targetWeight; diff --git a/BrainSimulator/Modules/Agents/ModuleBalanceTreeDlg.xml.cs b/BrainSimulator/Modules/Agents/ModuleBalanceTreeDlg.xaml.cs similarity index 99% rename from BrainSimulator/Modules/Agents/ModuleBalanceTreeDlg.xml.cs rename to BrainSimulator/Modules/Agents/ModuleBalanceTreeDlg.xaml.cs index ac8a5c1..8dbeb30 100644 --- a/BrainSimulator/Modules/Agents/ModuleBalanceTreeDlg.xml.cs +++ b/BrainSimulator/Modules/Agents/ModuleBalanceTreeDlg.xaml.cs @@ -56,4 +56,4 @@ private void Enable_Checked(object sender, RoutedEventArgs e) } } } -} +} \ No newline at end of file diff --git a/BrainSimulator/Modules/ModuleGPTInfo.cs b/BrainSimulator/Modules/ModuleGPTInfo.cs index c7bc2fa..01ff081 100644 --- a/BrainSimulator/Modules/ModuleGPTInfo.cs +++ b/BrainSimulator/Modules/ModuleGPTInfo.cs @@ -123,6 +123,8 @@ public static async Task GetChatGPTVerifyParentChild(string child,string parent) //this turns dotted names back into more english-language strings private static string GetStringFromThoughtLabel(string thoughtLabel) { + if (string.IsNullOrEmpty(thoughtLabel)) + return ""; string theString = thoughtLabel.ToLower(); if (theString[0] == '.') theString = theString.Substring(1); string[] s = theString.Split('.'); diff --git a/BrainSimulator/Modules/ModuleLearnMelody.cs b/BrainSimulator/Modules/ModuleLearnMelody.cs index d95b028..e9db041 100644 --- a/BrainSimulator/Modules/ModuleLearnMelody.cs +++ b/BrainSimulator/Modules/ModuleLearnMelody.cs @@ -119,7 +119,7 @@ private void ProcessMelodyEntry(MelodyEntry entry) SeqElement seq2 = CreatePhraseFromNotes("temp*", entry.ResponsePhrase.Notes); foreach (Thought t in theUKS.Labeled("possibleAction").Children) { - SeqElement seq3 = GetTargetOfFirstLinkOfType(t, "soundAs"); + SeqElement seq3 = t.GetTargetOfFirstLinkOfType("soundAs") as SeqElement; var val = theUKS.CompareSequences(seq2, seq3); if (val == 1) { @@ -151,20 +151,6 @@ public bool ResponseHandled (Thought theResponse) return true; } - //TODO Move to UKS - public SeqElement GetTargetOfFirstLinkOfType(Thought thePhrase, string v) - { - foreach (var link in thePhrase.LinksTo) - { - if (link.LinkType.Label == v && link.To is SeqElement seq) - { - return seq; - } - } - return null; - } - - // Randomize the melody lines private void RandomizeMelodies() { diff --git a/BrainSimulator/Modules/ModuleOnlineInfo.cs b/BrainSimulator/Modules/ModuleOnlineInfo.cs index 8895fb1..a0a7924 100644 --- a/BrainSimulator/Modules/ModuleOnlineInfo.cs +++ b/BrainSimulator/Modules/ModuleOnlineInfo.cs @@ -24,6 +24,7 @@ using System.Text; using System.Text.Json; using System.Text.RegularExpressions; +using System.Threading.Tasks; using System.Xml; using System.Linq; using Pluralize.NET; @@ -70,10 +71,11 @@ public override void Fire() if (wordsToLookUp.Count > 0) { - string word = wordsToLookUp[0].Item1; - int mostUsed = wordsToLookUp.FindIndex(t => t.Item2 == wordsToLookUp.Max(t => t.Item2)); - var x = wordsToLookUp[0]; - wordsToLookUp.RemoveAt(0); + int maxUse = wordsToLookUp.Max(t => t.Item2); + int mostUsed = wordsToLookUp.FindIndex(t => t.Item2 == maxUse); + if (mostUsed < 0) mostUsed = 0; + var x = wordsToLookUp[mostUsed]; + wordsToLookUp.RemoveAt(mostUsed); ConceptNetLocal(x.Item1); } @@ -473,29 +475,9 @@ private static void GetValueFromURI(ref string URI, ref string partOfSpeech) URI = URI.Substring(URI.LastIndexOf("/") + 1); } - public async void GetConceptNetData(string text) + public void GetConceptNetData(string text) { ConceptNetLocal(text); - return; - var url = @"https://api.conceptnet.io/c/en/" + text; - var myClient = new HttpClient(); - var responseURL = await myClient.GetAsync(url); - var propertyURL = await responseURL.Content.ReadAsStringAsync(); - Root myDeserializedClass = JsonConvert.DeserializeObject(propertyURL); - Output = ""; - foreach (var edge in myDeserializedClass.edges) - { - if (edge.start.language != "en") continue; - if (edge.end.language != "en") continue; - string start = GetTailOfURL(edge.start.term); - string end = GetTailOfURL(edge.end.term); - string rel = edge.rel.label; - if (rel == "IsA") - Output += start + "->is-a-> " + end + " " + edge.surfaceText + " " + edge.weight.ToString("f3") + "\n"; - else - Output += start + "->" + rel + "-> " + end + " " + edge.surfaceText + " " + edge.weight.ToString("f3") + "\n"; - } - return; } string GetTailOfURL(string url) { @@ -506,22 +488,45 @@ string GetTailOfURL(string url) List<(string, string)> wordList2 = new(); List wordList = new List(); + private static string ResolveWordListPath() + { + var candidates = new List(); + string envPath = Environment.GetEnvironmentVariable("WORDLIST_PATH"); + if (!string.IsNullOrWhiteSpace(envPath)) + candidates.Add(envPath); + candidates.Add(Path.Combine(AppContext.BaseDirectory, "Resources", "wordlist.txt")); + candidates.Add(Path.Combine(Directory.GetCurrentDirectory(), "Resources", "wordlist.txt")); + candidates.Add(Path.Combine(Directory.GetCurrentDirectory(), "wordlist.txt")); + + foreach (string path in candidates) + { + if (!string.IsNullOrWhiteSpace(path) && File.Exists(path)) + return path; + } + return null; + } + private void SetupWordList() { wordList = new(); + string wordListPath = ResolveWordListPath(); + if (wordListPath is null) + { + Debug.WriteLine("SetupWordList: no wordlist found. Set WORDLIST_PATH or deploy Resources/wordlist.txt"); + return; + } try { - - // also a possible resource Vocabulary.com - - // common words.pdf - ///https://cehs.unl.edu/documents/secd/aac/vocablists/VLN1.pdf - string wordListPath = @"C:\Users\c_sim\source\wordlist.txt"; using (StreamReader reader = new StreamReader(wordListPath)) { string line = reader.ReadLine(); while (line is not null) { + if (line.TrimStart().StartsWith("#")) + { + line = reader.ReadLine(); + continue; + } line = line.Replace("\t", " "); string[] words = line.Split(" "); foreach (string s in words) @@ -601,7 +606,7 @@ public void SetupWordList2(string wordIn = "") word = word.Replace(",", ""); word = word.Replace("\t", " "); word = word.Replace("-", ""); - word = word.Replace("’", ""); + word = word.Replace("�", ""); word = word.ToLower(); word = RemoveParentheticals(word); //word = Thought.TrimDigits(word.Trim()); @@ -649,20 +654,24 @@ public void SetupWordList2(string wordIn = "") } } - //TODO: properly handle phrases, related, similar...currently only picks up first instance - public class KidsWord { public string word; public List definitions = new(); - public string related; - public string similar; - public string phrase; + public List related = new(); + public List similar = new(); + public List phrases = new(); public override string ToString() { string retVal = word + "\n"; foreach (var def in definitions) retVal += def.definition + "\n"; + if (phrases.Count > 0) + retVal += "phrases: " + string.Join(", ", phrases) + "\n"; + if (similar.Count > 0) + retVal += "similar: " + string.Join(", ", similar) + "\n"; + if (related.Count > 0) + retVal += "related: " + string.Join(", ", related) + "\n"; return retVal; } } @@ -695,7 +704,7 @@ public void GetKidsDefinition(string text) return; } - public async void GetKidsWordsmythNet(string text) + public async Task GetKidsWordsmythNet(string text) { var client = new HttpClient(); var response = await client.GetAsync($"https://kids.wordsmyth.net/we/?ent={text}"); @@ -756,13 +765,10 @@ int GetDefinition(int index) Thought incomingInfo = theUKS.GetOrAddThought("CurrentIncomingInfo", "Attention"); incomingInfo.V = kidsdef; + CollectStringValues(htmlContent, "phrase:", kidsdef.phrases, posSearch, "<"); + CollectStringValues(htmlContent, "similar words:", kidsdef.similar, posSearch, "<"); + CollectStringValues(htmlContent, "related words:", kidsdef.related, posSearch, "<"); int index = 0; - kidsdef.phrase = GetStringValue(htmlContent, "phrase:", ref index, posSearch, "<"); - index = 0; - kidsdef.similar = GetStringValue(htmlContent, "similar words:", ref index, posSearch, "<"); - index = 0; - kidsdef.related = GetStringValue(htmlContent, "related words:", ref index, posSearch, "<"); - index = 0; string retString = ""; index = 0; do @@ -789,6 +795,31 @@ string GetStringValue(string content, string target, ref int startIndex, string return retVal; } + private static void CollectStringValues(string content, string target, List dest, string startTag, string endTag) + { + int index = 0; + string val; + while ((val = GetStringValueStatic(content, target, ref index, startTag, endTag)) != "") + { + if (!dest.Contains(val)) + dest.Add(val); + } + } + + private static string GetStringValueStatic(string content, string target, ref int startIndex, string startTag, string endTag) + { + int i1 = content.IndexOf(target, startIndex); + if (i1 == -1) return ""; + i1 = content.IndexOf(startTag, i1); + if (i1 == -1) return ""; + i1 += startTag.Length; + int i2 = content.IndexOf(endTag, i1); + if (i2 == -1) return ""; + string retVal = content.Substring(i1, i2 - i1); + startIndex = i2; + return retVal; + } + public List FindAllIndices(string str, string substr) { var indices = new List(); @@ -803,7 +834,7 @@ public List FindAllIndices(string str, string substr) return indices; } - public async void GetWiktionaryData(string textIn) + public async Task GetWiktionaryData(string textIn) { var word = textIn; // the word to look up @@ -838,7 +869,7 @@ public async void GetWiktionaryData(string textIn) } public enum QueryType { general, isa, hasa, can, count, list, listCount, types, partsOf }; - public async void GetChatGPTResult(string textIn, QueryType qtIn = QueryType.isa, string altLabel = "") + public async Task GetChatGPTResult(string textIn, QueryType qtIn = QueryType.isa, string altLabel = "") { try { @@ -930,9 +961,10 @@ string PluralizePhrase(string input) //This method rerieves the wikidata query number value from wikidata query // for the Thought item and passes that value to GetPropertiesFromURL along // with the property query named prop - public async void GetWikidataData(string item, string prop) + public async Task GetWikidataData(string item, string prop) { var itemLabel = item; + bool handedOff = false; try { Network.httpClientBusy = true; @@ -941,32 +973,45 @@ public async void GetWikidataData(string item, string prop) "&language=en&format=xml"; var response = await Network.theHttpClient.GetAsync(url); - if (response is not null) + if (response is null || !response.IsSuccessStatusCode) + return; + + string xmlContent = await response.Content.ReadAsStringAsync(); + XmlDocument xmlItemDoc = new XmlDocument(); + xmlItemDoc.LoadXml(xmlContent); + var xmlItemDocValue = xmlItemDoc.GetElementsByTagName("entity"); + if (xmlItemDocValue.Count == 0) { - var content = response.Content.ReadAsStringAsync(); - XmlDocument xmlItemDoc = new XmlDocument(); - xmlItemDoc.LoadXml(content.Result.ToString()); - var xmlItemDocValue = xmlItemDoc.GetElementsByTagName("entity"); - var xmlItemDocValueFirst = xmlItemDocValue[0]; - if (xmlItemDocValueFirst is not null) - { - var nameLabel = xmlItemDocValueFirst.Attributes[0]; - string itemID = nameLabel.InnerXml; - Network.httpClientBusy = false; - GetPropertiesFromURL(itemID, prop);/// - } + Debug.WriteLine($"GetWikidataData: no entity for '{itemLabel}'."); + return; + } + var xmlItemDocValueFirst = xmlItemDocValue[0]; + if (xmlItemDocValueFirst?.Attributes?.Count > 0) + { + var nameLabel = xmlItemDocValueFirst.Attributes[0]; + string itemID = nameLabel.InnerXml; + handedOff = true; + await GetPropertiesFromURL(itemID, prop); } } - catch { } - + catch (Exception ex) + { + Debug.WriteLine($"GetWikidataData failed for '{itemLabel}': {ex.Message}"); + } + finally + { + if (!handedOff) + Network.httpClientBusy = false; + } } //This method gets all the properties or subproperties of a property propName from a Thought // with name propName and wikidata query number value numberOfName associated with propName - private async void GetPropertiesFromURL(string itemID, string propName) + private async Task GetPropertiesFromURL(string itemID, string propName) { + try + { Output = ""; propName = propName.ToLower(); - Network.httpClientBusy = true; var urlBegin = @"https://query.wikidata.org/sparql?query="; var url = @"SELECT ?wdLabel ?ps_Label ?wdpqLabel ?pq_Label " + @"{VALUES(?company) { (wd:" + itemID + @")} " + @@ -1094,6 +1139,15 @@ private async void GetPropertiesFromURL(string itemID, string propName) } } } + } + catch (Exception ex) + { + Debug.WriteLine($"GetPropertiesFromURL failed for '{itemID}': {ex.Message}"); + } + finally + { + Network.httpClientBusy = false; + } } @@ -1208,7 +1262,7 @@ public class View } - public async void GetFreeDictionaryAPIData(string text) + public async Task GetFreeDictionaryAPIData(string text) { var url = @"https://api.dictionaryapi.dev/api/v2/entries/en/" + text; var myClient = new HttpClient(); @@ -1272,7 +1326,7 @@ public class Root1 } - public async void GetWebstersDictionaryAPIData(string text) + public async Task GetWebstersDictionaryAPIData(string text) { var url = @"https://dictionaryapi.com/api/v3/references/sd2/json/" + text + "?key=a22c5742-ad8e-44b4-b4c4-9f3f9ac7aedb"; var myClient = new HttpClient(); diff --git a/BrainSimulator/Modules/ModuleUKSQueryDlg.xaml.cs b/BrainSimulator/Modules/ModuleUKSQueryDlg.xaml.cs index 81f33a9..d290219 100644 --- a/BrainSimulator/Modules/ModuleUKSQueryDlg.xaml.cs +++ b/BrainSimulator/Modules/ModuleUKSQueryDlg.xaml.cs @@ -150,7 +150,8 @@ private void QueryByAttributes() resultText1.Text += result1.t.Label + " " + result1.conf.ToString("0.00") + "\n"; } - if (allResults.Count == 1 || allResults[0].conf > allResults[1].conf) + if (allResults.Count > 0 && + (allResults.Count == 1 || allResults[0].conf > allResults[1].conf)) { UpdateMostRecent(allResults[0].t); } diff --git a/BrainSimulator/Modules/Vision/ModuleMentalModelDlg.xaml.cs b/BrainSimulator/Modules/Vision/ModuleMentalModelDlg.xaml.cs index afae1db..4ae470f 100644 --- a/BrainSimulator/Modules/Vision/ModuleMentalModelDlg.xaml.cs +++ b/BrainSimulator/Modules/Vision/ModuleMentalModelDlg.xaml.cs @@ -13,13 +13,14 @@ // // PROPRIETARY AND CONFIDENTIAL // Brain Simulator 3 v.1.0 -// © 2022 FutureAI, Inc., all rights reserved +// � 2022 FutureAI, Inc., all rights reserved // using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Shapes; +using BrainSimulator; using UKS; namespace BrainSimulator.Modules @@ -99,7 +100,7 @@ public override bool Draw(bool checkDrawTimer) curPos += offset; poly.Points.Add(curPos); } - catch { } + catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"Mental model distance parse failed: {ex.Message}"); } } } if (poly.Points.Count < 2) //there is no recenetly-refreshed data, use the stored shape diff --git a/BrainSimulator/Modules/Vision/ModuleVision.cs b/BrainSimulator/Modules/Vision/ModuleVision.cs index 6c92528..9a1134d 100644 --- a/BrainSimulator/Modules/Vision/ModuleVision.cs +++ b/BrainSimulator/Modules/Vision/ModuleVision.cs @@ -13,7 +13,7 @@ // // PROPRIETARY AND CONFIDENTIAL // Brain Simulator 3 v.1.0 -// © 2022 FutureAI, Inc., all rights reserved +// � 2022 FutureAI, Inc., all rights reserved // using System; @@ -563,7 +563,7 @@ private void FindOutlines() Thing theColor = GetOrAddColor(theCenterColor); currOutline.SetAttribute(theColor); } - catch (Exception e) { } + catch (Exception e) { System.Diagnostics.Debug.WriteLine($"Centroid color read failed: {e.Message}"); } //we now have an ordered, right-handed outline //add it to UKS diff --git a/BrainSimulator/Modules/Vision/ModuleVisionDlg.xaml.cs b/BrainSimulator/Modules/Vision/ModuleVisionDlg.xaml.cs index 49a6414..63d5e06 100644 --- a/BrainSimulator/Modules/Vision/ModuleVisionDlg.xaml.cs +++ b/BrainSimulator/Modules/Vision/ModuleVisionDlg.xaml.cs @@ -13,7 +13,7 @@ // // PROPRIETARY AND CONFIDENTIAL // Brain Simulator 3 v.1.0 -// © 2022 FutureAI, Inc., all rights reserved +// � 2022 FutureAI, Inc., all rights reserved // using System; @@ -56,7 +56,7 @@ public override bool Draw(bool checkDrawTimer) "\r\nCorners: " + parent.corners?.Count + "\r\nOutlines: " + parent.theUKS.Labeled("Outline")?.Children.Count; } - catch { return false; } + catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"Vision dialog label update failed: {ex.Message}"); return false; } theCanvas.Children.Clear(); @@ -287,7 +287,7 @@ public override bool Draw(bool checkDrawTimer) } } } - catch { } + catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"Vision dialog draw failed: {ex.Message}"); } return true; } diff --git a/BrainSimulator/Modules/Vision/README.md b/BrainSimulator/Modules/Vision/README.md new file mode 100644 index 0000000..3ef1ab7 --- /dev/null +++ b/BrainSimulator/Modules/Vision/README.md @@ -0,0 +1,12 @@ +# Vision modules + +Re-enabled 2026-07-07 via BrainSim3 compatibility layer in `UKS/`: + +- `Relationship.cs` — `Link` wrapper +- `Thought.BrainSim3Compat.cs` — `SetAttribute`, `GetAttribute`, `Relationships`, etc. +- `UKS.BrainSim3Compat.cs` — `GetOrAddThing`, `SearchForClosestMatch(ref)`, `HasSequence`, etc. +- `BrainSimulator/GlobalUsings.cs` — `Thing` → `Thought` alias + +`ModuleMentalModel*` in this folder are legacy BrainSim3 stubs. The canonical +implementation is `Modules/ModuleMentalModel*` and is excluded here in +`BrainSim Thought.csproj` to avoid duplicate-type build errors. \ No newline at end of file diff --git a/BrainSimulator/Network.cs b/BrainSimulator/Network.cs index 618df39..5381196 100644 --- a/BrainSimulator/Network.cs +++ b/BrainSimulator/Network.cs @@ -112,12 +112,15 @@ public static UdpClient UDPAudioReceive public static void Broadcast(string message) { //Debug.WriteLine("Broadcast: " + message); - if (broadcastAddress is null) SetBroadcastAddress(); + if (broadcastAddress is null && !SetBroadcastAddress()) + return; + if (broadcastAddress is null) + return; byte[] datagram = Encoding.UTF8.GetBytes(message); IPEndPoint ipEnd = new(broadcastAddress, UDPSendPort); UDPBroadcast.SendAsync(datagram, datagram.Length, ipEnd); - } + } public static bool UDP_Send(string message,IPAddress ipToSend, int udpPort) { if (ipToSend is null) return false; @@ -187,7 +190,7 @@ public static bool InitTCP(string podIPString)//This really needs to have some c return true; } - public static void SetBroadcastAddress() + public static bool SetBroadcastAddress() { var host = Dns.GetHostEntry(Dns.GetHostName()); foreach (var ip in host.AddressList) @@ -198,10 +201,11 @@ public static void SetBroadcastAddress() string[] ipComps = ipStr.Split("."); broadcastAddress = IPAddress.Parse(ipComps[0] + "." + ipComps[1] + "." + ipComps[2] + ".255"); - return; + return true; } } - throw new Exception("No network adapters with an IPv4 address in the system!"); + Debug.WriteLine("SetBroadcastAddress: no IPv4 adapter; UDP broadcast disabled."); + return false; } public static void SendStringToPodTCP(string msg) diff --git a/BrainSimulator/Resources/wordlist.txt b/BrainSimulator/Resources/wordlist.txt new file mode 100644 index 0000000..44e875b --- /dev/null +++ b/BrainSimulator/Resources/wordlist.txt @@ -0,0 +1,30 @@ +# Minimal word list for ModuleOnlineInfo.SetupWordList (one word per line). +# Replace or set WORDLIST_PATH to a full dictionary file. +the +be +to +of +and +a +in +that +have +it +for +not +on +with +he +as +you +do +at +dog +cat +bird +fish +horse +tree +water +sun +moon \ No newline at end of file diff --git a/BrainSimulator/UKSContent/NatureAnimals.xml b/BrainSimulator/UKSContent/NatureAnimals.xml new file mode 100644 index 0000000..95fa64f --- /dev/null +++ b/BrainSimulator/UKSContent/NatureAnimals.xml @@ -0,0 +1,1995 @@ + + + + 0 + + + + 1 + + + + 2 + + + + 3 + + + + 4 + + + + 5 + + + + 6 + + + + 7 + + + + 8 + + + + 9 + + + + 10 + + + + 11 + + + + 12 + + + + 13 + + + + 14 + + + + 15 + + + + 16 + + + + 17 + + + + 18 + + + + 19 + + + + 20 + + + + 21 + + + + 22 + + + + 23 + + + + 24 + + + + 25 + + + + 26 + + + + 27 + + + + 28 + + + + 29 + + + + 30 + + + + 31 + + + + 32 + + + + 33 + + + + 34 + + + + 35 + + + + 36 + + + + 37 + + + + 38 + + + + 39 + + + + 40 + + + + 41 + + + + 42 + + + + 43 + + + + 44 + + + + 45 + + + + 46 + + + + 47 + + + + 48 + + + + 49 + + + + 50 + + + + 51 + + + + 52 + + + + 53 + + + + 54 + + + + 55 + + + + 56 + + + + 57 + + + + 58 + + + + 59 + + + + 60 + + + + 61 + + + + 62 + + + + 63 + + + + 64 + + + + 65 + + + + 66 + + + + 67 + + + + 68 + + + + 69 + + + + 70 + + + + 71 + + + + 72 + + + + 73 + + + + 74 + + + + 75 + + + + 76 + + + + 77 + + + + 78 + + + + 79 + + + + 80 + + + + 81 + + + + 82 + + + + 83 + + + + 84 + + + + 85 + + + + 86 + + + + 87 + + + + 88 + + + + 89 + + + + 90 + + + + 91 + + + + 92 + + + + 93 + + + + 94 + + + + 95 + + + + 96 + + + + 97 + + + + 98 + + + + 99 + + + + 100 + + + + 101 + + + + 102 + + + + 103 + + + + 104 + + + + 105 + + + + 106 + + 1 + 10 + 0 + + + 107 + + 2 + 10 + 0 + + + 108 + + 3 + 10 + 0 + + + 109 + + 4 + 10 + 0 + + + 110 + + 5 + 10 + 4 + + + 111 + + 6 + 10 + 3 + + + 112 + + 7 + 10 + 3 + + + 113 + + 8 + 10 + 3 + + + 114 + + 9 + 10 + 0 + + + 115 + + 35 + 10 + 0 + + + 116 + + 10 + 10 + 2 + + + 117 + + 11 + 10 + 2 + + + 118 + + 12 + 10 + 2 + + + 119 + + 13 + 10 + 2 + + + 120 + + 14 + 10 + 2 + + + 121 + + 15 + 10 + 2 + + + 122 + + 16 + 10 + 2 + + + 123 + + 16 + 10 + 5 + + + 124 + + 17 + 10 + 2 + + + 125 + + 17 + 10 + 5 + + + 126 + + 18 + 10 + 2 + + + 127 + + 19 + 10 + 2 + + + 128 + + 20 + 10 + 2 + + + 129 + + 21 + 10 + 2 + + + 130 + + 22 + 10 + 11 + + + 131 + + 23 + 10 + 11 + + + 132 + + 24 + 10 + 11 + + + 133 + + 25 + 10 + 11 + + + 134 + + 26 + 10 + 11 + + + 135 + + 27 + 10 + 11 + + + 136 + + 28 + 10 + 4 + + + 137 + + 29 + 10 + 4 + + + 138 + + 30 + 10 + 4 + + + 139 + + 31 + 10 + 4 + + + 140 + + 32 + 10 + 4 + + + 141 + + 33 + 10 + 4 + + + 142 + + 34 + 10 + 33 + + + 143 + + 36 + 10 + 3 + + + 144 + + 39 + 10 + 3 + + + 145 + + 37 + 10 + 36 + + + 146 + + 38 + 10 + 36 + + + 147 + + 87 + 10 + 38 + + + 148 + + 40 + 10 + 37 + + + 149 + + 41 + 10 + 37 + + + 150 + + 42 + 10 + 37 + + + 151 + + 43 + 10 + 37 + + + 152 + + 44 + 10 + 37 + + + 153 + + 45 + 10 + 37 + + + 154 + + 46 + 10 + 40 + + + 155 + + 47 + 10 + 40 + + + 156 + + 48 + 10 + 40 + + + 157 + + 49 + 10 + 40 + + + 158 + + 50 + 10 + 40 + + + 159 + + 51 + 10 + 40 + + + 160 + + 52 + 10 + 40 + + + 161 + + 53 + 10 + 40 + + + 162 + + 54 + 10 + 40 + + + 163 + + 55 + 10 + 41 + + + 164 + + 56 + 10 + 41 + + + 165 + + 57 + 10 + 41 + + + 166 + + 58 + 10 + 41 + + + 167 + + 59 + 10 + 42 + + + 168 + + 60 + 10 + 42 + + + 169 + + 61 + 10 + 42 + + + 170 + + 62 + 10 + 43 + + + 171 + + 63 + 10 + 43 + + + 172 + + 64 + 10 + 43 + + + 173 + + 65 + 10 + 44 + + + 174 + + 66 + 10 + 45 + + + 175 + + 67 + 10 + 45 + + + 176 + + 68 + 10 + 6 + + + 177 + + 69 + 10 + 6 + + + 178 + + 70 + 10 + 6 + + + 179 + + 71 + 10 + 6 + + + 180 + + 72 + 10 + 6 + + + 181 + + 73 + 10 + 6 + + + 182 + + 74 + 10 + 6 + + + 183 + + 75 + 10 + 6 + + + 184 + + 76 + 10 + 6 + + + 185 + + 77 + 10 + 8 + + + 186 + + 78 + 10 + 8 + + + 187 + + 79 + 10 + 8 + + + 188 + + 80 + 10 + 8 + + + 189 + + 81 + 10 + 7 + + + 190 + + 82 + 10 + 7 + + + 191 + + 83 + 10 + 7 + + + 192 + + 84 + 10 + 7 + + + 193 + + 85 + 10 + 7 + + + 194 + + 86 + 10 + 7 + + + 195 + + 40 + 15 + 28 + + + 196 + + 40 + 15 + 30 + + + 197 + + 40 + 15 + 32 + + + 198 + + 41 + 15 + 28 + + + 199 + + 41 + 15 + 31 + + + 200 + + 41 + 15 + 32 + + + 201 + + 42 + 15 + 29 + + + 202 + + 42 + 15 + 31 + + + 203 + + 42 + 15 + 32 + + + 204 + + 43 + 15 + 29 + + + 205 + + 43 + 15 + 31 + + + 206 + + 43 + 15 + 32 + + + 207 + + 44 + 15 + 29 + + + 208 + + 44 + 15 + 31 + + + 209 + + 45 + 15 + 29 + + + 210 + + 37 + 15 + 32 + + + 211 + + 46 + 11 + 69 + + + 212 + + 46 + 22 + 68 + + + 213 + + 46 + 11 + 70 + + + 214 + + 46 + 14 + 77 + + + 215 + + 47 + 11 + 69 + + + 216 + + 47 + 22 + 68 + + + 217 + + 47 + 11 + 70 + + + 218 + + 47 + 14 + 78 + + + 219 + + 48 + 11 + 69 + + + 220 + + 48 + 22 + 68 + + + 221 + + 48 + 14 + 79 + + + 222 + + 49 + 11 + 73 + + + 223 + + 49 + 27 + 68 + + + 224 + + 50 + 11 + 74 + + + 225 + + 50 + 22 + 68 + + + 226 + + 51 + 22 + 68 + + + 227 + + 51 + 11 + 69 + + + 228 + + 52 + 11 + 69 + + + 229 + + 52 + 22 + 68 + + + 230 + + 52 + 11 + 70 + + + 231 + + 53 + 22 + 68 + + + 232 + + 53 + 11 + 69 + + + 233 + + 54 + 11 + 73 + + + 234 + + 54 + 27 + 68 + + + 235 + + 41 + 11 + 74 + + + 236 + + 41 + 11 + 71 + + + 237 + + 41 + 24 + 68 + + + 238 + + 41 + 11 + 76 + + + 239 + + 55 + 24 + 74 + + + 240 + + 56 + 24 + 74 + + + 241 + + 57 + 24 + 74 + + + 242 + + 58 + 24 + 74 + + + 243 + + 42 + 11 + 72 + + + 244 + + 59 + 27 + 68 + + + 245 + + 59 + 11 + 72 + + + 246 + + 60 + 22 + 68 + + + 247 + + 60 + 11 + 72 + + + 248 + + 61 + 22 + 68 + + + 249 + + 61 + 11 + 72 + + + 250 + + 43 + 11 + 73 + + + 251 + + 43 + 11 + 75 + + + 252 + + 43 + 11 + 72 + + + 253 + + 62 + 11 + 73 + + + 254 + + 63 + 11 + 73 + + + 255 + + 63 + 27 + 68 + + + 256 + + 65 + 22 + 68 + + + 257 + + 66 + 11 + 74 + + + 258 + + 66 + 25 + 68 + + + 259 + + 66 + 14 + 80 + + + 260 + + 67 + 25 + 68 + + + 261 + + 46 + 10 + 93 + + + 262 + + 47 + 10 + 93 + + + 263 + + 48 + 10 + 93 + + + 264 + + 52 + 10 + 94 + + + 265 + + 55 + 10 + 94 + + + 266 + + 53 + 10 + 94 + + + 267 + + 46 + 16 + 52 + + + 268 + + 46 + 16 + 47 + + + 269 + + 47 + 16 + 46 + + + 270 + + 52 + 16 + 46 + + + 271 + + 62 + 16 + 64 + + + 272 + + 55 + 16 + 58 + + + 273 + + 46 + 17 + 41 + + + 274 + + 41 + 17 + 43 + + + 275 + + 40 + 17 + 42 + + + 276 + + 49 + 17 + 43 + + + 277 + + 50 + 17 + 41 + + + 278 + + 59 + 17 + 46 + + + 279 + + 55 + 18 + 51 + + + 280 + + 51 + 19 + 55 + + + 281 + + 52 + 18 + 53 + + + 282 + + 53 + 19 + 52 + + + 283 + + 63 + 18 + 62 + + + 284 + + 62 + 19 + 63 + + + 285 + + 58 + 18 + 51 + + + 286 + + 47 + 18 + 51 + + + 287 + + 53 + 20 + 81 + + + 288 + + 55 + 20 + 83 + + + 289 + + 62 + 20 + 86 + + + 290 + + 49 + 20 + 82 + + + 291 + + 63 + 20 + 82 + + + 292 + + 54 + 20 + 82 + + + 293 + + 57 + 20 + 85 + + + 294 + + 56 + 20 + 81 + + + 295 + + 65 + 20 + 86 + + + 296 + + 87 + 20 + 81 + + + 297 + + 46 + 21 + 62 + + + 298 + + 47 + 21 + 51 + + + 299 + + 55 + 21 + 51 + + + 300 + + 52 + 21 + 53 + + + 301 + + 63 + 21 + 62 + + + 302 + + 95 + 10 + 46 + + + 303 + + 95 + 13 + 88 + + + 304 + + 95 + 22 + 68 + + + 305 + + 95 + 20 + 84 + + + 306 + + 96 + 10 + 46 + + + 307 + + 96 + 23 + 68 + + + 308 + + 97 + 10 + 47 + + + 309 + + 97 + 13 + 89 + + + 310 + + 97 + 20 + 84 + + + 311 + + 98 + 10 + 48 + + + 312 + + 98 + 13 + 88 + + + 313 + + 98 + 20 + 84 + + + 314 + + 99 + 10 + 46 + + + 315 + + 99 + 13 + 90 + + + 316 + + 100 + 10 + 55 + + + 317 + + 100 + 20 + 83 + + + 318 + + 101 + 10 + 59 + + + 319 + + 101 + 13 + 91 + + + 320 + + 101 + 20 + 81 + + + 321 + + 102 + 10 + 50 + + + 322 + + 102 + 20 + 81 + + + 323 + + 103 + 10 + 62 + + + 324 + + 103 + 20 + 86 + + + 325 + + 104 + 10 + 57 + + + 326 + + 104 + 20 + 85 + + + 327 + + 105 + 10 + 53 + + + 328 + + 105 + 13 + 88 + + + 329 + + 105 + 20 + 81 + + diff --git a/BrainSimulator/Utils.cs b/BrainSimulator/Utils.cs index 964dcc4..dc57c61 100644 --- a/BrainSimulator/Utils.cs +++ b/BrainSimulator/Utils.cs @@ -24,6 +24,7 @@ using System.Collections.Generic; using System.Linq; using System.Windows.Media.Media3D; +using System.Diagnostics; using System.IO; using System.Reflection.Metadata; @@ -111,7 +112,7 @@ public HSLColor(Dictionary values) saturation = values["Sat+"]; luminance = values["Lum+"]; } - catch { } + catch (Exception ex) { Debug.WriteLine($"HSLColor dictionary parse failed: {ex.Message}"); } } public HSLColor(byte a, byte r, byte g, byte b) { @@ -194,13 +195,12 @@ Color ColorFromHSL2() Color c; - if (000 <= hue && hue < 060) c = Color.FromArgb(255, (byte)((C + m) * 255), (byte)((X + m) * 255), (byte)((0 + m) * 255)); - if (060 <= hue && hue < 120) c = Color.FromArgb(255, (byte)((X + m) * 255), (byte)((C + m) * 255), (byte)((0 + m) * 255)); - if (120 <= hue && hue < 180) c = Color.FromArgb(255, (byte)((0 + m) * 255), (byte)((C + m) * 255), (byte)((X + m) * 255)); - if (180 <= hue && hue < 240) c = Color.FromArgb(255, (byte)((0 + m) * 255), (byte)((X + m) * 255), (byte)((C + m) * 255)); - if (240 <= hue && hue < 300) c = Color.FromArgb(255, (byte)((X + m) * 255), (byte)((0 + m) * 255), (byte)((C + m) * 255)); - if (300 <= hue && hue < 345) c = Color.FromArgb(255, (byte)((C + m) * 255), (byte)((0 + m) * 255), (byte)((C + m) * 255)); - if (hue > 345) c = Color.FromArgb(255, (byte)((C + m) * 255), (byte)((X + m) * 255), (byte)((0 + m) * 255)); + if (hue < 60) c = Color.FromArgb(255, (byte)((C + m) * 255), (byte)((X + m) * 255), (byte)((0 + m) * 255)); + else if (hue < 120) c = Color.FromArgb(255, (byte)((X + m) * 255), (byte)((C + m) * 255), (byte)((0 + m) * 255)); + else if (hue < 180) c = Color.FromArgb(255, (byte)((0 + m) * 255), (byte)((C + m) * 255), (byte)((X + m) * 255)); + else if (hue < 240) c = Color.FromArgb(255, (byte)((0 + m) * 255), (byte)((X + m) * 255), (byte)((C + m) * 255)); + else if (hue < 300) c = Color.FromArgb(255, (byte)((X + m) * 255), (byte)((0 + m) * 255), (byte)((C + m) * 255)); + else c = Color.FromArgb(255, (byte)((C + m) * 255), (byte)((0 + m) * 255), (byte)((X + m) * 255)); return c; } @@ -228,9 +228,8 @@ public bool Equals(HSLColor c1) if (c1.luminance > .95) return true; } float absHueDiff = Abs(hue - c1.hue); - if (absHueDiff < 5 || absHueDiff > 355) - return true; - return false; + float circularHueDiff = Min(absHueDiff, 360f - absHueDiff); + return circularHueDiff < 5; } } @@ -272,7 +271,7 @@ public static Control FindByName(Visual v, string name) if (c2 is not null) return c2; } - catch { } + catch (Exception ex) { Debug.WriteLine($"FindByName walk failed for '{name}': {ex.Message}"); } } } return null; diff --git a/BrainSimulator/archive/legacy/MainWindowPythonModules.cs b/BrainSimulator/archive/legacy/MainWindowPythonModules.cs new file mode 100644 index 0000000..7462c7f --- /dev/null +++ b/BrainSimulator/archive/legacy/MainWindowPythonModules.cs @@ -0,0 +1,173 @@ +/* + * Brain Simulator Through + * + * Copyright (c) 2026 Charles Simon + * + * This file is part of Brain Simulator Through and is licensed under + * the MIT License. You may use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of this software under the terms of + * the MIT License. + * + * See the LICENSE file in the project root for full license information. + */ + +using Python.Runtime; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Windows; +using UKS; +using System.Windows.Interop; + + +namespace BrainSimulator; + +public partial class MainWindow : Window +{ + public static List<(string, dynamic)> activePythonModules = new(); + public static List GetPythonModules() + { + //this is a buffer of python modules so they can be imported once and run many times. + List<(string, dynamic)> modules = new List<(string, dynamic)>(); + List pythonFiles = new(); + try + { + pythonFiles = Directory.GetFiles(@".\pythonModules", "*.py").ToList(); + string destDir = Directory.GetCurrentDirectory(); + string sourceDir = destDir + "\\PythonModules"; + for (int i = 0; i < pythonFiles.Count; i++) + { + if (pythonFiles[i].StartsWith("utils")) continue; + pythonFiles[i] = Path.GetFileName(pythonFiles[i]); + } + } + catch + { + + } + return pythonFiles; + } + static void RunScript(string moduleLabel) + { + bool firstTime = false; + //get the ModuleType + Thing tModule = theUKS.Labeled(moduleLabel); + if (tModule == null) { return; } + Thing tModuleType = tModule.Parents.FindFirst(x => x.HasAncestorLabeled("AvailableModule")); + if (tModuleType == null) return; + string moduleType = tModuleType.Label; + moduleType = moduleType.Replace(".py", ""); + + //if this is the very first call, initialize the python engine + if (Runtime.PythonDLL == null) + { + try + { + //TODO use variable + Runtime.PythonDLL = @"Python310"; + + PythonEngine.Initialize(); + dynamic sys = Py.Import("sys"); + dynamic os = Py.Import("os"); + sys.path.append(os.getcwd()); // enables finding scriptName module + sys.path.append(os.getcwd() + "\\pythonModules"); + } + catch + { + Console.WriteLine("Python engine initialization failed"); + return; + } + } + using (Py.GIL()) + { + var theModuleEntry = activePythonModules.FirstOrDefault(x => x.Item1.ToLower() == moduleLabel.ToLower()); + if (string.IsNullOrEmpty(theModuleEntry.Item1)) + { + //if this is the first time this modulw has been used + try + { + Console.WriteLine("Loading " + moduleLabel); + dynamic theModule = Py.Import(moduleType); + theModuleEntry = (moduleLabel, theModule); + activePythonModules.Add(theModuleEntry); + theModule.Init(); + firstTime = true; + } + catch (Exception ex) + { + Console.WriteLine("Load/initialize failed for module: " + moduleLabel + " Reason: " + ex.Message); + theModuleEntry = (moduleLabel, null); + activePythonModules.Add(theModuleEntry); + } + } + if (theModuleEntry.Item2 != null) + { + try + { + if (!theModuleEntry.Item2.Fire()) + { } //this doesn't seem to work because it thows an exception instead + if (firstTime) + { + var HWND = theModuleEntry.Item2.GetHWND(); + var ss = HWND.ToString(); + // this works, and returns 1322173 + int intValue = Convert.ToInt32(ss, 16); + firstTime = false; + SetOwner(intValue); + } + } + catch (Exception ex) + { + activePythonModules.Remove(theModuleEntry); + MainWindow.theWindow.DeactivateModule(moduleLabel); + Console.WriteLine("Fire method call failed for module: " + moduleLabel + " Reason: " + ex.Message); + } + } + } + } + + + private const int GWL_HWNDPARENT = -8; + + [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")] + private static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong); + + [DllImport("user32.dll", SetLastError = true)] + private static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong); + + static void SetOwner(int HWND) + { + // Example usage + IntPtr childHwnd = new IntPtr(HWND); // Child window handle + //IntPtr ownerHwnd = new IntPtr(654321); // New owner window handle + Window window = Window.GetWindow(MainWindow.theWindow); + var wih = new WindowInteropHelper(window); + IntPtr ownerHwnd = wih.Handle; + + ChangeWindowOwner(childHwnd, ownerHwnd); + } + + static void ChangeWindowOwner(IntPtr childHwnd, IntPtr ownerHwnd) + { + IntPtr result = 0; + if (IntPtr.Size == 8) + SetWindowLongPtr(childHwnd, GWL_HWNDPARENT, ownerHwnd); + else + SetWindowLong(childHwnd, GWL_HWNDPARENT, ownerHwnd); + + if (result == IntPtr.Zero) + { + int errorCode = Marshal.GetLastWin32Error(); + Console.WriteLine($"Failed to change window owner. Error code: {errorCode}"); + } + else + { + Console.WriteLine("Window owner changed successfully."); + } + } +} + + + diff --git a/BrainSimulator/archive/legacy/README.md b/BrainSimulator/archive/legacy/README.md new file mode 100644 index 0000000..746dae3 --- /dev/null +++ b/BrainSimulator/archive/legacy/README.md @@ -0,0 +1,10 @@ +# Legacy BrainSim3 sources (not compiled) + +Moved from `BrainSimulator/` root on 2026-07-07. Excluded via `` in `BrainSim Thought.csproj`. + +| File | Reason | +|------|--------| +| `XmlFile.cs` | BrainSim3Data XML serializer; app uses `UKS.LoadUKSfromXMLFile` / `SaveUKStoXMLFile` | +| `MainWindowPythonModules.cs` | Duplicate Python glue with hardcoded `Python310`; superseded by `ModuleHandler.cs` | + +Do not re-enable without porting to current UKS persistence and `PythonPath` configuration. \ No newline at end of file diff --git a/BrainSimulator/XmlFile.cs b/BrainSimulator/archive/legacy/XmlFile.cs similarity index 100% rename from BrainSimulator/XmlFile.cs rename to BrainSimulator/archive/legacy/XmlFile.cs diff --git a/PythonProj/MainWindow.py b/PythonProj/MainWindow.py index f5422e5..cb31961 100644 --- a/PythonProj/MainWindow.py +++ b/PythonProj/MainWindow.py @@ -16,6 +16,7 @@ def __init__(self, level: Union[tk.Tk, tk.Toplevel]) -> None: title: str = titleBase super(MainWindow, self).__init__( title=title, level=level, module_type=os.path.basename(__file__)) + self._closed = False self.setupUKS() self.build() @@ -36,9 +37,6 @@ def build(self): self.saveAsButton.pack(side='right',padx=50) self.saveButton.pack(side='top',pady=20) self.setupcontent() - - if sys.argv[0] != "": - self.level.mainloop() def setupcontent(self): self.moduleList.delete(0,'end') @@ -147,12 +145,21 @@ def activateModule(self,moduleTypeLabel): def onClosing(self): - print ("MainWindow closing") - os._exit(0) + print("MainWindow closing") + self._closed = True + try: + self.level.destroy() + except tk.TclError: + pass def fire(self): - #Put your functional code HERE - #This function is called repeateldly so you may wish to do things only on a timer like this: + if self._closed: + return False + try: + if not self.level.winfo_exists(): + return False + except tk.TclError: + return False curr_time: float = time.time() try: if curr_time > (self.prev_time + TIMEDELAY): @@ -163,9 +170,11 @@ def fire(self): #you always nee this: self.setupcontent() self.level.update() - #don't ever close this module while the program is running return True + def close(self): + self.onClosing() + ###################### ## Expose Methods ## @@ -185,6 +194,7 @@ def GetHWND() -> int: def SetLabel(label): view.setLabel(label) -if sys.argv[0] != "": +if __name__ == "__main__": Init() + view.level.mainloop() diff --git a/PythonProj/module_uks_tree.py b/PythonProj/module_uks_tree.py index 17232c1..3400e8c 100644 --- a/PythonProj/module_uks_tree.py +++ b/PythonProj/module_uks_tree.py @@ -138,11 +138,6 @@ def build(self) -> None: self.tree_view.bind("<>", self.handle_close_event) self.tree_view.bind("", self.handle_mouse_enter) self.tree_view.bind("", self.handle_mouse_leave) - - if sys.argv[0] != "": - self.level.mainloop() - - ############ ## Fire ## @@ -183,5 +178,6 @@ def SetLabel(label): def Close(): view.close() -if sys.argv[0] != "": +if __name__ == "__main__": Init() + view.level.mainloop() diff --git a/PythonProj/utils.py b/PythonProj/utils.py index e2e6887..fd26b31 100644 --- a/PythonProj/utils.py +++ b/PythonProj/utils.py @@ -33,26 +33,23 @@ def __init__(self, self.window_height = None self.window_x = None self.window_y = None - #BUG...if you enable the following line, the WINDOWS program will crash if you move/resize a window - #self.level.bind("",self.resize) + # Call bind_resize_events() after build if geometry sync to UKS is needed. def setLabel(self, new_label: str): self.label = new_label - def resize(self,event): - #breakpoint() - #this actually receives ALL the configuration events...so we have to sort out resize/move and the event source - if hasattr(event.widget, "widgetName"): - pass - else: #if it doesn't have a name, it must be top level - if (self.window_width != event.width) or (self.window_height != event.height): - #if height/width changed, it must be resize - self.window_width, self.window_height = event.width,event.height - if (self.window_x != event.x ) or (self.window_y != event.y): - self.window_x, self.window_y = event.x,event.y - print(self.module_type, self.label) - print(self.level.winfo_geometry()) - #TODO Add code to update values in UKS + def bind_resize_events(self): + self.level.bind("", self.resize) + + def resize(self, event): + # Only handle the toplevel window; child Configure events caused Windows crashes. + if event.widget is not self.level: + return + if (self.window_width != event.width) or (self.window_height != event.height): + self.window_width, self.window_height = event.width, event.height + if (self.window_x != event.x) or (self.window_y != event.y): + self.window_x, self.window_y = event.x, event.y + # TODO: persist geometry to UKS module attributes when safe def close(self): self.level.destroy() diff --git a/Tests/ModuleAlgorithm.Tests.cs b/Tests/ModuleAlgorithm.Tests.cs index 66a1073..4b55979 100644 --- a/Tests/ModuleAlgorithm.Tests.cs +++ b/Tests/ModuleAlgorithm.Tests.cs @@ -37,7 +37,7 @@ public ModuleAlgorithmTests() // Load algorithm.xml from UKSContent folder - string xmlPath = Path.Combine(brainSimRoot,"brainsimulator", "UKSContent", "algorithm.xml"); + string xmlPath = Path.Combine(brainSimRoot, "BrainSimulator", "UKSContent", "algorithm.xml"); if (!File.Exists(xmlPath)) { // Try alternative path diff --git a/Tests/NatureAnimalsXmlTests.cs b/Tests/NatureAnimalsXmlTests.cs new file mode 100644 index 0000000..3954922 --- /dev/null +++ b/Tests/NatureAnimalsXmlTests.cs @@ -0,0 +1,87 @@ +/* + * Brain Simulator Thought — NatureAnimals.xml import verification + */ + +using System.IO; +using UKS; +using Xunit; + +namespace UKS.Tests; + +public class NatureAnimalsXmlTests +{ + private static string XmlPath() + { + string fromTest = Path.Combine( + Directory.GetCurrentDirectory(), + "..", "..", "..", "..", + "BrainSimulator", "UKSContent", "NatureAnimals.xml"); + if (File.Exists(fromTest)) return Path.GetFullPath(fromTest); + + string fromRepo = Path.Combine( + AppContext.BaseDirectory, + "..", "..", "..", "..", "..", + "BrainSimulator", "UKSContent", "NatureAnimals.xml"); + return Path.GetFullPath(fromRepo); + } + + private static UKS LoadNatureUks() + { + var uks = new UKS(clear: true); + string path = XmlPath(); + Assert.True(File.Exists(path), $"NatureAnimals.xml not found at {path}"); + Assert.True(uks.LoadUKSfromXMLFile(path)); + return uks; + } + + private static void AssertLink(UKS uks, string from, string linkType, string to) + { + Thought f = uks.Labeled(from); + Thought lt = uks.Labeled(linkType); + Thought t = uks.Labeled(to); + Assert.NotNull(f); + Assert.NotNull(lt); + Assert.NotNull(t); + Assert.NotNull(f.HasLink(lt, t)); + } + + [Fact] + public void NatureAnimals_LoadsFromXml() + { + var uks = LoadNatureUks(); + Assert.NotNull(uks.Labeled("Fido")); + Assert.NotNull(uks.Labeled("mammal")); + Assert.True(uks.AtomicThoughts.Count > 100); + } + + [Fact] + public void NatureAnimals_FidoPattern() + { + var uks = LoadNatureUks(); + AssertLink(uks, "Fido", "is-a", "dog"); + AssertLink(uks, "Fido", "is", "brown"); + AssertLink(uks, "Fido", "has.4", "leg"); + AssertLink(uks, "dog", "has.4", "leg"); + } + + [Fact] + public void NatureAnimals_TripperException() + { + var uks = LoadNatureUks(); + AssertLink(uks, "Tripper", "is-a", "dog"); + AssertLink(uks, "Tripper", "has.3", "leg"); + } + + [Fact] + public void NatureAnimals_TaxonomyAndCrossSpecies() + { + var uks = LoadNatureUks(); + AssertLink(uks, "dog", "is-a", "mammal"); + AssertLink(uks, "eagle", "is-a", "bird"); + AssertLink(uks, "salmon", "is-a", "fish"); + AssertLink(uks, "dog", "isSimilarTo", "wolf"); + AssertLink(uks, "eagle", "predatorOf", "mouse"); + AssertLink(uks, "whale", "differsFrom", "fish"); + AssertLink(uks, "penguin", "livesIn", "antarctica"); + } +} \ No newline at end of file diff --git a/Tests/NonUksP0FixesRegressionTests.cs b/Tests/NonUksP0FixesRegressionTests.cs new file mode 100644 index 0000000..ee52fe2 --- /dev/null +++ b/Tests/NonUksP0FixesRegressionTests.cs @@ -0,0 +1,38 @@ +/* + * Regression tests for P0 non-UKS fixes (2026-07-07). + */ + +using BrainSimulator; +using Xunit; + +namespace UKS.Tests; + +public class NonUksP0FixesRegressionTests +{ + [Fact] + public void HSLColor_Equals_does_not_merge_hues_beyond_threshold_across_wrap() + { + var a = new HSLColor(350f, 0.8f, 0.5f); + var b = new HSLColor(10f, 0.8f, 0.5f); + + Assert.False(a.Equals(b)); + } + + [Fact] + public void HSLColor_Equals_distinguishes_visually_different_hues() + { + var a = new HSLColor(30f, 0.8f, 0.5f); + var b = new HSLColor(200f, 0.8f, 0.5f); + + Assert.False(a.Equals(b)); + } + + [Fact] + public void HSLColor_Equals_treats_near_wrap_pairs_as_equal() + { + var a = new HSLColor(2f, 0.8f, 0.5f); + var b = new HSLColor(358f, 0.8f, 0.5f); + + Assert.True(a.Equals(b)); + } +} \ No newline at end of file diff --git a/Tests/NonUksP1FixesRegressionTests.cs b/Tests/NonUksP1FixesRegressionTests.cs new file mode 100644 index 0000000..4d559b7 --- /dev/null +++ b/Tests/NonUksP1FixesRegressionTests.cs @@ -0,0 +1,39 @@ +/* + * Regression tests for P1 non-UKS fixes (2026-07-07). + */ + +using BrainSimulator; +using UKS; +using Xunit; + +namespace UKS.Tests; + +public class NonUksP1FixesRegressionTests +{ + [Fact] + public void Broadcast_does_not_throw_when_ipv4_unavailable() + { + Exception ex = Record.Exception(() => Network.Broadcast("brainsim-test")); + Assert.Null(ex); + } + + [Fact] + public void DeactivateModule_preserves_shared_link_targets() + { + var uks = new UKS.UKS(clear: true); + uks.CreateInitialStructure(); + var handler = new ModuleHandler(); + + Thought shared = uks.GetOrAddThought("SharedConfig", "Object"); + Thought moduleType = uks.GetOrAddThought("ModuleTest", uks.Labeled("AvailableModule")); + Thought instance = uks.CreateInstanceOf(moduleType); + uks.AddStatement(instance, "is", shared); + + string instanceLabel = instance.Label; + handler.DeactivateModule(instanceLabel); + + Assert.NotNull(uks.Labeled("SharedConfig")); + Assert.NotNull(uks.Labeled(moduleType.Label)); + Assert.Null(uks.Labeled(instanceLabel)); + } +} \ No newline at end of file diff --git a/Tests/NonUksP2FixesRegressionTests.cs b/Tests/NonUksP2FixesRegressionTests.cs new file mode 100644 index 0000000..9771bcf --- /dev/null +++ b/Tests/NonUksP2FixesRegressionTests.cs @@ -0,0 +1,52 @@ +/* + * Regression tests for P2 non-UKS fixes (2026-07-07). + */ + +using UKS; +using Xunit; + +namespace UKS.Tests; + +public class NonUksP2FixesRegressionTests +{ + [Fact] + public void Thought_GetTargetOfFirstLinkOfType_string_overload() + { + var uks = new UKS.UKS(clear: true); + uks.CreateInitialStructure(); + Thought parent = uks.GetOrAddThought("phrase1", "Object"); + Thought linkType = uks.GetOrAddThought("soundAs", "LinkType"); + var seq = uks.AddSequenceAndLink(parent, linkType, new List { uks.GetOrAddThought("note1", "Object") }); + Assert.NotNull(seq); + Thought target = parent.GetTargetOfFirstLinkOfType("soundAs"); + Assert.Same(seq, target); + } + + [Fact] + public void Bundled_wordlist_resource_exists() + { + string repoRoot = FindRepoRoot(); + string wordlist = Path.Combine(repoRoot, "BrainSimulator", "Resources", "wordlist.txt"); + Assert.True(File.Exists(wordlist)); + } + + [Fact] + public void Legacy_sources_moved_to_archive() + { + string repoRoot = FindRepoRoot(); + Assert.True(File.Exists(Path.Combine(repoRoot, "BrainSimulator", "archive", "legacy", "XmlFile.cs"))); + Assert.False(File.Exists(Path.Combine(repoRoot, "BrainSimulator", "XmlFile.cs"))); + } + + private static string FindRepoRoot() + { + var dir = new DirectoryInfo(Directory.GetCurrentDirectory()); + while (dir is not null) + { + if (File.Exists(Path.Combine(dir.FullName, "BrainSim Thought.sln"))) + return dir.FullName; + dir = dir.Parent; + } + throw new DirectoryNotFoundException("BrainSim Thought repo root not found."); + } +} \ No newline at end of file diff --git a/Tests/NonUksRemainingFixesRegressionTests.cs b/Tests/NonUksRemainingFixesRegressionTests.cs new file mode 100644 index 0000000..5f52939 --- /dev/null +++ b/Tests/NonUksRemainingFixesRegressionTests.cs @@ -0,0 +1,56 @@ +/* + * Regression tests for remaining P1 (#9-10) and P3 (#19-23) non-UKS fixes (2026-07-07). + */ + +using System.Reflection; +using System.Threading.Tasks; +using BrainSimulator; +using BrainSimulator.Modules; +using Xunit; + +namespace UKS.Tests; + +public class NonUksRemainingFixesRegressionTests +{ + [Fact] + public void GetStringFromThoughtLabel_empty_returns_empty() + { + var method = typeof(ModuleGPTInfo).GetMethod( + "GetStringFromThoughtLabel", + BindingFlags.NonPublic | BindingFlags.Static); + Assert.NotNull(method); + var result = (string)method!.Invoke(null, new object[] { "" })!; + Assert.Equal("", result); + } + + [Fact] + public void HSLColor_ToColor_hue345_returns_defined_color() + { + var hsl = new HSLColor(345f, 0.8f, 0.5f); + var color = hsl.ToColor(); + Assert.InRange(color.R + color.G + color.B, 1, 765); + } + + [Theory] + [InlineData(nameof(ModuleOnlineInfo.GetKidsWordsmythNet))] + [InlineData(nameof(ModuleOnlineInfo.GetWiktionaryData))] + [InlineData(nameof(ModuleOnlineInfo.GetChatGPTResult))] + [InlineData(nameof(ModuleOnlineInfo.GetWikidataData))] + [InlineData(nameof(ModuleOnlineInfo.GetFreeDictionaryAPIData))] + [InlineData(nameof(ModuleOnlineInfo.GetWebstersDictionaryAPIData))] + public void ModuleOnlineInfo_public_fetch_methods_return_task(string methodName) + { + var method = typeof(ModuleOnlineInfo).GetMethod(methodName); + Assert.NotNull(method); + Assert.Equal(typeof(Task), method!.ReturnType); + } + + [Fact] + public void ModuleBalanceTreeDlg_code_behind_uses_xaml_cs_suffix() + { + var repoRoot = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "..")); + var path = Path.Combine(repoRoot, "BrainSimulator", "Modules", "Agents", "ModuleBalanceTreeDlg.xaml.cs"); + Assert.True(File.Exists(path), $"Expected code-behind at {path}"); + Assert.False(File.Exists(path.Replace(".xaml.cs", ".xml.cs"))); + } +} \ No newline at end of file diff --git a/Tests/UKSFixesRegressionTests.cs b/Tests/UKSFixesRegressionTests.cs new file mode 100644 index 0000000..f0ef3bd --- /dev/null +++ b/Tests/UKSFixesRegressionTests.cs @@ -0,0 +1,117 @@ +/* + * Regression tests for UKS fixes (2026-07-07 inspection) + */ + +using System.IO; +using UKS; +using Xunit; + +namespace UKS.Tests; + +public class UKSFixesRegressionTests +{ + private static UKS CreateUks() { var uks = new UKS(clear: true); uks.CreateInitialStructure(); return uks; } + + [Fact] + public void LinksAreExclusive_CommonParentSources_AreExclusive() + { + var uks = CreateUks(); + uks.AddStatement("animal", "is-a", "Object"); + uks.AddStatement("dog", "is-a", "animal"); + uks.AddStatement("cat", "is-a", "animal"); + uks.AddStatement("legs", "is-a", "Object"); + uks.AddStatement("has.4", "is-a", "has"); + + var dogLegs = uks.GetLink(uks.AddStatement("dog", "has.4", "legs")); + var catLegs = uks.GetLink(uks.AddStatement("cat", "has.4", "legs")); + + Assert.NotNull(dogLegs); + Assert.NotNull(catLegs); + Assert.True(uks.LinksAreExclusive_ForTests(dogLegs, catLegs)); + } + + [Fact] + public void ChildrenWithSubclasses_UsesIsA_NotLabelPrefix() + { + var uks = CreateUks(); + uks.AddStatement("dog", "is-a", "Object"); + uks.AddStatement("doghouse", "is-a", "Object"); + uks.AddStatement("puppy", "is-a", "dog"); + + var dog = uks.Labeled("dog"); + var doghouse = uks.Labeled("doghouse"); + var puppy = uks.Labeled("puppy"); + var children = dog.ChildrenWithSubclasses; + + Assert.Contains(puppy, children); + Assert.DoesNotContain(doghouse, children); + } + + [Fact] + public void AddStatement_WiresLabeledPlaceholder() + { + var uks = CreateUks(); + uks.AddStatement("dog", "is-a", "Object"); + uks.AddStatement("Fido", "is-a", "dog"); + + var placeholder = new Link { Label = "mylink" }; + uks.AtomicThoughts.Add(placeholder); + + var link = uks.AddStatement(uks.Labeled("Fido"), uks.Labeled("is-a"), uks.Labeled("dog"), "mylink"); + + Assert.NotNull(link); + Assert.Same(uks.Labeled("Fido"), link.From); + Assert.NotNull(link.From.HasLink(uks.Labeled("is-a"), uks.Labeled("dog"))); + } + + [Fact] + public void XmlRoundTrip_PreservesLink() + { + var uks = CreateUks(); + uks.AddStatement("dog", "is-a", "Object"); + uks.AddStatement("Fido", "is-a", "dog"); + + string path = Path.Combine(Path.GetTempPath(), $"uks_roundtrip_{Guid.NewGuid():N}.xml"); + try + { + Assert.True(uks.SaveUKStoXMLFile(path)); + + var uks2 = new UKS(clear: true); + Assert.True(uks2.LoadUKSfromXMLFile(path)); + + Assert.NotNull(uks2.Labeled("Fido")); + Assert.NotNull(uks2.GetLink(uks2.Labeled("Fido"), uks2.Labeled("is-a"), uks2.Labeled("dog"))); + } + finally + { + if (File.Exists(path)) File.Delete(path); + } + } + + [Fact] + public void ExportTextFile_ThrowsOnInvalidPath() + { + var uks = CreateUks(); + uks.AddStatement("dog", "is-a", "Object"); + Assert.Throws(() => + uks.ExportTextFile("Object", "/nonexistent_path_zzzz/export.txt")); + } + + [Fact] + public void HasSequence_UnsupportedFlagsThrow() + { + var uks = CreateUks(); + var targets = new List { uks.GetOrAddThought("A"), uks.GetOrAddThought("B") }; + Assert.Throws(() => + uks.HasSequence(targets, uks.Labeled("spelled"), circularSearch: true)); + } + + [Fact] + public void CreateMinimumStructure_RegistersNxtNotNxe() + { + var uks = new UKS(clear: true); + uks.CreateMinimumStructureForTests(); + Assert.NotNull(uks.Labeled("NXT")); + Assert.Null(uks.Labeled("NXE")); + } +} \ No newline at end of file diff --git a/Tests/VisionCompatRegressionTests.cs b/Tests/VisionCompatRegressionTests.cs new file mode 100644 index 0000000..33e8f63 --- /dev/null +++ b/Tests/VisionCompatRegressionTests.cs @@ -0,0 +1,52 @@ +/* + * Regression tests for Vision / BrainSim3 UKS compatibility layer. + */ + +using UKS; +using Xunit; + +namespace UKS.Tests; + +public class VisionCompatRegressionTests +{ + [Fact] + public void GetOrAddThing_alias_matches_GetOrAddThought() + { + var uks = new UKS.UKS(clear: true); + uks.CreateInitialStructure(); + Thought t = uks.GetOrAddThing("VisionTest", "Object"); + Assert.Same(t, uks.Labeled("VisionTest")); + } + + [Fact] + public void SetAttribute_and_GetAttribute_round_trip() + { + var uks = new UKS.UKS(clear: true); + uks.CreateInitialStructure(); + uks.AddStatement("Color", "is-a", "Attribute"); + Thought shape = uks.GetOrAddThought("shape1", "Object"); + Thought color = uks.GetOrAddThought("color1", "Color"); + shape.SetAttribute(color); + Assert.Same(color, shape.GetAttribute("Color")); + } + + [Fact] + public void SearchForClosestMatch_ref_returns_ranked_results() + { + var uks = new UKS.UKS(clear: true); + uks.CreateInitialStructure(); + Thought root = uks.GetOrAddThought("Stored", "Object"); + Thought a = uks.GetOrAddThought("a", root); + Thought b = uks.GetOrAddThought("b", root); + Thought target = uks.GetOrAddThought("target", "Object"); + uks.AddStatement(target, "is", a); + uks.AddStatement(a, "is", b); + + float best = 0; + Thought? first = uks.SearchForClosestMatch(target, root, ref best); + Assert.NotNull(first); + float best2 = 0; + Thought? second = uks.GetNextClosestMatch(ref best2); + Assert.True(first is not null); + } +} \ No newline at end of file diff --git a/UKS/IReadOnlyListExtensiion.cs b/UKS/IReadOnlyListExtension.cs similarity index 100% rename from UKS/IReadOnlyListExtensiion.cs rename to UKS/IReadOnlyListExtension.cs diff --git a/UKS/Relationship.cs b/UKS/Relationship.cs new file mode 100644 index 0000000..0a21110 --- /dev/null +++ b/UKS/Relationship.cs @@ -0,0 +1,33 @@ +/* + * BrainSim3 compatibility wrapper over UKS Link (Thought/Link model). + */ + +namespace UKS; + +/// Legacy BrainSim3 relationship view of a . +public sealed class Relationship +{ + public Link Link { get; } + + public Relationship(Link link) => Link = link; + + public Thought? target => Link?.To; + public Thought? relType => Link?.LinkType; + public Thought? reltype => Link?.LinkType; + + public float Weight + { + get => Link?.Weight ?? 0f; + set { if (Link is not null) Link.Weight = value; } + } + + public TimeSpan TimeToLive + { + get => Link?.TimeToLive ?? TimeSpan.MaxValue; + set { if (Link is not null) Link.TimeToLive = value; } + } + + public static Relationship? FromLink(Link? link) => link is null ? null : new Relationship(link); + + public static implicit operator Relationship?(Link? link) => FromLink(link); +} \ No newline at end of file diff --git a/UKS/Thought.BrainSim3Compat.cs b/UKS/Thought.BrainSim3Compat.cs new file mode 100644 index 0000000..8365bcb --- /dev/null +++ b/UKS/Thought.BrainSim3Compat.cs @@ -0,0 +1,104 @@ +/* + * BrainSim3 / Vision API compatibility on Thought (maps to Link graph). + */ + +namespace UKS; + +public partial class Thought +{ + /// Legacy casing alias for . + public DateTime lastFiredTime + { + get => LastFiredTime; + set => LastFiredTime = value; + } + + public IReadOnlyList Relationships => + LinksTo.Select(r => Relationship.FromLink(r)).Where(r => r is not null).Cast().ToList(); + + public IReadOnlyList RelationshipsFrom => + LinksFrom.Select(r => Relationship.FromLink(r)).Where(r => r is not null).Cast().ToList(); + + public void SetFired() => Fire(); + + public bool HasAncestorLabeled(string label) + { + Thought? ancestor = UKS.theUKS?.Labeled(label); + return ancestor is not null && HasAncestor(ancestor); + } + + public Thought? GetAttribute(string name) + { + if (string.IsNullOrWhiteSpace(name)) return null; + foreach (Link r in LinksTo) + { + if (r.LinkType?.Label is not ("hasAttribute" or "is")) continue; + if (r.To is null) continue; + if (string.Equals(r.To.Label, name, StringComparison.OrdinalIgnoreCase)) + return r.To; + foreach (Thought parent in r.To.Parents) + { + if (string.Equals(parent.Label, name, StringComparison.OrdinalIgnoreCase)) + return r.To; + } + if (r.To.HasAncestorLabeled(name)) + return r.To; + } + return null; + } + + public Relationship? SetAttribute(Thought attribute) + { + if (attribute is null || UKS.theUKS is null) return null; + Thought hasAttribute = UKS.theUKS.GetOrAddThought("hasAttribute", "LinkType"); + foreach (Link existing in LinksTo.ToList()) + { + if (existing.LinkType?.Label != "hasAttribute") continue; + if (existing.To is null) continue; + bool sameCategory = existing.To.Parents.Any(p => attribute.Parents.Contains(p)) + || existing.To.Label == attribute.Label; + if (sameCategory) + RemoveLink(existing); + } + Link link = UKS.theUKS.AddStatement(this, hasAttribute, attribute); + return Relationship.FromLink(link); + } + + public void AddRelationship(Thought target, string linkTypeLabel) + { + if (target is null || UKS.theUKS is null) return; + Thought linkType = UKS.theUKS.GetOrAddThought(linkTypeLabel, "LinkType"); + UKS.theUKS.AddStatement(this, linkType, target); + } + + public void AddRelationship(string targetLabel, string linkTypeLabel) + { + if (UKS.theUKS is null) return; + Thought target = UKS.theUKS.GetOrAddThought(targetLabel, "Object"); + AddRelationship(target, linkTypeLabel); + } + + public List GetRelationshipsWithAncestor(Thought ancestor) + { + List retVal = new(); + if (ancestor is null) return retVal; + foreach (Link r in LinksTo) + if (r.To?.HasAncestor(ancestor) == true) + { + var wrapped = Relationship.FromLink(r); + if (wrapped is not null) retVal.Add(wrapped); + } + return retVal; + } + + public Relationship? HasRelationshipWithAncestorLabeled(string label) + { + Thought? ancestor = UKS.theUKS?.Labeled(label); + if (ancestor is null) return null; + Link? link = LinksTo.FindFirst(r => r.To?.HasAncestor(ancestor) == true); + return Relationship.FromLink(link); + } + + public void AddRelationship(Thought target, Thought linkType) => + UKS.theUKS?.AddStatement(this, linkType, target); +} \ No newline at end of file diff --git a/UKS/Thought.cs b/UKS/Thought.cs index 17f4e86..43d87e1 100644 --- a/UKS/Thought.cs +++ b/UKS/Thought.cs @@ -58,9 +58,10 @@ public override string ToString() /// A Thought is an atomic unit of thought. In the lexicon of graphs, a Thought is both a "node" and an Edge. /// A Thought can represent anything, physical object, attribute, word, action, feeling, etc. /// -public class Thought +public partial class Thought { - private static Queue recentlyFired = new(); + private static readonly Queue recentlyFired = new(); + private static readonly object recentlyFiredLock = new(); public static Thought IsA { get => ThoughtLabels.GetThought("is-a"); } //this is a cache value shortcut for (Thought)"is-a" private readonly List _linksTo = new(); // links to "has", "is", is-a, many others @@ -103,7 +104,7 @@ public string Label public void Delete() { - if (LinksFrom.FindFirst(x=>x.LinkType.Label == "VLU") is not null) + if (LinksFrom.FindFirst(x => x.LinkType?.Label == "VLU") is not null) { //this Thought is the object of a sequence. } @@ -274,15 +275,16 @@ public IReadOnlyList ChildrenWithSubclasses { get { - List retVal = Children.ToList(); - for (int i = 0; i < retVal.Count; i++) + List retVal = new(); + HashSet seen = new(); + foreach (Thought child in Children) { - Thought t = retVal[i]; - if (t.Label.StartsWith(this._label)) + if (seen.Add(child)) + retVal.Add(child); + foreach (Thought descendant in child.Descendants) { - retVal.AddRange(t.Children); - retVal.RemoveAt(i); - i--; + if (seen.Add(descendant)) + retVal.Add(descendant); } } return retVal; @@ -376,21 +378,30 @@ public void Fire() private void AddToRecentlyFired() { int maxCount = 100; - recentlyFired.Enqueue(this); - while (recentlyFired.Count > maxCount) _ = recentlyFired.Dequeue(); + lock (recentlyFiredLock) + { + recentlyFired.Enqueue(this); + while (recentlyFired.Count > maxCount) _ = recentlyFired.Dequeue(); + } } public static void DeleteFromRecentlyFired(Thought t) { - //CAUTION NOT THREAD SAFE - var tempList = recentlyFired.Where(x => x != t).ToList(); - recentlyFired = new Queue(tempList); + lock (recentlyFiredLock) + { + var tempList = recentlyFired.Where(x => x != t).ToList(); + recentlyFired.Clear(); + foreach (var item in tempList) + recentlyFired.Enqueue(item); + } } public static IReadOnlyList GetRecentlyFiredThoughts(TimeSpan recency) { //remove duplicates while preserving order (keeping the most recent occurrence of each Thought) DateTime cutoff = DateTime.MinValue; if (recency < DateTime.Now-DateTime.MinValue) cutoff = DateTime.Now - recency; - var snapshot = recentlyFired.Where(x=>x.LastFiredTime > cutoff).ToArray(); + Thought[] snapshot; + lock (recentlyFiredLock) + snapshot = recentlyFired.Where(x=>x.LastFiredTime > cutoff).ToArray(); var seen = new HashSet(); var resultRev = new List(); foreach (var item in snapshot.Reverse()) @@ -403,17 +414,23 @@ public static IReadOnlyList GetRecentlyFiredThoughts(TimeSpan recency) public static void FireAllRecentlyFiredThoughts(TimeSpan recency) { DateTime cutoff = DateTime.Now - recency; - var snapshot = recentlyFired.ToArray(); - var seen = new HashSet(); - var resultRev = new List(); - - foreach (var item in snapshot.Reverse()) + List resultRev; + lock (recentlyFiredLock) { - if (seen.Add(item)) - resultRev.Add(item); // keep first time we see it from the back (i.e., the last occurrence) + var snapshot = recentlyFired.ToArray(); + var seen = new HashSet(); + resultRev = new List(); + + foreach (var item in snapshot.Reverse()) + { + if (seen.Add(item)) + resultRev.Add(item); + } + resultRev.Reverse(); + recentlyFired.Clear(); + foreach (var item in resultRev) + recentlyFired.Enqueue(item); } - resultRev.Reverse(); - recentlyFired = new(resultRev); // restore original ordering of the kept items foreach (Thought t in resultRev.Where(x => x.LastFiredTime > cutoff)) { @@ -422,7 +439,8 @@ public static void FireAllRecentlyFiredThoughts(TimeSpan recency) } public static void ClearRecentlyFiredQueue() { - recentlyFired.Clear(); + lock (recentlyFiredLock) + recentlyFired.Clear(); } private void UpdateTimeToLive() @@ -520,6 +538,7 @@ public void RemoveLink(Link r) if (r.LinkType is null) return; if (r.From is null) { + if (r.To is null) return; lock (r.LinkType._linksFrom) { lock (r.To._linksFrom) @@ -562,6 +581,11 @@ public Thought GetTargetOfFirstLinkOfType(Thought linkType) { return LinksTo.FindFirst(x => x.LinkType == linkType)?.To; } + + public Thought GetTargetOfFirstLinkOfType(string linkTypeLabel) + { + return LinksTo.FindFirst(x => x.LinkType?.Label == linkTypeLabel)?.To; + } public Link HasLink(Thought linkType, Thought to = null) { foreach (Link r in _linksTo) diff --git a/UKS/UKS .Initialize.cs b/UKS/UKS .Initialize.cs index e7b5a7a..8a6884f 100644 --- a/UKS/UKS .Initialize.cs +++ b/UKS/UKS .Initialize.cs @@ -27,7 +27,7 @@ public void CreateMinimumStructureForTests() isA.AddParent(linkType); GetOrAddThought("Unknown", "Thought"); GetOrAddThought("VLU", "LinkType"); - GetOrAddThought("NXE", "LinkType"); + GetOrAddThought("NXT", "LinkType"); GetOrAddThought("FRST", "LinkType"); } diff --git a/UKS/UKS.BrainSim3Compat.cs b/UKS/UKS.BrainSim3Compat.cs new file mode 100644 index 0000000..ac15009 --- /dev/null +++ b/UKS/UKS.BrainSim3Compat.cs @@ -0,0 +1,102 @@ +/* + * BrainSim3 / Vision API compatibility on UKS. + */ + +namespace UKS; + +public partial class UKS +{ + private List<(Thought t, float conf)>? _closestMatchResults; + private int _closestMatchIndex; + + public IReadOnlyList UKSList + { + get + { + lock (AtomicThoughts) + return AtomicThoughts.ToList(); + } + } + + public Thought GetOrAddThing(string label, object parent = null, Thought source = null) => + GetOrAddThought(label, parent, source); + + public Thought AddThing(string label, Thought parent) => + GetOrAddThought(label, parent); + + public void DeleteAllChildren(Thought t) + { + if (t is null) return; + foreach (Thought child in t.Children.ToList()) + child.Delete(); + } + + public Relationship? GetRelationship(string fromLabel, string linkTypeLabel, string toLabel) + { + Thought? from = Labeled(fromLabel); + Thought? linkType = Labeled(linkTypeLabel); + Thought? to = Labeled(toLabel); + if (from is null || linkType is null || to is null) return null; + return Relationship.FromLink(GetLink(from, linkType, to)); + } + + public Thought? SearchForClosestMatch(Thought target, Thought root, ref float bestValue) + { + _closestMatchResults = SearchForClosestMatch(target, root); + _closestMatchIndex = 0; + if (_closestMatchResults.Count == 0) + { + bestValue = 0; + return null; + } + bestValue = _closestMatchResults[0].conf; + return _closestMatchResults[0].t; + } + + public Thought? GetNextClosestMatch(ref float bestValue) + { + if (_closestMatchResults is null) return null; + _closestMatchIndex++; + if (_closestMatchIndex >= _closestMatchResults.Count) + return null; + bestValue = _closestMatchResults[_closestMatchIndex].conf; + return _closestMatchResults[_closestMatchIndex].t; + } + + /// Compare rotational go* feature chains between stored and live shapes. + public float HasSequence(Thought candidate, Thought pattern, out int offset, bool circular) + { + offset = 0; + List patternLinks = pattern.LinksTo + .Where(x => x.LinkType?.Label?.StartsWith("go", StringComparison.OrdinalIgnoreCase) == true) + .ToList(); + List candidateLinks = candidate.LinksTo + .Where(x => x.LinkType?.Label?.StartsWith("go", StringComparison.OrdinalIgnoreCase) == true) + .ToList(); + if (patternLinks.Count == 0 || candidateLinks.Count == 0) + return 0f; + + float bestScore = 0f; + int bestOffset = 0; + int maxStart = circular ? candidateLinks.Count : 1; + for (int start = 0; start < maxStart; start++) + { + int matches = 0; + for (int i = 0; i < patternLinks.Count; i++) + { + int ci = circular ? (start + i) % candidateLinks.Count : start + i; + if (ci >= candidateLinks.Count) break; + if (patternLinks[i].To?.Label == candidateLinks[ci].To?.Label) + matches++; + } + float score = (float)matches / patternLinks.Count; + if (score > bestScore) + { + bestScore = score; + bestOffset = start; + } + } + offset = bestOffset; + return bestScore; + } +} \ No newline at end of file diff --git a/UKS/UKS.Exclusivity.cs b/UKS/UKS.Exclusivity.cs index bf88f57..a040154 100644 --- a/UKS/UKS.Exclusivity.cs +++ b/UKS/UKS.Exclusivity.cs @@ -56,10 +56,13 @@ private bool LinksAreExclusive(Link r1, Link r2) if (r2.HasProperty("isResult")) return false; if (r2.HasProperty("isCondition")) return false; + if (LinkTypesAreExclusive(r1, r2)) + return true; + if (r1.From == r2.From || r1.From.AncestorsWithSelf.Contains(r2.From) || r2.From.AncestorsWithSelf.Contains(r1.From) || - FindCommonParents(r1.From, r1.From).Count() > 0) + FindCommonParents(r1.From, r2.From).Count > 0) { IReadOnlyList r1LinkiProps = r1.LinkType.GetAttributes(); @@ -67,8 +70,7 @@ private bool LinksAreExclusive(Link r1, Link r2) //handle case with properties of the target if (r1.To is not null && r1.To == r2.To && (r1.To.AncestorsWithSelf.Contains(r2.To) || - r2.To.AncestorsWithSelf.Contains(r1.To) || - FindCommonParents(r1.To, r1.To).Count() > 0)) + r2.To.AncestorsWithSelf.Contains(r1.To))) { IReadOnlyList r1TargetProps = r1.To.GetAttributes(); IReadOnlyList r2TargetProps = r2.To.GetAttributes(); diff --git a/UKS/UKS.Sequence.cs b/UKS/UKS.Sequence.cs index d57d18b..23962a1 100644 --- a/UKS/UKS.Sequence.cs +++ b/UKS/UKS.Sequence.cs @@ -201,7 +201,21 @@ public SeqElement InsertElement(SeqElement prevElementIn, Thought value) } else { - throw new NotImplementedException(); + SeqElement? predecessor = prevElementIn.FRST; + while (predecessor?.NXT is not null && predecessor.NXT != prevElementIn) + predecessor = predecessor.NXT; + if (predecessor is null || predecessor.NXT != prevElementIn) + throw new ArgumentException("prevElementIn is not in its FRST chain", nameof(prevElementIn)); + + SeqElement newNode = new() + { + Label = prevElementIn.Label + "*", + FRST = prevElementIn.FRST, + NXT = prevElementIn, + }; + newNode.AddLink("VLU", value); + predecessor.NXT = newNode; + return prevElementIn.FRST ?? first; } return first; } @@ -308,7 +322,7 @@ public int GetHashCode(IReadOnlyList list) } public SeqElement AddSequence(string label, List targets, bool allowCompression = true) { - if (targets.Count < 1) return null; //a sequence must have at least 2 elements + if (targets.Count < 2) return null; //a sequence must have at least 2 elements List resolvedTargets = new(targets); @@ -370,7 +384,7 @@ public SeqElement AddSequence(string label, List targets, bool allowCom /// The first node of the created or reused sequence, or null if insufficient targets. public SeqElement AddSequenceAndLink(Thought source, Thought linkType, List targets, float baseWeight = 1.0f) { - if (targets.Count < 1) return null; //a sequence must have at least 2 elements + if (targets.Count < 2) return null; //a sequence must have at least 2 elements //clear out any existing sequence links of this type source.RemoveLinks(linkType); //TODO delete the sequence @@ -414,7 +428,10 @@ public Thought GetReferrer(SeqElement seqNode, Thought linkType) public List<(SeqElement seqNode, float confidence)> HasSequence(List targets, Thought linkType, bool mustMatchFirst = false, bool mustMatchLast = false, bool circularSearch = false, bool allowOutOfOrder = false) { - //this function searches the UKS for sequences matching the specified pattern in targets. + if (circularSearch || allowOutOfOrder) + throw new NotSupportedException("circularSearch and allowOutOfOrder are not yet implemented."); + + //this function searches the UKS for sequences matching the specified pattern in targets. //If circularSearch is true, then the search will consider sequences that wrap around from end to start Thought. //If firstLastPriority is true, then matches that have the first and last elements matching will be given higher confidence @@ -757,9 +774,13 @@ public IEnumerable EnumerateSequenceElements(SeqElement sequenceStar if (visitedSequences.Contains(sequenceStart)) yield break; // Already visited this sequence, stop to prevent infinite recursion visitedSequences.Push(sequenceStart); var current = sequenceStart; + var visitedInMain = new HashSet(); while (current is not null) { + if (!visitedInMain.Add(current)) + break; + // Get the VLU Linkto find what this sequence node points to Thought valueRel = GetElementValue(current); @@ -776,10 +797,6 @@ public IEnumerable EnumerateSequenceElements(SeqElement sequenceStar // Move to next node via NXT Link current = GetNextElement(current); - if (current is null) break; - - // Stop if we've circled back to the start - if (current == sequenceStart) break; //BROKEN? } visitedSequences.Pop(); } diff --git a/UKS/UKS.Statement.cs b/UKS/UKS.Statement.cs index a4c265b..13e2f84 100644 --- a/UKS/UKS.Statement.cs +++ b/UKS/UKS.Statement.cs @@ -44,36 +44,31 @@ public Link AddStatement(Thought source, Thought linkType, Thought target, strin { if (source is null || linkType is null) return null; - Thought t = Labeled(label); - Link existing = t as Link; - Link lnk = null; - if (existing is null) existing = GetLink(source, linkType, target); + Link wired = GetLink(source, linkType, target); + Link labeledLink = string.IsNullOrEmpty(label) ? null : Labeled(label) as Link; + bool isUnwiredPlaceholder = labeledLink is not null && labeledLink.From is null; - if (existing is null) + source.Fire(); + linkType.Fire(); + target?.Fire(); + + if (wired is not null && !isUnwiredPlaceholder) { - //create the link but don't add it to the UKS - lnk = CreateTheLink(source, linkType, target); - existing = GetLink(lnk); + WeakenConflictingLinks(source, wired); + wired.Fire(); + return wired; } - else - { - existing.LinkType = linkType; - existing.To = target; - existing.From = source; - } - source.Fire(); - linkType.Fire(); - target?.Fire(); - - //does this link already exist (without conditions)? - if (existing is not null) + + Link lnk = isUnwiredPlaceholder ? labeledLink : CreateTheLink(source, linkType, target); + if (isUnwiredPlaceholder) { - WeakenConflictingLinks(source, existing); - existing.Fire(); - return existing; + lnk.From = source; + lnk.LinkType = linkType; + lnk.To = target; } - if (lnk?.From?.Label == "") lnk.From.AddDefaultLabel(); - if (lnk?.To?.Label == "") lnk.To.AddDefaultLabel(); + + if (lnk.From?.Label == "") lnk.From.AddDefaultLabel(); + if (lnk.To?.Label == "") lnk.To.AddDefaultLabel(); if (!string.IsNullOrEmpty(label)) lnk.Label = label.Trim(); diff --git a/UKS/UKS.TextFile.cs b/UKS/UKS.TextFile.cs index f5be1ec..70ec8a9 100644 --- a/UKS/UKS.TextFile.cs +++ b/UKS/UKS.TextFile.cs @@ -10,6 +10,7 @@ * * See the LICENSE file in the project root for full license information. */ +using System.Diagnostics; using System.Text; using System.Text.RegularExpressions; @@ -50,7 +51,10 @@ public void ExportTextFile(string root, string path, int maxDepth = 12) } } catch (Exception ex) - { } + { + Debug.WriteLine($"ExportTextFile failed: {ex}"); + throw; + } RemoveTempLabels(Root); } @@ -147,27 +151,16 @@ public void ImportTextFile(string filePath) .Where(label => referencedLabels.Contains(label)) .ToList(); - // Now pre-allocate only the labels that are actually used as references + // Pre-allocate unwired Link placeholders only for forward references (label not yet defined) foreach (var label in labelsToPreAllocate) { Thought existing = Labeled(label); - if (existing is null) - { - Link placeholder = new Link(); - placeholder.Label = label; - AtomicThoughts.Add(placeholder); - } - else if (existing is not Link) - { - // Existing Thought needs to become a Link - existing.Label = ""; // Release the label - Link replacement = new Link(); - replacement.Label = label; - AtomicThoughts.Add(replacement); - - if (existing.LinksTo.Count == 0 && existing.LinksFrom.Count == 0) - existing.Delete(); - } + if (existing is not null) + continue; + + Link placeholder = new Link(); + placeholder.Label = label; + AtomicThoughts.Add(placeholder); } // THIRD PASS: Actually process the lines diff --git a/UKS/UKS.XMLFile.cs b/UKS/UKS.XMLFile.cs index 1daa6ed..c391060 100644 --- a/UKS/UKS.XMLFile.cs +++ b/UKS/UKS.XMLFile.cs @@ -105,6 +105,7 @@ private int GetIndex(Thought t) { index = UKSTemp.Count, label = t.Label, + weight = t.Weight, V = t.V, }; if (t is Link lnk) @@ -121,32 +122,9 @@ private int GetIndex(Thought t) private void FormatContentForSaving(Thought root) { - // TODO: Wipe transient data ... - //foreach (Thought t in AllThoughts) GetIndex(root); foreach (var t in root.EnumerateSubThoughts()) - { - string label = t.Label; - if (string.IsNullOrWhiteSpace(label)) // Put the GUID into the label only when it's unlabeled - label = $"unl_{Guid.NewGuid().ToString("N")[..8]}"; - int from = GetIndex((t as Link)?.From); - int sType = GetIndex((t as Link)?.LinkType); - int to = GetIndex((t as Link)?.To); - if (UKSTemp.Count >= 170) - { } - - sThought st = new() - { - index = UKSTemp.Count, - label = label, - source = from, - linkType = sType, - target = to, - weight = t.Weight, - V = t.V, - }; - UKSTemp.Add(st); - } + GetIndex(t); RemoveTempLabels(root); } @@ -269,7 +247,8 @@ private void MergeStringListIntoUKS(List contentToRestore) AddThought("BrainSim", null); foreach (string s in contentToRestore) { - string[] strings = s.Split("->"); + if (string.IsNullOrWhiteSpace(s)) continue; + ProcessSingleLine(s.Trim()); } } @@ -329,6 +308,8 @@ private void DeFormatContentAfterLoading() theLink.TimeToLive = TimeSpan.MaxValue; Link newLink = theLink.From.AddLink(theLink.LinkType, theLink.To); newLink.Weight = st.weight; + if (!AtomicThoughts.Contains(newLink)) + AtomicThoughts.Add(newLink); if (linkType.Label == "VLU") PromoteToSeqElement(theLink.From); } diff --git a/tools/generate_nature_animals_xml.py b/tools/generate_nature_animals_xml.py new file mode 100644 index 0000000..2a70557 --- /dev/null +++ b/tools/generate_nature_animals_xml.py @@ -0,0 +1,359 @@ +#!/usr/bin/env python3 +"""Generate NatureAnimals.xml — sThought UKS import for BrainSim-Thought.""" + +from __future__ import annotations +import uuid +from pathlib import Path + +OUTPUT = Path(__file__).resolve().parents[1] / "BrainSimulator" / "UKSContent" / "NatureAnimals.xml" + +nodes: list[str] = [] +links: list[tuple[int, int, int, float | None]] = [] +index_by_label: dict[str, int] = {} + + +def unl() -> str: + return f"unl_{uuid.uuid4().hex[:8]}" + + +def add_node(label: str) -> int: + if label in index_by_label: + return index_by_label[label] + idx = len(nodes) + nodes.append(label) + index_by_label[label] = idx + return idx + + +def add_link(source: str, link_type: str, target: str, weight: float | None = None) -> int: + links.append((index_by_label[source], index_by_label[link_type], index_by_label[target], weight)) + return len(nodes) + len(links) - 1 + + +def build() -> None: + # --- Bootstrap ontology (required for UKS loader) --- + for label in ( + "Thought", "Unknown", "LinkType", "Object", "Property", "Comparison", + "bodyPart", "habitat", "sound", "Action", + ): + add_node(label) + + for label in ( + "is-a", "has", "has-child", "is", "can", "hasProperty", + "isSimilarTo", "differsFrom", "predatorOf", "preyOf", "livesIn", "eats", + "has.4", "has.3", "has.2", "has.6", "has.8", "has.0", + "warmBlooded", "coldBlooded", "givesLiveBirth", "laysEggs", "vertebrate", + "NOT", "not", + ): + add_node(label) + + # --- Nature taxonomy --- + for label in ( + "nature", "livingThing", "animal", "plant", "ecosystem", + "mammal", "bird", "reptile", "fish", "amphibian", "insect", + "dog", "cat", "horse", "whale", "bat", "mouse", "wolf", "deer", "dolphin", + "eagle", "sparrow", "penguin", "owl", + "snake", "turtle", "crocodile", + "salmon", "shark", "trout", + "frog", "bee", "ant", + "leg", "tail", "fur", "feather", "scale", "fin", "wing", "gill", "beak", + "bark(dog)", "meow(cat)", "neigh(horse)", "buzz(bee)", + "forest", "ocean", "sky", "grassland", "antarctica", "river", "tree", + "brown", "black", "golden", "green", "gray", + "pet", "wild", + # Named instances (Fido-style) + "Fido", "Tripper", "Whiskers", "Shadow", "Buddy", + "Talon", "Slither", "Echo", "Nemo", "Penny", "Bramble", + ): + add_node(label) + + ISA = "is-a" + HAS = "has" + IS = "is" + CAN = "can" + HP = "hasProperty" + + # Ontology structure + add_link("Unknown", ISA, "Thought") + add_link("LinkType", ISA, "Thought") + add_link("Object", ISA, "Thought") + add_link("Property", ISA, "Thought") + add_link("Comparison", ISA, "Property") + add_link("bodyPart", ISA, "Object") + add_link("habitat", ISA, "Object") + add_link("sound", ISA, "Object") + add_link("Action", ISA, "Thought") + add_link("nature", ISA, "Thought") + + add_link(ISA, ISA, "LinkType") + add_link(HAS, ISA, "LinkType") + add_link("has-child", ISA, "LinkType") + add_link(IS, ISA, "LinkType") + add_link(CAN, ISA, "LinkType") + add_link(HP, ISA, "LinkType") + add_link("isSimilarTo", ISA, "LinkType") + add_link("isSimilarTo", ISA, "Comparison") + add_link("differsFrom", ISA, "LinkType") + add_link("differsFrom", ISA, "Comparison") + add_link("predatorOf", ISA, "LinkType") + add_link("preyOf", ISA, "LinkType") + add_link("livesIn", ISA, "LinkType") + add_link("eats", ISA, "LinkType") + + for n in ("has.4", "has.3", "has.2", "has.6", "has.8", "has.0"): + add_link(n, ISA, HAS) + + for n in ("warmBlooded", "coldBlooded", "givesLiveBirth", "laysEggs", "vertebrate"): + add_link(n, ISA, "Property") + + add_link("NOT", ISA, "Property") + add_link("not", ISA, "NOT") + + # Living things hierarchy + add_link("livingThing", ISA, "Object") + add_link("ecosystem", ISA, "Object") + add_link("animal", ISA, "livingThing") + add_link("plant", ISA, "livingThing") + add_link("tree", ISA, "plant") + + add_link("mammal", ISA, "animal") + add_link("bird", ISA, "animal") + add_link("reptile", ISA, "animal") + add_link("fish", ISA, "animal") + add_link("amphibian", ISA, "animal") + add_link("insect", ISA, "animal") + + # Species → class + for species, cls in ( + ("dog", "mammal"), ("cat", "mammal"), ("horse", "mammal"), ("whale", "mammal"), + ("bat", "mammal"), ("mouse", "mammal"), ("wolf", "mammal"), ("deer", "mammal"), + ("dolphin", "mammal"), + ("eagle", "bird"), ("sparrow", "bird"), ("penguin", "bird"), ("owl", "bird"), + ("snake", "reptile"), ("turtle", "reptile"), ("crocodile", "reptile"), + ("salmon", "fish"), ("shark", "fish"), ("trout", "fish"), + ("frog", "amphibian"), ("bee", "insect"), ("ant", "insect"), + ): + add_link(species, ISA, cls) + + # Body parts + for part in ("leg", "tail", "fur", "feather", "scale", "fin", "wing", "gill", "beak"): + add_link(part, ISA, "bodyPart") + + # Sounds + for snd in ("bark(dog)", "meow(cat)", "neigh(horse)", "buzz(bee)"): + add_link(snd, ISA, "sound") + + # Habitats + for h in ("forest", "ocean", "sky", "grassland", "antarctica", "river"): + add_link(h, ISA, "habitat") + + # Class-level properties (inheritance) + add_link("mammal", HP, "warmBlooded") + add_link("mammal", HP, "givesLiveBirth") + add_link("mammal", HP, "vertebrate") + add_link("bird", HP, "warmBlooded") + add_link("bird", HP, "laysEggs") + add_link("bird", HP, "vertebrate") + add_link("reptile", HP, "coldBlooded") + add_link("reptile", HP, "laysEggs") + add_link("reptile", HP, "vertebrate") + add_link("fish", HP, "coldBlooded") + add_link("fish", HP, "laysEggs") + add_link("fish", HP, "vertebrate") + add_link("amphibian", HP, "coldBlooded") + add_link("amphibian", HP, "laysEggs") + add_link("insect", HP, "coldBlooded") + add_link("animal", HP, "vertebrate") + + # Class-level anatomy (inherited by instances) + add_link("dog", HAS, "tail") + add_link("dog", "has.4", "leg") + add_link("dog", HAS, "fur") + add_link("dog", CAN, "bark(dog)") + add_link("cat", HAS, "tail") + add_link("cat", "has.4", "leg") + add_link("cat", HAS, "fur") + add_link("cat", CAN, "meow(cat)") + add_link("horse", HAS, "tail") + add_link("horse", "has.4", "leg") + add_link("horse", CAN, "neigh(horse)") + add_link("whale", HAS, "fin") + add_link("whale", "has.0", "leg") # exception: no legs + add_link("bat", HAS, "wing") + add_link("bat", "has.4", "leg") + add_link("mouse", "has.4", "leg") + add_link("mouse", HAS, "tail") + add_link("wolf", HAS, "tail") + add_link("wolf", "has.4", "leg") + add_link("wolf", HAS, "fur") + add_link("deer", "has.4", "leg") + add_link("deer", HAS, "tail") + add_link("dolphin", HAS, "fin") + add_link("dolphin", "has.0", "leg") + + add_link("bird", HAS, "wing") + add_link("bird", HAS, "feather") + add_link("bird", "has.2", "leg") + add_link("bird", HAS, "beak") + add_link("eagle", "has.2", "wing") + add_link("sparrow", "has.2", "wing") + add_link("penguin", "has.2", "wing") + add_link("owl", "has.2", "wing") + + add_link("reptile", HAS, "scale") + add_link("snake", "has.0", "leg") + add_link("snake", HAS, "scale") + add_link("turtle", "has.4", "leg") + add_link("turtle", HAS, "scale") + add_link("crocodile", "has.4", "leg") + add_link("crocodile", HAS, "scale") + + add_link("fish", HAS, "fin") + add_link("fish", HAS, "gill") + add_link("fish", HAS, "scale") + add_link("salmon", HAS, "fin") + add_link("shark", HAS, "fin") + add_link("shark", "has.0", "leg") + + add_link("frog", "has.4", "leg") + add_link("bee", HAS, "wing") + add_link("bee", "has.6", "leg") + add_link("bee", CAN, "buzz(bee)") + add_link("ant", "has.6", "leg") + + # Pet / wild classification + add_link("dog", ISA, "pet") + add_link("cat", ISA, "pet") + add_link("horse", ISA, "pet") + add_link("wolf", ISA, "wild") + add_link("eagle", ISA, "wild") + add_link("deer", ISA, "wild") + + # Cross-species similarities and differences + add_link("dog", "isSimilarTo", "wolf") + add_link("dog", "isSimilarTo", "cat") + add_link("cat", "isSimilarTo", "dog") + add_link("wolf", "isSimilarTo", "dog") + add_link("salmon", "isSimilarTo", "trout") + add_link("eagle", "isSimilarTo", "owl") + + add_link("dog", "differsFrom", "bird") + add_link("bird", "differsFrom", "fish") + add_link("mammal", "differsFrom", "reptile") + add_link("whale", "differsFrom", "fish") + add_link("bat", "differsFrom", "bird") + add_link("snake", "differsFrom", "dog") + + # Predator / prey chains + add_link("eagle", "predatorOf", "mouse") + add_link("mouse", "preyOf", "eagle") + add_link("wolf", "predatorOf", "deer") + add_link("deer", "preyOf", "wolf") + add_link("shark", "predatorOf", "salmon") + add_link("salmon", "preyOf", "shark") + add_link("owl", "predatorOf", "mouse") + add_link("cat", "predatorOf", "mouse") + + # Habitat relationships + add_link("deer", "livesIn", "forest") + add_link("eagle", "livesIn", "sky") + add_link("salmon", "livesIn", "river") + add_link("whale", "livesIn", "ocean") + add_link("shark", "livesIn", "ocean") + add_link("dolphin", "livesIn", "ocean") + add_link("penguin", "livesIn", "antarctica") + add_link("sparrow", "livesIn", "forest") + add_link("frog", "livesIn", "river") + add_link("tree", "livesIn", "forest") + + # Diet + add_link("dog", "eats", "salmon") + add_link("cat", "eats", "mouse") + add_link("eagle", "eats", "mouse") + add_link("wolf", "eats", "deer") + add_link("shark", "eats", "salmon") + + # --- Named instances (Fido pattern) --- + add_link("Fido", ISA, "dog") + add_link("Fido", IS, "brown") + add_link("Fido", "has.4", "leg") + add_link("Fido", "livesIn", "grassland") + + add_link("Tripper", ISA, "dog") + add_link("Tripper", "has.3", "leg") # README exception: 3 legs overrides inherited 4 + + add_link("Whiskers", ISA, "cat") + add_link("Whiskers", IS, "black") + add_link("Whiskers", "livesIn", "grassland") + + add_link("Shadow", ISA, "horse") + add_link("Shadow", IS, "brown") + add_link("Shadow", "livesIn", "grassland") + + add_link("Buddy", ISA, "dog") + add_link("Buddy", IS, "golden") + + add_link("Talon", ISA, "eagle") + add_link("Talon", "livesIn", "sky") + + add_link("Slither", ISA, "snake") + add_link("Slither", IS, "green") + add_link("Slither", "livesIn", "forest") + + add_link("Echo", ISA, "bat") + add_link("Echo", "livesIn", "forest") + + add_link("Nemo", ISA, "salmon") + add_link("Nemo", "livesIn", "river") + + add_link("Penny", ISA, "penguin") + add_link("Penny", "livesIn", "antarctica") + + add_link("Bramble", ISA, "deer") + add_link("Bramble", IS, "brown") + add_link("Bramble", "livesIn", "forest") + + +def render_xml() -> str: + lines = [ + '', + '', + ] + for i, label in enumerate(nodes): + lines.extend([ + " ", + f" {i}", + f" ", + " ", + ]) + base = len(nodes) + for j, (src, lt, tgt, weight) in enumerate(links): + idx = base + j + lines.extend([ + " ", + f" {idx}", + f" ", + f" {src}", + f" {lt}", + f" {tgt}", + ]) + if weight is not None: + lines.append(f" {weight}") + lines.append(" ") + lines.append("") + return "\n".join(lines) + "\n" + + +def main() -> None: + build() + xml = render_xml() + OUTPUT.parent.mkdir(parents=True, exist_ok=True) + OUTPUT.write_text(xml, encoding="utf-8") + print(f"Wrote {OUTPUT}") + print(f" nodes: {len(nodes)}") + print(f" links: {len(links)}") + print(f" total sThought entries: {len(nodes) + len(links)}") + + +if __name__ == "__main__": + main() \ No newline at end of file From 2fb5d9940d4811a48d04f3f0ff81bb9eff2619b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Slabber?= Date: Wed, 8 Jul 2026 15:00:31 +0200 Subject: [PATCH 2/9] Regression Tests fixed --- BrainSimulator/AssemblyInfo.cs | 3 + BrainSimulator/BrainSim Thought.csproj | 5 +- BrainSimulator/MainWindow.xaml.cs | 38 +-- BrainSimulator/MainWindowFiles.cs | 1 - BrainSimulator/ModuleViewMenu.cs | 1 - .../Modules/Agents/ModuleAddCounts.cs | 2 +- .../Modules/Agents/ModuleAttributeBubble.cs | 2 +- .../Modules/Agents/ModuleBalanceTree.cs | 3 +- .../Modules/Agents/ModuleClassCreate.cs | 2 +- .../Modules/Agents/ModuleRemoveRedundancy.cs | 2 +- BrainSimulator/Modules/GPT.cs | 4 +- BrainSimulator/Modules/ModuleAlgorithm.cs | 9 +- BrainSimulator/Modules/ModuleAttention.cs | 58 ---- BrainSimulator/Modules/ModuleBaseDlg.cs | 24 +- BrainSimulator/Modules/ModuleGPTInfo.cs | 3 +- .../Modules/ModuleGPTInfoDlg.xaml.cs | 19 +- .../Modules/ModuleLearnMelodyDlg.xaml.cs | 2 +- BrainSimulator/Modules/ModuleOnlineInfo.cs | 23 +- .../Modules/ModuleOnlineInfoDlg.xaml.cs | 18 +- BrainSimulator/Modules/ModuleSoundIn.cs | 4 +- BrainSimulator/Modules/ModuleSoundOut.cs | 8 +- BrainSimulator/Modules/ModuleStressTest.cs | 2 - .../Modules/ModuleStressTestDlg.xaml.cs | 2 +- BrainSimulator/Modules/ModuleText.cs | 74 +---- BrainSimulator/Modules/ModuleUKSDlg.xaml | 2 +- BrainSimulator/Modules/ModuleUKSDlg.xaml.cs | 10 +- .../Modules/ModuleUKSQueryDlg.xaml.cs | 1 - BrainSimulator/Modules/PointPlus.cs | 27 +- .../Modules/Vision/ModuleVision.Boundary.cs | 3 +- .../Modules/Vision/ModuleVisionDlg.xaml.cs | 35 ++- BrainSimulator/Network.cs | 2 +- Tests/InheritanceCh5RegressionTests.cs | 160 +++++++++++ Tests/ModuleAlgorithm.Tests.cs | 54 ++-- Tests/ModuleAttributeBubbleTests.cs | 4 +- Tests/ModuleMentelModelTests.cs | 2 +- Tests/NonUksP1FixesRegressionTests.cs | 2 +- Tests/NonUksP2FixesRegressionTests.cs | 9 +- Tests/NonUksRemainingFixesRegressionTests.cs | 1 + Tests/Tests.csproj | 4 +- Tests/UKSFixesRegressionTests.cs | 3 +- Tests/VisionCompatRegressionTests.cs | 10 +- UKS.Tests/AssemblyInfo.cs | 3 + UKS.Tests/UKS.Tests.csproj | 22 +- UKS/Thought.BrainSim3Compat.cs | 15 +- UKS/Thought.cs | 102 +++++-- UKS/ThoughtLabels.cs | 10 +- UKS/UKS .Initialize.cs | 44 ++- UKS/UKS.BrainSim3Compat.cs | 4 +- UKS/UKS.Exclusivity.cs | 33 ++- UKS/UKS.Query.cs | 216 ++++++++------ UKS/UKS.Sequence.cs | 27 +- UKS/UKS.Statement.cs | 62 ++-- UKS/UKS.TextFile.cs | 64 +++-- UKS/UKS.XMLFile.cs | 84 +++--- UKS/UKS.cs | 87 +++--- UKS/UKS.csproj | 1 + test-log.txt | 266 ++++++++++++++++++ 57 files changed, 1056 insertions(+), 622 deletions(-) create mode 100644 Tests/InheritanceCh5RegressionTests.cs create mode 100644 UKS.Tests/AssemblyInfo.cs create mode 100644 test-log.txt diff --git a/BrainSimulator/AssemblyInfo.cs b/BrainSimulator/AssemblyInfo.cs index 8d0dca9..41a0b5f 100644 --- a/BrainSimulator/AssemblyInfo.cs +++ b/BrainSimulator/AssemblyInfo.cs @@ -10,8 +10,11 @@ * * See the LICENSE file in the project root for full license information. */ +using System.Runtime.CompilerServices; using System.Windows; +[assembly: InternalsVisibleTo("Tests")] + [assembly: ThemeInfo( ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located //(used if a resource is not found in the page, diff --git a/BrainSimulator/BrainSim Thought.csproj b/BrainSimulator/BrainSim Thought.csproj index 676960f..825e1f8 100644 --- a/BrainSimulator/BrainSim Thought.csproj +++ b/BrainSimulator/BrainSim Thought.csproj @@ -12,7 +12,7 @@ 1.6.4 Iconsmall.ico build$([System.DateTime]::UtcNow.ToString("yyyyMMddHHmmss")) - AllEnabledByDefault + Default true @@ -24,6 +24,9 @@ False preview + + + diff --git a/BrainSimulator/MainWindow.xaml.cs b/BrainSimulator/MainWindow.xaml.cs index d8fa77e..6ae9a45 100644 --- a/BrainSimulator/MainWindow.xaml.cs +++ b/BrainSimulator/MainWindow.xaml.cs @@ -51,40 +51,6 @@ private void MainWindow_Loaded(object sender, RoutedEventArgs e) //setup the python support pythonPath = (string)Environment.GetEnvironmentVariable("PythonPath", EnvironmentVariableTarget.User); - if (false) - //if (string.IsNullOrEmpty(pythonPath)) - { - var result1 = MessageBox.Show("Do you want to use Python Modules?", "Python?", MessageBoxButton.YesNo); - if (result1 == MessageBoxResult.Yes) - { - string likeliPath = (string)Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); - likeliPath += @"\Programs\Python"; - System.Windows.Forms.OpenFileDialog openFileDialog = new() - { - Title = "SELECT path to Python .dll (or cancel for no Python support)", - InitialDirectory = likeliPath, - }; - - // Show the file Dialog. - System.Windows.Forms.DialogResult result = openFileDialog.ShowDialog(); - // If the user clicked OK in the dialog and - if (result == System.Windows.Forms.DialogResult.OK) - { - pythonPath = openFileDialog.FileName; - Environment.SetEnvironmentVariable("PythonPath", pythonPath, EnvironmentVariableTarget.User); - } - else - { - Environment.SetEnvironmentVariable("PythonPath", "", EnvironmentVariableTarget.User); - } - openFileDialog.Dispose(); - } - else - { - pythonPath = "no"; - Environment.SetEnvironmentVariable("PythonPath", pythonPath, EnvironmentVariableTarget.User); - } - } moduleHandler.PythonPath = pythonPath; if (pythonPath != "no") { @@ -112,7 +78,7 @@ private void MainWindow_Loaded(object sender, RoutedEventArgs e) CreateEmptyUKS(); } } - catch (Exception ex) + catch (Exception) { System.Windows.MessageBox.Show("UKS Content not loaded"); } @@ -327,7 +293,7 @@ public static void ResumeEngine() } //THIS IS THE MAIN ENGINE LOOP - private void Dt_Tick(object? sender, EventArgs e) + private void Dt_Tick(object sender, EventArgs e) { Thought activeModuleParent = theUKS.Labeled("ActiveModule"); if (activeModuleParent is null) return; diff --git a/BrainSimulator/MainWindowFiles.cs b/BrainSimulator/MainWindowFiles.cs index 50aea99..e5438bc 100644 --- a/BrainSimulator/MainWindowFiles.cs +++ b/BrainSimulator/MainWindowFiles.cs @@ -29,7 +29,6 @@ namespace BrainSimulator /// public partial class MainWindow : Window { - private static StackPanel loadedModulesSP; private bool LoadFile(string fileName) { SuspendEngine(); diff --git a/BrainSimulator/ModuleViewMenu.cs b/BrainSimulator/ModuleViewMenu.cs index 5103beb..4b8b156 100644 --- a/BrainSimulator/ModuleViewMenu.cs +++ b/BrainSimulator/ModuleViewMenu.cs @@ -33,7 +33,6 @@ public void CreateContextMenu(ModuleBase nr, FrameworkElement r, ContextMenu cm cm = new ContextMenu(); cm.SetValue(moduleNameProperty, nr.Label); - StackPanel sp; MenuItem mi = new MenuItem(); mi = new MenuItem(); mi.Header = "Delete"; diff --git a/BrainSimulator/Modules/Agents/ModuleAddCounts.cs b/BrainSimulator/Modules/Agents/ModuleAddCounts.cs index 5d480f8..7a0476b 100644 --- a/BrainSimulator/Modules/Agents/ModuleAddCounts.cs +++ b/BrainSimulator/Modules/Agents/ModuleAddCounts.cs @@ -33,7 +33,7 @@ public override void Fire() UpdateDialog(); } - public bool isEnabled { get; set; } + public new bool isEnabled { get; set; } private Timer timer; //private UKS.UKS theUKS1; diff --git a/BrainSimulator/Modules/Agents/ModuleAttributeBubble.cs b/BrainSimulator/Modules/Agents/ModuleAttributeBubble.cs index c293f63..212f84b 100644 --- a/BrainSimulator/Modules/Agents/ModuleAttributeBubble.cs +++ b/BrainSimulator/Modules/Agents/ModuleAttributeBubble.cs @@ -34,7 +34,7 @@ public override void Fire() UpdateDialog(); } - public bool isEnabled { get; set; } + public new bool isEnabled { get; set; } private Timer timer; //private UKS.UKS theUKS1; diff --git a/BrainSimulator/Modules/Agents/ModuleBalanceTree.cs b/BrainSimulator/Modules/Agents/ModuleBalanceTree.cs index 899df25..3717c39 100644 --- a/BrainSimulator/Modules/Agents/ModuleBalanceTree.cs +++ b/BrainSimulator/Modules/Agents/ModuleBalanceTree.cs @@ -35,13 +35,12 @@ public override void Fire() UpdateDialog(); } - public bool isEnabled { get; set; } + public new bool isEnabled { get; set; } private Timer timer; //private UKS.UKS theUKS1; public string debugString = "Initialized\n"; private int maxChildren = 6; - private int minCommonAttributes = 3; public int MaxChildren { get => maxChildren; set => maxChildren = value; } private void Setup() diff --git a/BrainSimulator/Modules/Agents/ModuleClassCreate.cs b/BrainSimulator/Modules/Agents/ModuleClassCreate.cs index 402049c..b901966 100644 --- a/BrainSimulator/Modules/Agents/ModuleClassCreate.cs +++ b/BrainSimulator/Modules/Agents/ModuleClassCreate.cs @@ -32,7 +32,7 @@ public override void Fire() UpdateDialog(); } - public bool isEnabled { get; set; } + public new bool isEnabled { get; set; } private Timer timer; //private UKS.UKS theUKS1; diff --git a/BrainSimulator/Modules/Agents/ModuleRemoveRedundancy.cs b/BrainSimulator/Modules/Agents/ModuleRemoveRedundancy.cs index 6cc2aa2..cd86ac3 100644 --- a/BrainSimulator/Modules/Agents/ModuleRemoveRedundancy.cs +++ b/BrainSimulator/Modules/Agents/ModuleRemoveRedundancy.cs @@ -31,7 +31,7 @@ public override void Fire() UpdateDialog(); } - public bool isEnabled { get; set; } + public new bool isEnabled { get; set; } private Timer timer; //private UKS.UKS theUKS1; diff --git a/BrainSimulator/Modules/GPT.cs b/BrainSimulator/Modules/GPT.cs index 0daf626..68a5bca 100644 --- a/BrainSimulator/Modules/GPT.cs +++ b/BrainSimulator/Modules/GPT.cs @@ -118,9 +118,9 @@ public static async Task GetGPTResult(string userText, string systemText else if (completionResult.error is not null) answerString = "ERROR: " + completionResult.error.message; } - catch (Exception ex) + catch (Exception) { - throw ex; + throw; } // Deserialize the response body to a CompletionResult object diff --git a/BrainSimulator/Modules/ModuleAlgorithm.cs b/BrainSimulator/Modules/ModuleAlgorithm.cs index d937cf9..1ab6e6c 100644 --- a/BrainSimulator/Modules/ModuleAlgorithm.cs +++ b/BrainSimulator/Modules/ModuleAlgorithm.cs @@ -221,6 +221,7 @@ public bool ExecuteTask(string taskName, string param1Value = "", string param2V LastLinkWritten = null; CycleCount = 0; LastAction = ""; + Thought.ClearRecentlyFiredQueue(); if (theUKS == null) return false; @@ -276,7 +277,11 @@ public bool ExecuteTask(string taskName, string param1Value = "", string param2V Thought mainTaskThought = theUKS.Labeled(mainTaskName); if (mainTaskThought is not null) { - mainTaskThought.Fire(); + SeqElement mainSteps = mainTaskThought.GetTargetOfFirstLinkOfType("steps") as SeqElement; + if (mainSteps is not null) + mainSteps.Fire(); + else + mainTaskThought.Fire(); } } @@ -315,7 +320,7 @@ private bool ExecuteAllSteps() while (HandleFiringNeurons()) { } ; - LastAction = $"TASK COMPLETE ({CycleCount} cycles): {LastLinkWritten.ToString()}"; + LastAction = $"TASK COMPLETE ({CycleCount} cycles): {LastLinkWritten?.ToString()}"; LastExecutedStep = null; return true; } diff --git a/BrainSimulator/Modules/ModuleAttention.cs b/BrainSimulator/Modules/ModuleAttention.cs index d111f34..225339a 100644 --- a/BrainSimulator/Modules/ModuleAttention.cs +++ b/BrainSimulator/Modules/ModuleAttention.cs @@ -33,7 +33,6 @@ public class ModuleAttention : ModuleBase private Thought _queueRoot; private Thought _predRoot; private Thought _ltQueued; - private Thought _ltQueueFor; private Thought _ltPredItem; private Thought _ltPredFrom; private Thought _ltPredTo; @@ -226,9 +225,6 @@ private void PruneAttentionQueue(DateTime now, ModuleMentalModel mm) private void TouchQueueItem(Thought focus) { return; - var item = FindQueueItemFor(focus); - if (item is null) return; - item.LastFiredTime = DateTime.Now; } private IEnumerable<(Thought item, Thought target)> EnumerateQueueItems() @@ -263,68 +259,26 @@ private void RemoveQueueItem(Thought item) private float ComputeSalience(Thought t, ModuleMentalModel mm, double surprise, int seenCount, DateTime lastSeen) { return .5f; - if (t is null || mm is null) return 0; - double novelty = 1.0 / (1.0 + t.UseCount); - double activation = ComputeActivation(t); - double proximity = mm.ComputeProximity(t); - double habituation = seenCount <= 0 ? 0 : seenCount / (seenCount + HabituationDenominator); - double recencyPenalty = (DateTime.Now - lastSeen).TotalSeconds / AttentionStaleSeconds; - recencyPenalty = Math.Max(0, recencyPenalty); - - double sal = wNovelty * novelty - + wActivation * activation - + wSurprise * surprise - + wProximity * proximity - - wHabituation * habituation - - 0.05 * recencyPenalty; - return (float)Math.Max(0, sal); } private static float ComputeActivation(Thought t) { return 0.5f; - double seconds = Math.Max(0, (DateTime.Now - t.LastFiredTime).TotalSeconds); - return (float)Math.Exp(-seconds / ActivationHalfLifeSeconds); } private void BoostActivation(Thought t) { return; - float boosted = t.Weight + ActivationBoost; - t.Weight = (float)Math.Min(boosted, ActivationBoostMax); } private void ActivateRelated(Thought focus) { return; - foreach (var link in focus.LinksTo.Where(x => - x.LinkType?.Label is "is-a" or "hasAttribute" or "is" or "part-of" or "means")) - link.To?.Fire(); - - foreach (var link in focus.LinksFrom.Where(x => - x.LinkType?.Label is "is-a" or "part-of" or "means")) - link.From?.Fire(); } private void BuildPredictions(Thought focus) { return; - EnsureLinkTypes(); - ClearPredictions(); - - foreach (var link in focus.LinksFrom.Where(x => x.LinkType?.Label == "VLU")) - { - if (link.From is not SeqElement elem) continue; - SeqElement nxt = elem.NXT; - Thought nextValue = nxt?.VLU; - if (nextValue is null) continue; - - Thought predItem = theUKS.GetOrAddThought("_attn:pred:*", "attention"); - _predRoot.AddLink(_ltPredItem, predItem); - predItem.AddLink(_ltPredFrom, elem); - predItem.AddLink(_ltPredTo, nextValue); - predItem.TimeToLive = TimeSpan.FromSeconds(5); - } } private IEnumerable<(SeqElement source, Thought next)> FindPredictionsFor(Thought focus) @@ -354,23 +308,11 @@ private IEnumerable EnumeratePredictionTargets() private void ClearPredictions() { return; - EnsureLinkTypes(); - foreach (var link in _predRoot.LinksTo.Where(x => x.LinkType == _ltPredItem).ToList()) - { - Thought pred = link.To; - _predRoot.RemoveLink(link); - pred?.Delete(); - } } private static void ReinforcePrediction((SeqElement source, Thought next) pred) { return; - pred.source.Fire(); - var nxtLink = pred.source.LinksToWriteable.FindFirst(x => x.LinkType?.Label == "NXT"); - nxtLink?.Fire(); - pred.source.NXT?.Fire(); - pred.next.Fire(); } private ModuleMentalModel GetMentalModel() diff --git a/BrainSimulator/Modules/ModuleBaseDlg.cs b/BrainSimulator/Modules/ModuleBaseDlg.cs index 52c679e..9aabf24 100644 --- a/BrainSimulator/Modules/ModuleBaseDlg.cs +++ b/BrainSimulator/Modules/ModuleBaseDlg.cs @@ -28,8 +28,6 @@ namespace BrainSimulator.Modules; public class ModuleBaseDlg : Window { public ModuleBase ParentModule; - private DateTime dt; - private DispatcherTimer timer; public int UpdateMS = 100; public Label statusLabel; private bool initializedLayout = false; @@ -45,7 +43,7 @@ private void ModuleBaseDlg_Loaded(object sender, RoutedEventArgs e) initializedLayout = true; // capture original content - UIElement? originalContent = this.Content as UIElement; + UIElement originalContent = this.Content as UIElement; // create outer grid (single row) and overlay bottom bar at the bottom Grid shell = new() @@ -128,7 +126,7 @@ private void ModuleBaseDlg_Loaded(object sender, RoutedEventArgs e) /// Searches for a file with the given name (no path) in the specified root directory /// and all its subdirectories. /// - public static string? FindFile(string rootPath, string fileName) + public static string FindFile(string rootPath, string fileName) { if (!Directory.Exists(rootPath)) throw new DirectoryNotFoundException($"Root path not found: {rootPath}"); @@ -188,24 +186,6 @@ virtual public bool Draw(bool checkDrawTimer) return true; } - public void Timer_Tick(object sender, EventArgs e) - { - timer.Stop(); - if (Application.Current is null) return; - if (this is not null) - Draw(false); - - } - - //this picks up a final draw after 1/4 second - public void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) - { - timer.Stop(); - if (Application.Current is null) return; - if (this is not null) - Draw(false); - } - /// /// Sets a status message at the bottom of the dialog. Seets the background yellow if the color is red or null /// diff --git a/BrainSimulator/Modules/ModuleGPTInfo.cs b/BrainSimulator/Modules/ModuleGPTInfo.cs index 01ff081..7d0caa7 100644 --- a/BrainSimulator/Modules/ModuleGPTInfo.cs +++ b/BrainSimulator/Modules/ModuleGPTInfo.cs @@ -643,7 +643,7 @@ public static void ParseGPTOutput(string textIn, string GPTOutput) } } - public static async Task SolveDuplicates() + public static Task SolveDuplicates() { // Get the UKS. UKS.UKS theUKS = MainWindow.theUKS; @@ -685,6 +685,7 @@ public static async Task SolveDuplicates() ModuleGPTInfoDlg.linkCount++; } + return Task.CompletedTask; } } diff --git a/BrainSimulator/Modules/ModuleGPTInfoDlg.xaml.cs b/BrainSimulator/Modules/ModuleGPTInfoDlg.xaml.cs index 3969a40..36da545 100644 --- a/BrainSimulator/Modules/ModuleGPTInfoDlg.xaml.cs +++ b/BrainSimulator/Modules/ModuleGPTInfoDlg.xaml.cs @@ -215,7 +215,7 @@ public async Task ProcessWordsAsync(List words) if (word == words.Last()) await ModuleGPTInfo.GetChatGPTData(word.Trim()); if (word.Trim() != "") - ModuleGPTInfo.GetChatGPTData(word.Trim()); + _ = ModuleGPTInfo.GetChatGPTData(word.Trim()); } txtOutput.Text = $"Done running! Total word count: {words.Count}. Total link count: {linkCount}. Total error count (not accepted): {errorCount}."; @@ -235,7 +235,7 @@ public async Task ProcessAmbiguityAsync(List words) if (word == words.Last()) await ModuleGPTInfo.DisambiguateTermsFile(word.Trim()); if (word.Trim() != "") - ModuleGPTInfo.DisambiguateTermsFile(word.Trim()); + _ = ModuleGPTInfo.DisambiguateTermsFile(word.Trim()); } txtOutput.Text = $"Done running! Total word count: {words.Count}. Total link count: {linkCount}. Total error count (not accepted): {errorCount}."; @@ -254,7 +254,7 @@ public async Task ProcessParentsAsync(List words) if (word == words.Last()) await ModuleGPTInfo.GetChatGPTParents(word.Trim()); if (word.Trim() != "") - ModuleGPTInfo.GetChatGPTParents(word.Trim()); + _ = ModuleGPTInfo.GetChatGPTParents(word.Trim()); } SetOutputText($"Done processing unknowns! Total word count: {words.Count}. Total link count: {linkCount}. Total error count (not accepted): {errorCount}."); @@ -275,25 +275,26 @@ public async Task verifyAllAsync() if (t == mf.theUKS.AtomicThoughts.Last()) await VerifyAsync(t.Label); else - VerifyAsync(t.Label); + _ = VerifyAsync(t.Label); } SetOutputText($"Done verifying is-a links for reasonableness. Checked {count} links."); } - public async Task VerifyAsync(string label) + public Task VerifyAsync(string label) { ModuleGPTInfo mf = (ModuleGPTInfo)base.ParentModule; if (!label.StartsWith(".")) label = "." + label; UKS.Thought t = mf.theUKS.Labeled(label); - if (t is null) return; + if (t is null) return Task.CompletedTask; foreach (Link r in t.LinksTo) { //if (r.GPTVerified) continue; if (r.LinkType.Label != "has-child") continue; count++; - ModuleGPTInfo.GetChatGPTVerifyParentChild(r.To.Label, t.Label); + _ = ModuleGPTInfo.GetChatGPTVerifyParentChild(r.To.Label, t.Label); } + return Task.CompletedTask; } private void ClearButton_Click(object sender, RoutedEventArgs e) @@ -358,7 +359,7 @@ private void Button_Click(object sender, RoutedEventArgs e) } else if (b.Content.ToString().StartsWith("Verify All")) { - verifyAllAsync(); + _ = verifyAllAsync(); } else if (b.Content.ToString().StartsWith("Add Clauses To All")) { @@ -384,7 +385,7 @@ private void Button_Click(object sender, RoutedEventArgs e) words.Add(thought.Label); } - ProcessParentsAsync(words); + _ = ProcessParentsAsync(words); } } } diff --git a/BrainSimulator/Modules/ModuleLearnMelodyDlg.xaml.cs b/BrainSimulator/Modules/ModuleLearnMelodyDlg.xaml.cs index a7961b5..9db1c2d 100644 --- a/BrainSimulator/Modules/ModuleLearnMelodyDlg.xaml.cs +++ b/BrainSimulator/Modules/ModuleLearnMelodyDlg.xaml.cs @@ -86,7 +86,7 @@ private void TheGrid_SizeChanged(object sender, SizeChangedEventArgs e) Draw(false); } - private void SetStatus(string message, Color? color = null) + private new void SetStatus(string message, Color? color = null) { if (statusLabel != null) { diff --git a/BrainSimulator/Modules/ModuleOnlineInfo.cs b/BrainSimulator/Modules/ModuleOnlineInfo.cs index a0a7924..8fdf15f 100644 --- a/BrainSimulator/Modules/ModuleOnlineInfo.cs +++ b/BrainSimulator/Modules/ModuleOnlineInfo.cs @@ -149,7 +149,7 @@ public void GetCSKGData(string word) } } } - catch (Exception ex) + catch (Exception) { } Debug.WriteLine($"{count.ToString("N0")} entries with {countEN.ToString("N0")} in english"); } @@ -187,6 +187,10 @@ public override bool Equals(object obj) return this == r; return false; } + public override int GetHashCode() + { + return HashCode.Combine(rel, sourceURI, targetURI, fWeight); + } } public void ConceptNetLocal(string word) @@ -323,7 +327,7 @@ public void ConceptNetLocal(string word) } } } - catch (Exception ex) + catch (Exception) { } } @@ -427,7 +431,7 @@ private void ReadConceptNetFile() } } } - catch (Exception ex) + catch (Exception) { } foreach (var w in wordList2) { @@ -624,7 +628,7 @@ public void SetupWordList2(string wordIn = "") } } } - catch (Exception ex) + catch (Exception) { } wordList2 = wordList2.OrderBy(x => x.Item1).ToList(); GetUKS(); @@ -875,10 +879,6 @@ public async Task GetChatGPTResult(string textIn, QueryType qtIn = QueryType.isa { QueryType qType = qtIn; if (altLabel == "") altLabel = textIn; - string prompt; - string apiKey = ConfigurationManager.AppSettings["APIKey"]; - var client = new HttpClient(); - var url = "https://api.openai.com/v1/chat/completions"; string queryText = textIn; textIn = textIn.ToLower(); @@ -931,7 +931,7 @@ public async Task GetChatGPTResult(string textIn, QueryType qtIn = QueryType.isa else Output = answerString; } - catch (Exception ex) + catch (Exception) { } @@ -1020,7 +1020,7 @@ private async Task GetPropertiesFromURL(string itemID, string propName) @"?ps.OPTIONAL{?statement ?pq ?pq_. ?wdpq wikibase:qualifier " + @"?pq .} SERVICE wikibase:label { bd:serviceParam wikibase:language ""en"" }} " + @"ORDER BY ?wd ?statement ?ps_"; - url = urlBegin + Uri.EscapeUriString(url); + url = urlBegin + Uri.EscapeDataString(url); var myClient = new HttpClient(); myClient.DefaultRequestHeaders.Add("User-Agent", "c# program"); var responseURL = await myClient.GetAsync(url); @@ -1074,7 +1074,6 @@ private async Task GetPropertiesFromURL(string itemID, string propName) } docCount++; } - string propString = ""; //TextBoxWiki.Text = ""; for (int i = 0; i < docPropertyValues.Count; i++) { @@ -1098,7 +1097,6 @@ private async Task GetPropertiesFromURL(string itemID, string propName) int docCount = 0; foreach (XmlElement xn in docPropertyValues) { - bool found = false; string[] fn = new string[xn.ChildNodes.Count]; //Thought prop = new Thought(); for (int i = 0; i < xn.ChildNodes.Count; i++) @@ -1122,7 +1120,6 @@ private async Task GetPropertiesFromURL(string itemID, string propName) docCount++; } - string propString = ""; //TextBoxWiki.Text = ""; for (int i = 0; i < docPropertyValues.Count; i++) { diff --git a/BrainSimulator/Modules/ModuleOnlineInfoDlg.xaml.cs b/BrainSimulator/Modules/ModuleOnlineInfoDlg.xaml.cs index eaaccbc..b62e9a9 100644 --- a/BrainSimulator/Modules/ModuleOnlineInfoDlg.xaml.cs +++ b/BrainSimulator/Modules/ModuleOnlineInfoDlg.xaml.cs @@ -84,16 +84,16 @@ private void txtInput_PreviewKeyDown(object sender, KeyEventArgs e) { case "ChatGPT": if (txt.EndsWith("?")) - mcn.GetChatGPTResult(txt, ModuleOnlineInfo.QueryType.general); + _ = mcn.GetChatGPTResult(txt, ModuleOnlineInfo.QueryType.general); else if (txt.StartsWith("list some")) - mcn.GetChatGPTResult(txt.Substring(10), ModuleOnlineInfo.QueryType.list); + _ = mcn.GetChatGPTResult(txt.Substring(10), ModuleOnlineInfo.QueryType.list); else if (txt.StartsWith("count some")) - mcn.GetChatGPTResult(txt.Substring(11), ModuleOnlineInfo.QueryType.listCount); + _ = mcn.GetChatGPTResult(txt.Substring(11), ModuleOnlineInfo.QueryType.listCount); else if (txt.EndsWith("can")) - mcn.GetChatGPTResult(txt.Substring(0,txt.Length-3), ModuleOnlineInfo.QueryType.can); + _ = mcn.GetChatGPTResult(txt.Substring(0,txt.Length-3), ModuleOnlineInfo.QueryType.can); else { - mcn.GetChatGPTResult(txt, qType); + _ = mcn.GetChatGPTResult(txt, qType); //Thread.Sleep(1000); //mcn.GetChatGPTData(txt, ModuleOnlineInfo.QueryType.hasa); //Thread.Sleep(1000); @@ -108,16 +108,16 @@ private void txtInput_PreviewKeyDown(object sender, KeyEventArgs e) mcn.GetConceptNetData(txt); break; case "WikiData": - mcn.GetWikidataData(txt, "subclass of"); + _ = mcn.GetWikidataData(txt, "subclass of"); break; case "Wiktionary": - mcn.GetWiktionaryData(txt); + _ = mcn.GetWiktionaryData(txt); break; case "Free Dictionary": - mcn.GetFreeDictionaryAPIData(txt); + _ = mcn.GetFreeDictionaryAPIData(txt); break; case "Webster's Elementary": - mcn.GetWebstersDictionaryAPIData(txt); + _ = mcn.GetWebstersDictionaryAPIData(txt); break; case "Kid's Definition": mcn.GetKidsDefinition(txt); diff --git a/BrainSimulator/Modules/ModuleSoundIn.cs b/BrainSimulator/Modules/ModuleSoundIn.cs index 1aa9a39..1e06187 100644 --- a/BrainSimulator/Modules/ModuleSoundIn.cs +++ b/BrainSimulator/Modules/ModuleSoundIn.cs @@ -29,9 +29,7 @@ public class ModuleSoundIn : ModuleBase { DateTime lastFiredTime = DateTime.Now; - DateTime? lastNotePressed = null; DateTime lastCadenceTime = DateTime.Now; - List tuneToSearch = null; private readonly Dictionary _pitchs = new(); private const int MinNote = 60; // C4 @@ -42,7 +40,7 @@ public class ModuleSoundIn : ModuleBase private const int MidiPatch = 0; // Acoustic Grand Piano - public static MidiOut? midi; + public static MidiOut midi; public static MidiOut Midi => midi ??= InitMidi(); private static MidiOut InitMidi() diff --git a/BrainSimulator/Modules/ModuleSoundOut.cs b/BrainSimulator/Modules/ModuleSoundOut.cs index 19ef5d4..85ad45b 100644 --- a/BrainSimulator/Modules/ModuleSoundOut.cs +++ b/BrainSimulator/Modules/ModuleSoundOut.cs @@ -29,9 +29,7 @@ public class ModuleSoundOut : ModuleBase { DateTime lastFiredTime = DateTime.Now; - DateTime? lastNotePressed = null; DateTime lastCadenceTime = DateTime.Now; - List tuneToSearch = null; private readonly HashSet _pressedNotes = new(); private readonly Dictionary _pitchs = new(); @@ -43,13 +41,11 @@ public class ModuleSoundOut : ModuleBase private const int MidiPatch = 0; // Acoustic Grand Piano - IEnumerator enumerator = null; //we'll needc multiple enumerators soon - // Add these properties to the ModuleSound class public int Cadence { get; set; } = 100; public int PitchOffset { get; set; } = 0; - public static MidiOut? midi; + public static MidiOut midi; public static MidiOut Midi => midi ??= InitMidi(); private static MidiOut InitMidi() @@ -205,7 +201,7 @@ public async void PlayCMajorTriad(int timetonextMs = 300) Midi.Send(MidiMessage.StopNote(g, 0, channel).RawData); } - public async void PlayNote(int midiNote, bool AddToMentalModel = false, int timetonextMs = 250) + public void PlayNote(int midiNote, bool AddToMentalModel = false, int timetonextMs = 250) { //Debug.WriteLine($"PlayNote: {midiNote} {timetonextMs}"); var listener = MainWindow.theWindow?.activeModules.OfType().FirstOrDefault(); diff --git a/BrainSimulator/Modules/ModuleStressTest.cs b/BrainSimulator/Modules/ModuleStressTest.cs index e047c74..bf1f3d8 100644 --- a/BrainSimulator/Modules/ModuleStressTest.cs +++ b/BrainSimulator/Modules/ModuleStressTest.cs @@ -71,8 +71,6 @@ public static String AddManyTestItems(int count) items.Add(i.ToString()); } - int times = 0; - // Add each item to the UKS. //for (int i = 0; i < items.Count; i++) diff --git a/BrainSimulator/Modules/ModuleStressTestDlg.xaml.cs b/BrainSimulator/Modules/ModuleStressTestDlg.xaml.cs index 3421797..f72378c 100644 --- a/BrainSimulator/Modules/ModuleStressTestDlg.xaml.cs +++ b/BrainSimulator/Modules/ModuleStressTestDlg.xaml.cs @@ -59,7 +59,7 @@ private void SetOutputText(string theText) txtOutput.Text = theText; } - private async void Button_Click(object sender, RoutedEventArgs e) + private void Button_Click(object sender, RoutedEventArgs e) { if (sender is Button btn) { diff --git a/BrainSimulator/Modules/ModuleText.cs b/BrainSimulator/Modules/ModuleText.cs index e6b1864..e0b8fb4 100644 --- a/BrainSimulator/Modules/ModuleText.cs +++ b/BrainSimulator/Modules/ModuleText.cs @@ -189,7 +189,7 @@ public int LoadTextFromFileOld(string filePath) // Incremental file-load state private StreamReader _phraseReader; private string _phraseReaderPath; - public async Task LoadTextFromFile(string filePath, int phrasesPerCall = 500) + public int LoadTextFromFile(string filePath, int phrasesPerCall = 500) { if (phrasesPerCall <= 0) phrasesPerCall = 1; if (!File.Exists(filePath)) @@ -473,78 +473,6 @@ public static int CreateTrigrams() CreateUniversalPatternClasses(); // FindPatterns(); return retVal; - - var theUKS = MainWindow.theUKS; - //int retVal = 0; - - // Ensure type + link types exist - theUKS.GetOrAddThought("trigram", "LanguageElement"); - theUKS.GetOrAddThought("first", "LinkType"); - theUKS.GetOrAddThought("second", "LinkType"); - theUKS.GetOrAddThought("third", "LinkType"); - - // Iterate all existing bigram link-thoughts - foreach (Thought t in ((Thought)"bigram").Children) - { - if (t is not Link lnk) continue; - // Expect: t is a followedBy link from A -> B - Thought a = lnk.From; - Thought b = lnk.To; - - if (a == null || b == null) continue; - - // Find B --followedBy--> C (second bigram) - foreach (Link l in b.LinksTo.Where(x => x.LinkType.Label == "followedBy")) - { - Thought c = l.To; - if (c == null) continue; - if (a.Label == "w:the" && b.Label == "w:baby") - { } - - // Optional: ensure A,B,C occurs somewhere in actual ingested sequences - // This prevents creating trigrams that never appeared. - var results = theUKS.HasSequence(new List { a, b, c }, null); - if (results.Count == 0) - continue; - - // Build a deterministic trigram key (prefer IDs if stable) - string trigramKey = $"tg_{a.Label}_{b.Label}_{c.Label}"; - if (trigramKey == "tg_the_baby_bird") - { } - - Thought tg = theUKS.Labeled(trigramKey); - if (tg is null) - { - tg = theUKS.GetOrAddThought(trigramKey, "trigram"); - - // Link to components (idempotent if AddStatement de-dupes) - theUKS.AddStatement(tg, "first", a); - theUKS.AddStatement(tg, "second", b); - theUKS.AddStatement(tg, "third", c); - - // Set / reinforce trigram weight (use avg or min; min is more conservative) - float w = MathF.Min(t.Weight, l.Weight); // conservative - //float w = 0.5f * (t.Weight + l.Weight); // alternative - - tg.Weight = MathF.Min(tg.Weight, 0.10f * w); // start small but proportional - tg.Weight = results.Count; - retVal++; - } - //else - //{ - // // reinforce existing trigram - // //tg.Weight = MathF.Min(1f, tg.Weight + 0.05f * (1f - tg.Weight)); - // tg.Weight += 1; // simple increment; could also use a weighted average of component weights - //} - - tg.LastFiredTime = DateTime.Now; // swap for UKS ticks later if you add recency - } - } - Thought trigrams = theUKS.Labeled("trigram"); - var topTrigrams = trigrams.Children.OrderByDescending(x => x.Weight).ToList(); - for (int i = 50; i < topTrigrams.Count; i++) - topTrigrams[i].Delete(); - return retVal; } public static void FindPatterns() { diff --git a/BrainSimulator/Modules/ModuleUKSDlg.xaml b/BrainSimulator/Modules/ModuleUKSDlg.xaml index 1c56e74..79d34bf 100644 --- a/BrainSimulator/Modules/ModuleUKSDlg.xaml +++ b/BrainSimulator/Modules/ModuleUKSDlg.xaml @@ -34,7 +34,7 @@ Text="Thought" primitives:TextBoxBase.TextChanged="textBoxRoot_TextChanged" PreviewKeyDown="TextBoxRoot_KeyDown"/> -