Skip to content

Instantly share code, notes, and snippets.

@mariogeiger
Created January 23, 2023 22:50
Show Gist options
  • Save mariogeiger/c93deddb401f9b5fc45c318cac3cfcc8 to your computer and use it in GitHub Desktop.
Save mariogeiger/c93deddb401f9b5fc45c318cac3cfcc8 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"id": "adbe2e21",
"metadata": {
"id": "adbe2e21"
},
"source": [
"# Introduction to Groups\n",
"### In this notebook, we will implement functions for testing matrix representations of groups.\n",
"\n",
"Learning Goals:\n",
"1. Understand the requirements for a group.\n",
"2. Test if a set of matrices satisfy the requirements for a group.\n",
"3. Generate a group from a subset of elements.\n",
"3. Compute the multiplication table for a group."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "c03ee812",
"metadata": {
"id": "c03ee812",
"outputId": "c195c0f7-4da1-4b62-ad33-e8fc886fb146"
},
"outputs": [],
"source": [
"import itertools\n",
"from collections import defaultdict\n",
"\n",
"import matplotlib.pyplot as plt\n",
"import numpy as np"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "b3f8daae",
"metadata": {
"id": "b3f8daae"
},
"source": [
"## A group is a set decorated with a binary operations ($\\cdot$) that satisfy the following criteria\n",
"1. Associativity: for all $a, b, c$ in group $G$, $(a \\cdot b) \\cdot c = a \\cdot (b \\cdot c)$ \n",
"2. There exists a <u>unique</u> identity element $e$ such that for all $a$ in group G, $e \\cdot a$ = $a \\cdot e$ = $a$\n",
"3. For every $a$ in G, there exists an element $b$ such that $a \\cdot b = b \\cdot a = e$"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "84a1354c",
"metadata": {
"id": "84a1354c"
},
"outputs": [],
"source": [
"def permutation_group(n):\n",
" elements = []\n",
" for p in itertools.permutations(range(n)):\n",
" m = np.zeros((n, n))\n",
" m[range(n), p] = 1\n",
" elements.append(m)\n",
" return np.stack(elements, axis=0)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "bc125b35",
"metadata": {
"id": "bc125b35"
},
"outputs": [],
"source": [
"p2 = permutation_group(2)\n",
"p3 = permutation_group(3)\n",
"p4 = permutation_group(4)\n",
"p3_dup_id = np.concatenate([p3, np.eye(3)[np.newaxis]])\n",
"p3_dup_elem = np.concatenate([p3, p3[1][np.newaxis]])\n",
"p3_missing_id = p3[1:]\n",
"p3_missing_elem = p3[:-1]\n",
"# test_group(p3_dup_id)"
]
},
{
"cell_type": "code",
"execution_count": 35,
"id": "8d61dc5c",
"metadata": {
"id": "8d61dc5c"
},
"outputs": [],
"source": [
"def test_membership_index(test, members, tol=1e-6):\n",
" \"\"\"Determine if test matrix in member matrices and return indices of match.\n",
" Inputs:\n",
" test: np.array shape [d, d] or [m, d, d]\n",
" tol: float numerical tolerance \n",
" members: np.array shape [n, d, d]\n",
" Output:\n",
" If test is in member, returns index / indices that match. Otherwise empty list.\n",
" Hint: Use np.nonzero, np.all, and np.any. Be mindful of your axes!\n",
" \"\"\"\n",
" if test.ndim == members.ndim - 1:\n",
" test = test[np.newaxis]\n",
"\n",
" assert test.shape[1:] == members.shape[1:]\n",
" diff = test[np.newaxis, :] - members[:, np.newaxis] # Since we have floats checking close to zero is easiest\n",
" diff = diff.reshape(len(members), len(test), -1) # [members, test, :]\n",
" equal = np.all(np.abs(diff) < tol, axis=2) # [members, test] True if equal\n",
" return np.nonzero(equal)"
]
},
{
"cell_type": "code",
"execution_count": 36,
"id": "9f4f3d8d",
"metadata": {
"id": "9f4f3d8d"
},
"outputs": [],
"source": [
"# test_membership_index\n",
"assert np.equal(test_membership_index(p3, p3), np.arange(6).reshape(1, -1).repeat(2, axis=0)).all()\n",
"assert np.allclose(test_membership_index(p3, p3), np.arange(6).reshape(1, -1).repeat(2, axis=0))\n",
"assert np.equal(test_membership_index(np.arange(9).reshape(3, 3), p3), (np.array([]), np.array([]))).all()\n",
"assert np.allclose(test_membership_index(np.arange(9).reshape(3, 3), p3), (np.array([]), np.array([])))"
]
},
{
"cell_type": "code",
"execution_count": 38,
"id": "6f480169",
"metadata": {
"id": "6f480169"
},
"outputs": [],
"source": [
"def test_membership(test, members, tol=1e-6):\n",
" \"\"\"Determine if test matrix in member matrices and return True / False / ValueError for duplicates.\n",
" Inputs:\n",
" test: np.array shape [d, d]\n",
" tol: float numerical tolerance\n",
" members: np.array shape [n, d, d]\n",
" Output:\n",
" If len(test.shape) == 2, return True if match or False if no match\n",
" If len(test.shape) == 3, return list of True / False values\n",
" Hint: Remember to handle all cases!\n",
" \"\"\"\n",
" i, j = test_membership_index(test, members, tol=1e-6)\n",
"\n",
" if test.ndim == 2:\n",
" return len(i) > 0\n",
"\n",
" out = np.zeros(len(test), dtype=bool)\n",
" out[j] = True\n",
" return out\n"
]
},
{
"cell_type": "code",
"execution_count": 34,
"id": "a3a231ad",
"metadata": {
"id": "a3a231ad"
},
"outputs": [],
"source": [
"# test_membership\n",
"assert np.equal(test_membership(p3[::-1], p3), [True] * 6).all()\n",
"assert np.equal(test_membership(np.arange(9).reshape(3, 3), p3), False).all()"
]
},
{
"cell_type": "code",
"execution_count": 41,
"id": "d3ccdc56",
"metadata": {
"id": "d3ccdc56"
},
"outputs": [],
"source": [
"def generate_new_elements(matrices, max_recurse=10, tol=1e-6):\n",
" \"\"\"Generate new group elements from matrices (group representations)\n",
" Input:\n",
" matrices: np.array of shape [n, d, d] of known elements\n",
" max_recurse: maximum dept of recursion\n",
" Output:\n",
" new: np.array of shape [m, d, d] of new elements with shape [0, d, d] if no new element\n",
" \"\"\"\n",
" _, d, d2 = matrices.shape\n",
" assert d == d2\n",
" new = np.zeros((0, d, d))\n",
" if max_recurse == 0:\n",
" yield new\n",
" for i, m in enumerate(matrices):\n",
" new_elements = np.einsum(\"ij,djk->dik\", m, matrices[i:])\n",
" membership = test_membership(new_elements, matrices, tol)\n",
" # Any matrices not in original matrices (False) are new\n",
" new = new_elements[~membership]\n",
" if new.shape[0] != 0:\n",
" yield new\n",
" break\n",
" if new.shape[0] != 0:\n",
" for new in generate_new_elements(\n",
" np.concatenate([matrices, new], axis=0), max_recurse - 1, tol\n",
" ):\n",
" yield new\n",
" else:\n",
" yield new\n"
]
},
{
"cell_type": "code",
"execution_count": 42,
"id": "9b86a600",
"metadata": {
"id": "9b86a600"
},
"outputs": [],
"source": [
"# generate_new_elements\n",
"assert(np.allclose(np.concatenate([p for p in generate_new_elements(p3)]), np.empty([0, 3, 3])))\n",
"assert(np.allclose(np.concatenate([p for p in generate_new_elements(p3[:-1])]), p3[-1:]))\n",
"assert(np.allclose(np.concatenate([p for p in generate_new_elements(p3[:-2])]), p3[-2:]) or\n",
" np.allclose(np.concatenate([p for p in generate_new_elements(p3[:-2])]), p3[-2:][[1, 0]]))"
]
},
{
"cell_type": "code",
"execution_count": 43,
"id": "0cf52d97",
"metadata": {
"id": "0cf52d97"
},
"outputs": [],
"source": [
"def test_closed(matrices, tol=1e-6):\n",
" \"\"\"Tests if group is closed.\n",
" Input:\n",
" matrices: np.array of shape [n, d, d]\n",
" tol: float numerical tolerance\n",
" Output:\n",
" True if closed and False if not.\n",
" Hint: Use generate_new_elements.\n",
" \"\"\"\n",
" for new in generate_new_elements(matrices):\n",
" if new.shape[0] != 0:\n",
" return False\n",
" return True"
]
},
{
"cell_type": "code",
"execution_count": 44,
"id": "c9bddb9d",
"metadata": {
"id": "c9bddb9d"
},
"outputs": [],
"source": [
"# test_closed\n",
"assert(test_closed(p2))\n",
"assert(test_closed(p2[:-1])) # identity\n",
"assert(test_closed(p3))\n",
"assert(not test_closed(p3[:-1]))\n",
"assert(not test_closed(p3[:-2]))\n",
"assert(test_closed(p4))\n",
"assert(not test_closed(p4[:-1]))"
]
},
{
"cell_type": "code",
"execution_count": 63,
"id": "258823c0",
"metadata": {
"id": "258823c0"
},
"outputs": [],
"source": [
"def test_identity(matrices, tol=1e-6):\n",
" \"\"\"Tests if identity is present in matrices.\n",
" Input:\n",
" matrices: np.array of shape [n, d, d]\n",
" tol: float numerical tolerance\n",
" Output:\n",
" False if no identity,\n",
" (i, m) if identity is present where i is index and m is matrix,\n",
" raises ValueError if multiple identities.\n",
" \"\"\"\n",
" identity = []\n",
" for i, m in enumerate(matrices):\n",
" new_elements = np.einsum('ij,djk->dik', m, matrices)\n",
" if np.allclose(new_elements, matrices, rtol=tol):\n",
" identity.append((i, m))\n",
" if len(identity) == 0:\n",
" return False\n",
"\n",
" if len(identity) == 1:\n",
" return identity[0]\n",
"\n",
" raise ValueError(\"Multiple identities {}.\".format(ids))"
]
},
{
"cell_type": "code",
"execution_count": 64,
"id": "95dec2ea",
"metadata": {
"id": "95dec2ea"
},
"outputs": [],
"source": [
"assert(not test_identity(p3[1:]))\n",
"assert(test_identity(p3)[0] == 0)\n",
"assert(np.allclose(test_identity(p3)[1], np.eye(3)))"
]
},
{
"cell_type": "code",
"execution_count": 65,
"id": "aceb5a07",
"metadata": {
"id": "aceb5a07"
},
"outputs": [],
"source": [
"def test_inverses(matrices, tol=1e-6):\n",
" \"\"\"Tests inverses for matrices.\n",
" Input:\n",
" matrices: np.array of shape [n, d, d]\n",
" tol: float numerical tolerance\n",
" Output:\n",
" np.array of shape [n] if single inverse exist for all elements,\n",
" otherwise raises ValueError.\n",
" \"\"\"\n",
" if not test_identity(matrices):\n",
" raise ValueError(\"missing identity\")\n",
" i, identity = test_identity(matrices)\n",
" inverses = []\n",
" for i, m in enumerate(matrices):\n",
" new_elements = np.einsum('ij,djk->dik', m, matrices)\n",
" result = new_elements - identity\n",
" inv_index = np.nonzero(np.all(np.all(np.abs(result) < tol, axis=-1), axis=-1))[0]\n",
" if inv_index.shape[0] != 1:\n",
" raise ValueError(\"Number of inverses incorrect {} should be 1\".format(inv_index.shape[0]))\n",
" inverses.append(inv_index)\n",
" return np.concatenate(inverses, axis=0)"
]
},
{
"cell_type": "code",
"execution_count": 66,
"id": "5647a464",
"metadata": {
"id": "5647a464"
},
"outputs": [],
"source": [
"# test_inverses\n",
"assert(np.equal(test_inverses(p3), np.array([0, 1, 2, 4, 3, 5])).all())\n",
"assert(np.equal(test_inverses(np.eye(3).reshape(1, 3, 3)), np.array([0])).all())"
]
},
{
"cell_type": "code",
"execution_count": 67,
"id": "b92503bd",
"metadata": {
"id": "b92503bd"
},
"outputs": [],
"source": [
"def test_group(matrices, tol=1e-6):\n",
" \"\"\"Tests whether matrices for group representation.\n",
" Input:\n",
" matrices: np.array of shape [n, d, d]\n",
" tol: float numberical tolerance\n",
" Output:\n",
" True if group, False if not.\n",
" \"\"\"\n",
" # Test identity\n",
" try:\n",
" assert test_identity(matrices) \n",
" except:\n",
" print(\"Multiple or missing identity element(s).\")\n",
" return False\n",
" # Test for inverses (and duplicates)\n",
" try:\n",
" test_inverses(matrices, tol)\n",
" except:\n",
" print(\"Does not contain all inverses or duplicate elements.\")\n",
" return False\n",
" # Test closed\n",
" if not test_closed(matrices):\n",
" print(\"Not closed.\")\n",
" return False\n",
" print(\"Elements form a group!\")\n",
" return True "
]
},
{
"cell_type": "code",
"execution_count": 68,
"id": "4d14d7f2",
"metadata": {
"id": "4d14d7f2",
"outputId": "e15cbae9-5944-4554-8a14-403a427adf8a"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Elements form a group!\n",
"Multiple or missing identity element(s).\n",
"Does not contain all inverses or duplicate elements.\n",
"Multiple or missing identity element(s).\n",
"Not closed.\n"
]
}
],
"source": [
"# test_group\n",
"assert test_group(p3) == True\n",
"assert test_group(p3_dup_id) == False\n",
"assert test_group(p3_dup_elem) == False\n",
"assert test_group(p3_missing_id) == False\n",
"assert test_group(p3_missing_elem) == False"
]
},
{
"cell_type": "code",
"execution_count": 69,
"id": "dbd314b6",
"metadata": {
"id": "dbd314b6"
},
"outputs": [],
"source": [
"def make_multiplication_table(matrices, tol=1e-6):\n",
" \"\"\"Tests whether matrices for group representation.\n",
" Input:\n",
" matrices: np.array of shape [n, d, d]\n",
" tol: float numberical tolerance\n",
" Output:\n",
" Group multiplication table.\n",
" np.array of shape [n, n] where entries correspond to indices of first dim of matrices.\n",
" \"\"\"\n",
" n, d, d2 = matrices.shape\n",
" assert d == d2\n",
" mtables = np.einsum('nij,mjk->nmik', matrices, matrices)\n",
" result = mtables.reshape(1, n, n, d, d) - matrices.reshape(n, 1, 1, d, d)\n",
" indices = np.nonzero(np.all(np.all(np.abs(result) < tol, axis=-1), axis=-1))\n",
" indices = np.stack(indices)\n",
" table = np.zeros([n, n], dtype=np.int32)\n",
" table[indices[1], indices[2]] = indices[0]\n",
" return table"
]
},
{
"cell_type": "code",
"execution_count": 70,
"id": "50e695c7",
"metadata": {
"id": "50e695c7"
},
"outputs": [],
"source": [
"# make_multiplication_table\n",
"assert(np.equal(make_multiplication_table(p2), np.array([[0, 1], [1, 0]])).all())\n",
"assert(np.equal(make_multiplication_table(p3), np.array([[0, 1, 2, 3, 4, 5],\n",
" [1, 0, 3, 2, 5, 4],\n",
" [2, 4, 0, 5, 1, 3],\n",
" [3, 5, 1, 4, 0, 2],\n",
" [4, 2, 5, 0, 3, 1],\n",
" [5, 3, 4, 1, 2, 0]], dtype=np.int32)).all())"
]
},
{
"cell_type": "markdown",
"id": "0aae0f5c",
"metadata": {
"id": "0aae0f5c"
},
"source": [
"## Let's test to see if the following elements form a group"
]
},
{
"cell_type": "code",
"execution_count": 71,
"id": "86a231fb",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 129
},
"id": "86a231fb",
"outputId": "b98e643d-139c-4e94-de59-cd8e8b6841a7"
},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAgMAAAClCAYAAADBAf6NAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAAADUElEQVR4nO3Y0W3CMBRAUaiYgv/+s0TFBJ2yEyCWYArUKUhHaCQgVnLP+baUJ9mxrryfpmnaAQBZH6MHAADGEgMAECcGACBODABAnBgAgDgxAABxYgAA4sQAAMQd5i58/H6+c45FnI+n0SPkXR8/i3/z6+N78W++2uV+Gz3CU7bw7404u+5dXmHO2fUyAABxYgAA4sQAAMSJAQCIEwMAECcGACBODABAnBgAgDgxAABxYgAA4sQAAMSJAQCIEwMAECcGACBODABAnBgAgDgxAABxYgAA4sQAAMSJAQCIEwMAECcGACBODABAnBgAgDgxAABxYgAA4sQAAMSJAQCIEwMAECcGACBODABAnBgAgDgxAABxYgAA4sQAAMSJAQCIEwMAECcGACBODABAnBgAgDgxAABxYgAA4sQAAMSJAQCIEwMAECcGACBODABAnBgAgLjD3IXn4+mNYyzjcr+NHuEpW9iDEda+77udva+y7+Nt4f6Yw8sAAMSJAQCIEwMAECcGACBODABAnBgAgDgxAABxYgAA4sQAAMSJAQCIEwMAECcGACBODABAnBgAgDgxAABxYgAA4sQAAMSJAQCIEwMAECcGACBODABAnBgAgDgxAABxYgAA4sQAAMSJAQCIEwMAECcGACBODABAnBgAgDgxAABxYgAA4sQAAMSJAQCIEwMAECcGACBODABAnBgAgDgxAABxYgAA4sQAAMSJAQCIEwMAECcGACBODABAnBgAgDgxAABxh9EDLOl8PI0e4SmX+230CKu09n3fAme3a+17v4X74/r4f42XAQCIEwMAECcGACBODABAnBgAgDgxAABxYgAA4sQAAMSJAQCIEwMAECcGACBODABAnBgAgDgxAABxYgAA4sQAAMSJAQCIEwMAECcGACBODABAnBgAgDgxAABxYgAA4sQAAMSJAQCIEwMAECcGACBODABAnBgAgDgxAABxYgAA4sQAAMSJAQCIEwMAECcGACBODABAnBgAgDgxAABxYgAA4sQAAMSJAQCIEwMAECcGACBODABAnBgAgDgxAABxYgAA4sQAAMTtp2maRg8BAIzjZQAA4sQAAMSJAQCIEwMAECcGACBODABAnBgAgDgxAABxYgAA4v4AE1ktkag5/8kAAAAASUVORK5CYII=",
"text/plain": [
"<Figure size 640x480 with 3 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"m1 = np.eye(3)\n",
"m2 = m1.copy()\n",
"m3 = m2.copy()\n",
"m2[:,0:2] = m2[:,[1, 0]]\n",
"m3[:,1:] = m3[:,[2, 1]]\n",
"m1, m2, m3\n",
"fig, ax = plt.subplots(nrows=1, ncols=3)\n",
"for a, m in zip(ax, [m1, m2, m3]):\n",
" a.imshow(m)\n",
" a.axis('off')"
]
},
{
"cell_type": "code",
"execution_count": 72,
"id": "68f464cb",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 129
},
"id": "68f464cb",
"outputId": "aaefd620-e80c-4b20-cf69-e94711862337"
},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAgMAAAClCAYAAADBAf6NAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAAADWElEQVR4nO3Y0WkCQRRA0YlYRLAKmwhWkCpTgdiE//m3DDclZInosLnnfD/YBzMLl3lblmUZAEDWbvYCAMBcYgAA4sQAAMSJAQCIEwMAECcGACBODABAnBgAgLj92sGP3ecz92CF8+06e4WH7d6/X/5Nd3c+d/dv/sPd3frZnw7H2Ss87HL/+nXGywAAxIkBAIgTAwAQJwYAIE4MAECcGACAODEAAHFiAADixAAAxIkBAIgTAwAQJwYAIE4MAECcGACAODEAAHFiAADixAAAxIkBAIgTAwAQJwYAIE4MAECcGACAODEAAHFiAADixAAAxIkBAIgTAwAQJwYAIE4MAECcGACAODEAAHFiAADixAAAxIkBAIgTAwAQJwYAIE4MAECcGACAODEAAHFiAADixAAAxIkBAIgTAwAQJwYAIE4MAECcGACAODEAAHFiAADi9msHz7frE9d4jdPhOHuFh2x9/zHGuNxnb7BNW///3N2urZ/91v+9tbwMAECcGACAODEAAHFiAADixAAAxIkBAIgTAwAQJwYAIE4MAECcGACAODEAAHFiAADixAAAxIkBAIgTAwAQJwYAIE4MAECcGACAODEAAHFiAADixAAAxIkBAIgTAwAQJwYAIE4MAECcGACAODEAAHFiAADixAAAxIkBAIgTAwAQJwYAIE4MAECcGACAODEAAHFiAADixAAAxIkBAIgTAwAQJwYAIE4MAECcGACAODEAAHFiAADixAAAxIkBAIgTAwAQt187eDocn7jGa5xv19krPOQ/nMEMWz/3MZx9lbs739b3H2OMy/33GS8DABAnBgAgTgwAQJwYAIA4MQAAcWIAAOLEAADEiQEAiBMDABAnBgAgTgwAQJwYAIA4MQAAcWIAAOLEAADEiQEAiBMDABAnBgAgTgwAQJwYAIA4MQAAcWIAAOLEAADEiQEAiBMDABAnBgAgTgwAQJwYAIA4MQAAcWIAAOLEAADEiQEAiBMDABAnBgAgTgwAQJwYAIA4MQAAcWIAAOLEAADEiQEAiBMDABAnBgAgTgwAQJwYAIA4MQAAcWIAAOLEAADEiQEAiHtblmWZvQQAMI+XAQCIEwMAECcGACBODABAnBgAgDgxAABxYgAA4sQAAMSJAQCI+wErnjAlcICLNQAAAABJRU5ErkJggg==",
"text/plain": [
"<Figure size 640x480 with 3 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"new_matrices = np.concatenate(list(generate_new_elements(np.stack([m1, m2, m3], axis=0))), axis=0)\n",
"n, _, _ = new_matrices.shape\n",
"fig, ax = plt.subplots(nrows=1, ncols=3)\n",
"for a, m in zip(ax, new_matrices):\n",
" a.imshow(m)\n",
" a.axis('off')"
]
},
{
"cell_type": "code",
"execution_count": 73,
"id": "8jsJbzqFwb2t",
"metadata": {
"id": "8jsJbzqFwb2t"
},
"outputs": [],
"source": [
"all_elements = np.concatenate([np.stack([m1, m2, m3], axis=0), new_matrices], axis=0)"
]
},
{
"cell_type": "code",
"execution_count": 74,
"id": "03f20e6e",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "03f20e6e",
"outputId": "cc47d04c-b0c9-4f73-94f9-fb8fb2b83dc1"
},
"outputs": [
{
"data": {
"text/plain": [
"array([0, 1, 2, 5, 4, 3])"
]
},
"execution_count": 74,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"test_inverses(all_elements)"
]
},
{
"cell_type": "code",
"execution_count": 75,
"id": "7d47c17d",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "7d47c17d",
"outputId": "7068061c-fde9-4b13-a7ed-ea915e92a8b8"
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 75,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"test_closed(all_elements)"
]
},
{
"cell_type": "code",
"execution_count": 76,
"id": "a7fb4ac2",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 79
},
"id": "a7fb4ac2",
"outputId": "3c9889d1-085c-470f-eabe-fabf08eeb98a"
},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAgQAAABaCAYAAADHGU44AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAAACLUlEQVR4nO3YsY3bMBiA0e8MDxG4T+8lAk+QKTOB4SXcpzcyhZUqRYoDDkp+WMK9V0sESZPGB70ty7IEAHxqh1dPAAB4PUEAAAgCAEAQAAAJAgAgQQAAJAgAgAQBAFAdP/rg89fXyXl0OZ1Hx590e/5Y9d63w/f/PJO/XR/3sbGnf6+1e+qcvm+r53TS5B2oOnz5ueo9e/q+re7pZ/g/9YUAABAEAIAgAAASBABAggAASBAAAAkCACBBAAAkCACABAEAkCAAABIEAECCAABIEAAACQIAIEEAACQIAIAEAQCQIAAAEgQAQIIAAEgQAAAJAgCgOn70wcvpPDiNuj7uY2NPz32tyTXXdtc9ac9rnj4Pa+35nE6fh9tzdPjV9vx/utU9nVz3Vu6+LwQAgCAAAAQBAJAgAAASBABAggAASBAAAAkCACBBAAAkCACABAEAkCAAABIEAECCAABIEAAACQIAIEEAACQIAIAEAQCQIAAAEgQAQIIAAKiOr57AH5fTeWzs6+M+Nva/mFzztK3u6bTJdU+fh9tz3XvT89rznq41fX+2uu5Je97Trdx9XwgAAEEAAAgCACBBAAAkCACABAEAkCAAABIEAECCAABIEAAACQIAIEEAACQIAIAEAQCQIAAAEgQAQIIAAEgQAAAJAgAgQQAAJAgAgAQBAJAgAACqt2VZlldPAgB4LV8IAABBAAAIAgAgQQAAJAgAgAQBAJAgAAASBABAggAAqH4DHlZT2RCtrLgAAAAASUVORK5CYII=",
"text/plain": [
"<Figure size 640x480 with 6 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"fig, ax = plt.subplots(nrows=1, ncols=all_elements.shape[0])\n",
"for (i, element) in enumerate(all_elements):\n",
" ax[i].imshow(element)\n",
" ax[i].axis('off')"
]
},
{
"cell_type": "code",
"execution_count": 77,
"id": "f23c65d6",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 283
},
"id": "f23c65d6",
"outputId": "b06dee8e-d0ed-4b25-a625-0eccc029a296"
},
"outputs": [
{
"data": {
"text/plain": [
"<matplotlib.image.AxesImage at 0x10ec9b040>"
]
},
"execution_count": 77,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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",
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Note that multiplication table demonstrates the rearrangement theorem\n",
"# Multiplication by a group element to all elements, contains each element only once\n",
"table = make_multiplication_table(all_elements)\n",
"plt.imshow(table)"
]
},
{
"cell_type": "code",
"execution_count": 78,
"id": "9de71269",
"metadata": {
"id": "9de71269"
},
"outputs": [],
"source": [
"import itertools\n",
"from itertools import combinations"
]
},
{
"cell_type": "code",
"execution_count": 79,
"id": "e3594355",
"metadata": {
"id": "e3594355"
},
"outputs": [],
"source": [
"from functools import reduce\n",
"\n",
"def factors(n): \n",
" return set(reduce(list.__add__,\n",
" ([i, n//i] for i in range(1, int(n**0.5) + 1) if n % i == 0)))"
]
},
{
"cell_type": "code",
"execution_count": 80,
"id": "742066ea",
"metadata": {
"id": "742066ea"
},
"outputs": [],
"source": [
"def find_subgroups(group):\n",
" \"\"\"Find all subgroups of group.\n",
" Input:\n",
" group: np.array of shape [n, d, d]\n",
" Output:\n",
" Yields tuples of elements that form subgroup.\n",
" \"\"\"\n",
" n, d, d2 = group.shape\n",
" table = make_multiplication_table(group)\n",
" assert d == d2\n",
" for f in factors(n):\n",
" for c in combinations(range(n), f):\n",
" subtable = table[np.array(list(c))][:, np.array(list(c))] \n",
" if set(c) == set(subtable.reshape(-1)):\n",
" yield c"
]
},
{
"cell_type": "code",
"execution_count": 81,
"id": "df2bda0d",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "df2bda0d",
"outputId": "b754832a-7c12-449d-ca6a-232ef436ef12"
},
"outputs": [
{
"data": {
"text/plain": [
"{(0,), (0, 1), (0, 1, 2, 3, 4, 5), (0, 2), (0, 3, 5), (0, 4)}"
]
},
"execution_count": 81,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"set(list(find_subgroups(all_elements)))"
]
},
{
"cell_type": "code",
"execution_count": 82,
"id": "f77de2cb",
"metadata": {
"id": "f77de2cb",
"outputId": "d319fa5f-fca5-41e0-f042-bbe8849ad828"
},
"outputs": [
{
"data": {
"text/plain": [
"{(0,), (0, 1, 2)}"
]
},
"execution_count": 82,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"set(list(find_subgroups(p3[[0, 3, 4]])))"
]
},
{
"cell_type": "code",
"execution_count": 83,
"id": "7d8859e3",
"metadata": {
"id": "7d8859e3"
},
"outputs": [],
"source": [
"def right_coset(subgroup, group, tol=1e-6):\n",
" table = make_multiplication_table(group)\n",
" subgroup_indices = test_membership_index(subgroup, group, tol=1e-6)[0]\n",
" sets = set()\n",
" for i in table[subgroup_indices].T:\n",
" sets.add(frozenset(i))\n",
" return set(sets)\n",
"\n",
"def left_coset(subgroup, group, tol=1e-6):\n",
" table = make_multiplication_table(group)\n",
" subgroup_indices = test_membership_index(subgroup, group, tol=1e-6)[0]\n",
" sets = set()\n",
" for i in table[:, subgroup_indices]:\n",
" sets.add(frozenset(i))\n",
" return set(sets)"
]
},
{
"cell_type": "code",
"execution_count": 84,
"id": "277e5e28",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "277e5e28",
"outputId": "a3eb586b-f1b8-4ade-dfbe-5d0d4980ce5b"
},
"outputs": [
{
"data": {
"text/plain": [
"{frozenset({4, 5}), frozenset({0, 1}), frozenset({2, 3})}"
]
},
"execution_count": 84,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"right_coset(all_elements[[0,1]], all_elements)"
]
},
{
"cell_type": "code",
"execution_count": 85,
"id": "db97c8bb",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "db97c8bb",
"outputId": "e8600a6e-aea5-4ded-92a2-0171f2a31d92"
},
"outputs": [
{
"data": {
"text/plain": [
"{frozenset({2, 4}),\n",
" frozenset({1, 4}),\n",
" frozenset({3, 5}),\n",
" frozenset({1, 2}),\n",
" frozenset({0, 3}),\n",
" frozenset({0, 5})}"
]
},
"execution_count": 85,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"right_coset(all_elements[[0,3]], all_elements)"
]
},
{
"cell_type": "code",
"execution_count": 86,
"id": "1f0a5f13",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "1f0a5f13",
"outputId": "983d9fc2-7a75-4657-9ed5-c02da85a7a26"
},
"outputs": [
{
"data": {
"text/plain": [
"{frozenset({2, 4}),\n",
" frozenset({1, 4}),\n",
" frozenset({3, 5}),\n",
" frozenset({1, 2}),\n",
" frozenset({0, 3}),\n",
" frozenset({0, 5})}"
]
},
"execution_count": 86,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"left_coset(all_elements[[0,3]], all_elements)"
]
},
{
"cell_type": "markdown",
"id": "IXjZqPnuxMev",
"metadata": {
"id": "IXjZqPnuxMev"
},
"source": [
"## Conjugation and Class"
]
},
{
"cell_type": "code",
"execution_count": 87,
"id": "8824e436",
"metadata": {
"id": "8824e436"
},
"outputs": [],
"source": [
"def conjugacy(group):\n",
" n, d, d2 = group.shape\n",
" assert d == d2\n",
" sets = set()\n",
" inverses = test_inverses(group)\n",
" table = make_multiplication_table(group)\n",
" for i in range(n):\n",
" sets.add(frozenset(table[inverses, table[i]]))\n",
" return sets"
]
},
{
"cell_type": "code",
"execution_count": 88,
"id": "S-CvQYmFw7Wv",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "S-CvQYmFw7Wv",
"outputId": "4a19f6af-b145-4f43-be61-d005e864b4a7"
},
"outputs": [
{
"data": {
"text/plain": [
"[(0,), (0, 1), (0, 2), (0, 4), (0, 3, 5), (0, 1, 2, 3, 4, 5)]"
]
},
"execution_count": 88,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"list(find_subgroups(all_elements))"
]
},
{
"cell_type": "code",
"execution_count": 89,
"id": "0f7f7199",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "0f7f7199",
"outputId": "2c2caf94-cd26-4cd4-fce8-ecd683f995eb"
},
"outputs": [
{
"data": {
"text/plain": [
"{frozenset({1, 2, 4}), frozenset({0}), frozenset({3, 5})}"
]
},
"execution_count": 89,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"conjugacy(all_elements)"
]
},
{
"cell_type": "code",
"execution_count": 90,
"id": "jxy8uHqsy0pP",
"metadata": {
"id": "jxy8uHqsy0pP"
},
"outputs": [],
"source": [
"def selfconjugate_subgroups(group):\n",
" id = test_identity(group)\n",
" inv = test_inverses(group)\n",
" subgroups = list(find_subgroups(group))\n",
" conj = list(conjugacy(all_elements))\n",
" for s in subgroups:\n",
" conj_set = set()\n",
" for e in s:\n",
" for c in conj:\n",
" if e in c:\n",
" conj_set.update(set(c))\n",
" if conj_set == set(s):\n",
" yield s"
]
},
{
"cell_type": "code",
"execution_count": 91,
"id": "g6nfLGULz49e",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "g6nfLGULz49e",
"outputId": "c7ba6f93-a242-42de-c050-79a6b3246352"
},
"outputs": [
{
"data": {
"text/plain": [
"[(0,), (0, 3, 5), (0, 1, 2, 3, 4, 5)]"
]
},
"execution_count": 91,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"list(selfconjugate_subgroups(all_elements))"
]
},
{
"cell_type": "markdown",
"id": "SShl8C49vT88",
"metadata": {
"id": "SShl8C49vT88"
},
"source": [
"## Factor Group"
]
},
{
"cell_type": "code",
"execution_count": 92,
"id": "35f5c8fd",
"metadata": {
"id": "35f5c8fd",
"outputId": "3ba95fb5-fb00-480c-8465-c3148595949f"
},
"outputs": [
{
"data": {
"text/plain": [
"{frozenset({1, 2, 4}), frozenset({0, 3, 5})}"
]
},
"execution_count": 92,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"right_coset(all_elements[[0,3,5]], all_elements)"
]
},
{
"cell_type": "code",
"execution_count": 93,
"id": "i0bXVJ5K3ApC",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "i0bXVJ5K3ApC",
"outputId": "b6bd099f-82db-42a8-a768-a0c2fae0f5ef"
},
"outputs": [
{
"data": {
"text/plain": [
"array([{1, 2}, {3, 4}], dtype=object)"
]
},
"execution_count": 93,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.array([set([1, 2]), set([3, 4])])"
]
},
{
"cell_type": "code",
"execution_count": 94,
"id": "wvmGmHb22nOl",
"metadata": {
"id": "wvmGmHb22nOl"
},
"outputs": [],
"source": [
"def factor_group(selfconj_sub, group):\n",
" rc = right_coset(all_elements[[0,3,5]], all_elements)\n",
" table = make_multiplication_table(group)\n",
" new_table = np.empty([len(rc), len(rc)], dtype=set)\n",
" int_table = np.empty([len(rc), len(rc)], dtype=np.int32)\n",
" for i,r in enumerate(list(rc)):\n",
" for j,q in enumerate(list(rc)):\n",
" # print(i, r, j, q)\n",
" # print(table[list(r), list(q)])\n",
" sub_table = set(\n",
" table[list(r), list(q)].reshape(-1).tolist()\n",
" )\n",
" new_table[i, j] = sub_table\n",
" which_coset = np.nonzero([sub_table.issubset(s) for s in rc])[0]\n",
" int_table[i, j] = which_coset\n",
"\n",
" return rc, new_table, int_table"
]
},
{
"cell_type": "code",
"execution_count": 95,
"id": "Bd2po1vM3iJq",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Bd2po1vM3iJq",
"outputId": "c819c0ec-668d-4d48-9027-eefe953b2a3e"
},
"outputs": [
{
"data": {
"text/plain": [
"({frozenset({1, 2, 4}), frozenset({0, 3, 5})},\n",
" array([[{0}, {1, 2, 4}],\n",
" [{1}, {0, 3, 5}]], dtype=object),\n",
" array([[1, 0],\n",
" [0, 1]], dtype=int32))"
]
},
"execution_count": 95,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"factor_group(all_elements[[0,3,5]], all_elements)"
]
},
{
"cell_type": "markdown",
"id": "718e45d8",
"metadata": {
"id": "718e45d8"
},
"source": [
"## Chocolates and Generators\n",
"This is based on a puzzle Mario and I were told once, I don't think this is an exact reproduction of the puzzle but it goes something like this.\n",
"A demon challenges you to a game. There are n coins that are in a random configuration of heads up and down. You win the game if all the coins are heads up. You are allowed to take the following actions: 1) Flip all the coins at once and 2) The demon flips a single coin at random (this is the part that I think departs from the game -- I think the demon is suppose to actively try to make you not win -- but i think in that case then you can't win for n > 2). Describe an deterministic algorithm that is guaranteed to result in winning."
]
},
{
"cell_type": "code",
"execution_count": 96,
"id": "1a8a1f78",
"metadata": {
"id": "1a8a1f78"
},
"outputs": [],
"source": [
"n = 4\n",
"flip_all = -np.eye(n)\n",
"flip_one = np.repeat(np.eye(n)[np.newaxis,], n, axis=0)\n",
"for i in range(n):\n",
" flip_one[i, i, i] = -1"
]
},
{
"cell_type": "code",
"execution_count": 97,
"id": "2e103f78",
"metadata": {
"id": "2e103f78"
},
"outputs": [],
"source": [
"new = np.concatenate(list(generate_new_elements(flip_one, max_recurse=1000)), axis=0)"
]
},
{
"cell_type": "code",
"execution_count": 98,
"id": "630705e5",
"metadata": {
"id": "630705e5"
},
"outputs": [],
"source": [
"all_elements = np.concatenate([flip_one, new])"
]
},
{
"cell_type": "code",
"execution_count": 99,
"id": "b058c0f4",
"metadata": {
"id": "b058c0f4",
"outputId": "ae187a8b-efa7-48a9-9a68-e112e9daacca"
},
"outputs": [
{
"data": {
"text/plain": [
"(16, 4, 4)"
]
},
"execution_count": 99,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"all_elements.shape"
]
},
{
"cell_type": "code",
"execution_count": 100,
"id": "d5e9409b",
"metadata": {
"id": "d5e9409b"
},
"outputs": [],
"source": [
"def rand_state(n, seed=42):\n",
"# np.random.seed(seed)\n",
" return np.random.randint(0, 2, size=n)*2 - 1"
]
},
{
"cell_type": "code",
"execution_count": 101,
"id": "4670a242",
"metadata": {
"id": "4670a242"
},
"outputs": [],
"source": [
"def test_win(x):\n",
" return np.allclose(x, np.ones_like(x))"
]
},
{
"cell_type": "code",
"execution_count": 102,
"id": "a984279d",
"metadata": {
"id": "a984279d"
},
"outputs": [],
"source": [
"def flipall(x):\n",
" return -1 * x\n",
"\n",
"def flipone(x):\n",
" n = len(x)\n",
" i = np.random.randint(0, n)\n",
" y = x.copy()\n",
" y[i] = -1 * x[i]\n",
" return y"
]
},
{
"cell_type": "code",
"execution_count": 103,
"id": "17ea81ca",
"metadata": {
"id": "17ea81ca"
},
"outputs": [],
"source": [
"def play(x, i=0, max_recurse=1000):\n",
" if i > max_recurse:\n",
" return False\n",
" x = flipone(x)\n",
"# print(x)\n",
" i += 1\n",
" if test_win(x):\n",
" return i\n",
" x = flipall(x)\n",
"# print(x)\n",
" i += 1\n",
" if test_win(x):\n",
" return i\n",
" return play(x, i=i, max_recurse=max_recurse)\n",
" "
]
},
{
"cell_type": "code",
"execution_count": 104,
"id": "d487f637",
"metadata": {
"id": "d487f637",
"outputId": "f9c0b831-eb72-42d2-8c20-e9ba8622269b"
},
"outputs": [
{
"data": {
"text/plain": [
"23"
]
},
"execution_count": 104,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"play(rand_state(6))"
]
},
{
"cell_type": "code",
"execution_count": 105,
"id": "4ddf4210",
"metadata": {
"id": "4ddf4210",
"outputId": "48a61a60-bf13-4655-ae2c-d114fbba7559"
},
"outputs": [
{
"data": {
"text/plain": [
"array([-1, 1, -1, 1])"
]
},
"execution_count": 105,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"flipone(np.array([1, 1, -1, 1]))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e0f9ffc2",
"metadata": {
"id": "e0f9ffc2"
},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "264c53a0",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"colab": {
"provenance": []
},
"gpuClass": "standard",
"kernelspec": {
"display_name": "base",
"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.10.9"
},
"vscode": {
"interpreter": {
"hash": "f26faf9d33dc8b83cd077f62f5d9010e5bc51611e479f12b96223e2da63ba699"
}
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment