private static Tuple<int, int>[] Link12_Extra(Tuple<int, int>[] initial, LinkItem[] items1, LinkItem[] items2, DistributeDistances distances, ItemLinker_ExtraArgs extraArgs) { Random rand = StaticRandom.GetRandomForThread(); int wholePercent = extraArgs.Percent.ToInt_Floor(); List<int> addOrder = new List<int>(); if (extraArgs.BySize) { double totalSize = items2.Sum(o => o.Size); double maxSize = extraArgs.Percent * totalSize; double usedSize = 0; if (extraArgs.EvenlyDistribute) { #region by size, evenly distribute // Add some complete passes if over 100% percent for (int cntr = 0; cntr < wholePercent; cntr++) { addOrder.AddRange(UtilityCore.RandomRange(0, items2.Length)); } usedSize = wholePercent * totalSize; #endregion } #region by size, distribute the rest //NOTE: Building this list by size so that larger items have a higher chance of being chosen var bySize = items2. Select((o, i) => Tuple.Create(i, o.Size / totalSize)). OrderByDescending(o => o.Item2). ToArray(); // Keep selecting items unti the extra size is consumed (or if no more can be added) while (true) { bool foundOne = false; for (int cntr = 0; cntr < 1000; cntr++) // this is an infinite loop detector { int attemptIndex = UtilityCore.GetIndexIntoList(rand.NextDouble(), bySize); // get the index into the list that the rand percent represents attemptIndex = bySize[attemptIndex].Item1; // get the index into items2 if (items2[attemptIndex].Size + usedSize <= maxSize) { foundOne = true; usedSize += items2[attemptIndex].Size; addOrder.Add(attemptIndex); break; } } if (!foundOne) { // No more will fit break; } } #endregion } else { if (extraArgs.EvenlyDistribute) { #region ignore size, evenly distribute // Add some complete passes if over 100% percent for (int cntr = 0; cntr < wholePercent; cntr++) { addOrder.AddRange(UtilityCore.RandomRange(0, items2.Length)); } // Add some items based on the portion of percent that is less than 100% int remainder = (items2.Length * (extraArgs.Percent - wholePercent)). ToInt_Round(); addOrder.AddRange(UtilityCore.RandomRange(0, items2.Length, remainder)); #endregion } else { #region ignore size, randomly distribute int totalCount = (items2.Length * extraArgs.Percent). ToInt_Round(); //NOTE: UtilityCore.RandomRange stops when the list is exhausted, and makes sure not to have dupes. That's not what is wanted //here. Just randomly pick X times addOrder.AddRange(Enumerable.Range(0, totalCount).Select(o => rand.Next(items2.Length))); #endregion } } return AddLinks(items1, items2, distances, addOrder, initial); }
/// <summary> /// This adds 2s to 1s one at a time (specified by distances2to1_AddOrder) /// </summary> private static Tuple<int, int>[] AddLinks(LinkItem[] items1, LinkItem[] items2, DistributeDistances distances, IEnumerable<int> distances2to1_AddOrder, Tuple<int, int>[] initial = null) { // Store the inital link burdens BrainBurden[] links = Enumerable.Range(0, items1.Length). Select(o => new BrainBurden(o, items1, items2)). ToArray(); if (initial != null) { #region Store initial foreach (var set in initial.ToLookup(o => o.Item1)) { foreach (int item2Index in set.Select(o => o.Item2)) { links[set.Key].AddIOLink(item2Index); } } #endregion } foreach (var distanceIO in distances2to1_AddOrder.Select(o => distances.Distances2to1[o])) { int ioIndex = distanceIO.Index2; int closestBrainIndex = distanceIO.DistancesTo1[0].Item1; AddIOLink(links, ioIndex, items2[ioIndex].Size, closestBrainIndex, distances.ResistancesItem1[closestBrainIndex]); } // Build the return List<Tuple<int, int>> retVal = new List<Tuple<int, int>>(); foreach (BrainBurden burden in links) { retVal.AddRange(burden.IOLinks.Select(o => Tuple.Create(burden.Index, o))); } return retVal.ToArray(); }
private static Tuple<int, int>[] Link12_Distribute(LinkItem[] items1, LinkItem[] items2, DistributeDistances distances) { IEnumerable<int> addOrder = Enumerable.Range(0, distances.Distances2to1.Length); return AddLinks(items1, items2, distances, addOrder); }