Project: s41467-025-56623-1 | Function: scRNA_seq_normalization (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 CLTS (Count based on Linearized Transcriptome Size) normalization algorithm that corrects scRNA-seq data by utilizing linear relationships between transcriptome sizes across samples while preserving biological variation between cell types

**KEY TERMS:** {
  "L_Para_LR": "Linear regression parameters (a_i, b_i)",
  "t_v_new": "Normalized expression value",
  "L_v_max": "v_max from equation",
  "t_shift": "(v_max - b_i/a_i)/G shift value"
}

**CONTEXT CODE:** 
def get_LR(p_sp_tp_mean, p_chosen_s, p_fix_idx=0):
    L_rets = {}
    L_fixed_sp = ''
    count = -1
    L_sp_list = []
    for sp in p_sp_tp_mean:
        L_sp_list.append(sp)
    L_sp_list.sort()
    for sp in L_sp_list:
        count += 1
        if count == p_fix_idx:
            L_fixed_sp = sp
            break
    if (p_st_using.upper())[0] == 'Y':
        print('---Fixed sp:', L_fixed_sp)

    L_data_1 = p_sp_tp_mean[L_fixed_sp]
    for sp in p_chosen_s:
        L_data_2 = p_sp_tp_mean[sp]

        Y_list = []
        X_list = []
        X_tp = []
        for idx in range(len(L_data_1)):
            v1 = L_data_1[idx]
            v2 = L_data_2[idx]
            if v1 > 0 and v2 > 0:
                X_list.append([v1, 1])
                Y_list.append(v2)
                X_tp.append(v1)

        # print('\n---+++')
        # print(L_fixed_sp, (X_tp))
        # print(sp, (Y_list))

        x_train = numpy.array(X_list, dtype=numpy.float32)
        y_train = numpy.array(Y_list, dtype=numpy.float32)

        x_train_t = x_train.transpose()
        x_train_mul = numpy.dot(x_train_t, x_train)
        x_train_inv = inv(x_train_mul)
        x_result_ma = numpy.dot(x_train_inv, x_train_t)
        L_para = numpy.dot(x_result_ma, y_train)

        L_rets[sp] = [L_para[0], L_para[1]]
        # print('a=',L_para[0], 'b=', L_para[1])
    return L_rets


def scRNA_seq_normalization(p_exp, p_exp_out, p_meta, p_sp_ctp_tra_size_mean, p_cell_size, p_chosen_samples,
                            p_fixed_sample=0):
    """
    Core CLTS (Count based on Linearized Transcriptome Size) normalization algorithm.

    This function corrects scRNA-seq data by utilizing linear relationships between
    transcriptome sizes across samples while preserving biological variation between
    cell types. It implements the CLTS normalization approach that addresses
    differential expression genes typically misidentified by standard count per 10K
    normalization.

    Args:
        p_exp: Input expression data file path
        p_exp_out: Output normalized expression data file path
        p_meta: Metadata file path containing cell type information
        p_sp_ctp_tra_size_mean: Sample-celltype-transcriptome size mean file path
        p_cell_size: Dictionary of cell sizes
        p_chosen_samples: List of chosen samples for linear regression
        p_fixed_sample: Fixed sample index for normalization (default: 0)

    Returns:
        Normalized expression data written to output file, or 0 if normalization fails
    """
    raise NotImplementedError("This function has been masked for testing purposes")


def get_LR_All(p_sp_tp_mean, p_fix_idx=0):
    L_rets = {}
    L_fixed_sp = ''
    count = -1
    L_sp_list = []
    for sp in p_sp_tp_mean:
        L_sp_list.append(sp)
    L_sp_list.sort()
    for sp in L_sp_list:
        count += 1
        if count == p_fix_idx:
            L_fixed_sp = sp
            break
    if (p_st_using.upper())[0] == 'Y':
        print('---Fixed sp:', L_fixed_sp)

    L_data_1 = p_sp_tp_mean[L_fixed_sp]
    for sp in p_sp_tp_mean:
        L_data_2 = p_sp_tp_mean[sp]

        Y_list = []
        X_list = []
        X_tp = []
        for idx in range(len(L_data_1)):
            v1 = L_data_1[idx]
            v2 = L_data_2[idx]
            if v1 > 0 and v2 > 0:
                X_list.append([v1, 1])
                Y_list.append(v2)
                X_tp.append(v1)

        # print('\n---+++')
        # print(L_fixed_sp, (X_tp))
        # print(sp, (Y_list))

        x_train = numpy.array(X_list, dtype=numpy.float32)
        y_train = numpy.array(Y_list, dtype=numpy.float32)

        x_train_t = x_train.transpose()
        x_train_mul = numpy.dot(x_train_t, x_train)
        x_train_inv = inv(x_train_mul)
        x_result_ma = numpy.dot(x_train_inv, x_train_t)
        L_para = numpy.dot(x_result_ma, y_train)

        L_rets[sp] = [L_para[0], L_para[1]]
        # print('a=',L_para[0], 'b=', L_para[1])
    return L_rets


def scRNA_seq_normalization_All(p_exp, p_exp_out, p_meta, p_sp_ctp_tra_size_mean, p_cell_size, p_fixed_sample=0):
    L_sp_tp_mean = read_sp_tp_mean(p_sp_ctp_tra_size_mean)
    L_Para_LR = get_LR_All(L_sp_tp_mean, p_fixed_sample)

    L_v_max = -100;
    L_a_min = 100
    count = 0
    for sp in L_Para_LR:
        # if (p_st_using.upper())[0] == 'Y':
        #    print(sp,'\ta =',L_Para_LR[sp][0],'\tb =',L_Para_LR[sp][1],'\tratio =',L_Para_LR[sp][1]/L_Para_LR[sp][0])
        if L_Para_LR[sp][0] < L_a_min:
            L_a_min = L_Para_LR[sp][0]
        count += 1
        if count == 1:
            L_v_max = L_Para_LR[sp][1] / L_Para_LR[sp][0]
        else:
            t_ratio = L_Para_LR[sp][1] / L_Para_LR[sp][0]
            if L_v_max < t_ratio:
                L_v_max = t_ratio
        # print('--max ratio: ',L_v_max)
    if L_a_min <= 0:
        if (p_st_using.upper())[0] == 'Y':
            print(
                '!!! As at least one of constant "a" is negative, transcriptome sizes of cell types in at least two samples have problems.\n')
            print(


Complete the function implementation replacing "raise NotImplementedError".