def registration_cpd(
    source: Union[np.ndarray, o3.geometry.PointCloud],
    target: Union[np.ndarray, o3.geometry.PointCloud],
    tf_type_name: str = "rigid",
    w: float = 0.0,
    maxiter: int = 50,
    tol: float = 0.001,
    callbacks: List[Callable] = [],
    use_color: bool = False,
    use_cuda: bool = False,
    **kwargs: Any,
) -> MstepResult:
    """CPD Registraion.

    Args:
        source (numpy.ndarray): Source point cloud data.
        target (numpy.ndarray): Target point cloud data.
        tf_type_name (str, optional): Transformation type('rigid', 'affine', 'nonrigid', 'nonrigid_constrained')
        w (float, optional): Weight of the uniform distribution, 0 < `w` < 1.
        maxitr (int, optional): Maximum number of iterations to EM algorithm.
        tol (float, optional): Tolerance for termination.
        callback (:obj:`list` of :obj:`function`, optional): Called after each iteration.
            `callback(probreg.Transformation)`
        use_color (bool, optional): Use color information (if available).
        use_cuda (bool, optional): Use CUDA.

    Keyword Args:
        update_scale (bool, optional): If this flag is true and tf_type is rigid transformation,
            then the scale is treated. The default is true.
        tf_init_params (dict, optional): Parameters to initialize transformation (for rigid or affine).

    Returns:
        MstepResult: Result of the registration (transformation, sigma2, q)
    """
    xp = np
    if use_cuda:
        import cupy as cp

        xp = cp
    if use_color:
        cv = (
            lambda x: xp.c_[xp.asarray(x.points), xp.asarray(x.colors)]
            if isinstance(x, o3.geometry.PointCloud)
            else xp.asanyarray(x)[:, :6]
        )
    else:
        cv = lambda x: xp.asarray(x.points if isinstance(x, o3.geometry.PointCloud) else x)[
            :, : CoherentPointDrift._N_DIM
        ]
    if tf_type_name == "rigid":
        cpd = RigidCPD(cv(source), use_color=use_color, use_cuda=use_cuda, **kwargs)
    elif tf_type_name == "affine":
        cpd = AffineCPD(cv(source), use_color=use_color, use_cuda=use_cuda, **kwargs)
    elif tf_type_name == "nonrigid":
        cpd = NonRigidCPD(cv(source), use_color=use_color, use_cuda=use_cuda, **kwargs)
    elif tf_type_name == "nonrigid_constrained":
        cpd = ConstrainedNonRigidCPD(cv(source), use_color=use_color, use_cuda=use_cuda, **kwargs)
    else:
        raise ValueError("Unknown transformation type %s" % tf_type_name)
    cpd.set_callbacks(callbacks)
    return cpd.registration(cv(target), w, maxiter, tol)
CPD Registraion.

    Args:
        source (numpy.ndarray): Source point cloud data.
        target (numpy.ndarray): Target point cloud data.
        tf_type_name (str, optional): Transformation type('rigid', 'affine', 'nonrigid', 'nonrigid_constrained')
        w (float, optional): Weight of the uniform distribution, 0 < `w` < 1.
        maxitr (int, optional): Maximum number of iterations to EM algorithm.
        tol (float, optional): Tolerance for termination.
        callback (:obj:`list` of :obj:`function`, optional): Called after each iteration.
            `callback(probreg.Transformation)`
        use_color (bool, optional): Use color information (if available).
        use_cuda (bool, optional): Use CUDA.

    Keyword Args:
        update_scale (bool, optional): If this flag is true and tf_type is rigid transformation,
            then the scale is treated. The default is true.
        tf_init_params (dict, optional): Parameters to initialize transformation (for rigid or affine).

    Returns:
        MstepResult: Result of the registration (transformation, sigma2, q)
    
probreg/cpd.py