eyeleng 1.0.8 → 1.0.10

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.
@@ -0,0 +1,289 @@
1
+ # GPS — generic route-planning over a road graph.
2
+ #
3
+ # Adapted from eyeling/examples/gps.n3:
4
+ # https://raw.githubusercontent.com/eyereasoner/eyeling/refs/heads/main/examples/gps.n3
5
+ #
6
+ # The facts below provide a tiny western-Belgium road map and one route query.
7
+ # The rules are generic: they build simple paths from any gps:Drive graph,
8
+ # compute accumulated duration/cost/belief/comfort metrics, mark dominated
9
+ # completed paths, and recommend each non-dominated completed path.
10
+
11
+ PREFIX log: <http://www.w3.org/2000/10/swap/log#>
12
+ PREFIX gps: <http://example.org/gps#>
13
+ PREFIX : <http://example.org/gps-demo/>
14
+ PREFIX path: <http://example.org/gps-demo/path/>
15
+
16
+ DATA {
17
+ :Gent gps:label "Gent" .
18
+ :Brugge gps:label "Brugge" .
19
+ :Kortrijk gps:label "Kortrijk" .
20
+ :Oostende gps:label "Oostende" .
21
+
22
+ :i1 gps:location :Gent .
23
+
24
+ :question a gps:RouteQuery ;
25
+ gps:traveller :i1 ;
26
+ gps:to :Oostende ;
27
+ gps:maxLegs 4 ;
28
+ gps:text "Which route should we take from Gent to Oostende?" .
29
+
30
+ :drive_gent_brugge a gps:Drive ;
31
+ gps:from :Gent ; gps:to :Brugge ;
32
+ gps:actionLabel "drive_gent_brugge" ;
33
+ gps:duration 1500.0 ; gps:cost 0.006 ; gps:belief 0.96 ; gps:comfort 0.99 .
34
+
35
+ :drive_gent_kortrijk a gps:Drive ;
36
+ gps:from :Gent ; gps:to :Kortrijk ;
37
+ gps:actionLabel "drive_gent_kortrijk" ;
38
+ gps:duration 1600.0 ; gps:cost 0.007 ; gps:belief 0.96 ; gps:comfort 0.99 .
39
+
40
+ :drive_kortrijk_brugge a gps:Drive ;
41
+ gps:from :Kortrijk ; gps:to :Brugge ;
42
+ gps:actionLabel "drive_kortrijk_brugge" ;
43
+ gps:duration 1600.0 ; gps:cost 0.007 ; gps:belief 0.96 ; gps:comfort 0.99 .
44
+
45
+ :drive_brugge_oostende a gps:Drive ;
46
+ gps:from :Brugge ; gps:to :Oostende ;
47
+ gps:actionLabel "drive_brugge_oostende" ;
48
+ gps:duration 900.0 ; gps:cost 0.004 ; gps:belief 0.98 ; gps:comfort 1.0 .
49
+ }
50
+
51
+ # Resolve the traveller's current location and human-readable endpoint labels.
52
+ RULE {
53
+ ?query gps:from ?source ;
54
+ gps:fromLabel ?sourceLabel ;
55
+ gps:toLabel ?destinationLabel .
56
+ }
57
+ WHERE {
58
+ ?query a gps:RouteQuery ;
59
+ gps:traveller ?traveller ;
60
+ gps:to ?destination .
61
+ ?traveller gps:location ?source .
62
+ ?source gps:label ?sourceLabel .
63
+ ?destination gps:label ?destinationLabel .
64
+ }
65
+
66
+ # Seed one-leg candidate paths from the query source.
67
+ RULE {
68
+ ?path a gps:CandidatePath ;
69
+ gps:query ?query ;
70
+ gps:last ?next ;
71
+ gps:legs 1 ;
72
+ gps:pathKey ?pathKey ;
73
+ gps:routeLabel ?routeLabel ;
74
+ gps:actions ?actions ;
75
+ gps:pathIRI ?path ;
76
+ gps:duration ?duration ;
77
+ gps:cost ?cost ;
78
+ gps:belief ?belief ;
79
+ gps:comfort ?comfort .
80
+ }
81
+ WHERE {
82
+ ?query a gps:RouteQuery ;
83
+ gps:from ?source .
84
+ ?drive a gps:Drive ;
85
+ gps:from ?source ;
86
+ gps:to ?next ;
87
+ gps:actionLabel ?action ;
88
+ gps:duration ?duration ;
89
+ gps:cost ?cost ;
90
+ gps:belief ?belief ;
91
+ gps:comfort ?comfort .
92
+ FILTER(!sameTerm(?source, ?next))
93
+ ?source gps:label ?sourceLabel .
94
+ ?next gps:label ?nextLabel .
95
+ SET(?pathKey := CONCAT("|", STR(?source), "|", STR(?next), "|"))
96
+ SET(?routeLabel := CONCAT(?sourceLabel, " → ", ?nextLabel))
97
+ SET(?actions := ?action)
98
+ SET(?pathSlug1 := REPLACE(?routeLabel, " → ", "_", "g"))
99
+ SET(?pathSlug := REPLACE(?pathSlug1, "[^A-Za-z0-9_-]", "_", "g"))
100
+ SET(?path := IRI(CONCAT("http://example.org/gps-demo/path/", ?pathSlug)))
101
+ }
102
+
103
+ # Extend candidate paths through the graph while staying within the query's
104
+ # leg bound and avoiding revisiting already-seen locations.
105
+ RULE {
106
+ ?nextPath a gps:CandidatePath ;
107
+ gps:query ?query ;
108
+ gps:last ?next ;
109
+ gps:legs ?nextLegs ;
110
+ gps:pathKey ?nextPathKey ;
111
+ gps:routeLabel ?nextRouteLabel ;
112
+ gps:actions ?nextActions ;
113
+ gps:pathIRI ?nextPath ;
114
+ gps:duration ?nextDuration ;
115
+ gps:cost ?nextCost ;
116
+ gps:belief ?nextBelief ;
117
+ gps:comfort ?nextComfort .
118
+ }
119
+ WHERE {
120
+ ?path a gps:CandidatePath ;
121
+ gps:query ?query ;
122
+ gps:last ?current ;
123
+ gps:legs ?legs ;
124
+ gps:pathKey ?pathKey ;
125
+ gps:routeLabel ?routeLabel ;
126
+ gps:actions ?actions ;
127
+ gps:pathIRI ?path ;
128
+ gps:duration ?duration ;
129
+ gps:cost ?cost ;
130
+ gps:belief ?belief ;
131
+ gps:comfort ?comfort .
132
+ ?query gps:to ?destination ;
133
+ gps:maxLegs ?maxLegs .
134
+ FILTER(!sameTerm(?current, ?destination))
135
+ FILTER(?legs < ?maxLegs)
136
+ ?drive a gps:Drive ;
137
+ gps:from ?current ;
138
+ gps:to ?next ;
139
+ gps:actionLabel ?action ;
140
+ gps:duration ?legDuration ;
141
+ gps:cost ?legCost ;
142
+ gps:belief ?legBelief ;
143
+ gps:comfort ?legComfort .
144
+ FILTER(!sameTerm(?current, ?next))
145
+ SET(?needle := CONCAT("|", STR(?next), "|"))
146
+ FILTER(!CONTAINS(?pathKey, ?needle))
147
+ ?next gps:label ?nextLabel .
148
+ SET(?nextLegs := ?legs + 1)
149
+ SET(?nextPathKey := CONCAT(?pathKey, STR(?next), "|"))
150
+ SET(?nextRouteLabel := CONCAT(?routeLabel, " → ", ?nextLabel))
151
+ SET(?nextActions := CONCAT(?actions, ", ", ?action))
152
+ SET(?nextDuration := ?duration + ?legDuration)
153
+ SET(?nextCost := ?cost + ?legCost)
154
+ SET(?nextBelief := ?belief * ?legBelief)
155
+ SET(?nextComfort := ?comfort * ?legComfort)
156
+ SET(?nextPathSlug1 := REPLACE(?nextRouteLabel, " → ", "_", "g"))
157
+ SET(?nextPathSlug := REPLACE(?nextPathSlug1, "[^A-Za-z0-9_-]", "_", "g"))
158
+ SET(?nextPath := IRI(CONCAT("http://example.org/gps-demo/path/", ?nextPathSlug)))
159
+ }
160
+
161
+ # A completed path is any candidate that reaches the query destination.
162
+ RULE {
163
+ ?path a gps:CompletedPath .
164
+ ?query gps:hasCandidatePath ?path .
165
+ }
166
+ WHERE {
167
+ ?query a gps:RouteQuery ;
168
+ gps:to ?destination .
169
+ ?path a gps:CandidatePath ;
170
+ gps:query ?query ;
171
+ gps:last ?destination .
172
+ }
173
+
174
+ # Generic dominance: another completed path for the same query is better when
175
+ # it is faster, cheaper, more reliable, and at least as comfortable.
176
+ RULE {
177
+ ?path gps:dominatedBy ?better .
178
+ }
179
+ WHERE {
180
+ ?path a gps:CompletedPath ;
181
+ gps:query ?query ;
182
+ gps:duration ?duration ;
183
+ gps:cost ?cost ;
184
+ gps:belief ?belief ;
185
+ gps:comfort ?comfort .
186
+ ?better a gps:CompletedPath ;
187
+ gps:query ?query ;
188
+ gps:duration ?betterDuration ;
189
+ gps:cost ?betterCost ;
190
+ gps:belief ?betterBelief ;
191
+ gps:comfort ?betterComfort .
192
+ FILTER(!sameTerm(?path, ?better))
193
+ FILTER(?betterDuration < ?duration)
194
+ FILTER(?betterCost < ?cost)
195
+ FILTER(?betterBelief > ?belief)
196
+ FILTER(?betterComfort >= ?comfort)
197
+ }
198
+
199
+ # Recommend every completed path that is not dominated by another completed
200
+ # path. In this data set there is one such path, but the rule itself is not
201
+ # tied to Gent, Brugge, Kortrijk, or Oostende.
202
+ RULE {
203
+ ?query gps:recommendedPath ?path .
204
+ ?path gps:recommended true .
205
+ }
206
+ WHERE {
207
+ ?path a gps:CompletedPath ;
208
+ gps:query ?query .
209
+ NOT { ?path gps:dominatedBy ?other }
210
+ }
211
+
212
+ # Present the recommendation as compact, readable facts first. The path-search
213
+ # bookkeeping remains in the inferred graph under path:* resources for users who
214
+ # want to inspect how the answer was found.
215
+ RULE {
216
+ :answer a gps:RouteRecommendation ;
217
+ gps:question ?questionText ;
218
+ gps:route ?bestLabel ;
219
+ gps:routeActions ?actions ;
220
+ gps:routeDuration ?duration ;
221
+ gps:routeCost ?displayCost ;
222
+ gps:routeBelief ?belief ;
223
+ gps:routeComfort ?comfort ;
224
+ gps:alternativeRoute ?alternativeLabel ;
225
+ gps:alternativeRouteActions ?alternativeActions ;
226
+ gps:alternativeRouteDuration ?alternativeDuration ;
227
+ gps:alternativeRouteCost ?alternativeDisplayCost ;
228
+ gps:alternativeRouteBelief ?alternativeBelief ;
229
+ gps:alternativeRouteComfort ?alternativeComfort ;
230
+ gps:reasonWhy ?reasonWhy ;
231
+ log:outputString ?block .
232
+ }
233
+ WHERE {
234
+ ?query a gps:RouteQuery ;
235
+ gps:text ?questionText ;
236
+ gps:fromLabel ?sourceLabel ;
237
+ gps:toLabel ?destinationLabel ;
238
+ gps:recommendedPath ?bestPath .
239
+ ?bestPath gps:routeLabel ?bestLabel ;
240
+ gps:actions ?actions ;
241
+ gps:duration ?duration ;
242
+ gps:cost ?cost ;
243
+ gps:belief ?belief ;
244
+ gps:comfort ?comfort .
245
+ ?alternative a gps:CompletedPath ;
246
+ gps:query ?query ;
247
+ gps:dominatedBy ?bestPath ;
248
+ gps:routeLabel ?alternativeLabel ;
249
+ gps:actions ?alternativeActions ;
250
+ gps:duration ?alternativeDuration ;
251
+ gps:cost ?alternativeCost ;
252
+ gps:belief ?alternativeBelief ;
253
+ gps:comfort ?alternativeComfort .
254
+ SET(?displayCost := ROUND(?cost * 1000) / 1000)
255
+ SET(?alternativeDisplayCost := ROUND(?alternativeCost * 1000) / 1000)
256
+ SET(?outcome := CONCAT("Take ", ?bestLabel, "."))
257
+ SET(?reasonWhy := CONCAT(
258
+ "From ", ?sourceLabel, " to ", ?destinationLabel,
259
+ ", the planner found two routes in this small map. The direct route (", ?bestLabel,
260
+ ") takes ", STR(?duration), " seconds at cost ", STR(?displayCost),
261
+ ", with belief ", STR(?belief), " and comfort ", STR(?comfort),
262
+ ". The alternative (", ?alternativeLabel, ") takes ", STR(?alternativeDuration),
263
+ " seconds at cost ", STR(?alternativeDisplayCost), ", with belief ", STR(?alternativeBelief),
264
+ " and comfort ", STR(?alternativeComfort),
265
+ ". So the direct route is faster, cheaper, more reliable, and slightly more comfortable."
266
+ ))
267
+ SET(?block := CONCAT(
268
+ "GPS — Generic route planning\n\n",
269
+ "## Question\n", ?questionText, "\n\n",
270
+ "## Answer\n", ?outcome, "\n\n",
271
+ "## Recommended Route\n", ?bestLabel, "\n",
272
+ "Actions: ", ?actions, "\n",
273
+ "Duration: ", STR(?duration), " seconds\n",
274
+ "Cost: ", STR(?displayCost), "\n",
275
+ "Belief: ", STR(?belief), "\n",
276
+ "Comfort: ", STR(?comfort), "\n\n",
277
+ "## Alternative Route\n", ?alternativeLabel, "\n",
278
+ "Actions: ", ?alternativeActions, "\n",
279
+ "Duration: ", STR(?alternativeDuration), " seconds\n",
280
+ "Cost: ", STR(?alternativeDisplayCost), "\n",
281
+ "Belief: ", STR(?alternativeBelief), "\n",
282
+ "Comfort: ", STR(?alternativeComfort), "\n\n",
283
+ "## Reason Why\n", ?reasonWhy, "\n\n",
284
+ "## Check\n",
285
+ "C1 OK - complete paths are discovered by chaining gps:Drive facts.\n",
286
+ "C2 OK - cycles are avoided with the generated path key.\n",
287
+ "C3 OK - dominated complete paths are rejected before recommendation.\n"
288
+ ))
289
+ }
@@ -0,0 +1,86 @@
1
+ :answer a gps:RouteRecommendation .
2
+ :answer gps:alternativeRoute "Gent → Kortrijk → Brugge → Oostende" .
3
+ :answer gps:alternativeRouteActions "drive_gent_kortrijk, drive_kortrijk_brugge, drive_brugge_oostende" .
4
+ :answer gps:alternativeRouteBelief 0.903168 .
5
+ :answer gps:alternativeRouteComfort 0.9801 .
6
+ :answer gps:alternativeRouteCost 0.018 .
7
+ :answer gps:alternativeRouteDuration 4100 .
8
+ :answer gps:question "Which route should we take from Gent to Oostende?" .
9
+ :answer gps:reasonWhy "From Gent to Oostende, the planner found two routes in this small map. The direct route (Gent → Brugge → Oostende) takes 2400 seconds at cost 0.01, with belief 0.9408 and comfort 0.99. The alternative (Gent → Kortrijk → Brugge → Oostende) takes 4100 seconds at cost 0.018, with belief 0.903168 and comfort 0.9801. So the direct route is faster, cheaper, more reliable, and slightly more comfortable." .
10
+ :answer gps:route "Gent → Brugge → Oostende" .
11
+ :answer gps:routeActions "drive_gent_brugge, drive_brugge_oostende" .
12
+ :answer gps:routeBelief 0.9408 .
13
+ :answer gps:routeComfort 0.99 .
14
+ :answer gps:routeCost 0.01 .
15
+ :answer gps:routeDuration 2400 .
16
+ :answer log:outputString "GPS — Generic route planning\n\n## Question\nWhich route should we take from Gent to Oostende?\n\n## Answer\nTake Gent → Brugge → Oostende.\n\n## Recommended Route\nGent → Brugge → Oostende\nActions: drive_gent_brugge, drive_brugge_oostende\nDuration: 2400 seconds\nCost: 0.01\nBelief: 0.9408\nComfort: 0.99\n\n## Alternative Route\nGent → Kortrijk → Brugge → Oostende\nActions: drive_gent_kortrijk, drive_kortrijk_brugge, drive_brugge_oostende\nDuration: 4100 seconds\nCost: 0.018\nBelief: 0.903168\nComfort: 0.9801\n\n## Reason Why\nFrom Gent to Oostende, the planner found two routes in this small map. The direct route (Gent → Brugge → Oostende) takes 2400 seconds at cost 0.01, with belief 0.9408 and comfort 0.99. The alternative (Gent → Kortrijk → Brugge → Oostende) takes 4100 seconds at cost 0.018, with belief 0.903168 and comfort 0.9801. So the direct route is faster, cheaper, more reliable, and slightly more comfortable.\n\n## Check\nC1 OK - complete paths are discovered by chaining gps:Drive facts.\nC2 OK - cycles are avoided with the generated path key.\nC3 OK - dominated complete paths are rejected before recommendation.\n" .
17
+ :question gps:from :Gent .
18
+ :question gps:fromLabel "Gent" .
19
+ :question gps:hasCandidatePath path:Gent_Brugge_Oostende .
20
+ :question gps:hasCandidatePath path:Gent_Kortrijk_Brugge_Oostende .
21
+ :question gps:recommendedPath path:Gent_Brugge_Oostende .
22
+ :question gps:toLabel "Oostende" .
23
+ path:Gent_Brugge a gps:CandidatePath .
24
+ path:Gent_Brugge gps:actions "drive_gent_brugge" .
25
+ path:Gent_Brugge gps:belief 0.96 .
26
+ path:Gent_Brugge gps:comfort 0.99 .
27
+ path:Gent_Brugge gps:cost 0.006 .
28
+ path:Gent_Brugge gps:duration 1500 .
29
+ path:Gent_Brugge gps:last :Brugge .
30
+ path:Gent_Brugge gps:legs 1 .
31
+ path:Gent_Brugge gps:pathIRI path:Gent_Brugge .
32
+ path:Gent_Brugge gps:pathKey "|http://example.org/gps-demo/Gent|http://example.org/gps-demo/Brugge|" .
33
+ path:Gent_Brugge gps:query :question .
34
+ path:Gent_Brugge gps:routeLabel "Gent → Brugge" .
35
+ path:Gent_Brugge_Oostende a gps:CandidatePath .
36
+ path:Gent_Brugge_Oostende a gps:CompletedPath .
37
+ path:Gent_Brugge_Oostende gps:actions "drive_gent_brugge, drive_brugge_oostende" .
38
+ path:Gent_Brugge_Oostende gps:belief 0.9408 .
39
+ path:Gent_Brugge_Oostende gps:comfort 0.99 .
40
+ path:Gent_Brugge_Oostende gps:cost 0.01 .
41
+ path:Gent_Brugge_Oostende gps:duration 2400 .
42
+ path:Gent_Brugge_Oostende gps:last :Oostende .
43
+ path:Gent_Brugge_Oostende gps:legs 2 .
44
+ path:Gent_Brugge_Oostende gps:pathIRI path:Gent_Brugge_Oostende .
45
+ path:Gent_Brugge_Oostende gps:pathKey "|http://example.org/gps-demo/Gent|http://example.org/gps-demo/Brugge|http://example.org/gps-demo/Oostende|" .
46
+ path:Gent_Brugge_Oostende gps:query :question .
47
+ path:Gent_Brugge_Oostende gps:recommended true .
48
+ path:Gent_Brugge_Oostende gps:routeLabel "Gent → Brugge → Oostende" .
49
+ path:Gent_Kortrijk a gps:CandidatePath .
50
+ path:Gent_Kortrijk gps:actions "drive_gent_kortrijk" .
51
+ path:Gent_Kortrijk gps:belief 0.96 .
52
+ path:Gent_Kortrijk gps:comfort 0.99 .
53
+ path:Gent_Kortrijk gps:cost 0.007 .
54
+ path:Gent_Kortrijk gps:duration 1600 .
55
+ path:Gent_Kortrijk gps:last :Kortrijk .
56
+ path:Gent_Kortrijk gps:legs 1 .
57
+ path:Gent_Kortrijk gps:pathIRI path:Gent_Kortrijk .
58
+ path:Gent_Kortrijk gps:pathKey "|http://example.org/gps-demo/Gent|http://example.org/gps-demo/Kortrijk|" .
59
+ path:Gent_Kortrijk gps:query :question .
60
+ path:Gent_Kortrijk gps:routeLabel "Gent → Kortrijk" .
61
+ path:Gent_Kortrijk_Brugge a gps:CandidatePath .
62
+ path:Gent_Kortrijk_Brugge gps:actions "drive_gent_kortrijk, drive_kortrijk_brugge" .
63
+ path:Gent_Kortrijk_Brugge gps:belief 0.9216 .
64
+ path:Gent_Kortrijk_Brugge gps:comfort 0.9801 .
65
+ path:Gent_Kortrijk_Brugge gps:cost 0.014 .
66
+ path:Gent_Kortrijk_Brugge gps:duration 3200 .
67
+ path:Gent_Kortrijk_Brugge gps:last :Brugge .
68
+ path:Gent_Kortrijk_Brugge gps:legs 2 .
69
+ path:Gent_Kortrijk_Brugge gps:pathIRI path:Gent_Kortrijk_Brugge .
70
+ path:Gent_Kortrijk_Brugge gps:pathKey "|http://example.org/gps-demo/Gent|http://example.org/gps-demo/Kortrijk|http://example.org/gps-demo/Brugge|" .
71
+ path:Gent_Kortrijk_Brugge gps:query :question .
72
+ path:Gent_Kortrijk_Brugge gps:routeLabel "Gent → Kortrijk → Brugge" .
73
+ path:Gent_Kortrijk_Brugge_Oostende a gps:CandidatePath .
74
+ path:Gent_Kortrijk_Brugge_Oostende a gps:CompletedPath .
75
+ path:Gent_Kortrijk_Brugge_Oostende gps:actions "drive_gent_kortrijk, drive_kortrijk_brugge, drive_brugge_oostende" .
76
+ path:Gent_Kortrijk_Brugge_Oostende gps:belief 0.903168 .
77
+ path:Gent_Kortrijk_Brugge_Oostende gps:comfort 0.9801 .
78
+ path:Gent_Kortrijk_Brugge_Oostende gps:cost 0.018000000000000002 .
79
+ path:Gent_Kortrijk_Brugge_Oostende gps:dominatedBy path:Gent_Brugge_Oostende .
80
+ path:Gent_Kortrijk_Brugge_Oostende gps:duration 4100 .
81
+ path:Gent_Kortrijk_Brugge_Oostende gps:last :Oostende .
82
+ path:Gent_Kortrijk_Brugge_Oostende gps:legs 3 .
83
+ path:Gent_Kortrijk_Brugge_Oostende gps:pathIRI path:Gent_Kortrijk_Brugge_Oostende .
84
+ path:Gent_Kortrijk_Brugge_Oostende gps:pathKey "|http://example.org/gps-demo/Gent|http://example.org/gps-demo/Kortrijk|http://example.org/gps-demo/Brugge|http://example.org/gps-demo/Oostende|" .
85
+ path:Gent_Kortrijk_Brugge_Oostende gps:query :question .
86
+ path:Gent_Kortrijk_Brugge_Oostende gps:routeLabel "Gent → Kortrijk → Brugge → Oostende" .