Skip to content

Commit 6a35c8b

Browse files
committed
submit test case for legacy cases.
1 parent 244b87f commit 6a35c8b

File tree

10 files changed

+1341
-0
lines changed

10 files changed

+1341
-0
lines changed

tests/0.1_qem_and_lib.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import sys
2+
import os
3+
import matplotlib.pyplot as plt
4+
5+
# Add the directory containing your module to Python's search path
6+
module_path = ".."
7+
sys.path.insert(0, module_path)
8+
9+
import tensorcircuit as tc
10+
from tensorcircuit.cloud.apis import submit_task, get_device, set_provider, set_token
11+
from library.adder import gen_adder_circ
12+
from library.aqft import gen_aqft_circ
13+
from library.bv import gen_bv_circ
14+
from library.grover import gen_grover_circ
15+
from library.qft_adder import qft_adder
16+
from library.uccsd import gen_uccsd
17+
from library.hwea import gen_hwea_circ
18+
19+
set_token(os.getenv("TOKEN"))
20+
shots = 8192
21+
mit = tc.results.rem.ReadoutMit('tianji_s2?o=7')
22+
mit.cals_from_system(13, shots, method='local')
23+
set_provider("tencent")
24+
d = get_device("tianji_s2")
25+
submit_task(
26+
circuit=gen_adder_circ(3),
27+
shots=shots,
28+
device=d
29+
)
30+
submit_task(
31+
circuit=gen_grover_circ(3),
32+
shots=shots,
33+
device=d
34+
)
35+
# submit_task(
36+
# circuit=dynamics_circuit(4, 1.0, 0.1, 3),
37+
# shots=shots,
38+
# device=get_device("tianji_s2"),
39+
# )
40+
submit_task(
41+
circuit=gen_bv_circ(9, 4),
42+
shots=shots,
43+
device=d
44+
)
45+
submit_task(
46+
circuit=gen_uccsd(4),
47+
shots=shots,
48+
device=d
49+
)
50+
qc = qft_adder(3, 2, 5)
51+
print(qc)
52+
submit_task(
53+
circuit=qc,
54+
shots=shots,
55+
device=d
56+
)
57+
submit_task(
58+
circuit=gen_hwea_circ(4, 2),
59+
shots=shots,
60+
device=d
61+
)
62+
submit_task(
63+
circuit=gen_aqft_circ(4),
64+
shots=shots,
65+
device=d
66+
)
67+
print("✅ TEST FILE DONE")

tests/library/adder.py

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
'''
2+
Teague Tomesh - 2/10/2020
3+
4+
Implementation of an n-bit ripple-carry adder.
5+
6+
Based on the specification given in Cuccaro, Draper, Kutin, Moulton.
7+
(https://arxiv.org/abs/quant-ph/0410184v1)
8+
'''
9+
10+
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
11+
import tensorcircuit as tc
12+
from .randinit import qc_randinit
13+
14+
15+
class RCAdder:
16+
"""
17+
An n-bit ripple-carry adder can be generated using an instance of the
18+
RCAdder class by calling the gen_circuit() method.
19+
20+
This adder circuit uses 1 ancilla qubit to add together two values
21+
a = a_(n-1)...a_0 and b = b_(n-1)...a_0
22+
and store their sum
23+
s = s_n...s_0
24+
in the registers which initially held the b value.
25+
26+
The adder circuit uses 2 + binary_len(a) + binary_len(b) qubits.
27+
The initial carry value is stored in the qubit at index = 0.
28+
The binary value of a_i is stored in the qubit at index = 2*i + 2
29+
The binary value of b_i is stored in the qubit at index = 2*i + 1
30+
The high bit, s_n, is stored in the last qubit at index = num_qubits - 1
31+
32+
Attributes
33+
----------
34+
nbits : int
35+
size, in bits, of the numbers the adder can handle
36+
nq : int
37+
number of qubits needed to construct the adder circuit
38+
a, b : int
39+
optional parameters to specify the numbers the adder should add.
40+
Will throw an exception if the length of the bitstring representations
41+
of a or b are greater than nbits.
42+
use_toffoli : bool
43+
Should the toffoli gate be used in the generated circuit or should it
44+
first be decomposed
45+
barriers : bool
46+
should barriers be included in the generated circuit
47+
regname : str
48+
optional string to name the quantum and classical registers. This
49+
allows for the easy concatenation of multiple QuantumCircuits.
50+
qr : QuantumRegister
51+
Qiskit QuantumRegister holding all of the quantum bits
52+
circ : QuantumCircuit
53+
Qiskit QuantumCircuit that represents the uccsd circuit
54+
"""
55+
56+
def __init__(self, nbits=None, a=0, b=0, use_toffoli=False, barriers=False,
57+
measure=False, regname=None):
58+
59+
# number of bits the adder can handle
60+
if nbits is None:
61+
raise Exception('Number of bits must be specified')
62+
else:
63+
self.nbits = nbits
64+
65+
# given nbits, compute the number of qubits the adder will need
66+
# number of qubits = 1 ancilla for the initial carry value
67+
# + 2*nbits to hold both a and b
68+
# + 1 more qubit to hold the high bit, s_n
69+
self.nq = 1 + 2*nbits + 1
70+
71+
# set flags for circuit generation
72+
if len('{0:b}'.format(a)) > nbits or len('{0:b}'.format(b)) > nbits:
73+
raise Exception('Binary representations of a and b must be less than or equal to nbits')
74+
75+
self.a = a
76+
self.b = b
77+
self.use_toffoli = use_toffoli
78+
self.barriers = barriers
79+
self.measure = measure
80+
81+
# create a QuantumCircuit object
82+
if regname is None:
83+
self.qr = QuantumRegister(self.nq)
84+
else:
85+
self.qr = QuantumRegister(self.nq, name=regname)
86+
self.circ = QuantumCircuit(self.qr)
87+
qc_randinit(self.circ)
88+
89+
# add ClassicalRegister if measure is True
90+
if self.measure:
91+
self.cr = ClassicalRegister(self.nq)
92+
self.circ.add_register(self.cr)
93+
94+
95+
def _initialize_value(self, indices, value):
96+
"""
97+
Initialize the qubits at indices to the given value
98+
99+
Parameters
100+
----------
101+
indices : List[int]
102+
List of qubit indices
103+
value : int
104+
The desired initial value
105+
"""
106+
binstr = '{0:b}'.format(value)
107+
for index, val in enumerate(reversed(binstr)):
108+
if val is '1':
109+
self.circ.x(indices[index])
110+
111+
112+
def _toffoli(self, x, y, z):
113+
"""
114+
Implement the toffoli gate using 1 and 2 qubit gates
115+
"""
116+
self.circ.h(z)
117+
self.circ.cx(y,z)
118+
self.circ.tdg(z)
119+
self.circ.cx(x,z)
120+
self.circ.t(z)
121+
self.circ.cx(y,z)
122+
self.circ.t(y)
123+
self.circ.tdg(z)
124+
self.circ.cx(x,z)
125+
self.circ.cx(x,y)
126+
self.circ.t(z)
127+
self.circ.h(z)
128+
self.circ.t(x)
129+
self.circ.tdg(y)
130+
self.circ.cx(x,y)
131+
132+
133+
def _MAJ(self, x, y, z):
134+
"""
135+
Implement the MAJ (Majority) gate described in Cuccaro, Draper, Kutin,
136+
Moulton.
137+
"""
138+
self.circ.cx(z,y)
139+
self.circ.cx(z,x)
140+
141+
if self.use_toffoli:
142+
self.circ.ccx(x,y,z)
143+
else:
144+
# use a decomposed version of toffoli
145+
self._toffoli(x,y,z)
146+
147+
148+
def _UMA(self, x, y, z):
149+
"""
150+
Implement the UMA (UnMajority and Add) gate described in Cuccaro,
151+
Draper, Kutin, Moulton.
152+
"""
153+
self.circ.x(y)
154+
self.circ.cx(x,y)
155+
if self.use_toffoli:
156+
self.circ.ccx(x,y,z)
157+
else:
158+
# use a decomposed version of toffoli
159+
self._toffoli(x,y,z)
160+
self.circ.x(y)
161+
self.circ.cx(z,x)
162+
self.circ.cx(z,y)
163+
164+
165+
def gen_circuit(self):
166+
"""
167+
Create a circuit implementing the ripple-carry adder
168+
169+
Returns
170+
-------
171+
QuantumCircuit
172+
QuantumCircuit object of size self.nq
173+
"""
174+
high_bit_index = self.nq-1
175+
176+
# initialize the a and b registers
177+
a_indices = [2*i+2 for i in range(self.nbits)]
178+
b_indices = [2*i+1 for i in range(self.nbits)]
179+
for index_list, value in zip([a_indices, b_indices], [self.a, self.b]):
180+
self._initialize_value(index_list, value)
181+
182+
# compute the carry bits, c_i, in order using the MAJ ladder
183+
for a_i in a_indices:
184+
self._MAJ(a_i-2, a_i-1, a_i)
185+
186+
# write the final carry bit value to the high bit register
187+
self.circ.cx(a_indices[-1], high_bit_index)
188+
189+
# erase the carry bits in reverse order using the UMA ladder
190+
for a_i in reversed(a_indices):
191+
self._UMA(a_i-2, a_i-1, a_i)
192+
193+
return self.circ
194+
195+
196+
def gen_adder_circ(nbits):
197+
adder = RCAdder(nbits, a=0, b=0)
198+
circ = adder.gen_circuit()
199+
return tc.Circuit.from_qiskit(circ)
200+

tests/library/aqft.py

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import math
2+
import numpy as np
3+
import tensorcircuit as tc
4+
from .randinit import qc_randinit
5+
6+
class QFT:
7+
"""
8+
Class which generates the circuit to perform the Quantum Fourier
9+
Transform (or its inverse) as described in Mike & Ike Chapter 5.
10+
11+
(Michael A Nielsen and Isaac L Chuang. Quantum computation and quantum
12+
information (10th anniv. version), 2010.)
13+
14+
For another example see Figure 1 of Daniel E Browne 2007 New J. Phys. 9 146
15+
16+
A QFT or iQFT circuit can be generated with a given instance of the
17+
QFT class by calling the gen_circuit() method.
18+
19+
Attributes
20+
----------
21+
width : int
22+
number of qubits
23+
inverse : bool
24+
Set to true to generate the inverse quantum fourier transform
25+
kvals : bool
26+
optional parameter that will change the angle of the controlled
27+
rotations so that when the circuit is printed it will display
28+
the same k values that are shown in Mike & Ike Chpt 5, Fig 5.1
29+
(NOTE: the generated circuit will no longer be valid! This is
30+
for visualization purposes only.)
31+
barriers : bool
32+
should barriers be included in the generated circuit
33+
measure : bool
34+
should a classical register & measurement be added to the circuit
35+
regname : str
36+
optional string to name the quantum and classical registers. This
37+
allows for the easy concatenation of multiple QuantumCircuits.
38+
qr : QuantumRegister
39+
Qiskit QuantumRegister holding all of the quantum bits
40+
cr : ClassicalRegister
41+
Qiskit ClassicalRegister holding all of the classical bits
42+
circ : QuantumCircuit
43+
Qiskit QuantumCircuit that represents the uccsd circuit
44+
"""
45+
46+
def __init__(self, width, approximation_degree, inverse=False, kvals=False, barriers=True,
47+
measure=False, regname=None):
48+
49+
# number of qubits
50+
self.nq = width
51+
self.approximation_degree = approximation_degree
52+
53+
# set flags for circuit generation
54+
self.inverse = inverse
55+
self.kvals = kvals
56+
self.barriers = barriers
57+
self.measure = measure
58+
59+
# create a QuantumCircuit object
60+
self.circ = tc.Circuit(self.nq)
61+
qc_randinit(self.circ)
62+
63+
64+
def reg_qft(self):
65+
"""
66+
Implement the QFT on self.circ
67+
68+
j ranges from 0 -> nq-1
69+
k ranges from j+1 -> nq-1
70+
71+
For each j qubit, a controlled cu1 gate is applied with target=j,
72+
control=k (for each k).
73+
74+
cu1 = 1 0
75+
0 e^(2pi*i / 2^(k-j+1))
76+
"""
77+
78+
# CPHASE gate decompostion
79+
def cu1(circ, theta, j, k):
80+
circ.RZ(k, theta=theta)
81+
circ.cnot(j, k)
82+
circ.RZ(k, theta=-theta/2)
83+
circ.cnot(j, k)
84+
circ.RZ(k, theta=-theta/2)
85+
circ.RZ(j, theta=-theta/2)
86+
87+
for j in range(self.nq):
88+
self.circ.H(j)
89+
for k in range(j+1,self.nq):
90+
if k-j+1<=self.approximation_degree:
91+
cu1(self.circ, (2*np.pi)/(2**(k-j+1)), j, k)
92+
93+
94+
95+
def gen_circuit(self):
96+
"""
97+
Create a circuit implementing the UCCSD ansatz
98+
99+
Given the number of qubits and parameters, construct the
100+
ansatz as given in Whitfield et al.
101+
102+
Returns
103+
-------
104+
QuantumCircuit
105+
QuantumCircuit object of size nq with no ClassicalRegister and
106+
no measurements
107+
"""
108+
self.reg_qft()
109+
110+
return self.circ
111+
112+
113+
def gen_aqft_circ(full_circ_size, approximation_degree=None):
114+
if not approximation_degree:
115+
approximation_degree=int(math.log(full_circ_size,2)+1)
116+
full_circ = QFT(full_circ_size, approximation_degree).gen_circuit()
117+
return full_circ

0 commit comments

Comments
 (0)