code: def canonicalize(x):
      """Canonicalize the Hadamard product ``x`` with mathematical properties.
  
      Examples
      ========
  
      >>> from sympy import MatrixSymbol, HadamardProduct
      >>> from sympy import OneMatrix, ZeroMatrix
      >>> from sympy.matrices.expressions.hadamard import canonicalize
      >>> from sympy import init_printing
      >>> init_printing(use_unicode=False)
  
      >>> A = MatrixSymbol('A', 2, 2)
      >>> B = MatrixSymbol('B', 2, 2)
      >>> C = MatrixSymbol('C', 2, 2)
  
      Hadamard product associativity:
  
      >>> X = HadamardProduct(A, HadamardProduct(B, C))
      >>> X
      A.*(B.*C)
      >>> canonicalize(X)
      A.*B.*C
  
      Hadamard product commutativity:
  
      >>> X = HadamardProduct(A, B)
      >>> Y = HadamardProduct(B, A)
      >>> X
      A.*B
      >>> Y
      B.*A
      >>> canonicalize(X)
      A.*B
      >>> canonicalize(Y)
      A.*B
  
      Hadamard product identity:
  
      >>> X = HadamardProduct(A, OneMatrix(2, 2))
      >>> X
      A.*1
      >>> canonicalize(X)
      A
  
      Absorbing element of Hadamard product:
  
      >>> X = HadamardProduct(A, ZeroMatrix(2, 2))
      >>> X
      A.*0
      >>> canonicalize(X)
      0
  
      Rewriting to Hadamard Power
  
      >>> X = HadamardProduct(A, A, A)
      >>> X
      A.*A.*A
      >>> canonicalize(X)
       .3
      A
  
      Notes
      =====
  
      As the Hadamard product is associative, nested products can be flattened.
  
      The Hadamard product is commutative so that factors can be sorted for
      canonical form.
  
      A matrix of only ones is an identity for Hadamard product,
      so every matrices of only ones can be removed.
  
      Any zero matrix will make the whole product a zero matrix.
  
      Duplicate elements can be collected and rewritten as HadamardPower
  
      References
      ==========
  
      .. [1] https://en.wikipedia.org/wiki/Hadamard_product_(matrices)
      """
      # Associativity
      rule = condition(
          lambda x: isinstance(x, HadamardProduct), flatten
      )
      fun = exhaust(rule)
      x = fun(x)
  
      # Identity
      fun = condition(
          lambda x: isinstance(x, HadamardProduct),
          rm_id(lambda x: isinstance(x, OneMatrix)),
      )
      x = fun(x)
  
      # Absorbing by Zero Matrix
      def absorb(x):
          if any(isinstance(c, ZeroMatrix) for c in x.args):
              return ZeroMatrix(*x.shape)
          else:
              return x
  
      fun = condition(lambda x: isinstance(x, HadamardProduct), absorb)
      x = fun(x)
  
      # Rewriting with HadamardPower
      if isinstance(x, HadamardProduct):
          tally = Counter(x.args)
  
          new_arg = []
          for base, exp in tally.items():
              if exp == 1:
                  new_arg.append(base)
              else:
                  new_arg.append(HadamardPower(base, exp))
  
          x = HadamardProduct(*new_arg)
  
      # Commutativity
      fun = condition(
          lambda x: isinstance(x, HadamardProduct),
          sort(default_sort_key),
      )
      x = fun(x)
  
      # Unpacking
      x = unpack(x)
      return x
  
imports: from collections import Counter
  from sympy.core import Mul, sympify
  from sympy.core.add import Add
  from sympy.core.expr import ExprBuilder
  from sympy.core.sorting import default_sort_key
  from sympy.functions.elementary.exponential import log
  from sympy.matrices.expressions.matexpr import MatrixExpr
  from sympy.matrices.expressions._shape import validate_matadd_integer
  from sympy.matrices.expressions.special import ZeroMatrix, OneMatrix
  from sympy.strategies import unpack, flatten, condition, exhaust, rm_id, sort
  from sympy.utilities.exceptions import sympy_deprecation_warning
label_desc: Use image node_id 2 for calling a global function with example usage: canonicalize(x) and returns: x, ZeroMatrix, x