Exemplo n.º 1
0
        public double Bidon()
        {
            ReferencePoints rp         = new ReferencePoints(this.Ob01, this.A, this.Start.Copy(), this.Range, this.InestimableLowerLimit, epsilon: this.Precision);
            LModeExt        refPtsMode = rp.GetPoints();
            bool            cntn       = false;
            double          uMode;
            double          x;
            double          target;
            double          areaMode;
            bool            distrnLeftSide = false;
            double          mathLowerLimit = this.Ob01.MathLowerLimit;
            bool            converged      = false;
            double          areaX;
            double          precision = this.Precision;
            Func <double, SGNFnAParam, double> area;

            if (refPtsMode.Found)
            {
                // A$f < -o$f
                this.A.F          = this.Ob01.F;
                this.A.LowerLimit = refPtsMode.Remote[0];
                this.A.M          = refPtsMode.H; // # (kind of a) standardizing constant
                area = this.A.AreaFnFromALLimToX;
                double areaTot = WebExpoFunctions3.SmoothedAreaEstimate(
                    area,
                    refPtsMode.Remote[1],
                    this.A,
                    mathLowerLimit,
                    refPtsMode.Remote,
                    this.InestimableLowerLimit,
                    remoteRight: true);

                target    = this.U * areaTot;
                precision = this.Precision * areaTot;
                x         = refPtsMode.X;
                areaX     = 0;
                areaMode  = WebExpoFunctions3.SmoothedAreaEstimate(area, x, this.A, mathLowerLimit, refPtsMode.Remote, this.InestimableLowerLimit);
                uMode     = areaMode / areaTot;
                converged = Math.Abs(areaMode - target) < precision;
                cntn      = !converged;
            }
            else
            {
                throw new WEException("Mode not found");
            }

            if (cntn)
            {
                distrnLeftSide = this.U < uMode;
                if (distrnLeftSide)
                {
                    area = this.A.AreaFn_FromXToAULim;
                    this.A.UpperLimit = refPtsMode.X;
                    this.Range        = Tools.Combine(refPtsMode.Remote[0], refPtsMode.X);
                }
                else
                {
                    this.A.LowerLimit = refPtsMode.X;
                    this.Range        = Tools.Combine(refPtsMode.X, refPtsMode.Remote[1]);
                }
            }

            //converged = true;
            if (cntn && this.Ob01.PotentiallyBimodal)
            {
                // Slower but safer algorithm for posterior distrns that are potentially bimodal
                double fMode = A.F(refPtsMode.X, A);
                double start = refPtsMode.X + (target - areaMode) / fMode;
                cntn      = false;
                converged = true; // voir l'impact !!!

                double highestPoint;
                double hMax;
                if (distrnLeftSide)
                {
                    highestPoint = refPtsMode.Remote[0];
                    hMax         = areaMode;
                    target       = (uMode - this.U) / uMode * hMax;
                }
                else
                {
                    highestPoint = refPtsMode.Remote[1];
                    hMax         = WebExpoFunctions3.SmoothedAreaEstimate(area, refPtsMode.Remote[1], this.A, mathLowerLimit, this.Range, this.InestimableLowerLimit, remoteRight: true);
                    target       = (this.U - uMode) / (1 - uMode) * hMax;
                }

                SecuredNRA      oCum = new SecuredNRA(area, this.Ob01.F);
                SecuredNRSearch nr   = new SecuredNRSearch(oCum, this.A, start, precision, this.Range,
                                                           maxPoint: new LMode(highestPoint, hMax), target: target, inestimableLowerLimit: this.InestimableLowerLimit);
                // le dernier paramètre a une valeur par défaut: expectedHpSign = -1
                if (nr.Converged)
                {
                    x = nr.X;
                }
                else
                {
                    //# it seems we were caught in an infinite loop, had we not limited the number of iterations;
                    //# see if we can rule that problem out
                    x = nr.Bounds.X[0];
                    double h = nr.Bounds.H[0];
                    x = ICDFFunctions.PingpongTieBreaker(area, this.A, x, h, target, mathLowerLimit, this.Range, this.InestimableLowerLimit, precision, distrnLeftSide);
                }
            }

            int direction = 0;
            int count     = 0;

            if (cntn)
            {
                direction = distrnLeftSide ? -1 : 1;
                if (distrnLeftSide)
                {
                    target = (uMode - this.U) / uMode * areaMode;
                }
                else
                {
                    double areaRemoteRight = WebExpoFunctions3.SmoothedAreaEstimate(
                        area,
                        refPtsMode.Remote[1],
                        this.A,
                        mathLowerLimit,
                        this.Range,
                        this.InestimableLowerLimit,
                        remoteRight: true);
                    target = (this.U - uMode) / (1 - uMode) * areaRemoteRight;
                }
            }

            while (cntn)
            {
                double hp     = this.Ob01.F(x, A);
                double change = (target - areaX) / hp * direction;
                x         = x + change;
                areaX     = area(x, A);
                count     = count + 1;
                converged = Math.Abs(areaX - target) < precision;
                cntn      = !converged && count <= this.NRMaxIter;
            }

            if (!converged)
            {
                if (x > refPtsMode.Remote[1] || x < refPtsMode.Remote[0])
                {
                    throw new WEException("Stepped out of bounds -- due to numerical imprecision?");
                }
                else
                {
                    //# it seems we were caught in an infinite loop, had we not limited the number of iterations;
                    //# see if we can rule that problem out
                    x = ICDFFunctions.PingpongTieBreaker(area, this.A, x, areaX, target, mathLowerLimit, this.Range, this.InestimableLowerLimit, precision, distrnLeftSide);
                }
            }
            return(x);
        }
Exemplo n.º 2
0
        } //# end of max.fastTrack

        internal LModeExt GetPoints()
        {
            //# Arguments:
            //# ----------------------------------------------
            //# o: same nature as o in dens.gen.icdf arguments
            //# start: EITHER a vector of length 2 [two potential starting points]
            //#        or a scalar
            //# f.ratio.remote: scalar
            //# epsilon: scalar
            //# range: vector of length 2
            //# --------------------------------------------------------------------------
            //# If range is finite and log.f not inestimable at lower end,
            //# then we first look for values at both ends before searching for a mode

            //mode = list(x = numeric(0), h = numeric(0), found = false) # modif_0.11
            LMode mode = new LMode();

            if ((this.Range[0].IsFinite() && this.Range[1].IsFinite() && !this.InestimableLowerLimit))
            {
                double[] logFPrime = new double[] { this.O.LogFPrime(this.Range[0], A), this.O.LogFPrime(this.Range[1], A) };
                //# If slope (f') is the same at both ends, then there is no mode between the 2 endpoints (assuming a unimodal distrn)
                //# and we then assume that the highest end value for log.f is hence the local mode
                double[] logFPrimeSign = new double[] { Math.Sign(logFPrime[0]), Math.Sign(logFPrime[1]) };
                if (logFPrime.Prod() > 0)
                {
                    double[] logF = new double[] { this.O.LogF(this.Range[0], A), this.O.LogF(this.Range[1], A) };
                    int      w    = (logF[0] >= logF[1]) ? 0 : 1;
                    mode = new LMode(w == 0 ? this.Range[0] : this.Range[1], logF[w], true);
                }
            } // if ((this.Range[0]

            SecuredNRSearch nr = null;
            double          startingPoint;

            if (!mode.Found)
            {
                //# Choose a starting point among suggested starting points, if more than one point was suggested
                if (this.Start.Length > 1)
                {
                    this.Start = Tools.Combine(this.Start, this.Start.Mean());
                    //# Add the middle point to the two potential starting points
                    double[] logF = new double[this.Start.Length];
                    for (int i = 0; i < this.Start.Length; i++)
                    {
                        logF[i] = this.O.LogF(this.Start[i], A);
                    }
                    //double[] logF = new double[] { this.O.LogF(this.Start[0], A), this.O.LogF(this.Start[1], A), this.O.LogF(this.Start.Mean(), A) };
                    //TODO peut planter
                    startingPoint = this.Start[logF.WhichMax()];
                } //if (this.Start.Length > 1)
                else
                {
                    startingPoint = this.Start[0];
                }
                //# Find mode by Newton-Raphson
                SecuredNRA oMode = new SecuredNRA(this.O.LogFPrime, this.O.LogFSecond, this.Range);
                nr = new SecuredNRSearch(oMode, A, startingPoint, this.Epsilon, this.Range);
                // 4 derniers paramètres prennent les valeurs par défaut:
                // maxPoint = null, target = 0, inestimableLowerLimit = false,  expectedHpSign = -1
                if (nr.Converged)
                {
                    double hs = this.O.LogFSecond(nr.X, A);
                    if (hs > 0)
                    {
                        //# we have found a mimimum point (between two local modes):
                        //# we redo the search on both sides of this dip
                        mode.X = HigherLocalMax(this.O, A, nr.X, this.Range, this.Epsilon);
                    } //if (hs > 0)
                    else
                    {
                        mode.X = nr.X;
                    } //if (hs > 0)

                    mode.Found = true;
                } //if (nr.Converged)
                else
                {
                    double[] xA           = nr.Bounds.X;
                    double[] hA           = nr.Bounds.H;
                    bool     hOnBothSides = hA.Aggregate(1, (x, y) => x * Math.Sign(y)) < 0;
                    double   diffX        = xA.Diff()[0];
                    if ((diffX < this.Epsilon) && hOnBothSides)
                    {
                        mode.X     = xA.Mean();
                        mode.Found = true;
                    } //if ((diffX < this.Epsilon) && hOnBothSides)
                    else
                    {
                        bool converged = false;
                        if ((nr.Bounds.X.Diff()[0] < this.Epsilon) && nr.Bounds.H.All(a => a < 0))
                        {
                            if (this.Range[0].IsFinite())
                            {
                                //# We try a little bit further to find the actual mode,
                                //# since it looks like we are almost there...
                                converged = true;
                                MaxFastTrackObject tmp = MaxFastTrack(this.O, A, this.Range[1], nr.Bounds.X[0], nr.Bounds.H[0]); //# yes: 4th argument is bounds$h (and not hp!)

                                if (tmp.Converged)
                                {
                                    mode.X     = tmp.X;
                                    mode.Found = true;
                                } //if (tmp.Converged)
                                else
                                {
                                    mode.X     = this.Range[1];
                                    mode.Found = !this.InestimableLowerLimit;
                                } //if (tmp.Converged)
                            }     //if (this.Range[0].IsFinite())
                            else
                            {
                                double x   = nr.Bounds.X[0];
                                double h   = nr.Bounds.H[0];
                                double tmp = Math.Abs(h / this.O.LogFSecond(x, this.A));
                                if (tmp < 1e-12)
                                {
                                    mode      = new LMode(x, h, true);
                                    converged = true;
                                } //if (tmp < 1e-12)
                            }     //if (this.Range[0].IsFinite())
                        }

                        if (!converged)
                        {
                            throw new WEException("Algorithm did not converge.");
                        } //if (!converged)
                    }     //if ((diffX < this.Epsilon) && hOnBothSides)
                }         //if (nr.Converged)

                if (mode.Found)
                {
                    mode.H = this.O.LogF(mode.X, this.A);
                }
            } //if (!mode.Found)

            double logFRatioRemote = Math.Log(this.FRatioRemote);// # new_0.11
            double target          = Tools.ND; // R n'a pas vraiment de notion de scope

            if (mode.Found)
            {
                target = mode.H + logFRatioRemote;
            }

            this.A.Mode = mode.X; //  # some 'remote.*' functions need that information
                                  //# modif_0.11
                                  //# Find remote points on both sides of mode
            double remoteLeft = 0, remoteRight = 0;

            bool[] modeOnBorder = new bool[2];
            double fs           = Tools.ND;

            if (mode.Found)
            {
                //TODO pourquoi la définition et l'affectation de target ne serait-elle pas ici?
                double[] x  = new double[] { Tools.NA, Tools.NA };
                double[] f  = new double[] { Tools.NA, Tools.NA };
                double[] fp = new double[] { Tools.NA, Tools.NA };
                fs = this.O.LogFSecond(mode.X, A);// # scalar
                double d = 10 / Math.Abs(fs);
                //# new_0.11
                double[] remoteStart = this.O.LogFInvRemote(target, this.A).ToArray();                 //  # vector
                                                                                                       // TODO start est un paramètre de la fonction en R, vérifier l'impact de modifier la référence d'objet ici.
                this.Start = SplitStartingValuesLeftRight(this.O, target, A, this.Range, remoteStart); // # vector of length 2

                modeOnBorder = new bool[2] {
                    this.Range[0] == mode.X, this.Range[1] == mode.X
                };                                                                               //# new_0.11
                List <int> jSeq = new List <int>();
                for (int i = 0; i < 2; i++)
                {
                    if (!modeOnBorder[i] && this.Start[i].IsNA())
                    {
                        jSeq.Add(i);
                    }
                }

                foreach (int j in jSeq)
                {
                    //# modif_0.11 (first block that appeared here was moved above)
                    // condition inutile
                    if (Tools.IsNA(this.Start[j]))
                    {
                        int    dir      = (j == 0) ? -1 : 1;
                        double tmp      = mode.X + dir * d;
                        bool   accepted = (tmp > this.Range[0]) && (tmp < this.Range[1]);
                        if (!accepted)
                        {
                            double myD = d;
                            while (!accepted)
                            {
                                myD      = myD / 2;
                                tmp      = mode.X + dir * myD;
                                accepted = (tmp > this.Range[0]) && (tmp < this.Range[1]);
                            }
                        }

                        fp[0]    = this.O.LogFPrime(tmp, A);
                        accepted = fp[0].IsFinite();
                        while (!accepted)
                        {
                            tmp      = (tmp + mode.X) / 2;
                            fp[0]    = this.O.LogFPrime(tmp, A);
                            accepted = fp[0].IsFinite();
                        }

                        double a  = fp[0] / d;                                                // # estimated rate of slope acceleration
                        double d2 = Math.Sqrt(2 * Math.Abs(Math.Log(this.FRatioRemote) / a)); // # estimated distance we need to get from mode,
                                                                                              //# at the rate above, to reach the f.ratio.remote distance
                        double x2 = mode.X + dir * d2;
                        accepted = (x2 > this.Range[0]) && (x2 < this.Range[1]);
                        while (!accepted)
                        {
                            d2       = d2 / 2;
                            x2       = mode.X + dir * d2;
                            accepted = x2 > this.Range[0] & x2 < this.Range[1];
                        }

                        double fp2 = this.O.LogFPrime(x2, A);
                        accepted = fp2.IsFinite();

                        while (!accepted)
                        {
                            d2       = d2 / 2;
                            x2       = mode.X + dir * d2;
                            fp2      = this.O.LogFPrime(x2, A);
                            accepted = Tools.IsFinite(fp2);
                        }

                        x = new double[2] {
                            tmp, x2
                        };
                        f = new double[2] {
                            Tools.NA, Tools.NA
                        };
                        for (int i = 0; i < 2; i++)
                        {
                            f[i] = this.O.LogF(x[i], A);
                        }
                        fp[1] = fp2;

                        //# Approximating the shape of log.f.prime by a straight line,
                        //# we can estimate the point where the distance
                        //# prescribed by f.ratio.remote is reached

                        double[,] xSolved = Matrix2x2.Solve2x2(new double[] { x[0], x[1], 1, 1 }, byCol: true); // # 2 x 2 matrix
                        double[] theta = Matrix2x2.Product(xSolved, fp);
                        double   qA    = theta[0];
                        double   qB    = theta[1];
                        // ifelse(xor(j==1, x[1]>x[2]), 2, 1)
                        int    innerSide = (j == 0) ^ (x[0] > x[1]) ? 1 : 0;
                        double innerX    = x[innerSide];
                        double qC        = -qA *Math.Pow(innerX, 2) - qB * innerX - (target - f[innerSide]);

                        double l;
                        double u;
                        if (j == 0)
                        {
                            l = this.Range[0];
                            u = mode.X;
                        }
                        else
                        {
                            l = mode.X;
                            u = this.Range[1];
                        }

                        List <double> roots = QuadraticEquation.GetRealRoots(new double[] { qC, qB, qA }, l: l, u: u, ROrder: true);// # modif_0.11
                        switch (roots.Count)
                        {
                        case 0:
                            this.Start[j] = x[1 - innerSide];
                            break;

                        case 1:
                            this.Start[j] = roots[0];
                            break;

                        default:
                            if (j == 1)
                            {
                                this.Start[j] = roots.Max();
                            }
                            else
                            {
                                this.Start[j] = roots.Min();
                            }
                            break;
                        }
                    }
                }
                //# new_0.11
                //# Suggest another starting point (on both sides)
                //# based on the 2nd degree polynomial approximation (Taylor series devpmt) of log.f

                f = new double[0];
                if (!modeOnBorder.Any(pX => pX))
                {
                    double   delta = Math.Sqrt(2 * logFRatioRemote / fs);
                    double[] altStart;

                    //# Left
                    double xScalar = mode.X - delta;
                    if (xScalar > this.Range[0])
                    {
                        altStart = new double[] { this.Start[0], xScalar };
                        f        = new double[] { Math.Abs(this.O.LogF(altStart[0], A) - target), Math.Abs(this.O.LogF(altStart[1], A) - target) };
                        IEnumerable <double> lstD = f.Substract(target).Abs();
                        int w = (lstD.First() < lstD.Last()) ? 0 : 1;
                        this.Start[0] = altStart[w];
                    }

                    //# Right side
                    xScalar = mode.X + delta;
                    if (xScalar < this.Range[1])
                    {
                        altStart = new double[] { this.Start[1], xScalar };
                        f        = new double[] { Math.Abs(this.O.LogF(altStart[0], A) - target), Math.Abs(this.O.LogF(altStart[1], A) - target) };
                        IEnumerable <double> lstD = f.Substract(target).Abs();
                        int w = (lstD.First() < lstD.Last()) ? 0 : 1;
                        this.Start[1] = altStart[w];
                    }
                }
                //oh <- list(h=o$log.f, hp=o$log.f.prime, hs=o$log.f.second)
                SecuredNRA oh = new SecuredNRA(this.O.LogF, this.O.LogFPrime, this.O.LogFSecond);// # modif_0.11
                if (Tools.IsNA(this.Start[0]))
                {
                    remoteLeft = mode.X;
                }
                else
                {
                    double[] range = new double[] { this.Range[0], mode.X };
                    //LMaxPoint lm = new LMaxPoint(mode);
                    nr = new SecuredNRSearch(oh, A, this.Start[0], this.Epsilon, range,
                                             maxPoint: mode, target: target, inestimableLowerLimit: this.InestimableLowerLimit);
                    // le dernier paramètre a une valeur par défaut: expectedHpSign = -1

                    if (nr.Converged)
                    {
                        remoteLeft = nr.X;
                    }
                    else if (this.Range[0].IsFinite())
                    {
                        remoteLeft = this.Range[0];
                    }
                    else
                    {
                        //TODO Exception
                        throw new WEException("Fin temporaire!");
                    }
                }

                if (Tools.IsNA(this.Start[1]))
                {
                    remoteRight = mode.X;
                } // if
                else
                {
                    this.Range = new double[] { mode.X, this.Range[1] };
                    nr         = new SecuredNRSearch(oh, A, this.Start[1], this.Epsilon, this.Range,
                                                     maxPoint: mode, target: target);
                    // les 2 derniers paramètres prennent des valeurs par défaut:
                    // inestimableLowerLimit = false, expectedHpSign = -1
                    if (nr.Converged)
                    {
                        remoteRight = nr.X;
                    }
                    else
                    {
                        throw new WEException("Algorithm did not converge.");// # should not happen
                    }
                }
            }
            else
            {
                //# new_0.11
                //# mode was not found
                remoteLeft  = Tools.NA;
                remoteRight = Tools.NA;
            }

            //list(mode = mode, remote = c(remote.left, remote.right))

            LModeExt lmext = new LModeExt(mode, remoteLeft, remoteRight);

            return(lmext);
        } //# end of ref.points