Metadata-Version: 2.4
Name: conceptual-taxonomy
Version: 0.1.0
Summary: Discover class abstractions (rdfs:subClassOf) in a conceptual schema bundle, independently of the source paradigm.
Author: Arthur Keen
License: Apache-2.0
Project-URL: Homepage, https://github.com/ArthurKeen/conceptual-taxonomy
Project-URL: Repository, https://github.com/ArthurKeen/conceptual-taxonomy
Project-URL: Issues, https://github.com/ArthurKeen/conceptual-taxonomy/issues
Keywords: ontology,taxonomy,owl,rdfs,subclassof,schema,conceptual-model,formal-concept-analysis,arangodb,relational
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Database
Classifier: Topic :: Scientific/Engineering :: Information Analysis
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: ruff>=0.5; extra == "dev"
Requires-Dist: mypy>=1.10; extra == "dev"
Requires-Dist: build>=1.2; extra == "dev"
Requires-Dist: twine>=5.0; extra == "dev"
Dynamic: license-file

# conceptual-taxonomy

Find class abstractions — `rdfs:subClassOf` hierarchies — in a conceptual schema, whatever
kind of database it came from.

```bash
pip install conceptual-taxonomy
```

```python
from conceptual_taxonomy import discover_abstractions

result = discover_abstractions(bundle)          # a {conceptualSchema, physicalMapping} bundle
result.abstract_classes                          # proposed classes, with evidence
result.subclass_edges                            # proposed subClassOf edges
merged = result.merge_into(bundle)               # additive; never rewrites what is already there
```

Pure function. No database access, no connectors, no credentials, no I/O. Same input, same
output, every time.

## The problem it solves

A database stores `Account → {Checking, Savings, Mortgage, Insurance}` in any of several ways:
one table with a type column; a parent table plus subtype tables joined on a shared key; four
independent tables with the common columns copied into each; and the ArangoDB equivalents of
all three. Same concepts, completely different physical shapes.

**All of them must produce the same conceptual answer.** That is the whole requirement, and it
is what the [fixture set](fixtures/) tests: one bank-account taxonomy in eight encodings, one
expected result.

Designed as a companion to
[`arango-schema-analyzer`](https://pypi.org/project/arangodb-schema-analyzer/) and
[`relational-schema-analyzer`](https://pypi.org/project/relational-schema-analyzer/), which
already emit the same `{conceptualSchema, physicalMapping, metadata}` bundle shape. Neither
discovers abstractions today, and the logic is identical for both — so it lives here rather
than being written twice.

## Why one implementation and not two

An abstraction must separate properties present on **every** subclass from those present on
only some:

```python
top.shared_properties    # [{"name": "balance", ...}]  → SUM(balance) across all accounts is sound
top.partial_properties   # [{"name": "monthlyPayment", "presentOn": ["MortgageAccount"],
                         #   "coverage": 0.25}]        → SUM(monthlyPayment) reads 1 of 4 subclasses
```

Aggregating over the second kind silently under-reports, with no error. Two implementations
would drift on that boundary, and the drift shows up as one of them answering confidently and
wrong. That is a correctness argument for sharing, not a tidiness one.

## How it finds them

Four mechanisms; the first three are deterministic and need no LLM.

| | Mechanism | Finds |
|---|---|---|
| 4.1 | Discriminator values | one container + a type column |
| 4.2 | Formal concept analysis | sibling tables with a shared property core and no parent |
| 4.3 | Shared-key subsumption | a child keyed on its parent's key, and the ER specialization pattern |
| 4.4 | Naming hook (optional LLM) | a domain name where morphology gives none |

Concept analysis yields a genuine lattice, so multi-level taxonomies come out multi-level:
`Account → FinancialAccount → Checking` alongside `Account → InsuranceAccount`.

Mechanism 4.4 may only **rename or subdivide** what the deterministic mechanisms produced — it
can never introduce a class none of them proposed.

## Output is proposals, not facts

Every class and edge carries `mechanism`, `confidence`, and `evidence`, and `merge_into` is
additive and reversible. Consumers are expected to arbitrate: schema-derived taxonomy will
compete with taxonomy extracted from documents and from cross-ontology alignment, and
resolving those conflicts — cycle detection, disjointness checking, human curation — belongs
downstream, not here.

Correspondingly, this library does no consistency checking of its own.

## Disjointness and completeness, measured rather than assumed

Where the caller supplies key-overlap counts, the ER specialization constraints are derived:
`disjoint` when no parent key appears in two subtypes, `complete` when every parent key appears
in one. Unmeasured yields `None` — never `False`. Absence of evidence is not evidence of
absence, and blanket disjointness assertions are how schema-to-OWL pipelines produce
unsatisfiable ontologies.

## Not in scope

- **Database access** — input is a bundle, output is a bundle fragment
- **Foreign-key inference** — paradigm-specific; lives in the two analyzers
- **Query generation** — consumers compile abstractions into AQL / SQL / SPARQL themselves

## Documentation

- [`docs/SPEC.md`](docs/SPEC.md) — the contract, mechanism by mechanism
- [`fixtures/README.md`](fixtures/README.md) — the worked example, and the bugs it caught
- [`docs/CROSS-REPO-PLAN.md`](docs/CROSS-REPO-PLAN.md) — how this fits the surrounding work

## Status

Pre-1.0 and moving. The API is one function and will change as real analyzers feed it —
**pin a version**.

## License

Apache-2.0, matching the surrounding Arango ecosystem libraries.
