├── knowledge_clustering ├── __init__.py ├── scripts │ ├── __init__.py │ └── app.py ├── _version.py ├── data │ ├── french.ini │ └── english.ini ├── config.py ├── misc.py ├── check_update.py ├── cst.py ├── diagnose.py ├── autofinder.py ├── add_anchor.py ├── file_updater.py ├── scope_meaning.py ├── clustering.py ├── tex_document.py ├── distance.py ├── add_quotes.py └── knowledges.py ├── img ├── preservation-after.png └── preservation-before.png ├── pyproject.toml ├── .gitignore ├── tests ├── .ordinal.diagnose.original ├── .ordinal.kl.original ├── .ordinal.kl.solution ├── .ordinal.tex.original ├── test_anchor.py ├── test_addquotes.py ├── test_autofinder.py └── test_clustering.py ├── examples ├── preservation │ ├── preservation.diagnose │ └── preservation.kl ├── ordinal │ ├── ordinal.tex │ ├── ordinal.kl │ └── ordinal.diagnose └── phd │ └── default.kl ├── Makefile ├── LICENSE.md ├── setup.cfg ├── .github └── workflows │ └── python-publish.yml └── README.md /knowledge_clustering/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /knowledge_clustering/scripts/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /knowledge_clustering/_version.py: -------------------------------------------------------------------------------- 1 | """Version of knowledge-clustering.""" 2 | VERSION = "0.8.0.dev" 3 | -------------------------------------------------------------------------------- /img/preservation-after.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remimorvan/knowledge-clustering/HEAD/img/preservation-after.png -------------------------------------------------------------------------------- /img/preservation-before.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remimorvan/knowledge-clustering/HEAD/img/preservation-before.png -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = [ 3 | "setuptools>=42", 4 | "wheel", 5 | ] 6 | build-backend = "setuptools.build_meta" -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | *.pyc 3 | *.egg-info* 4 | *.whl 5 | *.tar.gz 6 | dist/* 7 | build/* 8 | .vim/* 9 | kw-devel/* 10 | venv-black/* 11 | *.venv 12 | .vscode 13 | .coverage 14 | kl3.11/* -------------------------------------------------------------------------------- /knowledge_clustering/data/french.ini: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | PREFIXES_SIMILAR= 3 | # Empty string 4 | - # ignore dashes 5 | a 6 | il 7 | im 8 | in 9 | ir 10 | non 11 | non- 12 | -------------------------------------------------------------------------------- /tests/.ordinal.diagnose.original: -------------------------------------------------------------------------------- 1 | ************************ 2 | * Undefined knowledges * 3 | ************************ 4 | 5 | \knowledge{ignore} 6 | | inseparability 7 | | semigroup 8 | | words 9 | | semigroups 10 | | countable ordinal word -------------------------------------------------------------------------------- /tests/.ordinal.kl.original: -------------------------------------------------------------------------------- 1 | \knowledge{notion} 2 | | word 3 | 4 | \knowledge{notion} 5 | | word@ord 6 | 7 | \knowledge{notion} 8 | | regular language over countable ordinals 9 | | regular languages@ord 10 | 11 | \knowledge{notion} 12 | | separation 13 | -------------------------------------------------------------------------------- /knowledge_clustering/data/english.ini: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | PREFIXES_SIMILAR= 3 | # Empty string 4 | - # ignore dashes 5 | a # (a)chromatic 6 | il 7 | im 8 | in # (in)separable 9 | ir 10 | non 11 | non- # (non-)atomic 12 | un # (un)ambiguous 13 | -------------------------------------------------------------------------------- /examples/preservation/preservation.diagnose: -------------------------------------------------------------------------------- 1 | ************************ 2 | * Undefined knowledges * 3 | ************************ 4 | 5 | \knowledge{ignore} 6 | | preserved under extension 7 | | preservation under extension 8 | | preservation under substructures 9 | | substructures 10 | | homomorphisms 11 | -------------------------------------------------------------------------------- /tests/.ordinal.kl.solution: -------------------------------------------------------------------------------- 1 | \knowledge{notion} 2 | | word 3 | % | words 4 | 5 | \knowledge{notion} 6 | | word@ord 7 | % | countable ordinal word 8 | 9 | \knowledge{notion} 10 | | regular language over countable ordinals 11 | | regular languages@ord 12 | 13 | \knowledge{notion} 14 | | separation 15 | % | inseparability 16 | %%%%% NEW KNOWLEDGES 17 | % 18 | %\knowledge{notion} 19 | % | semigroup 20 | % | semigroups 21 | -------------------------------------------------------------------------------- /examples/preservation/preservation.kl: -------------------------------------------------------------------------------- 1 | \knowledge{notion} 2 | | extensions 3 | 4 | \knowledge{notion} 5 | | preservation under extensions 6 | % | preservation under extension 7 | 8 | \knowledge{notion} 9 | | preserved under extensions 10 | % | preserved under extension 11 | %%%%% NEW KNOWLEDGES 12 | % 13 | %\knowledge{notion} 14 | % | preservation under substructures 15 | % 16 | %\knowledge{notion} 17 | % | substructures 18 | % 19 | %\knowledge{notion} 20 | % | homomorphisms 21 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | VENV-BLACK=black.venv 2 | 3 | .PHONY: black check test coverage build deploy-test 4 | 5 | black: 6 | source ./$(VENV-BLACK)/bin/activate && black . 7 | 8 | check: 9 | mypy knowledge_clustering/*.py --check-untyped-defs # Check typing 10 | pylint knowledge_clustering/*.py # Linter 11 | 12 | test: 13 | python -m pytest tests/ -v 14 | 15 | coverage: 16 | python -m pytest tests/ --cov 17 | 18 | build: 19 | python -m build . 20 | 21 | deploy-test: knowledge_clustering/_version.py 22 | python -m twine upload --repository testpypi dist/* -------------------------------------------------------------------------------- /examples/ordinal/ordinal.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | 3 | \usepackage[utf8]{inputenc} 4 | \usepackage[T1]{fontenc} 5 | \pdfoutput = 1 6 | 7 | \usepackage[breaklinks,hidelinks]{hyperref} 8 | \usepackage{xcolor} 9 | 10 | \usepackage{knowledge} 11 | \knowledgeconfigure{notion} 12 | \knowledgeconfigure{quotation} 13 | \input{ordinal-kl.tex} 14 | 15 | \title{Blabla} 16 | \date{\today} 17 | \author{Charles-Édouard} 18 | 19 | 20 | \begin{document} 21 | 22 | \maketitle 23 | 24 | \AP ""word"" 25 | "words" 26 | ""word@@ord"" 27 | "countable ordinal word" 28 | ""regular language over countable ordinals"" 29 | \kl[ord]{regular languages} 30 | \intro{separation} 31 | "inseparability" 32 | ""semigroup"" 33 | \kl{semigroups} 34 | 35 | 36 | \end{document} -------------------------------------------------------------------------------- /tests/.ordinal.tex.original: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | 3 | \usepackage[utf8]{inputenc} 4 | \usepackage[T1]{fontenc} 5 | \pdfoutput = 1 6 | 7 | \usepackage[breaklinks,hidelinks]{hyperref} 8 | \usepackage{xcolor} 9 | 10 | \usepackage{knowledge} 11 | \knowledgeconfigure{notion} 12 | \knowledgeconfigure{quotation} 13 | \input{ordinal-kl.tex} 14 | 15 | \title{Blabla} 16 | \date{\today} 17 | \author{Charles-Édouard} 18 | 19 | 20 | \begin{document} 21 | 22 | \maketitle 23 | 24 | \AP ""word"" 25 | "words" 26 | ""word@@ord"" 27 | "countable ordinal word" 28 | 29 | blablablablablablablablablablablablablablablablablablablabla 30 | blablablablablablablablablablablablablablablablablablablabla 31 | blablablablablablablablablablablablablablablablablablablabla 32 | 33 | ""regular language over countable ordinals"" 34 | \kl[ord]{regular languages} 35 | \intro{separation} 36 | 37 | "inseparability" 38 | ""semigroup"" 39 | \kl{semigroups} 40 | 41 | 42 | \end{document} -------------------------------------------------------------------------------- /tests/test_anchor.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests for the modules of knowledge_clustering on which the anchor command is based. 3 | """ 4 | 5 | from pathlib import Path 6 | import shutil 7 | 8 | from knowledge_clustering.add_anchor import app as app_anchor 9 | 10 | 11 | def test_app_anchor() -> None: 12 | """Tests the anchor command.""" 13 | shutil.copy("tests/.ordinal.tex.original", "tests/ordinal.tex") 14 | with open("tests/output_anchor.txt", "w", encoding="utf-8") as out: 15 | app_anchor("tests/ordinal.tex", 200, out) 16 | nb_line_output = sum( 17 | 1 for line in open("tests/output_anchor.txt", encoding="utf-8") 18 | ) 19 | b1: bool = nb_line_output == 3 20 | with open("tests/output_anchor.txt", "w", encoding="utf-8") as out: 21 | app_anchor("tests/ordinal.tex", 5, out) 22 | with open("tests/output_anchor.txt", "r", encoding="utf-8") as out: 23 | nb_line_output = sum(1 for _ in out) 24 | b2: bool = nb_line_output == 4 25 | p = Path("tests/") 26 | for filename in ["ordinal.tex", "output_anchor.txt"]: 27 | (p / filename).unlink() 28 | assert b1 and b2 29 | -------------------------------------------------------------------------------- /tests/test_addquotes.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests for the modules of knowledge_clustering on which the addquotes command is based. 3 | """ 4 | 5 | from pathlib import Path 6 | import shutil 7 | 8 | from knowledge_clustering.add_quotes import app as app_addquotes 9 | 10 | 11 | def test_app_addquotes() -> None: 12 | """Tests the addquotes command.""" 13 | shutil.copy("tests/.ordinal.tex.original", "tests/ordinal.tex") 14 | shutil.copy("tests/.ordinal.kl.original", "tests/ordinal.kl") 15 | with open("tests/yes.txt", "w", encoding="utf-8") as yes: 16 | yes.write("y\n" * 100) 17 | with open("tests/yes.txt", "r", encoding="utf-8") as inp: 18 | with open("tests/output_addquotes.txt", "w", encoding="utf-8") as out: 19 | app_addquotes("tests/ordinal.tex", ["tests/ordinal.kl"], 1, inp, out) 20 | with open("tests/output_addquotes.txt", "r", encoding="utf-8") as out: 21 | nb_line_output = sum(1 for _ in out) 22 | b: bool = nb_line_output == 7 23 | p = Path("tests/") 24 | for filename in ["yes.txt", "ordinal.tex", "ordinal.kl", "output_addquotes.txt"]: 25 | (p / filename).unlink() 26 | assert b 27 | -------------------------------------------------------------------------------- /knowledge_clustering/config.py: -------------------------------------------------------------------------------- 1 | """Parse a configuration file.""" 2 | 3 | from __future__ import annotations # Support of `|` for type union in Python 3.9 4 | from pathlib import Path 5 | 6 | import configparser 7 | 8 | 9 | class ListConfigParser(configparser.ConfigParser): 10 | """Extended Config Parser to handle lists.""" 11 | 12 | def getlist(self, section, option): 13 | """Return list in some config file.""" 14 | value = self.get(section, option) 15 | return list(x.split("#")[0].strip() for x in value.splitlines()) 16 | 17 | # def getlistint(self, section, option): 18 | # return [int(x) for x in self.getlist(section, option)] 19 | 20 | 21 | def parse(filename: Path) -> list[str]: 22 | """ 23 | Reads a config file and returns the list of words occuring 24 | under the keyphrase `[DEFAULT] PREFIXES_SIMILAR=`. 25 | 26 | Args: 27 | filename: the name of a config file. 28 | 29 | Returns: 30 | a list of prefixes that should be ignored by the clustering algorithm. 31 | """ 32 | p = ListConfigParser() 33 | p.read(filename) 34 | return p.getlist("DEFAULT", "PREFIXES_SIMILAR") 35 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Rémi Morvan, Thomas Colcombet and Aliaume Lopez 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 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name = knowledge-clustering 3 | version = attr: knowledge_clustering._version.VERSION 4 | author = Rémi Morvan 5 | author_email = remi@morvan.xyz 6 | description = Automated notion clustering for the knowledge LaTeX package 7 | long_description = file: README.md 8 | long_description_content_type = text/markdown 9 | url = https://github.com/remimorvan/knowledge-clustering 10 | project_urls = 11 | Bug Tracker = https://github.com/remimorvan/knowledge-clustering/issues 12 | classifiers = 13 | Programming Language :: Python :: 3 14 | License :: OSI Approved :: MIT License 15 | Operating System :: OS Independent 16 | keywords = 17 | knowledge :: latex :: clustering 18 | 19 | [options] 20 | packages = find: 21 | python_requires = >=3.9 22 | install_requires = 23 | click 24 | click_default_group 25 | numpy==1.26.4 # nltk requires numpy < 2.0 26 | nltk 27 | spacy 28 | toposort 29 | unidecode 30 | requests 31 | 32 | [options.package_data] 33 | * = data/* 34 | 35 | [options.entry_points] 36 | console_scripts = 37 | knowledge = knowledge_clustering.scripts.app:cli 38 | 39 | [options.extras_require] 40 | tests = 41 | pytest 42 | filecmp -------------------------------------------------------------------------------- /.github/workflows/python-publish.yml: -------------------------------------------------------------------------------- 1 | # This workflow will upload a Python Package using Twine when a release is created 2 | # For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries 3 | 4 | # This workflow uses actions that are not certified by GitHub. 5 | # They are provided by a third-party and are governed by 6 | # separate terms of service, privacy policy, and support 7 | # documentation. 8 | 9 | name: Upload Python Package 10 | 11 | on: 12 | release: 13 | types: [published] 14 | 15 | jobs: 16 | deploy: 17 | 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - uses: actions/checkout@v2 22 | - name: Set up Python 23 | uses: actions/setup-python@v2 24 | with: 25 | python-version: '3.x' 26 | - name: Install dependencies 27 | run: | 28 | python -m pip install --upgrade pip 29 | pip install build 30 | - name: Build package 31 | run: python -m build 32 | - name: Publish package 33 | uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 34 | with: 35 | user: __token__ 36 | password: ${{ secrets.PYPI_TOKEN }} 37 | -------------------------------------------------------------------------------- /knowledge_clustering/misc.py: -------------------------------------------------------------------------------- 1 | """Misc functions, for emphasizing a string.""" 2 | 3 | from __future__ import annotations # Support of `|` for type union in Python 3.9 4 | 5 | 6 | BEGIN_EMPH: str = "\033[1m\033[95m" 7 | BEGIN_EMPH_ALT: str = "\033[1m\033[92m" 8 | BEGIN_BOLD: str = "\033[1m" 9 | BEGIN_RED: str = "\033[31m" 10 | BEGIN_ORANGE: str = "\033[33m" 11 | BEGIN_GREEN: str = "\033[32m" 12 | END_EMPH: str = "\033[0m" 13 | 14 | 15 | def emph(string: str) -> str: 16 | """Emphasizes a string.""" 17 | return BEGIN_EMPH + string + END_EMPH 18 | 19 | 20 | def emph_alt(string: str) -> str: 21 | """Alternative emphasis of a string.""" 22 | return BEGIN_EMPH_ALT + string + END_EMPH 23 | 24 | 25 | def add_red(string: str) -> str: 26 | """Puts a string in red.""" 27 | return BEGIN_RED + string + END_EMPH 28 | 29 | 30 | def add_orange(string: str) -> str: 31 | """Puts a string in orange.""" 32 | return BEGIN_ORANGE + string + END_EMPH 33 | 34 | 35 | def add_green(string: str) -> str: 36 | """Puts a string in green.""" 37 | return BEGIN_GREEN + string + END_EMPH 38 | 39 | 40 | def add_bold(string: str) -> str: 41 | """Puts a string in bold.""" 42 | return BEGIN_BOLD + string + END_EMPH 43 | -------------------------------------------------------------------------------- /knowledge_clustering/check_update.py: -------------------------------------------------------------------------------- 1 | """ 2 | Checks if there is a newer version of knowledge-clustering available on PyPI. 3 | """ 4 | 5 | import requests 6 | 7 | from knowledge_clustering import _version 8 | from knowledge_clustering.misc import add_bold, add_red, add_orange, add_green 9 | from knowledge_clustering.cst import TIMEOUT_REQUEST 10 | 11 | 12 | def check_update() -> None: 13 | """ 14 | Checks if an update is available, and if so, prints a message in 15 | the string pointer given as input. 16 | """ 17 | # From https://stackoverflow.com/a/62571316/19340201 18 | try: 19 | package = "knowledge-clustering" 20 | response = requests.get( 21 | f"https://pypi.org/pypi/{package}/json", timeout=TIMEOUT_REQUEST 22 | ) 23 | latest_version: str = response.json()["info"]["version"] 24 | is_available: bool = latest_version != _version.VERSION 25 | except requests.exceptions.RequestException: 26 | is_available = False 27 | latest_version = "" 28 | # If available, print message 29 | msg = "" 30 | if is_available: 31 | msg += ( 32 | "\n" 33 | + add_bold(add_orange("[notice]")) 34 | + " A new release of knowledge-clustering is available: " 35 | + add_red(_version.VERSION) 36 | + " -> " 37 | + add_green(latest_version) 38 | ) 39 | msg += ( 40 | "\n" 41 | + add_bold(add_orange("[notice]")) 42 | + " To update, run: " 43 | + add_green("pipx upgrade knowledge-clustering") 44 | ) 45 | print(msg) 46 | -------------------------------------------------------------------------------- /knowledge_clustering/cst.py: -------------------------------------------------------------------------------- 1 | """ 2 | Constants used throughout knowledge-clustering. 3 | """ 4 | 5 | from __future__ import annotations # Support of `|` for type union in Python 3.9 6 | 7 | from pathlib import Path 8 | from importlib import resources 9 | 10 | ALPHA = 0 11 | 12 | CONFIG_FILENAME: dict[str, str] = {"en": "english.ini", "fr": "french.ini"} 13 | ref = resources.files("knowledge_clustering") / "data" 14 | with resources.as_file(ref) as path: 15 | CONFIG_DIR: Path = path 16 | CONFIG_FILE: dict[str, Path] = dict() 17 | for lan, filename in CONFIG_FILENAME.items(): 18 | ref_file = resources.files("knowledge_clustering") / f"data/{filename}" 19 | with resources.as_file(ref_file) as path_file: 20 | CONFIG_FILE[lan] = path_file 21 | NLTK_LANG: dict[str, str] = {"en": "english", "fr": "french"} 22 | 23 | INTRO_DELIMITERS: list[tuple[str, str]] = [ 24 | ('""', '""'), 25 | ("\\intro{", "}"), 26 | ("\\reintro{", "}"), 27 | ("\\phantomintro{", "}"), 28 | ("\\intro[", "]"), 29 | ("\\reintro[", "]"), 30 | ("\\phantomintro[", "]"), 31 | ] 32 | AP_STRING: list[str] = ["\\AP", "\\itemAP"] 33 | 34 | KL_DELIMITERS: list[tuple[str, str]] = [ 35 | ('"', '"'), 36 | ('"', "@"), 37 | ("@", '"'), 38 | ("@", "@"), 39 | ("\\kl{", "}"), 40 | ("\\intro{", "}"), 41 | ("\\reintro{", "}"), 42 | ("\\phantomintro{", "}"), 43 | ("\\kl[", "]"), 44 | ("\\intro[", "]"), 45 | ("\\reintro[", "]"), 46 | ("\\phantomintro[", "]"), 47 | ] 48 | 49 | SEPARATION_HEADING_KL_BLOCK = "************************" 50 | 51 | IMPORTANT_POS = [ 52 | "CD", 53 | "JJ", 54 | "JJR", 55 | "JJS", 56 | "NN", 57 | "NNP", 58 | "NNS", 59 | "PDT", 60 | "RB", 61 | "RBR", 62 | "RBS", 63 | "VB", 64 | "VBD", 65 | "VBG", 66 | "VBN", 67 | "VBP", 68 | "VBZ", 69 | ] 70 | IGNORE_SUFFIXES = ["", "s"] 71 | INFINITY = 10000 72 | IGNORE_CHAR_BACKSLASH = [ 73 | # LaTeX accents defined using non-alphanumerical commands 74 | "\\`", 75 | "\\'", 76 | "\\^", 77 | '\\"', 78 | "\\~", 79 | "\\=", 80 | "\\.", 81 | "\\-", # Hyphen 82 | ] 83 | IGNORE_CHAR_NO_BACKSLASH = ["{", "}"] 84 | SPACE_CHAR = ["~", "\\\\"] 85 | 86 | DISCARD_LINE = "%%%%% NEW KNOWLEDGES " 87 | 88 | TIMEOUT_REQUEST: float = ( 89 | 0.25 # Timeout to resquest the latest version 90 | # of knowledge-clustering (in seconds) 91 | ) 92 | -------------------------------------------------------------------------------- /knowledge_clustering/diagnose.py: -------------------------------------------------------------------------------- 1 | """ 2 | Functions for handling the .diagnose files. 3 | """ 4 | 5 | from __future__ import annotations # Support of `|` for type union in Python 3.9 6 | 7 | from typing import Callable, Generator 8 | from knowledge_clustering import cst 9 | 10 | 11 | def automata_line(state: int, line: str) -> tuple[int, str | None]: 12 | """ 13 | Transition function of a transducers parsing knowledges from a diagnose file, 14 | which is read line by line. 15 | 16 | Args: 17 | state: the curring state of the automata, with the following semantic: 18 | 0: waiting for knowledge block; 19 | 1: seen the heading of a knowledge block; 20 | 2: we are in a knowledge block. 21 | line: a line of the .diagnose document. 22 | 23 | Returns: 24 | a pair (state, kl) where state is the new state of the automaton, 25 | and kl is either None, or a knowledge parsed while reading the line given as input. 26 | """ 27 | if state == 0 and "Undefined knowledges" in line: 28 | return 1, None 29 | if state == 1 and cst.SEPARATION_HEADING_KL_BLOCK in line: 30 | return 2, None 31 | if (state in {0, 2}) and cst.SEPARATION_HEADING_KL_BLOCK in line: 32 | return 0, None 33 | if state == 2 and "| " in line: 34 | s = (line.split("| ", 1)[1]).split("\n", 1)[0] 35 | return 2, s 36 | return state, None 37 | 38 | 39 | def unroll( 40 | automata: Callable[[int, str], tuple[int, str | None]], 41 | initial_state: int, 42 | str_input: list[str], 43 | ) -> Generator[str | None, None, None]: 44 | """Builds a generator object from the transition function of a transducer.""" 45 | state: int = initial_state 46 | z: str | None 47 | for y in str_input: 48 | state, z = automata(state, y) 49 | yield z 50 | 51 | 52 | def parse(filename: str) -> list[str]: 53 | """ 54 | Parses a diagnose file and returns the knowledges it contains. 55 | 56 | Args: 57 | filename: the name of the .diagnose file. 58 | 59 | Returns: 60 | a list of knowledges. 61 | """ 62 | with open(filename, encoding="utf-8") as f: 63 | list_notions = [] 64 | for notion in unroll(automata_line, 0, f.readlines()): 65 | if notion is not None and notion not in list_notions: 66 | list_notions.append(notion) 67 | return list(list_notions) 68 | -------------------------------------------------------------------------------- /knowledge_clustering/autofinder.py: -------------------------------------------------------------------------------- 1 | """Automatically finds files in the current directory.""" 2 | 3 | from __future__ import annotations # Support of `|` for type union in Python 3.9 4 | 5 | from pathlib import Path 6 | 7 | 8 | class NoFile(Exception): 9 | """When no file is found.""" 10 | 11 | 12 | class TooManyFiles(Exception): 13 | """When too many files are found compared to what was expected.""" 14 | 15 | 16 | def find_ext(dr: Path, ext: str) -> list[Path]: 17 | """ 18 | Lists all files present in a directory (and its subdirectory, recursively) 19 | that ends with some given extension. 20 | """ 21 | return list(dr.glob(f"**/*.{ext}")) 22 | 23 | 24 | def get_unique_diagnose_file(dr: Path) -> Path: 25 | """ 26 | Returns the unique .diagnose file present in a directory (and its subdirectory, recursively), 27 | fails otherwise. 28 | """ 29 | dg_files = find_ext(dr, "diagnose") 30 | if len(dg_files) == 0: 31 | raise NoFile("No .diagnose file present in the directory.") 32 | if len(dg_files) > 1: 33 | raise TooManyFiles( 34 | f"Multiple .diagnose files present in the directory: \ 35 | {dg_files[0]} and {dg_files[1]}." 36 | ) 37 | return dg_files[0] 38 | 39 | 40 | def get_knowledge_files(dr: Path) -> list[Path]: 41 | """ 42 | Returns the list of all .kl files present in a directory (and its subdirectory, recursively). 43 | Fails if there is no .kl file. Fails if there are multiple .kl file, but not a unique one 44 | ending with `default.kl`. 45 | """ 46 | kl_files = find_ext(dr, "kl") 47 | if len(kl_files) == 0: 48 | raise NoFile("No .kl file present in the directory.") 49 | if len(kl_files) == 1: 50 | return kl_files 51 | list_default = [] 52 | for i, p in enumerate(kl_files): 53 | if str(p).endswith("default.kl"): 54 | list_default.append(i) 55 | if len(list_default) == 0: 56 | raise NoFile("No file ending with `default.kl` present in the directory.") 57 | if len(list_default) > 1: 58 | raise TooManyFiles( 59 | f"Multiple files ending with `default.kl` present in the directory: \ 60 | {kl_files[list_default[0]]} and {kl_files[list_default[1]]}." 61 | ) 62 | idx_default = list_default[0] 63 | idx_last = len(kl_files) - 1 64 | kl_files[idx_last], kl_files[idx_default] = ( 65 | kl_files[idx_default], 66 | kl_files[idx_last], 67 | ) 68 | return kl_files 69 | -------------------------------------------------------------------------------- /knowledge_clustering/add_anchor.py: -------------------------------------------------------------------------------- 1 | """ 2 | Adding anchor points to a document. 3 | """ 4 | 5 | from __future__ import annotations # Support of `|` for type union in Python 3.9 6 | 7 | import re # Regular expressions 8 | from typing import TextIO 9 | import sys 10 | 11 | from knowledge_clustering.tex_document import TexDocument 12 | from knowledge_clustering import misc, cst 13 | 14 | 15 | def app(tex_filename: str, space: int, out: TextIO = sys.stdout) -> None: 16 | """ 17 | Prints warning when a knowledge is introduced but is not preceded by an anchor point. 18 | Args: 19 | tex_filename: the name of the tex file. 20 | space: an integer specifying the maximal number of characters allowed between the 21 | introduction of a knowledge and an anchor point. 22 | out: an output stream. 23 | """ 24 | with open(tex_filename, "r", encoding="utf-8") as f: 25 | tex_doc = TexDocument(f.read()) 26 | return missing_anchor(tex_doc, space, out) 27 | 28 | 29 | def missing_anchor(tex_doc: TexDocument, space: int, out: TextIO) -> None: 30 | """ 31 | Prints line numbers containing the introduction of a knowledge which 32 | is further away from an anchor point than the integer given as input. 33 | 34 | Args: 35 | tex_doc: a TeX document. 36 | space: the maximal distance between the introduction of a 37 | knowledge and the anchor point preceeding it. 38 | out: an output stream. 39 | """ 40 | # First, compute the list of pairs (i1,i2,i3,i4) corresponding to 41 | # the indices in s = tex_doc.tex_cleaned of some pair in cst.INTRO_DELIMITERS, i.e. 42 | # (s[i1:i2], s[i3:i4]) is in cst.INTRO_DELIMITERS 43 | matches: list[tuple[int, int, int, int]] = [] 44 | is_end_of_match = [False for _ in range(len(tex_doc.tex_cleaned))] 45 | for beg_str, end_str in cst.INTRO_DELIMITERS: 46 | for i_match in re.finditer(re.escape(beg_str), tex_doc.tex_cleaned): 47 | i1: int = i_match.start() 48 | i2: int = i_match.end() 49 | if not is_end_of_match[i1]: 50 | i3: int = i2 + tex_doc.tex_cleaned[i2:].find(end_str) 51 | i4: int = i3 + len(end_str) 52 | if i3 != -1: 53 | matches.append((i1, i2, i3, i4)) 54 | is_end_of_match[i3] = True 55 | matches.sort(key=lambda x: x[0]) 56 | for i1, i2, i3, _ in matches: 57 | beg: int = max(0, i1 - space) 58 | if not any(ap_str in tex_doc.tex_cleaned[beg:i1] for ap_str in cst.AP_STRING): 59 | start_pt: int | None = tex_doc.pointer[i1] 60 | if start_pt is not None: 61 | message: str = f"Missing anchor point at line {tex_doc.find_line[start_pt]} (knowledge: {misc.emph(tex_doc.tex_cleaned[i2:i3])})." 62 | print(message, file=out) 63 | else: 64 | raise IndexError("Undefined pointer", tex_doc.pointer, i1) 65 | -------------------------------------------------------------------------------- /knowledge_clustering/file_updater.py: -------------------------------------------------------------------------------- 1 | """ 2 | Allow to atomically update a file by writing to a temporary 3 | file and comparing hashes. 4 | In case of conflicting uses, the user has to manually merge 5 | and a prompt is offered using click. 6 | """ 7 | 8 | from __future__ import annotations # Support of `|` for type union in Python 3.9 9 | 10 | from pathlib import Path 11 | 12 | import hashlib 13 | import tempfile 14 | import click 15 | 16 | 17 | def hash_file(filepath: str): 18 | """ 19 | Compute a hash of the content of the given filepath 20 | """ 21 | with open(filepath, "rb") as f: 22 | file_hash = hashlib.blake2b() 23 | chunk: bytes = f.read(8192) 24 | while chunk: 25 | file_hash.update(chunk) 26 | chunk = f.read(8192) 27 | return file_hash 28 | 29 | 30 | class AtomicUpdate: 31 | """ 32 | A small class using a temporary file to ensure that we have 33 | properly replaced the content. Prompts the user if we detect 34 | a change in the hash of the file given as input. 35 | """ 36 | 37 | def __init__(self, filename: str, original_hash=None): 38 | self.filename: str = filename 39 | self.hash = hash_file(filename) 40 | self.ctx = tempfile.NamedTemporaryFile(mode="w", dir=Path.cwd(), delete=False) 41 | self.tmp = None 42 | if ( 43 | original_hash is not None 44 | and original_hash.hexdigest() != self.hash.hexdigest() 45 | ): 46 | click.confirm( 47 | f"File {self.filename} has been modified during the run of the program, \ 48 | erase anyway?", 49 | default=None, 50 | abort=True, 51 | prompt_suffix=": ", 52 | show_default=True, 53 | err=False, 54 | ) 55 | 56 | def __enter__(self): 57 | self.tmp = self.ctx.__enter__() # type: ignore 58 | return self.tmp 59 | 60 | def __exit__(self, typ, value, traceback): 61 | new_hash = hash_file(self.filename) 62 | if self.tmp is not None: 63 | if new_hash.hexdigest() != self.hash.hexdigest(): 64 | print(f"{new_hash.hexdigest()} ≠ {self.hash.hexdigest()}") 65 | confirm = click.confirm( 66 | f"File {self.filename} has been modified\ 67 | during the run of \ 68 | the program, erase anyway?", 69 | default=None, 70 | abort=False, 71 | prompt_suffix=": ", 72 | show_default=True, 73 | err=False, 74 | ) 75 | if confirm is False: 76 | print(f"Temporary file accessible at {self.tmp.name}") 77 | return self.ctx.__exit__(typ, value, traceback) 78 | _ = Path(self.tmp.name).replace(self.filename) 79 | return self.ctx.__exit__(typ, value, traceback) 80 | -------------------------------------------------------------------------------- /knowledge_clustering/scope_meaning.py: -------------------------------------------------------------------------------- 1 | """Infer the scope from known knowledges.""" 2 | 3 | from __future__ import annotations # Support of `|` for type union in Python 3.9 4 | from typing import TypeVar 5 | 6 | import copy 7 | 8 | import knowledge_clustering.distance as dist 9 | 10 | T = TypeVar("T") # Generic type 11 | 12 | 13 | def union_list_of_lists(l1: list[T], l2: list[T]) -> list[T]: 14 | """Returns the union (without repetition) of two lists of lists.""" 15 | s = copy.copy(l1) 16 | for sublist in l2: 17 | if sublist not in s: 18 | s.append(sublist) 19 | return s 20 | 21 | 22 | def infer_scope(list_kl: list[str], scope: str, lang: str) -> list[list[str]]: 23 | """ 24 | Takes a list of knowledges that all belong to the same bag and a scope. 25 | 26 | If the list contains a knowledge with this scope, we try to infer the meaning of the scope 27 | by looking at similar knowledges. 28 | 29 | Example: 30 | Running the algorithm on ["word@some-scope", "countable ordinal word", 31 | "ordinal word", "scattered language"] for the scope `some-scope` will return 32 | the list [["countable", "ordinal"], ["ordinal"]]. 33 | """ 34 | result: list[list[str]] = [] 35 | list_kl_broke: list[tuple[list[str], str]] = [ 36 | dist.breakup_notion(kl, lang) for kl in list_kl 37 | ] 38 | for kl1_words, sc1 in list_kl_broke: 39 | if sc1 == scope: 40 | for kl2_words, sc2 in list_kl_broke: 41 | if sc2 == "": 42 | if dist.inclusion_sets_of_words(kl1_words, kl2_words, ("",), lang): 43 | # If every word of kl1 appears in kl2 and kl2 has an empty scope, 44 | # return the words in kl2 not appearing in kl1 45 | result.append([w for w in kl2_words if w not in kl1_words]) 46 | return result 47 | 48 | 49 | def infer_all_scopes( 50 | known_knowledges: list[list[str]], lang: str 51 | ) -> dict[str, list[list[str]]]: 52 | """ 53 | Given known knowledges and a langage, returns the infer meaning of scopes occuring 54 | in said these knowledges. 55 | """ 56 | list_scopes: set[str] = { 57 | sc for bag in known_knowledges for (_, sc) in map(dist.extract_scope, bag) 58 | } 59 | if "" in list_scopes: 60 | list_scopes.remove("") 61 | scopes_meaning: dict[str, list[list[str]]] = {sc: [] for sc in list_scopes} 62 | for scope in list_scopes: 63 | for bag in known_knowledges: 64 | scopes_meaning[scope] = union_list_of_lists( 65 | scopes_meaning[scope], infer_scope(bag, scope, lang) 66 | ) 67 | if [scope] not in scopes_meaning[scope]: 68 | scopes_meaning[scope].append([scope]) 69 | return scopes_meaning 70 | 71 | 72 | def print_scopes( 73 | scopes_meaning: dict[str, list[list[str]]], print_meaning: bool = False 74 | ) -> None: 75 | """Prints the infered meaning of scopes.""" 76 | print("Defined scopes:") 77 | if not print_meaning: 78 | print("\t", list(scopes_meaning.keys())) 79 | else: 80 | for sc in scopes_meaning: 81 | print(f"\t@{sc}:{scopes_meaning[sc]}") 82 | -------------------------------------------------------------------------------- /tests/test_autofinder.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests for the autofinder module. 3 | """ 4 | 5 | from pathlib import Path 6 | 7 | from knowledge_clustering.autofinder import ( 8 | NoFile, 9 | TooManyFiles, 10 | get_unique_diagnose_file, 11 | get_knowledge_files, 12 | ) 13 | 14 | 15 | def test_autofinder() -> None: 16 | """Test function for the functions get_unique_diagnose_file, get_knowledge_files 17 | from the module autofinder.""" 18 | p = Path("tests/testaf/") 19 | p.mkdir() 20 | test_results = [False] * 6 21 | # 0th test with 1 diagnose file and 3 .kl with a unique default file (OK) 22 | (p / "subdir1").mkdir() 23 | (p / "subdir2").mkdir() 24 | (p / "subdir3").mkdir() 25 | (p / "subdir1/coolproject.diagnose").touch() 26 | (p / "subdir2/abbreviations.kl").touch() 27 | (p / "subdir2/main-default.kl").touch() 28 | (p / "subdir3/omega-automata.kl").touch() 29 | # Content of testaf directory: 30 | # - subdir1 31 | # |-- coolproject.diagnose 32 | # - subdir2 33 | # |-- abbreviations.kl 34 | # |-- main-default.kl 35 | # - subdir3 36 | # |-- omega-automata.kl 37 | try: 38 | dg_file = get_unique_diagnose_file(p) 39 | kl_files = get_knowledge_files(p) 40 | if ( 41 | str(dg_file) == "tests/testaf/subdir1/coolproject.diagnose" 42 | and len(kl_files) == 3 43 | and str(kl_files[2]) == "tests/testaf/subdir2/main-default.kl" 44 | ): 45 | test_results[0] = True 46 | except (NoFile, TooManyFiles): 47 | pass 48 | # 1st test with 1 diagnose file and 4 .kl with a two default files (not OK) 49 | (p / "subdir3/secondary-default.kl").touch() 50 | # Content of testaf directory: 51 | # - subdir1 52 | # |-- coolproject.diagnose 53 | # - subdir2 54 | # |-- abbreviations.kl 55 | # |-- main-default.kl 56 | # - subdir3 57 | # |-- omega-automata.kl 58 | # |-- secondary-default.kl 59 | try: 60 | _ = get_knowledge_files(p) 61 | except TooManyFiles: 62 | test_results[1] = True 63 | # 2nd test with 1 diagnose file and 2 .kl with no default files (not OK) 64 | (p / "subdir2/main-default.kl").unlink() 65 | (p / "subdir3/secondary-default.kl").unlink() 66 | # Content of testaf directory: 67 | # - subdir1 68 | # |-- coolproject.diagnose 69 | # - subdir2 70 | # |-- abbreviations.kl 71 | # - subdir3 72 | # |-- omega-automata.kl 73 | try: 74 | _ = get_knowledge_files(p) 75 | except NoFile: 76 | test_results[2] = True 77 | # 3rd test with 1 diagnose file and 1 .kl with no default files (OK) 78 | (p / "subdir2/abbreviations.kl").unlink() 79 | # Content of testaf directory: 80 | # - subdir1 81 | # |-- coolproject.diagnose 82 | # - subdir2 83 | # - subdir3 84 | # |-- omega-automata.kl 85 | try: 86 | _ = get_knowledge_files(p) 87 | test_results[3] = True 88 | except (NoFile, TooManyFiles): 89 | pass 90 | # 4th test with 2 diagnose file and 1 .kl with no default files (not OK) 91 | (p / "subdir2/another-file.diagnose").touch() 92 | # Content of testaf directory: 93 | # - subdir1 94 | # |-- coolproject.diagnose 95 | # - subdir2 96 | # |-- another-file.diagnose 97 | # - subdir3 98 | # |-- omega-automata.kl 99 | try: 100 | _ = get_unique_diagnose_file(p) 101 | except TooManyFiles: 102 | test_results[4] = True 103 | # 5th test with no diagnose file and 1 .kl with no default files (not OK) 104 | (p / "subdir1/coolproject.diagnose").unlink() 105 | (p / "subdir2/another-file.diagnose").unlink() 106 | # Content of testaf directory: 107 | # - subdir1 108 | # - subdir2 109 | # - subdir3 110 | # |-- omega-automata.kl 111 | try: 112 | _ = get_unique_diagnose_file(p) 113 | except NoFile: 114 | test_results[5] = True 115 | # Remove all files and directory created for the test 116 | (p / "subdir3/omega-automata.kl").unlink() 117 | for dirname in ["subdir3", "subdir2", "subdir1", ""]: 118 | (p / dirname).rmdir() 119 | assert all(test_results) 120 | -------------------------------------------------------------------------------- /tests/test_clustering.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests for the modules of knowledge_clustering on which the cluster command is based. 3 | """ 4 | 5 | from typing import TypeVar 6 | from pathlib import Path 7 | import filecmp 8 | import shutil 9 | 10 | from knowledge_clustering.distance import distance, new_stemmer, normalise_notion 11 | from knowledge_clustering.scope_meaning import infer_scope, infer_all_scopes 12 | from knowledge_clustering.clustering import clustering 13 | from knowledge_clustering.knowledges import Knowledges 14 | from knowledge_clustering.diagnose import parse as parse_diagnose 15 | from knowledge_clustering.config import parse as parse_config 16 | from knowledge_clustering.clustering import app as app_clustering 17 | 18 | T = TypeVar("T") # Generic type 19 | 20 | 21 | def test_normalise() -> None: 22 | assert ( 23 | normalise_notion("two-way\\\\rational~relation") == "two-way rational relation" 24 | ) 25 | 26 | 27 | def test_distance() -> None: 28 | """Test functions from the the distance module.""" 29 | assert distance("", "", ("",), {}, "english") == 0 30 | # Tests where only the empty word is allowed as a prefix. No prior scope meaning is known. 31 | assert ( 32 | distance("ordinal semigroup", "ordinal semigroups", ("",), {}, "english") == 0 33 | ) 34 | assert distance("cheval", "chevaux", ("",), {}, "french") == 0 35 | assert distance("cheval", "chevaux", ("",), {}, "english") > 0 36 | # Tests with a scope 37 | assert ( 38 | distance("ordinal semigroup", "semigroups@ordinal", ("",), {}, "english") == 0 39 | ) 40 | assert distance("semigroup", "semigroups@ordinal", ("",), {}, "english") > 0 41 | # Tests with prefixes 42 | assert distance("foo", "turbofoo", ("", "turbo"), {}, "english") == 0 43 | assert distance("foo", "turbofoo", ("",), {}, "english") > 0 44 | assert distance("foo", "megafoo", ("", "turbo"), {}, "english") > 0 45 | assert distance("full", "non-full", ("", "non-"), {}, "english") == 0 46 | # Test with accent and math 47 | assert distance("Büchi", 'B\\"uchi', ("",), {}, "english") == 0 48 | assert ( 49 | distance("Büchi", '\\textsf{$\\omega$-B\\"{u}chi}', ("", "-"), {}, "english") 50 | == 0 51 | ) 52 | # Tests with scope 53 | assert ( 54 | distance("word@ord", "ordinal word", ("",), {"ord": [["ordinal"]]}, "english") 55 | == 0 56 | ) 57 | assert distance("word@ord", "ordinal word", ("",), {}, "english") > 0 58 | # Tests with scope (should be case-insensitive) 59 | assert distance("foo@BaR", "foo@bar", ("",), {}, "english") == 0 60 | # Tests with space 61 | assert distance("foo~bar", "foo bar", ("",), {}, "english") == 0 62 | assert distance("foo\\\\bar", "foo bar", ("",), {}, "english") == 0 63 | assert distance("foo\\\\ bar", "foo bar", ("",), {}, "english") == 0 64 | assert ( 65 | distance( 66 | "two-way\\\\rational@rel", "two-way rational@rel", ("",), {}, "english" 67 | ) 68 | == 0 69 | ) 70 | 71 | 72 | def compare(l1: list[list[T]], l2: list[list[T]]) -> bool: 73 | """Compares if two lists of lists contain the same elements.""" 74 | 75 | def compare_lists(t1: list[T], t2: list[T]) -> bool: 76 | return set(t1) == set(t2) 77 | 78 | for t1 in l1: 79 | if not any(compare_lists(t1, t2) for t2 in l2): 80 | return False 81 | for t2 in l2: 82 | if not any(compare_lists(t1, t2) for t1 in l1): 83 | return False 84 | return True 85 | 86 | 87 | def test_scope_meaning() -> None: 88 | """Tests functions from the module scope_meaning""" 89 | # Test infer_scope 90 | assert compare( 91 | infer_scope( 92 | ["regular language over countable ordinals", "regular languages@ord"], 93 | "ord", 94 | "english", 95 | ), 96 | [["ordinals", "countable"]], 97 | ) 98 | # Test infer_all_scopes 99 | assert compare( 100 | infer_all_scopes( 101 | [ 102 | [ 103 | "word@some-scope", 104 | "foo word", 105 | ], 106 | ["langage@some-scope", "bar langage"], 107 | ], 108 | "english", 109 | )["some-scope"], 110 | [["foo"], ["bar"], ["some-scope"]], 111 | ) 112 | 113 | 114 | def test_clustering() -> None: 115 | """Tests functions from the clustering module.""" 116 | kls = Knowledges("tests/.ordinal.kl.original") 117 | unknown_kl = parse_diagnose("tests/.ordinal.diagnose.original") 118 | list_prefixes = parse_config("knowledge_clustering/data/english.ini") 119 | scopes_meaning = infer_all_scopes(kls.get_all_bags(), "english") 120 | clustering(kls, unknown_kl, 0, list_prefixes, scopes_meaning, "english") 121 | solution = [ 122 | ["word", "words"], 123 | ["word@ord", "countable ordinal word"], 124 | ["regular language over countable ordinals", "regular languages@ord"], 125 | ["separation", "inseparability"], 126 | ["semigroup", "semigroups"], 127 | ] 128 | assert compare(kls.get_all_bags(), solution) 129 | 130 | 131 | def test_app_clustering() -> None: 132 | """Tests the cluster command.""" 133 | for filename in ["ordinal.kl", "ordinal.diagnose"]: 134 | shutil.copy(f"tests/.{filename}.original", f"tests/{filename}") 135 | app_clustering( 136 | ["tests/ordinal.kl"], "tests/ordinal.diagnose", False, False, "en", None 137 | ) 138 | # Diagnose file should be left unchanged… 139 | assert filecmp.cmp( 140 | "tests/ordinal.diagnose", "tests/.ordinal.diagnose.original", shallow=False 141 | ) 142 | # Check if knowledge file has good content 143 | assert filecmp.cmp("tests/ordinal.kl", "tests/.ordinal.kl.solution", shallow=False) 144 | p = Path("tests/") 145 | for filename in ["ordinal.kl", "ordinal.diagnose"]: 146 | (p / filename).unlink() 147 | -------------------------------------------------------------------------------- /examples/ordinal/ordinal.kl: -------------------------------------------------------------------------------- 1 | %%%%% NEW KNOWLEDGES 2 | % 3 | %\knowledge{notion} 4 | % | \FO -separability 5 | % | \FO -separator 6 | % | separates 7 | % | \FO -separation 8 | % | \FO -separable 9 | % | \FO -separated 10 | % | separable 11 | % | inseparability 12 | % | \FO -inseparability 13 | % 14 | %\knowledge{notion} 15 | % | \FO -formula 16 | % 17 | %\knowledge{notion} 18 | % | countable ordinal words 19 | % | Countable ordinal words 20 | % | countable ordinal word 21 | % 22 | %\knowledge{notion} 23 | % | separation problem 24 | % | separation problems 25 | % 26 | %\knowledge{notion} 27 | % | regular languages of countable ordinal words 28 | % 29 | %\knowledge{notion} 30 | % | yes 31 | % 32 | %\knowledge{notion} 33 | % | ie 34 | % 35 | %\knowledge{notion} 36 | % | no 37 | % 38 | %\knowledge{notion} 39 | % | witness function 40 | % 41 | %\knowledge{notion} 42 | % | \FO -sentence 43 | % 44 | %\knowledge{notion} 45 | % | regular languages@COW 46 | % | regular language@cow 47 | % | regular languages@cow 48 | % 49 | %\knowledge{notion} 50 | % | countable ordinals 51 | % | countable ordinal 52 | % 53 | %\knowledge{notion} 54 | % | ordinal monoids 55 | % | ordinal monoid 56 | % 57 | %\knowledge{notion} 58 | % | \FO -pointlike sets 59 | % | pointlike sets 60 | % 61 | %\knowledge{notion} 62 | % | \FO -definable@lang 63 | % 64 | %\knowledge{notion} 65 | % | saturation 66 | % 67 | %\knowledge{notion} 68 | % | \FO -approximant 69 | % | \FO -approximants 70 | % | {\FO }-approximants 71 | % 72 | %\knowledge{notion} 73 | % | aperiodic 74 | % | aperiodicity 75 | % 76 | %\knowledge{notion} 77 | % | syntactic monoid 78 | % 79 | %\knowledge{notion} 80 | % | $\Jeq $-trivial 81 | % 82 | %\knowledge{notion} 83 | % | aperiodic pointlike sets 84 | % 85 | %\knowledge{notion} 86 | % | covering problem 87 | % | covering problems 88 | % | \FO -covering problem 89 | % 90 | %\knowledge{notion} 91 | % | scattered@linord 92 | % 93 | %\knowledge{notion} 94 | % | first-order logic 95 | % 96 | %\knowledge{notion} 97 | % | first-order definable maps 98 | % 99 | %\knowledge{notion} 100 | % | algorithm 101 | % 102 | %\knowledge{notion} 103 | % | pointlikes 104 | % 105 | %\knowledge{notion} 106 | % | linear ordering 107 | % | linear orderings 108 | % 109 | %\knowledge{notion} 110 | % | countable@linord 111 | % 112 | %\knowledge{notion} 113 | % | finite@linord 114 | % 115 | %\knowledge{notion} 116 | % | morphism@linord 117 | % 118 | %\knowledge{notion} 119 | % | isomorphism@linord 120 | % 121 | %\knowledge{notion} 122 | % | sum@linord 123 | % 124 | %\knowledge{notion} 125 | % | product@linord 126 | % 127 | %\knowledge{notion} 128 | % | well-founded 129 | % 130 | %\knowledge{notion} 131 | % | ordinal 132 | % | ordinals 133 | % 134 | %\knowledge{notion} 135 | % | embedding@linord 136 | % 137 | %\knowledge{notion} 138 | % | successor ordinal 139 | % 140 | %\knowledge{notion} 141 | % | limit ordinal 142 | % 143 | %\knowledge{notion} 144 | % | word 145 | % | $\omega $-word 146 | % | words 147 | % | $\omega $-words 148 | % 149 | %\knowledge{notion} 150 | % | domain 151 | % 152 | %\knowledge{notion} 153 | % | countable@word 154 | % | countable words 155 | % 156 | %\knowledge{notion} 157 | % | finite@word 158 | % | finite words 159 | % | finite words 160 | % | finite word 161 | % 162 | %\knowledge{notion} 163 | % | scattered@word 164 | % 165 | %\knowledge{notion} 166 | % | ordinal@linord 167 | % 168 | %\knowledge{notion} 169 | % | omega iteration 170 | % 171 | %\knowledge{notion} 172 | % | semigroup 173 | % | semigroups 174 | % 175 | %\knowledge{notion} 176 | % | monoid 177 | % 178 | %\knowledge{notion} 179 | % | idempotent 180 | % 181 | %\knowledge{notion} 182 | % | idempotent power 183 | % 184 | %\knowledge{notion} 185 | % | group-trivial 186 | % 187 | %\knowledge{notion} 188 | % | generalised product 189 | % 190 | %\knowledge{notion} 191 | % | generalised associativity 192 | % 193 | %\knowledge{notion} 194 | % | ordinal monoid morphism 195 | % 196 | %\knowledge{notion} 197 | % | ordered ordinal monoid 198 | % 199 | %\knowledge{notion} 200 | % | alphabet 201 | % 202 | %\knowledge{notion} 203 | % | recognised@OM 204 | % | recognisable@OM 205 | % | recognising@OM 206 | % 207 | %\knowledge{notion} 208 | % | regular@cow 209 | % 210 | %\knowledge{notion} 211 | % | presentation@OM 212 | % 213 | %\knowledge{notion} 214 | % | power ordinal monoid 215 | % 216 | %\knowledge{notion} 217 | % | Free variables 218 | % | free variables 219 | % 220 | %\knowledge{notion} 221 | % | valuation 222 | % 223 | %\knowledge{notion} 224 | % | word@ord 225 | % | words@ord 226 | % 227 | %\knowledge{notion} 228 | % | satisfies 229 | % 230 | %\knowledge{notion} 231 | % | accepts 232 | % 233 | %\knowledge{notion} 234 | % | Bedon's theorem 235 | % 236 | %\knowledge{notion} 237 | % | \FO -definable@map 238 | % | \FO -definable map 239 | % 240 | %\knowledge{notion} 241 | % | \FO -definable language 242 | % | \FO -definable languages 243 | % 244 | %\knowledge{notion} 245 | % | condensation 246 | % 247 | %\knowledge{notion} 248 | % | condensation formula 249 | % | condensation \FO -formula 250 | % 251 | %\knowledge{notion} 252 | % | finite condensation 253 | % 254 | %\knowledge{notion} 255 | % | \FO -definable functions 256 | % | \FO -definable function 257 | % 258 | %\knowledge{notion} 259 | % | $\omega $-iteration 260 | % | $\omega $-iterations 261 | % 262 | %\knowledge{notion} 263 | % | \FO -separator sentence 264 | % 265 | %\knowledge{notion} 266 | % | quantifier depth 267 | % 268 | %\knowledge{notion} 269 | % | \FOk -equivalent 270 | % 271 | %\knowledge{notion} 272 | % | ordinal monoids with merge 273 | % | ordinal monoid with merge 274 | % 275 | %\knowledge{notion} 276 | % | Merge operators 277 | % | merge operator 278 | % 279 | %\knowledge{notion} 280 | % | Green's relations 281 | % 282 | %\knowledge{notion} 283 | % | \FOk -closure 284 | % 285 | %\knowledge{notion} 286 | % | \FO -covering 287 | % 288 | %\knowledge{notion} 289 | % | aperiodic pointlikes 290 | % 291 | %\knowledge{notion} 292 | % | words of countable ordinal length 293 | % 294 | %\knowledge{notion} 295 | % | words of length~$\omega $ 296 | -------------------------------------------------------------------------------- /knowledge_clustering/clustering.py: -------------------------------------------------------------------------------- 1 | """Clustering algorithm.""" 2 | 3 | from __future__ import annotations # Support of `|` for type union in Python 3.9 4 | from pathlib import Path 5 | 6 | import copy 7 | 8 | from knowledge_clustering import distance, config, scope_meaning, diagnose, cst 9 | from knowledge_clustering.knowledges import KnowledgesList, remove_redundant_files 10 | from knowledge_clustering.misc import emph 11 | 12 | 13 | def app( 14 | kl_filename: list[str], 15 | dg_filename: str, 16 | scope: bool, 17 | print_kl: bool, 18 | lang: str, 19 | config_filename: None | Path, 20 | ): 21 | """ 22 | Defines, as a comment and in the knowledge file, all the knowledges occuring 23 | in the diagnose file. 24 | Args: 25 | kl_filename: the list of name of the knowledge files. 26 | dg_filename: the name of the diagnose file. 27 | scope: a boolean specifying whether the scopes meaning should be printed. 28 | lang: the langage of the document. 29 | config_filename: a configuration file, specifying prefixes to ignore. 30 | """ 31 | kls = KnowledgesList(remove_redundant_files(kl_filename)) 32 | 33 | if config_filename is None: 34 | config_filename = cst.CONFIG_FILE[lang] 35 | 36 | list_prefixes = config.parse(config_filename) 37 | 38 | scopes_meaning = scope_meaning.infer_all_scopes( 39 | kls.get_all_bags(), cst.NLTK_LANG[lang] 40 | ) 41 | if scope: 42 | scope_meaning.print_scopes(scopes_meaning, print_meaning=True) 43 | unknown_knowledges = diagnose.parse(dg_filename) 44 | 45 | if len(unknown_knowledges) == 0: 46 | return 47 | 48 | # update `kl` using the clustering algorithm 49 | clustering( 50 | kls, 51 | unknown_knowledges, 52 | cst.ALPHA, 53 | list_prefixes, 54 | scopes_meaning, 55 | cst.NLTK_LANG[lang], 56 | ) 57 | print( 58 | f"Found a solution by adding {len(kls.get_new_bags())} new bag" 59 | + ("s" if len(kls.get_new_bags()) >= 2 else "") 60 | + ".\n" 61 | ) 62 | changed_filenames = [ 63 | kl.filename for kl in kls.get_all_kls_struct() if kl.was_changed() 64 | ] 65 | if len(changed_filenames) == 0: 66 | msg = "No file was changed." 67 | elif not print_kl: 68 | msg = "The following files were changed:" 69 | for i, fn in enumerate(changed_filenames): 70 | msg += emph(f" {fn}") 71 | msg += "," if i < len(changed_filenames) - 1 else "." 72 | else: 73 | msg = "" 74 | for i, fn in enumerate(changed_filenames): 75 | msg += "Added in file " + emph(f" {fn}") + ":\n" 76 | for kl in kls.get_new_knowledges_in_file(fn): 77 | msg += f"\t{kl}\n" 78 | print(msg) 79 | kls.write_knowledges_in_file() 80 | 81 | 82 | def clustering( 83 | kls: KnowledgesList, 84 | unknown_kl: list[str], 85 | alpha: float, 86 | list_prefixes: list[str], 87 | scopes_meaning: dict[str, list[list[str]]], 88 | lang: str, 89 | ): 90 | """ 91 | Adds all knowledges in unknown_kl to the structure kls. 92 | 93 | The invariant satisfied by the algorithm is the following: 94 | any two notions in the same bag are near, where near either means: 95 | - both in the same bag of knowledges at the beggining of the algorithm ; 96 | - at distance (from module "dist") at most alpha if at least one of 97 | the two notions initially belongs to unknown_kls. 98 | 99 | Args: 100 | kls: known knowledges. 101 | unknown_kl: a list of unknown knowledges. 102 | alpha: a threshold indicating the maximal distance allowed for clustering 103 | two knowkledges together. 104 | list_prefixes: a list of prefixes that are ignored when computing the 105 | distance between two knowledges. 106 | scope_meaning: a dictionnary, assigning to every scope a list of 107 | its possible meanings, each possible meaning being a list of words; 108 | used to compute the distance. 109 | lang: a string describing the language of the document; 110 | a value from the dictionnary knowledge_clustering.app._NLTK_LANG; 111 | used to compute the distance. 112 | """ 113 | kl_processed_old = [] 114 | kl_processed_new = kls.get_all_knowledges() 115 | while unknown_kl: 116 | # If there is no newly processed knowledge, pick an unknown knowledge 117 | # and add it to a new bag. 118 | if not kl_processed_new: 119 | kl = unknown_kl[0] 120 | unknown_kl = unknown_kl[1:] 121 | kls.add_new_bag(kl) 122 | kl_processed_new = [kl] 123 | size_kl_processed_new = len(kl_processed_new) 124 | # Tries to add every unknown knowledge to a bag 125 | unknown_kl_copy = copy.copy(unknown_kl) 126 | for kl in unknown_kl_copy: 127 | dist_min = None 128 | kl2_min_list = [] 129 | # Finds the processed notion that is at a minimal distance from kl 130 | for kl2 in kl_processed_new: 131 | d = distance.distance( 132 | kl, kl2, tuple(list_prefixes), scopes_meaning, lang 133 | ) 134 | if dist_min is None or d < dist_min: 135 | dist_min = d 136 | kl2_min_list = [kl2] 137 | elif d == dist_min: 138 | kl2_min_list.append(kl2) 139 | # If this minimal distance is smaller than the threshold alpha, add kl to the bag 140 | if dist_min is not None and dist_min <= alpha: 141 | # Choose kl2_min in kl2_min_list minimising the edit distance 142 | kl2_min = distance.minimise_levenshtein_distance(kl, kl2_min_list) 143 | # Add kl to the bag of kl2_min 144 | kls.define_synonym_of(kl, kl2_min) 145 | unknown_kl.remove(kl) 146 | kl_processed_new.append(kl) 147 | # Every "new processed knowledge" that was known at the beginning of the while iteration 148 | # becomes an "old processed knowledge" 149 | kl_processed_old += kl_processed_new[:size_kl_processed_new] 150 | kl_processed_new = kl_processed_new[size_kl_processed_new:] 151 | -------------------------------------------------------------------------------- /knowledge_clustering/tex_document.py: -------------------------------------------------------------------------------- 1 | """Handling a Tex document.""" 2 | 3 | from __future__ import annotations # Support of `|` for type union in Python 3.9 4 | from typing import TextIO 5 | 6 | from knowledge_clustering import misc 7 | 8 | 9 | class TexDocument: 10 | """Class for handling a tex document.""" 11 | 12 | def __init__(self, tex_code: str) -> None: 13 | self.tex_code: str = tex_code 14 | self.lines: list[str] = self.tex_code.split("\n") 15 | self.__update_col_line() 16 | self.__clean() 17 | self.length: int = len(self.tex_cleaned) 18 | 19 | def __update_col_line(self) -> None: 20 | """ 21 | Compute two arrays, saying for each index i of self.text, at what column and 22 | what line of the text this index is located. 23 | """ 24 | self.find_line: list[int] = [0] * len(self.tex_code) 25 | self.find_col: list[int] = [0] * len(self.tex_code) 26 | line: int = 1 27 | col: int = 1 28 | for position, letter in enumerate(self.tex_code): 29 | self.find_line[position] = line 30 | self.find_col[position] = col 31 | if letter == "\n": 32 | line += 1 33 | col = 1 34 | else: 35 | col += 1 36 | 37 | def __clean(self): 38 | """ 39 | Reads self.tex_code (the original tex file), given as a single string. 40 | Converts spaces, tabulations and new lines into a single space, except 41 | if there is two consecutive new lines. Removes commented lines. 42 | The cleaned file is stored in self.tex_cleaned. A pointer 43 | from tex_cleaned to tex_code, in the form of an array, is produced in self.pointer. 44 | """ 45 | 46 | # Essentially, the algorithm is a deterministic transducer with five states 47 | # 0: the last character is `normal` (not a space, a tab, nor a new line) ; initial state 48 | # 1: the last character is not normal, 49 | # and no new line was read since the last normal character 50 | # 2: the last character is not normal, 51 | # and exactly one new line was read since the last normal character 52 | # 3: the last character is not normal, 53 | # and at least two new lines were read since the last normal character 54 | # 4: the line is commented. 55 | def is_normal(letter: str) -> bool: 56 | return letter not in [" ", "\t", "\n", "%"] 57 | 58 | def transition( 59 | state: int, letter: str, counter: int 60 | ) -> tuple[int, str, int | None]: 61 | """ 62 | Input: curent state, input letter and the size of produced output so far 63 | Output: returns the new state, the output, and the pointer of the input letter. 64 | """ 65 | if is_normal(letter): 66 | if state == 4: 67 | return (4, "", None) 68 | return (0, letter, counter) 69 | if letter == "%": 70 | return (4, "", None) 71 | if letter == "\n": 72 | if state == 4: 73 | return (0, "", None) 74 | if state == 0: 75 | return (2, " ", None) 76 | if state == 1: 77 | return (2, "", None) 78 | if state == 2: 79 | return (3, "\\par ", counter) 80 | return (3, "", None) 81 | if letter in [" ", "\t"]: 82 | if state == 0: 83 | return (1, " ", counter) 84 | return (state, "", None) 85 | raise KeyError("Transition not defined", state, letter) 86 | 87 | state: int = 0 88 | tex_cleaned: str = "" 89 | m: int = 0 90 | pointer: list[None | int] = [] 91 | for position, letter in enumerate(self.tex_code): 92 | state, output, input_pointer = transition(state, letter, m) 93 | tex_cleaned += output 94 | m += len(output) 95 | # Put position at index input_pointer 96 | if input_pointer is not None: 97 | pointer += [None] * (input_pointer - len(pointer)) + [position] 98 | self.tex_cleaned: str = tex_cleaned 99 | self.pointer: list[None | int] = pointer 100 | 101 | def print(self, start: int, end: int, n: int, out: TextIO): 102 | """ 103 | Prints the lines between positions (in the clean tex) `start` and `end` 104 | together with `n`-1 lines preceding `start`. 105 | Emphasize the part between `start` and `end`. 106 | """ 107 | start_p = self.pointer[start] 108 | end_p = self.pointer[end] 109 | if isinstance(start_p, int) and isinstance(end_p, int): 110 | l_start: int = self.find_line[start_p] 111 | c_start: int = self.find_col[start_p] 112 | l_end: int = self.find_line[end_p] 113 | c_end: int = self.find_col[end_p] 114 | for i in range(max(0, l_start - n), l_end): 115 | if i + 1 == l_start and i + 1 == l_end: 116 | print( 117 | f"l{i+1}: \t{self.lines[i][:c_start-1]}" 118 | + misc.emph(self.lines[i][c_start - 1 : c_end]) 119 | + self.lines[i][c_end:], 120 | file=out, 121 | ) 122 | elif i + 1 == l_start: 123 | print( 124 | f"l{i+1}: \t{self.lines[i][:c_start-1]}" 125 | + misc.emph(self.lines[i][c_start - 1 :]), 126 | file=out, 127 | ) 128 | elif i + 1 == l_end: 129 | print( 130 | f"l{i+1}: \t" 131 | + misc.emph(self.lines[i][:c_end]) 132 | + self.lines[i][c_end:], 133 | file=out, 134 | ) 135 | elif l_start < i + 1 and i + 1 < l_end: 136 | print(f"l{i+1}: \t" + misc.emph(self.lines[i]), file=out) 137 | else: 138 | print(f"l{i+1}: \t{self.lines[i]}", file=out) 139 | else: 140 | raise IndexError("Undefined pointer", self.pointer, (start, end)) 141 | -------------------------------------------------------------------------------- /knowledge_clustering/scripts/app.py: -------------------------------------------------------------------------------- 1 | """ 2 | Launching knowledge commands (init, cluster, addquotes, anchor). 3 | """ 4 | 5 | from __future__ import annotations # Support of `|` for type union in Python 3.9 6 | from pathlib import Path 7 | 8 | import os 9 | import sys 10 | import click 11 | from click_default_group import DefaultGroup # type: ignore 12 | import nltk # type: ignore 13 | 14 | from knowledge_clustering import ( 15 | add_anchor, 16 | add_quotes, 17 | clustering, 18 | cst, 19 | _version, 20 | autofinder, 21 | ) 22 | from knowledge_clustering.check_update import check_update 23 | from knowledge_clustering.misc import add_red, add_bold 24 | 25 | 26 | # https://stackoverflow.com/a/67324391/19340201 27 | class AliasedGroup(DefaultGroup): 28 | """Group where `AP` is a synonym for `anchor`.""" 29 | 30 | def get_command(self, ctx, cmd_name): 31 | if cmd_name in ["anchor", "AP"]: 32 | return DefaultGroup.get_command(self, ctx, "anchor") 33 | return DefaultGroup.get_command(self, ctx, cmd_name) 34 | 35 | 36 | @click.group(cls=AliasedGroup, default="cluster", default_if_no_args=True) 37 | @click.version_option(_version.VERSION) 38 | def cli(): 39 | """Automated notion clustering for the knowledge LaTeX package""" 40 | 41 | 42 | @cli.command() 43 | def init(): 44 | """Downloads the required NLTK packages.""" 45 | nltk.download("punkt") 46 | nltk.download("punkt_tab") 47 | nltk.download("averaged_perceptron_tagger") 48 | nltk.download("averaged_perceptron_tagger_eng") 49 | 50 | 51 | @cli.command() 52 | @click.option( 53 | "--knowledge", 54 | "-k", 55 | "kl_filename", 56 | multiple=True, 57 | type=click.Path( 58 | exists=True, file_okay=True, dir_okay=False, writable=True, readable=True 59 | ), 60 | help="File containing the knowledges that are already defined. \ 61 | Multiple files are allowed; new knowledges will be written in the last one. \ 62 | If the option is not specified, all .kl file in the current directory (and subdirectory, \ 63 | recursively) will be taken. If there are multiple files, exactly one of them must end \ 64 | with `default.kl`.", 65 | required=False, 66 | ) 67 | @click.option( 68 | "--diagnose", 69 | "-d", 70 | "dg_filename", 71 | type=click.Path(exists=True, file_okay=True, dir_okay=False, readable=True), 72 | help="Diagnose file produced by LaTeX. If the option is not specified, the unique \ 73 | .diagnose file in the current directory (and subdirectory, recursively) is taken instead.", 74 | required=False, 75 | ) 76 | @click.option( 77 | "--lang", 78 | "-l", 79 | default="en", 80 | type=click.Choice(["en", "fr"]), 81 | help="Language of your TeX document.", 82 | ) 83 | @click.option( 84 | "--scope/--no-scope", 85 | "-S/ ", 86 | default=False, 87 | help="Print the scopes defined in the knowledge file and print \ 88 | the possible meaning of those scope inferred by knowledge-clustering.", 89 | ) 90 | @click.option( 91 | "--print/--no-print", 92 | "-P/ ", 93 | "print_kl", 94 | default=False, 95 | help="Print all new knowledges.", 96 | ) 97 | @click.option( 98 | "--no-update/--update", 99 | "-N/ ", 100 | "noupdate", 101 | default=False, 102 | help="Don't look on PyPI if a newer version of knowledge-clustering is available.", 103 | ) 104 | @click.option( 105 | "--config-file", 106 | "-c", 107 | "config_filename", 108 | default=None, 109 | help=f"Specify the configuration file. By default the configuration file \ 110 | in the folder {cst.CONFIG_DIR} corresponding to your language is used.", 111 | ) 112 | def cluster( 113 | kl_filename: tuple[str], 114 | dg_filename: str, 115 | lang: str, 116 | scope: bool, 117 | print_kl: bool, 118 | noupdate: bool, 119 | config_filename: None | str, 120 | ): 121 | """ 122 | Defines, as a comment and in the knowledge files, all the knowledges occuring in the file. 123 | """ 124 | try: 125 | if not dg_filename: 126 | dg_filename = autofinder.get_unique_diagnose_file(Path(".")) 127 | kl_filename = list(kl_filename) 128 | if not kl_filename: 129 | kl_filename = autofinder.get_knowledge_files(Path(".")) 130 | clustering.app(kl_filename, dg_filename, scope, print_kl, lang, config_filename) 131 | if not noupdate: 132 | check_update() 133 | except (autofinder.NoFile, autofinder.TooManyFiles) as e: 134 | print(add_bold(add_red("\n[Error] ")) + e.args[0]) 135 | 136 | 137 | @cli.command() 138 | @click.option( 139 | "--tex", 140 | "-t", 141 | "tex_filename", 142 | type=click.Path( 143 | exists=True, file_okay=True, dir_okay=False, writable=True, readable=True 144 | ), 145 | help="Your TeX file.", 146 | required=True, 147 | ) 148 | @click.option( 149 | "--knowledge", 150 | "-k", 151 | "kl_filename", 152 | multiple=True, 153 | type=click.Path( 154 | exists=True, file_okay=True, dir_okay=False, writable=True, readable=True 155 | ), 156 | help="File containing the knowledges that are already defined. \ 157 | Multiple files are allowed; new knowledges will be written in the last one. \ 158 | If the option is not specified, all .kl file in the current directory (and subdirectory, \ 159 | recursively) will be taken. If there are multiple files, exactly one of them must end \ 160 | with `default.kl`.", 161 | required=False, 162 | ) 163 | @click.option( 164 | "--print", 165 | "-p", 166 | "print_line", 167 | type=int, 168 | default=1, 169 | help="When finding a match, number of lines (preceding the match) that are printed \ 170 | in the prompt to the user.", 171 | ) 172 | @click.option( 173 | "--no-update/--update", 174 | "-N/ ", 175 | "noupdate", 176 | default=False, 177 | ) 178 | def addquotes(tex_filename: str, kl_filename: str, print_line: int, noupdate: bool): 179 | """ 180 | Finds knowledges defined in the knowledge files that appear in tex file without quote 181 | symbols. Proposes to add quotes around them. 182 | """ 183 | try: 184 | kl_filename = list(kl_filename) 185 | if not kl_filename: 186 | kl_filename = autofinder.get_knowledge_files(Path(".")) 187 | add_quotes.app(tex_filename, kl_filename, print_line) 188 | if not noupdate: 189 | check_update() 190 | except (autofinder.NoFile, autofinder.TooManyFiles) as e: 191 | print(add_bold(add_red("\n[Error] ")) + e.args[0]) 192 | 193 | 194 | @cli.command() 195 | @click.option( 196 | "--tex", 197 | "-t", 198 | "tex_filename", 199 | type=click.Path( 200 | exists=True, file_okay=True, dir_okay=False, writable=True, readable=True 201 | ), 202 | help="Your TeX file.", 203 | required=True, 204 | ) 205 | @click.option( 206 | "--space", 207 | "-s", 208 | type=int, 209 | default=200, 210 | help="Number of characters tolerated between an anchor point and the introduction \ 211 | of a knowledge. (Default value: 200)", 212 | ) 213 | @click.option( 214 | "--no-update/--update", 215 | "-N/ ", 216 | "noupdate", 217 | default=False, 218 | ) 219 | def anchor(tex_filename: str, space: int, noupdate: bool): 220 | """ 221 | Prints warning when a knowledge is introduced but is not preceded by an anchor point. 222 | """ 223 | add_anchor.app(tex_filename, space) 224 | if not noupdate: 225 | check_update() 226 | 227 | 228 | if __name__ == "__main__": 229 | cli() 230 | -------------------------------------------------------------------------------- /examples/ordinal/ordinal.diagnose: -------------------------------------------------------------------------------- 1 | *********** 2 | * Summary * 3 | *********** 4 | 5 | 181 undefined knowledge(s). 6 | 1 autoreference(s) are introduced twice. 7 | 1 autoreference(s) are used but not introduced. 8 | 9 | 44 autoreference(s) are properly used. 10 | 1 autoreference(s) are defined but not used. 11 | 12 | 13 | ******** 14 | * Help * 15 | ******** 16 | 17 | \knowledgeconfigure{diagnose bar=false} deactivate `|'-notation in diagnose file. 18 | \knowledgeconfigure{diagnose help=false} deactivate long help in the diagnose file. 19 | \knowledgeconfigure{diagnose line=true} add line numbers to diagnose file. 20 | 21 | ************************ 22 | * Undefined knowledges * 23 | ************************ 24 | 25 | \knowledge{ignore} 26 | % introduction.tex:5 27 | | \FO -separability 28 | | \FO -formula 29 | | countable ordinal words 30 | % introduction.tex:6 31 | | separation problem 32 | % introduction.tex:7 33 | | regular languages of countable ordinal words 34 | % introduction.tex:9 35 | | yes 36 | | \FO -separator 37 | % introduction.tex:10 38 | | separates 39 | % introduction.tex:11 40 | | ie 41 | % introduction.tex:12 42 | | no 43 | | witness function 44 | % introduction.tex:13 45 | | \FO -sentence 46 | % introduction.tex:23 47 | | Countable ordinal words 48 | % introduction.tex:24 49 | | regular languages@COW 50 | % introduction.tex:31 51 | | countable ordinals 52 | | ordinal monoids 53 | % introduction.tex:35 54 | | \FO -pointlike sets 55 | | ordinal monoid 56 | % introduction.tex:36 57 | | \FO -definable@lang 58 | | saturation 59 | | \FO -approximant 60 | % introduction.tex:41 61 | | aperiodic 62 | | syntactic monoid 63 | | $\Jeq $-trivial 64 | % introduction.tex:42 65 | | aperiodic pointlike sets 66 | | covering problem 67 | % introduction.tex:46 68 | | covering problems 69 | % introduction.tex:49 70 | | scattered@linord 71 | % introduction.tex:53 72 | | \FO -separation 73 | % introduction.tex:57 74 | | first-order logic 75 | | first-order definable maps 76 | % introduction.tex:58 77 | | algorithm 78 | % introduction.tex:60 79 | | pointlikes 80 | % preliminaries.tex:10 81 | | linear ordering 82 | % preliminaries.tex:11 83 | | countable@linord 84 | | finite@linord 85 | % preliminaries.tex:12 86 | | linear orderings 87 | % preliminaries.tex:13 88 | | morphism@linord 89 | % preliminaries.tex:15 90 | | isomorphism@linord 91 | % preliminaries.tex:16 92 | | morphism@linord 93 | % preliminaries.tex:18 94 | | sum@linord 95 | | product@linord 96 | % preliminaries.tex:42 97 | | well-founded 98 | % preliminaries.tex:44 99 | | ordinal 100 | % preliminaries.tex:45 101 | | isomorphism@linord 102 | % preliminaries.tex:48 103 | | ordinals 104 | % preliminaries.tex:50 105 | | embedding@linord 106 | % preliminaries.tex:53 107 | | successor ordinal 108 | % preliminaries.tex:54 109 | | limit ordinal 110 | % preliminaries.tex:94 111 | | word 112 | % preliminaries.tex:95 113 | | domain 114 | % preliminaries.tex:97 115 | | countable@word 116 | | finite@word 117 | | scattered@word 118 | | $\omega $-word 119 | % preliminaries.tex:98 120 | | countable@linord 121 | | finite@linord 122 | | scattered@linord 123 | % preliminaries.tex:99 124 | | countable ordinal word 125 | | countable@linord 126 | | ordinal@linord 127 | % preliminaries.tex:102 128 | | finite words 129 | % preliminaries.tex:112 130 | | omega iteration 131 | % preliminaries.tex:132 132 | | semigroup 133 | % preliminaries.tex:133 134 | | monoid 135 | % preliminaries.tex:137 136 | | idempotent 137 | % preliminaries.tex:139 138 | | idempotent power 139 | % preliminaries.tex:147 140 | | group-trivial 141 | % preliminaries.tex:150 142 | | countable ordinal 143 | % preliminaries.tex:152 144 | | words 145 | % preliminaries.tex:168 146 | | generalised product 147 | % preliminaries.tex:177 148 | | generalised associativity 149 | % preliminaries.tex:186 150 | | ordinal monoid morphism 151 | % preliminaries.tex:192 152 | | ordered ordinal monoid 153 | % preliminaries.tex:196 154 | | alphabet 155 | | recognised@OM 156 | % preliminaries.tex:200 157 | | recognisable@OM 158 | % preliminaries.tex:201 159 | | recognisable@OM 160 | % preliminaries.tex:202 161 | | regular@cow 162 | % preliminaries.tex:236 163 | | presentation@OM 164 | % preliminaries.tex:244 165 | | power ordinal monoid 166 | % preliminaries.tex:299 167 | | Free variables 168 | % preliminaries.tex:300 169 | | free variables 170 | % preliminaries.tex:303 171 | | valuation 172 | % preliminaries.tex:304 173 | | word@ord 174 | % preliminaries.tex:310 175 | | word@ord 176 | % preliminaries.tex:315 177 | | satisfies 178 | | accepts 179 | % preliminaries.tex:319 180 | | \FO -definable@lang 181 | % preliminaries.tex:321 182 | | words@ord 183 | % preliminaries.tex:339 184 | | Bedon's theorem 185 | % preliminaries.tex:341 186 | | \FO -definable@lang 187 | % preliminaries.tex:342 188 | | recognised@OM 189 | % preliminaries.tex:348 190 | | \FO -definable@map 191 | % preliminaries.tex:350 192 | | \FO -definable language 193 | % preliminaries.tex:352 194 | | \FO -definable@map 195 | % preliminaries.tex:375 196 | | \FO -definable@map 197 | % preliminaries.tex:378 198 | | \FO -definable@map 199 | % preliminaries.tex:397 200 | | condensation 201 | % preliminaries.tex:407 202 | | condensation formula 203 | % preliminaries.tex:425 204 | | finite condensation 205 | % preliminaries.tex:432 206 | | word@ord 207 | % preliminaries.tex:437 208 | | \FO -definable functions 209 | % preliminaries.tex:438 210 | | \FO -definable function 211 | % preliminaries.tex:444 212 | | condensation \FO -formula 213 | % preliminaries.tex:452 214 | | \FO -definable@map 215 | % algorithm.tex:84 216 | | recognised@OM 217 | % algorithm.tex:122 218 | | $\omega $-iteration 219 | % algorithm.tex:160 220 | | words@ord 221 | | words@ord 222 | | words@ord 223 | | words@ord 224 | | words@ord 225 | | words@ord 226 | | words@ord 227 | | words@ord 228 | | words@ord 229 | | words@ord 230 | | words@ord 231 | | words@ord 232 | | words@ord 233 | | words@ord 234 | | words@ord 235 | | words@ord 236 | | words@ord 237 | | words@ord 238 | | words@ord 239 | | words@ord 240 | | words@ord 241 | | words@ord 242 | | words@ord 243 | | words@ord 244 | % algorithm.tex:182 245 | | \FO -definable@lang 246 | | recognising@OM 247 | % algorithm.tex:186 248 | | presentation@OM 249 | % algorithm.tex:193 250 | | \FO -separable 251 | % algorithm.tex:206 252 | | \FO -separator sentence 253 | % algorithm.tex:207 254 | | pointlike sets 255 | % answer-no.tex:10 256 | | quantifier depth 257 | % answer-no.tex:12 258 | | \FOk -equivalent 259 | % answer-no.tex:61 260 | | \FO -separated 261 | % answer-no.tex:164 262 | | \FO -inseparability 263 | % answer-yes.tex:8 264 | | ordinal monoids with merge 265 | % answer-yes.tex:9 266 | | \FO -approximants 267 | | \FO -definable@map 268 | % answer-yes.tex:10 269 | | ordinal monoid with merge 270 | % answer-yes.tex:11 271 | | $\omega $-words 272 | % answer-yes.tex:13 273 | | Merge operators 274 | | {\FO }-approximants 275 | % answer-yes.tex:19 276 | | presentation@OM 277 | % answer-yes.tex:20 278 | | merge operator 279 | % answer-yes.tex:33 280 | | \FO -definable@map 281 | % answer-yes.tex:35 282 | | \FO -definable map 283 | % answer-yes.tex:67 284 | | \FO -definable@map 285 | | \FO -definable@lang 286 | % answer-yes.tex:89 287 | | regular language@cow 288 | | recognised@OM 289 | % answer-yes.tex:91 290 | | aperiodicity 291 | % answer-yes.tex:106 292 | | words@ord 293 | % answer-yes.tex:219 294 | | \FO -definable@lang 295 | % answer-yes.tex:261 296 | | Green's relations 297 | % answer-yes.tex:347 298 | | \FO -definable@lang 299 | % answer-yes.tex:348 300 | | \FO -definable@map 301 | % related.tex:10 302 | | \FO -covering problem 303 | % related.tex:11 304 | | regular languages@cow 305 | | \FO -definable languages 306 | % related.tex:12 307 | | separation problems 308 | % related.tex:13 309 | | separable 310 | % related.tex:20 311 | | \FOk -closure 312 | % related.tex:38 313 | | semigroups 314 | % related.tex:53 315 | | \FO -covering 316 | % related.tex:55 317 | | aperiodic pointlikes 318 | % related.tex:60 319 | | finite words 320 | % conclusion.tex:5 321 | | words of countable ordinal length 322 | | words of length~$\omega $ 323 | % conclusion.tex:8 324 | | $\omega $-words 325 | % conclusion.tex:12 326 | | $\omega $-iterations 327 | % conclusion.tex:15 328 | | finite word 329 | % conclusion.tex:18 330 | | scattered@word 331 | | countable words 332 | | scattered@word 333 | | inseparability 334 | | semigroup 335 | | words 336 | | semigroups 337 | | countable ordinal word 338 | 339 | **************************** 340 | * autoref-introduced-twice * 341 | **************************** 342 | 343 | % answer-yes.tex:66 344 | answer-yes.tex:66: {\singordmap }{default}{base} 345 | answer-yes.tex:66: {\singordmap }{default}{base} 346 | 347 | 348 | ****************************** 349 | * Autoref used without intro * 350 | ****************************** 351 | 352 | % macros.tex:303 353 | \nointro{default}{base}{\Jeq } 354 | 355 | 356 | *********************************** 357 | * Autoref introduced but not used * 358 | *********************************** 359 | 360 | % macros.tex:157 361 | macros.tex:157: {\lessord }{default}{base} 362 | 363 | 364 | -------------------------------------------------------------------------------- /knowledge_clustering/distance.py: -------------------------------------------------------------------------------- 1 | """Compute the distance between two knowledges.""" 2 | 3 | from __future__ import annotations # Support of `|` for type union in Python 3.9 4 | 5 | import copy 6 | import nltk # type: ignore 7 | import nltk.stem.snowball as nss # type: ignore 8 | from unidecode import unidecode 9 | from functools import cache 10 | 11 | from knowledge_clustering import cst 12 | from knowledge_clustering.misc import emph 13 | 14 | # --- 15 | # Edit distance 16 | # --- 17 | 18 | 19 | def levenshtein_distance(s: str, t: str) -> int: 20 | """ 21 | Computes the Levenshtein (insertions, deletions or substitutions are allowed) 22 | edit distance between two strings. 23 | """ 24 | # Implementation of the Wagner–Fischer algorithm 25 | # https://en.wikipedia.org/wiki/Wagner%E2%80%93Fischer_algorithm 26 | m, n = len(s), len(t) 27 | dist = [[0 for _ in range(n + 1)] for _ in range(m + 1)] 28 | for i in range(1, m + 1): 29 | dist[i][0] = i 30 | for j in range(1, n + 1): 31 | dist[0][j] = j 32 | for j in range(1, n + 1): 33 | for i in range(1, m + 1): 34 | substitution_cost = 0 if s[i - 1] == t[j - 1] else 1 35 | dist[i][j] = min( 36 | dist[i - 1][j] + 1, 37 | dist[i][j - 1] + 1, 38 | dist[i - 1][j - 1] + substitution_cost, 39 | ) 40 | return dist[m][n] 41 | 42 | 43 | def minimise_levenshtein_distance(s: str, t_list: list[str]) -> str: 44 | """ 45 | Given a string s, and a non-empty list of strings, returns an element of t_list 46 | minimising the edit distance with s. 47 | """ 48 | t_min = t_list[0] 49 | dist_min = levenshtein_distance(s, t_min) 50 | for t in t_list[1:]: 51 | dist = levenshtein_distance(s, t) 52 | if dist < dist_min: 53 | t_min = t 54 | dist_min = dist 55 | return t_min 56 | 57 | 58 | # --- 59 | # Functions to extract content from strings 60 | # --- 61 | 62 | 63 | def extract_scope(notion: str) -> tuple[str, str]: 64 | """ 65 | Given a notion of the form "knowledge@scope" or "knowledge", 66 | returns a pair consisting of the knowledge and the (possibly empty) scope. 67 | """ 68 | if "@" in notion: 69 | s = notion.split("@", 1) 70 | return s[0], s[1] 71 | return notion, "" 72 | 73 | 74 | def normalise_notion(notion: str) -> str: 75 | """ 76 | Returns the substring of a notion obtained by removing math, commands, accents 77 | and non-brekable spaces. 78 | """ 79 | notion_norm = notion.lower() # to lowercase 80 | while "$" in notion_norm: 81 | sp = notion_norm.split("$", 2) 82 | if len(sp) <= 1: 83 | break 84 | notion_norm = sp[0] + sp[2] 85 | for remove_char in cst.IGNORE_CHAR_BACKSLASH: 86 | while remove_char in notion_norm: 87 | # If the notion contains remove_char, remove it. 88 | sp = notion_norm.split(remove_char, 1) 89 | notion_norm = sp[0] + sp[1] 90 | for space_char in cst.SPACE_CHAR: 91 | while space_char in notion_norm: 92 | # If the notion contains remove_char, replace it with a space. 93 | sp = notion_norm.split(space_char, 1) 94 | notion_norm = sp[0] + " " + sp[1] 95 | while "\\" in notion_norm: 96 | # If the notion contains a backslash, remove every letter following the backslash 97 | # see https://tex.stackexchange.com/a/34381/206008 for naming conventions of TeX commands 98 | sp = notion_norm.split("\\", 1) 99 | pref, suff = sp[0], sp[1] 100 | i = 0 101 | while i < len(suff) and suff[i].isalpha(): 102 | i += 1 103 | notion_norm = pref + suff[i:] 104 | for remove_char in cst.IGNORE_CHAR_NO_BACKSLASH: 105 | while remove_char in notion_norm: 106 | # If the notion contains remove_char, remove it. 107 | sp = notion_norm.split(remove_char, 1) 108 | notion_norm = sp[0] + sp[1] 109 | return unidecode(notion_norm) # Ascii-fy (in particular, remove accents) the result 110 | 111 | 112 | @cache 113 | def cached_tokenize(word: str, lang: str) -> list[str]: 114 | return nltk.word_tokenize(word, language=lang) 115 | 116 | 117 | @cache 118 | def cached_POStag(tokens: tuple[str, ...]) -> list: 119 | return nltk.pos_tag(list(tokens)) 120 | 121 | 122 | def breakup_notion(notion: str, lang: str) -> tuple[list[str], str]: 123 | """ 124 | Takes a notion, and a language, and returns 125 | a set of words contained in the notion. 126 | 127 | If the language is `english`, remove unimportant words. 128 | Important words are: cardinals, preposition or conjunction, subordinating, 129 | adjectives, nouns, pre-determiners, adverbs, verbs (list defined in cst.IMPORTANT_POS). 130 | 131 | """ 132 | kl, scope = extract_scope(normalise_notion(notion)) 133 | try: 134 | if lang == "english": 135 | words_with_POStag = cached_POStag(tuple(cached_tokenize(kl, lang))) 136 | important_words = { 137 | w for (w, pos) in words_with_POStag if pos in cst.IMPORTANT_POS 138 | } 139 | return (list(important_words), scope) 140 | return (list(set(cached_tokenize(kl, lang))), scope) 141 | except LookupError as e: 142 | raise LookupError( 143 | f"Missing NLTK data. Run `" 144 | + emph("knowledge init") 145 | + "` before using the cluster command." 146 | ) from e 147 | 148 | 149 | # --- 150 | # Computing the distance between two notions 151 | # --- 152 | 153 | 154 | @cache 155 | def similar_words(w1: str, w2: str, prefixes: tuple[str, ...], lang: str) -> bool: 156 | """ 157 | Checks if two words w1 and w2 are similar up to taking their stem (removing a suffix) 158 | and removing a prefix in the list `prefixes`. 159 | """ 160 | 161 | def asymmetric_similar(s1: str, s2: str) -> bool: 162 | if s1 in s2: 163 | for p in prefixes: 164 | if s2.startswith(p): 165 | for s in cst.IGNORE_SUFFIXES: 166 | if p + s1 + s == s2: 167 | return True 168 | return False 169 | 170 | if w1 == w2: 171 | return True 172 | for s1 in [w1, cached_stem(w1, lang)]: 173 | for s2 in [w2, cached_stem(w2, lang)]: 174 | if asymmetric_similar(s1, s2) or asymmetric_similar(s2, s1): 175 | return True 176 | return False 177 | 178 | 179 | def __semi_distance_sets_of_words( 180 | set_words1: list[str], set_words2: list[str], prefixes: tuple[str, ...], lang: str 181 | ) -> tuple[int, int]: 182 | """ 183 | Given two sets of words (considered up to permutation), computes the 184 | numbers of words of w1 that aren't close to a word of w2 and reciprocally. 185 | """ 186 | for w1 in set_words1: 187 | similar_to_w1 = [ 188 | w2 for w2 in set_words2 if similar_words(w1, w2, prefixes, lang) 189 | ] 190 | # If you find a pair of similar words, remove them. 191 | if len(similar_to_w1) > 0: 192 | w2 = similar_to_w1[0] 193 | set_words1.remove(w1) 194 | set_words2.remove(w2) 195 | return __semi_distance_sets_of_words(set_words1, set_words2, prefixes, lang) 196 | return (len(set_words1), len(set_words2)) 197 | 198 | 199 | def inclusion_sets_of_words( 200 | set_words1: list[str], set_words2: list[str], prefixes: tuple[str, ...], lang: str 201 | ) -> bool: 202 | """ 203 | Given two sets of words (considered up to permutation), are 204 | all words of the first set similar to words of the second set? 205 | """ 206 | d1, _ = __semi_distance_sets_of_words(set_words1, set_words2, prefixes, lang) 207 | return d1 == 0 208 | 209 | 210 | def distance_sets_of_words( 211 | set_words1: list[str], set_words2: list[str], prefixes: tuple[str, ...], lang: str 212 | ) -> int: 213 | """ 214 | Given two sets of words (considered up to permutation), computes the distance between them. 215 | """ 216 | d1, d2 = __semi_distance_sets_of_words(set_words1, set_words2, prefixes, lang) 217 | return d1 + d2 218 | 219 | 220 | @cache # todo check if useful 221 | def new_stemmer(lang: str): 222 | """Returns a stemmer.""" 223 | return nss.SnowballStemmer(lang) 224 | 225 | 226 | @cache 227 | def cached_stem(word: str, lang: str): 228 | return new_stemmer(lang).stem(word) 229 | 230 | 231 | def distance( 232 | notion1: str, 233 | notion2: str, 234 | prefixes: tuple[str, ...], 235 | scopes_meaning: dict[str, list[list[str]]], 236 | lang: str, 237 | ) -> int: 238 | """ 239 | Measures the distance between two notions, given a list of prefixes to ignore and 240 | a list of possible meaning for each scope. 241 | Args: 242 | notion1: first notion 243 | notion2: second notion 244 | prefixes: a list of prefixes that will be ignored 245 | scope_meaning: a dictionnary, assigning to every scope a list of 246 | its possible meanings, each possible meaning being a list of words 247 | lang: the identifier of some language (e.g. "english") 248 | 249 | Returns: 250 | The distance between notion1 and notion2. 251 | """ 252 | kl1_words, sc1 = breakup_notion(notion1, lang) 253 | kl2_words, sc2 = breakup_notion(notion2, lang) 254 | if sc1 != "" and sc2 != "" and sc1 != sc2: 255 | return cst.INFINITY 256 | if len(kl1_words) == 0 and len(kl2_words) == 0: 257 | # Can happen if the notion is a command 258 | return 0 259 | if len(kl1_words) == 0 or len(kl2_words) == 0: 260 | # Can happen if the notion is a command 261 | return cst.INFINITY 262 | if sc1 == sc2: 263 | return distance_sets_of_words(kl1_words, kl2_words, prefixes, lang) 264 | if sc1 == "": 265 | kl1_words, sc1, kl2_words, sc2 = kl2_words, sc2, kl1_words, sc1 266 | # sc2 is empty and sc1 isn't 267 | # return the minimal distance obtained by replacing sc1 by one of its possible meanings 268 | dist = cst.INFINITY 269 | if sc1 in scopes_meaning: 270 | sc1_meaning = scopes_meaning[sc1] 271 | else: 272 | sc1_meaning = [[sc1]] 273 | for meaning in sc1_meaning: 274 | kl1_with_meaning = list(copy.copy(kl1_words)) 275 | kl1_with_meaning.extend([w for w in meaning if w not in kl1_with_meaning]) 276 | dist = min( 277 | dist, 278 | distance_sets_of_words(kl1_with_meaning, kl2_words, prefixes, lang), 279 | ) 280 | return dist 281 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # knowledge-clustering 2 | 3 | [![PyPI](https://img.shields.io/pypi/v/knowledge-clustering.svg)](https://pypi.python.org/pypi/knowledge-clustering) 4 | 5 | Command-line tool to help with the use of the [knowledge LaTeX package](https://ctan.org/pkg/knowledge). 6 | A tutorial on how to use both `knowledge` and `knowledge-clustering` can be found [here](https://github.com/remimorvan/knowledge-examples). 7 | 8 | ## Principle 9 | 10 | The goal of `knowledge-clustering` is to help the user write a LaTeX document with 11 | the [knowledge package](https://ctan.org/pkg/knowledge). 12 | It has three features: 13 | 14 | - **Clustering**: provide suggestions to the user of what notions should be grouped together. 15 | - **Add quotes**: find where you might have missed some quotes in your document. 16 | - **Anchor points**: find where you might have missed anchor points in your document. 17 | 18 | The **clustering** algorithm is meant to be used while writing your document, while the last two tools 19 | should be used when your document is (nearly) ready to be published, to check if everything is right. 20 | 21 | ## Installation 22 | 23 | To **install** `knowledge-clustering`, you need to have Python 3.9 (or a more recent version), and then run 24 | 25 | python3 -m pip install --user pipx 26 | python3 -m pipx ensurepath 27 | 28 | and then, in a new terminal, 29 | 30 | pipx install knowledge 31 | knowledge init 32 | 33 | To check if you have the latest version of `knowledge-clustering`, you can run 34 | 35 | knowledge --version 36 | 37 | To **upgrade**, simply run 38 | 39 | pipx upgrade knowledge-clustering 40 | 41 | ## Clustering notions 42 | 43 | ### Syntax 44 | 45 | ``` 46 | Usage: knowledge cluster [OPTIONS] 47 | 48 | Defines, as a comment and in the knowledge files, all the knowledges 49 | occuring in the file. 50 | 51 | Options: 52 | -k, --knowledge FILE File containing the knowledges that are already 53 | defined. Multiple files are allowed; new 54 | knowledges will be written in the last one. If 55 | the option is not specified, all .kl file in the 56 | current directory (and subdirectory, 57 | recursively) will be taken. If there are 58 | multiple files, exactly one of them must end 59 | with `default.kl`. 60 | -d, --diagnose FILE Diagnose file produced by LaTeX. If the option 61 | is not specified, the unique .diagnose file in 62 | the current directory (and subdirectory, 63 | recursively) is taken instead. 64 | -l, --lang [en|fr] Language of your TeX document. 65 | -S, --scope / --no-scope Print the scopes defined in the knowledge file 66 | and print the possible meaning of those scope 67 | inferred by knowledge-clustering. 68 | -P, --print / --no-print Print all new knowledges. 69 | -N, --no-update / --update Don't look on PyPI if a newer version of 70 | knowledge-clustering is available. 71 | -c, --config-file TEXT Specify the configuration file. By default the 72 | configuration file in the folder 73 | /Users/rmorvan/knowledge- 74 | clustering/knowledge_clustering/data 75 | corresponding to your language is used. 76 | --help Show this message and exit. 77 | ``` 78 | 79 | ### Example 80 | 81 | Example files can be found in the `examples/` folder. 82 | 83 | While writing some document, you have defined some knowledges in a file called `preservation.kl` (distinct 84 | from your main `LaTeX`). 85 | You continued writing your `LaTeX` document (not provided in the `examples/` folder) 86 | for some time, and used some knowledges that were undefined. 87 | When compiling, `LaTeX` and the [`knowledge package`](https://ctan.org/pkg/knowledge) gives you a warning 88 | and writes in a `.diagnose` file some information explaining what went wrong. This `.diagnose` file contains 89 | a section called "Undefined knowledges" containing all knowledges used in your main `LaTeX` file but not 90 | defined in `preservation.kl`. We reproduced this section 91 | in the `preservation.diagnose` file. 92 | 93 | ![Screenshot of the `preservation.kl` and `preservation.diagnose` files before running knowledge-clustering. `preservation.kl` contains three knowledges, while `preservation.diagnose` contains five undefined knowledges.](img/preservation-before.png "Files `preservation.kl` and `preservation.diagnose` before running knowledge-clustering") 94 | 95 | Normally, you would add every undefined knowledge, one after the other, in your 96 | `preservation.kl`. This is quite burdensome and can 97 | largely be automated. This is precisely what `knowledge-clustering` does: after running 98 | 99 | knowledge cluster -k preservation.kl -d preservation.diagnose 100 | 101 | your file `preservation.diagnose` is left unchanged 102 | but `preservation.kl` is updated with comments. 103 | 104 | The `cluster` command is optional: you can also write `knowledge -k preservation.kl -d preservation.diagnose`. 105 | 106 | ![After running knowledge-clustering, the five undefined knowledges are included in the `preservation.kl` file as comments.](img/preservation-after.png "Files `preservation.kl` and `preservation.diagnose` after running knowledge-clustering`") 107 | 108 | Now you simply have to check that the recommendations of `knowledge-clustering` are 109 | correct, and uncomment those lines. 110 | 111 | ### Autofinder 112 | 113 | If the current directory (and its recursive subdirectories) contains 114 | a unique `.diagnose` file and a unique `.kl` file, 115 | you can simply write `knowledge cluster` (or `knowledge`): the files will be automatically found. 116 | 117 | ### Multiple knowledge files 118 | 119 | If you have **multiple knowledge files**, you can use the `-k` option multiple times. 120 | For instance, you could write: 121 | 122 | knowledge cluster -k 1.kl -k 2.kl -d ordinal.diagnose 123 | 124 | Synonyms of knowledges defined in `1.kl` (resp. `2.kl`) will be defined, as comments, 125 | in `1.kl` (resp. `2.kl`). New knowledges will always be added, as comments, to the last 126 | file, which is `2.kl` in the example. 127 | 128 | You can also use the autofinder in this case, using `knowledge cluster` 129 | or `knowledge`: if multiple `.kl` files are present in the current directory (and 130 | its recursive subdirectories), exactly one of them must end with `default.kl`—this is 131 | where new knowledges will be put. 132 | 133 | ## Adding quotes 134 | 135 | /!\ This feature is somewhat experimental. 136 | 137 | ``` 138 | Usage: knowledge addquotes [OPTIONS] 139 | 140 | Finds knowledges defined in the knowledge files that appear in tex file 141 | without quote symbols. Proposes to add quotes around them. 142 | 143 | Options: 144 | -t, --tex FILE Your TeX file. [required] 145 | -k, --knowledge FILE File containing the knowledges that are already 146 | defined. Multiple files are allowed; new 147 | knowledges will be written in the last one. If 148 | the option is not specified, all .kl file in the 149 | current directory (and subdirectory, 150 | recursively) will be taken. If there are 151 | multiple files, exactly one of them must end 152 | with `default.kl`. 153 | -p, --print INTEGER When finding a match, number of lines (preceding 154 | the match) that are printed in the prompt to the 155 | user. 156 | -N, --no-update / --update 157 | --help Show this message and exit. 158 | ``` 159 | 160 | After running 161 | 162 | knowledge addquotes -t mydocument.tex -k knowledges1.kl -k knowledges2.kl 163 | 164 | your prompt will propose to add quotes around defined knowledges, 165 | and to define synonyms of knowledges that occur in your TeX file. For instance, if 166 | "algorithm" is a defined knowledge and "algorithms" occurs in your TeX file, then 167 | it will propose to you to define "algorithms" as a synonym of the knowledge "algorithm", 168 | and to add a pair of quotes around the string "algorithms" that occurs in your TeX file. 169 | 170 | Whenever the algorithm finds a match for a knowledge, it will print the line of 171 | the document where it found the match, and emphasize the string corresponding to the knowledge. 172 | If you want to print more than one line, you can use the `-p` (or `--print`) option 173 | to print more than one line. 174 | 175 | ## Finding missing anchor points 176 | 177 | ``` 178 | Usage: knowledge anchor [OPTIONS] 179 | 180 | Prints warning when a knowledge is introduced but is not preceded by an 181 | anchor point. 182 | 183 | Options: 184 | -t, --tex FILE Your TeX file. [required] 185 | -s, --space INTEGER Number of characters tolerated between an anchor 186 | point and the introduction of a knowledge. 187 | (Default value: 200) 188 | -N, --no-update / --update 189 | --help Show this message and exit. 190 | ``` 191 | 192 | When one runs 193 | 194 | knowledge anchor -t mydocument.tex 195 | 196 | the tool will print the lines of the document containing the 197 | introduction of a knowledge that is not preceded by an anchor point. 198 | The tolerance on how far away the anchor point can be from the 199 | introduction of a knowledge can be changed with the `-s` (or `--space`) 200 | option. The default value is 150 characters (corresponding to 2-3 lines in a 201 | TeX document). 202 | 203 | ## Devel using virtualenv 204 | 205 | Using `venv` and the `--editable` option from `pip` allows for an easy 206 | setup of a development environment that will match a future user install without 207 | the hassle. 208 | 209 | For bash and Zsh users 210 | 211 | ```bash 212 | python3 -m venv kl.venv 213 | source ./kl.venv/bin/activate 214 | python3 -m pip install --editable . 215 | ``` 216 | 217 | For fish users 218 | 219 | ```fish 220 | python3 -m venv kl.venv 221 | source ./kl.venv/bin/activate.fish 222 | python3 -m pip install --editable . 223 | ``` 224 | 225 | ## FAQ 226 | 227 | - `knowledge: command not found` after installing `knowledge-clustering` 228 | > Try running it in a new terminal (or source your `.*rc` file). 229 | > Make sure you have Python>=3.9. 230 | 231 | - When running `knowledge`, I obtain a long message error indicating "Resource punkt not found." 232 | > Run `knowledge init`. 233 | 234 | - `Error: Got unexpected extra argument` when using multiple knowledge files. 235 | > You should use the option `-k` before **every** knowledge file, like in 236 | > 237 | > knowledge cluster -k 1.kl -k 2.kl -d blabla.diagnose 238 | 239 | -------------------------------------------------------------------------------- /knowledge_clustering/add_quotes.py: -------------------------------------------------------------------------------- 1 | """ 2 | Add missing quotes around knowledges occuring in a TeX document. 3 | """ 4 | 5 | from __future__ import annotations # Support of `|` for type union in Python 3.9 6 | 7 | import re # Regular expressions 8 | from typing import NamedTuple, TextIO 9 | import sys 10 | 11 | from knowledge_clustering.knowledges import KnowledgesList, remove_redundant_files 12 | from knowledge_clustering.tex_document import TexDocument 13 | from knowledge_clustering import file_updater, misc, cst 14 | 15 | 16 | class NewKL(NamedTuple): 17 | """ 18 | Object storing a new knowledge, together with its starting and ending point in some TeX 19 | document, together with a smaller knowledge, that is already known, and is a substring of 20 | the knowledge. 21 | """ 22 | 23 | kl_origin: str 24 | start_origin: int 25 | end_origin: int 26 | kl: str 27 | start: int 28 | end: int 29 | 30 | 31 | class AddQuote(NamedTuple): 32 | """ 33 | Stores the starting and ending indexes of the occurence of some knowledge in a TeX document. 34 | """ 35 | 36 | kl: str 37 | start: int 38 | end: int 39 | 40 | 41 | def ask_consent(message: str, inp: TextIO, out: TextIO): 42 | """ 43 | Asks whether the user wants to do an action, after printing the string `message`. 44 | Returns a boolean. 45 | """ 46 | print(message, file=out) 47 | ans = inp.readline().rstrip("\n") 48 | return ans.lower() in ["y", "yes"] 49 | 50 | 51 | def app( 52 | tex_filename: str, 53 | kl_filenames: list[str], 54 | print_line: int, 55 | inp: TextIO = sys.stdin, 56 | out: TextIO = sys.stdout, 57 | ) -> None: 58 | """ 59 | Finds knowledges defined in the knowledge file that appear in tex file without quote 60 | symbols. Proposes to add quotes around them. 61 | Args: 62 | tex_filename: the name of the tex file. 63 | kl_filenames: the names of the knowledge files. 64 | print_line: an integer specifying how many lines of the tex file should be printed. 65 | inp: input stream. 66 | out: output stream. 67 | """ 68 | tex_hash = file_updater.hash_file(tex_filename) 69 | with open(tex_filename, "r", encoding="utf-8") as f: 70 | tex_doc = TexDocument(f.read()) 71 | f.close() 72 | kls = KnowledgesList(remove_redundant_files(kl_filenames)) 73 | tex_document_new, new_knowledges = quote_maximal_substrings( 74 | tex_doc, kls, print_line, inp, out 75 | ) 76 | with file_updater.AtomicUpdate(tex_filename, original_hash=tex_hash) as f: 77 | f.write(tex_document_new) 78 | f.close() 79 | for known_kl, new_kl in new_knowledges: 80 | kls.define_synonym_of(new_kl, known_kl) 81 | kls.write_knowledges_in_file(nocomment=True) 82 | 83 | 84 | def add_quote( 85 | tex_doc: TexDocument, 86 | operations: list[NewKL | AddQuote], 87 | print_line: int, 88 | inp: TextIO, 89 | out: TextIO, 90 | ) -> tuple[str, list[tuple[str, str]]]: 91 | """ 92 | In the TeX document, for every operation of type AddQuote, proposes to add quotes before 93 | and after the match with the knowledge. 94 | For every operation of type NewKL, proposes to define a new knowledge, and to add 95 | quotes before and after the match. 96 | 97 | Args: 98 | tex_doc: a TeX document. 99 | operations: a list of operations, whose type is either NewKL or AddQuote. 100 | print_line: an integer specifying how many lines of the tex file should be printed. 101 | inp: an input stream. 102 | out: an output stram. 103 | Given a tex code, and a list of triples (_, start, end), add a quote before the 104 | start and after the end. If the boolean interactive if true, asks the user 105 | if they want to add quotes: moreover, print the print_line lines preceding 106 | the match before asking the user's input. 107 | """ 108 | result: str = "" 109 | new_knowledges: list[tuple[str, str]] = [] 110 | ignore_synonym = [] 111 | ignore_subknowledge = [] 112 | operations.sort(key=lambda x: x.start) 113 | operations_addquote: list[AddQuote] = [] 114 | for op in operations: 115 | if isinstance(op, NewKL): 116 | if op.kl not in ignore_synonym: 117 | if op.kl not in [k for (_, k) in new_knowledges]: 118 | # Propose to the user to define a synonym 119 | tex_doc.print(op.start, op.end, print_line, out) 120 | message = ( 121 | f"Do you want to add `{misc.emph_alt(op.kl)}` as a synonym " 122 | f"of `{misc.emph_alt(op.kl_origin)}` and add quotes? [y/n] " 123 | ) 124 | if ask_consent(message, inp, out): 125 | # Adds op.kl as a new knowledge, defined as a synonym of op.kl_origin 126 | new_knowledges.append((op.kl_origin, op.kl)) 127 | operations_addquote.append(AddQuote(op.kl, op.start, op.end)) 128 | # Removes any operations occuring on a substring of our new knowledge 129 | for op2 in operations: 130 | if isinstance(op2, AddQuote): 131 | if op.start <= op2.start and op2.end <= op.end: 132 | operations.remove(op2) 133 | else: 134 | # From this point, do not propose again to define op.kl as a new knowledge. 135 | ignore_synonym.append(op.kl) 136 | if ( 137 | op.kl_origin 138 | == tex_doc.tex_code[op.start_origin : op.end_origin + 1] 139 | ): 140 | # Propose to the user to add quotes around the original knowledge 141 | # instead, if we have a precise match. 142 | if ask_consent( 143 | f"Add quotes around `{misc.emph(op.kl_origin)}` instead? [y/n] ", 144 | inp, 145 | out, 146 | ): 147 | operations_addquote.append( 148 | AddQuote( 149 | op.kl_origin, op.start_origin, op.end_origin 150 | ) 151 | ) 152 | else: 153 | ignore_subknowledge.append(op.kl) 154 | print("", file=out) 155 | else: 156 | # If op.kl was already accepted as a synonym earlier, treat it 157 | # as a regular knowledge 158 | op = AddQuote(op.kl, op.start, op.end) 159 | elif op.kl not in ignore_subknowledge: 160 | # If the user doesn't want op.kl as a synonym but might want 161 | # to add quotes around op.kl_origin 162 | op = AddQuote(op.kl_origin, op.start_origin, op.end_origin) 163 | elif isinstance(op, AddQuote): 164 | tex_doc.print(op.start, op.end, print_line, out) 165 | if ask_consent("Add quotes? [y/n] ", inp, out): 166 | operations_addquote.append(op) 167 | print("", file=out) 168 | add_quote_before = [tex_doc.pointer[op.start] for op in operations_addquote] 169 | add_quote_after = [tex_doc.pointer[op.end] for op in operations_addquote] 170 | # Simply add quotes before and after every positions corresponding to the beginning / end of 171 | # a match with a knowledge. 172 | for i, char in enumerate(tex_doc.tex_code): 173 | if i in add_quote_before: 174 | result += '"' 175 | result += char 176 | if i in add_quote_after: 177 | result += '"' 178 | print( 179 | f"Added {len(operations_addquote)} pair" 180 | + ("s" if len(operations_addquote) > 1 else "") 181 | + f" of quotes. Defined {len(new_knowledges)} synonym" 182 | + ("s." if len(new_knowledges) > 1 else "."), 183 | file=out, 184 | ) 185 | return result, new_knowledges 186 | 187 | 188 | def quote_maximal_substrings( 189 | tex_doc: TexDocument, 190 | kls: KnowledgesList, 191 | print_line: int, 192 | inp: TextIO, 193 | out: TextIO, 194 | ) -> tuple[str, list[tuple[str, str]]]: 195 | """ 196 | Finds knowledges defined in the knowledge file that appear in tex file without quote 197 | symbols. Proposes to add quotes around them. 198 | 199 | Args: 200 | tex_doc: a TeX document. 201 | kls: list of knowledges. 202 | print_line: an integer specifying how many lines of the tex file should be printed. 203 | inp: input stream. 204 | out: output stream. 205 | """ 206 | 207 | def stop_expanding(char): 208 | return not char.isalpha() 209 | 210 | ignore_position = [False] * tex_doc.length 211 | add_quote_location: list[NewKL | AddQuote] = [] 212 | for ignore_case in [False, True]: 213 | # Start the algo by being case sensitive, then run it while being insensitive. 214 | for s1 in kls.get_sorted_knowledges(): 215 | match_list = ( 216 | re.finditer(re.escape(s1), tex_doc.tex_cleaned, re.IGNORECASE) 217 | if ignore_case 218 | else re.finditer(re.escape(s1), tex_doc.tex_cleaned) 219 | ) 220 | for match in match_list: 221 | start, end = match.start(), match.end() - 1 222 | if not ignore_position[start]: 223 | # Ignore every infix of s1 that is also a substring of the list 224 | for i in range(start, end + 1): 225 | ignore_position[i] = True 226 | for s2 in kls.dependency[s1]: 227 | for submatch in re.finditer( 228 | re.escape(s2), tex_doc.tex_cleaned[start : end + 1] 229 | ): 230 | ignore_position[start + submatch.start()] = True 231 | # Check if s1 is precedeed by quotes, if not, either check 232 | # if we can define a new knowledge, or add the match to the 233 | # list of quotes to add. 234 | if not any( 235 | tex_doc.tex_cleaned.endswith(beg_kl, 0, start) 236 | and tex_doc.tex_cleaned.startswith(end_kl, end + 1) 237 | for (beg_kl, end_kl) in cst.KL_DELIMITERS 238 | ): 239 | start2, end2 = start, end 240 | while start2 > 0 and not stop_expanding( 241 | tex_doc.tex_cleaned[start2 - 1] 242 | ): 243 | start2 -= 1 244 | while end2 + 1 < len( 245 | tex_doc.tex_cleaned 246 | ) and not stop_expanding(tex_doc.tex_cleaned[end2 + 1]): 247 | end2 += 1 248 | # text_cleaned[start2: end2 + 1] is the maximal substring 249 | # containing text_cleaned[start, end + 1] = s1 as a factor, 250 | # and obtained by only addings letters (no space). 251 | new_kl = tex_doc.tex_cleaned[start2 : end2 + 1] 252 | if s1 != new_kl: 253 | # Propose to add new_kl as a new knowledge 254 | add_quote_location.append( 255 | NewKL(s1, start, end, new_kl, start2, end2) 256 | ) 257 | else: 258 | add_quote_location.append(AddQuote(s1, start, end)) 259 | return add_quote(tex_doc, add_quote_location, print_line, inp, out) 260 | -------------------------------------------------------------------------------- /knowledge_clustering/knowledges.py: -------------------------------------------------------------------------------- 1 | """Manipulating known knowledges.""" 2 | 3 | from __future__ import annotations # Support of `|` for type union in Python 3.9 4 | 5 | from typing import NamedTuple 6 | import toposort # Topological sort pylint: disable=import-error 7 | 8 | import knowledge_clustering.file_updater as fu 9 | from knowledge_clustering import cst 10 | from knowledge_clustering.misc import add_orange, add_bold 11 | 12 | 13 | class DocInfoTex(NamedTuple): 14 | """Lines of a TeX document.""" 15 | 16 | lines: list[str] 17 | 18 | 19 | class DocInfoKnowledge(NamedTuple): 20 | """Lines of TeX document corresponding to the definition of a knowledge.""" 21 | 22 | lines: list[str] 23 | command: str 24 | number: int 25 | 26 | 27 | def flat(list_of_list): 28 | """Flattens a list of list into a single list.""" 29 | return [x for y in list_of_list for x in y] 30 | 31 | 32 | class Knowledges: 33 | def __init__(self, filename): 34 | """ 35 | Reads a knowledge file from a file descriptor f. 36 | 37 | Args: 38 | filename: the name of a file containing knowledges. 39 | 40 | Computes: 41 | self.original_hash: the hash of the document ; 42 | self.document: a list of records, either of the form: 43 | { 44 | "type"="tex", 45 | "lines"= list of strings (the lines) 46 | } 47 | or { 48 | "type"="knowledge", 49 | "lines"= list of strings (the lines) 50 | "command" = string representing the line introducing the knowledge, 51 | "number" = the number of the knowledge 52 | } 53 | self.known_knowledges: a list of list of strings. 54 | Each list of strings contains strings corresponding to the same knowledge. 55 | The position in the string corresponds to the "number" field in the above 56 | document description. 57 | """ 58 | self.bags: list[list[str]] = [] # Lists of lists, containing knowledges. 59 | self.filename: str = filename 60 | self.original_hash = fu.hash_file(filename) 61 | with open(filename, encoding="utf-8") as file: 62 | lines: list[str] = file.readlines() 63 | 64 | document: list[DocInfoTex | DocInfoKnowledge] = [] 65 | knowledges: list[list[str]] = [] 66 | 67 | reading_mode: str = "tex" 68 | current_block: list[str] = [] 69 | current_kl_cmd: str = "" 70 | current_kl_strs: list[str] = [] 71 | 72 | def push_block(): 73 | nonlocal reading_mode 74 | nonlocal document 75 | nonlocal current_block 76 | nonlocal current_kl_cmd 77 | nonlocal current_kl_strs 78 | nonlocal knowledges 79 | nonlocal current_kl_strs 80 | if reading_mode == "tex" and len(current_block) > 0: 81 | document.append(DocInfoTex(lines=current_block)) 82 | current_block = [] 83 | elif reading_mode == "knowledge": 84 | document.append( 85 | DocInfoKnowledge( 86 | lines=current_block, 87 | command=current_kl_cmd, 88 | number=len(knowledges), 89 | ) 90 | ) 91 | current_block = [] 92 | current_kl_cmd = "" 93 | knowledges.append(current_kl_strs) 94 | current_kl_strs = [] 95 | 96 | def line_is_discard(line): 97 | return line.strip() == cst.DISCARD_LINE.strip() 98 | 99 | def line_is_comment(line): 100 | return line.strip().startswith("%") 101 | 102 | def line_is_knowledge(line): 103 | return line.strip().startswith("\\knowledge{") 104 | 105 | def bar_knowledge_from_line(line): 106 | line = line.strip() 107 | if line.startswith("|"): 108 | return line[1:].strip() 109 | return None 110 | 111 | def line_is_comment_bar_knowledge_from_line(line): 112 | line = line.strip() 113 | if line.startswith("%"): 114 | return (line[1:].strip()).startswith("|") 115 | return False 116 | 117 | for line in lines: 118 | if line[-1] == "\n": 119 | line = line[:-1] 120 | if reading_mode == "discard" and not line_is_comment(line): 121 | reading_mode = "tex" 122 | if line_is_discard(line): 123 | push_block() 124 | reading_mode = "discard" 125 | elif line_is_knowledge(line): 126 | push_block() 127 | reading_mode = "knowledge" 128 | current_kl_cmd = line 129 | current_block = [line] 130 | current_kl_strs = [] 131 | elif reading_mode == "knowledge": 132 | kl = bar_knowledge_from_line(line) 133 | if kl is not None: 134 | current_block.append(line) 135 | current_kl_strs.append(kl) 136 | elif line_is_comment_bar_knowledge_from_line(line): 137 | pass 138 | else: 139 | push_block() 140 | reading_mode = "tex" 141 | current_block = [line] 142 | elif reading_mode == "tex": 143 | current_block.append(line) 144 | push_block() 145 | self.document = document 146 | self.bags = knowledges 147 | self.nb_known_bags: int = len(self.bags) 148 | self.length_known_bags: list[int] = [len(bag) for bag in self.bags] 149 | 150 | def get_all_bags(self) -> list[list[str]]: 151 | """Returns all bags as a list of lists of strings.""" 152 | return self.bags 153 | 154 | def get_old_bags(self) -> list[list[str]]: 155 | """Returns all bags that were present at the last checkpoint, 156 | as a list of lists of strings.""" 157 | return self.bags[: self.nb_known_bags] 158 | 159 | def get_new_bags(self) -> list[list[str]]: 160 | """Returns all bags that were not added since the last checkpoint, 161 | as a list of lists of strings.""" 162 | return self.bags[self.nb_known_bags :] 163 | 164 | def get_all_knowledges(self) -> list[str]: 165 | """Returns all knowledges, as a list of strings.""" 166 | return flat(self.bags) 167 | 168 | def get_known_knowledges_in_bag(self, b_id: int) -> list[str]: 169 | """Returns the list of knowledges contained in the `b_id`-th bag 170 | during the last checkpoint, as a list of strings.""" 171 | if b_id < self.nb_known_bags: 172 | return self.bags[b_id][: self.length_known_bags[b_id]] 173 | return [] 174 | 175 | def get_new_knowledges_in_bag(self, b_id: int) -> list[str]: 176 | """Returns the list of knowledges contained in the `id`-th bag 177 | that were added since the last checkpoint, as a list of strings.""" 178 | if b_id < self.nb_known_bags: 179 | return self.bags[b_id][self.length_known_bags[b_id] :] 180 | return self.bags[b_id] 181 | 182 | def add_new_bag(self, kl: str) -> None: 183 | """Adds a new bag that contains only the string `kl`.""" 184 | self.bags.append([kl]) 185 | 186 | def define_synonym_of(self, kl1: str, kl2: str) -> None: 187 | """ 188 | Defines a new knowledge (string) `kl1` as a new synonym of the already 189 | existing knowledge (string) `kl2`. 190 | """ 191 | for b_id, bag in enumerate(self.bags): 192 | if kl2 in bag: 193 | self.bags[b_id].append(kl1) 194 | return 195 | raise KeyError(f"Error: {kl2} is not a knowledge.") 196 | 197 | def was_changed(self) -> bool: 198 | """ 199 | Returns whether kl has new bags or new synonyms. 200 | """ 201 | if len(self.get_new_bags()) > 0: 202 | return True 203 | for b_id in range(len(self.get_old_bags())): 204 | if len(self.get_new_knowledges_in_bag(b_id)) > 0: 205 | return True 206 | return False 207 | 208 | def write_knowledges_in_file(self, nocomment: bool = False) -> None: 209 | """ 210 | Writes the new synonyms and new knowledges in the file containing the knowledges. 211 | """ 212 | with fu.AtomicUpdate(self.filename, original_hash=self.original_hash) as file: 213 | for b in self.document: 214 | if isinstance(b, DocInfoTex): 215 | for line in b.lines: 216 | file.write(line + "\n") 217 | elif isinstance(b, DocInfoKnowledge): 218 | for line in b.lines: 219 | file.write(line + "\n") 220 | if b.number < self.nb_known_bags: 221 | for kl in self.get_new_knowledges_in_bag(b.number): 222 | file.write((f" | {kl}\n" if nocomment else f"% | {kl}\n")) 223 | if len(self.get_new_bags()) > 0: 224 | file.write(cst.DISCARD_LINE + "\n") 225 | for bag in self.get_new_bags(): 226 | if len(bag) > 0: 227 | file.write("%\n") 228 | file.write("%\\knowledge{notion}\n") 229 | for kl in bag: 230 | file.write((f" | {kl}\n" if nocomment else f"% | {kl}\n")) 231 | 232 | 233 | class KnowledgesList: 234 | def __init__(self, kls_filenames: list[str]): 235 | """ 236 | Reads a list of knowledge files. 237 | 238 | Args: 239 | kls_list: the list of filenames containing knowledges. 240 | """ 241 | self.nb_file: int = len(kls_filenames) 242 | self.kls_list: dict[str, Knowledges] = { 243 | fn: Knowledges(fn) for fn in kls_filenames 244 | } 245 | self.default_fn: str = kls_filenames[self.nb_file - 1] 246 | self.compute_dependency_graph() 247 | 248 | def get_all_kls_struct(self) -> list[Knowledges]: 249 | """Returns the list of all knowledge structures""" 250 | return list(self.kls_list.values()) 251 | 252 | def default_kls(self) -> Knowledges: 253 | """Returns the default kls.""" 254 | return self.kls_list[self.default_fn] 255 | 256 | def get_all_bags(self) -> list[list[str]]: 257 | """Returns all bags as a list of lists of strings.""" 258 | return flat([kls.get_all_bags() for kls in self.kls_list.values()]) 259 | 260 | def get_all_knowledges(self) -> list[str]: 261 | """Returns all knowledges, as a list of strings.""" 262 | return flat([kls.get_all_knowledges() for kls in self.kls_list.values()]) 263 | 264 | def get_sorted_knowledges(self) -> list[str]: 265 | """Returns all knowledges, sorted by topological sort.""" 266 | return self.all_knowledges_sorted 267 | 268 | def add_new_bag(self, kl: str) -> None: 269 | """Adds a new bag that contains only the string `kl`.""" 270 | self.default_kls().add_new_bag(kl) 271 | 272 | def define_synonym_of(self, kl1: str, kl2: str) -> None: 273 | """ 274 | Defines a new knowledge (string) `kl1` as a new synonym of the already 275 | existing knowledge (string) `kl2`. 276 | """ 277 | for kls in self.kls_list.values(): 278 | for b_id, bag in enumerate(kls.bags): 279 | if kl2 in bag: 280 | kls.bags[b_id].append(kl1) 281 | return 282 | raise KeyError(f"Error: {kl2} is not a knowledge.") 283 | 284 | def write_knowledges_in_file(self, nocomment: bool = False) -> None: 285 | """ 286 | Writes the new synonyms and new knowledges in the file containing the knowledges. 287 | """ 288 | for kls in self.kls_list.values(): 289 | kls.write_knowledges_in_file(nocomment) 290 | 291 | def get_new_bags(self) -> list[list[str]]: 292 | """Returns all bags that were added since the last checkpoint, 293 | as a list of lists of strings.""" 294 | return self.default_kls().get_new_bags() 295 | 296 | def get_new_knowledges_in_file(self, fn: str) -> list[str]: 297 | """Returns all new knowledges that were added in some file since the last 298 | checkpoint, as a list of strings.""" 299 | if fn not in self.kls_list: 300 | raise KeyError(f"No knowledge file named {fn}.") 301 | return flat( 302 | [ 303 | self.kls_list[fn].get_new_knowledges_in_bag(bag_id) 304 | for bag_id in range(len(self.kls_list[fn].get_all_bags())) 305 | ] 306 | ) 307 | 308 | def compute_dependency_graph(self) -> None: 309 | """ 310 | Computes the dependency graph of all knowledges, for the substring relation. 311 | Then, sort all knowledges using topological sorting. 312 | Result are stored in self.dependency and self.all_knowledges_sorted. 313 | """ 314 | dependency: dict[str, set[str]] = {} 315 | dependency_reversed: dict[str, set[str]] = {} 316 | for s1 in self.get_all_knowledges(): 317 | dependency[s1] = { 318 | s2 for s2 in self.get_all_knowledges() if s2 in s1 and s1 != s2 319 | } 320 | dependency_reversed[s1] = { 321 | s2 for s2 in self.get_all_knowledges() if s1 in s2 and s1 != s2 322 | } 323 | self.dependency: dict[str, set[str]] = dependency 324 | self.all_knowledges_sorted: list[str] = list( 325 | toposort.toposort_flatten(dependency_reversed) 326 | ) 327 | 328 | 329 | def remove_redundant_files(list_filenames: list[str]) -> list[str]: 330 | """ 331 | Given a list of filenames, return the same list without duplicates, and output a warning 332 | if there is such a duplicate. 333 | """ 334 | output: list[str] = [] 335 | for fn in list_filenames: 336 | if fn in output: 337 | print( 338 | add_bold(add_orange("[Warning]")) 339 | + f" same knowledge file given twice ({fn}), second occurrence is ignored." 340 | ) 341 | else: 342 | output.append(fn) 343 | return output 344 | -------------------------------------------------------------------------------- /examples/phd/default.kl: -------------------------------------------------------------------------------- 1 | %%%%% NEW KNOWLEDGES 2 | % 3 | %\knowledge{notion} 4 | % | CC BY 4.0 5 | % 6 | %\knowledge{notion} 7 | % | knowledge package 8 | % 9 | %\knowledge{notion} 10 | % | automatic structure 11 | % | automatic structures 12 | % | Automatic structures 13 | % | $\omega $-automatic structures 14 | % | automatic $\sigma $-structure 15 | % | automatic $\sigma $-structures 16 | % 17 | %\knowledge{notion} 18 | % | knowledge 19 | % 20 | %\knowledge{notion} 21 | % | knowledge-clustering 22 | % 23 | %\knowledge{notion} 24 | % | CC BY SA 4.0 25 | % 26 | %\knowledge{notion} 27 | % | Malament–Hogarth spacetime 28 | % 29 | %\knowledge{notion} 30 | % | NP 31 | % 32 | %\knowledge{notion} 33 | % | P 34 | % 35 | %\knowledge{notion} 36 | % | NL 37 | % 38 | %\knowledge{notion} 39 | % | homomorphism problem 40 | % | homomorphism problems 41 | % | Homomorphism Problem 42 | % 43 | %\knowledge{notion} 44 | % | primitive-positive formulas 45 | % | primitive-positive@formula 46 | % | primitive-positive formula 47 | % 48 | %\knowledge{notion} 49 | % | conjunctive query 50 | % | conjunctive queries 51 | % | Conjunctive queries 52 | % | Conjunctive Queries 53 | % 54 | %\knowledge{notion} 55 | % | constraint satisfaction 56 | % 57 | %\knowledge{notion} 58 | % | homomorphism 59 | % | homomorphisms 60 | % | Homomorphisms 61 | % | Homomorphism 62 | % 63 | %\knowledge{notion} 64 | % | edges 65 | % 66 | %\knowledge{notion} 67 | % | relational structure 68 | % | relational structures 69 | % | Relational structures 70 | % 71 | %\knowledge{notion} 72 | % | signature 73 | % | signatures 74 | % 75 | %\knowledge{notion} 76 | % | $\sigma $-structures 77 | % | structure 78 | % | $\sigma $-structure 79 | % | structures 80 | % | $\sigma '$-structures 81 | % | $\tau $-structure 82 | % | $\signatureSynchronous {\Sigma }$-structure 83 | % | $\extendedSignature {\sigma }{\?B}$-structure 84 | % | $\extendedSignature {\sigma }{\?B}$-structures 85 | % | \(\sigma \)-structures 86 | % 87 | %\knowledge{notion} 88 | % | source structure 89 | % 90 | %\knowledge{notion} 91 | % | target structure 92 | % | target structures 93 | % 94 | %\knowledge{notion} 95 | % | relational database 96 | % | relational databases 97 | % | Relational Databases 98 | % 99 | %\knowledge{notion} 100 | % | query@sem 101 | % | queries@sem 102 | % 103 | %\knowledge{notion} 104 | % | predicates 105 | % | predicate 106 | % 107 | %\knowledge{notion} 108 | % | st 109 | % 110 | %\knowledge{notion} 111 | % | marked structure 112 | % 113 | %\knowledge{notion} 114 | % | $k$-colourable 115 | % | $3$-colouring 116 | % | $k$-colouring 117 | % | $3$-colourability 118 | % | $3$-colourable 119 | % | $2$-colouring 120 | % | colouring 121 | % | $4$-colouring 122 | % | $(k+1)$-colouring 123 | % | $(k-1)$-colouring 124 | % 125 | %\knowledge{notion} 126 | % | ie 127 | % 128 | %\knowledge{notion} 129 | % | graph@dir 130 | % | graphs@dir 131 | % 132 | %\knowledge{notion} 133 | % | substructure 134 | % | substructures 135 | % 136 | %\knowledge{notion} 137 | % | first-order logic 138 | % | First-order logic 139 | % 140 | %\knowledge{notion} 141 | % | output@var 142 | % 143 | %\knowledge{notion} 144 | % | CQ 145 | % | CQs 146 | % 147 | %\knowledge{notion} 148 | % | primitive-positive fragment 149 | % 150 | %\knowledge{notion} 151 | % | conjunctive query evaluation 152 | % | Conjunctive Query Evaluation 153 | % 154 | %\knowledge{notion} 155 | % | uniform-AC0 156 | % 157 | %\knowledge{notion} 158 | % | AC0 159 | % 160 | %\knowledge{notion} 161 | % | XP 162 | % 163 | %\knowledge{notion} 164 | % | fixed-parameter tractable 165 | % 166 | %\knowledge{notion} 167 | % | FPT 168 | % 169 | %\knowledge{notion} 170 | % | core 171 | % | cores 172 | % | coRE 173 | % 174 | %\knowledge{notion} 175 | % | finite $\sigma $-structure 176 | % | finite structure 177 | % | finite structures 178 | % | finite $\signatureCRPQ {\A }$-structure 179 | % | finite $\sigma $-structures 180 | % | finiteness@structure 181 | % | finite@structure 182 | % 183 | %\knowledge{notion} 184 | % | iff 185 | % 186 | %\knowledge{notion} 187 | % | semantically equivalent 188 | % | semantical equivalence 189 | % 190 | %\knowledge{notion} 191 | % | eg 192 | % 193 | %\knowledge{notion} 194 | % | tree-width 195 | % | Tree-width 196 | % 197 | %\knowledge{notion} 198 | % | queries@CQ 199 | % 200 | %\knowledge{notion} 201 | % | path-width 202 | % 203 | %\knowledge{notion} 204 | % | W[1] 205 | % 206 | %\knowledge{notion} 207 | % | graph@undir 208 | % 209 | %\knowledge{notion} 210 | % | $k$-clique 211 | % | $3$-clique 212 | % | $2$-clique 213 | % | clique 214 | % | cliques 215 | % 216 | %\knowledge{notion} 217 | % | W1 218 | % 219 | %\knowledge{notion} 220 | % | tree-shaped 221 | % 222 | %\knowledge{notion} 223 | % | semantic tree-width 224 | % 225 | %\knowledge{notion} 226 | % | distance@struct 227 | % | distances@struct 228 | % 229 | %\knowledge{notion} 230 | % | graph databases 231 | % | graph database 232 | % | Graph databases 233 | % | database@graph 234 | % | databases@graph 235 | % 236 | %\knowledge{notion} 237 | % | Wikidata 238 | % 239 | %\knowledge{notion} 240 | % | Statistique des gens de lettres et des savants existant en France@wd 241 | % 242 | %\knowledge{notion} 243 | % | François-Fortuné Guyot de Fère@wd 244 | % 245 | %\knowledge{notion} 246 | % | French@wd 247 | % 248 | %\knowledge{notion} 249 | % | biographical dictionary@wd 250 | % 251 | %\knowledge{notion} 252 | % | biography@wd 253 | % 254 | %\knowledge{notion} 255 | % | dictionary@wd 256 | % 257 | %\knowledge{notion} 258 | % | catalogue@wd 259 | % 260 | %\knowledge{notion} 261 | % | knowledge organization system@wd 262 | % 263 | %\knowledge{notion} 264 | % | reference work@wd 265 | % 266 | %\knowledge{notion} 267 | % | biographical work@wd 268 | % 269 | %\knowledge{notion} 270 | % | non-fiction work@wd 271 | % 272 | %\knowledge{notion} 273 | % | literary work@wd 274 | % 275 | %\knowledge{notion} 276 | % | conjunctive regular path queries 277 | % | conjunctive regular path query 278 | % 279 | %\knowledge{notion} 280 | % | regular language 281 | % | regular languages 282 | % 283 | %\knowledge{notion} 284 | % | ExpSpace 285 | % | $k$-ExpSpace 286 | % 287 | %\knowledge{notion} 288 | % | minimization problem@CRPQ 289 | % | minimization problem for CRPQs 290 | % | Minimization problem@CRPQ 291 | % 292 | %\knowledge{notion} 293 | % | CRPQ 294 | % | CRPQs 295 | % 296 | %\knowledge{notion} 297 | % | query@CRPQ 298 | % | queries@CRPQ 299 | % 300 | %\knowledge{notion} 301 | % | atoms 302 | % | atom 303 | % | atomic 304 | % | non-atomic 305 | % 306 | %\knowledge{notion} 307 | % | maximal under-approximation 308 | % | maximal under-approximations 309 | % | Maximal under-approximations 310 | % 311 | %\knowledge{notion} 312 | % | minor-closed 313 | % 314 | %\knowledge{notion} 315 | % | semantical structure theorem 316 | % 317 | %\knowledge{notion} 318 | % | tree decomposition 319 | % | tree decompositions 320 | % | Tree decomposition 321 | % 322 | %\knowledge{notion} 323 | % | contractions@2w 324 | % | contract@2w 325 | % | contraction@2w 326 | % | contracted@2w 327 | % 328 | %\knowledge{notion} 329 | % | contracted path-width 330 | % 331 | %\knowledge{notion} 332 | % | simple regular expressions 333 | % | simple regular expression 334 | % 335 | %\knowledge{notion} 336 | % | aka 337 | % 338 | %\knowledge{notion} 339 | % | constraint satisfaction problems 340 | % | constraint satisfaction problem 341 | % 342 | %\knowledge{notion} 343 | % | $3$-colourability problem 344 | % | $k$-colourability problem 345 | % 346 | %\knowledge{notion} 347 | % | wlog 348 | % | Wlog 349 | % 350 | %\knowledge{notion} 351 | % | wrt 352 | % 353 | %\knowledge{notion} 354 | % | undirected graphs 355 | % | directed graphs 356 | % | undirected graph 357 | % | directed graph 358 | % | \emph {undirected} graph 359 | % 360 | %\knowledge{notion} 361 | % | L 362 | % 363 | %\knowledge{notion} 364 | % | FOfin 365 | % 366 | %\knowledge{notion} 367 | % | first-order definable 368 | % | non-first-order definable 369 | % | definable@first-order 370 | % 371 | %\knowledge{notion} 372 | % | finite@struct 373 | % 374 | %\knowledge{notion} 375 | % | incompleteness theorem 376 | % 377 | %\knowledge{notion} 378 | % | Gödel's incompleteness theorem 379 | % | Gödel's completeness theorem 380 | % 381 | %\knowledge{notion} 382 | % | Zermelo–Fraenkel set theory plus the axiom of choice 383 | % 384 | %\knowledge{notion} 385 | % | first-order sentence 386 | % | first-order sentences 387 | % 388 | %\knowledge{notion} 389 | % | automatic@struct 390 | % | non-automaticity@struct 391 | % | automaticity@struct 392 | % 393 | %\knowledge{notion} 394 | % | configuration graph 395 | % | Configuration graph 396 | % 397 | %\knowledge{notion} 398 | % | Turing machine 399 | % 400 | %\knowledge{notion} 401 | % | automatic graph 402 | % | automatic graphs 403 | % | automaticity@graph 404 | % | automatic@graph 405 | % 406 | %\knowledge{notion} 407 | % | 2-colourable 408 | % 409 | %\knowledge{notion} 410 | % | regular homomorphisms 411 | % | regular homomorphism 412 | % 413 | %\knowledge{notion} 414 | % | $3$-transitive tournament 415 | % | transitive tournament 416 | % | $k$-transitive tournament 417 | % | $2$-transitive tournament 418 | % 419 | %\knowledge{notion} 420 | % | regular $2$-colouring 421 | % | regular colouring 422 | % | regular $k$-colouring 423 | % | regularly $k$-colourable 424 | % | regular $k$-colourability 425 | % | regular@colouring 426 | % | regularly $2$-colourable 427 | % | regular colourings 428 | % 429 | %\knowledge{notion} 430 | % | first-order formula 431 | % | first-order formulas 432 | % 433 | %\knowledge{notion} 434 | % | finite duality 435 | % 436 | %\knowledge{notion} 437 | % | hyperedge consistency algorithm@finite 438 | % 439 | %\knowledge{notion} 440 | % | Rice's theorem 441 | % 442 | %\knowledge{notion} 443 | % | $\AUT $/$\REC $-separability problem 444 | % | $\RAT $/$\REC $-separability problem 445 | % | $\AUT $/$\REC $-separability@problem 446 | % | $\AUT $/$\kREC $-separability@problem 447 | % | $\RAT $/$\REC $-sepa\-ra\-bility problems 448 | % 449 | %\knowledge{notion} 450 | % | automatic relations 451 | % | automatic relation 452 | % | Automatic relations 453 | % 454 | %\knowledge{notion} 455 | % | synchronous automata 456 | % 457 | %\knowledge{notion} 458 | % | separated@rel 459 | % | separable@rel 460 | % | separates@rel 461 | % | separator@rel 462 | % | $\+V$-separable@rel 463 | % 464 | %\knowledge{notion} 465 | % | recognizable relation 466 | % | recognizable relations 467 | % | $\+V$-recognizable relations 468 | % 469 | %\knowledge{notion} 470 | % | syntactic monoid 471 | % | syntactic monoids 472 | % 473 | %\knowledge{notion} 474 | % | regular@lang 475 | % | regularity@lang 476 | % 477 | %\knowledge{notion} 478 | % | monoid 479 | % | monoids 480 | % | Monoids 481 | % 482 | %\knowledge{notion} 483 | % | synchronous algebras 484 | % | synchronous algebra 485 | % 486 | %\knowledge{notion} 487 | % | syntactic synchronous algebra 488 | % | syntactic synchronous algebras 489 | % 490 | %\knowledge{notion} 491 | % | automatic@rel 492 | % 493 | %\knowledge{notion} 494 | % | synchronous automaton 495 | % | Synchronous automaton 496 | % 497 | %\knowledge{notion} 498 | % | RE 499 | % 500 | %\knowledge{notion} 501 | % | via 502 | % 503 | %\knowledge{notion} 504 | % | approximations 505 | % | approximation 506 | % 507 | %\knowledge{notion} 508 | % | refinement 509 | % | refinements 510 | % | $m$-refinement 511 | % | $m$-refinements 512 | % | refining 513 | % | Refinements 514 | % | refine 515 | % 516 | %\knowledge{notion} 517 | % | expansion 518 | % | expansions 519 | % | Expansion 520 | % 521 | %\knowledge{notion} 522 | % | pseudovariety of monoids 523 | % | pseudovarieties of monoids 524 | % | pseudovarieties of mon\-oids 525 | % 526 | %\knowledge{notion} 527 | % | finite regular colourability@pb 528 | % 529 | %\knowledge{notion} 530 | % | coNP 531 | % 532 | %\knowledge{notion} 533 | % | functional@rel 534 | % | Functional@rel 535 | % 536 | %\knowledge{notion} 537 | % | reflexive@rel 538 | % 539 | %\knowledge{notion} 540 | % | symmetric@rel 541 | % 542 | %\knowledge{notion} 543 | % | transitive@rel 544 | % 545 | %\knowledge{notion} 546 | % | purely relational signature 547 | % | purely relational@signature 548 | % 549 | %\knowledge{notion} 550 | % | relational signature 551 | % | relational@signature 552 | % | relational signatures 553 | % 554 | %\knowledge{notion} 555 | % | interpretation@predicate 556 | % | predicate interpretations 557 | % | interpretation@predicates 558 | % | interpreted@predicate 559 | % | interpreting@predicate 560 | % | predicate interpreted 561 | % | interpretations@predicate 562 | % | interpret@predicate 563 | % 564 | %\knowledge{notion} 565 | % | graph signature 566 | % 567 | %\knowledge{notion} 568 | % | $\+R$-tuple 569 | % | $\+R$-tuples 570 | % 571 | %\knowledge{notion} 572 | % | hyperedge 573 | % | hyperedges 574 | % | non-hyperedges 575 | % 576 | %\knowledge{notion} 577 | % | proper substructure 578 | % 579 | %\knowledge{notion} 580 | % | induced substructure 581 | % | induced@substructure 582 | % 583 | %\knowledge{notion} 584 | % | pointed structures 585 | % | pointed $\sigma $-structures 586 | % | pointed $\sigma $-structure 587 | % 588 | %\knowledge{notion} 589 | % | disjoint union 590 | % | disjoint unions 591 | % 592 | %\knowledge{notion} 593 | % | Cartesian product 594 | % | Cartesian products 595 | % 596 | %\knowledge{notion} 597 | % | block product 598 | % 599 | %\knowledge{notion} 600 | % | adjacency 601 | % | adjacencies 602 | % 603 | %\knowledge{notion} 604 | % | undirected path 605 | % | directed paths 606 | % | directed path 607 | % 608 | %\knowledge{notion} 609 | % | connected 610 | % 611 | %\knowledge{notion} 612 | % | connected component 613 | % | connected components 614 | % 615 | %\knowledge{notion} 616 | % | incidence graph 617 | % 618 | %\knowledge{notion} 619 | % | diameter 620 | % 621 | %\knowledge{notion} 622 | % | locally finite@structure 623 | % 624 | %\knowledge{notion} 625 | % | simple path 626 | % 627 | %\knowledge{notion} 628 | % | directed cycle 629 | % | directed cycles 630 | % 631 | %\knowledge{notion} 632 | % | directed acyclic graph 633 | % 634 | %\knowledge{notion} 635 | % | DAG 636 | % 637 | %\knowledge{notion} 638 | % | directed tree 639 | % | directed trees 640 | % 641 | %\knowledge{notion} 642 | % | chromatic number 643 | % 644 | %\knowledge{notion} 645 | % | finitely colourable 646 | % 647 | %\knowledge{notion} 648 | % | embedding 649 | % 650 | %\knowledge{notion} 651 | % | strong onto homomorphism 652 | % | strong onto homomorphisms 653 | % 654 | %\knowledge{notion} 655 | % | homomorphic image 656 | % | homomorphic images 657 | % 658 | %\knowledge{notion} 659 | % | isomorphism 660 | % | isomorphic 661 | % | isomorphisms 662 | % 663 | %\knowledge{notion} 664 | % | automorphism 665 | % | automorphisms 666 | % 667 | %\knowledge{notion} 668 | % | congruence@struct 669 | % 670 | %\knowledge{notion} 671 | % | quotient structure 672 | % | quotient structures 673 | % 674 | %\knowledge{notion} 675 | % | quotient@struct 676 | % 677 | %\knowledge{notion} 678 | % | homomorphically equivalent 679 | % | homomorphical equivalence 680 | % | homomorphic equivalence 681 | % 682 | %\knowledge{notion} 683 | % | Boolean 684 | % | non-Boolean 685 | % 686 | %\knowledge{notion} 687 | % | (semantical) query 688 | % | (semantical) queries 689 | % | semantical query 690 | % | semantical queries 691 | % 692 | %\knowledge{notion} 693 | % | quantifier alternation rank 694 | % 695 | %\knowledge{notion} 696 | % | existential formulas 697 | % | existential formula 698 | % 699 | %\knowledge{notion} 700 | % | existential FO 701 | % 702 | %\knowledge{notion} 703 | % | existential-positive formulas 704 | % | existential-positive@formula 705 | % 706 | %\knowledge{notion} 707 | % | positive quantifier-free formulas 708 | % | positive quantifier-free formula 709 | % 710 | %\knowledge{notion} 711 | % | monadic second-order logic 712 | % 713 | %\knowledge{notion} 714 | % | second-order logic 715 | % 716 | %\knowledge{notion} 717 | % | signature of binary strings 718 | % 719 | %\knowledge{notion} 720 | % | monoid morphism 721 | % | monoid morphisms 722 | % | morphism@monoid 723 | % 724 | %\knowledge{notion} 725 | % | finite monoid 726 | % | finite monoids 727 | % 728 | %\knowledge{notion} 729 | % | syntactic morphisms 730 | % | syntactic morphism 731 | % 732 | %\knowledge{notion} 733 | % | divides@monoid 734 | % | divide@monoid 735 | % 736 | %\knowledge{notion} 737 | % | monoid division 738 | % | division@monoid 739 | % 740 | %\knowledge{notion} 741 | % | $\ast $-pseudovariety of regular languages 742 | % | $*$-pseudovariety of regular languages 743 | % | pseudovariety of regular languages 744 | % | $\ast $-pseudovarieties of regular languages 745 | % 746 | %\knowledge{notion} 747 | % | Eilenberg-Schützenberger correspondence@lang 748 | % | Eilenberg-Schützenberger correspondences@lang 749 | % 750 | %\knowledge{notion} 751 | % | $\+V$-membership problem@lang 752 | % 753 | %\knowledge{notion} 754 | % | corresponding@EilenbergLang 755 | % 756 | %\knowledge{notion} 757 | % | configuration@TM 758 | % 759 | %\knowledge{notion} 760 | % | initial configuration 761 | % | initial configurations 762 | % 763 | %\knowledge{notion} 764 | % | reachable@configuration 765 | % | reachable configurations 766 | % 767 | %\knowledge{notion} 768 | % | computationally equivalent 769 | % 770 | %\knowledge{notion} 771 | % | Complexity Zoo 772 | % 773 | %\knowledge{notion} 774 | % | first-order definable classes 775 | % 776 | %\knowledge{notion} 777 | % | first-order reductions 778 | % | first-order reduction 779 | % | first-order@reduction 780 | % 781 | %\knowledge{notion} 782 | % | PSpace 783 | % 784 | %\knowledge{notion} 785 | % | SigmaP2 786 | % 787 | %\knowledge{notion} 788 | % | PiP2 789 | % 790 | %\knowledge{notion} 791 | % | $k$-ExpTime 792 | % | ExpTime 793 | % 794 | %\knowledge{notion} 795 | % | Tower 796 | % | TOWER 797 | % 798 | %\knowledge{notion} 799 | % | arithmetical hierarchy 800 | % | \emph {arithmetical} hierarchy 801 | % 802 | %\knowledge{notion} 803 | % | Sigma0-2 804 | % 805 | %\knowledge{notion} 806 | % | Pi0-2 807 | % 808 | %\knowledge{notion} 809 | % | analytical hierarchy 810 | % | \emph {analytical} hierarchy 811 | % 812 | %\knowledge{notion} 813 | % | Connectivity in Finite Graphs 814 | % | Connectivity in finite graphs 815 | % 816 | %\knowledge{notion} 817 | % | Reachability in Finite Graphs 818 | % | Reachability in finite graphs 819 | % | reachability in finite graphs 820 | % 821 | %\knowledge{notion} 822 | % | $k$-path 823 | % | $2$-path 824 | % 825 | %\knowledge{notion} 826 | % | duality@CQ 827 | % | Duality@CQ 828 | % 829 | %\knowledge{notion} 830 | % | pointed relational database 831 | % | pointed relational databases 832 | % | pointed relational $\sigma $-database 833 | % 834 | %\knowledge{notion} 835 | % | isolated vertices 836 | % 837 | %\knowledge{notion} 838 | % | isolated variables 839 | % 840 | %\knowledge{notion} 841 | % | quantified Boolean formula problem 842 | % 843 | %\knowledge{notion} 844 | % | Trakhtenbrot's theorem 845 | % 846 | %\knowledge{notion} 847 | % | formula@FO 848 | % | formulas@FO 849 | % 850 | %\knowledge{notion} 851 | % | prenex form 852 | % | Prenex form 853 | % 854 | %\knowledge{notion} 855 | % | atoms@cq 856 | % 857 | %\knowledge{notion} 858 | % | free variables@cq 859 | % 860 | %\knowledge{notion} 861 | % | output variables@cq 862 | % 863 | %\knowledge{notion} 864 | % | output variable 865 | % | output variables 866 | % 867 | %\knowledge{notion} 868 | % | canonical database@cq 869 | % | canonical databases@cq 870 | % | canonical database@CQ 871 | % | canonical databases@CQ 872 | % 873 | %\knowledge{notion} 874 | % | Boolean queries 875 | % | Boolean query 876 | % | non-Boolean queries 877 | % 878 | %\knowledge{notion} 879 | % | Boolean@cq 880 | % | Boolean CQs 881 | % 882 | %\knowledge{notion} 883 | % | database@rel 884 | % | databases@rel 885 | % 886 | %\knowledge{notion} 887 | % | evaluation map 888 | % | Evaluation maps 889 | % | evaluations maps 890 | % | evaluation maps 891 | % 892 | %\knowledge{notion} 893 | % | Boolean conjunctive queries 894 | % | Boolean conjunctive query 895 | % 896 | %\knowledge{notion} 897 | % | containment 898 | % | contained 899 | % | Containment 900 | % | contains 901 | % 902 | %\knowledge{notion} 903 | % | canonical conjunctive query 904 | % | canonical conjunctive queries 905 | % 906 | %\knowledge{notion} 907 | % | closed under homomorphisms 908 | % 909 | %\knowledge{notion} 910 | % | canonical database 911 | % | canonical databases 912 | % 913 | %\knowledge{notion} 914 | % | vs 915 | % 916 | %\knowledge{notion} 917 | % | synthesis problem 918 | % 919 | %\knowledge{notion} 920 | % | disjoint conjunction 921 | % 922 | %\knowledge{notion} 923 | % | weak union 924 | % 925 | %\knowledge{notion} 926 | % | canonical CQ 927 | % 928 | %\knowledge{notion} 929 | % | mapped homomorphically 930 | % 931 | %\knowledge{notion} 932 | % | subquery@CQ 933 | % 934 | %\knowledge{notion} 935 | % | monotone@classCQ 936 | % | monotonicity@classCQ 937 | % 938 | %\knowledge{notion} 939 | % | Monotone classes of CQs 940 | % | monotone classes of CQs 941 | % | monotone class of CQs 942 | % 943 | %\knowledge{notion} 944 | % | core@CQ 945 | % | cores@cq 946 | % | cores@CQ 947 | % 948 | %\knowledge{notion} 949 | % | CQ minimization problem over $\+C$ 950 | % 951 | %\knowledge{notion} 952 | % | subquery 953 | % | subqueries 954 | % 955 | %\knowledge{notion} 956 | % | pointed databases@rel 957 | % 958 | %\knowledge{notion} 959 | % | synthesis problem for CQs 960 | % | Synthesis Problem for CQs 961 | % | synthesis problem@CQ 962 | % 963 | %\knowledge{notion} 964 | % | coNExp 965 | % 966 | %\knowledge{notion} 967 | % | evaluated 968 | % | evaluation 969 | % | evaluate 970 | % 971 | %\knowledge{notion} 972 | % | bag 973 | % | bags 974 | % 975 | %\knowledge{notion} 976 | % | contains@tw 977 | % | contained@tw 978 | % | containing@tw 979 | % 980 | %\knowledge{notion} 981 | % | width 982 | % 983 | %\knowledge{notion} 984 | % | forests 985 | % | forest 986 | % 987 | %\knowledge{notion} 988 | % | evaluation problem@cq 989 | % | CQ evaluation problem 990 | % 991 | %\knowledge{notion} 992 | % | containing@bag 993 | % 994 | %\knowledge{notion} 995 | % | equivalent@sem 996 | % 997 | %\knowledge{notion} 998 | % | Grohe's theorem 999 | % 1000 | %\knowledge{notion} 1001 | % | path decomposition 1002 | % | path decompositions 1003 | % | Path decomposition 1004 | % 1005 | %\knowledge{notion} 1006 | % | UC2RPQs 1007 | % | UC2RPQ 1008 | % 1009 | %\knowledge{notion} 1010 | % | database@relpointed 1011 | % 1012 | %\knowledge{notion} 1013 | % | union of conjunctive queries 1014 | % | unions of conjunctive queries 1015 | % 1016 | %\knowledge{notion} 1017 | % | UCQ 1018 | % | UCQs 1019 | % 1020 | %\knowledge{notion} 1021 | % | disjunct 1022 | % | disjuncts 1023 | % 1024 | %\knowledge{notion} 1025 | % | CC BY SA 3.0 1026 | % 1027 | %\knowledge{notion} 1028 | % | hom-minimal 1029 | % | hom-minimality 1030 | % 1031 | %\knowledge{notion} 1032 | % | Rossman's theorem 1033 | % 1034 | %\knowledge{notion} 1035 | % | finite relational structures 1036 | % | finite relational structure 1037 | % 1038 | %\knowledge{notion} 1039 | % | unions of conjunctive regular path queries 1040 | % | Unions of conjunctive regular path queries 1041 | % 1042 | %\knowledge{notion} 1043 | % | first-order queries 1044 | % 1045 | %\knowledge{notion} 1046 | % | pointed graph database 1047 | % 1048 | %\knowledge{notion} 1049 | % | satisfies@db 1050 | % | satisfy@db 1051 | % | satisfying@db 1052 | % 1053 | %\knowledge{notion} 1054 | % | interpret@pred 1055 | % | interpreted@pred 1056 | % 1057 | %\knowledge{notion} 1058 | % | Conjunctive Regular Path Queries Evaluation 1059 | % 1060 | %\knowledge{notion} 1061 | % | conjunctive regular path queries evaluation problem 1062 | % 1063 | %\knowledge{notion} 1064 | % | CQ evaluation 1065 | % 1066 | %\knowledge{notion} 1067 | % | Regular path queries 1068 | % 1069 | %\knowledge{notion} 1070 | % | RPQ 1071 | % 1072 | %\knowledge{notion} 1073 | % | CRPQ with two-way navigation 1074 | % 1075 | %\knowledge{notion} 1076 | % | C2RPQ 1077 | % | C2RPQs 1078 | % 1079 | %\knowledge{notion} 1080 | % | UCRPQs 1081 | % | UCRPQ 1082 | % 1083 | %\knowledge{notion} 1084 | % | unions of conjunctive two-way regular path queries 1085 | % 1086 | %\knowledge{notion} 1087 | % | Infinitary unions 1088 | % | infinitary unions 1089 | % | infinitary union 1090 | % 1091 | %\knowledge{notion} 1092 | % | canonical databases@CRPQ 1093 | % | canonical database@CRPQ 1094 | % 1095 | %\knowledge{notion} 1096 | % | C(2)RPQs 1097 | % 1098 | %\knowledge{notion} 1099 | % | equality atoms 1100 | % | equality atom 1101 | % 1102 | %\knowledge{notion} 1103 | % | sublanguage 1104 | % | sublanguages 1105 | % 1106 | %\knowledge{notion} 1107 | % | atom $m$-refinement 1108 | % | atom refinement 1109 | % | $m$-refinements@atom 1110 | % | atom $m'$-refinement 1111 | % | atom refinements 1112 | % 1113 | %\knowledge{notion} 1114 | % | condensation 1115 | % | condense 1116 | % | condensations 1117 | % 1118 | %\knowledge{notion} 1119 | % | refinement length 1120 | % 1121 | %\knowledge{notion} 1122 | % | equivalent 1123 | % | equivalence 1124 | % | Equivalent 1125 | % | equivalences 1126 | % 1127 | %\knowledge{notion} 1128 | % | UC(2)RPQs 1129 | % 1130 | %\knowledge{notion} 1131 | % | containment problem 1132 | % | con\-tainment problem 1133 | % 1134 | %\knowledge{notion} 1135 | % | Boolean CRPQs 1136 | % | Boolean CRPQ 1137 | % 1138 | %\knowledge{notion} 1139 | % | SRE 1140 | % | SREs 1141 | % 1142 | %\knowledge{notion} 1143 | % | positive simple regular expressions 1144 | % | simple regular expression@positive 1145 | % | simple regular expressions@positive 1146 | % 1147 | %\knowledge{notion} 1148 | % | (U)C(2)RPQ 1149 | % 1150 | %\knowledge{notion} 1151 | % | 2ExpSpace 1152 | % 1153 | %\knowledge{notion} 1154 | % | minimization problem 1155 | % | Minimization problem 1156 | % | minimization problems 1157 | % 1158 | %\knowledge{notion} 1159 | % | minimization of CRPQs 1160 | % | CRPQ minimization 1161 | % 1162 | %\knowledge{notion} 1163 | % | strong minimality 1164 | % | strongly minimal 1165 | % 1166 | %\knowledge{notion} 1167 | % | variable-minimization problem 1168 | % | Variable-minimization problem 1169 | % 1170 | %\knowledge{notion} 1171 | % | minimal 1172 | % | minimality 1173 | % 1174 | %\knowledge{notion} 1175 | % | internal variable 1176 | % | internal@variable 1177 | % | Internal variables 1178 | % | internal variables 1179 | % 1180 | %\knowledge{notion} 1181 | % | external 1182 | % 1183 | %\knowledge{notion} 1184 | % | one-way internal path 1185 | % | one-way internal paths 1186 | % 1187 | %\knowledge{notion} 1188 | % | internal path 1189 | % 1190 | %\knowledge{notion} 1191 | % | internal 1192 | % 1193 | %\knowledge{notion} 1194 | % | segment 1195 | % | segments 1196 | % | Segments 1197 | % 1198 | %\knowledge{notion} 1199 | % | cyclic@segment 1200 | % | cyclic segment 1201 | % 1202 | %\knowledge{notion} 1203 | % | incident@segment 1204 | % 1205 | %\knowledge{notion} 1206 | % | segment graph 1207 | % 1208 | %\knowledge{notion} 1209 | % | external variable 1210 | % | external variables 1211 | % 1212 | %\knowledge{notion} 1213 | % | contraction@1w 1214 | % | contracted@1w 1215 | % | Contractions@1w 1216 | % | contractions@1w 1217 | % | contract@1w 1218 | % 1219 | %\knowledge{notion} 1220 | % | fully contracted 1221 | % 1222 | %\knowledge{notion} 1223 | % | redundant atom 1224 | % 1225 | %\knowledge{notion} 1226 | % | non-redundant 1227 | % | redundant 1228 | % | non-redundancy 1229 | % 1230 | %\knowledge{notion} 1231 | % | atom expansion 1232 | % | atom expansions 1233 | % 1234 | %\knowledge{notion} 1235 | % | underlying graph 1236 | % | underlying graphs 1237 | % 1238 | %\knowledge{notion} 1239 | % | minor 1240 | % | minors 1241 | % 1242 | %\knowledge{notion} 1243 | % | contracting edges 1244 | % | edge contraction 1245 | % 1246 | %\knowledge{notion} 1247 | % | class of CRPQs 1248 | % | classes of CRPQs 1249 | % | class@CRPQ 1250 | % 1251 | %\knowledge{notion} 1252 | % | underlying graph@dir 1253 | % 1254 | %\knowledge{notion} 1255 | % | Semantical Structure 1256 | % 1257 | %\knowledge{notion} 1258 | % | hom-equivalent 1259 | % | hom-equivalence 1260 | % 1261 | %\knowledge{notion} 1262 | % | $\gamma $-type 1263 | % | type 1264 | % | types 1265 | % 1266 | %\knowledge{notion} 1267 | % | basic paths 1268 | % | basic path 1269 | % 1270 | %\knowledge{notion} 1271 | % | subgraphs 1272 | % 1273 | %\knowledge{notion} 1274 | % | explicit approximation 1275 | % 1276 | %\knowledge{notion} 1277 | % | contained@approx 1278 | % 1279 | %\knowledge{notion} 1280 | % | contraction length 1281 | % 1282 | %\knowledge{notion} 1283 | % | UCRPQ(SRE) 1284 | % 1285 | %\knowledge{notion} 1286 | % | resp 1287 | % 1288 | %\knowledge{notion} 1289 | % | CRPQ(SRE) 1290 | % 1291 | %\knowledge{notion} 1292 | % | (i)@sre 1293 | % 1294 | %\knowledge{notion} 1295 | % | (ii)@sre 1296 | % 1297 | %\knowledge{notion} 1298 | % | (iii)@sre 1299 | % 1300 | %\knowledge{notion} 1301 | % | non-degenerate@db 1302 | % 1303 | %\knowledge{notion} 1304 | % | non-degenerate expansion 1305 | % 1306 | %\knowledge{notion} 1307 | % | $\classCRPQ $-canonization problem 1308 | % | canonization problem 1309 | % 1310 | %\knowledge{notion} 1311 | % | non-degenerate@cdb 1312 | % 1313 | %\knowledge{notion} 1314 | % | strong onto 1315 | % 1316 | %\knowledge{notion} 1317 | % | $\classCRPQ $-strong canonization problem 1318 | % | strong canonization problem 1319 | % 1320 | %\knowledge{notion} 1321 | % | $\classCRPQ $-canonization oracle 1322 | % 1323 | %\knowledge{notion} 1324 | % | $\classCRPQ $-strong canonization oracle 1325 | % 1326 | %\knowledge{notion} 1327 | % | closed under disjoint conjunction 1328 | % 1329 | %\knowledge{notion} 1330 | % | relevant@prooflowerbound 1331 | % 1332 | %\knowledge{notion} 1333 | % | locally redundant 1334 | % 1335 | %\knowledge{notion} 1336 | % | locally redundant atom 1337 | % | locally redundant atoms 1338 | % 1339 | %\knowledge{notion} 1340 | % | forest-shaped CRPQs 1341 | % | forest-shaped CRPQ 1342 | % 1343 | %\knowledge{notion} 1344 | % | (U)CRPQs 1345 | % | (U)CRPQ 1346 | % 1347 | %\knowledge{notion} 1348 | % | variable-minimization problem(s) 1349 | % 1350 | %\knowledge{notion} 1351 | % | variable minimal 1352 | % 1353 | %\knowledge{notion} 1354 | % | tree patterns 1355 | % | tree pattern 1356 | % 1357 | %\knowledge{notion} 1358 | % | 4ExpSpace 1359 | % 1360 | %\knowledge{notion} 1361 | % | encoding 1362 | % | Encoding 1363 | % | encode 1364 | % 1365 | %\knowledge{notion} 1366 | % | expanding 1367 | % 1368 | %\knowledge{notion} 1369 | % | closed under variable marking 1370 | % 1371 | %\knowledge{notion} 1372 | % | class of CRPQs closed under disjoint conjunction 1373 | % 1374 | %\knowledge{notion} 1375 | % | degenerate@CRPQ 1376 | % | non-degenerate@CRPQ 1377 | % | degenerate CRPQ 1378 | % 1379 | %\knowledge{notion} 1380 | % | union of C2RPQs 1381 | % 1382 | %\knowledge{notion} 1383 | % | evaluation problem 1384 | % 1385 | %\knowledge{notion} 1386 | % | semantic tree-width $k$ problem 1387 | % | semantic tree-width $1$ problem 1388 | % 1389 | %\knowledge{notion} 1390 | % | one-way semantic tree-width 1391 | % 1392 | %\knowledge{notion} 1393 | % | one-way semantic tree-width $k$ problem 1394 | % | one-way semantic tree-width $1$ problem 1395 | % 1396 | %\knowledge{notion} 1397 | % | Key Lemma 1398 | % 1399 | %\knowledge{notion} 1400 | % | closed under sublanguages 1401 | % 1402 | %\knowledge{notion} 1403 | % | semantic tree-width 1 problem 1404 | % | semantic tree-width 1 problems 1405 | % 1406 | %\knowledge{notion} 1407 | % | one-way semantic tree-width 1 problem 1408 | % 1409 | %\knowledge{notion} 1410 | % | semantic path-width $k$ problems 1411 | % | semantic path-width $k$ problem 1412 | % 1413 | %\knowledge{notion} 1414 | % | semantic path-width 1415 | % 1416 | %\knowledge{notion} 1417 | % | para-NL 1418 | % 1419 | %\knowledge{notion} 1420 | % | one-way semantic path-width 1421 | % 1422 | %\knowledge{notion} 1423 | % | two-way navigation 1424 | % 1425 | %\knowledge{notion} 1426 | % | cf 1427 | % 1428 | %\knowledge{notion} 1429 | % | finitely redundant 1430 | % | finite redundancy 1431 | % 1432 | %\knowledge{notion} 1433 | % | two-way contractions 1434 | % 1435 | %\knowledge{notion} 1436 | % | one-way contractions 1437 | % | one-way contraction 1438 | % 1439 | %\knowledge{notion} 1440 | % | fine tree decomposition 1441 | % 1442 | %\knowledge{notion} 1443 | % | full bag 1444 | % | non-full bags 1445 | % | full bags 1446 | % 1447 | %\knowledge{notion} 1448 | % | (U)C2RPQ 1449 | % 1450 | %\knowledge{notion} 1451 | % | bridge-width 1452 | % 1453 | %\knowledge{notion} 1454 | % | bridge 1455 | % 1456 | %\knowledge{notion} 1457 | % | Savitch's Theorem 1458 | % 1459 | %\knowledge{notion} 1460 | % | tagged tree decomposition 1461 | % | tagged tree decompositions 1462 | % 1463 | %\knowledge{notion} 1464 | % | tagging 1465 | % | tagged 1466 | % | tag 1467 | % 1468 | %\knowledge{notion} 1469 | % | fine tagged tree decomposition 1470 | % | fine tagged tree decompositions 1471 | % | fine tagged tree decom\-position 1472 | % 1473 | %\knowledge{notion} 1474 | % | fine 1475 | % | fineness 1476 | % 1477 | %\knowledge{notion} 1478 | % | path induced 1479 | % | induces the path 1480 | % | induced path 1481 | % | induces a path 1482 | % 1483 | %\knowledge{notion} 1484 | % | link 1485 | % | $n$-link 1486 | % | $n$-linked 1487 | % | linked 1488 | % | $1$-link 1489 | % | $1$-linked 1490 | % 1491 | %\knowledge{notion} 1492 | % | leaves 1493 | % | leaving 1494 | % 1495 | %\knowledge{notion} 1496 | % | cyclic@path 1497 | % | acyclic@path 1498 | % | acyclic paths 1499 | % | acyclic path 1500 | % | cyclic path 1501 | % 1502 | %\knowledge{notion} 1503 | % | non-branching paths 1504 | % | non-branching path 1505 | % | Non-branching path 1506 | % 1507 | %\knowledge{notion} 1508 | % | non-full 1509 | % | full 1510 | % 1511 | %\knowledge{notion} 1512 | % | trio 1513 | % | Trio 1514 | % 1515 | %\knowledge{notion} 1516 | % | induce 1517 | % | induces 1518 | % | induced 1519 | % 1520 | %\knowledge{notion} 1521 | % | locally acyclic 1522 | % | local acyclicity 1523 | % 1524 | %\knowledge{notion} 1525 | % | profile 1526 | % | Profiles 1527 | % | profiles 1528 | % 1529 | %\knowledge{notion} 1530 | % | type@stw 1531 | % | types@stw 1532 | % 1533 | %\knowledge{notion} 1534 | % | atomic bags 1535 | % | non-atomic bags 1536 | % 1537 | %\knowledge{notion} 1538 | % | summary query 1539 | % | Summary queries 1540 | % | $k$-summary query 1541 | % | $k$-summary queries 1542 | % 1543 | %\knowledge{notion} 1544 | % | path-$l$ approximations 1545 | % | path-$l$ approximation 1546 | % 1547 | %\knowledge{notion} 1548 | % | refinement@summary 1549 | % | refinements@summary 1550 | % 1551 | %\knowledge{notion} 1552 | % | tree decomposition@summary 1553 | % 1554 | %\knowledge{notion} 1555 | % | homomorphism@summary 1556 | % 1557 | %\knowledge{notion} 1558 | % | recursive atom 1559 | % | non-recursive atom 1560 | % | non-recursive atoms 1561 | % | recursive atoms 1562 | % 1563 | %\knowledge{notion} 1564 | % | non-recursive@nrat 1565 | % 1566 | %\knowledge{notion} 1567 | % | recursive@rat 1568 | % 1569 | %\knowledge{notion} 1570 | % | (two-way) internal path 1571 | % 1572 | %\knowledge{notion} 1573 | % | contracted tree-width 1574 | % 1575 | %\knowledge{notion} 1576 | % | one-way contracted tree-width 1577 | % 1578 | %\knowledge{notion} 1579 | % | one-wayness 1580 | % 1581 | %\knowledge{notion} 1582 | % | visits 1583 | % | visit 1584 | % 1585 | %\knowledge{notion} 1586 | % | paraNL 1587 | % 1588 | %\knowledge{notion} 1589 | % | one-way contracted path-width 1590 | % 1591 | %\knowledge{notion} 1592 | % | one-way semantic path-width $k$ problem 1593 | % 1594 | %\knowledge{notion} 1595 | % | asymmetric containment problem for tree-width $k$ 1596 | % 1597 | %\knowledge{notion} 1598 | % | loopless CRPQs 1599 | % 1600 | %\knowledge{notion} 1601 | % | loopless 1602 | % 1603 | %\knowledge{notion} 1604 | % | parameterized clique problem 1605 | % 1606 | %\knowledge{notion} 1607 | % | infinitary UCQ 1608 | % 1609 | %\knowledge{notion} 1610 | % | Regular Queries 1611 | % 1612 | %\knowledge{notion} 1613 | % | Evaluation problem@crpq 1614 | % 1615 | %\knowledge{notion} 1616 | % | sem. path-w. 1617 | % 1618 | %\knowledge{notion} 1619 | % | sem. tree-w. 1620 | % 1621 | %\knowledge{notion} 1622 | % | profinite databases 1623 | % | profinite database 1624 | % 1625 | %\knowledge{notion} 1626 | % | forest-shaped 1627 | % 1628 | %\knowledge{notion} 1629 | % | UCRPQ minimization 1630 | % 1631 | %\knowledge{notion} 1632 | % | closed under minors 1633 | % 1634 | %\knowledge{notion} 1635 | % | duality 1636 | % 1637 | %\knowledge{notion} 1638 | % | hom-minimal expansions 1639 | % 1640 | %\knowledge{notion} 1641 | % | finite databases 1642 | % 1643 | %\knowledge{notion} 1644 | % | minor-closed classes 1645 | % 1646 | %\knowledge{notion} 1647 | % | semantically forest-shaped 1648 | % 1649 | %\knowledge{notion} 1650 | % | DAG-shaped 1651 | % 1652 | %\knowledge{notion} 1653 | % | unfolding 1654 | % 1655 | %\knowledge{notion} 1656 | % | DAG-shaped CRPQ 1657 | % 1658 | %\knowledge{notion} 1659 | % | hom-minimal canonical database 1660 | % 1661 | %\knowledge{notion} 1662 | % | semantically DAG-shaped 1663 | % 1664 | %\knowledge{notion} 1665 | % | multitape automata 1666 | % | Multitape automata 1667 | % | $\{\{i\} \mid i \in \intInt {1,k}\}^*$-multitape automata 1668 | % | $T$-multitape automata 1669 | % 1670 | %\knowledge{notion} 1671 | % | isomorphism problem 1672 | % 1673 | %\knowledge{notion} 1674 | % | same parity length relation 1675 | % 1676 | %\knowledge{notion} 1677 | % | prefix relation 1678 | % 1679 | %\knowledge{notion} 1680 | % | identity relation 1681 | % 1682 | %\knowledge{notion} 1683 | % | subword relation 1684 | % 1685 | %\knowledge{notion} 1686 | % | suffix relation 1687 | % 1688 | %\knowledge{notion} 1689 | % | deterministic rational relations 1690 | % | deterministic\\rational relations 1691 | % 1692 | %\knowledge{notion} 1693 | % | rational relations 1694 | % | Rational relations 1695 | % | rational relation 1696 | % 1697 | %\knowledge{notion} 1698 | % | deterministic two-way rational relations 1699 | % | Deterministic two-way rational relations 1700 | % | deterministic\\two-way rational\\ relations 1701 | % 1702 | %\knowledge{notion} 1703 | % | two-way rational relations 1704 | % | two-way\\rational relations 1705 | % | two-way rational relation 1706 | % 1707 | %\knowledge{notion} 1708 | % | functional relations 1709 | % | functional relation 1710 | % 1711 | %\knowledge{notion} 1712 | % | regular functions@bojan 1713 | % | Regular functions@bojan 1714 | % 1715 | %\knowledge{notion} 1716 | % | recognizable@rel 1717 | % | $\+V$-recognizable@rel 1718 | % 1719 | %\knowledge{notion} 1720 | % | transducers 1721 | % | transducer 1722 | % 1723 | %\knowledge{notion} 1724 | % | deterministic two-way transductions 1725 | % | Deterministic two-way transductions 1726 | % 1727 | %\knowledge{notion} 1728 | % | $\+D$-membership problem for $\+C$-relations 1729 | % 1730 | %\knowledge{notion} 1731 | % | $\+C$/$\+D$-membership problem 1732 | % | $\RAT $/$\REC $-membership problem 1733 | % | $\DRAT $/$\REC $-membership problem 1734 | % 1735 | %\knowledge{notion} 1736 | % | $\+D$-membership problem 1737 | % | $\REC $-membership problem 1738 | % | $\REC $-membership@problem 1739 | % | $\kREC $-membership problem 1740 | % | $\kPROD $-membership problem 1741 | % | membership problem 1742 | % | membership problems 1743 | % 1744 | %\knowledge{notion} 1745 | % | $\+D$-separability problem for $\+C$-relations 1746 | % 1747 | %\knowledge{notion} 1748 | % | membership@problemrel 1749 | % 1750 | %\knowledge{notion} 1751 | % | separability@problemrel 1752 | % 1753 | %\knowledge{notion} 1754 | % | $\+D$-separability problem 1755 | % | $\REC $-separability problem 1756 | % | $\kREC [1]$-separability problem 1757 | % | $\kREC $-separability problem 1758 | % | $\kPROD [1]$-separability problem 1759 | % | $\kPROD $-separability problem 1760 | % | $\kPROD [2]$-separability problem 1761 | % | separability problems 1762 | % 1763 | %\knowledge{notion} 1764 | % | inclusion problem@rel 1765 | % 1766 | %\knowledge{notion} 1767 | % | equivalence problem@rel 1768 | % 1769 | %\knowledge{notion} 1770 | % | same parity relation 1771 | % 1772 | %\knowledge{notion} 1773 | % | Mezei theorem 1774 | % 1775 | %\knowledge{notion} 1776 | % | pseudovariety@reglang 1777 | % | $*$-pseudovarieties@reglang 1778 | % | $\ast $-pseudovariety@reglang 1779 | % 1780 | %\knowledge{notion} 1781 | % | membership@problang 1782 | % 1783 | %\knowledge{notion} 1784 | % | reflexive relations 1785 | % 1786 | %\knowledge{notion} 1787 | % | Ramsey's infinite theorem 1788 | % 1789 | %\knowledge{notion} 1790 | % | equal-length relation 1791 | % 1792 | %\knowledge{notion} 1793 | % | convolution@word 1794 | % 1795 | %\knowledge{notion} 1796 | % | blank symbol 1797 | % | non-blank symbols 1798 | % 1799 | %\knowledge{notion} 1800 | % | padding symbol 1801 | % | padding symbols 1802 | % 1803 | %\knowledge{notion} 1804 | % | recognizing@syncauto 1805 | % | recognizes@syncauto 1806 | % | recognized@syncauto 1807 | % | recognize@syncauto 1808 | % 1809 | %\knowledge{notion} 1810 | % | well-formed 1811 | % 1812 | %\knowledge{notion} 1813 | % | well-formed words 1814 | % 1815 | %\knowledge{notion} 1816 | % | $I$-locally finite 1817 | % | $\intInt {1,k}$-locally finite 1818 | % | $\{3\}$-locally finite 1819 | % 1820 | %\knowledge{notion} 1821 | % | 3ExpTime 1822 | % 1823 | %\knowledge{notion} 1824 | % | 2ExpTime 1825 | % 1826 | %\knowledge{notion} 1827 | % | $\REC $-membership problem for automatic relations 1828 | % 1829 | %\knowledge{notion} 1830 | % | separation problem@rel 1831 | % 1832 | %\knowledge{notion} 1833 | % | $\REC $-separability problem for automatic relations 1834 | % 1835 | %\knowledge{notion} 1836 | % | length-multiplying 1837 | % 1838 | %\knowledge{notion} 1839 | % | length-multiplying morphisms 1840 | % | length-multiplying morphism 1841 | % 1842 | %\knowledge{notion} 1843 | % | multitape automaton 1844 | % | $T$-multitape automaton 1845 | % | $T_{\textrm {sync}}$-multitape automaton 1846 | % | $T_{\textrm {rec}}$-multitape automaton 1847 | % | Multitape automaton 1848 | % 1849 | %\knowledge{notion} 1850 | % | rational@rel 1851 | % 1852 | %\knowledge{notion} 1853 | % | recognized@desync 1854 | % 1855 | %\knowledge{notion} 1856 | % | automaton@desync 1857 | % 1858 | %\knowledge{notion} 1859 | % | intersection non-emptiness problem 1860 | % 1861 | %\knowledge{notion} 1862 | % | automaton@sync 1863 | % 1864 | %\knowledge{notion} 1865 | % | deterministic@desync 1866 | % 1867 | %\knowledge{notion} 1868 | % | deterministic@multitape 1869 | % 1870 | %\knowledge{notion} 1871 | % | deterministic multitape automaton 1872 | % 1873 | %\knowledge{notion} 1874 | % | deterministic rational@rel 1875 | % | deterministic\\rational@rel 1876 | % 1877 | %\knowledge{notion} 1878 | % | synchronous@auto 1879 | % 1880 | %\knowledge{notion} 1881 | % | recognizes@multitape 1882 | % 1883 | %\knowledge{notion} 1884 | % | Deterministic multitape automata 1885 | % | deterministic multitape automata 1886 | % 1887 | %\knowledge{notion} 1888 | % | intersection non-emptiness problem@drat 1889 | % 1890 | %\knowledge{notion} 1891 | % | $T$-controlled relation 1892 | % | $T$-controlled relations 1893 | % | $T_1$-controlled relations 1894 | % | $T_2$-controlled relations 1895 | % 1896 | %\knowledge{notion} 1897 | % | Right-automatic relations 1898 | % | right-automatic relations 1899 | % 1900 | %\knowledge{notion} 1901 | % | right-automatic@rel 1902 | % 1903 | %\knowledge{notion} 1904 | % | equivalence@pbrel 1905 | % 1906 | %\knowledge{notion} 1907 | % | deterministic two-way multitape automata 1908 | % 1909 | %\knowledge{notion} 1910 | % | deterministic one-way rational relations 1911 | % 1912 | %\knowledge{notion} 1913 | % | deterministic two-way rational@rel 1914 | % 1915 | %\knowledge{notion} 1916 | % | two-way\\rational@rel 1917 | % 1918 | %\knowledge{notion} 1919 | % | non-deterministic one-way transducers 1920 | % | deterministic one-way transducer 1921 | % 1922 | %\knowledge{notion} 1923 | % | transductions 1924 | % 1925 | %\knowledge{notion} 1926 | % | deterministic transducer 1927 | % | deterministic@transducer 1928 | % | deterministic transducers 1929 | % 1930 | %\knowledge{notion} 1931 | % | deterministic transduction 1932 | % | deterministic transductions 1933 | % 1934 | %\knowledge{notion} 1935 | % | two-way transductions 1936 | % 1937 | %\knowledge{notion} 1938 | % | regular functions 1939 | % | regular function 1940 | % 1941 | %\knowledge{notion} 1942 | % | determinstic\\transductions 1943 | % 1944 | %\knowledge{notion} 1945 | % | polyregular\\functions@bojan 1946 | % | polyregular functions@bojan 1947 | % | polyregular function@bojan 1948 | % 1949 | %\knowledge{notion} 1950 | % | one-way deterministic transductions 1951 | % 1952 | %\knowledge{notion} 1953 | % | regular@bojan 1954 | % 1955 | %\knowledge{notion} 1956 | % | first-order interpretation 1957 | % | first-order interpretable 1958 | % | first-order interpretations 1959 | % 1960 | %\knowledge{notion} 1961 | % | $d$-dimensional first-order interpretation 1962 | % 1963 | %\knowledge{notion} 1964 | % | $\+I$-interpretation of $\?A$ 1965 | % | interpretation 1966 | % | Interpretation 1967 | % 1968 | %\knowledge{notion} 1969 | % | one-dimensional interpretation 1970 | % | one-dimensional interpretations 1971 | % 1972 | %\knowledge{notion} 1973 | % | two-dimensional interpretation 1974 | % 1975 | %\knowledge{notion} 1976 | % | injective@interpretation 1977 | % | injective interpretation 1978 | % 1979 | %\knowledge{notion} 1980 | % | first-order equivalent 1981 | % 1982 | %\knowledge{notion} 1983 | % | injective first-order interpretation 1984 | % 1985 | %\knowledge{notion} 1986 | % | FO-interpretations 1987 | % | FO-interpretation 1988 | % 1989 | %\knowledge{notion} 1990 | % | FO-reduction 1991 | % 1992 | %\knowledge{notion} 1993 | % | lexicographic order 1994 | % 1995 | %\knowledge{notion} 1996 | % | FO 1997 | % 1998 | %\knowledge{notion} 1999 | % | MSO 2000 | % 2001 | %\knowledge{notion} 2002 | % | definable relations 2003 | % 2004 | %\knowledge{notion} 2005 | % | automatic groups 2006 | % | automatic group 2007 | % 2008 | %\knowledge{notion} 2009 | % | automatic presentation $\+A$ of a $\sigma $-structure 2010 | % | presentations of automatic $\sigma $-structures 2011 | % | automatic presentations of $\sigma $-structures 2012 | % 2013 | %\knowledge{notion} 2014 | % | structure represented 2015 | % 2016 | %\knowledge{notion} 2017 | % | automatic presentation 2018 | % | automatic presentations 2019 | % | presentation@automatic 2020 | % 2021 | %\knowledge{notion} 2022 | % | represented@struct 2023 | % | represents@struct 2024 | % 2025 | %\knowledge{notion} 2026 | % | injective presentations 2027 | % | injective presentation 2028 | % 2029 | %\knowledge{notion} 2030 | % | injective automatic presentation 2031 | % 2032 | %\knowledge{notion} 2033 | % | length-lexicographic 2034 | % 2035 | %\knowledge{notion} 2036 | % | length-lexicographic order 2037 | % 2038 | %\knowledge{notion} 2039 | % | automatic@pres 2040 | % 2041 | %\knowledge{notion} 2042 | % | presentation 2043 | % | presentations 2044 | % 2045 | %\knowledge{notion} 2046 | % | injective@pres 2047 | % 2048 | %\knowledge{notion} 2049 | % | $d$-dimensional interpretation 2050 | % 2051 | %\knowledge{notion} 2052 | % | tree-automatic structures 2053 | % | $\omega $-tree-automatic structures 2054 | % 2055 | %\knowledge{notion} 2056 | % | First-Order Model Checking of Automatic $\sigma $-Structures 2057 | % | First-order model checking of automatic structures 2058 | % | first-order model checking of automatic structures 2059 | % 2060 | %\knowledge{notion} 2061 | % | data complexity 2062 | % 2063 | %\knowledge{notion} 2064 | % | Hodgson's theorem 2065 | % 2066 | %\knowledge{notion} 2067 | % | first-order model-checking 2068 | % 2069 | %\knowledge{notion} 2070 | % | primitive-positive sentences 2071 | % 2072 | %\knowledge{notion} 2073 | % | finite graph reachability problem 2074 | % 2075 | %\knowledge{notion} 2076 | % | existential sentences 2077 | % 2078 | %\knowledge{notion} 2079 | % | FOaut 2080 | % 2081 | %\knowledge{notion} 2082 | % | Presburger arithmetic 2083 | % 2084 | %\knowledge{notion} 2085 | % | higher-order automatic structures 2086 | % | higher-order automatic structure 2087 | % 2088 | %\knowledge{notion} 2089 | % | higher-order automatic 2090 | % 2091 | %\knowledge{notion} 2092 | % | upward Löwenheim–Skolem theorem 2093 | % 2094 | %\knowledge{notion} 2095 | % | order-invariant first-order formula 2096 | % | $\omega $-order-invariant first-order formulas 2097 | % | $\omega $-order-invariant first-order formula 2098 | % | order-invariant first-order formulas 2099 | % 2100 | %\knowledge{notion} 2101 | % | sentences@FO 2102 | % 2103 | %\knowledge{notion} 2104 | % | $\omega $-order-invariant@FO 2105 | % | order-invariant@FO 2106 | % | order-invariance@FO 2107 | % 2108 | %\knowledge{notion} 2109 | % | Isomorphism Problem for Automatic Structures 2110 | % 2111 | %\knowledge{notion} 2112 | % | isomorphic@struct 2113 | % 2114 | %\knowledge{notion} 2115 | % | Automatic ordinals 2116 | % | automatic ordinals 2117 | % 2118 | %\knowledge{notion} 2119 | % | $\omega $-tree-automatic ordinals 2120 | % | tree-automatic ordinals 2121 | % 2122 | %\knowledge{notion} 2123 | % | automatic Boolean algebras 2124 | % 2125 | %\knowledge{notion} 2126 | % | $\omega $-tree-automaticity 2127 | % 2128 | %\knowledge{notion} 2129 | % | $\omega $-tree-automatic Boolean algebras 2130 | % 2131 | %\knowledge{notion} 2132 | % | ZFC 2133 | % 2134 | %\knowledge{notion} 2135 | % | automatic semigroups 2136 | % 2137 | %\knowledge{notion} 2138 | % | finite regular colourability of automatic graphs 2139 | % | Finite Regular Colourability of Automatic Graphs 2140 | % 2141 | %\knowledge{notion} 2142 | % | regular@hom 2143 | % | Regularity@hom 2144 | % | regularity@hom 2145 | % 2146 | %\knowledge{notion} 2147 | % | Mycielski's construction 2148 | % 2149 | %\knowledge{notion} 2150 | % | CSPs 2151 | % | CSP 2152 | % 2153 | %\knowledge{notion} 2154 | % | coNLogTime 2155 | % 2156 | %\knowledge{notion} 2157 | % | modL 2158 | % 2159 | %\knowledge{notion} 2160 | % | finite graph 2161 | % 2162 | %\knowledge{notion} 2163 | % | obstructions 2164 | % | obstruction 2165 | % 2166 | %\knowledge{notion} 2167 | % | Atserias' theorem 2168 | % 2169 | %\knowledge{notion} 2170 | % | Larose-Tesson theorem 2171 | % 2172 | %\knowledge{notion} 2173 | % | source side@struct 2174 | % 2175 | %\knowledge{notion} 2176 | % | regular $k$-colourability problem 2177 | % | regular $k$-colourability@problem 2178 | % | regular colourability problem 2179 | % | regular $2$-colourability problem 2180 | % 2181 | %\knowledge{notion} 2182 | % | finite regular colourability@problem 2183 | % | finite regular colourability problem 2184 | % 2185 | %\knowledge{notion} 2186 | % | regular homomorphism problem 2187 | % 2188 | %\knowledge{notion} 2189 | % | Dichotomy Theorem for Automatic Structures 2190 | % | dichotomy theorem for automatic structures 2191 | % 2192 | %\knowledge{notion} 2193 | % | uniformly first-order definable homomorphisms 2194 | % | Uniformly first-order definable homomorphisms 2195 | % 2196 | %\knowledge{notion} 2197 | % | reversible Turing machines 2198 | % 2199 | %\knowledge{notion} 2200 | % | regular reachability problem 2201 | % 2202 | %\knowledge{notion} 2203 | % | linear Turing machines 2204 | % | linear Turing machine 2205 | % 2206 | %\knowledge{notion} 2207 | % | regular unconnectivity in automatic graphs 2208 | % | Regular Unconnectivity in Automatic Graphs 2209 | % | Regular unconnectivity in automatic graphs 2210 | % 2211 | %\knowledge{notion} 2212 | % | hyperedge consistency algorithm@automatic 2213 | % 2214 | %\knowledge{notion} 2215 | % | tree duality 2216 | % 2217 | %\knowledge{notion} 2218 | % | presentation@auto 2219 | % 2220 | %\knowledge{notion} 2221 | % | presentation of an automatic graph 2222 | % 2223 | %\knowledge{notion} 2224 | % | idempotent core 2225 | % 2226 | %\knowledge{notion} 2227 | % | De Bruijn–Erdős Theorem 2228 | % | De Bruijn-Erdős theorem 2229 | % 2230 | %\knowledge{notion} 2231 | % | Tychonoff's compactness theorem 2232 | % 2233 | %\knowledge{notion} 2234 | % | induced@structure 2235 | % 2236 | %\knowledge{notion} 2237 | % | finite intersection property 2238 | % 2239 | %\knowledge{notion} 2240 | % | dual 2241 | % | duals 2242 | % 2243 | %\knowledge{notion} 2244 | % | critical@obs 2245 | % 2246 | %\knowledge{notion} 2247 | % | critical obstruction 2248 | % | critical obstructions 2249 | % 2250 | %\knowledge{notion} 2251 | % | zigzag graph 2252 | % 2253 | %\knowledge{notion} 2254 | % | rigid 2255 | % 2256 | %\knowledge{notion} 2257 | % | strongly acyclic@struct 2258 | % 2259 | %\knowledge{notion} 2260 | % | $\sigma $-tree 2261 | % | $\sigma $-trees 2262 | % 2263 | %\knowledge{notion} 2264 | % | height@struct 2265 | % 2266 | %\knowledge{notion} 2267 | % | compatible@recognizable 2268 | % | incompatible@recognizable 2269 | % 2270 | %\knowledge{notion} 2271 | % | incompatibility graph 2272 | % | Incompatibility graph 2273 | % 2274 | %\knowledge{notion} 2275 | % | incompatibility relation 2276 | % 2277 | %\knowledge{notion} 2278 | % | finitely regularly colourable 2279 | % 2280 | %\knowledge{notion} 2281 | % | reversible 2282 | % 2283 | %\knowledge{notion} 2284 | % | well-founded 2285 | % 2286 | %\knowledge{notion} 2287 | % | linear@TM 2288 | % 2289 | %\knowledge{notion} 2290 | % | germinal 2291 | % 2292 | %\knowledge{notion} 2293 | % | germinal configurations 2294 | % 2295 | %\knowledge{notion} 2296 | % | $k$-coloured automaton 2297 | % 2298 | %\knowledge{notion} 2299 | % | $k$-coloured automata 2300 | % 2301 | %\knowledge{notion} 2302 | % | symmetric relation 2303 | % 2304 | %\knowledge{notion} 2305 | % | Connectivity in automatic graphs 2306 | % | Connectivity in Automatic Graphs 2307 | % | connectivity in automatic graphs 2308 | % 2309 | %\knowledge{notion} 2310 | % | unary type 2311 | % 2312 | %\knowledge{notion} 2313 | % | obstructing@unarytype 2314 | % 2315 | %\knowledge{notion} 2316 | % | regularly unconnected 2317 | % 2318 | %\knowledge{notion} 2319 | % | hyperedge consistency algorithm for automatic structures 2320 | % 2321 | %\knowledge{notion} 2322 | % | hyperedge consistency algorithm for finite structures 2323 | % 2324 | %\knowledge{notion} 2325 | % | hyperedge consistency@finite 2326 | % 2327 | %\knowledge{notion} 2328 | % | complete lattice 2329 | % 2330 | %\knowledge{notion} 2331 | % | Knaster-Tarski theorem 2332 | % 2333 | %\knowledge{notion} 2334 | % | regularity@fun 2335 | % | regular@fun 2336 | % 2337 | %\knowledge{notion} 2338 | % | quantifier alternation 2339 | % 2340 | %\knowledge{notion} 2341 | % | locally finite@struct 2342 | % 2343 | %\knowledge{notion} 2344 | % | connected graphs 2345 | % 2346 | %\knowledge{notion} 2347 | % | unconnected@struct 2348 | % | connectivity@struct 2349 | % 2350 | %\knowledge{notion} 2351 | % | graph isomorphisms 2352 | % 2353 | %\knowledge{notion} 2354 | % | finite colourability problem 2355 | % 2356 | %\knowledge{notion} 2357 | % | Finite Colourability of Automatic Graphs 2358 | % | Finite colourability of automatic graphs 2359 | % | finite colourability of automatic graphs 2360 | % 2361 | %\knowledge{notion} 2362 | % | finite subgraph 2363 | % 2364 | %\knowledge{notion} 2365 | % | source@struct 2366 | % 2367 | %\knowledge{notion} 2368 | % | contain unbounded tournaments 2369 | % 2370 | %\knowledge{notion} 2371 | % | has bounded tournaments 2372 | % 2373 | %\knowledge{notion} 2374 | % | triangle-free graphs@dir 2375 | % 2376 | %\knowledge{notion} 2377 | % | triangle-free@undir 2378 | % 2379 | %\knowledge{notion} 2380 | % | triangle-free@dir 2381 | % 2382 | %\knowledge{notion} 2383 | % | triangle-free graph@undir 2384 | % | triangle-free graphs@undir 2385 | % 2386 | %\knowledge{notion} 2387 | % | Mycielskian 2388 | % 2389 | %\knowledge{notion} 2390 | % | adjacent elements 2391 | % 2392 | %\knowledge{notion} 2393 | % | infinite Mycielski graph 2394 | % 2395 | %\knowledge{notion} 2396 | % | $\+V$-relation 2397 | % | $\+V$-relations 2398 | % | $\symbf {\+V}$-relation 2399 | % 2400 | %\knowledge{notion} 2401 | % | lifting theorem 2402 | % | Lifting Theorem 2403 | % | Lifting theorem 2404 | % 2405 | %\knowledge{notion} 2406 | % | dependency relation 2407 | % 2408 | %\knowledge{notion} 2409 | % | syntactic congruence@sync 2410 | % 2411 | %\knowledge{notion} 2412 | % | syntactic congruence 2413 | % 2414 | %\knowledge{notion} 2415 | % | dependency 2416 | % | dependent 2417 | % 2418 | %\knowledge{notion} 2419 | % | Lifting theorem: Elementary Formulation 2420 | % 2421 | %\knowledge{notion} 2422 | % | corresponding@EilenbergSg 2423 | % 2424 | %\knowledge{notion} 2425 | % | recognized@sync 2426 | % | recognizes@sync 2427 | % | recognize@sync 2428 | % | recognizing@sync 2429 | % 2430 | %\knowledge{notion} 2431 | % | underlying monoids 2432 | % | underlying monoid 2433 | % 2434 | %\knowledge{notion} 2435 | % | syntactic algebras@sync 2436 | % | syntactic algebra@sync 2437 | % 2438 | %\knowledge{notion} 2439 | % | residuals 2440 | % | residual 2441 | % 2442 | %\knowledge{notion} 2443 | % | lifting theorem@monoids 2444 | % | lifting theorem for monoids 2445 | % 2446 | %\knowledge{notion} 2447 | % | $*$-pseudovarieties of automatic relations 2448 | % | $\ast $-pseudovariety of automatic relations 2449 | % | $\ast $-pseudo\-variety of automatic relations 2450 | % | $\ast $-pseudovarieties of automatic relations 2451 | % | pseudovariety of automatic relations 2452 | % 2453 | %\knowledge{notion} 2454 | % | lifting theorem@monoidspseudovar 2455 | % 2456 | %\knowledge{notion} 2457 | % | complement@rel 2458 | % 2459 | %\knowledge{notion} 2460 | % | group relations 2461 | % | group relation 2462 | % 2463 | %\knowledge{notion} 2464 | % | letter-type 2465 | % | letter-types 2466 | % 2467 | %\knowledge{notion} 2468 | % | $\types $-typed set 2469 | % | typed set 2470 | % | typed sets 2471 | % | $\typesEps $-typed sets 2472 | % 2473 | %\knowledge{notion} 2474 | % | map between typed sets 2475 | % | maps of typed sets 2476 | % 2477 | %\knowledge{notion} 2478 | % | dependent set 2479 | % | dependent sets 2480 | % 2481 | %\knowledge{notion} 2482 | % | closed subset 2483 | % | closed subsets 2484 | % 2485 | %\knowledge{notion} 2486 | % | synchronous words 2487 | % 2488 | %\knowledge{notion} 2489 | % | compatible@type 2490 | % | compatibility@type 2491 | % | compatible type 2492 | % 2493 | %\knowledge{notion} 2494 | % | product 2495 | % 2496 | %\knowledge{notion} 2497 | % | Eilenberg-Moore algebras 2498 | % 2499 | %\knowledge{notion} 2500 | % | Morphisms of synchronous algebras 2501 | % | synchronous algebra morphisms 2502 | % | synchronous algebra morphism 2503 | % | morphism of synchronous algebras 2504 | % 2505 | %\knowledge{notion} 2506 | % | morphism@sync 2507 | % | morphisms@sync 2508 | % 2509 | %\knowledge{notion} 2510 | % | recognizability@sync 2511 | % 2512 | %\knowledge{notion} 2513 | % | induces@sync 2514 | % 2515 | %\knowledge{notion} 2516 | % | consolidation 2517 | % 2518 | %\knowledge{notion} 2519 | % | syntactic synchronous algebra morphism 2520 | % 2521 | %\knowledge{notion} 2522 | % | Syntactic morphism theorem@sync 2523 | % 2524 | %\knowledge{notion} 2525 | % | algebra@sync 2526 | % | algebras@sync 2527 | % 2528 | %\knowledge{notion} 2529 | % | congruence@sync 2530 | % 2531 | %\knowledge{notion} 2532 | % | locally transitive 2533 | % 2534 | %\knowledge{notion} 2535 | % | quotient structure@sync 2536 | % 2537 | %\knowledge{notion} 2538 | % | syntactic morphism@sync 2539 | % | syntactic morphisms@sync 2540 | % 2541 | %\knowledge{notion} 2542 | % | closed 2543 | % 2544 | %\knowledge{notion} 2545 | % | synchronous algebra induced by the monoid 2546 | % 2547 | %\knowledge{notion} 2548 | % | divides@sync 2549 | % | divide@sync 2550 | % 2551 | %\knowledge{notion} 2552 | % | naive synchronous algebra 2553 | % 2554 | %\knowledge{notion} 2555 | % | pseudovariety of synchronous algebras 2556 | % | pseudovarieties of synchronous algebras 2557 | % 2558 | %\knowledge{notion} 2559 | % | Eilenberg-Schützenberger correspondence@sync 2560 | % 2561 | %\knowledge{notion} 2562 | % | quotient@sync 2563 | % 2564 | %\knowledge{notion} 2565 | % | subalgebra@sync 2566 | % 2567 | %\knowledge{notion} 2568 | % | locally generated@sync 2569 | % 2570 | %\knowledge{notion} 2571 | % | locally generated 2572 | % 2573 | %\knowledge{notion} 2574 | % | pseudovariety@syncalg 2575 | % 2576 | %\knowledge{notion} 2577 | % | Boolean combinations 2578 | % | Boolean combination 2579 | % 2580 | %\knowledge{notion} 2581 | % | Syntactic derivatives 2582 | % | syntactic derivatives 2583 | % 2584 | %\knowledge{notion} 2585 | % | Inverse morphisms 2586 | % | inverse morphisms 2587 | % 2588 | %\knowledge{notion} 2589 | % | generated@var 2590 | % 2591 | %\knowledge{notion} 2592 | % | pseudovariety generated 2593 | % 2594 | %\knowledge{notion} 2595 | % | subalgebras 2596 | % 2597 | %\knowledge{notion} 2598 | % | Eilenberg-Schützenberger correspondence theorem@sync 2599 | % 2600 | %\knowledge{notion} 2601 | % | An Eilenberg theorem for automatic relations 2602 | % 2603 | %\knowledge{notion} 2604 | % | division@sync 2605 | % 2606 | %\knowledge{notion} 2607 | % | Lifting Theorem: Pseudovariety Formulation 2608 | % 2609 | %\knowledge{notion} 2610 | % | fully-preordered@lang 2611 | % 2612 | %\knowledge{notion} 2613 | % | monadic second-order 2614 | % 2615 | %\knowledge{notion} 2616 | % | first-order 2617 | % 2618 | %\knowledge{notion} 2619 | % | monad adjunction 2620 | % 2621 | %\knowledge{notion} 2622 | % | monad functor 2623 | % | Monad functors 2624 | % | Monads functors 2625 | % | monad functors 2626 | % 2627 | %\knowledge{notion} 2628 | % | Kleene's monad 2629 | % 2630 | %\knowledge{notion} 2631 | % | Wilke's monad 2632 | % 2633 | %\knowledge{notion} 2634 | % | 2-typed sets 2635 | % 2636 | %\knowledge{notion} 2637 | % | mutually dependent 2638 | % 2639 | %\knowledge{notion} 2640 | % | $\DRAT $/$\REC $-separability@pb 2641 | % 2642 | %\knowledge{notion} 2643 | % | $\Omega $-path algebras 2644 | % | $\WellFormed $-path algebras 2645 | % | $\Omega _T$-path algebras 2646 | % 2647 | %\knowledge{notion} 2648 | % | fully-preordered languages 2649 | --------------------------------------------------------------------------------