@@ -396,7 +396,10 @@ def compute_group(self, group_name: str, update_history: bool = False) -> torch.
396396 # apply post-processing
397397 if term_cfg .modifiers is not None :
398398 for modifier in term_cfg .modifiers :
399- obs = modifier .func (obs , ** modifier .params )
399+ if isinstance (modifier , modifiers .ModifierBaseCfg ):
400+ obs = modifier .func (obs )
401+ else :
402+ obs = modifier .func (obs , ** modifier .params )
400403 if isinstance (term_cfg .noise , noise .NoiseCfg ):
401404 obs = term_cfg .noise .func (obs , term_cfg .noise )
402405 elif isinstance (term_cfg .noise , noise .NoiseModelCfg ) and term_cfg .noise .func is not None :
@@ -577,52 +580,8 @@ def _prepare_terms(self):
577580
578581 # prepare modifiers for each observation
579582 if term_cfg .modifiers is not None :
580- # initialize list of modifiers for term
581583 for mod_cfg in term_cfg .modifiers :
582- # check if class modifier and initialize with observation size when adding
583- if isinstance (mod_cfg , modifiers .ModifierCfg ):
584- # to list of modifiers - instantiate class-based modifiers
585- if inspect .isclass (mod_cfg .func ):
586- mod_cfg .func = mod_cfg .func (cfg = mod_cfg , data_dim = obs_dims , device = self ._env .device )
587- # verify the instance is the correct type
588- if not isinstance (mod_cfg .func , modifiers .ModifierBase ):
589- raise TypeError (
590- f"Modifier function '{ mod_cfg .func } ' for observation term '{ term_name } '"
591- f" is not an instance of 'ModifierBase'. Received: '{ type (mod_cfg .func )} '."
592- )
593- # add to list of class modifiers
594- self ._group_obs_class_instances .append (mod_cfg .func )
595- else :
596- raise TypeError (
597- f"Modifier configuration '{ mod_cfg } ' of observation term '{ term_name } ' is not of"
598- f" required type ModifierCfg, Received: '{ type (mod_cfg )} '"
599- )
600-
601- # check if function is callable
602- if not callable (mod_cfg .func ):
603- raise AttributeError (
604- f"Modifier '{ mod_cfg } ' of observation term '{ term_name } ' is not callable."
605- f" Received: { mod_cfg .func } "
606- )
607-
608- # TODO(jichuanh): improvement can be made in two ways:
609- # 1. modifier specific check can be done in the modifier class
610- # 2. general param vs function matching check can be a common utility
611- # check if term's arguments are matched by params
612- term_params = list (mod_cfg .params .keys ())
613- args = inspect .signature (mod_cfg .func ).parameters
614- args_with_defaults = [arg for arg in args if args [arg ].default is not inspect .Parameter .empty ]
615- args_without_defaults = [arg for arg in args if args [arg ].default is inspect .Parameter .empty ]
616- args = args_without_defaults + args_with_defaults
617- # ignore first two arguments for env and env_ids
618- # Think: Check for cases when kwargs are set inside the function?
619- if len (args ) > 1 :
620- if set (args [1 :]) != set (term_params + args_with_defaults ):
621- raise ValueError (
622- f"Modifier '{ mod_cfg } ' of observation term '{ term_name } ' expects"
623- f" mandatory parameters: { args_without_defaults [1 :]} "
624- f" and optional parameters: { args_with_defaults } , but received: { term_params } ."
625- )
584+ self ._prepare_modifier (mod_cfg , term_name , obs_dims )
626585
627586 # prepare noise model classes
628587 if term_cfg .noise is not None and isinstance (term_cfg .noise , noise .NoiseModelCfg ):
@@ -659,3 +618,37 @@ def _prepare_terms(self):
659618 term_cfg .func .reset ()
660619 # add history buffers for each group
661620 self ._group_obs_term_history_buffer [group_name ] = group_entry_history_buffer
621+
622+ def _prepare_modifier (self , mod_cfg : modifiers .ModifierCfg , term_name : str , obs_dims : tuple [int , ...]) -> None :
623+ """Validate a modifier configuration and construct its stateful implementation."""
624+ if not isinstance (mod_cfg , modifiers .ModifierCfg ):
625+ raise TypeError (
626+ f"Modifier configuration '{ mod_cfg } ' of observation term '{ term_name } ' is not of"
627+ f" required type ModifierCfg, Received: '{ type (mod_cfg )} '"
628+ )
629+ if not callable (mod_cfg .func ):
630+ raise AttributeError (
631+ f"Modifier '{ mod_cfg } ' of observation term '{ term_name } ' is not callable. Received: { mod_cfg .func } "
632+ )
633+
634+ if isinstance (mod_cfg , modifiers .ModifierBaseCfg ):
635+ mod_cfg .func = mod_cfg .func (cfg = mod_cfg , data_dim = obs_dims , device = self ._env .device )
636+ if not isinstance (mod_cfg .func , modifiers .ModifierBase ):
637+ raise TypeError (
638+ f"Modifier function '{ mod_cfg .func } ' for observation term '{ term_name } ' is not an instance of"
639+ f" 'ModifierBase'. Received: '{ type (mod_cfg .func )} '."
640+ )
641+ self ._group_obs_class_instances .append (mod_cfg .func )
642+ return
643+
644+ term_params = list (mod_cfg .params .keys ())
645+ args = inspect .signature (mod_cfg .func ).parameters
646+ args_with_defaults = [arg for arg in args if args [arg ].default is not inspect .Parameter .empty ]
647+ args_without_defaults = [arg for arg in args if args [arg ].default is inspect .Parameter .empty ]
648+ args = args_without_defaults + args_with_defaults
649+ if len (args ) > 1 and set (args [1 :]) != set (term_params + args_with_defaults ):
650+ raise ValueError (
651+ f"Modifier '{ mod_cfg } ' of observation term '{ term_name } ' expects mandatory parameters:"
652+ f" { args_without_defaults [1 :]} and optional parameters: { args_with_defaults } , but received:"
653+ f" { term_params } ."
654+ )
0 commit comments