def test_ecev(self): """ European Call Expected Value test """ bounds = np.array([0., 7.]) num_qubits = [3] entangler_map = [] for i in range(sum(num_qubits)): entangler_map.append([i, int(np.mod(i + 1, sum(num_qubits)))]) g_params = [ 0.29399714, 0.38853322, 0.9557694, 0.07245791, 6.02626428, 0.13537225 ] # Set an initial state for the generator circuit init_dist = NormalDistribution(int(sum(num_qubits)), mu=1., sigma=1., low=bounds[0], high=bounds[1]) init_distribution = np.sqrt(init_dist.probabilities) init_distribution = Custom(num_qubits=sum(num_qubits), state_vector=init_distribution) var_form = TwoLocal(int(np.sum(num_qubits)), 'ry', 'cz', reps=1, initial_state=init_distribution, entanglement=entangler_map) uncertainty_model = UnivariateVariationalDistribution(int( sum(num_qubits)), var_form, g_params, low=bounds[0], high=bounds[1]) strike_price = 2 c_approx = 0.25 european_call = EuropeanCallExpectedValue(uncertainty_model, strike_price=strike_price, c_approx=c_approx) uncertainty_model.set_probabilities( QuantumInstance(BasicAer.get_backend('statevector_simulator'))) algo = AmplitudeEstimation(5, european_call) result = algo.run( quantum_instance=BasicAer.get_backend('statevector_simulator')) self.assertAlmostEqual(result['estimation'], 1.2580, places=4) self.assertAlmostEqual(result['max_probability'], 0.8785, places=4)
def test_ecev(self, use_circuits): """ European Call Expected Value test """ if not use_circuits: # ignore deprecation warnings from the deprecation of VariationalForm as input for # the univariate variational distribution warnings.filterwarnings("ignore", category=DeprecationWarning) bounds = np.array([0., 7.]) num_qubits = [3] entangler_map = [] for i in range(sum(num_qubits)): entangler_map.append([i, int(np.mod(i + 1, sum(num_qubits)))]) g_params = [ 0.29399714, 0.38853322, 0.9557694, 0.07245791, 6.02626428, 0.13537225 ] # Set an initial state for the generator circuit init_dist = NormalDistribution(int(sum(num_qubits)), mu=1., sigma=1., low=bounds[0], high=bounds[1]) init_distribution = np.sqrt(init_dist.probabilities) init_distribution = Custom(num_qubits=sum(num_qubits), state_vector=init_distribution) var_form = RY(int(np.sum(num_qubits)), depth=1, initial_state=init_distribution, entangler_map=entangler_map, entanglement_gate='cz') if use_circuits: theta = ParameterVector('θ', var_form.num_parameters) var_form = var_form.construct_circuit(theta) uncertainty_model = UnivariateVariationalDistribution(int( sum(num_qubits)), var_form, g_params, low=bounds[0], high=bounds[1]) if use_circuits: uncertainty_model._var_form_params = theta strike_price = 2 c_approx = 0.25 european_call = EuropeanCallExpectedValue(uncertainty_model, strike_price=strike_price, c_approx=c_approx) uncertainty_model.set_probabilities( QuantumInstance(BasicAer.get_backend('statevector_simulator'))) algo = AmplitudeEstimation(5, european_call) result = algo.run( quantum_instance=BasicAer.get_backend('statevector_simulator')) self.assertAlmostEqual(result['estimation'], 1.2580, places=4) self.assertAlmostEqual(result['max_probability'], 0.8785, places=4) if not use_circuits: warnings.filterwarnings(action="always", category=DeprecationWarning)
def __init__(self, n_normal, normal_max_value, p_zeros, rhos, i_normal=None, i_ps=None): """ Constructor. The Gaussian Conditional Independence Model for Credit Risk Reference: https://arxiv.org/abs/1412.1183 Args: n_normal (int): number of qubits to represent the latent normal random variable Z normal_max_value (float): min/max value to truncate the latent normal random variable Z p_zeros (list or array): standard default probabilities for each asset rhos (list or array): sensitivities of default probability of assets with respect to latent variable Z i_normal (list or array): indices of qubits to represent normal variable i_ps (list or array): indices of qubits to represent asset defaults """ self.n_normal = n_normal self.normal_max_value = normal_max_value self.p_zeros = p_zeros self.rhos = rhos self.K = len(p_zeros) num_qubits = [n_normal] + [1]*self.K # set and store indices if i_normal is not None: self.i_normal = i_normal else: self.i_normal = range(n_normal) if i_ps is not None: self.i_ps = i_ps else: self.i_ps = range(n_normal, n_normal + self.K) # get normal (inverse) CDF and pdf def F(x): return norm.cdf(x) def F_inv(x): return norm.ppf(x) def f(x): return norm.pdf(x) # set low/high values low = [-normal_max_value] + [0]*self.K high = [normal_max_value] + [1]*self.K # call super constructor super().__init__(num_qubits, low=low, high=high) # create normal distribution self._normal = NormalDistribution(n_normal, 0, 1, -normal_max_value, normal_max_value) # create linear rotations for conditional defaults self._slopes = np.zeros(self.K) self._offsets = np.zeros(self.K) self._rotations = [] for k in range(self.K): psi = F_inv(p_zeros[k]) / np.sqrt(1 - rhos[k]) # compute slope / offset slope = -np.sqrt(rhos[k]) / np.sqrt(1 - rhos[k]) slope *= f(psi) / np.sqrt(1 - F(psi)) / np.sqrt(F(psi)) offset = 2*np.arcsin(np.sqrt(F(psi))) # adjust for integer to normal range mapping offset += slope * (-normal_max_value) slope *= 2*normal_max_value / (2**n_normal - 1) self._offsets[k] = offset self._slopes[k] = slope lry = LinearYRotation(slope, offset, n_normal, i_state=self.i_normal, i_target=self.i_ps[k]) self._rotations += [lry]
class GaussianConditionalIndependenceModel(MultivariateDistribution): """ The Gaussian Conditional Independence Model for Credit Risk Reference: https://arxiv.org/abs/1412.1183 Dependency between individual risk variabels and latent variable is approximated linearly. """ CONFIGURATION = { 'name': 'GaussianConditionalIndependenceModel', 'description': 'Gaussian Conditional Independence Model', 'input_schema': { '$schema': 'http://json-schema.org/schema#', 'id': 'GaussianConditionalIndependenceModel_schema', 'type': 'object', 'properties': { 'n_normal': { 'type': 'number' }, 'normal_max_value': { "type": "number" }, 'p_zeros': { 'type': ['array'], "items": { "type": "number" } }, 'rhos': { 'type': ['array'], "items": { "type": "number" } }, 'i_normal': { 'type': ['array', 'null'], "items": { "type": "number" }, 'default': None }, 'i_ps': { 'type': ['array', 'null'], "items": { "type": "number" }, 'default': None } }, 'additionalProperties': False } } def __init__(self, n_normal, normal_max_value, p_zeros, rhos, i_normal=None, i_ps=None): """ Constructor. The Gaussian Conditional Independence Model for Credit Risk Reference: https://arxiv.org/abs/1412.1183 Args: n_normal (int): number of qubits to represent the latent normal random variable Z normal_max_value (float): min/max value to truncate the latent normal random variable Z p_zeros (list or array): standard default probabilities for each asset rhos (list or array): sensitivities of default probability of assets with respect to latent variable Z i_normal (list or array): indices of qubits to represent normal variable i_ps (list or array): indices of qubits to represent asset defaults """ self.n_normal = n_normal self.normal_max_value = normal_max_value self.p_zeros = p_zeros self.rhos = rhos self.K = len(p_zeros) num_qubits = [n_normal] + [1]*self.K # set and store indices if i_normal is not None: self.i_normal = i_normal else: self.i_normal = range(n_normal) if i_ps is not None: self.i_ps = i_ps else: self.i_ps = range(n_normal, n_normal + self.K) # get normal (inverse) CDF and pdf def F(x): return norm.cdf(x) def F_inv(x): return norm.ppf(x) def f(x): return norm.pdf(x) # set low/high values low = [-normal_max_value] + [0]*self.K high = [normal_max_value] + [1]*self.K # call super constructor super().__init__(num_qubits, low=low, high=high) # create normal distribution self._normal = NormalDistribution(n_normal, 0, 1, -normal_max_value, normal_max_value) # create linear rotations for conditional defaults self._slopes = np.zeros(self.K) self._offsets = np.zeros(self.K) self._rotations = [] for k in range(self.K): psi = F_inv(p_zeros[k]) / np.sqrt(1 - rhos[k]) # compute slope / offset slope = -np.sqrt(rhos[k]) / np.sqrt(1 - rhos[k]) slope *= f(psi) / np.sqrt(1 - F(psi)) / np.sqrt(F(psi)) offset = 2*np.arcsin(np.sqrt(F(psi))) # adjust for integer to normal range mapping offset += slope * (-normal_max_value) slope *= 2*normal_max_value / (2**n_normal - 1) self._offsets[k] = offset self._slopes[k] = slope lry = LinearYRotation(slope, offset, n_normal, i_state=self.i_normal, i_target=self.i_ps[k]) self._rotations += [lry] def build(self, qc, q, q_ancillas=None, params=None): self._normal.build(qc, q, q_ancillas) for lry in self._rotations: lry.build(qc, q, q_ancillas)
from qiskit.tools.monitor import job_monitor from qiskit.aqua.components.uncertainty_models import NormalDistribution, UniformDistribution, LogNormalDistribution IBMQ.enable_account('Enter API key') provider = IBMQ.get_provider(hub='ibm-q') backend = provider.get_backend('ibmq_qasm_simulator') q = QuantumRegister(5, 'q') c = ClassicalRegister(5, 'c') print("\n Normal Distribution") print("-----------------") circuit = QuantumCircuit(q, c) normal = NormalDistribution(num_target_qubits=5, mu=0, sigma=1, low=-1, high=1) normal.build(circuit, q) circuit.measure(q, c) circuit.draw(output='mpl', filename='normal.png') job = execute(circuit, backend, shots=8192) job_monitor(job) counts = job.result().get_counts() print(counts) sortedcounts = [] sortedkeys = sorted(counts) for i in sortedkeys: for j in counts:
# Set upper and lower data values bounds = np.array([0.,7.]) # Set number of qubits used in the uncertainty model num_qubits = [3] # Set entangler map entangler_map = [] for i in range(sum(num_qubits)): entangler_map.append([i, int(np.mod(i+1, sum(num_qubits)))]) # Load the trained circuit parameters g_params = [0.29399714, 0.38853322, 0.9557694, 0.07245791, 6.02626428, 0.13537225] # Set an initial state for the generator circuit init_dist = NormalDistribution(sum(num_qubits), mu=1., sigma=1., low=bounds[0], high=bounds[1]) init_distribution = np.sqrt(init_dist.probabilities) init_distribution = Custom(num_qubits=sum(num_qubits), state_vector=init_distribution) # construct the variational form var_form = RealAmplitudes(sum(num_qubits), entanglement=entangler_map, reps=1, initial_state=init_distribution) var_form.entanglement_blocks = 'cz' theta = ParameterVector('θ', var_form.num_parameters) var_form = var_form.assign_parameters(theta) # Set generator circuit g_circuit = UnivariateVariationalDistribution(sum(num_qubits), var_form, g_params, low=bounds[0], high=bounds[1]) g_circuit._var_form_params = theta # construct circuit factory for uncertainty model