Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added function to generate gate rules from a sequence. Needed

to create functions to do them based on Mul.  Also dealt with issue
of min_qubits from non-hermitian gates by looking at the base value
of the Pow object.
  • Loading branch information...
commit 393331c74b9df888c790aebad80d57e5042205df 1 parent 0680c38
rayman authored
View
146 sympy/physics/quantum/identitysearch.py
@@ -2,7 +2,7 @@
from random import randint
from sympy.external import import_module
-from sympy import Mul, Basic, Number
+from sympy import Mul, Basic, Number, Pow
from sympy.matrices import Matrix, eye
from sympy.physics.quantum.gate import (X, Y, Z, H, S, T, CNOT,
IdentityGate, gate_simp)
@@ -12,14 +12,17 @@
from sympy.physics.quantum.dagger import Dagger
__all__ = [
+ 'is_scalar_sparse_matrix',
+ 'is_scalar_nonsparse_matrix',
'll_op',
'lr_op',
'rl_op',
'rr_op',
+ 'generate_gate_rules_with_seq',
+ 'generate_gate_rules',
+ 'generate_equivalent_ids_with_seq',
'generate_equivalent_ids',
'GateIdentity',
- 'is_scalar_sparse_matrix',
- 'is_scalar_nonsparse_matrix',
'is_degenerate',
'is_reducible',
'bfs_identity_search',
@@ -178,6 +181,12 @@ def is_scalar_nonsparse_matrix(circuit, nqubits, identity_only):
else:
is_scalar_matrix = is_scalar_nonsparse_matrix
+def _get_min_qubits(a_gate):
+ if isinstance(a_gate, Pow):
+ return a_gate.base.min_qubits
+ else:
+ return a_gate.min_qubits
+
def ll_op(left, rite):
"""Perform a LL operation. If LL is possible, it
returns a 2-tuple representing the new gate rule;
@@ -201,11 +210,12 @@ def ll_op(left, rite):
>>> ll_op((x, y), (z,))
((Y(0),), (X(0), Z(0)))
"""
+
if (len(left) > 0):
ll_gate = left[0]
ll_gate_is_unitary = is_scalar_matrix(
(Dagger(ll_gate), ll_gate),
- ll_gate.min_qubits,
+ _get_min_qubits(ll_gate),
True)
if (len(left) > 0 and ll_gate_is_unitary):
@@ -241,11 +251,12 @@ def lr_op(left, rite):
>>> lr_op((x, y), (z,))
((X(0),), (Z(0), Y(0)))
"""
+
if (len(left) > 0):
lr_gate = left[len(left)-1]
lr_gate_is_unitary = is_scalar_matrix(
(Dagger(lr_gate), lr_gate),
- lr_gate.min_qubits,
+ _get_min_qubits(lr_gate),
True)
if (len(left) > 0 and lr_gate_is_unitary):
@@ -281,11 +292,12 @@ def rl_op(left, rite):
>>> rl_op((x, y), (z,))
((Z(0), X(0), Y(0)), ())
"""
+
if (len(rite) > 0):
rl_gate = rite[0]
rl_gate_is_unitary = is_scalar_matrix(
(Dagger(rl_gate), rl_gate),
- rl_gate.min_qubits,
+ _get_min_qubits(rl_gate),
True)
if (len(rite) > 0 and rl_gate_is_unitary):
@@ -321,12 +333,13 @@ def rr_op(left, rite):
>>> rr_op((x,), (y, z))
((X(0), Z(0)), (Y(0),))
"""
+
if (len(rite) > 0):
rr_gate = rite[len(rite)-1]
rr_gate_is_unitary = is_scalar_matrix(
- (Dagger(rr_gate), rr_gate),
- rr_gate.min_qubits,
- True)
+ (Dagger(rr_gate), rr_gate),
+ _get_min_qubits(rr_gate),
+ True)
if (len(rite) > 0 and rr_gate_is_unitary):
# Get the new right side w/o the rightmost gate
@@ -338,17 +351,11 @@ def rr_op(left, rite):
return None
-def generate_equivalent_ids(*gate_seq):
- """Returns a set of equivalent gate identities.
-
- A gate identity is a quantum circuit such that the product
- of the gates in the circuit is equal to a scalar value.
- For example, XYZ = i, where X, Y, Z are the Pauli gates and
- i is the imaginary value, is considered a gate identity.
+def generate_gate_rules_with_seq(*gate_seq):
+ """Returns a set of gate rules.
This function uses the four operations (LL, LR, RL, RR)
- to generate gate rules and, subsequently, to locate equivalent
- gate identities.
+ to generate the gate rules.
A gate rule is an expression such as ABC = D or AB = CD, where
A, B, C, and D are gates. Each value on either side of the
@@ -379,6 +386,91 @@ def generate_equivalent_ids(*gate_seq):
RR : right circuit, right multiply
AB = CD -> ABD = CDD -> ABD = C
+ The number of gate rules generated is n*(n+1), where n
+ is the number of gates in the sequence (unproven).
+
+ Parameters
+ ==========
+ gate_seq : tuple, Gate
+ A variable length tuple of Gates whose product is equal to
+ a scalar matrix.
+
+ Examples
+ ========
+
+ Find the gate rules of the current circuit:
+
+ >>> from sympy.physics.quantum.identitysearch import \
+ generate_gate_rules_with_seq
+ >>> from sympy.physics.quantum.gate import X, Y, Z
+ >>> x = X(0); y = Y(0); z = Z(0)
+ >>> generate_equivalent_ids(x, x)
+ set([(X(0), X(0))])
+
+ >>> generate_equivalent_ids(x, y, z)
+ set([(X(0), Y(0), Z(0)), (X(0), Z(0), Y(0)), (Y(0), X(0), Z(0)),
+ (Y(0), Z(0), X(0)), (Z(0), X(0), Y(0)), (Z(0), Y(0), X(0))])
+ """
+
+ # Each item in queue is a 3-tuple:
+ # i) first item is the left side of an equality
+ # ii) second item is the right side of an equality
+ # iii) third item is the number of operations performed
+ # The argument, gate_seq, will start on the left side, and
+ # the right side will be empty, implying the presence of an
+ # identity.
+ queue = deque()
+ # A set of gate rules
+ rules = set()
+ # Maximum number of operations to perform
+ max_ops = len(gate_seq)
+
+ def process_new_rule(new_rule, ops):
+ if (new_rule is not None):
+ (new_left, new_rite) = new_rule
+
+ if (new_rule not in rules and (new_rite, new_left) not in rules):
+ rules.add(new_rule)
+ # If haven't reached the max limit on operations
+ if (ops + 1 < max_ops):
+ queue.append(new_rule + (ops + 1,))
+
+ queue.append((gate_seq, (), 0))
+ rules.add((gate_seq, ()))
+
+ while (len(queue) > 0):
+ (left, rite, ops) = queue.popleft()
+ #print((left, rite, ops))
+ # Do a LL
+ new_rule = ll_op(left, rite)
+ process_new_rule(new_rule, ops)
+ # Do a LR
+ new_rule = lr_op(left, rite)
+ process_new_rule(new_rule, ops)
+ # Do a RL
+ new_rule = rl_op(left, rite)
+ process_new_rule(new_rule, ops)
+ # Do a RR
+ new_rule = rr_op(left, rite)
+ process_new_rule(new_rule, ops)
+
+ return rules
+
+def generate_gate_rules(circuit):
+ pass
+
+def generate_equivalent_ids_with_seq(*gate_seq):
+ """Returns a set of equivalent gate identities.
+
+ A gate identity is a quantum circuit such that the product
+ of the gates in the circuit is equal to a scalar value.
+ For example, XYZ = i, where X, Y, Z are the Pauli gates and
+ i is the imaginary value, is considered a gate identity.
+
+ This function uses the four operations (LL, LR, RL, RR)
+ to generate the gate rules and, subsequently, to locate equivalent
+ gate identities.
+
Note that all equivalent identities are reachable in n operations
from the starting gate identity, where n is the number of gates
in the sequence.
@@ -395,7 +487,7 @@ def generate_equivalent_ids(*gate_seq):
Find equivalent gate identities from the current circuit:
>>> from sympy.physics.quantum.identitysearch import \
- generate_equivalent_ids
+ generate_equivalent_ids_with_seq
>>> from sympy.physics.quantum.gate import X, Y, Z
>>> x = X(0); y = Y(0); z = Z(0)
>>> generate_equivalent_ids(x, x)
@@ -405,7 +497,6 @@ def generate_equivalent_ids(*gate_seq):
set([(X(0), Y(0), Z(0)), (X(0), Z(0), Y(0)), (Y(0), X(0), Z(0)),
(Y(0), Z(0), X(0)), (Z(0), X(0), Y(0)), (Z(0), Y(0), X(0))])
"""
-
# Each item in queue is a 3-tuple:
# i) first item is the left side of an equality
# ii) second item is the right side of an equality
@@ -484,6 +575,9 @@ def generate_equivalent_ids(*gate_seq):
return eq_ids
+def generate_equivalent_ids(circuit):
+ pass
+
class GateIdentity(Basic):
"""Wrapper class for circuits that reduce to a scalar value.
@@ -519,23 +613,27 @@ class GateIdentity(Basic):
def __new__(cls, *args):
# args should be a tuple - a variable length argument list
obj = Basic.__new__(cls, *args)
- obj._eq_ids = generate_equivalent_ids(*args)
+ obj._circuit = Mul(*args)
+ obj._eq_ids = generate_equivalent_ids_with_seq(*args)
return obj
@property
def circuit(self):
- return self.args
+ return self._circuit
@property
def eq_identities(self):
return self._eq_ids
+ @property
+ def sequence(self):
+ return self.args
+
def __str__(self):
"""Returns the string of gates in a tuple."""
return str(self.circuit)
-
def is_degenerate(identity_set, gate_identity):
"""Checks if a gate identity is a permutation of another identity.
@@ -703,7 +801,7 @@ def random_identity_search(gate_list, numgates, nqubits):
"""
gate_size = len(gate_list)
- circuit = (IdentityGate(0),)
+ circuit = ()
for i in range(numgates):
next_gate = gate_list[randint(0, gate_size - 1)]
View
9 sympy/physics/quantum/qcevolve.py
@@ -6,6 +6,9 @@
http://pyevolve.sourceforge.net/index.html
+TODO:
+* Implement a mutator operator
+* Implement an evaluator
"""
from random import Random
@@ -113,7 +116,7 @@ def __repr__(self):
def random_reduce(circuit, gate_ids, seed=None):
"""Shorten the length of a quantum circuit.
- qc_random_reduce looks for circuit identities
+ random_reduce looks for circuit identities
in circuit, randomly chooses one to remove,
and returns a shorter yet equivalent circuit.
If no identities are found, the same circuit
@@ -163,7 +166,7 @@ def random_reduce(circuit, gate_ids, seed=None):
def random_insert(circuit, choices, seed=None):
"""Insert a circuit into another quantum circuit.
- qc_random_insert randomly selects a circuit from
+ random_insert randomly selects a circuit from
choices and randomly chooses a location to insert
into circuit.
@@ -213,7 +216,7 @@ def linear_init(genome, **args):
In many cases, will include an instance of GSimpleGA
"""
- new_circuit = qc_random_insert(
+ new_circuit = random_insert(
genome.genome_circuit,
genome.insert_choices
)
View
109 sympy/physics/quantum/tests/test_identitysearch.py
@@ -1,6 +1,6 @@
from sympy.external import import_module
from sympy.physics.quantum.gate import (X, Y, Z, H, S, T, CNOT,
- IdentityGate, CGate, Phase, gate_simp)
+ IdentityGate, CGate, PhaseGate, TGate, gate_simp)
from sympy.physics.quantum.identitysearch import *
from sympy.physics.quantum.dagger import Dagger
@@ -8,77 +8,127 @@ def create_gate_sequence(qubit=0):
gates = (X(qubit), Y(qubit), Z(qubit), H(qubit))
return gates
-def test_generate_equivalent_ids():
+def test_generate_gate_rules_with_seq():
+ (x, y, z, h) = create_gate_sequence()
+ ph = PhaseGate(0)
+ cgate_t = CGate(0, TGate(1))
+
+ assert generate_gate_rules_with_seq(x) == set([((x,), ())])
+
+ gate_rules = set([((x,y,z), ()), ((y,z,x), ()), ((z,x,y), ()),
+ ((), (x,z,y)), ((), (y,x,z)), ((), (z,y,x)),
+ ((x,), (z,y)), ((y,z), (x,)), ((y,), (x,z)),
+ ((z,x), (y,)), ((z,), (y,x)), ((x,y), (z,))])
+ actual = generate_gate_rules_with_seq(x, y, z)
+ assert actual == gate_rules
+
+ gate_rules = set([((), (h,z,y,x)), ((), (x,h,z,y)), ((), (y,x,h,z)),
+ ((), (z,y,x,h)), ((h,), (z,y,x)), ((x,), (h,z,y)),
+ ((y,), (x,h,z)), ((z,), (y,x,h)), ((h,x), (z,y)),
+ ((x,y), (h,z)), ((y,z), (x,h)), ((z,h), (y,x)),
+ ((h,x,y), (z,)), ((x,y,z), (h,)), ((y,z,h), (x,)),
+ ((z,h,x), (y,)), ((h,x,y,z), ()), ((x,y,z,h), ()),
+ ((y,z,h,x), ()), ((z,h,x,y), ())])
+ actual = generate_gate_rules_with_seq(x, y, z, h)
+ assert actual == gate_rules
+
+ gate_rules = set([((), (cgate_t**(-1), ph**(-1), x)),
+ ((), (ph**(-1), x, cgate_t**(-1))),
+ ((), (x, cgate_t**(-1), ph**(-1))),
+ ((cgate_t,), (ph**(-1), x)),
+ ((ph,), (x, cgate_t**(-1))),
+ ((x,), (cgate_t**(-1), ph**(-1))),
+ ((cgate_t, x), (ph**(-1),)),
+ ((ph, cgate_t), (x,)),
+ ((x, ph), (cgate_t**(-1),)),
+ ((cgate_t, x, ph), ()),
+ ((ph, cgate_t, x), ()),
+ ((x, ph, cgate_t), ())])
+ actual = generate_gate_rules_with_seq(x, ph, cgate_t)
+ assert actual == gate_rules
+
+def test_generate_equivalent_ids_with_seq():
(x, y, z, h) = create_gate_sequence()
- assert generate_equivalent_ids(x) == set([(x,)])
- assert generate_equivalent_ids(x, y) == set([(x, y), (y, x)])
+ assert generate_equivalent_ids_with_seq(x) == set([(x,)])
+ assert generate_equivalent_ids_with_seq(x, y) == set([(x, y), (y, x)])
gate_seq = (x, y, z)
gate_rules = set([(x, y, z), (y, z, x), (z, x, y), (z, y, x),
(y, x, z), (x, z, y)])
- assert generate_equivalent_ids(*gate_seq) == gate_rules
+ assert generate_equivalent_ids_with_seq(*gate_seq) == gate_rules
gate_seq = (x, y, z, h)
gate_rules = set([(x, y, z, h), (y, z, h, x),
(h, x, y, z), (h, z, y, x),
(z, y, x, h), (y, x, h, z),
(z, h, x, y) ,(x, h, z, y)])
- assert generate_equivalent_ids(*gate_seq) == gate_rules
+ assert generate_equivalent_ids_with_seq(*gate_seq) == gate_rules
gate_seq = (x, y, x, y)
gate_rules = set([(x, y, x, y), (y, x, y, x)])
- assert generate_equivalent_ids(*gate_seq) == gate_rules
+ assert generate_equivalent_ids_with_seq(*gate_seq) == gate_rules
cgate_y = CGate((1,), y)
gate_seq = (y, cgate_y, y, cgate_y)
gate_rules = set([(y, cgate_y, y, cgate_y), (cgate_y, y, cgate_y, y)])
- assert generate_equivalent_ids(*gate_seq) == gate_rules
+ assert generate_equivalent_ids_with_seq(*gate_seq) == gate_rules
cnot = CNOT(1,0)
cgate_z = CGate((0,), Z(1))
gate_seq = (cnot, h, cgate_z, h)
gate_rules = set([(cnot, h, cgate_z, h), (h, cgate_z, h, cnot),
(h, cnot, h, cgate_z), (cgate_z, h, cnot, h)])
- assert generate_equivalent_ids(*gate_seq) == gate_rules
+ assert generate_equivalent_ids_with_seq(*gate_seq) == gate_rules
def test_is_scalar_nonsparse_matrix():
numqubits = 2
id_only = False
id_gate = (IdentityGate(1),)
- assert is_scalar_nonsparse_matrix(id_gate, numqubits, id_only) == True
+ actual = is_scalar_nonsparse_matrix(id_gate, numqubits, id_only)
+ assert actual == True
x0 = X(0)
xx_circuit = (x0, x0)
- assert is_scalar_nonsparse_matrix(xx_circuit, numqubits, id_only) == True
+ actual = is_scalar_nonsparse_matrix(xx_circuit, numqubits, id_only)
+ assert actual == True
x1 = X(1)
y1 = Y(1)
xy_circuit = (x1, y1)
- assert is_scalar_nonsparse_matrix(xy_circuit, numqubits, id_only) == False
+ actual = is_scalar_nonsparse_matrix(xy_circuit, numqubits, id_only)
+ assert actual == False
z1 = Z(1)
xyz_circuit = (x1, y1, z1)
- assert is_scalar_nonsparse_matrix(xyz_circuit, numqubits, id_only) == True
+ actual = is_scalar_nonsparse_matrix(xyz_circuit, numqubits, id_only)
+ assert actual == True
cnot = CNOT(1,0)
cnot_circuit = (cnot, cnot)
- assert is_scalar_nonsparse_matrix(cnot_circuit, numqubits, id_only) == True
+ actual = is_scalar_nonsparse_matrix(cnot_circuit, numqubits, id_only)
+ assert actual == True
h = H(0)
hh_circuit = (h, h)
- assert is_scalar_nonsparse_matrix(hh_circuit, numqubits, id_only) == True
+ actual = is_scalar_nonsparse_matrix(hh_circuit, numqubits, id_only)
+ assert actual == True
h1 = H(1)
xhzh_circuit = (x1, h1, z1, h1)
- assert is_scalar_nonsparse_matrix(xhzh_circuit, numqubits, id_only) == True
+ actual = is_scalar_nonsparse_matrix(xhzh_circuit, numqubits, id_only)
+ assert actual == True
id_only = True
- assert is_scalar_nonsparse_matrix(xhzh_circuit, numqubits, id_only) == True
- assert is_scalar_nonsparse_matrix(xyz_circuit, numqubits, id_only) == False
- assert is_scalar_nonsparse_matrix(cnot_circuit, numqubits, id_only) == True
- assert is_scalar_nonsparse_matrix(hh_circuit, numqubits, id_only) == True
+ actual = is_scalar_nonsparse_matrix(xhzh_circuit, numqubits, id_only)
+ assert actual == True
+ actual = is_scalar_nonsparse_matrix(xyz_circuit, numqubits, id_only)
+ assert actual == False
+ actual = is_scalar_nonsparse_matrix(cnot_circuit, numqubits, id_only)
+ assert actual == True
+ actual = is_scalar_nonsparse_matrix(hh_circuit, numqubits, id_only)
+ assert actual == True
def test_is_scalar_sparse_matrix():
np = import_module('numpy', min_python_version=(2, 6))
@@ -249,12 +299,13 @@ def test_bfs_identity_search():
GateIdentity(cnot, h, cgate_z, h)])
assert bfs_identity_search(gate_list, 2, max_depth=4) == id_set
- # Check what should be done about this case.
- # Fails because Phase(0) is not Hermitian, so Dagger(Phase(0))
- # returns S(0)**(-1), which is Pow object. Throws exception
- # at line 136ish.
- #s = Phase(0)
- #t = T(0)
- #gate_list = [s, t]
- #id_set = set([])
- #assert bfs_identity_search(gate_list, 1, max_depth=4) == id_set
+ s = PhaseGate(0)
+ t = TGate(0)
+ gate_list = [s, t]
+ id_set = set([GateIdentity(s, s, s, s)])
+ assert bfs_identity_search(gate_list, 1, max_depth=4) == id_set
+
+ # Throws an error in represent: "exponent must be >= 0"
+ #gate_list = [Dagger(s), t]
+ #id_set = set([GateIdentity(Dagger(s), t, t)])
+ #assert bfs_identity_search(gate_list, 1, max_depth=3) == id_set
Please sign in to comment.
Something went wrong with that request. Please try again.