'Creates a single causal dilated convolution layer.
Args:
input_batch: Input to the dilation layer.
layer_index: Integer indicating which layer this is.
dilation: Integer specifying the dilation size.
global_conditioning_batch: Tensor containing the global data upon
which the output is to be conditioned upon. Shape:
[batch size, 1, channels]. The 1 is for the axis
corresponding to time so that the result is broadcast to
all time steps.
The layer contains a gated filter that connects to dense output
and to a skip connection:
|-> [gate]   -|        |-> 1x1 conv -> skip output
input -|-> [filter] -|        |-> 1x1 conv -|
|                                    |-> (+) -> dense output
Where `[gate]` and `[filter]` are causal convolutions with a
non-linear activation at the output. Biases and global conditioning
are omitted due to the limits of ASCII art.'

def _create_dilation_layer(self, input_batch, layer_index, dilation, global_condition_batch, output_width):

    variables = self.variables['dilated_stack'][layer_index]
    weights_filter = variables['filter']
    weights_gate = variables['gate']
    conv_filter = causal_conv(input_batch, weights_filter, dilation)
    conv_gate = causal_conv(input_batch, weights_gate, dilation)
    if (global_condition_batch is not None):
        weights_gc_filter = variables['gc_filtweights']
        conv_filter = (conv_filter + tf.nn.conv1d(global_condition_batch, weights_gc_filter, stride=1, padding='SAME', name='gc_filter'))
        weights_gc_gate = variables['gc_gateweights']
        conv_gate = (conv_gate + tf.nn.conv1d(global_condition_batch, weights_gc_gate, stride=1, padding='SAME', name='gc_gate'))
    if self.use_biases:
        filter_bias = variables['filter_bias']
        gate_bias = variables['gate_bias']
        conv_filter = tf.add(conv_filter, filter_bias)
        conv_gate = tf.add(conv_gate, gate_bias)
    out = (tf.tanh(conv_filter) * tf.sigmoid(conv_gate))
    weights_dense = variables['dense']
    transformed = tf.nn.conv1d(out, weights_dense, stride=1, padding='SAME', name='dense')
    skip_cut = (tf.shape(out)[1] - output_width)
    out_skip = tf.slice(out, [0, skip_cut, 0], [(-1), (-1), (-1)])
    weights_skip = variables['skip']
    skip_contribution = tf.nn.conv1d(out_skip, weights_skip, stride=1, padding='SAME', name='skip')
    if self.use_biases:
        dense_bias = variables['dense_bias']
        skip_bias = variables['skip_bias']
        transformed = (transformed + dense_bias)
        skip_contribution = (skip_contribution + skip_bias)
    if self.histograms:
        layer = 'layer{}'.format(layer_index)
        tf.histogram_summary((layer + '_filter'), weights_filter)
        tf.histogram_summary((layer + '_gate'), weights_gate)
        tf.histogram_summary((layer + '_dense'), weights_dense)
        tf.histogram_summary((layer + '_skip'), weights_skip)
        if self.use_biases:
            tf.histogram_summary((layer + '_biases_filter'), filter_bias)
            tf.histogram_summary((layer + '_biases_gate'), gate_bias)
            tf.histogram_summary((layer + '_biases_dense'), dense_bias)
            tf.histogram_summary((layer + '_biases_skip'), skip_bias)
    input_cut = (tf.shape(input_batch)[1] - tf.shape(transformed)[1])
    input_batch = tf.slice(input_batch, [0, input_cut, 0], [(-1), (-1), (-1)])
    return (skip_contribution, (input_batch + transformed))
