code: def test_redundancy_thoroughly():
      # To make sure there aren't any lurking bugs analogous to the ones that R
      # has (see above), we check that we get the correct matrix rank for every
      # possible combination of 2 categorical and 2 numerical factors.
      data = balanced(a=2, b=2, repeat=5)
      data["x1"] = np.linspace(0, 1, len(data["a"]))
      data["x2"] = data["x1"] ** 2
  
      def all_subsets(l):
          if not l:
              yield tuple()
          else:
              obj = l[0]
              for subset in all_subsets(l[1:]):
                  yield tuple(sorted(subset))
                  yield tuple(sorted((obj,) + subset))
  
      all_terms = list(all_subsets(("a", "b", "x1", "x2")))
      all_termlist_templates = list(all_subsets(all_terms))
      print(len(all_termlist_templates))
      # eliminate some of the symmetric versions to speed things up
      redundant = [
          [("b",), ("a",)],
          [("x2",), ("x1",)],
          [("b", "x2"), ("a", "x1")],
          [("a", "b", "x2"), ("a", "b", "x1")],
          [("b", "x1", "x2"), ("a", "x1", "x2")],
      ]
      count = 0
      import time
  
      start = time.time()
      for termlist_template in all_termlist_templates:
          termlist_set = set(termlist_template)
          for dispreferred, preferred in redundant:
              if (
                  dispreferred in termlist_set
                  and preferred not in termlist_set
              ):
                  break
          else:
              expanded_terms = set()
              for term_template in termlist_template:
                  numeric = tuple(
                      [t for t in term_template if t.startswith("x")]
                  )
                  rest = [
                      t for t in term_template if not t.startswith("x")
                  ]
                  for subset_rest in all_subsets(rest):
                      expanded_terms.add(
                          frozenset(subset_rest + numeric)
                      )
              # Because our categorical variables have 2 levels, each expanded
              # term corresponds to 1 unique dimension of variation
              expected_rank = len(expanded_terms)
              if termlist_template in [(), ((),)]:
                  # No data dependence, should fail
                  pytest.raises(
                      PatsyError,
                      make_matrix,
                      data,
                      expected_rank,
                      termlist_template,
                  )
              else:
                  make_matrix(data, expected_rank, termlist_template)
              count += 1
              if count % 100 == 0:
                  print("Completed:", count)
      print("Took %0.2f seconds" % (time.time() - start,))
  
imports: from __future__ import print_function
  import six
  import numpy
  import pytest
  from patsy import PatsyError
  from patsy.util import atleast_2d_column_default, have_pandas, have_pandas_categorical
  from patsy.desc import Term, INTERCEPT
  from patsy.build import *
  from patsy.categorical import C
  from patsy.user_util import balanced, LookupFactor
  from patsy.design_info import DesignMatrix, DesignInfo
label_desc: Use image node_id 8 for calling a global function with example usage: test_redundancy_thoroughly() without return types