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 _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 _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))