# Path: qkeras/qtools/quantized_operators/accumulator_impl.py
# def po2_to_qbits(quantizer: quantizer_impl.IQuantizer):
#   def implemented_as():
#   def __init__(
#       self,
#       multiplier: multiplier_impl.IMultiplier
#   ):
#   def implemented_as():
#   def __init__(
#       self,
#       kernel_shape,
#       multiplier: multiplier_impl.IMultiplier,
#       use_bias=True
#   ):
#   def implemented_as():
#   def __init__(
#       self,
#       kernel_shape,
#       multiplier: multiplier_impl.IMultiplier,
#       use_bias=True
#   ):
#   def implemented_as():
# class IAccumulator(abc.ABC):
# class FloatingPointAccumulator(IAccumulator):
# class FixedPointAccumulator(IAccumulator):
# class Po2Accumulator(FixedPointAccumulator):
# 
# Path: qkeras/qtools/quantized_operators/multiplier_impl.py
# class IMultiplier(abc.ABC):
# class Mux(IMultiplier):
# class XorGate(IMultiplier):
# class Shifter(IMultiplier):
# class AndGate(IMultiplier):
# class Adder(IMultiplier):
# class FloatingPointMultiplier(IMultiplier):
# class FixedPointMultiplier(IMultiplier):
#   def __init__(self, weight_quantizer: quantizer_impl.IQuantizer,
#                input_quantizer: quantizer_impl.IQuantizer,
#                output_quantizer: quantizer_impl.IQuantizer):
#   def implemented_as():
#   def name(self) -> str:
#   def output_quantizer(self):
# def assert_neither_input_and_weights_is_floating_point(
#     multiplier: IMultiplier):
#   def __init__(self, weight_quantizer: quantizer_impl.IQuantizer,
#                input_quantizer: quantizer_impl.IQuantizer,
#                output_quantizer: quantizer_impl.IQuantizer):
#   def implemented_as():
#   def __init__(self, weight_quantizer: quantizer_impl.IQuantizer,
#                input_quantizer: quantizer_impl.IQuantizer,
#                output_quantizer: quantizer_impl.IQuantizer):
#   def implemented_as():
#   def __init__(
#       self, weight_quantizer: quantizer_impl.IQuantizer,
#       input_quantizer: quantizer_impl.IQuantizer,
#       output_quantizer: quantizer_impl.IQuantizer
#   ):
#   def implemented_as():
#   def __init__(
#       self, weight_quantizer: quantizer_impl.IQuantizer,
#       input_quantizer: quantizer_impl.IQuantizer,
#       output_quantizer: quantizer_impl.IQuantizer
#   ):
#   def implemented_as():
#   def __init__(self, weight_quantizer: quantizer_impl.IQuantizer,
#                input_quantizer: quantizer_impl.IQuantizer,
#                output_quantizer: quantizer_impl.IQuantizer):
#   def implemented_as():
#   def __init__(self, weight_quantizer: quantizer_impl.IQuantizer,
#                input_quantizer: quantizer_impl.IQuantizer,
#                output_quantizer: quantizer_impl.IQuantizer):
#   def implemented_as():
#   def __init__(self, weight_quantizer: quantizer_impl.IQuantizer,
#                input_quantizer: quantizer_impl.IQuantizer,
#                output_quantizer: quantizer_impl.IQuantizer):
#   def implemented_as():


import copy
from qkeras.qtools.quantized_operators import accumulator_impl
from qkeras.qtools.quantized_operators import multiplier_impl
from __future__ import print_function




class AccumulatorFactory:
  """interface for accumulator type."""

  def make_accumulator(
      self, kernel_shape,
      multiplier: multiplier_impl.IMultiplier,
      use_bias=True
  ) -> accumulator_impl.IAccumulator:
    """Create an accumulator instance."""

    # Creates a local deep copy so that any changes we made to the multiplier
    # will not impact the input multiplier type. This is necessary in case
    # we call this function multiple times to get different multipliers.
    local_multiplier = copy.deepcopy(multiplier)

    # The type and bit width of the accumulator is deteremined from the
    # multiplier implementation, and the shape of both kernel and bias

    if local_multiplier.output.is_floating_point:
      accumulator = accumulator_impl.FloatingPointAccumulator(
          local_multiplier)

    # po2*po2 is implemented as Adder; output type is po2
    # in multiplier, po2 needs to be converted to FixedPoint
    elif local_multiplier.output.is_po2:

# Path: qkeras/qtools/quantized_operators/accumulator_impl.py
# def po2_to_qbits(quantizer: quantizer_impl.IQuantizer):
#   def implemented_as():
#   def __init__(
#       self,
#       multiplier: multiplier_impl.IMultiplier
#   ):
#   def implemented_as():
#   def __init__(
#       self,
#       kernel_shape,
#       multiplier: multiplier_impl.IMultiplier,
#       use_bias=True
#   ):
#   def implemented_as():
#   def __init__(
#       self,
#       kernel_shape,
#       multiplier: multiplier_impl.IMultiplier,
#       use_bias=True
#   ):
#   def implemented_as():
# class IAccumulator(abc.ABC):
# class FloatingPointAccumulator(IAccumulator):
# class FixedPointAccumulator(IAccumulator):
# class Po2Accumulator(FixedPointAccumulator):
# 
# Path: qkeras/qtools/quantized_operators/multiplier_impl.py
# class IMultiplier(abc.ABC):
# class Mux(IMultiplier):
# class XorGate(IMultiplier):
# class Shifter(IMultiplier):
# class AndGate(IMultiplier):
# class Adder(IMultiplier):
# class FloatingPointMultiplier(IMultiplier):
# class FixedPointMultiplier(IMultiplier):
#   def __init__(self, weight_quantizer: quantizer_impl.IQuantizer,
#                input_quantizer: quantizer_impl.IQuantizer,
#                output_quantizer: quantizer_impl.IQuantizer):
#   def implemented_as():
#   def name(self) -> str:
#   def output_quantizer(self):
# def assert_neither_input_and_weights_is_floating_point(
#     multiplier: IMultiplier):
#   def __init__(self, weight_quantizer: quantizer_impl.IQuantizer,
#                input_quantizer: quantizer_impl.IQuantizer,
#                output_quantizer: quantizer_impl.IQuantizer):
#   def implemented_as():
#   def __init__(self, weight_quantizer: quantizer_impl.IQuantizer,
#                input_quantizer: quantizer_impl.IQuantizer,
#                output_quantizer: quantizer_impl.IQuantizer):
#   def implemented_as():
#   def __init__(
#       self, weight_quantizer: quantizer_impl.IQuantizer,
#       input_quantizer: quantizer_impl.IQuantizer,
#       output_quantizer: quantizer_impl.IQuantizer
#   ):
#   def implemented_as():
#   def __init__(
#       self, weight_quantizer: quantizer_impl.IQuantizer,
#       input_quantizer: quantizer_impl.IQuantizer,
#       output_quantizer: quantizer_impl.IQuantizer
#   ):
#   def implemented_as():
#   def __init__(self, weight_quantizer: quantizer_impl.IQuantizer,
#                input_quantizer: quantizer_impl.IQuantizer,
#                output_quantizer: quantizer_impl.IQuantizer):
#   def implemented_as():
#   def __init__(self, weight_quantizer: quantizer_impl.IQuantizer,
#                input_quantizer: quantizer_impl.IQuantizer,
#                output_quantizer: quantizer_impl.IQuantizer):
#   def implemented_as():
#   def __init__(self, weight_quantizer: quantizer_impl.IQuantizer,
#                input_quantizer: quantizer_impl.IQuantizer,
#                output_quantizer: quantizer_impl.IQuantizer):
#   def implemented_as():


# Path: qkeras/qtools/quantized_operators/accumulator_factory.py
import copy
from qkeras.qtools.quantized_operators import accumulator_impl
from qkeras.qtools.quantized_operators import multiplier_impl

from __future__ import print_function




class AccumulatorFactory:
  """interface for accumulator type."""

  def make_accumulator(
      self, kernel_shape,
      multiplier: multiplier_impl.IMultiplier,
      use_bias=True
  ) -> accumulator_impl.IAccumulator:
    """Create an accumulator instance."""

    # Creates a local deep copy so that any changes we made to the multiplier
    # will not impact the input multiplier type. This is necessary in case
    # we call this function multiple times to get different multipliers.
    local_multiplier = copy.deepcopy(multiplier)

    # The type and bit width of the accumulator is deteremined from the
    # multiplier implementation, and the shape of both kernel and bias

    if local_multiplier.output.is_floating_point:
      accumulator = accumulator_impl.FloatingPointAccumulator(
          local_multiplier)

    # po2*po2 is implemented as Adder; output type is po2
    # in multiplier, po2 needs to be converted to FixedPoint
    elif local_multiplier.output.is_po2:

      accumulator = accumulator_impl.Po2Accumulator(