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); }
internal static double PingpongTieBreaker( Func <double, SGNFnAParam, double> area, SGNFnAParam A, double start, double areaX, double target, double mathLowerLimit, double[] refRange, bool inestimableLowerLimit, double epsilon, bool distrnLeftSide = false, int maxCount = 100) { int hpMult = distrnLeftSide ? -1 : 1; bool cntn = true; int count = 0; double x = start; Visits visitedX = new Visits(maxCount); visitedX.Add(x); bool converged = false; bool caughtInLoop = false; while (cntn) { double hp = A.F(x, A) * hpMult; double change = (target - areaX) / hp; x = x + change; // new_0.11 if (x < refRange[0]) { x = (refRange[0] == mathLowerLimit) && inestimableLowerLimit ? (x - change + mathLowerLimit) / 2.0 : refRange[0]; } areaX = WebExpoFunctions3.SmoothedAreaEstimate(area, x, A, mathLowerLimit, refRange, inestimableLowerLimit, hpMult: hpMult); count++; converged = Math.Abs(areaX - target) < epsilon; visitedX.Add(x); caughtInLoop = visitedX.CaughtInLoop; // La propiété CaughtInLoop est mise à jour à chaque ajout d'un x. // x doit être fini, et avoir déjà été visité. cntn = !converged && (visitedX.Count <= maxCount) && !caughtInLoop; } if (!converged && caughtInLoop) { // We have found the series of points that are repeatedly visited: // recalibrate and try Newton-Raphson again double[] tail = visitedX.GetFromTail(x); x = (distrnLeftSide) ? x = tail.Max() : tail.Min(); areaX = WebExpoFunctions3.SmoothedAreaEstimate(area, x, A, mathLowerLimit, refRange, inestimableLowerLimit, hpMult: hpMult); if (distrnLeftSide) { A.UpperLimit = x; } else { A.LowerLimit = x; } target = target - areaX; areaX = 0.0; count = 0; cntn = true; while (cntn) { double hp = A.F(x, A) * hpMult; double change = (target - areaX) / hp; x = x + change; areaX = area(x, A); count = count + 1; converged = Math.Abs(areaX - target) < epsilon; cntn = !converged && (count <= maxCount); } } if (!converged) { //TODO Exception throw new WEException("Newton-Raphson algorithm did not converge. Sorry.\n"); } return(x); } // end of ping.pong.tie.breaker