Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions projectq/backends/_sim/_simulator_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@
from projectq import MainEngine
from projectq.cengines import (BasicEngine, BasicMapperEngine, DummyEngine,
LocalOptimizer, NotYetMeasuredError)
from projectq.ops import (All, Allocate, BasicGate, MatrixGate, BasicMathGate, CNOT,
Command, H, Measure, QubitOperator, Rx, Ry, Rz, S,
TimeEvolution, Toffoli, X, Y, Z)
from projectq.ops import (All, Allocate, BasicGate, BasicMathGate, CNOT,
Command, H, MatrixGate, Measure, QubitOperator,
Rx, Ry, Rz, S, TimeEvolution, Toffoli, X, Y, Z)
from projectq.meta import Control, Dagger, LogicalQubitIDTag
from projectq.types import WeakQubitRef

Expand Down
53 changes: 35 additions & 18 deletions projectq/ops/_basics.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class NotInvertible(Exception):

class BasicGate(object):
"""
Base class of all gates.
Base class of all gates. (Don't use it directly but derive from it)
"""
def __init__(self):
"""
Expand Down Expand Up @@ -203,20 +203,15 @@ def __or__(self, qubits):
cmd = self.generate_command(qubits)
apply_command(cmd)

@property
def matrix(self):
raise AttributeError("BasicGate has no matrix property. Use MatrixGate instead.")

@matrix.setter
def matrix(self, matrix=None):
raise AttributeError("You cannot set the matrix property of gates derived"
"from BasicGate. Please use MatrixGate instead if"
"you need that functionality.")

def __eq__(self, other):
""" Return True if equal (i.e., instance of same class).
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe better "Return True if instance of the same class, unless other is an instance of :class:MatrixGate, in which case equality is to be checked by testing for existence and (approximate) equality of matrix representations."

"""
return isinstance(other, self.__class__)
if isinstance(other, self.__class__):
return True
elif isinstance(other, MatrixGate):
return NotImplemented
else:
return False

def __ne__(self, other):
return not self.__eq__(other)
Expand All @@ -227,13 +222,30 @@ def __str__(self):
def __hash__(self):
return hash(str(self))


class MatrixGate(BasicGate):
"""
Defines a base class of a matrix gate.
Defines a gate class whose instances are defined by a matrix.

Note:
Use this gate class only for gates acting on a small numbers of qubits.
In general, consider instead using one of the provided ProjectQ gates
or define a new class as this allows the compiler to work symbolically.

Example:

.. code-block:: python

A matrix gate is defined via its matrix.
gate = MatrixGate([[0, 1], [1, 0]])
gate | qubit
"""
def __init__(self, matrix=None):
"""
Initialize MatrixGate

Args:
matrix(numpy.matrix): matrix which defines the gate. Default: None
"""
BasicGate.__init__(self)
self._matrix = np.matrix(matrix) if matrix is not None else None

Expand All @@ -246,9 +258,7 @@ def matrix(self, matrix):
self._matrix = np.matrix(matrix)

def __eq__(self, other):
""" Return True if equal (i.e., instance of same class).
"""
if not isinstance(other, self.__class__):
if not hasattr(other, 'matrix'):
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I achnowledge that the docstring was not good, but do you really want no docstring at all?

Copy link
Contributor

Choose a reason for hiding this comment

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

👍

return False
if (not isinstance(self.matrix, np.matrix) or
not isinstance(other.matrix, np.matrix)):
Expand All @@ -262,12 +272,19 @@ def __eq__(self, other):
return True
return False

def __ne__(self, other):
return not self.__eq__(other)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why is that necessary? Isn't __ne__() with the same implementation inherited from BasicGate?

Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry my bad, of course it uses __ne__ from BasicGate.
(It's a habit from Python2's old classes)

def __str__(self):
raise NotImplementedError('This gate does not implement __str__.')
return("MatrixGate(" + str(self.matrix.tolist()) + ")")
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why do you convert to list here? Isn't it better if it is visible in the output that self.matrix is a numpy array (i.e., no commas between elements vs. commas between elements for lists)?

Copy link
Contributor

Choose a reason for hiding this comment

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

Just so that the CommandPrinter prints such a gate on one line. A numpy matrix string has line breaks which then looks slightly weird to me.

We can use numpy arrays for this string once we switch from numpy matrix to numpy arrays #287


def __hash__(self):
return hash(str(self))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Again, this seems superflous because __hash__() is inherited.

Copy link
Contributor

Choose a reason for hiding this comment

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

👍

Copy link
Contributor

Choose a reason for hiding this comment

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

uups. Python3 seems to remove hash if eq is redefined...


def get_inverse(self):
return MatrixGate(np.linalg.inv(self.matrix))


class SelfInverseGate(BasicGate):
"""
Self-inverse basic gate class.
Expand Down
7 changes: 6 additions & 1 deletion projectq/ops/_basics_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import pytest

from projectq.types import Qubit, Qureg
from projectq.ops import Command
from projectq.ops import Command, X
from projectq import MainEngine
from projectq.cengines import DummyEngine

Expand Down Expand Up @@ -295,6 +295,7 @@ def __init__(self):
math_fun = gate.get_math_function(("qreg1", "qreg2", "qreg3"))
assert math_fun([2, 3, 5]) == [2, 3, 11]


def test_matrix_gate():
gate1 = _basics.MatrixGate()
gate2 = _basics.MatrixGate()
Expand All @@ -321,3 +322,7 @@ def test_matrix_gate():
gate9 = _basics.MatrixGate([[1, 0], [0, (1-1j)/math.sqrt(2)]])
gate10 = gate9.get_inverse()
assert gate10 == gate8
assert gate3 == X
assert X == gate3
assert str(gate3) == "MatrixGate([[0, 1], [1, 0]])"
assert hash(gate3) == hash("MatrixGate([[0, 1], [1, 0]])")
4 changes: 2 additions & 2 deletions projectq/ops/_metagates.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
* C (Creates an n-ary controlled version of an arbitrary gate)
"""

from ._basics import BasicGate, MatrixGate, NotInvertible
from ._basics import BasicGate, NotInvertible
from ._command import Command, apply_command


Expand All @@ -39,7 +39,7 @@ class ControlQubitError(Exception):
pass


class DaggeredGate(MatrixGate): #todo: do we want this?
class DaggeredGate(BasicGate):
"""
Wrapper class allowing to execute the inverse of a gate, even when it does
not define one.
Expand Down
4 changes: 2 additions & 2 deletions projectq/setups/decompositions/arb1qubit2rzandry_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
from projectq.backends import Simulator
from projectq.cengines import (AutoReplacer, DecompositionRuleSet,
DummyEngine, InstructionFilter, MainEngine)
from projectq.ops import (BasicGate, MatrixGate, ClassicalInstructionGate, Measure, Ph, R,
Rx, Ry, Rz, X)
from projectq.ops import (BasicGate, ClassicalInstructionGate, MatrixGate,
Measure, Ph, R, Rx, Ry, Rz, X)
from projectq.meta import Control

from . import arb1qubit2rzandry as arb1q
Expand Down
4 changes: 2 additions & 2 deletions projectq/setups/decompositions/carb1qubit2cnotrzandry_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
from projectq.cengines import (AutoReplacer, DecompositionRuleSet,
DummyEngine, InstructionFilter, MainEngine)
from projectq.meta import Control
from projectq.ops import (All, BasicGate, MatrixGate, ClassicalInstructionGate, Measure,
Ph, R, Rx, Ry, Rz, X, XGate)
from projectq.ops import (All, BasicGate, ClassicalInstructionGate,
MatrixGate, Measure, Ph, R, Rx, Ry, Rz, X, XGate)
from projectq.setups.decompositions import arb1qubit2rzandry_test as arb1q_t

from . import carb1qubit2cnotrzandry as carb1q
Expand Down