diff --git a/research/rainbow_options/RainbowOptions-DirectMethod.ipynb b/research/rainbow_options_direct_method/rainbow_options_direct_method.ipynb similarity index 76% rename from research/rainbow_options/RainbowOptions-DirectMethod.ipynb rename to research/rainbow_options_direct_method/rainbow_options_direct_method.ipynb index baaa0eacd..5cc527041 100644 --- a/research/rainbow_options/RainbowOptions-DirectMethod.ipynb +++ b/research/rainbow_options_direct_method/rainbow_options_direct_method.ipynb @@ -40,8 +40,9 @@ ] }, { - "metadata": {}, "cell_type": "code", + "execution_count": 11, + "outputs": [], "source": [ "import numpy as np\n", "import scipy\n", @@ -56,15 +57,23 @@ "COV = np.array([[0.000335, 0.000257], [0.000257, 0.000418]])\n", "MU_LOG_RET = np.array([0.00050963, 0.00062552])" ], - "id": "31301483d80050bc", - "outputs": [], - "execution_count": null + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-18T13:36:52.901454Z", + "start_time": "2024-06-18T13:36:52.729371Z" + } + } }, { "cell_type": "code", "id": "d2d99529", "metadata": { - "collapsed": false + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-18T13:36:54.045061Z", + "start_time": "2024-06-18T13:36:54.042470Z" + } }, "source": [ "MU = MU_LOG_RET * dt\n", @@ -72,7 +81,7 @@ "SCALING_FACTOR = 1 / CHOLESKY[0, 0]" ], "outputs": [], - "execution_count": null + "execution_count": 13 }, { "cell_type": "markdown", @@ -96,7 +105,11 @@ "cell_type": "code", "id": "172e7a00", "metadata": { - "collapsed": false + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-18T13:36:54.046821Z", + "start_time": "2024-06-18T13:36:54.042960Z" + } }, "source": [ "def gaussian_discretization(num_qubits, mu=0, sigma=1, stds_around_mean_to_include=3):\n", @@ -120,7 +133,7 @@ "MIN_X = grid_points[0]" ], "outputs": [], - "execution_count": null + "execution_count": 14 }, { "cell_type": "markdown", @@ -141,15 +154,24 @@ { "cell_type": "code", "id": "5713c295", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2024-06-18T13:36:54.051730Z", + "start_time": "2024-06-18T13:36:54.046283Z" + } + }, "source": [ "from IPython.display import Markdown\n", "\n", - "if K >= max(S0*np.exp(np.dot(CHOLESKY,[grid_points[-1]]*2) + MU)):\n", - " display(Markdown(' K always greater than the maximum asset values. Stop the run, the payoff is 0'))" + "if K >= max(S0 * np.exp(np.dot(CHOLESKY, [grid_points[-1]] * 2) + MU)):\n", + " display(\n", + " Markdown(\n", + " \" K always greater than the maximum asset values. Stop the run, the payoff is 0\"\n", + " )\n", + " )" ], "outputs": [], - "execution_count": null + "execution_count": 15 }, { "cell_type": "markdown", @@ -170,21 +192,27 @@ { "cell_type": "code", "id": "7794ce7c", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2024-06-18T13:36:54.055944Z", + "start_time": "2024-06-18T13:36:54.051241Z" + } + }, "source": [ "FRAC_PLACES = 2\n", "\n", + "\n", "def round_factor(a):\n", - " precision_factor = 2 ** FRAC_PLACES\n", + " precision_factor = 2**FRAC_PLACES\n", " return round(a * precision_factor) / precision_factor\n", "\n", "\n", "def floor_factor(a):\n", - " precision_factor = 2 ** FRAC_PLACES\n", + " precision_factor = 2**FRAC_PLACES\n", " return np.floor(a * precision_factor) / precision_factor" ], "outputs": [], - "execution_count": null + "execution_count": 16 }, { "cell_type": "markdown", @@ -199,7 +227,9 @@ { "metadata": {}, "cell_type": "markdown", - "source": " $\\mu_i= (t-t_0)\\tilde{\\mu}_i$, being $\\tilde{\\mu}_i$ the expected daily log-return value. It can be estimated by considering the historical time series of log returns for the $i$-th asset.", + "source": [ + " $\\mu_i= (t-t_0)\\tilde{\\mu}_i$, being $\\tilde{\\mu}_i$ the expected daily log-return value. It can be estimated by considering the historical time series of log returns for the $i$-th asset." + ], "id": "74a02871489d9ec9" }, { @@ -217,24 +247,29 @@ { "cell_type": "code", "id": "4f6f55cb", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2024-06-18T13:36:54.074035Z", + "start_time": "2024-06-18T13:36:54.056533Z" + } + }, "source": [ "from functools import reduce\n", "\n", - "from classiq import QNum, get_expression_numeric_attributes, qfunc, Output\n", + "from classiq import Output, QNum, get_expression_numeric_attributes, qfunc\n", "from classiq.qmod.symbolic import max as qmax\n", "\n", "a = STEP_X / SCALING_FACTOR\n", "b = np.log(S0[0]) + MU[0] + MIN_X * CHOLESKY[0].sum()\n", "c = (\n", - " SCALING_FACTOR\n", - " * (\n", + " SCALING_FACTOR\n", + " * (\n", " np.log(S0[1])\n", " + MU[1]\n", " - (np.log(S0[0]) + MU[0])\n", " + MIN_X * sum(CHOLESKY[1] - CHOLESKY[0])\n", " )\n", - " / STEP_X\n", + " / STEP_X\n", ")\n", "c = round_factor(c)\n", "\n", @@ -264,13 +299,17 @@ "MAX_FRAC_PLACES = calculate_max_reg_type()[1]" ], "outputs": [], - "execution_count": null + "execution_count": 17 }, { "cell_type": "code", "id": "0074a98c", "metadata": { - "collapsed": false + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-18T13:36:54.074322Z", + "start_time": "2024-06-18T13:36:54.068844Z" + } }, "source": [ "@qfunc\n", @@ -278,7 +317,7 @@ " res |= qmax(get_affine_formula([x1, x2], 0), get_affine_formula([x1, x2], 1) + c)" ], "outputs": [], - "execution_count": null + "execution_count": 18 }, { "cell_type": "markdown", @@ -297,16 +336,39 @@ " \\end{cases}\n", "\\end{equation}\n", "\n", - "where $\\hat{x}$ is the binary complement of $x$ ($\\hat{x}=x-x_{max}$) and $x_{max}=2^R-1$, the maximum value that can be stored in $|x\\rangle$ register. For loading $e^{-a\\hat{x}}$ the $|r\\rangle$ is initialized to all zeros and one controlled rotation for each qubit is performed as shown in Figure \\ref{fig:circuit}. The rotations angles are: $\\theta_i = 2\\arccos \\left({\\sqrt{e^{-a2^i}}}\\right)$. All the probabilities of getting a $|0\\rangle^{\\otimes{R}}$ in the $|r\\rangle$ are then collected by a multi-controlled X (MCX) gate and stored in the $|1\\rangle$ state of a target qubit." + "where $\\hat{x}$ is the binary complement of $x$ ($\\hat{x}=x-x_{max}$) and $x_{max}=2^R-1$, the maximum value that can be stored in $|x\\rangle$ register. For loading $e^{-a\\hat{x}}$ the $|r\\rangle$ is initialized to all zeros and one controlled rotation for each qubit is performed. The rotations angles are: $\\theta_i = 2\\arccos \\left({\\sqrt{e^{-a2^i}}}\\right)$. All the probabilities of getting a $|0\\rangle^{\\otimes{R}}$ in the $|r\\rangle$ are then collected by a multi-controlled X (MCX) gate and stored in the $|1\\rangle$ state of a target qubit." ] }, { "cell_type": "code", "id": "06717f7c", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2024-06-18T13:36:54.082410Z", + "start_time": "2024-06-18T13:36:54.075286Z" + } + }, "source": [ - "from classiq import X, RY, apply_to_all, CReal, QArray, repeat, QBit, Constraints, synthesize, create_model, allocate, inplace_prepare_state, within_apply, control, bind, show\n", - "from classiq.qmod.symbolic import acos, asin, sqrt, exp\n", + "from classiq import (\n", + " RY,\n", + " Constraints,\n", + " CReal,\n", + " QArray,\n", + " QBit,\n", + " X,\n", + " allocate,\n", + " apply_to_all,\n", + " bind,\n", + " control,\n", + " create_model,\n", + " inplace_prepare_state,\n", + " repeat,\n", + " show,\n", + " synthesize,\n", + " within_apply,\n", + ")\n", + "from classiq.qmod.symbolic import acos, asin, exp, sqrt\n", + "\n", "\n", "@qfunc\n", "def exponential_amplitude_loading(\n", @@ -317,7 +379,7 @@ " x.len,\n", " lambda index: control(\n", " x[index],\n", - " lambda: RY(2 * acos(1 / sqrt(exp(exp_rate * (2**index)))), aux[index])\n", + " lambda: RY(2 * acos(1 / sqrt(exp(exp_rate * (2**index)))), aux[index]),\n", " ),\n", " )\n", " apply_to_all(X, x)\n", @@ -328,14 +390,21 @@ " bind(aux_num, aux)" ], "outputs": [], - "execution_count": null + "execution_count": 19 }, { "cell_type": "code", - "id": "ae5249a2", - "metadata": { - "collapsed": false - }, + "execution_count": 20, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Starting synthesis\n", + "Opening: http://nightly.platform.classiq.io/circuit/50b6df7b-70a9-4158-841a-89e2e2bd8425?version=0.43.0.dev22\n" + ] + } + ], "source": [ "def get_payoff_expression(x, size, fraction_digits):\n", " payoff = sqrt(\n", @@ -377,6 +446,7 @@ " lambda: direct_load_amplitudes(geq_reg, max_reg, aux_reg, ind_reg),\n", " )\n", "\n", + "\n", "@qfunc\n", "def asset_geq_strike_price(\n", " x: QNum,\n", @@ -387,9 +457,10 @@ " COMP_VALUE = (np.log(K) - b) / a\n", " res |= x > floor_factor(COMP_VALUE)\n", "\n", + "\n", "@qfunc\n", "def rainbow_direct(\n", - " x1: QNum, \n", + " x1: QNum,\n", " x2: QNum,\n", " aux_reg: QNum,\n", " ind_reg: QBit,\n", @@ -405,7 +476,7 @@ "\n", "@qfunc\n", "def main(\n", - " x1: Output[QNum], \n", + " x1: Output[QNum],\n", " x2: Output[QNum],\n", " aux_reg: Output[QNum],\n", " ind_reg: Output[QBit],\n", @@ -416,14 +487,20 @@ " allocate(1, ind_reg)\n", " rainbow_direct(x1, x2, aux_reg, ind_reg)\n", "\n", + "\n", "constraints = Constraints(max_width=23)\n", "qmod = create_model(main, constraints=constraints)\n", "print(\"Starting synthesis\")\n", "qprog = synthesize(qmod)\n", "show(qprog)" ], - "outputs": [], - "execution_count": null + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-18T13:37:06.181557Z", + "start_time": "2024-06-18T13:36:54.096250Z" + } + } }, { "cell_type": "markdown", @@ -437,10 +514,14 @@ "cell_type": "code", "id": "ecb49c61", "metadata": { - "collapsed": false + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-18T13:37:06.182864Z", + "start_time": "2024-06-18T13:37:06.177291Z" + } }, "source": [ - "from classiq import cfunc, Z\n", + "from classiq import Z, cfunc\n", "from classiq.qmod.builtins.classical_execution_primitives import iqae, save\n", "\n", "\n", @@ -448,21 +529,28 @@ "def qmci_oracle(ind: QBit):\n", " Z(ind)\n", "\n", + "\n", "@cfunc\n", "def cmain():\n", " iqae_res = iqae(epsilon=0.05, alpha=0.1)\n", " save({\"iqae_res\": iqae_res})" ], "outputs": [], - "execution_count": null + "execution_count": 21 }, { "cell_type": "code", "id": "3dddfbea", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2024-06-18T13:37:06.191736Z", + "start_time": "2024-06-18T13:37:06.183610Z" + } + }, "source": [ "from classiq import CInt, QCallable, grover_operator, power\n", "\n", + "\n", "@qfunc\n", "def grover_algorithm(\n", " k: CInt,\n", @@ -474,13 +562,17 @@ " power(k, lambda: grover_operator(oracle_operand, sp_operand, x))" ], "outputs": [], - "execution_count": null + "execution_count": 22 }, { "cell_type": "code", "id": "19a8b150", "metadata": { - "collapsed": false + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-18T13:37:06.199316Z", + "start_time": "2024-06-18T13:37:06.188686Z" + } }, "source": [ "def get_main():\n", @@ -508,14 +600,20 @@ " return main" ], "outputs": [], - "execution_count": null + "execution_count": 23 }, { "cell_type": "code", "id": "355f9bd4", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2024-06-18T13:37:06.202755Z", + "start_time": "2024-06-18T13:37:06.194549Z" + } + }, "source": [ - "from classiq import execute\n", + "from classiq import execute, write_qmod\n", + "\n", "\n", "def synthesize_and_execute(post_process):\n", " constraints = Constraints(max_width=25)\n", @@ -524,6 +622,7 @@ " constraints=constraints,\n", " classical_execution_function=cmain,\n", " )\n", + " write_qmod(qmod, \"rainbow_options_direct_method\")\n", " print(\"Starting synthesis\")\n", " qprog = synthesize(qmod)\n", " show(qprog)\n", @@ -535,7 +634,7 @@ " return (qmod, qprog, iqae_res, parsed_res)" ], "outputs": [], - "execution_count": null + "execution_count": 24 }, { "cell_type": "markdown", @@ -555,21 +654,27 @@ { "cell_type": "code", "id": "514ff089", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2024-06-18T13:37:06.242002Z", + "start_time": "2024-06-18T13:37:06.201965Z" + } + }, "source": [ "import sympy\n", "\n", + "\n", "def parse_result_direct(iqae_res):\n", " payoff_expression = f\"sqrt(max({S0[0]} * exp({STEP_X / SCALING_FACTOR * (2 ** (MAX_NUM_QUBITS - MAX_FRAC_PLACES))} * x + ({MU[0]+MIN_X*CHOLESKY[0].sum()})), {K}))\"\n", " payoff_func = sympy.lambdify(sympy.symbols(\"x\"), payoff_expression)\n", - " payoff_max = payoff_func(1 - 1 / (2**MAX_NUM_QUBITS)) \n", + " payoff_max = payoff_func(1 - 1 / (2**MAX_NUM_QUBITS))\n", "\n", " option_value = iqae_res.estimation * (payoff_max**2) - K\n", " confidence_interval = np.array(iqae_res.confidence_interval) * (payoff_max**2) - K\n", " return (option_value, confidence_interval)" ], "outputs": [], - "execution_count": null + "execution_count": 25 }, { "cell_type": "markdown", @@ -582,17 +687,55 @@ { "cell_type": "code", "id": "af4639dd", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "start_time": "2024-06-18T13:37:06.278944Z" + } + }, "source": [ "qmod_direct, qprog_direct, iqae_res_direct, parsed_res_direct = synthesize_and_execute(\n", " parse_result_direct\n", ")\n", "result, conf_interval = parsed_res_direct\n", - "print(f\"raw iqae results: {iqae_res_direct.estimation} with confidence interval {iqae_res_direct.confidence_interval}\")\n", + "print(\n", + " f\"raw iqae results: {iqae_res_direct.estimation} with confidence interval {iqae_res_direct.confidence_interval}\"\n", + ")\n", "print(f\"option estimated value: {result} with confidence interval {conf_interval}\")" ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Starting synthesis\n", + "Opening: http://nightly.platform.classiq.io/circuit/4ebd619d-7799-4255-abe2-9e2d311a8b0d?version=0.43.0.dev22\n", + "Starting execution\n", + "raw iqae results: 0.08032238745732972 with confidence interval (0.07819024342750738, 0.08245453148715207)\n", + "option estimated value: 24.743424470456375 with confidence interval [19.04309702 30.44375192]\n" + ] + } + ], + "execution_count": 26 + }, + { + "cell_type": "markdown", + "source": [ + "## Assertions" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": 27, "outputs": [], - "execution_count": null + "source": [ + "assert -5 <= result <= 45" + ], + "metadata": { + "collapsed": false + } }, { "metadata": {}, diff --git a/research/rainbow_options_direct_method/rainbow_options_direct_method.metadata.json b/research/rainbow_options_direct_method/rainbow_options_direct_method.metadata.json new file mode 100644 index 000000000..ed29ef218 --- /dev/null +++ b/research/rainbow_options_direct_method/rainbow_options_direct_method.metadata.json @@ -0,0 +1,8 @@ +{ + "friendly_name": "Rainbow Options Direct Method", + "description": "Rainbow Options payoff using Direct Method in QAE", + "problem_domain_tags": ["risk analysis"], + "vertical_tags": ["finance"], + "qmod_type": ["application"], + "level": ["advanced"] +} diff --git a/research/rainbow_options_direct_method/rainbow_options_direct_method.qmod b/research/rainbow_options_direct_method/rainbow_options_direct_method.qmod new file mode 100644 index 000000000..94b1621b8 --- /dev/null +++ b/research/rainbow_options_direct_method/rainbow_options_direct_method.qmod @@ -0,0 +1,90 @@ +qfunc qmci_oracle(ind: qbit) { + Z(ind); +} + +qfunc affine_max(x1: qnum, x2: qnum, output res: qnum) { + res = max(x1 * 1.0, ((x1 * 0.75) + (x2 * 0.75)) + (-1.25)); +} + +qfunc asset_geq_strike_price(x: qnum, output res: qbit) { + res = x > 1.5; +} + +qfunc exponential_amplitude_loading(x: qbit[], aux: qbit[], res: qbit) { + apply_to_all(x); + repeat (index: x.len) { + control (x[index]) { + RY<2 * acos(1 / sqrt(exp(exp_rate * (2 ** index))))>(aux[index]); + } + } + apply_to_all(x); + aux_num: qnum; + aux -> aux_num; + control (aux_num == 0) { + X(res); + } + aux_num -> aux; +} + +qfunc direct_load_amplitudes(geq_reg: qnum, max_reg: qnum, aux_reg: qnum, ind_reg: qbit) { + control (geq_reg == 1) { + exponential_amplitude_loading<(1 / (2 ** max_reg.fraction_digits)) * 0.4341>(max_reg, aux_reg, ind_reg); + } + control (geq_reg == 0) { + RY<2 * asin(13.784 / sqrt(max(193.97 * exp(((0.4341 * (2 ** (max_reg.size - max_reg.fraction_digits))) * (1 - (1 / (2 ** max_reg.size)))) + (-0.7408)), 190)))>(ind_reg); + } +} + +qfunc direct_payoff(max_reg: qnum, aux_reg: qnum, ind_reg: qbit) { + geq_reg: qbit; + within { + asset_geq_strike_price(max_reg, geq_reg); + } apply { + direct_load_amplitudes(geq_reg, max_reg, aux_reg, ind_reg); + } +} + +qfunc rainbow_direct(x1: qnum, x2: qnum, aux_reg: qnum, ind_reg: qbit) { + inplace_prepare_state<[ + 0.0656, + 0.4344, + 0.4344, + 0.0656 + ], 0>(x1); + inplace_prepare_state<[ + 0.0656, + 0.4344, + 0.4344, + 0.0656 + ], 0>(x2); + max_out: qnum; + within { + affine_max(x1, x2, max_out); + } apply { + direct_payoff(max_out, aux_reg, ind_reg); + } +} + +qfunc grover_algorithm(x: qbit[]) { + sp_operand(x); + power (k) { + grover_operator(x); + } +} + +qfunc main(output ind_reg: qbit) { + full_reg: qbit[]; + allocate<10>(full_reg); + grover_algorithm(full_reg); + state_reg: qbit[]; + full_reg -> {state_reg, ind_reg}; +} + +cscope ``` +iqae_res = iqae(epsilon=0.05, alpha=0.1) +save({'iqae_res': iqae_res}) +``` diff --git a/research/rainbow_options_direct_method/rainbow_options_direct_method.synthesis_options.json b/research/rainbow_options_direct_method/rainbow_options_direct_method.synthesis_options.json new file mode 100644 index 000000000..29a83131d --- /dev/null +++ b/research/rainbow_options_direct_method/rainbow_options_direct_method.synthesis_options.json @@ -0,0 +1,5 @@ +{ + "constraints": { + "max_width": 25 + } +} diff --git a/research/rainbow_options/RainbowOptions-IntegrationMethod.ipynb b/research/rainbow_options_integration_method/rainbow_options_integration_method.ipynb similarity index 74% rename from research/rainbow_options/RainbowOptions-IntegrationMethod.ipynb rename to research/rainbow_options_integration_method/rainbow_options_integration_method.ipynb index af9cb2c4d..a61433c6d 100644 --- a/research/rainbow_options/RainbowOptions-IntegrationMethod.ipynb +++ b/research/rainbow_options_integration_method/rainbow_options_integration_method.ipynb @@ -43,7 +43,11 @@ "cell_type": "code", "id": "3ad37909", "metadata": { - "collapsed": false + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-17T15:36:19.194173Z", + "start_time": "2024-06-17T15:36:18.829050Z" + } }, "source": [ "import numpy as np\n", @@ -60,10 +64,15 @@ "MU_LOG_RET = np.array([0.00050963, 0.00062552])" ], "outputs": [], - "execution_count": null + "execution_count": 1 }, { - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2024-06-17T15:36:21.973561Z", + "start_time": "2024-06-17T15:36:21.971943Z" + } + }, "cell_type": "code", "source": [ "MU = MU_LOG_RET * dt\n", @@ -72,7 +81,7 @@ ], "id": "1d608bccabd7ae78", "outputs": [], - "execution_count": null + "execution_count": 3 }, { "cell_type": "markdown", @@ -96,7 +105,11 @@ "cell_type": "code", "id": "69184d44", "metadata": { - "collapsed": false + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-17T15:36:22.119513Z", + "start_time": "2024-06-17T15:36:21.977493Z" + } }, "source": [ "def gaussian_discretization(num_qubits, mu=0, sigma=1, stds_around_mean_to_include=3):\n", @@ -120,7 +133,7 @@ "MIN_X = grid_points[0]" ], "outputs": [], - "execution_count": null + "execution_count": 4 }, { "cell_type": "markdown", @@ -141,15 +154,24 @@ { "cell_type": "code", "id": "5b51052a", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2024-06-17T15:36:22.123499Z", + "start_time": "2024-06-17T15:36:22.121075Z" + } + }, "source": [ "from IPython.display import Markdown\n", "\n", - "if K >= max(S0*np.exp(np.dot(CHOLESKY,[grid_points[-1]]*2) + MU)):\n", - " display(Markdown(' K always greater than the maximum asset values. Stop the run, the payoff is 0'))" + "if K >= max(S0 * np.exp(np.dot(CHOLESKY, [grid_points[-1]] * 2) + MU)):\n", + " display(\n", + " Markdown(\n", + " \" K always greater than the maximum asset values. Stop the run, the payoff is 0\"\n", + " )\n", + " )" ], "outputs": [], - "execution_count": null + "execution_count": 5 }, { "cell_type": "markdown", @@ -170,21 +192,27 @@ { "cell_type": "code", "id": "4b0bc081", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2024-06-17T15:36:22.126453Z", + "start_time": "2024-06-17T15:36:22.124385Z" + } + }, "source": [ "FRAC_PLACES = 2\n", "\n", + "\n", "def round_factor(a):\n", - " precision_factor = 2 ** FRAC_PLACES\n", + " precision_factor = 2**FRAC_PLACES\n", " return round(a * precision_factor) / precision_factor\n", "\n", "\n", "def floor_factor(a):\n", - " precision_factor = 2 ** FRAC_PLACES\n", + " precision_factor = 2**FRAC_PLACES\n", " return np.floor(a * precision_factor) / precision_factor" ], "outputs": [], - "execution_count": null + "execution_count": 6 }, { "cell_type": "markdown", @@ -197,24 +225,29 @@ { "cell_type": "code", "id": "dc03563a", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2024-06-17T15:36:22.134629Z", + "start_time": "2024-06-17T15:36:22.133323Z" + } + }, "source": [ "from functools import reduce\n", "\n", - "from classiq import QNum, get_expression_numeric_attributes, qfunc, Output\n", + "from classiq import Output, QNum, get_expression_numeric_attributes, qfunc\n", "from classiq.qmod.symbolic import max as qmax\n", "\n", "a = STEP_X / SCALING_FACTOR\n", "b = np.log(S0[0]) + MU[0] + MIN_X * CHOLESKY[0].sum()\n", "c = (\n", - " SCALING_FACTOR\n", - " * (\n", + " SCALING_FACTOR\n", + " * (\n", " np.log(S0[1])\n", " + MU[1]\n", " - (np.log(S0[0]) + MU[0])\n", " + MIN_X * sum(CHOLESKY[1] - CHOLESKY[0])\n", " )\n", - " / STEP_X\n", + " / STEP_X\n", ")\n", "c = round_factor(c)\n", "\n", @@ -229,6 +262,7 @@ " ],\n", " )\n", "\n", + "\n", "def calculate_max_reg_type():\n", " x1 = QNum(\"x1\", NUM_QUBITS, False, 0)\n", " x2 = QNum(\"x2\", NUM_QUBITS, False, 0)\n", @@ -243,13 +277,17 @@ "MAX_FRAC_PLACES = calculate_max_reg_type()[1]" ], "outputs": [], - "execution_count": null + "execution_count": 7 }, { "cell_type": "code", "id": "1f613230", "metadata": { - "collapsed": false + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-17T15:36:22.137014Z", + "start_time": "2024-06-17T15:36:22.135935Z" + } }, "source": [ "@qfunc\n", @@ -257,7 +295,7 @@ " res |= qmax(get_affine_formula([x1, x2], 0), get_affine_formula([x1, x2], 1) + c)" ], "outputs": [], - "execution_count": null + "execution_count": 8 }, { "cell_type": "markdown", @@ -295,10 +333,15 @@ "cell_type": "code", "id": "75122cba", "metadata": { - "collapsed": false + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-17T15:36:22.151404Z", + "start_time": "2024-06-17T15:36:22.138806Z" + } }, "source": [ - "from classiq import QBit, prepare_exponential_state, bind\n", + "from classiq import QBit, bind, prepare_exponential_state\n", + "\n", "\n", "@qfunc\n", "def integrator(x: QNum, ref: QNum, res: QBit) -> None:\n", @@ -310,18 +353,23 @@ " bind(x_uint, x)" ], "outputs": [], - "execution_count": null + "execution_count": 9 }, { "cell_type": "code", "id": "95c12d95", "metadata": { - "collapsed": false + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-17T15:36:22.151716Z", + "start_time": "2024-06-17T15:36:22.142523Z" + } }, "source": [ - "from classiq import control, RY\n", + "from classiq import RY, control\n", "from classiq.qmod.symbolic import asin, exp, sqrt\n", "\n", + "\n", "def get_strike_price_theta_integration(x: QNum):\n", " exp_rate = (1 / (2**x.fraction_digits)) * a\n", " B = (exp((2**x.size) * exp_rate) - 1) / exp(exp_rate)\n", @@ -329,6 +377,7 @@ " C = S0[0] * exp((MU[0] + MIN_X * CHOLESKY[0].sum()))\n", " return 2 * asin(sqrt((K - (C * A)) / (C * B)))\n", "\n", + "\n", "@qfunc\n", "def integration_load_amplitudes(\n", " geq_reg: QNum, max_reg: QNum, integrator_reg: QNum, ind_reg: QBit\n", @@ -338,13 +387,17 @@ " control(geq_reg == 0, lambda: RY(strike_price_theta, ind_reg))" ], "outputs": [], - "execution_count": null + "execution_count": 10 }, { "cell_type": "code", "id": "c4ab6177", "metadata": { - "collapsed": false + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-17T15:36:22.151756Z", + "start_time": "2024-06-17T15:36:22.145268Z" + } }, "source": [ "@qfunc\n", @@ -355,20 +408,25 @@ " a = STEP_X / SCALING_FACTOR\n", " b = np.log(S0[0]) + MU[0] + MIN_X * CHOLESKY[0].sum()\n", " COMP_VALUE = (np.log(K) - b) / a\n", - " res |= x > floor_factor(COMP_VALUE)\n" + " res |= x > floor_factor(COMP_VALUE)" ], "outputs": [], - "execution_count": null + "execution_count": 11 }, { "cell_type": "code", "id": "07c9e4f7", "metadata": { - "collapsed": false + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-17T15:36:22.151786Z", + "start_time": "2024-06-17T15:36:22.147679Z" + } }, "source": [ "from classiq import within_apply\n", "\n", + "\n", "@qfunc\n", "def integration_payoff(max_reg: QNum, integrator_reg: QNum, ind_reg: QBit):\n", " geq_reg = QBit(\"geq_reg\")\n", @@ -378,20 +436,33 @@ " )" ], "outputs": [], - "execution_count": null + "execution_count": 12 }, { "cell_type": "code", "id": "c7870263", "metadata": { - "collapsed": false + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-17T15:36:33.147051Z", + "start_time": "2024-06-17T15:36:22.163847Z" + } }, "source": [ - "from classiq import Constraints, create_model, synthesize, show, allocate, allocate_num, inplace_prepare_state\n", + "from classiq import (\n", + " Constraints,\n", + " allocate,\n", + " allocate_num,\n", + " create_model,\n", + " inplace_prepare_state,\n", + " show,\n", + " synthesize,\n", + ")\n", + "\n", "\n", "@qfunc\n", "def rainbow_integration(\n", - " x1: QNum, \n", + " x1: QNum,\n", " x2: QNum,\n", " integrator_reg: QNum,\n", " ind_reg: QBit,\n", @@ -407,7 +478,7 @@ "\n", "@qfunc\n", "def main(\n", - " x1: Output[QNum], \n", + " x1: Output[QNum],\n", " x2: Output[QNum],\n", " integrator_reg: Output[QNum],\n", " ind_reg: Output[QBit],\n", @@ -425,8 +496,17 @@ "qprog = synthesize(qmod)\n", "show(qprog)" ], - "outputs": [], - "execution_count": null + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Starting synthesis\n", + "Opening: http://nightly.platform.classiq.io/circuit/0d7e0aec-3ea7-4141-8e1d-c717d75fffcd?version=0.43.0.dev21\n" + ] + } + ], + "execution_count": 13 }, { "cell_type": "markdown", @@ -440,10 +520,14 @@ "cell_type": "code", "id": "7e9554eb", "metadata": { - "collapsed": false + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-17T15:36:33.152567Z", + "start_time": "2024-06-17T15:36:33.150260Z" + } }, "source": [ - "from classiq import cfunc, Z\n", + "from classiq import Z, cfunc\n", "from classiq.qmod.builtins.classical_execution_primitives import iqae, save\n", "\n", "\n", @@ -451,20 +535,27 @@ "def qmci_oracle(ind: QBit):\n", " Z(ind)\n", "\n", + "\n", "@cfunc\n", "def cmain():\n", " iqae_res = iqae(epsilon=0.05, alpha=0.1)\n", " save({\"iqae_res\": iqae_res})" ], "outputs": [], - "execution_count": null + "execution_count": 14 }, { "cell_type": "code", "id": "2420716d", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2024-06-17T15:36:33.156505Z", + "start_time": "2024-06-17T15:36:33.154508Z" + } + }, "source": [ - "from classiq import CInt, QCallable, grover_operator, power, QArray\n", + "from classiq import CInt, QArray, QCallable, grover_operator, power\n", + "\n", "\n", "@qfunc\n", "def grover_algorithm(\n", @@ -477,13 +568,17 @@ " power(k, lambda: grover_operator(oracle_operand, sp_operand, x))" ], "outputs": [], - "execution_count": null + "execution_count": 15 }, { "cell_type": "code", "id": "0c8c1dbc", "metadata": { - "collapsed": false + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-17T15:36:33.161555Z", + "start_time": "2024-06-17T15:36:33.160026Z" + } }, "source": [ "def get_main():\n", @@ -511,14 +606,20 @@ " return main" ], "outputs": [], - "execution_count": null + "execution_count": 16 }, { "cell_type": "code", "id": "19deb769", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2024-06-17T15:36:33.167424Z", + "start_time": "2024-06-17T15:36:33.164466Z" + } + }, "source": [ - "from classiq import execute\n", + "from classiq import execute, write_qmod\n", + "\n", "\n", "def synthesize_and_execute(post_process):\n", " constraints = Constraints(max_width=25)\n", @@ -527,6 +628,7 @@ " constraints=constraints,\n", " classical_execution_function=cmain,\n", " )\n", + " write_qmod(qmod, \"rainbow_options_integration_method\")\n", " print(\"Starting synthesis\")\n", " qprog = synthesize(qmod)\n", " show(qprog)\n", @@ -539,7 +641,7 @@ " return (qmod, qprog, iqae_res, parsed_res)" ], "outputs": [], - "execution_count": null + "execution_count": 17 }, { "cell_type": "markdown", @@ -561,7 +663,12 @@ { "cell_type": "code", "id": "f62ac3e6", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2024-06-17T15:36:33.267922Z", + "start_time": "2024-06-17T15:36:33.169530Z" + } + }, "source": [ "def parse_result_integration(iqae_res):\n", " exp_rate = (1 / (2**MAX_FRAC_PLACES)) * a\n", @@ -576,28 +683,74 @@ " return (option_value, confidence_interval)" ], "outputs": [], - "execution_count": null + "execution_count": 18 }, { "cell_type": "markdown", "id": "697fa83f", "metadata": {}, - "source": "# Run method" + "source": [ + "# Run method" + ] }, { "cell_type": "code", "id": "fde9fc59", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2024-06-17T15:40:57.775557Z", + "start_time": "2024-06-17T15:36:33.303932Z" + } + }, "source": [ "qmod_integration, qprog_integration, iqae_res_integration, parsed_res_integration = (\n", " synthesize_and_execute(parse_result_integration)\n", ")\n", "result, conf_interval = parsed_res_integration\n", - "print(f\"raw iqae results: {iqae_res_integration.estimation} with confidence interval {iqae_res_integration.confidence_interval}\")\n", + "print(\n", + " f\"raw iqae results: {iqae_res_integration.estimation} with confidence interval {iqae_res_integration.confidence_interval}\"\n", + ")\n", "print(f\"option estimated value: {result} with confidence interval {conf_interval}\")" ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Starting synthesis\n", + "Opening: http://nightly.platform.classiq.io/circuit/6217ff8d-dc65-4cbe-becb-b008b537d406?version=0.43.0.dev21\n", + "Starting execution\n", + "raw iqae results: 0.05152406153567188 (0.0478111147516288, 0.05523700831971495)\n", + "raw iqae results: 0.05152406153567188 with confidence interval (0.0478111147516288, 0.05523700831971495)\n", + "option estimated value: 26.439360758928842 with confidence interval [16.82076595 36.05795557]\n" + ] + } + ], + "execution_count": 19 + }, + { + "cell_type": "markdown", + "source": [ + "## Assertions" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": 20, "outputs": [], - "execution_count": null + "source": [ + "assert -5 <= result <= 45" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-06-17T15:40:57.779163Z", + "start_time": "2024-06-17T15:40:57.777435Z" + } + } }, { "metadata": {}, @@ -605,24 +758,16 @@ "source": [ "## References\n", "\n", - "[1]: [Francesca Cibrario et al., Quantum Amplitude Loading for Rainbow Options Pricing. Preprint](https://arxiv.org/abs/2402.05574v2)" + "[1]: [Francesca Cibrario et al., Quantum Amplitude Loading for Rainbow Options Pricing. Preprint](https://arxiv.org/abs/2402.05574v2)\n" ], "id": "f859b2b3ac750050" - }, - { - "metadata": {}, - "cell_type": "code", - "source": "", - "id": "75c5a77d0cc56f98", - "outputs": [], - "execution_count": null } ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "name": "python3", "language": "python", - "name": "ipykernel" + "display_name": "Python 3 (ipykernel)" }, "language_info": { "codemirror_mode": { diff --git a/research/rainbow_options_integration_method/rainbow_options_integration_method.metadata.json b/research/rainbow_options_integration_method/rainbow_options_integration_method.metadata.json new file mode 100644 index 000000000..382ca842b --- /dev/null +++ b/research/rainbow_options_integration_method/rainbow_options_integration_method.metadata.json @@ -0,0 +1,8 @@ +{ + "friendly_name": "Rainbow Options Integration Method", + "description": "Rainbow Options payoff using Integration Method in QAE", + "problem_domain_tags": ["risk analysis"], + "vertical_tags": ["finance"], + "qmod_type": ["application"], + "level": ["advanced"] +} diff --git a/research/rainbow_options_integration_method/rainbow_options_integration_method.qmod b/research/rainbow_options_integration_method/rainbow_options_integration_method.qmod new file mode 100644 index 000000000..4a3a0cce2 --- /dev/null +++ b/research/rainbow_options_integration_method/rainbow_options_integration_method.qmod @@ -0,0 +1,82 @@ +qfunc qmci_oracle(ind: qbit) { + Z(ind); +} + +qfunc affine_max(x1: qnum, x2: qnum, output res: qnum) { + res = max(x1 * 1.0, ((x1 * 0.75) + (x2 * 0.75)) + (-1.25)); +} + +qfunc asset_geq_strike_price(x: qnum, output res: qbit) { + res = x > 1.5; +} + +qfunc integrator(x: qnum, ref: qnum, res: qbit) { + prepare_exponential_state<-((1 / (2 ** x.fraction_digits)) * 0.4341)>(ref); + x_uint: qnum; + x -> x_uint; + res ^= x_uint >= ref; + x_uint -> x; +} + +qfunc integration_load_amplitudes(geq_reg: qnum, max_reg: qnum, integrator_reg: qnum, ind_reg: qbit) { + control (geq_reg == 1) { + integrator(max_reg, integrator_reg, ind_reg); + } + control (geq_reg == 0) { + RY<2 * asin(sqrt((190 - ((193.97 * exp(-0.7408)) * (1 / exp((1 / (2 ** max_reg.fraction_digits)) * 0.4341)))) / ((193.97 * exp(-0.7408)) * ((exp((2 ** max_reg.size) * ((1 / (2 ** max_reg.fraction_digits)) * 0.4341)) - 1) / exp((1 / (2 ** max_reg.fraction_digits)) * 0.4341)))))>(ind_reg); + } +} + +qfunc integration_payoff(max_reg: qnum, integrator_reg: qnum, ind_reg: qbit) { + geq_reg: qbit; + within { + asset_geq_strike_price(max_reg, geq_reg); + } apply { + integration_load_amplitudes(geq_reg, max_reg, integrator_reg, ind_reg); + } +} + +qfunc rainbow_integration(x1: qnum, x2: qnum, integrator_reg: qnum, ind_reg: qbit) { + inplace_prepare_state<[ + 0.0656, + 0.4344, + 0.4344, + 0.0656 + ], 0>(x1); + inplace_prepare_state<[ + 0.0656, + 0.4344, + 0.4344, + 0.0656 + ], 0>(x2); + max_out: qnum; + within { + affine_max(x1, x2, max_out); + } apply { + integration_payoff(max_out, integrator_reg, ind_reg); + } +} + +qfunc grover_algorithm(x: qbit[]) { + sp_operand(x); + power (k) { + grover_operator(x); + } +} + +qfunc main(output ind_reg: qbit) { + full_reg: qbit[]; + allocate<10>(full_reg); + grover_algorithm(full_reg); + state_reg: qbit[]; + full_reg -> {state_reg, ind_reg}; +} + +cscope ``` +iqae_res = iqae(epsilon=0.05, alpha=0.1) +save({'iqae_res': iqae_res}) +``` diff --git a/research/rainbow_options_integration_method/rainbow_options_integration_method.synthesis_options.json b/research/rainbow_options_integration_method/rainbow_options_integration_method.synthesis_options.json new file mode 100644 index 000000000..29a83131d --- /dev/null +++ b/research/rainbow_options_integration_method/rainbow_options_integration_method.synthesis_options.json @@ -0,0 +1,5 @@ +{ + "constraints": { + "max_width": 25 + } +}