class_docstr: This class is used to build partition-based formulations
  of neural networks.
  
  Parameters
  ----------
  network_structure : NetworkDefinition
      the neural network definition
  split_func : callable
      the function used to compute the splits
class_docstr_tok: ["This","class","is","used","to","build","partition-based","formulations","of","neural","networks",".","Parameters","--","--","--","--","--","network_structure",":","NetworkDefinition","the","neural","network","definition","split_func",":","callable","the","function","used","to","compute","the","splits"]
code: def _build_formulation(self):
      _setup_scaled_inputs_outputs(
          self.block, self.__scaling_object, self.__scaled_input_bounds
      )
      block = self.block
      net = self.__network_definition
      layers = list(net.layers)
      split_func = self.__split_func
  
      block.layers = pyo.Set(
          initialize=[id(layer) for layer in layers], ordered=True
      )
  
      # create the z and z_hat variables for each of the layers
      @block.Block(block.layers)
      def layer(b, layer_id):
          net_layer = net.layer(layer_id)
          b.z = pyo.Var(net_layer.output_indexes, initialize=0)
          if isinstance(net_layer, InputLayer):
              for index in net_layer.output_indexes:
                  input_var = block.scaled_inputs[index]
                  z_var = b.z[index]
                  z_var.setlb(input_var.lb)
                  z_var.setub(input_var.ub)
          else:
              # add zhat only to non input layers
              b.zhat = pyo.Var(net_layer.output_indexes, initialize=0)
  
          return b
  
      for layer in layers:
          if isinstance(layer, InputLayer):
              continue
          layer_id = id(layer)
          layer_block = block.layer[layer_id]
          if isinstance(layer, DenseLayer):
              if layer.activation == "relu":
                  partition_based_dense_relu_layer(
                      block, net, layer_block, layer, split_func
                  )
              elif layer.activation == "linear":
                  full_space_dense_layer(block, net, layer_block, layer)
                  linear_activation_constraint(
                      block, net, layer_block, layer
                  )
              else:
                  raise ValueError(
                      "ReluPartitionFormulation supports Dense layers with relu or linear activation"
                  )
          else:
              raise ValueError(
                  "ReluPartitionFormulation supports only Dense layers"
              )
  
      # This check is never hit. The formulation._build_formulation() function is
      # only ever called by an OmltBlock.build_formulation(), and that runs the
      # input_indexes and output_indexes first, which will catch any formulations
      # with multiple input or output layers.
  
      # setup input variables constraints
      # currently only support a single input layer
      input_layers = list(net.input_layers)
      if len(input_layers) != 1:
          raise ValueError(
              "Multiple input layers are not currently supported."
          )
      input_layer = input_layers[0]
  
      @block.Constraint(input_layer.output_indexes)
      def input_assignment(b, *output_index):
          return (
              b.scaled_inputs[output_index]
              == b.layer[id(input_layer)].z[output_index]
          )
  
      # setup output variables constraints
      # currently only support a single output layer
      output_layers = list(net.output_layers)
      if len(output_layers) != 1:
          raise ValueError(
              "Multiple output layers are not currently supported."
          )
      output_layer = output_layers[0]
  
      @block.Constraint(output_layer.output_indexes)
      def output_assignment(b, *output_index):
          return (
              b.scaled_outputs[output_index]
              == b.layer[id(output_layer)].z[output_index]
          )
  
imports: import numpy
  import pyomo.environ
  from omlt.formulation import _PyomoFormulation, _setup_scaled_inputs_outputs
  from omlt.neuralnet.activations import ACTIVATION_FUNCTION_MAP
  from omlt.neuralnet.activations import ComplementarityReLUActivation, bigm_relu_activation_constraint, linear_activation_constraint, linear_activation_function, sigmoid_activation_constraint, sigmoid_activation_function, softplus_activation_constraint, softplus_activation_function, tanh_activation_constraint, tanh_activation_function
  from omlt.neuralnet.layer import ConvLayer2D, DenseLayer, InputLayer, PoolingLayer2D
  from omlt.neuralnet.layers.full_space import full_space_conv2d_layer, full_space_dense_layer, full_space_maxpool2d_layer
  from omlt.neuralnet.layers.partition_based import default_partition_split_func, partition_based_dense_relu_layer
  from omlt.neuralnet.layers.reduced_space import reduced_space_dense_layer
label_desc: Use image node_id 2 for calling the ReluPartitionFormulation obj's underlying member method code with example usage: obj._build_formulation() and returns: b, unknown, unknown