def __init__(self, robot, obs_nuisance=[], cmd_nuisance=[]): self.inner_robot_name = robot boot_config = get_boot_config() id_robot, self.robot = boot_config.robots.instance_smarter(robot) if not isinstance(self.robot, RobotInterface): msg = 'Expected RobotInterface, got %s' % describe_type(self.robot) raise ValueError(msg) warnings.warn('handle the case better') self.desc = ('EquivRobot(%s,obs:%s,cmd:%s)' % (id_robot, obs_nuisance, cmd_nuisance)) # convert to (possibly empty) list of strings if isinstance(obs_nuisance, str): obs_nuisance = [obs_nuisance] if isinstance(cmd_nuisance, str): cmd_nuisance = [cmd_nuisance] instance = lambda y: boot_config.nuisances.instance_smarter(y)[1] self.obs_nuisances = [instance(x) for x in obs_nuisance] self.cmd_nuisances = [instance(x) for x in cmd_nuisance] # No - we should not call inverse() before transform_spec() obs_spec = self.robot.get_spec().get_observations() for n in self.obs_nuisances: obs_spec = n.transform_spec(obs_spec) cmd_spec = self.robot.get_spec().get_commands() for n in self.cmd_nuisances: cmd_spec = n.transform_spec(cmd_spec) # We don't really need to compute this... try: self.cmd_nuisances_inv = [x.inverse() for x in self.cmd_nuisances] # now initialize in reverse cmd_spec_i = cmd_spec for n in reversed(self.cmd_nuisances_inv): cmd_spec_i = n.transform_spec(cmd_spec_i) StreamSpec.check_same_spec(cmd_spec_i, self.robot.get_spec().get_commands()) # TODO: why do we do this for commands, not for osbservations? except Exception as e: logger.warning('It seems that this chain of nuisances is not ' 'exact, but it could be OK to continue. ' ' The chain is %s; the error is:\n%s' % (cmd_nuisance, indent(str(e).strip(), '> '))) self.spec = BootSpec(obs_spec=obs_spec, cmd_spec=cmd_spec) self.obs_nuisances_id = obs_nuisance self.cmd_nuisances_id = cmd_nuisance
def check_conversions(stream_spec1, nuisance): # print('Checking %s / %s ' % (stream_spec1, nuisance)) nuisance_inv = None try: try: stream_spec2 = nuisance.transform_spec(stream_spec1) except UnsupportedSpec as e: logger.info('Skipping %s/%s because incompatible: %s' % (stream_spec1, nuisance, e)) return value1 = stream_spec1.get_random_value() stream_spec1.check_valid_value(value1) value2 = nuisance.transform_value(value1) stream_spec2.check_valid_value(value2) try: nuisance_inv = nuisance.inverse() except NuisanceNotInvertible as e: logger.info('Skipping some tests %s/%s because not invertible:' ' %s' % (stream_spec1, nuisance, e)) return try: stream_spec1b = nuisance_inv.transform_spec(stream_spec2) except UnsupportedSpec as e: msg = ('The inverse of the nuisance does not seem to be able ' 'to handle the result:\n%s\n\n' ' stream_spec1: %s\n' ' nuisance: %s\n' ' stream_spec2: %s\n' ' nuisance_inv: %s\n' % (indent(str(e), '>'), stream_spec1.to_yaml(), nuisance, stream_spec2.to_yaml(), nuisance_inv)) raise ValueError(msg) try: StreamSpec.check_same_spec(stream_spec1, stream_spec1b) except Exception as e: msg = ('The inverse of the nuisance does not recreate the ' 'initial spec:\n%s\n\n' ' stream_spec1: %s\n' ' nuisance: %s\n' ' stream_spec2: %s\n' ' nuisance_inv: %s\n' ' stream_spec1b: %s\n' % (indent(str(e), '>'), stream_spec1.to_yaml(), nuisance, stream_spec2.to_yaml(), nuisance_inv, stream_spec1b.to_yaml())) raise ValueError(msg) value1b = nuisance_inv.transform_value(value2) stream_spec1.check_valid_value(value1b) # TODO: if exact assert_allclose(value1, value1b, rtol=1e-5) except: logger.error('Error while testing:') logger.error(' stream_spec: %s ' % stream_spec1.to_yaml()) logger.error(' nuisance: %s' % nuisance) logger.error(' nuisance_inv: %s' % nuisance_inv) raise