/// <summary>Creates an instance and performs partition</summary> /// <param name="nmbs">identified values to be distributed</param> /// <param name="result">final result</param> /// <param name="avr">average value sum</param> /// <param name="limMult"> /// DSTree method call's limit multiplier; /// if 0 then omit DSTree method invoking /// </param> public Partition(IdNumbers nmbs, Result result, float avr, byte limMult) { numbs = nmbs; finalResult = result; avrSum = avr; isAvrFract = (int)avrSum != avrSum; callLimit = minCallLimit * limMult; sumDiff = largestSum; ushort ssCnt = finalResult.SubsetCount; int i = 0; methods[i++] = UGreedy; methods[i++] = WrapGreedy; methods[i++] = SGreedy; methods[i++] = ISTree; numbs.SortByDescent(); int cnt = limMult > 0 ? 4 : 3; // for the degenerate case numbs.Count<=ssCnt method UGreedy() is comepletely enough if (numbs.Count <= ssCnt) { cnt = 1; } for (i = 0; i < cnt; i++) { if (DoPartition(i, ssCnt)) { return; } } }
/// <summary>Copies bin's indexes</summary> internal void CopyIndexes(IdNumbers numbers) { for (int i = 0; i < Count; i++) { this[i].BinIInd = numbers[i].BinIInd; } }
internal IdNumbers(IdNumbers numbers) { Capacity = numbers.Capacity; foreach (IdNumber n in numbers) { Add(new IdNumber(n)); } }
/// <summary>Initializes partition by identified numbers.</summary> /// <param name="numbs">identified numbers to be distributed</param> /// <param name="ssCnt">count of subsets</param> /// <param name="limMult"> /// DSTree method call's limit multiplier; /// if 0 then omit DSTree method invoking (fast, but not 'perfect) /// </param> private void Init(IdNumbers numbs, ushort ssCnt, byte limMult) { result = new Result(numbs.Count, ssCnt); if (ssCnt == 0) { return; } Partition Partition = new(numbs, result, avr = numbs.AvrSum(ssCnt), limMult); }
/// <summary>Outfits this result</summary> /// <param name="numbs">numbers to be distributed</param> /// <param name="ind">index of the first subset: 1 for SGreedy() or 0 for DSTree()</param> /// <param name="diff">difference between the subset sums</param> internal void Fill(IdNumbers numbs, byte ind, ulong diff) { ushort ssCnt = (ushort)(SubsetCount - ind); // count of subsets minus first index Clear(); foreach (IdNumber n in numbs) { Bins[ssCnt - n.BinIInd].AddNumb(n); } SumDiff = diff; }
/// <summary>Performs iterative 'Dynamic Search Tree' partition.</summary> /// <param name="ssCnt">count of subsets</param> private void ISTree(ushort ssCnt) { // initial range expansion around average uint up = avrSum < numbs[0].Val ? numbs[0].Val - Convert.ToUInt32(avrSum) + 2 : 1; if (up > avrSum) { up = Convert.ToUInt32(avrSum) - 1; } standbySumDiff = largestSum; // undefined standby inaccuracy lastSumDiff = finalResult.SumDiff; standbyNumbs = new IdNumbers(numbs); do { minSum = (ulong)(avrSum - up); maxSum = (ulong)(avrSum + up); sumDiff = maxSum - minSum; callCnt = complete = 0; numbs.Reset(); currResult.Clear(); DSTree(0, (ushort)(ssCnt - 1)); if (IsCompleteByPerfect || (up *= 2) >= minSum) // increase and checkup range expansion { break; } if (currResult.SumDiff > standbySumDiff) // is current result worse than standby one? { break; } } while (lastSumDiff != currResult.SumDiff); // until previous and current inaccuracy are different // use last fitted result { SetRange(finalResult); finalResult.Fill(standbyNumbs, 1, standbySumDiff); } }
/// <summary> /// Constructs numbers partition by identified numbers, /// with sums sorted in descending order. /// </summary> /// <param name="numbs">identified numbers to be distributed</param> /// <param name="ssCnt"> /// count of subsets; /// if 0 then creates an empty partition with undefined (maximum type's value) inaccuracy /// </param> /// <param name="limMult"> /// DSTree method call's limit multiplier - /// it increases the limit of 1 million recursive invokes by limMult times; /// if 0 then omit DSTree method invoking (fast, but not 'perfect') /// </param> public effPartition(IdNumbers numbs, ushort ssCnt, byte limMult = 1) { Init(numbs, ssCnt, limMult); }