# Path: deep_verify/src/layers/layers.py
# class VerifiableLayer(object):
# class CustomOp(object):
# class SingleVerifiableLayer(VerifiableLayer):
# class AffineLayer(SingleVerifiableLayer):
# class Conv(AffineLayer):
# class Linear(AffineLayer):
# class AvgPool(AffineLayer):
# class MaxPool(SingleVerifiableLayer):
# class Activation(SingleVerifiableLayer):
#   def __init__(self):
#   def branches(self):
#   def input_node(self):
#   def output_node(self):
#   def input_shape(self):
#   def output_shape(self):
#   def inputs(self):
#   def outputs(self):
#   def input_bounds(self):
#   def output_bounds(self):
#   def dual_shape(self):
#   def set_no_duals(self):
#   def reshape_duals_forwards(self, next_layer, dual_vars):
#   def project_duals_op(self, dual_vars):  # pylint:disable=unused-argument
#   def visit_linear(self, layer, w, b, *args, **kwargs):
#   def visit_conv(self, layer, w, b, padding, strides, *args, **kwargs):
#   def visit_avgpool(self, layer, *args, **kwargs):
#   def visit_maxpool(self, layer, *args, **kwargs):
#   def visit_activation(self, layer, *args, **kwargs):
#   def __init__(self, input_node, output_node, module,
#                batch_norm=None, reshape=False):
#   def input_node(self):
#   def output_node(self):
#   def is_activation(self):
#   def module(self):
#   def batch_norm(self):
#   def reshape(self):
#   def backward_prop_batchnorm(self, y):
#   def backward_prop_batchnorm_bias(self, y, bias):
#   def custom_op(self, op, *args, **kwargs):
#   def is_activation(self):
#   def forward_prop(self, x, apply_bias=False, w_fn=None):
#   def backward_prop(self, y, w_fn=None):
#   def backward_prop_bias(self, y):
#   def flatten(self):
#   def __init__(self, input_node, output_node, module, batch_norm=None,
#                reshape=False):
#   def forward_prop(self, x, apply_bias=False, w_fn=None):
#   def backward_prop(self, y, w_fn=None):
#   def backward_prop_bias(self, y):
#   def flatten(self):
#   def custom_op(self, op, *args, **kwargs):
#   def __init__(self, input_node, output_node, module, batch_norm=None,
#                reshape=False):
#   def forward_prop(self, x, apply_bias=False, w_fn=None):
#   def backward_prop(self, y, w_fn=None):
#   def backward_prop_bias(self, y):
#   def flatten(self):
#   def custom_op(self, op, *args, **kwargs):
#   def get_objective_weights(self, labels, target_strategy=None):
#   def __init__(self, input_node, output_node,
#                kernel_shape, strides, reshape=False):
#   def kernel_shape(self):
#   def strides(self):
#   def forward_prop(self, x, apply_bias=False, w_fn=None):
#   def backward_prop(self, y, w_fn=None):
#   def backward_prop_bias(self, y):
#   def flatten(self):
#   def custom_op(self, op, *args, **kwargs):
#   def __init__(self, input_node, output_node,
#                kernel_shape, strides, with_relu=False, reshape=False):
#   def kernel_shape(self):
#   def strides(self):
#   def with_relu(self):
#   def is_activation(self):
#   def custom_op(self, op, *args, **kwargs):
#   def __init__(self, input_node, output_node, module,
#                reshape=False, parameters=None):
#   def is_activation(self):
#   def activation(self):
#   def parameters(self):
#   def custom_op(self, op, *args, **kwargs):
# def create_verifiable_layer(input_node, output_node, module,
#                             batch_norm=None, reshape=False,
#                             parameters=None):


from deep_verify.src.layers import layers
import sonnet as snt
import tensorflow as tf
    bias = bias + self._first_layer.backward_prop_bias(y)
    return bias

  def flatten(self):
    if (self._first_layer.batch_norm is not None or
        self._second_layer.batch_norm is not None):
      raise ValueError('Batch norm not supported.')
    return tf.matmul(self._first_layer.flatten(),
                     self._second_layer.flatten())

  def backward_prop_batchnorm(self, y):
    return y

  def backward_prop_batchnorm_bias(self, y, bias):
    return y, bias


def combine_trailing_linear_layers(verifiable_layers):
  """If the network culminates in two or more linear layers, combines them.

  Args:
    verifiable_layers: List of `SingleVerifiableLayer`.

  Returns:
    List of `VerifiableLayer` in which trailing linear layers have been combined
      into one.

  Raises:
    ValueError: if an unsupported layer type or arrangement is encountered.
  """

# Path: deep_verify/src/layers/layers.py
# class VerifiableLayer(object):
# class CustomOp(object):
# class SingleVerifiableLayer(VerifiableLayer):
# class AffineLayer(SingleVerifiableLayer):
# class Conv(AffineLayer):
# class Linear(AffineLayer):
# class AvgPool(AffineLayer):
# class MaxPool(SingleVerifiableLayer):
# class Activation(SingleVerifiableLayer):
#   def __init__(self):
#   def branches(self):
#   def input_node(self):
#   def output_node(self):
#   def input_shape(self):
#   def output_shape(self):
#   def inputs(self):
#   def outputs(self):
#   def input_bounds(self):
#   def output_bounds(self):
#   def dual_shape(self):
#   def set_no_duals(self):
#   def reshape_duals_forwards(self, next_layer, dual_vars):
#   def project_duals_op(self, dual_vars):  # pylint:disable=unused-argument
#   def visit_linear(self, layer, w, b, *args, **kwargs):
#   def visit_conv(self, layer, w, b, padding, strides, *args, **kwargs):
#   def visit_avgpool(self, layer, *args, **kwargs):
#   def visit_maxpool(self, layer, *args, **kwargs):
#   def visit_activation(self, layer, *args, **kwargs):
#   def __init__(self, input_node, output_node, module,
#                batch_norm=None, reshape=False):
#   def input_node(self):
#   def output_node(self):
#   def is_activation(self):
#   def module(self):
#   def batch_norm(self):
#   def reshape(self):
#   def backward_prop_batchnorm(self, y):
#   def backward_prop_batchnorm_bias(self, y, bias):
#   def custom_op(self, op, *args, **kwargs):
#   def is_activation(self):
#   def forward_prop(self, x, apply_bias=False, w_fn=None):
#   def backward_prop(self, y, w_fn=None):
#   def backward_prop_bias(self, y):
#   def flatten(self):
#   def __init__(self, input_node, output_node, module, batch_norm=None,
#                reshape=False):
#   def forward_prop(self, x, apply_bias=False, w_fn=None):
#   def backward_prop(self, y, w_fn=None):
#   def backward_prop_bias(self, y):
#   def flatten(self):
#   def custom_op(self, op, *args, **kwargs):
#   def __init__(self, input_node, output_node, module, batch_norm=None,
#                reshape=False):
#   def forward_prop(self, x, apply_bias=False, w_fn=None):
#   def backward_prop(self, y, w_fn=None):
#   def backward_prop_bias(self, y):
#   def flatten(self):
#   def custom_op(self, op, *args, **kwargs):
#   def get_objective_weights(self, labels, target_strategy=None):
#   def __init__(self, input_node, output_node,
#                kernel_shape, strides, reshape=False):
#   def kernel_shape(self):
#   def strides(self):
#   def forward_prop(self, x, apply_bias=False, w_fn=None):
#   def backward_prop(self, y, w_fn=None):
#   def backward_prop_bias(self, y):
#   def flatten(self):
#   def custom_op(self, op, *args, **kwargs):
#   def __init__(self, input_node, output_node,
#                kernel_shape, strides, with_relu=False, reshape=False):
#   def kernel_shape(self):
#   def strides(self):
#   def with_relu(self):
#   def is_activation(self):
#   def custom_op(self, op, *args, **kwargs):
#   def __init__(self, input_node, output_node, module,
#                reshape=False, parameters=None):
#   def is_activation(self):
#   def activation(self):
#   def parameters(self):
#   def custom_op(self, op, *args, **kwargs):
# def create_verifiable_layer(input_node, output_node, module,
#                             batch_norm=None, reshape=False,
#                             parameters=None):


# Path: deep_verify/src/layers/layers_combined.py
from deep_verify.src.layers import layers
import sonnet as snt
import tensorflow as tf

    bias = bias + self._first_layer.backward_prop_bias(y)
    return bias

  def flatten(self):
    if (self._first_layer.batch_norm is not None or
        self._second_layer.batch_norm is not None):
      raise ValueError('Batch norm not supported.')
    return tf.matmul(self._first_layer.flatten(),
                     self._second_layer.flatten())

  def backward_prop_batchnorm(self, y):
    return y

  def backward_prop_batchnorm_bias(self, y, bias):
    return y, bias


def combine_trailing_linear_layers(verifiable_layers):
  """If the network culminates in two or more linear layers, combines them.

  Args:
    verifiable_layers: List of `SingleVerifiableLayer`.

  Returns:
    List of `VerifiableLayer` in which trailing linear layers have been combined
      into one.

  Raises:
    ValueError: if an unsupported layer type or arrangement is encountered.
  """

  if not isinstance(verifiable_layers[-1], layers.Linear):