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
+ }
+}