eyeling 1.14.4 → 1.14.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/HANDBOOK.md CHANGED
@@ -1549,12 +1549,6 @@ Returns a copy of `s` with the character at index `i` (0-based) replaced by:
1549
1549
 
1550
1550
  If `i` is out of range, `out` is the original string.
1551
1551
 
1552
- #### `string:hammingDistance`
1553
-
1554
- **Shape:** `( a b ) string:hammingDistance d`
1555
-
1556
- Returns the number of differing positions between `a` and `b`. Fails if the two strings have different lengths.
1557
-
1558
1552
  ### Containment and prefix/suffix tests
1559
1553
 
1560
1554
  - `string:contains`
@@ -0,0 +1,219 @@
1
+ # Mapping two data models (beginner-friendly)
2
+
3
+ When people say “map two data models,” they mean:
4
+
5
+ > **Taking data described using one vocabulary (Model A) and expressing the same meaning using another vocabulary (Model B).**
6
+
7
+ In the Semantic Web / Linked Data world, a “data model” is often a **set of RDF terms** (classes + properties) defined by an ontology or vocabulary—like **schema.org** or **FOAF**.
8
+
9
+ ---
10
+
11
+ ## Why would you map vocabularies?
12
+
13
+ Even if two vocabularies describe similar things, they may use **different names** and **different structures**.
14
+
15
+ - **schema.org** is common for publishing data on the web (SEO, structured data).
16
+ - **FOAF (Friend of a Friend)** is common for describing people, names, online accounts, and social relationships.
17
+
18
+ Mapping lets you:
19
+
20
+ - reuse tools built for another vocabulary,
21
+ - integrate datasets that use different terms,
22
+ - keep your original data but still answer queries in the target vocabulary.
23
+
24
+ ---
25
+
26
+ ## The core idea: “same meaning, different words”
27
+
28
+ Example concept:
29
+
30
+ - In **schema.org**, a person is `schema:Person`
31
+ - In **FOAF**, a person is `foaf:Person`
32
+
33
+ Those two classes can represent the same real-world thing (a person), just in different vocabularies.
34
+
35
+ Similarly for properties:
36
+
37
+ - `schema:name` ≈ `foaf:name`
38
+ - `schema:givenName` ≈ `foaf:givenName`
39
+ - `schema:familyName` ≈ `foaf:familyName`
40
+
41
+ A mapping is just a **set of rules** that says:
42
+
43
+ > “If you see X in schema.org, you can also produce Y in FOAF.”
44
+
45
+ ---
46
+
47
+ ## What is N3 (Notation3) and what are N3 rules?
48
+
49
+ **N3** is a compact RDF syntax that also supports **rules**.
50
+
51
+ A rule looks like:
52
+
53
+ - **Left side (condition):** patterns you look for in your data
54
+ - **Right side (conclusion):** triples you can _generate_ when the condition matches
55
+
56
+ General shape:
57
+
58
+ ```n3
59
+ { # IF you find these triples...
60
+ ...patterns...
61
+ }
62
+ =>
63
+ { # THEN you may add these triples...
64
+ ...new triples...
65
+ }.
66
+ ```
67
+
68
+ This is sometimes called **forward-chaining**: you start with data you have, and rules _derive_ additional data.
69
+
70
+ ---
71
+
72
+ ## Example data in schema.org (RDF/Turtle)
73
+
74
+ Imagine your dataset contains:
75
+
76
+ ```turtle
77
+ @prefix schema: <https://schema.org/> .
78
+ @prefix ex: <https://example.org/> .
79
+
80
+ ex:alice a schema:Person ;
81
+ schema:name "Alice Example" ;
82
+ schema:givenName "Alice" ;
83
+ schema:familyName "Example" .
84
+ ```
85
+
86
+ This says:
87
+
88
+ - `ex:alice` is a `schema:Person`
89
+ - her full name is `"Alice Example"`
90
+ - her given and family names are included too
91
+
92
+ ---
93
+
94
+ ## Mapping to FOAF using N3 rules
95
+
96
+ Now we write rules that _derive_ FOAF triples.
97
+
98
+ ```n3
99
+ @prefix schema: <https://schema.org/> .
100
+ @prefix foaf: <http://xmlns.com/foaf/0.1/> .
101
+
102
+ # Rule 1: schema:Person -> foaf:Person
103
+ {
104
+ ?p a schema:Person .
105
+ }
106
+ =>
107
+ {
108
+ ?p a foaf:Person .
109
+ }.
110
+
111
+ # Rule 2: schema:name -> foaf:name
112
+ {
113
+ ?p schema:name ?name .
114
+ }
115
+ =>
116
+ {
117
+ ?p foaf:name ?name .
118
+ }.
119
+
120
+ # Rule 3: schema:givenName -> foaf:givenName
121
+ {
122
+ ?p schema:givenName ?gn .
123
+ }
124
+ =>
125
+ {
126
+ ?p foaf:givenName ?gn .
127
+ }.
128
+
129
+ # Rule 4: schema:familyName -> foaf:familyName
130
+ {
131
+ ?p schema:familyName ?fn .
132
+ }
133
+ =>
134
+ {
135
+ ?p foaf:familyName ?fn .
136
+ }.
137
+ ```
138
+
139
+ Read Rule 2 in plain English:
140
+
141
+ > If a person `?p` has a `schema:name` value `?name`, then we can also say `?p` has a `foaf:name` value `?name`.
142
+
143
+ ---
144
+
145
+ ## What output do you get?
146
+
147
+ After applying the rules, you still have your original schema.org data, **plus** extra FOAF triples like:
148
+
149
+ ```turtle
150
+ @prefix foaf: <http://xmlns.com/foaf/0.1/> .
151
+ @prefix ex: <https://example.org/> .
152
+
153
+ ex:alice a foaf:Person ;
154
+ foaf:name "Alice Example" ;
155
+ foaf:givenName "Alice" ;
156
+ foaf:familyName "Example" .
157
+ ```
158
+
159
+ So now FOAF-based tools or queries can work, even though your “source of truth” is schema.org.
160
+
161
+ ---
162
+
163
+ ## Important beginner notes
164
+
165
+ ### 1) Mapping usually _adds_ data (it doesn’t delete or replace)
166
+
167
+ Most rule-based mappings are “non-destructive”:
168
+
169
+ - Keep the original triples
170
+ - Derive additional triples in the target vocabulary
171
+
172
+ ### 2) 1-to-1 mappings are the easy case
173
+
174
+ `schema:name -> foaf:name` is straightforward.
175
+
176
+ But sometimes:
177
+
178
+ - one term in schema.org maps to **multiple** terms in FOAF, or
179
+ - the target expects a different structure (blank nodes, split names, etc.)
180
+
181
+ ### 3) “Same meaning” is a judgment call
182
+
183
+ Two properties might be _similar_ but not truly identical in all contexts. Mapping works best when you understand the intended meaning of each term.
184
+
185
+ ---
186
+
187
+ ## A simple mental checklist for mapping
188
+
189
+ 1. **List the things** you have (classes + properties in schema.org)
190
+ 2. **Decide what you want** to support (FOAF terms you need)
191
+ 3. For each target term, ask:
192
+ - “Where can I get this information from in the source?”
193
+
194
+ 4. Write rules:
195
+ - **conditions** match the source triples
196
+ - **conclusions** emit the target triples
197
+
198
+ 5. Run a reasoner/rule engine and test with a few example resources
199
+
200
+ ---
201
+
202
+ ## Next step ideas (optional)
203
+
204
+ - Map online profiles:
205
+ - `schema:sameAs` could help populate `foaf:page` or related links (careful: semantics differ).
206
+
207
+ - Add type rules beyond `Person`
208
+ - Write rules that create structured nodes (more advanced)
209
+
210
+ ---
211
+
212
+ ## Summary
213
+
214
+ Mapping two models is about **translating meaning across vocabularies**.
215
+
216
+ - You start with data described in **schema.org**
217
+ - You write **N3 rules** that recognize schema.org patterns
218
+ - You **derive FOAF triples**
219
+ - The result is data that can be consumed as if it were FOAF, without rewriting your original dataset
@@ -0,0 +1,260 @@
1
+ # ================================================================================
2
+ # Genetic Algorithm demo: 0/1 Knapsack via mutation + selection
3
+ #
4
+ # Goal
5
+ # ----
6
+ # Evolve a bitstring genome that selects a subset of items to maximize total VALUE
7
+ # while staying within a WEIGHT capacity.
8
+ #
9
+ # Representation
10
+ # --------------
11
+ # - Items: list of pairs (weight value)
12
+ # - Genome: a string of '0'/'1' of the same length as the item list
13
+ # - bit i = '1' => item i is included
14
+ # - bit i = '0' => item i is excluded
15
+ #
16
+ # Fitness (lower is better)
17
+ # -------------------------
18
+ # We want: feasible solutions (weight <= capacity) with high value.
19
+ #
20
+ # If weight <= capacity:
21
+ # fitness = 1_000_000 - value (so higher value => lower fitness)
22
+ # If overweight:
23
+ # fitness = 2_000_000 + (weight - capacity)
24
+ # (overweight candidates are always worse than any feasible candidate)
25
+ #
26
+ # Variation (mutation)
27
+ # --------------------
28
+ # Single-bit flip: generate all "neighbors" of the current genome by flipping
29
+ # exactly one position. This is deterministic (no randomness), but it still
30
+ # demonstrates the core GA pattern of mutation + selection.
31
+ #
32
+ # Selection
33
+ # ---------
34
+ # Compare parent + all mutants, keep the candidate with the lowest fitness.
35
+ # This is essentially a (1 + λ) evolutionary strategy / hill-climber.
36
+ #
37
+ # Stopping criteria
38
+ # -----------------
39
+ # Stop when either:
40
+ # - maxGenerations is reached, or
41
+ # - no mutant improves fitness (local optimum under 1-bit flips)
42
+ # ================================================================================
43
+
44
+ @prefix : <urn:ga:>.
45
+ @prefix log: <http://www.w3.org/2000/10/swap/log#>.
46
+ @prefix math: <http://www.w3.org/2000/10/swap/math#>.
47
+ @prefix list: <http://www.w3.org/2000/10/swap/list#>.
48
+ @prefix string: <http://www.w3.org/2000/10/swap/string#>.
49
+
50
+ :cfg
51
+ :capacity 50;
52
+ :maxGenerations 64;
53
+
54
+ # Each item is (weight value). Genome bits select items by index.
55
+ :items (
56
+ (12 24)
57
+ (7 13)
58
+ (11 23)
59
+ (8 15)
60
+ (9 16)
61
+ (6 12)
62
+ (10 21)
63
+ (4 9)
64
+ (5 11)
65
+ (14 28)
66
+ (3 7)
67
+ (13 26)
68
+ ).
69
+
70
+ # -------------
71
+ # small helpers
72
+ # -------------
73
+
74
+ { ( ?N 1 ) :inc ?N1 } <= { ( ?N 1 ) math:sum ?N1 }.
75
+
76
+ # build a string of N zeros
77
+ { ( 0 ) :zeros "" } <= true.
78
+
79
+ { ( ?N ) :zeros ?S } <= {
80
+ ?N math:greaterThan 0 .
81
+ ( ?N 1 ) math:difference ?N1 .
82
+ ( ?N1 ) :zeros ?Rest .
83
+ ( "%s%s" "0" ?Rest ) string:format ?S
84
+ }.
85
+
86
+ # flip a bit at index i in a 0/1 string
87
+ { ( ?S ?I ) :flipBit ?Out } <= {
88
+ ( ?S ?I ) string:charAt "0" .
89
+ ( ?S ?I "1" ) string:setCharAt ?Out
90
+ }.
91
+
92
+ { ( ?S ?I ) :flipBit ?Out } <= {
93
+ ( ?S ?I ) string:charAt "1" .
94
+ ( ?S ?I "0" ) string:setCharAt ?Out
95
+ }.
96
+
97
+ # generate all single-bit mutants of S
98
+ { ( ?S ?Len ) :mutants ?Out } <= {
99
+ ( ?S 0 ?Len ) :mutantsFrom ?Out
100
+ }.
101
+
102
+ { ( ?S ?I ?Len ) :mutantsFrom () } <= {
103
+ ?I math:equalTo ?Len
104
+ }.
105
+
106
+ { ( ?S ?I ?Len ) :mutantsFrom ?Out } <= {
107
+ ?I math:lessThan ?Len .
108
+ ( ?S ?I ) :flipBit ?Cand .
109
+ ( ?I 1 ) :inc ?I1 .
110
+ ( ?S ?I1 ?Len ) :mutantsFrom ?Rest .
111
+ ( ( ?Cand ) ?Rest ) list:append ?Out
112
+ }.
113
+
114
+ # -----------------------------------------
115
+ # decode genome -> (totalWeight totalValue)
116
+ # -----------------------------------------
117
+
118
+ { ( ?Bits ?Items ) :totals ( ?Wsum ?Vsum ) } <= {
119
+ ?Bits string:length ?Len .
120
+ ( ?Bits ?Items 0 ?Len 0 0 ) :totalsAcc ( ?Wsum ?Vsum )
121
+ }.
122
+
123
+ { ( ?Bits ?Items ?I ?Len ?AccW ?AccV ) :totalsAcc ( ?AccW ?AccV ) } <= {
124
+ ?I math:equalTo ?Len
125
+ }.
126
+
127
+ { ( ?Bits ?Items ?I ?Len ?AccW ?AccV ) :totalsAcc ( ?Wsum ?Vsum ) } <= {
128
+ ?I math:lessThan ?Len .
129
+ ( ?Bits ?I ) string:charAt "1" .
130
+
131
+ ( ?Items ?I ) list:memberAt ?Pair .
132
+ ( ?Pair 0 ) list:memberAt ?W .
133
+ ( ?Pair 1 ) list:memberAt ?V .
134
+
135
+ ( ?AccW ?W ) math:sum ?AccW1 .
136
+ ( ?AccV ?V ) math:sum ?AccV1 .
137
+
138
+ ( ?I 1 ) :inc ?I1 .
139
+ ( ?Bits ?Items ?I1 ?Len ?AccW1 ?AccV1 ) :totalsAcc ( ?Wsum ?Vsum )
140
+ }.
141
+
142
+ { ( ?Bits ?Items ?I ?Len ?AccW ?AccV ) :totalsAcc ( ?Wsum ?Vsum ) } <= {
143
+ ?I math:lessThan ?Len .
144
+ ( ?Bits ?I ) string:charAt "0" .
145
+
146
+ ( ?I 1 ) :inc ?I1 .
147
+ ( ?Bits ?Items ?I1 ?Len ?AccW ?AccV ) :totalsAcc ( ?Wsum ?Vsum )
148
+ }.
149
+
150
+ # -------------------------
151
+ # fitness (lower is better)
152
+ # -------------------------
153
+
154
+ { ( ?W ?V ?Cap ) :fitness ?F } <= {
155
+ ?W math:notGreaterThan ?Cap .
156
+ ( 1000000 ?V ) math:difference ?F
157
+ }.
158
+
159
+ { ( ?W ?V ?Cap ) :fitness ?F } <= {
160
+ ?W math:greaterThan ?Cap .
161
+ ( ?W ?Cap ) math:difference ?Over .
162
+ ( 2000000 ?Over ) math:sum ?F
163
+ }.
164
+
165
+ { ( ?W ?Cap ) :feasible "true" } <= { ?W math:notGreaterThan ?Cap }.
166
+ { ( ?W ?Cap ) :feasible "false" } <= { ?W math:greaterThan ?Cap }.
167
+
168
+ { ( ?Bits ?Cap ?Items ) :candidateScore ( ?Fit ?Wsum ?Vsum ) } <= {
169
+ ( ?Bits ?Items ) :totals ( ?Wsum ?Vsum ) .
170
+ ( ?Wsum ?Vsum ?Cap ) :fitness ?Fit
171
+ }.
172
+
173
+ # pick best of two candidates by fitness (ties keep the left candidate)
174
+ { ( ?C1 ?S1 ?W1 ?V1 ?C2 ?S2 ?W2 ?V2 ) :pickBest ( ?C1 ?S1 ?W1 ?V1 ) } <= {
175
+ ?S1 math:notGreaterThan ?S2
176
+ }.
177
+
178
+ { ( ?C1 ?S1 ?W1 ?V1 ?C2 ?S2 ?W2 ?V2 ) :pickBest ( ?C2 ?S2 ?W2 ?V2 ) } <= {
179
+ ?S1 math:greaterThan ?S2
180
+ }.
181
+
182
+ # best candidate from a list
183
+ { ( ?Cap ?Items ?L ) :bestMutant ( ?Best ?BestScore ?BestW ?BestV ) } <= {
184
+ ?L list:length 1 .
185
+ ?L list:first ?Best .
186
+ ( ?Best ?Cap ?Items ) :candidateScore ( ?BestScore ?BestW ?BestV )
187
+ }.
188
+
189
+ { ( ?Cap ?Items ?L ) :bestMutant ( ?Best ?BestScore ?BestW ?BestV ) } <= {
190
+ ?L list:length ?N .
191
+ ?N math:greaterThan 1 .
192
+
193
+ ?L list:first ?H .
194
+ ?L list:rest ?T .
195
+
196
+ ( ?Cap ?Items ?T ) :bestMutant ( ?B2 ?S2 ?W2 ?V2 ) .
197
+ ( ?H ?Cap ?Items ) :candidateScore ( ?S1 ?W1 ?V1 ) .
198
+
199
+ ( ?H ?S1 ?W1 ?V1 ?B2 ?S2 ?W2 ?V2 ) :pickBest ( ?Best ?BestScore ?BestW ?BestV )
200
+ }.
201
+
202
+ # --------------
203
+ # evolution loop
204
+ # --------------
205
+
206
+ # generation cap
207
+ { ( ?Bits ?Cap ?Items ?Gen ?MaxGen ) :evolve ( ?Bits ?Gen ) } <= {
208
+ ?Gen math:equalTo ?MaxGen
209
+ }.
210
+
211
+ # stop if best doesn't improve
212
+ { ( ?Bits ?Cap ?Items ?Gen ?MaxGen ) :evolve ( ?Bits ?Gen ) } <= {
213
+ ?Gen math:lessThan ?MaxGen .
214
+ ( ?Bits ?Cap ?Items ) :candidateScore ( ?Score ?W ?V ) .
215
+
216
+ ?Bits string:length ?Len .
217
+ ( ?Bits ?Len ) :mutants ?Ms .
218
+ ( ( ?Bits ) ?Ms ) list:append ?Candidates .
219
+
220
+ ( ?Cap ?Items ?Candidates ) :bestMutant ( ?Best ?BestScore ?BW ?BV ) .
221
+ ?BestScore math:equalTo ?Score
222
+ }.
223
+
224
+ # keep evolving while improvement exists
225
+ { ( ?Bits ?Cap ?Items ?Gen ?MaxGen ) :evolve ( ?Final ?FinalGen ) } <= {
226
+ ?Gen math:lessThan ?MaxGen .
227
+ ( ?Bits ?Cap ?Items ) :candidateScore ( ?Score ?W ?V ) .
228
+
229
+ ?Bits string:length ?Len .
230
+ ( ?Bits ?Len ) :mutants ?Ms .
231
+ ( ( ?Bits ) ?Ms ) list:append ?Candidates .
232
+
233
+ ( ?Cap ?Items ?Candidates ) :bestMutant ( ?Best ?BestScore ?BW ?BV ) .
234
+ ?BestScore math:notEqualTo ?Score .
235
+
236
+ ( ?Gen 1 ) :inc ?Gen1 .
237
+ ( ?Best ?Cap ?Items ?Gen1 ?MaxGen ) :evolve ( ?Final ?FinalGen )
238
+ }.
239
+
240
+ # --------------
241
+ # query / output
242
+ # --------------
243
+
244
+ {
245
+ :cfg :capacity ?Cap;
246
+ :maxGenerations ?Max;
247
+ :items ?Items.
248
+
249
+ ?Items list:length ?Len .
250
+ ( ?Len ) :zeros ?Start .
251
+
252
+ ( ?Start ?Cap ?Items 0 ?Max ) :evolve ( ?Best ?Gen ) .
253
+ ( ?Best ?Cap ?Items ) :candidateScore ( ?Fit ?W ?V ) .
254
+ ( ?W ?Cap ) :feasible ?Ok .
255
+
256
+ ( "Knapsack GA best genome %s (feasible=%s): weight=%s value=%s after %s generations.\n"
257
+ ?Best ?Ok ?W ?V ?Gen ) string:format ?Line
258
+ }
259
+ log:query
260
+ { 1 log:outputString ?Line }.
@@ -0,0 +1,153 @@
1
+ # ====================================================================
2
+ # N3 LINKS POLICY, PROVENANCE, AND INFERENCE
3
+ #
4
+ # Another “speaks for itself” case:
5
+ # Delegation-based trust + distributed authorization.
6
+ #
7
+ # What it shows (in one syntax):
8
+ # - Quoted claims from multiple web documents
9
+ # - A tiny trust policy that can *delegate* trust to other documents
10
+ # - Importing only trusted statements into the fact set
11
+ # - Reasoning across imported facts to derive permissions
12
+ # - Provenance output using singleton graph terms (formulas),
13
+ # and *not stored* as derived facts.
14
+ #
15
+ # Run:
16
+ # eyeling examples/n3-delegation-access.n3
17
+ #
18
+ # Output:
19
+ # - :report :trusts <doc>
20
+ # - :report :entails { <user> :canRead <resource>. }
21
+ # - { ... } :assertedBy <doc> (singleton graph provenance)
22
+ # ====================================================================
23
+
24
+ @prefix : <https://example.org/n3-delegation#>.
25
+ @prefix id: <https://example.org/id/>.
26
+ @prefix foaf: <http://xmlns.com/foaf/0.1/>.
27
+ @prefix log: <http://www.w3.org/2000/10/swap/log#>.
28
+
29
+ # ----------
30
+ # Trust root
31
+ # ----------
32
+
33
+ :policy :trusts <https://root.example/policy.n3>.
34
+
35
+ # ------------------------------
36
+ # The Web "says" (quoted graphs)
37
+ # ------------------------------
38
+
39
+ # Root policy delegates trust outward.
40
+ <https://root.example/policy.n3> :says {
41
+ :policy :delegatesTo <https://hr.example/policy.n3>.
42
+ :policy :delegatesTo <https://team.example/members.n3>.
43
+ }.
44
+
45
+ # HR publishes what groups may read what.
46
+ <https://hr.example/policy.n3> :says {
47
+ :eng :mayRead :buildReport.
48
+ :eng :mayRead :roadmap.
49
+ }.
50
+
51
+ # Team publishes membership, and delegates further.
52
+ <https://team.example/members.n3> :says {
53
+ id:alice foaf:name "Alice".
54
+ id:alice :memberOf :eng.
55
+
56
+ :policy :delegatesTo <https://interns.example/members.n3>.
57
+ }.
58
+
59
+ # Intern list becomes trusted only because Team delegated to it.
60
+ <https://interns.example/members.n3> :says {
61
+ id:eve foaf:name "Eve".
62
+ id:eve :memberOf :eng.
63
+ }.
64
+
65
+ # Untrusted rumor: present as quoted data, but will not be imported.
66
+ <http://shady.example/rumor.n3> :says {
67
+ id:mallory foaf:name "Mallory".
68
+ id:mallory :memberOf :eng.
69
+ :eng :mayRead :secrets.
70
+ }.
71
+
72
+ # --------------------------------
73
+ # Trust can be delegated (forward)
74
+ # --------------------------------
75
+
76
+ {
77
+ :policy :trusts ?Doc.
78
+ ?Doc :says ?F.
79
+ ?F log:includes { :policy :delegatesTo ?Other. }.
80
+ }
81
+ =>
82
+ {
83
+ :policy :trusts ?Other.
84
+ }.
85
+
86
+ # ----------------------------------
87
+ # Import only trusted quoted triples
88
+ # ----------------------------------
89
+ {
90
+ :policy :trusts ?Doc.
91
+ ?Doc :says ?F.
92
+ ?F log:includes { ?S ?P ?O. }.
93
+ }
94
+ =>
95
+ {
96
+ ?S ?P ?O.
97
+ }.
98
+
99
+ # ------------------------------------------------
100
+ # Local meaning: membership + policy => permission
101
+ # ------------------------------------------------
102
+ {
103
+ ?U :memberOf ?G.
104
+ ?G :mayRead ?R.
105
+ }
106
+ =>
107
+ {
108
+ ?U :canRead ?R.
109
+ }.
110
+
111
+ # ------
112
+ # REPORT
113
+ # ------
114
+
115
+ # Which documents ended up trusted (root + delegated)
116
+ {
117
+ :policy :trusts ?Doc.
118
+ }
119
+ log:query
120
+ {
121
+ :report :trusts ?Doc.
122
+ }.
123
+
124
+ # What the system entails
125
+ {
126
+ ?U :canRead ?R.
127
+ }
128
+ log:query
129
+ {
130
+ :report :entails { ?U :canRead ?R. }.
131
+ }.
132
+
133
+ # Why (provenance), using singleton graph terms:
134
+ # show the two supporting asserted statements and where they came from.
135
+ {
136
+ ?U :canRead ?R.
137
+
138
+ ?U :memberOf ?G.
139
+ ?G :mayRead ?R.
140
+
141
+ :policy :trusts ?DocM.
142
+ ?DocM :says ?FM.
143
+ ?FM log:includes { ?U :memberOf ?G. }.
144
+
145
+ :policy :trusts ?DocP.
146
+ ?DocP :says ?FP.
147
+ ?FP log:includes { ?G :mayRead ?R. }.
148
+ }
149
+ log:query
150
+ {
151
+ { ?U :memberOf ?G. } :assertedBy ?DocM.
152
+ { ?G :mayRead ?R. } :assertedBy ?DocP.
153
+ }.