diff --git a/docs/en/basics/expressions.ipynb b/docs/en/basics/expressions.ipynb index bac7404..9aa0da5 100644 --- a/docs/en/basics/expressions.ipynb +++ b/docs/en/basics/expressions.ipynb @@ -25,10 +25,10 @@ "id": "e511a2c6", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:05:22.675579Z", - "iopub.status.busy": "2026-03-24T02:05:22.675518Z", - "iopub.status.idle": "2026-03-24T02:05:22.680581Z", - "shell.execute_reply": "2026-03-24T02:05:22.680173Z" + "iopub.execute_input": "2026-04-16T07:03:51.250049Z", + "iopub.status.busy": "2026-04-16T07:03:51.249843Z", + "iopub.status.idle": "2026-04-16T07:03:51.285753Z", + "shell.execute_reply": "2026-04-16T07:03:51.284748Z" } }, "outputs": [], @@ -58,10 +58,10 @@ "id": "fdd9d4ad", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:05:22.681647Z", - "iopub.status.busy": "2026-03-24T02:05:22.681589Z", - "iopub.status.idle": "2026-03-24T02:05:22.747100Z", - "shell.execute_reply": "2026-03-24T02:05:22.746786Z" + "iopub.execute_input": "2026-04-16T07:03:51.288701Z", + "iopub.status.busy": "2026-04-16T07:03:51.288546Z", + "iopub.status.idle": "2026-04-16T07:03:51.623277Z", + "shell.execute_reply": "2026-04-16T07:03:51.622658Z" }, "label": "test-problem" }, @@ -78,7 +78,7 @@ { "data": { "text/plain": [ - "'Expression(sum(N.map(lambda i: y[i])))'" + "'Expression(sum(set(N).map(lambda i: y[i])))'" ] }, "metadata": {}, @@ -182,10 +182,10 @@ "id": "e38e46d8", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:05:22.748301Z", - "iopub.status.busy": "2026-03-24T02:05:22.748242Z", - "iopub.status.idle": "2026-03-24T02:05:22.763581Z", - "shell.execute_reply": "2026-03-24T02:05:22.763245Z" + "iopub.execute_input": "2026-04-16T07:03:51.625014Z", + "iopub.status.busy": "2026-04-16T07:03:51.624895Z", + "iopub.status.idle": "2026-04-16T07:03:51.673186Z", + "shell.execute_reply": "2026-04-16T07:03:51.672645Z" } }, "outputs": [ @@ -225,10 +225,10 @@ "id": "e7874eab", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:05:22.764719Z", - "iopub.status.busy": "2026-03-24T02:05:22.764658Z", - "iopub.status.idle": "2026-03-24T02:05:22.773383Z", - "shell.execute_reply": "2026-03-24T02:05:22.773031Z" + "iopub.execute_input": "2026-04-16T07:03:51.674685Z", + "iopub.status.busy": "2026-04-16T07:03:51.674553Z", + "iopub.status.idle": "2026-04-16T07:03:51.752515Z", + "shell.execute_reply": "2026-04-16T07:03:51.751337Z" } }, "outputs": [ @@ -238,13 +238,13 @@ "text": [ "Traceback (most recent last):\n", " while inferring the type of expression `x + Located { inner: \"hoge\", src_span: NoSrcSpan }',\n", - " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_48108/594888127.py\", line 3, col 19-29\n", + " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_62910/594888127.py\", line 3, col 19-29\n", " while inferring the type of expression `x + Located { inner: \"hoge\", src_span: NoSrcSpan }',\n", - " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_48108/594888127.py\", line 3, col 19-29\n", + " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_62910/594888127.py\", line 3, col 19-29\n", " while checking if types `binary!' and `Literal[\"hoge\"]' can be combined with numeric operator `Add',\n", - " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_48108/594888127.py\", line 3, col 19-29\n", + " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_62910/594888127.py\", line 3, col 19-29\n", "\n", - "File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_48108/594888127.py\", line 3, col 19-29:\n", + "File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_62910/594888127.py\", line 3, col 19-29:\n", "\n", " 3 | problem.infer(x + \"hoge\")\n", " ^^^^^^^^^^\n", @@ -319,10 +319,10 @@ "id": "dc85ae1d", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:05:22.774450Z", - "iopub.status.busy": "2026-03-24T02:05:22.774398Z", - "iopub.status.idle": "2026-03-24T02:05:23.035083Z", - "shell.execute_reply": "2026-03-24T02:05:23.034403Z" + "iopub.execute_input": "2026-04-16T07:03:51.754458Z", + "iopub.status.busy": "2026-04-16T07:03:51.754333Z", + "iopub.status.idle": "2026-04-16T07:03:53.730095Z", + "shell.execute_reply": "2026-04-16T07:03:53.729682Z" } }, "outputs": [ @@ -384,10 +384,10 @@ "id": "4cdd5152", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:05:23.036874Z", - "iopub.status.busy": "2026-03-24T02:05:23.036736Z", - "iopub.status.idle": "2026-03-24T02:05:23.047188Z", - "shell.execute_reply": "2026-03-24T02:05:23.046886Z" + "iopub.execute_input": "2026-04-16T07:03:53.731292Z", + "iopub.status.busy": "2026-04-16T07:03:53.731198Z", + "iopub.status.idle": "2026-04-16T07:03:53.749974Z", + "shell.execute_reply": "2026-04-16T07:03:53.749636Z" } }, "outputs": [ @@ -415,10 +415,10 @@ "id": "28d877b6", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:05:23.048413Z", - "iopub.status.busy": "2026-03-24T02:05:23.048354Z", - "iopub.status.idle": "2026-03-24T02:05:23.072555Z", - "shell.execute_reply": "2026-03-24T02:05:23.072178Z" + "iopub.execute_input": "2026-04-16T07:03:53.751054Z", + "iopub.status.busy": "2026-04-16T07:03:53.750995Z", + "iopub.status.idle": "2026-04-16T07:03:53.881347Z", + "shell.execute_reply": "2026-04-16T07:03:53.880994Z" } }, "outputs": [ @@ -446,10 +446,10 @@ "id": "f96d34c7", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:05:23.073523Z", - "iopub.status.busy": "2026-03-24T02:05:23.073463Z", - "iopub.status.idle": "2026-03-24T02:05:23.090106Z", - "shell.execute_reply": "2026-03-24T02:05:23.089743Z" + "iopub.execute_input": "2026-04-16T07:03:53.882501Z", + "iopub.status.busy": "2026-04-16T07:03:53.882436Z", + "iopub.status.idle": "2026-04-16T07:03:53.936561Z", + "shell.execute_reply": "2026-04-16T07:03:53.936045Z" } }, "outputs": [ @@ -477,10 +477,10 @@ "id": "5adad4bc", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:05:23.091104Z", - "iopub.status.busy": "2026-03-24T02:05:23.091047Z", - "iopub.status.idle": "2026-03-24T02:05:23.114714Z", - "shell.execute_reply": "2026-03-24T02:05:23.114316Z" + "iopub.execute_input": "2026-04-16T07:03:53.937974Z", + "iopub.status.busy": "2026-04-16T07:03:53.937884Z", + "iopub.status.idle": "2026-04-16T07:03:54.072652Z", + "shell.execute_reply": "2026-04-16T07:03:54.072134Z" } }, "outputs": [ @@ -508,10 +508,10 @@ "id": "6ab268e5", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:05:23.115598Z", - "iopub.status.busy": "2026-03-24T02:05:23.115550Z", - "iopub.status.idle": "2026-03-24T02:05:23.132080Z", - "shell.execute_reply": "2026-03-24T02:05:23.131772Z" + "iopub.execute_input": "2026-04-16T07:03:54.073869Z", + "iopub.status.busy": "2026-04-16T07:03:54.073777Z", + "iopub.status.idle": "2026-04-16T07:03:54.155655Z", + "shell.execute_reply": "2026-04-16T07:03:54.155126Z" } }, "outputs": [ @@ -547,10 +547,10 @@ "id": "75aa08e2", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:05:23.133342Z", - "iopub.status.busy": "2026-03-24T02:05:23.133282Z", - "iopub.status.idle": "2026-03-24T02:05:23.142279Z", - "shell.execute_reply": "2026-03-24T02:05:23.141967Z" + "iopub.execute_input": "2026-04-16T07:03:54.157695Z", + "iopub.status.busy": "2026-04-16T07:03:54.157496Z", + "iopub.status.idle": "2026-04-16T07:03:54.180138Z", + "shell.execute_reply": "2026-04-16T07:03:54.179701Z" } }, "outputs": [ @@ -560,13 +560,13 @@ "text": [ "Traceback (most recent last):\n", " while inferring the type of expression `S * y',\n", - " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_48108/2932800859.py\", line 3, col 19-24\n", + " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_62910/2932800859.py\", line 3, col 19-24\n", " while inferring the type of expression `S * y',\n", - " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_48108/2932800859.py\", line 3, col 19-24\n", + " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_62910/2932800859.py\", line 3, col 19-24\n", " while checking if types `TotalDict[N; float]' and `Array[N, M; int!]' can be combined with numeric operator `Mul',\n", - " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_48108/2932800859.py\", line 3, col 19-24\n", + " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_62910/2932800859.py\", line 3, col 19-24\n", "\n", - "File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_48108/2932800859.py\", line 3, col 19-24:\n", + "File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_62910/2932800859.py\", line 3, col 19-24:\n", "\n", " 3 | problem.infer(S * y)\n", " ^^^^^\n", @@ -589,10 +589,10 @@ "id": "17c3299c", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:05:23.143225Z", - "iopub.status.busy": "2026-03-24T02:05:23.143170Z", - "iopub.status.idle": "2026-03-24T02:05:23.152189Z", - "shell.execute_reply": "2026-03-24T02:05:23.151909Z" + "iopub.execute_input": "2026-04-16T07:03:54.181246Z", + "iopub.status.busy": "2026-04-16T07:03:54.181178Z", + "iopub.status.idle": "2026-04-16T07:03:54.201250Z", + "shell.execute_reply": "2026-04-16T07:03:54.200873Z" } }, "outputs": [ @@ -602,13 +602,13 @@ "text": [ "Traceback (most recent last):\n", " while inferring the type of expression `y + z',\n", - " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_48108/3762455632.py\", line 3, col 19-24\n", + " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_62910/3762455632.py\", line 3, col 19-24\n", " while inferring the type of expression `y + z',\n", - " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_48108/3762455632.py\", line 3, col 19-24\n", + " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_62910/3762455632.py\", line 3, col 19-24\n", " while checking if types `Array[N, M; int!]' and `Array[N, M, N; float!]' can be combined with numeric operator `Add',\n", - " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_48108/3762455632.py\", line 3, col 19-24\n", + " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_62910/3762455632.py\", line 3, col 19-24\n", "\n", - "File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_48108/3762455632.py\", line 3, col 19-24:\n", + "File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_62910/3762455632.py\", line 3, col 19-24:\n", "\n", " 3 | problem.infer(y + z)\n", " ^^^^^\n", @@ -625,12 +625,169 @@ " print(e)" ] }, + { + "cell_type": "markdown", + "id": "53427afe", + "metadata": {}, + "source": [ + "### Alternative syntax: constructing arrays with `genarray`\n", + "\n", + "In the example above, operations involving nontrivial broadcasting, such as `y + z`, result in an (intentional) error.\n", + "In such cases, you can use the {py:func}`~jijmodeling.genarray` function to construct the resulting array explicitly by specifying the shape and the expression for each entry:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "8654fb78", + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-16T07:03:54.203129Z", + "iopub.status.busy": "2026-04-16T07:03:54.202957Z", + "iopub.status.idle": "2026-04-16T07:03:54.564392Z", + "shell.execute_reply": "2026-04-16T07:03:54.563929Z" + } + }, + "outputs": [ + { + "data": { + "text/latex": [ + "$${\\left( {y}_{i,j}+{z}_{i,j,k}\\right) }_{\\substack{i\\in \\left\\{0,\\ldots ,N-1\\right\\}\\\\j\\in \\left\\{0,\\ldots ,M-1\\right\\}\\\\k\\in \\left\\{0,\\ldots ,N-1\\right\\}}}$$" + ], + "text/plain": [ + "Expression(genarray(lambda (i, j, k): y[i, j] + z[i, j, k], (N, M, N)))" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$$\\mathop{\\mathrm{Array}}\\left[N\\times M\\times N;\\mathbb{R}\\right]$$" + ], + "text/plain": [ + "Array[N, M, N; float!]" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "A = jm.genarray(lambda i, j, k: y[i, j] + z[i, j, k], (N, M, N))\n", + "display(A)\n", + "problem.infer(A)" + ] + }, + { + "cell_type": "markdown", + "id": "bdd5d5a5", + "metadata": {}, + "source": [ + "When using the Decorator API, you can also use a comprehension with `jm.genarray` as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "58b52480", + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-16T07:03:54.565751Z", + "iopub.status.busy": "2026-04-16T07:03:54.565661Z", + "iopub.status.idle": "2026-04-16T07:03:54.844680Z", + "shell.execute_reply": "2026-04-16T07:03:54.844197Z" + } + }, + "outputs": [ + { + "data": { + "text/latex": [ + "$${\\left( {y}_{i,j}+{z}_{i,j,k}\\right) }_{\\substack{i\\in \\left\\{0,\\ldots ,N-1\\right\\}\\\\j\\in \\left\\{0,\\ldots ,M-1\\right\\}\\\\k\\in \\left\\{0,\\ldots ,N-1\\right\\}}}$$" + ], + "text/plain": [ + "Expression(genarray(lambda (i, j, k): y[i, j] + z[i, j, k], (N, M, N)))" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$$\\mathop{\\mathrm{Array}}\\left[N\\times M\\times N;\\mathbb{R}\\right]$$" + ], + "text/plain": [ + "Array[N, M, N; float!]" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "@problem.update\n", + "def _(problem: jm.DecoratedProblem):\n", + " A = jm.genarray(y[i, j] + z[i, j, k] for i, j, k in (N, M, N))\n", + " display(A)\n", + " display(problem.infer(A))" + ] + }, + { + "cell_type": "markdown", + "id": "4e4b4dec", + "metadata": {}, + "source": [ + "Only one `for .. in ...` clause is allowed in a `genarray` comprehension.\n", + "Be careful, because using multiple `for` clauses as shown below raises an error:" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "ba29b19b", + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-16T07:03:54.845879Z", + "iopub.status.busy": "2026-04-16T07:03:54.845808Z", + "iopub.status.idle": "2026-04-16T07:03:54.860047Z", + "shell.execute_reply": "2026-04-16T07:03:54.859485Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "A genarray comprehension must have exactly one for-clause:\n", + "\n", + " 9 | Sums = problem.NamedExpr(jm.genarray(a[i, j] * x[i] for i in N for j in M))\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + ] + } + ], + "source": [ + "try:\n", + "\n", + " @jm.Problem.define(\"genarray example\")\n", + " def _(problem):\n", + " N = problem.Natural()\n", + " M = problem.Natural()\n", + " a = problem.Float(shape=(N, M))\n", + " x = problem.BinaryVar(shape=N)\n", + " Sums = problem.NamedExpr(jm.genarray(a[i, j] * x[i] for i in N for j in M))\n", + "except SyntaxError as e:\n", + " print(str(e))" + ] + }, { "cell_type": "markdown", "id": "f2b8a23e", "metadata": {}, "source": [ - ":::{admonition} Division by decision variables\n", + "::{admonition} Division by decision variables\n", ":class: caution\n", "\n", "At the modeling stage, decision variables can appear on either side of arithmetic operators.\n", @@ -662,14 +819,14 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 17, "id": "6c81d662", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:05:23.153443Z", - "iopub.status.busy": "2026-03-24T02:05:23.153393Z", - "iopub.status.idle": "2026-03-24T02:05:23.176773Z", - "shell.execute_reply": "2026-03-24T02:05:23.176454Z" + "iopub.execute_input": "2026-04-16T07:03:55.024305Z", + "iopub.status.busy": "2026-04-16T07:03:55.024197Z", + "iopub.status.idle": "2026-04-16T07:03:55.241419Z", + "shell.execute_reply": "2026-04-16T07:03:55.240558Z" } }, "outputs": [ @@ -682,7 +839,7 @@ "Comparison[binary!, Array[N, M; int!]]" ] }, - "execution_count": 13, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } @@ -693,14 +850,14 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 18, "id": "b43188e5", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:05:23.177982Z", - "iopub.status.busy": "2026-03-24T02:05:23.177925Z", - "iopub.status.idle": "2026-03-24T02:05:23.187379Z", - "shell.execute_reply": "2026-03-24T02:05:23.187017Z" + "iopub.execute_input": "2026-04-16T07:03:55.243486Z", + "iopub.status.busy": "2026-04-16T07:03:55.243268Z", + "iopub.status.idle": "2026-04-16T07:03:55.270778Z", + "shell.execute_reply": "2026-04-16T07:03:55.269975Z" } }, "outputs": [ @@ -713,7 +870,7 @@ "bool" ] }, - "execution_count": 14, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } @@ -724,14 +881,14 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 19, "id": "49d90ad4", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:05:23.188286Z", - "iopub.status.busy": "2026-03-24T02:05:23.188236Z", - "iopub.status.idle": "2026-03-24T02:05:23.225769Z", - "shell.execute_reply": "2026-03-24T02:05:23.225380Z" + "iopub.execute_input": "2026-04-16T07:03:55.272857Z", + "iopub.status.busy": "2026-04-16T07:03:55.272767Z", + "iopub.status.idle": "2026-04-16T07:03:55.708341Z", + "shell.execute_reply": "2026-04-16T07:03:55.707270Z" } }, "outputs": [ @@ -744,7 +901,7 @@ "Comparison[Array[N, M; float!], Array[N, M; float!]]" ] }, - "execution_count": 15, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } @@ -791,14 +948,14 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 20, "id": "c4eff827", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:05:23.226698Z", - "iopub.status.busy": "2026-03-24T02:05:23.226647Z", - "iopub.status.idle": "2026-03-24T02:05:23.290179Z", - "shell.execute_reply": "2026-03-24T02:05:23.289811Z" + "iopub.execute_input": "2026-04-16T07:03:55.712425Z", + "iopub.status.busy": "2026-04-16T07:03:55.712281Z", + "iopub.status.idle": "2026-04-16T07:03:56.171638Z", + "shell.execute_reply": "2026-04-16T07:03:56.171245Z" } }, "outputs": [ @@ -815,7 +972,7 @@ "Problem(name=\"Index and Keys Example\", sense=MINIMIZE, objective=0, constraints=[])" ] }, - "execution_count": 16, + "execution_count": 20, "metadata": {}, "output_type": "execute_result" } @@ -890,14 +1047,14 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 21, "id": "1b8b9adc", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:05:23.291256Z", - "iopub.status.busy": "2026-03-24T02:05:23.291200Z", - "iopub.status.idle": "2026-03-24T02:05:23.369196Z", - "shell.execute_reply": "2026-03-24T02:05:23.368776Z" + "iopub.execute_input": "2026-04-16T07:03:56.172815Z", + "iopub.status.busy": "2026-04-16T07:03:56.172757Z", + "iopub.status.idle": "2026-04-16T07:03:56.567134Z", + "shell.execute_reply": "2026-04-16T07:03:56.566711Z" } }, "outputs": [ @@ -909,10 +1066,10 @@ "$$" ], "text/plain": [ - "Problem(name=\"Sum Example\", sense=MINIMIZE, objective=sum(N.map(lambda (i: natural): a[i] * x[i])), constraints=[])" + "Problem(name=\"Sum Example\", sense=MINIMIZE, objective=sum(set(N).map(lambda (i: natural): a[i] * x[i])), constraints=[])" ] }, - "execution_count": 17, + "execution_count": 21, "metadata": {}, "output_type": "execute_result" } @@ -944,14 +1101,14 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 22, "id": "49336545", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:05:23.370170Z", - "iopub.status.busy": "2026-03-24T02:05:23.370113Z", - "iopub.status.idle": "2026-03-24T02:05:23.388606Z", - "shell.execute_reply": "2026-03-24T02:05:23.388206Z" + "iopub.execute_input": "2026-04-16T07:03:56.568437Z", + "iopub.status.busy": "2026-04-16T07:03:56.568380Z", + "iopub.status.idle": "2026-04-16T07:03:56.698518Z", + "shell.execute_reply": "2026-04-16T07:03:56.698103Z" } }, "outputs": [ @@ -987,14 +1144,14 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 23, "id": "e35b793f", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:05:23.389577Z", - "iopub.status.busy": "2026-03-24T02:05:23.389524Z", - "iopub.status.idle": "2026-03-24T02:05:23.462197Z", - "shell.execute_reply": "2026-03-24T02:05:23.461854Z" + "iopub.execute_input": "2026-04-16T07:03:56.699627Z", + "iopub.status.busy": "2026-04-16T07:03:56.699556Z", + "iopub.status.idle": "2026-04-16T07:03:57.210870Z", + "shell.execute_reply": "2026-04-16T07:03:57.210208Z" } }, "outputs": [ @@ -1009,7 +1166,7 @@ "Problem(name=\"Sum Example (Plain)\", sense=MINIMIZE, objective=sum(N.map(lambda (i: natural): a[i] * x[i])), constraints=[])" ] }, - "execution_count": 19, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } @@ -1034,14 +1191,14 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 24, "id": "a48f127c", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:05:23.463249Z", - "iopub.status.busy": "2026-03-24T02:05:23.463195Z", - "iopub.status.idle": "2026-03-24T02:05:23.543095Z", - "shell.execute_reply": "2026-03-24T02:05:23.542728Z" + "iopub.execute_input": "2026-04-16T07:03:57.212717Z", + "iopub.status.busy": "2026-04-16T07:03:57.212570Z", + "iopub.status.idle": "2026-04-16T07:03:57.769718Z", + "shell.execute_reply": "2026-04-16T07:03:57.768569Z" } }, "outputs": [ @@ -1056,7 +1213,7 @@ "Problem(name=\"Sum Example (Plain, Alt)\", sense=MINIMIZE, objective=sum(N.map(lambda (i: natural): a[i] * x[i])), constraints=[])" ] }, - "execution_count": 20, + "execution_count": 24, "metadata": {}, "output_type": "execute_result" } @@ -1092,14 +1249,14 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 25, "id": "788d6c0f", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:05:23.544323Z", - "iopub.status.busy": "2026-03-24T02:05:23.544268Z", - "iopub.status.idle": "2026-03-24T02:05:23.670726Z", - "shell.execute_reply": "2026-03-24T02:05:23.670416Z" + "iopub.execute_input": "2026-04-16T07:03:57.775980Z", + "iopub.status.busy": "2026-04-16T07:03:57.775613Z", + "iopub.status.idle": "2026-04-16T07:03:58.473966Z", + "shell.execute_reply": "2026-04-16T07:03:58.472860Z" } }, "outputs": [ @@ -1111,10 +1268,10 @@ "$$" ], "text/plain": [ - "Problem(name=\"Even Sum Example\", sense=MINIMIZE, objective=sum(N.filter(lambda i: i % 2 == 0).map(lambda (i: natural): a[i] * x[i])), constraints=[])" + "Problem(name=\"Even Sum Example\", sense=MINIMIZE, objective=sum(set(N.filter(lambda i: i % 2 == 0)).map(lambda (i: natural): a[i] * x[i])), constraints=[])" ] }, - "execution_count": 21, + "execution_count": 25, "metadata": {}, "output_type": "execute_result" } @@ -1141,14 +1298,14 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 26, "id": "718ac630", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:05:23.671828Z", - "iopub.status.busy": "2026-03-24T02:05:23.671769Z", - "iopub.status.idle": "2026-03-24T02:05:23.765405Z", - "shell.execute_reply": "2026-03-24T02:05:23.765028Z" + "iopub.execute_input": "2026-04-16T07:03:58.475915Z", + "iopub.status.busy": "2026-04-16T07:03:58.475714Z", + "iopub.status.idle": "2026-04-16T07:03:58.995704Z", + "shell.execute_reply": "2026-04-16T07:03:58.994840Z" } }, "outputs": [ @@ -1163,7 +1320,7 @@ "Problem(name=\"Even Sum Example (Plain)\", sense=MINIMIZE, objective=sum(N.filter(lambda i: i % 2 == 0).map(lambda (i: natural): a[i] * x[i])), constraints=[])" ] }, - "execution_count": 22, + "execution_count": 26, "metadata": {}, "output_type": "execute_result" } @@ -1193,14 +1350,14 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 27, "id": "c5cf959f", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:05:23.766463Z", - "iopub.status.busy": "2026-03-24T02:05:23.766410Z", - "iopub.status.idle": "2026-03-24T02:05:23.879279Z", - "shell.execute_reply": "2026-03-24T02:05:23.878939Z" + "iopub.execute_input": "2026-04-16T07:03:58.996950Z", + "iopub.status.busy": "2026-04-16T07:03:58.996858Z", + "iopub.status.idle": "2026-04-16T07:03:59.925280Z", + "shell.execute_reply": "2026-04-16T07:03:59.924874Z" } }, "outputs": [ @@ -1212,10 +1369,10 @@ "$$" ], "text/plain": [ - "Problem(name=\"Double Sum Example\", sense=MINIMIZE, objective=sum(N.flat_map(lambda (i: natural): M.map(lambda (j: natural): (i, j))).map(lambda ((i, j): Tuple[natural, natural]): Q[i, j])), constraints=[])" + "Problem(name=\"Double Sum Example\", sense=MINIMIZE, objective=sum(set(N.flat_map(lambda (i: natural): M.map(lambda (j: natural): (i, j)))).map(lambda ((i, j): Tuple[natural, natural]): Q[i, j])), constraints=[])" ] }, - "execution_count": 23, + "execution_count": 27, "metadata": {}, "output_type": "execute_result" } @@ -1243,14 +1400,14 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 28, "id": "54bec6e0", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:05:23.881047Z", - "iopub.status.busy": "2026-03-24T02:05:23.880962Z", - "iopub.status.idle": "2026-03-24T02:05:23.991294Z", - "shell.execute_reply": "2026-03-24T02:05:23.990927Z" + "iopub.execute_input": "2026-04-16T07:03:59.926786Z", + "iopub.status.busy": "2026-04-16T07:03:59.926705Z", + "iopub.status.idle": "2026-04-16T07:04:01.216521Z", + "shell.execute_reply": "2026-04-16T07:04:01.215347Z" } }, "outputs": [ @@ -1262,10 +1419,10 @@ "$$" ], "text/plain": [ - "Problem(name=\"Double Sum Example (Alt)\", sense=MINIMIZE, objective=sum(set((N, M)).map(lambda ((i, j): Tuple[natural, natural]): Q[i, j])), constraints=[])" + "Problem(name=\"Double Sum Example (Alt)\", sense=MINIMIZE, objective=sum(set(set((N, M))).map(lambda ((i, j): Tuple[natural, natural]): Q[i, j])), constraints=[])" ] }, - "execution_count": 24, + "execution_count": 28, "metadata": {}, "output_type": "execute_result" } @@ -1283,6 +1440,58 @@ "double_sum_example_alt" ] }, + { + "cell_type": "markdown", + "id": "40ddfaec", + "metadata": {}, + "source": [ + "Also, in places such as the right-hand side of `in` in Decorator API comprehensions and the `domain=` keyword argument of `Constraint`, you can omit `jm.product` and represent the Cartesian product with a tuple as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "7bd1e8b4", + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-16T07:04:01.220142Z", + "iopub.status.busy": "2026-04-16T07:04:01.219966Z", + "iopub.status.idle": "2026-04-16T07:04:01.710462Z", + "shell.execute_reply": "2026-04-16T07:04:01.710067Z" + } + }, + "outputs": [ + { + "data": { + "text/latex": [ + "$$\\begin{array}{rl}\n", + "\\text{Problem}\\colon &\\text{Double Sum Example (Alt)}\\\\\\displaystyle \\min &\\displaystyle \\sum _{i=0}^{N-1}{\\sum _{j=0}^{M-1}{{Q}_{i,j}}}\\\\&\\\\\\text{where}&\\\\&\\text{Decision Variables:}\\\\&\\qquad \\begin{alignedat}{2}x&\\in \\mathop{\\mathrm{Array}}\\left[N\\times M;\\left\\{0, 1\\right\\}\\right]&\\quad &2\\text{-dim binary variable}\\\\\\end{alignedat}\\\\&\\\\&\\text{Placeholders:}\\\\&\\qquad \\begin{alignedat}{2}M&\\in \\mathbb{N}&\\quad &\\text{A scalar placeholder in }\\mathbb{N}\\\\N&\\in \\mathbb{N}&\\quad &\\text{A scalar placeholder in }\\mathbb{N}\\\\Q&\\in \\mathop{\\mathrm{Array}}\\left[N\\times M;\\mathbb{R}\\right]&\\quad &2\\text{-dimensional array of placeholders with elements in }\\mathbb{R}\\\\\\end{alignedat}\\end{array}\n", + "$$" + ], + "text/plain": [ + "Problem(name=\"Double Sum Example (Alt)\", sense=MINIMIZE, objective=sum(set((N, M)).map(lambda ((i, j): Tuple[natural, natural]): Q[i, j])), constraints=[])" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "@jm.Problem.define(\"Double Sum Example (Alt)\")\n", + "def double_sum_example_alt(problem: jm.DecoratedProblem):\n", + " N = problem.Length()\n", + " M = problem.Length()\n", + " Q = problem.Float(shape=(N, M))\n", + " x = problem.BinaryVar(shape=(N, M))\n", + "\n", + " # Note: the Cartesian product is represented by a tuple, not product\n", + " problem += jm.sum(Q[i, j] for (i, j) in (N, M))\n", + "\n", + "\n", + "double_sum_example_alt" + ] + }, { "cell_type": "markdown", "id": "8eb42148", @@ -1293,14 +1502,14 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 30, "id": "b37473be", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:05:23.992442Z", - "iopub.status.busy": "2026-03-24T02:05:23.992383Z", - "iopub.status.idle": "2026-03-24T02:05:24.137472Z", - "shell.execute_reply": "2026-03-24T02:05:24.137062Z" + "iopub.execute_input": "2026-04-16T07:04:01.711565Z", + "iopub.status.busy": "2026-04-16T07:04:01.711505Z", + "iopub.status.idle": "2026-04-16T07:04:02.364653Z", + "shell.execute_reply": "2026-04-16T07:04:02.364212Z" } }, "outputs": [ @@ -1312,10 +1521,10 @@ "$$" ], "text/plain": [ - "Problem(name=\"Filtered Double Sum Example\", sense=MINIMIZE, objective=sum(N.flat_map(lambda (i: natural): M.map(lambda (j: natural): (i, j))).filter(lambda (i, j): (i + j) % 2 == 0).map(lambda ((i, j): Tuple[natural, natural]): Q[i, j])), constraints=[])" + "Problem(name=\"Filtered Double Sum Example\", sense=MINIMIZE, objective=sum(set(N.flat_map(lambda (i: natural): M.map(lambda (j: natural): (i, j))).filter(lambda (i, j): (i + j) % 2 == 0)).map(lambda ((i, j): Tuple[natural, natural]): Q[i, j])), constraints=[])" ] }, - "execution_count": 25, + "execution_count": 30, "metadata": {}, "output_type": "execute_result" } @@ -1348,14 +1557,14 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 31, "id": "cc27b233", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:05:24.138503Z", - "iopub.status.busy": "2026-03-24T02:05:24.138438Z", - "iopub.status.idle": "2026-03-24T02:05:24.257288Z", - "shell.execute_reply": "2026-03-24T02:05:24.256983Z" + "iopub.execute_input": "2026-04-16T07:04:02.365890Z", + "iopub.status.busy": "2026-04-16T07:04:02.365829Z", + "iopub.status.idle": "2026-04-16T07:04:02.966887Z", + "shell.execute_reply": "2026-04-16T07:04:02.966497Z" } }, "outputs": [ @@ -1370,7 +1579,7 @@ "Problem(name=\"Filtered Double Sum Example (Plain)\", sense=MINIMIZE, objective=sum(set((N, M)).filter(lambda (i, j): (i + j) % 2 == 0).map(lambda ((i, j): Tuple[natural, natural]): Q[i, j])), constraints=[])" ] }, - "execution_count": 26, + "execution_count": 31, "metadata": {}, "output_type": "execute_result" } @@ -1398,14 +1607,14 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 32, "id": "38abd485", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:05:24.258572Z", - "iopub.status.busy": "2026-03-24T02:05:24.258514Z", - "iopub.status.idle": "2026-03-24T02:05:24.327328Z", - "shell.execute_reply": "2026-03-24T02:05:24.326896Z" + "iopub.execute_input": "2026-04-16T07:04:02.968231Z", + "iopub.status.busy": "2026-04-16T07:04:02.968167Z", + "iopub.status.idle": "2026-04-16T07:04:03.250766Z", + "shell.execute_reply": "2026-04-16T07:04:03.250361Z" } }, "outputs": [ @@ -1418,7 +1627,7 @@ "Expression(sum(N.flat_map(lambda i: M.map(lambda j: (i, j))).filter(lambda (i, j): (i + j) % 2 == 0).map(lambda (i, j): Q[i, j])))" ] }, - "execution_count": 27, + "execution_count": 32, "metadata": {}, "output_type": "execute_result" } @@ -1475,7 +1684,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.11" + "version": "3.11.14" } }, "nbformat": 4, diff --git a/docs/en/releases/unreleased.ipynb b/docs/en/releases/unreleased.ipynb index 74819fe..2630db3 100644 --- a/docs/en/releases/unreleased.ipynb +++ b/docs/en/releases/unreleased.ipynb @@ -57,13 +57,55 @@ "import jijmodeling as jm\n", "\n", "\n", + "problem = jm.Problem(\"genarray example\")\n", + "N = problem.Natural(\"N\")\n", + "M = problem.Natural(\"M\")\n", + "a = problem.Float(\"a\", shape=(N, M))\n", + "x = problem.BinaryVar(\"x\", shape=N)\n", + "Sums = problem.NamedExpr(\"Sums\", jm.genarray(lambda i, j: a[i, j] * x[i], (N, M)))\n", + "\n", + "\n", + "problem" + ] + }, + { + "cell_type": "markdown", + "id": "f9b38e45", + "metadata": {}, + "source": [ + "When using the Decorator API, you can also use a comprehension syntax with `jm.genarray` as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "e4cc3c0d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "$$\\begin{array}{rl}\n", + "\\text{Problem}\\colon &\\text{genarray example}\\\\\\displaystyle \\min &\\displaystyle 0\\\\&\\\\\\text{where}&\\\\&\\text{Decision Variables:}\\\\&\\qquad \\begin{alignedat}{2}x&\\in \\mathop{\\mathrm{Array}}\\left[N;\\left\\{0, 1\\right\\}\\right]&\\quad &1\\text{-dim binary variable}\\\\\\end{alignedat}\\\\&\\\\&\\text{Placeholders:}\\\\&\\qquad \\begin{alignedat}{2}a&\\in \\mathop{\\mathrm{Array}}\\left[N\\times M;\\mathbb{R}\\right]&\\quad &2\\text{-dimensional array of placeholders with elements in }\\mathbb{R}\\\\M&\\in \\mathbb{N}&\\quad &\\text{A scalar placeholder in }\\mathbb{N}\\\\N&\\in \\mathbb{N}&\\quad &\\text{A scalar placeholder in }\\mathbb{N}\\\\\\end{alignedat}\\\\&\\\\&\\text{Named Expressions:}\\\\&\\qquad \\begin{alignedat}{2}Sums&={\\left( {a}_{i,j}\\cdot {x}_{i}\\right) }_{\\substack{i\\in \\left\\{0,\\ldots ,N-1\\right\\}\\\\j\\in \\left\\{0,\\ldots ,M-1\\right\\}}}&\\quad &\\in \\mathop{\\mathrm{Array}}\\left[N\\times M;\\mathbb{R}\\right]\\\\\\end{alignedat}\\end{array}\n", + "$$" + ], + "text/plain": [ + "Problem(name=\"genarray example\", sense=MINIMIZE, objective=0, constraints=[])" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ "@jm.Problem.define(\"genarray example\")\n", "def problem(problem):\n", " N = problem.Natural()\n", " M = problem.Natural()\n", " a = problem.Float(shape=(N, M))\n", " x = problem.BinaryVar(shape=N)\n", - " Sums = problem.NamedExpr(jm.genarray(lambda i, j: a[i, j] * x[i], (N, M)))\n", + " Sums = problem.NamedExpr(jm.genarray(a[i, j] * x[i] for i, j in (N, M)))\n", "\n", "\n", "problem" @@ -71,12 +113,53 @@ }, { "cell_type": "markdown", - "id": "f9b38e45", + "id": "80abaea8", + "metadata": {}, + "source": [ + "Only one `for .. in ...` clause is allowed in a `genarray` comprehension.\n", + "The following is an example that raises an error because it uses multiple `for` clauses:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "f88d8930", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "A genarray comprehension must have exactly one for-clause:\n", + "\n", + " 9 | Sums = problem.NamedExpr(jm.genarray(a[i, j] * x[i] for i in N for j in M))\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + ] + } + ], + "source": [ + "try:\n", + "\n", + " @jm.Problem.define(\"genarray example\")\n", + " def problem(problem):\n", + " N = problem.Natural()\n", + " M = problem.Natural()\n", + " a = problem.Float(shape=(N, M))\n", + " x = problem.BinaryVar(shape=N)\n", + " Sums = problem.NamedExpr(jm.genarray(a[i, j] * x[i] for i in N for j in M))\n", + "except SyntaxError as e:\n", + " print(str(e))" + ] + }, + { + "cell_type": "markdown", + "id": "e3e6fc12", "metadata": {}, "source": [ "### Support for `min` / `max` along axes\n", "\n", - "Previously, {py:func}`jm.sum ` and {py:meth}`Expression.sum ` supported taking sums along a specific axis of a multidimensional array via the `axis` keyword argument. Starting with this version, the same functionality has been added to {py:func}`jm.min ` and {py:func}`jm.max ` as well as their corresponding `Expression` methods." + "Previously, {py:func}`jm.sum ` and {py:meth}`Expression.sum ` supported taking sums along a specific axis of a multidimensional array via the `axis` keyword argument.\n", + "Starting with this version, the same functionality has been added to {py:func}`jm.min ` and {py:func}`jm.max ` as well as their corresponding `Expression` methods." ] }, { @@ -623,7 +706,8 @@ "\n", "## Other Changes\n", "\n", - "- Relaxed version bounds to allow installation on any Python 3 version from Python 3.11 onwards." + "- Relaxed version bounds to allow installation on any Python 3 version from Python 3.11 onwards.\n", + "- Error messages for invalid comprehensions used with the Decorator API in `sum` and similar constructs now report the specific location in the source code." ] } ], diff --git a/docs/ja/basics/expressions.ipynb b/docs/ja/basics/expressions.ipynb index 3d02d8d..3007ff7 100644 --- a/docs/ja/basics/expressions.ipynb +++ b/docs/ja/basics/expressions.ipynb @@ -25,10 +25,10 @@ "id": "a065d0ee", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:04:31.021717Z", - "iopub.status.busy": "2026-03-24T02:04:31.021117Z", - "iopub.status.idle": "2026-03-24T02:04:31.087860Z", - "shell.execute_reply": "2026-03-24T02:04:31.085039Z" + "iopub.execute_input": "2026-04-16T07:04:04.740233Z", + "iopub.status.busy": "2026-04-16T07:04:04.740139Z", + "iopub.status.idle": "2026-04-16T07:04:04.768519Z", + "shell.execute_reply": "2026-04-16T07:04:04.764810Z" } }, "outputs": [], @@ -57,10 +57,10 @@ "id": "beaddc39", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:04:31.204323Z", - "iopub.status.busy": "2026-03-24T02:04:31.204108Z", - "iopub.status.idle": "2026-03-24T02:04:31.456503Z", - "shell.execute_reply": "2026-03-24T02:04:31.454952Z" + "iopub.execute_input": "2026-04-16T07:04:04.775259Z", + "iopub.status.busy": "2026-04-16T07:04:04.774997Z", + "iopub.status.idle": "2026-04-16T07:04:05.036085Z", + "shell.execute_reply": "2026-04-16T07:04:05.035587Z" }, "label": "test-problem" }, @@ -77,7 +77,7 @@ { "data": { "text/plain": [ - "'Expression(sum(N.map(lambda i: y[i])))'" + "'Expression(sum(set(N).map(lambda i: y[i])))'" ] }, "metadata": {}, @@ -177,10 +177,10 @@ "id": "e73538ae", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:04:31.459948Z", - "iopub.status.busy": "2026-03-24T02:04:31.459712Z", - "iopub.status.idle": "2026-03-24T02:04:31.493888Z", - "shell.execute_reply": "2026-03-24T02:04:31.492863Z" + "iopub.execute_input": "2026-04-16T07:04:05.037667Z", + "iopub.status.busy": "2026-04-16T07:04:05.037573Z", + "iopub.status.idle": "2026-04-16T07:04:05.092196Z", + "shell.execute_reply": "2026-04-16T07:04:05.091774Z" } }, "outputs": [ @@ -220,10 +220,10 @@ "id": "b525d6c0", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:04:31.496510Z", - "iopub.status.busy": "2026-03-24T02:04:31.496297Z", - "iopub.status.idle": "2026-03-24T02:04:31.510912Z", - "shell.execute_reply": "2026-03-24T02:04:31.510357Z" + "iopub.execute_input": "2026-04-16T07:04:05.093666Z", + "iopub.status.busy": "2026-04-16T07:04:05.093586Z", + "iopub.status.idle": "2026-04-16T07:04:05.112806Z", + "shell.execute_reply": "2026-04-16T07:04:05.112344Z" } }, "outputs": [ @@ -233,13 +233,13 @@ "text": [ "Traceback (most recent last):\n", " while inferring the type of expression `x + Located { inner: \"hoge\", src_span: NoSrcSpan }',\n", - " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_45473/2391251849.py\", line 3, col 19-29\n", + " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_63555/2391251849.py\", line 3, col 19-29\n", " while inferring the type of expression `x + Located { inner: \"hoge\", src_span: NoSrcSpan }',\n", - " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_45473/2391251849.py\", line 3, col 19-29\n", + " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_63555/2391251849.py\", line 3, col 19-29\n", " while checking if types `binary!' and `Literal[\"hoge\"]' can be combined with numeric operator `Add',\n", - " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_45473/2391251849.py\", line 3, col 19-29\n", + " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_63555/2391251849.py\", line 3, col 19-29\n", "\n", - "File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_45473/2391251849.py\", line 3, col 19-29:\n", + "File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_63555/2391251849.py\", line 3, col 19-29:\n", "\n", " 3 | problem.infer(x + \"hoge\")\n", " ^^^^^^^^^^\n", @@ -312,10 +312,10 @@ "id": "5de5e593", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:04:31.513259Z", - "iopub.status.busy": "2026-03-24T02:04:31.512999Z", - "iopub.status.idle": "2026-03-24T02:04:31.831159Z", - "shell.execute_reply": "2026-03-24T02:04:31.830325Z" + "iopub.execute_input": "2026-04-16T07:04:05.114276Z", + "iopub.status.busy": "2026-04-16T07:04:05.114194Z", + "iopub.status.idle": "2026-04-16T07:04:06.402997Z", + "shell.execute_reply": "2026-04-16T07:04:06.402602Z" } }, "outputs": [ @@ -371,10 +371,10 @@ "id": "3aa8e74d", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:04:31.833669Z", - "iopub.status.busy": "2026-03-24T02:04:31.833435Z", - "iopub.status.idle": "2026-03-24T02:04:31.843551Z", - "shell.execute_reply": "2026-03-24T02:04:31.843202Z" + "iopub.execute_input": "2026-04-16T07:04:06.404250Z", + "iopub.status.busy": "2026-04-16T07:04:06.404156Z", + "iopub.status.idle": "2026-04-16T07:04:06.420719Z", + "shell.execute_reply": "2026-04-16T07:04:06.420340Z" } }, "outputs": [ @@ -402,10 +402,10 @@ "id": "f7348dfe", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:04:31.844709Z", - "iopub.status.busy": "2026-03-24T02:04:31.844654Z", - "iopub.status.idle": "2026-03-24T02:04:31.874483Z", - "shell.execute_reply": "2026-03-24T02:04:31.874088Z" + "iopub.execute_input": "2026-04-16T07:04:06.421767Z", + "iopub.status.busy": "2026-04-16T07:04:06.421713Z", + "iopub.status.idle": "2026-04-16T07:04:06.511448Z", + "shell.execute_reply": "2026-04-16T07:04:06.511111Z" } }, "outputs": [ @@ -433,10 +433,10 @@ "id": "200cbd4b", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:04:31.875609Z", - "iopub.status.busy": "2026-03-24T02:04:31.875546Z", - "iopub.status.idle": "2026-03-24T02:04:31.894764Z", - "shell.execute_reply": "2026-03-24T02:04:31.894331Z" + "iopub.execute_input": "2026-04-16T07:04:06.512517Z", + "iopub.status.busy": "2026-04-16T07:04:06.512458Z", + "iopub.status.idle": "2026-04-16T07:04:06.607426Z", + "shell.execute_reply": "2026-04-16T07:04:06.606963Z" } }, "outputs": [ @@ -464,10 +464,10 @@ "id": "e9405fa6", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:04:31.895944Z", - "iopub.status.busy": "2026-03-24T02:04:31.895852Z", - "iopub.status.idle": "2026-03-24T02:04:31.923431Z", - "shell.execute_reply": "2026-03-24T02:04:31.923081Z" + "iopub.execute_input": "2026-04-16T07:04:06.608524Z", + "iopub.status.busy": "2026-04-16T07:04:06.608464Z", + "iopub.status.idle": "2026-04-16T07:04:06.703975Z", + "shell.execute_reply": "2026-04-16T07:04:06.703612Z" } }, "outputs": [ @@ -495,10 +495,10 @@ "id": "1dff7e02", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:04:31.924550Z", - "iopub.status.busy": "2026-03-24T02:04:31.924469Z", - "iopub.status.idle": "2026-03-24T02:04:31.944181Z", - "shell.execute_reply": "2026-03-24T02:04:31.943471Z" + "iopub.execute_input": "2026-04-16T07:04:06.705222Z", + "iopub.status.busy": "2026-04-16T07:04:06.705161Z", + "iopub.status.idle": "2026-04-16T07:04:06.795627Z", + "shell.execute_reply": "2026-04-16T07:04:06.795268Z" } }, "outputs": [ @@ -534,10 +534,10 @@ "id": "7a5b888f", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:04:31.949457Z", - "iopub.status.busy": "2026-03-24T02:04:31.949222Z", - "iopub.status.idle": "2026-03-24T02:04:31.964785Z", - "shell.execute_reply": "2026-03-24T02:04:31.963941Z" + "iopub.execute_input": "2026-04-16T07:04:06.796819Z", + "iopub.status.busy": "2026-04-16T07:04:06.796744Z", + "iopub.status.idle": "2026-04-16T07:04:06.816870Z", + "shell.execute_reply": "2026-04-16T07:04:06.816344Z" } }, "outputs": [ @@ -547,13 +547,13 @@ "text": [ "Traceback (most recent last):\n", " while inferring the type of expression `S * y',\n", - " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_45473/3719066850.py\", line 3, col 19-24\n", + " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_63555/3719066850.py\", line 3, col 19-24\n", " while inferring the type of expression `S * y',\n", - " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_45473/3719066850.py\", line 3, col 19-24\n", + " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_63555/3719066850.py\", line 3, col 19-24\n", " while checking if types `TotalDict[N; float]' and `Array[N, M; int!]' can be combined with numeric operator `Mul',\n", - " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_45473/3719066850.py\", line 3, col 19-24\n", + " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_63555/3719066850.py\", line 3, col 19-24\n", "\n", - "File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_45473/3719066850.py\", line 3, col 19-24:\n", + "File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_63555/3719066850.py\", line 3, col 19-24:\n", "\n", " 3 | problem.infer(S * y)\n", " ^^^^^\n", @@ -576,10 +576,10 @@ "id": "7bf01863", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:04:31.966503Z", - "iopub.status.busy": "2026-03-24T02:04:31.966416Z", - "iopub.status.idle": "2026-03-24T02:04:31.978720Z", - "shell.execute_reply": "2026-03-24T02:04:31.977829Z" + "iopub.execute_input": "2026-04-16T07:04:06.819579Z", + "iopub.status.busy": "2026-04-16T07:04:06.819047Z", + "iopub.status.idle": "2026-04-16T07:04:06.842386Z", + "shell.execute_reply": "2026-04-16T07:04:06.842098Z" } }, "outputs": [ @@ -589,13 +589,13 @@ "text": [ "Traceback (most recent last):\n", " while inferring the type of expression `y + z',\n", - " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_45473/3550267328.py\", line 3, col 19-24\n", + " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_63555/3550267328.py\", line 3, col 19-24\n", " while inferring the type of expression `y + z',\n", - " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_45473/3550267328.py\", line 3, col 19-24\n", + " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_63555/3550267328.py\", line 3, col 19-24\n", " while checking if types `Array[N, M; int!]' and `Array[N, M, N; float!]' can be combined with numeric operator `Add',\n", - " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_45473/3550267328.py\", line 3, col 19-24\n", + " defined at File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_63555/3550267328.py\", line 3, col 19-24\n", "\n", - "File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_45473/3550267328.py\", line 3, col 19-24:\n", + "File \"/var/folders/mg/mg6st30d18s7pxjjrk6pkxym0000gn/T/ipykernel_63555/3550267328.py\", line 3, col 19-24:\n", "\n", " 3 | problem.infer(y + z)\n", " ^^^^^\n", @@ -612,12 +612,169 @@ " print(e)" ] }, + { + "cell_type": "markdown", + "id": "36cc003d", + "metadata": {}, + "source": [ + "### 代替記法:`genarray` による配列の構築\n", + "\n", + "上の例では、`y + z` のように、非自明なブロードキャストを伴う演算は(意図的に)エラーになっていました。\n", + "このような場合、{py:func}`~jijmodeling.genarray` 関数を使い、陽にシェイプと成分の式を指定することで、結果の配列を構築できるようになります:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "8caa0e4b", + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-16T07:04:06.843768Z", + "iopub.status.busy": "2026-04-16T07:04:06.843710Z", + "iopub.status.idle": "2026-04-16T07:04:07.112763Z", + "shell.execute_reply": "2026-04-16T07:04:07.112429Z" + } + }, + "outputs": [ + { + "data": { + "text/latex": [ + "$${\\left( {y}_{i,j}+{z}_{i,j,k}\\right) }_{\\substack{i\\in \\left\\{0,\\ldots ,N-1\\right\\}\\\\j\\in \\left\\{0,\\ldots ,M-1\\right\\}\\\\k\\in \\left\\{0,\\ldots ,N-1\\right\\}}}$$" + ], + "text/plain": [ + "Expression(genarray(lambda (i, j, k): y[i, j] + z[i, j, k], (N, M, N)))" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$$\\mathop{\\mathrm{Array}}\\left[N\\times M\\times N;\\mathbb{R}\\right]$$" + ], + "text/plain": [ + "Array[N, M, N; float!]" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "A = jm.genarray(lambda i, j, k: y[i, j] + z[i, j, k], (N, M, N))\n", + "display(A)\n", + "problem.infer(A)" + ] + }, + { + "cell_type": "markdown", + "id": "d690e0a1", + "metadata": {}, + "source": [ + "また、Decorator API を利用している場合、以下のように `jm.genarray` で内包表記を用いることもできます:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "eec6742a", + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-16T07:04:07.114983Z", + "iopub.status.busy": "2026-04-16T07:04:07.114893Z", + "iopub.status.idle": "2026-04-16T07:04:07.380626Z", + "shell.execute_reply": "2026-04-16T07:04:07.380075Z" + } + }, + "outputs": [ + { + "data": { + "text/latex": [ + "$${\\left( {y}_{i,j}+{z}_{i,j,k}\\right) }_{\\substack{i\\in \\left\\{0,\\ldots ,N-1\\right\\}\\\\j\\in \\left\\{0,\\ldots ,M-1\\right\\}\\\\k\\in \\left\\{0,\\ldots ,N-1\\right\\}}}$$" + ], + "text/plain": [ + "Expression(genarray(lambda (i, j, k): y[i, j] + z[i, j, k], (N, M, N)))" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$$\\mathop{\\mathrm{Array}}\\left[N\\times M\\times N;\\mathbb{R}\\right]$$" + ], + "text/plain": [ + "Array[N, M, N; float!]" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "@problem.update\n", + "def _(problem: jm.DecoratedProblem):\n", + " A = jm.genarray(y[i, j] + z[i, j, k] for i, j, k in (N, M, N))\n", + " display(A)\n", + " display(problem.infer(A))" + ] + }, + { + "cell_type": "markdown", + "id": "0a0fe8d9", + "metadata": {}, + "source": [ + "`genarray` の内包表記では、`for .. in ...` は一つしか許容されません。\n", + "以下のように、複数の `for`-節を使ってしまうとエラーになるので注意してください:" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "0683580a", + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-16T07:04:07.381879Z", + "iopub.status.busy": "2026-04-16T07:04:07.381817Z", + "iopub.status.idle": "2026-04-16T07:04:07.395525Z", + "shell.execute_reply": "2026-04-16T07:04:07.394961Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "A genarray comprehension must have exactly one for-clause:\n", + "\n", + " 9 | Sums = problem.NamedExpr(jm.genarray(a[i, j] * x[i] for i in N for j in M))\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + ] + } + ], + "source": [ + "try:\n", + "\n", + " @jm.Problem.define(\"genarray example\")\n", + " def _(problem):\n", + " N = problem.Natural()\n", + " M = problem.Natural()\n", + " a = problem.Float(shape=(N, M))\n", + " x = problem.BinaryVar(shape=N)\n", + " Sums = problem.NamedExpr(jm.genarray(a[i, j] * x[i] for i in N for j in M))\n", + "except SyntaxError as e:\n", + " print(str(e))" + ] + }, { "cell_type": "markdown", "id": "bca012a7", "metadata": {}, "source": [ - ":::{admonition} 決定変数による除算について\n", + "::{admonition} 決定変数による除算について\n", ":class: caution\n", "\n", "モデルの構築の時点では、決定変数が現れうる式は加減乗除の左右どちらの辺にも現れることができます。\n", @@ -647,14 +804,14 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 17, "id": "19d6caee", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:04:31.980904Z", - "iopub.status.busy": "2026-03-24T02:04:31.980793Z", - "iopub.status.idle": "2026-03-24T02:04:32.009101Z", - "shell.execute_reply": "2026-03-24T02:04:32.008669Z" + "iopub.execute_input": "2026-04-16T07:04:07.515824Z", + "iopub.status.busy": "2026-04-16T07:04:07.515737Z", + "iopub.status.idle": "2026-04-16T07:04:07.623423Z", + "shell.execute_reply": "2026-04-16T07:04:07.622939Z" } }, "outputs": [ @@ -667,7 +824,7 @@ "Comparison[binary!, Array[N, M; int!]]" ] }, - "execution_count": 13, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } @@ -678,14 +835,14 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 18, "id": "0829b0d0", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:04:32.010430Z", - "iopub.status.busy": "2026-03-24T02:04:32.010366Z", - "iopub.status.idle": "2026-03-24T02:04:32.022376Z", - "shell.execute_reply": "2026-03-24T02:04:32.021783Z" + "iopub.execute_input": "2026-04-16T07:04:07.624679Z", + "iopub.status.busy": "2026-04-16T07:04:07.624605Z", + "iopub.status.idle": "2026-04-16T07:04:07.642826Z", + "shell.execute_reply": "2026-04-16T07:04:07.642439Z" } }, "outputs": [ @@ -698,7 +855,7 @@ "bool" ] }, - "execution_count": 14, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } @@ -709,14 +866,14 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 19, "id": "98865e29", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:04:32.023477Z", - "iopub.status.busy": "2026-03-24T02:04:32.023417Z", - "iopub.status.idle": "2026-03-24T02:04:32.063664Z", - "shell.execute_reply": "2026-03-24T02:04:32.063191Z" + "iopub.execute_input": "2026-04-16T07:04:07.644241Z", + "iopub.status.busy": "2026-04-16T07:04:07.644068Z", + "iopub.status.idle": "2026-04-16T07:04:07.882949Z", + "shell.execute_reply": "2026-04-16T07:04:07.882562Z" } }, "outputs": [ @@ -729,7 +886,7 @@ "Comparison[Array[N, M; float!], Array[N, M; float!]]" ] }, - "execution_count": 15, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } @@ -774,14 +931,14 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 20, "id": "6e97e0ff", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:04:32.064961Z", - "iopub.status.busy": "2026-03-24T02:04:32.064902Z", - "iopub.status.idle": "2026-03-24T02:04:32.135412Z", - "shell.execute_reply": "2026-03-24T02:04:32.134755Z" + "iopub.execute_input": "2026-04-16T07:04:07.884099Z", + "iopub.status.busy": "2026-04-16T07:04:07.884041Z", + "iopub.status.idle": "2026-04-16T07:04:08.231863Z", + "shell.execute_reply": "2026-04-16T07:04:08.231547Z" } }, "outputs": [ @@ -798,7 +955,7 @@ "Problem(name=\"Index and Keys Example\", sense=MINIMIZE, objective=0, constraints=[])" ] }, - "execution_count": 16, + "execution_count": 20, "metadata": {}, "output_type": "execute_result" } @@ -871,14 +1028,14 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 21, "id": "17eb39a1", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:04:32.136689Z", - "iopub.status.busy": "2026-03-24T02:04:32.136610Z", - "iopub.status.idle": "2026-03-24T02:04:32.225585Z", - "shell.execute_reply": "2026-03-24T02:04:32.225253Z" + "iopub.execute_input": "2026-04-16T07:04:08.233129Z", + "iopub.status.busy": "2026-04-16T07:04:08.233060Z", + "iopub.status.idle": "2026-04-16T07:04:08.686641Z", + "shell.execute_reply": "2026-04-16T07:04:08.686282Z" } }, "outputs": [ @@ -890,10 +1047,10 @@ "$$" ], "text/plain": [ - "Problem(name=\"Sum Example\", sense=MINIMIZE, objective=sum(N.map(lambda (i: natural): a[i] * x[i])), constraints=[])" + "Problem(name=\"Sum Example\", sense=MINIMIZE, objective=sum(set(N).map(lambda (i: natural): a[i] * x[i])), constraints=[])" ] }, - "execution_count": 17, + "execution_count": 21, "metadata": {}, "output_type": "execute_result" } @@ -925,14 +1082,14 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 22, "id": "dffc0a7b", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:04:32.226702Z", - "iopub.status.busy": "2026-03-24T02:04:32.226644Z", - "iopub.status.idle": "2026-03-24T02:04:32.247109Z", - "shell.execute_reply": "2026-03-24T02:04:32.246635Z" + "iopub.execute_input": "2026-04-16T07:04:08.687870Z", + "iopub.status.busy": "2026-04-16T07:04:08.687791Z", + "iopub.status.idle": "2026-04-16T07:04:08.737062Z", + "shell.execute_reply": "2026-04-16T07:04:08.736722Z" } }, "outputs": [ @@ -968,14 +1125,14 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 23, "id": "15434b93", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:04:32.248315Z", - "iopub.status.busy": "2026-03-24T02:04:32.248250Z", - "iopub.status.idle": "2026-03-24T02:04:32.326263Z", - "shell.execute_reply": "2026-03-24T02:04:32.325891Z" + "iopub.execute_input": "2026-04-16T07:04:08.738170Z", + "iopub.status.busy": "2026-04-16T07:04:08.738115Z", + "iopub.status.idle": "2026-04-16T07:04:09.149340Z", + "shell.execute_reply": "2026-04-16T07:04:09.148064Z" } }, "outputs": [ @@ -990,7 +1147,7 @@ "Problem(name=\"Sum Example (Plain)\", sense=MINIMIZE, objective=sum(N.map(lambda (i: natural): a[i] * x[i])), constraints=[])" ] }, - "execution_count": 19, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } @@ -1015,14 +1172,14 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 24, "id": "0112b897", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:04:32.327381Z", - "iopub.status.busy": "2026-03-24T02:04:32.327327Z", - "iopub.status.idle": "2026-03-24T02:04:32.407739Z", - "shell.execute_reply": "2026-03-24T02:04:32.407284Z" + "iopub.execute_input": "2026-04-16T07:04:09.150683Z", + "iopub.status.busy": "2026-04-16T07:04:09.150617Z", + "iopub.status.idle": "2026-04-16T07:04:09.548851Z", + "shell.execute_reply": "2026-04-16T07:04:09.548325Z" } }, "outputs": [ @@ -1037,7 +1194,7 @@ "Problem(name=\"Sum Example (Plain, Alt)\", sense=MINIMIZE, objective=sum(N.map(lambda (i: natural): a[i] * x[i])), constraints=[])" ] }, - "execution_count": 20, + "execution_count": 24, "metadata": {}, "output_type": "execute_result" } @@ -1070,14 +1227,14 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 25, "id": "84a0a84c", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:04:32.409030Z", - "iopub.status.busy": "2026-03-24T02:04:32.408972Z", - "iopub.status.idle": "2026-03-24T02:04:32.537563Z", - "shell.execute_reply": "2026-03-24T02:04:32.536101Z" + "iopub.execute_input": "2026-04-16T07:04:09.550085Z", + "iopub.status.busy": "2026-04-16T07:04:09.550015Z", + "iopub.status.idle": "2026-04-16T07:04:10.030400Z", + "shell.execute_reply": "2026-04-16T07:04:10.029923Z" } }, "outputs": [ @@ -1089,10 +1246,10 @@ "$$" ], "text/plain": [ - "Problem(name=\"Even Sum Example\", sense=MINIMIZE, objective=sum(N.filter(lambda i: i % 2 == 0).map(lambda (i: natural): a[i] * x[i])), constraints=[])" + "Problem(name=\"Even Sum Example\", sense=MINIMIZE, objective=sum(set(N.filter(lambda i: i % 2 == 0)).map(lambda (i: natural): a[i] * x[i])), constraints=[])" ] }, - "execution_count": 21, + "execution_count": 25, "metadata": {}, "output_type": "execute_result" } @@ -1119,14 +1276,14 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 26, "id": "1e520da7", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:04:32.540122Z", - "iopub.status.busy": "2026-03-24T02:04:32.539880Z", - "iopub.status.idle": "2026-03-24T02:04:32.789053Z", - "shell.execute_reply": "2026-03-24T02:04:32.785953Z" + "iopub.execute_input": "2026-04-16T07:04:10.031620Z", + "iopub.status.busy": "2026-04-16T07:04:10.031566Z", + "iopub.status.idle": "2026-04-16T07:04:10.530312Z", + "shell.execute_reply": "2026-04-16T07:04:10.516385Z" } }, "outputs": [ @@ -1141,7 +1298,7 @@ "Problem(name=\"Even Sum Example (Plain)\", sense=MINIMIZE, objective=sum(N.filter(lambda i: i % 2 == 0).map(lambda (i: natural): a[i] * x[i])), constraints=[])" ] }, - "execution_count": 22, + "execution_count": 26, "metadata": {}, "output_type": "execute_result" } @@ -1171,14 +1328,14 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 27, "id": "28b8bad3", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:04:32.794215Z", - "iopub.status.busy": "2026-03-24T02:04:32.793767Z", - "iopub.status.idle": "2026-03-24T02:04:33.220395Z", - "shell.execute_reply": "2026-03-24T02:04:33.219529Z" + "iopub.execute_input": "2026-04-16T07:04:10.534229Z", + "iopub.status.busy": "2026-04-16T07:04:10.533832Z", + "iopub.status.idle": "2026-04-16T07:04:11.091517Z", + "shell.execute_reply": "2026-04-16T07:04:11.091121Z" } }, "outputs": [ @@ -1190,10 +1347,10 @@ "$$" ], "text/plain": [ - "Problem(name=\"Double Sum Example\", sense=MINIMIZE, objective=sum(N.flat_map(lambda (i: natural): M.map(lambda (j: natural): (i, j))).map(lambda ((i, j): Tuple[natural, natural]): Q[i, j])), constraints=[])" + "Problem(name=\"Double Sum Example\", sense=MINIMIZE, objective=sum(set(N.flat_map(lambda (i: natural): M.map(lambda (j: natural): (i, j)))).map(lambda ((i, j): Tuple[natural, natural]): Q[i, j])), constraints=[])" ] }, - "execution_count": 23, + "execution_count": 27, "metadata": {}, "output_type": "execute_result" } @@ -1221,14 +1378,14 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 28, "id": "385cb7b1", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:04:33.222404Z", - "iopub.status.busy": "2026-03-24T02:04:33.222261Z", - "iopub.status.idle": "2026-03-24T02:04:33.563555Z", - "shell.execute_reply": "2026-03-24T02:04:33.561832Z" + "iopub.execute_input": "2026-04-16T07:04:11.092772Z", + "iopub.status.busy": "2026-04-16T07:04:11.092711Z", + "iopub.status.idle": "2026-04-16T07:04:11.573549Z", + "shell.execute_reply": "2026-04-16T07:04:11.573230Z" } }, "outputs": [ @@ -1240,10 +1397,10 @@ "$$" ], "text/plain": [ - "Problem(name=\"Double Sum Example (Alt)\", sense=MINIMIZE, objective=sum(set((N, M)).map(lambda ((i, j): Tuple[natural, natural]): Q[i, j])), constraints=[])" + "Problem(name=\"Double Sum Example (Alt)\", sense=MINIMIZE, objective=sum(set(set((N, M))).map(lambda ((i, j): Tuple[natural, natural]): Q[i, j])), constraints=[])" ] }, - "execution_count": 24, + "execution_count": 28, "metadata": {}, "output_type": "execute_result" } @@ -1261,6 +1418,58 @@ "double_sum_example_alt" ] }, + { + "cell_type": "markdown", + "id": "e12efa57", + "metadata": {}, + "source": [ + "また、Decorator API での内包表記の `in` の右辺や、`Constraint` の `domain=` キーワード引数などでは、`jm.product` を省略して次のようにタプルで直積を表すことができます:" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "710245ee", + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-16T07:04:11.574879Z", + "iopub.status.busy": "2026-04-16T07:04:11.574810Z", + "iopub.status.idle": "2026-04-16T07:04:12.098044Z", + "shell.execute_reply": "2026-04-16T07:04:12.097699Z" + } + }, + "outputs": [ + { + "data": { + "text/latex": [ + "$$\\begin{array}{rl}\n", + "\\text{Problem}\\colon &\\text{Double Sum Example (Alt)}\\\\\\displaystyle \\min &\\displaystyle \\sum _{i=0}^{N-1}{\\sum _{j=0}^{M-1}{{Q}_{i,j}}}\\\\&\\\\\\text{where}&\\\\&\\text{Decision Variables:}\\\\&\\qquad \\begin{alignedat}{2}x&\\in \\mathop{\\mathrm{Array}}\\left[N\\times M;\\left\\{0, 1\\right\\}\\right]&\\quad &2\\text{-dim binary variable}\\\\\\end{alignedat}\\\\&\\\\&\\text{Placeholders:}\\\\&\\qquad \\begin{alignedat}{2}M&\\in \\mathbb{N}&\\quad &\\text{A scalar placeholder in }\\mathbb{N}\\\\N&\\in \\mathbb{N}&\\quad &\\text{A scalar placeholder in }\\mathbb{N}\\\\Q&\\in \\mathop{\\mathrm{Array}}\\left[N\\times M;\\mathbb{R}\\right]&\\quad &2\\text{-dimensional array of placeholders with elements in }\\mathbb{R}\\\\\\end{alignedat}\\end{array}\n", + "$$" + ], + "text/plain": [ + "Problem(name=\"Double Sum Example (Alt)\", sense=MINIMIZE, objective=sum(set((N, M)).map(lambda ((i, j): Tuple[natural, natural]): Q[i, j])), constraints=[])" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "@jm.Problem.define(\"Double Sum Example (Alt)\")\n", + "def double_sum_example_alt(problem: jm.DecoratedProblem):\n", + " N = problem.Length()\n", + " M = problem.Length()\n", + " Q = problem.Float(shape=(N, M))\n", + " x = problem.BinaryVar(shape=(N, M))\n", + "\n", + " # 注目! productではなく、タプルで直積を表している\n", + " problem += jm.sum(Q[i, j] for (i, j) in (N, M))\n", + "\n", + "\n", + "double_sum_example_alt" + ] + }, { "cell_type": "markdown", "id": "3fae32b9", @@ -1271,14 +1480,14 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 30, "id": "3362f83d", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:04:33.580391Z", - "iopub.status.busy": "2026-03-24T02:04:33.580170Z", - "iopub.status.idle": "2026-03-24T02:04:34.019243Z", - "shell.execute_reply": "2026-03-24T02:04:34.018524Z" + "iopub.execute_input": "2026-04-16T07:04:12.099290Z", + "iopub.status.busy": "2026-04-16T07:04:12.099216Z", + "iopub.status.idle": "2026-04-16T07:04:13.001106Z", + "shell.execute_reply": "2026-04-16T07:04:13.000669Z" } }, "outputs": [ @@ -1290,10 +1499,10 @@ "$$" ], "text/plain": [ - "Problem(name=\"Filtered Double Sum Example\", sense=MINIMIZE, objective=sum(N.flat_map(lambda (i: natural): M.map(lambda (j: natural): (i, j))).filter(lambda (i, j): (i + j) % 2 == 0).map(lambda ((i, j): Tuple[natural, natural]): Q[i, j])), constraints=[])" + "Problem(name=\"Filtered Double Sum Example\", sense=MINIMIZE, objective=sum(set(N.flat_map(lambda (i: natural): M.map(lambda (j: natural): (i, j))).filter(lambda (i, j): (i + j) % 2 == 0)).map(lambda ((i, j): Tuple[natural, natural]): Q[i, j])), constraints=[])" ] }, - "execution_count": 25, + "execution_count": 30, "metadata": {}, "output_type": "execute_result" } @@ -1326,14 +1535,14 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 31, "id": "7c2e2ab9", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:04:34.021942Z", - "iopub.status.busy": "2026-03-24T02:04:34.021733Z", - "iopub.status.idle": "2026-03-24T02:04:34.275517Z", - "shell.execute_reply": "2026-03-24T02:04:34.274631Z" + "iopub.execute_input": "2026-04-16T07:04:13.002348Z", + "iopub.status.busy": "2026-04-16T07:04:13.002288Z", + "iopub.status.idle": "2026-04-16T07:04:13.610579Z", + "shell.execute_reply": "2026-04-16T07:04:13.609824Z" } }, "outputs": [ @@ -1348,7 +1557,7 @@ "Problem(name=\"Filtered Double Sum Example (Plain)\", sense=MINIMIZE, objective=sum(set((N, M)).filter(lambda (i, j): (i + j) % 2 == 0).map(lambda ((i, j): Tuple[natural, natural]): Q[i, j])), constraints=[])" ] }, - "execution_count": 26, + "execution_count": 31, "metadata": {}, "output_type": "execute_result" } @@ -1376,14 +1585,14 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 32, "id": "2027a720", "metadata": { "execution": { - "iopub.execute_input": "2026-03-24T02:04:34.278299Z", - "iopub.status.busy": "2026-03-24T02:04:34.277933Z", - "iopub.status.idle": "2026-03-24T02:04:34.368643Z", - "shell.execute_reply": "2026-03-24T02:04:34.367875Z" + "iopub.execute_input": "2026-04-16T07:04:13.612856Z", + "iopub.status.busy": "2026-04-16T07:04:13.612757Z", + "iopub.status.idle": "2026-04-16T07:04:13.993722Z", + "shell.execute_reply": "2026-04-16T07:04:13.993261Z" } }, "outputs": [ @@ -1396,7 +1605,7 @@ "Expression(sum(N.flat_map(lambda i: M.map(lambda j: (i, j))).filter(lambda (i, j): (i + j) % 2 == 0).map(lambda (i, j): Q[i, j])))" ] }, - "execution_count": 27, + "execution_count": 32, "metadata": {}, "output_type": "execute_result" } @@ -1453,7 +1662,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.11" + "version": "3.11.14" } }, "nbformat": 4, diff --git a/docs/ja/releases/unreleased.ipynb b/docs/ja/releases/unreleased.ipynb index 2c22c43..21f4160 100644 --- a/docs/ja/releases/unreleased.ipynb +++ b/docs/ja/releases/unreleased.ipynb @@ -26,7 +26,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 5, "id": "454e2d9a", "metadata": { "execution": { @@ -48,7 +48,7 @@ "Problem(name=\"genarray example\", sense=MINIMIZE, objective=0, constraints=[])" ] }, - "execution_count": 1, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -57,18 +57,98 @@ "import jijmodeling as jm\n", "\n", "\n", + "problem = jm.Problem(\"genarray example\")\n", + "N = problem.Natural(\"N\")\n", + "M = problem.Natural(\"M\")\n", + "a = problem.Float(\"a\", shape=(N, M))\n", + "x = problem.BinaryVar(\"x\", shape=N)\n", + "Sums = problem.NamedExpr(\"Sums\", jm.genarray(lambda i, j: a[i, j] * x[i], (N, M)))\n", + "\n", + "\n", + "problem" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "また、Decorator API を利用している場合、以下のように `jm.genarray` で内包表記を用いることもできます:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "$$\\begin{array}{rl}\n", + "\\text{Problem}\\colon &\\text{genarray example}\\\\\\displaystyle \\min &\\displaystyle 0\\\\&\\\\\\text{where}&\\\\&\\text{Decision Variables:}\\\\&\\qquad \\begin{alignedat}{2}x&\\in \\mathop{\\mathrm{Array}}\\left[N;\\left\\{0, 1\\right\\}\\right]&\\quad &1\\text{-dim binary variable}\\\\\\end{alignedat}\\\\&\\\\&\\text{Placeholders:}\\\\&\\qquad \\begin{alignedat}{2}a&\\in \\mathop{\\mathrm{Array}}\\left[N\\times M;\\mathbb{R}\\right]&\\quad &2\\text{-dimensional array of placeholders with elements in }\\mathbb{R}\\\\M&\\in \\mathbb{N}&\\quad &\\text{A scalar placeholder in }\\mathbb{N}\\\\N&\\in \\mathbb{N}&\\quad &\\text{A scalar placeholder in }\\mathbb{N}\\\\\\end{alignedat}\\\\&\\\\&\\text{Named Expressions:}\\\\&\\qquad \\begin{alignedat}{2}Sums&={\\left( {a}_{i,j}\\cdot {x}_{i}\\right) }_{\\substack{i\\in \\left\\{0,\\ldots ,N-1\\right\\}\\\\j\\in \\left\\{0,\\ldots ,M-1\\right\\}}}&\\quad &\\in \\mathop{\\mathrm{Array}}\\left[N\\times M;\\mathbb{R}\\right]\\\\\\end{alignedat}\\end{array}\n", + "$$" + ], + "text/plain": [ + "Problem(name=\"genarray example\", sense=MINIMIZE, objective=0, constraints=[])" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ "@jm.Problem.define(\"genarray example\")\n", "def problem(problem):\n", " N = problem.Natural()\n", " M = problem.Natural()\n", " a = problem.Float(shape=(N, M))\n", " x = problem.BinaryVar(shape=N)\n", - " Sums = problem.NamedExpr(jm.genarray(lambda i, j: a[i, j] * x[i], (N, M)))\n", + " Sums = problem.NamedExpr(jm.genarray(a[i, j] * x[i] for i, j in (N, M)))\n", "\n", "\n", "problem" ] }, + { + "cell_type": "markdown", + "id": "194ab910", + "metadata": {}, + "source": [ + "`genarray` の内包表記では、`for .. in ...` は一つしか許容されません。\n", + "以下は、複数の `for`-節を使ってしまい、エラーになっている例です:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "210ec92a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "A genarray comprehension must have exactly one for-clause:\n", + "\n", + " 9 | Sums = problem.NamedExpr(jm.genarray(a[i, j] * x[i] for i in N for j in M))\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + ] + } + ], + "source": [ + "try:\n", + "\n", + " @jm.Problem.define(\"genarray example\")\n", + " def problem(problem):\n", + " N = problem.Natural()\n", + " M = problem.Natural()\n", + " a = problem.Float(shape=(N, M))\n", + " x = problem.BinaryVar(shape=N)\n", + " Sums = problem.NamedExpr(jm.genarray(a[i, j] * x[i] for i in N for j in M))\n", + "except SyntaxError as e:\n", + " print(str(e))" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -611,7 +691,8 @@ "\n", "## その他の変更\n", "\n", - "- バージョン条件を緩和し、Python 3.11 以降の任意の Python 3 でのインストールを許容しました。" + "- バージョン条件を緩和し、Python 3.11 以降の任意の Python 3 でのインストールを許容しました。\n", + "- Decorator API の `sum` などで不正な内包表記を使った際のエラーメッセージが、具体的なコード上の位置を報告するようになりました。" ] } ], diff --git a/markdowns/en/basics/expressions.md b/markdowns/en/basics/expressions.md index 47be6f4..cad0f7d 100644 --- a/markdowns/en/basics/expressions.md +++ b/markdowns/en/basics/expressions.md @@ -257,7 +257,45 @@ except Exception as e: print(e) ``` -:::{admonition} Division by decision variables +### Alternative syntax: constructing arrays with `genarray` + +In the example above, operations involving nontrivial broadcasting, such as `y + z`, result in an (intentional) error. +In such cases, you can use the {py:func}`~jijmodeling.genarray` function to construct the resulting array explicitly by specifying the shape and the expression for each entry: + +```{code-cell} ipython3 +A = jm.genarray(lambda i, j, k: y[i, j] + z[i, j, k], (N, M, N)) +display(A) +problem.infer(A) +``` + +When using the Decorator API, you can also use a comprehension with `jm.genarray` as follows: + +```{code-cell} ipython3 +@problem.update +def _(problem: jm.DecoratedProblem): + A = jm.genarray(y[i, j] + z[i, j, k] for i, j, k in (N, M, N)) + display(A) + display(problem.infer(A)) +``` + +Only one `for .. in ...` clause is allowed in a `genarray` comprehension. +Be careful, because using multiple `for` clauses as shown below raises an error: + +```{code-cell} ipython3 +try: + + @jm.Problem.define("genarray example") + def _(problem): + N = problem.Natural() + M = problem.Natural() + a = problem.Float(shape=(N, M)) + x = problem.BinaryVar(shape=N) + Sums = problem.NamedExpr(jm.genarray(a[i, j] * x[i] for i in N for j in M)) +except SyntaxError as e: + print(str(e)) +``` + +::{admonition} Division by decision variables :class: caution At the modeling stage, decision variables can appear on either side of arithmetic operators. @@ -516,6 +554,23 @@ def double_sum_example_alt(problem: jm.DecoratedProblem): problem += jm.sum(Q[i, j] for (i, j) in jm.product(N, M)) +double_sum_example_alt +``` + +Also, in places such as the right-hand side of `in` in Decorator API comprehensions and the `domain=` keyword argument of `Constraint`, you can omit `jm.product` and represent the Cartesian product with a tuple as follows: + +```{code-cell} ipython3 +@jm.Problem.define("Double Sum Example (Alt)") +def double_sum_example_alt(problem: jm.DecoratedProblem): + N = problem.Length() + M = problem.Length() + Q = problem.Float(shape=(N, M)) + x = problem.BinaryVar(shape=(N, M)) + + # Note: the Cartesian product is represented by a tuple, not product + problem += jm.sum(Q[i, j] for (i, j) in (N, M)) + + double_sum_example_alt ``` diff --git a/markdowns/en/releases/unreleased.md b/markdowns/en/releases/unreleased.md index a286243..7fc120d 100644 --- a/markdowns/en/releases/unreleased.md +++ b/markdowns/en/releases/unreleased.md @@ -28,21 +28,53 @@ This is similar to {py:func}`~numpy.fromfunction` in NumPy. import jijmodeling as jm +problem = jm.Problem("genarray example") +N = problem.Natural("N") +M = problem.Natural("M") +a = problem.Float("a", shape=(N, M)) +x = problem.BinaryVar("x", shape=N) +Sums = problem.NamedExpr("Sums", jm.genarray(lambda i, j: a[i, j] * x[i], (N, M))) + + +problem +``` + +When using the Decorator API, you can also use a comprehension syntax with `jm.genarray` as follows: + +```{code-cell} ipython3 @jm.Problem.define("genarray example") def problem(problem): N = problem.Natural() M = problem.Natural() a = problem.Float(shape=(N, M)) x = problem.BinaryVar(shape=N) - Sums = problem.NamedExpr(jm.genarray(lambda i, j: a[i, j] * x[i], (N, M))) + Sums = problem.NamedExpr(jm.genarray(a[i, j] * x[i] for i, j in (N, M))) problem ``` +Only one `for .. in ...` clause is allowed in a `genarray` comprehension. +The following is an example that raises an error because it uses multiple `for` clauses: + +```{code-cell} ipython3 +try: + + @jm.Problem.define("genarray example") + def problem(problem): + N = problem.Natural() + M = problem.Natural() + a = problem.Float(shape=(N, M)) + x = problem.BinaryVar(shape=N) + Sums = problem.NamedExpr(jm.genarray(a[i, j] * x[i] for i in N for j in M)) +except SyntaxError as e: + print(str(e)) +``` + ### Support for `min` / `max` along axes -Previously, {py:func}`jm.sum ` and {py:meth}`Expression.sum ` supported taking sums along a specific axis of a multidimensional array via the `axis` keyword argument. Starting with this version, the same functionality has been added to {py:func}`jm.min ` and {py:func}`jm.max ` as well as their corresponding `Expression` methods. +Previously, {py:func}`jm.sum ` and {py:meth}`Expression.sum ` supported taking sums along a specific axis of a multidimensional array via the `axis` keyword argument. +Starting with this version, the same functionality has been added to {py:func}`jm.min ` and {py:func}`jm.max ` as well as their corresponding `Expression` methods. ```{code-cell} ipython3 import jijmodeling as jm @@ -188,3 +220,4 @@ Starting with this release, the settings are preserved as shown above, and the b ## Other Changes - Relaxed version bounds to allow installation on any Python 3 version from Python 3.11 onwards. +- Error messages for invalid comprehensions used with the Decorator API in `sum` and similar constructs now report the specific location in the source code. diff --git a/markdowns/ja/basics/expressions.md b/markdowns/ja/basics/expressions.md index 683f175..2bdee08 100644 --- a/markdowns/ja/basics/expressions.md +++ b/markdowns/ja/basics/expressions.md @@ -244,7 +244,45 @@ except Exception as e: print(e) ``` -:::{admonition} 決定変数による除算について +### 代替記法:`genarray` による配列の構築 + +上の例では、`y + z` のように、非自明なブロードキャストを伴う演算は(意図的に)エラーになっていました。 +このような場合、{py:func}`~jijmodeling.genarray` 関数を使い、陽にシェイプと成分の式を指定することで、結果の配列を構築できるようになります: + +```{code-cell} ipython3 +A = jm.genarray(lambda i, j, k: y[i, j] + z[i, j, k], (N, M, N)) +display(A) +problem.infer(A) +``` + +また、Decorator API を利用している場合、以下のように `jm.genarray` で内包表記を用いることもできます: + +```{code-cell} ipython3 +@problem.update +def _(problem: jm.DecoratedProblem): + A = jm.genarray(y[i, j] + z[i, j, k] for i, j, k in (N, M, N)) + display(A) + display(problem.infer(A)) +``` + +`genarray` の内包表記では、`for .. in ...` は一つしか許容されません。 +以下のように、複数の `for`-節を使ってしまうとエラーになるので注意してください: + +```{code-cell} ipython3 +try: + + @jm.Problem.define("genarray example") + def _(problem): + N = problem.Natural() + M = problem.Natural() + a = problem.Float(shape=(N, M)) + x = problem.BinaryVar(shape=N) + Sums = problem.NamedExpr(jm.genarray(a[i, j] * x[i] for i in N for j in M)) +except SyntaxError as e: + print(str(e)) +``` + +::{admonition} 決定変数による除算について :class: caution モデルの構築の時点では、決定変数が現れうる式は加減乗除の左右どちらの辺にも現れることができます。 @@ -494,6 +532,23 @@ def double_sum_example_alt(problem: jm.DecoratedProblem): problem += jm.sum(Q[i, j] for (i, j) in jm.product(N, M)) +double_sum_example_alt +``` + +また、Decorator API での内包表記の `in` の右辺や、`Constraint` の `domain=` キーワード引数などでは、`jm.product` を省略して次のようにタプルで直積を表すことができます: + +```{code-cell} ipython3 +@jm.Problem.define("Double Sum Example (Alt)") +def double_sum_example_alt(problem: jm.DecoratedProblem): + N = problem.Length() + M = problem.Length() + Q = problem.Float(shape=(N, M)) + x = problem.BinaryVar(shape=(N, M)) + + # 注目! productではなく、タプルで直積を表している + problem += jm.sum(Q[i, j] for (i, j) in (N, M)) + + double_sum_example_alt ``` diff --git a/markdowns/ja/releases/unreleased.md b/markdowns/ja/releases/unreleased.md index 4c6d89e..fa05422 100644 --- a/markdowns/ja/releases/unreleased.md +++ b/markdowns/ja/releases/unreleased.md @@ -28,18 +28,49 @@ kernelspec: import jijmodeling as jm +problem = jm.Problem("genarray example") +N = problem.Natural("N") +M = problem.Natural("M") +a = problem.Float("a", shape=(N, M)) +x = problem.BinaryVar("x", shape=N) +Sums = problem.NamedExpr("Sums", jm.genarray(lambda i, j: a[i, j] * x[i], (N, M))) + + +problem +``` + +また、Decorator API を利用している場合、以下のように `jm.genarray` で内包表記を用いることもできます: + +```{code-cell} ipython3 @jm.Problem.define("genarray example") def problem(problem): N = problem.Natural() M = problem.Natural() a = problem.Float(shape=(N, M)) x = problem.BinaryVar(shape=N) - Sums = problem.NamedExpr(jm.genarray(lambda i, j: a[i, j] * x[i], (N, M))) + Sums = problem.NamedExpr(jm.genarray(a[i, j] * x[i] for i, j in (N, M))) problem ``` +`genarray` の内包表記では、`for .. in ...` は一つしか許容されません。 +以下は、複数の `for`-節を使ってしまい、エラーになっている例です: + +```{code-cell} ipython3 +try: + + @jm.Problem.define("genarray example") + def problem(problem): + N = problem.Natural() + M = problem.Natural() + a = problem.Float(shape=(N, M)) + x = problem.BinaryVar(shape=N) + Sums = problem.NamedExpr(jm.genarray(a[i, j] * x[i] for i in N for j in M)) +except SyntaxError as e: + print(str(e)) +``` + ## 軸に沿った `min` / `max` のサポート 旧来は {py:func}`jm.sum ` や {py:meth}`Expression.sum ` では `axis` キーワード引数により、多次元配列の特定の軸に沿った和を取ることができましたが、今回のバージョンからは {py:func}`jm.min ` と {py:func}`jm.max `(そしてその対応する `Expression` メソッド)にも同様の機能が追加されました。 @@ -184,3 +215,4 @@ problem ## その他の変更 - バージョン条件を緩和し、Python 3.11 以降の任意の Python 3 でのインストールを許容しました。 +- Decorator API の `sum` などで不正な内包表記を使った際のエラーメッセージが、具体的なコード上の位置を報告するようになりました。