/// <summary> /// This does a fuzzy match to find the best links it can /// </summary> /// <remarks> /// The existing links passed in point to where neurons used to be. This method compares those positions with where /// neurons are now, and tries to match up with the closest it can /// /// NOTE: Both neurons and links could have been mutated independent of each other. This method doesn't care how /// they got the way they are, it just goes by position /// </remarks> private static LinkIndexed[] BuildInternalLinksExisting_Continue(IEnumerable<INeuron> neurons, int count, NeuralLinkDNA[] existing, int maxBrainChemicals, int maxIntermediateLinks, int maxFinalLinks) { NeuralLinkDNA[] existingPruned = existing; if (existing.Length > count) { // Prune without distributing weight (if this isn't done here, then the prune at the bottom of this method will // artificially inflate weights with the links that this step is removing) existingPruned = existing.OrderByDescending(o => Math.Abs(o.Weight)).Take(count).ToArray(); } Point3D[] allPoints = neurons.Select(o => o.Position).ToArray(); #region Find closest points // Get a unique list of points Dictionary<Point3D, ClosestExistingResult[]> resultsByPoint = new Dictionary<Point3D, ClosestExistingResult[]>(); // can't use SortedList, because point isn't sortable (probably doesn't have IComparable) foreach (var exist in existingPruned) { if (!resultsByPoint.ContainsKey(exist.From)) { resultsByPoint.Add(exist.From, GetClosestExisting(exist.From, allPoints, maxIntermediateLinks)); } if (!resultsByPoint.ContainsKey(exist.To)) { resultsByPoint.Add(exist.To, GetClosestExisting(exist.To, allPoints, maxIntermediateLinks)); } } #endregion List<LinkIndexed> retVal = new List<LinkIndexed>(); #region Build links foreach (var exist in existingPruned) { HighestPercentResult[] links = GetHighestPercent(resultsByPoint[exist.From], resultsByPoint[exist.To], maxFinalLinks, true); foreach (HighestPercentResult link in links) { double[] brainChemicals = null; if (exist.BrainChemicalModifiers != null) { brainChemicals = exist.BrainChemicalModifiers. Take(maxBrainChemicals). // if there are more, just drop them Select(o => o). //Select(o => o * link.Percent). // I decided not to multiply by percent. The weight is already reduced, no point in double reducing ToArray(); } retVal.Add(new LinkIndexed(link.From.Index, link.To.Index, exist.Weight * link.Percent, brainChemicals)); } } #endregion // Exit Function if (retVal.Count > count) { #region Prune // Prune the weakest links // Need to redistribute the lost weight (since this method divided links into smaller ones). If I don't, then over many generations, // the links will tend toward zero retVal = retVal.OrderByDescending(o => Math.Abs(o.Weight)).ToList(); LinkIndexed[] kept = retVal.Take(count).ToArray(); LinkIndexed[] removed = retVal.Skip(count).ToArray(); double keptSum = kept.Sum(o => Math.Abs(o.Weight)); double removedSum = removed.Sum(o => Math.Abs(o.Weight)); double ratio = keptSum / (keptSum + removedSum); ratio = 1d / ratio; return kept.Select(o => new LinkIndexed(o.From, o.To, o.Weight * ratio, o.BrainChemicalModifiers)).ToArray(); #endregion } else { return retVal.ToArray(); } }
public ContainerInput(long token, INeuronContainer container, NeuronContainerType containerType, Point3D position, Quaternion orientation, double? internalRatio, Tuple<NeuronContainerType, ExternalLinkRatioCalcType, double>[] externalRatios, int brainChemicalCount, NeuralLinkDNA[] internalLinks, NeuralLinkExternalDNA[] externalLinks) { this.Token = token; this.Container = container; this.ContainerType = containerType; this.Position = position; this.Orientation = orientation; this.InternalRatio = internalRatio; this.ExternalRatios = externalRatios; this.BrainChemicalCount = brainChemicalCount; this.InternalLinks = internalLinks; this.ExternalLinks = externalLinks; }