public BulkLoader() { var itemValidator = new ItemValidator(); var itemLinker = new ItemLinker(); OnItemProcessing = new Chain <IItemProcessor> { new ItemBucketer(), new ItemVersionEnsurer(), itemValidator, new ItemLinker() }; OnStagedDataValidating = new Chain <IValidateStagedData> { itemValidator, new ValidateNoDuplicates() }; OnTempDataValidating = new Chain <IValidateStagedData> { new ValidateDataIntegrity() }; OnTransactionCommitting = new Chain <ISyncInTransaction> { new SyncHistoryTable(), new SyncPublishQueue() }; OnItemsLoading = new Chain <IChangeProcessor> { new ChangeCacheClearer() }; OnItemsLoaded = new Chain <IChangeProcessor> { new ChangeLogger(), itemLinker, new ChangeIndexer() }; }
private static NeuronMapping[] MapNeurons(Point3D[] externalPoints, Point3D[] internalPoints) { // FuzzyLink wasn't designed for from and to points to be sitting on top of each other, so need to pull them apart // // external is pulled to -Z, internal is +Z. These offset coordinates don't have any meaning outside this function, they are just // a hack to allow FuzzyLink to work properly // Figure out how far to separate them to ensure they are fully separated var aabb = Math3D.GetAABB(externalPoints.Concat(internalPoints)); double offsetDist = Math1D.Max(aabb.Item2.X - aabb.Item1.X, aabb.Item2.Y - aabb.Item1.Y, aabb.Item2.Z - aabb.Item1.Z); offsetDist *= 3; Vector3D offset = new Vector3D(0, 0, offsetDist); // Create seed links. The easiest approach is just to create one per internal point and then let the fuzzy linker find the best // external point // // I could see the argument for remembering the links across generations so that if the external points drift around too much, // the original linking will better persist. But if the bot is mutating that much over generations, the neat NN should be retrained // from time to time. Also, if a mismapping causes the bot to perform bad, then it won't be making children (and a mismapping // might end up causing better performance) Tuple <Point3D, Point3D, double>[] initialLinks = internalPoints. Select(o => Tuple.Create(o - offset, o + offset, 1d)). ToArray(); Point3D[] pointsForFuzzy = externalPoints.Select(o => o - offset). Concat(internalPoints.Select(o => o + offset)). ToArray(); // Allow a few more links than points. If the external and internal points are aligned well, then the extra link allowance won't // be used int numLinks = (internalPoints.Length * 1.1).ToInt_Ceiling(); var finalLinks = ItemLinker.FuzzyLink(initialLinks, pointsForFuzzy, numLinks, 6); const double THICKNESS = .005; const double DOT = THICKNESS * 3; Debug3DWindow window = new Debug3DWindow(); window.AddDots(externalPoints, DOT, Colors.IndianRed); window.AddDots(internalPoints, DOT, Colors.DodgerBlue); window.AddDots(pointsForFuzzy, DOT, Colors.Silver); window.AddLines(initialLinks.Select(o => (o.Item1, o.Item2)), THICKNESS, Colors.Orchid); List <NeuronMapping> retVal = new List <NeuronMapping>(); foreach (var link in finalLinks) { int?externalIndex = null; int?internalIndex = null; foreach (int index in new[] { link.Item1, link.Item2 }) { if (index < externalPoints.Length) { externalIndex = index; } else { internalIndex = index - externalPoints.Length; } } if (externalIndex == null || internalIndex == null) { // This should never happen in practice, the internal and external sets are pulled too far apart to accidentally be linked together. // Just ignore this link continue; } retVal.Add(new NeuronMapping() { Index_External = externalIndex.Value, Index_NEAT = internalIndex.Value, Weight = link.Item3, }); } foreach (var link in finalLinks) { window.AddLine(pointsForFuzzy[link.Item1], pointsForFuzzy[link.Item2], THICKNESS * link.Item3, Colors.GhostWhite); } foreach (var link in retVal) { window.AddLine(externalPoints[link.Index_External], internalPoints[link.Index_NEAT], THICKNESS * link.Weight, Colors.Coral); } window.Show(); return(retVal.ToArray()); }