def testresolve(self, gate_from, gate_to, targets, controls): qc1 = QubitCircuit(2) qc1.add_gate(gate_from, targets=targets, controls=controls) U1 = gates.gate_sequence_product(qc1.propagators()) qc2 = qc1.resolve_gates(basis=gate_to) U2 = gates.gate_sequence_product(qc2.propagators()) assert _op_dist(U1, U2) < 1e-12
def test_numerical_evolution(num_qubits, gates, device_class, kwargs): num_qubits = 2 circuit = QubitCircuit(num_qubits) for gate in gates: circuit.add_gate(gate) device = device_class(num_qubits, **kwargs) device.load_circuit(circuit) state = qutip.rand_ket(2**num_qubits) state.dims = [[2] * num_qubits, [1] * num_qubits] target = gate_sequence_product([state] + circuit.propagators()) if isinstance(device, DispersiveCavityQED): num_ancilla = len(device.dims) - num_qubits ancilla_indices = slice(0, num_ancilla) extra = qutip.basis(device.dims[ancilla_indices], [0] * num_ancilla) init_state = qutip.tensor(extra, state) elif isinstance(device, SCQubits): # expand to 3-level represetnation init_state = _ket_expaned_dims(state, device.dims) else: init_state = state options = qutip.Options(store_final_state=True, nsteps=50_000) result = device.run_state(init_state=init_state, analytical=False, options=options) numerical_result = result.final_state if isinstance(device, DispersiveCavityQED): target = qutip.tensor(extra, target) elif isinstance(device, SCQubits): target = _ket_expaned_dims(target, device.dims) assert _tol > abs(1 - qutip.metrics.fidelity(numerical_result, target))
def test_simple_hadamard(self): """ Test for optimizing a simple hadamard gate """ N = 1 H_d = sigmaz() H_c = sigmax() qc = QubitCircuit(N) qc.add_gate("SNOT", 0) # test load_circuit, with verbose info num_tslots = 10 evo_time = 10 test = OptPulseProcessor(N, drift=H_d) test.add_control(H_c, targets=0) tlist, coeffs = test.load_circuit(qc, num_tslots=num_tslots, evo_time=evo_time, verbose=True) # test run_state rho0 = qubit_states(1, [0]) plus = (qubit_states(1, [0]) + qubit_states(1, [1])).unit() result = test.run_state(rho0) assert_allclose(fidelity(result.states[-1], plus), 1, rtol=1.0e-6)
def test_N_level_system(self): """ Test for circuit with N-level system. """ mat3 = qp.rand_unitary_haar(3) def controlled_mat3(arg_value): """ A qubit control an operator acting on a 3 level system """ control_value = arg_value dim = mat3.dims[0][0] return (tensor(fock_dm(2, control_value), mat3) + tensor(fock_dm(2, 1 - control_value), identity(dim))) qc = QubitCircuit(2, dims=[3, 2]) qc.user_gates = {"CTRLMAT3": controlled_mat3} qc.add_gate("CTRLMAT3", targets=[1, 0], arg_value=1) props = qc.propagators() final_fid = qp.average_gate_fidelity(mat3, ptrace(props[0], 0) - 1) assert pytest.approx(final_fid, 1.0e-6) == 1 init_state = basis([3, 2], [0, 1]) result = qc.run(init_state) final_fid = qp.fidelity(result, props[0] * init_state) assert pytest.approx(final_fid, 1.0e-6) == 1.
def test_scheduling_pulse(instructions, method, expected_length, random_shuffle, gates_schedule): circuit = QubitCircuit(4) for instruction in instructions: circuit.add_gate( Gate(instruction.name, instruction.targets, instruction.controls)) if random_shuffle: repeat_num = 5 else: repeat_num = 0 result0 = gate_sequence_product(circuit.propagators()) # run the scheduler scheduler = Scheduler(method) gate_cycle_indices = scheduler.schedule(instructions, gates_schedule=gates_schedule, repeat_num=repeat_num) # check if the scheduled length is expected assert (max(gate_cycle_indices) == expected_length) scheduled_gate = [[] for i in range(max(gate_cycle_indices) + 1)] # check if the scheduled circuit is correct for i, cycles in enumerate(gate_cycle_indices): scheduled_gate[cycles].append(circuit.gates[i]) circuit.gates = sum(scheduled_gate, []) result1 = gate_sequence_product(circuit.propagators()) assert (tracedist(result0 * result1.dag(), qeye(result0.dims[0])) < 1.0e-7)
def test_compiling_with_scheduler(): """ Here we test if the compiling with scheduler works properly. The non scheduled pulse should be twice as long as the scheduled one. The numerical results are tested in test_device.py """ circuit = QubitCircuit(2) circuit.add_gate("X", 0) circuit.add_gate("X", 1) processor = DispersiveCavityQED(2) processor.load_circuit(circuit, schedule_mode=None) tlist = processor.get_full_tlist() time_not_scheduled = tlist[-1] - tlist[0] processor.load_circuit(circuit, schedule_mode="ASAP") tlist = processor.get_full_tlist() time_scheduled1 = tlist[-1] - tlist[0] processor.load_circuit(circuit, schedule_mode="ALAP") tlist = processor.get_full_tlist() time_scheduled2 = tlist[-1] - tlist[0] assert (abs(time_scheduled1 * 2 - time_not_scheduled) < 1.0e-10) assert (abs(time_scheduled2 * 2 - time_not_scheduled) < 1.0e-10)
def test_numerical_evolution(num_qubits, gates, device_class, kwargs): num_qubits = 3 circuit = QubitCircuit(num_qubits) for gate in gates: circuit.add_gate(gate) device = device_class(num_qubits, **kwargs) device.load_circuit(circuit) state = qutip.rand_ket(2**num_qubits) state.dims = [[2] * num_qubits, [1] * num_qubits] target = gate_sequence_product([state] + circuit.propagators()) if len(device.dims) > num_qubits: num_ancilla = len(device.dims) - num_qubits ancilla_indices = slice(0, num_ancilla) extra = qutip.basis(device.dims[ancilla_indices], [0] * num_ancilla) init_state = qutip.tensor(extra, state) else: init_state = state options = qutip.Options(store_final_state=True, nsteps=50_000) result = device.run_state(init_state=init_state, analytical=False, options=options) if len(device.dims) > num_qubits: target = qutip.tensor(extra, target) assert _tol > abs(1 - qutip.metrics.fidelity(result.final_state, target))
def construct_circuit(self, angles): """ Construct a circuit by specifying values for each free parameter. Parameters ---------- angles: list of float A list of dimension (n,) for n free parameters in the circuit Returns ------- circ: :obj:`.QubitCircuit` """ circ = QubitCircuit(self.num_qubits) circ.user_gates = self.user_gates i = 0 for layer_num in range(self.num_layers): for block in self.blocks: if block.initial and layer_num > 0: continue if block.is_native_gate: circ.add_gate(block.operator, targets=block.targets) else: n = block.get_free_parameters_num() circ.add_gate( block.name, targets=list(range(self.num_qubits)), arg_value=angles[i:i + n] if n > 0 else None, ) i += n return circ
def test_compiler_result_format(): """ Test if compiler return correctly different kind of compiler result and if processor can successfully read them. """ num_qubits = 1 circuit = QubitCircuit(num_qubits) circuit.add_gate("RX", targets=[0], arg_value=np.pi / 2) processor = LinearSpinChain(num_qubits) compiler = SpinChainCompiler(num_qubits, params=processor.params, setup="circular") tlist, coeffs = compiler.compile(circuit) assert (isinstance(tlist, dict)) assert ("sx0" in tlist) assert (isinstance(coeffs, dict)) assert ("sx0" in coeffs) processor.coeffs = coeffs processor.set_all_tlist(tlist) assert_array_equal(processor.pulses[0].coeff, coeffs["sx0"]) assert_array_equal(processor.pulses[0].tlist, tlist["sx0"]) compiler.gate_compiler["RX"] = rx_compiler_without_pulse_dict tlist, coeffs = compiler.compile(circuit) assert (isinstance(tlist, dict)) assert (0 in tlist) assert (isinstance(coeffs, dict)) assert (0 in coeffs) processor.coeffs = coeffs processor.set_all_tlist(tlist) assert_array_equal(processor.pulses[0].coeff, coeffs[0]) assert_array_equal(processor.pulses[0].tlist, tlist[0])
def test_simple_hadamard(self): """ Test for optimizing a simple hadamard gate """ N = 1 H_d = sigmaz() H_c = sigmax() qc = QubitCircuit(N) qc.add_gate("SNOT", 0) # test load_circuit, with verbose info num_tslots = 10 evo_time = 10 test = OptPulseProcessor(N, drift=H_d) test.add_control(H_c, targets=0) tlist, coeffs = test.load_circuit(qc, num_tslots=num_tslots, evo_time=evo_time, verbose=True) # test run_state rho0 = qubit_states(1, [0]) plus = (qubit_states(1, [0]) + qubit_states(1, [1])).unit() result = test.run_state(rho0) assert_allclose(fidelity(result.states[-1], plus), 1, rtol=1.0e-6) # test add/remove ctrl test.add_control(sigmay()) test.remove_pulse(0) assert_(len(test.pulses) == 1, msg="Method of remove_pulse could be wrong.") assert_allclose(test.drift.drift_hamiltonians[0].qobj, H_d) assert_(sigmay() in test.ctrls, msg="Method of remove_pulse could be wrong.")
def test_user_gate(self): """ User defined gate for QubitCircuit """ def customer_gate1(arg_values): mat = np.zeros((4, 4), dtype=np.complex128) mat[0, 0] = mat[1, 1] = 1. mat[2:4, 2:4] = gates.rx(arg_values).full() return Qobj(mat, dims=[[2, 2], [2, 2]]) def customer_gate2(): mat = np.array([[1., 0], [0., 1.j]]) return Qobj(mat, dims=[[2], [2]]) qc = QubitCircuit(3) qc.user_gates = {"CTRLRX": customer_gate1, "T1": customer_gate2} qc.add_gate("CTRLRX", targets=[1, 2], arg_value=np.pi/2) qc.add_gate("T1", targets=[1]) props = qc.propagators() result1 = tensor(identity(2), customer_gate1(np.pi/2)) np.testing.assert_allclose(props[0].full(), result1.full()) result2 = tensor(identity(2), customer_gate2(), identity(2)) np.testing.assert_allclose(props[1].full(), result2.full())
def test_qasm_str(): expected_qasm_str = ('// QASM 2.0 file generated by QuTiP\n\nOPENQASM 2.0;' '\ninclude "qelib1.inc";\n\nqreg q[2];\ncreg c[1];\n\n' 'x q[0];\nmeasure q[1] -> c[0]\n') simple_qc = QubitCircuit(2, num_cbits=1) simple_qc.add_gate("X", targets=[0]) simple_qc.add_measurement("M", targets=[1], classical_store=0) assert circuit_to_qasm_str(simple_qc) == expected_qasm_str
def test_device_against_gate_sequence(num_qubits, gates, device_class, kwargs): circuit = QubitCircuit(num_qubits) for gate in gates: circuit.add_gate(gate) U_ideal = gate_sequence_product(circuit.propagators()) device = device_class(num_qubits) U_physical = gate_sequence_product(device.run(circuit)) assert (U_ideal - U_physical).norm() < _tol
def test_scqubits_single_qubit_gate(): # Check the accuracy of the single-qubit gate for SCQubits. circuit = QubitCircuit(1) circuit.add_gate("X", targets=[0]) processor = SCQubits(1, omega_single=0.04) processor.load_circuit(circuit) U = _compute_propagator(processor, circuit) fid = qutip.average_gate_fidelity(qutip.Qobj(U.full()[:2, :2]), qutip.sigmax()) assert pytest.approx(fid, rel=1.0e-6) == 1
def test_zz_cross_talk(self): circuit = QubitCircuit(2) circuit.add_gate("X", 0) processor = SCQubits(2) processor.add_noise(ZZCrossTalk(processor.params)) processor.load_circuit(circuit) pulses = processor.get_noisy_pulses(device_noise=True, drift=True) for pulse in pulses: if not isinstance(pulse, Drift) and pulse.label=="systematic_noise": assert(len(pulse.coherent_noise) == 1)
def _circuit1(): circuit1 = QubitCircuit(6) circuit1.add_gate("SNOT", 2) circuit1.add_gate("CNOT", 4, 2) circuit1.add_gate("CNOT", 3, 2) circuit1.add_gate("CNOT", 1, 2) circuit1.add_gate("CNOT", 5, 4) circuit1.add_gate("CNOT", 1, 5) circuit1.add_gate("SWAP", [0, 1]) return circuit1
def testFREDKINdecompose(self): """ FREDKIN to rotation and CNOT: compare unitary matrix for FREDKIN and product of resolved matrices in terms of rotation gates and CNOT. """ qc1 = QubitCircuit(3) qc1.add_gate("FREDKIN", targets=[0, 1], controls=[2]) U1 = gates.gate_sequence_product(qc1.propagators()) qc2 = qc1.resolve_gates() U2 = gates.gate_sequence_product(qc2.propagators()) assert _op_dist(U1, U2) < 1e-12
def testSNOTdecompose(self): """ SNOT to rotation: compare unitary matrix for SNOT and product of resolved matrices in terms of rotation gates. """ qc1 = QubitCircuit(1) qc1.add_gate("SNOT", targets=0) U1 = gates.gate_sequence_product(qc1.propagators()) qc2 = qc1.resolve_gates() U2 = gates.gate_sequence_product(qc2.propagators()) assert _op_dist(U1, U2) < 1e-12
def test_analytical_evolution(num_qubits, gates, device_class, kwargs): circuit = QubitCircuit(num_qubits) for gate in gates: circuit.add_gate(gate) state = qutip.rand_ket(2**num_qubits) state.dims = [[2] * num_qubits, [1] * num_qubits] ideal = gate_sequence_product([state] + circuit.propagators()) device = device_class(num_qubits) operators = device.run_state(init_state=state, qc=circuit, analytical=True) result = gate_sequence_product(operators) assert abs(qutip.metrics.fidelity(result, ideal) - 1) < _tol
def testadjacentgates(self): """ Adjacent Gates: compare unitary matrix for ISWAP and product of resolved matrices in terms of adjacent gates interaction. """ qc1 = QubitCircuit(3) qc1.add_gate("ISWAP", targets=[0, 2]) U1 = gates.gate_sequence_product(qc1.propagators()) qc0 = qc1.adjacent_gates() qc2 = qc0.resolve_gates(basis="ISWAP") U2 = gates.gate_sequence_product(qc2.propagators()) assert _op_dist(U1, U2) < 1e-12
def _teleportation_circuit2(): teleportation = QubitCircuit(3, num_cbits=2, input_states=["q0", "0", "0", "c0", "c1"]) teleportation.add_gate("SNOT", targets=[1]) teleportation.add_gate("CNOT", targets=[2], controls=[1]) teleportation.add_gate("CNOT", targets=[1], controls=[0]) teleportation.add_gate("SNOT", targets=[0]) teleportation.add_gate("CNOT", targets=[2], controls=[1]) teleportation.add_gate("CZ", targets=[2], controls=[0]) return teleportation
def test_collapse_with_different_tlist(self): """ Test if there are errors raised because of wrong tlist handling. """ qc = QubitCircuit(1) qc.add_gate("X", 0) proc = LinearSpinChain(1) proc.load_circuit(qc) tlist = np.linspace(0, 30., 100) coeff = tlist * 0.1 noise = DecoherenceNoise(sigmam(), targets=0, coeff=coeff, tlist=tlist) proc.add_noise(noise) proc.run_state(basis(2, 0))
def test_pulse_plotting(processor_class): try: import matplotlib.pyplot as plt except Exception: return True qc = QubitCircuit(3) qc.add_gate("CNOT", 1, 0) qc.add_gate("X", 1) processor = processor_class(3) processor.load_circuit(qc) fig, ax = processor.plot_pulses() plt.close(fig)
def test_globalphase_gate_propagators(self): qc = QubitCircuit(2) qc.add_gate("GLOBALPHASE", arg_value=np.pi / 2) [gate] = qc.gates assert gate.name == "GLOBALPHASE" assert gate.arg_value == np.pi / 2 [U_expanded] = qc.propagators() assert U_expanded == 1j * qp.qeye([2, 2]) [U_unexpanded] = qc.propagators(expand=False) assert U_unexpanded == 1j * qp.qeye([2, 2])
def test_add_circuit(self): """ Addition of a circuit to a `QubitCircuit` """ qc = QubitCircuit(6) qc.add_gate("CNOT", targets=[1], controls=[0]) test_gate = Gate("SWAP", targets=[1, 4]) qc.add_gate(test_gate) qc.add_gate("TOFFOLI", controls=[0, 1], targets=[2]) qc.add_gate("SNOT", targets=[3]) qc.add_gate(test_gate, index=[3]) qc.add_measurement("M0", targets=[0], classical_store=[1]) qc.add_1q_gate("RY", start=4, end=5, arg_value=1.570796) qc1 = QubitCircuit(6) qc1.add_circuit(qc) # Test if all gates and measurements are added assert len(qc1.gates) == len(qc.gates) for i in range(len(qc1.gates)): assert (qc1.gates[i].name == qc.gates[i].name) assert (qc1.gates[i].targets == qc.gates[i].targets) if (isinstance(qc1.gates[i], Gate) and isinstance(qc.gates[i], Gate)): assert (qc1.gates[i].controls == qc.gates[i].controls) assert (qc1.gates[i].classical_controls == qc.gates[i].classical_controls) elif (isinstance(qc1.gates[i], Measurement) and isinstance(qc.gates[i], Measurement)): assert (qc1.gates[i].classical_store == qc.gates[i].classical_store) # Test exception when qubit out of range pytest.raises(NotImplementedError, qc1.add_circuit, qc, start=4) qc2 = QubitCircuit(8) qc2.add_circuit(qc, start=2) # Test if all gates are added assert len(qc2.gates) == len(qc.gates) # Test if the positions are correct for i in range(len(qc2.gates)): if qc.gates[i].targets is not None: assert (qc2.gates[i].targets[0] == qc.gates[i].targets[0] + 2) if (isinstance(qc.gates[i], Gate) and qc.gates[i].controls is not None): assert (qc2.gates[i].controls[0] == qc.gates[i].controls[0] + 2)
def test_compiler_with_continous_pulse(spline_kind, schedule_mode): num_qubits = 2 circuit = QubitCircuit(num_qubits) circuit.add_gate("X", targets=0) circuit.add_gate("X", targets=1) circuit.add_gate("X", targets=0) processor = CircularSpinChain(num_qubits) gauss_compiler = MyCompiler( processor.N, processor.params, processor.pulse_dict) processor.load_circuit( circuit, schedule_mode = schedule_mode, compiler=gauss_compiler) result = processor.run_state(init_state = basis([2,2], [0,0])) assert(abs(fidelity(result.states[-1],basis([2,2],[0,1])) - 1) < 1.e-6)
def test_with_model(self): model = SpinChainModel(3, setup="linear") processor = OptPulseProcessor(3, model=model) qc = QubitCircuit(3) qc.add_gate("CNOT", 1, 0) qc.add_gate("X", 2) processor.load_circuit(qc, merge_gates=True, num_tslots=10, evo_time=2.0) init_state = qutip.rand_ket(8, dims=[[2, 2, 2], [1, 1, 1]]) num_result = processor.run_state(init_state=init_state).states[-1] ideal_result = qc.run(init_state) assert (pytest.approx(qutip.fidelity(num_result, ideal_result), 1.0e-5) == 1.0)
def test_compiler_without_pulse_dict(): """ Test for a compiler function without pulse_dict and using args. """ num_qubits = 2 circuit = QubitCircuit(num_qubits) circuit.add_gate("X", targets=[0]) circuit.add_gate("X", targets=[1]) processor = CircularSpinChain(num_qubits) compiler = SpinChainCompiler( num_qubits, params=processor.params, pulse_dict=None, setup="circular") compiler.gate_compiler["RX"] = rx_compiler_without_pulse_dict compiler.args = {"params": processor.params} processor.load_circuit(circuit, compiler=compiler) result = processor.run_state(basis([2,2], [0,0])) assert(abs(fidelity(result.states[-1], basis([2,2], [1,1])) - 1.) < 1.e-6 )
def test_export_image(self, in_temporary_directory): from qutip_qip import circuit_latex qc = QubitCircuit(2, reverse_states=False) qc.add_gate("CSIGN", controls=[0], targets=[1]) if "png" in circuit_latex.CONVERTERS: file_png200 = "exported_pic_200.png" file_png400 = "exported_pic_400.png" qc.draw("png", 200, file_png200.split('.')[0], "") qc.draw("png", 400.5, file_png400.split('.')[0], "") assert file_png200 in os.listdir('.') assert file_png400 in os.listdir('.') assert os.stat(file_png200).st_size < os.stat(file_png400).st_size if "svg" in circuit_latex.CONVERTERS: file_svg = "exported_pic.svg" qc.draw("svg", file_svg.split('.')[0], "") assert file_svg in os.listdir('.')
def single_crosstalk_simulation(num_gates): """ A single simulation, with num_gates representing the number of rotations. Args: num_gates (int): The number of random gates to add in the simulation. Returns: result (qutip.solver.Result): A qutip Result object obtained from any of the solver methods such as mesolve. """ num_qubits = 2 # Qubit-0 is the target qubit. Qubit-1 suffers from crosstalk. myprocessor = ModelProcessor(model=MyModel(num_qubits)) # Add qubit frequency detuning 1.852MHz for the second qubit. myprocessor.add_drift(2 * np.pi * (sigmaz() + 1) / 2 * 1.852, targets=1) myprocessor.native_gates = None # Remove the native gates mycompiler = MyCompiler(num_qubits, { "pulse_amplitude": 0.02, "duration": 25 }) myprocessor.add_noise(ClassicalCrossTalk(1.0)) # Define a randome circuit. gates_set = [ Gate("ROT", 0, arg_value=0), Gate("ROT", 0, arg_value=np.pi / 2), Gate("ROT", 0, arg_value=np.pi), Gate("ROT", 0, arg_value=np.pi / 2 * 3), ] circuit = QubitCircuit(num_qubits) for ind in np.random.randint(0, 4, num_gates): circuit.add_gate(gates_set[ind]) # Simulate the circuit. myprocessor.load_circuit(circuit, compiler=mycompiler) init_state = tensor( [Qobj([[init_fid, 0], [0, 0.025]]), Qobj([[init_fid, 0], [0, 0.025]])]) options = SolverOptions(nsteps=10000) # increase the maximal allowed steps e_ops = [tensor([qeye(2), fock_dm(2)])] # observable # compute results of the run using a solver of choice with custom options result = myprocessor.run_state(init_state, solver="mesolve", options=options, e_ops=e_ops) result = result.expect[0][-1] # measured expectation value at the end return result