def is_streusle_transition_allowed(from_tag: str,
                                   to_tag: str):
    """
    Given a constraint type and strings ``from_tag`` and ``to_tag`` that
    represent the origin and destination of the transition, return whether
    the transition is allowed under the STREUSLE tagging scheme.

    Parameters
    ----------
    from_tag : ``str``, required
        The tag that the transition originates from. For example, if the
        label is ``I~-V-v.cognition``, the ``from_tag`` is ``I~``.
    to_tag : ``str``, required
        The tag that the transition leads to. For example, if the
        label is ``I~-V-v.cognition``, the ``to_tag`` is ``I~``.

    Returns
    -------
    ``bool``
        Whether the transition is allowed under the given ``constraint_type``.
    """
    # pylint: disable=too-many-return-statements
    if from_tag not in ('O', 'B', 'I_', 'I~', 'o', 'b', 'i_', 'i~', 'START', 'END'):
        raise ValueError("Got invalid from_tag {}".format(from_tag))
    if to_tag not in ('O', 'B', 'I_', 'I~', 'o', 'b', 'i_', 'i~', 'START', 'END'):
        raise ValueError("Got invalid to_tag {}".format(to_tag))

    if to_tag == "START" or from_tag == "END":
        # Cannot transition into START or from END
        return False

    if from_tag == "START":
        return to_tag in ('O', 'B')
    if to_tag == "END":
        return from_tag in ('O', 'I_', 'I~')
    return any([
            # B can transition to o-*, b-*, I_-*, or I~-*
            # o can transition to o-*, b-*, I_-*, or I~-*
            from_tag in ('B', 'o') and to_tag in ('o', 'b', 'I_', 'I~'),
            # b can transition to i_ or i~, but only if the entity tags match
            from_tag in ('b',) and to_tag in ('i_', 'i~'),
            # O can transition to O-*, B-*, or END
            from_tag in ('O',) and to_tag in ('O', 'B'),
            # I_, I~ can transition to all tags except i_-* or i~-*
            from_tag in ('I_', 'I~') and to_tag not in ('i_', 'i~'),
            # i_, i~ can transition to all tags except O, B
            from_tag in ('i_', 'i~') and to_tag not in ('O', 'B'),
    ])