Skip to content

Commit

Permalink
Added function to generate gate rules from a sequence. Needed
Browse files Browse the repository at this point in the history
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
rayman authored and rayman committed Mar 24, 2012
1 parent 0680c38 commit 393331c
Show file tree
Hide file tree
Showing 3 changed files with 208 additions and 56 deletions.
146 changes: 122 additions & 24 deletions sympy/physics/quantum/identitysearch.py
Expand Up @@ -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)
Expand All @@ -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',
Expand Down Expand Up @@ -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;
Expand All @@ -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):
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -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)
Expand All @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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)]
Expand Down
9 changes: 6 additions & 3 deletions sympy/physics/quantum/qcevolve.py
Expand Up @@ -6,6 +6,9 @@
http://pyevolve.sourceforge.net/index.html
TODO:
* Implement a mutator operator
* Implement an evaluator
"""

from random import Random
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
)
Expand Down

0 comments on commit 393331c

Please sign in to comment.