mirror of https://github.com/Qiskit/qiskit.git
Merge branch 'Dev' into isma/clean-quantum-program
This commit is contained in:
commit
d5a3dfceab
45
README.md
45
README.md
|
@ -12,51 +12,50 @@ Related external projects:
|
|||
|
||||
## Organization
|
||||
|
||||
The *scripts* directory contains Jupyter notebooks showing how to use the
|
||||
The *tutorial* directory contains Jupyter notebooks showing how to use the
|
||||
[Python API](https://github.com/IBM/qiskit-api-py) with
|
||||
[OPENQASM](https://github.com/IBM/qiskit-openqasm).
|
||||
|
||||
There are Jupyter notebooks demonstrating components of
|
||||
the SDK in the *scripts* directory. There are also command line test scripts
|
||||
in the *testscripts* directory. The root directory contains some miscellaneous
|
||||
examples and an index Jupyter notebook.
|
||||
the SDK in the *tutorial* directory, and more python and qasm examples in the *examples* directory. There are also command line test scripts
|
||||
in the *test* directory.
|
||||
|
||||
We want to reorganize the SDK so that it has a comfortable and intuitive
|
||||
interface for developers.
|
||||
Users can construct a *QuantumProgram* to create, modify, compile, and execute a collection of quantum circuits.
|
||||
|
||||
Users can create instances of *QuantumRegister* and *ClassicalRegister*, and
|
||||
use these to construct a *QuantumCircuit*. They can then call methods of these
|
||||
objects to apply gates within the circuit. The *extensions* directory extends
|
||||
these objects as needed to support new gate sets and algorithms. The "cswap"
|
||||
gate in the standard extension shows how to build gates that are sequences of
|
||||
Each *QuantumCircuit* has some set of registers, *QuantumRegister* and *ClassicalRegister*, and methods of these objects are used to apply instructions within the circuit. The *extensions* directory extends
|
||||
the quantum circuit as needed to support new gate sets and algorithms. For example, the "cswap" gate in the standard extension shows how to build gates that are sequences of
|
||||
other unitary gates. The Python file "header.py" shows how we append OPENQASM
|
||||
gate definitions as we import extensions. The *QuantumCircuit* can generate
|
||||
OPENQASM code that can flow through other components in the *qiskit* directory.
|
||||
|
||||
The *qiskit* directory is the main Python module and contains the programming
|
||||
interface objects *QuantumRegister*, *ClassicalRegister*, and *QuantumCircuit*.
|
||||
The directory also contains a *qasm* module for parsing OPENQASM circuits,
|
||||
an *unroll* module to flatten QASM for a target gate basis by expanding
|
||||
interface objects *QuantumProgram*, *QuantumRegister*, *ClassicalRegister*, and *QuantumCircuit*.
|
||||
The directory also contains internal modules: a *qasm* module for parsing OPENQASM circuits,
|
||||
an *unroll* module to "flatten" QASM for a target gate basis by expanding
|
||||
gate subroutines as needed, a *circuit* module for working with circuits as
|
||||
graphs, and a *localize* module for mapping all-to-all circuits to run on
|
||||
graphs, and a *mapper* module for mapping all-to-all circuits to run on
|
||||
devices with fixed couplings.
|
||||
|
||||
Quantum circuits flow through the components as follows. The programming
|
||||
interface is used to generate **OPENQASM** circuits. **OPENQASM** source,
|
||||
as a file or string, is passed into a *Qasm* object, whose *parse* method
|
||||
produces an abstract syntax tree (**AST**) representation. The **AST** is
|
||||
produces an abstract syntax tree (**AST**). The **AST** is
|
||||
passed to an *Unroller* that is attached to an *UnrollerBackend*. There is
|
||||
a *PrinterBackend* for outputting text and a *CircuitBackend* for constructing *Circuit* objects. The *Circuit* object represents an unrolled **OPENQASM**
|
||||
circuit as a directed acyclic graph (**DAG**). The *Circuit* provides methods
|
||||
for representing, transforming, and computing properties of a circuit as a
|
||||
**DAG** and outputting the results again as **OPENQASM**. The whole flow is
|
||||
used by the *localize* module's *swap_mapper* method to insert SWAP gates
|
||||
so a circuit can execute on a device with fixed couplings given by a
|
||||
*CouplingGraph*.
|
||||
used by the *mapper* module to rewrite a circuit to execute on a device
|
||||
with fixed couplings given by a *CouplingGraph*.
|
||||
|
||||
The circuit representations and how they are currently transformed into each other are summarized in ![](images/circuit_representations.png?raw=true).
|
||||
|
||||
The unroller backends and their outputs are summarized in ![](images/unroller_backends.png?raw=true).
|
||||
|
||||
|
||||
## Install
|
||||
|
||||
- Intall Anaconda: https://www.continuum.io/downloads
|
||||
- Install Anaconda: https://www.continuum.io/downloads
|
||||
- Clone the repo:
|
||||
|
||||
```sh
|
||||
|
@ -86,7 +85,7 @@ make run
|
|||
|
||||
## FAQ
|
||||
|
||||
If you upgrade the dependencies and next error happens try with this fix:
|
||||
If you upgrade the dependencies and next error happens try this fix:
|
||||
|
||||
```sh
|
||||
pip install --upgrade IBMQuantumExperience
|
||||
|
@ -98,7 +97,7 @@ curl https://bootstrap.pypa.io/ez_setup.py -o - | python
|
|||
|
||||
## Developer guide
|
||||
|
||||
Please, use [GitHub pull requests](https://help.github.com/articles/using-pull-requests) to send the contributions.
|
||||
Please, use [GitHub pull requests](https://help.github.com/articles/using-pull-requests) to send contributions.
|
||||
|
||||
We use [Pylint](https://www.pylint.org) and [PEP 8](https://www.python.org/dev/peps/pep-0008) style guide.
|
||||
|
||||
|
@ -121,6 +120,6 @@ Note: You can get yout "putYourQExperienceTokenHere" from [IBM Quantum Experienc
|
|||
|
||||
### Commit messages rules
|
||||
|
||||
- It should be formed by a one-line subject, followed by one line of white space. Followed by one or more descriptive paragraphs, each separated by one line of white space. All of them finished by a dot.
|
||||
- It should be formed by a one-line subject, followed by one line of white space. Followed by one or more descriptive paragraphs, each separated by one line of white space. All of them finished by a dot.
|
||||
- If it fixes an issue, it should include a reference to the issue ID in the first line of the commit.
|
||||
- It should provide enough information for a reviewer to understand the changes and their relation to the rest of the code.
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
"""
|
||||
Test script for localization of quantum circuits.
|
||||
Test script for mapping quantum circuits.
|
||||
|
||||
This script takes a QASM file and produces output that shows the
|
||||
process of finding SWAP gates to map the circuit onto the coupling graph.
|
||||
The final output is QASM source for a "localized" version of the input
|
||||
process of mapping the circuit onto the coupling graph.
|
||||
The final output is QASM source for a "mapped" version of the input
|
||||
circuit.
|
||||
|
||||
The coupling graph and target basis are hard-coded into this script.
|
||||
|
@ -106,14 +106,14 @@ def make_unrolled_circuit_from_data(dat, basis):
|
|||
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print("localize.py <qasm>\n")
|
||||
print("mapper.py <qasm>\n")
|
||||
print(" qasm = main circuit")
|
||||
print("")
|
||||
print("Generates a new \"localized\" circuit matching the coupling.")
|
||||
print("Generates a new \"mapped\" circuit matching the coupling.")
|
||||
sys.exit(1)
|
||||
|
||||
# This is the QE basis
|
||||
basis = "u1,u2,u3,cx"
|
||||
basis = "u1,u2,u3,cx,id"
|
||||
|
||||
layout_type = "qe5" # "qe5" or "2x8"
|
||||
|
||||
|
@ -148,7 +148,7 @@ elif layout_type == "2x8":
|
|||
|
||||
# Three', expand swaps into cx gates
|
||||
c_prime = make_unrolled_circuit_from_data(c_prime.qasm(qeflag=True),
|
||||
"cx,u1,u2,u3")
|
||||
"cx,u1,u2,u3,id")
|
||||
|
||||
# Fourth, do direction mapping
|
||||
c_dblp = mapper.direction_mapper(c_prime, coupling, verbose=True)
|
||||
|
@ -156,5 +156,5 @@ print("c_dblp.qasm() = \n%s" % c_dblp.qasm(qeflag=True))
|
|||
|
||||
# Unroll again
|
||||
c_final = make_unrolled_circuit_from_data(c_dblp.qasm(qeflag=True),
|
||||
"cx,u1,u2,u3")
|
||||
"cx,u1,u2,u3,id")
|
||||
print("c_final.qasm() = \n%s" % c_final.qasm(qeflag=True))
|
|
@ -239,7 +239,3 @@ print("factors = %d" % C_directions_unrolled.num_tensor_factors())
|
|||
print("operations:")
|
||||
for key, val in C_directions_unrolled.count_ops().items():
|
||||
print(" %s: %d" % (key, val))
|
||||
|
||||
# TODO: test on examples using simulator
|
||||
# TODO: understand swap_mapper with all-all
|
||||
# TODO: simple unit tests for qasm, mapper, unroller, circuit
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
import sys
|
||||
import os
|
||||
|
||||
# We don't know from where the user is running the example,
|
||||
# so we need a relative position from this file path.
|
||||
# TODO: Relative imports for intra-package imports are highly discouraged.
|
||||
# http://stackoverflow.com/a/7506006
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
|
||||
from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit
|
||||
from qiskit.extensions.standard import h, cx
|
||||
|
||||
q2 = QuantumRegister("q", 2)
|
||||
c2 = ClassicalRegister("c", 2)
|
||||
bell = QuantumCircuit(q2, c2)
|
||||
bell.h(q2[0])
|
||||
bell.cx(q2[0], q2[1])
|
||||
|
||||
measureIZ = QuantumCircuit(q2, c2)
|
||||
measureIZ.measure(q2[0], c2[0])
|
||||
|
||||
c = bell + measureIZ
|
||||
|
||||
print(c.qasm())
|
|
@ -1,16 +0,0 @@
|
|||
import sys
|
||||
import os
|
||||
|
||||
# We don't know from where the user is running the example,
|
||||
# so we need a relative position from this file path.
|
||||
# TODO: Relative imports for intra-package imports are highly discouraged.
|
||||
# http://stackoverflow.com/a/7506006
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
|
||||
from qiskit.qasm import Qasm
|
||||
|
||||
badqasm = """
|
||||
OPENQASM 2.0;
|
||||
qreg Q[5];
|
||||
"""
|
||||
|
||||
ast = Qasm(data=badqasm).parse()
|
|
@ -19,10 +19,8 @@ from qiskit.extensions.standard import barrier, ubase, cxbase
|
|||
from qiskit.extensions.standard import h, cx, u1, u2, u3, iden, x, y, z, s
|
||||
from qiskit.extensions.standard import t, ccx, cswap
|
||||
|
||||
# Issues
|
||||
# .q_if is not implemented, store controls on each gate, two methods
|
||||
|
||||
# Ismael advice - keep it simple
|
||||
# Issues:
|
||||
# .q_if is not implemented
|
||||
|
||||
n = 5
|
||||
q = QuantumRegister("q", n)
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 73 KiB |
|
@ -9,9 +9,9 @@
|
|||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="373.08823mm"
|
||||
height="188.52194mm"
|
||||
viewBox="0 0 1321.9661 667.99114"
|
||||
width="373.08826mm"
|
||||
height="188.52196mm"
|
||||
viewBox="0 0 1321.9662 667.99119"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
|
@ -262,8 +262,8 @@
|
|||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.49497475"
|
||||
inkscape:cx="692.84134"
|
||||
inkscape:cy="446.68561"
|
||||
inkscape:cx="692.84131"
|
||||
inkscape:cy="446.68564"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
|
@ -292,7 +292,7 @@
|
|||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(782.22436,66.629243)">
|
||||
transform="translate(782.22433,66.629243)">
|
||||
<rect
|
||||
style="fill:#bfd6e9;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter4198-1-0-3-3)"
|
||||
id="rect3336-7-6-5-6"
|
||||
|
@ -442,27 +442,37 @@
|
|||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="-573.70044"
|
||||
x="-569.70044"
|
||||
y="395.6506"
|
||||
id="text4210-6"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
x="-573.70044"
|
||||
x="-569.70044"
|
||||
y="395.6506"
|
||||
id="tspan4224-6"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold'">UnitarySimulator</tspan></text>
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold'">SimulatorBackend</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:15px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="-695.38416"
|
||||
style="font-style:normal;font-weight:normal;font-size:15px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="-576.29749"
|
||||
y="567.98627"
|
||||
id="text7822-2"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan7824-0"
|
||||
x="-695.38416"
|
||||
x="-576.29749"
|
||||
y="567.98627"
|
||||
style="font-size:25px">Simulator input data</tspan></text>
|
||||
style="font-size:25px;text-align:center;text-anchor:middle">Simulator input data</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="-576.29749"
|
||||
y="599.23627"
|
||||
style="font-size:25px;text-align:center;text-anchor:middle"
|
||||
id="tspan3534">unroller.backend.circuit</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="-576.29749"
|
||||
y="630.48627"
|
||||
style="font-size:25px;text-align:center;text-anchor:middle"
|
||||
id="tspan3532" /></text>
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.06642962;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Mend-1-6-4)"
|
||||
d="m -568.31169,433.32069 0,95.70907"
|
||||
|
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
@ -23,6 +23,7 @@ Authors: Andrew Cross, Jay M. Gambetta, Ismael Faro
|
|||
# pylint: disable=line-too-long
|
||||
|
||||
import time
|
||||
import random
|
||||
from collections import Counter
|
||||
# use the external IBMQuantumExperience Library
|
||||
from IBMQuantumExperience.IBMQuantumExperience import IBMQuantumExperience
|
||||
|
@ -38,6 +39,10 @@ from . import unroll
|
|||
from . import qasm
|
||||
from . import mapper
|
||||
|
||||
from .unroll import SimulatorBackend
|
||||
from .simulators._unitarysimulator import UnitarySimulator
|
||||
from .simulators._qasmsimulator import QasmSimulator
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
from qiskit.extensions.standard import x, h, cx, s, ry, barrier
|
||||
|
@ -47,8 +52,8 @@ class QuantumProgram(object):
|
|||
""" Quantum Program Class
|
||||
|
||||
Class internal properties """
|
||||
__online_devices = ["qx5q", "qx5qv2","simulator", "online_simulator"]
|
||||
__local_devices = ["unitary_simulator"]
|
||||
__online_devices = ["qx5qv2", "ibmqx2", "ibmqx3", "ibmqx_qasm_simulator", "simulator"]
|
||||
__local_devices = ["local_unitary_simulator", "local_qasm_simulator"]
|
||||
|
||||
__specs = {}
|
||||
__quantum_registers = {}
|
||||
|
@ -168,16 +173,6 @@ class QuantumProgram(object):
|
|||
""" Set the API url """
|
||||
self.set_api(url=url)
|
||||
|
||||
def get_job_list_status(self, jobids):
|
||||
"""Given a list of job ids, return a list of job status.
|
||||
jobids is a list of id strings.
|
||||
api is an IBMQuantumExperience object.
|
||||
"""
|
||||
status_list = []
|
||||
for i in jobids:
|
||||
status_list.append(self.__api.get_job(i)['status'])
|
||||
return status_list
|
||||
|
||||
def load_qasm(self, qasm_file, basis_gates=None):
|
||||
""" Load qasm file
|
||||
qasm_file qasm file name
|
||||
|
@ -219,14 +214,14 @@ class QuantumProgram(object):
|
|||
qasm_circuits.append({'qasm': circuit.qasm()})
|
||||
return qasm_circuits
|
||||
|
||||
def compile(self, circuits, device="simulator", shots=1024, max_credits=3, coupling_map=None):
|
||||
def compile(self, circuits, device="simulator", shots=1024, max_credits=3, basis_gates=None, coupling_map=None):
|
||||
""" Compile unrole the code
|
||||
circuits are circuits to unroll
|
||||
basis_gates are the base gates by default are: u1,u2,u3,cx,id
|
||||
"""
|
||||
qasm_circuits = []
|
||||
for circuit in circuits:
|
||||
qasm_source, circuit_unrolled = self.unroller_code(circuit)
|
||||
qasm_source, circuit_unrolled = self.unroller_code(circuit, basis_gates)
|
||||
if coupling_map:
|
||||
print("pre-mapping properties: %s"
|
||||
% circuit_unrolled.property_summary())
|
||||
|
@ -258,12 +253,8 @@ class QuantumProgram(object):
|
|||
|
||||
def run(self, wait=5, timeout=60):
|
||||
"""Run a program (a pre compiled quantum program).
|
||||
program is a list of quantum_circuits
|
||||
api the api for the device
|
||||
device is a string for real or simulator
|
||||
shots is the number of shots
|
||||
max_credits is the credits of the experiments.
|
||||
basis_gates are the base gates by default are: u1,u2,u3,cx,id
|
||||
wait time to check if the job is Completed.
|
||||
timeout time after that the execution stop
|
||||
"""
|
||||
|
||||
backend = self.__qasm_compile['backend']['name']
|
||||
|
@ -283,7 +274,8 @@ class QuantumProgram(object):
|
|||
if job_result['status'] == 'Error':
|
||||
return job_result
|
||||
else:
|
||||
return {"status": "Error", "result": "Not local simulations"}
|
||||
self.run_local()
|
||||
# return {"status": "Error", "result": "Not local simulations"}
|
||||
|
||||
self.__qasm_compile['compiled_circuits'] = job_result['qasms']
|
||||
self.__qasm_compile['used_credits'] = job_result['usedCredits']
|
||||
|
@ -299,10 +291,35 @@ class QuantumProgram(object):
|
|||
max_credits is the credits of the experiments.
|
||||
basis_gates are the base gates by default are: u1,u2,u3,cx,id
|
||||
"""
|
||||
pass
|
||||
shots = self.__qasm_compile['shots']
|
||||
qasms = self.__qasm_compile['compiled_circuits']
|
||||
|
||||
# /print(qasms)
|
||||
|
||||
outcomes = {'qasms':[]}
|
||||
for qasm in qasms:
|
||||
print('----------------')
|
||||
print(qasm['qasm'])
|
||||
print('----------------')
|
||||
basis = []
|
||||
unroller = unroll.Unroller(qasm['qasm'],SimulatorBackend(basis))
|
||||
print('----%%-----')
|
||||
unroller.backend.set_trace(False)
|
||||
print('-----++-----')
|
||||
unroller.execute()
|
||||
print('------**-----')
|
||||
for i in range(shots):
|
||||
print('.................')
|
||||
b = QasmSimulator(unroller.backend.circuit, random.random()).run()
|
||||
print('.................')
|
||||
print(b)
|
||||
|
||||
# outcomes['qasms'].append(bin(b['result']['classical_state'])[2:].zfill(b['number_of_cbits']))
|
||||
print(outcomes)
|
||||
return outcomes
|
||||
|
||||
def execute(self, circuits, device, shots, coupling_map=None,
|
||||
max_credits=3, basis_gates=None, wait=5, timeout=60):
|
||||
def execute(self, circuits, device, shots=1024,
|
||||
max_credits=3, wait=5, timeout=60, basis_gates=None, coupling_map=None):
|
||||
"""Execute, compile and run a program (array of quantum circuits).
|
||||
program is a list of quantum_circuits
|
||||
api the api for the device
|
||||
|
@ -359,6 +376,16 @@ class QuantumProgram(object):
|
|||
return {"status": "Error", "result": "Time Out"}
|
||||
return job
|
||||
|
||||
def get_job_list_status(self, jobids):
|
||||
"""Given a list of job ids, return a list of job status.
|
||||
jobids is a list of id strings.
|
||||
api is an IBMQuantumExperience object.
|
||||
"""
|
||||
status_list = []
|
||||
for i in jobids:
|
||||
status_list.append(self.__api.get_job(i)['status'])
|
||||
return status_list
|
||||
|
||||
def wait_for_jobs(self, jobids, wait=5, timeout=60):
|
||||
"""Wait until all status results are 'COMPLETED'.
|
||||
jobids is a list of id strings.
|
||||
|
@ -540,6 +567,9 @@ class QuantumProgram(object):
|
|||
else:
|
||||
basicplotter.plot_qsphere(data, circuit_number)
|
||||
|
||||
def get_qasm_image(self,):
|
||||
pass
|
||||
|
||||
def get_data(self, results, i):
|
||||
"""Get the dict of labels and counts from the output of get_job."""
|
||||
return results['qasms'][i]['result']['data']['counts']
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
"""
|
||||
Rotation around the x-axis.
|
||||
"""Rotation around the x-axis.
|
||||
|
||||
Author: Jay using andrew code.
|
||||
Author: Jay Gambetta and Andrew Cross
|
||||
"""
|
||||
from qiskit import QuantumRegister
|
||||
from qiskit import QuantumCircuit
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
"""
|
||||
Rotation around the y-axis.
|
||||
"""Rotation around the y-axis.
|
||||
|
||||
Author: Jay using andrew code.
|
||||
Author: Jay Gambetta and Andrew Cross
|
||||
"""
|
||||
from qiskit import QuantumRegister
|
||||
from qiskit import QuantumCircuit
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
"""
|
||||
Rotation around the z-axis.
|
||||
"""Rotation around the z-axis.
|
||||
|
||||
Author: Jay using andrew code.
|
||||
Author: Jay Gambetta and Andrew Cross
|
||||
"""
|
||||
from qiskit import QuantumRegister
|
||||
from qiskit import QuantumCircuit
|
||||
|
|
|
@ -4,16 +4,17 @@ OPENQASM Lexer.
|
|||
This is a wrapper around the PLY lexer to support the "include" statement
|
||||
by creating a stack of lexers.
|
||||
|
||||
Author: Jim Challenger
|
||||
Authors: Jim Challenger
|
||||
Jesus Perez <jesusper@us.ibm.com>
|
||||
"""
|
||||
|
||||
import os
|
||||
import ply.lex as lex
|
||||
from ._qasmexception import QasmException
|
||||
from . import _node as node
|
||||
|
||||
CORE_LIBS_PATH = os.path.join(os.path.dirname(__file__), 'libs')
|
||||
# TODO: Get dinamically from the folder "qasm/lib"
|
||||
CORE_LIBS = ['qelib1.inc']
|
||||
CORE_LIBS = os.listdir(CORE_LIBS_PATH)
|
||||
|
||||
|
||||
class QasmLexer(object):
|
||||
|
|
|
@ -1 +1 @@
|
|||
from ._unitarysimulator import UnitarySimulator
|
||||
|
||||
|
|
|
@ -0,0 +1,193 @@
|
|||
"""
|
||||
Contains a (slow) python simulator that makes the qasm of the circuit.
|
||||
|
||||
We advise using the c++ simulator or online for larger size systems
|
||||
|
||||
Author: Jay Gambetta
|
||||
|
||||
{'number_of_qubits': 2,
|
||||
'number_of_cbits': 2,
|
||||
'number_of_operations': 2
|
||||
'qubit_order': {('q', 0): 0, ('v', 0): 1}
|
||||
'cbit_order': {('c', 1): 1, ('c', 0): 0},
|
||||
'qasm': [{
|
||||
'type': 'gate',
|
||||
'name': 'U(1.570796326794897,0.000000000000000,3.141592653589793)',
|
||||
'qubit_indices': [0],
|
||||
'gate_size': 1,
|
||||
'matrix': array([[ 0.70710678 +0.00000000e+00j,
|
||||
0.70710678 -8.65956056e-17j],
|
||||
[ 0.70710678 +0.00000000e+00j,
|
||||
-0.70710678 +8.65956056e-17j]])
|
||||
},
|
||||
{
|
||||
'type': 'measure',
|
||||
'cbit_indices': [0],
|
||||
'qubit_indices': [0]
|
||||
}],
|
||||
'result': {
|
||||
'quantum_state': array([ 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]),
|
||||
'classical_state': 0
|
||||
}
|
||||
}
|
||||
"""
|
||||
import numpy as np
|
||||
import random
|
||||
|
||||
|
||||
class QasmSimulator(object):
|
||||
"""
|
||||
Python implementation of a unitary computer simulator.
|
||||
"""
|
||||
|
||||
def __init__(self, circuit, random_seed):
|
||||
self.circuit = circuit
|
||||
self._number_of_qubits = self.circuit['number_of_qubits']
|
||||
self._number_of_cbits = self.circuit['number_of_cbits']
|
||||
self.circuit['result'] = {}
|
||||
self._quantum_state = np.zeros(2**(self._number_of_qubits),
|
||||
dtype=complex)
|
||||
self._quantum_state[0] = 1
|
||||
self._classical_state = 0
|
||||
random.seed(random_seed)
|
||||
self._number_of_operations = self.circuit['number_of_operations']
|
||||
|
||||
def _add_qasm_single(self, gate, qubit):
|
||||
"""Apply the single qubit gate.
|
||||
|
||||
gate is the single qubit gate
|
||||
qubit is the qubit to apply it on counts from 0 and order
|
||||
is q_{n-1} ... otimes q_1 otimes q_0
|
||||
number_of_qubits is the number of qubits in the system
|
||||
returns a complex numpy array
|
||||
"""
|
||||
temp_1 = np.identity(2**(self._number_of_qubits-qubit-1),
|
||||
dtype=complex)
|
||||
temp_2 = np.identity(2**(qubit), dtype=complex)
|
||||
unitaty_add = np.kron(temp_1, np.kron(gate, temp_2))
|
||||
self._quantum_state = np.dot(unitaty_add, self._quantum_state)
|
||||
|
||||
def _add_qasm_two(self, gate, qubit_1, qubit_2):
|
||||
"""Apply the two-qubit gate.
|
||||
|
||||
gate is the two-qubit gate
|
||||
qubit_1 is the first qubit (control) counts from 0
|
||||
qubit_2 is the second qubit (target)
|
||||
number_of_qubits is the number of qubits in the system
|
||||
returns a complex numpy array
|
||||
"""
|
||||
temp_1 = np.kron(np.identity(2**(self._number_of_qubits-2),
|
||||
dtype=complex), gate)
|
||||
unitaty_add = np.identity(2**(self._number_of_qubits), dtype=complex)
|
||||
# print('here !!!!!!!!!!!!!!!')
|
||||
for ii in range(2**self._number_of_qubits):
|
||||
iistring = bin(ii)[2:]
|
||||
bits = list(reversed(iistring.zfill(self._number_of_qubits)))
|
||||
swap_1 = bits[0]
|
||||
swap_2 = bits[1]
|
||||
bits[0] = bits[qubit_1]
|
||||
bits[1] = bits[qubit_2]
|
||||
bits[qubit_1] = swap_1
|
||||
bits[qubit_2] = swap_2
|
||||
iistring = ''.join(reversed(bits))
|
||||
iip = int(iistring, 2)
|
||||
for jj in range(2**self._number_of_qubits):
|
||||
jjstring = bin(jj)[2:]
|
||||
bits = list(reversed(jjstring.zfill(self._number_of_qubits)))
|
||||
swap_1 = bits[0]
|
||||
swap_2 = bits[1]
|
||||
bits[0] = bits[qubit_1]
|
||||
bits[1] = bits[qubit_2]
|
||||
bits[qubit_1] = swap_1
|
||||
bits[qubit_2] = swap_2
|
||||
jjstring = ''.join(reversed(bits))
|
||||
jjp = int(jjstring, 2)
|
||||
unitaty_add[iip, jjp] = temp_1[ii, jj]
|
||||
self._quantum_state = np.dot(unitaty_add, self._quantum_state)
|
||||
# print(self._quantum_state)
|
||||
|
||||
def _add_qasm_decision(self, qubit):
|
||||
"""Apply the measurement/reset qubit gate."""
|
||||
# print(qubit)
|
||||
probability_zero = 0
|
||||
random_number = random.random()
|
||||
for ii in range(2**self._number_of_qubits):
|
||||
iistring = bin(ii)[2:]
|
||||
bits = list(reversed(iistring.zfill(self._number_of_qubits)))
|
||||
if bits[qubit] == '0':
|
||||
probability_zero += np.abs(self._quantum_state[ii])**2
|
||||
# print(probability_zero)
|
||||
if random_number <= probability_zero:
|
||||
outcome = '0'
|
||||
norm = np.sqrt(probability_zero)
|
||||
else:
|
||||
outcome = '1'
|
||||
norm = np.sqrt(1-probability_zero)
|
||||
return (outcome, norm)
|
||||
|
||||
def _add_qasm_measure(self, qubit, cbit):
|
||||
"""Apply the measurement qubit gate."""
|
||||
|
||||
outcome, norm = self._add_qasm_decision(qubit)
|
||||
# print(outcome)
|
||||
# print(norm)
|
||||
for ii in range(2**self._number_of_qubits):
|
||||
# update quantum state
|
||||
iistring = bin(ii)[2:]
|
||||
bits = list(reversed(iistring.zfill(self._number_of_qubits)))
|
||||
if bits[qubit] == outcome:
|
||||
self._quantum_state[ii] = self._quantum_state[ii]/norm
|
||||
else:
|
||||
self._quantum_state[ii] = 0
|
||||
# update classical state
|
||||
temp = bin(self._classical_state)[2:]
|
||||
cbits_string = list(reversed(temp.zfill(self._number_of_cbits)))
|
||||
cbits_string[cbit] = outcome
|
||||
self._classical_state = int(''.join(reversed(cbits_string)), 2)
|
||||
|
||||
def _add_qasm_reset(self, qubit):
|
||||
"""Apply the reset to the qubit.
|
||||
|
||||
I to this by applying a measurment and ignoring the outcome"""
|
||||
"""Apply the measurement qubit gate."""
|
||||
|
||||
outcome, norm = self._add_qasm_decision(qubit)
|
||||
# print(outcome)
|
||||
temp = self._quantum_state
|
||||
for ii in range(2**self._number_of_qubits):
|
||||
# update quantum state
|
||||
iistring = bin(ii)[2:]
|
||||
bits = list(reversed(iistring.zfill(self._number_of_qubits)))
|
||||
if outcome == '0':
|
||||
iip = ii
|
||||
else:
|
||||
bits[qubit] == '0'
|
||||
iip = int(''.join(reversed(bits)), 2)
|
||||
if bits[qubit] == '0':
|
||||
self._quantum_state[iip] = temp[ii]/norm
|
||||
else:
|
||||
self._quantum_state[iip] = 0
|
||||
# print(self._quantum_state)
|
||||
|
||||
def run(self):
|
||||
"""Run."""
|
||||
for j in range(self._number_of_operations):
|
||||
if self.circuit['qasm'][j]['type'] == 'gate':
|
||||
gate = self.circuit['qasm'][j]['matrix']
|
||||
if self.circuit['qasm'][j]['gate_size'] == 1:
|
||||
qubit = self.circuit['qasm'][j]['qubit_indices'][0]
|
||||
self._add_qasm_single(gate, qubit)
|
||||
elif self.circuit['qasm'][j]['gate_size'] == 2:
|
||||
qubit0 = self.circuit['qasm'][j]['qubit_indices'][0]
|
||||
qubit1 = self.circuit['qasm'][j]['qubit_indices'][1]
|
||||
self._add_qasm_two(gate, qubit0, qubit1)
|
||||
elif self.circuit['qasm'][j]['type'] == 'measure':
|
||||
qubit = self.circuit['qasm'][j]['qubit_indices'][0]
|
||||
cbit = self.circuit['qasm'][j]['cbit_indices'][0]
|
||||
self._add_qasm_measure(qubit, cbit)
|
||||
elif self.circuit['qasm'][j]['type'] == 'reset':
|
||||
qubit = self.circuit['qasm'][j]['qubit_indices'][0]
|
||||
self._add_qasm_reset(qubit)
|
||||
self.circuit['result']['quantum_state'] = self._quantum_state
|
||||
self.circuit['result']['classical_state'] = self._classical_state
|
||||
return self.circuit
|
|
@ -0,0 +1,119 @@
|
|||
"""
|
||||
Contains a (slow) python simulator that makes the unitary of the circuit.
|
||||
|
||||
These are simple methods for making common matrices used in quantum computing.
|
||||
|
||||
Author: Jay Gambetta
|
||||
|
||||
circuit =
|
||||
{
|
||||
'number_of_qubits': 2,
|
||||
'number_of_operations': 2
|
||||
'qubit_order': {('q', 0): 0, ('v', 0): 1}
|
||||
'qasm': [{
|
||||
'type': 'gate',
|
||||
'name': 'U(1.570796326794897,0.000000000000000,3.141592653589793)',
|
||||
'qubit_indices': [0],
|
||||
'gate_size': 1,
|
||||
'matrix': array([[ 0.70710678 +0.00000000e+00j,
|
||||
0.70710678 -8.65956056e-17j],
|
||||
[ 0.70710678 +0.00000000e+00j,
|
||||
-0.70710678 +8.65956056e-17j]])
|
||||
}]
|
||||
'result': {
|
||||
unitary: array([[ 0.70710678 +0.00000000e+00j,
|
||||
0.70710678 -8.65956056e-17j],
|
||||
[ 0.70710678 +0.00000000e+00j,
|
||||
-0.70710678 +8.65956056e-17j]])
|
||||
}
|
||||
}
|
||||
"""
|
||||
import numpy as np
|
||||
|
||||
|
||||
class UnitarySimulator(object):
|
||||
"""UnitarySimulator class."""
|
||||
|
||||
def __init__(self, circuit):
|
||||
self.circuit = circuit
|
||||
self._number_of_qubits = self.circuit['number_of_qubits']
|
||||
self.circuit['result'] = {}
|
||||
self._unitary_state = np.identity(2**(self._number_of_qubits),
|
||||
dtype=complex)
|
||||
self._number_of_operations = self.circuit['number_of_operations']
|
||||
# print(self._unitary_state)
|
||||
|
||||
def _add_unitary_single(self, gate, qubit):
|
||||
"""Apply the single qubit gate.
|
||||
|
||||
gate is the single qubit gate
|
||||
qubit is the qubit to apply it on counts from 0 and order
|
||||
is q_{n-1} ... otimes q_1 otimes q_0
|
||||
number_of_qubits is the number of qubits in the system
|
||||
returns a complex numpy array
|
||||
"""
|
||||
temp_1 = np.identity(2**(self._number_of_qubits-qubit-1),
|
||||
dtype=complex)
|
||||
temp_2 = np.identity(2**(qubit), dtype=complex)
|
||||
unitaty_add = np.kron(temp_1, np.kron(gate, temp_2))
|
||||
self._unitary_state = np.dot(unitaty_add, self._unitary_state)
|
||||
|
||||
def _add_unitary_two(self, gate, qubit_1, qubit_2):
|
||||
"""Apply the two-qubit gate.
|
||||
|
||||
gate is the two-qubit gate
|
||||
qubit_1 is the first qubit (control) counts from 0
|
||||
qubit_2 is the second qubit (target)
|
||||
number_of_qubits is the number of qubits in the system
|
||||
returns a complex numpy array
|
||||
"""
|
||||
temp_1 = np.kron(np.identity(2**(self._number_of_qubits-2),
|
||||
dtype=complex), gate)
|
||||
unitaty_add = np.identity(2**(self._number_of_qubits), dtype=complex)
|
||||
for ii in range(2**self._number_of_qubits):
|
||||
iistring = bin(ii)[2:]
|
||||
bits = list(reversed(iistring.zfill(self._number_of_qubits)))
|
||||
# this is reverse order for assignement as list jut put it out
|
||||
# 0001 is 4 qubit int 1 and this becomes [0,0,0,1]
|
||||
# print(bits)
|
||||
swap_1 = bits[0]
|
||||
swap_2 = bits[1]
|
||||
bits[0] = bits[qubit_1]
|
||||
bits[1] = bits[qubit_2]
|
||||
bits[qubit_1] = swap_1
|
||||
bits[qubit_2] = swap_2
|
||||
iistring = ''.join(reversed(bits))
|
||||
iip = int(iistring, 2)
|
||||
# print(iip)
|
||||
for jj in range(2**self._number_of_qubits):
|
||||
jjstring = bin(jj)[2:]
|
||||
bits = list(reversed(jjstring.zfill(self._number_of_qubits)))
|
||||
swap_1 = bits[0]
|
||||
swap_2 = bits[1]
|
||||
bits[0] = bits[qubit_1]
|
||||
bits[1] = bits[qubit_2]
|
||||
bits[qubit_1] = swap_1
|
||||
bits[qubit_2] = swap_2
|
||||
jjstring = ''.join(reversed(bits))
|
||||
jjp = int(jjstring, 2)
|
||||
unitaty_add[iip, jjp] = temp_1[ii, jj]
|
||||
self._unitary_state = np.dot(unitaty_add, self._unitary_state)
|
||||
|
||||
def run(self):
|
||||
"""Apply the single qubit gate."""
|
||||
for j in range(self._number_of_operations):
|
||||
if self.circuit['qasm'][j]['type'] == 'gate':
|
||||
gate = self.circuit['qasm'][j]['matrix']
|
||||
if self.circuit['qasm'][j]['gate_size'] == 1:
|
||||
qubit = self.circuit['qasm'][j]['qubit_indices'][0]
|
||||
self._add_unitary_single(gate, qubit)
|
||||
elif self.circuit['qasm'][j]['gate_size'] == 2:
|
||||
qubit0 = self.circuit['qasm'][j]['qubit_indices'][0]
|
||||
qubit1 = self.circuit['qasm'][j]['qubit_indices'][1]
|
||||
self._add_unitary_two(gate, qubit0, qubit1)
|
||||
elif self.circuit['qasm'][j]['type'] == 'measure':
|
||||
print('Warning have droped measure from unitary simulator')
|
||||
elif self.circuit['qasm'][j]['type'] == 'reset':
|
||||
print('Warning have droped reset from unitary simulator')
|
||||
self.circuit['result']['unitary'] = self._unitary_state
|
||||
return self.circuit
|
|
@ -1,12 +0,0 @@
|
|||
OPENQASM 2.0;
|
||||
include "qelib1.inc";
|
||||
qreg q[1];
|
||||
creg c[2];
|
||||
h q;
|
||||
qreg v[1];
|
||||
h v;
|
||||
|
||||
|
||||
cx q[0],v[0];
|
||||
h v;
|
||||
h q;
|
|
@ -1,13 +0,0 @@
|
|||
"""Quick test program for unitary simulator backend."""
|
||||
import qiskit.unroll as unroll
|
||||
from qiskit.qasm import Qasm
|
||||
from qiskit.simulators import UnitarySimulator
|
||||
from unitary import unitary_simulator
|
||||
basis = [] # empty basis, defaults to U, CX
|
||||
unroller = unroll.Unroller(Qasm(filename="example.qasm").parse(),
|
||||
UnitarySimulator(basis))
|
||||
unroller.backend.set_trace(False) # print calls as they happen
|
||||
unroller.execute() # Here is where simulation happens
|
||||
unitary_gates = unroller.backend.unitary_gates
|
||||
unitary_simulator(unitary_gates)
|
||||
# print(unitary_gates)
|
|
@ -1,73 +0,0 @@
|
|||
"""
|
||||
Quantum tools and common operators.
|
||||
|
||||
These are simple methods for making common matrices used in quantum computing.
|
||||
|
||||
Author: Jay Gambetta
|
||||
"""
|
||||
import numpy as np
|
||||
|
||||
|
||||
def unitary_qi(gate, qubit, number_of_qubits):
|
||||
"""Apply the single qubit gate.
|
||||
|
||||
gate is the single qubit gate
|
||||
qubit is the qubit to apply it on counts from 0 and order
|
||||
is q_{n-1} ... otimes q_1 otimes q_0
|
||||
number_of_qubits is the number of qubits in the system
|
||||
returns a complex numpy array
|
||||
"""
|
||||
return np.kron(np.identity(2**(number_of_qubits-qubit-1), dtype=complex),
|
||||
np.kron(gate, np.identity(2**(qubit), dtype=complex)))
|
||||
|
||||
|
||||
def unitary_qij(gate, qubit_1, qubit_2, number_of_qubits):
|
||||
"""Apply the two-qubit gate.
|
||||
|
||||
gate is the two-qubit gate
|
||||
qubit_1 is the first qubit (control) counts from 0
|
||||
qubit_2 is the second qubit (target)
|
||||
number_of_qubits is the number of qubits in the system
|
||||
returns a complex numpy array
|
||||
"""
|
||||
temp_1 = np.kron(np.identity(2**(number_of_qubits-2), dtype=complex), gate)
|
||||
temp_2 = np.identity(2**(number_of_qubits), dtype=complex)
|
||||
for ii in range(2**number_of_qubits):
|
||||
iistring = bin(ii)[2:]
|
||||
bits = list(iistring.zfill(number_of_qubits))
|
||||
swap_1 = bits[0]
|
||||
swap_2 = bits[1]
|
||||
bits[0] = bits[qubit_1]
|
||||
bits[1] = bits[qubit_2]
|
||||
bits[qubit_1] = swap_1
|
||||
bits[qubit_2] = swap_2
|
||||
iistring = ''.join(bits)
|
||||
iip = int(iistring, 2)
|
||||
for jj in range(2**number_of_qubits):
|
||||
jjstring = bin(jj)[2:]
|
||||
bits = list(jjstring.zfill(number_of_qubits))
|
||||
swap_1 = bits[0]
|
||||
swap_2 = bits[1]
|
||||
bits[0] = bits[qubit_1]
|
||||
bits[1] = bits[qubit_2]
|
||||
bits[qubit_1] = swap_1
|
||||
bits[qubit_2] = swap_2
|
||||
jjstring = ''.join(bits)
|
||||
jjp = int(jjstring, 2)
|
||||
temp_2[iip, jjp] = temp_1[ii, jj]
|
||||
return temp_2
|
||||
|
||||
|
||||
def unitary_simulator(unitary_gates):
|
||||
number_of_qubits = unitary_gates['number_of_qubits']
|
||||
number_of_gates = unitary_gates['number_of_gates']
|
||||
unitary_state = np.identity(2**(number_of_qubits))
|
||||
for key in sorted(unitary_gates['gates'].keys()):
|
||||
gate = unitary_gates['gates'][key]['matrix']
|
||||
if unitary_gates['gates'][key]['qubits'] == 1:
|
||||
unitary_state = unitary_qi(gate, unitary_gates['gates'][key]
|
||||
['elements'][0], number_of_qubits) * unitary_state
|
||||
elif unitary_gates['gates'][key]['qubits'] == 2:
|
||||
unitary_state = unitary_qij(gate, unitary_gates['gates'][key]['elements'][0],
|
||||
unitary_gates['gates'][key]['elements'][1], number_of_qubits) * unitary_state
|
||||
print(unitary_state)
|
|
@ -4,3 +4,4 @@ from ._oneregisterbackend import OneRegisterBackend
|
|||
from ._printerbackend import PrinterBackend
|
||||
from ._unrollerbackend import UnrollerBackend
|
||||
from ._backendexception import BackendException
|
||||
from ._simulatorbackend import SimulatorBackend
|
||||
|
|
|
@ -1,37 +1,49 @@
|
|||
"""
|
||||
Backend for the unroller that composes unitary matrices to simulate circuit.
|
||||
"""Backend for the unroller that composes unitary matrices to simulate circuit.
|
||||
|
||||
Author: Andrew Cross and Jay Gambetta
|
||||
Author: Jay Gambetta and Andrew Cross
|
||||
|
||||
{'number_of_qubits': 2,
|
||||
'number_of_cbits': 2,
|
||||
'number_of_operations': 2
|
||||
'qubit_order': {('q', 0): 0, ('v', 0): 1}
|
||||
'cbit_order': {('c', 1): 1, ('c', 0): 0},
|
||||
'qasm': [{
|
||||
'type': 'gate',
|
||||
'name': 'U(1.570796326794897,0.000000000000000,3.141592653589793)',
|
||||
'qubit_indices': [0],
|
||||
'gate_size': 1,
|
||||
'matrix': array([[ 0.70710678 +0.00000000e+00j,
|
||||
0.70710678 -8.65956056e-17j],
|
||||
[ 0.70710678 +0.00000000e+00j,
|
||||
-0.70710678 +8.65956056e-17j]])
|
||||
},
|
||||
{
|
||||
'type': 'measure',
|
||||
'cbit_indices': [0],
|
||||
'qubit_indices': [0]
|
||||
}],
|
||||
}
|
||||
"""
|
||||
import numpy as np
|
||||
from qiskit.unroll import BackendException
|
||||
from qiskit.unroll import UnrollerBackend
|
||||
|
||||
# Jay, attach the backend to the unroller and run it:
|
||||
# Take a look at ~/test/testsim.py
|
||||
# I could not test it because QuantumProgram is hosed.
|
||||
|
||||
# You probably want "getters" to give back the final unitary matrix
|
||||
# or print it in some nice way (not implemented):
|
||||
#
|
||||
# print(unroller.backend.get_unitary_matrix())
|
||||
class SimulatorBackend(UnrollerBackend):
|
||||
"""Backend for the unroller that composes unitary matrices."""
|
||||
|
||||
|
||||
class UnitarySimulator(UnrollerBackend):
|
||||
""" Backend for the unroller that composes unitary matrices.
|
||||
|
||||
"""
|
||||
def __init__(self, basis=None):
|
||||
"""Setup this backend.
|
||||
|
||||
basis is a list of operation name strings.
|
||||
"""
|
||||
self.unitary_gates = {}
|
||||
self.unitary_gates['gates'] = {}
|
||||
self.unitaries = {}
|
||||
self.number_of_qubits = 0
|
||||
self.qubit_order = {}
|
||||
self.gate_order = 0
|
||||
self.circuit = {}
|
||||
self.circuit['qasm'] = []
|
||||
self._number_of_qubits = 0
|
||||
self._number_of_cbits = 0
|
||||
self._qubit_order = {}
|
||||
self._cbit_order = {}
|
||||
self._operation_order = 0
|
||||
self.prec = 15
|
||||
self.creg = None
|
||||
self.cval = None
|
||||
|
@ -49,10 +61,6 @@ class UnitarySimulator(UnrollerBackend):
|
|||
"""Set trace to True to enable."""
|
||||
self.trace = trace
|
||||
|
||||
def get_unitary_gates(self):
|
||||
"""reteurns the dictionary of unitary gates."""
|
||||
return self.unitary_gates
|
||||
|
||||
def set_basis(self, basis):
|
||||
"""Declare the set of user-defined gates to emit.
|
||||
|
||||
|
@ -84,13 +92,14 @@ class UnitarySimulator(UnrollerBackend):
|
|||
assert size >= 0, "invalid qreg size"
|
||||
|
||||
for j in range(size):
|
||||
self.qubit_order[(name, j)] = self.number_of_qubits + j
|
||||
self.number_of_qubits += size
|
||||
self._qubit_order[(name, j)] = self._number_of_qubits + j
|
||||
self._number_of_qubits += size
|
||||
# print(self.qubit_order)
|
||||
self.unitary_gates['number_of_qubits'] = self.number_of_qubits
|
||||
self.circuit['number_of_qubits'] = self._number_of_qubits
|
||||
self.circuit['qubit_order'] = self._qubit_order
|
||||
if self.trace:
|
||||
print("added %d qubits from qreg %s giving a total of %d qubits" %
|
||||
(size, name, self.number_of_qubits))
|
||||
(size, name, self._number_of_qubits))
|
||||
|
||||
def new_creg(self, name, size):
|
||||
"""Create a new classical register.
|
||||
|
@ -98,7 +107,16 @@ class UnitarySimulator(UnrollerBackend):
|
|||
name = name of the register
|
||||
sz = size of the register
|
||||
"""
|
||||
pass
|
||||
assert size >= 0, "invalid creg size"
|
||||
|
||||
for j in range(size):
|
||||
self._cbit_order[(name, j)] = self._number_of_cbits + j
|
||||
self._number_of_cbits += size
|
||||
self.circuit['number_of_cbits'] = self._number_of_cbits
|
||||
self.circuit['cbit_order'] = self._cbit_order
|
||||
if self.trace:
|
||||
print("added %d cbits from creg %s giving a total of %d qubits" %
|
||||
(size, name, self._number_of_cbits))
|
||||
|
||||
def define_gate(self, name, gatedata):
|
||||
"""Define a new quantum gate.
|
||||
|
@ -128,18 +146,23 @@ class UnitarySimulator(UnrollerBackend):
|
|||
qubit[1]))
|
||||
if self.creg is not None:
|
||||
raise BackendException("UnitarySimulator does not support if")
|
||||
element = self.qubit_order.get(qubit)
|
||||
self.gate_order +=1
|
||||
gate = np.array([[np.cos(arg[0]/2.0), -np.exp(1j*arg[2])*np.sin(arg[0]/2.0)], [np.exp(1j*arg[1])*np.sin(arg[0]/2.0), np.exp(1j*arg[1])*np.exp(1j*arg[2])*np.cos(arg[0]/2.0)]])
|
||||
self.unitary_gates['number_of_gates'] = self.gate_order
|
||||
self.unitary_gates['gates'][self.gate_order] = {
|
||||
'qubits': 1,
|
||||
qubit_indices = [self._qubit_order.get(qubit)]
|
||||
self._operation_order += 1
|
||||
# print(np.exp(1j*arg[2])*np.sin(arg[0]/2.0))
|
||||
gate = np.array([[np.cos(arg[0]/2.0),
|
||||
-np.exp(1j*arg[2])*np.sin(arg[0]/2.0)],
|
||||
[np.exp(1j*arg[1])*np.sin(arg[0]/2.0),
|
||||
np.exp(1j*arg[1]+1j*arg[2])*np.cos(arg[0]/2.0)]])
|
||||
self.circuit['number_of_operations'] = self._operation_order
|
||||
self.circuit['qasm'].append({
|
||||
'type': 'gate',
|
||||
'gate_size': 1,
|
||||
'matrix': gate,
|
||||
'name' : "U(%s,%s,%s)" % (self._fs(arg[0]),
|
||||
self._fs(arg[1]),
|
||||
self._fs(arg[2])),
|
||||
'elements': [element]
|
||||
}
|
||||
'name': "U(%s,%s,%s)" % (self._fs(arg[0]),
|
||||
self._fs(arg[1]),
|
||||
self._fs(arg[2])),
|
||||
'qubit_indices': qubit_indices
|
||||
})
|
||||
|
||||
# print(self.unitary_gates)
|
||||
|
||||
|
@ -149,7 +172,6 @@ class UnitarySimulator(UnrollerBackend):
|
|||
qubit0 is (regname,idx) tuple for the control qubit.
|
||||
qubit1 is (regname,idx) tuple for the target qubit.
|
||||
"""
|
||||
|
||||
if self.listen:
|
||||
if "CX" not in self.basis:
|
||||
self.basis.append("CX")
|
||||
|
@ -160,26 +182,35 @@ class UnitarySimulator(UnrollerBackend):
|
|||
qubit1[0], qubit1[1]))
|
||||
if self.creg is not None:
|
||||
raise BackendException("UnitarySimulator does not support if")
|
||||
element = [self.qubit_order.get(qubit0),
|
||||
self.qubit_order.get(qubit1)]
|
||||
self.gate_order +=1
|
||||
cx = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1],
|
||||
[0, 0, 1, 0]])
|
||||
self.unitary_gates['number_of_gates'] = self.gate_order
|
||||
self.unitary_gates['gates'][self.gate_order] = {
|
||||
'qubits': 2,
|
||||
qubit_indices = [self._qubit_order.get(qubit0),
|
||||
self._qubit_order.get(qubit1)]
|
||||
self._operation_order += 1
|
||||
cx = np.array([[1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0],
|
||||
[0, 1, 0, 0]])
|
||||
self.circuit['number_of_operations'] = self._operation_order
|
||||
self.circuit['qasm'].append({
|
||||
'type': 'gate',
|
||||
'gate_size': 2,
|
||||
'matrix': cx,
|
||||
'name': 'CX',
|
||||
'elements': element,
|
||||
}
|
||||
'qubit_indices': qubit_indices,
|
||||
})
|
||||
|
||||
def measure(self, qubit, bit):
|
||||
def measure(self, qubit, cbit):
|
||||
"""Measurement operation.
|
||||
|
||||
qubit is (regname, idx) tuple for the input qubit.
|
||||
bit is (regname, idx) tuple for the output bit.
|
||||
"""
|
||||
raise BackendException("UnitarySimulator does not support measurement")
|
||||
self._operation_order += 1
|
||||
self.circuit['number_of_operations'] = self._operation_order
|
||||
qubit_indices = [self._qubit_order.get(qubit)]
|
||||
cbit_indices = [self._cbit_order.get(cbit)]
|
||||
self.circuit['qasm'].append({
|
||||
'type': 'measure',
|
||||
'qubit_indices': qubit_indices,
|
||||
'cbit_indices': cbit_indices
|
||||
})
|
||||
|
||||
def barrier(self, qubitlists):
|
||||
"""Barrier instruction.
|
||||
|
@ -193,7 +224,13 @@ class UnitarySimulator(UnrollerBackend):
|
|||
|
||||
qubit is a (regname, idx) tuple.
|
||||
"""
|
||||
raise BackendException("UnitarySimulator does not support reset")
|
||||
self._operation_order += 1
|
||||
self.circuit['number_of_operations'] = self._operation_order
|
||||
qubit_indices = [self._qubit_order.get(qubit)]
|
||||
self.circuit['qasm'].append({
|
||||
'type': 'reset',
|
||||
'qubit_indices': qubit_indices,
|
||||
})
|
||||
|
||||
def set_condition(self, creg, cval):
|
||||
"""Attach a current condition.
|
|
@ -0,0 +1,19 @@
|
|||
OPENQASM 2.0;
|
||||
include "qelib1.inc";
|
||||
qreg q[1];
|
||||
creg c[3];
|
||||
h q[0];
|
||||
qreg v[2];
|
||||
h v[1];
|
||||
|
||||
|
||||
cx q[0],v[0];
|
||||
//cx q[0],v[1];
|
||||
// h v;
|
||||
//h q;
|
||||
|
||||
reset v[1];
|
||||
|
||||
measure q[0] -> c[0];
|
||||
measure v[0] -> c[1];
|
||||
measure v[1] -> c[2];
|
15
test/test.py
15
test/test.py
|
@ -339,6 +339,21 @@ class TestQISKit(unittest.TestCase):
|
|||
|
||||
def test_last(self):
|
||||
QP_program = QuantumProgram(specs=QPS_SPECS)
|
||||
qc, qr, cr = QP_program.quantum_elements()
|
||||
qc2 = QP_program.create_circuit("qc2", ["qname"], ["cname"])
|
||||
qc3 = QP_program.create_circuit("qc3", ["qname"], ["cname"])
|
||||
qc2.h(qr[0])
|
||||
qc3.h(qr[0])
|
||||
circuits = [qc2, qc3]
|
||||
|
||||
device = 'local_qasm_simulator' # the device to run on
|
||||
shots = 1024 # the number of shots in the experiment.
|
||||
credits = 3
|
||||
coupling_map = None
|
||||
|
||||
result = QP_program.execute(circuits, device, shots)
|
||||
self.assertEqual(result['status'], 'COMPLETED')
|
||||
|
||||
# QP_program.plotter()
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
"""Quick test program for unitary simulator backend.
|
||||
|
||||
Author: Jay Gambetta
|
||||
"""
|
||||
import qiskit.unroll as unroll
|
||||
from qiskit.qasm import Qasm
|
||||
from qiskit.unroll import SimulatorBackend
|
||||
from qiskit.simulators._unitarysimulator import UnitarySimulator
|
||||
from qiskit.simulators._qasmsimulator import QasmSimulator
|
||||
import random
|
||||
from collections import Counter
|
||||
|
||||
basis = [] # empty basis, defaults to U, CX
|
||||
unroller = unroll.Unroller(Qasm(filename="example.qasm").parse(),
|
||||
SimulatorBackend(basis))
|
||||
unroller.backend.set_trace(False) # print calls as they happen
|
||||
unroller.execute() # Here is where simulation happens
|
||||
|
||||
|
||||
print('using the unirary simulator')
|
||||
a = UnitarySimulator(unroller.backend.circuit).run()
|
||||
print('\n\n Unitary = ')
|
||||
print(a['result']['unitary'])
|
||||
|
||||
print('\n\nusing the qasm simulator')
|
||||
shots = 1024
|
||||
outcomes = []
|
||||
for i in range(shots):
|
||||
# running the quantum_circuit
|
||||
b = QasmSimulator(unroller.backend.circuit, random.random()).run()
|
||||
#print(b['result']['quantum_state'])
|
||||
#print(b['result']['classical_state'])
|
||||
outcomes.append(bin(b['result']['classical_state'])[2:].zfill(b['number_of_cbits']))
|
||||
|
||||
print('\n\n outcomes = ')
|
||||
print(dict(Counter(outcomes)))
|
|
@ -19,7 +19,7 @@
|
|||
"\n",
|
||||
"***\n",
|
||||
"### Contributors\n",
|
||||
"Jay M. Gambetta, Andrew Cross, Antonio Córcoles, Andreas Fuhrer"
|
||||
"Jay M. Gambetta, Antonio Córcoles, Andrew Cross, Ismael Faro, Andreas Fuhrer "
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -44,7 +44,11 @@
|
|||
"## Introducing the tools\n",
|
||||
"\n",
|
||||
"These notebooks give an introduction to using the QISKit tools\n",
|
||||
"* [Getting Started with the Quantum Experience Web API](sections/getting_started_with_the_qx_api.ipynb) shows how to use the API to run your own quantum program on the QX. "
|
||||
"* [Getting Started with QISKit SDK, Tutorial for Developers](sections/tutorial4developer.ipynb) shows how to use the the QISKit SDK tools. \n",
|
||||
"* Running the Local simulator \n",
|
||||
"* Running on a real chip\n",
|
||||
"* load/save a quantum program\n",
|
||||
"* Visualizing a quanutm state"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -56,9 +60,7 @@
|
|||
"The next set of notebooks show how you explore some simple concepts of quantum information science. Currently we have:\n",
|
||||
"\n",
|
||||
"* [Superposition and entanglement](sections/superposition_and_entanglement.ipynb) - illustrates how to make simple quantum states on one and two qubits and shows concepts such as a quantum superpositions and entanglement. \n",
|
||||
"* [Single qubit states: amplitude and phase](scripts/single_qubit_states_amplitude_and_phase.ipynb) illustrates more complicated single qubit states. \n",
|
||||
"* [Superposition and entanglement](sections/superposition_and_entanglement.ipynb) - illustrates how to make simple quantum states on one and two qubits and shows concepts such as a quantum superpositions and entanglement. \n",
|
||||
"* [Single qubit states: amplitude and phase](scripts/single_qubit_states_amplitude_and_phase.ipynb) TODO WITH JAY\n",
|
||||
"* [Single qubit states: amplitude and phase](scripts/single_qubit_states_amplitude_and_phase.ipynb) illustrates more complicated single qubit states. \n",
|
||||
"* [Entanglement revisited](scripts/entanglement_revisited.ipynb) - illustrates the CHSH inequality and extensions for three qubits (Mermin). \n",
|
||||
"* Quantum sphere TODO WITH JAY\n",
|
||||
"* Quantum teleportation TODO WITH JAY\n",
|
||||
|
|
|
@ -1,95 +0,0 @@
|
|||
// Quantum Experience (QE) Standard Header
|
||||
// file: qelib1.inc
|
||||
|
||||
// --- QE Hardware primitives ---
|
||||
|
||||
// 3-parameter 2-pulse single qubit gate
|
||||
gate u3(theta,phi,lambda) q { U(theta,phi,lambda) q; }
|
||||
// 2-parameter 1-pulse single qubit gate
|
||||
gate u2(phi,lambda) q { U(pi/2,phi,lambda) q; }
|
||||
// 1-parameter 0-pulse single qubit gate
|
||||
gate u1(lambda) q { U(0,0,lambda) q; }
|
||||
// controlled-NOT
|
||||
gate cx c,t { CX c,t; }
|
||||
// idle gate (identity)
|
||||
gate id a { U(0,0,0) a; }
|
||||
|
||||
// --- QE Standard Gates ---
|
||||
|
||||
// Pauli gate: bit-flip
|
||||
gate x a { u3(pi,0,pi) a; }
|
||||
// Pauli gate: bit and phase flip
|
||||
gate y a { u3(pi,pi/2,pi/2) a; }
|
||||
// Pauli gate: phase flip
|
||||
gate z a { u1(pi) a; }
|
||||
// Clifford gate: Hadamard
|
||||
gate h a { u2(0,pi) a; }
|
||||
// Clifford gate: sqrt(Z) phase gate
|
||||
gate s a { u1(pi/2) a; }
|
||||
// Clifford gate: conjugate of sqrt(Z)
|
||||
gate sdg a { u1(-pi/2) a; }
|
||||
// C3 gate: sqrt(S) phase gate
|
||||
gate t a { u1(pi/4) a; }
|
||||
// C3 gate: conjugate of sqrt(S)
|
||||
gate tdg a { u1(-pi/4) a; }
|
||||
|
||||
// --- Standard rotations ---
|
||||
// Rotation around X-axis
|
||||
gate rx(theta) a { u3(theta, -pi/2,pi/2) a; }
|
||||
// rotation around Y-axis
|
||||
gate ry(theta) a { u3(theta,0,0) a; }
|
||||
// rotation around Z axis
|
||||
gate rz(phi) a { u1(phi) a; }
|
||||
|
||||
// --- QE Standard User-Defined Gates ---
|
||||
|
||||
// controlled-Phase
|
||||
gate cz a,b { h b; cx a,b; h b; }
|
||||
// controlled-Y
|
||||
gate cy a,b { sdg b; cx a,b; s b; }
|
||||
// controlled-H
|
||||
gate ch a,b {
|
||||
h b; sdg b;
|
||||
cx a,b;
|
||||
h b; t b;
|
||||
cx a,b;
|
||||
t b; h b; s b; x b; s a;
|
||||
}
|
||||
// C3 gate: Toffoli
|
||||
gate ccx a,b,c
|
||||
{
|
||||
h c;
|
||||
cx b,c; tdg c;
|
||||
cx a,c; t c;
|
||||
cx b,c; tdg c;
|
||||
cx a,c; t b; t c; h c;
|
||||
cx a,b; t a; tdg b;
|
||||
cx a,b;
|
||||
}
|
||||
// controlled rz rotation
|
||||
gate crz(lambda) a,b
|
||||
{
|
||||
u1(lambda/2) b;
|
||||
cx a,b;
|
||||
u1(-lambda/2) b;
|
||||
cx a,b;
|
||||
}
|
||||
// controlled phase rotation
|
||||
gate cu1(lambda) a,b
|
||||
{
|
||||
u1(lambda/2) a;
|
||||
cx a,b;
|
||||
u1(-lambda/2) b;
|
||||
cx a,b;
|
||||
u1(lambda/2) b;
|
||||
}
|
||||
// controlled-U
|
||||
gate cu3(theta,phi,lambda) c, t
|
||||
{
|
||||
// implements controlled-U(theta,phi,lambda) with target t and control c
|
||||
u1((lambda-phi)/2) t;
|
||||
cx c,t;
|
||||
u3(-theta/2,0,-(phi+lambda)/2) t;
|
||||
cx c,t;
|
||||
u3(theta/2,phi,0) t;
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,516 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"<img src=\"../images/QISKit-c.gif\" alt=\"Note: In order for images to show up in this jupyter notebook you need to select File => Trusted Notebook\" width=\"250 px\" align=\"left\">"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## _*Tutorial for Developers*_ \n",
|
||||
"\n",
|
||||
"For more information about how to use the Quantum Experience consult the [Quantum Experience tutorials](https://quantumexperience.ng.bluemix.net/qstage/#/tutorial?sectionId=c59b3710b928891a1420190148a72cce&pageIndex=0) or check-out the [community](https://quantumexperience.ng.bluemix.net/qstage/#/community).\n",
|
||||
"\n",
|
||||
"***\n",
|
||||
"### Contributors\n",
|
||||
"Ismael Faro, Jay M. Gambetta"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Quantum QISKit SDK tutorial\n",
|
||||
"\n",
|
||||
"This tutorial focus is to explain how use the QISKit SDK, from a developer point of view. We review how install, and start to use the SDK tools.\n",
|
||||
"\n",
|
||||
"QISKIt is a Python software development kit (SDK), that you can use to create your Quantum programs, based in circuits over [OpenQASM 2.0](https://github.com/IBM/qiskit-openqasm) Specs, compile and execute it in several Backends (Real Chips, Simulators online and Simulators in local). For the online Backend QISKit use our [python API connector](https://github.com/IBM/qiskit-api-py) to the [IBM Quantum Experience API project (http://quantumexperience.ng.bluemix.net/).\n",
|
||||
"\n",
|
||||
"We have other tutorials that introduce you to more complex concepts directly related with the Quantum.\n",
|
||||
"\n",
|
||||
"more examples:\n",
|
||||
"[superposition and entanglement](superposition_and_entanglement.ipynb) we introduced you to the concept of entanglement.\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Install QISKit\n",
|
||||
"\n",
|
||||
"the most easy way to install QISKit is using Anaconda python distribution.\n",
|
||||
"\n",
|
||||
"- Install Anaconda: https://www.continuum.io/downloads\n",
|
||||
"\n",
|
||||
"After that you need to install your QISKit from the git repository\n",
|
||||
"\n",
|
||||
"- Clone the repo:\n",
|
||||
"\n",
|
||||
"```sh\n",
|
||||
"git clone https://github.ibm.com/IBMQuantum/qiskit-sdk-py-dev\n",
|
||||
"cd qiskit-sdk-py-dev\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"- Create the environment with the dependencies:\n",
|
||||
"\n",
|
||||
"```sh\n",
|
||||
"make env\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"## Use\n",
|
||||
"\n",
|
||||
"You can use the examples in an easy way with Jupyter or Python\n",
|
||||
"\n",
|
||||
"Add your API token to the file \"Qconfig.py\" (get it from [IBM Quantum Experience](https://quantumexperience.ng.bluemix.net) > Account):\n",
|
||||
"\n",
|
||||
"```sh\n",
|
||||
"cp tutorial/Qconfig.py.default Qconfig.py\n",
|
||||
"```\n",
|
||||
"Run Jupyter notebook.\n",
|
||||
"- Run it:\n",
|
||||
"\n",
|
||||
"```sh\n",
|
||||
"make run\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Basic Concept\n",
|
||||
"\n",
|
||||
"### Create a Program\n",
|
||||
"\n",
|
||||
"Firts you need to import the QuantumProgram from QISKit"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import sys\n",
|
||||
"sys.path.append(\"../../\") # solve the relative dependencies if you clone QISKit from the Git repo and use like a global.\n",
|
||||
"\n",
|
||||
"from qiskit import QuantumProgram\n",
|
||||
"import Qconfig"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The basic elements that you need to create your first program are, the QuantumProgram, one Circuit, one Quantum Register and One Classical Register."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Creating Programs\n",
|
||||
"# create your first QuantumProgram object instance.\n",
|
||||
"Q_program = QuantumProgram()\n",
|
||||
"\n",
|
||||
"# Creating Registers\n",
|
||||
"# create your first Quantum Register called \"qr\" with 2 Qbit \n",
|
||||
"qr = Q_program.create_quantum_registers(\"qr\", 2)\n",
|
||||
"# create your first Classical Register called \"cr\" with 2 bit\n",
|
||||
"cr = Q_program.create_classical_registers(\"cr\", 2)\n",
|
||||
"\n",
|
||||
"# Creating Circuits\n",
|
||||
"# create your first Quantum Circuit called \"qc\" related with your Quantum Register \"qr\"\n",
|
||||
"# and your Classical Register \"cr\"\n",
|
||||
"qc = Q_program.create_circuit(\"qc\", [\"qr\"], [\"cr\"])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"As another option to create your QuantumProgram instance you can define a Dictionary with all the component of your program."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"Q_SPECS = {\n",
|
||||
" \"name\": \"Program-tutorial\",\n",
|
||||
" \"circuits\": [{\n",
|
||||
" \"name\": \"Circuit\",\n",
|
||||
" \"quantum_registers\": [{\n",
|
||||
" \"name\":\"qr\",\n",
|
||||
" \"size\": 4\n",
|
||||
" }],\n",
|
||||
" \"classical_registers\": [{\n",
|
||||
" \"name\":\"cr\",\n",
|
||||
" \"size\": 4\n",
|
||||
" }]}],\n",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"One Program must to have a name, and one circuits array, any circuit must have a name and it can have several Quantum registers and several Classical Registers. Every register needs to have a name and the number of the elements (qubits or bits).\n",
|
||||
"\n",
|
||||
"After that, you can use this dictionary definition like the specs of one QuantumProgram object to initialize it."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"new_Q_program = QuantumProgram(specs=Q_SPECS)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"You can get every component from your new_Q_program to use."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"#get the components.\n",
|
||||
"\n",
|
||||
"#get the circuit by Name\n",
|
||||
"circuit = new_Q_program.circuit(\"Circuit\")\n",
|
||||
"\n",
|
||||
"#get the Quantum Register by Name\n",
|
||||
"quantum_r = new_Q_program.quantum_registers(\"qr\")\n",
|
||||
"\n",
|
||||
"#get the Quantum Register by Name\n",
|
||||
"classical_r = new_Q_program.classical_registers('cr')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"source": [
|
||||
"### add gates to your circuit\n",
|
||||
"After you create the circuit with its registers you can add gates to manipulate the registers. The next is the example of the all the gates that you can use.\n",
|
||||
"\n",
|
||||
"You can find extensive information about these gates and how use it into our [Quantum Experience User Guide](https://quantumexperience.ng.bluemix.net/qstage/#/tutorial?sectionId=71972f437b08e12d1f465a8857f4514c&pageIndex=2) "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# H (Hadamard) gate to the Qbit 0 in the Quantum Register \"qr\" \n",
|
||||
"circuit.h(quantum_r[0])\n",
|
||||
"\n",
|
||||
"# Pauli X gate to the Qbit 1 in the Quantum Register \"qr\" \n",
|
||||
"circuit.x(quantum_r[1])\n",
|
||||
"\n",
|
||||
"# Pauli Y gate to the Qbit 2 in the Quantum Register \"qr\" \n",
|
||||
"circuit.y(quantum_r[2])\n",
|
||||
"\n",
|
||||
"# Pauli Z gate to the Qbit 3 in the Quantum Register \"qr\" \n",
|
||||
"circuit.z(quantum_r[3])\n",
|
||||
"\n",
|
||||
"# Cnot (Controlled-NOT)gate from Qbit 0 to the Qbit 2\n",
|
||||
"circuit.cx(quantum_r[0], quantum_r[2])\n",
|
||||
"\n",
|
||||
"# add a barrier to your circuit\n",
|
||||
"circuit.barrier()\n",
|
||||
"\n",
|
||||
"# first physical gate: u1(lambda) to Qbit 0\n",
|
||||
"circuit.u1(0.3, quantum_r[0])\n",
|
||||
"\n",
|
||||
"# second physical gate: u2(phi,lambda) to Qbit 1\n",
|
||||
"circuit.u2(0.3, 0.2, quantum_r[1])\n",
|
||||
"\n",
|
||||
"# second physical gate: u3(theta,phi,lambda) to Qbit 2\n",
|
||||
"circuit.u3(0.3, 0.2, 0.1, quantum_r[2])\n",
|
||||
"\n",
|
||||
"# S Phase gate to Qbit 0\n",
|
||||
"circuit.s(quantum_r[0])\n",
|
||||
"\n",
|
||||
"# T Phase gate to Qbit 1\n",
|
||||
"circuit.t(quantum_r[1])\n",
|
||||
"\n",
|
||||
"# identity gate to Qbit 1\n",
|
||||
"circuit.iden(quantum_r[1])\n",
|
||||
"\n",
|
||||
"# Classical if, from Qbit2 gate Z to classical bit 1\n",
|
||||
"# circuit.z(quantum_r[2]).c_if(classical_r, 1)\n",
|
||||
"\n",
|
||||
"# measure gate from the Qbit 0 to Classical bit 0\n",
|
||||
"circuit.measure(quantum_r[0], classical_r[0])\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### extract QASM\n",
|
||||
"\n",
|
||||
"You can obtain a QASM representation of your code."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# QASM from a circuit\n",
|
||||
"\n",
|
||||
"QASM_source = circuit.qasm()\n",
|
||||
"\n",
|
||||
"print (QASM_source)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Qasm from a program\n",
|
||||
"\n",
|
||||
"QASM_source = new_Q_program.program_to_text()\n",
|
||||
"\n",
|
||||
"print(QASM_source)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"source": [
|
||||
"Note: you can appreciate that the both codes don't have the same notation, the second one return a conversion from every H, X, Y, Z gate the u1, u2 and u3 representation."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"source": [
|
||||
"### Compile & run or Execute"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"device = 'simulator' #Backend where execute your program, in this case it is the online simulator\n",
|
||||
"circuits = [circuit] #Group of circuits to exec\n",
|
||||
"\n",
|
||||
"Q_program.set_api(Qconfig.APItoken, Qconfig.config[\"url\"]) #set the APIToken and API url"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"Q_program.compile(circuits, device) #Compile your program\n",
|
||||
"\n",
|
||||
"result = Q_program.run(wait=2, timeout=240) #Run your program in the device and check the execution result every 2 seconds \n",
|
||||
"\n",
|
||||
"print(result)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"source": [
|
||||
"When you run a program the result can be:\n",
|
||||
"\n",
|
||||
"```JSON\n",
|
||||
"JOB_STATUS = {\n",
|
||||
" inProgress: 'RUNNING',\n",
|
||||
" errorOnCreate: 'ERROR_CREATING_JOB',\n",
|
||||
" errorExecuting: 'ERROR_RUNNING_JOB',\n",
|
||||
" completed: 'COMPLETED'\n",
|
||||
" };\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"The *run()* command waiting until timeout or when receive the \"COMPLETED\" or some error message.\n",
|
||||
"\n",
|
||||
"You can use the *execute()* to make the compile and run in a unique step."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"result = Q_program.execute(circuits, device, wait=2, timeout=240)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Compile parameters\n",
|
||||
"Q_program.compile(circuits, device=\"simulator\", shots=1024, max_credits=3, basis_gates=None, coupling_map=None)\n",
|
||||
" - circuits: Array of circuit to compile\n",
|
||||
" - device: Backend \n",
|
||||
" [\"ibmqx_qasm_simulator\", # Online simulator\n",
|
||||
" \"ibmqx2\", # Online RealChip, 5Qbits\n",
|
||||
" \"ibmqx3\", # Online RealChip, 16Qbits\n",
|
||||
" \"local_unitary_simulator\", # Local unitary Simulator \n",
|
||||
" \"local_qasm_simulator\"] # Local Simulator \n",
|
||||
" - shots: Number of shots, only for real chips and qasm simulators\n",
|
||||
" - max_credits: Maximum number of the credits to spend in the executions. If the executions are more expensives, the job is aborted, only the real chips\n",
|
||||
" - basis_gates: are the base gates, by default are: u1,u2,u3,cx,id\n",
|
||||
" - coupling_map: Object that represent the physical/topological Layout of a chip.\n",
|
||||
"#### Run parameters\n",
|
||||
"Q_program.run(wait=5, timeout=60)\n",
|
||||
" - wait: Time to wait to check if the execution is COMPLETED.\n",
|
||||
" - timeout: Timeout of the execution.\n",
|
||||
"#### Execute parameters \n",
|
||||
"*the Execute has the combined parameters of Compile and Run*\n",
|
||||
"\n",
|
||||
"Q_program.execute(circuits, device, shots=1024,\n",
|
||||
" max_credits=3, basis_gates=None, wait=5, timeout=60, basis_gates=None, coupling_map=None,)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Execute in a real device"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"device = 'qx5qv2' #Backed where execute your program, in this case in the Real Quantum Chip online \n",
|
||||
"circuits = [circuit] #Group of circuits to exec\n",
|
||||
"shots = 1024 #Number of Shots to run the program (experiment), Maximum 8192 shots.\n",
|
||||
"max_credits=3 #Maximum number of the credits to spend in the executions. \n",
|
||||
"\n",
|
||||
"result = Q_program.execute(circuits, device, shots, max_credits=3, wait=10, timeout=240)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Result\n",
|
||||
"You can access to the result in the element: qasms[n].result.data.counts "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"result['qasms'][0]['result']['data']['counts']"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"source": [
|
||||
"or you can use the function tool get_data(n) to obtain it directly"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"Q_program.get_data(result,0) "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"anaconda-cloud": {},
|
||||
"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.6.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
Loading…
Reference in New Issue