public static double[] Partitioning(this PartitioningMethod method, int partitionCount = DefaultPartitionCount,
double totalAmount = DefaultPartitionAmount) {
partitionCount.ShouldBePositive("partitionCouunt");
totalAmount.ShouldBePositive("totalAmount");
if(IsDebugEnabled)
log.Debug("총액을 분배합니다. PartitioningMethod=[{0}], partitionCount=[{1}], totalAmount=[{2}]", method, partitionCount,
totalAmount);
if(partitionCount == DefaultPartitionCount && Math.Abs(totalAmount - DefaultPartitionAmount) < double.Epsilon)
return DefaultPartitioningArray[method];
Guard.Assert(() => partitionCount % 2 == 0, "PartitionCount는 짝수여야 합니다. PartitionCount=[{0}]", partitionCount);
double[] result;
double a, b;
var half = partitionCount / 2;
var uniformParition = totalAmount / partitionCount;
switch(method) {
case PartitioningMethod.HorizontaolUniform:
result = Generate(partitionCount, x => uniformParition).ToArray<double>();
break;
case PartitioningMethod.VerticalBegin:
result = new double[partitionCount];
result[0] = totalAmount;
break;
case PartitioningMethod.VerticalEnd:
result = new double[partitionCount];
result[partitionCount - 1] = totalAmount;
break;
case PartitioningMethod.TriangleBegin:
a = -16.0 / 9.0;
b = 18.0 * totalAmount / DefaultPartitionAmount;
result = Generate<double>(partitionCount, x => a * x + b).Select(y => Math.Round(y, 0)).ToArray<double>();
break;
case PartitioningMethod.TriangleMiddle:
result = new double[partitionCount];
b = 2.0 * totalAmount / DefaultPartitionAmount;
var triangleMiddle = Generate<double>(half, x => 4 * x + b).Select(y => Math.Round(y, 0)).ToArray<double>();
Array.Copy(triangleMiddle, result, half);
Array.Copy(triangleMiddle.Reverse().ToArray<double>(), 0, result, half, half);
break;
case PartitioningMethod.TriangleEnd:
a = 16.0 / 9.0;
b = 2.0 * totalAmount / DefaultPartitionAmount;
result = Generate<double>(partitionCount, x => a * x + b).Select(y => Math.Round(y, 0)).ToArray<double>();
break;
case PartitioningMethod.TwoStepBegin:
Func<int, double> @twostepBegin = x => (x < half) ? 1.3 * uniformParition : 0.7 * uniformParition;
result = Generate<double>(partitionCount, x => @twostepBegin(x)).Select(y => Math.Round(y, 0)).ToArray<double>();
break;
case PartitioningMethod.TwoStepEnd:
Func<int, double> @twostepEnd = x => (x < half) ? 0.7 * uniformParition : 1.3 * uniformParition;
result = Generate<double>(partitionCount, x => @twostepEnd(x)).Select(y => Math.Round(y, 0)).ToArray<double>();
break;
case PartitioningMethod.TrapezoidMiddle:
result = new double[partitionCount];
b = 2.0 * totalAmount / DefaultPartitionAmount;
var trapezoid = Generate<double>(half - 1, x => 13.0 / 3.0 * x + b).Select(y => Math.Round(y, 0)).ToArray<double>();
Array.Copy(trapezoid, result, half - 1);
Array.Copy(trapezoid.Reverse().ToArray(), 0, result, half + 1, half - 1);
result[half] = result[half - 1];
break;
case PartitioningMethod.Normal:
result =
Generate<double>(partitionCount, x => totalAmount * NormalDistribution(4.0, half, x + 1)).Select(
y => Math.Round(y, 0)).ToArray<double>();
break;
case PartitioningMethod.ThreeMiddle:
var countByThree = 0.3 * partitionCount;
var countBySeven = 0.7 * partitionCount;
Func<int, double> @treeMiddle =
x => (x <= countByThree || x >= countBySeven) ? 0.8 * uniformParition : 1.3 * uniformParition;
result = Generate<double>(partitionCount, x => @treeMiddle(x)).Select(y => Math.Round(y, 0)).ToArray<double>();
break;
default:
throw new NotSupportedException(string.Format("지원하지 않는 분할 방식입니다. method=[{0}]", method));
}
return result;
}