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

(feat) Added Bitflip Channel #990

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

RajdeepAher
Copy link

@RajdeepAher RajdeepAher commented Mar 4, 2025

Description

Related to #989 (partially)

Implemented the bitflip function to model quantum bit-flip . This function simulates a bit-flip operation occurring with a given probability.

Changes

  • Added bitflip function to simulate bit-flip.
  • Implemented unit tests covering edge cases (probabilities 0, 1, and intermediate values).
  • Added input validation to check probability values are within the range ([0,1]).

Checklist

Before marking your PR ready for review, make sure you checked the following locally. If this is your first PR, you might be notified of some workflow failures after a maintainer has approved the workflow jobs to be run on your PR.

Additional information is available in the documentation.

  • Use ruff for errors related to code style and formatting.
  • Verify all previous and newly added unit tests pass in pytest.
  • Check the documentation build does not lead to any failures. Sphinx build can be checked locally for any failures related to your PR.
  • Use linkcheck to check for broken links in the documentation.
  • Use doctest to verify the examples in the function docstrings work as expected.

Copy link
Owner

@vprusso vprusso 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 your contribution, @RajdeepAher !

I've added a few comments here on the MR.

return kraus_ops

# Apply the channel to the input state
# print(type(input_mat))
Copy link
Owner

Choose a reason for hiding this comment

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

Looks like an extra print statement was left here.

Copy link
Author

Choose a reason for hiding this comment

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

Yes, will remove it. Thanks

# X gate for the flip case
if dim == 2:
k1 = flip_prob * np.array([[0, 1], [1, 0]])
else:
Copy link
Owner

Choose a reason for hiding this comment

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

If the bitflip channel is only defined when dim == 2, why do we make this a parameter in the function?

Copy link
Author

Choose a reason for hiding this comment

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

I felt that my understanding was somewhat lacking, and there might be a future extension of this to higher dimensions that I am not aware of at the moment and hence the parameter. I can remove it too!

or the result of applying the channel to input_mat.

"""
if prob < 0 or prob > 1:
Copy link
Owner

Choose a reason for hiding this comment

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

You can write this more succinctly as if not (0 <= prob <= 1):

raise ValueError("Probability must be between 0 and 1.")

# If input is a CVX variable, handle it appropriately
if isinstance(input_mat, Variable):
Copy link
Owner

Choose a reason for hiding this comment

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

I'm not sure why we would need to cover the case here when the input_mat is a CVXPY-type object.

Copy link
Author

Choose a reason for hiding this comment

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

I saw rest of the implementations in toqito/channels and thought it would be better to include CVXPY object. I can remove it , if it is wrong

@@ -0,0 +1,80 @@
"""Test cases for the bit-flip channel in Toqito."""
Copy link
Owner

Choose a reason for hiding this comment

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

We can remove the "in Toqito" part of the this docstring.

@@ -0,0 +1,80 @@
"""Test cases for the bit-flip channel in Toqito."""

import unittest
Copy link
Owner

Choose a reason for hiding this comment

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

We should use pytest (not unittest) to conform with how testing is done elsewhere in toqito for consistency.

args: [ --fix ]
# Run the formatter.
- id: ruff-format
repos:
Copy link
Owner

Choose a reason for hiding this comment

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

Seems okay, but since these seem identical, I wonder why GitHub is flagging them as having changed. Can probably ignore this comment, but mentioning it as it also seems to be the case in channels/__init__.py as well.

Copy link
Author

Choose a reason for hiding this comment

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

yes, even I am not aware of why it is happening

Copy link

codecov bot commented Mar 4, 2025

Codecov Report

Attention: Patch coverage is 77.77778% with 6 lines in your changes missing coverage. Please review.

Project coverage is 97.7%. Comparing base (3cde097) to head (d1d9457).

Files with missing lines Patch % Lines
toqito/channels/bitflip.py 77.7% 5 Missing and 1 partial ⚠️
Additional details and impacted files
@@           Coverage Diff            @@
##           master    #990     +/-   ##
========================================
- Coverage    97.9%   97.7%   -0.2%     
========================================
  Files         169     170      +1     
  Lines        3321    3348     +27     
  Branches      727     733      +6     
========================================
+ Hits         3253    3274     +21     
- Misses         44      49      +5     
- Partials       24      25      +1     

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

root added 3 commits March 5, 2025 19:06
- Removed littered comments
- Forced
- Fixed  range
- Removed compatibility for CVXPY object
- Rewrote tests in pytest
@purva-thakre
Copy link
Collaborator

@RajdeepAher Please make sure your function is properly covered by unit tests.

image

@RajdeepAher
Copy link
Author

@RajdeepAher Please make sure your function is properly covered by unit tests.

image

Hello,
The error in coverage was due to inclusion of CVXPY-type object, but now I have removed it

@purva-thakre
Copy link
Collaborator

The *bitflip channel* is a quantum channel that flips a qubit from :math:`|0\rangle` to :math:`|1\rangle`
and from :math:`|1\rangle` to :math:`|0\rangle` with probability :math:`p`. It is defined by
the following operation:
.. math::
Copy link
Collaborator

Choose a reason for hiding this comment

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

Comment on lines +56 to +57
[1] https://arxiv.org/abs/1106.1445
[2] https://www.quantumchannelzoo.org/person/bit-flip
Copy link
Collaborator

Choose a reason for hiding this comment

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

Add these to refs.bib instead of directly listing links to references.

https://toqito.readthedocs.io/en/latest/contributing.html#references-in-docstrings

Comment on lines +55 to +71
def test_invalid_probability_negative():
"""Test that a negative probability raises an error."""
with pytest.raises(ValueError, match="Probability must be between 0 and 1."):
bitflip(prob=-0.1)


def test_invalid_probability_greater_than_1():
"""Test that a probability greater than 1 raises an error."""
with pytest.raises(ValueError, match="Probability must be between 0 and 1."):
bitflip(prob=1.1)


def test_invalid_dimension():
"""Test that invalid dimensions raise an error."""
rho = np.eye(3) # 3x3 matrix
with pytest.raises(ValueError, match="Bitflip channel is only defined for qubits"):
bitflip(rho, prob=0.3)
Copy link
Collaborator

Choose a reason for hiding this comment

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

These can be condensed into one unit tests using parametrize.

https://docs.pytest.org/en/stable/how-to/parametrize.html

Comment on lines +13 to +14
expected_k0 = np.sqrt(1 - prob) * np.eye(2)
expected_k1 = np.sqrt(prob) * np.array([[0, 1], [1, 0]])
Copy link
Collaborator

@purva-thakre purva-thakre Mar 5, 2025

Choose a reason for hiding this comment

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

You can create a list/array of these two and directly compare the calculated output to the expected output.

Comment on lines +20 to +52
def test_apply_to_state_0():
"""Test bitflip application to |0><0| state."""
prob = 0.3
rho = np.array([[1, 0], [0, 0]]) # |0><0|
expected_output = (1 - prob) * rho + prob * np.array([[0, 0], [0, 1]])
result = bitflip(rho, prob=prob)

np.testing.assert_almost_equal(result, expected_output)


def test_apply_to_state_1():
"""Test bitflip application to |1><1| state."""
prob = 0.3
rho = np.array([[0, 0], [0, 1]]) # |1><1|
expected_output = (1 - prob) * rho + prob * np.array([[1, 0], [0, 0]])
result = bitflip(rho, prob=prob)

np.testing.assert_almost_equal(result, expected_output)


def test_probability_0():
"""Test bitflip with probability 0 (no change)."""
rho = np.array([[0.5, 0.5], [0.5, 0.5]])
result = bitflip(rho, prob=0)
np.testing.assert_almost_equal(result, rho)


def test_probability_1():
"""Test bitflip with probability 1 (always flips)."""
rho = np.array([[0.5, 0.5], [0.5, 0.5]])
expected_output = np.array([[0.5, 0.5], [0.5, 0.5]]) # Same for maximally mixed state
result = bitflip(rho, prob=1)
np.testing.assert_almost_equal(result, expected_output)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same as my other comment, most of these unit tests can be condensed into 1 by using using parameterize.

Comment on lines +61 to +62
:return: Either the Kraus operators of the bitflip channel if input_mat is None,
or the result of applying the channel to input_mat.
Copy link
Collaborator

Choose a reason for hiding this comment

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

If you are referring to a parameter, sandwich it between `

Comment on lines +68 to +75
if input_mat is not None:
dim = input_mat.shape[0]
else:
dim = 2

# Enforce 2-dimensional (qubit) requirement
if dim != 2:
raise ValueError("Bitflip channel is only defined for qubits (dim=2).")
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
if input_mat is not None:
dim = input_mat.shape[0]
else:
dim = 2
# Enforce 2-dimensional (qubit) requirement
if dim != 2:
raise ValueError("Bitflip channel is only defined for qubits (dim=2).")
if input_mat is not None:
if input_mat.shape[0] != 2:
raise ValueError("Bitflip channel is only defined for qubits (dim=2).")
dim = 2

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