Skip to content

[Feature] qjit-compatible implementation of itertools.product #1340

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
josh146 opened this issue Nov 28, 2024 · 3 comments
Open

[Feature] qjit-compatible implementation of itertools.product #1340

josh146 opened this issue Nov 28, 2024 · 3 comments
Labels
enhancement New feature or request

Comments

@josh146
Copy link
Member

josh146 commented Nov 28, 2024

It's quite common to see workflows that make use of itertools related functionality, in particular

  • itertools.product,
  • itertools.combinations, and
  • itertools.permutations.

Here, I focus only on product as this is part of the workflow I am using.

For example, consider:

@qml.qjit(autograph=True)
def fn(x):

    for i, j in itertools.product(range(2), repeat=2):
        x += i + j - i * j * jnp.sin(j)

    return x

Here, product has the following rough semantics:

def p(*iterables, repeat=1):
    result = [[]]

    if repeat < 0:
        raise ValueError('repeat argument cannot be negative')

    for l in range(repeat):
        for pool in map(tuple, iterables):
            _temp = []

            for i in result:
                for j in pool:
                    _temp.append(i + [j])

            result = _temp

    for prod in result:
        yield tuple(prod)

(note this is not exactly the implementation, as the actual implementation does not generate intermediate lists in memory).

This will fail to compile, since Autograph is not able to recognize and convert itertools.product (even though the arguments are all compile-time constant).

It is also non-trivial to re-write as pure catalyst loops using range in complex cases.

I propose adding our own catalyst.product, similar to our existing range, that AutoGraph can use as the conversion target. This would then lower to a fast implementation of product (likely as nested for loops) at the MLIR layer. An advantage here is that this would allow product to work even with dynamic arguments.

@josh146 josh146 added the enhancement New feature or request label Nov 28, 2024
@josh146
Copy link
Member Author

josh146 commented Nov 28, 2024

Longer term, we could also do the same thing for itertools.combinations and itertools.permutations.

@dime10
Copy link
Contributor

dime10 commented Apr 16, 2025

Hi @josh146, I think this

This will fail to compile, since Autograph is not able to recognize and convert itertools.product (even though the arguments are all compile-time constant).

was actually a bug because static constructs should always be able to fall-back into their Python implementation. I fixed it in #1665, but it still won't allow you to supply dynamic args to itertool functions.

dime10 added a commit that referenced this issue Apr 17, 2025
Fix AutoGraph fallback for valid iteration targets with constant data
but no length, for example the following program is now supported:

```py
@qml.qjit(autograph=True)
def fn(x):

    for i, j in itertools.product(range(2), repeat=2):
        x += i + j - i * j * jnp.sin(j)

    return x

>>> fn(5)
8.158529015192103
```

Fixes the bug discovered in #1340, but doesn't close it as it also
contains a feature request.
[sc-89322]

(Also adjusts the line length `isort` is working with to 100, same as
our other tools.)
@josh146
Copy link
Member Author

josh146 commented Apr 18, 2025

oh awesome, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants