示例#1
0
文件: PLEpy.py 项目: pstefano91/plepy
    def bsearch(self,
                pname: str,
                clevel: float,
                acc: int,
                direct: int = 1,
                idx=None) -> float:
        """Binary search for confidence limit
        Args
        ----
        pname : str
            parameter name
        clevel: float
            value of log of objective function at confidence limit
        acc: int
            accuracy in terms of the number of significant figures to
            consider

        Keywords
        --------
        direct : int, optional
            direction to search (0=downwards, 1=upwards), by default 1
        idx: optional
            for indexed parameters, the value of the index to get the
            confidence limits for

        Returns
        -------
        float
            value of parameter bound
        """
        from plepy.helper import sigfig, sflag

        # manually change parameter of interest
        if idx is None:
            self.plist[pname].fix()
            x_out = float(self.pbounds[pname][direct])
            x_in = float(self.popt[pname])
        else:
            self.plist[pname][idx].fix()
            x_out = float(self.pbounds[pname][idx][direct])
            x_in = float(self.popt[pname][idx])

        # Initialize values based on direction
        x_mid = x_out
        # for upper CI search
        if direct:
            x_high = x_out
            x_low = x_in
            plc = 'upper'
            puc = 'Upper'
            no_lim = float(x_out)
        # for lower CI search
        else:
            x_high = x_in
            x_low = x_out
            plc = 'lower'
            puc = 'Lower'
            no_lim = float(x_out)

        # Print search info
        print(' ' * 80)
        print('Parameter: {:s}'.format(pname))
        if idx is not None:
            print('Index: {:s}'.format(str(idx)))
        print('Bound: {:s}'.format(puc))
        print(' ' * 80)

        # check convergence criteria
        ctol = sigfig(x_high, acc) - sigfig(x_low, acc)

        # Find outermost feasible value
        # evaluate at outer bound
        r_mid = self.m_eval(pname, x_mid, idx=idx)
        fcheck = sflag(r_mid)
        self.m.solutions.load_from(r_mid)
        err = np.log(penv.value(self.m.obj))
        # If solution is feasible and the error is less than the value
        # at the confidence limit, there is no CI in that direction.
        # Set to bound.
        if fcheck == 0 and err < clevel:
            pCI = no_lim
            print('No %s CI! Setting to %s bound.' % (plc, plc))
        else:
            fiter = 0
            # If solution is infeasible, find a new value for x_out
            # that is feasible and above the confidence threshold.
            while (fcheck == 1 or err < clevel) and ctol > 0.0:
                print('f_iter: %i, x_high: %f, x_low: %f' %
                      (fiter, x_high, x_low))
                # check convergence criteria
                ctol = sigfig(x_high, acc) - sigfig(x_low, acc)
                # evaluate at midpoint
                x_mid = 0.5 * (x_high + x_low)
                r_mid = self.m_eval(pname, x_mid, idx)
                fcheck = sflag(r_mid)
                # if infeasible, continue search inward from current
                # midpoint
                if fcheck == 1:
                    x_out = float(x_mid)
                self.m.solutions.load_from(r_mid)
                err = np.log(penv.value(self.m.obj))
                # if feasbile, but not over CL threshold, continue
                # search outward from current midpoint
                if fcheck == 0 and err < clevel:
                    x_in = float(x_mid)
                if direct:
                    x_high = x_out
                    x_low = x_in
                else:
                    x_high = x_in
                    x_low = x_out
                fiter += 1
            # if convergence reached, there is no upper CI
            if ctol == 0.0:
                pCI = no_lim
                print('No %s CI! Setting to %s bound.' % (plc, plc))
            # otherwise, find the upper CI between outermost feasible
            # pt and optimal solution using binary search
            else:
                x_out = float(x_mid)
                if direct:
                    x_high = x_out
                    x_low = x_in
                else:
                    x_high = x_in
                    x_low = x_out
                biter = 0
                # repeat until convergence criteria is met
                # (i.e. x_high = x_low)
                while ctol > 0.0:
                    print('b_iter: %i, x_high: %f, x_low: %f' %
                          (biter, x_high, x_low))
                    # check convergence criteria
                    ctol = sigfig(x_high, acc) - sigfig(x_low, acc)
                    # evaluate at midpoint
                    x_mid = 0.5 * (x_high + x_low)
                    r_mid = self.m_eval(pname, x_mid, idx=idx)
                    fcheck = sflag(r_mid)
                    self.m.solutions.load_from(r_mid)
                    err = np.log(penv.value(self.m.obj))
                    print(self.popt[pname])
                    biter += 1
                    # if midpoint infeasible, continue search inward
                    if fcheck == 1:
                        x_out = float(x_mid)
                    # if midpoint over CL, continue search inward
                    elif err > clevel:
                        x_out = float(x_mid)
                    # if midpoint under CL, continue search outward
                    else:
                        x_in = float(x_mid)
                    if direct:
                        x_high = x_out
                        x_low = x_in
                    else:
                        x_high = x_in
                        x_low = x_out
                pCI = sigfig(x_mid, acc)
                print('%s CI of %f found!' % (puc, pCI))
        # reset parameter
        self.setval(pname, self.popt[pname])
        if idx is None:
            self.plist[pname].free()
        else:
            self.plist[pname][idx].free()
        print(self.popt[pname])
        return pCI
示例#2
0
文件: PLEpy.py 项目: pstefano91/plepy
        def inner_loop(xopt, xb, direct=1, idx=None) -> dict:
            from plepy.helper import sflag

            pdict = {}
            if direct:
                print('Going up...')
                x0 = np.linspace(xopt, xb, n + 2, endpoint=True)
            else:
                print('Going down...')
                x0 = np.linspace(xb, xopt, n + 2, endpoint=True)
            print('x0:', x0)
            # evaluate objective at each discretization point
            for w, x in enumerate(x0):
                xdict = {}
                if w == 0:
                    for p in self.pnames:
                        self.setval(p, self.popt[p])
                else:
                    for p in self.pnames:
                        prevx = pdict[x0[w - 1]][p]
                        self.setval(p, prevx)
                try:
                    rx = self.m_eval(pname, x, idx=idx, reset=False)
                    xdict['flag'] = sflag(rx)
                    self.m.solutions.load_from(rx)
                    xdict['obj'] = np.log(penv.value(self.m.obj))
                    # store values of other parameters at each point
                    for p in self.pnames:
                        xdict[p] = self.getval(p)
                except ValueError:
                    xdict = copy.deepcopy(pdict[x0[w - 1]])
                pdict[x] = xdict
            if direct:
                x_out = x0[1:]
                x_in = x0[:-1]
            else:
                x_out = x0[:-1]
                x_in = x0[1:]
            # calculate magnitude of step sizes
            dx = x_out - x_in
            y0 = np.array([pdict[x]['obj'] for x in x0])
            print('y0:', y0)
            if direct:
                y_out = y0[1:]
                y_in = y0[:-1]
            else:
                y_out = y0[:-1]
                y_in = y0[1:]
            # calculate magnitude of objective value changes between
            # each step
            dy = np.abs(y_out - y_in)
            # pull indices where objective value change is greater than
            # threshold value (dtol) and step size is greater than
            # minimum
            ierr = [(i > dtol and j > min_step) for i, j in zip(dy, dx)]
            print('ierr:', ierr)
            itr = 0
            # For intervals of large change (above dtol), calculate
            # values at midpoint. Repeat until no large changes or
            # minimum step size is reached.
            while len(ierr) != 0:
                print('iter: %i' % (itr))
                x_oerr = np.array([j for i, j in zip(ierr, x_out) if i])
                x_ierr = np.array([j for i, j in zip(ierr, x_in) if i])
                x_mid = 0.5 * (x_oerr + x_ierr)
                for w, x in enumerate(x_mid):
                    xdict = {}
                    for p in self.pnames:
                        prevx = pdict[x_ierr[w]][p]
                        self.setval(p, prevx)
                    try:
                        rx = self.m_eval(pname, x, idx=idx, reset=False)
                        xdict['flag'] = sflag(rx)
                        self.m.solutions.load_from(rx)
                        xdict['obj'] = np.log(penv.value(self.m.obj))
                        # store values of other parameters at each pt
                        for p in self.pnames:
                            xdict[p] = self.getval(p)
                    except ValueError:
                        xdict = copy.deepcopy(pdict[x_ierr[w]])
                    pdict[x] = xdict
                # get parameter values needed to calculate change in
                # error over intervals that have not converged
                x0 = np.array(sorted(set([*x_oerr, *x_mid, *x_ierr])))
                print('x0:', x0)
                x_out = x0[1:]
                x_in = x0[:-1]
                # calculate magnitude of step sizes
                dx = x_out - x_in
                y0 = np.array([pdict[x]['obj'] for x in x0])
                print('y0:', y0)
                y_out = y0[1:]
                y_in = y0[:-1]
                # calculate magnitude of objective value change between
                # each step
                dy = np.abs(y_out - y_in)
                # pull indices where objective value change is greater
                # than threshold value (dtol) and step size is greater
                # than minimum
                ierr = [(i > dtol and j > min_step) for i, j in zip(dy, dx)]
                print('ierr:', ierr)
                itr += 1
            return pdict