public static DiscreteDistribution Divide(DiscreteDistribution dpdfX, DiscreteDistribution dpdfY)
 {
     return(TwoDiscreteDistributions(dpdfX, dpdfY, DistributionsOperation.Divide));
 }
        private static DiscreteDistribution DiscreteDistributionAndValue(DiscreteDistribution dpdf, double value, DistributionsOperation action)
        {
            int length = dpdf.InnerSamples;

            double[] leftX = dpdf.XCoordinatesInternal;
            double[] leftY = dpdf.YCoordinatesInternal;

            double[] yCoordinates = new double[length];
            double[] xCoordinates = new double[length];

            switch (action)
            {
            case DistributionsOperation.Add:
            {
                for (int i = 0; i < length; i++)
                {
                    yCoordinates[i] = leftY[i];
                    xCoordinates[i] = leftX[i] + value;
                }
                break;
            }

            case DistributionsOperation.Sub:
            {
                for (int i = 0; i < length; i++)
                {
                    yCoordinates[i] = leftY[i];
                    xCoordinates[i] = leftX[i] - value;
                }
                break;
            }

            case DistributionsOperation.SubInv:
            {
                for (int i = 0; i < length; i++)
                {
                    yCoordinates[length - i - 1] = leftY[i];
                    xCoordinates[length - i - 1] = value - leftX[i];
                }
                break;
            }

            case DistributionsOperation.Muliply:
            {
                if (value == 0)
                {
                    throw new DistributionsInvalidOperationException(DistributionsInvalidOperationExceptionType.MultiplyRandomByZero);
                }

                if (value < 0)
                {
                    for (int i = 0; i < length; i++)
                    {
                        yCoordinates[length - i - 1] = leftY[i] / Math.Abs(value);
                        xCoordinates[length - i - 1] = leftX[i] * value;
                    }
                }
                else
                {
                    for (int i = 0; i < length; i++)
                    {
                        yCoordinates[i] = leftY[i] / Math.Abs(value);
                        xCoordinates[i] = leftX[i] * value;
                    }
                }
                break;
            }

            case DistributionsOperation.Divide:
            {
                if (value == 0)
                {
                    throw new DistributionsInvalidOperationException(DistributionsInvalidOperationExceptionType.DivisionByZero);
                }

                if (value < 0)
                {
                    for (int i = 0; i < length; i++)
                    {
                        yCoordinates[length - i - 1] = leftY[i] * Math.Abs(value);
                        xCoordinates[length - i - 1] = leftX[i] / value;
                    }
                }
                else
                {
                    for (int i = 0; i < length; i++)
                    {
                        yCoordinates[i] = leftY[i] * Math.Abs(value);
                        xCoordinates[i] = leftX[i] / value;
                    }
                }
                break;
            }

            default:
            {
                throw new NotImplementedException();
            }
            }

            return(new DiscreteDistribution(xCoordinates, yCoordinates));
        }
 public static DiscreteDistribution Sub(DiscreteDistribution dpdfLeft, DiscreteDistribution dpdfRight)
 {
     return(TwoDiscreteDistributions(dpdfLeft, dpdfRight, DistributionsOperation.Sub));
 }
 public static DiscreteDistribution Multiply(DiscreteDistribution dpdfX, DiscreteDistribution dpdfY)
 {
     return(TwoDiscreteDistributions(dpdfX, dpdfY, DistributionsOperation.Muliply));
 }
 public static DiscreteDistribution Negate(DiscreteDistribution value)
 {
     return(Multiply(value, -1));
 }
 public static DiscreteDistribution Power(DiscreteDistribution dpdfLeft, DiscreteDistribution dpdfRight)
 {
     return(TwoDiscreteDistributions(dpdfRight, dpdfLeft, DistributionsOperation.PowerInv));
 }
        private static DiscreteDistribution[] Swap(DiscreteDistribution dpdfLeft, DiscreteDistribution dpdfRight, DistributionsOperation action, out DistributionsOperation newAction)
        {
            double stepX = dpdfLeft.Step;
            double stepY = dpdfRight.Step;

            switch (action)
            {
            case DistributionsOperation.Add:
            {
                newAction = action;

                if (stepX < stepY)
                {
                    return(new DiscreteDistribution[] { dpdfRight, dpdfLeft });
                }
                else
                {
                    return(new DiscreteDistribution[] { dpdfLeft, dpdfRight });
                }
            }

            case DistributionsOperation.Sub:
            {
                if (stepX < stepY)
                {
                    newAction = DistributionsOperation.Add;
                    return(new DiscreteDistribution[] { Multiply(dpdfRight, -1), dpdfLeft });
                }
                else
                {
                    newAction = action;
                    return(new DiscreteDistribution[] { dpdfLeft, dpdfRight });
                }
            }

            case DistributionsOperation.Muliply:
            {
                newAction = action;

                // When one of distributions crossing Oy we need to exact locate them to eliminate 1/0 error on numerical integration
                if (dpdfRight.MinX <= 0 && dpdfRight.MaxX >= 0 && !(dpdfLeft.MinX <= 0 && dpdfLeft.MaxX >= 0))
                {
                    return(new DiscreteDistribution[] { dpdfRight, dpdfLeft });
                }
                else if (dpdfLeft.MinX <= 0 && dpdfLeft.MaxX >= 0 && !(dpdfRight.MinX <= 0 && dpdfRight.MaxX >= 0))
                {
                    return(new DiscreteDistribution[] { dpdfLeft, dpdfRight });
                }
                else
                {
                    if (stepX < stepY)
                    {
                        return(new DiscreteDistribution[] { dpdfRight, dpdfLeft });
                    }
                    else
                    {
                        return(new DiscreteDistribution[] { dpdfLeft, dpdfRight });
                    }
                }
            }

            default:
            {
                newAction = action;
                return(new DiscreteDistribution[] { dpdfLeft, dpdfRight });
            }
            }
        }
 public static DiscreteDistribution Log(DiscreteDistribution dpdf, DiscreteDistribution nBase)
 {
     return(TwoDiscreteDistributions(dpdf, nBase, DistributionsOperation.Log));
 }
 public static DiscreteDistribution Divide(DiscreteDistribution dpdf, double value)
 {
     return(DiscreteDistributionAndValue(dpdf, value, DistributionsOperation.Divide));
 }
 public static DiscreteDistribution Multiply(DiscreteDistribution dpdf, double value)
 {
     return(DiscreteDistributionAndValue(dpdf, value, DistributionsOperation.Muliply));
 }
 public static DiscreteDistribution Sub(double value, DiscreteDistribution dpdf)
 {
     return(DiscreteDistributionAndValue(dpdf, value, DistributionsOperation.SubInv));
 }
 public static DiscreteDistribution Add(DiscreteDistribution dpdf, double value)
 {
     return(DiscreteDistributionAndValue(dpdf, value, DistributionsOperation.Add));
 }
        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);
        }