Project: s41467-025-57183-0 | Function: data_quantization (python)

system: You are an expert Python programmer implementing algorithms from scientific papers.
Complete the masked function based on the algorithm description.
Follow Python best practices and maintain consistent code style.
Return **only** the complete Python function code.

user: Complete this Python function:

**DESCRIPTION:** Core quantization algorithm that converts floating-point data to fixed-point representation for CIM hardware. Supports symmetric/asymmetric quantization, positive-only mode, and various clipping strategies.

**KEY TERMS:** {
  "data_float": "floating-point input data",
  "symmetric": "symmetric quantization mode",
  "bit": "quantization bit width",
  "scale": "quantization scale factor",
  "zero_point": "quantization zero point"
}

**CONTEXT CODE:** import torch
import torch.nn as nn
import torch.nn.functional as F
import math

# 
def grad_scale(x, scale):
    y = x
    y_grad = x * scale
    return (y - y_grad).detach() + y_grad
# 
def round_pass(x):
    y = x.round()
    y_grad = x
    return (y - y_grad).detach() + y_grad

def floor_pass(x):
    y = x.floor()
    y_grad = x
    return (y - y_grad).detach() + y_grad

# Add noise to input data
def add_noise(weight, method = 'add', n_scale = 0.074, n_range = 'max'):
    # 
    if n_scale == 0:
        return weight
    std = weight.std()

    if n_range == 'max':
        factor = weight.abs().max()
    if n_range == 'std':
        factor = std
    if n_range == 'max_min':
        factor = weight.max() - weight.min()
    if n_range == 'maxabs_2':
        factor = 2 * torch.max(torch.abs(weight))

    if method == 'add':
        w_noise = torch.randn_like(weight, device=weight.device).clamp_(-3.0, 3.0) * factor * n_scale
        weight_noise = weight + w_noise
    if method == 'mul':
        w_noise = torch.randn_like(weight, device=weight.device).clamp_(-3.0,
                                                                        3.0) * n_scale + 1  ## whether clamp randn to (-3,3)
        weight_noise = weight * w_noise
    weight_noise = (weight_noise - weight).detach() + weight
    return weight_noise
# 
def data_quantization(data_float, symmetric = True, bit = 8, clamp_std = None,
                        th_point='max', th_scale=None, all_positive=False):
    """
    Core quantization algorithm for CIM hardware acceleration.

    This function converts floating-point data to fixed-point representation for
    computing-in-memory systems. It implements the quantization methodology described
    in the OpenCIMTC paper, supporting symmetric/asymmetric quantization modes,
    positive-only quantization, and various clipping strategies for optimal hardware
    deployment.

    Args:
        data_float (torch.Tensor): Input floating-point data to be quantized
        symmetric (bool): Whether to use symmetric quantization (default: True)
        bit (int): Quantization bit width (default: 8)
        clamp_std (float): Standard deviation-based clamping threshold (default: None)
        th_point (str): Threshold point calculation mode ('max' or 'min', default: 'max')
        th_scale (float): Scale factor for threshold adjustment (default: None)
        all_positive (bool): Whether input data is all positive (default: False)

    Returns:
        torch.Tensor: Quantized data in floating-point format

    Raises:
        NotImplementedError: Function has been masked for testing purposes
    """
    raise NotImplementedError("This function has been masked for testing purposes")

def data_quantization_int(data_float, symmetric = True, bit = 8, clamp_std = None,
                        th_point='max', th_scale=None, all_positive=False):
    # data_float -> Input data needs to be quantized
    # symmetric -> whether use symmetric quantized
    # bit -> quant bits
    # clamp_std -> Clamp data_float to [- std * clamp_std, std * clamp_std]
    # th_point -> clamp data_float mode
    # th_scale -> scale the clamp thred, used together with th_point
    # all_positive -> whether data_float is all positive

    std = data_float.std()
    max_data = data_float.max()
    min_data = data_float.min()
    # if min_data.item() >= 0:
    #     all_positive = True

    if clamp_std != None and clamp_std != 0 and th_scale != None:
        raise ValueError("clamp_std and th_scale, only one clamp method can be used. ")
    if clamp_std != None and clamp_std != 0:
        data_float = torch.clamp(data_float, min = -clamp_std * std, max = clamp_std * std)
    else:
        if min_data.item() * max_data.item() < 0. and th_point == 'min':
            th = min(max_data.abs().item(), min_data.abs().item())
        else:
            th = max(max_data.abs().item(), min_data.abs().item())
        if th_scale != None:
            th *= th_scale
        data_float = torch.clamp(data_float, min = -th, max = th)

    if all_positive:
        if data_float.min().item() < 0:
            raise ValueError("all_positive uniform_quantizer's data_float is not all positive. ")
        data_range = data_float.max()
        quant_range = 2**bit-1
        zero_point = 0
    elif symmetric:
        data_range = 2*abs(data_float).max()
        quant_range = 2**bit - 2
        zero_point = 0
    else:
        data_range = data_float.max() - data_float.min()
        quant_range = 2**bit - 1
        zero_point = data_float.min() / data_range * quant_range

    if data_range == 0:
        return data_float, 1

    scale = data_range / quant_range
    data_quantized = (round_pass(data_float / scale - zero_point) + zero_point) * scale

    if zero_point != 0:
        raise ValueError("asymmetric uniform quantizer can not be valid next step yet. ")

    return round_pass(data_float / scale - zero_point), scale.item()

class uniform_quantizer(nn.Module):
    def __init__(self, symmetric=False, bit=4, clamp_std=0, th_point='max', th_scale=None, all_positive=False, noise_scale=0,
                noise_method='add', noise_range='max', int_flag=False, *args, **kwargs):
        # symmetric -> whether use symmetric quantized
        # bit -> quant bits
        # clamp_std -> Clamp data_float to [- std * clamp_std, std * clamp_std]
        # th_point -> clamp data_float mode
        # th_scale -> scale the clamp thred, used together with th_point
        # all_positive -> whether data_float is all positive
        # noise_scale -> noise scale
        # noise_method -> noise method, {'add', 'mul'}
        # noise_range -> noise range, activated when noise_method is 'add'
        super(uniform_quantizer, self).__init__()
        self.symmetric = symmetric
        self.bit = bit
        self.clamp_std = clamp_std
        self.th_point = th_point


Complete the function implementation replacing "raise NotImplementedError".