def test_rescaling(self): """Test the rescaling.""" amplitude = 0.8 scaling = 0.25 circuit = QuantumCircuit(1) circuit.ry(2 * np.arcsin(amplitude), 0) problem = EstimationProblem(circuit, objective_qubits=[0]) rescaled = problem.rescale(scaling) rescaled_amplitude = Statevector.from_instruction(rescaled.state_preparation).data[3] self.assertAlmostEqual(scaling * amplitude, rescaled_amplitude)
def test_iqae_confidence_intervals(self): """End-to-end test for the IQAE confidence interval.""" n = 3 qae = IterativeAmplitudeEstimation(0.1, 0.01, quantum_instance=self._statevector) expected_confint = (0.1984050, 0.3511015) estimation_problem = EstimationProblem(SineIntegral(n), objective_qubits=[n]) # statevector simulator result = qae.estimate(estimation_problem) self.assertGreaterEqual(self._statevector.time_taken, 0.) self._statevector.reset_execution_results() confint = result.confidence_interval # confidence interval based on statevector should be empty, as we are sure of the result self.assertAlmostEqual(confint[1] - confint[0], 0.0) self.assertAlmostEqual(confint[0], result.estimation) # qasm simulator shots = 100 qae.quantum_instance = self._qasm(shots) result = qae.estimate(estimation_problem) confint = result.confidence_interval np.testing.assert_array_almost_equal(confint, expected_confint) self.assertTrue(confint[0] <= result.estimation <= confint[1])
def test_iqae_circuits(self, efficient_circuit): """Test circuits resulting from iterative amplitude estimation. Build the circuit manually and from the algorithm and compare the resulting unitaries. """ prob = 0.5 problem = EstimationProblem(BernoulliStateIn(prob), objective_qubits=[0]) for k in [2, 5]: qae = IterativeAmplitudeEstimation(0.01, 0.05) angle = 2 * np.arcsin(np.sqrt(prob)) # manually set up the inefficient AE circuit q_objective = QuantumRegister(1, "q") circuit = QuantumCircuit(q_objective) # A operator circuit.ry(angle, q_objective) if efficient_circuit: qae.grover_operator = BernoulliGrover(prob) circuit.ry(2 * k * angle, q_objective[0]) else: oracle = QuantumCircuit(1) oracle.z(0) state_preparation = QuantumCircuit(1) state_preparation.ry(angle, 0) grover_op = GroverOperator(oracle, state_preparation) grover_op.global_phase = np.pi for _ in range(k): circuit.compose(grover_op, inplace=True) actual_circuit = qae.construct_circuit(problem, k, measurement=False) self.assertEqual(Operator(circuit), Operator(actual_circuit))
def test_confidence_intervals(self, qae, key, expect): """End-to-end test for all confidence intervals.""" n = 3 qae.quantum_instance = self._statevector estimation_problem = EstimationProblem(SineIntegral(n), objective_qubits=[n]) # statevector simulator result = qae.estimate(estimation_problem) self.assertGreater(self._statevector.time_taken, 0.0) self._statevector.reset_execution_results() methods = ["lr", "fi", "oi"] # short for likelihood_ratio, fisher, observed_fisher alphas = [0.1, 0.00001, 0.9] # alpha shouldn't matter in statevector for alpha, method in zip(alphas, methods): confint = qae.compute_confidence_interval(result, alpha, method) # confidence interval based on statevector should be empty, as we are sure of the result self.assertAlmostEqual(confint[1] - confint[0], 0.0) self.assertAlmostEqual(confint[0], getattr(result, key)) # qasm simulator shots = 100 alpha = 0.01 qae.quantum_instance = self._qasm(shots) result = qae.estimate(estimation_problem) for method, expected_confint in expect.items(): confint = qae.compute_confidence_interval(result, alpha, method) np.testing.assert_array_almost_equal(confint, expected_confint) self.assertTrue(confint[0] <= getattr(result, key) <= confint[1])
def test_good_state(self, backend_str, expect): """Test with a good state function.""" def is_good_state(bitstr): return bitstr[1] == "1" # construct the estimation problem where the second qubit is ignored a_op = QuantumCircuit(2) a_op.ry(2 * np.arcsin(np.sqrt(0.2)), 0) # oracle only affects first qubit oracle = QuantumCircuit(2) oracle.z(0) # reflect only on first qubit q_op = GroverOperator(oracle, a_op, reflection_qubits=[0]) # but we measure both qubits (hence both are objective qubits) problem = EstimationProblem( a_op, objective_qubits=[0, 1], grover_operator=q_op, is_good_state=is_good_state ) # construct algo backend = QuantumInstance( BasicAer.get_backend(backend_str), seed_simulator=2, seed_transpiler=2 ) # cannot use rescaling with a custom grover operator fae = FasterAmplitudeEstimation(0.01, 5, rescale=False, quantum_instance=backend) # run the algo result = fae.estimate(problem) # assert the result is correct self.assertAlmostEqual(result.estimation, expect, places=5)
def test_run_without_rescaling(self): """Run Faster AE without rescaling if the amplitude is in [0, 1/4].""" # construct estimation problem prob = 0.11 a_op = QuantumCircuit(1) a_op.ry(2 * np.arcsin(np.sqrt(prob)), 0) problem = EstimationProblem(a_op, objective_qubits=[0]) # construct algo without rescaling backend = BasicAer.get_backend('statevector_simulator') fae = FasterAmplitudeEstimation(0.1, 1, rescale=False, quantum_instance=backend) # run the algo result = fae.estimate(problem) # assert the result is correct self.assertAlmostEqual(result.estimation, prob) # assert no rescaling was used theta = np.mean(result.theta_intervals[-1]) value_without_scaling = np.sin(theta)**2 self.assertAlmostEqual(result.estimation, value_without_scaling)
def test_application(self): """Test an end-to-end application.""" from qiskit import Aer num_qubits = 3 # parameters for considered random distribution s_p = 2.0 # initial spot price vol = 0.4 # volatility of 40% r = 0.05 # annual interest rate of 4% t_m = 40 / 365 # 40 days to maturity # resulting parameters for log-normal distribution mu = (r - 0.5 * vol**2) * t_m + np.log(s_p) sigma = vol * np.sqrt(t_m) 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 bounds = (low, high) # construct circuit for uncertainty model uncertainty_model = LogNormalDistribution(num_qubits, mu=mu, sigma=sigma**2, bounds=bounds).decompose() # set the strike price (should be within the low and the high value of the uncertainty) strike_price = 1.896 # create amplitude function european_call_delta = EuropeanCallDeltaObjective( num_state_qubits=num_qubits, strike_price=strike_price, bounds=bounds) # create state preparation state_preparation = european_call_delta.compose(uncertainty_model, front=True) problem = EstimationProblem( state_preparation=state_preparation, objective_qubits=[num_qubits], post_processing=european_call_delta.post_processing, ) # run amplitude estimation q_i = QuantumInstance(Aer.get_backend("aer_simulator"), seed_simulator=125, seed_transpiler=80) iae = IterativeAmplitudeEstimation(epsilon_target=0.01, alpha=0.05, quantum_instance=q_i) result = iae.estimate(problem) self.assertAlmostEqual(result.estimation_processed, 0.8088790606143996)
def test_qasm(self, prob, shots, qae, expect): """ qasm test """ qae.quantum_instance = self._qasm(shots) problem = EstimationProblem(BernoulliStateIn(prob), [0], BernoulliGrover(prob)) result = qae.estimate(problem) for key, value in expect.items(): self.assertAlmostEqual(value, getattr(result, key), places=3, msg="estimate `{}` failed".format(key))
def test_qasm(self, n, shots, qae, expect): """QASM simulator end-to-end test.""" # construct factories for A and Q qae.quantum_instance = self._qasm(shots) estimation_problem = EstimationProblem(SineIntegral(n), objective_qubits=[n]) result = qae.estimate(estimation_problem) for key, value in expect.items(): self.assertAlmostEqual(value, getattr(result, key), places=3, msg="estimate `{}` failed".format(key))
def test_statevector(self, prob, qae, expect): """statevector test""" qae.quantum_instance = self._statevector problem = EstimationProblem(BernoulliStateIn(prob), 0, BernoulliGrover(prob)) result = qae.estimate(problem) self._statevector.reset_execution_results() for key, value in expect.items(): self.assertAlmostEqual( value, getattr(result, key), places=3, msg=f"estimate `{key}` failed" )
def test_application(self): """Test an end-to-end application.""" try: from qiskit import ( Aer, ) # pylint: disable=unused-import,import-outside-toplevel except ImportError as ex: # pylint: disable=broad-except self.skipTest( "Aer doesn't appear to be installed. Error: '{}'".format( str(ex))) return a_n = np.eye(2) b = np.zeros(2) num_qubits = [2, 2] # specify the lower and upper bounds for the different dimension bounds = [(0, 0.12), (0, 0.24)] mu = [0.12, 0.24] sigma = 0.01 * np.eye(2) # construct corresponding distribution dist = NormalDistribution(num_qubits, mu, sigma, bounds=bounds) # specify cash flow c_f = [1.0, 2.0] # specify approximation factor rescaling_factor = 0.125 # get fixed income circuit appfactory fixed_income = FixedIncomePricingObjective(num_qubits, a_n, b, c_f, rescaling_factor, bounds) # build state preparation operator state_preparation = fixed_income.compose(dist, front=True) problem = EstimationProblem( state_preparation=state_preparation, objective_qubits=[4], post_processing=fixed_income.post_processing, ) # run simulation q_i = QuantumInstance(Aer.get_backend("qasm_simulator"), seed_simulator=2, seed_transpiler=2) iae = IterativeAmplitudeEstimation(epsilon_target=0.01, alpha=0.05, quantum_instance=q_i) result = iae.estimate(problem) # compare to precomputed solution self.assertAlmostEqual(result.estimation_processed, 2.3389012822103044)
def test_qae_circuit(self, efficient_circuit): """Test circuits resulting from canonical amplitude estimation. Build the circuit manually and from the algorithm and compare the resulting unitaries. """ prob = 0.5 problem = EstimationProblem(BernoulliStateIn(prob), objective_qubits=[0]) for m in [2, 5]: qae = AmplitudeEstimation(m) angle = 2 * np.arcsin(np.sqrt(prob)) # manually set up the inefficient AE circuit qr_eval = QuantumRegister(m, "a") qr_objective = QuantumRegister(1, "q") circuit = QuantumCircuit(qr_eval, qr_objective) # initial Hadamard gates for i in range(m): circuit.h(qr_eval[i]) # A operator circuit.ry(angle, qr_objective) if efficient_circuit: qae.grover_operator = BernoulliGrover(prob) for power in range(m): circuit.cry(2 * 2**power * angle, qr_eval[power], qr_objective[0]) else: oracle = QuantumCircuit(1) oracle.z(0) state_preparation = QuantumCircuit(1) state_preparation.ry(angle, 0) grover_op = GroverOperator(oracle, state_preparation) grover_op.global_phase = np.pi for power in range(m): circuit.compose( grover_op.power(2**power).control(), qubits=[qr_eval[power], qr_objective[0]], inplace=True, ) # fourier transform iqft = QFT(m, do_swaps=False).inverse().reverse_bits() circuit.append(iqft.to_instruction(), qr_eval) actual_circuit = qae.construct_circuit(problem, measurement=False) self.assertEqual(Operator(circuit), Operator(actual_circuit))
def test_statevector(self, n, qae, expect): """Statevector end-to-end test""" # construct factories for A and Q # qae.state_preparation = SineIntegral(n) qae.quantum_instance = self._statevector estimation_problem = EstimationProblem(SineIntegral(n), objective_qubits=[n]) # result = qae.run(self._statevector) result = qae.estimate(estimation_problem) self._statevector.reset_execution_results() for key, value in expect.items(): self.assertAlmostEqual( value, getattr(result, key), places=3, msg=f"estimate `{key}` failed" )
def test_rescaling_with_custom_grover_raises(self): """Test that the rescaling option fails if a custom Grover operator is used.""" prob = 0.8 a_op = BernoulliStateIn(prob) q_op = BernoulliGrover(prob) problem = EstimationProblem(a_op, objective_qubits=[0], grover_operator=q_op) # construct algo without rescaling backend = BasicAer.get_backend("statevector_simulator") fae = FasterAmplitudeEstimation(0.1, 1, quantum_instance=backend) # run the algo with self.assertWarns(Warning): _ = fae.estimate(problem)
def test_mlae_circuits(self, efficient_circuit): """ Test the circuits constructed for MLAE """ prob = 0.5 problem = EstimationProblem(BernoulliStateIn(prob), objective_qubits=[0]) for k in [2, 5]: qae = MaximumLikelihoodAmplitudeEstimation(k) angle = 2 * np.arcsin(np.sqrt(prob)) # compute all the circuits used for MLAE circuits = [] # 0th power q_objective = QuantumRegister(1, 'q') circuit = QuantumCircuit(q_objective) circuit.ry(angle, q_objective) circuits += [circuit] # powers of 2 for power in range(k): q_objective = QuantumRegister(1, 'q') circuit = QuantumCircuit(q_objective) # A operator circuit.ry(angle, q_objective) # Q^(2^j) operator if efficient_circuit: qae.grover_operator = BernoulliGrover(prob) circuit.ry(2 * 2**power * angle, q_objective[0]) else: oracle = QuantumCircuit(1) oracle.z(0) state_preparation = QuantumCircuit(1) state_preparation.ry(angle, 0) grover_op = GroverOperator(oracle, state_preparation) grover_op.global_phase = np.pi for _ in range(2**power): circuit.compose(grover_op, inplace=True) circuits += [circuit] actual_circuits = qae.construct_circuits(problem, measurement=False) for actual, expected in zip(actual_circuits, circuits): self.assertEqual(Operator(actual), Operator(expected))
def test_application(self): """Test an end-to-end application.""" from qiskit import Aer bounds = np.array([0.0, 7.0]) num_qubits = 3 # the distribution circuit is a normal distribution plus a QGAN-trained ansatz circuit dist = NormalDistribution(num_qubits, mu=1, sigma=1, bounds=bounds) ansatz = TwoLocal(num_qubits, "ry", "cz", reps=1, entanglement="circular") trained_params = [ 0.29399714, 0.38853322, 0.9557694, 0.07245791, 6.02626428, 0.13537225, ] ansatz.assign_parameters(trained_params, inplace=True) dist.compose(ansatz, inplace=True) # create the European call expected value strike_price = 2 rescaling_factor = 0.25 european_call = EuropeanCallPricingObjective( num_state_qubits=num_qubits, strike_price=strike_price, rescaling_factor=rescaling_factor, bounds=bounds, ) # create the state preparation circuit state_preparation = european_call.compose(dist, front=True) problem = EstimationProblem( state_preparation=state_preparation, objective_qubits=[num_qubits], post_processing=european_call.post_processing, ) q_i = QuantumInstance( Aer.get_backend("aer_simulator"), seed_simulator=125, seed_transpiler=80 ) iae = IterativeAmplitudeEstimation(epsilon_target=0.01, alpha=0.05, quantum_instance=q_i) result = iae.estimate(problem) self.assertAlmostEqual(result.estimation_processed, 1.0364776997977694)
def test_application(self): """Test an end-to-end application.""" try: from qiskit import Aer # pylint: disable=unused-import,import-outside-toplevel except ImportError as ex: # pylint: disable=broad-except self.skipTest("Aer doesn't appear to be installed. Error: '{}'".format(str(ex))) return bounds = np.array([0., 7.]) num_qubits = 3 # the distribution circuit is a normal distribution plus a QGAN-trained ansatz circuit dist = NormalDistribution(num_qubits, mu=1, sigma=1, bounds=bounds) ansatz = TwoLocal(num_qubits, 'ry', 'cz', reps=1, entanglement='circular') trained_params = [0.29399714, 0.38853322, 0.9557694, 0.07245791, 6.02626428, 0.13537225] ansatz.assign_parameters(trained_params, inplace=True) dist.compose(ansatz, inplace=True) # create the European call expected value strike_price = 2 rescaling_factor = 0.25 european_call = EuropeanCallPricingObjective(num_state_qubits=num_qubits, strike_price=strike_price, rescaling_factor=rescaling_factor, bounds=bounds) # create the state preparation circuit state_preparation = european_call.compose(dist, front=True) problem = EstimationProblem(state_preparation=state_preparation, objective_qubits=[num_qubits], post_processing=european_call.post_processing) q_i = QuantumInstance(Aer.get_backend('qasm_simulator'), seed_simulator=125, seed_transpiler=80) iae = IterativeAmplitudeEstimation(epsilon_target=0.01, alpha=0.05, quantum_instance=q_i) result = iae.estimate(problem) self.assertAlmostEqual(result.estimation_processed, 1.0127253837345427)
def test_distribution_load(self): """ Test that calculates a cumulative probability from the P&L distribution.""" correl = ft.get_correl("AAPL", "MSFT") bounds_std = 3.0 num_qubits = [3, 3] sigma = correl bounds = [(-bounds_std, bounds_std), (-bounds_std, bounds_std)] mu = [0, 0] # starting point is a multi-variate normal distribution normal = NormalDistribution(num_qubits, mu=mu, sigma=sigma, bounds=bounds) pl_set = [] coeff_set = [] for ticker in ["MSFT", "AAPL"]: ((cdf_x, cdf_y), sigma) = ft.get_cdf_data(ticker) (x, y) = ft.get_fit_data(ticker, norm_to_rel=False) (pl, coeffs) = ft.fit_piecewise_linear(x, y) # scale, to apply an arbitrary delta (we happen to use the same value here, but could be different) coeffs = ft.scaled_coeffs(coeffs, 1.2) pl_set.append(lambda z: ft.piecewise_linear(z, *coeffs)) coeff_set.append(coeffs) # calculate the max and min P&Ls p_max = max(pl_set[0](bounds_std), pl_set[1](bounds_std)) p_min = min(pl_set[0](-bounds_std), pl_set[1](-bounds_std)) # we discretise the transforms and create the circuits transforms = [] i_to_js = [] for i, ticker in enumerate(["MSFT", "AAPL"]): (i_0, i_1, a0, a1, a2, b0, b1, b2, i_to_j, i_to_x, j_to_y) = ft.integer_piecewise_linear_coeffs(coeff_set[i], x_min=-bounds_std, x_max=bounds_std, y_min=p_min, y_max=p_max) transforms.append( PiecewiseLinearTransform3(i_0, i_1, a0, a1, a2, b0, b1, b2)) i_to_js.append(np.vectorize(i_to_j)) i1, i2 = get_sims(normal) j1 = i_to_js[0](i1) j2 = i_to_js[1](i2) j_tot = j1 + j2 num_ancillas = transforms[0].num_ancilla_qubits qr_input = QuantumRegister(6, 'input') # 2 times 3 registers qr_objective = QuantumRegister(1, 'objective') qr_result = QuantumRegister(6, 'result') qr_ancilla = QuantumRegister(num_ancillas, 'ancilla') #output = ClassicalRegister(6, 'output') state_preparation = QuantumCircuit(qr_input, qr_objective, qr_result, qr_ancilla) #, output) state_preparation.append(normal, qr_input) for i in range(2): offset = i * 3 state_preparation.append( transforms[i], qr_input[offset:offset + 3] + qr_result[:] + qr_ancilla[:]) # to calculate the cdf, we use an additional comparator x_eval = 4 comparator = IntegerComparator(len(qr_result), x_eval + 1, geq=False) state_preparation.append( comparator, qr_result[:] + qr_objective[:] + qr_ancilla[0:comparator.num_ancillas]) # now check check = False if check: job = execute(state_preparation, backend=Aer.get_backend('statevector_simulator')) var_prob = 0 for i, a in enumerate(job.result().get_statevector()): b = ('{0:0%sb}' % (len(qr_input) + 1)).format(i)[-(len(qr_input) + 1):] prob = np.abs(a)**2 if prob > 1e-6 and b[0] == '1': var_prob += prob print('Operator CDF(%s)' % x_eval + ' = %.4f' % var_prob) # now do AE problem = EstimationProblem(state_preparation=state_preparation, objective_qubits=[len(qr_input)]) # target precision and confidence level epsilon = 0.01 alpha = 0.05 qi = QuantumInstance(Aer.get_backend('aer_simulator'), shots=100) ae_cdf = IterativeAmplitudeEstimation(epsilon, alpha=alpha, quantum_instance=qi) result_cdf = ae_cdf.estimate(problem) conf_int = np.array(result_cdf.confidence_interval) print('Estimated value:\t%.4f' % result_cdf.estimation) print('Confidence interval: \t[%.4f, %.4f]' % tuple(conf_int)) state_preparation.draw()
def test_readme_sample(self): """ readme sample test """ # pylint: disable=import-outside-toplevel,redefined-builtin def print(*args): """ overloads print to log values """ if args: self.log.debug(args[0], *args[1:]) # --- Exact copy of sample code ---------------------------------------- import numpy as np from qiskit import BasicAer from qiskit.algorithms import AmplitudeEstimation, EstimationProblem from qiskit.circuit.library import NormalDistribution from qiskit_finance.applications import FixedIncomeExpectedValue # Create a suitable multivariate distribution num_qubits = [2, 2] bounds = [(0, 0.12), (0, 0.24)] mvnd = NormalDistribution(num_qubits, mu=[0.12, 0.24], sigma=0.01 * np.eye(2), bounds=bounds) # Create fixed income component fixed_income = FixedIncomeExpectedValue(num_qubits, np.eye(2), np.zeros(2), cash_flow=[1.0, 2.0], rescaling_factor=0.125, bounds=bounds) # the FixedIncomeExpectedValue provides us with the necessary rescalings # create the A operator for amplitude estimation by prepending the # normal distribution to the function mapping state_preparation = fixed_income.compose(mvnd, front=True) problem = EstimationProblem( state_preparation=state_preparation, objective_qubits=[4], post_processing=fixed_income.post_processing) # Set number of evaluation qubits (samples) num_eval_qubits = 5 # Construct and run amplitude estimation q_i = BasicAer.get_backend('statevector_simulator') algo = AmplitudeEstimation(num_eval_qubits=num_eval_qubits, quantum_instance=q_i) result = algo.estimate(problem) print('Estimated value:\t%.4f' % result.estimation_processed) print('Probability: \t%.4f' % result.max_probability) # ---------------------------------------------------------------------- with self.subTest('test estimation'): self.assertAlmostEqual(result.estimation_processed, 2.46, places=4) with self.subTest('test max.probability'): self.assertAlmostEqual(result.max_probability, 0.8487, places=4)
def test_application(self): """Test an end-to-end application.""" try: from qiskit import Aer # pylint: disable=unused-import,import-outside-toplevel except ImportError as ex: # pylint: disable=broad-except self.skipTest( "Aer doesn't appear to be installed. Error: '{}'".format( str(ex))) return num_qubits = 3 # parameters for considered random distribution s_p = 2.0 # initial spot price vol = 0.4 # volatility of 40% r = 0.05 # annual interest rate of 4% t_m = 40 / 365 # 40 days to maturity # resulting parameters for log-normal distribution mu = ((r - 0.5 * vol**2) * t_m + np.log(s_p)) sigma = vol * np.sqrt(t_m) 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 bounds = (low, high) # construct circuit factory for uncertainty model uncertainty_model = LogNormalDistribution(num_qubits, mu=mu, sigma=sigma**2, bounds=bounds) # set the strike price (should be within the low and the high value of the uncertainty) strike_price = 1.896 # create amplitude function european_call_delta = EuropeanCallDelta(num_state_qubits=num_qubits, strike_price=strike_price, bounds=bounds) # create state preparation state_preparation = european_call_delta.compose(uncertainty_model, front=True) problem = EstimationProblem( state_preparation=state_preparation, objective_qubits=[num_qubits], post_processing=european_call_delta.post_processing) # run amplitude estimation q_i = QuantumInstance(Aer.get_backend('qasm_simulator'), seed_simulator=125, seed_transpiler=80) iae = IterativeAmplitudeEstimation(epsilon_target=0.01, alpha=0.05, quantum_instance=q_i) result = iae.estimate(problem) self.assertAlmostEqual(result.estimation_processed, 0.8079816552117238)