{"id":26487964,"url":"https://github.com/acrion/zelph","last_synced_at":"2026-01-21T17:05:03.168Z","repository":{"id":281512089,"uuid":"942928612","full_name":"acrion/zelph","owner":"acrion","description":"A sophisticated semantic network system capable of encoding inference rules within the network itself. Built for efficient memory usage and powerful logical reasoning, zelph can process the entire Wikidata knowledge graph (1.7TB) to detect contradictions and make logical deductions.","archived":false,"fork":false,"pushed_at":"2026-01-15T20:33:10.000Z","size":830,"stargazers_count":3,"open_issues_count":1,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-15T21:56:34.936Z","etag":null,"topics":["contradiction-detection","cpp-library","inference-engine","knowledge-graph","knowledge-representation","logical-reasoning","memory-optimization","semantic-network","semantic-web","wikidata"],"latest_commit_sha":null,"homepage":"https://zelph.org","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/acrion.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"acrion","liberapay":"acrion","buy_me_a_coffee":"acrion","patreon":"acriondev"}},"created_at":"2025-03-04T22:47:30.000Z","updated_at":"2026-01-15T20:33:15.000Z","dependencies_parsed_at":"2025-09-23T13:12:09.326Z","dependency_job_id":"b877ee83-f711-4bcb-adb4-bf856ead57ff","html_url":"https://github.com/acrion/zelph","commit_stats":null,"previous_names":["acrion/zelph"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/acrion/zelph","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acrion%2Fzelph","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acrion%2Fzelph/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acrion%2Fzelph/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acrion%2Fzelph/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/acrion","download_url":"https://codeload.github.com/acrion/zelph/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acrion%2Fzelph/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28636733,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-21T15:01:31.228Z","status":"ssl_error","status_checked_at":"2026-01-21T14:42:58.942Z","response_time":86,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["contradiction-detection","cpp-library","inference-engine","knowledge-graph","knowledge-representation","logical-reasoning","memory-optimization","semantic-network","semantic-web","wikidata"],"created_at":"2025-03-20T06:54:46.394Z","updated_at":"2026-01-21T17:05:03.160Z","avatar_url":"https://github.com/acrion.png","language":"C","funding_links":["https://github.com/sponsors/acrion","https://liberapay.com/acrion","https://buymeacoffee.com/acrion","https://patreon.com/acriondev"],"categories":[],"sub_categories":[],"readme":"# zelph: A Sophisticated Semantic Network System\n\n## Quick Start Guide\n\n### Installation\n\nChoose the method that matches your operating system:\n\n#### 🐧 Linux (Arch Linux)\n\nzelph is available in the [AUR](https://aur.archlinux.org/packages/zelph):\n\n```bash\npikaur -S zelph\n```\n\n#### 🐧 Linux (Other Distributions)\n\nDownload the latest `zelph-linux.zip` from [Releases](https://github.com/acrion/zelph/releases), extract it, and run the binary directly.\nAlternatively, see [Building zelph](#building-zelph) below to compile from source.\n\n#### 🍏 macOS (via Homebrew)\n\n```bash\nbrew tap acrion/zelph\nbrew install zelph\n```\n\n#### 🪟 Windows (via Chocolatey)\n\n```powershell\nchoco install zelph\n```\n\n### Basic Usage\n\nOnce installed, you can run zelph in interactive mode simply by typing `zelph` in your terminal.\n(If you downloaded a binary manually without installing, run `./zelph` from the extraction directory).\n\nLet’s try a basic example:\n\n```\nBerlin \"is capital of\" Germany\nGermany \"is located in\" Europe\nX is capital of Y, Y is located in Z =\u003e X is located in Z\n```\n\nAfter entering these statements, zelph will automatically infer that Berlin is located in Europe:\n\n```\n«Berlin» «is located in» «Europe» ⇐ («Germany» «is located in» «Europe»), («Berlin» «is capital of» «Germany»)\n```\n\nNote that none of the items used in the above statements are predefined, i.e. all are made known to zelph by these statements.\nIn section [Semantic Network Structure](#semantic-network-structure) you’ll find details about the core concepts, including syntactic details.\n\n### Using Sample Scripts\n\nzelph comes with sample scripts to demonstrate its capabilities:\n\n```bash\n# Run with the English examples script\n./build/bin/zelph sample_scripts/english.zph\n\n# Or try the Wikidata integration script\n./build/bin/zelph sample_scripts/wikidata.zph\n```\n\nWithin interactive mode, you can load a `.zph` script file using:\n\n```\n.import sample_scripts/english.zph\n```\n\n### Loading and Saving Network State\n\nzelph allows you to save the current network state to a binary file and load it later:\n\n```\n.save network.bin          # Save the current network\n.load network.bin          # Load a previously saved network\n```\n\nThe `.load` command is general-purpose:\n\n- If the file ends with `.bin`, it loads the serialized network directly (fast).\n- If the file ends with `.json` (a Wikidata dump), it imports the data and automatically creates a `.bin` cache file for future loads.\n\n### Data Cleanup Commands\n\nzelph provides powerful commands for targeted data removal:\n\n- `.prune-facts \u003cpattern\u003e` – Removes only the matching facts (statement nodes).  \n  Useful for deleting specific properties without affecting the entities themselves.\n\n- `.prune-nodes \u003cpattern\u003e` – Removes matching facts **and** all nodes bound to the single variable.  \n  Requirements: exactly one variable (subject or single object), fixed relation.  \n  **Warning**: This completely deletes the nodes and **all** their connections – use with caution!\n\n- `.cleanup` – Removes all isolated nodes and cleans name mappings.\n\nExample:\n\n```\n.lang wikidata\nA P31 Q8054                 # Query all proteins\n.prune-facts A P31 Q8054    # Remove only \"instance of protein\" statements\n.prune-nodes A P31 Q8054    # Remove statements AND all protein nodes (with all their properties!)\n.cleanup                    # Clean up any remaining isolated nodes\n```\n\n### Full Command Reference\n\nType `.help` inside the interactive session for a complete overview, or `.help \u003ccommand\u003e` for details on a specific command.\n\nKey commands include:\n\n- `.help [command]`          – Show help\n- `.exit`                    – Exit interactive mode\n- `.lang [code]`             – Show or set current language (e.g., `en`, `de`, `wikidata`)\n- `.name \u003cnode|id\u003e \u003cnew_name\u003e` – Set node name in current language\n- `.name \u003cnode|id\u003e \u003clang\u003e \u003cnew_name\u003e` – Set node name in specific language\n- `.delname \u003cnode|id\u003e [lang]` – Delete node name in current (or specified) language\n- `.node \u003cname|id\u003e`          – Show detailed node information (names, connections, representation, Wikidata URL)\n- `.list \u003ccount\u003e`            – List first N existing nodes (internal order, with details)\n- `.clist \u003ccount\u003e`           – List first N nodes named in current language (sorted by ID if feasible)\n- `.out \u003cname|id\u003e [count]`   – List outgoing connected nodes (default 20)\n- `.in \u003cname|id\u003e [count]`    – List incoming connected nodes (default 20)\n- `.mermaid \u003cname\u003e [depth]`  – Generate Mermaid HTML file for a node (default depth 3)\n- `.run`                     – Full inference\n- `.run-once`                – Single inference pass\n- `.run-md \u003csubdir\u003e`         – Inference + Markdown export\n- `.run-file \u003cfile\u003e`         – Inference + write deduced facts to file (compressed if wikidata)\n- `.decode \u003cfile\u003e`           – Decode a file produced by `.run-file`\n- `.list-rules`              – List all defined rules\n- `.list-predicate-usage [max]` – Show predicate usage statistics (top N most frequent)\n- `.list-predicate-value-usage \u003cpred\u003e [max]` – Show object/value usage statistics (top N most frequent values)\n- `.remove-rules`            – Remove all inference rules\n- `.remove \u003cname|id\u003e`        – Remove a node (destructive: disconnects all edges and cleans names)\n- `.import \u003cfile.zph\u003e`       – Load and execute a zelph script\n- `.load \u003cfile\u003e`             – Load saved network (.bin) or import Wikidata JSON (creates .bin cache)\n- `.save \u003cfile.bin\u003e`         – Save current network to binary file\n- `.prune-facts \u003cpattern\u003e`   – Remove all facts matching the query pattern (only statements)\n- `.prune-nodes \u003cpattern\u003e`   – Remove matching facts AND all involved subject/object nodes\n- `.cleanup`                 – Remove isolated nodes\n- `.stat`                    – Show network statistics (nodes, RAM usage, name entries, languages, rules)\n- `.wikidata-constraints \u003cjson\u003e \u003cdir\u003e` – Export property constraints as zelph scripts\n\n### What’s Next?\n\n- Explore the [Core Concepts](#core-concepts) to understand how zelph represents knowledge\n- Learn about [Rules and Inference](#rules-and-inference) to leverage zelph’s reasoning capabilities\n- Check out the [Example Script](#example-script) for a comprehensive demonstration\n\n## Introduction\n\nzelph is an innovative semantic network system that allows inference rules to be defined within the network itself.\nThis project provides a powerful foundation for knowledge representation and automated reasoning, with a special focus on efficiency and logical inference capabilities.\nWith dedicated import functions and specialized semantic scripts (like [wikidata.zph](https://github.com/acrion/zelph/blob/main/sample_scripts/wikidata.zph)),\nzelph offers powerful analysis capabilities for the complete Wikidata knowledge graph while remaining adaptable for any semantic domain.\n\n### Community and Support\n\nDevelopment of zelph is supported by the [Wikimedia Community Fund](https://meta.wikimedia.org/wiki/Grants:Programs/Wikimedia_Community_Fund/Rapid_Fund/zelph:Wikidata_Contradiction_Detection_and_Constraint_Integration_(ID:_23553409)).\n\nThe project addresses real-world challenges in large-scale ontology management through direct collaboration with the [Wikidata Ontology Cleaning Task Force](https://www.wikidata.org/wiki/Wikidata:WikiProject_Ontology/Cleaning_Task_Force) and the [Mereology Task Force](https://www.wikidata.org/wiki/Wikidata_talk:WikiProject_Ontology/Mereology_Task_Force).\n\n### Components\n\nThe zelph ecosystem includes:\n\n- A core C++ library providing both C++ and C interfaces\n- A single command-line binary that offers both interactive usage (CLI) and batch processing capabilities\n- API functions beyond what’s available in the command-line interface\n- Integration options for languages like Go and Lua through the C interface\n\nThe key features of zelph include:\n\n- Representation of knowledge in a semantic network structure\n- Rules encoded within the same semantic network as facts\n- Support for multi-language node naming\n- Contradiction detection and resolution\n- Memory-efficient data structures optimized at bit level\n- A flexible scripting language for knowledge definition and querying\n- Built-in import functionality for Wikidata JSON datasets and general binary save/load\n\n## Core Concepts\n\n### Semantic Network Structure\n\nIn zelph, knowledge is represented as a network of nodes connected by relations.\nUnlike traditional semantic networks where relations are labeled edges,\nzelph treats relation types as first-class nodes themselves.\nThis unique approach enables powerful meta-reasoning about relations.\n\n### Facts and Relations\n\nFacts in zelph are represented as triples consisting of a subject, relation type, and object.\nThe standard relation type is `~`, which represents a categorical relation (similar to \"is a\" or \"instance of\").\nFor example:\n\n```\nX ~ Y\n```\n\nThis means \"X is an instance of category Y\" or \"X is a Y\".\n\n#### Working with Custom Relations\n\nzelph can work with any type of relation, not just the standard `~` relation.\nHere’s how custom relations work:\n\n```\nis opposite of ~ -\u003e\n\u003e «is opposite of» «~» «-\u003e»\nwhite is opposite of black\n\u003e «white» «is opposite of» «black»\n```\n\nIn this example, using the interactive CLI, the first line declares \"is opposite of\" as a relation type (a member of the `-\u003e` category).\nAfter the `\u003e` symbol, we see zelph’s responses.\n\nzelph creates new relation types automatically as needed. The explicit declaration of \"is opposite of\" can actually be omitted:\n\n```\nwhite \"is opposite of\" black\n\u003e «white» «is opposite of» «black»\n```\n\nHere, zelph automatically recognizes that \"is opposite of\" must be a relation type.\nNote that when a relation contains spaces and is being used for the first time, it must be enclosed in quotation marks.\nOnce the relation is known to zelph, the quotation marks are no longer necessary in subsequent usage.\n\n### Internal Representation of facts\n\nIn a conventional semantic network, relations between nodes are labeled, e.g.\n\n```mermaid\ngraph LR\n    white --\u003e|is opposite of| black\n```\n\nzelph’s representation of relation types works fundamentally differently.\nAs mentioned in the introduction, one of zelph’s distinguishing features is that it treats relation types as first-class nodes rather than as mere edge labels.\n\nAt the network level, there is only a single primitive relation type: `~`, which represents a general category relation.\nFar from being a limitation, this is actually one of zelph’s most powerful characteristics.\nRelations that differ from the basic `~` type are not represented as arrow labels in zelph, but as regular nodes with the same status as any other node in the network.\n\nInternally, zelph creates special nodes to represent relations. For example, when defining:\n\n```\n\"is opposite of\" ~ -\u003e\n```\n\nThis tells zelph that \"is opposite of\" is a relation (represented by `-\u003e`, which is the category of all relations).\nzelph creates a special node to represent this fact.\n\nThis can be visualized as follows:\n\n```mermaid\ngraph TD\n    A(\"is opposite of ~ -\u003e\") \u003c--\u003e B(\"is opposite of\")\n    C(\"-\u003e\") --\u003e A\n    A --\u003e D(\"~\")\n```\n\nThe nodes `-\u003e` and `~` are predefined zelph nodes. `-\u003e` represents the category of all relations, while `~` represents a subset of this category, namely the category of categorical relations. Every relation that differs from the standard relation `~` (like \"is opposite of\") is linked to `-\u003e` via a `~` relation.\n\nThe node `is opposite of ~ -\u003e` represents this specific relation (hence its name).\nThe relations to other nodes encode its meaning.\n\nThis approach provides several advantages:\n\n1. It enables meta-reasoning about relations themselves\n2. It simplifies the underlying data structures\n3. It allows relations to participate in other relations (higher-order relations)\n4. It provides a unified representation mechanism for both facts and rules\n\nThis architecture is particularly valuable when working with knowledge bases like Wikidata, where relations (called \"properties\" in Wikidata terminology) are themselves first-class entities with their own attributes, constraints, and relationships to other entities. zelph’s approach naturally aligns with Wikidata’s conceptual model, allowing for seamless representation and inference across the entire knowledge graph.\n\nSimilarly, when stating:\n\n```\nwhite \"is opposite of\" black\n```\n\nzelph creates a special relation node that connects the subject \"white\" bidirectionally, the object \"black\" in reverse direction, and the relation type \"is opposite of\" in the forward direction.\n\n```mermaid\ngraph TD\n    A(\"white is opposite of black\") \u003c--\u003e B(\"white\")\n    C(\"black\") --\u003e A\n    A --\u003e D(\"is opposite of\")\n```\n\nThe directions of the relations are as follows:\n\n| Element       | Example        | Relation Direction |\n|---------------|----------------|--------------------|\n| Subject       | white          | bidirectional      |\n| Object        | black          | backward           |\n| Relation Type | is opposite of | forward            |\n\nThis semantics is used by zelph in several contexts, such as rule unification. It’s required because zelph doesn’t encode relation types as labels on arrows but rather as equal nodes. This has the advantage of facilitating statements about statements, for example, the statement that a relation is transitive.\n\nThis design prevents subject and object from being identical in a relation. There are examples of this in Wikidata, e.g., \"South Africa (Q258)\" \"country (P17)\" \"South Africa (Q258)\". \"South Africa\" is thus linked to itself in Wikidata via the relation (property) \"Country\". These examples are extremely rare in Wikidata and are ignored during import, with a warning.\n\n## Creating a node graph\n\nYou can generate a node graph yourself using zelph’s `.mermaid` command, which outputs a Mermaid HTML format file. For example:\n\n```\n.mermaid name 3\n```\n\nIn this example, `name` refers to the node identifier (in the currently active language specified via the `.lang` command) whose connections you want to visualise. The following number represents the depth of connections to include in the graph (default is 3).\n\nTo view the Mermaid graph, open the generated HTML file in a web browser.\n\n## Rules and Inference\n\nOne of zelph’s most powerful features is the ability to define inference rules within the same network as facts. Rules are statements containing `=\u003e` with conditions before it and a consequence after it.\n\nExample rule:\n\n```\nR ~ \"transitive relation\", X R Y, Y R Z =\u003e X R Z\n```\n\nThis rule states that if R is a transitive relation, and X is related to Y by R, and Y is related to Z by R, then X is also related to Z by R.\nVariables in the zelph syntax are currently single uppercase letters. This restricts the number of variables in a rule to 26.\nNote that the scope of variables always is a single rule. Internally, more complex rules are possible, but this is currently\nonly supported via zelph’s API, not via the scripting interface. See [main.cpp](https://github.com/acrion/zelph/blob/main/src/app/main.cpp)\nfor an example on how to use the API.\n\nHere is a practical example of how this rule works in zelph (which you can also try out in interactive mode):\n\n```\nR ~ transitive relation, X R Y, Y R Z =\u003e X R Z\n\u003e ((Y R Z), (X R Y), (R «~» «transitive relation»)) «=\u003e» (X R Z)\n```\n\nAfter the `\u003e` symbol, we see zelph’s output, which in this case simply confirms the input of the rule.\nThe brackets `()` indicate that their content is represented as a separate node - each condition is a separate node in the semantic network.\n\nNow, let’s declare that the relation `\u003e` (greater than) belongs to the category (`~`) of transitive relations:\n\n```\n\u003e ~ transitive relation\n\u003e «\u003e» «~» «transitive relation»\n```\n\nNext, we provide three elements (\"4\", \"5\" and \"6\") for which the `\u003e` relation applies:\n\n```\n6 \u003e 5\n\u003e «6» «\u003e» «5»\n5 \u003e 4\n\u003e «5» «\u003e» «4»\n«6» «\u003e» «4» ⇐ («5» «\u003e» «4»), («6» «\u003e» «5»), («\u003e» «~» «transitive relation»)\n```\n\nAfter entering `5 \u003e 4`, zelph’s unification mechanism takes effect and automatically adds a new fact: `6 \u003e 4`. This demonstrates the power of the transitive relation rule in action.\n\nRules can also define contradictions using `!`:\n\n```\nX \"is opposite of\" Y, A ~ X, A ~ Y =\u003e !\n```\n\nThis rule states that if X is opposite of Y, then an entity A cannot be both an X and a Y, as this would be a contradiction.\n\nIf a contradiction is detected when a fact is entered (via the scripting language or during import of Wikidata data), the corresponding relation (the fact) is not entered into the semantic network. Instead, a fact is entered that describes this contradiction (making it visible in the Markdown export of the facts).\n\n### Performing Inference\n\nFacts and rules are added immediately, but inferences are only performed when you explicitly run `.run`.  \nQueries containing variables (e.g., `A \"is capital of\" Germany`) are answered immediately without `.run`.\n\nAfter entering facts and rules (interactively or via script), start the inference engine with:\n\n```\n.run\n```\n\nThis performs full inference: rules are applied repeatedly until no new facts can be derived. New deductions are printed as they are found.\n\nFor a single inference pass:\n\n```\n.run-once\n```\n\nTo export all deductions and contradictions as structured Markdown reports:\n\n```\n.run-md \u003csubdir\u003e\n```\n\nThis command generates a tree of Markdown files in `mkdocs/docs/\u003csubdir\u003e/` (the directory `mkdocs/docs/` must already exist in the current working directory).  \nIt is intended for integrating detailed reports into an existing MkDocs site – this is exactly how the contradiction and deduction reports on \u003chttps://zelph.org\u003e were produced.  \nFor normal interactive or script use, `.run` is the standard command.\n\n#### Exporting Deduced Facts to File\n\nThe command `.run-file \u003cpath\u003e` performs full inference (like `.run`) but additionally writes every deduced fact (positive deductions and contradictions) to the specified file – one per line.\n\nKey characteristics of the file output:\n\n- **Reversed order**: The reasoning chain comes first, followed by `⇒` and then the conclusion (or `!` for contradictions).\n- **Clean format**: No `«»` markup, no parentheses, no additional explanations – only the pure facts.\n- **Console output unchanged**: On the terminal you still see the normal format with `⇐` explanations and markup.\n\nExample session (with `.lang wikidata` active):\n\n```\n\u003e Q1 P1 Q2\n«Q1» «P1» «Q2»\n\u003e Q2 P1 Q3\n«Q2» «P1» «Q3»\n\u003e A P1 B, B P1 C =\u003e A P2 C\n((A «P1» B), (B «P1» C)) «=\u003e» (A «P2» C)\n\u003e .run-file /home/stefan/RAMDisk/output2.txt\nStarting full inference in encode mode – deduced facts (reversed order, no brackets/markup) will be written to /home/stefan/RAMDisk/output2.txt (with Wikidata token encoding).\n...\n«Q1» «P2» «Q3» ⇐ («Q1» «P1» «Q2»), («Q2» «P1» «Q3»)\n...\n\u003e Ready.\n```\n\nContent of `output2.txt`:\n\n```\n丂 一丂 七, 七 一丂 丄 ⇒ 丂 一七 丄\n```\n\nDecoding the file:\n\n```\n\u003e .decode /home/stefan/RAMDisk/output2.txt\nQ1 P1 Q2, Q2 P1 Q3 ⇒ Q1 P2 Q3\n```\n\nThe command is **general-purpose** and works with any language setting. It simply collects all deductions in a clean, machine-readable text file.\n\nWhen the current language is set to `wikidata` (via `.lang wikidata`), the output is **automatically compressed** using a dense encoding that maps Q/P identifiers to CJK characters. This dramatically reduces file size and – crucially – makes the data highly suitable for training or prompting large language models (LLMs). Standard tokenizers struggle with long numeric identifiers (Q123456789), often splitting them into many sub-tokens. The compact CJK encoding avoids this problem entirely, enabling efficient fine-tuning or continuation tasks on Wikidata-derived logical data.\n\nTo read an encoded (or plain) file back in human-readable form, use:\n\n```\n.decode \u003cpath\u003e\n```\n\nThis prints each line decoded (if it was encoded) using Wikidata identifiers.\n\n### Internal representation of rules\n\nLet’s explain the internal representation of rules based on the example rule above.\nThe complete rule graph looks like this:\n\n```mermaid\ngraph TD\n    n1[\"((Y R Z), (X R Y), (R «~» «transitive relation»)) «=\u003e» (X R Z)\"] --\u003e n2[\"=\u003e\"]\n    n3[\"-\u003e\"] --\u003e n4[\"R «~» «-\u003e»\"]\n    n10[\"transitive relation\"] --\u003e n11[\"R «~» «transitive relation»\"]\n    n12[\"(Y R Z), (X R Y), (R «~» «transitive relation»)\"] \u003c--\u003e n1\n    n12 --\u003e n13[\",\"]\n    n4 --\u003e n8[\"~\"]\n    n4 \u003c--\u003e n14[\"R\"]\n    n11 --\u003e n8\n    n11 --\u003e n12\n    n11 \u003c--\u003e n14\n    n15[\"X R Y\"] --\u003e n12\n    n15 --\u003e n14\n    n16[\"X R Z\"] --\u003e n1\n    n16 --\u003e n14\n    n17[\"X\"] \u003c--\u003e n15\n    n17 \u003c--\u003e n16\n    n18[\"Y R Z\"] --\u003e n12\n    n18 --\u003e n14\n    n19[\"Y\"] --\u003e n15\n    n19 \u003c--\u003e n18\n    n20[\"Z\"] --\u003e n16\n    n20 --\u003e n18\n    \n    style n12 fill:#87CEFA\n    style n14 fill:#EEE8AA\n    style n16 fill:#B3EE3A\n```\n\nThis graph may seem somewhat overwhelming at first glance, but it follows a clear structure.\nLet’s break it down:\n\n1. The three conditions of the rule are connected to the blue condition node, which itself points to the logical operation of the condition: `,` (which represents the logical AND operation):\n    ```mermaid\n    graph TD\n        n12[\"(Y R Z), (X R Y), (R «~» «transitive relation»)\"] --\u003e n13[\",\"]\n        n11[\"R «~» «transitive relation»\"] --\u003e n12\n        n15[\"X R Y\"] --\u003e n12\n        n18[\"Y R Z\"] --\u003e n12\n        \n        style n12 fill:#87CEFA\n    ```\n2. The blue condition node serves as the subject of the rule clause S =\u003e O (which is assigned the complete rule statement as a name). The green conclusion node functions as the object of the rule clause:\n    ```mermaid\n    graph TD\n        n1[\"((Y R Z), (X R Y), (R «~» «transitive relation»)) «=\u003e» (X R Z)\"] --\u003e n2[\"=\u003e\"]\n        n12[\"(Y R Z), (X R Y), (R «~» «transitive relation»)\"] \u003c--\u003e n1\n        n16[\"X R Z\"] --\u003e n1\n        \n        style n12 fill:#87CEFA\n        style n16 fill:#B3EE3A\n    ```\n\n3. Each condition, as well as the conclusion, is represented exactly like a fact (see the previous section \"Internal Representation of facts\").\n\nThis summarizes the complete diagram shown above. As mentioned earlier, the elegant aspect of this representation method is that the inference system can be applied not only to facts but also to rules.\nConsequently, it becomes possible to formulate rules that generate other rules.\n\n### Facts and Rules in One Network: Unique Identification via Topological Semantics\n\nA distinctive aspect of **zelph** is that **facts and rules live in the same semantic network**. That raises a natural question: how does the unification engine avoid confusing ordinary entities with statement nodes, and how does it keep rule matching unambiguous?\n\nThe answer lies in the network’s **strict topological semantics** (see [Internal Representation of facts](#internal-representation-of-facts) and [Internal representation of rules](#internal-representation-of-rules)). In zelph, a _statement node_ is not “just a node with a long label”; it has a **unique structural signature**:\n\n- **Bidirectional** connection to its **subject**\n- **Forward** connection to its **relation type** (a first-class node)\n- **Backward** connection to its **object**\n\nThe unification engine is **hard-wired to search only for this pattern** when matching a rule’s conditions. In other words, a variable that ranges over “statements” can only unify with nodes that expose exactly this subject/rel/type/object wiring. Conversely, variables intended to stand for ordinary entities cannot accidentally match a statement node, because ordinary entities **lack** that tri-partite signature.\n\nTwo immediate consequences follow:\n\n1. **Unambiguous matching.** The matcher cannot mistake an entity for a statement or vice versa; they occupy disjoint topological roles.\n2. **Network stability.** Because statementhood is encoded structurally, rules cannot “drift” into unintended parts of the graph. This design prevents spurious matches and the sort of runaway growth that would result if arbitrary nodes could pose as statements.\n\nThese constraints are not merely aesthetic; they are core to zelph’s reasoning guarantees and underpin the termination argument below.\n\n## Example Script\n\nHere’s a comprehensive example demonstrating zelph’s capabilities:\n\n```\nX \"is a\" Y  =\u003e X ~ Y\nX \"is an\" Y =\u003e X \"is a\" Y\n\nis               \"is a\" -\u003e\n\"has part\"       \"is a\" -\u003e\n\"is opposite of\" \"is a\" -\u003e\n\n\"is attribute of\" \"is opposite of\" is\n\"is part of\"      \"is opposite of\" \"has part\"\n\"is for example\"  \"is opposite of\" \"is a\"\n\n\"has part\"      \"is transitive\"\n\"has attribute\" \"is transitive\"\n~               \"is transitive\"\n\nR \"is transitive\", X R Y, Y R Z =\u003e X R Z\nX is E, E \"is a\" K  =\u003e X is K\nX \"has part\" P, P \"is a\" K  =\u003e X \"has part\" K\nK is E, X \"is a\" K  =\u003e X is E\nK \"has part\" P, X \"is a\" K  =\u003e X \"has part\" P\nX \"is opposite of\" Y, X \"is a\" K =\u003e Y \"is a\" K\nX \"is opposite of\" Y =\u003e Y \"is opposite of\" X\nR \"is opposite of\" S, X R Y =\u003e Y S X\n\nX \"is opposite of\" Y, A is X, A is Y =\u003e !\nX \"is opposite of\" Y, A \"has part\" X, A \"has part\" Y =\u003e !\nX \"is opposite of\" Y, A \"is a\" X, A \"is a\" Y =\u003e !\nX is E, X \"is a\" E =\u003e !\nX is E, E \"is a\" X =\u003e !\nX is E, E \"has part\" X =\u003e !\n\ngenerates \"is a\" -\u003e\nneeds \"is a\" -\u003e\n\n\"is needed by\" \"is opposite of\" needs\n\"is generated by\" \"is opposite of\" generates\n\nX generates energy =\u003e X \"is an\" \"energy source\"\nA is hot =\u003e A generates heat\nA generates oxygen =\u003e A is alive\n\nchimpanzee \"is an\" ape\nape is alive\n\nchimpanzee \"has part\" hand\nhand \"has part\" finger\n\n\"green mint\" \"is an\" mint\n\"water mint\" \"is a\" mint\npeppermint \"is an\" mint\nmint \"is a\" lamiacea\ncatnip \"is a\" lamiacea\n\"green mint\" is sweet\n\n\"is ancestor of\" \"is transitive\"\npeter \"is ancestor of\" paul\npaul \"is ancestor of\" pius\nA \"is ancestor of\" pius\n```\n\nWhen executed, the last line is interpreted as a query, because it contains a variable (single uppercase letter) and is no rule. Here are the results:\n\n```\nAnswer: «paul» «is ancestor of» «pius»\n«catnip» «~» «lamiacea» ⇐ «catnip» «is a» «lamiacea»\n«needs» «~» «-\u003e» ⇐ «needs» «is a» «-\u003e»\n«water mint» «~» «mint» ⇐ «water mint» «is a» «mint»\n«mint» «~» «lamiacea» ⇐ «mint» «is a» «lamiacea»\n«chimpanzee» «has part» «finger» ⇐ («hand» «has part» «finger»), («chimpanzee» «has part» «hand»), («has part» «is» «transitive»)\n«peter» «is ancestor of» «pius» ⇐ («paul» «is ancestor of» «pius»), («peter» «is ancestor of» «paul»), («is ancestor of» «is» «transitive»)\n«water mint» «~» «lamiacea» ⇐ («mint» «~» «lamiacea»), («water mint» «~» «mint»), («~» «is» «transitive»)\n«peppermint» «is a» «mint» ⇐ «peppermint» «is an» «mint»\n«chimpanzee» «is a» «ape» ⇐ «chimpanzee» «is an» «ape»\n«green mint» «is a» «mint» ⇐ «green mint» «is an» «mint»\n«chimpanzee» «is» «alive» ⇐ («chimpanzee» «is a» «ape»), («ape» «is» «alive»)\n«generates» «is opposite of» «is generated by» ⇐ «is generated by» «is opposite of» «generates»\n«has part» «is opposite of» «is part of» ⇐ «is part of» «is opposite of» «has part»\n«is a» «is opposite of» «is for example» ⇐ «is for example» «is opposite of» «is a»\n«is» «is opposite of» «is attribute of» ⇐ «is attribute of» «is opposite of» «is»\n«needs» «is opposite of» «is needed by» ⇐ «is needed by» «is opposite of» «needs»\n«finger» «is part of» «hand» ⇐ («hand» «has part» «finger»), («has part» «is opposite of» «is part of»)\n«hand» «is part of» «chimpanzee» ⇐ («chimpanzee» «has part» «hand»), («has part» «is opposite of» «is part of»)\n«finger» «is part of» «chimpanzee» ⇐ («chimpanzee» «has part» «finger»), («has part» «is opposite of» «is part of»)\n«sweet» «is attribute of» «green mint» ⇐ («green mint» «is» «sweet»), («is» «is opposite of» «is attribute of»)\n«alive» «is attribute of» «ape» ⇐ («ape» «is» «alive»), («is» «is opposite of» «is attribute of»)\n«transitive» «is attribute of» «is ancestor of» ⇐ («is ancestor of» «is» «transitive»), («is» «is opposite of» «is attribute of»)\n«alive» «is attribute of» «chimpanzee» ⇐ («chimpanzee» «is» «alive»), («is» «is opposite of» «is attribute of»)\n«transitive» «is attribute of» «has part» ⇐ («has part» «is» «transitive»), («is» «is opposite of» «is attribute of»)\n«transitive» «is attribute of» «~» ⇐ («~» «is» «transitive»), («is» «is opposite of» «is attribute of»)\n«transitive» «is attribute of» «has attribute» ⇐ («has attribute» «is» «transitive»), («is» «is opposite of» «is attribute of»)\n«mint» «is for example» «green mint» ⇐ («green mint» «is a» «mint»), («is a» «is opposite of» «is for example»)\n«lamiacea» «is for example» «catnip» ⇐ («catnip» «is a» «lamiacea»), («is a» «is opposite of» «is for example»)\n«-\u003e» «is for example» «needs» ⇐ («needs» «is a» «-\u003e»), («is a» «is opposite of» «is for example»)\n«mint» «is for example» «water mint» ⇐ («water mint» «is a» «mint»), («is a» «is opposite of» «is for example»)\n«-\u003e» «is for example» «is» ⇐ («is» «is a» «-\u003e»), («is a» «is opposite of» «is for example»)\n«-\u003e» «is for example» «has part» ⇐ («has part» «is a» «-\u003e»), («is a» «is opposite of» «is for example»)\n«ape» «is for example» «chimpanzee» ⇐ («chimpanzee» «is a» «ape»), («is a» «is opposite of» «is for example»)\n«lamiacea» «is for example» «mint» ⇐ («mint» «is a» «lamiacea»), («is a» «is opposite of» «is for example»)\n«-\u003e» «is for example» «is opposite of» ⇐ («is opposite of» «is a» «-\u003e»), («is a» «is opposite of» «is for example»)\n«-\u003e» «is for example» «generates» ⇐ («generates» «is a» «-\u003e»), («is a» «is opposite of» «is for example»)\n«mint» «is for example» «peppermint» ⇐ («peppermint» «is a» «mint»), («is a» «is opposite of» «is for example»)\n«green mint» «~» «mint» ⇐ «green mint» «is a» «mint»\n«chimpanzee» «~» «ape» ⇐ «chimpanzee» «is a» «ape»\n«peppermint» «~» «mint» ⇐ «peppermint» «is a» «mint»\n«peppermint» «~» «lamiacea» ⇐ («mint» «~» «lamiacea»), («peppermint» «~» «mint»), («~» «is» «transitive»)\n«green mint» «~» «lamiacea» ⇐ («mint» «~» «lamiacea»), («green mint» «~» «mint»), («~» «is» «transitive»)\n«is needed by» «is a» «-\u003e» ⇐ («needs» «is a» «-\u003e»), («needs» «is opposite of» «is needed by»)\n«is attribute of» «is a» «-\u003e» ⇐ («is» «is a» «-\u003e»), («is» «is opposite of» «is attribute of»)\n«is part of» «is a» «-\u003e» ⇐ («has part» «is a» «-\u003e»), («has part» «is opposite of» «is part of»)\n«is generated by» «is a» «-\u003e» ⇐ («generates» «is a» «-\u003e»), («generates» «is opposite of» «is generated by»)\n«-\u003e» «is for example» «is generated by» ⇐ («is generated by» «is a» «-\u003e»), («is a» «is opposite of» «is for example»)\n«-\u003e» «is for example» «is attribute of» ⇐ («is attribute of» «is a» «-\u003e»), («is a» «is opposite of» «is for example»)\n«-\u003e» «is for example» «is needed by» ⇐ («is needed by» «is a» «-\u003e»), («is a» «is opposite of» «is for example»)\n«-\u003e» «is for example» «is part of» ⇐ («is part of» «is a» «-\u003e»), («is a» «is opposite of» «is for example»)\n«is generated by» «~» «-\u003e» ⇐ «is generated by» «is a» «-\u003e»\n«is needed by» «~» «-\u003e» ⇐ «is needed by» «is a» «-\u003e»\nReady.\n```\n\nThe results demonstrate zelph’s powerful inference capabilities. It not only answers the specific query about who is an ancestor of pius, but also derives numerous other facts based on the rules and base facts provided in the script.\n\n## Multi-language Support\n\nzelph allows nodes to have names in multiple languages. This feature is particularly useful when integrating with external knowledge bases. The preferred language can be set in scripts using the `.lang` command:\n\n```\n.lang zelph\n```\n\nThis capability is fully utilized in the Wikidata integration, where node names include both human-readable labels and Wikidata identifiers. An item in zelph can be assigned names in any number of languages, with Wikidata IDs being handled as a specific language (\"wikidata\").\n\n## Project Status\n\nThe project is currently in **Version 0.9.3 (Beta)**. Core functionality is operational and has been rigorously tested against the full Wikidata dataset.\n\nCurrent focus areas include:\n\n- **REPL and parser refinement**: The REPL interface and the zelph language parser require architectural improvements.\n- **Enhancement of semantic rules**: The [wikidata.zph](https://github.com/acrion/zelph/blob/main/sample_scripts/wikidata.zph) script serves as a base, but the strategy has shifted from generic deductions to targeted contradiction detection. See the [Grant Report](grant-report.md) for details on this approach.\n- **Potential Wikidata integration**: Exploring pathways for integration with the Wikidata ecosystem, e.g. the [WikiProject Ontology](https://www.wikidata.org/wiki/Wikidata:WikiProject_Ontology).\n\nRegarding potential Wikidata integration and the enhancement of semantic scripts, collaboration with domain experts would be particularly valuable. Expert input on conceptual alignment and implementation of best practices would significantly accelerate development and ensure optimal compatibility with existing Wikidata infrastructure and standards.\n\n## Building zelph\n\nYou need:\n\n- C++ compiler (supporting at least C++20)\n- CMake 3.25.2+\n- Git\n\n### Build Instructions\n\n1. Clone the repository with all submodules:\n\n```bash\ngit clone --recurse-submodules https://github.com/acrion/zelph.git\n```\n\n2. Configure the build (Release mode):\n\n```bash\ncmake -D CMAKE_BUILD_TYPE=Release -B build src\n```\n\n3. Build the project (for MSVC, add `--config Release`):\n\n```bash\ncmake --build build\n```\n\n### Verifying the Build\n\nTest your installation by running the CLI:\n\n```bash\n./build/bin/zelph\n```\n\nor\n\n```bash\n./build/bin/zelph sample_scripts/english.zph\n```\n\n## Licensing\n\nzelph is dual-licensed:\n\n1. **AGPL v3 or later** for open-source use,\n2. **Commercial licensing** for closed-source integration or special requirements.\n\nWe would like to emphasize that offering a dual license does not restrict users of the normal open-source license (including commercial users).\nThe dual licensing model is designed to support both open-source collaboration and commercial integration needs.\nFor commercial licensing inquiries, please contact us at [https://acrion.ch/sales](https://acrion.ch/sales).\n\n# zelph and Wikidata: Finding Logical Connections and Contradictions\n\n## Wikidata as an Ideal Use Case for zelph\n\nWikidata represents an excellent application case for zelph’s capabilities.\nIt contains over 113 million entries interconnected by relations, all subject to logical constraints.\nThis complex web of knowledge presents two key opportunities for zelph:\n\n1. **Finding contradictions**: Identifying logical inconsistencies in the data\n2. **Making deductions**: Deriving new facts through logical inference\n\nFor example, if class `A` is the opposite of class `B` (such as [successor](https://www.wikidata.org/wiki/Q106110771) and [predecessor](https://www.wikidata.org/wiki/Q106110777)), then no entity `X` can belong to both classes (like [replacing entity](https://www.wikidata.org/wiki/Q45025415)).\n\nSimilarly, inferences can be made. Example: If X is related to Y and Y is related to Z through the same relation (e.g., X=[Canada](https://www.wikidata.org/wiki/Q16), Y=[American continent](https://www.wikidata.org/wiki/Q828), Z=[Earth's surface](https://www.wikidata.org/wiki/Q1349417), relation=[is part of](https://www.wikidata.org/wiki/Property:P361)), and the relation is [transitive](https://www.wikidata.org/wiki/Q64861), then X must also be related to Z in the same way.\n\n### Architectural Synergy with Wikidata\n\nzelph’s architecture of treating relations as first-class nodes creates a perfect alignment with Wikidata’s data model.\nIn Wikidata, properties (P-entities) are not merely labels on edges but are themselves entities with their own attributes, constraints, and relationships to other entities.\nThis fundamental similarity enables zelph to:\n\n1. **Naturally represent Wikidata’s property hierarchy**: Properties in Wikidata can have subproperties, domains, ranges, and other metadata - all of which are directly representable in zelph’s relation-as-node approach.\n\n2. **Reason about properties themselves**: zelph can apply inference rules to properties just as it does to regular entities, enabling powerful meta-reasoning capabilities essential for working with Wikidata’s complex property structure.\n\n3. **Enforce property constraints**: Wikidata’s property constraints (symmetry, transitivity, inverse relationships) map directly to zelph’s rule system, allowing automatic validation and inference.\n\nThis structural compatibility makes zelph well-suited for analyzing and enriching Wikidata’s knowledge graph while maintaining its semantic integrity.\n\n## Technical Implementation\n\n### Memory Efficiency\n\nThe scale of Wikidata is massive: the JSON dump is approximately 1.7 TB in size, containing over 113 million entries. zelph has been optimized to handle this scale effectively.\n\nThe system is capable of importing the **entire** Wikidata graph into memory, a significant achievement that enables non-iterative, complete contradiction detection. After processing, the complete semantic network is serialized to disk in a highly efficient format (~100 GB).\n\nWhile the serialized footprint is compact given the data volume (99 GB), loading the graph for active reasoning (where all relationships and structures must be accessible) requires significant memory. In practice, a system with **256 GB of RAM** is recommended for full-speed operation. Systems with 128 GB can process the graph by utilizing aggressive swap and compression (ZRAM), though at reduced performance.\n\n### Processing Performance\n\nRunning the inference process on Wikidata data is computationally intensive but highly optimized:\n\n- **Parallel Processing:** Both the data import and the unification/reasoning engine are multi-threaded, utilizing all available CPU cores to speed up processing.\n- **Performance:** A complete inference pass on the full dataset takes approximately 2.5 hours on high-end hardware (e.g., Intel Core i9 with 24 cores), though this depends heavily on available RAM and the specific rules being applied.\n- **Workflow:** Users can run targeted scripts to find specific classes of contradictions (see [Grant Report](grant-report.md) for examples like Split Order Violations).\n\n## Wikidata Integration Script\n\nThe following script demonstrates how zelph connects with Wikidata data:\n\n```\n.lang zelph\n\n.name !                wikidata Q363948\n.name ~                wikidata P31\n.name \"is subclass of\" wikidata P279\n.name \"is facet of\"    wikidata P1269\n.name =\u003e               wikidata Q374182\n.name -\u003e               wikidata Q130901\n.name \"is part of\"     wikidata P361\n.name \"has part\"       wikidata P527\n.name \"is opposite of\" wikidata P461\n.name \"is inverse of\"  wikidata P1696\n.name \"has quality\"    wikidata P1552\n.name \"is for example\" wikidata Q21514624\n.name \"transitive relation\" wikidata Q18647515\n\n# The following facts are part of wikidata:\n#\"is subclass of\" ~ transitive relation\n#\"has part\"       ~ transitive relation\n#\"is facet of\"    ~ transitive relation\n#\"is part of\"     ~ transitive relation\n#\"is part of\"     is inverse of \"has part\"\n\n# The following facts are not part of wikidata:\n\"has quality\" ~ transitive relation\n\nX is facet of Y, Y ~ C =\u003e X ~ C\nX is facet of Y, Y is subclass of C =\u003e X is subclass of C\nX is facet of Y, Y has part P =\u003e X has part P\nX is facet of Y, Y is part of P =\u003e X is part of P\nX is facet of Y, Y has quality Q =\u003e X has quality Q\n\n# The following fact is not part of wikidata. Wikidata only includes the fact \"is subclass of\" \"subject item of this property\" \"is for example\"\n\"is for example\"  is inverse of \"~\"\n\nR ~ transitive relation, X R Y, Y R Z =\u003e X R Z\nP ~ transitive relation, P is inverse of Q =\u003e Q ~ transitive relation\nX ~ K, K is subclass of U =\u003e X ~ U\n\nX has quality E,   E ~ K                =\u003e X has quality K\nX has quality E,   E is subclass of K  =\u003e X has quality K\nK has quality E,   X ~ K                =\u003e X has quality E\nK has quality E,   X is subclass of K  =\u003e X has quality E\nX has part P,      P ~ K                =\u003e X has part K\nK has part P,      X is subclass of K  =\u003e X has part P\n\nX is opposite of Y, X ~ K              =\u003e Y ~ K\nX is opposite of Y, X is subclass of K =\u003e Y is subclass of K\nX is inverse of Y,  X ~ K              =\u003e Y ~ K\nX is inverse of Y,  X is subclass of K =\u003e Y is subclass of K\n\nX is opposite of Y        =\u003e Y is opposite of X\nX is inverse of Y         =\u003e Y is inverse of X\nR is opposite of S, X R Y =\u003e Y S X\nR is inverse of S,  X R Y =\u003e Y S X\n\nX is opposite of Y, A has quality X, A has quality Y =\u003e !\nX is inverse of Y,  A has quality X, A has quality Y =\u003e !\nX is opposite of Y, A has part X,    A has part Y    =\u003e !\nX is inverse of Y,  A has part X,    A has part Y    =\u003e !\n\nX is opposite of Y, A ~ X,              A ~ Y              =\u003e !\nX is opposite of Y, A is subclass of X, A is subclass of Y =\u003e !\nX is inverse of Y,  A ~ X,              A ~ Y              =\u003e !\nX is inverse of Y,  A is subclass of X, A is subclass of Y =\u003e !\n\nX has quality E, X ~ E              =\u003e !\nX has quality E, X is subclass of E =\u003e !\nX has quality E, E ~ X              =\u003e !\nX has quality E, E is subclass of X =\u003e !\nX has quality E, E has part X       =\u003e !\n\nX has part E, X ~ E              =\u003e !\nX has part E, X is subclass of E =\u003e !\nX has part E, E ~ X              =\u003e !\nX has part E, E is subclass of X =\u003e !\n\n# The following contradiction requires that X cannot be at the same time an instance and a subclass:\nX ~ A, X is subclass of B =\u003e !\n\nA ~ B, B ~ A                           =\u003e !\nA is subclass of B, B is subclass of A =\u003e !\nA is facet of B, B is facet of A       =\u003e !\nA ~ B, B is subclass of A              =\u003e !\nA ~ B, B is facet of A                 =\u003e !\nA is subclass of B, B is facet of A    =\u003e !\n```\n\nThis script maps zelph’s relation types to Wikidata properties and items, defines inference rules, and establishes contradiction checks.\n\n## Understanding the Script\n\n### Relation Mapping\n\nThe script begins by mapping zelph’s internal names to Wikidata entities:\n\n- `~` is mapped to Wikidata’s [instance of (P31)](https://www.wikidata.org/wiki/Property:P31)\n- `is subclass of` is mapped to [subclass of (P279)](https://www.wikidata.org/wiki/Property:P279)\n- `is facet of` is mapped to [facet of (P1269)](https://www.wikidata.org/wiki/Property:P1269)\n\nThis careful mapping ensures that zelph can interpret Wikidata’s relational structure correctly.\n\n### Handling \"is a\" Relations\n\nWikidata makes a granular distinction between different types of category relations:\n\n1. [instance of (P31)](https://www.wikidata.org/wiki/Property:P31)\n2. [subclass of (P279)](https://www.wikidata.org/wiki/Property:P279)\n3. [facet of (P1269)](https://www.wikidata.org/wiki/Property:P1269)\n\nzelph’s flexible design accommodates these distinctions.\nThe idea of the script is to follow the [Wikidata usage guidelines](https://www.wikidata.org/wiki/Property:P2559).\nIt can be easily adapted or extended for further improvements.\n\nNotably, Wikidata only marks \"subclass of\" as transitive, not the other two relations.\nThis makes sense for \"instance of\" (since an instance is not a class), but the script adds transitivity for \"facet of\" along with additional rules that reflect its documented meaning:\nif X is a \"facet of\" Y, then X inherits all properties of Y.\n\nFor this case, the following rules are included in the script:\n\n- If `Y` is an [instance of](https://www.wikidata.org/wiki/Property:P31) `C`, then `X` must also be an [instance of](https://www.wikidata.org/wiki/Property:P31) `C`.\n- If `Y` is a [subclass of](https://www.wikidata.org/wiki/Property:P279) `C`, then `X` must also be a [subclass of](https://www.wikidata.org/wiki/Property:P279) `C`.\n- If `Y` [has part](https://www.wikidata.org/wiki/Property:P527) `P`, then `X` must also [have part](https://www.wikidata.org/wiki/Property:P527) `P`.\n- If `Y` is [part of](https://www.wikidata.org/wiki/Property:P361) `P`, then `X` must also be [part of](https://www.wikidata.org/wiki/Property:P361) `P`.\n- If `Y` has a [characteristic](https://www.wikidata.org/wiki/Property:P1552) `Q`, then `X` must also have a [characteristic](https://www.wikidata.org/wiki/Property:P1552) `Q`.\n\n### Example Inference Process\n\nHere’s a step-by-step example of zelph’s inference process when working with Wikidata:\n\n1. According to Wikidata, the property [greater than (P5135)](https://www.wikidata.org/wiki/Property:P5135) is an instance of [transitive Wikidata property (Q18647515)](https://www.wikidata.org/wiki/Q18647515).\n2. Wikidata also states that [transitive Wikidata property (Q18647515)](https://www.wikidata.org/wiki/Q18647515) is a [facet of (P1269)](https://www.wikidata.org/wiki/Property:P1269) [transitive relation (Q64861)](https://www.wikidata.org/wiki/Q64861).\n3. The script contains the rule: `X is facet of Y, Y ~ C =\u003e X ~ C`\n4. Therefore, zelph infers that [greater than (P5135)](https://www.wikidata.org/wiki/Property:P5135) is also an instance of [transitive relation (Q64861)](https://www.wikidata.org/wiki/Q64861).\n\n## Rules in the Semantic Network\n\nRules in zelph are encoded in the same semantic network as facts, using the special relation `=\u003e` (which corresponds to [logical consequence (Q374182)](https://www.wikidata.org/wiki/Q374182) in Wikidata).\n\nThis innovative approach enables tight integration between the fact base and the rules, allowing rules to be reasoned about in the same way as facts.\nThis makes zelph particularly powerful for applications like Wikidata, where the knowledge base itself contains statements about relations, including properties like [transitivity](https://www.wikidata.org/wiki/Q18647515).\n\nA rule is just a special case of a fact that uses the relation `=\u003e`. In the case of the application of zelph to Wikidata data, this relation corresponds to [logical consequence](https://www.wikidata.org/wiki/Q374182).\n\n## Loading and Processing Wikidata\n\nTo download the compressed JSON file, browse to https://dumps.wikimedia.org/wikidatawiki/entities/. You may need to\nsearch through the subdirectories to find a download link for `wikidata-*-all.json.bz2`.\n\nAfter uncompression, you may start zelph with the provided `wikidata.zph` script:\n\n```bash\nzelph sample_scripts/wikidata.zph\n```\n\n### Basic Import\n\nTo import Wikidata data (or load a previously saved network), use the `.load` command:\n\n```\n.wikidata download/wikidata-20250127-all.json\n```\n\nThis command is general-purpose:\n\n- For a Wikidata JSON dump, it imports the data and automatically creates a `.bin` cache file in the same directory for faster future loads.\n- For a `.bin` file (created by `.save`), it loads the serialized network directly.\n\n### Advanced Commands\n\nzelph provides several additional commands for working with Wikidata:\n\n* **Export Constraints:** Extract constraints from the dump and generate zelph scripts for them:\n  ```\n  .wikidata-constraints download/wikidata-20250127-all.json constraints_output_dir\n  ```\n\nInference is performed using the general `.run`, `.run-once`, `.run-md`, and `.run-file` commands (see the [Performing Inference](#performing-inference) section above).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Facrion%2Fzelph","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Facrion%2Fzelph","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Facrion%2Fzelph/lists"}