def test_two_qubit_synthesis_not_pulse_optimal(self): """Verify not attempting pulse optimal decomposition when pulse_optimize==False.""" backend = FakeVigo() conf = backend.configuration() qr = QuantumRegister(2) coupling_map = CouplingMap([[0, 1], [1, 2], [1, 3], [3, 4]]) triv_layout_pass = TrivialLayout(coupling_map) qc = QuantumCircuit(qr) qc.unitary(random_unitary(4, seed=12), [0, 1]) unisynth_pass = UnitarySynthesis( basis_gates=conf.basis_gates, coupling_map=coupling_map, backend_props=backend.properties(), pulse_optimize=False, natural_direction=True, ) pm = PassManager([triv_layout_pass, unisynth_pass]) qc_out = pm.run(qc) if isinstance(qc_out, QuantumCircuit): num_ops = qc_out.count_ops() # pylint: disable=no-member else: num_ops = qc_out[0].count_ops() self.assertIn("sx", num_ops) self.assertGreaterEqual(num_ops["sx"], 16)
def test_hidden_identity_block(self): """Test that extracting linear functions and synthesizing them back results in an equivalent circuit when a linear block represents the identity matrix.""" # Create a circuit with multiple non-linear blocks circuit1 = QuantumCircuit(3) circuit1.h(0) circuit1.h(1) circuit1.h(2) circuit1.swap(0, 2) circuit1.swap(0, 2) circuit1.h(0) circuit1.h(1) circuit1.h(2) # collect linear functions circuit2 = PassManager(CollectLinearFunctions()).run(circuit1) # synthesize linear functions circuit3 = PassManager(LinearFunctionsSynthesis()).run(circuit2) # check that we have an equivalent circuit self.assertEqual(Operator(circuit1), Operator(circuit3))
def test_all_gates_in_basis_after_translation_with_target(self): """Test circuit with gates in basis after conditional translation.""" target = FakeBackend5QV2().target basis_gates = ["cx", "u"] property_set = {} analysis_pass = GatesInBasis(basis_gates, target) circuit = QuantumCircuit(2) circuit.h(0) circuit.cx(0, 1) circuit.measure_all() analysis_pass(circuit, property_set=property_set) self.assertFalse(property_set["all_gates_in_basis"]) pm = PassManager() pm.append(analysis_pass) pm.append( BasisTranslator(SessionEquivalenceLibrary, basis_gates, target=target), condition=lambda property_set: not property_set[ "all_gates_in_basis"], ) pm.append(analysis_pass) pm.run(circuit) self.assertTrue(pm.property_set["all_gates_in_basis"])
def test_expand_method(self, num_qubits_1, num_qubits_2): """Test expand method""" samples = 5 num_gates = 10 seed = 800 gates = 'all' for i in range(samples): circ1 = random_clifford_circuit(num_qubits_1, num_gates, gates=gates, seed=seed + i) circ2 = random_clifford_circuit(num_qubits_2, num_gates, gates=gates, seed=seed + samples + i) cliff1 = Clifford(circ1) cliff2 = Clifford(circ2) value = cliff1.expand(cliff2) circ = QuantumCircuit(num_qubits_1 + num_qubits_2) circ.append(circ1, range(num_qubits_1)) circ.append(circ2, range(num_qubits_1, num_qubits_1 + num_qubits_2)) target = Clifford(circ) self.assertEqual(target, value)
def test_repetetive_parameter_setting(self): """Test alternate setting of parameters and circuit construction.""" x = Parameter("x") circuit = QuantumCircuit(1) circuit.rx(x, 0) nlocal = NLocal(1, entanglement_blocks=circuit, reps=3, insert_barriers=True) with self.subTest(msg="immediately after initialization"): self.assertEqual(len(nlocal.parameters), 3) with self.subTest(msg="after circuit construction"): self.assertEqual(len(nlocal.parameters), 3) q = Parameter("q") nlocal.assign_parameters([x, q, q], inplace=True) with self.subTest(msg="setting parameter to Parameter objects"): self.assertEqual(nlocal.parameters, set({x, q})) nlocal.assign_parameters([0, -1], inplace=True) with self.subTest(msg="setting parameter to numbers"): self.assertEqual(nlocal.parameters, set())
def test_name_collision(self): """Name collision during ancilla allocation.""" qr_ancilla = QuantumRegister(3, 'ancilla') circuit = QuantumCircuit(qr_ancilla) circuit.h(qr_ancilla) dag = circuit_to_dag(circuit) initial_layout = Layout() initial_layout[0] = qr_ancilla[0] initial_layout[1] = qr_ancilla[1] initial_layout[2] = qr_ancilla[2] pass_ = FullAncillaAllocation(self.cmap5) pass_.property_set['layout'] = initial_layout pass_.run(dag) after_layout = pass_.property_set['layout'] qregs = {v.register for v in after_layout.get_virtual_bits().keys()} self.assertEqual(2, len(qregs)) self.assertIn(qr_ancilla, qregs) qregs.remove(qr_ancilla) other_reg = qregs.pop() self.assertEqual(len(other_reg), 2) self.assertRegex(other_reg.name, r'^ancilla\d+$')
def test_non_commutative_circuit_2(self): """A simple circuit where no gates commute qr0:----.------------- | qr1:---(+)------.----- | qr2:---[H]-----(+)---- """ qr = QuantumRegister(3, "qr") circuit = QuantumCircuit(qr) circuit.cx(qr[0], qr[1]) circuit.h(qr[2]) circuit.cx(qr[1], qr[2]) dag = circuit_to_dag(circuit) self.pass_.run(dag) expected = { qr[0]: [[0], [6], [1]], qr[1]: [[2], [6], [8], [3]], qr[2]: [[4], [7], [8], [5]], } self.assertCommutationSet(self.pset["commutation_set"], expected)
def test_run_path_with_expressions_multiple_params_per_instruction(self): """Test parameterized circuit path via backed.run()""" shots = 1000 backend = AerSimulator() circuit = QuantumCircuit(2) theta = Parameter('theta') theta_squared = theta * theta circuit.rx(theta, 0) circuit.cx(0, 1) circuit.rz(theta_squared, 1) circuit.u(theta, theta_squared, theta, 1) circuit.measure_all() parameter_binds = [{theta: [0, pi, 2 * pi]}] * 3 res = backend.run([circuit] * 3, shots=shots, parameter_binds=parameter_binds).result() counts = res.get_counts() self.assertEqual(counts, [{ '00': shots }, { '01': shots }, { '00': shots }] * 3)
def test_amplitude_damping_error(self): """Test amplitude damping error damps to correct state""" qr = QuantumRegister(1, 'qr') cr = ClassicalRegister(1, 'cr') circuit = QuantumCircuit(qr, cr) circuit.x(qr) # prepare + state for _ in range(30): # Add noisy identities circuit.barrier(qr) circuit.i(qr) circuit.barrier(qr) circuit.measure(qr, cr) shots = 4000 backend = AerSimulator() # test noise model error = amplitude_damping_error(0.75, 0.25) noise_model = NoiseModel() noise_model.add_all_qubit_quantum_error(error, 'id') # Execute target = {'0x0': 3 * shots / 4, '0x1': shots / 4} circuit = transpile(circuit, basis_gates=noise_model.basis_gates, optimization_level=0) result = backend.run(circuit, shots=shots, noise_model=noise_model).result() self.assertSuccess(result) self.compare_counts(result, [circuit], [target], delta=0.05 * shots)
def _define(self): """Calculate a subcircuit that implements this initialization Implements a recursive initialization algorithm, including optimizations, from "Synthesis of Quantum Logic Circuits" Shende, Bullock, Markov https://arxiv.org/abs/quant-ph/0406176v5 Additionally implements some extra optimizations: remove zero rotations and double cnots. """ # call to generate the circuit that takes the desired vector to zero disentangling_circuit = self.gates_to_uncompute() # invert the circuit to create the desired vector from zero (assuming # the qubits are in the zero state) initialize_gate = disentangling_circuit.to_instruction().inverse() q = QuantumRegister(self.num_qubits) initialize_circuit = QuantumCircuit(q) # TODO: make initialize an Instruction, and insert reset # TODO: avoid explicit reset if compiler determines a |0> state initialize_circuit.append(initialize_gate, q[:]) self.definition = initialize_circuit.data
def test_statevector(self, expression, good_states): """Circuit generation""" oracle = PhaseOracle(expression) num_qubits = oracle.num_qubits circuit = QuantumCircuit(num_qubits) circuit.h(range(num_qubits)) circuit.compose(oracle, inplace=True) statevector = Statevector.from_instruction(circuit) valid_state = -1 / sqrt(2**num_qubits) invalid_state = 1 / sqrt(2**num_qubits) states = list(range(2**num_qubits)) expected_valid = [state in good_states for state in states] result_valid = [ isclose(statevector.data[state], valid_state) for state in states ] expected_invalid = [state not in good_states for state in states] result_invalid = [ isclose(statevector.data[state], invalid_state) for state in states ] self.assertListEqual(expected_valid, result_valid) self.assertListEqual(expected_invalid, result_invalid)
def replace_q_indices(circuit, q_nums, qr): """ Take a circuit that is ordered from 0,1,2 qubits and replace 0 with the qubit label in the first index of q_nums, 1 with the second index... Args: circuit (QuantumCircuit): circuit to operate on q_nums (list): list of qubit indices qr (QuantumRegister): A quantum register to use for the output circuit Returns: QuantumCircuit: updated circuit """ new_circuit = QuantumCircuit(qr) bit_indices = {bit: index for index, bit in enumerate(circuit.qubits)} for instr, qargs, cargs in circuit.data: new_qargs = [ qr[q_nums[x]] for x in [bit_indices[arg] for arg in qargs] ] new_op = copy.deepcopy((instr, new_qargs, cargs)) new_circuit.data.append(new_op) return new_circuit
def get_ghz_po(self, n, delta): """ Get Parity Oscillation circuit """ circ, initial_layout = self.get_ghz_layout(n) q = QuantumRegister(n, 'q') rotate = QuantumCircuit(q) rotate.barrier() rotate.u2(delta, -delta, q) rotate.barrier() rotate = transpile(rotate, backend=self.backend, initial_layout=initial_layout) meas = self.get_measurement_circ(n, 'q', 'c', True) meas = transpile(meas, backend=self.backend, initial_layout=initial_layout) new_circ = circ + rotate + meas return new_circ, initial_layout
def dagdependency_to_circuit(dagdependency): """Build a ``QuantumCircuit`` object from a ``DAGDependency``. Args: dagdependency (DAGDependency): the input dag. Return: QuantumCircuit: the circuit representing the input dag dependency. """ name = dagdependency.name or None circuit = QuantumCircuit(*dagdependency.qregs.values(), *dagdependency.cregs.values(), name=name) circuit.calibrations = dagdependency.calibrations for node in dagdependency.get_nodes(): # Get arguments for classical control (if any) inst = node.op.copy() inst.condition = node.condition circuit._append(inst, node.qargs, node.cargs) return circuit
def setUp(self): super().setUp() # specify "run configuration" self.quantum_instance_sv = QuantumInstance( Aer.get_backend('statevector_simulator')) self.quantum_instance_qasm = QuantumInstance( Aer.get_backend('qasm_simulator'), shots=100) # define feature map and variational form num_qubits = 2 feature_map = ZZFeatureMap(num_qubits, reps=1) var_form = RealAmplitudes(num_qubits, reps=1) # construct circuit self.qc = QuantumCircuit(num_qubits) self.qc.append(feature_map, range(2)) self.qc.append(var_form, range(2)) # store params self.input_params = list(feature_map.parameters) self.weight_params = list(var_form.parameters) # define interpret functions def interpret_1d(x): return sum([s == '1' for s in '{0:0b}'.format(x)]) % 2 self.interpret_1d = interpret_1d self.output_shape_1d = 2 # takes values in {0, 1} def interpret_2d(x): return np.array([self.interpret_1d(x), 2 * self.interpret_1d(x)]) self.interpret_2d = interpret_2d self.output_shape_2d = ( 2, 3) # 1st dim. takes values in {0, 1} 2nd dim in {0, 1, 2}
def to_instruction(self): """Convert to Pauli circuit instruction.""" from math import pi pauli, phase = self._to_label(self.z, self.x, self._phase[0], full_group=False, return_phase=True) if len(pauli) == 1: gate = { 'I': IGate(), 'X': XGate(), 'Y': YGate(), 'Z': ZGate() }[pauli] else: gate = PauliGate(pauli) if not phase: return gate # Add global phase circuit = QuantumCircuit(self.num_qubits, name=str(self)) circuit.global_phase = -phase * pi / 2 circuit.append(gate, range(self.num_qubits)) return circuit.to_instruction()
def test_node_middle_of_blocks(self): """Test that a node surrounded by blocks stays in the same place This is a larger test to ensure multiple blocks can all be collected and added back in the correct order. blocks = [['cx', 'id'], ['cx', 'id'], ['id', 'cx'], ['id', 'cx']] q_0: |0>──■───────────────────■── ┌─┴─┐┌────┐ ┌────┐┌─┴─┐ q_1: |0>┤ X ├┤ Id ├─X─┤ Id ├┤ X ├ ├───┤├────┤ │ ├────┤├───┤ q_2: |0>┤ X ├┤ Id ├─X─┤ Id ├┤ X ├ └─┬─┘└────┘ └────┘└─┬─┘ q_3: |0>──■───────────────────■── """ qc = QuantumCircuit(4) qc.cx(0, 1) qc.cx(3, 2) qc.i(1) qc.i(2) qc.swap(1, 2) qc.i(1) qc.i(2) qc.cx(0, 1) qc.cx(3, 2) pass_manager = PassManager() pass_manager.append(Collect2qBlocks()) pass_manager.append(ConsolidateBlocks()) qc1 = transpile(qc, pass_manager=pass_manager) self.assertEqual(qc, qc1)
def test_list_op_parameters(self): """Test that Parameters are stored correctly in a List Operator""" lam = Parameter('λ') phi = Parameter('φ') omega = Parameter('ω') mat_op = PrimitiveOp([[0, 1], [1, 0]], coeff=omega) qc = QuantumCircuit(1) qc.rx(phi, 0) qc_op = PrimitiveOp(qc) op1 = SummedOp([mat_op, qc_op]) params = [phi, omega] self.assertEqual(op1.parameters, set(params)) # check list nesting case op2 = PrimitiveOp([[1, 0], [0, -1]], coeff=lam) list_op = ListOp([op1, op2]) params.append(lam) self.assertEqual(list_op.parameters, set(params))
def test_measure_to_registers_when_conditionals(self): """Verify assemble_circuits maps all measure ops on to a register slot for a circuit containing conditionals.""" qr = QuantumRegister(2) cr1 = ClassicalRegister(1) cr2 = ClassicalRegister(2) qc = QuantumCircuit(qr, cr1, cr2) qc.measure(qr[0], cr1) # Measure not required for a later conditional qc.measure(qr[1], cr2[1]) # Measure required for a later conditional qc.h(qr[1]).c_if(cr2, 3) qobj = assemble(qc) validate_qobj_against_schema(qobj) first_measure, second_measure = [ op for op in qobj.experiments[0].instructions if op.name == 'measure' ] self.assertTrue(hasattr(first_measure, 'register')) self.assertEqual(first_measure.register, first_measure.memory) self.assertTrue(hasattr(second_measure, 'register')) self.assertEqual(second_measure.register, second_measure.memory)
def pauli_evolution(self, pauli_string, time): """Get the evolution block for the given pauli string.""" # for some reason this is in reversed order pauli_string = pauli_string[::-1] # trim the pauli string if identities are included trimmed = [] indices = [] for i, pauli in enumerate(pauli_string): if pauli != "I": trimmed += [pauli] indices += [i] evo = QuantumCircuit(len(pauli_string)) if len(trimmed) == 0: return evo def basis_change(circuit, inverse=False): for i, pauli in enumerate(pauli_string): if pauli == "X": circuit.h(i) elif pauli == "Y": circuit.rx(-np.pi / 2 if inverse else np.pi / 2, i) def cx_chain(circuit, inverse=False): num_cx = len(indices) - 1 for i in reversed(range(num_cx)) if inverse else range(num_cx): circuit.cx(indices[i], indices[i + 1]) basis_change(evo) cx_chain(evo) evo.p(self.alpha * time, indices[-1]) cx_chain(evo, inverse=True) basis_change(evo, inverse=True) return evo
def _define(self): """Calculate a subcircuit that implements this initialization Implements a recursive initialization algorithm, including optimizations, from "Synthesis of Quantum Logic Circuits" Shende, Bullock, Markov https://arxiv.org/abs/quant-ph/0406176v5 Additionally implements some extra optimizations: remove zero rotations and double cnots. """ # call to generate the circuit that takes the desired vector to zero disentangling_circuit = self.gates_to_uncompute() # invert the circuit to create the desired vector from zero (assuming # the qubits are in the zero state) initialize_instr = disentangling_circuit.to_instruction().inverse() q = QuantumRegister(self.num_qubits, 'q') initialize_circuit = QuantumCircuit(q, name='init_def') for qubit in q: initialize_circuit.append(Reset(), [qubit]) initialize_circuit.append(initialize_instr, q[:]) self.definition = initialize_circuit.data
def get_ghz_mqc_para( self, n: int, full_measurement: bool = True ) -> Tuple[QuantumCircuit, Parameter, Dict]: """ Get a parametrized MQC circuit. Remember that get_counts() method accepts an index now, not a circuit Args: n: number of qubits full_measurement: Whether to append full measurement, or only on the first qubit Returns: The MQC circuit, its delta parameter, and the initial GHZ layout """ circ, initial_layout = self.get_ghz_layout(n) q = QuantumRegister(n, 'q') rotate = QuantumCircuit(q) delta = Parameter('t') rotate.barrier() rotate.u1(delta, q) rotate.barrier() rotate.x(q) rotate.barrier() rotate = transpile(rotate, backend=self.backend, initial_layout=initial_layout) meas = self.get_measurement_circ(n, 'q', 'c', full_measurement) meas = transpile(meas, backend=self.backend, initial_layout=initial_layout) new_circ = circ + rotate + circ.inverse() + meas return new_circ, delta, initial_layout
def repeat(self, n): """Creates an instruction with `gate` repeated `n` amount of times. Args: n (int): Number of times to repeat the instruction Returns: qiskit.circuit.Instruction: Containing the definition. Raises: CircuitError: If n < 1. """ if int(n) != n or n < 1: raise CircuitError( "Repeat can only be called with strictly positive integer.") n = int(n) instruction = self._return_repeat(n) qargs = [] if self.num_qubits == 0 else QuantumRegister( self.num_qubits, "q") cargs = [] if self.num_clbits == 0 else ClassicalRegister( self.num_clbits, "c") if instruction.definition is None: # pylint: disable=cyclic-import from qiskit import QuantumCircuit qc = QuantumCircuit() if qargs: qc.add_register(qargs) if cargs: qc.add_register(cargs) qc.data = [(self, qargs[:], cargs[:])] * n instruction.definition = qc return instruction
def test_successors_predecessors(self): """Test the method direct_successors.""" circuit = QuantumCircuit(self.qreg, self.creg) circuit.h(self.qreg[0]) circuit.x(self.qreg[0]) circuit.h(self.qreg[0]) circuit.x(self.qreg[1]) circuit.h(self.qreg[0]) circuit.measure(self.qreg[0], self.creg[0]) self.dag = circuit_to_dagdependency(circuit) dir_successors_second = self.dag.direct_successors(1) self.assertEqual(dir_successors_second, [2, 4]) dir_successors_fourth = self.dag.direct_successors(3) self.assertEqual(dir_successors_fourth, []) successors_second = self.dag.successors(1) self.assertEqual(successors_second, [2, 4, 5]) successors_fourth = self.dag.successors(3) self.assertEqual(successors_fourth, []) dir_predecessors_sixth = self.dag.direct_predecessors(5) self.assertEqual(dir_predecessors_sixth, [2, 4]) dir_predecessors_fourth = self.dag.direct_predecessors(3) self.assertEqual(dir_predecessors_fourth, []) predecessors_sixth = self.dag.predecessors(5) self.assertEqual(predecessors_sixth, [0, 1, 2, 4]) predecessors_fourth = self.dag.predecessors(3) self.assertEqual(predecessors_fourth, [])
def test_blocks_in_topological_order(self): """the pass returns blocks in correct topological order ______ q0:--[u1]-------.---- q0:-------------| |-- | ______ | U2 | q1:--[u2]--(+)-(+)--- = q1:---| |--|______|-- | | U1 | q2:---------.-------- q2:---|______|------------ """ qr = QuantumRegister(3, "qr") qc = QuantumCircuit(qr) qc.u1(0.5, qr[0]) qc.u2(0.2, 0.6, qr[1]) qc.cx(qr[2], qr[1]) qc.cx(qr[0], qr[1]) dag = circuit_to_dag(qc) topo_ops = list(dag.topological_op_nodes()) block_1 = [topo_ops[1], topo_ops[2]] block_2 = [topo_ops[0], topo_ops[3]] pass_ = Collect2qBlocks() pass_.run(dag) self.assertTrue(pass_.property_set['block_list'], [block_1, block_2])
def _gate_rules_to_qiskit_circuit(self, node, params): """From a gate definition in qasm, to a QuantumCircuit format.""" rules = [] qreg = QuantumRegister(node['n_bits']) bit_args = {node['bits'][i]: q for i, q in enumerate(qreg)} exp_args = {node['args'][i]: Real(q) for i, q in enumerate(params)} for child_op in node['body'].children: qparams = [] eparams = [] for param_list in child_op.children[1:]: if param_list.type == 'id_list': qparams = [ bit_args[param.name] for param in param_list.children ] elif param_list.type == 'expression_list': for param in param_list.children: eparams.append(param.sym(nested_scope=[exp_args])) op = self._create_op(child_op.name, params=eparams) rules.append((op, qparams, [])) circ = QuantumCircuit(qreg) for instr, qargs, cargs in rules: circ._append(instr, qargs, cargs) return circ
def test_pauli_op_to_circuit(self): """Test PauliOp.to_circuit()""" with self.subTest("single Pauli"): pauli = PauliOp(Pauli("Y")) expected = QuantumCircuit(1) expected.y(0) self.assertEqual(pauli.to_circuit(), expected) with self.subTest("single Pauli with phase"): pauli = PauliOp(Pauli("-iX")) expected = QuantumCircuit(1) expected.x(0) expected.global_phase = -pi / 2 self.assertEqual(Operator(pauli.to_circuit()), Operator(expected)) with self.subTest("two qubit"): pauli = PauliOp(Pauli("IX")) expected = QuantumCircuit(2) expected.pauli("IX", range(2)) self.assertEqual(pauli.to_circuit(), expected) expected = QuantumCircuit(2) expected.x(0) expected.id(1) self.assertEqual(pauli.to_circuit().decompose(), expected) with self.subTest("two qubit with phase"): pauli = PauliOp(Pauli("iXZ")) expected = QuantumCircuit(2) expected.pauli("XZ", range(2)) expected.global_phase = pi / 2 self.assertEqual(pauli.to_circuit(), expected) expected = QuantumCircuit(2) expected.z(0) expected.x(1) expected.global_phase = pi / 2 self.assertEqual(pauli.to_circuit().decompose(), expected)
RYYGate, ECRGate, ZGate, CZGate, ) _sel = StandardEquivalenceLibrary = EquivalenceLibrary() # Import existing gate definitions # HGate q = QuantumRegister(1, "q") def_h = QuantumCircuit(q) def_h.append(U2Gate(0, pi), [q[0]], []) _sel.add_equivalence(HGate(), def_h) # CHGate q = QuantumRegister(2, "q") def_ch = QuantumCircuit(q) for inst, qargs, cargs in [ (SGate(), [q[1]], []), (HGate(), [q[1]], []), (TGate(), [q[1]], []), (CXGate(), [q[0], q[1]], []), (TdgGate(), [q[1]], []), (HGate(), [q[1]], []), (SdgGate(), [q[1]], []),
def test_asian_barrier_spread(self): """Test the asian barrier spread model.""" try: from qiskit.aqua.circuits import WeightedSumOperator, FixedValueComparator as Comparator from qiskit.aqua.components.uncertainty_problems import ( UnivariatePiecewiseLinearObjective as PwlObjective, MultivariateProblem) from qiskit.aqua.components.uncertainty_models import MultivariateLogNormalDistribution except ImportError: import warnings warnings.warn( 'Qiskit Aqua is not installed, skipping the application test.') return # number of qubits per dimension to represent the uncertainty num_uncertainty_qubits = 2 # parameters for considered random distribution spot_price = 2.0 # initial spot price volatility = 0.4 # volatility of 40% interest_rate = 0.05 # annual interest rate of 5% time_to_maturity = 40 / 365 # 40 days to maturity # resulting parameters for log-normal distribution # pylint: disable=invalid-name mu = ((interest_rate - 0.5 * volatility**2) * time_to_maturity + np.log(spot_price)) sigma = volatility * np.sqrt(time_to_maturity) mean = np.exp(mu + sigma**2 / 2) variance = (np.exp(sigma**2) - 1) * np.exp(2 * mu + sigma**2) stddev = np.sqrt(variance) # lowest and highest value considered for the spot price; in between, # an equidistant discretization is considered. low = np.maximum(0, mean - 3 * stddev) high = mean + 3 * stddev # map to higher dimensional distribution # for simplicity assuming dimensions are independent and identically distributed) dimension = 2 num_qubits = [num_uncertainty_qubits] * dimension low = low * np.ones(dimension) high = high * np.ones(dimension) mu = mu * np.ones(dimension) cov = sigma**2 * np.eye(dimension) # construct circuit factory distribution = MultivariateLogNormalDistribution(num_qubits=num_qubits, low=low, high=high, mu=mu, cov=cov) # determine number of qubits required to represent total loss weights = [] for n in num_qubits: for i in range(n): weights += [2**i] num_sum_qubits = WeightedSumOperator.get_required_sum_qubits(weights) # create circuit factoy agg = WeightedSumOperator(sum(num_qubits), weights) # set the strike price (should be within the low and the high value of the uncertainty) strike_price_1 = 3 strike_price_2 = 4 # set the barrier threshold barrier = 2.5 # map strike prices and barrier threshold from [low, high] to {0, ..., 2^n-1} max_value = 2**num_sum_qubits - 1 low_ = low[0] high_ = high[0] mapped_strike_price_1 = (strike_price_1 - dimension*low_) / \ (high_ - low_) * (2**num_uncertainty_qubits - 1) mapped_strike_price_2 = (strike_price_2 - dimension*low_) / \ (high_ - low_) * (2**num_uncertainty_qubits - 1) mapped_barrier = (barrier - low) / (high - low) * (2**num_uncertainty_qubits - 1) conditions = [] for i in range(dimension): # target dimension of random distribution and corresponding condition conditions += [(i, Comparator(num_qubits[i], mapped_barrier[i] + 1, geq=False))] # set the approximation scaling for the payoff function c_approx = 0.25 # setup piecewise linear objective fcuntion breakpoints = [0, mapped_strike_price_1, mapped_strike_price_2] slopes = [0, 1, 0] offsets = [0, 0, mapped_strike_price_2 - mapped_strike_price_1] f_min = 0 f_max = mapped_strike_price_2 - mapped_strike_price_1 bull_spread_objective = PwlObjective(num_sum_qubits, 0, max_value, breakpoints, slopes, offsets, f_min, f_max, c_approx) # define overall multivariate problem asian_barrier_spread = MultivariateProblem(distribution, agg, bull_spread_objective, conditions=conditions) num_req_qubits = asian_barrier_spread.num_target_qubits num_req_ancillas = asian_barrier_spread.required_ancillas() qr = QuantumRegister(num_req_qubits, name='q') qr_ancilla = QuantumRegister(num_req_ancillas, name='q_a') qc = QuantumCircuit(qr, qr_ancilla) asian_barrier_spread.build(qc, qr, qr_ancilla) job = execute(qc, backend=BasicAer.get_backend('statevector_simulator')) # evaluate resulting statevector value = 0 for i, amplitude in enumerate(job.result().get_statevector()): b = ('{0:0%sb}' % asian_barrier_spread.num_target_qubits ).format(i)[-asian_barrier_spread.num_target_qubits:] prob = np.abs(amplitude)**2 if prob > 1e-4 and b[0] == '1': value += prob # all other states should have zero probability due to ancilla qubits if i > 2**num_req_qubits: break # map value to original range mapped_value = asian_barrier_spread.value_to_estimation(value) / ( 2**num_uncertainty_qubits - 1) * (high_ - low_) expected = 0.83188 self.assertAlmostEqual(mapped_value, expected, places=5)
def test_compose_classical(self): """Composing on classical bits. ┌───┐ ┌─────┐┌─┐ lqr_1_0: |0>───┤ H ├─── rqr_0: |0>──■──┤ Tdg ├┤M├ ├───┤ ┌─┴─┐└─┬─┬─┘└╥┘ lqr_1_1: |0>───┤ X ├─── rqr_1: |0>┤ X ├──┤M├───╫─ ┌──┴───┴──┐ └───┘ └╥┘ ║ lqr_1_2: |0>┤ U1(0.1) ├ + rcr_0: 0 ════════╬════╩═ = └─────────┘ ║ lqr_2_0: |0>─────■───── rcr_1: 0 ════════╩══════ ┌─┴─┐ lqr_2_1: |0>───┤ X ├─── └───┘ lcr_0: 0 ══════════════ lcr_1: 0 ══════════════ ┌───┐ lqr_1_0: |0>───┤ H ├────────────────── ├───┤ ┌─────┐┌─┐ lqr_1_1: |0>───┤ X ├─────■──┤ Tdg ├┤M├ ┌──┴───┴──┐ │ └─────┘└╥┘ lqr_1_2: |0>┤ U1(0.1) ├──┼──────────╫─ └─────────┘ │ ║ lqr_2_0: |0>─────■───────┼──────────╫─ ┌─┴─┐ ┌─┴─┐ ┌─┐ ║ lqr_2_1: |0>───┤ X ├───┤ X ├──┤M├───╫─ └───┘ └───┘ └╥┘ ║ lcr_0: 0 ═══════════════════╩════╬═ ║ lcr_1: 0 ════════════════════════╩═ """ qreg = QuantumRegister(2, 'rqr') creg = ClassicalRegister(2, 'rcr') right_qubit0 = qreg[0] right_qubit1 = qreg[1] right_clbit0 = creg[0] right_clbit1 = creg[1] circuit_right = QuantumCircuit(qreg, creg) circuit_right.cx(qreg[0], qreg[1]) circuit_right.tdg(qreg[0]) circuit_right.measure(qreg, creg) dag_left = circuit_to_dag(self.circuit_left) dag_right = circuit_to_dag(circuit_right) # permuted subset of qubits and clbits dag_left.compose(dag_right, edge_map={right_qubit0: self.left_qubit1, right_qubit1: self.left_qubit4, right_clbit0: self.left_clbit1, right_clbit1: self.left_clbit0}) circuit_composed = dag_to_circuit(dag_left) circuit_expected = self.circuit_left.copy() circuit_expected.cx(self.left_qubit1, self.left_qubit4) circuit_expected.tdg(self.left_qubit1) circuit_expected.measure(self.left_qubit4, self.left_clbit0) circuit_expected.measure(self.left_qubit1, self.left_clbit1) self.assertEqual(circuit_composed, circuit_expected)