DefaultStrategy.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. // Author: Orlys
  2. // Github: https://github.com/Orlys
  3. namespace Yuuna.Contracts.Optimization
  4. {
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Collections.Immutable;
  8. using System.Diagnostics.CodeAnalysis;
  9. using System.Runtime.CompilerServices;
  10. using Yuuna.Contracts.Patterns;
  11. using Yuuna.Contracts.Modules;
  12. using Yuuna.Contracts.Semantics;
  13. using System.Linq;
  14. public enum Status
  15. {
  16. /// <summary>
  17. /// 無有效解。
  18. /// </summary>
  19. Invalid,
  20. /// <summary>
  21. /// 最佳解。表示與模式(Pattern)完全符合。
  22. /// </summary>
  23. Optimal,
  24. /// <summary>
  25. /// 近似解。表示缺少一個群組(Group)。
  26. /// </summary>
  27. Closest,
  28. /// <summary>
  29. /// 命題。表示具有兩個近似解(<see cref="Closest"/>)。
  30. /// </summary>
  31. Proposition,
  32. /// <summary>
  33. /// 悖論。表示具有多個最佳解(<see cref="Optimal"/>),這實際上屬於模組設計上的問題。
  34. /// </summary>
  35. Paradox,
  36. /// <summary>
  37. /// 沒有已安裝的模組。
  38. /// </summary>
  39. NoModuleInstalled = -1,
  40. }
  41. public class Alternative
  42. {
  43. public Status Status { get; }
  44. public IImmutableList<Match> Matches { get; }
  45. public Alternative(IImmutableList<Match> matches)
  46. {
  47. var count = matches?.Count ?? 0;
  48. if (count.Equals(1))
  49. {
  50. var single = matches[0].Missing.Count;
  51. if (single.Equals(0))
  52. {
  53. this.Status = Status.Optimal; // 最佳解
  54. }
  55. else if (single.Equals(1))
  56. {
  57. this.Status = Status.Closest;// 近似解(缺一組條件,詢問使用者)
  58. }
  59. }
  60. else if (count.Equals(2))
  61. {
  62. if (matches.All(x => x.Missing.Count == 0))
  63. {
  64. this.Status = Status.Paradox;// 內部錯誤(多個意圖重複)
  65. }
  66. else if (matches.All(x => x.Missing.Count == 1))
  67. {
  68. this.Status = Status.Proposition;// 兩個近似解,詢問使用者(二選一 + 離開情境)
  69. }
  70. }
  71. else if (count.Equals(0))
  72. {
  73. // 無有效模組
  74. this.Status = Status.NoModuleInstalled;
  75. }
  76. else
  77. {
  78. // 不採用
  79. this.Status = Status.Invalid;
  80. }
  81. this.Matches = matches;
  82. }
  83. }
  84. public class DefaultStrategy : IStrategy
  85. {
  86. public DefaultStrategy()
  87. {
  88. }
  89. public Alternative FindBest(IEnumerable<IPatternSet> patternSetCollection, IImmutableList<string> feed)
  90. {
  91. var list = ImmutableArray.CreateBuilder<Match>();
  92. foreach (var pattern in patternSetCollection)
  93. {
  94. foreach (var p in pattern.ToImmutable())
  95. {
  96. var match = this.CountPatternMatch(p, feed);
  97. list.Add(match);
  98. }
  99. }
  100. var e = this.SelectBestMatch(list.ToImmutable());
  101. return e;
  102. }
  103. /// <summary>
  104. ///
  105. /// </summary>
  106. /// <param name="matches"></param>
  107. /// <returns></returns>
  108. protected virtual Alternative SelectBestMatch(IImmutableList<Match> matches)
  109. {
  110. //if(matches is null || matches.Count == 0)
  111. // return //沒有安裝任何模組
  112. var sta = new SortedList<int, List<Match>>();
  113. foreach (var match in matches)
  114. {
  115. var key = match.SequentialMatches.Count;
  116. if (!sta.ContainsKey(key))
  117. {
  118. sta.Add(key, new List<Match> { match });
  119. }
  120. else
  121. {
  122. sta[key].Add(match);
  123. }
  124. }
  125. var weight = double.MinValue;
  126. var bestSelect = default(List<Match>);
  127. foreach (var s in sta)
  128. {
  129. var y = -( Math.Tanh(Math.Pow(Math.E, (s.Value.Count) / (double)-(matches.Count * s.Key))));
  130. if (y > weight)
  131. {
  132. weight = y;
  133. bestSelect = s.Value;
  134. }
  135. }
  136. return new Alternative(bestSelect?.ToImmutableArray());
  137. //var tuple = new List<Tuple<Match, double>>();
  138. //foreach (var s in sta)
  139. //{
  140. // var x = (s.Value) / (double)-(matches.Count * s.Key.SequentialMatches.Count);
  141. // var y = Math.Tanh(Math.Pow(Math.E, x));
  142. // tuple.Add(Tuple.Create(s.Key, y));
  143. //}
  144. //var bestSelect = tuple.OrderByDescending(x => x.Item2).FirstOrDefault();
  145. //return bestSelect?.Item1;
  146. //var hold = double.MinValue;
  147. //var bestSelect = default(Match);
  148. //foreach (var s in sta)
  149. //{
  150. // var y = Math.Tanh(Math.Pow(Math.E, (s.Value) / (double)-(matches.Count * s.Key.Pattern.Count)));
  151. // if (y > hold)
  152. // {
  153. // hold = y;
  154. // bestSelect = s.Key;
  155. // }
  156. //}
  157. //if (bestSelect.SequentialMatches.Count == 0)
  158. // return null;
  159. //return bestSelect;
  160. }
  161. /// <summary>
  162. /// 評估 <paramref name="pattern"/> 與 <paramref name="feed"/> 的符合程度並返回一個 <see cref="Match"/> 物件。
  163. /// </summary>
  164. /// <param name="pattern"></param>
  165. /// <param name="feed"></param>
  166. /// <returns></returns>
  167. protected virtual Match CountPatternMatch(IPattern pattern, IImmutableList<string> feed)
  168. {
  169. var matches = ImmutableArray.CreateBuilder<ISynonym>();
  170. using (var iterator = pattern.ToImmutable().GetEnumerator())
  171. {
  172. iterator.MoveNext();
  173. foreach (var word in feed)
  174. {
  175. if (iterator.Current.TryGetSynonym(word, out var s))
  176. {
  177. matches.Add(s);
  178. if (!iterator.MoveNext())
  179. break;
  180. }
  181. }
  182. }
  183. return new Match(pattern, matches.ToImmutable());
  184. }
  185. }
  186. }