private static DiscreteDistribution Bivariate(BivariateContinuousDistribution distribution, DistributionsOperation operation) { if (operation == DistributionsOperation.PowerInv) { distribution = distribution.Rotate(); } int samples = distribution.Samples; double[] range = CommonRandomMath.GetRange(distribution.SupportMinLeft, distribution.SupportMaxLeft, distribution.SupportMinRight, distribution.SupportMaxRight, operation); double[] rightAxis = CommonRandomMath.GenerateXAxis(distribution.SupportMinRight, distribution.SupportMaxRight, samples, out double rightStep); double[] xAxis = CommonRandomMath.GenerateXAxis(range[0], range[1], samples, out double step); double[] result = new double[samples]; switch (operation) { case DistributionsOperation.Add: { Parallel.For(0, xAxis.Length, i => { double x = xAxis[i]; double sum = 0; // Trap rule is useless because both normal and t-distributions are smoooth. for (int j = 1; j < samples; j++) { double m = rightAxis[j]; sum += distribution.ProbabilityDensityFunction(x - m, m); } result[i] = sum * rightStep; }); break; } case DistributionsOperation.Sub: { Parallel.For(0, xAxis.Length, i => { double x = xAxis[i]; double sum = 0; for (int j = 1; j < samples; j++) { double m = rightAxis[j]; sum += distribution.ProbabilityDensityFunction(x + m, m); } result[i] = sum * rightStep; }); break; } case DistributionsOperation.Muliply: { Parallel.For(0, xAxis.Length, i => { double x = xAxis[i]; double sum = 0; for (int j = 1; j < samples; j++) { double m = rightAxis[j]; if (m != 0) { sum += distribution.ProbabilityDensityFunction(x / m, m) / Math.Abs(m); } } result[i] = sum * rightStep; }); break; } case DistributionsOperation.Divide: { Parallel.For(0, xAxis.Length, i => { double x = xAxis[i]; double sum = 0; for (int j = 1; j < samples; j++) { double m = rightAxis[j]; if (m != 0) { sum += distribution.ProbabilityDensityFunction(x * m, m) * Math.Abs(m); } } result[i] = sum * rightStep; }); break; } case DistributionsOperation.PowerInv: { Parallel.For(0, xAxis.Length, i => { double m = 0; double sum = 0; double x = xAxis[i]; double d = 0; double k = 0; for (int j = 1; j < samples; j++) { m = rightAxis[j]; d = Math.Log(x, m); k = Math.Abs(Math.Log(m) * x); sum += distribution.ProbabilityDensityFunction(d, m) / k; } result[i] = sum * rightStep; }); break; } case DistributionsOperation.Log: { Parallel.For(0, xAxis.Length, i => { double m = 0; double sum = 0; double x = xAxis[i]; double d = 0; double k = 0; for (int j = 1; j < samples; j++) { m = rightAxis[j]; d = Math.Pow(m, x); k = Math.Abs(Math.Log(m) * d); sum += distribution.ProbabilityDensityFunction(d, m) * k; } result[i] = sum * rightStep; }); break; } default: { throw new DistributionsInvalidOperationException(); } } return(new DiscreteDistribution(xAxis, result)); }
private static DiscreteDistribution TwoDiscreteDistributions(DiscreteDistribution dpdfLeft, DiscreteDistribution dpdfRight, DistributionsOperation action) { var exchange = Swap(dpdfLeft, dpdfRight, action, out DistributionsOperation newAction); action = newAction; dpdfLeft = exchange[0]; dpdfRight = exchange[1]; int lengthLeft = dpdfLeft.InnerSamples; int lengthRight = dpdfRight.InnerSamples; double stepRight = dpdfRight.Step; double stepLeft = dpdfLeft.Step; double leftMinX = dpdfLeft.MinX; double leftMaxX = dpdfLeft.MaxX; double[] leftX = dpdfLeft.XCoordinatesInternal; double[] leftY = dpdfLeft.YCoordinatesInternal; double[] rightX = dpdfRight.XCoordinatesInternal; double[] rightY = dpdfRight.YCoordinatesInternal; double[] yCoordinates = new double[lengthRight]; double[] range = CommonRandomMath.GetRange(dpdfLeft.InnerMinX, dpdfLeft.InnerMaxX, dpdfRight.InnerMinX, dpdfRight.InnerMaxX, action); double[] xCoordinates = CommonRandomMath.GenerateXAxis(range[0], range[1], lengthRight, out double stepX0); switch (action) { case DistributionsOperation.Add: { List <int> operations = new List <int>(); Parallel.For(0, lengthRight, i => { double m = 0; double x = xCoordinates[i]; double sum = 0; double y = 0; double r = 0; for (int j = 0; j < lengthRight; j++) { m = rightX[j]; y = rightY[j]; r = y * GetYByX(x - m, leftY, leftMinX, leftMaxX, stepLeft, lengthLeft); if (j == 0 || j == lengthRight - 1) { r /= 2; } sum += r; } yCoordinates[i] = sum * stepRight; }); break; } case DistributionsOperation.Sub: { Parallel.For(0, lengthRight, i => { double m = 0; double x = xCoordinates[i]; double sum = 0; double r = 0; double y = 0; for (int j = 0; j < lengthRight; j++) { m = rightX[j]; y = rightY[j]; r = y * GetYByX(x + m, leftY, leftMinX, leftMaxX, stepLeft, lengthLeft); if (j == 0 || j == lengthRight - 1) { r /= 2; } sum += r; } yCoordinates[i] = sum * stepRight; }); break; } case DistributionsOperation.Muliply: { Parallel.For(0, lengthRight, i => { double m = 0; double sum = 0; double x = xCoordinates[i]; double k = 0; double r = 0; double y = 0; for (int j = 0; j < lengthRight; j++) { m = rightX[j]; y = rightY[j]; k = Math.Abs(m); if (k != 0) { r = y * GetYByX(x / m, leftY, leftMinX, leftMaxX, stepLeft, lengthLeft) / k; if (j == 0 || j == lengthRight - 1) { r /= 2; } sum += r; } } yCoordinates[i] = sum * stepRight; }); // in case when both of distributions cross Oy it is inf in zero if (dpdfLeft.MinX <= 0 && dpdfLeft.MaxX >= 0 && dpdfRight.MinX <= 0 && dpdfRight.MaxX >= 0) { for (int i = 0; i < lengthRight - 1; i++) { if (xCoordinates[i] <= 0 && xCoordinates[i + 1] > 0) { yCoordinates[i] = double.PositiveInfinity; break; } } } break; } case DistributionsOperation.Divide: { Parallel.For(0, lengthRight, i => { double m = 0; double sum = 0; double x = xCoordinates[i]; double k = 0; double r = 0; double y = 0; for (int j = 0; j < lengthRight; j++) { m = rightX[j]; y = rightY[j]; k = Math.Abs(m); if (k != 0) { r = y * GetYByX(x * m, leftY, leftMinX, leftMaxX, stepLeft, lengthLeft) * k; if (j == 0 || j == lengthRight - 1) { r /= 2; } sum += r; } } yCoordinates[i] = sum * stepRight; }); break; } case DistributionsOperation.PowerInv: { Parallel.For(0, lengthRight, i => { double m = 0; double sum = 0; double x = xCoordinates[i]; double k = 0; double r = 0; double y = 0; for (int j = 0; j < lengthRight; j++) { m = rightX[j]; y = rightY[j]; k = Math.Abs(Math.Log(m) * x); if (k != 0) { r = y * GetYByX(Math.Log(x, m), leftY, leftMinX, leftMaxX, stepLeft, lengthLeft) / k; if (j == 0 || j == lengthRight - 1) { r /= 2; } sum += r; } } yCoordinates[i] = sum * stepRight; }); break; } case DistributionsOperation.Log: { Parallel.For(0, lengthRight, i => { double m = 0; double sum = 0; double x = xCoordinates[i]; double d = 0; double k = 0; double r = 0; double y = 0; for (int j = 0; j < lengthRight; j++) { m = rightX[j]; y = rightY[j]; d = Math.Pow(m, x); k = Math.Abs(Math.Log(m) * d); if (k != 0) { r = y * GetYByX(d, leftY, leftMinX, leftMaxX, stepLeft, lengthLeft) * k; if (j == 0 || j == lengthRight - 1) { r /= 2; } sum += r; } } yCoordinates[i] = sum * stepRight; }); break; } default: { throw new NotImplementedException(); } } var result = new DiscreteDistribution(xCoordinates, yCoordinates); return(result); }