def build(self, qc, q, q_ancillas=None, params=None): # get parameters i_state = self.i_state i_target = self.i_target # apply comparators and controlled linear rotations for i, bp in enumerate(self.breakpoints): if i == 0 and self.contains_zero_breakpoint: # apply rotation lin_r = LinR(self.mapped_slopes[i], self.mapped_offsets[i], self.num_state_qubits, basis=self.basis, i_state=i_state, i_target=i_target) lin_r.build(qc, q) elif self.contains_zero_breakpoint: # apply comparator comp = Comparator(self.num_state_qubits, bp) q_ = [q[i] for i in range(self.num_state_qubits)] # map register to list q_ = q_ + [q_ancillas[i - 1]] # add ancilla as compare qubit # take remaining ancillas as ancilla register (list) q_ancillas_ = [q_ancillas[j] for j in range(i, len(q_ancillas))] comp.build(qc, q_, q_ancillas_) # apply controlled rotation lin_r = LinR(self.mapped_slopes[i], self.mapped_offsets[i], self.num_state_qubits, basis=self.basis, i_state=i_state, i_target=i_target) lin_r.build_controlled(qc, q, q_ancillas[i - 1], use_basis_gates=False) # uncompute comparator comp.build_inverse(qc, q_, q_ancillas_) else: # apply comparator comp = Comparator(self.num_state_qubits, bp) q_ = [q[i] for i in range(self.num_state_qubits)] # map register to list q_ = q_ + [q_ancillas[i]] # add ancilla as compare qubit # take remaining ancillas as ancilla register (list) q_ancillas_ = [q_ancillas[j] for j in range(i + 1, len(q_ancillas))] comp.build(qc, q_, q_ancillas_) # apply controlled rotation lin_r = LinR(self.mapped_slopes[i], self.mapped_offsets[i], self.num_state_qubits, basis=self.basis, i_state=i_state, i_target=i_target) lin_r.build_controlled(qc, q, q_ancillas[i], use_basis_gates=False) # uncompute comparator comp.build_inverse(qc, q_, q_ancillas_)
class EuropeanCallExpectedValue(UncertaintyProblem): """ The European Call Option Expected Value. Evaluates the expected payoff for a European call option given an uncertainty model. The payoff function is f(S, K) = max(0, S - K) for a spot price S and strike price K. """ def __init__(self, uncertainty_model: UnivariateDistribution, strike_price: float, c_approx: float, i_state: Optional[Union[List[int], np.ndarray]] = None, i_compare: Optional[int] = None, i_objective: Optional[int] = None) -> None: """ Constructor. Args: uncertainty_model: uncertainty model for spot price strike_price: strike price of the European option c_approx: approximation factor for linear payoff i_state: indices of qubits representing the uncertainty i_compare: index of qubit for comparing spot price to strike price (enabling payoff or not) i_objective: index of qubit for objective function """ super().__init__(uncertainty_model.num_target_qubits + 2) self._uncertainty_model = uncertainty_model self._strike_price = strike_price self._c_approx = c_approx if i_state is None: i_state = list(range(uncertainty_model.num_target_qubits)) self.i_state = i_state if i_compare is None: i_compare = uncertainty_model.num_target_qubits self.i_compare = i_compare if i_objective is None: i_objective = uncertainty_model.num_target_qubits + 1 self.i_objective = i_objective # map strike price to {0, ..., 2^n-1} lb = uncertainty_model.low ub = uncertainty_model.high self._mapped_strike_price = int(np.round((strike_price - lb) / (ub - lb) * (uncertainty_model.num_values - 1))) # create comparator self._comparator = FixedValueComparator(uncertainty_model.num_target_qubits, self._mapped_strike_price) self.offset_angle_zero = np.pi / 4 * (1 - self._c_approx) if self._mapped_strike_price < uncertainty_model.num_values - 1: self.offset_angle = -1 * np.pi / 2 * self._c_approx * self._mapped_strike_price / \ (uncertainty_model.num_values - self._mapped_strike_price - 1) self.slope_angle = np.pi / 2 * self._c_approx / \ (uncertainty_model.num_values - self._mapped_strike_price - 1) else: self.offset_angle = 0 self.slope_angle = 0 def value_to_estimation(self, value): estimator = value - 1 / 2 + np.pi / 4 * self._c_approx estimator *= 2 / np.pi / self._c_approx estimator *= (self._uncertainty_model.num_values - self._mapped_strike_price - 1) estimator *= (self._uncertainty_model.high - self._uncertainty_model.low) / \ (self._uncertainty_model.num_values - 1) return estimator def required_ancillas(self): num_uncertainty_ancillas = self._uncertainty_model.required_ancillas() num_comparator_ancillas = self._comparator.required_ancillas() num_ancillas = int(np.maximum(num_uncertainty_ancillas, num_comparator_ancillas)) return num_ancillas def build(self, qc, q, q_ancillas=None, params=None): # get qubits q_state = [q[i] for i in self.i_state] q_compare = q[self.i_compare] q_objective = q[self.i_objective] # apply uncertainty model self._uncertainty_model.build(qc, q_state, q_ancillas) # apply comparator to compare qubit self._comparator.build(qc, q_state + [q_compare], q_ancillas) # apply approximate payoff function qc.ry(2 * self.offset_angle_zero, q_objective) qc.cry(2 * self.offset_angle, q_compare, q_objective) for i, qi in enumerate(q_state): qc.mcry(2 * self.slope_angle * 2 ** i, [q_compare, qi], q_objective, None)
class EuropeanCallExpectedValue(UncertaintyProblem): """ The European Call Option Expected Value. Evaluates the expected payoff for a European call option given an uncertainty model. The payoff function is f(S, K) = max(0, S - K) for a spot price S and strike price K. """ CONFIGURATION = { 'name': 'EuropeanCallExpectedValue', 'description': 'European Call Expected Value', 'input_schema': { '$schema': 'http://json-schema.org/draft-07/schema#', 'id': 'ECEV_schema', 'type': 'object', 'properties': { 'strike_price': { 'type': 'number', 'default': 0 }, 'c_approx': { 'type': 'number', 'default': 0.5 }, 'i_state': { 'type': ['array', 'null'], 'items': { 'type': 'integer' }, 'default': None }, 'i_compare': { 'type': ['integer', 'null'], 'default': None }, 'i_objective': { 'type': ['integer', 'null'], 'default': None } }, 'additionalProperties': False }, 'depends': [ { 'pluggable_type': 'univariate_distribution', 'default': { 'name': 'NormalDistribution' } }, ], } def __init__(self, uncertainty_model, strike_price, c_approx, i_state=None, i_compare=None, i_objective=None): """ Constructor. Args: uncertainty_model (UnivariateDistribution): uncertainty model for spot price strike_price (float): strike price of the European option c_approx (float): approximation factor for linear payoff i_state (list or array): indices of qubits representing the uncertainty i_compare (int): index of qubit for comparing spot price to strike price (enabling payoff or not) i_objective (int): index of qubit for objective function """ super().__init__(uncertainty_model.num_target_qubits + 2) self._uncertainty_model = uncertainty_model self._strike_price = strike_price self._c_approx = c_approx if i_state is None: i_state = list(range(uncertainty_model.num_target_qubits)) self.i_state = i_state if i_compare is None: i_compare = uncertainty_model.num_target_qubits self.i_compare = i_compare if i_objective is None: i_objective = uncertainty_model.num_target_qubits + 1 self.i_objective = i_objective super().validate(locals()) # map strike price to {0, ..., 2^n-1} lb = uncertainty_model.low ub = uncertainty_model.high self._mapped_strike_price = int( np.round((strike_price - lb) / (ub - lb) * (uncertainty_model.num_values - 1))) # create comparator self._comparator = FixedValueComparator( uncertainty_model.num_target_qubits, self._mapped_strike_price) self.offset_angle_zero = np.pi / 4 * (1 - self._c_approx) if self._mapped_strike_price < uncertainty_model.num_values - 1: self.offset_angle = -1 * np.pi / 2 * self._c_approx * self._mapped_strike_price / \ (uncertainty_model.num_values - self._mapped_strike_price - 1) self.slope_angle = np.pi / 2 * self._c_approx / \ (uncertainty_model.num_values - self._mapped_strike_price - 1) else: self.offset_angle = 0 self.slope_angle = 0 def value_to_estimation(self, value): estimator = value - 1 / 2 + np.pi / 4 * self._c_approx estimator *= 2 / np.pi / self._c_approx estimator *= (self._uncertainty_model.num_values - self._mapped_strike_price - 1) estimator *= (self._uncertainty_model.high - self._uncertainty_model.low) / \ (self._uncertainty_model.num_values - 1) return estimator def required_ancillas(self): num_uncertainty_ancillas = self._uncertainty_model.required_ancillas() num_comparator_ancillas = self._comparator.required_ancillas() num_ancillas = int( np.maximum(num_uncertainty_ancillas, num_comparator_ancillas)) return num_ancillas def build(self, qc, q, q_ancillas=None, params=None): # get qubits q_state = [q[i] for i in self.i_state] q_compare = q[self.i_compare] q_objective = q[self.i_objective] # apply uncertainty model self._uncertainty_model.build(qc, q_state, q_ancillas) # apply comparator to compare qubit self._comparator.build(qc, q_state + [q_compare], q_ancillas) # apply approximate payoff function qc.ry(2 * self.offset_angle_zero, q_objective) qc.cry(2 * self.offset_angle, q_compare, q_objective) for i, qi in enumerate(q_state): qc.mcry(2 * self.slope_angle * 2**i, [q_compare, qi], q_objective, None)
class EuropeanCallDelta(UncertaintyProblem): """ The European Call Option Delta. Evaluates the variance for a European call option given an uncertainty model. The payoff function is f(S, K) = max(0, S - K) for a spot price S and strike price K. """ CONFIGURATION = { 'name': 'EuropeanCallDelta', 'description': 'European Call Delta', 'input_schema': { '$schema': 'http://json-schema.org/schema#', 'id': 'ECD_schema', 'type': 'object', 'properties': { 'strike_price': { 'type': 'number', 'default': 0 }, 'i_state': { 'type': ['array', 'null'], 'items': { 'type': 'integer' }, 'default': None }, 'i_objective': { 'type': ['integer', 'null'], 'default': None } }, 'additionalProperties': False }, 'depends': [ { 'pluggable_type': 'univariate_distribution', 'default': { 'name': 'NormalDistribution' } }, ], } def __init__(self, uncertainty_model, strike_price, i_state=None, i_objective=None): """ Constructor. Args: uncertainty_model (UnivariateDistribution): uncertainty model for spot price strike_price (float): strike price of the European option c_approx (float): approximation factor for linear payoff i_state (list or array): indices of qubits representing the uncertainty i_objective (int): index of qubit for objective function """ super().__init__(uncertainty_model.num_target_qubits + 1) self._uncertainty_model = uncertainty_model self._strike_price = strike_price if i_state is None: i_state = list(range(uncertainty_model.num_target_qubits)) self.i_state = i_state if i_objective is None: i_objective = uncertainty_model.num_target_qubits self.i_objective = i_objective super().validate(locals()) # map strike price to {0, ..., 2^n-1} lb = uncertainty_model.low ub = uncertainty_model.high self._mapped_strike_price = int( np.ceil((strike_price - lb) / (ub - lb) * (uncertainty_model.num_values - 1))) # create comparator self._comparator = FixedValueComparator( uncertainty_model.num_target_qubits, self._mapped_strike_price) def required_ancillas(self): num_uncertainty_ancillas = self._uncertainty_model.required_ancillas() num_comparator_ancillas = self._comparator.required_ancillas() num_ancillas = num_uncertainty_ancillas + num_comparator_ancillas return num_ancillas def required_ancillas_controlled(self): num_uncertainty_ancillas = self._uncertainty_model.required_ancillas_controlled( ) num_comparator_ancillas = self._comparator.required_ancillas_controlled( ) num_ancillas_controlled = num_uncertainty_ancillas + num_comparator_ancillas return num_ancillas_controlled def build(self, qc, q, q_ancillas=None): # get qubit lists q_state = [q[i] for i in self.i_state] q_objective = q[self.i_objective] # apply uncertainty model self._uncertainty_model.build(qc, q_state, q_ancillas) # apply comparator to compare qubit self._comparator.build(qc, q_state + [q_objective], q_ancillas)
class EuropeanCallDelta(UncertaintyProblem): """ The European Call Option Delta. Evaluates the variance for a European call option given an uncertainty model. The payoff function is f(S, K) = max(0, S - K) for a spot price S and strike price K. """ def __init__(self, uncertainty_model: UnivariateDistribution, strike_price: float, i_state: Optional[Union[List[int], np.ndarray]] = None, i_objective: Optional[int] = None) -> None: """ Constructor. Args: uncertainty_model: uncertainty model for spot price strike_price: strike price of the European option i_state: indices of qubits representing the uncertainty i_objective: index of qubit for objective function """ super().__init__(uncertainty_model.num_target_qubits + 1) self._uncertainty_model = uncertainty_model self._strike_price = strike_price if i_state is None: i_state = list(range(uncertainty_model.num_target_qubits)) self.i_state = i_state if i_objective is None: i_objective = uncertainty_model.num_target_qubits self.i_objective = i_objective # map strike price to {0, ..., 2^n-1} lb = uncertainty_model.low ub = uncertainty_model.high self._mapped_strike_price = int( np.ceil((strike_price - lb) / (ub - lb) * (uncertainty_model.num_values - 1))) # create comparator self._comparator = FixedValueComparator( uncertainty_model.num_target_qubits, self._mapped_strike_price) def required_ancillas(self): num_uncertainty_ancillas = self._uncertainty_model.required_ancillas() num_comparator_ancillas = self._comparator.required_ancillas() num_ancillas = num_uncertainty_ancillas + num_comparator_ancillas return num_ancillas def required_ancillas_controlled(self): num_uncertainty_ancillas = self._uncertainty_model.required_ancillas_controlled( ) num_comparator_ancillas = self._comparator.required_ancillas_controlled( ) num_ancillas_controlled = num_uncertainty_ancillas + num_comparator_ancillas return num_ancillas_controlled def build(self, qc, q, q_ancillas=None, params=None): # get qubit lists q_state = [q[i] for i in self.i_state] q_objective = q[self.i_objective] # apply uncertainty model self._uncertainty_model.build(qc, q_state, q_ancillas) # apply comparator to compare qubit self._comparator.build(qc, q_state + [q_objective], q_ancillas)