Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/experiments/a/ @ektrah
29 changes: 29 additions & 0 deletions .github/workflows/experiment-a.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Validate Experiment A

on:
push:
pull_request:

jobs:
validate:
runs-on: ubuntu-latest

env:
SHIFTY_VERSION: "0.4.4"

steps:
- uses: actions/checkout@v5

- uses: actions/cache@v6
id: shifty-cache
with:
path: ~/.cargo/bin
key: shifty-${{ runner.os }}-${{ env.SHIFTY_VERSION }}

- name: Install shifty-cli
if: steps.shifty-cache.outputs.cache-hit != 'true'
run: cargo install shifty-cli --version "$SHIFTY_VERSION"

- name: Validate
working-directory: experiments/a/
run: shifty validate --shapes shapes.ttl --data ontology.ttl.md
20 changes: 14 additions & 6 deletions experiments/a/ontology.ttl.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,15 +175,23 @@

#. This can be used in conjunction with deprecations: mark a class as deprecated, define a replacement class, and make the two classes subclasses of each other, i.e., equivalent. Instances of the old class automatically become instances of the new class, and vice versa.

#. This is also useful without deprecations and can be used to define multiple alternative IRIs for the same class or property. However, then it is no longer obvious which is the recommended "main class" in the group of equivalent classes.
#. This is also useful without deprecations and can be used to define multiple alternative IRIs for the same class or property. However, then it is no longer obvious which is the canonical "main class" in the group of equivalent classes.

#. We use `bro:aliasOf` as a directed form of `owl:equivalentClass`: If `:x bro:aliasOf :y` then `:x owl:equivalentClass :y .`, `:x rdfs:subClassOf :y .`, `:y rdfs:subClassOf :x .`, and `:y` is the recommended "main class" in the group.
#. We use `bro:aliasClassOf` as a directed form of `owl:equivalentClass`: If `:x bro:aliasClassOf :y` then `:x owl:equivalentClass :y .` `:x rdfs:subClassOf :y .` `:y rdfs:subClassOf :x .`, and `:y` is the canonical class.

bro:aliasClassOf
a owl:ObjectProperty ;
rdfs:subPropertyOf owl:equivalentClass ;
rdfs:label "alias of"@en ;
rdfs:comment "Relates an alias class to its canonical class."@en ;
rdfs:domain rdfs:Class ;
rdfs:range rdfs:Class .

#. The change of aliasing statements is a non-breaking change as long as the new main class is already in the group. The addition of aliasing statements is a non-breaking change as long as the added group member is added to the ontology in the same version. Any other addition, change, or removal of aliasing statements is a breaking change.

#. When a node is an alias, any other statements about that node are removed from the ontology. This is considered a non-breaking change. As a consequence, users must be prepared to always follow aliasing statements to the main class first (e.g., `?x bro:aliasOf?/rdfs:label ?y` instead of `?x rdfs:label ?y`).
#. When a node is an alias, any other statements about that node are removed from the ontology. This is considered a non-breaking change. As a consequence, users must be prepared to always follow aliasing statements to the main class first (e.g., `?x bro:aliasClassOf?/rdfs:label ?y` instead of `?x rdfs:label ?y`).

#. In principle, aliasing statements could be defined as reflexive and transitive (e.g., if `:x bro:aliasOf :y` and `:y bro:aliasOf :z`, then it can be inferred that `:x bro:aliasOf :z`). However, to simplify things, if `?x bro:aliasOf ?y`, then there shall not be any `?y bro:aliasOf ?z`.
#. In principle, aliasing statements could be defined as reflexive and transitive (e.g., if `:x bro:aliasClassOf :y` and `:y bro:aliasClassOf :z`, then it can be inferred that `:x bro:aliasClassOf :z`). However, to simplify things, if `?x bro:aliasClassOf ?y`, then there shall not be any `?y bro:aliasClassOf ?z`.

## 7. Modeling Conventions

Expand Down Expand Up @@ -250,7 +258,7 @@

#. — Dynamic quantity with a last known value: `:x a brick:Motor ; brick:hasPoint [ a brick:Temperature_Sensor ; brick:lastKnownValue [ brick:timestamp "2026-09-17T12:00:00Z"^^xsd:dateTime ; brick:value 50 ] ] .`

#. — Dynamic quantity with an external reference: `:x a brick:Motor ; brick:hasPoint [ a brick:Temperature_Sensor ; rdf:hasExternalReference [ ..... ] ] .`
#. — Dynamic quantity with an external reference: `:x a brick:Motor ; brick:hasPoint [ a brick:Temperature_Sensor ; ref:hasExternalReference [ ..... ] ] .`

#### RealEstateCore

Expand All @@ -262,7 +270,7 @@

#### 223

#. — Static quantity with a unit: `:x a s223:Motor ; s223:hasProperty [ a s223:QuantifiableObservableProperty ; qudt:hasQuantityKind qk:Temperature ; qudt:hasUnit unit:DEG_C ; qudt:quantityValue [ qudt:value 50 ] ] .`
#. — Static quantity with a unit: `:x a s223:Motor ; s223:hasProperty [ a s223:QuantifiableProperty ; s223:hasAspect s223:Aspect-Rated ; qudt:hasQuantityKind qk:Voltage ; qudt:hasUnit unit:V ; qudt:quantityValue [ qudt:value 240 ] ] .`

#. — Dynamic quantity with an external reference: `:x a s223:Motor ; s223:hasProperty [ a s223:QuantifiableObservableProperty ; qudt:hasQuantityKind qk:Temperature ; qudt:hasUnit unit:DEG_C ; s223:hasExternalReference [ ..... ] ] .`

Expand Down
48 changes: 48 additions & 0 deletions experiments/a/shapes.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix bro: <https://ontology.brickschema.org/2.0/#bro:> .

bro:AliasClassOfShape
a sh:NodeShape ;
sh:targetSubjectsOf bro:aliasClassOf ;

# x aliasClassOf y => x must be a class
sh:class rdfs:Class ;

# x aliasClassOf y => y must be a class
sh:property [
sh:path bro:aliasClassOf ;
sh:class rdfs:Class ;
sh:maxCount 1 ;
sh:message "bro:aliasClassOf must point to a class." ;
] ;

# x aliasClassOf y => x subClassOf y
sh:rule [
a sh:TripleRule ;
sh:subject sh:this ;
sh:predicate rdfs:subClassOf ;
sh:object [
sh:path bro:aliasClassOf
]
] ;

# x aliasClassOf y => y subClassOf x
sh:rule [
a sh:TripleRule ;
sh:subject [
sh:path bro:aliasClassOf
] ;
sh:predicate rdfs:subClassOf ;
sh:object sh:this
] ;

# x aliasClassOf y => y must not be an alias
sh:property [
sh:path (
bro:aliasClassOf
bro:aliasClassOf
) ;
sh:maxCount 0 ;
sh:message "The canonical class of an aliasClassOf relation must not itself be an alias." ;
] .
Loading