123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- // Author: Orlys
- // Github: https://github.com/Orlys
- namespace Yuuna.Contracts.Optimization
- {
- using System;
- using System.Collections.Generic;
- using System.Collections.Immutable;
- using System.Diagnostics.CodeAnalysis;
- using System.Runtime.CompilerServices;
- using Yuuna.Contracts.Patterns;
- 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
- {
- public DefaultStrategy()
- {
- }
- public Alternative FindBest(IEnumerable<IPatternSet> patternSetCollection, IImmutableList<string> feed)
- {
- var list = ImmutableArray.CreateBuilder<Match>();
- foreach (var pattern in patternSetCollection)
- {
- foreach (var p in pattern.ToImmutable())
- {
- var match = this.CountPatternMatch(p, feed);
- list.Add(match);
- }
- }
- var e = this.SelectBestMatch(list.ToImmutable());
- return e;
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="matches"></param>
- /// <returns></returns>
- 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)
- {
- var key = match.SequentialMatches.Count;
- if (!sta.ContainsKey(key))
- {
- sta.Add(key, new List<Match> { match });
- }
- else
- {
- 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)
- //{
- // var x = (s.Value) / (double)-(matches.Count * s.Key.SequentialMatches.Count);
- // 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.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"/> 物件。
- /// </summary>
- /// <param name="pattern"></param>
- /// <param name="feed"></param>
- /// <returns></returns>
- protected virtual Match CountPatternMatch(IPattern pattern, IImmutableList<string> feed)
- {
- var matches = ImmutableArray.CreateBuilder<ISynonym>();
- using (var iterator = pattern.ToImmutable().GetEnumerator())
- {
- iterator.MoveNext();
- foreach (var word in feed)
- {
- if (iterator.Current.TryGetSynonym(word, out var s))
- {
- matches.Add(s);
- if (!iterator.MoveNext())
- break;
- }
- }
- }
- return new Match(pattern, matches.ToImmutable());
- }
- }
- }
|