소스 검색

整理最佳化邏輯

0x0001F36D 5 년 전
부모
커밋
f06eec7f30

+ 3 - 3
src/Yuuna.Contracts/Plugins/PluginBase.cs → src/Yuuna.Contracts/Modules/ModuleBase.cs

@@ -1,7 +1,7 @@
 // Author: Orlys
 // Github: https://github.com/Orlys
 
-namespace Yuuna.Contracts.Plugins
+namespace Yuuna.Contracts.Modules
 {
     using System;
     using System.Collections.Immutable;
@@ -11,13 +11,13 @@ namespace Yuuna.Contracts.Plugins
     using Yuuna.Contracts.Semantics;
     using Yuuna.Contracts.TextSegmention;
     
-    public abstract class PluginBase
+    public abstract class ModuleBase
     {
         private readonly PatternFactory _patternfactory;
         
         internal IPatternSet Patterns => this._patternfactory;
 
-        public PluginBase()
+        public ModuleBase()
         {
             this._patternfactory = new PatternFactory(this);
         }

+ 135 - 29
src/Yuuna.Contracts/Optimization/DefaultStrategy.cs

@@ -10,8 +10,86 @@ namespace Yuuna.Contracts.Optimization
     using System.Runtime.CompilerServices;
 
     using Yuuna.Contracts.Patterns;
-    using Yuuna.Contracts.Plugins;
+    using Yuuna.Contracts.Modules;
     using Yuuna.Contracts.Semantics;
+    using System.Linq;
+
+    public enum Status
+    {
+        /// <summary>
+        /// 無有效解。
+        /// </summary>
+        Invalid,
+        /// <summary>
+        /// 最佳解。表示與模式(Pattern)完全符合。
+        /// </summary>
+        Optimal,
+        /// <summary>
+        /// 近似解。表示缺少一個群組(Group)。
+        /// </summary>
+        Closest,
+        /// <summary>
+        /// 命題。表示具有兩個近似解(<see cref="Closest"/>)。
+        /// </summary>
+        Proposition,
+        /// <summary>
+        /// 悖論。表示具有多個最佳解(<see cref="Optimal"/>),這實際上屬於模組設計上的問題。
+        /// </summary>
+        Paradox,
+
+        /// <summary>
+        /// 沒有已安裝的模組。
+        /// </summary>
+        NoModuleInstalled = -1,
+    }
+
+    public class Alternative
+    {
+        public Status Status { get; }
+        public IImmutableList<Match> Matches { get; }
+
+        public Alternative(IImmutableList<Match> matches)
+        {
+            var count = matches?.Count ?? 0;
+            if (count.Equals(1))
+            {
+                var single = matches[0].Missing.Count;
+                if (single.Equals(0))
+                {
+                    this.Status = Status.Optimal;  // 最佳解
+
+                }
+                else if (single.Equals(1))
+                {
+                    this.Status = Status.Closest;// 近似解(缺一組條件,詢問使用者) 
+                }
+            }
+            else if (count.Equals(2))
+            {
+                if (matches.All(x => x.Missing.Count == 0))
+                {
+                    this.Status = Status.Paradox;// 內部錯誤(多個意圖重複)
+                }
+                else if (matches.All(x => x.Missing.Count == 1))
+                {
+                    this.Status = Status.Proposition;// 兩個近似解,詢問使用者(二選一 + 離開情境)
+                }
+            } 
+            else if (count.Equals(0))
+            {
+                // 無有效模組
+                this.Status = Status.NoModuleInstalled;
+            }
+            else
+            {
+                // 不採用
+                this.Status = Status.Invalid;
+            }
+
+            this.Matches = matches;
+        }
+         
+    }
 
     public class DefaultStrategy : IStrategy
     {
@@ -20,16 +98,15 @@ namespace Yuuna.Contracts.Optimization
 
         }
 
-        public Match? FindBest(IEnumerable<PluginBase> plugins, IImmutableList<string> feed)
+        public Alternative FindBest(IEnumerable<ModuleBase> plugins, IImmutableList<string> feed)
         {
             var list = ImmutableArray.CreateBuilder<Match>();
             foreach (var plugin in plugins)
             {
                 foreach (var p in plugin.Patterns.ToImmutable())
                 {
-                    var score = this.CalculatePatternMatch(p, feed);
-                    if (score.HasValue)
-                        list.Add(score.Value);
+                    var match = this.CountPatternMatch(p, feed);  
+                    list.Add(match);
                 }
             }
 
@@ -42,17 +119,43 @@ namespace Yuuna.Contracts.Optimization
         /// </summary>
         /// <param name="matches"></param>
         /// <returns></returns>
-        protected virtual Match? SelectBestMatch(IImmutableList<Match> matches)
-        {
-            var sta = new SortedList<Match, int>();
-            foreach (var j in matches)
+        protected virtual Alternative SelectBestMatch(IImmutableList<Match> matches)
+        { 
+           //if(matches is null || matches.Count == 0)
+           //     return //沒有安裝任何模組
+
+            var sta = new SortedList<int, List<Match>>();
+            foreach (var match in matches)
             {
-                if (!sta.ContainsKey(j))
-                    sta.Add(j, 1);
+                var key = match.SequentialMatches.Count;
+                if (!sta.ContainsKey(key))
+                { 
+                    sta.Add(key, new List<Match> { match }); 
+                }
                 else
-                    sta[j]++;
+                {
+                    sta[key].Add(match);
+                }
             }
 
+
+            var weight = double.MinValue;
+            var bestSelect = default(List<Match>);
+            foreach (var s in sta)
+            {
+                var y = -( Math.Tanh(Math.Pow(Math.E, (s.Value.Count) / (double)-(matches.Count * s.Key))));
+                if (y > weight)
+                {
+                    weight = y;
+                    bestSelect = s.Value;
+                }
+            }
+
+
+            return new Alternative(bestSelect?.ToImmutableArray());
+
+
+
             //var tuple = new List<Tuple<Match, double>>();
             //foreach (var s in sta)
             //{
@@ -60,33 +163,35 @@ namespace Yuuna.Contracts.Optimization
             //    var y = Math.Tanh(Math.Pow(Math.E, x));
             //    tuple.Add(Tuple.Create(s.Key, y));
             //}
-
             //var bestSelect = tuple.OrderByDescending(x => x.Item2).FirstOrDefault();
-
             //return bestSelect?.Item1;
 
-            var hold = double.MinValue;
-            var bestSelect = default(Match?);
-            foreach (var s in sta)
-            {
-                var y = Math.Tanh(Math.Pow(Math.E, (s.Value) / (double)-(matches.Count * s.Key.SequentialMatches.Count)));
-                if (y >= hold)
-                {
-                    hold = y;
-                    bestSelect = s.Key;
-                }
-            }
-            return bestSelect;
+
+            //var hold = double.MinValue;
+            //var bestSelect = default(Match);
+            //foreach (var s in sta)
+            //{
+            //    var y = Math.Tanh(Math.Pow(Math.E, (s.Value) / (double)-(matches.Count * s.Key.Pattern.Count))); 
+            //    if (y > hold)
+            //    {
+            //        hold = y;
+            //        bestSelect = s.Key;
+            //    }
+            //}
+
+            //if (bestSelect.SequentialMatches.Count == 0)
+            //    return null;
+
+            //return bestSelect;
         }
 
         /// <summary>
-        /// 評估 <paramref name="pattern"/> 與 <paramref name="feed"/> 的符合程度並給予一個分數,並返回一個 <see cref="Match"/> 物件。
-        /// 若回傳 <see langword="null"/> 則此規則將不列入計算。
+        /// 評估 <paramref name="pattern"/> 與 <paramref name="feed"/> 的符合程度並返回一個 <see cref="Match"/> 物件。
         /// </summary>
         /// <param name="pattern"></param>
         /// <param name="feed"></param>
         /// <returns></returns>
-        protected virtual Match? CalculatePatternMatch(IPattern pattern, IImmutableList<string> feed)
+        protected virtual Match CountPatternMatch(IPattern pattern, IImmutableList<string> feed)
         {
             var matches = ImmutableArray.CreateBuilder<ISynonym>();
 
@@ -103,6 +208,7 @@ namespace Yuuna.Contracts.Optimization
                     }
                 }
             }
+
             return new Match(pattern, matches.ToImmutable());
         }
     }

+ 4 - 4
src/Yuuna.Contracts/Optimization/IStrategy.cs

@@ -1,14 +1,14 @@
 // Author: Orlys
 // Github: https://github.com/Orlys
 
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using Yuuna.Contracts.Plugins;
 
 namespace Yuuna.Contracts.Optimization
 {
+    using System.Collections.Generic;
+    using System.Collections.Immutable;
+    using Yuuna.Contracts.Modules;
     public interface IStrategy
     {
-        Match? FindBest(IEnumerable<PluginBase> plugins, IImmutableList<string> feed);
+        Alternative FindBest(IEnumerable<ModuleBase> plugins, IImmutableList<string> feed);
     }
 }

+ 2 - 2
src/Yuuna.Contracts/Optimization/Match.cs

@@ -41,7 +41,7 @@ namespace Yuuna.Contracts.Optimization
             this.Pattern = pattern;
             this.SequentialMatches = matches;
             this.Missing = pattern.ToImmutable().Except(matches.Select(x => x.Owner)).ToImmutableArray();
-            this.IsExactMatch = pattern.Count.Equals(matches.Count);
+            this.IsExactMatch = this.Missing.Count.Equals(default);
         }
 
         public bool Equals(Match other)
@@ -51,7 +51,7 @@ namespace Yuuna.Contracts.Optimization
 
         public int CompareTo(Match other)
         {
-            return this.Pattern.Count - other.Pattern.Count;
+            return this.SequentialMatches.Count - other.SequentialMatches.Count;
         }
     } 
 }

+ 2 - 2
src/Yuuna.Contracts/Patterns/IPattern.cs

@@ -8,11 +8,11 @@ namespace Yuuna.Contracts.Patterns
 
     using Yuuna.Contracts.Semantics;
     using Yuuna.Common.Linq;
-    using Yuuna.Contracts.Plugins;
+    using Yuuna.Contracts.Modules;
 
     public interface IPattern : IEquatable<IPattern>, IImmutable<IGroup>
     {
-        PluginBase Owner { get; }
+        ModuleBase Owner { get; }
 
         int Count { get; }
 

+ 4 - 5
src/Yuuna.Contracts/Patterns/Internal/PatternFactory.cs

@@ -9,15 +9,15 @@ namespace Yuuna.Contracts.Patterns
     using System.Collections.Immutable;
 
     using Yuuna.Common.Artisan.Cascade;
-    using Yuuna.Contracts.Plugins;
+    using Yuuna.Contracts.Modules;
     using Yuuna.Contracts.Semantics;
 
     internal sealed class PatternFactory : Initial<InvokeBuilder, IPattern>, IPatternSet, IPatternBuilder
     {
         private readonly ConcurrentDictionary<IPattern, Bag> _list;
-        private readonly PluginBase _owner;
+        private readonly ModuleBase _owner;
 
-        internal PatternFactory(PluginBase owner)
+        internal PatternFactory(ModuleBase owner)
         {
             this._list = new ConcurrentDictionary<IPattern, Bag>();
             this._owner = owner;
@@ -46,14 +46,13 @@ namespace Yuuna.Contracts.Patterns
         }
 
         protected override void OnCompleted(Queue<object> session)
-        {
+        {                                              
             var ge = new Bag
             {
                 Pattern = session.Dequeue() as IPattern,
                 Invoke = session.Dequeue() as Invoke,
                 Incomplete = session.Dequeue() as Incomplete,
             };
-            
             this._list.TryAdd(ge.Pattern, ge);
         }
     }

+ 3 - 3
src/Yuuna.Contracts/Patterns/Pattern.cs

@@ -6,7 +6,7 @@ namespace Yuuna.Contracts.Patterns
     using System.Collections.Immutable;
     using System.Diagnostics;
     using System.Linq;
-    using Yuuna.Contracts.Plugins;
+    using Yuuna.Contracts.Modules;
     using Yuuna.Contracts.Semantics;
 
     public sealed class Pattern : IPattern
@@ -26,9 +26,9 @@ namespace Yuuna.Contracts.Patterns
 
         public IImmutableList<string> SequentialKeys { get; private set; }
 
-        public PluginBase Owner { get; }
+        public ModuleBase Owner { get; }
 
-        internal Pattern(PluginBase owner)
+        internal Pattern(ModuleBase owner)
         {
             this._keyBuilder = ImmutableArray.CreateBuilder<string>();
             this._groupBuilder = ImmutableArray.CreateBuilder<IGroup>();

+ 2 - 2
src/Yuuna.Faker/Fake.cs

@@ -7,11 +7,11 @@ namespace TestPlugin
 
     using Yuuna.Contracts.Interaction;
     using Yuuna.Contracts.Patterns;
-    using Yuuna.Contracts.Plugins;
+    using Yuuna.Contracts.Modules;
     using Yuuna.Contracts.Semantics;
     using Yuuna.Common.Utilities;
 
-    public sealed class Fake : PluginBase
+    public sealed class Fake : ModuleBase
     {
         protected override void BuildPatterns(IGroupManager g, IPatternBuilder p)
         {

+ 23 - 22
src/Yuuna/EntryPoint.cs

@@ -12,7 +12,7 @@ namespace Yuuna
     using TestPlugin;
 
     using Yuuna.Contracts.Optimization;
-    using Yuuna.Contracts.Plugins;
+    using Yuuna.Contracts.Modules;
     using Yuuna.Contracts.TextSegmention;
     using Yuuna.Recognition.Speech;
     using Yuuna.Semantics;
@@ -25,7 +25,7 @@ namespace Yuuna
         public static void Main(string[] args)
         {
 
-            Send("打開門");
+            Send("門");
 
             return;
             // Send("打開門"); Send("開燈");
@@ -66,7 +66,7 @@ namespace Yuuna
         public static void Send(string text)
         {
             var segmenter = new JiebaTextSegmenter() as ITextSegmenter;
-            var allPlugins = new PluginBase[] { new Fake() };
+            var allPlugins = new ModuleBase[] { new Fake() };
             foreach (var item in allPlugins)
             {
                 item.Initialize(segmenter, new GroupManager());
@@ -78,27 +78,28 @@ namespace Yuuna
             Console.WriteLine($"來自分詞器 {segmenter.Name} 的分詞結果: [ {string.Join(", ", cutted)} ]");
 
             IStrategy plan = new DefaultStrategy();
-            var m = plan.FindBest(allPlugins, cutted);
-            if (m.HasValue)
+            var alternative = plan.FindBest(allPlugins, cutted);
+            switch (alternative.Status)
             {
-                var match = m.Value;
-                var pattern = match.Pattern;
-                if (pattern.Owner.Patterns.TryGet(pattern, out var bag))
-                {
-                    if (match.IsExactMatch)
-                    {
-                        Console.WriteLine(bag.Invoke(match));
-                    }                    
-                    else
-                    {
-                        Console.WriteLine();
-                    }
-                }
-                else
-                    throw new Exception("未知的錯誤");
+                case Status.Invalid:
+                    Console.WriteLine("無效的模組");
+                    break;
+                case Status.Optimal:
+                    alternative.Matches[0].Pattern.Owner.Patterns.TryGet(alternative.Matches[0].Pattern, out var bag);
+                    bag.Invoke(alternative.Matches[0]);
+                    break;
+                case Status.Closest:
+                    break;
+                case Status.Proposition:
+                    break;
+                case Status.Paradox:
+                    break;
+                case Status.NoModuleInstalled:
+                    break;
+                default:
+                    break;
             }
-            else
-                Console.WriteLine("沒有任何模組相符");
+
 
 
             //var list = new List<IScore>();