{ "cells": [ { "cell_type": "markdown", "id": "23b65719", "metadata": {}, "source": [ "# Declaring Variables" ] }, { "cell_type": "markdown", "id": "d3b11879", "metadata": {}, "source": [ "Below, we show how to declare stand-alone variables, and multi-dimensional arrays of variables." ] }, { "cell_type": "markdown", "id": "25ebddf7", "metadata": {}, "source": [ "**Remark.** In PyCSP$^3$, which is currently targeted to XCSP$^3$-core, we can only define integer and symbolic variables with finite domains, i.e., variables with a finite set of integers or symbols (strings). " ] }, { "cell_type": "markdown", "id": "afc8c33b", "metadata": {}, "source": [ "To see how it works, we need first to import the library PyCSP$^3$:" ] }, { "cell_type": "code", "execution_count": 1, "id": "1a8fe71c", "metadata": {}, "outputs": [], "source": [ "from pycsp3 import *" ] }, { "cell_type": "markdown", "id": "1dfe0e62", "metadata": {}, "source": [ "## Stand-alone Variables" ] }, { "cell_type": "markdown", "id": "45666e62", "metadata": {}, "source": [ "Stand-alone variables can be declared by means of the PyCSP$^3$ function *Var()*.\n", "To define the domain of a variable, we can simply list values, or use range(). \n", "For example, we can define three integer variables w, x and y, as well as a symbolic variable z as follows:" ] }, { "cell_type": "code", "execution_count": 2, "id": "592db2f3", "metadata": {}, "outputs": [], "source": [ "w = Var(range(15))\n", "x = Var(0, 1)\n", "y = Var(0, 2, 4, 6, 8)\n", "z = Var(\"a\", \"b\", \"c\")" ] }, { "cell_type": "markdown", "id": "8afe27a7", "metadata": {}, "source": [ "The domain of a variable is given by a field called *dom*. So, we can control the domain of the declared variables:" ] }, { "cell_type": "code", "execution_count": 3, "id": "7a43c557", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Domain of w: 0..14\n", "Domain of x: 0 1\n", "Domain of y: 0 2 4 6 8\n", "Domain of z: a b c\n" ] } ], "source": [ "print(\"Domain of w: \", w.dom)\n", "print(\"Domain of x: \", x.dom)\n", "print(\"Domain of y: \", y.dom)\n", "print(\"Domain of z: \", z.dom)" ] }, { "cell_type": "markdown", "id": "62584ff1", "metadata": {}, "source": [ "Note that values can be directly listed as above, or given in a set as follows:" ] }, { "cell_type": "code", "execution_count": 4, "id": "2d31bf38", "metadata": {}, "outputs": [], "source": [ "clear() # to discard previously posted variables\n", "w = Var(set(range(15))) \n", "x = Var({0, 1})\n", "y = Var({0, 2, 4, 6, 8})\n", "z = Var({\"a\", \"b\", \"c\"})" ] }, { "cell_type": "markdown", "id": "56319bad", "metadata": {}, "source": [ "We can check that we obtain similar domains:" ] }, { "cell_type": "code", "execution_count": 5, "id": "6b4e5515", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Domain of w: 0..14\n", "Domain of x: 0 1\n", "Domain of y: 0 2 4 6 8\n", "Domain of z: a b c\n" ] } ], "source": [ "print(\"Domain of w: \", w.dom)\n", "print(\"Domain of x: \", x.dom)\n", "print(\"Domain of y: \", y.dom)\n", "print(\"Domain of z: \", z.dom)" ] }, { "cell_type": "markdown", "id": "b3eded28", "metadata": {}, "source": [ "It is also possible to name the parameter *dom* when defining the domain:" ] }, { "cell_type": "code", "execution_count": 6, "id": "84729290", "metadata": {}, "outputs": [], "source": [ "clear() # to discard previously posted variables\n", "w = Var(dom=range(15)) # or equivalently, w = Var(dom=set(range(15)))\n", "x = Var(dom={0, 1})\n", "y = Var(dom={0, 2, 4, 6, 8})\n", "z = Var(dom={\"a\", \"b\", \"c\"})" ] }, { "cell_type": "markdown", "id": "ffa6e4d6", "metadata": {}, "source": [ "We can check that we obtain similar domains:" ] }, { "cell_type": "code", "execution_count": 7, "id": "a8e85933", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Domain of w: 0..14\n", "Domain of x: 0 1\n", "Domain of y: 0 2 4 6 8\n", "Domain of z: a b c\n" ] } ], "source": [ "print(\"Domain of w: \", w.dom)\n", "print(\"Domain of x: \", x.dom)\n", "print(\"Domain of y: \", y.dom)\n", "print(\"Domain of z: \", z.dom)" ] }, { "cell_type": "markdown", "id": "a9e88eab", "metadata": {}, "source": [ "Finally, it is of course possible to use generators and comprehension sets. For example, for y, we\n", "can write:" ] }, { "cell_type": "code", "execution_count": 8, "id": "e06c846e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Domain of y: 0 2 4 6 8\n", "Domain of y: 0 2 4 6 8\n", "Domain of y: 0 2 4 6 8\n" ] } ], "source": [ "clear()\n", "y = Var(i for i in range (10) if i % 2 == 0)\n", "print(\"Domain of y: \", y.dom)\n", "clear()\n", "y = Var({i for i in range (10) if i % 2 == 0}) \n", "print(\"Domain of y: \", y.dom)\n", "clear()\n", "y = Var(dom={i for i in range(10) if i % 2 == 0})\n", "print(\"Domain of y: \", y.dom)" ] }, { "cell_type": "markdown", "id": "27a0904d", "metadata": {}, "source": [ "## Arrays of Variables" ] }, { "cell_type": "markdown", "id": "9903c929", "metadata": {}, "source": [ "The PyCSP$^3$ function for declaring an array of variables is *VarArray()* that requires two named parameters *size* and *dom*. For declaring a one-dimensional array of variables, the value of *size* must be an integer (or a list containing only one integer), for declaring a two-dimensional array of variables, the value of *size* must be a list containing exactly two integers, and so on. The named parameter *dom* indicates the domain of each variable in the array." ] }, { "cell_type": "markdown", "id": "6e6dbd36", "metadata": {}, "source": [ "For example, to declare:\n", "- x, a one-dimensional array of 10 variables with domain {0,1}\n", "- y, a two-dimensional array of $5 \\times 5$ variables with domain {0,1,..., 9}\n", "- z, a three-dimensional array of $4 \\times 3 \\times 4$ variables with domain {1, 5, 10, 20}\n", "\n", "we write:" ] }, { "cell_type": "code", "execution_count": 9, "id": "aaaa0031", "metadata": {}, "outputs": [], "source": [ "clear() # to discard previously posted variables\n", "x = VarArray(size=10, dom={0, 1})\n", "y = VarArray(size=[5, 5], dom=range(10))\n", "z = VarArray(size=[4, 3, 4], dom={1, 5, 10, 20})" ] }, { "cell_type": "markdown", "id": "f811310b", "metadata": {}, "source": [ "We can display the (structure of the) arrays, as well as the domains of the variables." ] }, { "cell_type": "code", "execution_count": 10, "id": "09098f53", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Array x: [x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9]]\n", "Array y: [\n", " [y[0][0], y[0][1], y[0][2], y[0][3], y[0][4]]\n", " [y[1][0], y[1][1], y[1][2], y[1][3], y[1][4]]\n", " [y[2][0], y[2][1], y[2][2], y[2][3], y[2][4]]\n", " [y[3][0], y[3][1], y[3][2], y[3][3], y[3][4]]\n", " [y[4][0], y[4][1], y[4][2], y[4][3], y[4][4]]\n", "]\n", "Array z: [\n", " [\n", " [z[0][0][0], z[0][0][1], z[0][0][2], z[0][0][3]]\n", " [z[0][1][0], z[0][1][1], z[0][1][2], z[0][1][3]]\n", " [z[0][2][0], z[0][2][1], z[0][2][2], z[0][2][3]]\n", " ],\n", " [\n", " [z[1][0][0], z[1][0][1], z[1][0][2], z[1][0][3]]\n", " [z[1][1][0], z[1][1][1], z[1][1][2], z[1][1][3]]\n", " [z[1][2][0], z[1][2][1], z[1][2][2], z[1][2][3]]\n", " ],\n", " [\n", " [z[2][0][0], z[2][0][1], z[2][0][2], z[2][0][3]]\n", " [z[2][1][0], z[2][1][1], z[2][1][2], z[2][1][3]]\n", " [z[2][2][0], z[2][2][1], z[2][2][2], z[2][2][3]]\n", " ],\n", " [\n", " [z[3][0][0], z[3][0][1], z[3][0][2], z[3][0][3]]\n", " [z[3][1][0], z[3][1][1], z[3][1][2], z[3][1][3]]\n", " [z[3][2][0], z[3][2][1], z[3][2][2], z[3][2][3]]\n", " ],\n", "]\n", "Domain of variables of x: 0 1\n", "Domain of variables of y: 0..9\n", "Domain of variables of z: 1 5 10 20\n" ] } ], "source": [ "print(\"Array x: \", x)\n", "print(\"Array y: \", y)\n", "print(\"Array z: \", z)\n", "print(\"Domain of variables of x: \", x[0].dom)\n", "print(\"Domain of variables of y: \", y[0][0].dom)\n", "print(\"Domain of variables of z: \", z[0][0][0].dom)" ] }, { "cell_type": "markdown", "id": "01e83221", "metadata": {}, "source": [ "**Important:** Indexing starts at 0. For example, x[2] is the third variable of x, and y[1] is the second row of y. Technically, variable arrays are objects that are instances of *ListVar*, a subclass of *list*; additional functionalities of such objects are useful, for example, when posting constraints *Element*. " ] }, { "cell_type": "markdown", "id": "bc5d9c21", "metadata": {}, "source": [ "### Arrays with Variables of Different Domains" ] }, { "cell_type": "markdown", "id": "ea57eb34", "metadata": {}, "source": [ "In some situations, you may want to declare variables in an array with different domains. For a one-dimensional array, you can give the name of a function that accepts an integer i and returns the domain to be associated with the variable at index i in the array. For a two-dimensional array, you can give the name of a function that accepts a pair of integers (i,j) and returns the domain to be associated with the variable at indexes i, j in the array. And so on." ] }, { "cell_type": "markdown", "id": "1dd062a7", "metadata": {}, "source": [ "For example, suppose that the domain of all variables of the first column of y is range(5) instead of range(10).\n", "We can write:" ] }, { "cell_type": "code", "execution_count": 11, "id": "911ecb8d", "metadata": {}, "outputs": [], "source": [ "clear() # to discard previously posted variables\n", "\n", "def domain_y(i,j):\n", " return range(5) if j == 0 else range(10)\n", "\n", "y = VarArray(size=[5, 5], dom=domain_y)" ] }, { "cell_type": "markdown", "id": "e33fcae1", "metadata": {}, "source": [ "We can observe that domains of variables in y are not all the same:" ] }, { "cell_type": "code", "execution_count": 12, "id": "da3e785b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Domains on row 0: [0..4, 0..9, 0..9, 0..9, 0..9]\n", "Domains on row 1: [0..4, 0..9, 0..9, 0..9, 0..9]\n", "Domains on row 2: [0..4, 0..9, 0..9, 0..9, 0..9]\n", "Domains on row 3: [0..4, 0..9, 0..9, 0..9, 0..9]\n", "Domains on row 4: [0..4, 0..9, 0..9, 0..9, 0..9]\n" ] } ], "source": [ "for i in range(5):\n", " print(f\"Domains on row {i}: {[y[i][j].dom for j in range(5)]}\")" ] }, { "cell_type": "markdown", "id": "c69552ad", "metadata": {}, "source": [ "We can also use a lambda function:" ] }, { "cell_type": "code", "execution_count": 13, "id": "904620a8", "metadata": {}, "outputs": [], "source": [ "clear() # to discard previously posted variables\n", "\n", "y = VarArray(size=[5, 5], dom=lambda i,j: range(5) if j == 0 else range(10))" ] }, { "cell_type": "markdown", "id": "0d3e854c", "metadata": {}, "source": [ "We can check:" ] }, { "cell_type": "code", "execution_count": 14, "id": "430ec3a9", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Domains on row 0: [0..4, 0..9, 0..9, 0..9, 0..9]\n", "Domains on row 1: [0..4, 0..9, 0..9, 0..9, 0..9]\n", "Domains on row 2: [0..4, 0..9, 0..9, 0..9, 0..9]\n", "Domains on row 3: [0..4, 0..9, 0..9, 0..9, 0..9]\n", "Domains on row 4: [0..4, 0..9, 0..9, 0..9, 0..9]\n" ] } ], "source": [ "for i in range(5):\n", " print(f\"Domains on row {i}: {[y[i][j].dom for j in range(5)]}\")" ] }, { "cell_type": "markdown", "id": "04d4ff37", "metadata": {}, "source": [ "Sometimes, not all variables in an array are relevant. For example, you may only want to use the variables in the lower part of a two-dimensional array (matrix). In that case, the value *None* must be used." ] }, { "cell_type": "markdown", "id": "cd177e42", "metadata": {}, "source": [ "For example, if one wanted to introduce an auxiliary array y for the problem *Golomb Ruler* to compute distances between any two pairs of the main array x, we could write:" ] }, { "cell_type": "code", "execution_count": 15, "id": "1ec789ff", "metadata": {}, "outputs": [], "source": [ "clear() # to discard previously posted variables\n", "\n", "# y[i][j] is the distance between x[i] and x[j] for i strictly less than j\n", "y = VarArray(size=[5, 5], dom=lambda i, j: range(1, 5 * 5) if i < j else None)" ] }, { "cell_type": "markdown", "id": "8aa84712", "metadata": {}, "source": [ "One can see that only half of the array is really used (i.e., really contains variables): the lower part (below the main downward diagonal) only contains *None*. For example, y[1][0] is equal to *None*." ] }, { "cell_type": "code", "execution_count": 16, "id": "da6c28e8", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Array y: [\n", " [None, y[0][1], y[0][2], y[0][3], y[0][4]]\n", " [None, None, y[1][2], y[1][3], y[1][4]]\n", " [None, None, None, y[2][3], y[2][4]]\n", " [None, None, None, None, y[3][4]]\n", " [None, None, None, None, None]\n", "]\n" ] } ], "source": [ "print(\"Array y: \", y)" ] }, { "cell_type": "markdown", "id": "f1750b72", "metadata": {}, "source": [ "## Naming Variables and Arrays of Variables" ] }, { "cell_type": "markdown", "id": "6093f03c", "metadata": {}, "source": [ "Since Version 2.1, when declaring a stand-alone variable, one can set the name (id) with the parameter *id*.\n", "Then, to designate the variable, you just has to call the function *var()* with the specified name.\n", "Here is an example of model:" ] }, { "cell_type": "code", "execution_count": 17, "id": "16187ce9", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "intension(function:ge(x,3))\n", "intension(function:le(x,6))\n", "intension(function:gt(yy_12,2))\n", "intension(function:lt(yy_12,4))\n", "intension(function:ne(z,4))\n", "intension(function:ne(add(d_0,d_1),0))\n", "intension(function:ne(add(d_0,d_1),2))" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "clear()\n", "\n", "x = Var(range(10))\n", "y = Var(dom=range(5), id=\"yy_12\")\n", "Var(dom=range(10), id=\"z\")\n", "\n", "d = dict()\n", "a = 1\n", "d[0] = Var(0, 1, id=\"d_0\")\n", "d[a] = Var(0, 1, id=\"d_1\")\n", "\n", "satisfy(\n", " x >= 3,\n", " var(\"x\") <= 6,\n", " y > 2,\n", " var(\"yy_12\") < 4,\n", " var(\"z\") != 4,\n", " d[0] + d[1] != 0,\n", " var(\"d_0\") + var(\"d_1\") != 2\n", ")" ] }, { "cell_type": "markdown", "id": "cb9c68d8", "metadata": {}, "source": [ "You can observe the correpondances (aliases) from the output above." ] }, { "cell_type": "markdown", "id": "c4376b45", "metadata": {}, "source": [ "Similarly, one can use the parameter *id* when declaring arrays of variables, and call the same function *var()* to get access to arrays. Here is an example of model:" ] }, { "cell_type": "code", "execution_count": 18, "id": "1c0ac7ba", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "sum(list:[x[0], x[1], x[2]], condition:(eq,1))\n", "sum(list:[yy[0], yy[1], yy[2]], condition:(gt,0))\n", "sum(list:[yy[0], yy[1], yy[2]], condition:(lt,2))\n", "sum(list:[zz[0], zz[1], zz[2]], condition:(lt,2))\n", "sum(list:[d0[0], d0[1], d0[2], d_a[0], d_a[1], d_a[2]], condition:(gt,0))\n", "sum(list:[d0[0], d0[1], d0[2], d_a[0], d_a[1], d_a[2]], condition:(lt,2))\n", "intension(function:eq(d_a[1],1))" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "clear()\n", "\n", "x = VarArray(size=3, dom={0, 1})\n", "y = VarArray(size=3, dom={0, 1}, id=\"yy\")\n", "VarArray(size=3, dom={0, 1}, id=\"zz\")\n", "\n", "d = dict()\n", "a = 1\n", "d[0] = VarArray(size=3, dom={0, 1}, id=\"d0\")\n", "d[a] = VarArray(size=3, dom={0, 1}, id=\"d_a\")\n", "\n", "satisfy(\n", " Sum(x) == 1,\n", " Sum(y) > 0,\n", " Sum(var(\"yy\")) < 2,\n", " Sum(var(\"zz\")) < 2,\n", " Sum(d[0] + d[a]) > 0,\n", " Sum(var(\"d0\") + var(\"d_a\")) < 2,\n", " var(\"d_a\")[1] == 1\n", ")" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.12" } }, "nbformat": 4, "nbformat_minor": 5 }