1# This file is part of QuTiP: Quantum Toolbox in Python. 2# 3# Copyright (c) 2011 and later, Paul D. Nation and Robert J. Johansson. 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions are 8# met: 9# 10# 1. Redistributions of source code must retain the above copyright notice, 11# this list of conditions and the following disclaimer. 12# 13# 2. Redistributions in binary form must reproduce the above copyright 14# notice, this list of conditions and the following disclaimer in the 15# documentation and/or other materials provided with the distribution. 16# 17# 3. Neither the name of the QuTiP: Quantum Toolbox in Python nor the names 18# of its contributors may be used to endorse or promote products derived 19# from this software without specific prior written permission. 20# 21# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 24# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32############################################################################### 33import os 34 35from numpy.testing import ( 36 assert_, run_module_suite, assert_allclose, assert_equal) 37import numpy as np 38 39from qutip.qip.device.processor import Processor 40from qutip.states import basis 41from qutip.operators import sigmaz, sigmax, sigmay, identity, destroy 42from qutip.qip.operations.gates import hadamard_transform 43from qutip.tensor import tensor 44from qutip.solver import Options 45from qutip.random_objects import rand_ket, rand_dm 46from qutip.qip.noise import ( 47 DecoherenceNoise, RandomNoise, ControlAmpNoise) 48from qutip.qip.qubits import qubit_states 49from qutip.metrics import fidelity 50from qutip.qip.pulse import Pulse 51 52 53class TestCircuitProcessor: 54 def test_modify_ctrls(self): 55 """ 56 Test for modifying Hamiltonian, add_control, remove_pulse 57 """ 58 N = 2 59 proc = Processor(N=N) 60 proc.ctrls 61 proc.add_control(sigmaz()) 62 assert_(tensor([sigmaz(), identity(2)]), proc.ctrls[0]) 63 proc.add_control(sigmax(), cyclic_permutation=True) 64 assert_allclose(len(proc.ctrls), 3) 65 assert_allclose(tensor([sigmax(), identity(2)]), proc.ctrls[1]) 66 assert_allclose(tensor([identity(2), sigmax()]), proc.ctrls[2]) 67 proc.add_control(sigmay(), targets=1) 68 assert_allclose(tensor([identity(2), sigmay()]), proc.ctrls[3]) 69 proc.remove_pulse([0, 1, 2]) 70 assert_allclose(tensor([identity(2), sigmay()]), proc.ctrls[0]) 71 proc.remove_pulse(0) 72 assert_allclose(len(proc.ctrls), 0) 73 74 def test_save_read(self): 75 """ 76 Test for saving and reading a pulse matrix 77 """ 78 proc = Processor(N=2) 79 proc.add_control(sigmaz(), cyclic_permutation=True) 80 proc1 = Processor(N=2) 81 proc1.add_control(sigmaz(), cyclic_permutation=True) 82 proc2 = Processor(N=2) 83 proc2.add_control(sigmaz(), cyclic_permutation=True) 84 # TODO generalize to different tlist 85 tlist = [0., 0.1, 0.2, 0.3, 0.4, 0.5] 86 amp1 = np.arange(0, 5, 1) 87 amp2 = np.arange(5, 0, -1) 88 89 proc.pulses[0].tlist = tlist 90 proc.pulses[0].coeff = amp1 91 proc.pulses[1].tlist = tlist 92 proc.pulses[1].coeff = amp2 93 proc.save_coeff("qutip_test_CircuitProcessor.txt") 94 proc1.read_coeff("qutip_test_CircuitProcessor.txt") 95 os.remove("qutip_test_CircuitProcessor.txt") 96 assert_allclose(proc1.get_full_coeffs(), proc.get_full_coeffs()) 97 assert_allclose(proc1.get_full_tlist(), proc.get_full_tlist()) 98 proc.save_coeff("qutip_test_CircuitProcessor.txt", inctime=False) 99 proc2.read_coeff("qutip_test_CircuitProcessor.txt", inctime=False) 100 proc2.set_all_tlist(tlist) 101 os.remove("qutip_test_CircuitProcessor.txt") 102 assert_allclose(proc2.get_full_coeffs(), proc.get_full_coeffs()) 103 104 def test_id_evolution(self): 105 """ 106 Test for identity evolution 107 """ 108 N = 1 109 proc = Processor(N=N) 110 init_state = rand_ket(2) 111 tlist = [0., 1., 2.] 112 proc.add_pulse(Pulse(identity(2), 0, tlist, False)) 113 result = proc.run_state( 114 init_state, options=Options(store_final_state=True)) 115 global_phase = init_state.data[0, 0]/result.final_state.data[0, 0] 116 assert_allclose(global_phase*result.final_state, init_state) 117 118 def test_id_with_T1_T2(self): 119 """ 120 Test for identity evolution with relaxation t1 and t2 121 """ 122 # setup 123 a = destroy(2) 124 Hadamard = hadamard_transform(1) 125 ex_state = basis(2, 1) 126 mines_state = (basis(2, 1)-basis(2, 0)).unit() 127 end_time = 2. 128 tlist = np.arange(0, end_time + 0.02, 0.02) 129 t1 = 1. 130 t2 = 0.5 131 132 # test t1 133 test = Processor(1, t1=t1) 134 # zero ham evolution 135 test.add_pulse(Pulse(identity(2), 0, tlist, False)) 136 result = test.run_state(ex_state, e_ops=[a.dag()*a]) 137 assert_allclose( 138 result.expect[0][-1], np.exp(-1./t1*end_time), 139 rtol=1e-5, err_msg="Error in t1 time simulation") 140 141 # test t2 142 test = Processor(1, t2=t2) 143 test.add_pulse(Pulse(identity(2), 0, tlist, False)) 144 result = test.run_state( 145 init_state=mines_state, e_ops=[Hadamard*a.dag()*a*Hadamard]) 146 assert_allclose( 147 result.expect[0][-1], np.exp(-1./t2*end_time)*0.5+0.5, 148 rtol=1e-5, err_msg="Error in t2 time simulation") 149 150 # test t1 and t2 151 t1 = np.random.rand(1) + 0.5 152 t2 = np.random.rand(1) * 0.5 + 0.5 153 test = Processor(1, t1=t1, t2=t2) 154 test.add_pulse(Pulse(identity(2), 0, tlist, False)) 155 result = test.run_state( 156 init_state=mines_state, e_ops=[Hadamard*a.dag()*a*Hadamard]) 157 assert_allclose( 158 result.expect[0][-1], np.exp(-1./t2*end_time)*0.5+0.5, 159 rtol=1e-5, 160 err_msg="Error in t1 & t2 simulation, " 161 "with t1={} and t2={}".format(t1, t2)) 162 163 def testPlot(self): 164 """ 165 Test for plotting functions 166 """ 167 try: 168 import matplotlib.pyplot as plt 169 except Exception: 170 return True 171 # step_func 172 tlist = np.linspace(0., 2*np.pi, 20) 173 processor = Processor(N=1, spline_kind="step_func") 174 processor.add_control(sigmaz()) 175 processor.pulses[0].tlist = tlist 176 processor.pulses[0].coeff = np.array([np.sin(t) for t in tlist]) 177 processor.plot_pulses() 178 plt.clf() 179 180 # cubic spline 181 tlist = np.linspace(0., 2*np.pi, 20) 182 processor = Processor(N=1, spline_kind="cubic") 183 processor.add_control(sigmaz()) 184 processor.pulses[0].tlist = tlist 185 processor.pulses[0].coeff = np.array([np.sin(t) for t in tlist]) 186 processor.plot_pulses() 187 plt.clf() 188 189 def testSpline(self): 190 """ 191 Test if the spline kind is correctly transfered into 192 the arguments in QobjEvo 193 """ 194 tlist = np.array([1, 2, 3, 4, 5, 6], dtype=float) 195 coeff = np.array([1, 1, 1, 1, 1, 1], dtype=float) 196 processor = Processor(N=1, spline_kind="step_func") 197 processor.add_control(sigmaz()) 198 processor.pulses[0].tlist = tlist 199 processor.pulses[0].coeff = coeff 200 201 ideal_qobjevo, _ = processor.get_qobjevo(noisy=False) 202 assert_(ideal_qobjevo.args["_step_func_coeff"]) 203 noisy_qobjevo, c_ops = processor.get_qobjevo(noisy=True) 204 assert_(noisy_qobjevo.args["_step_func_coeff"]) 205 processor.T1 = 100. 206 processor.add_noise(ControlAmpNoise(coeff=coeff, tlist=tlist)) 207 noisy_qobjevo, c_ops = processor.get_qobjevo(noisy=True) 208 assert_(noisy_qobjevo.args["_step_func_coeff"]) 209 210 tlist = np.array([1, 2, 3, 4, 5, 6], dtype=float) 211 coeff = np.array([1, 1, 1, 1, 1, 1], dtype=float) 212 processor = Processor(N=1, spline_kind="cubic") 213 processor.add_control(sigmaz()) 214 processor.pulses[0].tlist = tlist 215 processor.pulses[0].coeff = coeff 216 217 ideal_qobjevo, _ = processor.get_qobjevo(noisy=False) 218 assert_(not ideal_qobjevo.args["_step_func_coeff"]) 219 noisy_qobjevo, c_ops = processor.get_qobjevo(noisy=True) 220 assert_(not noisy_qobjevo.args["_step_func_coeff"]) 221 processor.T1 = 100. 222 processor.add_noise(ControlAmpNoise(coeff=coeff, tlist=tlist)) 223 noisy_qobjevo, c_ops = processor.get_qobjevo(noisy=True) 224 assert_(not noisy_qobjevo.args["_step_func_coeff"]) 225 226 def testGetObjevo(self): 227 tlist = np.array([1, 2, 3, 4, 5, 6], dtype=float) 228 coeff = np.array([1, 1, 1, 1, 1, 1], dtype=float) 229 processor = Processor(N=1) 230 processor.add_control(sigmaz()) 231 processor.pulses[0].tlist = tlist 232 processor.pulses[0].coeff = coeff 233 234 # without noise 235 unitary_qobjevo, _ = processor.get_qobjevo( 236 args={"test": True}, noisy=False) 237 assert_allclose(unitary_qobjevo.ops[0].qobj, sigmaz()) 238 assert_allclose(unitary_qobjevo.tlist, tlist) 239 assert_allclose(unitary_qobjevo.ops[0].coeff, coeff[0]) 240 assert_(unitary_qobjevo.args["test"], 241 msg="Arguments not correctly passed on") 242 243 # with decoherence noise 244 dec_noise = DecoherenceNoise( 245 c_ops=sigmax(), coeff=coeff, tlist=tlist) 246 processor.add_noise(dec_noise) 247 assert_equal(unitary_qobjevo.to_list(), 248 processor.get_qobjevo(noisy=False)[0].to_list()) 249 250 noisy_qobjevo, c_ops = processor.get_qobjevo( 251 args={"test": True}, noisy=True) 252 assert_(noisy_qobjevo.args["_step_func_coeff"], 253 msg="Spline type not correctly passed on") 254 assert_(noisy_qobjevo.args["test"], 255 msg="Arguments not correctly passed on") 256 assert_(sigmaz() in [pair[0] for pair in noisy_qobjevo.to_list()]) 257 assert_equal(c_ops[0].ops[0].qobj, sigmax()) 258 assert_equal(c_ops[0].tlist, tlist) 259 260 # with amplitude noise 261 processor = Processor(N=1, spline_kind="cubic") 262 processor.add_control(sigmaz()) 263 tlist = np.linspace(1, 6, int(5/0.2)) 264 coeff = np.random.rand(len(tlist)) 265 processor.pulses[0].tlist = tlist 266 processor.pulses[0].coeff = coeff 267 268 amp_noise = ControlAmpNoise(coeff=coeff, tlist=tlist) 269 processor.add_noise(amp_noise) 270 noisy_qobjevo, c_ops = processor.get_qobjevo( 271 args={"test": True}, noisy=True) 272 assert_(not noisy_qobjevo.args["_step_func_coeff"], 273 msg="Spline type not correctly passed on") 274 assert_(noisy_qobjevo.args["test"], 275 msg="Arguments not correctly passed on") 276 assert_equal(len(noisy_qobjevo.ops), 2) 277 assert_equal(sigmaz(), noisy_qobjevo.ops[0].qobj) 278 assert_allclose(coeff, noisy_qobjevo.ops[0].coeff, rtol=1.e-10) 279 280 def testNoise(self): 281 """ 282 Test for Processor with noise 283 """ 284 # setup and fidelity without noise 285 init_state = qubit_states(2, [0, 0, 0, 0]) 286 tlist = np.array([0., np.pi/2.]) 287 a = destroy(2) 288 proc = Processor(N=2) 289 proc.add_control(sigmax(), targets=1) 290 proc.pulses[0].tlist = tlist 291 proc.pulses[0].coeff = np.array([1]) 292 result = proc.run_state(init_state=init_state) 293 assert_allclose( 294 fidelity(result.states[-1], qubit_states(2, [0, 1, 0, 0])), 295 1, rtol=1.e-7) 296 297 # decoherence noise 298 dec_noise = DecoherenceNoise([0.25*a], targets=1) 299 proc.add_noise(dec_noise) 300 result = proc.run_state(init_state=init_state) 301 assert_allclose( 302 fidelity(result.states[-1], qubit_states(2, [0, 1, 0, 0])), 303 0.981852, rtol=1.e-3) 304 305 # white random noise 306 proc.noise = [] 307 white_noise = RandomNoise(0.2, np.random.normal, loc=0.1, scale=0.1) 308 proc.add_noise(white_noise) 309 result = proc.run_state(init_state=init_state) 310 311 def testMultiLevelSystem(self): 312 """ 313 Test for processor with multi-level system 314 """ 315 N = 2 316 proc = Processor(N=N, dims=[2, 3]) 317 proc.add_control(tensor(sigmaz(), rand_dm(3, density=1.))) 318 proc.pulses[0].coeff = np.array([1, 2]) 319 proc.pulses[0].tlist = np.array([0., 1., 2]) 320 proc.run_state(init_state=tensor([basis(2, 0), basis(3, 1)])) 321 322 def testDrift(self): 323 """ 324 Test for the drift Hamiltonian 325 """ 326 processor = Processor(N=1) 327 processor.add_drift(sigmaz(), 0) 328 tlist = np.array([0., 1., 2.]) 329 processor.add_pulse(Pulse(identity(2), 0, tlist, False)) 330 ideal_qobjevo, _ = processor.get_qobjevo(noisy=True) 331 assert_equal(ideal_qobjevo.cte, sigmaz()) 332 333 def testChooseSolver(self): 334 # setup and fidelity without noise 335 init_state = qubit_states(2, [0, 0, 0, 0]) 336 tlist = np.array([0., np.pi/2.]) 337 a = destroy(2) 338 proc = Processor(N=2) 339 proc.add_control(sigmax(), targets=1) 340 proc.pulses[0].tlist = tlist 341 proc.pulses[0].coeff = np.array([1]) 342 result = proc.run_state(init_state=init_state, solver="mcsolve") 343 assert_allclose( 344 fidelity(result.states[-1], qubit_states(2, [0, 1, 0, 0])), 345 1, rtol=1.e-7) 346 347if __name__ == "__main__": 348 run_module_suite() 349