/// <summary> /// Populate empty species with a single genome. /// </summary> /// <typeparam name="T">Connection weight data type.</typeparam> /// <param name="distanceMetric">Distance metric.</param> /// <param name="emptySpeciesArr">An array of empty species that are to be populated.</param> /// <param name="speciesArr">An array of all species.</param> public static void PopulateEmptySpecies <T>( IDistanceMetric <T> distanceMetric, Species <T>[] emptySpeciesArr, Species <T>[] speciesArr) where T : struct { // TODO: Select the required genomes all together, rather than one at a time per empty species. // Create a temporary, reusable, working list. var tmpPointList = new List <ConnectionGenes <T> >(); foreach (Species <T> emptySpecies in emptySpeciesArr) { // Get and remove a genome from a species with many genomes. var genome = GetGenomeForEmptySpecies(distanceMetric, speciesArr, tmpPointList); // Add the genome to the empty species. emptySpecies.GenomeById.Add(genome.Id, genome); // Update the centroid. There's only one genome so it is the centroid. emptySpecies.Centroid = genome.ConnectionGenes; } tmpPointList.Clear(); }
/// <summary> /// Creates a new HAC object that uses single-linkage as fusion function and the Jaccard index as distance metric /// to cluster the specified elements. /// </summary> /// <param name="elements"></param> public HacStart(Element[] elements) { setElements(elements); this.fusion = new SingleLinkage(); this.metric = new JaccardDistance(); this.fusion.Metric = metric; }
/// <summary> /// Calculates a centroid by comparing each coordinate with every other /// coordinate. The coord with the lowest average distance from all /// other coords is the most central coord (the centroid). This method /// uses an inefficient N*N comparison of coords to find a centroid. It /// is provided only as a last resort for distance metrics for which no /// means exist to calculate a centroid more directly. /// </summary> public static CoordinateVector CalculateCentroid(IDistanceMetric distanceMetric, IList <CoordinateVector> coordList) { // Test special case - one coord therefore it is the centroid.. if (1 == coordList.Count) { return(new CoordinateVector(coordList[0].CoordArray)); } // Find coord that is most central. // First element as provisional choice. double centroidDistance = CalculateMeanDistanceFromCoords(distanceMetric, coordList, 0); int centroidIdx = 0; int count = coordList.Count; for (int i = 1; i < count; i++) { double distance = CalculateMeanDistanceFromCoords(distanceMetric, coordList, i); if (distance < centroidDistance) { // We have a new centroid candidate. centroidDistance = distance; centroidIdx = i; } } // We make a copy of the element to avoid any problems // (CoordinateVector is intended to used as an immutable type but // it isn't actually immutable) return(new CoordinateVector(coordList[centroidIdx].CoordArray)); }
public static void ValidationTests( Species <double>[] speciesArr, IDistanceMetric <double> distanceMetric, int speciesCountExpected, List <NeatGenome <double> > fullGenomeList, bool validateNearestSpecies) { // Confirm correct number of species. Assert.AreEqual(speciesCountExpected, speciesArr.Length); // Confirm no empty species. int minSpeciesSize = speciesArr.Select(x => x.GenomeList.Count).Min(); Assert.IsTrue(minSpeciesSize > 0); // Get IDs of all genomes in species. var idSet = GetAllGenomeIds(speciesArr); // Confirm number of IDs equals number of genomes in main population list. Assert.AreEqual(fullGenomeList.Count, idSet.Count); // Confirm the genome list IDs match up with the genomes in the species. fullGenomeList.ForEach(x => Assert.IsTrue(idSet.Contains(x.Id))); // Confirm all species centroids are correct. Array.ForEach(speciesArr, x => Assert.AreEqual(0.0, distanceMetric.CalcDistance(x.Centroid, distanceMetric.CalculateCentroid(x.GenomeList.Select(y => y.ConnectionGenes))))); if (validateNearestSpecies) { // Confirm all genomes are in the species with the nearest centroid. // Note. If there are two or more species that are equally near then we test that a genome is in one of those. Array.ForEach(speciesArr, species => species.GenomeList.ForEach(genome => Assert.IsTrue(GetNearestSpeciesList(genome, speciesArr, distanceMetric).Contains(species)))); } }
/// <summary> /// Construct with the provided distance metric and k-means settings. /// </summary> /// <param name="distanceMetric">Distance metric.</param> /// <param name="maxKMeansIters">Maximum number of k-means iterations.</param> /// <param name="regularizationConstant">Regularization constant.</param> public RegularizedGeneticKMeansSpeciationStrategy( IDistanceMetric <T> distanceMetric, int maxKMeansIters, double regularizationConstant) : this(distanceMetric, maxKMeansIters, regularizationConstant, new ParallelOptions()) { }
/// <summary> /// Starts the clustering. /// </summary> /// <param name="elements"></param> /// <param name="fusion"></param> /// <param name="metric"></param> /// <returns></returns> protected internal Cluster[] Cluster(List<Element> elements, Fusion fusion, IDistanceMetric metric) { HashSet<Cluster> clusters = new HashSet<Cluster>(); ClusterPairs pairs = new ClusterPairs(); // 1. Initialize each element as a cluster foreach (Element el in elements) { Cluster cl = new Cluster(fusion); cl.AddElement(el); clusters.Add(cl); } // 2. a) Calculate the distances of all clusters to all other clusters foreach (Cluster cl1 in clusters) { foreach (Cluster cl2 in clusters) { if (cl1 == cl2) continue; ClusterPair pair = new ClusterPair(cl1, cl2, cl1.CalculateDistance(cl2)); pairs.AddPair(pair); } } // 2. b) Initialize the pair with the lowest distance to each other. ClusterPair lowestDistancePair = pairs.LowestDistancePair; // 3. Merge clusters to new clusters and recalculate distances in a loop until there are only countCluster clusters while (!isFinished(clusters, lowestDistancePair)) { // a) Merge: Create a new cluster and add the elements of the two old clusters lowestDistancePair = pairs.LowestDistancePair; Cluster newCluster = new Cluster(fusion); newCluster.AddElements(lowestDistancePair.Cluster1.GetElements()); newCluster.AddElements(lowestDistancePair.Cluster2.GetElements()); // b)Remove the two old clusters from clusters clusters.Remove(lowestDistancePair.Cluster1); clusters.Remove(lowestDistancePair.Cluster2); // c) Remove the two old clusters from pairs pairs.RemovePairsByOldClusters(lowestDistancePair.Cluster1, lowestDistancePair.Cluster2); // d) Calculate the distance of the new cluster to all other clusters and save each as pair foreach (Cluster cluster in clusters) { ClusterPair pair = new ClusterPair(cluster, newCluster, cluster.CalculateDistance(newCluster)); pairs.AddPair(pair); } // e) Add the new cluster to clusters clusters.Add(newCluster); } return clusters.ToArray<Cluster>(); }
/// <summary> /// Find medoid by comparing each coordinate with every other coordinate. The coord with the lowest /// average distance from all other coords is the most central coord (the medoid). /// This method uses an inefficient N*N comparison of coords to find a medoid. It is provided only as a last /// resort for distance metrics for which no means exist to calculate a centroid. /// </summary> /// <param name="distanceMetric">Distance metric.</param> /// <param name="pointList">Point list.</param> /// <returns>The index of the element in <paramref name="pointList"/> that is the medoid.</returns> public static int FindMedoid( IDistanceMetric <double> distanceMetric, IList <ConnectionGenes <double> > pointList) { // Special case. One item in list, therefore it is the centroid. if (pointList.Count == 1) { return(0); } // Find coord that is most central. // Handle first coordinate. int medoidIdx = 0; double medoidDistance = CalculateMeanDistanceFromCoords(distanceMetric, pointList, 0); // Handle all other coordinates. int count = pointList.Count; for (int i = 1; i < count; i++) { double distance = CalculateMeanDistanceFromCoords(distanceMetric, pointList, i); if (distance < medoidDistance) { // We have a new centroid candidate. medoidDistance = distance; medoidIdx = i; } } // Return the coord that is the medoid. return(medoidIdx); }
/// <summary> /// Calculates a centroid by comparing each coordinate with every other coordinate. The coord with the lowest /// average distance from all other coords is the most central coord (the centroid). /// This method uses an inefficient N*N comparison of coords to find a centroid. It is provided only as a last /// resort for distance metrics for which no means exist to calculate a centroid more directly. /// </summary> public static CoordinateVector CalculateCentroid(IDistanceMetric distanceMetric, IList<CoordinateVector> coordList) { // Test special case - one coord therefore it is the centroid.. if(1 == coordList.Count) { return new CoordinateVector(coordList[0].CoordArray); } // Find coord that is most central. int centroidIdx = 0; double centroidDistance = CalculateMeanDistanceFromCoords(distanceMetric, coordList, 0); int count = coordList.Count; for(int i=1; i<count; i++) { double distance = CalculateMeanDistanceFromCoords(distanceMetric, coordList, i); if(distance < centroidDistance) { // We have a new centroid candidate. centroidDistance = distance; centroidIdx = i; } } // We make a copy of the element to avoid any problems (CoordinateVector is intended to used as // an immutable type but it isn't actually immutable) return new CoordinateVector(coordList[centroidIdx].CoordArray); }
/// <summary> /// Gets the species with a centroid closest to the given genome. /// If multiple species are equally close then we return all of the those species. /// </summary> public static List <Species <T> > GetNearestSpeciesList <T>( NeatGenome <T> genome, Species <T>[] speciesArr, IDistanceMetric <T> distanceMetric) where T : struct { var nearestSpeciesList = new List <Species <T> >(4); nearestSpeciesList.Add(speciesArr[0]); double nearestDistance = distanceMetric.CalcDistance(genome.ConnectionGenes, speciesArr[0].Centroid); for (int i = 1; i < speciesArr.Length; i++) { double distance = distanceMetric.CalcDistance(genome.ConnectionGenes, speciesArr[i].Centroid); if (distance < nearestDistance) { nearestSpeciesList.Clear(); nearestSpeciesList.Add(speciesArr[i]); nearestDistance = distance; } else if (distance == nearestDistance) { nearestSpeciesList.Add(speciesArr[i]); } } return(nearestSpeciesList); }
public LeafNode(int index, IEnumerable <int> coords, IDistanceMetric distanceMetric) : base(1, distanceMetric) { Index = index; Coords = coords.ToDictionary(coord => coord, _ => 1.0); FirstLeaf = this; SecondLeaf = this; }
public LeafNode(int index, IEnumerable <float> coords, IDistanceMetric distanceMetric) : base(1, distanceMetric) { Index = index; Coords = coords.Select((coord, i) => new { i, coord }).Where(pair => pair.coord > 0).ToDictionary(pair => pair.i, pair => (double)pair.coord); FirstLeaf = this; SecondLeaf = this; }
private void RunClusteringAndGraph() { if (chartDataSource != null) { Cluster cluster; distanceMetric = DistanceMetric(currentDistanceMatrix); try { clusterResult = ClusterCalculate(); } catch (InvalidOperationException) { MessageBox.Show("Please try again."); return; } /* Executing scatterplot */ foreach (var dataPoint in chartDataSource) { cluster = clusterResult.FindCluster(dataPoint.Origin); if (cluster != null) { dataPoint.Group = string.Format("Cluster {0}", cluster.Id); } } chartDataSource = chartDataSource.OrderBy(item => item.Group).ToList(); scatterPlotControl1.BuildScatterPlot(chartDataSource); } }
/// <summary> /// Construct with the given distance metric. /// </summary> /// <param name="distanceMetric">Distance metric.</param> /// <param name="parallelOptions">Parallel options.</param> public GeneticKMeansSpeciationInit( IDistanceMetric <T> distanceMetric, ParallelOptions parallelOptions) { _distanceMetric = distanceMetric ?? throw new ArgumentNullException(nameof(distanceMetric)); _parallelOptions = parallelOptions; }
public void DistanceMatrixShouldReturnLargerCorrectDistanceMatrix() { double difference; collectionSize = 111; distanceMetric = new EuclideanMetric(); generatedDataCollection = new GenerateIdentifiableDataPointCollection(collectionSize); dataCollection = generatedDataCollection.Generate(); distanceMatrix = new DistanceMatrix(dataCollection, distanceMetric); expectedMatrix = ExpectedMatrix(); for (int row = 0; row < distanceMatrix.Rows; row++) { for (int col = 0; col < distanceMatrix.Columns; col++) { difference = distanceMatrix[row, col] - expectedMatrix[row, col]; if (!(difference < 0.01 && difference > -0.01 && distanceMatrix[row, col] >= 0)) { Assert.Fail("{0}, row = {1}, col = {2}", difference, row, col); } } } }
public GeneticKMeansSpeciationInit( IDistanceMetric <T> distanceMetric, IRandomSource rng) { _distanceMetric = distanceMetric; _rng = rng; }
public RobotIndividual(Robot robot, Individual[] parents) { Robot = robot; Genome = robot.Genome; Parents = parents; _distanceMetric = new EuclideanDistanceMetric(); }
public PointsDistance(IDistanceMetric gauge) { if (gauge == null) { throw new ArgumentNullException(nameof(gauge)); } Gauge = gauge; }
public GeneticKMeansSpeciationInit( IDistanceMetric <T> distanceMetric, ParallelOptions parallelOptions, IRandomSource rng) { _distanceMetric = distanceMetric; _parallelOptions = parallelOptions; _rng = rng; }
public GeneticKMeansSpeciationStrategy( IDistanceMetric <T> distanceMetric, int maxKMeansIters, IRandomSource rng) { _distanceMetric = distanceMetric; _maxKMeansIters = maxKMeansIters; _kmeansInit = new GeneticKMeansSpeciationInit <T>(distanceMetric, rng); }
/// <summary> /// Construct a new instance. /// </summary> /// <param name="distanceMetric">Distance metric.</param> /// <param name="maxKMeansIters">Maximum number of k-means iterations.</param> /// <param name="parallelOptions">Parallel execution options.</param> public GeneticKMeansSpeciationStrategy( IDistanceMetric <T> distanceMetric, int maxKMeansIters, ParallelOptions parallelOptions) { _distanceMetric = distanceMetric; _maxKMeansIters = maxKMeansIters; _parallelOptions = parallelOptions; _kmeansInit = new GeneticKMeansSpeciationInit <T>(distanceMetric, parallelOptions); }
public DataVisualizationForm(IdentifiableDataPointCollection dataSet) : this() { this.dataSet = dataSet; distanceMetric = DistanceMetric(currentDistanceMatrix); dataConversionTask = new DataConversionTask(); dataConversionTask.Success += DataConversionTask_Success; dataConversionTask.Failure += DataConversionTask_Failure; }
/// <summary> /// Construct with the provided distance metric and k-means settings. /// </summary> /// <param name="distanceMetric">Distance metric.</param> /// <param name="maxKMeansIters">Maximum number of k-means iterations.</param> /// <param name="regularizationConstant">Regularization constant.</param> public RegularizedGeneticKMeansSpeciationStrategy( IDistanceMetric <T> distanceMetric, int maxKMeansIters, double regularizationConstant) { _distanceMetric = distanceMetric; _maxKMeansIters = maxKMeansIters; _regularizationConstant = regularizationConstant; _kmeansInit = new GeneticKMeansSpeciationInit <T>(distanceMetric); }
public DistanceMatrix(IEnumerable <DataPoint> input, IDistanceMetric distanceMetric) : base(input.Count(), input.Count()) { if (distanceMetric == null) { throw new ArgumentNullException("distanceMetric"); } this.distanceMetric = distanceMetric; dataPointList = input.ToList(); CalculateEntries(); }
public RegularizedGeneticKMeansSpeciationStrategy( IDistanceMetric <T> distanceMetric, int maxKMeansIters, double regularizationConstant, IRandomSource rng) { _distanceMetric = distanceMetric; _maxKMeansIters = maxKMeansIters; _regularizationConstant = regularizationConstant; _parallelOptions = new ParallelOptions(); _kmeansInit = new GeneticKMeansSpeciationInit <T>(distanceMetric, _parallelOptions, rng); }
public NewtonSolver(List <T> ns, IDistanceMetric m) { metric = m; foreach (T n in ns) { Vector3 p = new Vector3(); p.x = (float)Eleven.random.NextDouble(); p.y = (float)Eleven.random.NextDouble(); n.transform.position = p; nodes.Add(new Node(n)); } }
/// <summary> /// Starts the task. /// </summary> /// <param name="dataSet">The list of objects that to be converted.</param> /// <param name="distanceMetric">The distance metric used to scale down dimensions.</param> public void Start(IdentifiableDataPointCollection dataSet, IDistanceMetric distanceMetric) { var args = new TaskRunnerArgumentSet { Data = dataSet, DistanceMetric = distanceMetric }; var task = Task.Factory.StartNew <DataConversionResult>(TaskRunner, args); // Make sure Success and Failure events are run within the caller thread. TaskScheduler currentContext = TaskScheduler.FromCurrentSynchronizationContext(); task.ContinueWith(TaskComplete, currentContext); task.ContinueWith(TaskFaulted, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, currentContext); }
public static void TestSpeciateAdd( int popSize, int inputNodeCount, int outputNodeCount, double connectionsProportion, IDistanceMetric <double> distanceMetric, ISpeciationStrategy <NeatGenome <double>, double> speciationStrategy, IRandomSource rng, bool validateNearestSpecies = true) { // Create population. NeatPopulation <double> neatPop = CreateNeatPopulation(popSize, inputNodeCount, outputNodeCount, connectionsProportion); // Split the population into three. int popSize1 = popSize / 3; int popSize2 = popSize / 3; int popSize3 = popSize - (popSize1 + popSize2); var genomeList1 = neatPop.GenomeList.GetRange(0, popSize1); var genomeList2 = neatPop.GenomeList.GetRange(popSize1, popSize2); var genomeList3 = neatPop.GenomeList.GetRange(popSize1 + popSize2, popSize3); for (int i = 0; i < 6; i++) { int speciesCount = rng.Next(1, (neatPop.GenomeList.Count / 4) + 1); var fullGenomeList = new List <NeatGenome <double> >(genomeList1); // Invoke speciation strategy, and run tests var speciesArr = speciationStrategy.SpeciateAll(genomeList1, speciesCount, rng); ValidationTests(speciesArr, distanceMetric, speciesCount, fullGenomeList, validateNearestSpecies); // Add second batch of genomes, and re-run tests. speciationStrategy.SpeciateAdd(genomeList2, speciesArr, rng); fullGenomeList.AddRange(genomeList2); ValidationTests(speciesArr, distanceMetric, speciesCount, fullGenomeList, validateNearestSpecies); // Add third batch of genomes, and re-run tests. speciationStrategy.SpeciateAdd(genomeList3, speciesArr, rng); fullGenomeList.AddRange(genomeList3); ValidationTests(speciesArr, distanceMetric, speciesCount, fullGenomeList, validateNearestSpecies); } }
public KMeans(IdentifiableDataPointCollection dataCollection, int k, IDistanceMetric distanceMetric, int maxIterations = 100) { if (k < 1) { throw new ArgumentException("Clusters cannot be generated for less than one centroid"); } this.dataCollection = dataCollection; this.maxIterations = maxIterations; this.distanceMetric = distanceMetric; this.centroids = dataCollection .OrderBy(dataPoint => Guid.NewGuid()) // Random order .Take(k) .Select(dataPoint => dataPoint.Clone()) .ToList(); EnsureDistinctCentroid(); }
public KMeans(IdentifiableDataPointCollection dataCollection, int[] centroidIndicies, IDistanceMetric distanceMetric, int maxIterations = 100) { this.dataCollection = dataCollection; this.maxIterations = maxIterations; this.distanceMetric = distanceMetric; if (centroidIndicies.Length != centroidIndicies.Distinct().Count()) { throw new ArgumentException( "Array contains dublicate indicies, which is not allowed.", "centroidIndicies"); } this.centroids = centroidIndicies .Select(index => this.dataCollection[index].Clone()) .ToList(); EnsureDistinctCentroid(); }
/// <summary> /// Populate empty species with a single genome. /// </summary> /// <typeparam name="T">Connection weight data type.</typeparam> /// <param name="distanceMetric">Distance metric.</param> /// <param name="emptySpeciesArr">An array of empty species that are to be populated.</param> /// <param name="speciesArr">An array of all species.</param> public static void PopulateEmptySpecies <T>( IDistanceMetric <T> distanceMetric, Species <T>[] emptySpeciesArr, Species <T>[] speciesArr) where T : struct { foreach (Species <T> emptySpecies in emptySpeciesArr) { // Get and remove a genome from a species with many genomes. var genome = GetGenomeForEmptySpecies(distanceMetric, speciesArr); // Add the genome to the empty species. emptySpecies.GenomeById.Add(genome.Id, genome); // Update the centroid. There's only one genome so it is the centroid. emptySpecies.Centroid = genome.ConnectionGenes; } }
/// <summary> /// Calculate the mean distance of the specified coord from all of the other coords using /// the provided distance metric. /// </summary> /// <param name="distanceMetric">The distance metric.</param> /// <param name="coordList">The list of coordinatres.</param> /// <param name="idx">The index of the coordinate to measure distance to.</param> private static double CalculateMeanDistanceFromCoords(IDistanceMetric distanceMetric, IList<CoordinateVector> coordList, int idx) { double totalDistance = 0.0; int count = coordList.Count; CoordinateVector targetCoord = coordList[idx]; // Measure distance to all coords before the target one. for(int i=0; i<idx; i++) { totalDistance += distanceMetric.MeasureDistance(targetCoord, coordList[i]); } // Measure distance to all coords after the target one. for(int i=idx+1; i<count; i++) { totalDistance += distanceMetric.MeasureDistance(targetCoord, coordList[i]); } return totalDistance / (count-1); }
public ClusterNode(Node first, Node second, double distance, IDistanceMetric distanceMetric) : base(first.NumChildren + second.NumChildren, distanceMetric) { Distance = distance; // Calculate the pairwise distances between the two sides of each clustered node. var distFirstFirst = first.FirstLeaf.DistanceTo(second.FirstLeaf); var distFirstSecond = second.FirstLeaf == second.SecondLeaf ? distFirstFirst : first.FirstLeaf.DistanceTo(second.SecondLeaf); var distSecondFirst = first.FirstLeaf == first.SecondLeaf ? distFirstFirst : first.SecondLeaf.DistanceTo(second.FirstLeaf); var distSecondSecond = second.FirstLeaf == second.SecondLeaf ? distSecondFirst : first.SecondLeaf.DistanceTo(second.SecondLeaf); // Order the two nodes so that the minimum distance is between them. if (Math.Min(distFirstSecond, distSecondFirst) <= Math.Min(distFirstFirst, distSecondSecond)) { if (distSecondFirst <= distFirstSecond) { First = first; Second = second; } else { First = second; Second = first; } } else { if (distSecondSecond <= distFirstFirst) { First = first; Second = second; Second.Reverse(); } else { First = second; Second = first; First.Reverse(); } } First.Parent = this; Second.Parent = this; FirstLeaf = First.FirstLeaf; SecondLeaf = Second.SecondLeaf; }
/// <summary> /// Calculate the mean distance of the specified coord from all of the /// other coords using the provided distance metric. /// </summary> /// <param name="distanceMetric">The distance metric.</param> /// <param name="coordList">The list of coordinatres.</param> /// <param name="idx">The index of the coordinate to measure distance to.</param> private static double CalculateMeanDistanceFromCoords(IDistanceMetric distanceMetric, IList <CoordinateVector> coordList, int idx) { double totalDistance = 0.0; int count = coordList.Count; CoordinateVector targetCoord = coordList[idx]; // Measure distance to all coords before the target one. for (int i = 0; i < idx; i++) { totalDistance += distanceMetric.MeasureDistance(targetCoord, coordList[i]); } // Measure distance to all coords after the target one. for (int i = idx + 1; i < count; i++) { totalDistance += distanceMetric.MeasureDistance(targetCoord, coordList[i]); } return(totalDistance / (count - 1)); }
private static NeatGenome <T> GetGenomeForEmptySpecies <T>( IDistanceMetric <T> distanceMetric, Species <T>[] speciesArr) where T : struct { // Get the species with the highest number of genomes. Species <T> species = speciesArr.Aggregate((x, y) => x.GenomeById.Count > y.GenomeById.Count ? x : y); // Get the genome furthest from the species centroid. var genome = species.GenomeById.Values.Aggregate((x, y) => distanceMetric.CalcDistance(species.Centroid, x.ConnectionGenes) > distanceMetric.CalcDistance(species.Centroid, y.ConnectionGenes) ? x : y); // Remove the genome from its current species. species.GenomeById.Remove(genome.Id); // Update the species centroid. species.Centroid = distanceMetric.CalculateCentroid(species.GenomeById.Values.Select(x => x.ConnectionGenes)); // Return the selected genome. return(genome); }
/// <summary> /// Creates a new HAC object to cluster the specified elements with the specified fusion and /// metric function. /// </summary> /// <param name="elements"></param> /// <param name="fusion"></param> /// <param name="metric"></param> public HacStart(Element[] elements, Fusion fusion, IDistanceMetric metric) { setElements(elements); this.fusion = fusion; this.fusion.Metric = metric; }