Academic Meta Tool

How to build an AMT file

An AMT file is an ordinary Turtle file with three kinds of statements: concepts, nodes and weighted edges. The most common mistake is to forget that both ends of an edge have to be nodes.

1. The parts

PartWhat it isHow you write it
Concepta kind of thing (Person, Coin, Authority)ex:Coin a amt:Concept ; rdfs:label "Coin" .
Nodeone thing of that kindex:c1 amt:instanceOf ex:Coin ; rdfs:label "coin 1" .
Edgea relation between two nodes that holds to a degreea statement with rdf:subject, rdf:predicate, rdf:object, amt:weight
Typewhat kind of fuzziness the weight expresses (optional; default vagueness)fw:hasType fw:Uncertainty
Methodhow the weight was obtained (optional)fw:hasMethod fw:EqualShareRule
Rolenames an edge type and says what it may connect (optional until an axiom needs it)ex:knows a amt:Role ; rdfs:domain ex:Person ; rdfs:range ex:Person .
Axioma rule that derives new edges (optional)see the data model

2. A complete file to start from

Copy this, replace the names, keep the structure. It passes every check.

Start with the prefixes. ex: stands for your own data; use your own namespace.

@prefix amt:  <http://academic-meta-tool.xyz/vocab#> .
@prefix rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd:  <http://www.w3.org/2001/XMLSchema#> .
@prefix fw:   <http://w3id.org/fw_ontology/> .
@prefix ex:   <http://example.org/> .
# 1. Concepts: the kinds of things your file talks about
ex:Person a amt:Concept ;
    rdfs:label "Person" .

# 2. Nodes: every end of an edge, each one an instance of a concept
ex:ada     amt:instanceOf ex:Person ; rdfs:label "Ada Lovelace" .
ex:charles amt:instanceOf ex:Person ; rdfs:label "Charles Babbage" .
ex:mary    amt:instanceOf ex:Person ; rdfs:label "Mary Somerville" .

# 3. Edges: subject, role, object and a weight between 0 and 1
[] rdf:subject   ex:ada ;
   rdf:predicate ex:knows ;
   rdf:object    ex:charles ;
   amt:weight    "0.8"^^xsd:decimal .

[] rdf:subject   ex:charles ;
   rdf:predicate ex:knows ;
   rdf:object    ex:mary ;
   amt:weight    "0.6"^^xsd:decimal .

3. Seven rules

  1. Every concept is declared with a amt:Concept and has an rdfs:label.
  2. Every end of every edge is a node: it has amt:instanceOf. This includes the thing an edge points to (the emperor, the place, the other person). A label alone does not make it a node.
  3. Never write amt:instanceOf amt:Concept. amt:Concept is the class of concepts. Point at a concept of your own.
  4. An edge is a statement with four required properties, all together: subject, predicate, object and weight. The subject and object must be IRIs, not literals. Type and method are optional (section 5).
  5. Weights are decimals from 0 to 1 (0.8 or "0.8"^^xsd:decimal). 1 means certain, 0 means not at all.
  6. Give nodes labels. Without one, the end of the IRI is shown, which is unreadable for IRIs like .../coin?afeid=15661.
  7. Extra triples are fine. AMT reads the parts above and ignores the rest. A link such as lado:hasAMT from a coin to its edge statement is harmless and can stay; the engine finds edges by their amt:weight, not by that link.

Rule 2 is the one behind the error AMT-E101. This is what it looks like when it is broken, and the repair:

Broken

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 node

Fixed

ex:Coins     a amt:Concept ; rdfs:label "Coins" .
ex:Authority a amt:Concept ; rdfs:label "Authority" .          # a second concept for the other end

ex:coin1     amt:instanceOf ex:Coins     ; rdfs:label "coin 1" .
ex:vespasian amt:instanceOf ex:Authority ; rdfs:label "vespasian" .     # now it is a node

[] rdf:subject ex:coin1 ; rdf:predicate ex:hasAuthority ; rdf:object ex:vespasian ; amt:weight 0.5 .

4. Roles and axioms (optional)

Edges work without declared roles. As soon as you write an axiom, the roles it names have to be declared with a label, a domain and a range:

ex:Person a amt:Concept ; rdfs:label "Person" .
ex:ada     amt:instanceOf ex:Person ; rdfs:label "Ada" .
ex:charles amt:instanceOf ex:Person ; rdfs:label "Charles" .

# A role is optional until an axiom needs it. Then it names its domain and range.
ex:knows a amt:Role ;
    rdfs:label  "knows" ;
    rdfs:domain ex:Person ;
    rdfs:range  ex:Person .

[] rdf:subject ex:ada ; rdf:predicate ex:knows ; rdf:object ex:charles ; amt:weight 0.8 .

# An axiom: whoever knows someone who knows someone, knows that person a little (product logic)
ex:RCA a amt:RoleChainAxiom ;
    amt:antecedents ( ex:knows ex:knows ) ;
    amt:consequent  ex:knows ;
    amt:logic       amt:ProductLogic .

All axiom types, with a figure and an example each, are on the data model page.

5. Type and method (optional)

An edge with subject, predicate, object and weight is a quadruple and is complete. Two more parts from the FW ontology make it a hextuple: fw:hasType (fw:Vagueness, fw:Uncertainty, fw:FuzzinessWobbliness, or fw:Certainty for a statement that is not fuzzy at all) and fw:hasMethod (how the weight was obtained). Add the prefix fw: and write them on the edge:

ex:Person a amt:Concept ; rdfs:label "Person" .
ex:ada     amt:instanceOf ex:Person ; rdfs:label "Ada Lovelace" .
ex:charles amt:instanceOf ex:Person ; rdfs:label "Charles Babbage" .

# The weight 0.5 is an uncertainty (one of two readings is right), obtained by an equal share.
[] rdf:subject   ex:ada ;
   rdf:predicate ex:knows ;
   rdf:object    ex:charles ;
   amt:weight    "0.5"^^xsd:decimal ;
   fw:hasType    fw:Uncertainty ;
   fw:hasMethod  fw:EqualShareRule .

Without fw:hasType an edge is a vagueness edge, also at weight 1. To say that a statement is certain, write fw:hasType fw:Certainty together with weight 1.0; a certain statement with a lower weight is reported as AMT-W206. A type without a method is allowed, but the engine points it out (AMT-N303); a type it does not know is reported as AMT-W205. The reasoner gives inferred edges a method and a type as well; the data model page says how.

6. From existing RDF with SPARQL CONSTRUCT

If your data is already RDF, you do not write the file by hand: a CONSTRUCT query produces it. The query has to produce three things, in this order of importance:

  1. the concepts, declared with labels (once, as constant triples),
  2. both ends of every edge as nodes with amt:instanceOf and a label,
  3. one weighted statement per edge.

The example turns the vague and certain emperor attributions of the AFE coins into AMT. Sample input:

@prefix afe: <http://afe.dainst.org/coin?afeid=> .
@prefix nfdi_fw: <http://w3id.org/fw_ontology/> .
@prefix nm: <http://nomisma.org/id/> .
@prefix nmo: <http://nomisma.org/ontology#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix skos: <http://www.w3.org/2004/02/skos/core#> .

# a coin that is either of two emperors (vague)
afe:15661 a nmo:NumismaticObject ;
    nmo:hasAuthority [ a nfdi_fw:VagueResourceValue, skos:Collection ;
        skos:member [ nfdi_fw:hasConfidence 0.5 ; rdf:value nm:vespasian ],
                    [ nfdi_fw:hasConfidence 0.5 ; rdf:value nm:titus ] ] .

# a coin with one certain emperor
afe:15668 a nmo:NumismaticObject ;
    nmo:hasAuthority nm:aurelian .

# a coin with one emperor, but only 60 % sure
afe:16048 a nmo:NumismaticObject ;
    nmo:hasAuthority [ a nfdi_fw:UncertainValue ;
        nfdi_fw:hasConfidence 0.6 ; rdf:value nm:philip_the_arab ] .

# a coin whose emperor is unknown: no edge, so it does not become a node
afe:11471 a nmo:NumismaticObject ;
    nmo:hasAuthority nm:uncertain_value .

and the query:

PREFIX amt:     <http://academic-meta-tool.xyz/vocab#>
PREFIX rdf:     <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs:    <http://www.w3.org/2000/01/rdf-schema#>
PREFIX xsd:     <http://www.w3.org/2001/XMLSchema#>
PREFIX skos:    <http://www.w3.org/2004/02/skos/core#>
PREFIX nmo:     <http://nomisma.org/ontology#>
PREFIX nm:      <http://nomisma.org/id/>
PREFIX afe:     <http://afe.dainst.org/coin?afeid=>
PREFIX nfdi_fw: <http://w3id.org/fw_ontology/>

CONSTRUCT {
  # 1. Declare the concepts once, with labels
  afe:Coins    a amt:Concept ; rdfs:label "AFE coins" .
  nm:Authority a amt:Concept ; rdfs:label "Authority" .

  # 2. Make BOTH ends of every edge a node (this is the line people forget)
  ?coin      amt:instanceOf afe:Coins ;    rdfs:label ?coinLabel .
  ?authority amt:instanceOf nm:Authority ; rdfs:label ?authorityLabel .

  # 3. One weighted statement per edge
  ?edge rdf:subject   ?coin ;
        rdf:predicate nmo:hasAuthority ;
        rdf:object    ?authority ;
        amt:weight    ?weight .
}
WHERE {
  {
    # vague or combined values: one edge per candidate, with its confidence
    ?coin a nmo:NumismaticObject ; nmo:hasAuthority ?container .
    ?container skos:member ?candidate .
    ?candidate rdf:value ?authority ; nfdi_fw:hasConfidence ?weight .
  }
  UNION
  {
    # one value with a confidence
    ?coin a nmo:NumismaticObject ; nmo:hasAuthority ?container .
    ?container a nfdi_fw:UncertainValue ; rdf:value ?authority ; nfdi_fw:hasConfidence ?weight .
  }
  UNION
  {
    # a certain authority: weight 1. Only real IRIs; the containers above are blank nodes
    ?coin a nmo:NumismaticObject ; nmo:hasAuthority ?authority .
    FILTER(isIRI(?authority) && ?authority != nm:uncertain_value)
    BIND("1.0"^^xsd:decimal AS ?weight)
  }
  BIND(BNODE() AS ?edge)
  BIND(STRAFTER(STR(?coin), "?") AS ?coinLabel)
  BIND(STRAFTER(STR(?authority), "http://nomisma.org/id/") AS ?authorityLabel)
}

Things to adapt: the two concept IRIs, the properties in WHERE, and how labels are made (here STRAFTER takes the part of the IRI after a marker). BNODE() makes a fresh node for each edge statement.

A CONSTRUCT that leaves out the second part (the authority nodes) is the typical cause of AMT-E101: the coins are nodes, the emperors are not. Run the check on a small sample first, then on the whole file.

6. Then check it

Save the result as my.ttl and continue with how to check an AMT file, then run it and look at the result.