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/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 94e72b8..aa8d629 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 @@ -25,9 +25,13 @@ preview + + + + - + @@ -49,7 +53,7 @@ - + @@ -123,6 +127,11 @@ PreserveNewest + + + PreserveNewest + + PreserveNewest @@ -131,11 +140,6 @@ PreserveNewest - - - - - - + \ No newline at end of file diff --git a/BrainSimulator/GlobalUsings.cs b/BrainSimulator/GlobalUsings.cs new file mode 100644 index 0000000..ff7e145 --- /dev/null +++ b/BrainSimulator/GlobalUsings.cs @@ -0,0 +1,2 @@ +// Legacy BrainSim3 "Thing" alias removed 2026-07 with old Vision code. +// Native code uses Thought / Link directly. Python interop updated separately if needed. \ No newline at end of file diff --git a/BrainSimulator/MainWindow.xaml.cs b/BrainSimulator/MainWindow.xaml.cs index d8fa77e..f4e6e00 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,8 +293,9 @@ 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) { + theUKS.BeginTraversalCycle(); Thought activeModuleParent = theUKS.Labeled("ActiveModule"); if (activeModuleParent is null) return; foreach (Thought module in activeModuleParent.Children) diff --git a/BrainSimulator/MainWindowFiles.cs b/BrainSimulator/MainWindowFiles.cs index 4e7b79a..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(); @@ -63,10 +62,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/MainWindowPythonModules.cs b/BrainSimulator/MainWindowPythonModules.cs index 7462c7f..367f105 100644 --- a/BrainSimulator/MainWindowPythonModules.cs +++ b/BrainSimulator/MainWindowPythonModules.cs @@ -53,9 +53,9 @@ static void RunScript(string moduleLabel) { bool firstTime = false; //get the ModuleType - Thing tModule = theUKS.Labeled(moduleLabel); + Thought tModule = theUKS.Labeled(moduleLabel); if (tModule == null) { return; } - Thing tModuleType = tModule.Parents.FindFirst(x => x.HasAncestorLabeled("AvailableModule")); + Thought tModuleType = tModule.Parents.FindFirst(x => x.HasAncestor("AvailableModule")); if (tModuleType == null) return; string moduleType = tModuleType.Label; moduleType = moduleType.Replace(".py", ""); diff --git a/BrainSimulator/ModuleDescriptions.xml b/BrainSimulator/ModuleDescriptions.xml index 127ebf2..bc9d944 100644 --- a/BrainSimulator/ModuleDescriptions.xml +++ b/BrainSimulator/ModuleDescriptions.xml @@ -172,14 +172,6 @@ Works together with SpeechParser, PhraseRecognizer, QueryResolution and SpeechOu ModuleUKSClause This dialog creates a Link between two Relastionships connected by a Clause Type. This can be used to create conditioinan links by using the clause type "if". That is, enter Mary can play outside if weather is sunny. This link will only be added to search results if the condition, weather is sunny, is true. - - ModuleVision - This module iintended to provide input/test data for visual recognition. It performs generic CV algorithms to locate corners in a simple visual input. - - - ModuleShape - This module allows the system to save shapes and retrieve them by content. - ModuleAttributeBubble This Agent scans the UKS Object tree looking for object Children which have common attributes which can be "bubbled" up to the parent. 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..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"; @@ -100,17 +99,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 +174,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/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 d0f782b..7dffa25 100644 --- a/BrainSimulator/Modules/Agents/ModuleAttributeBubble.cs +++ b/BrainSimulator/Modules/Agents/ModuleAttributeBubble.cs @@ -34,16 +34,46 @@ public override void Fire() UpdateDialog(); } - public bool isEnabled { get; set; } + public new bool isEnabled { get; set; } private Timer timer; - //private UKS.UKS theUKS1; + private Timer? debounceTimer; + private readonly HashSet pendingBubbleParents = new(); + private readonly object debounceLock = new(); public string debugString = "Initialized\n"; private void Setup() { if (timer is null) { timer = new Timer(SameThreadCallback, null, 0, 10000); + debounceTimer = new Timer(FlushDebouncedBubbles, null, Timeout.Infinite, Timeout.Infinite); + theUKS.LinkAdded += OnLinkAdded; + } + } + + private void OnLinkAdded(Link lnk) + { + if (!isEnabled || lnk.From is null) return; + lock (debounceLock) + { + foreach (Thought parent in lnk.From.Parents) + pendingBubbleParents.Add(parent); + } + debounceTimer?.Change(250, Timeout.Infinite); + } + + private void FlushDebouncedBubbles(object? _) + { + HashSet batch; + lock (debounceLock) + { + batch = new HashSet(pendingBubbleParents); + pendingBubbleParents.Clear(); + } + foreach (Thought parent in batch) + { + if (parent.HasAncestor("Object") || parent.HasAncestor("Unknown")) + BubbleChildAttributes(parent); } } private void SameThreadCallback(object state) @@ -89,123 +119,8 @@ public void DoTheWork() } void BubbleChildAttributes(Thought t) { - if (t.Children.Count == 0) return; - if (t.Label == "Unknown") return; - - //build a List of all the Links which this thought's children have - List itemCounts = new(); - foreach (Thought t1 in t.ChildrenWithSubclasses) - { - foreach (Link r in t1.LinksTo) - { - if (r.LinkType == Thought.IsA) continue; - Thought useLinkType = GetInstanceType(r.LinkType); - - LinkDest foundItem = itemCounts.FindFirst(x => x.linkType == useLinkType && x.target == r.To); - if (foundItem is null) - { - foundItem = new LinkDest { linkType = useLinkType, target = r.To }; - itemCounts.Add(foundItem); - } - foundItem.links.Add(r); - } - } - if (itemCounts.Count == 0) return; - var sortedItems = itemCounts.OrderByDescending(x => x.links.Count).ToList(); - - List excludeTypes = new List() { "hasProperty", "isTransitive", "isCommutative", "inverseOf", "hasAttribute", "hasDigit" }; - //bubble the links - for (int i = 0; i < sortedItems.Count; i++) - { - LinkDest rr = sortedItems[i]; - if (excludeTypes.Contains(rr.linkType.Label, comparer: StringComparer.OrdinalIgnoreCase)) continue; - - //find an existing link - Link r = theUKS.GetLink(t, rr.linkType, rr.target); - float currentWeight = (r is not null) ? r.Weight : 0f; - - //We need 1) count for this Thought, 2) count for any conflicting, 3) count without a reference - float totalCount = t.Children.Count; - float positiveCount = rr.links.FindAll(x => x.Weight > .5f).Count; - float positiveWeight = rr.links.Sum(x => x.Weight); - float negativeCount = 0; - float negativeWeight = 0; - //are there any conflicting links - for (int j = 0; j < sortedItems.Count; j++) - { - if (j == i) continue; - if (LinksConflict(rr, sortedItems[j])) - { - negativeCount += sortedItems[j].links.Count; //? why not += 1 - negativeWeight += sortedItems[j].links.Sum(x => x.Weight); - } - } - float noInfoCount = totalCount - (positiveCount + negativeCount); - positiveWeight += currentWeight + noInfoCount * 0.51f; - if (noInfoCount < 0) noInfoCount = 0; - - if (negativeCount >= positiveCount) - { - if (r is not null) - { - t.RemoveLink(r); - debugString += $"Removed {r} \n"; - } - continue; - } - - - //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 - 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; - else targetWeight = .3f; - if (currentWeight == 0) currentWeight = 0.5f; - float newWeight = currentWeight + targetWeight; - if (newWeight > 0.99f) newWeight = 0.99f; - - if (positiveCount > totalCount / 2) - if (newWeight != currentWeight || r is null) - { - if (newWeight < .5) - { - if (r is not null) - { - t.RemoveLink(r); - debugString += $"Removed {r.ToString()} \n"; - } - } - else - { - //bubble the property - r = t.AddLink(rr.linkType, rr.target); - r.Weight = newWeight; - r.Fire(); - debugString += $"Added {r.ToString()} {r.Weight.ToString(".0")} \n"; - - foreach (Thought t1 in t.Children) - { - Thought rrr = t1.RemoveLink(rr.linkType,rr.target); - debugString += $"Removed {rrr.ToString()} \n"; - } - //if there is a conflicting link, delete it - for (int j = 0; j < t.LinksTo.Count; j++) - { - if (LinksConflict(new LinkDest(r), new LinkDest(t.LinksTo[j]))) - { - t.RemoveLink(t.LinksTo[j]); - j--; - } - } - } - } - } - + if (theUKS.BubbleSharedAttributes(t)) + debugString += $"Bubbled attributes on {t.Label}\n"; } @@ -280,19 +195,7 @@ bool BubbleNeeded() //if the given thought is an instance of its parent, get the parent - public static Thought GetInstanceType(Thought t) - { - bool EndsInInteger(string input) - { - // Regular expression to check if the string ends with a sequence of digits - return Regex.IsMatch(input, @"\d+$"); - } - Thought useLinkType = t; - while (useLinkType.Parents.Count > 0 && EndsInInteger(useLinkType.Label) && - !t.Label.Contains(".") && useLinkType.Label.StartsWith(useLinkType.Parents[0].Label)) - useLinkType = useLinkType.Parents[0]; - return useLinkType; - } + public static Thought GetInstanceType(Thought t) => UKS.UKS.GetBubbleInstanceType(t); // Fill this method in with code which will execute once // when the module is added, when "initialize" is selected from the context menu, 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/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/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/CH4-GATING-MATRIX.md b/BrainSimulator/Modules/CH4-GATING-MATRIX.md new file mode 100644 index 0000000..c78f54e --- /dev/null +++ b/BrainSimulator/Modules/CH4-GATING-MATRIX.md @@ -0,0 +1,26 @@ +# Ch.4 relationship gating matrix + +Simon Ch.4: traversal requires **source thought AND relationship type** active together (biological AND-gate). Ch.2: sparse activation — only active subgraph participates per engine tick. + +## Runtime + +- `UKS.BeginTraversalCycle()` — called at start of `MainWindow.Dt_Tick`; clears `CurrentTraversal`. +- Modules call `CurrentTraversal.Activate(thought)` and `ActivateRelationship(linkType)` before gated queries. +- Activation marks thoughts in `TraversalContext` only — it does **not** call `Thought.Fire()` (that would re-enter `ModuleAlgorithm`'s interpreter queue). + + +## Module status (Phase B) + +| Module | Gating | Notes | +|--------|--------|-------| +| `ModuleAlgorithm` | **Reference** | `EvaluateContext` activates context root + `has` | +| `ModuleUKSQuery` | Ungated | Future: relationship filter → `ActivateRelationship` | +| Other modules | No change | Default `Fire()` only | + +> **Note (2026-07):** Legacy `ModuleVision` (old CV pipeline for corners/segments + discrete color) removed. Discrete sensory ingress now handled via direct Thought attribute injection (see DiscreteAttributeCh4 work and future modules). See [[Work-Log/2026-07-10-research-loop-brainsim-legacy-vision-removal]]. + +## API + +- `GetGatedLinks(source, linkType, ctx?)` — inherited `has` links when both active; direct `is-a` when both active. +- `Traverse(source, linkType, ctx?)` — gated target thoughts. + 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..2c4f28e 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(); } } @@ -311,11 +316,17 @@ private void CreateSpellingSequence(string word, Thought wordThought) private bool ExecuteAllSteps() { - //Run the whole program - while (HandleFiringNeurons()) { } - ; + const int maxCycles = 50_000; + while (HandleFiringNeurons()) + { + if (CycleCount > maxCycles) + { + LastAction = $"TASK ABORTED (>{maxCycles} cycles): possible interpreter loop"; + return false; + } + } - LastAction = $"TASK COMPLETE ({CycleCount} cycles): {LastLinkWritten.ToString()}"; + LastAction = $"TASK COMPLETE ({CycleCount} cycles): {LastLinkWritten?.ToString()}"; LastExecutedStep = null; return true; } @@ -337,48 +348,14 @@ private SeqElement GetReturn(Thought current) private Thought EvaluateContext(Thought contextRoot) { - Thought bestResponse = null; - float bestWeight = 0; - foreach (Thought t in contextRoot.Children) - { - float weight = 0; - foreach (Link l in t.LinksTo.Where(x => x.LinkType.Label == "has")) - { - Link test = (Link)l.To; - if (test.LinkType.HasAncestor("exist")) - { - bool not = false; - if (test.LinkType.HasAncestor("not")) not = true; - //Thought testType = test.LinkType.GetTargetOfFirstLinkOfType("is"); - Thought testType = test.LinkType.LinksTo.FindFirst(x => x.LinkType.Label.ToLower() == "is" && x.To.Label != "EXIST")?.To; - var src = HandleIndirection(test.From); - if (src is null) continue; - if (test.LinkType.HasAncestor("same") || test.LinkType.Label.ToLower().Contains("same")) //hack if ancestor not set properly - { - Thought target = HandleIndirection(test.To); - if (!not && src == target) weight += l.Weight; - if (not && src != target) weight += l.Weight; - } - else if (test.To.Label == "??") - { - if (!not && src.HasLink(testType) is not null) weight += l.Weight * test.Weight; - if (not && src.HasLink(testType) is null) weight += l.Weight * test.Weight; - } - else - { - Thought target = HandleIndirection(test.To); - if (!not && src.HasLink(testType, target) is not null) weight += l.Weight * test.Weight; - if (not && src.HasLink(testType, target) is null) weight += l.Weight * test.Weight; - } - } - } - Debug.WriteLine($"Case: {t.Label} Weight: {weight}"); - if (weight > bestWeight) - { - bestResponse = t.GetTargetOfFirstLinkOfType("response"); - bestWeight = weight; - } - } + // Ch.4 AND-gate: activate context root + has relationship before attribute matching. + theUKS.CurrentTraversal.Activate(contextRoot); + Thought? hasType = theUKS.Labeled("has"); + if (hasType is not null) + theUKS.CurrentTraversal.ActivateRelationship(hasType); + + ContextCaseResult? selected = theUKS.SelectBestContextCase(contextRoot, HandleIndirection); + Thought bestResponse = selected?.Response; Debug.WriteLine($"Context: {contextRoot} returned {bestResponse}"); bestResponse?.Fire(); 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 c7bc2fa..7d0caa7 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('.'); @@ -641,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; @@ -683,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/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/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 8895fb1..8fdf15f 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); } @@ -147,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"); } @@ -185,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) @@ -321,7 +327,7 @@ public void ConceptNetLocal(string word) } } } - catch (Exception ex) + catch (Exception) { } } @@ -425,7 +431,7 @@ private void ReadConceptNetFile() } } } - catch (Exception ex) + catch (Exception) { } foreach (var w in wordList2) { @@ -473,29 +479,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 +492,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 +610,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()); @@ -619,7 +628,7 @@ public void SetupWordList2(string wordIn = "") } } } - catch (Exception ex) + catch (Exception) { } wordList2 = wordList2.OrderBy(x => x.Item1).ToList(); GetUKS(); @@ -649,20 +658,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 +708,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 +769,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 +799,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 +838,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,16 +873,12 @@ 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 { 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(); @@ -900,7 +931,7 @@ public async void GetChatGPTResult(string textIn, QueryType qtIn = QueryType.isa else Output = answerString; } - catch (Exception ex) + catch (Exception) { } @@ -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 + @")} " + @@ -975,7 +1020,7 @@ private async void 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); @@ -1029,7 +1074,6 @@ private async void GetPropertiesFromURL(string itemID, string propName) } docCount++; } - string propString = ""; //TextBoxWiki.Text = ""; for (int i = 0; i < docPropertyValues.Count; i++) { @@ -1053,7 +1097,6 @@ private async void 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++) @@ -1077,7 +1120,6 @@ private async void GetPropertiesFromURL(string itemID, string propName) docCount++; } - string propString = ""; //TextBoxWiki.Text = ""; for (int i = 0; i < docPropertyValues.Count; i++) { @@ -1094,6 +1136,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 +1259,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 +1323,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/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"/> -