{"id":44947781,"url":"https://github.com/phoenixsmaug/reverse-gol","last_synced_at":"2026-02-18T10:01:04.591Z","repository":{"id":261461013,"uuid":"884347550","full_name":"PhoenixSmaug/reverse-gol","owner":"PhoenixSmaug","description":"A backwards Game of Life solver with Integer Programming and SAT Solving","archived":false,"fork":false,"pushed_at":"2024-11-14T12:57:42.000Z","size":30,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-11-16T02:33:34.978Z","etag":null,"topics":["game-of-life","integer-programming","or-tools","pseudo-boolean","sat"],"latest_commit_sha":null,"homepage":"","language":"Julia","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/PhoenixSmaug.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-11-06T15:33:05.000Z","updated_at":"2024-11-14T12:57:46.000Z","dependencies_parsed_at":"2024-11-06T17:47:39.059Z","dependency_job_id":"1363e2be-3b3f-4f4d-aeeb-a500febaa90d","html_url":"https://github.com/PhoenixSmaug/reverse-gol","commit_stats":null,"previous_names":["phoenixsmaug/reverse-gol"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/PhoenixSmaug/reverse-gol","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhoenixSmaug%2Freverse-gol","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhoenixSmaug%2Freverse-gol/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhoenixSmaug%2Freverse-gol/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhoenixSmaug%2Freverse-gol/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PhoenixSmaug","download_url":"https://codeload.github.com/PhoenixSmaug/reverse-gol/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhoenixSmaug%2Freverse-gol/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29575343,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-18T08:38:15.585Z","status":"ssl_error","status_checked_at":"2026-02-18T08:38:14.917Z","response_time":162,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["game-of-life","integer-programming","or-tools","pseudo-boolean","sat"],"created_at":"2026-02-18T10:00:53.691Z","updated_at":"2026-02-18T10:01:04.571Z","avatar_url":"https://github.com/PhoenixSmaug.png","language":"Julia","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Reversed Game of Life with Integer Programming and SAT Solving\n\nConway's famous [Game of Life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life) is a cellular automaton with the following rules, where $N$ is the number of living neighbours:\n\n```math\nx_{t+1} = \\begin{cases}\n1, \u0026 \\text{if } x_t = 1 \\text{ and } (N = 2 \\text{ or } N = 3) \\quad \\text{(survival)} \\\\1, \u0026 \\text{if } x_t = 0 \\text{ and } N = 3 \\quad \\text{(birth)} \\\\0, \u0026 \\text{otherwise} \\quad \\text{(death)}\n\\end{cases}\n```\n\n## Base Model\n\nTo model this as a system of linear inequalities suitable for integer programming and pseudo-Boolean SAT solving, we rewrite the rules into a single condition:\n```math\nx_{t+1} = 1 \\, \\iff \\, 5 \\leq x_t + 2 N \\leq 7\n```\n\nIt can be quickly verified that both systems are equivalent, but the latter is much easier to translate into pure linear inequalities.\n\n### Forward Direction\n\nWe start by encoding that $x_{t+1} = 1 \\implies 5 \\leq x_t + 2 N \\leq 7$ using the following two inequalities:\n```math\n5 x_{t + 1} \\leq x_t + 2 N \\leq 7 + 10 \\cdot (1 - x_{t + 1}) \n```\n\nSo for $x_{t + 1} = 1$ we get our inequality from before and for $x_{t + 1} = 0$ we get $0 \\leq x_t + 2 N \\leq 17$, which is always fulfilled.\n\n### Backwards Direction\n\nNow we encode $x_{t+1} = 1 \\impliedby 5 \\leq x_t + 2 N \\leq 7$ by the contraposition $x_{t+1} = 0 \\implies x_t + 2 N \\leq 4 \\text{ or } x_t + 2 N \\geq 8$. To encode the 'or', we introduce two auxillary binary variables, $m_t$ and $n_t$.\n```math\nx_t + 2 N \\geq 8 n_t \\quad \\quad x_t + 2 N \\leq 4 + 13 \\cdot (1 - m_t) \\quad \\quad 1 - x_t \\leq m_t + n_t\n```\nIf $n_t = 1$, the first inequality ensures $x_t + 2 N \\geq 8$ and if $m_t = 1$, the first inequality ensures $x_t + 2 N \\leq 4$. And finally, the third inequality ensures that if \n$x_{t+1} = 0$ then $m_t = 1$ or $n_t = 1$, i.e. $\\neg(5 \\leq x_t + 2 N \\leq 7)$ holds. If $x_{t + 1} = 1$ one can simply choose $n_t = m_t = 0$ and all three inequalities are fulfilled without restricting the values of $x_t$ and $N$.\n\n## Additions\n\nThis completes the model construction, which is implemented as `modelGOL(width, height, timesteps)`, where width and height specify the bounding box. To ensure that our simulated cells always stay within the bounds, we additionally force all cells on the boundary to be dead for all timesteps.\n\n### Reversed Search\n\nTo run Game of Life backwards, we simply restrict $x_{end}$ as desired. If we want to have a board which becomes Donald Knuths example $7 \\times 15$ board spelling out \"LIFE\" after 3 iterations, we can construct the model with `reversePlay(width, height, timesteps, cells)` and find a solution in 4.8s using the pseudo-Boolean SAT solver [Exact](https://gitlab.com/nonfiction-software/exact):\n\n```math\n\\begin{matrix}\n\\text{Time } t=1 \u0026 \\quad \u0026 \\text{Time } t=2 \u0026 \\quad \u0026 \\text{Time } t=3 \u0026 \\quad \u0026 \\text{Time } t=4 \\\\\n\\begin{bmatrix}\n. \u0026 . \u0026 . \u0026 X \u0026 . \u0026 . \u0026 . \u0026 X \u0026 . \u0026 . \u0026 . \u0026 X \u0026 . \u0026 X \u0026 . \\\n. \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 X \u0026 . \u0026 X \u0026 . \u0026 . \u0026 X \\\nX \u0026 X \u0026 X \u0026 . \u0026 X \u0026 . \u0026 . \u0026 X \u0026 X \u0026 . \u0026 . \u0026 . \u0026 X \u0026 X \u0026 . \\\nX \u0026 X \u0026 . \u0026 . \u0026 X \u0026 X \u0026 . \u0026 X \u0026 . \u0026 X \u0026 . \u0026 . \u0026 . \u0026 X \u0026 X \\\n. \u0026 . \u0026 X \u0026 . \u0026 X \u0026 . \u0026 X \u0026 . \u0026 X \u0026 . \u0026 X \u0026 . \u0026 X \u0026 . \u0026 . \\\n. \u0026 . \u0026 X \u0026 . \u0026 X \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 X \u0026 X \u0026 . \u0026 X \\\nX \u0026 . \u0026 X \u0026 . \u0026 X \u0026 . \u0026 X \u0026 . \u0026 X \u0026 X \u0026 . \u0026 . \u0026 . \u0026 X \u0026 . \\\n\\end{bmatrix}\n\u0026 \\rightarrow \u0026\n\\begin{bmatrix}\n. \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 X \u0026 . \u0026 X \u0026 . \u0026 . \\\n. \u0026 X \u0026 X \u0026 X \u0026 . \u0026 . \u0026 . \u0026 X \u0026 . \u0026 . \u0026 X \u0026 X \u0026 . \u0026 . \u0026 X \\\nX \u0026 . \u0026 X \u0026 X \u0026 X \u0026 X \u0026 X \u0026 X \u0026 . \u0026 X \u0026 X \u0026 . \u0026 X \u0026 . \u0026 . \\\nX \u0026 . \u0026 . \u0026 . \u0026 X \u0026 . \u0026 . \u0026 . \u0026 . \u0026 X \u0026 . \u0026 X \u0026 . \u0026 . \u0026 X \\\n. \u0026 . \u0026 X \u0026 . \u0026 X \u0026 . \u0026 X \u0026 X \u0026 X \u0026 X \u0026 X \u0026 . \u0026 X \u0026 . \u0026 X \\\n. \u0026 . \u0026 X \u0026 . \u0026 X \u0026 . \u0026 . \u0026 . \u0026 X \u0026 . \u0026 X \u0026 X \u0026 X \u0026 . \u0026 . \\\n. \u0026 X \u0026 . \u0026 . \u0026 . \u0026 X \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 X \u0026 X \u0026 . \\\n\\end{bmatrix}\n\u0026 \\rightarrow \u0026\n\\begin{bmatrix}\n. \u0026 . \u0026 X \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 X \u0026 . \u0026 . \u0026 . \u0026 . \\\n. \u0026 X \u0026 . \u0026 . \u0026 . \u0026 X \u0026 . \u0026 X \u0026 X \u0026 . \u0026 . \u0026 . \u0026 X \u0026 X \u0026 . \\\nX \u0026 . \u0026 . \u0026 . \u0026 . \u0026 X \u0026 X \u0026 X \u0026 . \u0026 X \u0026 . \u0026 . \u0026 X \u0026 X \u0026 . \\\n. \u0026 . \u0026 X \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 X \u0026 . \u0026 . \\\n. \u0026 X \u0026 . \u0026 . \u0026 X \u0026 . \u0026 . \u0026 X \u0026 . \u0026 . \u0026 . \u0026 . \u0026 X \u0026 . \u0026 . \\\n. \u0026 X \u0026 X \u0026 . \u0026 X \u0026 . \u0026 X \u0026 . \u0026 X \u0026 . \u0026 X \u0026 . \u0026 . \u0026 . \u0026 . \\\n. \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 X \u0026 X \u0026 . \\\n\\end{bmatrix}\n\u0026 \\rightarrow \u0026\n\\begin{bmatrix}\n. \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \\\n. \u0026 X \u0026 . \u0026 . \u0026 . \u0026 X \u0026 . \u0026 X \u0026 X \u0026 X \u0026 . \u0026 X \u0026 X \u0026 X \u0026 . \\\n. \u0026 X \u0026 . \u0026 . \u0026 . \u0026 X \u0026 . \u0026 X \u0026 . \u0026 . \u0026 . \u0026 X \u0026 . \u0026 . \u0026 . \\\n. \u0026 X \u0026 . \u0026 . \u0026 . \u0026 X \u0026 . \u0026 X \u0026 X \u0026 . \u0026 . \u0026 X \u0026 X \u0026 . \u0026 . \\\n. \u0026 X \u0026 . \u0026 . \u0026 . \u0026 X \u0026 . \u0026 X \u0026 . \u0026 . \u0026 . \u0026 X \u0026 . \u0026 . \u0026 . \\\n. \u0026 X \u0026 X \u0026 X \u0026 . \u0026 X \u0026 . \u0026 X \u0026 . \u0026 . \u0026 . \u0026 X \u0026 X \u0026 X \u0026 . \\\n. \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \\\n\\end{bmatrix}\n\\end{matrix}\n```\n\nIt also only takes only 10.7s to prove that no starting pattern exists which forms the \"LIFE\" example after 4 instead of 3 iterations.\n\n### Oscillator Optimization\n\nTo search for oscillators, i.e. patterns that repeat after a certain period, we need to add another binary auxiliary variable $o_t$ to our model. The equivalence $o_t = 1 \\iff x_{t = 1} \\neq x_t$ with:\n```math\nx_t - x_{t + 1} \\leq o_t \\quad \\quad x_{t + 1} - x_t \\leq o_t \\quad \\quad x_t + x_{t + 1} \\geq o_t \\quad \\quad 2 - (x_t + x_{t + 1}) \\geq o_t\n```\n\nNow we make sure that the patterns repeat after the period $p$ with $x_1 = x_{1 + p}$ for all tiles of the board and that they do not repeat earlier by adding $\\sum_i \\sum_j o_{t}(i, j) \\geq 1$ for all $t \\leq p$, i.e. at each time step the board differs from the start pattern by at least one tile. Finally we use the objective function $\\sum_i \\sum_j x_{p + 1}(i, j)$ to find the smallest possible oscillator.\n\nAs an example, we can look at period-3 oscillators, which are quite rare due to the binary nature of Game of Life. Again, using the Exact solver, we can prove that the following pattern called ‘Jam’ is indeed the smallest possible period-3 oscillator in a $7 \\times 7$ bounding box, in just 424s. The CP-SAT solver included in Google's [OR-Tools](https://developers.google.com/optimization) can even do it in just 167s, while even commercial Integer Programming solvers like [Gurobi](https://www.gurobi.com/) take over 20 minutes.\n\n```math\n\\begin{matrix}\n\\text{Time } t=1 \u0026 \\quad \u0026 \\text{Time } t=2 \u0026 \\quad \u0026 \\text{Time } t=3 \u0026 \\quad \u0026 \\text{Time } t=4 \\\\\n\\begin{bmatrix}\n. \u0026 . \u0026 . \u0026 . \u0026 X \u0026 X \u0026 . \\\n. \u0026 . \u0026 . \u0026 X \u0026 . \u0026 . \u0026 X \\\n. \u0026 X \u0026 . \u0026 . \u0026 X \u0026 . \u0026 X \\\n. \u0026 X \u0026 . \u0026 . \u0026 . \u0026 X \u0026 . \\\n. \u0026 X \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \\\n. \u0026 . \u0026 . \u0026 . \u0026 X \u0026 . \u0026 . \\\n. \u0026 . \u0026 X \u0026 X \u0026 . \u0026 . \u0026 . \\\n\\end{bmatrix}\n\u0026 \\rightarrow \u0026\n\\begin{bmatrix}\n. \u0026 . \u0026 . \u0026 . \u0026 X \u0026 X \u0026 . \\\n. \u0026 . \u0026 . \u0026 X \u0026 . \u0026 . \u0026 X \\\n. \u0026 . \u0026 X \u0026 . \u0026 X \u0026 . \u0026 X \\\nX \u0026 X \u0026 X \u0026 . \u0026 . \u0026 X \u0026 . \\\n. \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \\\n. \u0026 . \u0026 X \u0026 X \u0026 . \u0026 . \u0026 . \\\n. \u0026 . \u0026 . \u0026 X \u0026 . \u0026 . \u0026 . \\\n\\end{bmatrix}\n\u0026 \\rightarrow \u0026\n\\begin{bmatrix}\n. \u0026 . \u0026 . \u0026 . \u0026 X \u0026 X \u0026 . \\\n. \u0026 . \u0026 . \u0026 X \u0026 . \u0026 . \u0026 X \\\n. \u0026 . \u0026 X \u0026 . \u0026 X \u0026 . \u0026 X \\\n. \u0026 X \u0026 X \u0026 X \u0026 . \u0026 X \u0026 . \\\n. \u0026 . \u0026 . \u0026 X \u0026 . \u0026 . \u0026 . \\\n. \u0026 . \u0026 X \u0026 X \u0026 . \u0026 . \u0026 . \\\n. \u0026 . \u0026 X \u0026 X \u0026 . \u0026 . \u0026 . \\\n\\end{bmatrix}\n\u0026 \\rightarrow \u0026\n\\begin{bmatrix}\n. \u0026 . \u0026 . \u0026 . \u0026 X \u0026 X \u0026 . \\\n. \u0026 . \u0026 . \u0026 X \u0026 . \u0026 . \u0026 X \\\n. \u0026 X \u0026 . \u0026 . \u0026 X \u0026 . \u0026 X \\\n. \u0026 X \u0026 . \u0026 . \u0026 . \u0026 X \u0026 . \\\n. \u0026 X \u0026 . \u0026 . \u0026 . \u0026 . \u0026 . \\\n. \u0026 . \u0026 . \u0026 . \u0026 X \u0026 . \u0026 . \\\n. \u0026 . \u0026 X \u0026 X \u0026 . \u0026 . \u0026 . \\\n\\end{bmatrix}\n\\end{matrix}\n```\n\nUsing the Cube-and-Conquer SAT solver [treengeling](https://github.com/arminbiere/lingeling), we can also show in just 20 minutes that no period-5 oscillator can exist in a 7x7 bounding box, proving optimality of the [Fumarole](https://conwaylife.com/wiki/Fumarole) 7x8 period-5 oscillator. One can additionally prove that no period 5 oscillator with fewer tiles than Fumarole can exist in a 7x8 bounding box in around 2 hours.\n\n## External Solver Installation\n\nSince their installation can be quite tedious, you will find short installation instructions for the Exact Solver and the Or-Tools for Ubuntu here.\n\n### Google Or-Tools\n\nInstall the required build tools:\n\n```bash\nsudo apt install build-essential lsb-release -y\nsudo snap install cmake --classic\n```\n\nDownload the binary [here](https://developers.google.com/optimization/install/cpp/binary_linux), then compile:\n```bash\nmkdir -p or-tools \u0026\u0026 tar -xzf or-tools_*.tar.gz --strip-components=1 -C or-tools \u0026\u0026 cd or-tools\n```\n\n```bash\nmake test\nsudo cp bin/* /usr/local/bin\nsudo cp -r lib/* /usr/local/lib\nsudo cp -r share/* /usr/local/share\n```\n\nNow finally the CP-SAT solver can be used as:\n```bash\nsolve --solver=sat --num_threads=16 --input=test.mps --sol_file=test.sol\n```\n\n### Exact\n\nInstall the required build tools:\n\n```bash\nsudo apt-get install build-essential libbz2-dev coinor-libcoinutils-dev libboost-all-dev -y\n```\n\nTo compile the solver:\n\n```bash\ngit clone https://gitlab.com/nonfiction-software/exact.git \u0026\u0026 cd exact\ngit submodule init \u0026\u0026 git submodule update\nmkdir soplex_build \u0026\u0026 cd soplex_build\ncmake ../soplex -DBUILD_TESTING=\"0\" -DSANITIZE_UNDEFINED=\"0\" -DCMAKE_BUILD_TYPE=\"Release\" -DBOOST=\"0\" -DGMP=\"0\" -DCMAKE_WINDOWS_EXPORT_ALL_SYMBOLS=\"0\" -DZLIB=\"0\"\nmake -j 8\nsudo make install\n\ncd ../build_debug \u0026\u0026 cmake .. -DCMAKE_BUILD_TYPE=\"Release\" -Dsoplex=\"ON\" -Dcoinutils=\"ON\"\nmake -j 8\nmake install\n```\n\nNow finally the pseudo-Boolean SAT solver can be used as:\n\n```bash\nExact test.mps\n```\n\n(c) Mia Muessig\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphoenixsmaug%2Freverse-gol","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphoenixsmaug%2Freverse-gol","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphoenixsmaug%2Freverse-gol/lists"}