def _convert_and_retrieve_exported_program_op_mapping(
    model: "ExportedProgram",
    **converter_kwargs,
) -> Tuple[MLModel, Dict[torch.fx.Node, List[proto.MIL_pb2.Operation]]]:
    """
    Converts an ``ExportedProgram`` to a Core ML model and returns the
    mapping information mapping between `torch.fx.Node` and their
    corresponding operations in the converted Core ML model.

    Parameters
    ----------
    model : ExportedProgram
        The source model.

    **converter_kwargs:
        Additional keyword arguments to be passed to the Core ML conversion process.
        These can include options for optimization, input/output specifications, etc.

    Returns
    -------
    Tuple[MLModel, Dict[torch.fx.Node, List[proto.MIL_pb2.Operation]]]
        A tuple containing:
            - The converted Core ML model.
            - A dictionary-like object mapping each ``torch.fx.Node`` from the source model
              to a list of corresponding MIL operations in the Core ML model.
              This mapping helps trace the origin of operations in the converted
              model back to the source model for debugging and analysis.

    Examples
    --------
    .. sourcecode:: python
    
        (
            target_model,
            op_mapping,
        ) = coremltools.models.ml_program.experimental.torch._convert_and_retrieve_exported_program_op_mapping(
            model=program,
            inputs=[
                coremltools.TensorType(
                    name="x", shape=example_inputs[0].shape, dtype=np.float16
                ),
                coremltools.TensorType(
                    name="y", shape=example_inputs[1].shape, dtype=np.float16
                ),
            ],
            minimum_deployment_target=coremltools.target.iOS16,
            compute_units=coremltools.ComputeUnit.CPU_ONLY,
            skip_model_load=True,
        )
    """
    # Importing here to avoid circular import issues
    from .....converters import convert

    debug_handle = 1
    source_nodes = {}
    graph_module = model.graph_module
    for node in graph_module.graph.nodes:
        node.meta["debug_handle"] = debug_handle
        source_nodes[debug_handle] = node
        debug_handle += 1

    target_model = convert(
        model=model,
        **converter_kwargs,
    )

    output_name_to_op_map = _create_output_name_to_op_map_from_spec(
        spec=target_model.get_spec(),
        function_name="main",
    )

    program = target_model._mil_program
    block = program.functions["main"]
    source_to_target_ops = {source_node: [] for source_node in source_nodes.values()}
    for op in block.operations:
        scopes = op.scopes[ScopeSource.EXIR_DEBUG_HANDLE]
        debug_handle = scopes[-1] if isinstance(scopes, (list, tuple)) else None
        if debug_handle is None:
            continue

        source_op = source_nodes.get(debug_handle, None)
        if source_op is not None:
            output_names = [output.name for output in op.outputs]
            target_ops = [
                output_name_to_op_map.get(output_name, None) for output_name in output_names
            ]
            target_ops = list(filter(lambda op: op is not None, target_ops))
            source_to_target_ops[source_op].extend(target_ops)

    return (target_model, source_to_target_ops)

    Converts an ``ExportedProgram`` to a Core ML model and returns the
    mapping information mapping between `torch.fx.Node` and their
    corresponding operations in the converted Core ML model.

    Parameters
    ----------
    model : ExportedProgram
        The source model.

    **converter_kwargs:
        Additional keyword arguments to be passed to the Core ML conversion process.
        These can include options for optimization, input/output specifications, etc.

    Returns
    -------
    Tuple[MLModel, Dict[torch.fx.Node, List[proto.MIL_pb2.Operation]]]
        A tuple containing:
            - The converted Core ML model.
            - A dictionary-like object mapping each ``torch.fx.Node`` from the source model
              to a list of corresponding MIL operations in the Core ML model.
              This mapping helps trace the origin of operations in the converted
              model back to the source model for debugging and analysis.

    Examples
    --------
    .. sourcecode:: python
    
        (
            target_model,
            op_mapping,
        ) = coremltools.models.ml_program.experimental.torch._convert_and_retrieve_exported_program_op_mapping(
            model=program,
            inputs=[
                coremltools.TensorType(
                    name="x", shape=example_inputs[0].shape, dtype=np.float16
                ),
                coremltools.TensorType(
                    name="y", shape=example_inputs[1].shape, dtype=np.float16
                ),
            ],
            minimum_deployment_target=coremltools.target.iOS16,
            compute_units=coremltools.ComputeUnit.CPU_ONLY,
            skip_model_load=True,
        )
    
coremltools/models/ml_program/experimental/torch/debugging_utils.py