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);