code: def _infer_ndim_bcast(ndim, shape, *args):
      """
      Infer the number of dimensions from the shape or the other arguments.
  
      Returns
      -------
      (int, variable, tuple) triple, where the variable is an integer vector,
      and the tuple contains Booleans
          The first element returned is the inferred number of dimensions.
          The second element is the shape inferred (combining symbolic and
          constant informations from shape and args).
          The third element is a broadcasting pattern corresponding to that shape.
  
      """
  
      # Find the minimum value of ndim required by the *args
      if args:
          args_ndim = max(arg.ndim for arg in args)
      else:
          args_ndim = 0
  
      if isinstance(shape, (tuple, list)):
          # there is a convention that -1 means the corresponding shape of a
          # potentially-broadcasted symbolic arg
          #
          # This case combines together symbolic and non-symbolic shape
          # information
          shape_ndim = len(shape)
          if ndim is None:
              ndim = shape_ndim
          else:
              if shape_ndim != ndim:
                  raise ValueError(
                      "ndim should be equal to len(shape), but\n",
                      "ndim = %s, len(shape) = %s, shape = %s"
                      % (ndim, shape_ndim, shape),
                  )
  
          bcast = []
          pre_v_shape = []
          for i, s in enumerate(shape):
              if hasattr(s, "type"):  # s is symbolic
                  bcast.append(False)  # todo - introspect further
                  pre_v_shape.append(s)
              else:
                  if s >= 0:
                      pre_v_shape.append(tensor.as_tensor_variable(s))
                      bcast.append((s == 1))
                  elif s == -1:
                      n_a_i = 0
                      for a in args:
                          # ndim: _   _   _   _   _   _
                          # ashp:         s0  s1  s2  s3
                          #           i
                          if i >= ndim - a.ndim:
                              n_a_i += 1
                              a_i = i + a.ndim - ndim
                              if not a.broadcastable[a_i]:
                                  pre_v_shape.append(a.shape[a_i])
                                  bcast.append(False)
                                  break
                      else:
                          if n_a_i == 0:
                              raise ValueError(
                                  (
                                      "Auto-shape of -1 must overlap"
                                      "with the shape of one of the broadcastable"
                                      "inputs"
                                  )
                              )
                          else:
                              pre_v_shape.append(
                                  tensor.as_tensor_variable(1)
                              )
                              bcast.append(True)
                  else:
                      ValueError("negative shape", s)
          # post-condition: shape may still contain both symbolic and
          # non-symbolic things
          if len(pre_v_shape) == 0:
              v_shape = tensor.constant([], dtype="int64")
          else:
              v_shape = tensor.stack(pre_v_shape)
  
      elif shape is None:
          # The number of drawn samples will be determined automatically,
          # but we need to know ndim
          if not args:
              raise TypeError(
                  (
                      "_infer_ndim_bcast cannot infer shape without"
                      " either shape or args"
                  )
              )
          template = reduce(lambda a, b: a + b, args)
          v_shape = template.shape
          bcast = template.broadcastable
          ndim = template.ndim
      else:
          v_shape = tensor.as_tensor_variable(shape)
          if v_shape.ndim != 1:
              raise TypeError(
                  "shape must be a vector or list of scalar, got '%s'"
                  % v_shape
              )
  
          if ndim is None:
              ndim = tensor.get_vector_length(v_shape)
          bcast = [False] * ndim
  
      if v_shape.ndim != 1:
          raise TypeError(
              "shape must be a vector or list of scalar, got '%s'"
              % v_shape
          )
  
      if v_shape.dtype not in theano.tensor.integer_dtypes:
          raise TypeError(
              "shape must be an integer vector or list", v_shape.dtype
          )
  
      if args_ndim > ndim:
          raise ValueError(
              "ndim should be at least as big as required by args value",
              (ndim, args_ndim),
              args,
          )
  
      assert ndim == len(bcast)
      return ndim, tensor.cast(v_shape, "int64"), tuple(bcast)
  
imports: from __future__ import absolute_import, print_function, division
  import sys
  from copy import copy
  import numpy
  from six import string_types
  from six.moves import reduce, xrange
  import theano
  from theano import tensor
  from theano.tensor import opt
  from theano import gof
  from theano.compile import optdb
label_desc: Use image node_id 1 for calling a global function with example usage: _infer_ndim_bcast(ndim, shape) and returns: ndim,  tensor,  tuple