Skip to content
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

Circuit ansatze should be dagger functors #155

Merged
merged 7 commits into from
Sep 30, 2024

Conversation

kinianlo
Copy link
Contributor

It would be nice to have CircuitAnsatz acting as a dagger functor, that is

ansatz(diagram).dagger() == ansatz(diagram.dagger())

Currently this is not true. For instance:

from lambeq import IQPAnsatz, AtomicType
from lambeq.backend import Word
from lambeq.backend.drawing import draw_equation

ansatz = IQPAnsatz({AtomicType.NOUN: 1}, n_layers=1)
diagram = Word('John', AtomicType.NOUN)

circ1 = ansatz(diagram).dagger()
circ2 = ansatz(diagram.dagger())
draw_equation(circ1, circ2, symbol='!=', figsize=(6, 6))

b13fb54a-38dd-4d41-9e0c-353f6f86a964
Note that the symbols of circ2 are completely different to those in circ1. The ansatz simply takes the dagger as part of the symbol names.
This behaviour means that the use of RemoveCupsRewriter would lead to circuits that are outright different to those without the use of the rewriter. This should be undesirable as the role of RemoveCupsRewriter should be merely to improve computational efficiency, while keeping outputs untouched.

The proposed fix

In the _ar method of the base class CircuitAnsat, a check is added to see if the box is daggered. If so, the un-daggered box is passed to the ansatz whose output would be then daggered.

@nikhilkhatri
Copy link
Collaborator

Thanks a lot for this PR @kinianlo !
This is definitely something that needs fixing.

Your approach would work for circuits, but could be expanded to extend this behaviour to all functors (not just ansatze).

I'd recommend this be implemented by adding your logic in a apply_functor method added to the Daggered class in grammar.py.
Daggered class is here: https://github.com/CQCL/lambeq/blob/main/lambeq/backend/grammar.py#L1547
Example apply_functor from existing Box: https://github.com/CQCL/lambeq/blob/main/lambeq/backend/grammar.py#L447

This would yield the same behaviour for ansatze, and across functors applied to daggered boxes.

@kinianlo
Copy link
Contributor Author

@nikhilkhatri Thank you for the suggestion! I I’ve tried to implement that but there is a problem at its current state: Diagrammable does not have a dagger() method. Is Diagrammable supposed to have a dagger() method? Otherwise the logic should be applied to specific subclasses of Diagrams with a dagger() defined?

@nikhilkhatri
Copy link
Collaborator

@kinianlo I think it makes sense to add a dagger signature to Diagrammable.

Something as simple as the following should work:

    def dagger(self) -> Diagrammable:
        """Implements conjugation of diagrams."""

@kinianlo
Copy link
Contributor Author

@kinianlo I think it makes sense to add a dagger signature to Diagrammable.

Something as simple as the following should work:


    def dagger(self) -> Diagrammable:

        """Implements conjugation of diagrams."""

Copied and pasted👍

Copy link
Contributor

@dimkart dimkart left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this, looks good now.

@dimkart dimkart merged commit 88d93f8 into CQCL:main Sep 30, 2024
9 checks passed
kinianlo added a commit to kinianlo/lambeq that referenced this pull request Oct 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants