# This file was auto generated by Styx.
# Do not edit this file directly.

import typing
import pathlib
from styxdefs import *

MRREGISTER_METADATA = Metadata(
    id="33094a24a1ceaa262f78a671f02e86741a74a3db.boutiques",
    name="mrregister",
    package="mrtrix",
    container_image_tag="mrtrix3/mrtrix3:3.0.4",
)


_MrregisterTransformedParamsDictNoTag = typing.TypedDict('_MrregisterTransformedParamsDictNoTag', {
    "image": str,
})
MrregisterTransformedParamsDictTagged = typing.TypedDict('MrregisterTransformedParamsDictTagged', {
    "@type": typing.Literal["transformed"],
    "image": str,
})
MrregisterTransformedParamsDict = _MrregisterTransformedParamsDictNoTag | MrregisterTransformedParamsDictTagged


_MrregisterTransformedMidwayParamsDictNoTag = typing.TypedDict('_MrregisterTransformedMidwayParamsDictNoTag', {
    "image1_transformed": str,
    "image2_transformed": str,
})
MrregisterTransformedMidwayParamsDictTagged = typing.TypedDict('MrregisterTransformedMidwayParamsDictTagged', {
    "@type": typing.Literal["transformed_midway"],
    "image1_transformed": str,
    "image2_transformed": str,
})
MrregisterTransformedMidwayParamsDict = _MrregisterTransformedMidwayParamsDictNoTag | MrregisterTransformedMidwayParamsDictTagged


_MrregisterNlWarpParamsDictNoTag = typing.TypedDict('_MrregisterNlWarpParamsDictNoTag', {
    "warp1": str,
    "warp2": str,
})
MrregisterNlWarpParamsDictTagged = typing.TypedDict('MrregisterNlWarpParamsDictTagged', {
    "@type": typing.Literal["nl_warp"],
    "warp1": str,
    "warp2": str,
})
MrregisterNlWarpParamsDict = _MrregisterNlWarpParamsDictNoTag | MrregisterNlWarpParamsDictTagged


_MrregisterConfigParamsDictNoTag = typing.TypedDict('_MrregisterConfigParamsDictNoTag', {
    "key": str,
    "value": str,
})
MrregisterConfigParamsDictTagged = typing.TypedDict('MrregisterConfigParamsDictTagged', {
    "@type": typing.Literal["config"],
    "key": str,
    "value": str,
})
MrregisterConfigParamsDict = _MrregisterConfigParamsDictNoTag | MrregisterConfigParamsDictTagged


_MrregisterParamsDictNoTag = typing.TypedDict('_MrregisterParamsDictNoTag', {
    "type": typing.NotRequired[str | None],
    "transformed": typing.NotRequired[list[MrregisterTransformedParamsDict] | None],
    "transformed_midway": typing.NotRequired[list[MrregisterTransformedMidwayParamsDict] | None],
    "mask1": typing.NotRequired[InputPathType | None],
    "mask2": typing.NotRequired[InputPathType | None],
    "nan": bool,
    "rigid": typing.NotRequired[str | None],
    "rigid_1tomidway": typing.NotRequired[str | None],
    "rigid_2tomidway": typing.NotRequired[str | None],
    "rigid_init_translation": typing.NotRequired[str | None],
    "rigid_init_rotation": typing.NotRequired[str | None],
    "rigid_init_matrix": typing.NotRequired[InputPathType | None],
    "rigid_scale": typing.NotRequired[list[float] | None],
    "rigid_niter": typing.NotRequired[list[int] | None],
    "rigid_metric": typing.NotRequired[str | None],
    "rigid_metric_diff_estimator": typing.NotRequired[str | None],
    "rigid_lmax": typing.NotRequired[list[int] | None],
    "rigid_log": typing.NotRequired[str | None],
    "affine": typing.NotRequired[str | None],
    "affine_1tomidway": typing.NotRequired[str | None],
    "affine_2tomidway": typing.NotRequired[str | None],
    "affine_init_translation": typing.NotRequired[str | None],
    "affine_init_rotation": typing.NotRequired[str | None],
    "affine_init_matrix": typing.NotRequired[InputPathType | None],
    "affine_scale": typing.NotRequired[list[float] | None],
    "affine_niter": typing.NotRequired[list[int] | None],
    "affine_metric": typing.NotRequired[str | None],
    "affine_metric_diff_estimator": typing.NotRequired[str | None],
    "affine_lmax": typing.NotRequired[list[int] | None],
    "affine_log": typing.NotRequired[str | None],
    "init_translation_unmasked1": bool,
    "init_translation_unmasked2": bool,
    "init_rotation_unmasked1": bool,
    "init_rotation_unmasked2": bool,
    "init_rotation_search_angles": typing.NotRequired[list[float] | None],
    "init_rotation_search_scale": typing.NotRequired[float | None],
    "init_rotation_search_directions": typing.NotRequired[int | None],
    "init_rotation_search_run_global": bool,
    "init_rotation_search_global_iterations": typing.NotRequired[int | None],
    "linstage_iterations": typing.NotRequired[list[int] | None],
    "linstage_optimiser_first": typing.NotRequired[str | None],
    "linstage_optimiser_last": typing.NotRequired[str | None],
    "linstage_optimiser_default": typing.NotRequired[str | None],
    "linstage_diagnostics_prefix": typing.NotRequired[str | None],
    "nl_warp": typing.NotRequired[MrregisterNlWarpParamsDict | None],
    "nl_warp_full": typing.NotRequired[str | None],
    "nl_init": typing.NotRequired[InputPathType | None],
    "nl_scale": typing.NotRequired[list[float] | None],
    "nl_niter": typing.NotRequired[list[int] | None],
    "nl_update_smooth": typing.NotRequired[float | None],
    "nl_disp_smooth": typing.NotRequired[float | None],
    "nl_grad_step": typing.NotRequired[float | None],
    "nl_lmax": typing.NotRequired[list[int] | None],
    "diagnostics_image": typing.NotRequired[str | None],
    "directions": typing.NotRequired[InputPathType | None],
    "noreorientation": bool,
    "mc_weights": typing.NotRequired[list[float] | None],
    "datatype": typing.NotRequired[str | None],
    "info": bool,
    "quiet": bool,
    "debug": bool,
    "force": bool,
    "nthreads": typing.NotRequired[int | None],
    "config": typing.NotRequired[list[MrregisterConfigParamsDict] | None],
    "help": bool,
    "version": bool,
    "image1_image2": InputPathType,
    "contrast1_contrast2": typing.NotRequired[list[InputPathType] | None],
})
MrregisterParamsDictTagged = typing.TypedDict('MrregisterParamsDictTagged', {
    "@type": typing.Literal["mrtrix/mrregister"],
    "type": typing.NotRequired[str | None],
    "transformed": typing.NotRequired[list[MrregisterTransformedParamsDict] | None],
    "transformed_midway": typing.NotRequired[list[MrregisterTransformedMidwayParamsDict] | None],
    "mask1": typing.NotRequired[InputPathType | None],
    "mask2": typing.NotRequired[InputPathType | None],
    "nan": bool,
    "rigid": typing.NotRequired[str | None],
    "rigid_1tomidway": typing.NotRequired[str | None],
    "rigid_2tomidway": typing.NotRequired[str | None],
    "rigid_init_translation": typing.NotRequired[str | None],
    "rigid_init_rotation": typing.NotRequired[str | None],
    "rigid_init_matrix": typing.NotRequired[InputPathType | None],
    "rigid_scale": typing.NotRequired[list[float] | None],
    "rigid_niter": typing.NotRequired[list[int] | None],
    "rigid_metric": typing.NotRequired[str | None],
    "rigid_metric_diff_estimator": typing.NotRequired[str | None],
    "rigid_lmax": typing.NotRequired[list[int] | None],
    "rigid_log": typing.NotRequired[str | None],
    "affine": typing.NotRequired[str | None],
    "affine_1tomidway": typing.NotRequired[str | None],
    "affine_2tomidway": typing.NotRequired[str | None],
    "affine_init_translation": typing.NotRequired[str | None],
    "affine_init_rotation": typing.NotRequired[str | None],
    "affine_init_matrix": typing.NotRequired[InputPathType | None],
    "affine_scale": typing.NotRequired[list[float] | None],
    "affine_niter": typing.NotRequired[list[int] | None],
    "affine_metric": typing.NotRequired[str | None],
    "affine_metric_diff_estimator": typing.NotRequired[str | None],
    "affine_lmax": typing.NotRequired[list[int] | None],
    "affine_log": typing.NotRequired[str | None],
    "init_translation_unmasked1": bool,
    "init_translation_unmasked2": bool,
    "init_rotation_unmasked1": bool,
    "init_rotation_unmasked2": bool,
    "init_rotation_search_angles": typing.NotRequired[list[float] | None],
    "init_rotation_search_scale": typing.NotRequired[float | None],
    "init_rotation_search_directions": typing.NotRequired[int | None],
    "init_rotation_search_run_global": bool,
    "init_rotation_search_global_iterations": typing.NotRequired[int | None],
    "linstage_iterations": typing.NotRequired[list[int] | None],
    "linstage_optimiser_first": typing.NotRequired[str | None],
    "linstage_optimiser_last": typing.NotRequired[str | None],
    "linstage_optimiser_default": typing.NotRequired[str | None],
    "linstage_diagnostics_prefix": typing.NotRequired[str | None],
    "nl_warp": typing.NotRequired[MrregisterNlWarpParamsDict | None],
    "nl_warp_full": typing.NotRequired[str | None],
    "nl_init": typing.NotRequired[InputPathType | None],
    "nl_scale": typing.NotRequired[list[float] | None],
    "nl_niter": typing.NotRequired[list[int] | None],
    "nl_update_smooth": typing.NotRequired[float | None],
    "nl_disp_smooth": typing.NotRequired[float | None],
    "nl_grad_step": typing.NotRequired[float | None],
    "nl_lmax": typing.NotRequired[list[int] | None],
    "diagnostics_image": typing.NotRequired[str | None],
    "directions": typing.NotRequired[InputPathType | None],
    "noreorientation": bool,
    "mc_weights": typing.NotRequired[list[float] | None],
    "datatype": typing.NotRequired[str | None],
    "info": bool,
    "quiet": bool,
    "debug": bool,
    "force": bool,
    "nthreads": typing.NotRequired[int | None],
    "config": typing.NotRequired[list[MrregisterConfigParamsDict] | None],
    "help": bool,
    "version": bool,
    "image1_image2": InputPathType,
    "contrast1_contrast2": typing.NotRequired[list[InputPathType] | None],
})
MrregisterParamsDict = _MrregisterParamsDictNoTag | MrregisterParamsDictTagged


class MrregisterTransformedOutputs(typing.NamedTuple):
    """
    Output object returned when calling `list[MrregisterTransformedParamsDict] | None(...)`.
    """
    root: OutputPathType
    """Output root folder. This is the root folder for all outputs."""
    image: OutputPathType
    """image1 after registration transformed and regridded to the space of
    image2. Note that -transformed needs to be repeated for each contrast if
    multi-contrast registration is used."""


def mrregister_transformed(
    image: str,
) -> MrregisterTransformedParamsDictTagged:
    """
    Build parameters.
    
    Args:
        image: image1 after registration transformed and regridded to the space\
            of image2. Note that -transformed needs to be repeated for each\
            contrast if multi-contrast registration is used.
    Returns:
        Parameter dictionary
    """
    params = {
        "@type": "transformed",
        "image": image,
    }
    return params


def mrregister_transformed_validate(
    params: typing.Any,
) -> None:
    """
    Validate parameters. Throws an error if `params` is not a valid
    `MrregisterTransformedParamsDict` object.
    
    Args:
        params: The parameters object to validate.
    """
    if params is None or not isinstance(params, dict):
        raise StyxValidationError(f'Params object has the wrong type \'{type(params)}\'')
    if params.get("image", None) is None:
        raise StyxValidationError("`image` must not be None")
    if not isinstance(params["image"], str):
        raise StyxValidationError(f'`image` has the wrong type: Received `{type(params.get("image", None))}` expected `str`')


def mrregister_transformed_cargs(
    params: MrregisterTransformedParamsDict,
    execution: Execution,
) -> list[str]:
    """
    Build command-line arguments from parameters.
    
    Args:
        params: The parameters.
        execution: The execution object for resolving input paths.
    Returns:
        Command-line arguments.
    """
    cargs = []
    cargs.append("-transformed")
    cargs.append(params.get("image", None))
    return cargs


def mrregister_transformed_outputs(
    params: MrregisterTransformedParamsDict,
    execution: Execution,
) -> MrregisterTransformedOutputs:
    """
    Build outputs object containing output file paths and possibly stdout/stderr.
    
    Args:
        params: The parameters.
        execution: The execution object for resolving input paths.
    Returns:
        Outputs object.
    """
    ret = MrregisterTransformedOutputs(
        root=execution.output_file("."),
        image=execution.output_file(params.get("image", None)),
    )
    return ret


class MrregisterTransformedMidwayOutputs(typing.NamedTuple):
    """
    Output object returned when calling `list[MrregisterTransformedMidwayParamsDict] | None(...)`.
    """
    root: OutputPathType
    """Output root folder. This is the root folder for all outputs."""
    image1_transformed: OutputPathType
    """image1 and image2 after registration transformed and regridded to the
    midway space. Note that -transformed_midway needs to be repeated for each
    contrast if multi-contrast registration is used."""
    image2_transformed: OutputPathType
    """image1 and image2 after registration transformed and regridded to the
    midway space. Note that -transformed_midway needs to be repeated for each
    contrast if multi-contrast registration is used."""


def mrregister_transformed_midway(
    image1_transformed: str,
    image2_transformed: str,
) -> MrregisterTransformedMidwayParamsDictTagged:
    """
    Build parameters.
    
    Args:
        image1_transformed: image1 and image2 after registration transformed\
            and regridded to the midway space. Note that -transformed_midway needs\
            to be repeated for each contrast if multi-contrast registration is\
            used.
        image2_transformed: image1 and image2 after registration transformed\
            and regridded to the midway space. Note that -transformed_midway needs\
            to be repeated for each contrast if multi-contrast registration is\
            used.
    Returns:
        Parameter dictionary
    """
    params = {
        "@type": "transformed_midway",
        "image1_transformed": image1_transformed,
        "image2_transformed": image2_transformed,
    }
    return params


def mrregister_transformed_midway_validate(
    params: typing.Any,
) -> None:
    """
    Validate parameters. Throws an error if `params` is not a valid
    `MrregisterTransformedMidwayParamsDict` object.
    
    Args:
        params: The parameters object to validate.
    """
    if params is None or not isinstance(params, dict):
        raise StyxValidationError(f'Params object has the wrong type \'{type(params)}\'')
    if params.get("image1_transformed", None) is None:
        raise StyxValidationError("`image1_transformed` must not be None")
    if not isinstance(params["image1_transformed"], str):
        raise StyxValidationError(f'`image1_transformed` has the wrong type: Received `{type(params.get("image1_transformed", None))}` expected `str`')
    if params.get("image2_transformed", None) is None:
        raise StyxValidationError("`image2_transformed` must not be None")
    if not isinstance(params["image2_transformed"], str):
        raise StyxValidationError(f'`image2_transformed` has the wrong type: Received `{type(params.get("image2_transformed", None))}` expected `str`')


def mrregister_transformed_midway_cargs(
    params: MrregisterTransformedMidwayParamsDict,
    execution: Execution,
) -> list[str]:
    """
    Build command-line arguments from parameters.
    
    Args:
        params: The parameters.
        execution: The execution object for resolving input paths.
    Returns:
        Command-line arguments.
    """
    cargs = []
    cargs.append("-transformed_midway")
    cargs.append(params.get("image1_transformed", None))
    cargs.append(params.get("image2_transformed", None))
    return cargs


def mrregister_transformed_midway_outputs(
    params: MrregisterTransformedMidwayParamsDict,
    execution: Execution,
) -> MrregisterTransformedMidwayOutputs:
    """
    Build outputs object containing output file paths and possibly stdout/stderr.
    
    Args:
        params: The parameters.
        execution: The execution object for resolving input paths.
    Returns:
        Outputs object.
    """
    ret = MrregisterTransformedMidwayOutputs(
        root=execution.output_file("."),
        image1_transformed=execution.output_file(params.get("image1_transformed", None)),
        image2_transformed=execution.output_file(params.get("image2_transformed", None)),
    )
    return ret


class MrregisterNlWarpOutputs(typing.NamedTuple):
    """
    Output object returned when calling `MrregisterNlWarpParamsDict | None(...)`.
    """
    root: OutputPathType
    """Output root folder. This is the root folder for all outputs."""
    warp1: OutputPathType
    """the non-linear warp output defined as two deformation fields, where warp1
    can be used to transform image1->image2 and warp2 to transform
    image2->image1. The deformation fields also encapsulate any linear
    transformation estimated prior to non-linear registration."""
    warp2: OutputPathType
    """the non-linear warp output defined as two deformation fields, where warp1
    can be used to transform image1->image2 and warp2 to transform
    image2->image1. The deformation fields also encapsulate any linear
    transformation estimated prior to non-linear registration."""


def mrregister_nl_warp(
    warp1: str,
    warp2: str,
) -> MrregisterNlWarpParamsDictTagged:
    """
    Build parameters.
    
    Args:
        warp1: the non-linear warp output defined as two deformation fields,\
            where warp1 can be used to transform image1->image2 and warp2 to\
            transform image2->image1. The deformation fields also encapsulate any\
            linear transformation estimated prior to non-linear registration.
        warp2: the non-linear warp output defined as two deformation fields,\
            where warp1 can be used to transform image1->image2 and warp2 to\
            transform image2->image1. The deformation fields also encapsulate any\
            linear transformation estimated prior to non-linear registration.
    Returns:
        Parameter dictionary
    """
    params = {
        "@type": "nl_warp",
        "warp1": warp1,
        "warp2": warp2,
    }
    return params


def mrregister_nl_warp_validate(
    params: typing.Any,
) -> None:
    """
    Validate parameters. Throws an error if `params` is not a valid
    `MrregisterNlWarpParamsDict` object.
    
    Args:
        params: The parameters object to validate.
    """
    if params is None or not isinstance(params, dict):
        raise StyxValidationError(f'Params object has the wrong type \'{type(params)}\'')
    if params.get("warp1", None) is None:
        raise StyxValidationError("`warp1` must not be None")
    if not isinstance(params["warp1"], str):
        raise StyxValidationError(f'`warp1` has the wrong type: Received `{type(params.get("warp1", None))}` expected `str`')
    if params.get("warp2", None) is None:
        raise StyxValidationError("`warp2` must not be None")
    if not isinstance(params["warp2"], str):
        raise StyxValidationError(f'`warp2` has the wrong type: Received `{type(params.get("warp2", None))}` expected `str`')


def mrregister_nl_warp_cargs(
    params: MrregisterNlWarpParamsDict,
    execution: Execution,
) -> list[str]:
    """
    Build command-line arguments from parameters.
    
    Args:
        params: The parameters.
        execution: The execution object for resolving input paths.
    Returns:
        Command-line arguments.
    """
    cargs = []
    cargs.append("-nl_warp")
    cargs.append(params.get("warp1", None))
    cargs.append(params.get("warp2", None))
    return cargs


def mrregister_nl_warp_outputs(
    params: MrregisterNlWarpParamsDict,
    execution: Execution,
) -> MrregisterNlWarpOutputs:
    """
    Build outputs object containing output file paths and possibly stdout/stderr.
    
    Args:
        params: The parameters.
        execution: The execution object for resolving input paths.
    Returns:
        Outputs object.
    """
    ret = MrregisterNlWarpOutputs(
        root=execution.output_file("."),
        warp1=execution.output_file(params.get("warp1", None)),
        warp2=execution.output_file(params.get("warp2", None)),
    )
    return ret


def mrregister_config(
    key: str,
    value: str,
) -> MrregisterConfigParamsDictTagged:
    """
    Build parameters.
    
    Args:
        key: temporarily set the value of an MRtrix config file entry.
        value: temporarily set the value of an MRtrix config file entry.
    Returns:
        Parameter dictionary
    """
    params = {
        "@type": "config",
        "key": key,
        "value": value,
    }
    return params


def mrregister_config_validate(
    params: typing.Any,
) -> None:
    """
    Validate parameters. Throws an error if `params` is not a valid
    `MrregisterConfigParamsDict` object.
    
    Args:
        params: The parameters object to validate.
    """
    if params is None or not isinstance(params, dict):
        raise StyxValidationError(f'Params object has the wrong type \'{type(params)}\'')
    if params.get("key", None) is None:
        raise StyxValidationError("`key` must not be None")
    if not isinstance(params["key"], str):
        raise StyxValidationError(f'`key` has the wrong type: Received `{type(params.get("key", None))}` expected `str`')
    if params.get("value", None) is None:
        raise StyxValidationError("`value` must not be None")
    if not isinstance(params["value"], str):
        raise StyxValidationError(f'`value` has the wrong type: Received `{type(params.get("value", None))}` expected `str`')


def mrregister_config_cargs(
    params: MrregisterConfigParamsDict,
    execution: Execution,
) -> list[str]:
    """
    Build command-line arguments from parameters.
    
    Args:
        params: The parameters.
        execution: The execution object for resolving input paths.
    Returns:
        Command-line arguments.
    """
    cargs = []
    cargs.append("-config")
    cargs.append(params.get("key", None))
    cargs.append(params.get("value", None))
    return cargs


class MrregisterOutputs(typing.NamedTuple):
    """
    Output object returned when calling `MrregisterParamsDict(...)`.
    """
    root: OutputPathType
    """Output root folder. This is the root folder for all outputs."""
    rigid: OutputPathType | None
    """the output text file containing the rigid transformation as a 4x4 matrix
    """
    rigid_1tomidway: OutputPathType | None
    """the output text file containing the rigid transformation that aligns
    image1 to image2 in their common midway space as a 4x4 matrix """
    rigid_2tomidway: OutputPathType | None
    """the output text file containing the rigid transformation that aligns
    image2 to image1 in their common midway space as a 4x4 matrix """
    rigid_log: OutputPathType | None
    """write gradient descent parameter evolution to log file """
    affine: OutputPathType | None
    """the output text file containing the affine transformation as a 4x4 matrix
    """
    affine_1tomidway: OutputPathType | None
    """the output text file containing the affine transformation that aligns
    image1 to image2 in their common midway space as a 4x4 matrix """
    affine_2tomidway: OutputPathType | None
    """the output text file containing the affine transformation that aligns
    image2 to image1 in their common midway space as a 4x4 matrix """
    affine_log: OutputPathType | None
    """write gradient descent parameter evolution to log file """
    nl_warp_full: OutputPathType | None
    """output all warps used during registration. This saves four different
    warps that map each image to a midway space and their inverses in a single
    5D image file. The 4th image dimension indexes the x,y,z component of the
    deformation vector and the 5th dimension indexes the field in this order:
    image1->midway, midway->image1, image2->midway, midway->image2. Where
    image1->midway defines the field that maps image1 onto the midway space
    using the reverse convention When linear registration is performed first,
    the estimated linear transform will be included in the comments of the image
    header, and therefore the entire linear and non-linear transform can be
    applied (in either direction) using this output warp file with mrtransform
    """
    transformed: list[MrregisterTransformedOutputs] | None
    """Outputs from `mrregister_transformed_outputs`.This is a list of outputs
    with the same length and order as the inputs."""
    transformed_midway: list[MrregisterTransformedMidwayOutputs] | None
    """Outputs from `mrregister_transformed_midway_outputs`.This is a list of
    outputs with the same length and order as the inputs."""
    nl_warp: MrregisterNlWarpOutputs | None
    """Outputs from `mrregister_nl_warp_outputs`."""


def mrregister_params(
    image1_image2: InputPathType,
    type_: str | None = None,
    transformed: list[MrregisterTransformedParamsDict] | None = None,
    transformed_midway: list[MrregisterTransformedMidwayParamsDict] | None = None,
    mask1: InputPathType | None = None,
    mask2: InputPathType | None = None,
    nan: bool = False,
    rigid: str | None = None,
    rigid_1tomidway: str | None = None,
    rigid_2tomidway: str | None = None,
    rigid_init_translation: str | None = None,
    rigid_init_rotation: str | None = None,
    rigid_init_matrix: InputPathType | None = None,
    rigid_scale: list[float] | None = None,
    rigid_niter: list[int] | None = None,
    rigid_metric: str | None = None,
    rigid_metric_diff_estimator: str | None = None,
    rigid_lmax: list[int] | None = None,
    rigid_log: str | None = None,
    affine: str | None = None,
    affine_1tomidway: str | None = None,
    affine_2tomidway: str | None = None,
    affine_init_translation: str | None = None,
    affine_init_rotation: str | None = None,
    affine_init_matrix: InputPathType | None = None,
    affine_scale: list[float] | None = None,
    affine_niter: list[int] | None = None,
    affine_metric: str | None = None,
    affine_metric_diff_estimator: str | None = None,
    affine_lmax: list[int] | None = None,
    affine_log: str | None = None,
    init_translation_unmasked1: bool = False,
    init_translation_unmasked2: bool = False,
    init_rotation_unmasked1: bool = False,
    init_rotation_unmasked2: bool = False,
    init_rotation_search_angles: list[float] | None = None,
    init_rotation_search_scale: float | None = None,
    init_rotation_search_directions: int | None = None,
    init_rotation_search_run_global: bool = False,
    init_rotation_search_global_iterations: int | None = None,
    linstage_iterations: list[int] | None = None,
    linstage_optimiser_first: str | None = None,
    linstage_optimiser_last: str | None = None,
    linstage_optimiser_default: str | None = None,
    linstage_diagnostics_prefix: str | None = None,
    nl_warp: MrregisterNlWarpParamsDict | None = None,
    nl_warp_full: str | None = None,
    nl_init: InputPathType | None = None,
    nl_scale: list[float] | None = None,
    nl_niter: list[int] | None = None,
    nl_update_smooth: float | None = None,
    nl_disp_smooth: float | None = None,
    nl_grad_step: float | None = None,
    nl_lmax: list[int] | None = None,
    diagnostics_image: str | None = None,
    directions: InputPathType | None = None,
    noreorientation: bool = False,
    mc_weights: list[float] | None = None,
    datatype: str | None = None,
    info: bool = False,
    quiet: bool = False,
    debug: bool = False,
    force: bool = False,
    nthreads: int | None = None,
    config: list[MrregisterConfigParamsDict] | None = None,
    help_: bool = False,
    version: bool = False,
    contrast1_contrast2: list[InputPathType] | None = None,
) -> MrregisterParamsDictTagged:
    """
    Build parameters.
    
    Args:
        image1_image2: input image 1 ('moving') and input image 2 ('template').
        type_: the registration type. Valid choices are: rigid, affine,\
            nonlinear, rigid_affine, rigid_nonlinear, affine_nonlinear,\
            rigid_affine_nonlinear (Default: affine_nonlinear).
        transformed: image1 after registration transformed and regridded to the\
            space of image2. Note that -transformed needs to be repeated for each\
            contrast if multi-contrast registration is used.
        transformed_midway: image1 and image2 after registration transformed\
            and regridded to the midway space. Note that -transformed_midway needs\
            to be repeated for each contrast if multi-contrast registration is\
            used.
        mask1: a mask to define the region of image1 to use for optimisation.
        mask2: a mask to define the region of image2 to use for optimisation.
        nan: use NaN as out of bounds value. (Default: 0.0).
        rigid: the output text file containing the rigid transformation as a\
            4x4 matrix.
        rigid_1tomidway: the output text file containing the rigid\
            transformation that aligns image1 to image2 in their common midway\
            space as a 4x4 matrix.
        rigid_2tomidway: the output text file containing the rigid\
            transformation that aligns image2 to image1 in their common midway\
            space as a 4x4 matrix.
        rigid_init_translation: initialise the translation and centre of\
            rotation\
            Valid choices are:\
            mass (aligns the centers of mass of both images, default),\
            geometric (aligns geometric image centres) and none.
        rigid_init_rotation: initialise the rotation Valid choices are:\
            search (search for the best rotation using mean squared residuals),\
            moments (rotation based on directions of intensity variance with\
            respect to centre of mass),\
            none (default).
        rigid_init_matrix: initialise either the rigid, affine, or syn\
            registration with the supplied rigid transformation (as a 4x4 matrix in\
            scanner coordinates). Note that this overrides rigid_init_translation\
            and rigid_init_rotation initialisation.
        rigid_scale: use a multi-resolution scheme by defining a scale factor\
            for each level using comma separated values (Default: 0.25,0.5,1.0).
        rigid_niter: the maximum number of gradient descent iterations per\
            stage. This can be specified either as a single number for all\
            multi-resolution levels, or a single value for each level. (Default:\
            1000).
        rigid_metric: valid choices are: diff (intensity differences), Default:\
            diff.
        rigid_metric_diff_estimator: Valid choices are: l1 (least absolute:\
            |x|), l2 (ordinary least squares), lp (least powers: |x|^1.2), Default:\
            l2.
        rigid_lmax: explicitly set the lmax to be used per scale factor in\
            rigid FOD registration. By default FOD registration will use lmax 0,2,4\
            with default scale factors 0.25,0.5,1.0 respectively. Note that no\
            reorientation will be performed with lmax = 0.
        rigid_log: write gradient descent parameter evolution to log file.
        affine: the output text file containing the affine transformation as a\
            4x4 matrix.
        affine_1tomidway: the output text file containing the affine\
            transformation that aligns image1 to image2 in their common midway\
            space as a 4x4 matrix.
        affine_2tomidway: the output text file containing the affine\
            transformation that aligns image2 to image1 in their common midway\
            space as a 4x4 matrix.
        affine_init_translation: initialise the translation and centre of\
            rotation\
            Valid choices are:\
            mass (aligns the centers of mass of both images),\
            geometric (aligns geometric image centres) and none. (Default:\
            mass).
        affine_init_rotation: initialise the rotation Valid choices are:\
            search (search for the best rotation using mean squared residuals),\
            moments (rotation based on directions of intensity variance with\
            respect to centre of mass),\
            none (Default: none).
        affine_init_matrix: initialise either the affine, or syn registration\
            with the supplied affine transformation (as a 4x4 matrix in scanner\
            coordinates). Note that this overrides affine_init_translation and\
            affine_init_rotation initialisation.
        affine_scale: use a multi-resolution scheme by defining a scale factor\
            for each level using comma separated values (Default: 0.25,0.5,1.0).
        affine_niter: the maximum number of gradient descent iterations per\
            stage. This can be specified either as a single number for all\
            multi-resolution levels, or a single value for each level. (Default:\
            1000).
        affine_metric: valid choices are: diff (intensity differences),\
            Default: diff.
        affine_metric_diff_estimator: Valid choices are: l1 (least absolute:\
            |x|), l2 (ordinary least squares), lp (least powers: |x|^1.2), Default:\
            l2.
        affine_lmax: explicitly set the lmax to be used per scale factor in\
            affine FOD registration. By default FOD registration will use lmax\
            0,2,4 with default scale factors 0.25,0.5,1.0 respectively. Note that\
            no reorientation will be performed with lmax = 0.
        affine_log: write gradient descent parameter evolution to log file.
        init_translation_unmasked1: disregard mask1 for the translation\
            initialisation (affects 'mass').
        init_translation_unmasked2: disregard mask2 for the translation\
            initialisation (affects 'mass').
        init_rotation_unmasked1: disregard mask1 for the rotation\
            initialisation (affects 'search' and 'moments').
        init_rotation_unmasked2: disregard mask2 for the rotation\
            initialisation (affects 'search' and 'moments').
        init_rotation_search_angles: rotation angles for the local search in\
            degrees between 0 and 180. (Default: 2,5,10,15,20).
        init_rotation_search_scale: relative size of the images used for the\
            rotation search. (Default: 0.15).
        init_rotation_search_directions: number of rotation axis for local\
            search. (Default: 250).
        init_rotation_search_run_global: perform a global search. (Default:\
            local).
        init_rotation_search_global_iterations: number of rotations to\
            investigate (Default: 10000).
        linstage_iterations: number of iterations for each registration stage,\
            not to be confused with -rigid_niter or -affine_niter. This can be used\
            to generate intermediate diagnostics images\
            (-linstage.diagnostics.prefix) or to change the cost function optimiser\
            during registration (without the need to repeatedly resize the images).\
            (Default: 1 == no repetition).
        linstage_optimiser_first: Cost function optimisation algorithm to use\
            at first iteration of all stages. Valid choices: bbgd (Barzilai-Borwein\
            gradient descent) or gd (simple gradient descent). (Default: bbgd).
        linstage_optimiser_last: Cost function optimisation algorithm to use at\
            last iteration of all stages (if there are more than one). Valid\
            choices: bbgd (Barzilai-Borwein gradient descent) or gd (simple\
            gradient descent). (Default: bbgd).
        linstage_optimiser_default: Cost function optimisation algorithm to use\
            at any stage iteration other than first or last iteration. Valid\
            choices: bbgd (Barzilai-Borwein gradient descent) or gd (simple\
            gradient descent). (Default: bbgd).
        linstage_diagnostics_prefix: generate diagnostics images after every\
            registration stage.
        nl_warp: the non-linear warp output defined as two deformation fields,\
            where warp1 can be used to transform image1->image2 and warp2 to\
            transform image2->image1. The deformation fields also encapsulate any\
            linear transformation estimated prior to non-linear registration.
        nl_warp_full: output all warps used during registration. This saves\
            four different warps that map each image to a midway space and their\
            inverses in a single 5D image file. The 4th image dimension indexes the\
            x,y,z component of the deformation vector and the 5th dimension indexes\
            the field in this order: image1->midway, midway->image1,\
            image2->midway, midway->image2. Where image1->midway defines the field\
            that maps image1 onto the midway space using the reverse convention\
            When linear registration is performed first, the estimated linear\
            transform will be included in the comments of the image header, and\
            therefore the entire linear and non-linear transform can be applied (in\
            either direction) using this output warp file with mrtransform.
        nl_init: initialise the non-linear registration with the supplied warp\
            image. The supplied warp must be in the same format as output using the\
            -nl_warp_full option (i.e. have 4 deformation fields with the linear\
            transforms in the image header).
        nl_scale: use a multi-resolution scheme by defining a scale factor for\
            each level using comma separated values (Default: 0.25,0.5,1.0).
        nl_niter: the maximum number of iterations. This can be specified\
            either as a single number for all multi-resolution levels, or a single\
            value for each level. (Default: 50).
        nl_update_smooth: regularise the gradient update field with Gaussian\
            smoothing (standard deviation in voxel units, Default 2.0).
        nl_disp_smooth: regularise the displacement field with Gaussian\
            smoothing (standard deviation in voxel units, Default 1.0).
        nl_grad_step: the gradient step size for non-linear registration\
            (Default: 0.5).
        nl_lmax: explicitly set the lmax to be used per scale factor in\
            non-linear FOD registration. By default FOD registration will use lmax\
            0,2,4 with default scale factors 0.25,0.5,1.0 respectively. Note that\
            no reorientation will be performed with lmax = 0.
        diagnostics_image: write intermediate images for diagnostics purposes.
        directions: the directions used for FOD reorientation using apodised\
            point spread functions (Default: 60 directions).
        noreorientation: turn off FOD reorientation. Reorientation is on by\
            default if the number of volumes in the 4th dimension corresponds to\
            the number of coefficients in an antipodally symmetric spherical\
            harmonic series (i.e. 6, 15, 28, 45, 66 etc).
        mc_weights: relative weight of images used for multi-contrast\
            registration. Default: 1.0 (equal weighting).
        datatype: specify output image data type. Valid choices are: float32,\
            float32le, float32be, float64, float64le, float64be, int64, uint64,\
            int64le, uint64le, int64be, uint64be, int32, uint32, int32le, uint32le,\
            int32be, uint32be, int16, uint16, int16le, uint16le, int16be, uint16be,\
            cfloat32, cfloat32le, cfloat32be, cfloat64, cfloat64le, cfloat64be,\
            int8, uint8, bit.
        info: display information messages.
        quiet: do not display information messages or progress status;\
            alternatively, this can be achieved by setting the MRTRIX_QUIET\
            environment variable to a non-empty string.
        debug: display debugging messages.
        force: force overwrite of output files (caution: using the same file as\
            input and output might cause unexpected behaviour).
        nthreads: use this number of threads in multi-threaded applications\
            (set to 0 to disable multi-threading).
        config: temporarily set the value of an MRtrix config file entry.
        help_: display this information page and exit.
        version: display version information and exit.
        contrast1_contrast2: optional list of additional input images used as\
            additional contrasts. Can be used multiple times. contrastX and imageX\
            must share the same coordinate system.
    Returns:
        Parameter dictionary
    """
    params = {
        "@type": "mrtrix/mrregister",
        "nan": nan,
        "init_translation_unmasked1": init_translation_unmasked1,
        "init_translation_unmasked2": init_translation_unmasked2,
        "init_rotation_unmasked1": init_rotation_unmasked1,
        "init_rotation_unmasked2": init_rotation_unmasked2,
        "init_rotation_search_run_global": init_rotation_search_run_global,
        "noreorientation": noreorientation,
        "info": info,
        "quiet": quiet,
        "debug": debug,
        "force": force,
        "help": help_,
        "version": version,
        "image1_image2": image1_image2,
    }
    if type_ is not None:
        params["type"] = type_
    if transformed is not None:
        params["transformed"] = transformed
    if transformed_midway is not None:
        params["transformed_midway"] = transformed_midway
    if mask1 is not None:
        params["mask1"] = mask1
    if mask2 is not None:
        params["mask2"] = mask2
    if rigid is not None:
        params["rigid"] = rigid
    if rigid_1tomidway is not None:
        params["rigid_1tomidway"] = rigid_1tomidway
    if rigid_2tomidway is not None:
        params["rigid_2tomidway"] = rigid_2tomidway
    if rigid_init_translation is not None:
        params["rigid_init_translation"] = rigid_init_translation
    if rigid_init_rotation is not None:
        params["rigid_init_rotation"] = rigid_init_rotation
    if rigid_init_matrix is not None:
        params["rigid_init_matrix"] = rigid_init_matrix
    if rigid_scale is not None:
        params["rigid_scale"] = rigid_scale
    if rigid_niter is not None:
        params["rigid_niter"] = rigid_niter
    if rigid_metric is not None:
        params["rigid_metric"] = rigid_metric
    if rigid_metric_diff_estimator is not None:
        params["rigid_metric_diff_estimator"] = rigid_metric_diff_estimator
    if rigid_lmax is not None:
        params["rigid_lmax"] = rigid_lmax
    if rigid_log is not None:
        params["rigid_log"] = rigid_log
    if affine is not None:
        params["affine"] = affine
    if affine_1tomidway is not None:
        params["affine_1tomidway"] = affine_1tomidway
    if affine_2tomidway is not None:
        params["affine_2tomidway"] = affine_2tomidway
    if affine_init_translation is not None:
        params["affine_init_translation"] = affine_init_translation
    if affine_init_rotation is not None:
        params["affine_init_rotation"] = affine_init_rotation
    if affine_init_matrix is not None:
        params["affine_init_matrix"] = affine_init_matrix
    if affine_scale is not None:
        params["affine_scale"] = affine_scale
    if affine_niter is not None:
        params["affine_niter"] = affine_niter
    if affine_metric is not None:
        params["affine_metric"] = affine_metric
    if affine_metric_diff_estimator is not None:
        params["affine_metric_diff_estimator"] = affine_metric_diff_estimator
    if affine_lmax is not None:
        params["affine_lmax"] = affine_lmax
    if affine_log is not None:
        params["affine_log"] = affine_log
    if init_rotation_search_angles is not None:
        params["init_rotation_search_angles"] = init_rotation_search_angles
    if init_rotation_search_scale is not None:
        params["init_rotation_search_scale"] = init_rotation_search_scale
    if init_rotation_search_directions is not None:
        params["init_rotation_search_directions"] = init_rotation_search_directions
    if init_rotation_search_global_iterations is not None:
        params["init_rotation_search_global_iterations"] = init_rotation_search_global_iterations
    if linstage_iterations is not None:
        params["linstage_iterations"] = linstage_iterations
    if linstage_optimiser_first is not None:
        params["linstage_optimiser_first"] = linstage_optimiser_first
    if linstage_optimiser_last is not None:
        params["linstage_optimiser_last"] = linstage_optimiser_last
    if linstage_optimiser_default is not None:
        params["linstage_optimiser_default"] = linstage_optimiser_default
    if linstage_diagnostics_prefix is not None:
        params["linstage_diagnostics_prefix"] = linstage_diagnostics_prefix
    if nl_warp is not None:
        params["nl_warp"] = nl_warp
    if nl_warp_full is not None:
        params["nl_warp_full"] = nl_warp_full
    if nl_init is not None:
        params["nl_init"] = nl_init
    if nl_scale is not None:
        params["nl_scale"] = nl_scale
    if nl_niter is not None:
        params["nl_niter"] = nl_niter
    if nl_update_smooth is not None:
        params["nl_update_smooth"] = nl_update_smooth
    if nl_disp_smooth is not None:
        params["nl_disp_smooth"] = nl_disp_smooth
    if nl_grad_step is not None:
        params["nl_grad_step"] = nl_grad_step
    if nl_lmax is not None:
        params["nl_lmax"] = nl_lmax
    if diagnostics_image is not None:
        params["diagnostics_image"] = diagnostics_image
    if directions is not None:
        params["directions"] = directions
    if mc_weights is not None:
        params["mc_weights"] = mc_weights
    if datatype is not None:
        params["datatype"] = datatype
    if nthreads is not None:
        params["nthreads"] = nthreads
    if config is not None:
        params["config"] = config
    if contrast1_contrast2 is not None:
        params["contrast1_contrast2"] = contrast1_contrast2
    return params


def mrregister_validate(
    params: typing.Any,
) -> None:
    """
    Validate parameters. Throws an error if `params` is not a valid
    `MrregisterParamsDict` object.
    
    Args:
        params: The parameters object to validate.
    """
    if params is None or not isinstance(params, dict):
        raise StyxValidationError(f'Params object has the wrong type \'{type(params)}\'')
    if params.get("type", None) is not None:
        if not isinstance(params["type"], str):
            raise StyxValidationError(f'`type` has the wrong type: Received `{type(params.get("type", None))}` expected `str | None`')
    if params.get("transformed", None) is not None:
        if not isinstance(params["transformed"], list):
            raise StyxValidationError(f'`transformed` has the wrong type: Received `{type(params.get("transformed", None))}` expected `list[MrregisterTransformedParamsDict] | None`')
        for e in params["transformed"]:
            mrregister_transformed_validate(e)
    if params.get("transformed_midway", None) is not None:
        if not isinstance(params["transformed_midway"], list):
            raise StyxValidationError(f'`transformed_midway` has the wrong type: Received `{type(params.get("transformed_midway", None))}` expected `list[MrregisterTransformedMidwayParamsDict] | None`')
        for e in params["transformed_midway"]:
            mrregister_transformed_midway_validate(e)
    if params.get("mask1", None) is not None:
        if not isinstance(params["mask1"], (pathlib.Path, str)):
            raise StyxValidationError(f'`mask1` has the wrong type: Received `{type(params.get("mask1", None))}` expected `InputPathType | None`')
    if params.get("mask2", None) is not None:
        if not isinstance(params["mask2"], (pathlib.Path, str)):
            raise StyxValidationError(f'`mask2` has the wrong type: Received `{type(params.get("mask2", None))}` expected `InputPathType | None`')
    if params.get("nan", False) is None:
        raise StyxValidationError("`nan` must not be None")
    if not isinstance(params["nan"], bool):
        raise StyxValidationError(f'`nan` has the wrong type: Received `{type(params.get("nan", False))}` expected `bool`')
    if params.get("rigid", None) is not None:
        if not isinstance(params["rigid"], str):
            raise StyxValidationError(f'`rigid` has the wrong type: Received `{type(params.get("rigid", None))}` expected `str | None`')
    if params.get("rigid_1tomidway", None) is not None:
        if not isinstance(params["rigid_1tomidway"], str):
            raise StyxValidationError(f'`rigid_1tomidway` has the wrong type: Received `{type(params.get("rigid_1tomidway", None))}` expected `str | None`')
    if params.get("rigid_2tomidway", None) is not None:
        if not isinstance(params["rigid_2tomidway"], str):
            raise StyxValidationError(f'`rigid_2tomidway` has the wrong type: Received `{type(params.get("rigid_2tomidway", None))}` expected `str | None`')
    if params.get("rigid_init_translation", None) is not None:
        if not isinstance(params["rigid_init_translation"], str):
            raise StyxValidationError(f'`rigid_init_translation` has the wrong type: Received `{type(params.get("rigid_init_translation", None))}` expected `str | None`')
    if params.get("rigid_init_rotation", None) is not None:
        if not isinstance(params["rigid_init_rotation"], str):
            raise StyxValidationError(f'`rigid_init_rotation` has the wrong type: Received `{type(params.get("rigid_init_rotation", None))}` expected `str | None`')
    if params.get("rigid_init_matrix", None) is not None:
        if not isinstance(params["rigid_init_matrix"], (pathlib.Path, str)):
            raise StyxValidationError(f'`rigid_init_matrix` has the wrong type: Received `{type(params.get("rigid_init_matrix", None))}` expected `InputPathType | None`')
    if params.get("rigid_scale", None) is not None:
        if not isinstance(params["rigid_scale"], list):
            raise StyxValidationError(f'`rigid_scale` has the wrong type: Received `{type(params.get("rigid_scale", None))}` expected `list[float] | None`')
        for e in params["rigid_scale"]:
            if not isinstance(e, (float, int)):
                raise StyxValidationError(f'`rigid_scale` has the wrong type: Received `{type(params.get("rigid_scale", None))}` expected `list[float] | None`')
    if params.get("rigid_niter", None) is not None:
        if not isinstance(params["rigid_niter"], list):
            raise StyxValidationError(f'`rigid_niter` has the wrong type: Received `{type(params.get("rigid_niter", None))}` expected `list[int] | None`')
        for e in params["rigid_niter"]:
            if not isinstance(e, int):
                raise StyxValidationError(f'`rigid_niter` has the wrong type: Received `{type(params.get("rigid_niter", None))}` expected `list[int] | None`')
    if params.get("rigid_metric", None) is not None:
        if not isinstance(params["rigid_metric"], str):
            raise StyxValidationError(f'`rigid_metric` has the wrong type: Received `{type(params.get("rigid_metric", None))}` expected `str | None`')
    if params.get("rigid_metric_diff_estimator", None) is not None:
        if not isinstance(params["rigid_metric_diff_estimator"], str):
            raise StyxValidationError(f'`rigid_metric_diff_estimator` has the wrong type: Received `{type(params.get("rigid_metric_diff_estimator", None))}` expected `str | None`')
    if params.get("rigid_lmax", None) is not None:
        if not isinstance(params["rigid_lmax"], list):
            raise StyxValidationError(f'`rigid_lmax` has the wrong type: Received `{type(params.get("rigid_lmax", None))}` expected `list[int] | None`')
        for e in params["rigid_lmax"]:
            if not isinstance(e, int):
                raise StyxValidationError(f'`rigid_lmax` has the wrong type: Received `{type(params.get("rigid_lmax", None))}` expected `list[int] | None`')
    if params.get("rigid_log", None) is not None:
        if not isinstance(params["rigid_log"], str):
            raise StyxValidationError(f'`rigid_log` has the wrong type: Received `{type(params.get("rigid_log", None))}` expected `str | None`')
    if params.get("affine", None) is not None:
        if not isinstance(params["affine"], str):
            raise StyxValidationError(f'`affine` has the wrong type: Received `{type(params.get("affine", None))}` expected `str | None`')
    if params.get("affine_1tomidway", None) is not None:
        if not isinstance(params["affine_1tomidway"], str):
            raise StyxValidationError(f'`affine_1tomidway` has the wrong type: Received `{type(params.get("affine_1tomidway", None))}` expected `str | None`')
    if params.get("affine_2tomidway", None) is not None:
        if not isinstance(params["affine_2tomidway"], str):
            raise StyxValidationError(f'`affine_2tomidway` has the wrong type: Received `{type(params.get("affine_2tomidway", None))}` expected `str | None`')
    if params.get("affine_init_translation", None) is not None:
        if not isinstance(params["affine_init_translation"], str):
            raise StyxValidationError(f'`affine_init_translation` has the wrong type: Received `{type(params.get("affine_init_translation", None))}` expected `str | None`')
    if params.get("affine_init_rotation", None) is not None:
        if not isinstance(params["affine_init_rotation"], str):
            raise StyxValidationError(f'`affine_init_rotation` has the wrong type: Received `{type(params.get("affine_init_rotation", None))}` expected `str | None`')
    if params.get("affine_init_matrix", None) is not None:
        if not isinstance(params["affine_init_matrix"], (pathlib.Path, str)):
            raise StyxValidationError(f'`affine_init_matrix` has the wrong type: Received `{type(params.get("affine_init_matrix", None))}` expected `InputPathType | None`')
    if params.get("affine_scale", None) is not None:
        if not isinstance(params["affine_scale"], list):
            raise StyxValidationError(f'`affine_scale` has the wrong type: Received `{type(params.get("affine_scale", None))}` expected `list[float] | None`')
        for e in params["affine_scale"]:
            if not isinstance(e, (float, int)):
                raise StyxValidationError(f'`affine_scale` has the wrong type: Received `{type(params.get("affine_scale", None))}` expected `list[float] | None`')
    if params.get("affine_niter", None) is not None:
        if not isinstance(params["affine_niter"], list):
            raise StyxValidationError(f'`affine_niter` has the wrong type: Received `{type(params.get("affine_niter", None))}` expected `list[int] | None`')
        for e in params["affine_niter"]:
            if not isinstance(e, int):
                raise StyxValidationError(f'`affine_niter` has the wrong type: Received `{type(params.get("affine_niter", None))}` expected `list[int] | None`')
    if params.get("affine_metric", None) is not None:
        if not isinstance(params["affine_metric"], str):
            raise StyxValidationError(f'`affine_metric` has the wrong type: Received `{type(params.get("affine_metric", None))}` expected `str | None`')
    if params.get("affine_metric_diff_estimator", None) is not None:
        if not isinstance(params["affine_metric_diff_estimator"], str):
            raise StyxValidationError(f'`affine_metric_diff_estimator` has the wrong type: Received `{type(params.get("affine_metric_diff_estimator", None))}` expected `str | None`')
    if params.get("affine_lmax", None) is not None:
        if not isinstance(params["affine_lmax"], list):
            raise StyxValidationError(f'`affine_lmax` has the wrong type: Received `{type(params.get("affine_lmax", None))}` expected `list[int] | None`')
        for e in params["affine_lmax"]:
            if not isinstance(e, int):
                raise StyxValidationError(f'`affine_lmax` has the wrong type: Received `{type(params.get("affine_lmax", None))}` expected `list[int] | None`')
    if params.get("affine_log", None) is not None:
        if not isinstance(params["affine_log"], str):
            raise StyxValidationError(f'`affine_log` has the wrong type: Received `{type(params.get("affine_log", None))}` expected `str | None`')
    if params.get("init_translation_unmasked1", False) is None:
        raise StyxValidationError("`init_translation_unmasked1` must not be None")
    if not isinstance(params["init_translation_unmasked1"], bool):
        raise StyxValidationError(f'`init_translation_unmasked1` has the wrong type: Received `{type(params.get("init_translation_unmasked1", False))}` expected `bool`')
    if params.get("init_translation_unmasked2", False) is None:
        raise StyxValidationError("`init_translation_unmasked2` must not be None")
    if not isinstance(params["init_translation_unmasked2"], bool):
        raise StyxValidationError(f'`init_translation_unmasked2` has the wrong type: Received `{type(params.get("init_translation_unmasked2", False))}` expected `bool`')
    if params.get("init_rotation_unmasked1", False) is None:
        raise StyxValidationError("`init_rotation_unmasked1` must not be None")
    if not isinstance(params["init_rotation_unmasked1"], bool):
        raise StyxValidationError(f'`init_rotation_unmasked1` has the wrong type: Received `{type(params.get("init_rotation_unmasked1", False))}` expected `bool`')
    if params.get("init_rotation_unmasked2", False) is None:
        raise StyxValidationError("`init_rotation_unmasked2` must not be None")
    if not isinstance(params["init_rotation_unmasked2"], bool):
        raise StyxValidationError(f'`init_rotation_unmasked2` has the wrong type: Received `{type(params.get("init_rotation_unmasked2", False))}` expected `bool`')
    if params.get("init_rotation_search_angles", None) is not None:
        if not isinstance(params["init_rotation_search_angles"], list):
            raise StyxValidationError(f'`init_rotation_search_angles` has the wrong type: Received `{type(params.get("init_rotation_search_angles", None))}` expected `list[float] | None`')
        for e in params["init_rotation_search_angles"]:
            if not isinstance(e, (float, int)):
                raise StyxValidationError(f'`init_rotation_search_angles` has the wrong type: Received `{type(params.get("init_rotation_search_angles", None))}` expected `list[float] | None`')
    if params.get("init_rotation_search_scale", None) is not None:
        if not isinstance(params["init_rotation_search_scale"], (float, int)):
            raise StyxValidationError(f'`init_rotation_search_scale` has the wrong type: Received `{type(params.get("init_rotation_search_scale", None))}` expected `float | None`')
    if params.get("init_rotation_search_directions", None) is not None:
        if not isinstance(params["init_rotation_search_directions"], int):
            raise StyxValidationError(f'`init_rotation_search_directions` has the wrong type: Received `{type(params.get("init_rotation_search_directions", None))}` expected `int | None`')
    if params.get("init_rotation_search_run_global", False) is None:
        raise StyxValidationError("`init_rotation_search_run_global` must not be None")
    if not isinstance(params["init_rotation_search_run_global"], bool):
        raise StyxValidationError(f'`init_rotation_search_run_global` has the wrong type: Received `{type(params.get("init_rotation_search_run_global", False))}` expected `bool`')
    if params.get("init_rotation_search_global_iterations", None) is not None:
        if not isinstance(params["init_rotation_search_global_iterations"], int):
            raise StyxValidationError(f'`init_rotation_search_global_iterations` has the wrong type: Received `{type(params.get("init_rotation_search_global_iterations", None))}` expected `int | None`')
    if params.get("linstage_iterations", None) is not None:
        if not isinstance(params["linstage_iterations"], list):
            raise StyxValidationError(f'`linstage_iterations` has the wrong type: Received `{type(params.get("linstage_iterations", None))}` expected `list[int] | None`')
        for e in params["linstage_iterations"]:
            if not isinstance(e, int):
                raise StyxValidationError(f'`linstage_iterations` has the wrong type: Received `{type(params.get("linstage_iterations", None))}` expected `list[int] | None`')
    if params.get("linstage_optimiser_first", None) is not None:
        if not isinstance(params["linstage_optimiser_first"], str):
            raise StyxValidationError(f'`linstage_optimiser_first` has the wrong type: Received `{type(params.get("linstage_optimiser_first", None))}` expected `str | None`')
    if params.get("linstage_optimiser_last", None) is not None:
        if not isinstance(params["linstage_optimiser_last"], str):
            raise StyxValidationError(f'`linstage_optimiser_last` has the wrong type: Received `{type(params.get("linstage_optimiser_last", None))}` expected `str | None`')
    if params.get("linstage_optimiser_default", None) is not None:
        if not isinstance(params["linstage_optimiser_default"], str):
            raise StyxValidationError(f'`linstage_optimiser_default` has the wrong type: Received `{type(params.get("linstage_optimiser_default", None))}` expected `str | None`')
    if params.get("linstage_diagnostics_prefix", None) is not None:
        if not isinstance(params["linstage_diagnostics_prefix"], str):
            raise StyxValidationError(f'`linstage_diagnostics_prefix` has the wrong type: Received `{type(params.get("linstage_diagnostics_prefix", None))}` expected `str | None`')
    if params.get("nl_warp", None) is not None:
        mrregister_nl_warp_validate(params["nl_warp"])
    if params.get("nl_warp_full", None) is not None:
        if not isinstance(params["nl_warp_full"], str):
            raise StyxValidationError(f'`nl_warp_full` has the wrong type: Received `{type(params.get("nl_warp_full", None))}` expected `str | None`')
    if params.get("nl_init", None) is not None:
        if not isinstance(params["nl_init"], (pathlib.Path, str)):
            raise StyxValidationError(f'`nl_init` has the wrong type: Received `{type(params.get("nl_init", None))}` expected `InputPathType | None`')
    if params.get("nl_scale", None) is not None:
        if not isinstance(params["nl_scale"], list):
            raise StyxValidationError(f'`nl_scale` has the wrong type: Received `{type(params.get("nl_scale", None))}` expected `list[float] | None`')
        for e in params["nl_scale"]:
            if not isinstance(e, (float, int)):
                raise StyxValidationError(f'`nl_scale` has the wrong type: Received `{type(params.get("nl_scale", None))}` expected `list[float] | None`')
    if params.get("nl_niter", None) is not None:
        if not isinstance(params["nl_niter"], list):
            raise StyxValidationError(f'`nl_niter` has the wrong type: Received `{type(params.get("nl_niter", None))}` expected `list[int] | None`')
        for e in params["nl_niter"]:
            if not isinstance(e, int):
                raise StyxValidationError(f'`nl_niter` has the wrong type: Received `{type(params.get("nl_niter", None))}` expected `list[int] | None`')
    if params.get("nl_update_smooth", None) is not None:
        if not isinstance(params["nl_update_smooth"], (float, int)):
            raise StyxValidationError(f'`nl_update_smooth` has the wrong type: Received `{type(params.get("nl_update_smooth", None))}` expected `float | None`')
    if params.get("nl_disp_smooth", None) is not None:
        if not isinstance(params["nl_disp_smooth"], (float, int)):
            raise StyxValidationError(f'`nl_disp_smooth` has the wrong type: Received `{type(params.get("nl_disp_smooth", None))}` expected `float | None`')
    if params.get("nl_grad_step", None) is not None:
        if not isinstance(params["nl_grad_step"], (float, int)):
            raise StyxValidationError(f'`nl_grad_step` has the wrong type: Received `{type(params.get("nl_grad_step", None))}` expected `float | None`')
    if params.get("nl_lmax", None) is not None:
        if not isinstance(params["nl_lmax"], list):
            raise StyxValidationError(f'`nl_lmax` has the wrong type: Received `{type(params.get("nl_lmax", None))}` expected `list[int] | None`')
        for e in params["nl_lmax"]:
            if not isinstance(e, int):
                raise StyxValidationError(f'`nl_lmax` has the wrong type: Received `{type(params.get("nl_lmax", None))}` expected `list[int] | None`')
    if params.get("diagnostics_image", None) is not None:
        if not isinstance(params["diagnostics_image"], str):
            raise StyxValidationError(f'`diagnostics_image` has the wrong type: Received `{type(params.get("diagnostics_image", None))}` expected `str | None`')
    if params.get("directions", None) is not None:
        if not isinstance(params["directions"], (pathlib.Path, str)):
            raise StyxValidationError(f'`directions` has the wrong type: Received `{type(params.get("directions", None))}` expected `InputPathType | None`')
    if params.get("noreorientation", False) is None:
        raise StyxValidationError("`noreorientation` must not be None")
    if not isinstance(params["noreorientation"], bool):
        raise StyxValidationError(f'`noreorientation` has the wrong type: Received `{type(params.get("noreorientation", False))}` expected `bool`')
    if params.get("mc_weights", None) is not None:
        if not isinstance(params["mc_weights"], list):
            raise StyxValidationError(f'`mc_weights` has the wrong type: Received `{type(params.get("mc_weights", None))}` expected `list[float] | None`')
        for e in params["mc_weights"]:
            if not isinstance(e, (float, int)):
                raise StyxValidationError(f'`mc_weights` has the wrong type: Received `{type(params.get("mc_weights", None))}` expected `list[float] | None`')
    if params.get("datatype", None) is not None:
        if not isinstance(params["datatype"], str):
            raise StyxValidationError(f'`datatype` has the wrong type: Received `{type(params.get("datatype", None))}` expected `str | None`')
    if params.get("info", False) is None:
        raise StyxValidationError("`info` must not be None")
    if not isinstance(params["info"], bool):
        raise StyxValidationError(f'`info` has the wrong type: Received `{type(params.get("info", False))}` expected `bool`')
    if params.get("quiet", False) is None:
        raise StyxValidationError("`quiet` must not be None")
    if not isinstance(params["quiet"], bool):
        raise StyxValidationError(f'`quiet` has the wrong type: Received `{type(params.get("quiet", False))}` expected `bool`')
    if params.get("debug", False) is None:
        raise StyxValidationError("`debug` must not be None")
    if not isinstance(params["debug"], bool):
        raise StyxValidationError(f'`debug` has the wrong type: Received `{type(params.get("debug", False))}` expected `bool`')
    if params.get("force", False) is None:
        raise StyxValidationError("`force` must not be None")
    if not isinstance(params["force"], bool):
        raise StyxValidationError(f'`force` has the wrong type: Received `{type(params.get("force", False))}` expected `bool`')
    if params.get("nthreads", None) is not None:
        if not isinstance(params["nthreads"], int):
            raise StyxValidationError(f'`nthreads` has the wrong type: Received `{type(params.get("nthreads", None))}` expected `int | None`')
    if params.get("config", None) is not None:
        if not isinstance(params["config"], list):
            raise StyxValidationError(f'`config` has the wrong type: Received `{type(params.get("config", None))}` expected `list[MrregisterConfigParamsDict] | None`')
        for e in params["config"]:
            mrregister_config_validate(e)
    if params.get("help", False) is None:
        raise StyxValidationError("`help` must not be None")
    if not isinstance(params["help"], bool):
        raise StyxValidationError(f'`help` has the wrong type: Received `{type(params.get("help", False))}` expected `bool`')
    if params.get("version", False) is None:
        raise StyxValidationError("`version` must not be None")
    if not isinstance(params["version"], bool):
        raise StyxValidationError(f'`version` has the wrong type: Received `{type(params.get("version", False))}` expected `bool`')
    if params.get("image1_image2", None) is None:
        raise StyxValidationError("`image1_image2` must not be None")
    if not isinstance(params["image1_image2"], (pathlib.Path, str)):
        raise StyxValidationError(f'`image1_image2` has the wrong type: Received `{type(params.get("image1_image2", None))}` expected `InputPathType`')
    if params.get("contrast1_contrast2", None) is not None:
        if not isinstance(params["contrast1_contrast2"], list):
            raise StyxValidationError(f'`contrast1_contrast2` has the wrong type: Received `{type(params.get("contrast1_contrast2", None))}` expected `list[InputPathType] | None`')
        for e in params["contrast1_contrast2"]:
            if not isinstance(e, (pathlib.Path, str)):
                raise StyxValidationError(f'`contrast1_contrast2` has the wrong type: Received `{type(params.get("contrast1_contrast2", None))}` expected `list[InputPathType] | None`')


def mrregister_cargs(
    params: MrregisterParamsDict,
    execution: Execution,
) -> list[str]:
    """
    Build command-line arguments from parameters.
    
    Args:
        params: The parameters.
        execution: The execution object for resolving input paths.
    Returns:
        Command-line arguments.
    """
    cargs = []
    cargs.append("mrregister")
    if params.get("type", None) is not None:
        cargs.extend([
            "-type",
            params.get("type", None)
        ])
    if params.get("transformed", None) is not None:
        cargs.extend([a for c in [mrregister_transformed_cargs(s, execution) for s in params.get("transformed", None)] for a in c])
    if params.get("transformed_midway", None) is not None:
        cargs.extend([a for c in [mrregister_transformed_midway_cargs(s, execution) for s in params.get("transformed_midway", None)] for a in c])
    if params.get("mask1", None) is not None:
        cargs.extend([
            "-mask1",
            execution.input_file(params.get("mask1", None))
        ])
    if params.get("mask2", None) is not None:
        cargs.extend([
            "-mask2",
            execution.input_file(params.get("mask2", None))
        ])
    if params.get("nan", False):
        cargs.append("-nan")
    if params.get("rigid", None) is not None:
        cargs.extend([
            "-rigid",
            params.get("rigid", None)
        ])
    if params.get("rigid_1tomidway", None) is not None:
        cargs.extend([
            "-rigid_1tomidway",
            params.get("rigid_1tomidway", None)
        ])
    if params.get("rigid_2tomidway", None) is not None:
        cargs.extend([
            "-rigid_2tomidway",
            params.get("rigid_2tomidway", None)
        ])
    if params.get("rigid_init_translation", None) is not None:
        cargs.extend([
            "-rigid_init_translation",
            params.get("rigid_init_translation", None)
        ])
    if params.get("rigid_init_rotation", None) is not None:
        cargs.extend([
            "-rigid_init_rotation",
            params.get("rigid_init_rotation", None)
        ])
    if params.get("rigid_init_matrix", None) is not None:
        cargs.extend([
            "-rigid_init_matrix",
            execution.input_file(params.get("rigid_init_matrix", None))
        ])
    if params.get("rigid_scale", None) is not None:
        cargs.extend([
            "-rigid_scale",
            *map(str, params.get("rigid_scale", None))
        ])
    if params.get("rigid_niter", None) is not None:
        cargs.extend([
            "-rigid_niter",
            *map(str, params.get("rigid_niter", None))
        ])
    if params.get("rigid_metric", None) is not None:
        cargs.extend([
            "-rigid_metric",
            params.get("rigid_metric", None)
        ])
    if params.get("rigid_metric_diff_estimator", None) is not None:
        cargs.extend([
            "-rigid_metric.diff.estimator",
            params.get("rigid_metric_diff_estimator", None)
        ])
    if params.get("rigid_lmax", None) is not None:
        cargs.extend([
            "-rigid_lmax",
            *map(str, params.get("rigid_lmax", None))
        ])
    if params.get("rigid_log", None) is not None:
        cargs.extend([
            "-rigid_log",
            params.get("rigid_log", None)
        ])
    if params.get("affine", None) is not None:
        cargs.extend([
            "-affine",
            params.get("affine", None)
        ])
    if params.get("affine_1tomidway", None) is not None:
        cargs.extend([
            "-affine_1tomidway",
            params.get("affine_1tomidway", None)
        ])
    if params.get("affine_2tomidway", None) is not None:
        cargs.extend([
            "-affine_2tomidway",
            params.get("affine_2tomidway", None)
        ])
    if params.get("affine_init_translation", None) is not None:
        cargs.extend([
            "-affine_init_translation",
            params.get("affine_init_translation", None)
        ])
    if params.get("affine_init_rotation", None) is not None:
        cargs.extend([
            "-affine_init_rotation",
            params.get("affine_init_rotation", None)
        ])
    if params.get("affine_init_matrix", None) is not None:
        cargs.extend([
            "-affine_init_matrix",
            execution.input_file(params.get("affine_init_matrix", None))
        ])
    if params.get("affine_scale", None) is not None:
        cargs.extend([
            "-affine_scale",
            *map(str, params.get("affine_scale", None))
        ])
    if params.get("affine_niter", None) is not None:
        cargs.extend([
            "-affine_niter",
            *map(str, params.get("affine_niter", None))
        ])
    if params.get("affine_metric", None) is not None:
        cargs.extend([
            "-affine_metric",
            params.get("affine_metric", None)
        ])
    if params.get("affine_metric_diff_estimator", None) is not None:
        cargs.extend([
            "-affine_metric.diff.estimator",
            params.get("affine_metric_diff_estimator", None)
        ])
    if params.get("affine_lmax", None) is not None:
        cargs.extend([
            "-affine_lmax",
            *map(str, params.get("affine_lmax", None))
        ])
    if params.get("affine_log", None) is not None:
        cargs.extend([
            "-affine_log",
            params.get("affine_log", None)
        ])
    if params.get("init_translation_unmasked1", False):
        cargs.append("-init_translation.unmasked1")
    if params.get("init_translation_unmasked2", False):
        cargs.append("-init_translation.unmasked2")
    if params.get("init_rotation_unmasked1", False):
        cargs.append("-init_rotation.unmasked1")
    if params.get("init_rotation_unmasked2", False):
        cargs.append("-init_rotation.unmasked2")
    if params.get("init_rotation_search_angles", None) is not None:
        cargs.extend([
            "-init_rotation.search.angles",
            *map(str, params.get("init_rotation_search_angles", None))
        ])
    if params.get("init_rotation_search_scale", None) is not None:
        cargs.extend([
            "-init_rotation.search.scale",
            str(params.get("init_rotation_search_scale", None))
        ])
    if params.get("init_rotation_search_directions", None) is not None:
        cargs.extend([
            "-init_rotation.search.directions",
            str(params.get("init_rotation_search_directions", None))
        ])
    if params.get("init_rotation_search_run_global", False):
        cargs.append("-init_rotation.search.run_global")
    if params.get("init_rotation_search_global_iterations", None) is not None:
        cargs.extend([
            "-init_rotation.search.global.iterations",
            str(params.get("init_rotation_search_global_iterations", None))
        ])
    if params.get("linstage_iterations", None) is not None:
        cargs.extend([
            "-linstage.iterations",
            *map(str, params.get("linstage_iterations", None))
        ])
    if params.get("linstage_optimiser_first", None) is not None:
        cargs.extend([
            "-linstage.optimiser.first",
            params.get("linstage_optimiser_first", None)
        ])
    if params.get("linstage_optimiser_last", None) is not None:
        cargs.extend([
            "-linstage.optimiser.last",
            params.get("linstage_optimiser_last", None)
        ])
    if params.get("linstage_optimiser_default", None) is not None:
        cargs.extend([
            "-linstage.optimiser.default",
            params.get("linstage_optimiser_default", None)
        ])
    if params.get("linstage_diagnostics_prefix", None) is not None:
        cargs.extend([
            "-linstage.diagnostics.prefix",
            params.get("linstage_diagnostics_prefix", None)
        ])
    if params.get("nl_warp", None) is not None:
        cargs.extend(mrregister_nl_warp_cargs(params.get("nl_warp", None), execution))
    if params.get("nl_warp_full", None) is not None:
        cargs.extend([
            "-nl_warp_full",
            params.get("nl_warp_full", None)
        ])
    if params.get("nl_init", None) is not None:
        cargs.extend([
            "-nl_init",
            execution.input_file(params.get("nl_init", None))
        ])
    if params.get("nl_scale", None) is not None:
        cargs.extend([
            "-nl_scale",
            *map(str, params.get("nl_scale", None))
        ])
    if params.get("nl_niter", None) is not None:
        cargs.extend([
            "-nl_niter",
            *map(str, params.get("nl_niter", None))
        ])
    if params.get("nl_update_smooth", None) is not None:
        cargs.extend([
            "-nl_update_smooth",
            str(params.get("nl_update_smooth", None))
        ])
    if params.get("nl_disp_smooth", None) is not None:
        cargs.extend([
            "-nl_disp_smooth",
            str(params.get("nl_disp_smooth", None))
        ])
    if params.get("nl_grad_step", None) is not None:
        cargs.extend([
            "-nl_grad_step",
            str(params.get("nl_grad_step", None))
        ])
    if params.get("nl_lmax", None) is not None:
        cargs.extend([
            "-nl_lmax",
            *map(str, params.get("nl_lmax", None))
        ])
    if params.get("diagnostics_image", None) is not None:
        cargs.extend([
            "-diagnostics_image",
            params.get("diagnostics_image", None)
        ])
    if params.get("directions", None) is not None:
        cargs.extend([
            "-directions",
            execution.input_file(params.get("directions", None))
        ])
    if params.get("noreorientation", False):
        cargs.append("-noreorientation")
    if params.get("mc_weights", None) is not None:
        cargs.extend([
            "-mc_weights",
            *map(str, params.get("mc_weights", None))
        ])
    if params.get("datatype", None) is not None:
        cargs.extend([
            "-datatype",
            params.get("datatype", None)
        ])
    if params.get("info", False):
        cargs.append("-info")
    if params.get("quiet", False):
        cargs.append("-quiet")
    if params.get("debug", False):
        cargs.append("-debug")
    if params.get("force", False):
        cargs.append("-force")
    if params.get("nthreads", None) is not None:
        cargs.extend([
            "-nthreads",
            str(params.get("nthreads", None))
        ])
    if params.get("config", None) is not None:
        cargs.extend([a for c in [mrregister_config_cargs(s, execution) for s in params.get("config", None)] for a in c])
    if params.get("help", False):
        cargs.append("-help")
    if params.get("version", False):
        cargs.append("-version")
    cargs.append(execution.input_file(params.get("image1_image2", None)))
    if params.get("contrast1_contrast2", None) is not None:
        cargs.extend([execution.input_file(f) for f in params.get("contrast1_contrast2", None)])
    return cargs


def mrregister_outputs(
    params: MrregisterParamsDict,
    execution: Execution,
) -> MrregisterOutputs:
    """
    Build outputs object containing output file paths and possibly stdout/stderr.
    
    Args:
        params: The parameters.
        execution: The execution object for resolving input paths.
    Returns:
        Outputs object.
    """
    ret = MrregisterOutputs(
        root=execution.output_file("."),
        rigid=execution.output_file(params.get("rigid", None)) if (params.get("rigid") is not None) else None,
        rigid_1tomidway=execution.output_file(params.get("rigid_1tomidway", None)) if (params.get("rigid_1tomidway") is not None) else None,
        rigid_2tomidway=execution.output_file(params.get("rigid_2tomidway", None)) if (params.get("rigid_2tomidway") is not None) else None,
        rigid_log=execution.output_file(params.get("rigid_log", None)) if (params.get("rigid_log") is not None) else None,
        affine=execution.output_file(params.get("affine", None)) if (params.get("affine") is not None) else None,
        affine_1tomidway=execution.output_file(params.get("affine_1tomidway", None)) if (params.get("affine_1tomidway") is not None) else None,
        affine_2tomidway=execution.output_file(params.get("affine_2tomidway", None)) if (params.get("affine_2tomidway") is not None) else None,
        affine_log=execution.output_file(params.get("affine_log", None)) if (params.get("affine_log") is not None) else None,
        nl_warp_full=execution.output_file(params.get("nl_warp_full", None)) if (params.get("nl_warp_full") is not None) else None,
        transformed=[mrregister_transformed_outputs(i, execution) if mrregister_transformed_outputs else None for i in params.get("transformed")] if params.get("transformed") else None,
        transformed_midway=[mrregister_transformed_midway_outputs(i, execution) if mrregister_transformed_midway_outputs else None for i in params.get("transformed_midway")] if params.get("transformed_midway") else None,
        nl_warp=mrregister_nl_warp_outputs(params.get("nl_warp"), execution) if params.get("nl_warp") else None,
    )
    return ret


def mrregister_execute(
    params: MrregisterParamsDict,
    runner: Runner | None = None,
) -> MrregisterOutputs:
    """
    mrregister
    
    Register two images together using a symmetric rigid, affine or non-linear
    transformation model.
    
    By default this application will perform an affine, followed by non-linear
    registration.
    
    FOD registration (with apodised point spread reorientation) will be
    performed by default if the number of volumes in the 4th dimension equals
    the number of coefficients in an antipodally symmetric spherical harmonic
    series (e.g. 6, 15, 28 etc). The -no_reorientation option can be used to
    force reorientation off if required.
    
    Non-linear registration computes warps to map from both image1->image2 and
    image2->image1. Similar to Avants (2008) Med Image Anal. 12(1): 26â€“41,
    registration is performed by matching both the image1 and image2 in a
    'midway space'. Warps can be saved as two deformation fields that map
    directly between image1->image2 and image2->image1, or if using
    -nl_warp_full as a single 5D file that stores all 4 warps
    image1->mid->image2, and image2->mid->image1. The 5D warp format stores
    x,y,z deformations in the 4th dimension, and uses the 5th dimension to index
    the 4 warps. The affine transforms estimated (to midway space) are also
    stored as comments in the image header. The 5D warp file can be used to
    reinitialise subsequent registrations, in addition to transforming images to
    midway space (e.g. for intra-subject alignment in a 2-time-point
    longitudinal analysis).
    
    References:
    
    * If FOD registration is being performed:
    Raffelt, D.; Tournier, J.-D.; Fripp, J; Crozier, S.; Connelly, A. & Salvado,
    O. Symmetric diffeomorphic registration of fibre orientation distributions.
    NeuroImage, 2011, 56(3), 1171-1180
    
    Raffelt, D.; Tournier, J.-D.; Crozier, S.; Connelly, A. & Salvado, O.
    Reorientation of fiber orientation distributions using apodized point spread
    functions. Magnetic Resonance in Medicine, 2012, 67, 844-855.
    
    Author: MRTrix3 Developers
    
    URL: https://www.mrtrix.org/
    
    Args:
        params: The parameters.
        runner: Command runner.
    Returns:
        NamedTuple of outputs (described in `MrregisterOutputs`).
    """
    mrregister_validate(params)
    runner = runner or get_global_runner()
    execution = runner.start_execution(MRREGISTER_METADATA)
    params = execution.params(params)
    cargs = mrregister_cargs(params, execution)
    ret = mrregister_outputs(params, execution)
    execution.run(cargs)
    return ret


def mrregister(
    image1_image2: InputPathType,
    type_: str | None = None,
    transformed: list[MrregisterTransformedParamsDict] | None = None,
    transformed_midway: list[MrregisterTransformedMidwayParamsDict] | None = None,
    mask1: InputPathType | None = None,
    mask2: InputPathType | None = None,
    nan: bool = False,
    rigid: str | None = None,
    rigid_1tomidway: str | None = None,
    rigid_2tomidway: str | None = None,
    rigid_init_translation: str | None = None,
    rigid_init_rotation: str | None = None,
    rigid_init_matrix: InputPathType | None = None,
    rigid_scale: list[float] | None = None,
    rigid_niter: list[int] | None = None,
    rigid_metric: str | None = None,
    rigid_metric_diff_estimator: str | None = None,
    rigid_lmax: list[int] | None = None,
    rigid_log: str | None = None,
    affine: str | None = None,
    affine_1tomidway: str | None = None,
    affine_2tomidway: str | None = None,
    affine_init_translation: str | None = None,
    affine_init_rotation: str | None = None,
    affine_init_matrix: InputPathType | None = None,
    affine_scale: list[float] | None = None,
    affine_niter: list[int] | None = None,
    affine_metric: str | None = None,
    affine_metric_diff_estimator: str | None = None,
    affine_lmax: list[int] | None = None,
    affine_log: str | None = None,
    init_translation_unmasked1: bool = False,
    init_translation_unmasked2: bool = False,
    init_rotation_unmasked1: bool = False,
    init_rotation_unmasked2: bool = False,
    init_rotation_search_angles: list[float] | None = None,
    init_rotation_search_scale: float | None = None,
    init_rotation_search_directions: int | None = None,
    init_rotation_search_run_global: bool = False,
    init_rotation_search_global_iterations: int | None = None,
    linstage_iterations: list[int] | None = None,
    linstage_optimiser_first: str | None = None,
    linstage_optimiser_last: str | None = None,
    linstage_optimiser_default: str | None = None,
    linstage_diagnostics_prefix: str | None = None,
    nl_warp: MrregisterNlWarpParamsDict | None = None,
    nl_warp_full: str | None = None,
    nl_init: InputPathType | None = None,
    nl_scale: list[float] | None = None,
    nl_niter: list[int] | None = None,
    nl_update_smooth: float | None = None,
    nl_disp_smooth: float | None = None,
    nl_grad_step: float | None = None,
    nl_lmax: list[int] | None = None,
    diagnostics_image: str | None = None,
    directions: InputPathType | None = None,
    noreorientation: bool = False,
    mc_weights: list[float] | None = None,
    datatype: str | None = None,
    info: bool = False,
    quiet: bool = False,
    debug: bool = False,
    force: bool = False,
    nthreads: int | None = None,
    config: list[MrregisterConfigParamsDict] | None = None,
    help_: bool = False,
    version: bool = False,
    contrast1_contrast2: list[InputPathType] | None = None,
    runner: Runner | None = None,
) -> MrregisterOutputs:
    """
    mrregister
    
    Register two images together using a symmetric rigid, affine or non-linear
    transformation model.
    
    By default this application will perform an affine, followed by non-linear
    registration.
    
    FOD registration (with apodised point spread reorientation) will be
    performed by default if the number of volumes in the 4th dimension equals
    the number of coefficients in an antipodally symmetric spherical harmonic
    series (e.g. 6, 15, 28 etc). The -no_reorientation option can be used to
    force reorientation off if required.
    
    Non-linear registration computes warps to map from both image1->image2 and
    image2->image1. Similar to Avants (2008) Med Image Anal. 12(1): 26â€“41,
    registration is performed by matching both the image1 and image2 in a
    'midway space'. Warps can be saved as two deformation fields that map
    directly between image1->image2 and image2->image1, or if using
    -nl_warp_full as a single 5D file that stores all 4 warps
    image1->mid->image2, and image2->mid->image1. The 5D warp format stores
    x,y,z deformations in the 4th dimension, and uses the 5th dimension to index
    the 4 warps. The affine transforms estimated (to midway space) are also
    stored as comments in the image header. The 5D warp file can be used to
    reinitialise subsequent registrations, in addition to transforming images to
    midway space (e.g. for intra-subject alignment in a 2-time-point
    longitudinal analysis).
    
    References:
    
    * If FOD registration is being performed:
    Raffelt, D.; Tournier, J.-D.; Fripp, J; Crozier, S.; Connelly, A. & Salvado,
    O. Symmetric diffeomorphic registration of fibre orientation distributions.
    NeuroImage, 2011, 56(3), 1171-1180
    
    Raffelt, D.; Tournier, J.-D.; Crozier, S.; Connelly, A. & Salvado, O.
    Reorientation of fiber orientation distributions using apodized point spread
    functions. Magnetic Resonance in Medicine, 2012, 67, 844-855.
    
    Author: MRTrix3 Developers
    
    URL: https://www.mrtrix.org/
    
    Args:
        image1_image2: input image 1 ('moving') and input image 2 ('template').
        type_: the registration type. Valid choices are: rigid, affine,\
            nonlinear, rigid_affine, rigid_nonlinear, affine_nonlinear,\
            rigid_affine_nonlinear (Default: affine_nonlinear).
        transformed: image1 after registration transformed and regridded to the\
            space of image2. Note that -transformed needs to be repeated for each\
            contrast if multi-contrast registration is used.
        transformed_midway: image1 and image2 after registration transformed\
            and regridded to the midway space. Note that -transformed_midway needs\
            to be repeated for each contrast if multi-contrast registration is\
            used.
        mask1: a mask to define the region of image1 to use for optimisation.
        mask2: a mask to define the region of image2 to use for optimisation.
        nan: use NaN as out of bounds value. (Default: 0.0).
        rigid: the output text file containing the rigid transformation as a\
            4x4 matrix.
        rigid_1tomidway: the output text file containing the rigid\
            transformation that aligns image1 to image2 in their common midway\
            space as a 4x4 matrix.
        rigid_2tomidway: the output text file containing the rigid\
            transformation that aligns image2 to image1 in their common midway\
            space as a 4x4 matrix.
        rigid_init_translation: initialise the translation and centre of\
            rotation\
            Valid choices are:\
            mass (aligns the centers of mass of both images, default),\
            geometric (aligns geometric image centres) and none.
        rigid_init_rotation: initialise the rotation Valid choices are:\
            search (search for the best rotation using mean squared residuals),\
            moments (rotation based on directions of intensity variance with\
            respect to centre of mass),\
            none (default).
        rigid_init_matrix: initialise either the rigid, affine, or syn\
            registration with the supplied rigid transformation (as a 4x4 matrix in\
            scanner coordinates). Note that this overrides rigid_init_translation\
            and rigid_init_rotation initialisation.
        rigid_scale: use a multi-resolution scheme by defining a scale factor\
            for each level using comma separated values (Default: 0.25,0.5,1.0).
        rigid_niter: the maximum number of gradient descent iterations per\
            stage. This can be specified either as a single number for all\
            multi-resolution levels, or a single value for each level. (Default:\
            1000).
        rigid_metric: valid choices are: diff (intensity differences), Default:\
            diff.
        rigid_metric_diff_estimator: Valid choices are: l1 (least absolute:\
            |x|), l2 (ordinary least squares), lp (least powers: |x|^1.2), Default:\
            l2.
        rigid_lmax: explicitly set the lmax to be used per scale factor in\
            rigid FOD registration. By default FOD registration will use lmax 0,2,4\
            with default scale factors 0.25,0.5,1.0 respectively. Note that no\
            reorientation will be performed with lmax = 0.
        rigid_log: write gradient descent parameter evolution to log file.
        affine: the output text file containing the affine transformation as a\
            4x4 matrix.
        affine_1tomidway: the output text file containing the affine\
            transformation that aligns image1 to image2 in their common midway\
            space as a 4x4 matrix.
        affine_2tomidway: the output text file containing the affine\
            transformation that aligns image2 to image1 in their common midway\
            space as a 4x4 matrix.
        affine_init_translation: initialise the translation and centre of\
            rotation\
            Valid choices are:\
            mass (aligns the centers of mass of both images),\
            geometric (aligns geometric image centres) and none. (Default:\
            mass).
        affine_init_rotation: initialise the rotation Valid choices are:\
            search (search for the best rotation using mean squared residuals),\
            moments (rotation based on directions of intensity variance with\
            respect to centre of mass),\
            none (Default: none).
        affine_init_matrix: initialise either the affine, or syn registration\
            with the supplied affine transformation (as a 4x4 matrix in scanner\
            coordinates). Note that this overrides affine_init_translation and\
            affine_init_rotation initialisation.
        affine_scale: use a multi-resolution scheme by defining a scale factor\
            for each level using comma separated values (Default: 0.25,0.5,1.0).
        affine_niter: the maximum number of gradient descent iterations per\
            stage. This can be specified either as a single number for all\
            multi-resolution levels, or a single value for each level. (Default:\
            1000).
        affine_metric: valid choices are: diff (intensity differences),\
            Default: diff.
        affine_metric_diff_estimator: Valid choices are: l1 (least absolute:\
            |x|), l2 (ordinary least squares), lp (least powers: |x|^1.2), Default:\
            l2.
        affine_lmax: explicitly set the lmax to be used per scale factor in\
            affine FOD registration. By default FOD registration will use lmax\
            0,2,4 with default scale factors 0.25,0.5,1.0 respectively. Note that\
            no reorientation will be performed with lmax = 0.
        affine_log: write gradient descent parameter evolution to log file.
        init_translation_unmasked1: disregard mask1 for the translation\
            initialisation (affects 'mass').
        init_translation_unmasked2: disregard mask2 for the translation\
            initialisation (affects 'mass').
        init_rotation_unmasked1: disregard mask1 for the rotation\
            initialisation (affects 'search' and 'moments').
        init_rotation_unmasked2: disregard mask2 for the rotation\
            initialisation (affects 'search' and 'moments').
        init_rotation_search_angles: rotation angles for the local search in\
            degrees between 0 and 180. (Default: 2,5,10,15,20).
        init_rotation_search_scale: relative size of the images used for the\
            rotation search. (Default: 0.15).
        init_rotation_search_directions: number of rotation axis for local\
            search. (Default: 250).
        init_rotation_search_run_global: perform a global search. (Default:\
            local).
        init_rotation_search_global_iterations: number of rotations to\
            investigate (Default: 10000).
        linstage_iterations: number of iterations for each registration stage,\
            not to be confused with -rigid_niter or -affine_niter. This can be used\
            to generate intermediate diagnostics images\
            (-linstage.diagnostics.prefix) or to change the cost function optimiser\
            during registration (without the need to repeatedly resize the images).\
            (Default: 1 == no repetition).
        linstage_optimiser_first: Cost function optimisation algorithm to use\
            at first iteration of all stages. Valid choices: bbgd (Barzilai-Borwein\
            gradient descent) or gd (simple gradient descent). (Default: bbgd).
        linstage_optimiser_last: Cost function optimisation algorithm to use at\
            last iteration of all stages (if there are more than one). Valid\
            choices: bbgd (Barzilai-Borwein gradient descent) or gd (simple\
            gradient descent). (Default: bbgd).
        linstage_optimiser_default: Cost function optimisation algorithm to use\
            at any stage iteration other than first or last iteration. Valid\
            choices: bbgd (Barzilai-Borwein gradient descent) or gd (simple\
            gradient descent). (Default: bbgd).
        linstage_diagnostics_prefix: generate diagnostics images after every\
            registration stage.
        nl_warp: the non-linear warp output defined as two deformation fields,\
            where warp1 can be used to transform image1->image2 and warp2 to\
            transform image2->image1. The deformation fields also encapsulate any\
            linear transformation estimated prior to non-linear registration.
        nl_warp_full: output all warps used during registration. This saves\
            four different warps that map each image to a midway space and their\
            inverses in a single 5D image file. The 4th image dimension indexes the\
            x,y,z component of the deformation vector and the 5th dimension indexes\
            the field in this order: image1->midway, midway->image1,\
            image2->midway, midway->image2. Where image1->midway defines the field\
            that maps image1 onto the midway space using the reverse convention\
            When linear registration is performed first, the estimated linear\
            transform will be included in the comments of the image header, and\
            therefore the entire linear and non-linear transform can be applied (in\
            either direction) using this output warp file with mrtransform.
        nl_init: initialise the non-linear registration with the supplied warp\
            image. The supplied warp must be in the same format as output using the\
            -nl_warp_full option (i.e. have 4 deformation fields with the linear\
            transforms in the image header).
        nl_scale: use a multi-resolution scheme by defining a scale factor for\
            each level using comma separated values (Default: 0.25,0.5,1.0).
        nl_niter: the maximum number of iterations. This can be specified\
            either as a single number for all multi-resolution levels, or a single\
            value for each level. (Default: 50).
        nl_update_smooth: regularise the gradient update field with Gaussian\
            smoothing (standard deviation in voxel units, Default 2.0).
        nl_disp_smooth: regularise the displacement field with Gaussian\
            smoothing (standard deviation in voxel units, Default 1.0).
        nl_grad_step: the gradient step size for non-linear registration\
            (Default: 0.5).
        nl_lmax: explicitly set the lmax to be used per scale factor in\
            non-linear FOD registration. By default FOD registration will use lmax\
            0,2,4 with default scale factors 0.25,0.5,1.0 respectively. Note that\
            no reorientation will be performed with lmax = 0.
        diagnostics_image: write intermediate images for diagnostics purposes.
        directions: the directions used for FOD reorientation using apodised\
            point spread functions (Default: 60 directions).
        noreorientation: turn off FOD reorientation. Reorientation is on by\
            default if the number of volumes in the 4th dimension corresponds to\
            the number of coefficients in an antipodally symmetric spherical\
            harmonic series (i.e. 6, 15, 28, 45, 66 etc).
        mc_weights: relative weight of images used for multi-contrast\
            registration. Default: 1.0 (equal weighting).
        datatype: specify output image data type. Valid choices are: float32,\
            float32le, float32be, float64, float64le, float64be, int64, uint64,\
            int64le, uint64le, int64be, uint64be, int32, uint32, int32le, uint32le,\
            int32be, uint32be, int16, uint16, int16le, uint16le, int16be, uint16be,\
            cfloat32, cfloat32le, cfloat32be, cfloat64, cfloat64le, cfloat64be,\
            int8, uint8, bit.
        info: display information messages.
        quiet: do not display information messages or progress status;\
            alternatively, this can be achieved by setting the MRTRIX_QUIET\
            environment variable to a non-empty string.
        debug: display debugging messages.
        force: force overwrite of output files (caution: using the same file as\
            input and output might cause unexpected behaviour).
        nthreads: use this number of threads in multi-threaded applications\
            (set to 0 to disable multi-threading).
        config: temporarily set the value of an MRtrix config file entry.
        help_: display this information page and exit.
        version: display version information and exit.
        contrast1_contrast2: optional list of additional input images used as\
            additional contrasts. Can be used multiple times. contrastX and imageX\
            must share the same coordinate system.
        runner: Command runner.
    Returns:
        NamedTuple of outputs (described in `MrregisterOutputs`).
    """
    params = mrregister_params(
        type_=type_,
        transformed=transformed,
        transformed_midway=transformed_midway,
        mask1=mask1,
        mask2=mask2,
        nan=nan,
        rigid=rigid,
        rigid_1tomidway=rigid_1tomidway,
        rigid_2tomidway=rigid_2tomidway,
        rigid_init_translation=rigid_init_translation,
        rigid_init_rotation=rigid_init_rotation,
        rigid_init_matrix=rigid_init_matrix,
        rigid_scale=rigid_scale,
        rigid_niter=rigid_niter,
        rigid_metric=rigid_metric,
        rigid_metric_diff_estimator=rigid_metric_diff_estimator,
        rigid_lmax=rigid_lmax,
        rigid_log=rigid_log,
        affine=affine,
        affine_1tomidway=affine_1tomidway,
        affine_2tomidway=affine_2tomidway,
        affine_init_translation=affine_init_translation,
        affine_init_rotation=affine_init_rotation,
        affine_init_matrix=affine_init_matrix,
        affine_scale=affine_scale,
        affine_niter=affine_niter,
        affine_metric=affine_metric,
        affine_metric_diff_estimator=affine_metric_diff_estimator,
        affine_lmax=affine_lmax,
        affine_log=affine_log,
        init_translation_unmasked1=init_translation_unmasked1,
        init_translation_unmasked2=init_translation_unmasked2,
        init_rotation_unmasked1=init_rotation_unmasked1,
        init_rotation_unmasked2=init_rotation_unmasked2,
        init_rotation_search_angles=init_rotation_search_angles,
        init_rotation_search_scale=init_rotation_search_scale,
        init_rotation_search_directions=init_rotation_search_directions,
        init_rotation_search_run_global=init_rotation_search_run_global,
        init_rotation_search_global_iterations=init_rotation_search_global_iterations,
        linstage_iterations=linstage_iterations,
        linstage_optimiser_first=linstage_optimiser_first,
        linstage_optimiser_last=linstage_optimiser_last,
        linstage_optimiser_default=linstage_optimiser_default,
        linstage_diagnostics_prefix=linstage_diagnostics_prefix,
        nl_warp=nl_warp,
        nl_warp_full=nl_warp_full,
        nl_init=nl_init,
        nl_scale=nl_scale,
        nl_niter=nl_niter,
        nl_update_smooth=nl_update_smooth,
        nl_disp_smooth=nl_disp_smooth,
        nl_grad_step=nl_grad_step,
        nl_lmax=nl_lmax,
        diagnostics_image=diagnostics_image,
        directions=directions,
        noreorientation=noreorientation,
        mc_weights=mc_weights,
        datatype=datatype,
        info=info,
        quiet=quiet,
        debug=debug,
        force=force,
        nthreads=nthreads,
        config=config,
        help_=help_,
        version=version,
        image1_image2=image1_image2,
        contrast1_contrast2=contrast1_contrast2,
    )
    return mrregister_execute(params, runner)


__all__ = [
    "MRREGISTER_METADATA",
    "MrregisterConfigParamsDict",
    "MrregisterConfigParamsDictTagged",
    "MrregisterNlWarpOutputs",
    "MrregisterNlWarpParamsDict",
    "MrregisterNlWarpParamsDictTagged",
    "MrregisterOutputs",
    "MrregisterParamsDict",
    "MrregisterParamsDictTagged",
    "MrregisterTransformedMidwayOutputs",
    "MrregisterTransformedMidwayParamsDict",
    "MrregisterTransformedMidwayParamsDictTagged",
    "MrregisterTransformedOutputs",
    "MrregisterTransformedParamsDict",
    "MrregisterTransformedParamsDictTagged",
    "mrregister",
    "mrregister_config",
    "mrregister_execute",
    "mrregister_nl_warp",
    "mrregister_params",
    "mrregister_transformed",
    "mrregister_transformed_midway",
]
