How to check an AMT file
Three checks, from "is it well formed" to "does it say what I meant". Run them while you build the file, not after. Every message names the IRI it is about and says what to add.
- 1. What is checked
- 2. Run the check
- 3. Read the output
- 4. The messages, one by one
- 5. Exit codes
- 6. Questions that come up
1. What is checked
| Check | Question | Message looks like |
|---|---|---|
| Validation (SHACL) | Is the file well formed? Labels, weights, axioms complete? | FAIL Validation failed … [1] ex:Thing … |
| Diagnostics | Does it mean what you think? Are all edge ends nodes? | ERR [AMT-E101] … |
| Consistency | After reasoning, do the integrity axioms hold (disjoint roles, no reflexive roles)? | FAIL 2 consistency violation(s) |
The first two need no axioms and are what you want while building. The third only matters once you use axioms.
2. Run the check
With the wrapper (needs Python and git; it fetches the engine itself):
git clone https://github.com/alpaca-fair-framework/amt-runner
cd amt-runner
python run_amt.py my.ttl --check-only
If you get "does not know --check-only" or a Python traceback, the engine copy cached in .amt-cache/ is old:
python run_amt.py my.ttl --check-only --update
With the engine installed (pip install -e . in amt-engine):
amt-runner my.ttl --check-only
amt-runner my.ttl --check-only --strict
amt my.ttl --validate-only
--check-onlyvalidates, loads and diagnoses, and writes nothing.--strictturns diagnostic errors into exit code 1, useful in scripts and CI.amt --validate-onlyruns only the SHACL validation.- A full run (
python run_amt.py my.ttl) additionally reasons and writes Turtle, Cypher, CSV, an HTML graph and a report; step by step, from cloning to the graph. --debugshows the Python traceback if something unexpected fails.
In Python:
from amt import load_amt, diagnose
amt = load_amt("my.ttl")
for finding in diagnose(amt):
print(finding.format())
3. Read the output
A file whose emperors are not nodes (the case that prompted this page):
VAL Validating my.ttl ...
OK Validation passed.
LOAD Loading my.ttl ...
OK 1 Concepts | 0 Roles | 4 Nodes | 7 Edges | 0 Axioms <- 4 nodes, but 7 edges that end somewhere else
DIAG 1 error(s), 0 warning(s), 1 note(s):
ERR [AMT-E101] 7 IRI(s) are the subject or object of a weighted statement but are not AMT nodes: <http://nomisma.org/id/aurelian>, ...
-> Every end of an edge needs an amt:instanceOf … Add, for each, e.g.:
<http://nomisma.org/id/aurelian> amt:instanceOf <…> ; rdfs:label "..." .
Compare the counts in the OK line with what you expect: if there are far fewer Nodes than the things your edges
connect, some are not declared. A missing node is never silent any more, but a count that is too low is still the quickest hint.
Earlier versions of the engine stopped later with AssertionError: non existent node ... when drawing the graph.
That was this same problem; it is now reported up front, and the graph shows such IRIs as grey placeholder nodes.
4. The messages, one by one
Diagnostics
AMT-E101 error
N IRI(s) are the subject or object of a weighted statement but are not AMT nodes
Cause. An edge points at (or starts from) an IRI that has no amt:instanceOf. The reasoner cannot place it, so the edge cannot be followed or drawn. Giving the IRI an rdfs:label is not enough.
Fix. Add amt:instanceOf and a concept to every IRI named in the message. If these IRIs are a different kind of thing than the others (coins and emperors, say), declare a second concept for them.
Example
ex:Coins a amt:Concept ; rdfs:label "Coins" .
ex:coin1 amt:instanceOf ex:Coins ; rdfs:label "coin 1" .
[] rdf:subject ex:coin1 ; rdf:predicate ex:hasAuthority ; rdf:object ex:vespasian ; amt:weight 0.5 .
ex:vespasian rdfs:label "vespasian" . # a label does not make it a nodeAMT-E102 error
<...> is declared as amt:instanceOf amt:Concept / is the target of amt:instanceOf but is not declared as an amt:Concept
Cause. amt:instanceOf must point at a concept of your own, and that concept must be declared with a amt:Concept. Pointing at amt:Concept itself, or at an IRI that is never declared, means those nodes are not loaded.
Fix. Declare the concept once with a label and point to it.
Example
ex:coin1 amt:instanceOf ex:Coins . # ex:Coins is never declared as a conceptAMT-E103 error
A statement with amt:weight lacks rdf:subject / rdf:predicate / rdf:object
Cause. A weighted edge needs its four required properties together (subject, predicate, object, weight). A statement with a missing part is ignored.
Fix. Add the missing property.
Example
ex:C a amt:Concept ; rdfs:label "C" .
ex:a amt:instanceOf ex:C .
[] rdf:subject ex:a ; rdf:predicate ex:r ; amt:weight 0.5 . # no rdf:objectAMT-E104 error
The statement ... has amt:weight X and fw:hasDegreeOfConnection Y
Cause. The FW ontology calls the weight fw:hasDegreeOfConnection; AMT calls it amt:weight. The engine reads both and writes amt:weight. If a statement carries both with different values, amt:weight is used and this message tells you which statement it was.
Fix. Keep one of the two properties, or give both the same value.
AMT-W201 warning
Weight X is outside [0, 1]
Cause. Weights are degrees of truth between 0 and 1. SHACL rejects the file first, but with --no-validate the engine would clamp values above 1.
Fix. Use a value between 0 and 1.
Example
ex:C a amt:Concept ; rdfs:label "C" .
ex:a amt:instanceOf ex:C . ex:b amt:instanceOf ex:C .
[] rdf:subject ex:a ; rdf:predicate ex:r ; rdf:object ex:b ; amt:weight 1.5 .AMT-W205 warning
... is used as fw:hasType but is not one of the known types
Cause. A statement can say what kind of fuzziness its weight expresses: fw:Vagueness, fw:Uncertainty, fw:FuzzinessWobbliness, or fw:Certainty for a statement that is not fuzzy at all. Any other value is kept and counted as a type of its own, which is probably a typo or a term from another vocabulary.
Fix. Use one of the four, or leave fw:hasType out: a statement without a type is a vagueness statement.
AMT-W206 warning
N statement(s) have fw:hasType fw:Certainty but a weight below 1
Cause. A certain statement holds fully, so its weight is 1.0. A weight below 1 on a certain statement contradicts itself; the engine keeps the weight as it is and still counts the statement as certain, so an edge derived from it can be certain with a weight below 1.
Fix. Give the statement weight 1.0, or change its type to fw:Vagueness, fw:Uncertainty or fw:FuzzinessWobbliness.
AMT-W204 warning
The file contains no weighted statement
Cause. There is nothing to reason about. Typical reasons: the edges are written without amt:weight, or they are only linked from the nodes (for example with lado:hasAMT) and the reified statement itself is missing.
Fix. Write each edge as a statement with rdf:subject, rdf:predicate, rdf:object and amt:weight.
AMT-N303 note
N statement(s) have fw:hasType but no fw:hasMethod
Cause. The type says what kind of fuzziness the weight is, the method says how it was obtained. The type is used without a method, so nothing breaks; the method is what makes the statement reproducible.
Fix. Add fw:hasMethod, for example fw:EqualShareRule for a weight that comes from sharing equally.
AMT-N301 note
Role ... is used in edges but not declared as an amt:Role
Cause. Fine for simple files. Only axioms need declared roles.
Fix. Declare the role (label, domain, range) if you want to use it in an axiom.
AMT-N302 note
N node(s) have no rdfs:label
Cause. The end of the IRI is shown instead, which is hard to read in the graph.
Fix. Add an rdfs:label to the nodes.
Validation (SHACL)
These come from ontology/amt-shapes.ttl.
The line above each message is the IRI it is about, followed by a hint on what to add.
Each Concept must have at least one rdfs:label.
A concept has no label. The message names the IRI. Beware: every object of amt:instanceOf counts as a concept, so this message also appears when you write amt:instanceOf amt:Concept or point at an undeclared class.
ex:Coins a amt:Concept . # no rdfs:label
ex:coin1 amt:instanceOf ex:Coins .Each Role must have at least one rdfs:label. / exactly one rdfs:domain / exactly one rdfs:range.
A role declared with a amt:Role needs a label, one domain and one range.
amt:weight must be a single xsd:decimal in the closed interval [0, 1].
A weight is missing, doubled, not a number, or outside 0 to 1.
ex:C a amt:Concept ; rdfs:label "C" .
ex:a amt:instanceOf ex:C . ex:b amt:instanceOf ex:C .
[] rdf:subject ex:a ; rdf:predicate ex:r ; rdf:object ex:b ; amt:weight 1.5 .RoleChainAxiom must have exactly one amt:consequent / amt:logic ...
An axiom lacks a part, or uses the legacy and the list form of antecedents at once. The messages for the other axiom types (inverse, subsumption, disjoint) work the same way.
RoleChainAxiom using amt:HamacherProduct must specify amt:logicParameter.
The Hamacher operator needs its parameter: amt:logicParameter 0.5.
This is how a validation failure reads (two mistakes in one file):
FAIL Validation failed with 2 violation(s):
[1] amt:Concept
Each Concept must have at least one rdfs:label. (property: rdfs:label)
-> Add amt:Concept rdfs:label "..." . If this IRI is not meant to be a concept, check where it is used as the object of amt:instanceOf: …
[2] ex:Thing
Each Concept must have at least one rdfs:label. (property: rdfs:label)
-> Add ex:Thing rdfs:label "..." . …
5. Exit codes
| Code | Meaning |
|---|---|
0 | Done. Diagnostics may still have printed errors unless you used --strict; consistency violations of your axioms also leave this at 0. |
1 | The file did not pass validation, or --strict found a diagnostic error. |
2 | The input file was not found. |
3 | Something unexpected failed. Run with --debug and report it with the file, please. |