Explorar el Código

Recover code with debug

master
Pete Shadbolt hace 8 años
padre
commit
49708d426a
Se han modificado 1 ficheros con 279 adiciones y 0 borrados
  1. +279
    -0
      abp/graphstate_with_debug_statements.py

+ 279
- 0
abp/graphstate_with_debug_statements.py Ver fichero

@@ -0,0 +1,279 @@
"""
Provides an extremely basic graph structure, based on neighbour lists
"""

import itertools as it
import json
import qi, clifford, util
import random

output = open("debug_pete.txt", "w")
def debug(x):
output.write(str(x)+"\n")

class GraphState(object):

def __init__(self, nodes=[]):
self.adj, self.node = {}, {}
self.add_nodes(nodes)

def add_node(self, v, **kwargs):
""" Add a node """
assert not v in self.node
self.adj[v] = {}
self.node[v] = {"vop": clifford.by_name["hadamard"]}
self.node[v].update(kwargs)

def add_nodes(self, nodes):
""" Add a buncha nodes """
for n in nodes:
self.add_node(n)

def add_edge(self, v1, v2, data = {}):
""" Add an edge between two vertices in the self """
assert v1 != v2
self.adj[v1][v2] = data
self.adj[v2][v1] = data

def add_edges(self, edges):
""" Add a buncha edges """
for (v1, v2) in edges:
self.add_edge(v1, v2)

def del_edge(self, v1, v2):
""" Delete an edge between two vertices in the self """
debug("deling edge")
del self.adj[v1][v2]
del self.adj[v2][v1]

def has_edge(self, v1, v2):
""" Test existence of an edge between two vertices in the self """
return v2 in self.adj[v1]

def toggle_edge(self, v1, v2):
""" Toggle an edge between two vertices in the self """
if self.has_edge(v1, v2):
self.del_edge(v1, v2)
else:
self.add_edge(v1, v2)

def edgelist(self):
""" Describe a graph as an edgelist """
# TODO: inefficient
edges = set(tuple(sorted((i, n)))
for i, v in self.adj.items()
for n in v)
return tuple(edges)

def remove_vop(self, a, avoid):
""" Reduces VOP[a] to the identity """
# TODO: sucks!
others = set(self.adj[a]) - {avoid}
swap_qubit = others.pop() if others else avoid

debug("remove_byprod_op called: (v, avoid, vb):")
self.print_adj_list_line(a)
self.print_adj_list_line(avoid)
self.print_adj_list_line(swap_qubit)
converted = clifford.decompositions[self.node[a]["vop"]]
converted = "".join("U" if x == "x" else "V" for x in converted)
debug("using {}".format(converted))

for v in reversed(clifford.decompositions[self.node[a]["vop"]]):
if v == "x":
self.local_complementation(a, "U ->")
else:
self.local_complementation(swap_qubit, "V ->")

assert self.node[a]["vop"]==0

debug("remove_byprod_op: after (v, avoid, vb):")
self.print_adj_list_line(a)
self.print_adj_list_line(avoid)
self.print_adj_list_line(swap_qubit)

assert self.node[a]["vop"] == 0

def local_complementation(self, v, prefix = ""):
""" As defined in LISTING 1 of Anders & Briegel """
debug("{}Inverting about {}".format(prefix, self.get_adj_list_line(v)))
for i, j in it.combinations(self.adj[v], 2):
self.toggle_edge(i, j)

msqx_h = clifford.conjugation_table[clifford.by_name["msqx"]]
sqz_h = clifford.conjugation_table[clifford.by_name["sqz"]]
self.node[v]["vop"] = clifford.times_table[self.node[v]["vop"], msqx_h]
for i in self.adj[v]:
self.node[i]["vop"] = clifford.times_table[self.node[i]["vop"], sqz_h]

def act_local_rotation(self, v, op):
""" Act a local rotation """
rotation = clifford.by_name[str(op)]
self.node[v]["vop"] = clifford.times_table[rotation, self.node[v]["vop"]]

def act_hadamard(self, qubit):
""" Shorthand """
self.act_local_rotation(qubit, 10)

def act_cz(self, a, b):
""" Act a controlled-phase gate on two qubits """
debug("before cphase between {} and {}".format(a, b))
self.print_adj_list_line(a)
self.print_adj_list_line(b)

ci = self.get_connection_info(a, b)
if ci["non1"]:
debug("cphase: left vertex has NONs -> putting it to Id")
self.remove_vop(a, b)

ci = self.get_connection_info(a, b)
if ci["non2"]:
debug("cphase: right vertex has NONs -> putting it to Id")
self.remove_vop(b, a)

ci = self.get_connection_info(a, b)
if ci["non1"] and not clifford.is_diagonal(self.node[a]["vop"]):
debug("cphase: left one needs treatment again -> putting it to Id")
self.remove_vop(a, b)

self.cz_with_table(a, b)

def get_connection_info(self, a, b):
if self.has_edge(a, b):
return {"was_edge": True,
"non1": len(self.adj.get(a)) > 1,
"non2": len(self.adj.get(b)) > 1}
else:
return {"was_edge": False,
"non1": len(self.adj.get(a)) > 0,
"non2": len(self.adj.get(b)) > 0}

def cz_with_table(self, a, b):
""" Run the table """
debug("cphase_with_table called on:")
self.print_adj_list_line(a)
self.print_adj_list_line(b)

ci = self.get_connection_info(a, b)
try:
assert ci["non1"]==False or clifford.is_diagonal(self.node[a]["vop"])
assert ci["non2"]==False or clifford.is_diagonal(self.node[b]["vop"])
except AssertionError:
debug(ci)
debug(self.node[a]["vop"])
debug(self.node[b]["vop"])
edge = self.has_edge(a, b)
new_edge, self.node[a]["vop"], self.node[
b]["vop"] = clifford.cz_table[edge, self.node[a]["vop"], self.node[b]["vop"]]
if new_edge != edge:
self.toggle_edge(a, b)

debug("cphase_with_table: after")
self.print_adj_list_line(a)
self.print_adj_list_line(b)

ci = self.get_connection_info(a, b)
assert ci["non1"]==False or clifford.is_diagonal(self.node[a]["vop"])
assert ci["non2"]==False or clifford.is_diagonal(self.node[b]["vop"])

def measure_z(self, node, force=None):
""" Measure the graph in the Z-basis """
res = force if force!=None else random.choice([0, 1])

# Disconnect
for neighbour in self.adj[node]:
self.del_edge(node, neighbour)
if res:
self.act_local_rotation(neighbour, "pz")

# Rotate
if res:
self.act_local_rotation(node, "px")
self.act_local_rotation(node, "hadamard")
else:
self.act_local_rotation(node, "hadamard")

return res

def measure_x(self, i):
""" Measure the graph in the X-basis """
# TODO
pass

def measure_y(self, i):
""" Measure the graph in the Y-basis """
# TODO
pass

def order(self):
""" Get the number of qubits """
return len(self.node)

def __str__(self):
""" Represent as a string for quick debugging """
node = {key: clifford.get_name(value["vop"])
for key, value in self.node.items()}
nbstr = str(self.adj)
return "graph:\n node: {}\n adj: {}\n".format(node, nbstr)

def to_json(self):
""" Convert the graph to JSON form """
return {"node": self.node, "adj": self.adj}

def from_json(self, data):
""" Reconstruct from JSON """
self.__init__([])
#TODO

def to_state_vector(self):
""" Get the full state vector """
if len(self.node) > 15:
raise ValueError("Cannot build state vector: too many qubits")
state = qi.CircuitModel(len(self.node))
for i in range(len(self.node)):
state.act_hadamard(i)
for i, j in self.edgelist():
state.act_cz(i, j)
for i, n in self.node.items():
state.act_local_rotation(i, clifford.unitaries[n["vop"]])
return state

def to_stabilizer(self):
""" Get the stabilizer of this graph """
output = {a:{} for a in self.node}
for a, b in it.product(self.node, self.node):
if a == b:
output[a][b] = "X"
elif a in self.adj[b]:
output[a][b] = "Z"
else:
output[a][b] = "I"
return output

def adj_list(self):
""" For comparison with Anders and Briegel's C++ implementation """
rows = []
for key, node in self.node.items():
adj = " ".join(map(str, sorted(self.adj[key])))
vop = clifford.get_name(node["vop"])
s = "Vertex {}: VOp {}, neighbors {}".format(key, vop, adj)
rows.append(s)
return " \n".join(rows) + " \n"

def get_adj_list_line(self, key):
""" TODO: delete """
node = self.node[key]
adj = " ".join(map(str, sorted(self.adj[key])))
vop = clifford.get_name(node["vop"])
s = "Vertex {}: VOp {}, neighbors {}".format(key, vop, adj)
return s

def print_adj_list_line(self, key):
debug(self.get_adj_list_line(key))


def __eq__(self, other):
""" Check equality between graphs """
return self.adj == other.adj and self.node == other.node


Cargando…
Cancelar
Guardar