├── .gitignore ├── .readthedocs.yaml ├── LICENSE ├── Makefile ├── _static └── custom.css ├── conf.py ├── index.rst ├── intro.rst ├── language ├── commands.rst ├── expressions-and-constraints.rst ├── img │ ├── belongs_to.png │ ├── command.png │ ├── lone-dir.png │ ├── one-key.png │ ├── self-relation.png │ ├── set-user.png │ ├── sig-a.png │ ├── sig-with-relations.png │ └── some-author.png ├── index.rst ├── modules.rst ├── predicates-and-functions.rst ├── sets-and-relations.rst ├── signatures.rst └── time.rst ├── make.bat ├── modules ├── boolean.rst ├── graph.rst ├── index.rst ├── integer.rst ├── natural.rst ├── ordering.rst ├── relation.rst ├── ternary.rst └── time.rst ├── readme.md ├── requirements.txt ├── techniques ├── boolean-fields.rst ├── dynamics.rst ├── index.rst └── specs │ └── dynamics │ ├── browsing.als │ ├── keyboard-table.als │ ├── keyboard.als │ └── light.als ├── tooling ├── analyzer.rst ├── img │ ├── evaluator.png │ ├── kodkod.png │ ├── table.png │ ├── temporal_model.png │ ├── tree.png │ └── visualizer.png ├── index.rst ├── markdown.rst ├── specs │ ├── server.als │ ├── visualizer-counterexample.xml │ └── visualizer.als ├── themes.rst └── visualizer.rst └── utils ├── __init__.py └── alloy.py /.gitignore: -------------------------------------------------------------------------------- 1 | # sphinx build folder 2 | _build/ 3 | 4 | # Compiled source # 5 | ################### 6 | *.com 7 | *.class 8 | *.dll 9 | *.exe 10 | *.o 11 | *.so 12 | *.pyc 13 | 14 | # Byte-compiled / optimized / DLL files 15 | __pycache__/ 16 | *.py[cod] 17 | *$py.class 18 | 19 | # Packages # 20 | ############ 21 | # it's better to unpack these files and commit the raw source 22 | # git has its own built in compression methods 23 | *.7z 24 | *.dmg 25 | *.gz 26 | *.iso 27 | *.jar 28 | *.rar 29 | *.tar 30 | *.zip 31 | 32 | # Logs and databases # 33 | ###################### 34 | *.log 35 | *.sql 36 | *.sqlite 37 | 38 | # OS generated files # 39 | ###################### 40 | .DS_Store? 41 | ehthumbs.db 42 | Icon? 43 | Thumbs.db 44 | 45 | # Editor backup files # 46 | ####################### 47 | *~ 48 | .projectroot 49 | tags 50 | todo 51 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | build: 4 | os: ubuntu-20.04 5 | tools: 6 | python: "3.12" 7 | 8 | python: 9 | install: 10 | - requirements: requirements.txt 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Alloytools 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SOURCEDIR = . 8 | BUILDDIR = _build 9 | 10 | # Put it first so that "make" without argument is like "make help". 11 | help: 12 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 13 | 14 | .PHONY: help Makefile 15 | 16 | # Catch-all target: route all unknown targets to Sphinx using the new 17 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 18 | %: Makefile 19 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /_static/custom.css: -------------------------------------------------------------------------------- 1 | .advanced h1:before, 2 | .advanced h2:before, 3 | .advanced h3:before, 4 | .advanced h4:before { 5 | content: "[⋇] "; 6 | } 7 | -------------------------------------------------------------------------------- /conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Configuration file for the Sphinx documentation builder. 4 | # 5 | # This file does only contain a selection of the most common options. For a 6 | # full list see the documentation: 7 | # http://www.sphinx-doc.org/en/master/config 8 | 9 | # -- Path setup -------------------------------------------------------------- 10 | 11 | # If extensions (or modules to document with autodoc) are in another directory, 12 | # add these directories to sys.path here. If the directory is relative to the 13 | # documentation root, use os.path.abspath to make it absolute, like shown here. 14 | # 15 | import os 16 | import sys 17 | sys.path.append(os.path.abspath('./utils')) 18 | 19 | 20 | # -- Project information ----------------------------------------------------- 21 | 22 | project = 'Alloy Documentation' 23 | copyright = '2023' 24 | author = 'Hillel Wayne' 25 | 26 | # The short X.Y version 27 | version = '' 28 | # The full version, including alpha/beta/rc tags 29 | release = '' 30 | 31 | 32 | # -- General configuration --------------------------------------------------- 33 | 34 | # If your documentation needs a minimal Sphinx version, state it here. 35 | # 36 | # needs_sphinx = '1.0' 37 | 38 | # Add any Sphinx extension module names here, as strings. They can be 39 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 40 | # ones. 41 | extensions = [ 42 | 'sphinx.ext.todo', 43 | 'sphinx.ext.githubpages', 44 | 'sphinx_rtd_theme', 45 | 'alloy' 46 | ] 47 | 48 | # Add any paths that contain templates here, relative to this directory. 49 | templates_path = ['_templates'] 50 | 51 | # The suffix(es) of source filenames. 52 | # You can specify multiple suffix as a list of string: 53 | # 54 | # source_suffix = ['.rst', '.md'] 55 | source_suffix = '.rst' 56 | 57 | # The master toctree document. 58 | master_doc = 'index' 59 | 60 | # The language for content autogenerated by Sphinx. Refer to documentation 61 | # for a list of supported languages. 62 | # 63 | # This is also used if you do content translation via gettext catalogs. 64 | # Usually you set "language" from the command line for these cases. 65 | language = "en" 66 | 67 | default_role = "any" 68 | highlight_language = "alloy" 69 | 70 | # List of patterns, relative to source directory, that match files and 71 | # directories to ignore when looking for source files. 72 | # This pattern also affects html_static_path and html_extra_path. 73 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 74 | 75 | # The name of the Pygments (syntax highlighting) style to use. 76 | pygments_style = None 77 | 78 | 79 | # -- Options for HTML output ------------------------------------------------- 80 | 81 | # The theme to use for HTML and HTML Help pages. See the documentation for 82 | # a list of builtin themes. 83 | # 84 | html_theme = 'sphinx_rtd_theme' 85 | 86 | # Theme options are theme-specific and customize the look and feel of a theme 87 | # further. For a list of options available for each theme, see the 88 | # documentation. 89 | # 90 | # html_theme_options = {} 91 | 92 | # Add any paths that contain custom static files (such as style sheets) here, 93 | # relative to this directory. They are copied after the builtin static files, 94 | # so a file named "default.css" will overwrite the builtin "default.css". 95 | html_static_path = ['_static'] 96 | 97 | # Custom sidebar templates, must be a dictionary that maps document names 98 | # to template names. 99 | # 100 | # The default sidebars (for documents that don't match any pattern) are 101 | # defined by theme itself. Builtin themes are using these templates by 102 | # default: ``['localtoc.html', 'relations.html', 'sourcelink.html', 103 | # 'searchbox.html']``. 104 | # 105 | # html_sidebars = {} 106 | 107 | 108 | # -- Options for HTMLHelp output --------------------------------------------- 109 | 110 | # Output file base name for HTML help builder. 111 | htmlhelp_basename = 'AlloyDocumentationdoc' 112 | 113 | 114 | # -- Options for LaTeX output ------------------------------------------------ 115 | latex_engine = "xelatex" # solves problem of unicode characters 116 | latex_elements = { 117 | # The paper size ('letterpaper' or 'a4paper'). 118 | # 119 | # 'papersize': 'letterpaper', 120 | 121 | # The font size ('10pt', '11pt' or '12pt'). 122 | # 123 | # 'pointsize': '10pt', 124 | 125 | # Additional stuff for the LaTeX preamble. 126 | # 127 | # 'preamble': '', 128 | 129 | # Latex figure (float) alignment 130 | # 131 | # 'figure_align': 'htbp', 132 | } 133 | 134 | # Grouping the document tree into LaTeX files. List of tuples 135 | # (source start file, target name, title, 136 | # author, documentclass [howto, manual, or own class]). 137 | latex_documents = [ 138 | (master_doc, 'AlloyDocumentation.tex', 'Alloy Documentation Documentation', 139 | 'Alloy Board', 'manual'), 140 | ] 141 | 142 | 143 | # -- Options for manual page output ------------------------------------------ 144 | 145 | # One entry per manual page. List of tuples 146 | # (source start file, name, description, authors, manual section). 147 | man_pages = [ 148 | (master_doc, 'alloydocumentation', 'Alloy Documentation Documentation', 149 | [author], 1) 150 | ] 151 | 152 | 153 | # -- Options for Texinfo output ---------------------------------------------- 154 | 155 | # Grouping the document tree into Texinfo files. List of tuples 156 | # (source start file, target name, title, author, 157 | # dir menu entry, description, category) 158 | texinfo_documents = [ 159 | (master_doc, 'AlloyDocumentation', 'Alloy Documentation Documentation', 160 | author, 'AlloyDocumentation', 'One line description of project.', 161 | 'Miscellaneous'), 162 | ] 163 | 164 | 165 | # -- Options for Epub output ------------------------------------------------- 166 | 167 | # Bibliographic Dublin Core info. 168 | epub_title = project 169 | 170 | # The unique identifier of the text. This can be a ISBN number 171 | # or the project homepage. 172 | # 173 | # epub_identifier = '' 174 | 175 | # A unique identification for the text. 176 | # 177 | # epub_uid = '' 178 | 179 | # A list of files that should not be packed into the epub file. 180 | epub_exclude_files = ['search.html'] 181 | 182 | 183 | # -- Extension configuration ------------------------------------------------- 184 | 185 | # -- Options for todo extension ---------------------------------------------- 186 | 187 | # If true, `todo` and `todoList` produce output, else they produce nothing. 188 | # We can't pass the -D flag in ReadTheDocs, so we instead customize to their specific environment 189 | if os.environ.get('READTHEDOCS'): 190 | todo_include_todos = False 191 | else: 192 | todo_include_todos = True 193 | 194 | # We use brackets, not parenthesis 195 | add_function_parentheses = False 196 | 197 | # So we get the advanced directive 198 | def setup(app): 199 | app.add_css_file('custom.css') 200 | 201 | """ 202 | https://samprocter.com/2014/06/documenting-a-language-using-a-custom-sphinx-domain-and-pygments-lexer/ 203 | 204 | def setup(sphinx): 205 | sys.path.insert(0, os.path.abspath('./util')) 206 | from AADLLexer import AADLLexer 207 | from AADLDomain import AADLDomain 208 | sphinx.add_lexer("aadl", AADLLexer()) 209 | sphinx.add_domain(AADLDomain) 210 | """ 211 | -------------------------------------------------------------------------------- /index.rst: -------------------------------------------------------------------------------- 1 | .. Alloy Documentation documentation master file, created by 2 | sphinx-quickstart on Sun Feb 24 19:08:18 2019. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Alloy Docs 7 | =============================================== 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | :caption: Contents: 12 | 13 | intro 14 | language/index 15 | tooling/index 16 | modules/index 17 | techniques/index 18 | 19 | 20 | 21 | Indices and tables 22 | ================== 23 | 24 | * :ref:`genindex` 25 | * :ref:`modindex` 26 | * :ref:`search` 27 | 28 | .. todolist:: 29 | -------------------------------------------------------------------------------- /intro.rst: -------------------------------------------------------------------------------- 1 | Introduction 2 | ============= 3 | 4 | About Alloy 5 | -------------- 6 | 7 | Alloy is a tool for analyzing systems and seeing if they are designed correctly. You can read more `here `__ and download it `here `__. 8 | 9 | 10 | About This Guide 11 | ------------------- 12 | 13 | This is my tentative proposed documentation for the Alloy language. 14 | 15 | **This is not the official Alloy documentation.** It's a staging ground for material that's intended to *become* official documentation, but for now I'm writing this independently, not as part of the alloy board. 16 | 17 | **This is a work in progress.** This documentation is incomplete and changes may be made. There are also a lot of things that still need to be added. 18 | 19 | **This is meant as a reference**, not a tutorial. 20 | 21 | **This is not comprehensive**. Certain things are intentionally excluded, like bitshift operators, specific internal modules, anonymous predicates, and Alloy 3 legacy syntax. Generally these are things that I personally believe are only useful in very specific niche cases, and otherwise serve to confuse things. 22 | 23 | How to Read 24 | ----------- 25 | 26 | I’ve added commentary in the markup of the pages that is invisible in 27 | the final output. If you see something 28 | 29 | :: 30 | 31 | .. like this 32 | 33 | Then it will not be rendered. If I used a special ``run`` predicate to 34 | generate a particular visualization, I put it in a comment. 35 | 36 | Anything with a ``[⋇]`` is an advanced topic and unnecessary to learn if you're just a beginner. 37 | 38 | Issues with the documentation can be raised `here `__. 39 | 40 | 41 | About the Author 42 | --------------------- 43 | 44 | I'm Hillel. I also wrote a `guide to TLA+ `__ and have a `blog `__. 45 | -------------------------------------------------------------------------------- /language/commands.rst: -------------------------------------------------------------------------------- 1 | 2 | .. _commands: 3 | 4 | ++++++++ 5 | Commands 6 | ++++++++ 7 | 8 | A :dfn:`command` is what actually runs the analyzer. It can either find 9 | models that satisfy your specification, or counterexamples to given 10 | properties. 11 | 12 | By default, the analyzer will run the top command in the file. A 13 | specific command can be run under the ``Execute`` menu option. 14 | 15 | .. _run: 16 | 17 | ``run`` 18 | ======= 19 | 20 | **run** tells the analyzer to find a matching example of the spec. 21 | 22 | ``run pred`` 23 | ------------ 24 | 25 | Find examples where ``pred`` is true. If no examples match, the analyzer 26 | will suggest the predicate is inconsistent (see `unsat core `). The 27 | predicate may be consistent if the `scope ` is off. 28 | 29 | .. code:: alloy 30 | 31 | sig Node { 32 | edge: set Node 33 | } 34 | 35 | pred self_loop[n: Node] { 36 | n in n.edge 37 | } 38 | 39 | pred all_self_loop { 40 | all n: Node | self_loop[n] 41 | } 42 | 43 | run all_self_loop 44 | 45 | The analyzer will title the command as the predicate. 46 | 47 | .. image:: img/command.png 48 | 49 | 50 | ``run {constraint}`` 51 | -------------------- 52 | 53 | Finds an example satisfying the ad-hoc constraint in the braces. 54 | 55 | .. code:: alloy 56 | 57 | // some node with a self loop 58 | run {some n: Node | self_loop[n]} 59 | 60 | .. TIP:: The analyzer will title the command ``run${num}``. You can give the command a name by prepending the ``run`` with ``name:``: 61 | 62 | .. code:: alloy 63 | 64 | some_self_loop: run {some n: Node | self_loop[n]} 65 | 66 | 67 | .. _check: 68 | 69 | 70 | ``check`` 71 | ========= 72 | 73 | **check** tells the Analyzer to find a counterexample to a given 74 | constraint. You can use it to check that your specification behaves as 75 | you expect it to. 76 | 77 | .. _assert: 78 | 79 | Unlike with ``run`` commands, ``check`` uses **assertions**: 80 | 81 | .. code:: alloy 82 | 83 | assert no_self_loops { 84 | no n: Node | self_loop[n] 85 | } 86 | 87 | check no_self_loops 88 | 89 | Asserts may be used in ``check`` commands but not ``run`` commands. 90 | Assertions may not be called by other predicates or assertions. 91 | 92 | You can also call ``check`` with an ad-hoc constraint: 93 | 94 | .. code:: alloy 95 | 96 | check {no n: Node | self_loop[n]} 97 | 98 | 99 | ``check`` can also be given a named command. 100 | 101 | .. _scopes: 102 | 103 | Scopes 104 | ====== 105 | 106 | All alloy models are **bounded**: they must have a maximum possible 107 | size. If not specified, the analyzer will assume that there may be up to 108 | three of each top-level signature and any number of relations. This is 109 | called the **scope**, and can be changed for each command. 110 | 111 | Given the following spec: 112 | 113 | .. code:: alloy 114 | 115 | sig A {} 116 | sig B {} 117 | 118 | We can write the following scopes: 119 | 120 | .. _exactly: 121 | 122 | - ``run {} for 5``: Analyzer will look for models with up to five 123 | instances of each A and B. 124 | - ``run {} for 5 but 2 A``: Analyzer will look for models with up to 125 | two instances of A. 126 | - ``run {} for 5 but exactly 2 A``: Analyzer will only look for models 127 | with *exactly two* A. The exact scope *may* be higher than the 128 | general scope. 129 | - ``run {} for 5 but 2 A, 3 B``: Places scopes on A and B. 130 | 131 | If you are placing scopes on all of the signatures, the ``for N but`` 132 | is unnecessary: the last command can be written as 133 | ``run {} for 2 A, 3 B``. 134 | 135 | .. TIP:: When using `Arithmetic Operators `, you can specify ``Int`` like any other signature: 136 | 137 | .. code:: alloy 138 | 139 | run foo for 3 Int 140 | 141 | .. NOTE:: You cannot place scopes on relations. Instead, use a predicate. 142 | 143 | .. code:: alloy 144 | 145 | sig A { 146 | rel: A 147 | } 148 | 149 | run {#rel = 2} 150 | 151 | .. rst-class:: advanced 152 | 153 | Scopes on Subtypes 154 | ---------------------- 155 | 156 | 157 | Special scopes *may* be placed on `extensional subtypes `. The following is valid: 158 | 159 | .. code:: alloy 160 | 161 | sig Plant {} 162 | 163 | sig Tree extends Plant {} 164 | sig Grass extends Plant {} 165 | 166 | run {} for 4 Plant, exactly 2 Tree 167 | 168 | ``Grass`` does not need to be scoped, as it is considered part of 169 | ``Plant``. The maximum number of atoms for a subtype is either it or its 170 | parent’s scope, whichever is lower. The parent scope is shared across 171 | all children. In this command, there are a maximum of four ``Plant``\ s, 172 | exactly two of which will be ``Tree`` atoms. Therefore there may be at 173 | most two ``Grass`` atoms. 174 | 175 | In contrast, special scopes *may not* be placed on `subset types `. The following is invalid: 176 | 177 | .. code:: alloy 178 | 179 | sig Plant {} 180 | 181 | sig Seedling in Plant {} 182 | 183 | run {} for 4 Plant, exactly 2 Seedling 184 | 185 | Since ``Seedling`` is a subset type, it may not have a scope. If you 186 | need to scope on a subtype, use a constraint: 187 | 188 | .. code:: alloy 189 | 190 | run {#Seedling = 2} for 4 Plant 191 | 192 | 193 | .. _steps: 194 | 195 | Steps 196 | -------- 197 | 198 | For :doc:`dynamic