'Create a learnable diagonal gaussian distribution.
Args:
batch_size: The size of the batch, i.e. 0th dim in 2D tensor of samples.
z_size: The dimension of the distribution, i.e. 1st dim in 2D tensor.
name: prefix name for the mean and log TF variables.
mean_init (optional): The N-D mean initialization of the distribution.
var_init (optional): The N-D variance initialization of the diagonal
distribution.
var_min (optional): The minimum value the learned variance can take in any
dimension.
var_max (optional): The maximum value the learned variance can take in any
dimension.'

def __init__(self, batch_size, z_size, name, mean_init=0.0, var_init=1.0, var_min=0.0, var_max=1000000.0):

    size_1xn = [1, z_size]
    size__xn = [None, z_size]
    size_bx1 = tf.stack([batch_size, 1])
    assert (var_init > 0.0), 'Problems'
    assert (var_max >= var_min), 'Problems'
    assert (var_init >= var_min), 'Problems'
    assert (var_max >= var_init), 'Problems'
    z_mean_1xn = tf.get_variable(name=(name + '/mean'), shape=size_1xn, initializer=tf.constant_initializer(mean_init))
    self.mean_bxn = mean_bxn = tf.tile(z_mean_1xn, size_bx1)
    mean_bxn.set_shape(size__xn)
    log_var_init = np.log(var_init)
    if (var_max > var_min):
        var_is_trainable = True
    else:
        var_is_trainable = False
    z_logvar_1xn = tf.get_variable(name=(name + '/logvar'), shape=size_1xn, initializer=tf.constant_initializer(log_var_init), trainable=var_is_trainable)
    if var_is_trainable:
        z_logit_var_1xn = tf.exp(z_logvar_1xn)
        z_var_1xn = ((tf.nn.sigmoid(z_logit_var_1xn) * (var_max - var_min)) + var_min)
        z_logvar_1xn = tf.log(z_var_1xn)
    logvar_bxn = tf.tile(z_logvar_1xn, size_bx1)
    self.logvar_bxn = logvar_bxn
    self.noise_bxn = noise_bxn = tf.random_normal(tf.shape(logvar_bxn))
    self.sample_bxn = (mean_bxn + (tf.exp((0.5 * logvar_bxn)) * noise_bxn))
