docs: def ensure_col_dep_constraints(
              self, M_c, M_r, T, X_L, X_D, dep_constraints,
              seed, max_rejections=100):
          """Ensures dependencey or indepdendency between columns.
  
          `dep_constraints` is a list of where each entry is an (int, int, bool)
          tuple where the first two entries are column indices and the third entry
          describes whether the columns are to be dependent (True) or independent
          (False).
  
          Behavior Notes:
          `ensure_col_dep_constraints` will add `col_ensure` enforcement to the
          metadata (top level of `X_L`); unensure_col will remove it. Calling
          ensure_col_dep_constraints twice will replace the first ensure.
  
          This operation destroys the existing `X_L` and `X_D` metadata; the user
          should be aware that it will clobber any existing analyses.
  
          Implementation Notes:
          Initialization is implemented via rejection (by repeatedly initalizing
          states and throwing ones out that do not adhear to dep_constraints).
          This means that in the event the contraints in dep_constraints are
          complex, or impossible, that the rejection alogrithm may fail.
  
          The returned metadata looks like this:
          >>> dep_constraints
          [(1, 2, True), (2, 5, True), (1, 3, False)]
          >>> X_L['col_ensure']
          {
              "dependent" : {
                  1 : (1, 2, 5),
                  2 : (1, 2, 5),
                  5 : (1, 5, 2),
              },
              "independent" : {
                  1 : [3],
                  3 : [1],
              }
          }
          """
          X_L_list, X_D_list, was_multistate = su.ensure_multistate(X_L, X_D)
  
          if was_multistate:
              num_states = len(X_L_list)
          else:
              num_states = 1
  
          dependencies = [(c[0], c[1]) for c in dep_constraints if c[2]]
          independencies = [(c[0], c[1]) for c in dep_constraints if not c[2]]
  
          col_ensure_md = dict()
          col_ensure_md[True] = {
              str(key) : list(val) for
              key, val in gu.get_scc_from_tuples(dependencies).iteritems()
          }
          col_ensure_md[False] = {
              str(key) : list(val) for
              key, val in gu.get_scc_from_tuples(independencies).iteritems()
          }
  
          def assert_dep_constraints(X_L, X_D, dep_constraints):
              for col1, col2, dep in dep_constraints:
                  if not self.assert_col_dep_constraints(
                          X_L, X_D, col1, col2, dep, True):
                      return False
              return True
  
          X_L_out = []
          X_D_out = []
          get_next_seed = make_get_next_seed(seed)
  
          for _ in range(num_states):
              counter = 0
              X_L_i, X_D_i = self.initialize(M_c, M_r, T, get_next_seed())
              while not assert_dep_constraints(X_L_i, X_D_i, dep_constraints):
                  if counter > max_rejections:
                      raise RuntimeError(
                          'Could not ranomly generate a partition '
                          'that satisfies the constraints in dep_constraints.')
                  counter += 1
                  X_L_i, X_D_i = self.initialize(M_c, M_r, T, get_next_seed())
  
              X_L_i['col_ensure'] = dict()
              X_L_i['col_ensure']['dependent'] = col_ensure_md[True]
              X_L_i['col_ensure']['independent'] = col_ensure_md[False]
  
              X_D_out.append(X_D_i)
              X_L_out.append(X_L_i)
  
          if was_multistate:
              return X_L_out, X_D_out
          else:
              return X_L_out[0], X_D_out[0]