Exemplo n.º 1
0
def integercomparator(relative_numbers):
    from qiskit.circuit.library import IntegerComparator
    from unqomp.examples.intergercomparator import makeIntegerComparator

    n = 12
    v = 40

    circuit1 = makeIntegerComparator(n, v).circuitWithUncomputation()

    qcirc = IntegerComparator(n, v)
    print('IntegerComparator  ; ', end = '')

    #qiskit
    nb_qb_qi = qcirc.num_qubits
    nb_gates_qi = qcirc.decompose().decompose().decompose().decompose().decompose().count_ops()
    if not relative_numbers:
        print(str(nb_qb_qi) + ' ; ' + str(nb_gates_qi['cx'] + nb_gates_qi['u3']) + ' ; ' + str(nb_gates_qi['cx']) + ' ; ', end = '')

    #qiskit++
    nb_qb_mi = circuit1.num_qubits
    nb_gates_mi = circuit1.decompose().decompose().decompose().decompose().decompose().count_ops()
    if not relative_numbers:
        print(str(nb_qb_mi) + ' ; ' + str(nb_gates_mi['cx'] + nb_gates_mi['u3']) + ' ; ' + str(nb_gates_mi['cx']))

    if relative_numbers:
        print_relative_vals(nb_qb_qi, nb_gates_qi['cx'], nb_gates_qi['u3'], nb_qb_mi, nb_gates_mi['cx'], nb_gates_mi['u3'])
    def __init__(self, num_state_qubits, value, geq=True, i_state=None, i_target=None):
        """
        Args:
            num_state_qubits (int): number of state qubits, the target qubit comes on top of this
            value (int): fixed value to compare with
            geq (Optional(bool)): evaluate ">=" condition of "<" condition
            i_state (Optional(Union(list, numpy.ndarray))): indices of state qubits in
                given list of qubits / register,
                if None, i_state = list(range(num_state_qubits)) is used
            i_target (Optional(int)): index of target qubit in given list
                of qubits / register, if None, i_target = num_state_qubits is used
        """
        warnings.warn('The qiskit.aqua.circuits.FixedValueComparator object is deprecated and will '
                      'be removed no earlier than 3 months after the 0.7.0 release of Qiskit Aqua. '
                      'You should use qiskit.circuit.library.IntegerComparator instead.',
                      DeprecationWarning, stacklevel=2)

        super().__init__(num_state_qubits + 1)
        self._comparator_circuit = IntegerComparator(value=value,
                                                     num_state_qubits=num_state_qubits,
                                                     geq=geq)

        self.i_state = None
        if i_state is not None:
            self.i_state = i_state
        else:
            self.i_state = range(num_state_qubits)

        self.i_target = None
        if i_target is not None:
            self.i_target = i_target
        else:
            self.i_target = num_state_qubits
Exemplo n.º 3
0
    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 = IntegerComparator(uncertainty_model.num_target_qubits,
                                             self._mapped_strike_price)
Exemplo n.º 4
0
    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}
        lower = uncertainty_model.low
        upper = uncertainty_model.high
        self._mapped_strike_price = int(
            np.round((strike_price - lower) / (upper - lower) *
                     (uncertainty_model.num_values - 1)))

        # create comparator
        self._comparator = IntegerComparator(
            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
Exemplo n.º 5
0
 def test_to_estimation_problem(self):
     """Test the expected circuit."""
     num_qubits = 3
     strike_price = 0.5
     bounds = (0, 2)
     # make an estimation problem
     uncertain_model = UniformDistribution(num_qubits)
     ecd = EuropeanCallDelta(num_qubits, strike_price, bounds,
                             uncertain_model)
     est_problem = ecd.to_estimation_problem()
     # make a state_preparation circuit manually
     x = (strike_price - bounds[0]) / (bounds[1] -
                                       bounds[0]) * (2**num_qubits - 1)
     comparator = IntegerComparator(num_qubits, x)
     expected_circ = comparator.compose(uncertain_model, front=True)
     self.assertEqual(est_problem.objective_qubits, [num_qubits])
     self.assertTrue(
         Operator(est_problem.state_preparation).equiv(expected_circ))
     self.assertEqual(0.5, est_problem.post_processing(0.5))  # pylint: disable=not-callable
    def __init__(self, num_state_qubits: int, strike_price: float, bounds: Tuple[float, float]
                 ) -> None:
        """
        Args:
            num_state_qubits: The number of qubits used to encode the random variable.
            strike_price: strike price of the European option
            bounds: The tuple of the bounds, (min, max), of the discretized random variable.
        """
        # map strike price to {0, ..., 2^n-1}
        num_values = 2 ** num_state_qubits
        strike_price = (strike_price - bounds[0]) / (bounds[1] - bounds[0]) * (num_values - 1)
        strike_price = int(np.ceil(strike_price))

        # create comparator
        comparator = IntegerComparator(num_state_qubits, strike_price)

        # initialize circuit
        qr_state = QuantumRegister(comparator.num_qubits - comparator.num_ancillas, 'state')
        qr_work = QuantumRegister(comparator.num_ancillas, 'work')
        super().__init__(qr_state, qr_work, name='ECD')

        self.append(comparator.to_gate(), self.qubits)
    def test_circuit(self):
        """Test the expected circuit.

        If it equals the correct ``IntegerComparator`` we know the circuit is correct.
        """
        num_qubits = 3
        strike_price = 0.5
        bounds = (0, 2)
        ecd = EuropeanCallDelta(num_qubits, strike_price, bounds)

        # map strike_price to a basis state
        x = (strike_price - bounds[0]) / (bounds[1] - bounds[0]) * (2 ** num_qubits - 1)
        comparator = IntegerComparator(num_qubits, x)

        self.assertTrue(Operator(ecd).equiv(comparator))
Exemplo n.º 8
0
    def __init__(self, x0, x1, a0, a1, a2, b0, b1, b2, nbits = 3):
        qr_input = QuantumRegister(nbits, 'input')
        num_result_qubits = nbits * 2 
        qr_result = QuantumRegister(num_result_qubits, 'result')
        
        self.num_ancilla_qubits = 2 + num_result_qubits + 3
        qr_ancilla = QuantumRegister(self.num_ancilla_qubits, 'ancilla')

        qr_comp_anc = qr_ancilla[0:2]
        qr_arith_anc = qr_ancilla[2:2 + num_result_qubits]
        qr_range_anc = qr_ancilla[2 + num_result_qubits:2 + num_result_qubits + 3]
        
        super().__init__(qr_input, qr_result, qr_ancilla, name='pwise_lin_trans')

        comp0 = IntegerComparator(num_state_qubits=nbits, value=x0, name = "comparator0") # true if i >= point
        comp1 = IntegerComparator(num_state_qubits=nbits, value=x1, name = "comparator1") # true if i >= point
        trans0 = multiply_add.cond_classical_add_mult(a0, b0, qr_input, qr_result, qr_arith_anc) 
        trans1 = multiply_add.cond_classical_add_mult(a1, b1, qr_input, qr_result, qr_arith_anc) 
        trans2 = multiply_add.cond_classical_add_mult(a2, b2, qr_input, qr_result, qr_arith_anc)  

        self.append(comp0.to_gate(), qr_input[:] + [qr_comp_anc[0]] + qr_arith_anc[0:comp0.num_ancillas])
        self.append(comp1.to_gate(), qr_input[:] + [qr_comp_anc[1]] + qr_arith_anc[0:comp1.num_ancillas])

        # use three additional ancillas to define the ranges
        self.cx(qr_comp_anc[0], qr_range_anc[0])
        self.x(qr_range_anc[0])
        self.cx(qr_comp_anc[1], qr_range_anc[2])
        self.x(qr_range_anc[2])
        self.ccx(qr_comp_anc[0], qr_range_anc[2], qr_range_anc[1])

        self.append(trans0, [qr_range_anc[0]] + qr_input[:] + qr_result[:] + qr_arith_anc[:])
        self.append(trans1, [qr_range_anc[1]] + qr_input[:] + qr_result[:] + qr_arith_anc[:])
        self.append(trans2, [qr_comp_anc[1]] + qr_input[:] + qr_result[:] + qr_arith_anc[:])
        
        # uncompute range ancillas
        self.ccx(qr_comp_anc[0], qr_range_anc[2], qr_range_anc[1])
        self.x(qr_range_anc[2])
        self.cx(qr_comp_anc[1], qr_range_anc[2])
        self.x(qr_range_anc[0])
        self.cx(qr_comp_anc[0], qr_range_anc[0])
        
        # uncompute comparator ancillas 
        self.append(comp1.to_gate().inverse(), qr_input[:] + [qr_comp_anc[1]] + qr_arith_anc[0:comp1.num_ancillas])
        self.append(comp0.to_gate().inverse(), qr_input[:] + [qr_comp_anc[0]] + qr_arith_anc[0:comp0.num_ancillas])
Exemplo n.º 9
0
    def test_mutability(self):
        """Test changing the arguments of the comparator."""

        comp = IntegerComparator()

        with self.subTest(msg='missing num state qubits and value'):
            with self.assertRaises(AttributeError):
                print(comp.draw())

        comp.num_state_qubits = 2

        with self.subTest(msg='missing value'):
            with self.assertRaises(AttributeError):
                print(comp.draw())

        comp.value = 0
        comp.geq = True

        with self.subTest(msg='updating num state qubits'):
            comp.num_state_qubits = 1
            self.assertComparisonIsCorrect(comp, 1, 0, True)

        with self.subTest(msg='updating the value'):
            comp.num_state_qubits = 3
            comp.value = 2
            self.assertComparisonIsCorrect(comp, 3, 2, True)

        with self.subTest(msg='updating geq'):
            comp.geq = False
            self.assertComparisonIsCorrect(comp, 3, 2, False)
Exemplo n.º 10
0
 def test_fixed_value_comparator(self, num_state_qubits, value, geq):
     """Test the fixed value comparator circuit."""
     # build the circuit with the comparator
     comp = IntegerComparator(num_state_qubits, value, geq=geq)
     self.assertComparisonIsCorrect(comp, num_state_qubits, value, geq)
Exemplo n.º 11
0
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}
        lower = uncertainty_model.low
        upper = uncertainty_model.high
        self._mapped_strike_price = int(
            np.round((strike_price - lower) / (upper - lower) *
                     (uncertainty_model.num_values - 1)))

        # create comparator
        self._comparator = IntegerComparator(
            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.num_ancilla_qubits
        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
        qubits = q_state[:] + [q_compare]
        if q_ancillas:
            qubits += q_ancillas[:self._comparator.num_ancilla_qubits]
        qc.append(self._comparator.to_instruction(), qubits)

        # 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, q_i in enumerate(q_state):
            qc.mcry(2 * self.slope_angle * 2**i, [q_compare, q_i], q_objective,
                    None)
class FixedValueComparator(CircuitFactory):
    r"""Fixed Value Comparator.

    Operator compares basis states \|i>_n against a classically
    given fixed value L and flips a target qubit if i >= L (or < depending on parameters):

        \|i>_n\|0> --> \|i>_n\|1> if i >= L else \|i>\|0>

    Operator is based on two's complement implementation of binary
    subtraction but only uses carry bits and no actual result bits.
    If the most significant carry bit (= results bit) is 1, the ">="
    condition is True otherwise it is False.
    """

    def __init__(self, num_state_qubits, value, geq=True, i_state=None, i_target=None):
        """
        Args:
            num_state_qubits (int): number of state qubits, the target qubit comes on top of this
            value (int): fixed value to compare with
            geq (Optional(bool)): evaluate ">=" condition of "<" condition
            i_state (Optional(Union(list, numpy.ndarray))): indices of state qubits in
                given list of qubits / register,
                if None, i_state = list(range(num_state_qubits)) is used
            i_target (Optional(int)): index of target qubit in given list
                of qubits / register, if None, i_target = num_state_qubits is used
        """
        warnings.warn('The qiskit.aqua.circuits.FixedValueComparator object is deprecated and will '
                      'be removed no earlier than 3 months after the 0.7.0 release of Qiskit Aqua. '
                      'You should use qiskit.circuit.library.IntegerComparator instead.',
                      DeprecationWarning, stacklevel=2)

        super().__init__(num_state_qubits + 1)
        self._comparator_circuit = IntegerComparator(value=value,
                                                     num_state_qubits=num_state_qubits,
                                                     geq=geq)

        self.i_state = None
        if i_state is not None:
            self.i_state = i_state
        else:
            self.i_state = range(num_state_qubits)

        self.i_target = None
        if i_target is not None:
            self.i_target = i_target
        else:
            self.i_target = num_state_qubits

    @property
    def num_state_qubits(self):
        """ returns num state qubits """
        return self._comparator_circuit._num_state_qubits

    @property
    def value(self):
        """ returns value """
        return self._comparator_circuit._value

    def required_ancillas(self):
        return self.num_state_qubits - 1

    def required_ancillas_controlled(self):
        return self.num_state_qubits - 1

    def _get_twos_complement(self):
        """
        Returns the 2's complement of value as array

        Returns:
             list: two's complement
        """

        twos_complement = pow(2, self.num_state_qubits) - int(np.ceil(self.value))
        twos_complement = '{0:b}'.format(twos_complement).rjust(self.num_state_qubits, '0')
        twos_complement = \
            [1 if twos_complement[i] == '1' else 0 for i in reversed(range(len(twos_complement)))]
        return twos_complement

    def build(self, qc, q, q_ancillas=None, params=None):
        instr = self._comparator_circuit.to_instruction()
        qr = [q[i] for i in self.i_state] + [q[self.i_target]]
        if q_ancillas:
            # pylint:disable=unnecessary-comprehension
            qr += [qi for qi in q_ancillas[:self.required_ancillas()]]
        qc.append(instr, qr)
Exemplo n.º 13
0
    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()
Exemplo n.º 14
0
    def in_progress_test_piecewise_transform(self):
        """Simple end-to-end test of the (semi-classical) multiply and add building block."""

        import numpy as np
        import matplotlib.pyplot as plt

        from qiskit import execute, Aer, QuantumCircuit, QuantumRegister, ClassicalRegister, AncillaRegister
        from qiskit.aqua.algorithms import IterativeAmplitudeEstimation
        from qiskit.circuit.library import NormalDistribution, LogNormalDistribution, LinearAmplitudeFunction, IntegerComparator, WeightedAdder
        from qiskit.visualization import plot_histogram
        from quantum_mc.arithmetic import multiply_add

        qr_input = QuantumRegister(3, 'input')
        qr_result = QuantumRegister(6, 'result')
        qr_comp = QuantumRegister(2, 'comparisons')
        qr_ancilla = QuantumRegister(6, 'ancilla')
        qr_comp_anc = QuantumRegister(3, 'cond_ancilla')
        output = ClassicalRegister(6, 'output')
        circ = QuantumCircuit(qr_input, qr_result, qr_comp, qr_ancilla,
                              qr_comp_anc, output)

        # our test piece-wise transforms:
        # trans0 if x <= 2, x => 6*x + 7
        # trans1 if 2 < x <= 5, x => x + 17
        # trans2 if x > 5, x => 3*x + 7

        sigma = 1
        low = -3
        high = 3
        mu = 0

        normal = NormalDistribution(3,
                                    mu=mu,
                                    sigma=sigma**2,
                                    bounds=(low, high))
        circ.append(normal, qr_input)

        comp0 = IntegerComparator(num_state_qubits=3,
                                  value=3,
                                  name="comparator0")  # true if i >= point
        comp1 = IntegerComparator(num_state_qubits=3,
                                  value=6,
                                  name="comparator1")  # true if i >= point
        trans0 = multiply_add.cond_classical_add_mult(6, 7, qr_input,
                                                      qr_result, qr_ancilla)
        trans1 = multiply_add.cond_classical_add_mult(1, 17, qr_input,
                                                      qr_result, qr_ancilla)
        trans2 = multiply_add.cond_classical_add_mult(3, 7, qr_input,
                                                      qr_result, qr_ancilla)

        circ.append(
            comp0,
            qr_input[:] + [qr_comp[0]] + qr_ancilla[0:comp0.num_ancillas])
        circ.append(
            comp1,
            qr_input[:] + [qr_comp[1]] + qr_ancilla[0:comp0.num_ancillas])

        # use three additional ancillas to define the ranges
        circ.cx(qr_comp[0], qr_comp_anc[0])
        circ.x(qr_comp_anc[0])
        circ.cx(qr_comp[1], qr_comp_anc[2])
        circ.x(qr_comp_anc[2])
        circ.ccx(qr_comp[0], qr_comp_anc[2], qr_comp_anc[1])

        circ.append(trans0, [qr_comp_anc[0]] + qr_input[:] + qr_result[:] +
                    qr_ancilla[:])
        circ.append(trans1, [qr_comp_anc[1]] + qr_input[:] + qr_result[:] +
                    qr_ancilla[:])
        circ.append(trans2,
                    [qr_comp[1]] + qr_input[:] + qr_result[:] + qr_ancilla[:])

        # can uncompute qr_comp_anc
        # then uncompute the comparators

        circ.measure(qr_result, output)
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 = IntegerComparator(
            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.num_ancilla_qubits
        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.num_ancilla_qubits
        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
        qubits = q_state[:] + [q_objective]
        if q_ancillas:
            qubits += q_ancillas[:self.required_ancillas()]
        qc.append(self._comparator.to_instruction(), qubits)