private void InitializeManaged(IList <Target> targets, DistanceFunc distance, Func <Target, Extraction> targetToExtraction, Func <Extraction, Pronounceable> extractionToPronounceable) { this.targets = targets; this.distance = distance; this.targetToExtraction = targetToExtraction; this.extractionToPronounceable = extractionToPronounceable; this.nativeDistanceDelegate = this.Distance; if (targetToExtraction == null) { try { this.extractions = (IList <Extraction>)targets; } catch { throw new InvalidCastException(string.Format("Can't cast Target type [{0}] to Extraction type [{1}]. You must provide a conversion function 'targetToExtraction'.", typeof(Target), typeof(Extraction))); } } else { this.extractions = new Extraction[targets.Count]; } if (extractionToPronounceable == null) { this.pronounceables = (IList <Pronounceable>) this.extractions; } else { this.pronounceables = new Pronounceable[targets.Count]; } }
private static void AgnesClusteringPrint(IrisData[] irisData, DistanceDelegate calculateDistanceFunction, ClusterDistanceStrategy strategy) { var irisDataHier = irisData.Select(d => new double[] { d.PetalLength, d.PetalWidth, d.SepalLength, d.SepalWidth }).ToHashSet(); var hc = new AgnesClustering(calculateDistanceFunction, irisDataHier); var clusters = hc.Cluster(strategy, 3); var i = 0; Console.ForegroundColor = ConsoleColor.DarkYellow; Console.WriteLine($"Agnes {calculateDistanceFunction.Method.Name} {strategy.ToString()} Predicted:"); Console.ForegroundColor = ConsoleColor.Gray; var res = new IrisData[clusters.Count()][]; foreach (Cluster cl in clusters) { var pp = cl.GetAllPatterns(); var clusterResult = pp.Select(p => p.GetAttributes()).Select(p => _irisData.First(x => x.PetalLength == p[0] && x.PetalWidth == p[1] && x.SepalLength == p[2] && x.SepalWidth == p[3])).ToArray(); res[i++] = clusterResult; } PrintResult(res, irisData.Length); Console.WriteLine(); }
private static double CalculateClusteringInformation( double[][] data, int[] clustering, ref int[] centroidIdx, int clusterCount, ref int[] clusterItemCount, DistanceDelegate calculateDistanceFunction) { var means = CreateMatrix(clusterCount, data[0].Length); // Calculate the means for each cluster // Do this in two phases, first sum them all up and then divide by the count in each cluster for (var i = 0; i < data.Length; i++) { // Sum up the means var row = data[i]; var clusterIdx = clustering[i]; // What cluster is data i assigned to ++clusterItemCount[clusterIdx]; // Increment the count of the cluster that row i is assigned to for (var j = 0; j < row.Length; j++) { means[clusterIdx][j] += row[j]; } } // Now divide to get the average for (var k = 0; k < means.Length; k++) { for (var a = 0; a < means[k].Length; a++) { var itemCount = clusterItemCount[k]; means[k][a] /= itemCount > 0 ? itemCount : 1; } } double totalDistance = 0; var minDistances = new double[clusterCount].Select(x => double.MaxValue).ToArray(); for (var i = 0; i < data.Length; i++) { var clusterIdx = clustering[i]; // What cluster is data i assigned to var distance = calculateDistanceFunction(data[i], means[clusterIdx]); totalDistance += distance; if (distance < minDistances[clusterIdx]) { minDistances[clusterIdx] = distance; centroidIdx[clusterIdx] = i; } } return(totalDistance); }
public void Searcher(ActorRoot _curActor, ActorRoot _inActor, DistanceDelegate _delegate) { ulong num = _delegate(_curActor.location, _inActor.location); if (num < this.maxValue) { this.targetList.Clear(); this.maxValue = num; this.targetList.Add(_inActor); } else if (num == this.maxValue) { this.targetList.Add(_inActor); } }
public AgnesClustering(DistanceDelegate distanceFunction, HashSet <double[]> dataSet) { _clusters = new Clusters(); _patternMatrix = new HashSet <Pattern>(); foreach (var item in dataSet) { _pattern = new Pattern(); _pattern.Id = _patternIndex; _pattern.AddAttributes(item); _patternMatrix.Add(_pattern); _patternIndex++; } this._distanceFunction = distanceFunction; }
private static void KMeansWithDistanceFunc(IrisData[] irisData, DistanceDelegate calculateDistanceFunction) { Console.WriteLine(); var results = new List <KMeans.Result <IrisData> >(25); for (int i = 0; i < results.Capacity; i++) { var result = KMeans.Cluster(calculateDistanceFunction, irisData, 3); results.Add(result); } var bestResult = results.Aggregate((minItem, nextItem) => minItem.TotalDistance < nextItem.TotalDistance ? minItem : nextItem); Console.ForegroundColor = ConsoleColor.DarkYellow; Console.WriteLine($"KMeans {calculateDistanceFunction.Method.Name} Predicted:"); Console.ForegroundColor = ConsoleColor.Gray; PrintResult(bestResult.Clusters, irisData.Length, bestResult.Iteration); }
public static Result <T> Cluster <T>(DistanceDelegate calculateDistanceFunction, T[] items, int clusterCount, int maxIterations = 10) { var data = ConvertToVectors(items); var hasChanges = true; var iteration = 0; double totalDistance = 0; var numData = data.Length; // Create a random initial clustering assignment var clustering = InitializeClustering(numData, clusterCount); var centroidIdx = new int[clusterCount]; var clusterItemCount = new int[clusterCount]; // Perform the clustering while (hasChanges && iteration < maxIterations) { clusterItemCount = new int[clusterCount]; totalDistance = CalculateClusteringInformation(data, clustering, ref centroidIdx, clusterCount, ref clusterItemCount, calculateDistanceFunction); hasChanges = AssignClustering(data, clustering, centroidIdx, clusterCount, calculateDistanceFunction); ++iteration; } var clusters = new T[clusterCount][]; for (var k = 0; k < clusters.Length; k++) { clusters[k] = new T[clusterItemCount[k]]; } var clustersCurIdx = new int[clusterCount]; for (var i = 0; i < clustering.Length; i++) { var c = clustering[i]; clusters[c][clustersCurIdx[c]] = items[i]; ++clustersCurIdx[c]; } return(new Result <T>(clusters, totalDistance, iteration)); }
public int Spawn(LabeledVector <L> lvector, DistanceDelegate measure, ParallelStrategy parallelStrategy, bool spawnUsingLDA) { int nSpawnCount = 0; if (this.DoesEncloseVector(lvector, measure)) { if (parallelStrategy == ParallelStrategy.Multithreaded) { List <Task> lstSpawnThreads = new List <Task>(); foreach (SphereEx <L> child in this.Children) { lstSpawnThreads.Add(Task.Factory.StartNew(c => { nSpawnCount += ((SphereEx <L>)c).Spawn(lvector, measure, ParallelStrategy.SingleThreaded, spawnUsingLDA); }, child, TaskCreationOptions.LongRunning)); } Task.WaitAll(lstSpawnThreads.ToArray()); } else { foreach (SphereEx <L> child in this.Children) { nSpawnCount += child.Spawn(lvector, measure, ParallelStrategy.SingleThreaded, spawnUsingLDA); } } if (!spawnUsingLDA) { #region Regular Spawn if (!this.Label.Equals(lvector.Label) && !Vector.EqualsEx(this, lvector) && !this.DoesAtLeastOneChildEncloseVector(lvector, measure)) { this.AddChild(new SphereEx <L>(this.Radius - measure(this, lvector), lvector)); nSpawnCount++; } #endregion } else { #region LDA Spawn if (!this.DoesAtLeastOneChildEncloseVector(lvector, measure)) // Don't care about label as well as location of lvector { bool bContains = false; List <LabeledVector <L> > lst; if (!this.LDAVectors.TryGetValue(lvector.Label, out lst)) { this.LDAVectors.Add(lvector.Label, (lst = new List <LabeledVector <L> >())); } else { bContains = lst.Any(v => Vector.EqualsEx(v, lvector)); } if (!bContains) { lst.Add(lvector); if (this.LDAVectors.Keys.Count == 2 && !this.Children.Any()) { #region If the sphere contains exactly 2 classes, do the following... // 1. Create another discriminant // 2. If the discrimant CANNOT separate the classes, do the following... // 2a. Remove the lvector from the list it was just added to // 2b. Create new children from the classes // 2c. Try to spawn the presented LVector in the NEW children // 2d. Clear the dictionary, LDAVectors // 2e. If you can't spawn WITHIN the NEW children, add the vector to the this.LDAVectors // 3. Else (If the discrimant CAN separate the classes), do nothing but assign the property. bool bIsSeparable = false; DiscriminantEx <L> discriminant = null; try { //bIsSeparable = LDA.IsCompletelySeparatedWithDiscriminant(this.LDAVectors.ElementAt(0).Value, this.LDAVectors.ElementAt(1).Value, this, out discriminant); bIsSeparable = LDAEx.IsCompletelySeparatedWithDiscriminant(this.LDAVectors.ElementAt(0).Value, this.LDAVectors.ElementAt(1).Value, out discriminant); } catch { // Just consume, leaving bIsSeparable = false } if (!bIsSeparable) { lst.RemoveAt(lst.Count - 1); // Faster than .Remove() as I am not linearly searching List <SphereEx <L> > lstNewChildren = new List <SphereEx <L> >(); foreach (KeyValuePair <L, List <LabeledVector <L> > > kvp in this.LDAVectors) { if (kvp.Value.Any() && !kvp.Key.Equals(this.Label)) { //Vector vectorCentroid = Vector.Centroid(kvp.Value); //if (!Vector.EqualsEx(this, vectorCentroid)) //{ // SphereEx<L> child = new SphereEx<L>(this.Radius - measure(this, vectorCentroid), kvp.Key, (IVector)vectorCentroid); // this.AddChild(child); // lstNewChildren.Add(child); // nSpawnCount++; //} } } //bool hasSpawned = false; //foreach (SphereEx<L> child in lstNewChildren) //{ // if (child.DoesEncloseVector(lvector, measure)) // { // nSpawnCount += child.Spawn(lvector, measure, ParallelStrategy.SingleThreaded, spawnUsingLDA); // hasSpawned = true; // } //} this.LDAVectors.Clear(); //if (!hasSpawned) //{ // this.LDAVectors.Add(lvector.Label, new List<LabeledVector<L>>() { lvector }); //} } else { this.DiscriminantEx = discriminant; } #endregion } else if (this.LDAVectors.Keys.Count > 2) { #region If the sphere contains 3 or more classes, do the following... // 1. Create children from the OLDER label-sets // 2. Try to spawn the presented LVector IN the NEW children just created // 3. Clear the dictionary, LDAVectors // 4. If you can't spawn WITHIN the NEW children, add the vector to this.LDAVectors List <SphereEx <L> > lstNewChildren = new List <SphereEx <L> >(); foreach (KeyValuePair <L, List <LabeledVector <L> > > kvp in this.LDAVectors) { if (!kvp.Key.Equals(lvector.Label)) { Vector vectorCentroid = Vector.Centroid(kvp.Value); if (!Vector.EqualsEx(this, vectorCentroid)) { SphereEx <L> child = new SphereEx <L>(this.Radius - measure(this, vectorCentroid), kvp.Key, (IVector)vectorCentroid); this.AddChild(child); lstNewChildren.Add(child); nSpawnCount++; } } } //bool hasSpawned = false; //foreach (SphereEx<L> child in lstNewChildren) //{ // if (child.DoesEncloseVector(lvector, measure)) // { // nSpawnCount += child.Spawn(lvector, measure, ParallelStrategy.SingleThreaded, spawnUsingLDA); // hasSpawned = true; // } //} this.LDAVectors.Clear(); //if (!hasSpawned) //{ // this.LDAVectors.Add(lvector.Label, new List<LabeledVector<L>>() { lvector }); //} #endregion } // Note: If this.LDAVectors.Keys.Count == 1, don't do anything additional. } } #endregion } } return(nSpawnCount); }
public Composite CreateBehavior_MoveNearTarget(WoWObjectDelegate target, DistanceDelegate minRange, DistanceDelegate maxRange) { return ( new PrioritySelector(context => target(), // If we're too far from target, move closer... new Decorator(wowObject => (((WoWObject)wowObject).Distance > maxRange()), new Sequence( new DecoratorThrottled(Delay_StatusUpdateThrottle, ret => true, new Action(wowObject => { TreeRoot.StatusText = string.Format("Moving to {0} (distance: {1:0.0}) ", ((WoWObject)wowObject).Name, ((WoWObject)wowObject).Distance); })), CreateBehavior_InternalMoveTo(() => target().Location) )), // If we're too close to target, back up... new Decorator(wowObject => (((WoWObject)wowObject).Distance < minRange()), new PrioritySelector( // If backing up, make sure we're facing the target... new Decorator(ret => Me.MovementInfo.MovingBackward, new Action(wowObject => WoWMovement.Face(((WoWObject)wowObject).Guid))), // Start backing up... new Action(wowObject => { TreeRoot.StatusText = "Too close to \"" + ((WoWObject)wowObject).Name + "\"--backing up"; WoWMovement.MoveStop(); WoWMovement.Face(((WoWObject)wowObject).Guid); WoWMovement.Move(WoWMovement.MovementDirection.Backwards); }) )), // We're between MinRange and MaxRange, stop movement and face the target... new Decorator(ret => Me.IsMoving, new Sequence( new Action(delegate { WoWMovement.MoveStop(); }), new Action(wowObject => WoWMovement.Face(((WoWObject)wowObject).Guid)), new WaitContinue(Delay_WowClientLagTime, ret => false, new ActionAlwaysSucceed()), new ActionAlwaysFail() // fall through to next element )) )); }
private static bool AssignClustering(double[][] data, int[] clustering, int[] centroidIdx, int clusterCount, DistanceDelegate calculateDistanceFunction) { var changed = false; for (var i = 0; i < data.Length; i++) { var minDistance = double.MaxValue; var minClusterIndex = -1; for (var k = 0; k < clusterCount; k++) { var distance = calculateDistanceFunction(data[i], data[centroidIdx[k]]); if (distance < minDistance) { minDistance = distance; minClusterIndex = k; } } // Re-arrange the clustering for datapoint if needed if (minClusterIndex != -1 && clustering[i] != minClusterIndex) { changed = true; clustering[i] = minClusterIndex; } } return(changed); }
public override Sphere <L> Recognize(IVector vector, DistanceDelegate measure, ParallelStrategy parallelStrategy) { if (this is SphereEx <L> && ((SphereEx <L>) this).DiscriminantEx != null) { Sphere <L> sphereMinRadius = this.Parent == null ? this : null; if (this.DoesEncloseVector(vector, measure)) { double proj = Accord.Math.Matrix.Dot(this.DiscriminantEx.ProjectionVector, vector.Features); if (proj <= this.DiscriminantEx.ProjectedSetMean) { // Should be the ClassLabelLeft label // Graphical Example: // // |-------X--------+----------------| X => Decision point calculated by LDA, + => Centroid of Sphere // |-------| <-- If a point falls left of the decision point, I need the segment between | and X. Remember to divide by 2.0 because it should be a radius. // ^ // | // Remember to divide by two as it's a radius double farLeft = Accord.Math.Matrix.Dot(this.DiscriminantEx.ProjectionVector, this.Features) - (this.Radius * this.Radius); if (farLeft > this.DiscriminantEx.ProjectedLeftMean) { // Squared Euclidean may have a problem because the ProjectLeftMean may be left of the hypersphere // As such, add a small buffer (distance between farLeft and ProjectedLeftMean) // This is, perhaps, not the best method, but it works. Maybe explore other solutions when using Squared Euclidean Distance with LDA. sphereMinRadius = new Sphere <L>((this.DiscriminantEx.ProjectedSetMean - this.DiscriminantEx.ProjectedLeftMean) / 2.0, this.DiscriminantEx.ClassLeft, vector); } else { sphereMinRadius = new Sphere <L>((this.DiscriminantEx.ProjectedSetMean - farLeft) / 2.0, this.DiscriminantEx.ClassLeft, vector); } } else { // Should be the ClassLabelRight label double farRight = Accord.Math.Matrix.Dot(this.DiscriminantEx.ProjectionVector, this.Features) + (this.Radius * this.Radius); if (farRight < this.DiscriminantEx.ProjectedRightMean) { // Squared Euclidean may have a problem because the ProjectRightMean may be right of the hypersphere // As such, add a small buffer (distance between farRight and ProjectedRightMean) // This is, perhaps, not the best method, but it works. Maybe explore other solutions when using Squared Euclidean Distance with LDA. sphereMinRadius = new Sphere <L>((this.DiscriminantEx.ProjectedRightMean - this.DiscriminantEx.ProjectedSetMean) / 2.0, this.DiscriminantEx.ClassRight, vector); } else { sphereMinRadius = new Sphere <L>((farRight - this.DiscriminantEx.ProjectedSetMean) / 2.0, this.DiscriminantEx.ClassRight, vector); } } } return(sphereMinRadius); } else { return(base.Recognize(vector, measure, parallelStrategy)); } }
public int Spawn(LabeledVector <L> lvector, DistanceDelegate measure, ParallelStrategy parallelStrategy, bool spawnUsingLDA) { int nSpawnCount = 0; if (this.DoesEncloseVector(lvector, measure)) { if (parallelStrategy == ParallelStrategy.Multithreaded) { List <Task> lstSpawnThreads = new List <Task>(); foreach (SphereEx <L> child in this.Children) { lstSpawnThreads.Add(Task.Factory.StartNew(c => { nSpawnCount += ((SphereEx <L>)c).Spawn(lvector, measure, ParallelStrategy.SingleThreaded, spawnUsingLDA); }, child, TaskCreationOptions.LongRunning)); } Task.WaitAll(lstSpawnThreads.ToArray()); } else { foreach (SphereEx <L> child in this.Children) { nSpawnCount += child.Spawn(lvector, measure, ParallelStrategy.SingleThreaded, spawnUsingLDA); } } if (!spawnUsingLDA) { #region Regular Spawn if (!this.Label.Equals(lvector.Label) && !Vector.EqualsEx(this, lvector) && !this.DoesAtLeastOneChildEncloseVector(lvector, measure)) { SphereEx <L> child = new SphereEx <L>(this.Radius - measure(this, lvector), lvector); child.LDAVectors.Add(child.Label, new List <KeyValuePair <int, LabeledVector <L> > >() { new KeyValuePair <int, LabeledVector <L> >(0, lvector) }); this.AddChild(child); nSpawnCount++; } #endregion } else { #region LDA Spawn // Note that LDA Spawn doesn't work with SquaredEuclideanDistance. I may -- in the future -- do an additional check to see if the vector is contained by the hypersphere with SquaredEuclideanDistance and EuclideanDistance. If so, this will work. Until then, I'll leave it as is. if (this.Children.Any()) { // Next if-statement a duplicate of the region "Regular Spawn" // Remember, LDA is only applied at nodes with no children (leaf) if (!this.Label.Equals(lvector.Label) && !Vector.EqualsEx(this, lvector) && !this.DoesAtLeastOneChildEncloseVector(lvector, measure)) { SphereEx <L> child = new SphereEx <L>(this.Radius - measure(this, lvector), lvector); child.LDAVectors.Add(child.Label, new List <KeyValuePair <int, LabeledVector <L> > >() { new KeyValuePair <int, LabeledVector <L> >(0, lvector) }); this.AddChild(child); nSpawnCount++; } } else { bool bContains = false; List <KeyValuePair <int, LabeledVector <L> > > lst; if (!this.LDAVectors.TryGetValue(lvector.Label, out lst)) { this.LDAVectors.Add(lvector.Label, (lst = new List <KeyValuePair <int, LabeledVector <L> > >())); } else { bContains = lst.Any(kvp => Vector.EqualsEx(kvp.Value, lvector)); } if (!bContains) { lst.Add(new KeyValuePair <int, LabeledVector <L> >(this.LDAVectors.Sum(kvp => kvp.Value.Count), lvector)); if (this.LDAVectors.Keys.Count == 2) { #region If the sphere contains exactly 2 classes, do the following... bool bIsSeparable = false; DiscriminantEx <L> discriminant = null; try { bIsSeparable = LDAEx.IsCompletelySeparatedWithDiscriminant(this.LDAVectors.ElementAt(0).Value.Select(kvp => kvp.Value).ToList(), this.LDAVectors.ElementAt(1).Value.Select(kvp => kvp.Value).ToList(), out discriminant); } catch { // Just consume, leaving bIsSeparable = false } if (!bIsSeparable) { bool spawnedAtLeastOnce = false; List <LabeledVector <L> > lstCache = this.LDAVectors.SelectMany(kvp => kvp.Value).OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value).ToList(); this.LDAVectors.Clear(); this.DiscriminantEx = null; foreach (LabeledVector <L> v in lstCache) { if (!spawnedAtLeastOnce) { int count = this.Spawn(v, measure, ParallelStrategy.SingleThreaded, false); nSpawnCount += count; spawnedAtLeastOnce = count > 0; } else { nSpawnCount += this.Spawn(v, measure, ParallelStrategy.SingleThreaded, true); } } } else { if (discriminant != null) { this.DiscriminantEx = discriminant; } } #endregion } else if (this.LDAVectors.Keys.Count > 2) { #region If the sphere contains 3 or more classes, do the following... bool spawnedAtLeastOnce = false; List <LabeledVector <L> > lstCache = this.LDAVectors.SelectMany(kvp => kvp.Value).OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value).ToList(); this.LDAVectors.Clear(); this.DiscriminantEx = null; foreach (LabeledVector <L> v in lstCache) { if (!spawnedAtLeastOnce) { int count = this.Spawn(v, measure, ParallelStrategy.SingleThreaded, false); nSpawnCount += count; spawnedAtLeastOnce = count > 0; } else { nSpawnCount += this.Spawn(v, measure, ParallelStrategy.SingleThreaded, true); } } #endregion } // Note: If this.LDAVectors.Keys.Count == 1, don't do anything additional. } } #endregion } } return(nSpawnCount); }
public override L RecognizeAsLabel(IVector vector, DistanceDelegate measure, ParallelStrategy parallelStrategy) { Sphere <L> winner = this.Recognize(vector, measure, parallelStrategy); return(winner != null ? winner.Label : default(L)); }
protected static extern NativeResult FuzzyMatcher_Create(int count, DistanceDelegate distance, bool isAccelerated, out IntPtr fuzzyMatcher, StringBuilder errorMsg, ref int bufferSize);