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

Draw qml.cond: Part 2; qml.map_wires correctly maps nested tape wires #4901

Merged
merged 13 commits into from
Dec 1, 2023

Conversation

mudit2812
Copy link
Contributor

@mudit2812 mudit2812 commented Nov 29, 2023

Context:
This PR follows up on adding support for qml.cond with qml.draw by fully allowing users to draw multiple conditional operators that are conditioned on multiple mid-circuit measurements. While implementing this, I tried to use qml.map_wires on the tape being drawn (which was eventually scrapped as it's too messy to use with nested tapes), and found out that nested tapes were not handled by map_wires correctly.

An example of what drawings can look like is shown here:

def circuit():
    qml.RX(0.5, 0)
    qml.RX(0.5, 1)

    m0 = qml.measure(0, reset=True, postselect=1)
    m1 = qml.measure(1)
    qml.cond(m0 & m1, qml.MultiControlledX)(wires=[1, 2, 3, 0], control_values="110")
    qml.cond(m1, qml.PauliZ)(2)

    m2 = qml.measure(1)
    qml.CNOT([3, 2])
    qml.cond(m0, qml.ctrl(qml.SWAP, control=[1, 2], control_values=[True, False]))(wires=[0, 3])
    qml.cond(m2 & m1, qml.PauliY)(0)

    qml.Toffoli([3, 1, 0])

    m3 = qml.measure(3, postselect=0)
    qml.cond(m3, qml.RX)(1.23, 3)
    qml.cond(m3 & m1, qml.Hadamard)(2)

    return qml.expval(qml.PauliZ(0) @ qml.PauliZ(2))

print(qml.draw(circuit)())
0: ──RX(0.50)──┤↗₁│  │0⟩──────╭X────────────╭SWAP──Y─╭X────────────────────┤ ╭<Z@Z>
1: ──RX(0.50)───║─────────┤↗├─├●─────┤↗├────├●─────║─├●────────────────────┤ │     
2: ─────────────║──────────║──├●──Z───║──╭X─├○─────║─│───────────────────H─┤ ╰<Z@Z>
3: ─────────────║──────────║──╰○──║───║──╰●─╰SWAP──║─╰●──┤↗₀├──RX(1.23)──║─┤       
                ╚══════════║═══╬══║═══║══════╝     ║      ║    ║         ║         
                           ╚═══╩══╩═══║════════════╬══════║════║═════════╣         
                                      ╚════════════╝      ║    ║         ║         
                                                          ╚════╩═════════╝         

Description of the Change:

  • Update when fillers are used for drawing bit lines.
  • Update unicode character used when two bit lines cross over.
  • Removed use of defer_measurements in qml.draw. Now, QNodes won't defer measurements unconditionally, rather only when expansion_strategy=device is used, although this is only true for the new device API.
  • Update map_wires to correctly append mapped nested tapes to the parent tape.

Benefits:

  • qml.draw works fully with mid-circuit measurements!
  • qml.map_wires works with nested tapes

Possible Drawbacks:

Related GitHub Issues:

Copy link
Contributor

Hello. You may have forgotten to update the changelog!
Please edit doc/releases/changelog-dev.md with:

  • A one-to-two sentence description of the change. You may include a small working example for new features.
  • A link back to this PR.
  • Your name (or GitHub username) in the contributors section.

@mudit2812 mudit2812 marked this pull request as ready for review November 29, 2023 20:49
@mudit2812 mudit2812 requested a review from a team November 29, 2023 20:52
Copy link
Contributor

@timmysilv timmysilv left a comment

Choose a reason for hiding this comment

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

curious as to why you were testing with nested tapes? we try to avoid them in general. It might even be preferred to not add more support for them, and instead start removing support? don't feel super duper strong about it, but figured I'd mention it.

@mudit2812
Copy link
Contributor Author

mudit2812 commented Nov 30, 2023

curious as to why you were testing with nested tapes? we try to avoid them in general. It might even be preferred to not add more support for them, and instead start removing support? don't feel super duper strong about it, but figured I'd mention it.

@timmysilv I wasn't adding any tests using nested tapes. When I mapped wires in tape_text, it caused the already existing nested tape tests to fail. As for adding more support for nested tapes, I think we should do so until we actually mark it as a deprecated feature. In my opinion, if we're going to stop supporting something, we should be verbose about it. I do agree that we need to get rid of them though.

@mudit2812
Copy link
Contributor Author

[sc-49288]

Copy link

codecov bot commented Nov 30, 2023

Codecov Report

All modified and coverable lines are covered by tests ✅

Comparison is base (e734949) 99.65% compared to head (b82d0a8) 99.65%.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #4901      +/-   ##
==========================================
- Coverage   99.65%   99.65%   -0.01%     
==========================================
  Files         387      387              
  Lines       35051    34784     -267     
==========================================
- Hits        34931    34663     -268     
- Misses        120      121       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Contributor

@timmysilv timmysilv left a comment

Choose a reason for hiding this comment

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

looks fantastic. won't worry about the nested tapes in this PR, but will maybe get back to them. fwiw, in the past, test with nested tapes have been marked (I think by me..) as xfail

@mudit2812 mudit2812 requested a review from a team December 1, 2023 18:04
Copy link
Contributor

@lillian542 lillian542 left a comment

Choose a reason for hiding this comment

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

I offer you a tiny spelling/typo correction, a rocket ship and an approval 🚀

mudit2812 and others added 2 commits December 1, 2023 15:52
Co-authored-by: lillian542 <38584660+lillian542@users.noreply.github.com>
@mudit2812 mudit2812 merged commit 6ad2de6 into master Dec 1, 2023
@mudit2812 mudit2812 deleted the draw-mcm-3 branch December 1, 2023 22:09
mudit2812 added a commit that referenced this pull request Dec 7, 2023
…ires (#4901)

**Context:**
This PR follows up on adding support for `qml.cond` with `qml.draw` by
fully allowing users to draw multiple conditional operators that are
conditioned on multiple mid-circuit measurements. While implementing
this, I tried to use `qml.map_wires` on the tape being drawn (which was
eventually scrapped as it's too messy to use with nested tapes), and
found out that nested tapes were not handled by `map_wires` correctly.

An example of what drawings _can_ look like is shown here:
```python
def circuit():
    qml.RX(0.5, 0)
    qml.RX(0.5, 1)

    m0 = qml.measure(0, reset=True, postselect=1)
    m1 = qml.measure(1)
    qml.cond(m0 & m1, qml.MultiControlledX)(wires=[1, 2, 3, 0], control_values="110")
    qml.cond(m1, qml.PauliZ)(2)

    m2 = qml.measure(1)
    qml.CNOT([3, 2])
    qml.cond(m0, qml.ctrl(qml.SWAP, control=[1, 2], control_values=[True, False]))(wires=[0, 3])
    qml.cond(m2 & m1, qml.PauliY)(0)

    qml.Toffoli([3, 1, 0])

    m3 = qml.measure(3, postselect=0)
    qml.cond(m3, qml.RX)(1.23, 3)
    qml.cond(m3 & m1, qml.Hadamard)(2)

    return qml.expval(qml.PauliZ(0) @ qml.PauliZ(2))

print(qml.draw(circuit)())
```
```
0: ──RX(0.50)──┤↗₁│  │0⟩──────╭X────────────╭SWAP──Y─╭X────────────────────┤ ╭<Z@Z>
1: ──RX(0.50)───║─────────┤↗├─├●─────┤↗├────├●─────║─├●────────────────────┤ │
2: ─────────────║──────────║──├●──Z───║──╭X─├○─────║─│───────────────────H─┤ ╰<Z@Z>
3: ─────────────║──────────║──╰○──║───║──╰●─╰SWAP──║─╰●──┤↗₀├──RX(1.23)──║─┤
                ╚══════════║═══╬══║═══║══════╝     ║      ║    ║         ║
                           ╚═══╩══╩═══║════════════╬══════║════║═════════╣
                                      ╚════════════╝      ║    ║         ║
                                                          ╚════╩═════════╝
```

**Description of the Change:**
* Update when fillers are used for drawing bit lines.
* Update unicode character used when two bit lines cross over.
* Removed use of `defer_measurements` in `qml.draw`. Now, `QNode`s won't
defer measurements unconditionally, rather only when
`expansion_strategy=device` is used, although this is only true for the
new device API.
* Update `map_wires` to correctly append mapped nested tapes to the
parent tape.

**Benefits:**
* `qml.draw` works fully with mid-circuit measurements!
* `qml.map_wires` works with nested tapes

**Possible Drawbacks:**

**Related GitHub Issues:**

---------

Co-authored-by: lillian542 <38584660+lillian542@users.noreply.github.com>
mudit2812 added a commit that referenced this pull request Dec 14, 2023
…4930)

**Context:**
This PR adds support for drawing the collection of mid-circuit
measurement statistics with `qml.draw`. An example is shown below:
```python
def circ():
    qml.Hadamard(0)
    m0 = qml.measure(0)
    qml.Hadamard(1)
    m1 = qml.measure(1)
    qml.Hadamard(2)
    m2 = qml.measure(2)
    qml.Hadamard(3)
    qml.measure(3)
    qml.cond(m0, qml.PauliX)(0)
    qml.cond(m0 & m1, qml.PauliY)(1)
    return qml.expval(m2), qml.sample([m1, m2])

print(qml.draw(circ)())
```
```
0: ──H──┤↗├──────────────────────────X────┤                    
1: ──────║───H──┤↗├──────────────────║──Y─┤                    
2: ──────║───────║───H──┤↗├──────────║──║─┤                    
3: ──────║───────║───────║───H──┤↗├──║──║─┤                    
         ╚═══════║═══════║═══════════╩══╣                      
                 ╚═══════║══════════════╩═╡        ╭Sample[MCM]
                         ╚════════════════╡  <MCM> ╰Sample[MCM]
```

**Description of the Change:**

* Refactor `tape_text` to only run through one loop containing all
layers, not separate loops for op layers and measurement layers. The
logic inside the loop has been adjusted accordingly. I also added big
block comments to make the separation between different steps more
obvious.
* Add helpers to `tape_text.py` to add grouping symbols and labels for
mid-circuit measurement statistics correctly.
* Update `drawable_layers` to find layers for mid-circuit measurement
statistics correctly. This included adding a new helper to recursively
find layers for terminal measurements that use measurement values.
* The bit map is now initialized with `None` values before everything
else, and this is used to keep track of which mid-circuit measurements
are used. Mostly a refactor to tidy up the code.
* Remove code from `draw_mpl` that deferred measurements unconditionally
for qnodes with mid-circuit measurements. This code was removed from
`qml.draw` in #4901 and `qml.draw_mpl` is now updated as well.
* The example in the `iterative_qpe` docstring was written before we had
advanced mid-circuit measurement support and drawing capabilities, so I
updated the example as well.

**Benefits:**
* We can draw mid-circuit measurement statistics!
* Code related to the text drawer is slightly more readable.

**Possible Drawbacks:**

**Related GitHub Issues:**

---------

Co-authored-by: Tom Bromley <49409390+trbromley@users.noreply.github.com>
Co-authored-by: Christina Lee <christina@xanadu.ai>
Co-authored-by: Matthew Silverman <matthews@xanadu.ai>
mudit2812 added a commit that referenced this pull request Dec 15, 2023
…4930)

**Context:**
This PR adds support for drawing the collection of mid-circuit
measurement statistics with `qml.draw`. An example is shown below:
```python
def circ():
    qml.Hadamard(0)
    m0 = qml.measure(0)
    qml.Hadamard(1)
    m1 = qml.measure(1)
    qml.Hadamard(2)
    m2 = qml.measure(2)
    qml.Hadamard(3)
    qml.measure(3)
    qml.cond(m0, qml.PauliX)(0)
    qml.cond(m0 & m1, qml.PauliY)(1)
    return qml.expval(m2), qml.sample([m1, m2])

print(qml.draw(circ)())
```
```
0: ──H──┤↗├──────────────────────────X────┤                    
1: ──────║───H──┤↗├──────────────────║──Y─┤                    
2: ──────║───────║───H──┤↗├──────────║──║─┤                    
3: ──────║───────║───────║───H──┤↗├──║──║─┤                    
         ╚═══════║═══════║═══════════╩══╣                      
                 ╚═══════║══════════════╩═╡        ╭Sample[MCM]
                         ╚════════════════╡  <MCM> ╰Sample[MCM]
```

**Description of the Change:**

* Refactor `tape_text` to only run through one loop containing all
layers, not separate loops for op layers and measurement layers. The
logic inside the loop has been adjusted accordingly. I also added big
block comments to make the separation between different steps more
obvious.
* Add helpers to `tape_text.py` to add grouping symbols and labels for
mid-circuit measurement statistics correctly.
* Update `drawable_layers` to find layers for mid-circuit measurement
statistics correctly. This included adding a new helper to recursively
find layers for terminal measurements that use measurement values.
* The bit map is now initialized with `None` values before everything
else, and this is used to keep track of which mid-circuit measurements
are used. Mostly a refactor to tidy up the code.
* Remove code from `draw_mpl` that deferred measurements unconditionally
for qnodes with mid-circuit measurements. This code was removed from
`qml.draw` in #4901 and `qml.draw_mpl` is now updated as well.
* The example in the `iterative_qpe` docstring was written before we had
advanced mid-circuit measurement support and drawing capabilities, so I
updated the example as well.

**Benefits:**
* We can draw mid-circuit measurement statistics!
* Code related to the text drawer is slightly more readable.

**Possible Drawbacks:**

**Related GitHub Issues:**

---------

Co-authored-by: Tom Bromley <49409390+trbromley@users.noreply.github.com>
Co-authored-by: Christina Lee <christina@xanadu.ai>
Co-authored-by: Matthew Silverman <matthews@xanadu.ai>
mudit2812 added a commit that referenced this pull request Jan 19, 2024
…4930)

**Context:**
This PR adds support for drawing the collection of mid-circuit
measurement statistics with `qml.draw`. An example is shown below:
```python
def circ():
    qml.Hadamard(0)
    m0 = qml.measure(0)
    qml.Hadamard(1)
    m1 = qml.measure(1)
    qml.Hadamard(2)
    m2 = qml.measure(2)
    qml.Hadamard(3)
    qml.measure(3)
    qml.cond(m0, qml.PauliX)(0)
    qml.cond(m0 & m1, qml.PauliY)(1)
    return qml.expval(m2), qml.sample([m1, m2])

print(qml.draw(circ)())
```
```
0: ──H──┤↗├──────────────────────────X────┤                    
1: ──────║───H──┤↗├──────────────────║──Y─┤                    
2: ──────║───────║───H──┤↗├──────────║──║─┤                    
3: ──────║───────║───────║───H──┤↗├──║──║─┤                    
         ╚═══════║═══════║═══════════╩══╣                      
                 ╚═══════║══════════════╩═╡        ╭Sample[MCM]
                         ╚════════════════╡  <MCM> ╰Sample[MCM]
```

**Description of the Change:**

* Refactor `tape_text` to only run through one loop containing all
layers, not separate loops for op layers and measurement layers. The
logic inside the loop has been adjusted accordingly. I also added big
block comments to make the separation between different steps more
obvious.
* Add helpers to `tape_text.py` to add grouping symbols and labels for
mid-circuit measurement statistics correctly.
* Update `drawable_layers` to find layers for mid-circuit measurement
statistics correctly. This included adding a new helper to recursively
find layers for terminal measurements that use measurement values.
* The bit map is now initialized with `None` values before everything
else, and this is used to keep track of which mid-circuit measurements
are used. Mostly a refactor to tidy up the code.
* Remove code from `draw_mpl` that deferred measurements unconditionally
for qnodes with mid-circuit measurements. This code was removed from
`qml.draw` in #4901 and `qml.draw_mpl` is now updated as well.
* The example in the `iterative_qpe` docstring was written before we had
advanced mid-circuit measurement support and drawing capabilities, so I
updated the example as well.

**Benefits:**
* We can draw mid-circuit measurement statistics!
* Code related to the text drawer is slightly more readable.

**Possible Drawbacks:**

**Related GitHub Issues:**

---------

Co-authored-by: Tom Bromley <49409390+trbromley@users.noreply.github.com>
Co-authored-by: Christina Lee <christina@xanadu.ai>
Co-authored-by: Matthew Silverman <matthews@xanadu.ai>
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