Skip to content

Commit

Permalink
Merge pull request zxcalc#66 from rkruegs123/master
Browse files Browse the repository at this point in the history
Added annealing and genetic algorithms for local search
  • Loading branch information
akissinger authored Apr 28, 2021
2 parents fd1850c + e1254d8 commit 8845863
Show file tree
Hide file tree
Showing 12 changed files with 905 additions and 157 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ pyzx.egg-info
*.class
*.ipynb_checkpoints
pyzx/js/d3.v5.js
*~
224 changes: 224 additions & 0 deletions demos/LocalSearch.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "welcome-louisville",
"metadata": {},
"outputs": [],
"source": [
"import sys; sys.path.append('..')\n",
"import pyzx as zx\n",
"from pyzx.generate import CNOT_HAD_PHASE_circuit"
]
},
{
"cell_type": "markdown",
"id": "passive-variation",
"metadata": {},
"source": [
"We often want to extract a circuit from a ZX-diagram. However, equivalent ZX-diagrams can induce drastically different circuits upon extraction even if they have similar numbers of spiders and edges. We can apply two optimization techniques, simulated annealing and genetic algorithms, to search this local space for a ZX-diagram that is more amenable to extraction."
]
},
{
"cell_type": "markdown",
"id": "aging-prairie",
"metadata": {},
"source": [
"Given a circuit, the typical approach to searching this space is to first fully simplify the associated ZX-diagram and then search over ZX-diagrams that are equivalent to this fully simplified version. So, let's first generate a random circuit and convert it to a ZX-diagram:"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "searching-astronomy",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Circuit on 5 qubits with 100 gates.\n",
" 20 is the T-count\n",
" 80 Cliffords among which \n",
" 58 2-qubit gates (58 CNOT, 0 other) and\n",
" 22 Hadamard gates.\n"
]
}
],
"source": [
"N_QUBITS = 5\n",
"DEPTH = 100\n",
"c = CNOT_HAD_PHASE_circuit(qubits=N_QUBITS, depth=DEPTH, clifford=False)\n",
"print(c.stats())\n",
"g = c.to_graph()"
]
},
{
"cell_type": "markdown",
"id": "hindu-virus",
"metadata": {},
"source": [
"Then, we want to fully simplify this ZX-diagram. There are two ways of doing this: applying `full_reduce` or applying `teleport_reduce` followed by circuit-level optimizations via `basic_optimization`. Note that if you go with the latter, you have to put the resulting ZX-diagram in graph-like form with `zx.simplify.to_graph_like()`. We'll go with the former:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "color-split",
"metadata": {},
"outputs": [],
"source": [
"g_simp = g.copy()\n",
"zx.full_reduce(g_simp)"
]
},
{
"cell_type": "markdown",
"id": "answering-flower",
"metadata": {},
"source": [
"Now, we can search the space of equivalent ZX-diagrams. First lets do it with annealing:"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "surgical-birth",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"annealing...: 100%|██████████| 1000/1000 [00:18<00:00, 53.52it/s]\n"
]
}
],
"source": [
"N_ITERS = 1000\n",
"\n",
"g_anneal, _ = zx.anneal(g_simp, iters=N_ITERS)"
]
},
{
"cell_type": "markdown",
"id": "level-sunday",
"metadata": {},
"source": [
"Let's convert this new ZX-diagram back to a circuit and see how we did. We can apply some optimizations along the way:"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "healthy-toner",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Circuit on 5 qubits with 82 gates.\n",
" 18 is the T-count\n",
" 64 Cliffords among which \n",
" 37 2-qubit gates (30 CNOT, 7 other) and\n",
" 19 Hadamard gates.\n"
]
}
],
"source": [
"zx.full_reduce(g_anneal)\n",
"c_anneal = zx.extract_circuit(g_anneal.copy()).to_basic_gates()\n",
"c_anneal = zx.basic_optimization(c_anneal)\n",
"print(c_anneal.stats())"
]
},
{
"cell_type": "markdown",
"id": "native-highway",
"metadata": {},
"source": [
"We can do the same with genetic algorithms"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "massive-simon",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Generations: 100%|██████████| 40/40 [00:14<00:00, 2.76it/s]"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Circuit on 5 qubits with 80 gates.\n",
" 18 is the T-count\n",
" 62 Cliffords among which \n",
" 36 2-qubit gates (29 CNOT, 7 other) and\n",
" 15 Hadamard gates.\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"\n"
]
}
],
"source": [
"ga_opt = zx.GeneticOptimizer()\n",
"g_evolve = ga_opt.evolve(g_simp, n_mutants=20, n_generations=40, quiet=False)\n",
"zx.full_reduce(g_evolve)\n",
"c_evolve = zx.extract_circuit(g_evolve.copy()).to_basic_gates()\n",
"c_evolve = zx.basic_optimization(c_evolve)\n",
"print(c_evolve.stats())"
]
},
{
"cell_type": "markdown",
"id": "modified-johns",
"metadata": {},
"source": [
"Typically, this approach works well for small circuits (i.e., < 10 qubits) but it depends on the structure of the circuit. Also, annealing tends to do better than the genetic approach."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "qualified-impact",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"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.5"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
6 changes: 4 additions & 2 deletions pyzx/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# PyZX - Python library for quantum circuit rewriting
# PyZX - Python library for quantum circuit rewriting
# and optimisation using the ZX-calculus
# Copyright (C) 2018 - Aleks Kissinger and John van de Wetering

Expand Down Expand Up @@ -26,6 +26,8 @@
from .extract import *
from .io import *
from .tensor import *
from .local_search.simulated_annealing import anneal
from .local_search.genetic import GeneticOptimizer
from .circuit.qasmparser import qasm
from .circuit.sqasm import sqasm
from . import quantomatic
Expand All @@ -43,7 +45,7 @@
from . import simulate
from . import editor
from . import routing
from . import sparsify
from . import local_search
from .routing.parity_maps import CNOT_tracker

# some common scalars
Expand Down
15 changes: 15 additions & 0 deletions pyzx/local_search/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# PyZX - Python library for quantum circuit rewriting
# and optimization using the ZX-calculus
# Copyright (C) 2021 - Aleks Kissinger and John van de Wetering

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

# http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
Loading

0 comments on commit 8845863

Please sign in to comment.