code: def tree_multiplier(A, B, reducer=adders.wallace_reducer, adder_func=adders.kogge_stone):
      
  
      """
      The two tree multipliers basically works by splitting the multiplication
      into a series of many additions, and it works by applying 'reductions'.
      """
      triv_res = _trivial_mult(A, B)
      if triv_res is not None:
          return triv_res
  
      bits_length = (len(A) + len(B))
  
      # create a list of lists, with slots for all the weights (bit-positions)
      bits = [[] for weight in range(bits_length)]
  
      # AND every bit of A with every bit of B (N^2 results) and store by "weight" (bit-position)
      for i, a in enumerate(A):
          for j, b in enumerate(B):
              bits[i + j].append(a & b)
  
      return reducer(bits, bits_length, adder_func)
docs: Build an fast unclocked multiplier for inputs A and B using a Wallace or Dada Tree.
  
      :param WireVector A, B: two input wires for the multiplication
      :param function reducer: Reduce the tree using either a Dada recuder or a Wallace reducer
        determines whether it is a Wallace tree multiplier or a Dada tree multiplier
      :param function adder_func: an adder function that will be used to do the last addition
      :return WireVector: The multiplied result
  
      Delay is order logN, while area is order N^2.