예제 #1
0
        internal SecuredNRSearch(
            ISecuredNR o,
            SGNFnAParam A,
            double start,
            double epsilon,
            double[] range,
            LMode maxPoint             = null,
            double target              = 0,
            bool inestimableLowerLimit = false,
            // int maxNIter = 500,
            int expectedHpSign = -1)

        //max.point=list(x= numeric(0), h= numeric(0)),
        {
            //# Throughout this function, 'bounds' is a list with the following elements/dimensions:
            //# x, h, hp, range:   numeric (vectors of length 2)
            //# higherSide:       numeric (1)
            //# IncludeSoln:      logical (1)

            //TODO l'accès à h2Modeless est difficile à comprendre en R qui permet l'accès à des variables non initialisé ... quitte à planter!
            //pour ce faire on introduit ici h2Modeless ...

            //-->secured.NR.search ,start=9.24215468292111 ,target=0 ,range=( 0, Inf ) ,inestimable.lower.limit=FALSE ,max.point$x= ,max.point$h= ,expected.hpsign=-1

            double h2Modeless = Tools.NA;

            if (maxPoint == null)
            {
                maxPoint = new LMode();
            }
            bool   modeSearch = Tools.IsNA(maxPoint.X);
            bool   monotonic  = !modeSearch;
            LLimit limit      = new LLimit();

            limit.X        = range.Copy();          // les autres champs prennent les valeurs par défaut désirée
            limit.Chckd[0] = inestimableLowerLimit; //# new_0.11
            Bounds bounds = new Bounds(
                Tools.Rep(Tools.NA, 2),             //x
                Tools.Rep(Tools.NA, 2),             //h
                Tools.Rep(Tools.NA, 2),             //hp
                null,                               // range
                -1,                                 // higherSide
                false);                             // includeSoln)

            bool found2Bounds;
            bool correct4HpSign;
            int  higherSide;

            if (!Tools.IsNA(maxPoint.X))
            {
                higherSide            = (start < maxPoint.X) ? 1 : 0; // higherSide est un indice
                bounds.X[higherSide]  = maxPoint.X;
                bounds.H[higherSide]  = maxPoint.H;
                bounds.Hp[higherSide] = 0.0;
                found2Bounds          = true;
                expectedHpSign        = higherSide == 0 ? -1 : 1;
                correct4HpSign        = start > maxPoint.X;
                h2Modeless            = (maxPoint.H * 2.0) - target;
            }
            else
            {
                found2Bounds   = false;
                higherSide     = 0;
                correct4HpSign = true;
            }

            int    lowerSide = 1 - higherSide;
            double x         = start;

            //# make sure that x is not out of range
            if (x < limit.X[0])
            {
                x = (maxPoint.X + limit.X[0]) / 2;
            }


            bounds.Range      = range.Copy();
            bounds.HigherSide = higherSide;
            //# Register initial x into bounds
            double h  = o.H(x, A);
            double hp = o.HPrime(x, A);
            int    side;

            if (!Tools.IsNA(maxPoint.X))
            {
                bounds.IncludeSoln = h < target;
                side = lowerSide;
            }
            else
            {
                side = 0;
            }

            bounds.X[side]  = x;
            bounds.H[side]  = h;
            bounds.Hp[side] = hp;
            Visits visitedX = new Visits(SecuredNRSearch.MaxNIter);

            visitedX.Add(x);

            //# Do a first step
            bool cntn;

            if (correct4HpSign)
            {
                hp = expectedHpSign * Math.Abs(hp);
            }

            double change = (h - target) / hp;

            x = x - change;
            //# cntn until convergence
            bool unreachableMode = false;

            cntn = true;
            int  count     = 0;
            bool converged = false;
            int  debCount  = 0;

            while (cntn)
            {
                debCount++;
                if (x.IsNaN())
                {
                    if (1 == 1)
                    {
                    }
                }
                bool computedH = false;
                bool accepted  = false;
                count = count + 1;
                LWhere wb; // = WithinBounds(x, bounds);
                while (!accepted)
                {
                    wb = WithinBounds(x, bounds);
                    if (bounds.IncludeSoln)
                    {
                        if (wb.Within)
                        {
                            accepted = true;
                        }
                        else
                        {
                            x        = CubicExtrapolation.Extrapolate(target, bounds, monotonic, range);
                            accepted = !Tools.IsNA(x);
                        }
                    }
                    else if (wb.Above)
                    {
                        //# bounds do not include solution and we are looking above bounds
                        if (x > limit.X[1])
                        {
                            if (limit.Chckd[1])
                            {
                                accepted = true;
                                h        = limit.H[1];

                                if (UnreachedTarget(target, h, higherSide, monotonic, modeSearch))
                                {
                                    //# force end of while-loop, as target is not reached even at this end
                                    x         = limit.X[1];
                                    h         = target;
                                    computedH = true;
                                }
                                else if (limit.Usable[1])
                                {
                                    x         = bounds.Range[1];
                                    hp        = limit.Hp[1];
                                    computedH = true;
                                }
                                else
                                {
                                    x = (x + change + bounds.Range[1]) / 2;
                                }
                            }
                            else
                            {
                                limit.Chckd[1] = true;
                                h = o.H(limit.X[1], A);
                                if (UnreachedTarget(target, h, higherSide, monotonic, modeSearch))
                                {
                                    //# force end of while-loop, as target is not reached even at this end
                                    x         = limit.X[1];
                                    h         = target;
                                    accepted  = true;
                                    computedH = true;
                                }
                                else
                                {
                                    limit.H[1] = h;
                                    if (h.IsFinite())
                                    {
                                        hp              = o.HPrime(limit.X[1], A);
                                        limit.Hp[1]     = hp;
                                        limit.Usable[1] = hp.IsFinite();
                                        accepted        = limit.Usable[1];
                                    }
                                    else
                                    {
                                        accepted = false;
                                    }

                                    if (accepted)
                                    {
                                        x               = bounds.Range[1];
                                        computedH       = true;
                                        unreachableMode = modeSearch && h > 0;//# new_0.11
                                    }
                                    else
                                    {
                                        x = (x + change + bounds.Range[1]) / 2;
                                    }
                                }
                            }
                        }
                        else
                        {
                            ParamB01 tmp = NewBound(x, bounds, monotonic, o, A, target, range, wb.Above);
                            x         = tmp.X;
                            h         = tmp.H;
                            hp        = tmp.Hp;
                            computedH = true;
                            accepted  = true;
                        }
                    }
                    else
                    {
                        //# bounds do not include solution and we are looking below bounds
                        if (x <= limit.X[0])
                        {
                            //# we are looking out of the variable domain (bad!)
                            if (!limit.Chckd[0])
                            {
                                limit.Chckd[0] = true;
                                h          = o.H(limit.X[0], A);
                                limit.H[0] = h;
                                if (h.IsFinite())
                                {
                                    if (UnreachedTarget(target, h, higherSide, monotonic, modeSearch, leftSide: true))
                                    {
                                        //# force end of while-loop, as target is not reached even at this end
                                        x        = limit.X[0];
                                        h        = target;
                                        accepted = true;
                                    }
                                    else
                                    {
                                        hp              = o.HPrime(limit.X[0], A);
                                        limit.Hp[0]     = hp;
                                        limit.Usable[0] = hp.IsFinite();
                                        accepted        = limit.Usable[0];
                                    }

                                    computedH = accepted;
                                    if (accepted)
                                    {
                                        x = limit.X[0];
                                    }
                                }
                                else
                                {
                                    limit.Usable[0] = false;
                                    x = (bounds.X.Where(a => !Tools.IsNA(a)).Min() + limit.X[0]) / 2;
                                }
                            }
                            else if (limit.Usable[0])
                            {
                                x         = limit.X[0];
                                h         = limit.H[0];
                                hp        = limit.Hp[0];
                                computedH = true;
                                accepted  = true;
                            }
                            else
                            {
                                //# not limit$usable[1]
                                x = (bounds.X.Min() + limit.X[0]) / 2;
                            }
                        }
                        else
                        {
                            ParamB01 tmp = NewBound(x, bounds, monotonic, o, A, target, range, wb.Above);
                            x         = tmp.X;
                            h         = tmp.H;
                            hp        = tmp.Hp;
                            computedH = true;
                            accepted  = true;
                            //    # new_0.11
                            unreachableMode = modeSearch && (((x == limit.X[1]) && (h > 0)) || ((x == limit.X[0]) && (h < 0)));
                        }
                    }
                } // while(!accepted)

                if (!computedH)
                {
                    h  = o.H(x, A);
                    hp = o.HPrime(x, A);
                }

                converged = (Math.Abs(h - target) < epsilon) || unreachableMode;// # modif_0.11
                cntn      = !converged;
                if (cntn)
                {
                    //# register results in bounds
                    bool hLtTarget = h < target;
                    if (bounds.IncludeSoln)
                    {
                        side = hLtTarget ? lowerSide : higherSide;
                    }
                    else
                    {
                        bounds.IncludeSoln = hLtTarget ^ (bounds.H[0] < target);

                        if (found2Bounds)
                        {
                            bool changeOppositeSideBounds = true;
                            if (modeSearch)
                            {
                                side = hLtTarget ? lowerSide : higherSide;
                                changeOppositeSideBounds = true;
                            }
                            else if (bounds.IncludeSoln)
                            {
                                //# bounds newly include solution (happening for the first time with current x)
                                wb = WithinBounds(x, bounds);
                                if (wb.Within)
                                {
                                    if (higherSide == 1)
                                    {
                                        side = lowerSide;
                                        changeOppositeSideBounds = false;
                                        if (hp < 0)
                                        {
                                            bounds.X[lowerSide]  = x;
                                            bounds.H[lowerSide]  = h;
                                            bounds.Hp[lowerSide] = hp;
                                            ParamB01 tmp = LeftSideFastScan(bounds, o, A, target, range[0], h2Modeless);
                                            x    = tmp.X;
                                            h    = tmp.H;
                                            hp   = tmp.Hp;
                                            cntn = tmp.Cntn;
                                        }
                                    }
                                    else
                                    {
                                        throw new WEException("Scénario imprévu.");
                                    }
                                }
                                else if (wb.Below)
                                {
                                    side = 0;
                                    changeOppositeSideBounds = true;
                                }
                                else
                                {
                                    //# wb.above
                                    side = 1;
                                    changeOppositeSideBounds = true;
                                }
                            }
                            else
                            {
                                //# bounds still do not include solution
                                wb = WithinBounds(x, bounds);
                                if (wb.Within)
                                {
                                    changeOppositeSideBounds = false;
                                    if (h > bounds.H.Max())
                                    {
                                        side = higherSide;
                                    }
                                    else if (h < bounds.H.Min())
                                    {
                                        side = hp < 0 ? lowerSide : higherSide;
                                    }
                                    else
                                    {
                                        side = higherSide;
                                    }
                                }
                                else if (wb.Below)
                                {
                                    //Modifié à 1
                                    if (higherSide == 1)
                                    {
                                        if (hp < 0)
                                        {
                                            bounds.X[lowerSide]  = x;
                                            bounds.H[lowerSide]  = h;
                                            bounds.Hp[lowerSide] = hp;
                                            ParamB01 tmp = LeftSideFastScan(bounds, o, A, target, range[lowerSide], h2Modeless);
                                            x    = tmp.X;
                                            h    = tmp.H;
                                            hp   = tmp.Hp;
                                            cntn = tmp.Cntn;
                                            changeOppositeSideBounds = true;
                                        }
                                        else if (h < bounds.H.Min())
                                        {
                                            side = lowerSide;
                                            changeOppositeSideBounds = true;
                                        }
                                        else
                                        {
                                            L1       leftSidePotentialStartPoint = new L1(x, h, hp);
                                            double[] lim = new double[] { x, bounds.X[lowerSide] };
                                            x  = lim.Mean();
                                            hp = o.HPrime(x, A);
                                            while (hp > 0)
                                            {
                                                h         = o.H(x, A);
                                                side      = h > bounds.H[lowerSide] ? 0 : 1;
                                                lim[side] = x;
                                                x         = lim.Mean();
                                                hp        = o.HPrime(x, A);
                                            }
                                            h = o.H(x, A);

                                            bounds.X[higherSide]  = bounds.X[lowerSide];
                                            bounds.H[higherSide]  = bounds.H[lowerSide];
                                            bounds.Hp[higherSide] = bounds.Hp[lowerSide];
                                            bounds.X[lowerSide]   = x;
                                            bounds.H[lowerSide]   = h;
                                            bounds.Hp[lowerSide]  = hp;
                                            ParamB01 tmp = LeftSideFastScan(bounds, o, A, target, range[lowerSide], h2Modeless, leftSidePotentialStartPoint);
                                            x    = tmp.X;
                                            h    = tmp.H;
                                            hp   = tmp.Hp;
                                            cntn = tmp.Cntn;
                                            side = higherSide;
                                            changeOppositeSideBounds = false;
                                        }
                                    }
                                    else
                                    {
                                        throw new WEException("Scénario imprévu.");
                                    }
                                }
                                else
                                {
                                    //# wb.above
                                    side = lowerSide;
                                    changeOppositeSideBounds = true;
                                }
                            }

                            if (changeOppositeSideBounds)
                            {
                                int oppositeSide = 1 - side;
                                bounds.X[oppositeSide]  = bounds.X[side];
                                bounds.H[oppositeSide]  = bounds.H[side];
                                bounds.Hp[oppositeSide] = bounds.Hp[side];
                            }
                        }//if(found2bounds)
                        else
                        {
                            //# !found2bounds
                            found2Bounds = true;
                            side         = h < bounds.H[0] ? lowerSide : higherSide;
                            if (side == 0)
                            {
                                bounds.X[1]  = bounds.X[0];
                                bounds.H[1]  = bounds.H[0];
                                bounds.Hp[1] = bounds.Hp[0];
                            }
                        }
                    }

                    bounds.X[side]  = x;
                    bounds.H[side]  = h;
                    bounds.Hp[side] = hp;
                    visitedX.Add(x);
                    converged = (Math.Abs(h - target) < epsilon) || unreachableMode;// # modif_0.11
                    if (!converged)
                    {
                        cntn = count < SecuredNRSearch.MaxNIter;// # new_0.11: changed <= for <

                        if (!cntn)
                        {
                            //# Before we give up, we check one last thing:
                            //# if the last few steps were all leaning in the same direction,
                            //# then convergence may only be a question of time & patience!
                            //# Give it (yet) another chance!

                            //TODO BIEN VÉRIFIER LA LOGIQUE
                            Visits.DirectionChange[] directionChanges = visitedX.GetDirectionChanges();
                            if (directionChanges.Length > 0)
                            {
                                Visits.DirectionChange lastChangeDirection = directionChanges.Last(); //
                                IEnumerable <Visits.DirectionChange> inOppositeDirection = directionChanges.Where(a => a.Direction == -lastChangeDirection.Direction);
                                if (inOppositeDirection.Count() == 0)
                                {
                                    cntn = true;
                                }
                                else
                                {
                                    Visits.DirectionChange lastInOppositeDirection = inOppositeDirection.Last();
                                    if ((count - lastInOppositeDirection.Index) > 20)
                                    {
                                        cntn = true;
                                    }
                                }
                            }
                            else
                            {
                                //TODO ne devrait pas se produire.
                            }

                            if (cntn)
                            {
                                count    = 0;
                                visitedX = new Visits(SecuredNRSearch.MaxNIter);
                            }
                        } //if(!cntn)
                    }     // if (!converged)

                    if (cntn)
                    {
                        found2Bounds = true;
                        double absHp = Math.Abs(hp);
                        if (correct4HpSign)
                        {
                            hp = expectedHpSign * absHp;
                        }
                        change = (h - target) / hp;
                        double pctChange = Math.Abs(change) / bounds.X.Diff()[0];

                        if ((pctChange < 1e-4) && absHp > 1000)
                        {
                            double[] p;
                            if (change < 0)
                            {
                                p = new double[] { 0.9, 0.1 };
                            }
                            else
                            {
                                p = new double[] { 0.1, 0.9 };
                            }
                            x = p.Multiply(bounds.X).Sum();
                        }
                        else
                        {
                            x = x - change;
                        }
                    } //if (cntn)

                    //#cat('count=', count, '\n')
                    //#cat('x = ', x, '\n')
                    //#cat('h = ', h, '\n')
                    //#cat('target = ', target, '\n')
                    //#cat('abs(h-target)', abs(h-target), '\n')
                    //#cat('bounds.x = ', bounds.x, '\n')
                    //#cat('diff(bounds.x) = ', diff(bounds.x), '\n')
                    //#if (diff(bounds.x) < 0) cat('***************\n')
                } // if (cntn)
            }     //while (cntn)

            this.X         = x;
            this.Converged = converged;
            this.Bounds    = bounds;
            //list(x = x, converged = converged, bounds = bounds);
        } //# end of secured.NR.search
예제 #2
0
        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