def test_compile_probabilistic_normal_random_variable(self): mean = Expression(('number', 0.0)) var = Expression(('number', 1.0)) normal = Expression(('randomvar', ('Normal', (mean, var)))) expressions = [normal] self._test_random_variable_expressions(expressions)
def test_compile_probabilistic_gamma_random_variable(self): shape = Expression(('number', 5.0)) scale = Expression(('number', 1.0)) gamma = Expression(('randomvar', ('Gamma', (shape, scale)))) expressions = [gamma] self._test_random_variable_expressions(expressions)
def _compile_pvariable_expression(self, expr: Expression, scope: Dict[str, TensorFluent], **kwargs) -> TensorFluent: '''Compile a pvariable expression `expr` into a TensorFluent in the given `scope`. The resulting TensorFluent will have batch dimension given by `batch_size`. Args: expr (:obj:`rddl2tf.expr.Expression`): A RDDL pvariable expression. scope (Dict[str, :obj:`rddl2tf.core.fluent.TensorFluent`]): A fluent scope. kwargs: Additional keyword arguments. Returns: :obj:`rddl2tf.core.fluent.TensorFluent`: The compiled expression as a TensorFluent. ''' etype = expr.etype args = expr.args name = expr._pvar_to_name(args) if name not in scope: raise ValueError('Variable {} not in scope.'.format(name)) fluent = scope[name] scope = args[1] if args[1] is not None else [] if isinstance(fluent, TensorFluent): fluent = TensorFluent(fluent.tensor, scope, batch=fluent.batch) elif isinstance(fluent, tf.Tensor): fluent = TensorFluent(fluent, scope, batch=True) else: raise ValueError( 'Variable in scope must be TensorFluent-like: {}'.format( fluent)) return fluent
def test_gamma(compiler): if compiler.rddl.domain.name == "reservoir": shape_scope = compiler._get_reparameterization_shape_scope() shape = Expression(("pvar_expr", ("RAIN_SHAPE", ["?res"]))) scale = Expression(("pvar_expr", ("RAIN_SCALE", ["?res"]))) gamma = Expression(("randomvar", ("Gamma", (shape, scale)))) noise_lst = compiler._get_expression_reparameterization( gamma, shape_scope) assert isinstance(noise_lst, list) assert len(noise_lst) == 1 dist, shape = noise_lst[0] assert isinstance(dist, GAMMA) assert dist.batch_shape == (8, ) assert dist.event_shape == () assert shape == []
def p_expr(self, p): '''expr : pvar_expr | group_expr | function_expr | relational_expr | boolean_expr | quantifier_expr | numerical_expr | aggregation_expr | control_expr | randomvar_expr''' p[0] = Expression(p[1])
import pytest import tensorflow as tf from pyrddl.expr import Expression import rddlgym from rddl2tf.compilers import ReparameterizationCompiler from rddl2tf.core.fluent import TensorFluent from rddl2tf.core.fluentshape import TensorFluentShape NORMAL = tf.compat.v1.distributions.Normal GAMMA = tf.compat.v1.distributions.Gamma UNIFORM = tf.compat.v1.distributions.Uniform ZERO = Expression(("number", 0.0)) ONE = Expression(("number", 1.0)) TWO = Expression(("+", (ONE, ONE))) Z = Expression(("randomvar", ("Normal", (ZERO, ONE)))) MU = Expression(("pvar_expr", ("mu", ["?x"]))) SIGMA = Expression(("pvar_expr", ("sigma", ["?x"]))) X1 = Expression(("randomvar", ("Normal", (MU, ONE)))) X2 = Expression(("randomvar", ("Normal", (ZERO, SIGMA)))) X3 = Expression(("randomvar", ("Normal", (MU, SIGMA)))) X4 = Expression(("randomvar", ("Normal", (Z, ONE)))) X5 = Expression(("randomvar", ("Normal", (X1, ONE)))) X6 = Expression(("randomvar", ("Normal", (X1, SIGMA))))
def _get_reparameterization( self, expr: Expression, scope: ShapeScope, noise: NoiseList ) -> TensorFluentShape: etype = expr.etype args = expr.args if etype[0] == "constant": return TensorFluentShape([1], batch=False) elif etype[0] == "pvar": name = expr._pvar_to_name(args) if name not in scope: raise ValueError("Variable {} not in scope.".format(name)) shape = scope[name] return shape elif etype[0] == "randomvar": if etype[1] == "Normal": mean_shape = self._get_reparameterization(args[0], scope, noise) var_shape = self._get_reparameterization(args[1], scope, noise) shape = ReparameterizationCompiler._broadcast(mean_shape, var_shape) dist = tf.distributions.Normal(loc=0.0, scale=1.0) noise.append((dist, shape.as_list())) return shape elif etype[1] == "Exponential": rate_shape = self._get_reparameterization(args[0], scope, noise) dist = tf.distributions.Uniform(low=0.0, high=1.0) noise.append((dist, rate_shape.as_list())) return rate_shape elif etype[1] == "Gamma": for fluent in self.rddl.get_dependencies(expr): if fluent.is_state_fluent() or fluent.is_action_fluent(): raise ValueError( f"Expression is not an exogenous event: {expr}" ) shape = [] with self.graph.as_default(): scope = self._scope.non_fluents(self.non_fluents) shape_fluent = self._compile_expression(args[0], scope, noise=None) scale_fluent = self._compile_expression(args[1], scope, noise=None) concentration = shape_fluent.tensor rate = 1 / scale_fluent.tensor dist = tf.distributions.Gamma(concentration, rate) noise.append((dist, shape)) return shape elif etype[1] == "Uniform": low_shape = self._get_reparameterization(args[0], scope, noise) high_shape = self._get_reparameterization(args[1], scope, noise) shape = ReparameterizationCompiler._broadcast(low_shape, high_shape) dist = tf.distributions.Uniform(low=0.0, high=1.0) noise.append((dist, shape.as_list())) return shape elif etype[0] in ["arithmetic", "boolean", "relational"]: op1_shape = self._get_reparameterization(args[0], scope, noise) shape = op1_shape if len(args) > 1: op2_shape = self._get_reparameterization(args[1], scope, noise) shape = ReparameterizationCompiler._broadcast(op1_shape, op2_shape) return shape elif etype[0] == "func": op1_shape = self._get_reparameterization(args[0], scope, noise) shape = op1_shape if len(args) > 1: if len(args) == 2: op2_shape = self._get_reparameterization(args[1], scope, noise) shape = ReparameterizationCompiler._broadcast(op1_shape, op2_shape) else: raise ValueError("Invalid function:\n{}".format(expr)) return shape elif etype[0] == "control": if etype[1] == "if": condition_shape = self._get_reparameterization(args[0], scope, noise) true_case_shape = self._get_reparameterization(args[1], scope, noise) false_case_shape = self._get_reparameterization(args[2], scope, noise) shape = ReparameterizationCompiler._broadcast( condition_shape, true_case_shape ) shape = ReparameterizationCompiler._broadcast(shape, false_case_shape) return shape else: raise ValueError("Invalid control flow expression:\n{}".format(expr)) elif etype[0] == "aggregation": return self._get_reparameterization(args[-1], scope, noise) raise ValueError("Expression type unknown: {}".format(etype))
def name(self) -> str: '''Returns the CPF's pvariable name.''' return Expression._pvar_to_name(self.pvar[1])
def test_get_dependencies(rddl): if rddl.domain.name == 'reservoir': shape = Expression(('pvar_expr', ('RAIN_SHAPE', ['?res']))) scale = Expression(('pvar_expr', ('RAIN_SCALE', ['?res']))) gamma = Expression(('randomvar', ('Gamma', (shape, scale)))) deps = rddl.get_dependencies(gamma) assert isinstance(deps, set) assert len(deps) == 2 deps = set(map(lambda fluent: str(fluent), deps)) assert deps == {'RAIN_SCALE/1', 'RAIN_SHAPE/1'} elif rddl.domain.name == 'hvac_vav_fix': mean = Expression(('pvar_expr', ('TEMP_OUTSIDE_MEAN', ['?s']))) variance = Expression(('pvar_expr', ('TEMP_OUTSIDE_VARIANCE', ['?s']))) normal = Expression(('randomvar', ('Normal', (mean, variance)))) deps = rddl.get_dependencies(normal) assert isinstance(deps, set) assert len(deps) == 2 deps = set(map(lambda fluent: str(fluent), deps)) assert deps == {'TEMP_OUTSIDE_MEAN/1', 'TEMP_OUTSIDE_VARIANCE/1'} elif rddl.domain.name == 'Navigation': location = Expression(('pvar_expr', ('location', ['?l']))) move = Expression(('pvar_expr', ('move', ['?l']))) deceleration = Expression( ('prod', (('typed_var', ('?z', 'zone')), Expression(('pvar_expr', ('deceleration', ['?z'])))))) mean = Expression( ('+', (location, Expression(('*', (deceleration, move)))))) variance = Expression(('*', (Expression( ('pvar_expr', ('MOVE_VARIANCE_MULT', ['?l']))), move))) normal = Expression(('randomvar', ('Normal', (mean, variance)))) deps = rddl.get_dependencies(normal) assert isinstance(deps, set) assert len(deps) == 5 deps = set(map(lambda fluent: str(fluent), deps)) assert deps == { 'location/1', 'move/1', 'DECELERATION_ZONE_CENTER/2', 'DECELERATION_ZONE_DECAY/1', 'MOVE_VARIANCE_MULT/1' }
def _get_reparameterization(expr: Expression, scope: ShapeScope, noise: Noise) -> TensorFluentShape: etype = expr.etype args = expr.args if etype[0] == 'constant': return TensorFluentShape([1], batch=False) elif etype[0] == 'pvar': name = expr._pvar_to_name(args) if name not in scope: raise ValueError('Variable {} not in scope.'.format(name)) shape = scope[name] return shape elif etype[0] == 'randomvar': if etype[1] == 'Normal': mean_shape = _get_reparameterization(args[0], scope, noise) var_shape = _get_reparameterization(args[1], scope, noise) shape = _broadcast(mean_shape, var_shape) dist = tf.distributions.Normal(loc=0.0, scale=1.0) noise.append((dist, shape.as_list())) return shape elif etype[1] == 'Exponential': rate_shape = _get_reparameterization(args[0], scope, noise) dist = tf.distributions.Uniform(low=0.0, high=1.0) noise.append((dist, rate_shape.as_list())) return rate_shape elif etype[1] == 'Gamma': raise NotImplementedError elif etype[1] == 'Uniform': low_shape = _get_reparameterization(args[0], scope, noise) high_shape = _get_reparameterization(args[1], scope, noise) shape = _broadcast(low_shape, high_shape) dist = tf.distributions.Uniform(low=0.0, high=1.0) noise.append((dist, shape.as_list())) return shape elif etype[0] in ['arithmetic', 'boolean', 'relational']: op1_shape = _get_reparameterization(args[0], scope, noise) shape = op1_shape if len(args) > 1: op2_shape = _get_reparameterization(args[1], scope, noise) shape = _broadcast(op1_shape, op2_shape) return shape elif etype[0] == 'func': op1_shape = _get_reparameterization(args[0], scope, noise) shape = op1_shape if len(args) > 1: if len(args) == 2: op2_shape = _get_reparameterization(args[1], scope, noise) shape = _broadcast(op1_shape, op2_shape) else: raise ValueError('Invalid function:\n{}'.format(expr)) return shape elif etype[0] == 'control': if etype[1] == 'if': condition_shape = _get_reparameterization(args[0], scope, noise) true_case_shape = _get_reparameterization(args[1], scope, noise) false_case_shape = _get_reparameterization(args[2], scope, noise) shape = _broadcast(condition_shape, true_case_shape) shape = _broadcast(shape, false_case_shape) return shape else: raise ValueError( 'Invalid control flow expression:\n{}'.format(expr)) elif etype[0] == 'aggregation': return _get_reparameterization(args[-1], scope, noise) raise ValueError('Expression type unknown: {}'.format(etype))
def p_case_expr(self, p): '''case_expr : penum_expr | pvar_expr | numerical_expr''' p[0] = Expression(p[1])
def p_term(self, p): '''term : VAR | ENUM_VAL | pvar_expr''' p[0] = Expression(p[1]) if isinstance( p[1], tuple) and p[1][0] == 'pvar_expr' else p[1]
def setUpClass(cls): cls.zero = Expression(('number', 0.0)) cls.one = Expression(('number', 1.0)) cls.two = Expression(('+', (cls.one, cls.one))) cls.z = Expression(('randomvar', ('Normal', (cls.zero, cls.one)))) cls.mu = Expression(('pvar_expr', ('mu', ['?x']))) cls.sigma = Expression(('pvar_expr', ('sigma', ['?x']))) cls.x1 = Expression(('randomvar', ('Normal', (cls.mu, cls.one)))) cls.x2 = Expression(('randomvar', ('Normal', (cls.zero, cls.sigma)))) cls.x3 = Expression(('randomvar', ('Normal', (cls.mu, cls.sigma)))) cls.x4 = Expression(('randomvar', ('Normal', (cls.z, cls.one)))) cls.x5 = Expression(('randomvar', ('Normal', (cls.x1, cls.one)))) cls.x6 = Expression(('randomvar', ('Normal', (cls.x1, cls.sigma)))) cls.mu_plus_z = Expression(('+', (cls.mu, cls.z))) cls.z_plus_mu = Expression(('+', (cls.z, cls.mu))) cls.mu_plus_x2 = Expression(('+', (cls.mu, cls.x2))) cls.x2_plus_mu = Expression(('+', (cls.x2, cls.mu))) cls.x1_plus_z = Expression(('+', (cls.x1, cls.z))) cls.z_plus_x1 = Expression(('+', (cls.z, cls.x1))) cls.z_times_z = Expression(('*', (cls.z, cls.z))) cls.x2_times_x2 = Expression(('*', (cls.x2, cls.x2))) cls.x7 = Expression(('randomvar', ('Normal', (cls.one, cls.z_times_z)))) cls.x8 = Expression(('randomvar', ('Normal', (cls.mu, cls.z_times_z)))) cls.x9 = Expression(('randomvar', ('Normal', (cls.x3, cls.z_times_z)))) cls.exp_2 = Expression(('func', ('exp', [cls.two]))) cls.exp_z = Expression(('func', ('exp', [cls.z]))) cls.exp_x1 = Expression(('func', ('exp', [cls.x1]))) cls.y1 = Expression(('randomvar', ('Normal', (cls.one, cls.exp_z)))) cls.y2 = Expression(('randomvar', ('Normal', (cls.mu, cls.exp_z)))) cls.y3 = Expression(('randomvar', ('Normal', (cls.mu, cls.exp_x1)))) cls.gamma_shape = Expression(('pvar_expr', ('shape', ['?r']))) cls.gamma_scale = Expression(('pvar_expr', ('scale', ['?r']))) cls.gamma1 = Expression(('randomvar', ('Gamma', (cls.gamma_shape, cls.gamma_scale)))) cls.exp_rate = Expression(('pvar_expr', ('rate', ['?r']))) cls.exp1 = Expression(('randomvar', ('Exponential', (cls.exp_rate,))))