from typing import Union
from typing import Sequence


def generate_ucc_amplitudes(n_electrons: Union[int, float],
                            n_spin_orbitals: Union[int, float],) -> Sequence:
    """
    Create lists of amplidues to generate UCC operators.

    This function does not enforce spin-conservation in the
    excitation operators.

    Args:
        n_electrons (int): Number of electrons.
        n_spin_orbitals (int): Number of spin-orbitals,
            equivalent to number of qubits.

    Returns:
        single_amplitudes, double_amplitudes (list): List of single
            and double amplitudes as [[i,j], t_ij, [k,l], t_kl]

    Raises:
        TypeError: if n_electrons or n_spin_orbitals is not integer or float.
        ValueError: if n_electrons is greater than n_spin_orbitals.

    Notes:
        Assigns value 1 to each amplitude.
    """
    if isinstance(n_electrons, (int, float)):
        n_electrons = int(n_electrons)
    else:
        raise TypeError('Electrons must be a number.')
    if isinstance(n_spin_orbitals, (int, float)):
        n_spin_orbitals = int(n_spin_orbitals)
    else:
        raise TypeError('Orbitals must be a number.')
    if n_electrons > n_spin_orbitals:
        raise ValueError(
            'Number of electrons can not be greater than orbitals.')

    single_amplitudes = []
    double_amplitudes = []

    for one_el in range(0, n_electrons):
        for unocc_orb in range(n_electrons, n_spin_orbitals):
            single_amplitudes.append([[unocc_orb, one_el], 1.0])

            for two_el in range(one_el, n_electrons):
                for two_unocc_orb in range(unocc_orb, n_spin_orbitals):
                    if ((two_unocc_orb != unocc_orb) and (two_el != one_el)):
                        double_amplitudes.append(
                            [[two_unocc_orb, two_el, unocc_orb, one_el], 1.0])

    return single_amplitudes, double_amplitudes