"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# 作用在3个量子比特上的一层ansatz线路示例\n",
"build_ansatz(3, 1).svg()"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"text/html": [
" Circuit Summary \n",
"╭───────────────────────┬───────────────────────────────────────────────────────────────────╮\n",
"│ Info │ value │\n",
"├───────────────────────┼───────────────────────────────────────────────────────────────────┤\n",
"│ Number of qubit │ 127 │\n",
"├───────────────────────┼───────────────────────────────────────────────────────────────────┤\n",
"│ Total number of gate │ 889 │\n",
"│ Barrier │ 0 │\n",
"│ Noise Channel │ 0 │\n",
"│ Measurement │ 0 │\n",
"├───────────────────────┼───────────────────────────────────────────────────────────────────┤\n",
"│ Parameter gate │ 508 │\n",
"│ 508 ansatz parameters │ theta0, theta1, theta2, theta3, theta4, theta5, theta6, theta7, │\n",
"│ │ theta8, theta9... │\n",
"╰───────────────────────┴───────────────────────────────────────────────────────────────────╯\n",
"
\n"
],
"text/plain": [
"\u001b[1;38;2;255;0;0m Circuit Summary \u001b[0m\n",
"╭───────────────────────┬───────────────────────────────────────────────────────────────────╮\n",
"│\u001b[1m \u001b[0m\u001b[1;38;2;59;59;149mInfo\u001b[0m\u001b[1m \u001b[0m\u001b[1m \u001b[0m│\u001b[1m \u001b[0m\u001b[1;38;2;59;59;149mvalue\u001b[0m\u001b[1m \u001b[0m\u001b[1m \u001b[0m│\n",
"├───────────────────────┼───────────────────────────────────────────────────────────────────┤\n",
"│ \u001b[1mNumber of qubit\u001b[0m │ 127 │\n",
"├───────────────────────┼───────────────────────────────────────────────────────────────────┤\n",
"│ \u001b[1mTotal number of gate\u001b[0m │ 889 │\n",
"│ Barrier │ 0 │\n",
"│ Noise Channel │ 0 │\n",
"│ Measurement │ 0 │\n",
"├───────────────────────┼───────────────────────────────────────────────────────────────────┤\n",
"│ \u001b[1mParameter gate\u001b[0m │ 508 │\n",
"│ 508 ansatz parameters │ \u001b[38;2;72;201;176mtheta0, theta1, theta2, theta3, theta4, theta5, theta6, theta7, \u001b[0m │\n",
"│ │ \u001b[38;2;72;201;176mtheta8, theta9...\u001b[0m │\n",
"╰───────────────────────┴───────────────────────────────────────────────────────────────────╯\n"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# 初始线路共3层,作用在127个量子比特上\n",
"n_qubits = 127\n",
"depth = 3\n",
"circ1 = build_ansatz(n_qubits, depth)\n",
"circ1.summary() # 总结初始线路"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"接下来对初始量子线路进行编译。\n",
"\n",
"假设编译前的量子门集为:[H](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.11/core/gates/mindquantum.core.gates.HGate.html)、[CNOT](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.11/core/gates/mindquantum.core.gates.CNOTGate.html)、[RZ](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.11/core/gates/mindquantum.core.gates.RZ.html)、[RX](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.11/core/gates/mindquantum.core.gates.RX.html);编译后的量子门集为:[H](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.11/core/gates/mindquantum.core.gates.HGate.html)、[CNOT](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.11/core/gates/mindquantum.core.gates.CNOTGate.html)、[RZ](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.11/core/gates/mindquantum.core.gates.RZ.html)。编译规则是[H](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.11/core/gates/mindquantum.core.gates.HGate.html)、[CNOT](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.11/core/gates/mindquantum.core.gates.CNOTGate.html)、[RZ](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.11/core/gates/mindquantum.core.gates.RZ.html)门保持不变,将[RX](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.11/core/gates/mindquantum.core.gates.RX.html)门编译成[H](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.11/core/gates/mindquantum.core.gates.HGate.html)、[RZ](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.11/core/gates/mindquantum.core.gates.RZ.html)、[H](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.11/core/gates/mindquantum.core.gates.HGate.html)的组合。"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"def compile_circuit(circ):\n",
" circ_compiled = Circuit()\n",
"\n",
" for gate in circ: # 遍历初始线路中的量子门\n",
" # H,CNOT,RZ门保持不变\n",
" if gate.name == 'H' or gate.name == 'CNOT' or gate.name == 'RZ':\n",
" circ_compiled += gate\n",
" elif gate.name == 'RX': # RX门经过编译变成H*RZ*H\n",
" circ_compiled += H.on(gate.obj_qubits)\n",
" circ_compiled += RZ(gate.coeff).on(gate.obj_qubits)\n",
" circ_compiled += H.on(gate.obj_qubits)\n",
"\n",
" return circ_compiled"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
""
],
"text/plain": [
""
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# 一层ansatz线路编译后生成的线路示例,可以看到,所有RX门都根据编译规则发生了变化\n",
"compile_circuit(build_ansatz(3, 1)).svg()"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"text/html": [
" Circuit Summary \n",
"╭───────────────────────┬───────────────────────────────────────────────────────────────────╮\n",
"│ Info │ value │\n",
"├───────────────────────┼───────────────────────────────────────────────────────────────────┤\n",
"│ Number of qubit │ 127 │\n",
"├───────────────────────┼───────────────────────────────────────────────────────────────────┤\n",
"│ Total number of gate │ 1905 │\n",
"│ Barrier │ 0 │\n",
"│ Noise Channel │ 0 │\n",
"│ Measurement │ 0 │\n",
"├───────────────────────┼───────────────────────────────────────────────────────────────────┤\n",
"│ Parameter gate │ 508 │\n",
"│ 508 ansatz parameters │ theta0, theta1, theta2, theta3, theta4, theta5, theta6, theta7, │\n",
"│ │ theta8, theta9... │\n",
"╰───────────────────────┴───────────────────────────────────────────────────────────────────╯\n",
"
\n"
],
"text/plain": [
"\u001b[1;38;2;255;0;0m Circuit Summary \u001b[0m\n",
"╭───────────────────────┬───────────────────────────────────────────────────────────────────╮\n",
"│\u001b[1m \u001b[0m\u001b[1;38;2;59;59;149mInfo\u001b[0m\u001b[1m \u001b[0m\u001b[1m \u001b[0m│\u001b[1m \u001b[0m\u001b[1;38;2;59;59;149mvalue\u001b[0m\u001b[1m \u001b[0m\u001b[1m \u001b[0m│\n",
"├───────────────────────┼───────────────────────────────────────────────────────────────────┤\n",
"│ \u001b[1mNumber of qubit\u001b[0m │ 127 │\n",
"├───────────────────────┼───────────────────────────────────────────────────────────────────┤\n",
"│ \u001b[1mTotal number of gate\u001b[0m │ 1905 │\n",
"│ Barrier │ 0 │\n",
"│ Noise Channel │ 0 │\n",
"│ Measurement │ 0 │\n",
"├───────────────────────┼───────────────────────────────────────────────────────────────────┤\n",
"│ \u001b[1mParameter gate\u001b[0m │ 508 │\n",
"│ 508 ansatz parameters │ \u001b[38;2;72;201;176mtheta0, theta1, theta2, theta3, theta4, theta5, theta6, theta7, \u001b[0m │\n",
"│ │ \u001b[38;2;72;201;176mtheta8, theta9...\u001b[0m │\n",
"╰───────────────────────┴───────────────────────────────────────────────────────────────────╯\n"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# 编译初始线路\n",
"circ2 = compile_circuit(circ1)\n",
"circ2.summary() # 总结编译线路"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"最后构造完整的量子线路。\n",
"\n",
"根据量子线路的可逆性可知,若两个线路功能等价,那么将一个线路作用到量子比特上,再将另一个线路的逆线路作用到量子比特上,最终得到的量子态与两次作用之前的量子态等价。于是,完整的量子线路由编译后的线路和初始线路的逆线路组成。"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"text/html": [
" Circuit Summary \n",
"╭───────────────────────┬───────────────────────────────────────────────────────────────────╮\n",
"│ Info │ value │\n",
"├───────────────────────┼───────────────────────────────────────────────────────────────────┤\n",
"│ Number of qubit │ 127 │\n",
"├───────────────────────┼───────────────────────────────────────────────────────────────────┤\n",
"│ Total number of gate │ 2794 │\n",
"│ Barrier │ 0 │\n",
"│ Noise Channel │ 0 │\n",
"│ Measurement │ 0 │\n",
"├───────────────────────┼───────────────────────────────────────────────────────────────────┤\n",
"│ Parameter gate │ 1016 │\n",
"│ 508 ansatz parameters │ theta507, theta506, theta505, theta504, theta503, theta502, │\n",
"│ │ theta501, theta500, theta499, theta498... │\n",
"╰───────────────────────┴───────────────────────────────────────────────────────────────────╯\n",
"
\n"
],
"text/plain": [
"\u001b[1;38;2;255;0;0m Circuit Summary \u001b[0m\n",
"╭───────────────────────┬───────────────────────────────────────────────────────────────────╮\n",
"│\u001b[1m \u001b[0m\u001b[1;38;2;59;59;149mInfo\u001b[0m\u001b[1m \u001b[0m\u001b[1m \u001b[0m│\u001b[1m \u001b[0m\u001b[1;38;2;59;59;149mvalue\u001b[0m\u001b[1m \u001b[0m\u001b[1m \u001b[0m│\n",
"├───────────────────────┼───────────────────────────────────────────────────────────────────┤\n",
"│ \u001b[1mNumber of qubit\u001b[0m │ 127 │\n",
"├───────────────────────┼───────────────────────────────────────────────────────────────────┤\n",
"│ \u001b[1mTotal number of gate\u001b[0m │ 2794 │\n",
"│ Barrier │ 0 │\n",
"│ Noise Channel │ 0 │\n",
"│ Measurement │ 0 │\n",
"├───────────────────────┼───────────────────────────────────────────────────────────────────┤\n",
"│ \u001b[1mParameter gate\u001b[0m │ 1016 │\n",
"│ 508 ansatz parameters │ \u001b[38;2;72;201;176mtheta507, theta506, theta505, theta504, theta503, theta502, \u001b[0m │\n",
"│ │ \u001b[38;2;72;201;176mtheta501, theta500, theta499, theta498...\u001b[0m │\n",
"╰───────────────────────┴───────────────────────────────────────────────────────────────────╯\n"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# 完整线路\n",
"circ1_inv = dagger(circ1) # dagger()将量子线路左右逆转,得到初始线路的逆线路\n",
"circ_all = circ1_inv + circ2 # 完整线路=初始线路的逆线路+编译后的线路\n",
"circ_all.summary() # 总结完整线路"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 第二步\n",
"\n",
"将完整的量子线路转换成ZX图。\n",
"\n",
"含参量子线路等价性检查方法基于ZX演算实现,需要将量子线路转换成ZX图。\n",
"\n",
"量子门是ZX图中的顶点,分为3种颜色,[H](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.11/core/gates/mindquantum.core.gates.HGate.html)门表示成黄色顶点,[RX](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.11/core/gates/mindquantum.core.gates.RX.html)门表示成含参的红色顶点,[RZ](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.11/core/gates/mindquantum.core.gates.RZ.html)门表示成含参的绿色顶点,[CNOT](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.11/core/gates/mindquantum.core.gates.CNOTGate.html)门的受控位表示成红色顶点,控制位表示成绿色顶点,受控位与控制位的顶点互为邻居。同一个量子比特上相邻两个量子门的顶点互为邻居。\n",
"\n",
"先定义顶点类和图类。"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"# 顶点类\n",
"class Vertex:\n",
" def __init__(self, name, color, qubit, neighbor, phase=0.0):\n",
" self.name = name # 量子门顶点的序号\n",
" self.color = color # 量子门顶点的颜色\n",
" self.phase = phase # 含参量子门的参数\n",
" self.qubit = qubit # 作用在哪个量子比特上\n",
" self.neighbor = neighbor # 顶点之间的邻居关系"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"# 图类\n",
"class Graph:\n",
" def __init__(self):\n",
" self.vertices = {} # 初始图,空\n",
" self.count = 0 # 顶点总数,只增不减,也用于给新顶点命名\n",
"\n",
" # 新增边\n",
" def add_edge(self, from_vertex, to_vertex): # 添加一条从起点到终点的边\n",
" self.vertices[from_vertex].neighbor.append(to_vertex)\n",
"\n",
" # 新增顶点\n",
" def add_vertex(self, color, qubit, neighbor, phase=0.0):\n",
" name = self.count\n",
" self.count += 1\n",
" # 添加从新顶点到相邻顶点的边\n",
" self.vertices[name] = Vertex(name, color, qubit, neighbor, phase)\n",
" for v in neighbor: # 再添加从相邻顶点到新顶点的边\n",
" self.add_edge(v, name)\n",
"\n",
" # 打印图信息\n",
" def print(self):\n",
" print(\"==================graph message==================\")\n",
" for v in self.vertices.values():\n",
" print(v.name, '\\t', v.neighbor, '\\t', v.color, '\\t', v.phase)\n",
" print('\\n')\n",
"\n",
" # 删除自身的环\n",
" # 省略了ZX图的无环规则(本文中,所有“无环”均指不存在单条边构成的环)\n",
" def clear(self):\n",
" for v in self.vertices.values():\n",
" while v.name in v.neighbor:\n",
" # 将本顶点从自己的邻居中删除\n",
" self.vertices[v.name].neighbor.remove(v.name)\n",
"\n",
" # 删除顶点\n",
" def delete_vertex(self, name):\n",
" for v in self.vertices.values():\n",
" while name in v.neighbor: # 删除终点是该顶点的边\n",
" self.vertices[v.name].neighbor.remove(name)\n",
" self.vertices.pop(name) # 删除起点是该顶点的边\n",
"\n",
" # 两个电路是否等价\n",
" def equiv(self):\n",
" if not self.vertices: # 等价的两个电路,经过ZX演算化简后,图中无顶点\n",
" print(\"Equivalent!\")\n",
" else:\n",
" print(\"Not sure!\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"接下来将量子线路绘制成ZX图。\n",
"\n",
"遍历线路中的所有量子门,并依次将其绘制成ZX图中的顶点。若当前量子比特上暂无量子门,则当前的量子门暂无邻居;若当前量子比特上已有量子门,则当前的量子门与该量子比特上最后一个量子门互为邻居;[CNOT](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.11/core/gates/mindquantum.core.gates.CNOTGate.html)门在绘制时就添加了控制位与受控位顶点之间的邻居关系。"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"def draw_graph(circ):\n",
" g = Graph() # 初始化一个空图\n",
" last_name = [-1] * circ.n_qubits # last_name保存每个量子比特上当前的最后一个顶点\n",
" for gate in circ: # 遍历线路中的所有量子门\n",
" if gate.name == 'H': # H门绘制成黄色顶点\n",
" if last_name[gate.obj_qubits[0]] != -1: # 当前量子比特上已有顶点\n",
" g.add_vertex('yellow', gate.obj_qubits[0],\n",
" [last_name[gate.obj_qubits[0]]])\n",
" else: # 当前量子比特上暂无顶点\n",
" g.add_vertex('yellow', gate.obj_qubits[0], [])\n",
" last_name[gate.obj_qubits[0]] = g.count-1 # 更新当前量子比特上最后一个顶点为新增顶点\n",
" if gate.name == 'RX': # RX门绘制成红色顶点\n",
" if last_name[gate.obj_qubits[0]] != -1:\n",
" g.add_vertex('red', gate.obj_qubits[0],\n",
" [last_name[gate.obj_qubits[0]]], gate.coeff)\n",
" else:\n",
" g.add_vertex('red', gate.obj_qubits[0], [], gate.coeff)\n",
" last_name[gate.obj_qubits[0]] = g.count-1\n",
" if gate.name == 'RZ': # RZ门绘制成绿色顶点\n",
" if last_name[gate.obj_qubits[0]] != -1:\n",
" g.add_vertex('green', gate.obj_qubits[0],\n",
" [last_name[gate.obj_qubits[0]]], gate.coeff)\n",
" else:\n",
" g.add_vertex('green', gate.obj_qubits[0], [], gate.coeff)\n",
" last_name[gate.obj_qubits[0]] = g.count-1\n",
" if gate.name == 'CNOT': # CNOT门要分别绘制控制位顶点和受控位顶点\n",
" # 绘制控制位顶点,绿色\n",
" if last_name[gate.obj_qubits[1]] != -1:\n",
" g.add_vertex('green', gate.obj_qubits[1],\n",
" [last_name[gate.obj_qubits[1]]])\n",
" else:\n",
" g.add_vertex('green', gate.obj_qubits[1], [])\n",
" last_name[gate.obj_qubits[1]] = g.count-1\n",
" # 绘制受控位顶点,红色\n",
" if last_name[gate.obj_qubits[0]] != -1:\n",
" g.add_vertex('red', gate.obj_qubits[0],\n",
" [last_name[gate.obj_qubits[0]], g.count-1])\n",
" else:\n",
" g.add_vertex('red', gate.obj_qubits[0], [g.count-1])\n",
" last_name[gate.obj_qubits[0]] = g.count-1\n",
" return g"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"最后,将第一步构造好的完整量子线路绘制成ZX图。"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"g = draw_graph(circ_all)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 第三步\n",
"\n",
"化简ZX图。\n",
"\n",
"ZX演算由ZX图和化简规则组成,根据化简规则,对ZX图中的顶点和邻居关系进行化简。\n",
"\n",
"以下列出部分规则,具体实现过程即图和顶点的相关操作,只举例说明,不再一一赘述。\n",
"\n",
"规则1:不与其他量子比特上的顶点相邻的、参数为0的红色或绿色顶点可以删除。\n",
"\n",
""
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [],
"source": [
"def rule_1(g: Graph):\n",
" for v1 in list(g.vertices.keys()): # ZX演算过程中,图中的顶点会发生增减,用list()获取最初的所有顶点\n",
" if v1 not in g.vertices.keys(): # 判断当前顶点在化简过程中有没有被删除\n",
" continue # 已被删除,略过\n",
" v1 = g.vertices[v1]\n",
" # 顶点参数为0\n",
" if v1.phase == 0 or list(v1.phase.values()) == [0.0]*len(list(v1.phase.values())):\n",
" flag = True # 用于判断当前顶点是否与其他量子比特上的顶点相关,如果相关,暂时不能删除\n",
" for v2 in v1.neighbor:\n",
" v2 = g.vertices[v2]\n",
" if v2.qubit != v1.qubit: # 与其他量子比特上的顶点相关\n",
" flag = False\n",
" break\n",
" if flag: # 与其他量子比特上的顶点无关\n",
" for v2 in v1.neighbor:\n",
" v2 = g.vertices[v2]\n",
" v2.neighbor.extend(v1.neighbor) # 将前一个顶点与后一个顶点相连,略过当前顶点\n",
" g.clear() # 清除化简过程中可能产生的环\n",
" g.delete_vertex(v1.name) # 删除该顶点"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"规则2:相邻的、相同颜色的红色或绿色顶点可以合并。\n",
"\n",
""
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"def rule_2(g: Graph):\n",
" for v1 in list(g.vertices.keys()):\n",
" if v1 not in g.vertices.keys():\n",
" continue\n",
" v1 = g.vertices[v1]\n",
" if v1.color == 'red' or v1.color == 'green': # 红色或绿色顶点\n",
" for v2 in v1.neighbor: # 相邻\n",
" v2 = g.vertices[v2]\n",
" if v2.color == v1.color: # 相同颜色\n",
" v2.phase = v2.phase + v1.phase # 参数相加\n",
" v2.neighbor.extend(v1.neighbor) # 合并两个顶点\n",
" g.clear()\n",
" for v3 in v1.neighbor: # 更新合并顶点后的邻居关系\n",
" v3 = g.vertices[v3]\n",
" v3.neighbor.append(v2.name)\n",
" g.clear()\n",
" g.delete_vertex(v1.name) # 删除已被合并的顶点"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"规则3:所有邻居都是黄色顶点的绿色顶点,可以变成红色顶点,并删除相邻的黄色顶点。\n",
"\n",
""
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [],
"source": [
"def rule_3(g: Graph):\n",
" for v1 in list(g.vertices.keys()):\n",
" if v1 not in g.vertices.keys():\n",
" continue\n",
" v1 = g.vertices[v1]\n",
" if v1.color == 'green':\n",
" flag = True # 用于判断是否所有邻居都是黄色\n",
" for v2 in v1.neighbor:\n",
" v2 = g.vertices[v2]\n",
" if v2.color != 'yellow': # 不满足所有邻居都是黄色\n",
" flag = False\n",
" break\n",
" if flag: # 所有邻居都是黄色\n",
" v1.color = 'red' # 变成红色\n",
" v1_neighbor = list(v1.neighbor)\n",
" for v2 in v1_neighbor: # 删除这些黄色顶点\n",
" v2 = g.vertices[v2]\n",
" v1.neighbor.extend(v2.neighbor)\n",
" g.clear()\n",
" for v3 in v2.neighbor:\n",
" v3 = g.vertices[v3]\n",
" v3.neighbor.append(v1.name)\n",
" g.clear()\n",
" g.delete_vertex(v2.name)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"规则 4:相邻的、存在两条边的红绿顶点,可以删除这两条边。\n",
"\n",
""
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [],
"source": [
"def rule_4(g: Graph):\n",
" for v1 in list(g.vertices.keys()):\n",
" if v1 not in g.vertices.keys():\n",
" continue\n",
" v1 = g.vertices[v1]\n",
" if v1.color == 'green':\n",
" for v2 in v1.neighbor:\n",
" v2 = g.vertices[v2]\n",
" # 红绿顶点,且两顶点间有两条边\n",
" if v2.color == 'red' and v2.neighbor.count(v1.name) == 2:\n",
" while v2.name in g.vertices[v1.name].neighbor: # 删除相连的边\n",
" v1.neighbor.remove(v2.name)\n",
" while v1.name in g.vertices[v2.name].neighbor:\n",
" v2.neighbor.remove(v1.name)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"接下来利用以上规则对ZX图进行循环化简,若某轮循环中没有删除任何顶点,则认为化简结束。"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [],
"source": [
"def simplify(g: Graph):\n",
" temp = [] # 用于对比本轮循环是否有顶点被删除\n",
" while temp != list(g.vertices.keys()): # 如果本轮循环没有删除任何顶点,则认为化简结束,退出循环\n",
" temp = list(g.vertices.keys())\n",
" rule_3(g)\n",
" rule_2(g)\n",
" rule_4(g)\n",
" rule_1(g)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"完整线路规模较大,可以先构造一个作用在三个量子比特上的单层线路进行测试。"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
""
],
"text/plain": [
""
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"test_circ1 = build_ansatz(3, 1)\n",
"test_circ1_inv = dagger(test_circ1)\n",
"test_circ2 = compile_circuit(test_circ1)\n",
"\n",
"test_circ_all = test_circ1_inv + test_circ2\n",
"\n",
"test_circ_all.svg()"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"==================graph message==================\n",
"0 \t [4] \t red \t -theta5\n",
"1 \t [3] \t red \t -theta4\n",
"2 \t [5] \t red \t -theta3\n",
"3 \t [1, 4, 6] \t green \t 0.0\n",
"4 \t [0, 3, 7] \t red \t 0.0\n",
"5 \t [2, 6, 8] \t green \t 0.0\n",
"6 \t [3, 5, 10] \t red \t 0.0\n",
"7 \t [4, 8, 9] \t green \t 0.0\n",
"8 \t [5, 7, 11] \t red \t 0.0\n",
"9 \t [7, 18] \t red \t -theta2\n",
"10 \t [6, 15] \t red \t -theta1\n",
"11 \t [8, 12] \t red \t -theta0\n",
"12 \t [11, 13] \t yellow \t 0.0\n",
"13 \t [12, 14] \t green \t theta0\n",
"14 \t [13, 22] \t yellow \t 0.0\n",
"15 \t [10, 16] \t yellow \t 0.0\n",
"16 \t [15, 17] \t green \t theta1\n",
"17 \t [16, 24] \t yellow \t 0.0\n",
"18 \t [9, 19] \t yellow \t 0.0\n",
"19 \t [18, 20] \t green \t theta2\n",
"20 \t [19, 21] \t yellow \t 0.0\n",
"21 \t [20, 22, 26] \t green \t 0.0\n",
"22 \t [14, 21, 23] \t red \t 0.0\n",
"23 \t [22, 24, 27] \t green \t 0.0\n",
"24 \t [17, 23, 25] \t red \t 0.0\n",
"25 \t [24, 26, 30] \t green \t 0.0\n",
"26 \t [21, 25, 33] \t red \t 0.0\n",
"27 \t [23, 28] \t yellow \t 0.0\n",
"28 \t [27, 29] \t green \t theta3\n",
"29 \t [28] \t yellow \t 0.0\n",
"30 \t [25, 31] \t yellow \t 0.0\n",
"31 \t [30, 32] \t green \t theta4\n",
"32 \t [31] \t yellow \t 0.0\n",
"33 \t [26, 34] \t yellow \t 0.0\n",
"34 \t [33, 35] \t green \t theta5\n",
"35 \t [34] \t yellow \t 0.0\n",
"\n",
"\n"
]
}
],
"source": [
"# 将测试线路绘制成ZX图\n",
"test_g = draw_graph(test_circ_all)\n",
"test_g.print()"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"化简之前:\n",
"Not sure!\n",
"化简之后:\n",
"Equivalent!\n"
]
}
],
"source": [
"# 化简测试线路\n",
"print(\"化简之前:\")\n",
"test_g.equiv()\n",
"\n",
"simplify(test_g)\n",
"\n",
"print(\"化简之后:\")\n",
"test_g.equiv()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"化简功能测试通过,最后就可以化简完整线路的ZX图,化简结果显示编译前后的两个线路是等价的。"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"化简之前:\n",
"Not sure!\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"化简之后:\n",
"Equivalent!\n"
]
}
],
"source": [
"# 化简完整线路\n",
"print(\"化简之前:\")\n",
"g.equiv()\n",
"\n",
"simplify(g) # 化简\n",
"\n",
"print(\"化简之后:\")\n",
"g.equiv()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 第四\n",
"\n",
"若ZX演算无法确定则实例化参数。\n",
"\n",
"对于两个不等价的线路,ZX演算不能直接给出不等价的判定结果。这时,需要对线路中的参数进行实例化,判断实例化之后的两个线路是否等价。"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
""
],
"text/plain": [
""
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# 构造反例线路:ZX演算化简后无法确定、实际上不等价的两个线路\n",
"neq_circ1 = Circuit()\n",
"neq_circ1 += H.on(1)\n",
"neq_circ1 += RX(f'theta{0}').on(2)\n",
"neq_circ1 += CNOT.on(0, 1)\n",
"neq_circ1 += RZ(f'theta{1}').on(0)\n",
"neq_circ1 += CNOT.on(2, 1)\n",
"neq_circ1 += CNOT.on(0, 1)\n",
"neq_circ1 += RX(f'theta{2}').on(2)\n",
"\n",
"neq_circ1.svg()"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
""
],
"text/plain": [
""
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"neq_circ2 = Circuit()\n",
"neq_circ2 += H.on(1)\n",
"neq_circ2 += RX(f'theta{0}').on(2)\n",
"neq_circ2 += CNOT.on(0, 1)\n",
"neq_circ2 += RZ(f'theta{1}').on(0)\n",
"neq_circ2 += CNOT.on(2, 1)\n",
"neq_circ2 += CNOT.on(0, 1)\n",
"neq_circ2 += RX({f'theta{0}': 1, f'theta{1}': 1, f'theta{2}': 1}).on(2)\n",
"\n",
"neq_circ2.svg()"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"image/svg+xml": [
""
],
"text/plain": [
""
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"neq_circ1_inv = dagger(neq_circ1)\n",
"neq_circ_all = neq_circ1_inv + neq_circ2 # 构造完整反例线路\n",
"neq_circ_all.svg()"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"化简之前:\n",
"Not sure!\n",
"化简之后:\n",
"Not sure!\n"
]
}
],
"source": [
"# 将反例线路绘制成ZX图并进行化简\n",
"neq_g = draw_graph(neq_circ_all)\n",
"print(\"化简之前:\")\n",
"neq_g.equiv()\n",
"\n",
"simplify(neq_g)\n",
"\n",
"print(\"化简之后:\")\n",
"neq_g.equiv()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"对于反例线路,ZX演算化简之后,ZX图中仍有未删掉的顶点,于是ZX演算无法确定其等价性,需要实例化参数进行验证。\n",
"\n",
"实例化参数步骤分为两步:\n",
"\n",
"第一步,根据映射函数实例化参数,直接比较实例化之后两个线路的矩阵形式是否等价,若不等价则停止;\n",
"\n",
"第二步,若映射函数实例化未得到不等价的结果,则随机实例化参数,再直接比较实例化之后两个线路的矩阵形式是否等价,若不等价则最终判定两个线路不等价,否则,最终判定两个线路等价。"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [],
"source": [
"# 映射函数实例化参数\n",
"def map_para(n, r):\n",
" para = {}\n",
" for i in range(n):\n",
" para[f'theta{i}'] = (2*np.pi/((i+1)*r)-np.pi)\n",
" return para\n",
"\n",
"\n",
"# 随机实例化参数\n",
"def random_para(n):\n",
" para = {}\n",
" for i in range(n):\n",
" para[f'theta{i}'] = (np.random.uniform(np.pi, -np.pi))\n",
" return para"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"# 实例化参数验证两个线路是否等价,验证r轮\n",
"def verify_by_para(circ1, circ2, r):\n",
" n = len(list(set(circ1.params_name+circ2.params_name))) # 线路中一共n个参数\n",
" flag = True # 记录前r-1轮验证是否有结果\n",
" for i in range(r-1): # 前r-1轮指定参数\n",
" para = map_para(n, i+1)\n",
"\n",
" # 直接比较两个实例化之后的线路的矩阵形式是否等价\n",
" if np.array_equal(circ1.matrix(para), circ2.matrix(para)):\n",
" continue\n",
" else:\n",
" print('Not equivalent!') # 在任一情况下两个线路的矩阵不等价,即表示这两个线路不等价\n",
" flag = False # 验证已有结果,结束\n",
" break\n",
"\n",
" if flag: # 前r-1轮没有结果,最后一轮随机参数\n",
" para = random_para(n)\n",
" if np.array_equal(circ1.matrix(para), circ2.matrix(para)):\n",
" print('Equivalent!')\n",
" else:\n",
" print('Not equivalent!')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"用实例化参数的方法去验证两个反例线路的等价性,结果为不等价。"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Not equivalent!\n"
]
}
],
"source": [
"verify_by_para(neq_circ1, neq_circ2, 5)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 最后:将以上过程合并成一个完整的功能"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"def ZXcalculus(circ1, circ2):\n",
" circ1_inv = dagger(circ1) # 将原始线路左右逆转\n",
" circ = circ1_inv + circ2 # 构造完整线路\n",
" g = draw_graph(circ) # 将完整线路绘制成ZX图\n",
" print(\"化简之前:\")\n",
" g.equiv()\n",
" simplify(g) # 根据ZX演算规则进行化简\n",
" print(\"化简之后:\")\n",
" if not g.vertices: # 化简得到两个线路等价的结果\n",
" g.equiv()\n",
" else: # 化简未能得到结果,需要实例化参数进行验证\n",
" g.equiv()\n",
" print(\"实例化参数验证:\")\n",
" verify_by_para(circ1, circ2, 5)"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
" \n",
" Software | \n",
" Version | \n",
"
\n",
"mindquantum | 0.9.11 |
\n",
"scipy | 1.9.3 |
\n",
"numpy | 1.23.5 |
\n",
"\n",
" System | \n",
" Info | \n",
"
\n",
"Python | 3.8.17 |
OS | Linux x86_64 |
Memory | 16.62 GB |
CPU Max Thread | 16 |
Date | Tue Jan 2 17:38:24 2024 |
\n",
"
\n"
],
"text/plain": [
""
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from mindquantum.utils.show_info import InfoTable\n",
"\n",
"InfoTable('mindquantum', 'scipy', 'numpy')"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "MindSpore",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.17"
}
},
"nbformat": 4,
"nbformat_minor": 4
}