Skip to content

update_odometer

Updates the odometer.

update_odometer

update_odometer(old_ind: list[int] | ndarray, upper_lim: list[int] | ndarray) -> list[int] | ndarray

Increase a vector as odometer.

Increases the last entry of the vector old_ind by 1, unless that would make it larger than the last entry of the vector upper_lim. In this case, it sets the last entry to 0 and instead increases the second-last entry of old_ind, unless that would make it larger than the second-last entry of upper_lim. In this case, it sets the second-last entry to 0 and instead increases the third-last entry of old_ind (and so on; it works like an odometer).

This function is useful when you want to have k nested loops, but k isn't specified beforehand. For example, instead of looping over i and j going from 1 to 3, you could loop over a single variable going from 1 to 3^2 and set [i, j] = update_odometer([i, j], [3, 3]) at each step within the loop.

This function is adapted from QETLAB 1.

Examples:

from toqito.helper import update_odometer
import numpy as np
vec = np.array([0, 0])
upper_lim = np.array([3, 2])
for j in range(0, np.prod(upper_lim)-1):
        vec = update_odometer(vec, upper_lim)
        print(vec)

[0 1][1 0] [1 1][2 0] [2 1]

Parameters:

  • old_ind (list[int] | ndarray) –

    The initial vector.

  • upper_lim (list[int] | ndarray) –

    The upper limit on which to increase the odometer to.

Returns:

  • list[int] | ndarray

    The updated vector.

References

1 Johnston, Nathaniel. {{QETLAB}: {A MATLAB} toolbox for quantum entanglement}. doi:10.5281/zenodo.44637.

Source code in toqito/helper/update_odometer.py
def update_odometer(old_ind: list[int] | np.ndarray, upper_lim: list[int] | np.ndarray) -> list[int] | np.ndarray:
    r"""Increase a vector as odometer.

    Increases the last entry of the vector `old_ind` by 1, unless that would
    make it larger than the last entry of the vector `upper_lim`. In this case,
    it sets the last entry to 0 and instead increases the second-last entry of
    `old_ind`, unless that would make it larger than the second-last entry of
    `upper_lim`. In this case, it sets the second-last entry to 0 and instead
    increases the third-last entry of `old_ind` (and so on; it works like an
    odometer).

    This function is useful when you want to have k nested loops, but k isn't
    specified beforehand. For example, instead of looping over i and j going
    from 1 to 3, you could loop over a single variable going from 1 to 3^2 and
    set [i, j] = update_odometer([i, j], [3, 3]) at each step within the loop.

    This function is adapted from QETLAB [@QETLAB_link].

    Examples:
        ```python exec="1" source="above"
        from toqito.helper import update_odometer
        import numpy as np
        vec = np.array([0, 0])
        upper_lim = np.array([3, 2])
        for j in range(0, np.prod(upper_lim)-1):
                vec = update_odometer(vec, upper_lim)
                print(vec)
        ```

    Args:
        old_ind: The initial vector.
        upper_lim: The upper limit on which to increase the odometer to.

    Returns:
        The updated vector.

    """
    ind_len = len(old_ind)
    new_ind = old_ind[:]

    # Start by increasing the last index by 1.
    if len(new_ind) > 0:
        new_ind[-1] = new_ind[-1] + 1

    # Increment the "odometer": Repeatedly set each digit to 0 if it is too high
    # and carry the addition to the left until we hit a digit that is not too
    # high.
    for j in range(ind_len, 0, -1):
        # If we have hit the upper limit in this entry, move onto the next
        # entry.
        if new_ind[j - 1] >= upper_lim[j - 1]:
            new_ind[j - 1] = 0
            if j >= 2:
                new_ind[j - 2] = new_ind[j - 2] + 1
            else:
                # We are at the left end of the vector, so just stop.
                return new_ind
        else:
            # Always return if the odometer doesn't turn over.
            return new_ind
    return new_ind