Skip to content

Controlled gate construction cannot construct some cases #4512

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

Closed
dabacon opened this issue Sep 20, 2021 · 12 comments
Closed

Controlled gate construction cannot construct some cases #4512

dabacon opened this issue Sep 20, 2021 · 12 comments
Assignees
Labels
area/contrib good first issue This issue can be resolved by someone who is not familiar with the codebase. A good starting issue. good for learning For beginners in QC, this will help picking up some knowledge. Bit harder than "good first issues" kind/feature-request Describes new functionality priority/p3 Should be done in the next 6 months triage/accepted A consensus emerged that this bug report, feature request, or other action should be worked on

Comments

@dabacon
Copy link
Collaborator

dabacon commented Sep 20, 2021

Is your feature request related to a use case or problem? Please describe.

Suppose you want a three qubit controlled gate like (|00><00| + |11><11|) X + (|01><01| + |10><10| I which flips the third qubit if the first qubit is either 00 or 11. This currently isn't possible to construct given the way cirq specified control_values. This is because control_values is a sequence of length equal to the number of controls, and this sequence is either ints or sequences of ints. In the second case the sequence means "either of these". Thus you might think this would construct the gate above, but it does not

cirq.X(q2).controlled_by(q0, q1, control_values=((0, 1), (0, 1))

(this flips the third qubit for all inputs)
Or maybe this

cirq.X(q2).controlled_by(q0, q1, control_values=((0, 0), (1, 1))

(this flips the third qubit if the first control is zero and the second is one.

Describe the solution you'd like

Not sure we can fix this now, as this interface is used throughout :(

Probably the better interface would have been sequence of ints, same interperation, sequence of sequence either zipped up to get possible control positive values, or sequence of sequence where inner sequence is sequence of ints describing a positive control value. If you really want to include unions for any of these, places where there is an int could have either an indicator value or another sequence to unionize what this means.

[optional] Describe alternatives/workarounds you've considered

Create two ops in a row that do what you want. Custom gate controlled gate.

What is the urgency from your perspective for this issue? Is it blocking important work?

P2 - we should do it in the next couple of quarters

@dabacon dabacon added the kind/feature-request Describes new functionality label Sep 20, 2021
@tanujkhattar tanujkhattar added area/contrib good first issue This issue can be resolved by someone who is not familiar with the codebase. A good starting issue. good for learning For beginners in QC, this will help picking up some knowledge. Bit harder than "good first issues" priority/p3 Should be done in the next 6 months labels Sep 29, 2021
@NoureldinYosri
Copy link
Collaborator

hi, is anyone working on this (in other words can I work on it?)

@vtomole
Copy link
Collaborator

vtomole commented Oct 10, 2021

@NoureldinYosri I've assigned it to you.

@95-martin-orion 95-martin-orion added the triage/discuss Needs decision / discussion, bring these up during Cirq Cynque label Oct 13, 2021
@NoureldinYosri
Copy link
Collaborator

Analysis:
the reason for this behaviour is that the control qubits are assumed to be independent, the control_values list has length = number of control qubits and the combinations for which the gate is applied is the cartisian product of control_values, e.g. L109 for control_vals in itertools.product(*self.control_values):
furthermore the order of the values doesn't matter since the items of control_values are sorted during the contstruction of controlled_gate and controlled_operation , e.g. L76 and L56
# Convert to sorted tuples self.control_values = cast( Tuple[Tuple[int, ...], ...], tuple((val,) if isinstance(val, int) else tuple(sorted(val)) for val in control_values), )

Solution:
the needed behaviour is achieved if it's possible to represent the control combinations as a sum of products, e.g. ((1, 0), (0, 1)) would mean (q1 = 1 and q2 = 0) or (q1 == 0 and q2 == 1), however this list is currently interpreted as (0, 1)x(0, 1) -> all possible combinations

on the other hand the ability of having controlling the gates using independent qubits (in terms of the truth table of the control combinations) should still be supported not just for backward compatibility but also because it would make it easier to represent some truth tables

my suggestion is to create a class that maintains two things

  1. a list of "free variables" which is a list of variables with their needed values and the combinations are the cross product of the values for each variable (mirroring the existing implementation)
  2. a list/itertools.product of "constrained variables"
    the advantages are
  3. from these the list of combinations can be generated as for control_vals in itertools.product(self.contrained_variables, *self.free_variables):
  4. merging (taking the cross product) of combinations is also quite straightforward using this approach.
  5. backward compatibability is also straightforward e.g. in the constructors of controlled_gate and controlled_operation self.control_values = ControlValues(free_variables=control_values) and in _apply_unitary_ function the loop would be for control_vals in self.control_values.list():

I already wrote a small demo for this idea but wanted to check with you before I continue implementing @vtomole

@dstrain115 dstrain115 added triage/accepted A consensus emerged that this bug report, feature request, or other action should be worked on and removed triage/discuss Needs decision / discussion, bring these up during Cirq Cynque labels Oct 27, 2021
@dstrain115
Copy link
Collaborator

Cirq cync: We have a potential solution with a prototype. This will likely need careful consideration and review, but is doable with the solution from @NoureldinYosri

@NoureldinYosri
Copy link
Collaborator

NoureldinYosri commented Oct 28, 2021

This is a prototype of my solution @dstrain115 @vtomole
this code is also backward compatible with the old way, calling ControlValues(control_values) will give the same combinations as the ones expected in the old way

import itertools

def _flatten(A):
    def _flatten_aux(A):
        if isinstance(A, int):
            yield A
        else:
            for a in A:
                yield from _flatten_aux(a)
    return list(_flatten_aux(A))


class ControlValues:
    def __init__(self, control_values):
        if not len(control_values):
            raise "Empty control values"

        self.nxt = None
        self.vals = control_values[0]

        if len(control_values) > 1:
            self.nxt = ControlValues(control_values[1:])

        if isinstance(self.vals, int):
            self.vals = (self.vals, )

    def merge(self, other):
        # Cartesian product of all combinations in self x other
        cur = self
        while cur.nxt: cur = cur.nxt
        cur.nxt = other

    def __call__(self):
        return self.__iter__()

    def __iter__(self):
        nxt = self.nxt if self.nxt else lambda: [()]
        self.itr = itertools.product(self.vals, nxt())
        return self.itr

    def __next__(self):
        for v in self.itr:
            yield v

if __name__ == "__main__":
    CV1 = ControlValues((((1, 0), (0, 1)),)) # (q1 and not q2) or (not q1 and q2)
    CV2 = ControlValues([0, [0, 1], 1]) # not q3 and q5 with any value for q4
    for cv in CV1:
        print(_flatten(cv))
    print()
    for cv in CV2:
        print(_flatten(cv))
    print()
    CV1.merge(CV2) # all combinations in CV1 x all combinations in CV2
    for cv in CV1:
        print(_flatten(cv))

output is
[1, 0]
[0, 1]

[0, 0, 1]
[0, 1, 1]

[1, 0, 0, 0, 1]
[1, 0, 0, 1, 1]
[0, 1, 0, 0, 1]
[0, 1, 0, 1, 1]

@NoureldinYosri
Copy link
Collaborator

@dabacon could you please review the solution?

@dabacon
Copy link
Collaborator Author

dabacon commented Nov 19, 2021

The one kind of strange thing about your implementation (which is quite ingenious!) is that the two cases are distinguished by a) list of int or (list of int) and b) list of list of (list of ints). This is a bit hard for most people to see the difference between, i.e. staring at the list of list of lists to see thats what it is isn't too easy. What I would suggest is that we keep this "raw" form, but maybe also add some helpers for people to write this, i.e. instead of a) you could provide FreeVars(0, [0,1]) and for b) you could provide ConstrainedVars([0, 1], [0, 1]). To be clear I think it could also accept the way you have things currently constructed, but just adding this as a convenience I think would make it more usable for most people.

@NoureldinYosri
Copy link
Collaborator

sounds good, I'll incorporate your suggestion into my code and create a PR

NoureldinYosri added a commit to NoureldinYosri/Cirq that referenced this issue Nov 30, 2021
…mlib#4512

- created control_values.py which contains the ControlValues class.
- FreeVars and ConstrainedVars classes are provided for ease of use.
- while the basic idea of ControlValues integrating it inside the code base was challening
- the old way of using control_values assumed it's a tuple of tuples of ints and was used as thus (comparasion, hashing, slicing, fomatting, conditioning, and loops), the ControlValues class had to provide these functionalities
- the trickiest part to get right was the support for formatting!
- I'll create a follow up PR for unit tests for control_values.py
NoureldinYosri added a commit to NoureldinYosri/Cirq that referenced this issue Nov 30, 2021
…mlib#4512

- created control_values.py which contains the ControlValues class.
- FreeVars and ConstrainedVars classes are provided for ease of use.
- while the basic idea of ControlValues integrating it inside the code base was challening
- the old way of using control_values assumed it's a tuple of tuples of ints and was used as thus (comparasion, hashing, slicing, fomatting, conditioning, and loops), the ControlValues class had to provide these functionalities
- the trickiest part to get right was the support for formatting!
- I'll create a follow up PR for unit tests for control_values.py
NoureldinYosri added a commit to NoureldinYosri/Cirq that referenced this issue Dec 1, 2021
…mlib#4512 quantumlib#4714

- created control_values.py which contains the ControlValues class.
- FreeVars and ConstrainedVars classes are provided for ease of use.
- while the basic idea of ControlValues integrating it inside the code base was challening
- the old way of using control_values assumed it's a tuple of tuples of ints and was used as thus (comparasion, hashing, slicing, fomatting, conditioning, and loops), the ControlValues class had to provide these functionalities
- the trickiest part to get right was the support for formatting!
- I'll create a follow up PR for unit tests for control_values.py
NoureldinYosri added a commit to NoureldinYosri/Cirq that referenced this issue Dec 1, 2021
…mlib#4512

- created control_values.py which contains the ControlValues class.
- FreeVars and ConstrainedVars classes are provided for ease of use.
- while the basic idea of ControlValues integrating it inside the code base was challening
- the old way of using control_values assumed it's a tuple of tuples of ints and was used as thus (comparasion, hashing, slicing, fomatting, conditioning, and loops), the ControlValues class had to provide these functionalities
- the trickiest part to get right was the support for formatting!
- I'll create a follow up PR for unit tests for control_values.py
NoureldinYosri added a commit to NoureldinYosri/Cirq that referenced this issue Dec 1, 2021
…mlib#4512

created control_values.py which contains the ControlValues class.\nFreeVars and ConstrainedVars classes are provided for ease of use.\nwhile the basic idea of ControlValues integrating it inside the code base was challening\nthe old way of using control_values assumed it's a tuple of tuples of ints and was used as thus (comparasion, hashing, slicing, fomatting, conditioning, and loops), the ControlValues class had to provide these functionalities\nthe trickiest part to get right was the support for formatting!\nI'll create a follow up PR for unit tests for control_values.py
NoureldinYosri added a commit to NoureldinYosri/Cirq that referenced this issue Dec 1, 2021
…mlib#4512

created control_values.py which contains the ControlValues class.\nFreeVars and ConstrainedVars classes are provided for ease of use.\nwhile the basic idea of ControlValues integrating it inside the code base was challening\nthe old way of using control_values assumed it's a tuple of tuples of ints and was used as thus (comparasion, hashing, slicing, fomatting, conditioning, and loops), the ControlValues class had to provide these functionalities\nthe trickiest part to get right was the support for formatting!\nI'll create a follow up PR for unit tests for control_values.py
NoureldinYosri added a commit to NoureldinYosri/Cirq that referenced this issue Dec 1, 2021
…mlib#4512

created control_values.py which contains the ControlValues class.\nFreeVars and ConstrainedVars classes are provided for ease of use.\nwhile the basic idea of ControlValues integrating it inside the code base was challening\nthe old way of using control_values assumed it's a tuple of tuples of ints and was used as thus (comparasion, hashing, slicing, fomatting, conditioning, and loops), the ControlValues class had to provide these functionalities\nthe trickiest part to get right was the support for formatting!\nI'll create a follow up PR for unit tests for control_values.py
NoureldinYosri added a commit to NoureldinYosri/Cirq that referenced this issue Dec 1, 2021
…mlib#4512

created control_values.py which contains the ControlValues class.\nFreeVars and ConstrainedVars classes are provided for ease of use.\nwhile the basic idea of ControlValues integrating it inside the code base was challening\nthe old way of using control_values assumed it's a tuple of tuples of ints and was used as thus (comparasion, hashing, slicing, fomatting, conditioning, and loops), the ControlValues class had to provide these functionalities\nthe trickiest part to get right was the support for formatting!\nI'll create a follow up PR for unit tests for control_values.py
NoureldinYosri added a commit to NoureldinYosri/Cirq that referenced this issue Dec 1, 2021
…mlib#4512

created control_values.py which contains the ControlValues class.\nFreeVars and ConstrainedVars classes are provided for ease of use.\nwhile the basic idea of ControlValues integrating it inside the code base was challening\nthe old way of using control_values assumed it's a tuple of tuples of ints and was used as thus (comparasion, hashing, slicing, fomatting, conditioning, and loops), the ControlValues class had to provide these functionalities\nthe trickiest part to get right was the support for formatting!\nI'll create a follow up PR for unit tests for control_values.py
NoureldinYosri added a commit to NoureldinYosri/Cirq that referenced this issue Dec 1, 2021
…mlib#4512

created control_values.py which contains the ControlValues class.\nFreeVars and ConstrainedVars classes are provided for ease of use.\nwhile the basic idea of ControlValues integrating it inside the code base was challening\nthe old way of using control_values assumed it's a tuple of tuples of ints and was used as thus (comparasion, hashing, slicing, fomatting, conditioning, and loops), the ControlValues class had to provide these functionalities\nthe trickiest part to get right was the support for formatting!\nI'll create a follow up PR for unit tests for control_values.py
NoureldinYosri added a commit to NoureldinYosri/Cirq that referenced this issue Dec 1, 2021
…mlib#4512

created control_values.py which contains the ControlValues class.\nFreeVars and ConstrainedVars classes are provided for ease of use.\nwhile the basic idea of ControlValues integrating it inside the code base was challening\nthe old way of using control_values assumed it's a tuple of tuples of ints and was used as thus (comparasion, hashing, slicing, fomatting, conditioning, and loops), the ControlValues class had to provide these functionalities\nthe trickiest part to get right was the support for formatting!\nI'll create a follow up PR for unit tests for control_values.py
NoureldinYosri added a commit to NoureldinYosri/Cirq that referenced this issue Dec 1, 2021
…mlib#4512

created control_values.py which contains the ControlValues class.\nFreeVars and ConstrainedVars classes are provided for ease of use.\nwhile the basic idea of ControlValues integrating it inside the code base was challening\nthe old way of using control_values assumed it's a tuple of tuples of ints and was used as thus (comparasion, hashing, slicing, fomatting, conditioning, and loops), the ControlValues class had to provide these functionalities\nthe trickiest part to get right was the support for formatting!\nI'll create a follow up PR for unit tests for control_values.py
NoureldinYosri added a commit to NoureldinYosri/Cirq that referenced this issue Dec 1, 2021
…mlib#4512

created control_values.py which contains the ControlValues class.\nFreeVars and ConstrainedVars classes are provided for ease of use.\nwhile the basic idea of ControlValues integrating it inside the code base was challening\nthe old way of using control_values assumed it's a tuple of tuples of ints and was used as thus (comparasion, hashing, slicing, fomatting, conditioning, and loops), the ControlValues class had to provide these functionalities\nthe trickiest part to get right was the support for formatting!\nI'll create a follow up PR for unit tests for control_values.py
NoureldinYosri added a commit to NoureldinYosri/Cirq that referenced this issue Dec 2, 2021
…mlib#4512

created control_values.py which contains the ControlValues class.
FreeVars and ConstrainedVars classes are provided for ease of use.
while the basic idea of ControlValues integrating it inside the code base was challening
the old way of using control_values assumed it's a tuple of tuples of ints and was used as thus (comparasion, hashing, slicing, fomatting, conditioning, and loops), the ControlValues class had to provide these functionalities
the trickiest part to get right was the support for formatting!
NoureldinYosri added a commit to NoureldinYosri/Cirq that referenced this issue Dec 2, 2021
…mlib#4512

created control_values.py which contains the ControlValues class.
FreeVars and ConstrainedVars classes are provided for ease of use.
while the basic idea of ControlValues integrating it inside the code base was challening
the old way of using control_values assumed it's a tuple of tuples of ints and was used as thus (comparasion, hashing, slicing, fomatting, conditioning, and loops), the ControlValues class had to provide these functionalities
the trickiest part to get right was the support for formatting!
NoureldinYosri added a commit to NoureldinYosri/Cirq that referenced this issue Dec 11, 2021
…mlib#4512

created control_values.py which contains the ControlValues class.
FreeVars and ConstrainedVars classes are provided for ease of use.
while the basic idea of ControlValues integrating it inside the code base was challening
the old way of using control_values assumed it's a tuple of tuples of ints and was used as thus (comparasion, hashing, slicing, fomatting, conditioning, and loops), the ControlValues class had to provide these functionalities
the trickiest part to get right was the support for formatting!
NoureldinYosri added a commit to NoureldinYosri/Cirq that referenced this issue Dec 18, 2021
…mlib#4512

created control_values.py which contains the ControlValues class.
FreeVars and ConstrainedVars classes are provided for ease of use.
while the basic idea of ControlValues integrating it inside the code base was challening
the old way of using control_values assumed it's a tuple of tuples of ints and was used as thus (comparasion, hashing, slicing, fomatting, conditioning, and loops), the ControlValues class had to provide these functionalities
the trickiest part to get right was the support for formatting!
@daxfohl
Copy link
Collaborator

daxfohl commented Jan 17, 2022

@NoureldinYosri still working on this? It'll be required for deferred measurements #4818. Or, at least some way of defining the condition "at least one qubit is not zero".

@daxfohl
Copy link
Collaborator

daxfohl commented Jan 17, 2022

I think all I'd really need here is just another parameter control_values_explicit (or control_options, controls_as_list?), where you can pass in e.g. control_values_explicit=[(0, 0), (1, 1)] to construct the condition in the issue description. Is this possible? If this is possible, I think I'd prefer it. That way we can decouple the operation from the class that generates the exact list, freeing up the ability to create whatever kinds of generators we want (boolean expression, sympy, int-to-bits, etc), wherever and wherever we want them.

Edit: Looks like such a thing should be possible, as everywhere the existing control_values is used for calculations, it's done via itertools.product, meaning it produces what I'm wanting to provide explicitly in control_values_explicit. So we should be able to populate self._control_values_explicit in the constructor, from whichever of the two parameters is provided. The only issue is that self.control_values is public, so we should probably wrap that in a property and ensure the _explicit is also updated in the setter. It's not really a breaking change since all existing code will continue to work, but we'll probably want to deprecate that property since it's no longer able to represent all possible states.

@NoureldinYosri
Copy link
Collaborator

@daxfohl my GH-4714 has been pending review for sometime

in the PR I create a ControlValues class which supports the operations needed, the contructor for it can support both the _exact way for defining the allowed values as well as the old way, this way adding support for more ways to define control values would be as simple as creating a child class that reads the new form of input (e.g. list of ints) and set the internal variables correctly and maybe override some internal function(s).

so lets get GH-4714 reviewed and submitted :)

NoureldinYosri added a commit to NoureldinYosri/Cirq that referenced this issue Jan 28, 2022
…mlib#4512

created control_values.py which contains the ControlValues class.
FreeVars and ConstrainedVars classes are provided for ease of use.
while the basic idea of ControlValues integrating it inside the code base was challening
the old way of using control_values assumed it's a tuple of tuples of ints and was used as thus (comparasion, hashing, slicing, fomatting, conditioning, and loops), the ControlValues class had to provide these functionalities
the trickiest part to get right was the support for formatting!
CirqBot pushed a commit that referenced this issue Feb 9, 2022
Closes #4818, Also reimplements `mux` simulation based on this, in preparation to deprecate `ignore_measurement_results`.

Needs a follow-up after #4512 to support classical controls on multi-qubit measurements, as we need some way of defining the condition "at least one qubit is not zero" to match the classical interpretation of a multi-qubit measurement.
95-martin-orion pushed a commit to 95-martin-orion/Cirq that referenced this issue Mar 2, 2022
Closes quantumlib#4818, Also reimplements `mux` simulation based on this, in preparation to deprecate `ignore_measurement_results`.

Needs a follow-up after quantumlib#4512 to support classical controls on multi-qubit measurements, as we need some way of defining the condition "at least one qubit is not zero" to match the classical interpretation of a multi-qubit measurement.
NoureldinYosri added a commit to NoureldinYosri/Cirq that referenced this issue May 13, 2022
…n that replicates current behaviour.

refactored the code for control_values and abstracted its calls
this is a first step towards implementing more ways to represent control values in order to solve quantumlib#4512
CirqBot pushed a commit that referenced this issue Jul 8, 2022
Created a concrete implementation that replicates current behaviour.
refactored the code for control_values and abstracted its calls
this is a first step towards implementing more ways to represent control values in order to solve #4512
NoureldinYosri added a commit to NoureldinYosri/Cirq that referenced this issue Jul 13, 2022
This class allows the creation of control values that can't be factored into simple products hence solving quantumlib#4512
CirqBot pushed a commit that referenced this issue Jul 15, 2022
This class allows the creation of control values that can't be factored into simple products hence solving #4512
@tanujkhattar
Copy link
Collaborator

This is now completed. See #5788 for details on usage and tests.

rht pushed a commit to rht/Cirq that referenced this issue May 1, 2023
Closes quantumlib#4818, Also reimplements `mux` simulation based on this, in preparation to deprecate `ignore_measurement_results`.

Needs a follow-up after quantumlib#4512 to support classical controls on multi-qubit measurements, as we need some way of defining the condition "at least one qubit is not zero" to match the classical interpretation of a multi-qubit measurement.
rht pushed a commit to rht/Cirq that referenced this issue May 1, 2023
…5362)

Created a concrete implementation that replicates current behaviour.
refactored the code for control_values and abstracted its calls
this is a first step towards implementing more ways to represent control values in order to solve quantumlib#4512
rht pushed a commit to rht/Cirq that referenced this issue May 1, 2023
This class allows the creation of control values that can't be factored into simple products hence solving quantumlib#4512
harry-phasecraft pushed a commit to PhaseCraft/Cirq that referenced this issue Oct 31, 2024
Closes quantumlib#4818, Also reimplements `mux` simulation based on this, in preparation to deprecate `ignore_measurement_results`.

Needs a follow-up after quantumlib#4512 to support classical controls on multi-qubit measurements, as we need some way of defining the condition "at least one qubit is not zero" to match the classical interpretation of a multi-qubit measurement.
harry-phasecraft pushed a commit to PhaseCraft/Cirq that referenced this issue Oct 31, 2024
…5362)

Created a concrete implementation that replicates current behaviour.
refactored the code for control_values and abstracted its calls
this is a first step towards implementing more ways to represent control values in order to solve quantumlib#4512
harry-phasecraft pushed a commit to PhaseCraft/Cirq that referenced this issue Oct 31, 2024
This class allows the creation of control values that can't be factored into simple products hence solving quantumlib#4512
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/contrib good first issue This issue can be resolved by someone who is not familiar with the codebase. A good starting issue. good for learning For beginners in QC, this will help picking up some knowledge. Bit harder than "good first issues" kind/feature-request Describes new functionality priority/p3 Should be done in the next 6 months triage/accepted A consensus emerged that this bug report, feature request, or other action should be worked on
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants