Skip to content

Commit f5a9176

Browse files
authored
Merge pull request #151 from linkml/type-designator-docs
Docs for type designators
2 parents 97ba6cc + 7bf0306 commit f5a9176

File tree

4 files changed

+116
-33
lines changed

4 files changed

+116
-33
lines changed

linkml_model/model/docs/specification/02instances.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -321,11 +321,11 @@ To interpret a path *p*:
321321
1. **VariableName** is resolved to an instance *i*
322322
2. For each path component in the path, reset *i* to be the value of looking up that component:
323323
- if the path extension is `.<s>` then *r* must be an **InstanceOfClass*, and the value is equal to the value of the slot assignment for slot `s`
324-
- if the path extension is `[<id>]` then *r* must be an **InstanceOfCollection**, and the value is equals to the member of that list that has a slot with the role of *identifier* whose value is `<id>`
324+
- if the path extension is `[<key>]` then *r* must be an **InstanceOfCollection**, and the value is equals to the member of that list that has a slot with the role of *identifier* whose value is `<key>`
325325

326326
For example, if *i* is equal to the Person instance in the Combined Example above:
327327

328328
* `i` == `i`
329329
* `i.id` == `String^"SSN:123"`
330330
* `i.height.unit` == `String^"cm"`
331-
331+
* `i.relationships[0].related_to` == `Person&"SSN:456"`

linkml_model/model/docs/specification/04derived-schemas.md

Lines changed: 64 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ We use *m* to denote the input or asserted schema (model), and *m<sup>D</sup>* t
2424
We provide a non-normative example of a schema in canonical YAML. This will be referred to
2525
in the remainder of the document.
2626

27-
The schema is organized in a local folder as follows
27+
The schema is organized in a local folder as follows:
2828

2929
person.yaml:
3030
```yaml
@@ -96,7 +96,7 @@ This section defines functions that can be used in schema derivation rules.
9696

9797
### Normalize as List Function
9898

99-
The function **L**(*v*) normalizes `v`to a list:
99+
The function **L**(*v*) normalizes `v` to a list/collection:
100100

101101
| *v* | **L**(*v*) |
102102
|-------------------------------------|-----------------|
@@ -108,8 +108,8 @@ i.e.
108108

109109
```
110110
L(v) =
111-
v if v == [...]
112111
[] if v == None
112+
v if v == [...]
113113
[v] otherwise
114114
```
115115

@@ -121,9 +121,36 @@ In the metamodel, the identifier **SlotDefinitionName** is always `name`, so thi
121121

122122
> **K**(*v*) = *v*.**name**
123123
124+
### URI and CURIE functions
125+
126+
- a CURIE is a string that conforms to the [W3 CURIE specification](https://www.w3.org/TR/curie/)
127+
- a URI is a string that conforms to [rfc3987](https://www.ietf.org/rfc/rfc3987.txt)
128+
- The function **URI**(*s*, *v*) takes a string as input and normalizes it to a URI
129+
- if the input is already a URI, then return it
130+
- if the input is a CURIE, then expand it using the prefix map in *s*; this is known as *expansion*
131+
- The function **CURIE**(*s*, *v*) takes a string as input and normalizes it to a CURIE
132+
- if the input is already a CURIE, then return it
133+
- if the input is a URI, then shorten it using the prefix map in *s*; this is known as *contraction*
134+
135+
When a CURIE is expanded, it is first decomposed according to the grammar defined in [W3 CURIE specification](https://www.w3.org/TR/curie/):
136+
137+
> curie := [ [ prefix ] ':' ] reference
138+
>
139+
> prefix := [NCName](http://www.w3.org/TR/1999/REC-xml-names-19990114/#NT-NCName)
140+
>
141+
> reference := irelative-ref (as defined in [IRI](https://www.w3.org/TR/curie/#ref_IRI))
142+
143+
The following concatenation is applied
144+
145+
> **URI**(`<prefix>`: `<reference>`) = `m.prefixes`[`prefix`]`.prefix_reference` + `<reference>`
146+
147+
For the reverse operation, any URI that starts with a prefix reference can be used to generate a valid CURIE.
148+
The one with the shortest reference is chosen as the canonical.
149+
124150
### Resolve Functions
125151

126152
The function **Resolve** takes as input a **InstanceOfReference** and returns an **InstanceOfClass**
153+
that is the referenced object.
127154

128155
| *i* | **Resolve**(*i*) |
129156
|------------------------|------------------|
@@ -192,24 +219,23 @@ The imports closure function **I** returns the reflexive **ReferenceClosure** of
192219

193220
> **I**(*s*) = **C***(*s*, **s.imports**)
194221
195-
### Function: Element CURIEs
222+
### Function: Element CURIEs and URIs
196223

197-
The lookup table to retrieve the CURIE for an element is:
224+
For each element in the schema, we can derive a model URI and an element URI. These *may* be identical.
198225

199-
| Type | Main Rule | Default |
200-
|-------------------|---------------|------------------------------------------|
201-
| `ClassDefinition` | `e.class_uri` | `<m.default_prefix>:<SafeCamel(e.name)>` |
202-
| `SlotDefinition` | `e.slot_uri` | `<m.default_prefix>:<SafeSnake(e.name)>` |
203-
| `TypeDefinition` | `e.uri` | `<m.default_prefix>:<SafeCamel(e.name)>` |
204-
| `EnumDefinition` | `e.enum_uri` | `<m.default_prefix>:<SafeCamel(e.name)>` |
205-
| `PermissibleValue` | `e.meaning` | `CURIE(Enum) + "." + Safe(e.text)` |
226+
The following table is used:
206227

207-
### Function: Expand CURIEs
228+
| Type | Element URI | Model URI |
229+
|---------------------|---------------|------------------------------------------|
230+
| `ClassDefinition` | `e.class_uri` | `<m.default_prefix>:<SafeCamel(e.name)>` |
231+
| `SlotDefinition` | `e.slot_uri` | `<m.default_prefix>:<SafeSnake(e.name)>` |
232+
| `TypeDefinition` | `e.uri` | `<m.default_prefix>:<SafeCamel(e.name)>` |
233+
| `EnumDefinition` | `e.enum_uri` | `<m.default_prefix>:<SafeCamel(e.name)>` |
234+
| `PermissibleValue` | `e.meaning` | `ModelURI(Enum) + "." + Safe(e.text)` |
208235

209-
To expand a CURIE to a URL, the string is split on `:`. There must be two tokens.
210-
The first token is used to lookup `m.prefixes`, and the URL is constructed from:
236+
If the element URI slot is not set, then the model URI is used as the element URI.
211237

212-
> `uri(PREFIX: LOCAL) = m.prefixes[PREFIX].prefix_reference + LOCAL`
238+
URIs can be contracted to CURIEs using the `prefixes` map in the model, see next function.
213239

214240
### Function: Applicable Slots
215241

@@ -395,7 +421,28 @@ for c in m.classes:
395421

396422
### Rule: Derived Class and Slot URIs
397423

398-
For each class or slot, if a class_uri or slot_uri is not specified, then this is derived by concatenating `m.default_prefix` with the CURIE separator `:` followed by the SafeUpperCamelCase encoding of the name of that class or slot definition
424+
For each class or slot, if a class_uri or slot_uri is not specified, then this is derived using the rules specified
425+
for Element URIs above.
426+
427+
For example, given:
428+
429+
```yaml
430+
prefixes:
431+
foo: http://example.org/foo/
432+
bar: http://example.org/bar/
433+
default_prefix: foo
434+
classes:
435+
A:
436+
class_uri: bar:A
437+
...
438+
B:
439+
...
440+
```
441+
442+
the following values would be set:
443+
444+
* `A.class_uri` = `http://example.org/bar/A`
445+
* `B.class_uri` = `http://example.org/foo/B`
399446

400447
### Rule: Derived Permissible Values
401448

linkml_model/model/docs/specification/05validation.md

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@ The following holds for any validation procedure:
4848
| `NodeKind` | ERROR | range metatype | `NodeKindConstraintComponent` |
4949
| `MinimumValue` | ERROR | | `MinInclusiveConstraintComponent` |
5050
| `MaximumValue` | ERROR | | `MaxInclusiveConstraintComponent` |
51-
| `Pattern` | ERROR | | `PatternConstraintComponent` |
52-
| `EqualsExpression` | INFERENCE | | `EqualsConstraintComponent` |
53-
| `StringSerialization` | INFERENCE | | `EqualsConstraintComponent` |
54-
| `TypeDesignator` | INFERENCE | | |
51+
| `Pattern` | ERROR | | `PatternConstraintComponent` |
52+
| `EqualsExpression` | INFERENCE | | `EqualsConstraintComponent` |
53+
| `StringSerialization` | INFERENCE | | `EqualsConstraintComponent` |
54+
| `TypeDesignator` | INFERENCE | | |
5555

5656
For the `INFERENCE` type, the validation procedure MAY fill in missing values in the instance.
5757
There is only an error if the inferred value is not consistent with the asserted value.
@@ -133,13 +133,51 @@ The following checks only match when `i` is an **AtomicInstance**
133133

134134
The following checks only match when `i` is an **InstanceOfClass**
135135

136-
| **T** | Element | Check | Fail Condition |
137-
|--------|------------------------------------|-------------------|-----------------------------------------------------|
138-
| `in` | `<Class>(<Assignments>)` | `Abstract` | `Class.abstract` |
139-
| `in` | `<Class>(<Assignments>)` | `Mixin` | `Class.mixin` |
140-
| `in` | `<Class>(<Assignments>)` | `ClassRange` | `slot.range ∉ A*(<Class>)` |
141-
| `in` | `<Class>(..., <subslot>=<V>, ...)` | `ApplicableSlot` | `subslot ∉ <Class>.attributes` |
142-
| `in` | `<Class>(..., <ts>=<V>, ...)` | `DesignatedType` | `<V> ∉ A*(<Class>)` `ts = TypeDesignator(<Class>)` |
136+
| **T** | Element | Check | Fail Condition |
137+
|--------|------------------------------------|-------------------|---------------------------------------------------------------------------------|
138+
| `in` | `<Class>(<Assignments>)` | `Abstract` | `Class.abstract` |
139+
| `in` | `<Class>(<Assignments>)` | `Mixin` | `Class.mixin` |
140+
| `in` | `<Class>(<Assignments>)` | `ClassRange` | `slot.range ∉ A*(<Class>)` |
141+
| `in` | `<Class>(..., <subslot>=<V>, ...)` | `ApplicableSlot` | `subslot ∉ <Class>.attributes` |
142+
| `in` | `<Class>(..., <ts>=<V>, ...)` | `DesignatedType` | `∃ v ∈ L(<V>): v ∉ Norm(A*(<Class>), ts.range)` and `ts.designates_type = True` |
143+
144+
For the DesignatedType check, the `Norm` function takes as input as a list of classes,
145+
and expands these according to the range of the slot `ts` that designates the type.
146+
147+
148+
| Range | Match |
149+
|--------------|------------------------------------------------------|
150+
| `string` | { `c.name` } |
151+
| `curie` | { **CURIE**(`c.class_uri`) } |
152+
| `uri` | { **URI**(`c.class_uri`) } |
153+
| `uriorcurie` | { **CURIE**(`c.class_uri`), **URI**(`c.class_uri`) } |
154+
155+
For example, given an instance
156+
157+
> `Organization(name="acme", type=String^"Business")`
158+
159+
And a schema that includes:
160+
161+
```python
162+
ClassDefinition(
163+
name="Business",
164+
is_a=ClassDefinition&Organization,
165+
)
166+
ClassDefinition(
167+
name="Organization",
168+
attributes=[
169+
SlotDefinition(name="type", range=TypeDefinition&string),
170+
...
171+
```
172+
173+
This will pass the `DesignatedType` check, because:
174+
175+
* `A*(ClassDefinition&Business) = { ..., ClassDefinition&Organization, ... }`
176+
* `Norm(A*(ClassDefinition&Business), TypeDefinition&string) = { ..., String^"Business", ... }`
177+
* `String^"Business" ∉ { ..., String^"Business", ... }`
178+
179+
DesignatedType checks can also executed in inference mode, where an inference engine
180+
may choose to assign the most specific value allowed to the slot.
143181

144182
### Enum checks
145183

@@ -187,8 +225,6 @@ For each rule `r` in *C*.rules:
187225

188226
### Classification Rule evaluation
189227

190-
### type designator checks
191-
192228
## Validation of TypeDefinitions
193229

194230
For each slot `s` in **Assignments**, if `i.<s>` is not `None`, and `s.range` is in `m*.types`,

linkml_model/model/schema/meta.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ description: |-
77
For more information on LinkML:
88
99
* [linkml.io](https://linkml.io) main website
10-
* [specification](https://linkml.io/linkml-model/docs/specification/)
10+
* [specification](https://w3id.org/linkml/docs/specification/)
1111
1212
LinkML is self-describing. Every LinkML schema consists of elements
1313
that instantiate classes in this metamodel.

0 commit comments

Comments
 (0)