# Path: dltk/core/upsample.py
# def linear_upsample_3d(inputs,
#                        strides=(2, 2, 2),
#                        use_bias=False,
#                        trainable=False,
#                        name='linear_upsample_3d'):
#     """Linear upsampling layer in 3D using strided transpose convolutions. The
#         upsampling kernel size will be automatically computed to avoid
#         information loss.
# 
#     Args:
#         inputs (tf.Tensor): Input tensor to be upsampled
#         strides (tuple, optional): The strides determine the upsampling factor
#             in each dimension.
#         use_bias (bool, optional): Flag to train an additional bias.
#         trainable (bool, optional): Flag to set the variables to be trainable or not.
#         name (str, optional): Name of the layer.
# 
#     Returns:
#         tf.Tensor: Upsampled Tensor
#     """
#     static_inp_shape = tuple(inputs.get_shape().as_list())
#     dyn_inp_shape = tf.shape(inputs)
#     rank = len(static_inp_shape)
# 
#     num_filters = static_inp_shape[-1]
#     strides_5d = [1, ] + list(strides) + [1, ]
#     kernel_size = [2 * s if s > 1 else 1 for s in strides]
# 
#     kernel = get_linear_upsampling_kernel(
#         kernel_spatial_shape=kernel_size,
#         out_filters=num_filters,
#         in_filters=num_filters,
#         trainable=trainable)
# 
#     dyn_out_shape = [dyn_inp_shape[i] * strides_5d[i] for i in range(rank)]
#     dyn_out_shape[-1] = num_filters
# 
#     static_out_shape = [static_inp_shape[i] * strides_5d[i]
#                         if isinstance(static_inp_shape[i], int)
#                         else None for i in range(rank)]
# 
#     static_out_shape[-1] = num_filters
#     tf.logging.info('Upsampling from {} to {}'.format(
#         static_inp_shape, static_out_shape))
# 
#     upsampled = tf.nn.conv3d_transpose(
#         value=inputs,
#         filter=kernel,
#         output_shape=dyn_out_shape,
#         strides=strides_5d,
#         padding='SAME',
#         name='upsample')
# 
#     upsampled.set_shape(static_out_shape)
# 
#     return upsampled
# 
# Path: dltk/core/activations.py
# def prelu(inputs, alpha_initializer=tf.constant_initializer()):
#     """Probabilistic ReLu activation function
# 
#     Args:
#         (tf.Tensor): input Tensor
#         alpha_initializer (float, optional): an initial value for alpha
# 
#     Returns:
#         tf.Tensor: a PreLu activated tensor
#     """
# 
#     alpha = tf.get_variable('alpha',
#                             shape=[],
#                             dtype=tf.float32,
#                             initializer=alpha_initializer)
# 
#     return leaky_relu(inputs, alpha)
# 
# def leaky_relu(inputs, alpha=0.1):
#     """Leaky ReLu activation function
# 
#     Args:
#         inputs (tf.Tensor): input Tensor
#         alpha (float): leakiness parameter
# 
#     Returns:
#         tf.Tensor: a leaky ReLu activated tensor
#     """
#     return tf.maximum(inputs, alpha * inputs)


import tensorflow as tf
from dltk.core.upsample import linear_upsample_3d
from dltk.core.activations import prelu, leaky_relu

    x = inputs

    normal = _build_normal_pathway(x)
    pathways = _build_subsampled_pathways(x)

    normal_shape = normal.get_shape().as_list()[1:-1]
    paths = [normal]
    for x in pathways:
        paths.append(crop_central_block(x, normal_shape))

    x = tf.concat(paths, -1)

    layers = []
    for i in range(len(fc_filters)):
        with tf.variable_scope('fc_{}'.format(i)):
            layers.append(x)
            if i == 0 and any([k > 1 for k in first_fc_kernel]):
                x_shape = x.get_shape().as_list()
                # CAUTION: https://docs.python.org/2/faq/programming.html#how-do-i-create-a-multidimensional-list
                x_pad = [[0, 0] for _ in range(len(x_shape))]
                for j in range(len(first_fc_kernel)):
                    to_pad = (first_fc_kernel[j] - 1)
                    x_pad[j + 1][0] = to_pad // 2
                    x_pad[j + 1][1] = to_pad - x_pad[j + 1][0]
                    print(x_pad)
                x = tf.pad(x, x_pad, mode='SYMMETRIC')

            x = tf.layers.batch_normalization(
                x, training=mode == tf.estimator.ModeKeys.TRAIN)

# Path: dltk/core/upsample.py
# def linear_upsample_3d(inputs,
#                        strides=(2, 2, 2),
#                        use_bias=False,
#                        trainable=False,
#                        name='linear_upsample_3d'):
#     """Linear upsampling layer in 3D using strided transpose convolutions. The
#         upsampling kernel size will be automatically computed to avoid
#         information loss.
# 
#     Args:
#         inputs (tf.Tensor): Input tensor to be upsampled
#         strides (tuple, optional): The strides determine the upsampling factor
#             in each dimension.
#         use_bias (bool, optional): Flag to train an additional bias.
#         trainable (bool, optional): Flag to set the variables to be trainable or not.
#         name (str, optional): Name of the layer.
# 
#     Returns:
#         tf.Tensor: Upsampled Tensor
#     """
#     static_inp_shape = tuple(inputs.get_shape().as_list())
#     dyn_inp_shape = tf.shape(inputs)
#     rank = len(static_inp_shape)
# 
#     num_filters = static_inp_shape[-1]
#     strides_5d = [1, ] + list(strides) + [1, ]
#     kernel_size = [2 * s if s > 1 else 1 for s in strides]
# 
#     kernel = get_linear_upsampling_kernel(
#         kernel_spatial_shape=kernel_size,
#         out_filters=num_filters,
#         in_filters=num_filters,
#         trainable=trainable)
# 
#     dyn_out_shape = [dyn_inp_shape[i] * strides_5d[i] for i in range(rank)]
#     dyn_out_shape[-1] = num_filters
# 
#     static_out_shape = [static_inp_shape[i] * strides_5d[i]
#                         if isinstance(static_inp_shape[i], int)
#                         else None for i in range(rank)]
# 
#     static_out_shape[-1] = num_filters
#     tf.logging.info('Upsampling from {} to {}'.format(
#         static_inp_shape, static_out_shape))
# 
#     upsampled = tf.nn.conv3d_transpose(
#         value=inputs,
#         filter=kernel,
#         output_shape=dyn_out_shape,
#         strides=strides_5d,
#         padding='SAME',
#         name='upsample')
# 
#     upsampled.set_shape(static_out_shape)
# 
#     return upsampled
# 
# Path: dltk/core/activations.py
# def prelu(inputs, alpha_initializer=tf.constant_initializer()):
#     """Probabilistic ReLu activation function
# 
#     Args:
#         (tf.Tensor): input Tensor
#         alpha_initializer (float, optional): an initial value for alpha
# 
#     Returns:
#         tf.Tensor: a PreLu activated tensor
#     """
# 
#     alpha = tf.get_variable('alpha',
#                             shape=[],
#                             dtype=tf.float32,
#                             initializer=alpha_initializer)
# 
#     return leaky_relu(inputs, alpha)
# 
# def leaky_relu(inputs, alpha=0.1):
#     """Leaky ReLu activation function
# 
#     Args:
#         inputs (tf.Tensor): input Tensor
#         alpha (float): leakiness parameter
# 
#     Returns:
#         tf.Tensor: a leaky ReLu activated tensor
#     """
#     return tf.maximum(inputs, alpha * inputs)


# Path: dltk/networks/segmentation/deepmedic.py
import tensorflow as tf
from dltk.core.upsample import linear_upsample_3d
from dltk.core.activations import prelu, leaky_relu


    x = inputs

    normal = _build_normal_pathway(x)
    pathways = _build_subsampled_pathways(x)

    normal_shape = normal.get_shape().as_list()[1:-1]
    paths = [normal]
    for x in pathways:
        paths.append(crop_central_block(x, normal_shape))

    x = tf.concat(paths, -1)

    layers = []
    for i in range(len(fc_filters)):
        with tf.variable_scope('fc_{}'.format(i)):
            layers.append(x)
            if i == 0 and any([k > 1 for k in first_fc_kernel]):
                x_shape = x.get_shape().as_list()
                # CAUTION: https://docs.python.org/2/faq/programming.html#how-do-i-create-a-multidimensional-list
                x_pad = [[0, 0] for _ in range(len(x_shape))]
                for j in range(len(first_fc_kernel)):
                    to_pad = (first_fc_kernel[j] - 1)
                    x_pad[j + 1][0] = to_pad // 2
                    x_pad[j + 1][1] = to_pad - x_pad[j + 1][0]
                    print(x_pad)
                x = tf.pad(x, x_pad, mode='SYMMETRIC')

            x = tf.layers.batch_normalization(
                x, training=mode == tf.estimator.ModeKeys.TRAIN)

            x = prelu(x) if use_prelu else leaky_relu(x, 0.01)