示例#1
0
    async def _emparse(self, ctx, embed: Embed, fields: tuple) -> tuple:
        i = 0
        content = None
        while i < len(fields):
            if fields[i] == 'content':
                content = fields[i]
                i += 2
                continue

            # get a function callback using a string that corresponds to its name
            embuilder = utils.EmbedBuilder(ctx)
            method = getattr(embuilder, fields[i], None)
            if method == None:
                raise commands.BadArgument

            # extract the number of parameters
            params = len(sig(method).parameters)

            # create the embed, catching any embed limit violations
            try:
                await method(embed, *fields[i + 1:i + params])
                if len(embed) > 6000: raise utils.EmbedException('embed', 6000)
            except utils.EmbedException as err:
                embed.set_author(name=err.what(),
                                 icon_url='attachment://unknown.png')
                embed.color = utils.Color.red

                await ctx.reply(embed=embed,
                                file=File('assets/reddot.png', 'unknown.png'))

            i += params

        return content
示例#2
0
 def get_instance(cls, type_name, params=None, **kwargs):
     """Get instance."""
     _params = deepcopy(params)
     if not _params:
         return
     t_cls_name = _params.pop('type')
     if kwargs:
         _params.update(kwargs)
     t_cls = cls.get_cls(type_name, t_cls_name)
     if type_name != ClassType.NETWORK:
         return t_cls(**_params) if _params else t_cls()
     # remove extra params
     params_sig = sig(t_cls.__init__).parameters
     for k, v in params_sig.items():
         try:
             if '*' in str(v) and '**' not in str(v):
                 return t_cls(*list(_params.values())) if list(_params.values()) else t_cls()
             if '**' in str(v):
                 return t_cls(**_params) if _params else t_cls()
         except Exception as ex:
             logging.error("Failed to create instance:{}".format(t_cls))
             raise ex
     extra_param = {k: v for k, v in _params.items() if k not in params_sig}
     _params = {k: v for k, v in _params.items() if k not in extra_param}
     try:
         instance = t_cls(**_params) if _params else t_cls()
     except Exception as ex:
         logging.error("Failed to create instance:{}".format(t_cls))
         raise ex
     for k, v in extra_param.items():
         setattr(instance, k, v)
     return instance
示例#3
0
			def getDefaultArgs(func):
					signature = sig(func)
					return {
						k: v.default
						for k, v in signature.parameters.items()
						if v.default is not Parameter.empty
					}
示例#4
0
    def get_viz_value_str(self):
        res_str = str(self.prop_value)
        if hasattr(self.prop_value, "__impl_origin__"):
            res_str = "Impl. from " + self.prop_value.__impl_origin__ + ": " + \
                      self.prop_value.__name__ + str(sig(self.prop_value))

        return res_str
示例#5
0
文件: wrappers.py 项目: ylfzr/vega
 def wrapper(*args, **kwargs):
     """Make function as a wrapper."""
     params_sig = sig(func).parameters
     params = {
         param: value
         for param, value in kwargs.items() if param in params_sig
     }
     return func(*args, **params)
示例#6
0
def func_key(func, fargs=None, fkwargs=None):
    """
    Returns the key used in :attr:`Energy.values` for `func`.

    Parameters
    ----------
    func : :class:`function`
        The function whose results are to be stored in
        :attr:`Energy.values`.

    fargs : :class:`tuple`, optional
        The arguments passed to `func`.

    fkwargs : :class:`dict`, optional
        The keyword arguments passed to `func`.

    Returns
    -------
    :class:`.FunctionData`
        The :class:`.FunctionData` object representing the key when
        `func` is called with the arguments `fargs` and keyword
        arguments `fkwargs`.

    """

    if fargs is None:
        fargs = []
    if fkwargs is None:
        fkwargs = []

    # Check if the function has a `key` attribute. If it does use this
    # to get its key rather than the general purpose code written here.
    if hasattr(getattr(Energy, func.__name__, False), 'key'):
        return getattr(Energy, func.__name__).key(fargs, fkwargs)

    fsig = sig(func)
    # Get a dictionary of all the supplied parameters.
    bound = dict(fsig.bind_partial(*fargs, **fkwargs).arguments)
    # Get a dictionary of all the default initialized parameters.
    default = {
        key: value.default
        for key, value in dict(fsig.parameters).items()
        if key not in bound.keys()
    }
    # Combine the two sets of parameters and get rid of the `self`
    # parameter, if present.
    bound.update(default)
    if 'self' in bound.keys():
        bound.pop('self')
    # Remove any parameters that should not form key, listed in the
    # `exclude` attribute.
    if hasattr(func, 'exclude'):
        for key in func.exclude:
            bound.pop(key)

    # Return an FunctionData object representing the function and
    # chosen parameters.
    return FunctionData(func.__name__, **bound)
示例#7
0
    def curried(*args):
        if len(args) >= len(sig(func).parameters):
            return func(*args)
        else:

            def partial(*args2):
                return curried(*(args + args2))

            return partial
示例#8
0
def tune(default=None, tuning_range=(), args=None, name=None, tuner=None):
    """ 
    Return TuneInt/Enum/Float instantiated obj
    Property @val will return actual value 
    ----------
    Parameters: 
        default : value adopted in deafault mode
        tuning_range : dimensional search space 
        args : list of args for function
        name : identifier for var look-up
    ----------
    Return:
        value : string float or integer
    """
    if default == None:  # start tuning
        assert tuner, "not specify tuner"
        start()
        return

    if name:  # checke name validity
        import uptune as ut
        assert name not in ut.mapping.keys(), \
               "invalid name for registeration"

    if isinstance(tuning_range, list):
        assert len(tuning_range) > 0, \
               "must specify the tuning range as list"
        assert default in tuning_range, \
               "default should be in list"
        return types.TuneEnum(default, tuning_range, name=name).val

    # custom func defining enum inter-deps
    elif callable(tuning_range):
        assert args, "args for function not specified"
        assert len(args) == len(sig(tuning_range).parameters), \
               "parameter number not match"
        return types.TuneEnum(default, tuning_range, args=args, name=name).val

    # create nodes for numerical ops
    assert isinstance(tuning_range, tuple), \
           "tuple range for boolean and numerical values"

    if len(tuning_range) == 2:
        lower, upper = tuning_range
        if isinstance(lower, float) or isinstance(upper, float):
            return types.TuneFloat(default, tuning_range, name=name).val
        return types.TuneInt(default, tuning_range, name=name).val

    # create permutation or boolean param
    assert len(tuning_range) == 0 and \
           isinstance(default, (bool, list)), \
           "for boolean or permutation range should be ()"
    if isinstance(default, bool):
        return types.TuneBool(default, name=name).val
    else:  # create permutation param
        return types.TunePermutation(default, name=name).val
示例#9
0
def pseudoformation_key(fargs, fkwargs):
    """
    Generates key of the :meth:`Energy.pseudoformation`.

    Parameters
    ----------
    fargs : :class:`tuple`
        The arguments with which :meth:`Energy.pseudoformation` was
        called.

    fkwargs : :class:`dict`
        The keyword arguments with which :meth:`Energy.pseudoformation`
        was called.

    Returns
    -------
    :class:`.FunctionData`
        The :class:`.FunctionData` object representing the key when
        :meth:`Energy.pseudoformation` is called with the arguments
        `fargs` and keyword arguments `fkwargs`.

    """

    fsig = sig(Energy.pseudoformation)

    # Get a dictionary of all the supplied parameters.
    bound = dict(fsig.bind_partial(*fargs, **fkwargs).arguments)
    # Get a dictionary of all the default initialized parameters.
    default = {
        key: value.default
        for key, value in dict(fsig.parameters).items()
        if key not in bound.keys()
    }

    # Combine the two sets of parameters and get rid of the `self`
    # parameter, if present.
    bound.update(default)
    if 'self' in bound.keys():
        bound.pop('self')

    # Replace the energy function to be used with the key of the
    # energy function to be used.
    efuncdata = bound['func']
    efunc = getattr(Energy, efuncdata.name)
    bound['func'] = func_key(efunc, None, efuncdata.params)

    # Don't want this paramter in the key as it doenst affect the
    # result.
    bound.pop('force_e_calc')

    # Return an FunctionData object representing the function and
    # chosen parameters.
    return FunctionData('pseudoformation', **bound)
示例#10
0
 def __new__(cls, *args, **kwargs):
     """Record params."""
     desc = {}
     params_sig = sig(cls.__init__).parameters
     param_names = list(params_sig.keys())
     if len(param_names) > len(args):
         # not dynamic parameter for connections
         for idx, arg in enumerate(args):
             arg_name = param_names[idx + 1]
             desc[arg_name] = arg
     if kwargs:
         desc.update(kwargs)
     instance = super(Serializable, cls).__new__(cls)
     instance.desc = Config(desc) if desc else {}
     return instance
    def decorate(func):
        if not __debug__:
            return func

        fun_sig = sig(func)
        # 将签名与参数字典绑定
        bound_types = fun_sig.bind_partial(*ty_args, **ty_kwargs).arguments

        @wraps(func)
        def wrapper(*args, **kwargs):
            # 参数顺序字典
            bound_values = fun_sig.bind(*args, **kwargs)
            for name, value in bound_values.arguments.items():
                if name in bound_types:
                    if not isinstance(value, bound_types[name]):
                        raise TypeError('Argument {} must be {}'.format(
                            name, bound_types[name]))
            return func(*args, **kwargs)

        return wrapper
示例#12
0
def accumulate(operator, iterable, default=None):
	"""repeatedly call function with args last_result, item. first call args is item[0], item[1]"""
	from inspect import signature as sig
	i = iter(iterable)
	try:
		r = next(i)
	except StopIteration:
		# raise ArithmeticError("! attempted arithmetic on 0 items")
		return default
	while True:
		try:
			item = next(i)
		except StopIteration:
			break
		try:
			r = operator(r, item)
		except TypeError as e:
			if len(sig(operator).parameters) != 2:
				raise TypeError("! operator function should take two arguments")
			raise e
	return r
示例#13
0
 def get_instance(cls, type_name, params=None, **kwargs):
     """Get instance."""
     _params = deepcopy(params)
     if not _params:
         return
     t_cls_name = _params.pop('type')
     if kwargs:
         _params.update(kwargs)
     t_cls = cls.get_cls(type_name, t_cls_name)
     if type_name != ClassType.NETWORK:
         return t_cls(**_params) if _params else t_cls()
     # remove extra params
     params_sig = sig(t_cls.__init__).parameters
     for k, v in params_sig.items():
         if '**' in str(v) or '*' in str(v):
             return t_cls(**_params) if _params else t_cls()
     extra_param = {k: v for k, v in _params.items() if k not in params_sig}
     _params = {k: v for k, v in _params.items() if k not in extra_param}
     instance = t_cls(**_params) if _params else t_cls()
     for k, v in extra_param.items():
         setattr(instance, k, v)
     return instance
示例#14
0
def _generate_disp_info(
    func
) -> Tuple[Dict[str, _Param], Dict[str, _AnnotationPair],
           List[_AnnotationPair]]:
    defaults: Dict[str, _Param]
    keywords: Dict[str, _AnnotationPair]
    positionals: List[_AnnotationPair]
    defaults, keywords, positionals = {}, {}, []
    for n, p in sig(func).parameters.items():
        ann = p.annotation
        if ann is Parameter.empty:
            raise ValueError(f"parameter '{n}' is not annotated.")
        if not isinstance(ann, Annotation):
            raise TypeError(
                f"unexpected annotation type: {type(ann).__name__}")
        defaults[n] = p.default if p.default is not Parameter.empty else None
        if ann.positional:
            positionals.append((n, ann))
            continue
        keywords[_to_param_name(n)] = (n, ann)
        if ann.short_name:
            keywords[f"-{ann.short_name}"] = (n, ann)
    positionals.sort(key=lambda x: not x[1].required)
    return defaults, keywords, positionals
示例#15
0
文件: utils.py 项目: GlitchYou/WIHACK
def shargs(func):
    from inspect import signature as sig
    from sys import argv

    if '.py' in argv[0]:
        del argv[0]
    else:
        del argv[0:1]

    if argv[0] in ('-h', '--help'):
        help(func)
        exit()

    sig = sig(func)
    params = sig.parameters.values()

    args = []
    kwargs = {}

    for par in params:
        key = par.name
        mod = par.kind
        typ = 0

        if len(dir(par.default)) != 26:
            typ = type(par.default)
        elif len(dir(par.annotation)) != 26:
            typ = par.annotation

        if typ not in [str, int, float, bool, list, tuple]:
            del typ

        _arg = par.POSITIONAL_OR_KEYWORD
        _args = par.VAR_POSITIONAL
        _kwargs = par.VAR_KEYWORD

        _pos = par.POSITIONAL_ONLY
        _key = par.KEYWORD_ONLY

        if len(argv) > 0:

            if mod in (_arg, _pos):
                if f'--{key}' in argv:
                    i = argv.index(f'--{key}')

                    if 'typ' in locals():
                        val = typ(argv[i + 1])
                    else:
                        val = argv[i + 1]

                    args.append(val)
                    del argv[i]
                    del argv[i]

                else:

                    if 'typ' in locals():
                        val = typ(argv[0])
                    else:
                        val = argv[0]

                    args.append(val)
                    del argv[0]

            elif mod == _args:

                s = e = 0
                for a in argv:

                    if 'typ' in locals():
                        val = typ(a)
                    else:
                        val = a

                    if f'--' in a:
                        break
                    else:
                        args.append(val)
                        e += 1

                del argv[s:e]

            else:
                if f'--{key}' in argv:
                    i = argv.index(f'--{key}')

                    if 'typ' in locals():
                        val = typ(argv[i + 1])
                    else:
                        val = argv[i + 1]

                    kwargs[key] = val

    return func(*args, **kwargs)
示例#16
0
def arityof(method):
    return len([
        param for param in sig(method).parameters.values()
        if param.kind not in (Parameter.VAR_POSITIONAL, Parameter.VAR_KEYWORD)
    ]) if callable(method) else -1
示例#17
0
def p_arityof(method):
    return len([
        param for param in sig(method).parameters.values()
        if param.kind in (Parameter.POSITIONAL_ONLY,
                          Parameter.POSITIONAL_OR_KEYWORD)
    ]) if callable(method) else -1
示例#18
0
def params(f) -> int:
    return len(sig(f).parameters)
示例#19
0
    def simulation_OFC(self,ncmE,ncmC,f,g,Cfun,h,dt,tf,x0,z0,Qe,Qc,Re,Rc,\
        dscale=10,xnames="num",Ncol=1,FigSize=(20,10),FontSize=20,phis=None):
        """
        Perform NCM-based output feedback control of given nolinear dynamical
        systems and return simulation results
        

        Parameters
        ----------
        dt : float
            simulation time step
        tf : float
            terminal time
        x0 : ndarray - (n, )
            initial state
        z0 : ndarray - (n, ), to be used for iEC = "est"
            estimated initial state
        dscale : float, optional, default is 10
            scale of external disturbance 
        xnames : str, optional, default is "num"
            list containing names of each state, when xnames = "num", they are
            denoted as xnames = ["state 1","state 2",...]
        Ncol : int, optional, default is 1
            # columns of state figures to be generated
        FigSize : tuple, optional, default is (20,10)
            size of state figures to be generated
        FontSize : float, optional, default is 20
            font size of figures to be generated
        phis : system parameter history, optional, default is None
            history of system parameters

        Returns
        -------
        this : ndarray - (int(tf/dt)+1, )
            time histry 
        xhis : ndarray - (int(tf/dt)+1,n)
            state history
        zhis : ndarray - (int(tf/dt)+1,n), to be used for estimation tasks
            estimated state history

        """
        """
        
        
        1) SIMULATION
    
        
        """
        if len(sig(f).parameters) == 1:
            fun1 = f
            f = lambda x, p: fun1(x)
        if len(sig(g).parameters) == 1:
            fun2 = g
            g = lambda x, p: fun2(x)
        if len(sig(Cfun).parameters) == 1:
            fun3 = Cfun
            Cfun = lambda x, p: fun3(x)
        if len(sig(h).parameters) == 1:
            fun4 = h
            h = lambda x, p: fun4(x)
        print("========================================================")
        print("====================== SIMULATIOM ======================")
        print("========================================================")
        if dt <= self.dt_rk:
            self.dt_rk = dt
        self.Nrk = int(dt / self.dt_rk)
        Nsim = int(tf / dt)
        np.set_printoptions(precision=1)
        print("time step =", dt)
        print("terminal time =", tf)
        print("initial state =", x0)
        print("estimated initial state =", z0)
        funx = lambda x, p, dEf: f(x, p) + dEf(x, p)
        z = z0
        zhis = np.zeros((Nsim + 1, self.n))
        zhis[0, :] = z
        x = x0
        xhis = np.zeros((Nsim + 1, self.n))
        xhis[0, :] = x
        z2 = z0
        z2his = np.zeros((Nsim + 1, self.n))
        z2his[0, :] = z2
        x2 = x0
        x2his = np.zeros((Nsim + 1, self.n))
        x2his[0, :] = x2
        uehis = np.zeros(Nsim + 1)
        ue = 0
        ue2his = np.zeros(Nsim + 1)
        ue2 = 0
        tit1 = "Performance of NCM-based Output Feedback (1)"
        tit2 = "Performance of NCM-based Output Feedback (2)"
        tit3 = "Performance of NCM-based Output Feedback (3)"
        tit4 = "Performance of NCM-based Output Feedback (4)"
        tit5 = "Performance of NCM-based Output Feedback (5)"
        ly = r"estimation error: $\|x-\hat{x}\|_2$"
        lyb = r"tracking error: $\|x-x_d\|_2$"
        lyc = r"control effort $\int_0^t\|u(\tau)\|_2d\tau$"
        l1 = r"estimation error (NCM)"
        l2 = r"estimation error (SDRE)"
        l1b = r"tracking error (NCM)"
        l2b = r"tracking error (SDRE)"
        bNam1 = "=================== ESTIMATION ERROR ==================="
        bNam2 = "============ ESTIMATION ERROR OF EACH STATE ============"
        bNam3 = "==================== TRACKING ERROR ===================="
        bNam4 = "============= TRACKING ERROR OF EACH STATE ============="
        bNam5 = "==================== CONTROL EFFORT ===================="
        l3 = r"optimal steady-state upper bound"
        if phis == None:
            phis = np.linspace(self.plims[0, :], self.plims[1, :], Nsim)
        for k in range(Nsim):
            p = phis[k, :]
            Ax2 = self.Afun(z2, p)
            Mc = ncmC.ncm(z, p)
            Kc, _, _ = control.lqr(Ax2, g(z2, p), Qc, Rc)
            u = -g(z, p).T @ Mc @ z
            u2 = -Kc @ z2
            dEfC = lambda x, p: g(x, p) @ u
            dEfC2 = lambda x, p: g(x, p) @ u2
            d1 = self.unifrand2(ncmC.d1_over, np.size(ncmC.Bw(x, p),
                                                      1)) * dscale
            x = self.rk4(x, p, dEfC, funx) + ncmC.Bw(x, p) @ d1 * dt
            x2 = self.rk4(x2, p, dEfC2, funx) + ncmC.Bw(x2, p) @ d1 * dt
            xhis[k + 1, :] = x
            x2his[k + 1, :] = x2
            Me = ncmE.ncm(z, p)
            Cx = Cfun(z, p)
            Lx = Me @ Cx.T
            Cx2 = Cfun(z2, p)
            Ke, _, _ = control.lqr(Ax2.T, Cx2.T, Qe, Re)
            Lx2 = Ke.T
            #Lx = K.T
            d2 = self.unifrand2(ncmE.d2_over, np.size(ncmE.Gw(x, p),
                                                      1)) * dscale
            y = h(x, u, p) + ncmE.Gw(x, p) @ d2
            y2 = h(x2, u2, p) + ncmE.Gw(x2, p) @ d2
            funz = lambda z, p, dEf: f(z, p) + g(z, p) @ u + dEf(z, p)
            funz2 = lambda z, p, dEf: f(z, p) + g(z, p) @ u2 + dEf(z, p)
            dEfE = lambda z, p: Lx @ (y - h(z, u, p))
            dEfE2 = lambda z, p: Lx2 @ (y2 - h(z, u2, p))
            z = self.rk4(z, p, dEfE, funz)
            z2 = self.rk4(z2, p, dEfE2, funz2)
            zhis[k + 1, :] = z
            z2his[k + 1, :] = z2
            ue += np.linalg.norm(u) * dt
            ue2 += np.linalg.norm(u2) * dt
            uehis[k + 1] = ue
            ue2his[k + 1] = ue2
        this = np.linspace(0, tf, Nsim + 1)
        """
        
        
        2) FIGURE GENERATION
    
        
        """
        print("========================================================")
        print(bNam1)
        print("========================================================")
        matplotlib.rcParams.update({"font.size": 15})
        matplotlib.rc("text", usetex=True)
        plt.figure()
        plt.plot(this, np.sqrt(np.sum((xhis - zhis)**2, 1)))
        plt.plot(this, np.sqrt(np.sum((x2his - z2his)**2, 1)))
        plt.plot(this, np.ones(np.size(this)) * ncmE.Jcv_opt)
        plt.xlabel(r"time", fontsize=FontSize)
        plt.ylabel(ly, fontsize=FontSize)
        plt.legend([l1, l2, l3], loc="best")
        plt.title(tit1, fontsize=FontSize)
        plt.show()
        print("========================================================")
        print(bNam2)
        print("========================================================")
        Nrow = int(self.n / Ncol) + np.remainder(self.n, Ncol)
        fig, ax = plt.subplots(Nrow, Ncol, figsize=FigSize)
        plt.subplots_adjust(wspace=0.25, hspace=0.25)
        if Ncol == 1:
            ax = np.reshape(ax, (self.n, 1))
        elif Nrow == 1:
            ax = np.reshape(ax, (1, self.n))
        if xnames == "num":
            xnames = []
            for i in range(self.n):
                xnames += [r"state " + str(i + 1)]
        for row in range(Nrow):
            for col in range(Ncol):
                i = Ncol * row + col
                if i + 1 <= self.n:
                    ax[row, col].plot(this, xhis[:, i] - zhis[:, i])
                    ax[row, col].plot(this, x2his[:, i] - z2his[:, i])
                    ax[row, col].set_xlabel(r"time", fontsize=FontSize)
                    LabelName = r"estimation error: " + xnames[i]
                    ax[row, col].set_ylabel(LabelName, fontsize=FontSize)
                    ax[row, col].legend([r"NCM", r"SDRE"], loc="best")
        fig.suptitle(tit2, fontsize=FontSize)
        plt.show()
        print("========================================================")
        print(bNam3)
        print("========================================================")
        matplotlib.rcParams.update({"font.size": 15})
        matplotlib.rc("text", usetex=True)
        plt.figure()
        plt.plot(this, np.sqrt(np.sum((xhis)**2, 1)))
        plt.plot(this, np.sqrt(np.sum((x2his)**2, 1)))
        plt.plot(this, np.ones(np.size(this)) * ncmC.Jcv_opt)
        plt.xlabel(r"time", fontsize=FontSize)
        plt.ylabel(lyb, fontsize=FontSize)
        plt.legend([l1b, l2b, l3], loc="best")
        plt.title(tit3, fontsize=FontSize)
        plt.show()
        print("========================================================")
        print(bNam4)
        print("========================================================")
        Nrow = int(self.n / Ncol) + np.remainder(self.n, Ncol)
        fig, ax = plt.subplots(Nrow, Ncol, figsize=FigSize)
        plt.subplots_adjust(wspace=0.25, hspace=0.25)
        if Ncol == 1:
            ax = np.reshape(ax, (self.n, 1))
        elif Nrow == 1:
            ax = np.reshape(ax, (1, self.n))
        if xnames == "num":
            xnames = []
            for i in range(self.n):
                xnames += [r"state " + str(i + 1)]
        for row in range(Nrow):
            for col in range(Ncol):
                i = Ncol * row + col
                if i + 1 <= self.n:
                    ax[row, col].plot(this, xhis[:, i])
                    ax[row, col].plot(this, x2his[:, i])
                    ax[row, col].set_xlabel(r"time", fontsize=FontSize)
                    LabelName = r"tracking error: " + xnames[i]
                    ax[row, col].set_ylabel(LabelName, fontsize=FontSize)
                    ax[row, col].legend([r"NCM", r"SDRE"], loc="best")
        fig.suptitle(tit4, fontsize=FontSize)
        plt.show()
        print("========================================================")
        print(bNam5)
        print("========================================================")
        matplotlib.rcParams.update({"font.size": 15})
        matplotlib.rc("text", usetex=True)
        plt.figure()
        plt.plot(this, uehis)
        plt.plot(this, ue2his)
        plt.xlabel(r"time", fontsize=FontSize)
        plt.ylabel(lyc, fontsize=FontSize)
        plt.legend([r"NCM", r"SDRE"], loc="best")
        plt.title(tit5, fontsize=FontSize)
        plt.show()
        print("========================================================")
        print("==================== SIMULATIOM END ====================")
        print("========================================================")
        return this, xhis, zhis
示例#20
0
    def simulation(self,dt,tf,x0,z0=None,dscale=10.0,xnames="num",Ncol=1,\
                   FigSize=(20,10),FontSize=20,phis=None):
        """
        Perform NCM-based estimation or control of given nolinear dynamical
        systems and return simulation results
        

        Parameters
        ----------
        dt : float
            simulation time step
        tf : float
            terminal time
        x0 : ndarray - (n, )
            initial state
        z0 : ndarray - (n, ), to be used for iEC = "est"
            estimated initial state
        dscale : float, optional, default is 10
            scale of external disturbance 
        xnames : str, optional, default is "num"
            list containing names of each state, when xnames = "num", they are
            denoted as xnames = ["state 1","state 2",...]
        Ncol : int, optional, default is 1
            # columns of state figures to be generated
        FigSize : tuple, optional, default is (20,10)
            size of state figures to be generated
        FontSize : float, optional, default is 20
            font size of figures to be generated
        phis : system parameter history, optional, default is None
            history of system parameters

        Returns
        -------
        this : ndarray - (int(tf/dt)+1, )
            time histry 
        xhis : ndarray - (int(tf/dt)+1,n)
            state history
        zhis : ndarray - (int(tf/dt)+1,n), to be used for estimation tasks
            estimated state history

        """
        """
        
        
        1) SIMULATION
    
        
        """
        print("========================================================")
        print("====================== SIMULATIOM ======================")
        print("========================================================")
        if dt <= self.dt_rk:
            self.dt_rk = dt
        self.Nrk = int(dt / self.dt_rk)
        Nsim = int(tf / dt)
        np.set_printoptions(precision=1)
        print("time step =", dt)
        print("terminal time =", tf)
        print("initial state =", x0)
        if self.iEC == "est":
            print("estimated initial state =", z0)
            funx = lambda x, p, u: self.dynamicsf(x, p)
            funz = self.dynamics
            z = z0
            zhis = np.zeros((Nsim + 1, self.n))
            zhis[0, :] = z
            tit1 = "Performance of NCM-based Estimation (1)"
            tit2 = "Performance of NCM-based Estimation (2)"
            ly = r"estimation error: $\|x-\hat{x}\|_2$"
            l1 = r"estimation error"
            bNam1 = "=================== ESTIMATION ERROR ==================="
            bNam2 = "============ ESTIMATION ERROR OF EACH STATE ============"
        elif self.iEC == "con":
            funx = self.dynamics
            zhis = np.zeros((Nsim + 1, self.n))
            tit1 = "Performance of NCM-based Control (1)"
            tit2 = "Performance of NCM-based Control (2)"
            ly = r"tracking error: $\|x-x_d\|_2$"
            l1 = r"tracking error"
            bNam1 = "==================== TRACKING ERROR ===================="
            bNam2 = "============= TRACKING ERROR OF EACH STATE ============="
        else:
            raise ValueError('Invalid iEC: iEC = "est" or "con"')
        l2 = r"optimal steady-state upper bound"
        x = x0
        xhis = np.zeros((Nsim + 1, self.n))
        xhis[0, :] = x
        this = np.linspace(0, tf, Nsim + 1)
        if phis == None:
            phis = np.linspace(self.plims[0, :], self.plims[1, :], Nsim)
        if (self.iEC == "est") and (len(sig(self.Cfun).parameters) == 1):
            fun1 = self.Cfun
            self.Cfun = lambda x, p: fun1(x)
        if (len(sig(self.Bw).parameters) == 1):
            fun2 = self.Bw
            self.Bw = lambda x, p: fun2(x)
        if (self.iEC == "est") and (len(sig(self.Gw).parameters) == 1):
            fun3 = self.Gw
            self.Gw = lambda x, p: fun3(x)
        for k in range(Nsim):
            p = phis[k, :]
            if self.iEC == "est":
                Mx = self.ncm(z, p)
                Cx = self.Cfun(z, p)
                Lx = Mx @ Cx.T
                d2 = self.unifrand2(self.d2_over, np.size(self.Gw(x, p),
                                                          1)) * dscale
                y = self.h_or_g(x, p) + self.Gw(x, p) @ d2
                dEf = lambda z, p: Lx @ (y - self.h_or_g(z, p))
                z = self.rk4(z, p, dEf, funz)
                zhis[k + 1, :] = z
            elif self.iEC == "con":
                Mx = self.ncm(x, p)
                Bx = self.h_or_g(x, p)
                Kx = Bx.T @ Mx
                u = -Kx @ x
                dEf = lambda x, p: self.h_or_g(x, p) @ u
            else:
                raise ValueError('Invalid iEC: iEC = "est" or "con"')
            d1 = self.unifrand2(self.d1_over, np.size(self.Bw(x, p),
                                                      1)) * dscale
            x = self.rk4(x, p, dEf, funx) + self.Bw(x, p) @ d1 * dt
            xhis[k + 1, :] = x
        """
        
        
        2) FIGURE GENERATION
    
        
        """
        print("========================================================")
        print(bNam1)
        print("========================================================")
        matplotlib.rcParams.update({"font.size": 15})
        matplotlib.rc("text", usetex=True)
        plt.figure()
        plt.plot(this, np.sqrt(np.sum((xhis - zhis)**2, 1)))
        plt.plot(this, np.ones(np.size(this)) * self.Jcv_opt)
        plt.xlabel(r"time", fontsize=FontSize)
        plt.ylabel(ly, fontsize=FontSize)
        plt.legend([l1, l2], loc="best")
        plt.title(tit1, fontsize=FontSize)
        plt.show()
        print("========================================================")
        print(bNam2)
        print("========================================================")
        Nrow = int(self.n / Ncol) + np.remainder(self.n, Ncol)
        fig, ax = plt.subplots(Nrow, Ncol, figsize=FigSize)
        plt.subplots_adjust(wspace=0.25, hspace=0.25)
        if Ncol == 1:
            ax = np.reshape(ax, (self.n, 1))
        elif Nrow == 1:
            ax = np.reshape(ax, (1, self.n))
        if xnames == "num":
            xnames = []
            for i in range(self.n):
                xnames += [r"state " + str(i + 1)]
        for row in range(Nrow):
            for col in range(Ncol):
                i = Ncol * row + col
                if i + 1 <= self.n:
                    ax[row, col].plot(this, xhis[:, i] - zhis[:, i])
                    ax[row, col].set_xlabel(r"time", fontsize=FontSize)
                    if self.iEC == "est":
                        LabelName = r"estimation error: " + xnames[i]
                    elif self.iEC == "con":
                        LabelName = r"tracking error: " + xnames[i]
                    else:
                        txterr = 'Invalid iEC: iEC = "est" or "con"'
                        raise ValueError(txterr)
                    ax[row, col].set_ylabel(LabelName, fontsize=FontSize)
        fig.suptitle(tit2, fontsize=FontSize)
        plt.show()
        print("========================================================")
        print("==================== SIMULATIOM END ====================")
        print("========================================================")
        return this, xhis, zhis
示例#21
0
    def cvstem0(self, xs, ps, alp):
        """
        Run one single instance of CV-STEM algorithm for given states xs and
        contraction rate alpha


        Parameters
        ----------
        xs : ndarray - (Ncv,n), where Ncv is # state samples
            state samples for solving CV-STEM
        ps : ndarray - (Ncv,n_p), where Ncv is # state samples
            system parameter samples for solving CV-STEM
        alp : float
            contraction rate of interest

        Objects to be updated
        -------
        Ws : list of length Ncv
            list containing inverse of n by n optimal contraction metrics
            in current instance of CV-STEM
        chi : numpy.float64
            optimal upper bound of condition number of contraction metrics
            in current instance of CV-STEM
        nu : numpy.float64
            optimal upper bound of induced 2-norm of contraction metrics
            in current instance of CV-STEM
        Jcv : numpy.float64
            optimal steady-state upper bound of estimation or tracking error
            in current instance of CV-STEM
        cvx_status : str
            problem status of CV-STEM, "optimal", "infeasible", "unbounded",
            "infeasible_inaccurate", or "unbounded_inaccurate"

        """
        epsilon = self.epsilon
        Ncv = np.size(xs, 0)
        n = self.n
        I = np.identity(n)
        Ws = []
        for k in range(Ncv):
            Ws.append(cp.Variable((n, n), PSD=True))
        nu = cp.Variable(nonneg=True)
        chi = cp.Variable(nonneg=True)
        errtxt = "https://github.com/AstroHiro/ncm#troubleshooting"
        if len(sig(self.Afun).parameters) == 1:
            fun1 = self.Afun
            self.Afun = lambda x, p: fun1(x)
        if (self.iEC == "est") and (len(sig(self.Cfun).parameters) == 1):
            fun2 = self.Cfun
            self.Cfun = lambda x, p: fun2(x)
        if self.iEC == "est":
            Af = self.Afun
            Cf = self.Cfun
            J = (self.d1_over*self.b_over*chi\
                 +self.d2_over*self.c_over*self.g_over*nu)/alp
            print(self.d1_over * self.b_over / alp)
            print(self.d2_over * self.c_over * self.g_over / alp)
        elif self.iEC == "con":
            Af = lambda x, p: self.Afun(x, p).T
            Cf = lambda x, p: self.h_or_g(x, p).T
            J = self.d1_over * self.b_over * chi / alp + self.d2_over * nu
        else:
            raise ValueError('Invalid iEC: iEC = "est" or "con"')
        constraints = []
        for k in range(Ncv):
            x = xs[k, :]
            p = ps[k, :]
            Ax = Af(x, p)
            Cx = Cf(x, p)
            W = Ws[k]
            constraints += [chi * I - W >> 0, W - I >> 0]
            constraints += [-2*alp*W-((W-I)/self.dt+W@Ax+Ax.T@W-2*nu*Cx.T@Cx)\
                            >> epsilon*I]
        prob = cp.Problem(cp.Minimize(J), constraints)
        prob.solve(solver=cp.MOSEK)
        cvx_status = prob.status
        if cvx_status in ["infeasible", "infeasible_inaccurate"]:
            raise ValueError("Problem infeasible: see " + errtxt)
        elif cvx_status in ["unbounded", "unbounded_inaccurate"]:
            raise ValueError("Problem unbounded: " + errtxt)
        Wsout = []
        for k in range(Ncv):
            Wk = Ws[k].value / nu.value
            Wsout.append(Wk)
        self.Ws = Wsout
        self.nu = nu.value
        self.chi = chi.value
        self.Jcv = prob.value
        self.cvx_status = cvx_status
        pass
示例#22
0
    def __init__(self,dt,dynamicsf,h_or_g,xlims,alims,iEC,fname,d1_over=0.1,\
                 d2_over=0.1,da=0.1,Nx=1000,Nls=100,plims=np.empty((2,0))):
        """
        This class provides several objects and methods for designing a Neural 
        Contraction Metric (NCM) of a given nonliner dynamical system both for
        state estimation and feedback control.
        See the NCM paper https://arxiv.org/abs/2006.04361 and
        the CV-STEM paper https://arxiv.org/abs/2006.04359 for more details.
        See https://github.com/AstroHiro/ncm/wiki/Documentation for the
        documentation of this class file.
        
        
        Parameters
        (let n: state dimension and m: measurement or control input dimension)
        ----------
        dt : float
            discrete sampling period of CV-STEM
        dynamicsf : function - ndarray (n,n_p) -> (n, )
            vector field of given dynamical system 
            (i.e. f of dx/dt = f(x) or dx/dt = f(x)+g(x)u)
        h_or_g : function - ndarray (n,n_p) -> (m, ) for h, -> (n,m) for g
            measurement equation h or actuation matrix g
            (i.e. h of y = h(x,p) or g of dx/dt  = f(x,p)+g(x,p)u)
        xlims : ndarray - (2,n)
            lower and upper buonds of eash state
            (i.e. xlims[0,:]: lower bounds, xlims[1,:]: upper bounds)
        alims : ndarray - (2, )
            lower and upper bound of contraction rate alpha
            (i.e. alims[0]: lower bound, alims[0]: upper bound)
        iEC : str
            iEC = "est" for estimation and = "con" for control
        fname : str
            file name of your choice for storing NCM models and parameters
        d1_over : float, optional, default is 0.1
            upper bound of process noise
            (i.e. d1_over or d_over in the NCM paper)
        d2_over : float, optional, default is 0.1
            upper bound of measurement noise or penalty on feedback gains
            (i.e. d2_over or lambda in in the NCM paper)
        da : float, optional, default is 0.1
            step size of contraction rate alpha for line search in CV-STEM
        Nx : int, optional, default is 1000
            # samples of CV-STEM to be used for NCM training 
        Nls : int, optional, default is 100
            # samples to be used for line search in CV-STEM
        plims : ndarray - (2,n_p), default is np.empty((2,0))
            lower and upper bound of system parameters
            (i.e. plims[0,:]: lower bounds, plims[0,:]: upper bounds)

        Any other objects to be updated
        -------
        n : int
            state dimension
        m : int
            measurement or control input dimension
        n_p : int
            system parameter dimension
        Afun : function - ndarray (n,n_p) -> (n,n)
            Jacobian of dynamicsf (can be set to state-dependent coefficient
            matrix A s.t. f(x) = A(x)x, see the CV-STEM paper for details)
        Cfun : function - ndarray (n,n_p) -> (n,m), to be used for iEC = "est"
            Jacobian of measurement equation h (can be set to C s.t. 
            h(x) = C(x)x, see the CV-STEM paper for details)
        Bw : function - ndarray (n,n_p) -> (n,k1)
            B(x) given in equation (9) or B_2(x) in equation (17) of the NCM
            paper (B(x) = I and B_2(x) = g(x) are used by default, where g(x)
            is actuation matrix)
        Gw : function - ndarray (n,n_p) -> (m,k2), to be used for iEC = "est"
            G(x) given in equation (9) of the NCM paper (G(x) = I is used by
            default)
        c_over : numpy.float64, to be used for iEC = "est"
            approximate upper bound of Cfun(x) in given state space
        b_over : numpy.float64
            approximate upper bound of Bw(x) in given state space
        g_over : numpy.float64, to be used for iEC = "est"
            approximate upper bound of Gw(x) in given state space
        model : keras neural net model - ndarray (k,n) -> (k,int(n*(n+1)/2))
            function that returns cholesky-decomposed approximate optimal
            contraction metrics (i.e. NCMs) for given k states
        alp_opt : float
            optimal contraction rate
        chi_opt : numpy.float64
            optimal upper bound of condition number of contraction metrics
        nu_opt : numpy.float64
            optimal upper bound of induced 2-norm of contraction metrics
        Jcv_opt : numpy.float64
            optimal steady-state upper bound of estimation or tracking error
        xs_opt : ndarray - (Nx,n)
            randomized state samples
        Ws_opt : list of length Nx
            list containing inverse of ndarray (n,n) optimal contraction
            metrics sampled by CV-STEM
        Ms_opt : list of length Nx
            list containing ndarray (n,n) optimal contraction metrics sampled
            by CV-STEM
        cholMs : list of length Nx
            list containing ndarray (int(n*(n+1)/2), ) optimal contraction 
            metrics sampled by CV-STEM
        Ws : list of length Ncv
            list containing inverse of n by n optimal contraction metrics
            in current instance of CV-STEM
        chi : numpy.float64
            optimal upper bound of condition number of contraction metrics
            in current instance of CV-STEM
        nu : numpy.float64
            optimal upper bound of induced 2-norm of contraction metrics
            in current instance of CV-STEM
        Jcv : numpy.float64
            optimal steady-state upper bound of estimation or tracking error
            in current instance of CV-STEM
        cvx_status : str
            problem status of CV-STEM, "optimal", "infeasible", "unbounded",
            "infeasible_inaccurate", or "unbounded_inaccurate"
        epsilon : float, default is 0.0
            non-negative constant introduced to relax stability condition
        dt_rk : float, default is 0.01
            time step of numerical integration 
            
        """
        self.dt = dt
        if (len(sig(dynamicsf).parameters) == 1):
            self.dynamicsf = lambda x, p: dynamicsf(x)
        else:
            self.dynamicsf = dynamicsf
        if (len(sig(h_or_g).parameters) == 1):
            self.h_or_g = lambda x, p: h_or_g(x)
        else:
            self.h_or_g = h_or_g
        self.xlims = xlims
        self.alims = alims
        self.iEC = iEC
        self.fname = fname
        self.d1_over = d1_over
        self.d2_over = d2_over
        self.da = da
        self.Nx = Nx
        self.Nls = Nls
        self.n = np.size(xlims, 1)
        self.m = np.size(self.h_or_g(xlims[0, :], plims[0, :]).T, 0)
        self.n_p = np.size(plims, 1)
        self.Afun = lambda x, p: self.jacobian(x, p, self.dynamicsf)
        if self.iEC == "est":
            self.Cfun = lambda x, p: self.jacobian(x, p, self.h_or_g)
            self.Bw = lambda x, p: np.identity(self.n)
            self.Gw = lambda x, p: np.identity(self.m)
        elif self.iEC == "con":
            self.Bw = self.h_or_g
        else:
            raise ValueError('Invalid iEC: iEC = "est" or "con"')
        self.epsilon = 0
        self.dt_rk = 0.01
        self.plims = plims
示例#23
0
    def cvstem(self):
        """        
        Sample optimal contraction metrics by CV-STEM for constructing NCM


        Objects to be updated
        -------
        c_over : numpy.float64, to be used for iEC = "est"
            Approximate upper bound of Cfun(x) in given state space
        b_over : numpy.float64
            Approximate upper bound of Bw(x) in given state space
        g_over : numpy.float64, to be used for iEC = "est"
            Approximate upper bound of Gw(x) in given state space
        xs_opt : ndarray - (Nx,n), where Nx is # samples to be used for NCM
            randomized state samples
        Ws_opt : list of length Nx
            list containing inverse of ndarray (n,n) optimal contraction
            metrics
        chi_opt : numpy.float64
            optimal upper bound of condition number of contraction metrics
        nu_opt : numpy.float64
            optimal upper bound of induced 2-norm of contraction metrics
        Jcv_opt : numpy.float64
            optimal steady-state upper bound of estimation or tracking error
        
        """
        if (self.iEC == "est") and (len(sig(self.Cfun).parameters) == 1):
            fun1 = self.Cfun
            self.Cfun = lambda x, p: fun1(x)
        if (self.iEC == "est") and (len(sig(self.Gw).parameters) == 1):
            fun2 = self.Gw
            self.Gw = lambda x, p: fun2(x)
        if self.iEC == "est":
            self.c_over = self.matrix_2bound(self.Cfun)
            self.g_over = self.matrix_2bound(self.Gw)
        if (len(sig(self.Bw).parameters) == 1):
            fun3 = self.Bw
            self.Bw = lambda x, p: fun3(x)
        self.b_over = self.matrix_2bound(self.Bw)
        self.linesearch()
        alp = self.alp_opt
        Nx = self.Nx
        Nsplit = 1
        Np = int(Nx / Nsplit)
        Nr = np.remainder(Nx, Nsplit)
        xpmin = np.hstack((self.xlims[0, :], self.plims[0, :]))
        xpmax = np.hstack((self.xlims[1, :], self.plims[1, :]))
        Nxp = self.n + self.n_p
        xps = np.random.uniform(xpmin, xpmax, size=(Nx, Nxp))
        xs_opt, ps_opt, _ = np.hsplit(xps, np.array([self.n, Nxp]))
        Ws_opt = []
        chi_opt = 0
        nu_opt = 0
        print("========================================================")
        print("====== SAMPLING OF CONTRACTION METRICS BY CV-STEM ======")
        print("========================================================")
        for p in range(Np):
            if np.remainder(p, int(Np / 10)) == 0:
                print("# sampled metrics: ", p * Nsplit, "...")
            xs_p = xs_opt[Nsplit * p:Nsplit * (p + 1), :]
            ps_p = ps_opt[Nsplit * p:Nsplit * (p + 1), :]
            self.cvstem0(xs_p, ps_p, alp)
            Ws_opt += self.Ws
            if self.nu >= nu_opt:
                nu_opt = self.nu
            if self.chi >= chi_opt:
                chi_opt = self.chi
        if Nr != 0:
            print("# samples metrics: ", Nx, "...")
            xs_p = xs_opt[Nsplit * (p + 1):Nx, :]
            ps_p = ps_opt[Nsplit * (p + 1):Nx, :]
            self.cvstem0(xs_p, ps_p, alp)
            Ws_opt += self.Ws
            if self.nu >= nu_opt:
                nu_opt = self.nu
            if self.chi >= chi_opt:
                chi_opt = self.chi
        self.xs_opt = xs_opt
        self.ps_opt = ps_opt
        self.Ws_opt = Ws_opt
        self.chi_opt = chi_opt
        self.nu_opt = nu_opt
        if self.iEC == "est":
            self.Jcv_opt = (self.d1_over*self.b_over*np.sqrt(chi_opt)\
                            +self.d2_over*self.c_over*self.g_over*nu_opt)/alp
            print("Optimal steady-state estimation error =",\
                  "{:.2f}".format(self.Jcv_opt))
        elif self.iEC == "con":
            self.Jcv_opt = self.d1_over * self.b_over * np.sqrt(chi_opt) / alp
            print("Optimal steady-state tracking error =",\
                  "{:.2f}".format(self.Jcv_opt))
        else:
            raise ValueError('Invalid iEC: iEC = "est" or "con"')
        self.M2cholM()
        path = "models/optvals/" + self.fname
        if os.path.exists(path) == False:
            try:
                os.makedirs(path)
            except:
                raise OSError("Creation of directory %s failed" % path)
            else:
                print("Successfully created directory %s " % path)
        else:
            print("Directory %s already exists" % path)
        np.save(path + "/alp_opt.npy", alp)
        np.save(path + "/chi_opt.npy", self.chi_opt)
        np.save(path + "/nu_opt.npy", self.nu_opt)
        np.save(path + "/Jcv_opt.npy", self.Jcv_opt)
        print("========================================================")
        print("==== SAMPLING OF CONTRACTION METRICS BY CV-STEM END ====")
        print("========================================================\n\n")
        pass
示例#24
0
def equals(a, b):
    "Compares `a` and `b` for equality; supports sublists, tensors and arrays too"
    cmp = (torch.equal if isinstance(a, Tensor) and a.dim() else
           np.array_equal if isinstance(a, ndarray) else operator.eq
           if isinstance(a, str) else all_equal if is_iter(a) else operator.eq)
    return cmp(a, b)


# my own inspection helpers
from inspect import getdoc as doc, getsourcelines as source, getmodule as module, signature as sig, getmembers as member, getmro as clstree


def clstree(a):
    return getmro(a)


def dr(a):
    return a.__dir__()


def dt(a):
    return a.__dict__


doc(DataLoader)
sig(DataLoader)
source(DataLoader)
module(DataLoader)
member(DataLoader)
示例#25
0
文件: decorate.py 项目: bskinn/opan
        def wrapped_f(*args, **kwargs):

            # Check for if the target kwarg is missing
            if self.kw not in kwargs:
                # Missing. Must fetch.

                # Retrieve and materialize the enumerated arguments list.
                # Depends on the parameters being contained in an OrderedDict
                # so that signature order is retained.
                params = list(sig(f).parameters)

                # Initialize as empty the arguments list to pass to the
                # callable
                fetch_args = []

                # Populate fetch_args sequentially in the order specified by
                # the particular decorator constructor
                for a in self.arglist:
                    # Simple type checks on the argument specifiers
                    # should suffice since they were checked at
                    # construction.
                    if isinstance(a, str):
                        # Keyword argument; handle possible absence with get()
                        fetch_args.append(kwargs.get(a))
                    else:
                        # Integer argument for (optional-)positional args.
                        # Could be present as positional or as keyword,
                        # or could be absent.
                        if len(args) > a:
                            # Sufficient positional arguments; assume
                            # present and passed as optional-positional
                            fetch_args.append(args[a])
                        else:
                            # The **kwargs is not valid for this, so exclude
                            pname = params[:-1][a]
                            if pname in kwargs:
                                # Present in the passed-in kwargs
                                fetch_args.append(kwargs[pname])
                            else:
                                # Not found; pass the function default
                                fetch_args.append(
                                    sig(f).parameters[pname].default)

                # Populate fetch_kwargs according to what was specified
                # at decorator construction
                fetch_kwargs = {}
                for item in self.kwarglist.items():
                    # Same as above -- simple type checks should suffice
                    if isinstance(item[1], str):
                        # Keyword argument; handle possible absence with get()
                        fetch_kwargs.update({item[0]: kwargs.get(item[1])})
                    else:
                        # Optional-positional
                        if len(args) > item[1]:
                            # Sufficient positional args
                            fetch_kwargs.update({item[0]: args[item[1]]})
                        else:
                            # The **kwargs is not valid for this, so exclude
                            pname = params[:-1][item[1]]
                            if pname in kwargs:
                                # Insufficient positional; add from kwargs
                                # if present
                                fetch_kwargs.update({item[0]: kwargs[pname]})
                            else:
                                # Not found; store the function default
                                fetch_kwargs.update({
                                    item[0]:
                                    sig(f).parameters[pname].default
                                })

                # Call the callable and store the result into the target
                # keyword
                c_result = self.c(*fetch_args, **fetch_kwargs)
                kwargs.update({self.kw: c_result})

            # Whether the target kwarg was present or generated/injected,
            # call the wrapped function
            return f(*args, **kwargs)
示例#26
0
def isnullary(method):
    return callable(method) and len(sig(method).parameters) == 0