diff --git a/11_classes/00_content.ipynb b/11_classes/00_content.ipynb index 692af9c..6852453 100644 --- a/11_classes/00_content.ipynb +++ b/11_classes/00_content.ipynb @@ -272,7 +272,7 @@ "outputs": [], "source": [ "class Vector:\n", - " \"\"\"A standard one-dimensional vector from linear algebra.\"\"\"\n", + " \"\"\"A one-dimensional vector from linear algebra.\"\"\"\n", "\n", " dummy_variable = \"I am a vector\"\n", "\n", @@ -403,7 +403,7 @@ "data": { "text/plain": [ "\u001b[0;31mInit signature:\u001b[0m \u001b[0mVector\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mDocstring:\u001b[0m A standard one-dimensional vector from linear algebra.\n", + "\u001b[0;31mDocstring:\u001b[0m A one-dimensional vector from linear algebra.\n", "\u001b[0;31mType:\u001b[0m type\n", "\u001b[0;31mSubclasses:\u001b[0m \n" ] @@ -432,7 +432,7 @@ "Help on class Vector in module __main__:\n", "\n", "class Vector(builtins.object)\n", - " | A standard one-dimensional vector from linear algebra.\n", + " | A one-dimensional vector from linear algebra.\n", " | \n", " | Methods defined here:\n", " | \n", @@ -484,7 +484,7 @@ "data": { "text/plain": [ "mappingproxy({'__module__': '__main__',\n", - " '__doc__': 'A standard one-dimensional vector from linear algebra.',\n", + " '__doc__': 'A one-dimensional vector from linear algebra.',\n", " 'dummy_variable': 'I am a vector',\n", " 'dummy_method': ,\n", " '__dict__': ,\n", @@ -687,7 +687,7 @@ "outputs": [], "source": [ "class Vector:\n", - " \"\"\"A standard one-dimensional vector from linear algebra.\n", + " \"\"\"A one-dimensional vector from linear algebra.\n", "\n", " All entries are converted to floats.\n", " \"\"\"\n", diff --git a/11_classes/02_content.ipynb b/11_classes/02_content.ipynb index 1d99ecf..520339f 100644 --- a/11_classes/02_content.ipynb +++ b/11_classes/02_content.ipynb @@ -1815,17 +1815,16 @@ }, "outputs": [], "source": [ - "def norm(vector_or_matrix):\n", + "def norm(vec_or_mat):\n", " \"\"\"Calculate the Frobenius or Euclidean norm of a matrix or vector.\n", "\n", " Args:\n", - " vector_or_matrix (Vector/Matrix): the entries whose squares\n", - " are summed up\n", + " vec_or_mat (Vector / Matrix): object whose entries are squared and summed up\n", "\n", " Returns:\n", " norm (float)\n", " \"\"\"\n", - " return math.sqrt(sum(x ** 2 for x in vector_or_matrix))" + " return math.sqrt(sum(x ** 2 for x in vec_or_mat))" ] }, { diff --git a/11_classes/03_content.ipynb b/11_classes/03_content.ipynb index 7b3a9ae..9dc08a2 100644 --- a/11_classes/03_content.ipynb +++ b/11_classes/03_content.ipynb @@ -694,7 +694,7 @@ " def __add__(self, other):\n", " if isinstance(other, self.__class__): # vector addition\n", " if len(self) != len(other):\n", - " raise ValueError(\"vectors need to be of the same length\")\n", + " raise ValueError(\"vectors must be of the same length\")\n", " return Vector(x + y for (x, y) in zip(self, other))\n", " elif isinstance(other, numbers.Number): # broadcasting addition\n", " return Vector(x + other for x in self)\n", @@ -706,7 +706,7 @@ " def __sub__(self, other):\n", " if isinstance(other, self.__class__): # vector subtraction\n", " if len(self) != len(other):\n", - " raise ValueError(\"vectors need to be of the same length\")\n", + " raise ValueError(\"vectors must be of the same length\")\n", " return Vector(x - y for (x, y) in zip(self, other))\n", " elif isinstance(other, numbers.Number): # broadcasting subtraction\n", " return Vector(x - other for x in self)\n", @@ -721,7 +721,7 @@ " def __mul__(self, other):\n", " if isinstance(other, self.__class__): # dot product\n", " if len(self) != len(other):\n", - " raise ValueError(\"vectors need to be of the same length\")\n", + " raise ValueError(\"vectors must be of the same length\")\n", " return sum(x * y for (x, y) in zip(self, other))\n", " elif isinstance(other, numbers.Number): # scalar multiplication\n", " return Vector(x * other for x in self)\n", @@ -872,14 +872,14 @@ "outputs": [ { "ename": "ValueError", - "evalue": "vectors need to be of the same length", + "evalue": "vectors must be of the same length", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mv\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mw\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m\u001b[0m in \u001b[0;36m__mul__\u001b[0;34m(self, other)\u001b[0m\n\u001b[1;32m 45\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__class__\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;31m# dot product\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 46\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 47\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"vectors need to be of the same length\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 48\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0msum\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0my\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mzip\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mother\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 49\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnumbers\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mNumber\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;31m# scalar multiplication\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mValueError\u001b[0m: vectors need to be of the same length" + "\u001b[0;32m\u001b[0m in \u001b[0;36m__mul__\u001b[0;34m(self, other)\u001b[0m\n\u001b[1;32m 45\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__class__\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;31m# dot product\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 46\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 47\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"vectors must be of the same length\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 48\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0msum\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0my\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mzip\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mother\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 49\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnumbers\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mNumber\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;31m# scalar multiplication\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mValueError\u001b[0m: vectors must be of the same length" ] } ], @@ -992,14 +992,14 @@ "outputs": [ { "ename": "ValueError", - "evalue": "vectors need to be of the same length", + "evalue": "vectors must be of the same length", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mv\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mw\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m\u001b[0m in \u001b[0;36m__add__\u001b[0;34m(self, other)\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__class__\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;31m# vector addition\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 20\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"vectors need to be of the same length\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 21\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mVector\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0my\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mzip\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mother\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 22\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnumbers\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mNumber\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;31m# broadcasting addition\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mValueError\u001b[0m: vectors need to be of the same length" + "\u001b[0;32m\u001b[0m in \u001b[0;36m__add__\u001b[0;34m(self, other)\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__class__\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;31m# vector addition\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 20\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"vectors must be of the same length\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 21\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mVector\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0my\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mzip\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mother\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 22\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnumbers\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mNumber\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;31m# broadcasting addition\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mValueError\u001b[0m: vectors must be of the same length" ] } ], @@ -1171,7 +1171,7 @@ " def __add__(self, other):\n", " if isinstance(other, self.__class__): # matrix addition\n", " if (self.n_rows != other.n_rows) or (self.n_cols != other.n_cols):\n", - " raise ValueError(\"matrices need to be of the same dimensions\")\n", + " raise ValueError(\"matrices must have the same dimensions\")\n", " return Matrix((s_col + o_col for (s_col, o_col) in zip(s_row, o_row))\n", " for (s_row, o_row) in zip(self._entries, other._entries))\n", " elif isinstance(other, numbers.Number): # broadcasting addition\n", @@ -1186,7 +1186,7 @@ " def __sub__(self, other):\n", " if isinstance(other, self.__class__): # matrix subtraction\n", " if (self.n_rows != other.n_rows) or (self.n_cols != other.n_cols):\n", - " raise ValueError(\"matrices need to be of the same dimensions\")\n", + " raise ValueError(\"matrices must have the same dimensions\")\n", " return Matrix((s_col - o_col for (s_col, o_col) in zip(s_row, o_row))\n", " for (s_row, o_row) in zip(self._entries, other._entries))\n", " elif isinstance(other, numbers.Number): # broadcasting subtraction\n", @@ -1203,7 +1203,7 @@ " \n", " def _matrix_multiply(self, other):\n", " if self.n_cols != other.n_rows:\n", - " raise ValueError(\"matrices need to have compatible dimensions\")\n", + " raise ValueError(\"matrices must have compatible dimensions\")\n", " return Matrix((rv * cv for cv in other.cols()) for rv in self.rows())\n", "\n", " def __mul__(self, other):\n", @@ -1387,15 +1387,15 @@ "outputs": [ { "ename": "ValueError", - "evalue": "matrices need to have compatible dimensions", + "evalue": "matrices must have compatible dimensions", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mm\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mn\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m\u001b[0m in \u001b[0;36m__mul__\u001b[0;34m(self, other)\u001b[0m\n\u001b[1;32m 72\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_matrix_multiply\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mas_matrix\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mas_vector\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 73\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__class__\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 74\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_matrix_multiply\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 75\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mNotImplemented\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 76\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m\u001b[0m in \u001b[0;36m_matrix_multiply\u001b[0;34m(self, other)\u001b[0m\n\u001b[1;32m 63\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m_matrix_multiply\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mother\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 64\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mn_cols\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mother\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mn_rows\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 65\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"matrices need to have compatible dimensions\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 66\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mMatrix\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrv\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mcv\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mcv\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mother\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcols\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mrv\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrows\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 67\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mValueError\u001b[0m: matrices need to have compatible dimensions" + "\u001b[0;32m\u001b[0m in \u001b[0;36m__mul__\u001b[0;34m(self, other)\u001b[0m\n\u001b[1;32m 72\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_matrix_multiply\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mas_matrix\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mas_vector\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 73\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__class__\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 74\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_matrix_multiply\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 75\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mNotImplemented\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 76\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36m_matrix_multiply\u001b[0;34m(self, other)\u001b[0m\n\u001b[1;32m 63\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m_matrix_multiply\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mother\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 64\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mn_cols\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mother\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mn_rows\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 65\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"matrices must have compatible dimensions\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 66\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mMatrix\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrv\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mcv\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mcv\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mother\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcols\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mrv\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrows\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 67\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mValueError\u001b[0m: matrices must have compatible dimensions" ] } ], @@ -1497,15 +1497,15 @@ "outputs": [ { "ename": "ValueError", - "evalue": "matrices need to have compatible dimensions", + "evalue": "matrices must have compatible dimensions", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mv\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mn\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m\u001b[0m in \u001b[0;36m__rmul__\u001b[0;34m(self, other)\u001b[0m\n\u001b[1;32m 79\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mother\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 80\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mVector\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 81\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mother\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mas_matrix\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcolumn\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_matrix_multiply\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mas_vector\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 82\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mNotImplemented\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 83\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m\u001b[0m in \u001b[0;36m_matrix_multiply\u001b[0;34m(self, other)\u001b[0m\n\u001b[1;32m 63\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m_matrix_multiply\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mother\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 64\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mn_cols\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mother\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mn_rows\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 65\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"matrices need to have compatible dimensions\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 66\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mMatrix\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrv\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mcv\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mcv\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mother\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcols\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mrv\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrows\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 67\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mValueError\u001b[0m: matrices need to have compatible dimensions" + "\u001b[0;32m\u001b[0m in \u001b[0;36m__rmul__\u001b[0;34m(self, other)\u001b[0m\n\u001b[1;32m 79\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mother\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 80\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mVector\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 81\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mother\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mas_matrix\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcolumn\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_matrix_multiply\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mas_vector\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 82\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mNotImplemented\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 83\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36m_matrix_multiply\u001b[0;34m(self, other)\u001b[0m\n\u001b[1;32m 63\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m_matrix_multiply\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mother\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 64\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mn_cols\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mother\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mn_rows\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 65\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"matrices must have compatible dimensions\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 66\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mMatrix\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrv\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mcv\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mcv\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mother\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcols\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mrv\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrows\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 67\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mValueError\u001b[0m: matrices must have compatible dimensions" ] } ], @@ -1736,7 +1736,7 @@ " def __eq__(self, other):\n", " if isinstance(other, self.__class__):\n", " if len(self) != len(other):\n", - " raise ValueError(\"vectors need to be of the same length\")\n", + " raise ValueError(\"vectors must be of the same length\")\n", " for x, y in zip(self, other):\n", " if abs(x - y) > self.zero_threshold:\n", " return False # exit early if two corresponding entries differ\n", @@ -1972,12 +1972,9 @@ "metadata": {}, "outputs": [], "source": [ - "def norm(vector_or_matrix):\n", - " \"\"\"Calculate the Frobenius or Euclidean norm of a matrix or vector.\n", - " \n", - " ...\n", - " \"\"\"\n", - " return math.sqrt(sum(x ** 2 for x in vector_or_matrix))" + "def norm(vec_or_mat):\n", + " \"\"\"Calculate the Frobenius or Euclidean norm of a matrix or vector.\"\"\"\n", + " return math.sqrt(sum(x ** 2 for x in vec_or_mat))" ] }, { @@ -2020,7 +2017,7 @@ "\n", " def __float__(self):\n", " if len(self) != 1:\n", - " raise RuntimeError(\"vector must have one entry to become a scalar\")\n", + " raise RuntimeError(\"vector must have exactly one entry to become a scalar\")\n", " return self._entries[0]" ] }, @@ -2303,14 +2300,14 @@ "outputs": [ { "ename": "RuntimeError", - "evalue": "vector must have one entry to become a scalar", + "evalue": "vector must have exactly one entry to become a scalar", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mRuntimeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfloat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mv\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m\u001b[0m in \u001b[0;36m__float__\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 29\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m__float__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 30\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 31\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mRuntimeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"vector must have one entry to become a scalar\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 32\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_entries\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mRuntimeError\u001b[0m: vector must have one entry to become a scalar" + "\u001b[0;32m\u001b[0m in \u001b[0;36m__float__\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 29\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m__float__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 30\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 31\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mRuntimeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"vector must have exactly one entry to become a scalar\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 32\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_entries\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mRuntimeError\u001b[0m: vector must have exactly one entry to become a scalar" ] } ], diff --git a/11_classes/sample_package/__init__.py b/11_classes/sample_package/__init__.py new file mode 100644 index 0000000..1e8d12c --- /dev/null +++ b/11_classes/sample_package/__init__.py @@ -0,0 +1,30 @@ +"""This package provides linear algebra functionalities. + +The package is split into three modules: +- matrix: defines the Matrix class +- vector: defines the Vector class +- utils: defines the norm() function that is shared by Matrix and Vector + and package-wide constants + +The classes implement arithmetic operations involving vectors and matrices. + +See the docstrings in the modules and classes for further info. +""" + +# Import the classes here so that they are available +# from the package's top level. That means that a user +# who imports this package with `import sample_package` +# may then refer to, for example, the Matrix class with +# simply `sample_package.Matrix` instead of the longer +# `sample_package.matrix.Matrix`. +from sample_package.matrix import Matrix +from sample_package.vector import Vector + + +# Define meta information for the package. +# There are other (and more modern) ways of +# doing this, but specifying the following +# dunder variables here is the traditional way. +__name__ = "linear_algebra_tools" +__version__ = "0.1.0" # see https://semver.org/ for how the format works +__author__ = "Alexander Hess" diff --git a/11_classes/sample_package/matrix.py b/11_classes/sample_package/matrix.py new file mode 100644 index 0000000..b64e50d --- /dev/null +++ b/11_classes/sample_package/matrix.py @@ -0,0 +1,416 @@ +"""This module defines a Matrix class.""" + +import numbers + +# Note the import at the bottom of this file, and +# see the comments about imports in the matrix module. +from sample_package import utils + + +class Matrix: + """An m-by-n-dimensional matrix from linear algebra. + + All entries are converted to floats, or whatever is set in the typing attribute. + + Attributes: + storage (callable): data type used to store the entries internally; + defaults to tuple + typing (callable): type casting applied to all entries upon creation; + defaults to float + zero_threshold (float): max. tolerance when comparing an entry to zero; + defaults to 1e-12 + """ + + storage = utils.DEFAULT_ENTRIES_STORAGE + typing = utils.DEFAULT_ENTRY_TYPE + zero_threshold = utils.ZERO_THRESHOLD + + def __init__(self, data): + """Create a new matrix. + + Args: + data (sequence of sequences): the matrix's entries; + viewed as a sequence of the matrix's rows (i.e., row-major order); + use the .from_columns() class method if the data come as a sequence + of the matrix's columns (i.e., column-major order) + + Raises: + ValueError: + - if no entries are provided + - if the number of columns is inconsistent across the rows + """ + self._entries = self.storage( + self.storage(self.typing(x) for x in r) for r in data + ) + for row in self._entries[1:]: + if len(row) != self.n_cols: + raise ValueError("rows must have the same number of entries") + if len(self) == 0: + raise ValueError("a matrix must have at least one entry") + + @classmethod + def from_columns(cls, data): + """Create a new matrix. + + This is an alternative constructor for data provided in column-major order. + + Args: + data (sequence of sequences): the matrix's entries; + viewed as a sequence of the matrix's columns (i.e., column-major order); + use the normal constructor method if the data come as a sequence + of the matrix's rows (i.e., row-major order) + + Raises: + ValueError: + - if no entries are provided + - if the number of rows is inconsistent across the columns + """ + return cls(data).transpose() + + @classmethod + def from_rows(cls, data): + """See docstring for .__init__().""" + # Some users may want to use this .from_rows() constructor + # to explicitly communicate that the data are in row-major order. + # Otherwise, this method is redundant. + return cls(data) + + def __repr__(self): + """Text representation of a Matrix.""" + name = self.__class__.__name__ + args = ", ".join( + "(" + ", ".join(f"{c:.3f}" for c in r) + ",)" for r in self._entries + ) + return f"{name}(({args}))" + + def __str__(self): + """Human-readable text representation of a Matrix.""" + name = self.__class__.__name__ + first, last, m, n = self[0], self[-1], self.n_rows, self.n_cols + return f"{name}(({first:.1f}, ...), ..., (..., {last:.1f}))[{m:d}x{n:d}]" + + @property + def n_rows(self): + """Number of rows in a Matrix.""" + return len(self._entries) + + @property + def n_cols(self): + """Number of columns in a Matrix.""" + return len(self._entries[0]) + + def __len__(self): + """Number of entries in a Matrix.""" + return self.n_rows * self.n_cols + + def __getitem__(self, index): + """Obtain an individual entry of a Matrix. + + Args: + index (int / tuple of int's): if index is an integer, + the Matrix is viewed as a sequence in row-major order; + if index is a tuple of integers, the first one refers to + the row and the second one to the column of the entry + + Returns: + entry (Matrix.typing) + + Example Usage: + >>> m = Matrix([(1, 2), (3, 4)]) + >>> m[0] + 1.0 + >>> m[-1] + 4.0 + >>> m[0, 1] + 3.0 + """ + # Sequence-like indexing (one-dimensional) + if isinstance(index, int): + if index < 0: + index += len(self) + if not (0 <= index < len(self)): + raise IndexError("integer index out of range") + row, col = divmod(index, self.n_cols) + return self._entries[row][col] + # Mathematical-like indexing (two-dimensional) + elif ( + isinstance(index, tuple) + and len(index) == 2 + and isinstance(index[0], int) + and isinstance(index[1], int) + ): + return self._entries[index[0]][index[1]] + raise TypeError("index must be either an int or a tuple of two int's") + + def rows(self): + """Loop over a Matrix's rows. + + Returns: + rows (generator): produces a Matrix's rows as Vectors + """ + return (Vector(r) for r in self._entries) + + def cols(self): + """Loop over a Matrix's columns. + + Returns: + columns (generator): produces a Matrix's columns as Vectors + """ + return ( + Vector(self._entries[r][c] for r in range(self.n_rows)) + for c in range(self.n_cols) + ) + + def entries(self, *, reverse=False, row_major=True): + """Loop over a Matrix's entries. + + Args: + reverse (bool): flag to loop backwards; defaults to False + row_major (bool): flag to loop in row-major order; defaults to True + + Returns: + entries (generator): produces a Matrix's entries + """ + if reverse: + rows = range(self.n_rows - 1, -1, -1) + cols = range(self.n_cols - 1, -1, -1) + else: + rows, cols = range(self.n_rows), range(self.n_cols) + if row_major: + return (self._entries[r][c] for r in rows for c in cols) + return (self._entries[r][c] for c in cols for r in rows) + + def __iter__(self): + """Loop over a Matrix's entries. + + See .entries() for more customization options. + """ + return self.entries() + + def __reversed__(self): + """Loop over a Matrix's entries in reverse order. + + See .entries() for more customization options. + """ + return self.entries(reverse=True) + + def __add__(self, other): + """Handle `self + other` and `other + self`. + + This may be either matrix addition or broadcasting addition. + + Example Usage: + >>> Matrix([(1, 2), (3, 4)]) + Matrix([(2, 3), (4, 5)]) + Matrix(((3.0, 5.0), (7.0, 9.0))) + + >>> Matrix([(1, 2), (3, 4)]) + 5 + Matrix(((6.0, 7.0), (8.0, 9.0))) + + >>> 10 + Matrix([(1, 2), (3, 4)]) + Matrix(((11.0, 12.0), (13.0, 14.0))) + """ + # Matrix addition + if isinstance(other, self.__class__): + if (self.n_rows != other.n_rows) or (self.n_cols != other.n_cols): + raise ValueError("matrices must have the same dimensions") + return self.__class__( + (s_col + o_col for (s_col, o_col) in zip(s_row, o_row)) + for (s_row, o_row) in zip(self._entries, other._entries) + ) + # Broadcasting addition + elif isinstance(other, numbers.Number): + return self.__class__((c + other for c in r) for r in self._entries) + return NotImplemented + + def __radd__(self, other): + """See docstring for .__add__().""" + if isinstance(other, Vector): + raise TypeError("vectors and matrices cannot be added") + # As both matrix and broadcasting addition are commutative, + # we dispatch to .__add__(). + return self + other + + def __sub__(self, other): + """Handle `self - other` and `other - self`. + + This may be either matrix subtraction or broadcasting subtraction. + + Example Usage: + >>> Matrix([(2, 3), (4, 5)]) - Matrix([(1, 2), (3, 4)]) + Matrix(((1.0, 1.0), (1.0, 1.0))) + + >>> Matrix([(1, 2), (3, 4)]) - 1 + Matrix(((0.0, 1.0), (2.0, 3.0))) + + >>> 10 - Matrix([(1, 2), (3, 4)]) + Matrix(((9.0, 8.0), (7.0, 6.0))) + """ + # As subtraction is the inverse of addition, + # we first dispatch to .__neg__() to invert the signs of + # all entries in other and then dispatch to .__add__(). + return self + (-other) + + def __rsub__(self, other): + """See docstring for .__sub__().""" + if isinstance(other, Vector): + raise TypeError("vectors and matrices cannot be subtracted") + # Same comments as in .__sub__() apply + # with the roles of self and other swapped. + return (-self) + other + + def _matrix_multiply(self, other): + """Internal utility method to multiply to Matrix instances.""" + if self.n_cols != other.n_rows: + raise ValueError("matrices must have compatible dimensions") + # Matrix-matrix multiplication means that each entry of the resulting + # Matrix is the dot product of the respective row of the "left" Matrix + # and column of the "right" Matrix. So, the rows/columns are represented + # by the Vector instances provided by the .cols() and .rows() methods. + return self.__class__((rv * cv for cv in other.cols()) for rv in self.rows()) + + def __mul__(self, other): + """Handle `self * other` and `other * self`. + + This may be either scalar multiplication, matrix-vector multiplication, + vector-matrix multiplication, or matrix-matrix multiplication. + + Example Usage: + >>> Matrix([(1, 2), (3, 4)]) * Matrix([(1, 2), (3, 4)]) + Matrix(((7.0, 10.0), (15.0, 22.0))) + + >>> 2 * Matrix([(1, 2), (3, 4)]) + Matrix(((2.0, 4.0), (6.0, 8.0))) + + >>> Matrix([(1, 2), (3, 4)]) * 3 + Matrix(((3.0, 6.0), (9.0, 12.0))) + + Matrix-vector and vector-matrix multiplication are not commutative. + + >>> Matrix([(1, 2), (3, 4)]) * Vector([5, 6]) + Vector((17.0, 39.0)) + + >>> Vector([5, 6]) * Matrix([(1, 2), (3, 4)]) + Vector((23.0, 34.0)) + """ + # Scalar multiplication + if isinstance(other, numbers.Number): + return self.__class__((x * other for x in r) for r in self._entries) + # Matrix-vector multiplication: Vector is a column Vector + elif isinstance(other, Vector): + # First, cast the other Vector as a Matrix, then do matrix-matrix + # multiplication, and lastly return the result as a Vector again. + return self._matrix_multiply(other.as_matrix()).as_vector() + # Matrix-matrix multiplication + elif isinstance(other, self.__class__): + return self._matrix_multiply(other) + return NotImplemented + + def __rmul__(self, other): + """See docstring for .__mul__().""" + # As scalar multiplication is commutative, we dispatch to .__mul__(). + if isinstance(other, numbers.Number): + return self * other + # Vector-matrix multiplication: Vector is a row Vector + elif isinstance(other, Vector): + return other.as_matrix(column=False)._matrix_multiply(self).as_vector() + return NotImplemented + + def __truediv__(self, other): + """Handle `self / other`. + + Divide a Matrix by a scalar. + + Example Usage: + >>> Matrix([(1, 2), (3, 4)]) / 4 + Matrix([(0.25, 0.5), (0.75, 1.0)]) + """ + # As scalar division division is the same as multiplication + # with the inverse, we dispatch to .__mul__(). + if isinstance(other, numbers.Number): + return self * (1 / other) + return NotImplemented + + def __eq__(self, other): + """Handle `self == other`. + + Compare two Matrix instances for equality. + + Example Usage: + >>> Matrix([(1, 2), (3, 4)]) == Matrix([(1, 2), (3, 4)]) + True + + >>> Matrix([(1, 2), (3, 4)]) == Matrix([(5, 6), (7, 8)]) + False + """ + if isinstance(other, self.__class__): + if (self.n_rows != other.n_rows) or (self.n_cols != other.n_cols): + raise ValueError("matrices must have the same dimensions") + for x, y in zip(self, other): + if abs(x - y) > self.zero_threshold: + return False # exit early if two corresponding entries differ + return True + return NotImplemented + + def __pos__(self): + """Handle `+self`. + + This is simply an identity operator returning the Matrix itself. + """ + return self + + def __neg__(self): + """Handle `-self`. + + Negate all entries of a Matrix. + """ + return self.__class__((-x for x in r) for r in self._entries) + + def __abs__(self): + """The Frobenius norm of a Matrix.""" + return utils.norm(self) # use the norm() function shared with the Vector class + + def __bool__(self): + """A Matrix is truthy if its Frobenius norm is strictly positive.""" + return bool(abs(self)) + + def __float__(self): + """Cast a Matrix as a scalar. + + Returns: + scalar (float) + + Raises: + RuntimeError: if the Matrix has more than one entry + """ + if not (self.n_rows == 1 and self.n_cols == 1): + raise RuntimeError("matrix must have exactly one entry to become a scalar") + return self[0] + + def as_vector(self): + """Get a Vector representation of a Matrix. + + Returns: + vector (Vector) + + Raises: + RuntimeError: if one of the two dimensions, .n_rows or .n_cols, is not 1 + """ + if not (self.n_rows == 1 or self.n_cols == 1): + raise RuntimeError("one dimension (m or n) must be 1") + return Vector(x for x in self) + + def transpose(self): + """Switch the rows and columns of a Matrix. + + Returns: + matrix (Matrix) + """ + return self.__class__(zip(*self._entries)) + + +# This import needs to be made here as otherwise an ImportError is raised. +# That is so as both the matrix and vector modules import a class from each other. +# We call that a circular import. Whereas Python handles "circular" references +# (e.g., both the Matrix and Vector classes have methods that reference the +# respective other class), that is forbidden for imports. +from sample_package.vector import Vector diff --git a/11_classes/sample_package/utils.py b/11_classes/sample_package/utils.py new file mode 100644 index 0000000..2720372 --- /dev/null +++ b/11_classes/sample_package/utils.py @@ -0,0 +1,35 @@ +"""This module provides utilities for the whole package. + +The defined constants are used as defaults in the Vector and Matrix classes. + +The norm() function is shared by Vector.__abs__() and Matrix.__abs__(). +""" + +import math + + +# Define constants (i.e., normal variables that are, by convention, named in UPPERCASE) +# that are used as the defaults for class attributes within Vector and Matrix. +DEFAULT_ENTRIES_STORAGE = tuple +DEFAULT_ENTRY_TYPE = float +ZERO_THRESHOLD = 1e-12 + + +def norm(vec_or_mat): + """Calculate the Frobenius or Euclidean norm of a matrix or vector. + + Find more infos here: https://en.wikipedia.org/wiki/Matrix_norm#Frobenius_norm + + Args: + vec_or_mat (Vector / Matrix): object whose entries are squared and summed up + + Returns: + norm (float) + + Example Usage: + As Vector and Matrix objects are by design non-empty sequences, + norm() may be called, for example, with `[3, 4]` as the argument: + >>> norm([3, 4]) + 5.0 + """ + return math.sqrt(sum(x ** 2 for x in vec_or_mat)) diff --git a/11_classes/sample_package/vector.py b/11_classes/sample_package/vector.py new file mode 100644 index 0000000..1b6e305 --- /dev/null +++ b/11_classes/sample_package/vector.py @@ -0,0 +1,253 @@ +"""This module defines a Vector class.""" + +# Imports from the standard library go first ... +import numbers + +# ... and are followed by project-internal ones. +# If third-party libraries are needed, they are +# put into a group on their own in between. +# Within a group, imports are sorted lexicographically. +from sample_package import utils +from sample_package.matrix import Matrix + + +class Vector: + """A one-dimensional vector from linear algebra. + + All entries are converted to floats, or whatever is set in the typing attribute. + + Attributes: + storage (callable): data type used to store the entries internally; + defaults to tuple + typing (callable): type casting applied to all entries upon creation; + defaults to float + zero_threshold (float): max. tolerance when comparing an entry to zero; + defaults to 1e-12 + """ + + storage = utils.DEFAULT_ENTRIES_STORAGE + typing = utils.DEFAULT_ENTRY_TYPE + zero_threshold = utils.ZERO_THRESHOLD + + def __init__(self, data): + """Create a new vector. + + Args: + data (sequence): the vector's entries + + Raises: + ValueError: if no entries are provided + + Example Usage: + >>> Vector([1, 2, 3]) + Vector((1.0, 2.0, 3.0)) + + >>> Vector(range(3)) + Vector((0.0, 1.0, 2.0)) + """ + self._entries = self.storage(self.typing(x) for x in data) + if len(self) == 0: + raise ValueError("a vector must have at least one entry") + + def __repr__(self): + """Text representation of a Vector.""" + name = self.__class__.__name__ + args = ", ".join(f"{x:.3f}" for x in self) + return f"{name}(({args}))" + + def __str__(self): + """Human-readable text representation of a Vector.""" + name = self.__class__.__name__ + first, last, n_entries = self[0], self[-1], len(self) + return f"{name}({first:.1f}, ..., {last:.1f})[{n_entries:d}]" + + def __len__(self): + """Number of entries in a Vector.""" + return len(self._entries) + + def __getitem__(self, index): + """Obtain an individual entry of a Vector.""" + if not isinstance(index, int): + raise TypeError("index must be an integer") + return self._entries[index] + + def __iter__(self): + """Loop over a Vector's entries.""" + return iter(self._entries) + + def __reversed__(self): + """Loop over a Vector's entries in reverse order.""" + return reversed(self._entries) + + def __add__(self, other): + """Handle `self + other` and `other + self`. + + This may be either vector addition or broadcasting addition. + + Example Usage: + >>> Vector([1, 2, 3]) + Vector([2, 3, 4]) + Vector((3, 5, 7)) + + >>> Vector([1, 2, 3]) + 4 + Vector((5, 6, 7)) + + >>> 10 + Vector([1, 2, 3]) + Vector((11, 12, 13)) + """ + # Vector addition + if isinstance(other, self.__class__): + if len(self) != len(other): + raise ValueError("vectors must be of the same length") + return self.__class__(x + y for (x, y) in zip(self, other)) + # Broadcasting addition + elif isinstance(other, numbers.Number): + return self.__class__(x + other for x in self) + return NotImplemented + + def __radd__(self, other): + """See docstring for .__add__().""" + # As both vector and broadcasting addition are commutative, + # we dispatch to .__add__(). + return self + other + + def __sub__(self, other): + """Handle `self - other` and `other - self`. + + This may be either vector subtraction or broadcasting subtraction. + + Example Usage: + >>> Vector([7, 8, 9]) - Vector([1, 2, 3]) + Vector((6, 6, 6)) + + >>> Vector([1, 2, 3]) - 1 + Vector((0, 1, 2)) + + >>> 10 - Vector([1, 2, 3]) + Vector((9, 8, 7)) + """ + # As subtraction is the inverse of addition, + # we first dispatch to .__neg__() to invert the signs of + # all entries in other and then dispatch to .__add__(). + return self + (-other) + + def __rsub__(self, other): + """See docstring for .__sub__().""" + # Same comments as in .__sub__() apply + # with the roles of self and other swapped. + return (-self) + other + + def __mul__(self, other): + """Handle `self * other` and `other * self`. + + This may be either the dot product of two vectors or scalar multiplication. + + Example Usage: + >>> Vector([1, 2, 3]) * Vector([2, 3, 4]) + 14 + + >>> 2 * Vector([1, 2, 3]) + Vector((2.0, 4.0, 6.0)) + + >>> Vector([1, 2, 3]) * 3 + Vector((3.0, 6.0, 9.0)) + """ + # Dot product + if isinstance(other, self.__class__): + if len(self) != len(other): + raise ValueError("vectors must be of the same length") + return sum(x * y for (x, y) in zip(self, other)) + # Scalar multiplication + elif isinstance(other, numbers.Number): + return self.__class__(x * other for x in self) + return NotImplemented + + def __rmul__(self, other): + """See docstring for .__mul__().""" + # As both dot product and scalar multiplication are commutative, + # we dispatch to .__mul__(). + return self * other + + def __truediv__(self, other): + """Handle `self / other`. + + Divide a Vector by a scalar. + + Example Usage: + >>> Vector([9, 6, 12]) / 3 + Vector((3.0, 2.0, 4.0)) + """ + # As scalar division division is the same as multiplication + # with the inverse, we dispatch to .__mul__(). + if isinstance(other, numbers.Number): + return self * (1 / other) + return NotImplemented + + def __eq__(self, other): + """Handle `self == other`. + + Compare two Vectors for equality. + + Example Usage: + >>> Vector([1, 2, 3]) == Vector([1, 2, 3]) + True + + >>> Vector([1, 2, 3]) == Vector([4, 5, 6]) + False + """ + if isinstance(other, self.__class__): + if len(self) != len(other): + raise ValueError("vectors must be of the same length") + for x, y in zip(self, other): + if abs(x - y) > self.zero_threshold: + return False # exit early if two corresponding entries differ + return True + return NotImplemented + + def __pos__(self): + """Handle `+self`. + + This is simply an identity operator returning the Vector itself. + """ + return self + + def __neg__(self): + """Handle `-self`. + + Negate all entries of a Vector. + """ + return self.__class__(-x for x in self) + + def __abs__(self): + """The Euclidean norm of a vector.""" + return utils.norm(self) # use the norm() function shared with the Matrix class + + def __bool__(self): + """A Vector is truthy if its Euclidean norm is strictly positive.""" + return bool(abs(self)) + + def __float__(self): + """Cast a Vector as a scalar. + + Returns: + scalar (float) + + Raises: + RuntimeError: if the Vector has more than one entry + """ + if len(self) != 1: + raise RuntimeError("vector must have exactly one entry to become a scalar") + return self[0] + + def as_matrix(self, *, column=True): + """Get a Matrix representation of a Vector. + + Args: + column (bool): if the vector is interpreted as a + column vector or a row vector; defaults to True + + Returns: + matrix (Matrix) + """ + if column: + return Matrix([x] for x in self) + return Matrix([(x for x in self)])