| @@ -49,7 +49,7 @@ class GraphState(object): | |||||
| self._add_node(self, *args, **kwargs) | self._add_node(self, *args, **kwargs) | ||||
| def _del_node(self, node): | def _del_node(self, node): | ||||
| """ Remove a node. TODO: this is a hack right now! """ | |||||
| """ Remove a node. TODO: this is a hack right now. """ | |||||
| if not node in self.node: | if not node in self.node: | ||||
| return | return | ||||
| del self.node[node] | del self.node[node] | ||||
| @@ -57,6 +57,10 @@ class GraphState(object): | |||||
| del self.adj[k][node] | del self.adj[k][node] | ||||
| del self.adj[node] | del self.adj[node] | ||||
| def del_qubit(self, node): | |||||
| """ Remove a qubit. TODO: this is a hack right now. """ | |||||
| self._del_node(node) | |||||
| def _add_node(self, node, **kwargs): | def _add_node(self, node, **kwargs): | ||||
| """ Add a node. By default, nodes are initialized with ``vop=``:math:`I`, i.e. they are in the :math:`|+\\rangle` state. | """ Add a node. By default, nodes are initialized with ``vop=``:math:`I`, i.e. they are in the :math:`|+\\rangle` state. | ||||
| @@ -424,8 +428,7 @@ class GraphState(object): | |||||
| """ Represent as a string for quick debugging """ | """ Represent as a string for quick debugging """ | ||||
| s = "" | s = "" | ||||
| for key in sorted(self.node.keys()): | for key in sorted(self.node.keys()): | ||||
| s += "{}: {}\t".format( | |||||
| key, clifford.get_name(self.node[key]["vop"]).replace("YC", "-")) | |||||
| s += "{}: {}\t".format(key, clifford.get_name(self.node[key]["vop"])) | |||||
| if self.adj[key]: | if self.adj[key]: | ||||
| s += str(tuple(self.adj[key].keys())).replace(" ", "") | s += str(tuple(self.adj[key].keys())).replace(" ", "") | ||||
| else: | else: | ||||
| @@ -123,10 +123,18 @@ class CircuitModel(object): | |||||
| b = normalize_global_phase(other.state) | b = normalize_global_phase(other.state) | ||||
| return np.allclose(a, b) | return np.allclose(a, b) | ||||
| def __setitem__(self, key, value): | |||||
| """ Set a matrix element """ | |||||
| self.state[key] = value | |||||
| def __getitem__(self, key): | |||||
| """ Get a matrix element """ | |||||
| return self.state[key] | |||||
| def __str__(self): | def __str__(self): | ||||
| s = "" | s = "" | ||||
| for i in range(self.d): | for i in range(self.d): | ||||
| label = bin(i)[2:].rjust(self.nqubits, "0") | |||||
| label = bin(i)[2:].rjust(self.nqubits, "0")[::-1] | |||||
| if abs(self.state[i, 0]) > 0.00001: | if abs(self.state[i, 0]) > 0.00001: | ||||
| term = self.state[i, 0] | term = self.state[i, 0] | ||||
| real_sign = " " if term.real>=0 else "-" | real_sign = " " if term.real>=0 else "-" | ||||
| @@ -25,7 +25,7 @@ | |||||
| <div id=node_info class=hidden> nothing </div> | <div id=node_info class=hidden> nothing </div> | ||||
| <div id=server_info class=hidden> </div> | <div id=server_info class=hidden> </div> | ||||
| <div id=version>Version 0.4.20 develop mode</div> | |||||
| <div id=version>Version 0.4.20</div> | |||||
| <div id=node_data class=hidden> | <div id=node_data class=hidden> | ||||
| <div id=node_name></div> | <div id=node_name></div> | ||||
| @@ -45,32 +45,84 @@ If you want to modify and test ``abp`` without having to re-install, switch into | |||||
| Quickstart | Quickstart | ||||
| ---------------------------- | ---------------------------- | ||||
| It's pretty easy to build a graph state, act some gates, and do measurements:: | |||||
| Let's make a new ``GraphState`` object with a register of three qubits: | |||||
| >>> from abp import GraphState | >>> from abp import GraphState | ||||
| >>> g = GraphState(5) | |||||
| >>> for i in range(5): | |||||
| ... g.act_hadamard(i) | |||||
| ... | |||||
| >>> for i in range(4): | |||||
| ... g.act_cz(i, i+1) | |||||
| ... | |||||
| >>> print g | |||||
| 0: IA (1,) | |||||
| 1: IA (0,2) | |||||
| 2: IA (1,3) | |||||
| 3: IA (2,4) | |||||
| 4: IA (3,) | |||||
| >>> g.measure(2, "px") | |||||
| 0 | |||||
| >>> g = GraphState(3) | |||||
| All the qubits are initialized by default in the :math:`|+\rangle` state: | |||||
| >>> print g.to_state_vector() | |||||
| |000❭: √1/8 + i √0 | |||||
| |100❭: √1/8 + i √0 | |||||
| |010❭: √1/8 + i √0 | |||||
| |110❭: √1/8 + i √0 | |||||
| |001❭: √1/8 + i √0 | |||||
| |101❭: √1/8 + i √0 | |||||
| |011❭: √1/8 + i √0 | |||||
| |111❭: √1/8 + i √0 | |||||
| We can also check the stabilizer tableau: | |||||
| >>> print g.to_stabilizer() | |||||
| 0 1 2 | |||||
| --------- | |||||
| X | |||||
| X | |||||
| X | |||||
| Or look directly at the vertex operators and neighbour lists: | |||||
| >>> print g | |||||
| 0: IA - | |||||
| 1: IA - | |||||
| 2: IA - | |||||
| This representation might be unfamiliar. Each row shows the index of the qubit, then the _vertex operator_, then a list of neighbouring qubits. To understand vertex operators, read the original paper by Anders and Briegel. | |||||
| Let's act a Hadamard gate on the zeroth qubit -- this will evolve qubit ``0`` to the :math:`H|+\rangle = |1\rangle` state: | |||||
| >>> g.act_hadamard(0) | |||||
| >>> print g.to_state_vector() | |||||
| |000❭: √1/4 + i √0 | |||||
| |010❭: √1/4 + i √0 | |||||
| |001❭: √1/4 + i √0 | |||||
| |011❭: √1/4 + i √0 | |||||
| >>> print g | >>> print g | ||||
| 0: IA (3,) | |||||
| 1: ZC (3,) | |||||
| 0: YC - | |||||
| 1: IA - | |||||
| 2: IA - | 2: IA - | ||||
| 3: ZA (0,1,4) | |||||
| 4: IA (3,) | |||||
| Working with GraphStates | |||||
| And now run some CZ gates: | |||||
| >>> g.act_cz(0,1) | |||||
| >>> g.act_cz(1,2) | |||||
| >>> print g | |||||
| 0: YC - | |||||
| 1: IA (2,) | |||||
| 2: IA (1,) | |||||
| >>> print g.to_state_vector() | |||||
| |000❭: √1/4 + i √0 | |||||
| |010❭: √1/4 + i √0 | |||||
| |001❭: √1/4 + i √0 | |||||
| |011❭: -√1/4 + i √0 | |||||
| Tidy up a bit: | |||||
| >>> g.del_node(0) | |||||
| >>> g.act_hadamard(0) | |||||
| >>> print g.to_state_vector() | |||||
| |00❭: √1/2 + i √0 | |||||
| |11❭: √1/2 + i √0 | |||||
| Cool, we made a Bell state. Incidentally, those those state vectors and stabilizers are real objects with methods, not just string-like representations of the state: | |||||
| GraphState API | |||||
| ------------------------- | ------------------------- | ||||
| The ``abp.GraphState`` class is the main interface to ``abp``. | The ``abp.GraphState`` class is the main interface to ``abp``. | ||||
| @@ -169,3 +169,10 @@ def test_sqrt_notation(n=2): | |||||
| g = GraphState(range(n)) | g = GraphState(range(n)) | ||||
| g.act_circuit(c) | g.act_circuit(c) | ||||
| def test_indexint(): | |||||
| """ Test that we can index into state vectors """ | |||||
| psi = qi.CircuitModel(0) | |||||
| assert psi[0] == 1+0j | |||||
| psi[0] = 42 | |||||
| assert psi[0] == 42 | |||||