diff --git a/Esiur.Analysis/Esiur.Analysis.csproj b/Esiur.Analysis/Esiur.Analysis.csproj index 625bd34..1700991 100644 --- a/Esiur.Analysis/Esiur.Analysis.csproj +++ b/Esiur.Analysis/Esiur.Analysis.csproj @@ -6,8 +6,17 @@ + + + + + + + + + diff --git a/Esiur.Analysis/Fuzzy/ContinuousSet.cs b/Esiur.Analysis/Fuzzy/ContinuousSet.cs new file mode 100644 index 0000000..276e976 --- /dev/null +++ b/Esiur.Analysis/Fuzzy/ContinuousSet.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Esiur.Analysis.Fuzzy +{ + public class ContinuousSet : INumericalSet + { + public MembershipFunction Function { get; set; } + + public double AlphaCut { get; set; } = double.MinValue; + + + + public INumericalSet Intersection(INumericalSet with) + { + return new OperationSet(Operation.Intersection, this, with); + } + + public INumericalSet Union(INumericalSet with) + { + return new OperationSet(Operation.Union, this, with); + } + + public ContinuousSet(MembershipFunction function) + { + this.Function = function; + } + + public double this[double input] + { + get + { + + var results = Function(input); + + return results < AlphaCut ? 0 : results; + } + } + + + } +} diff --git a/Esiur.Analysis/Fuzzy/DiscreteSet.cs b/Esiur.Analysis/Fuzzy/DiscreteSet.cs new file mode 100644 index 0000000..358f172 --- /dev/null +++ b/Esiur.Analysis/Fuzzy/DiscreteSet.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Esiur.Analysis.Fuzzy +{ + public class DiscreteSet : INumericalSet, IEnumerable> + { + Dictionary vector = new Dictionary(); + + public double this[double index] + { + get => vector.ContainsKey(index) ? vector[index] : 0; + set + { + if (vector.ContainsKey(index)) + vector[index] = value; + else + vector.Add(index, value); + } + } + + public double AlphaCut { get; set; } + + + + public INumericalSet Intersection(INumericalSet with) + { + return new OperationSet(Operation.Intersection, new INumericalSet[] { this, with }); + } + + public INumericalSet Union(INumericalSet with) + { + return new OperationSet(Operation.Union, new INumericalSet[] { this, with }); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return vector.GetEnumerator(); + } + + IEnumerator> IEnumerable>.GetEnumerator() + { + return vector.GetEnumerator(); + } + + public KeyValuePair[] Maximas + { + get { + var max = vector.Values.Max(); + return vector.Where(x => x.Value == max).ToArray(); + } + } + + public KeyValuePair[] Minimas + { + get + { + var min = vector.Values.Min(); + return vector.Where(x => x.Value == min).ToArray(); + } + } + + } +} diff --git a/Esiur.Analysis/Fuzzy/FuzzyElement.cs b/Esiur.Analysis/Fuzzy/FuzzyElement.cs new file mode 100644 index 0000000..387d564 --- /dev/null +++ b/Esiur.Analysis/Fuzzy/FuzzyElement.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Analysis.Fuzzy +{ + public class FuzzyElement + { + public double Degree { get; set; } + public double Value { get; set; } + } +} diff --git a/Esiur.Analysis/Fuzzy/FuzzyExtensions.cs b/Esiur.Analysis/Fuzzy/FuzzyExtensions.cs new file mode 100644 index 0000000..f17725c --- /dev/null +++ b/Esiur.Analysis/Fuzzy/FuzzyExtensions.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Text; + +namespace Esiur.Analysis.Fuzzy +{ + public static class FuzzyExtensions + { + + public static double Or(this double value, double orValue) => value > orValue ? value : orValue; + public static double And(this double value, double orValue) => value < orValue ? value : orValue; + + public static double Is(this double value, INumericalSet set) => set[value]; + + // Mamdani + public static ContinuousSet Then(this double value, ContinuousSet set) + => new ContinuousSet(set.Function) { AlphaCut = value };// set.AlphaCut < value ? set.AlphaCut : value }; + + // TKS + public static double Then(this double value, double constant) + => value * constant; + + + public static INumericalSet FuzzyUnion(this INumericalSet[] sets) + { + return new OperationSet(Operation.Union, sets); + } + + public static INumericalSet FuzzyIntersection(this INumericalSet sets) + { + return new OperationSet(Operation.Intersection, sets); + + } + + public static DiscreteSet ToDiscrete(this INumericalSet set, double from, double to, double step) + { + var rt = new DiscreteSet(); + for (var x = from; x <= to; x += step) + rt[x] = set[x]; + + return rt; + } + } +} diff --git a/Esiur.Analysis/Fuzzy/FuzzyRule.cs b/Esiur.Analysis/Fuzzy/FuzzyRule.cs new file mode 100644 index 0000000..7e45548 --- /dev/null +++ b/Esiur.Analysis/Fuzzy/FuzzyRule.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Analysis.Fuzzy +{ + public class FuzzyRule + { + public string Name { get; set; } + + public FuzzySet InputSet { get; set; } + public FuzzySet OutputSet { get; set; } + + public FuzzyRule(string name, FuzzySet input, FuzzySet output) + { + Name = name; + InputSet = input; + OutputSet = output; + } + + public FuzzySet Evaluate(double input) + { + var val = InputSet[input]; + var results = new FuzzySet(OutputSet.Function) { AlphaCut = OutputSet.AlphaCut < val ? OutputSet.AlphaCut : val }; + return results; + } + } +} diff --git a/Esiur.Analysis/Fuzzy/IFuzzyEvaluator.cs b/Esiur.Analysis/Fuzzy/IFuzzyEvaluator.cs new file mode 100644 index 0000000..93d874f --- /dev/null +++ b/Esiur.Analysis/Fuzzy/IFuzzyEvaluator.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Analysis.Fuzzy +{ + public interface IFuzzyEvaluator + { + + public double[] Evaluate(double[] crispValues); + } +} diff --git a/Esiur.Analysis/Fuzzy/INumericalSet.cs b/Esiur.Analysis/Fuzzy/INumericalSet.cs new file mode 100644 index 0000000..615b44b --- /dev/null +++ b/Esiur.Analysis/Fuzzy/INumericalSet.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Analysis.Fuzzy +{ + public interface INumericalSet + { + public T this[T index] { get; } + public double AlphaCut { get; set; } + + public INumericalSet Intersection(INumericalSet with); + public INumericalSet Union(INumericalSet with); + + } +} diff --git a/Esiur.Analysis/Fuzzy/IVectorSet.cs b/Esiur.Analysis/Fuzzy/IVectorSet.cs new file mode 100644 index 0000000..dfbfc01 --- /dev/null +++ b/Esiur.Analysis/Fuzzy/IVectorSet.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Analysis.Fuzzy +{ + internal interface IVectorSet: IEnumerable + { + public double this[double index] + { + get; + } + } +} diff --git a/Esiur.Analysis/Fuzzy/MamdaniDefuzzifier.cs b/Esiur.Analysis/Fuzzy/MamdaniDefuzzifier.cs new file mode 100644 index 0000000..9e2bc65 --- /dev/null +++ b/Esiur.Analysis/Fuzzy/MamdaniDefuzzifier.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Esiur.Analysis.Fuzzy +{ + public enum MamdaniDefuzzifierMethod + { + CenterOfGravity, + FirstMaxima, + LastMaxima, + Bisector, + MeanOfMaxima, + } + public class MamdaniDefuzzifier + { + + public static double Evaluate(INumericalSet[] sets, MamdaniDefuzzifierMethod method, double from, double to, double step) + { + + var union = sets.FuzzyUnion(); + var output = union.ToDiscrete(from, to, step); + var max = output.Maximas; + return max[0].Key; + + } + + } +} diff --git a/Esiur.Analysis/Fuzzy/MembershipFunction.cs b/Esiur.Analysis/Fuzzy/MembershipFunction.cs new file mode 100644 index 0000000..908d66b --- /dev/null +++ b/Esiur.Analysis/Fuzzy/MembershipFunction.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Analysis.Fuzzy +{ + public delegate double MembershipFunction(double value); + + public static class MembershipFunctions + { + public static MembershipFunction Triangular(double start, double peak, double end) + { + return new MembershipFunction(x => + { + if (x < start || x > end) return 0; + if (x < peak) return (x - start) / (peak - start); + if (x > peak) return (end - x) / (end - peak); + return 1; // x = peak + }); + } + + public static MembershipFunction Descending(double peak, double end) + { + return new MembershipFunction(x => + { + if (x <= peak) return 1; + if (x > peak && x < end) return (end - x) / (end - peak); + return 0; + }); + } + + public static MembershipFunction Ascending(double start, double peak) + { + return new MembershipFunction(x => + { + if (x >= peak) return 1; + if (x < peak && x > start) return (x - start) / (peak - start); + return 0; + }); + } + } + +} diff --git a/Esiur.Analysis/Fuzzy/OperationSet.cs b/Esiur.Analysis/Fuzzy/OperationSet.cs new file mode 100644 index 0000000..f207339 --- /dev/null +++ b/Esiur.Analysis/Fuzzy/OperationSet.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography.X509Certificates; +using System.Text; + +namespace Esiur.Analysis.Fuzzy +{ + public enum Operation + { + Intersection, + Union + } + + public class OperationSet : INumericalSet + { + + public Operation Operation { get; set; } + + public INumericalSet[] Sets { get; internal set; } + + public double AlphaCut { get; set; } + + public double this[double index] + { + get + { + double x = 0; + if (Operation == Operation.Union) + x = Sets.Max(x => x[index]); + else if (Operation == Operation.Intersection) + x = Sets.Min(x => x[index]); + + // Alpha might be changed for this instance + return x < AlphaCut ? 0 : x; + } + } + + public OperationSet(Operation operation, params INumericalSet[] sets) + { + Sets = sets; + + if (operation == Operation.Intersection) + AlphaCut = sets.Min(x => x.AlphaCut); + else if (Operation == Operation.Union) + AlphaCut = sets.Max(x => x.AlphaCut); + + Operation = operation; + } + + public INumericalSet Intersection(INumericalSet with) + { + return new OperationSet(Operation.Intersection, new INumericalSet[] { this, with }); + } + + public INumericalSet Union(INumericalSet with) + { + return new OperationSet(Operation.Union, new INumericalSet[] { this, with }); + } + } +} diff --git a/Esiur.Analysis/Statistics/StatisticalFunctions.cs b/Esiur.Analysis/Statistics/StatisticalFunctions.cs index f0c5cf8..00744d2 100644 --- a/Esiur.Analysis/Statistics/StatisticalFunctions.cs +++ b/Esiur.Analysis/Statistics/StatisticalFunctions.cs @@ -38,7 +38,7 @@ namespace Esiur.Analysis.Statistics public static double Correlation(this double[] x, double[] y) { - return x.Covariance(y) / (x.StdDiv() * y.StdDiv()); + return Covariance(x, y) / (StdDiv(x) * StdDiv(y)); } } } diff --git a/Esiur.Analysis/Units/Frequency.cs b/Esiur.Analysis/Units/Frequency.cs new file mode 100644 index 0000000..07bbf65 --- /dev/null +++ b/Esiur.Analysis/Units/Frequency.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Text; + +namespace Esiur.Analysis.Units +{ + public enum FrequencyKind + { + Hertz, + Kilohertz, + Megahertz, + Gigahertz, + Terahertz + } + + public struct Frequency : IComparable + { + public double Value; + + + public Frequency(double value, FrequencyKind kind = FrequencyKind.Hertz) + { + if (kind == FrequencyKind.Kilohertz) + Value = value * 1000; + else if (kind == FrequencyKind.Megahertz) + Value = value * 1000000; + else if (kind == FrequencyKind.Gigahertz) + Value = value * 1000000000; + else if (kind == FrequencyKind.Terahertz) + Value = value * 1000000000000; + else + Value = value; + } + + public static implicit operator Frequency(double d) => new Frequency(d); + public static implicit operator double(Frequency d) => d.Value; + + //public static explicit operator PowerUnit(double d) => new PowerUnit(d, PowerUnitKind.Watt); + //public static explicit operator double(PowerUnit d) => d.Value; + + //public static PowerUnit operator +(PowerUnit a) => a; + //public static PowerUnit operator -(PowerUnit a) => new PowerUnit(-a.num, a.den); + + public static Frequency operator +(Frequency a, Frequency b) + => new Frequency(a.Value + b.Value); + + public static Frequency operator -(Frequency a, Frequency b) + => new Frequency(a.Value - b.Value); + + public static Frequency operator *(Frequency a, Frequency b) + => new Frequency(a.Value * b.Value); + + public static Frequency operator /(Frequency a, Frequency b) + { + if (b.Value == 0) + { + throw new DivideByZeroException(); + } + return new Frequency(a.Value / b.Value); + } + + + public override string ToString() + { + if (Value >= 1e12) + return (Value / 1e12).ToString("F") + " Terahertz"; + else if (Value >= 1e9) + return (Value / 1e9).ToString("F") + " Gigahertz"; + else if (Value >= 1e6) + return (Value / 1e6).ToString("F") + " Megahertz"; + else if (Value >= 1e3) + return (Value * 1e3).ToString("F") + " Kilohertz"; + else + return Value.ToString("F") + " Hertz"; + } + + + public int CompareTo(object obj) + { + if (obj is Frequency p) + return Value.CompareTo(p.Value); + else + return Value.CompareTo(obj); + } + } +} diff --git a/Test/Program.cs b/Test/Program.cs index 2892a85..bff75be 100644 --- a/Test/Program.cs +++ b/Test/Program.cs @@ -47,6 +47,7 @@ using System.Security.Cryptography; using System.Text; using Esiur.Analysis.Signals; using Esiur.Analysis.Units; +using Esiur.Analysis.Fuzzy; namespace Test { @@ -55,8 +56,6 @@ namespace Test { static async Task Main(string[] args) { - - //var outage = Capacity.ComputeOutage(20000000, new Capacity.CSI[] //{ // new Capacity.CSI(PowerUnit.FromDb(20), 0.1), @@ -74,6 +73,34 @@ namespace Test new Capacity.CSI(PowerUnit.FromDb(0), 0.2), }); + + var low = new ContinuousSet(MembershipFunctions.Descending(20, 40)); + var mid = new ContinuousSet(MembershipFunctions.Triangular(20, 40, 60)); + var high = new ContinuousSet(MembershipFunctions.Ascending(40, 60)); + + var bad = new ContinuousSet(MembershipFunctions.Descending(0, 30)); + var ok = new ContinuousSet(MembershipFunctions.Triangular(20, 50, 80)); + var excelent = new ContinuousSet(MembershipFunctions.Ascending(70, 100)); + + var small = new ContinuousSet(MembershipFunctions.Descending(100, 200)); + var avg = new ContinuousSet(MembershipFunctions.Triangular(150, 200, 250)); + var big = new ContinuousSet(MembershipFunctions.Ascending(200, 300)); + + //var speedIsLowThenSmall = new FuzzyRule("Low=>Small", low, small); + + double temp = 34; + double rating = 70; + + var v = MamdaniDefuzzifier.Evaluate(new INumericalSet[] + { + temp.Is(low).Or(rating.Is(bad)).Then(small), + temp.Is(mid).Or(rating.Is(ok)).Then(avg), + temp.Is(high).Or(rating.Is(excelent)).Then(big), + }, MamdaniDefuzzifierMethod.FirstMaxima, 0, 600, 1); + + + Console.WriteLine(v); + // Create stores to keep objects. var system = await Warehouse.Put("sys", new MemoryStore()); var server = await Warehouse.Put("sys/server", new DistributedServer()); @@ -111,7 +138,7 @@ namespace Test sender.Send("Hello"); }); - var ok = await Warehouse.Open(); + await Warehouse.Open(); // Start testing TestClient(service);