def testEqualBroadcastingBounds(self): spec_1 = array_spec.BoundedArraySpec((1, 2), np.int32, minimum=0.0, maximum=1.0) spec_2 = array_spec.BoundedArraySpec((1, 2), np.int32, minimum=[0.0, 0.0], maximum=[1.0, 1.0]) self.assertEqual(spec_1, spec_2)
def testNotEqualDifferentMaximum(self): spec_1 = array_spec.BoundedArraySpec((1, 2), np.int32, minimum=0.0, maximum=2.0) spec_2 = array_spec.BoundedArraySpec((1, 2), np.int32, minimum=[0.0, 0.0], maximum=[1.0, 1.0]) self.assertNotEqual(spec_1, spec_2)
def testScalarBounds(self): spec = array_spec.BoundedArraySpec((), np.float, minimum=0.0, maximum=1.0) self.assertIsInstance(spec.minimum, np.ndarray) self.assertIsInstance(spec.maximum, np.ndarray) # Sanity check that numpy compares correctly to a scalar for an empty shape. self.assertEqual(0.0, spec.minimum) self.assertEqual(1.0, spec.maximum) # Check that the spec doesn't fail its own input validation. _ = array_spec.BoundedArraySpec( spec.shape, spec.dtype, spec.minimum, spec.maximum)
def setUp(self): env = mock.MagicMock(spec=environment.Base) env.action_spec.return_value = specs.BoundedArraySpec( (1, ), np.float64, -1, 1) self.runtime = runtime.Runtime(env, mock.MagicMock()) self.runtime._step = mock.MagicMock() self.runtime._step.return_value = False
def testValidateBounds(self): spec = array_spec.BoundedArraySpec((2, 2), np.int32, minimum=5, maximum=10) spec.validate(np.array([[5, 6], [8, 10]], dtype=np.int32)) with self.assertRaises(ValueError): spec.validate(np.array([[5, 6], [8, 11]], dtype=np.int32)) with self.assertRaises(ValueError): spec.validate(np.array([[4, 6], [8, 10]], dtype=np.int32))
def testIsUnhashable(self): spec = array_spec.BoundedArraySpec(shape=(1, 2), dtype=np.int32, minimum=0.0, maximum=2.0) with six.assertRaisesRegex(self, TypeError, "unhashable type"): hash(spec)
def _action_spec_from_action_space(action_space): if isinstance(action_space, gym.spaces.Box): spec = specs.BoundedArraySpec(shape=action_space.shape, dtype=action_space.dtype, minimum=action_space.low, maximum=action_space.high) elif isinstance(action_space, gym.spaces.Discrete): spec = specs.BoundedArraySpec(shape=(1, ), dtype=action_space.dtype, minimum=0, maximum=action_space.n) else: raise NotImplementedError(action_space) return spec
def testGenerateValue(self): spec = array_spec.BoundedArraySpec((2, 2), np.int32, minimum=5, maximum=10) test_value = spec.generate_value() spec.validate(test_value)
def testRepr(self): as_string = repr( array_spec.BoundedArraySpec((1, 2), np.int32, minimum=101.0, maximum=73.0)) self.assertIn("101", as_string) self.assertIn("73", as_string)
def setUp(self): env = mock.MagicMock() env.action_spec.return_value = specs.BoundedArraySpec( (1, ), np.float64, -1, 1) self.runtime = runtime.Runtime(env, mock.MagicMock()) self.runtime._start = mock.MagicMock() self.runtime.get_time = mock.MagicMock() self.runtime.get_time.return_value = 0 self.runtime._step_simulation = mock.MagicMock(return_value=False)
def setUp(self): env = mock.MagicMock(spec=environment.Base) env.action_spec.return_value = specs.BoundedArraySpec( (1, ), np.float64, -1, 1) self.runtime = runtime.Runtime(env, mock.MagicMock()) self.runtime._step_paused = mock.MagicMock() self.runtime._step = mock.MagicMock(return_value=True) self.runtime.get_time = mock.MagicMock(return_value=0) self.time_step = 1e-2
def setUp(self): self.observation = mock.MagicMock() self.env = mock.MagicMock(spec=environment.Base) self.env.physics = mock.MagicMock() self.env.step = mock.MagicMock() self.env.action_spec.return_value = specs.BoundedArraySpec( (1, ), np.float64, -1, 1) self.policy = mock.MagicMock() self.actions = mock.MagicMock() self.runtime = runtime.Runtime(self.env, self.policy)
def action_spec(self): minimum, maximum = zip(*[ a.ctrlrange if a.ctrlrange is not None else (-1., 1.) for a in self.actuators ]) return specs.BoundedArraySpec( shape=(len(self.actuators), ), dtype=np.float, minimum=minimum, maximum=maximum, name='\t'.join([actuator.name for actuator in self.actuators]))
def action_spec(physics): """Returns a `BoundedArraySpec` matching the `physics` actuators.""" num_actions = physics.model.nu is_limited = physics.model.actuator_ctrllimited.ravel().astype(np.bool) control_range = physics.model.actuator_ctrlrange minima = np.full(num_actions, fill_value=-np.inf, dtype=np.float) maxima = np.full(num_actions, fill_value=np.inf, dtype=np.float) minima[is_limited], maxima[is_limited] = control_range[is_limited].T return specs.BoundedArraySpec( shape=(num_actions,), dtype=np.float, minimum=minima, maximum=maxima)
class DefaultActionFromSpecTest(parameterized.TestCase): def assertNestedArraysEqual(self, expected, actual): """Asserts that two potentially nested structures of arrays are equal.""" if isinstance(expected, (list, tuple)): self.assertIsInstance(actual, (list, tuple)) self.assertLen(actual, len(expected)) for expected_item, actual_item in zip(expected, actual): self.assertNestedArraysEqual(expected_item, actual_item) else: np.testing.assert_array_equal(expected, actual) _SHAPE = (2, ) _DTYPE = np.float64 _ACTION = np.zeros(_SHAPE) _ACTION_SPEC = specs.BoundedArraySpec(_SHAPE, np.float64, -1, 1) @parameterized.named_parameters( ('single_array', _ACTION_SPEC, _ACTION), ('tuple', (_ACTION_SPEC, _ACTION_SPEC), (_ACTION, _ACTION)), ('list', [_ACTION_SPEC, _ACTION_SPEC], (_ACTION, _ACTION))) def test_action_structure(self, action_spec, expected_action): self.assertNestedArraysEqual(expected_action, runtime._get_default_action(action_spec)) @parameterized.named_parameters( ('closed', specs.BoundedArraySpec(_SHAPE, _DTYPE, minimum=1., maximum=2.), np.full(_SHAPE, fill_value=1.5, dtype=_DTYPE)), ('left_open', specs.BoundedArraySpec(_SHAPE, _DTYPE, minimum=-np.inf, maximum=2.), np.full(_SHAPE, fill_value=2., dtype=_DTYPE)), ('right_open', specs.BoundedArraySpec(_SHAPE, _DTYPE, minimum=1., maximum=np.inf), np.full(_SHAPE, fill_value=1., dtype=_DTYPE)), ('unbounded', specs.BoundedArraySpec( _SHAPE, _DTYPE, minimum=-np.inf, maximum=np.inf), np.full(_SHAPE, fill_value=0., dtype=_DTYPE))) def test_action_spec_interval(self, action_spec, expected_action): self.assertNestedArraysEqual(expected_action, runtime._get_default_action(action_spec))
def discount_spec(self): """Describes the discount returned by the environment. By default this is assumed to be a single float between 0 and 1. Returns: An `ArraySpec`, or a nested dict, list or tuple of `ArraySpec`s. """ return specs.BoundedArraySpec(shape=(), dtype=float, minimum=0., maximum=1., name='discount')
def testNotEqualOtherClass(self): spec_1 = array_spec.BoundedArraySpec( (1, 2), np.int32, minimum=[0.0, -0.6], maximum=[1.0, 1.0]) spec_2 = array_spec.ArraySpec((1, 2), np.int32) self.assertNotEqual(spec_1, spec_2) self.assertNotEqual(spec_2, spec_1) spec_2 = None self.assertNotEqual(spec_1, spec_2) self.assertNotEqual(spec_2, spec_1) spec_2 = () self.assertNotEqual(spec_1, spec_2) self.assertNotEqual(spec_2, spec_1)
def setUp(self): with mock.patch(application.__name__ + '.gui'): self.app = application.Application() self.app._viewer = mock.MagicMock() self.app._keyboard_action = mock.MagicMock() self.environment = mock.MagicMock(spec=environment.Base) self.environment.action_spec.return_value = specs.BoundedArraySpec( (1, ), np.float64, -1, 1) self.environment.physics = mock.MagicMock() self.app._environment = self.environment self.agent = mock.MagicMock() self.loader = lambda: self.environment
def action_spec(self, physics): """Returns an `BoundedArraySpec` matching the `Physics` actuators. BoundedArraySpec.name should contain a tab-separated list of actuator names. When overloading this method, non-MuJoCo actuators should be added to the top of the list when possible, as a matter of convention. Args: physics: used to query actuator names in the model. """ names = [ physics.model.id2name(i, 'actuator') or str(i) for i in range(physics.model.nu) ] action_spec = mujoco.action_spec(physics) return specs.BoundedArraySpec(shape=action_spec.shape, dtype=action_spec.dtype, minimum=action_spec.minimum, maximum=action_spec.maximum, name='\t'.join(names))
class DefaultActionFromSpecTest(parameterized.TestCase): def assertNestedArraysEqual(self, expected, actual): """Asserts that two potentially nested structures of arrays are equal.""" self.assertIs(type(actual), type(expected)) if isinstance(expected, (list, tuple)): self.assertIsInstance(actual, (list, tuple)) self.assertLen(actual, len(expected)) for expected_item, actual_item in zip(expected, actual): self.assertNestedArraysEqual(expected_item, actual_item) elif isinstance(expected, collections.MutableMapping): keys_type = list if isinstance(expected, collections.OrderedDict) else set self.assertEqual(keys_type(actual.keys()), keys_type(expected.keys())) for key, expected_value in six.iteritems(expected): self.assertNestedArraysEqual(actual[key], expected_value) else: np.testing.assert_array_equal(expected, actual) _SHAPE = (2,) _DTYPE = np.float64 _ACTION = np.zeros(_SHAPE) _ACTION_SPEC = specs.BoundedArraySpec(_SHAPE, np.float64, -1, 1) @parameterized.named_parameters( ('single_array', _ACTION_SPEC, _ACTION), ('tuple', (_ACTION_SPEC, _ACTION_SPEC), (_ACTION, _ACTION)), ('list', [_ACTION_SPEC, _ACTION_SPEC], (_ACTION, _ACTION)), ('dict', {'a': _ACTION_SPEC, 'b': _ACTION_SPEC}, {'a': _ACTION, 'b': _ACTION}), ('OrderedDict', collections.OrderedDict([('a', _ACTION_SPEC), ('b', _ACTION_SPEC)]), collections.OrderedDict([('a', _ACTION), ('b', _ACTION)])), ) def test_action_structure(self, action_spec, expected_action): self.assertNestedArraysEqual(expected_action, runtime._get_default_action(action_spec)) def test_ordered_dict_action_structure_with_bad_ordering(self): reversed_spec = collections.OrderedDict([('a', self._ACTION_SPEC), ('b', self._ACTION_SPEC)]) expected_action = collections.OrderedDict([('b', self._ACTION), ('a', self._ACTION)]) with six.assertRaisesRegex(self, AssertionError, r"Lists differ: \['a', 'b'\] != \['b', 'a'\]"): self.assertNestedArraysEqual(expected_action, runtime._get_default_action(reversed_spec)) @parameterized.named_parameters( ('closed', specs.BoundedArraySpec(_SHAPE, _DTYPE, minimum=1., maximum=2.), np.full(_SHAPE, fill_value=1.5, dtype=_DTYPE)), ('left_open', specs.BoundedArraySpec(_SHAPE, _DTYPE, minimum=-np.inf, maximum=2.), np.full(_SHAPE, fill_value=2., dtype=_DTYPE)), ('right_open', specs.BoundedArraySpec(_SHAPE, _DTYPE, minimum=1., maximum=np.inf), np.full(_SHAPE, fill_value=1., dtype=_DTYPE)), ('unbounded', specs.BoundedArraySpec(_SHAPE, _DTYPE, minimum=-np.inf, maximum=np.inf), np.full(_SHAPE, fill_value=0., dtype=_DTYPE))) def test_action_spec_interval(self, action_spec, expected_action): self.assertNestedArraysEqual(expected_action, runtime._get_default_action(action_spec))
def make_action_spec(self, lower=(-1., ), upper=(1., )): lower, upper = np.broadcast_arrays(lower, upper) return specs.BoundedArraySpec(shape=lower.shape, dtype=float, minimum=lower, maximum=upper)
def testNotWriteable(self): spec = array_spec.BoundedArraySpec((1, 2, 3), np.float32, 0, (5, 5, 5)) with six.assertRaisesRegex(self, ValueError, "read-only"): spec.minimum[0] = -1 with six.assertRaisesRegex(self, ValueError, "read-only"): spec.maximum[0] = 100
def testMinMaxAttributes(self): spec = array_spec.BoundedArraySpec((1, 2, 3), np.float32, 0, (5, 5, 5)) self.assertEqual(type(spec.minimum), np.ndarray) self.assertEqual(type(spec.maximum), np.ndarray)
def testInvalidMaximum(self): with six.assertRaisesRegex(self, ValueError, "not compatible"): array_spec.BoundedArraySpec((3, 5), np.uint8, 0, (1, 1, 1))
def __enter__(self): """Allows the environment to be used in a with-statement context.""" return self def __exit__(self, unused_exception_type, unused_exc_value, unused_traceback): """Allows the environment to be used in a with-statement context.""" self.close() # A `StepType` enum can be safely cast to an array that conforms to this spec. STEP_TYPE_SPEC = specs.BoundedArraySpec(shape=(), dtype=np.promote_types( np.min_scalar_type(min(StepType)), np.min_scalar_type(max(StepType))), minimum=min(StepType), maximum=max(StepType), name='step_type') def make_step_spec(environment): """Returns a `TimeStep` describing the return values of an environment. Args: environment: An instance of `Base`. Returns: A `TimeStep` namedtuple. Each field contains an `ArraySpec`, or a nested dict, list or tuple of `ArraySpec`s that describe the corresponding field in the return values of `environment.reset()` and `environment.step()`.
def testInvalidMinimum(self): with self.assertRaisesRegexp(ValueError, "not compatible"): array_spec.BoundedArraySpec((3, 5), np.uint8, (0, 0, 0), (1, 1))
from absl.testing import absltest from absl.testing import parameterized from dm_control.rl import control import mock import numpy as np from dm_control.rl import specs _CONSTANT_REWARD_VALUE = 1.0 _CONSTANT_OBSERVATION = {'observations': np.asarray(_CONSTANT_REWARD_VALUE)} _ACTION_SPEC = specs.BoundedArraySpec(shape=(1, ), dtype=np.float, minimum=0.0, maximum=1.0) _OBSERVATION_SPEC = {'observations': specs.ArraySpec(shape=(), dtype=np.float)} class EnvironmentTest(parameterized.TestCase): def setUp(self): self._task = mock.Mock(spec=control.Task) self._task.initialize_episode = mock.Mock() self._task.get_observation = mock.Mock( return_value=_CONSTANT_OBSERVATION) self._task.get_reward = mock.Mock(return_value=_CONSTANT_REWARD_VALUE) self._task.get_termination = mock.Mock(return_value=None) self._task.action_spec = mock.Mock(return_value=_ACTION_SPEC) self._task.observation_spec.side_effect = NotImplementedError()