-
Notifications
You must be signed in to change notification settings - Fork 25
/
chunks-and-rules.html
1255 lines (1039 loc) · 83.3 KB
/
chunks-and-rules.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Chunks and Rules</title>
<script async class="remove" src="https://www.w3.org/Tools/respec/respec-w3c"></script>
<script class="remove">
var respecConfig = {
shortName: "chunks",
specStatus: "CG-DRAFT",
noRecTrack: true,
edDraftURI: "https://w3c.github.io/cogai/",
editors: [
{
name: "François Daoust",
company: "W3C",
companyURL: "https://www.w3.org/",
w3cid: "41989"
},
{
name: "Dave Raggett",
company: "W3C",
companyURL: "https://www.w3.org/",
w3cid: "2682"
}
],
group: "cogai",
github: {
repoURL: "https://github.com/w3c/cogai/",
branch: "master"
},
localBiblio: {
"CHUNKS-INTRO": {
title: "Introduction to chunks and rules",
href: "https://www.w3.org/Data/demos/chunks/chunks.html",
authors: [
"Dave Raggett"
]
},
"CHUNKS-DEMOS": {
title: "Chunk Demonstrators",
href: "https://github.com/w3c/cogai/blob/master/demos/README.md",
authors: [
"Dave Raggett"
]
},
"CHUNKS-LOWCODE": {
title: "Chunks and Rules for Cognitive Control",
href: "https://w3c.github.io/cogai/agents/low-code-with-chunks-and-rules.pdf",
authors: [
"Dave Raggett"
]
},
"IEEE-754-2019": {
title: "IEEE 754-2019: IEEE Standard for Floating-Point Arithmetic. Institute of Electrical and Electronic Engineers, New York (2019)"
},
"Date and Time Profile": {
title: "Date and Time Formats",
href: "https://www.w3.org/TR/1998/NOTE-datetime-19980827",
authors: [
"Misha Wolf",
"Charles Wicksteed"
]
},
"Rete Match Algorithm": {
title: "Rete: A fast algorithm for the many pattern/many object pattern match problem",
href: "https://www.sciencedirect.com/science/article/abs/pii/0004370282900200",
authors: [
"Charles L. Forgy"
]
}
}
};
</script>
<style>
.railroad {
margin-top: 1em;
margin-bottom: 2em;
}
</style>
</head>
<body>
<section id="abstract">
<p>This specification defines a cognitive graph database model featuring chunks as collections of properties, and rules that operate on them in conjunction with highly scalable graph algorithms, together with a simple notation for serializing graphs as a convenient abstraction above RDF. The model reflects functional characteristics of human memory and cognition, including stochastic recall and the forgetting curve. Chunks & Rules provide an attractive framework for low-code real-time control of digital twins for the Internet of Things, decoupled from the details of communication technologies and standards, using asynchronous messaging that enables distributed implementations and integration with robot systems based upon ROS (the robot operating system), see [[CHUNKS-LOWCODE]]</p>
</section>
<section id="sotd">
<p>This document reflects implementation experience, but is still subject to change. Feedback is welcome through <a href="https://github.com/w3c/cogai/issues">GitHub issues</a> or on the <a href="mailto:[email protected]">[email protected]</a> mailing-list (with <a href="https://lists.w3.org/Archives/Public/public-cogai/">public archives</a>).</p>
</section>
<section class="informative">
<h2>Introduction</h2>
<p>This specification introduces a simple notation and computational model for chunk graphs and rules. Chunks are collections of properties (name/value pairs) together with sub-symbolic parameters that mimic the characteristics of human memory, including the forgetting curve and stochastic recall. Chunk rules operate on chunk buffers that mimic the connections between the basal ganglia and cortical modules.</p>
<figure id="cog-arch">
<img src="demos/chunks/arch.png" alt="" />
<figcaption>Architecture of the cognitive database model</figcaption>
</figure>
<p>At its heart, the model is based on [=graphs of chunks=] composed of a collection of [=chunks=], where each [=chunk=] represents a collection of basic familiar units that have been grouped together and stored in memory. To ease manipulation of procedural knowledge as declarative knowledge, [=chunks=] are used to model both declarative knowledge (i.e. data) as well as procedural knowledge (i.e. rules). See [[CHUNKS-INTRO]] for details.</p>
<p>The [=rule engine=] operates on a set of [=modules=], where each [=module=] has a [=graph of chunks=] and supports an <a data-lt="built-in operations">extensible set of operations</a> on chunks. Each module has a single [=module buffer=] that the [=rule engine=] can process, and that can hold one and only one [=chunk=] at a time.</p>
<p>This specification also defines a <a href="#chunks-documents">serialization format</a> for graphs of chunks, used in examples throughout this specification.</p>
</section>
<section id="conformance">
<p>The grammatical rules in this document are to be interpreted as described in [[[RFC5234]]] [[RFC5234]].</p>
<section>
<h3>Conformance classes</h3>
<p>Conformance to this specification is defined for four conformance classes:</p>
<dl>
<dt><dfn>Chunks document</dfn></dt>
<dd>A serialization of a [=graph of chunks=] as a file. A [=chunks document=] is conformant to this specification if it follows the grammar described in <a href="#chunks-grammar"></a>.</dd>
<dt><dfn>Authoring tool</dfn></dt>
<dd>An application that writes a [=chunks document=]. An [=authoring tool=] is conformant to this specification if it writes conforming [=chunks documents=].</dd>
<dt><dfn>Parser</dfn></dt>
<dd>A [=parser=] transforms a [=chunks document=] into another representation. A [=parser=] is conformant to this specification if it accepts any conforming [=chunks document=].</dd>
<dt><dfn>Rule engine</dfn></dt>
<dd>A processing application that operates on graphs of chunks and rules, organized following the cognitive agent architecture described in this specification. A [=rule engine=] is conformant to this specification if it follows the algorithms defined in <a href="#rule-engine-execution"></a>.</dd>
</dl>
</section>
</section>
<section>
<h2>Data types</h2>
<p>This document uses the following restricted set of data types to describe [=chunks=]. See <a href="#chunks-grammar"></a> for a formal definition of their serialization.</p>
<p>A <dfn>number</dfn> represents a double-precision 64-bit format value as specified in the IEEE Standard for Binary Floating-Point Arithmetic [[IEEE-754-2019]]. It is serialized in base 10 using decimal digits, following the same grammar as <a data-cite="RFC8259#section-6">numbers in JSON</a> [[RFC8259]].</p>
<p>A <dfn>boolean</dfn> represents a logical entity having two values. It is serialized as either the literal name <code>true</code>, which gets interpreted as a truthy value, or the literal name <code>false</code>, which gets interpreted as a falsy value.</p>
<p>A <dfn>date</dfn> is a string that represents a date according to the [[Date and Time Profile]] of the [[ISO8601]] standard. A [=date=] value implicitly creates a read-only chunk whose type is <code>iso8601</code> with properties that match actual date components.</p>
<aside class="example" title="Date example">
<p>Here is an example of a chunk that describes Albert Einstein's birth date:</p>
<pre class="chk"><code>person Albert_Einstein {
birthdate 1879-03-14
}</code></pre>
<p>This chunk implicitly creates the following chunk definition:</p>
<pre class="chk"><code>iso8601 1879-03-14 {
year 1879
month 3
day 14
}
</code></pre>
</aside>
<p class="issue">Whether or not to prepend <code>iso8601</code> and its related properties with <code>@</code> (see <a href="https://github.com/w3c/cogai/issues/2">issue #2</a>).</p>
<p>A <dfn>string literal</dfn> is an arbitrary set of characters. It is serialized enclosed in double quotes, following the same grammar as <a data-cite="RFC8259#section-7">strings in JSON</a> [[RFC8259]].</p>
<p>A <dfn>name</dfn> is a string that can include letters, digits, period, hyphen, underscore and slash characters, and that cannot be interpreted as a [=number=], a [=boolean=]. Additionally, depending on the context under which it is used, a [=name=] may start with one of the name operators (see [[[#name-operators]]]).</p>
</section>
</section>
<section>
<h2>Chunks and graphs</h2>
<p>A <dfn>chunk</dfn> is a named typed collection of [=properties=]. A [=chunk=] is used to model both declarative knowledge and procedural knowledge as a collection of basic familiar units that have been grouped together and stored in memory.</p>
<p>A [=chunk=] has a [=type=] and an optional [=identifier=].</p>
<aside class="note" title="Serialization of a chunk">
<p>When serialized in a [=chunks document=], the declaration of a [=chunk=] always starts with a chunk [=type=], followed by an optional chunk [=identifier=], and a set of [=properties=] enclosed in braces (<code>{}</code>). Lists are represented as comma separated values. Whitespaces may appear anywhere between constructs. See <a href="#chunks-grammar"></a> for details.</p>
</aside>
<aside class="example" title="A chunk to describe a dog">
<pre class="chk">dog dog1 {
name "Fido"
age 4
}</pre>
<p>or using the compact syntax:</p>
<pre class="chk">dog dog1 {name "Fido"; age 4}</pre>
<p>This [=chunk=] describes a dog named "Fido" that is 4 years old. The chunk [=type=] is <code>dog</code>. Its [=identifier=] is <code>dog1</code> and uniquely identifies this chunk within the graph it is defined in. The chunk has two [=properties=]:</p>
<ul>
<li><code>name</code> whose value is the [=string literal=] <code>"Fido"</code></li>
<li><code>age</code> whose value is the [=number=] <code>4</code></li>
</ul>
<p>The interpretation of <em>age</em> as being stated in years is application dependent. Applications could choose to declare the units with an associated [=property=], e.g. <em>age-units</em> as an application dependent solution. A more general approach is proposed in the section [[[#data-models]]].</p>
</aside>
<section>
<h3>Chunk type</h3>
<p>A chunk <dfn>type</dfn> is a [=name=] that documents the nature of a chunk. The [=type=] is used to group and index chunks. [=Rules=] typically apply to chunks of a given [=type=].</p>
<aside class="example" title="A chunk of type "person"">
<pre class="chk"><code>person Dave {
knows Francois
}</code></pre>
</aside>
<p>As a special case, the [=type=] may be formed by a single asterisk (<code>*</code>), which is used to describe a [=condition=] or [=action=] that matches any chunk [=type=].</p>
</section>
<section>
<h3>Chunk identifier</h3>
<p>The chunk <dfn>identifier</dfn> is a [=name=] that uniquely identifies a chunk within the graph it is defined in.</p>
<p>The chunk [=identifier=] is optional. If missing, it will be automatically assigned when the chunk is added to a chunk module.</p>
</section>
<section>
<h3>Chunk properties</h3>
<p>A chunk <dfn>property</dfn> is a [=name=]/[=value=] pair that describes a chunk across the particular dimension identified by the property name.</p>
<p>A <dfn>value</dfn> is either an [=atomic value=] or an ordered list of [=atomic values=] (values are comma-separated in serialized form).</p>
<p>An <dfn>atomic value</dfn> is either:</p>
<ul>
<li>a [=name=], which can for instance be used to reference other chunks</li>
<li>a [=number=]</li>
<li>a [=boolean=] (<code>true</code> or <code>false</code>)</li>
<li>a [=date=]</li>
<li>a [=string literal=]</li>
</ul>
<p>A property [=value=] |a| <dfn>equals</dfn> property [=value=] |b| when the following algorithm returns <code>true</code>:</p>
<ul>
<li>If |a| is the [=wild card operator=] <code>*</code>, return <code>true</code>.</li>
<li>If |b| is the [=wild card operator=] <code>*</code>, return <code>true</code>.</li>
<li>If |a| is the [=negation operator=] <code>!</code>, return <code>false</code>.</li>
<li>If |b| is the [=negation operator=] <code>!</code>, return <code>false</code>.</li>
<li>If |a| is a [=name=] that starts with the [=negation operator=] <code>!</code>, return <code>false</code> if !|a| [=equals=] |b|, <code>true</code> otherwise.</li>
<li>If |b| is a [=name=] that starts with the [=negation operator=] <code>!</code>, return <code>false</code> if |a| [=equals=] !|b|, <code>true</code> otherwise.</li>
<li>If |a| is a [=variable=] that is not yet [=bound=] to a value, return <code>true</code>.</li>
<li>If |b| is a [=variable=] that is not yet [=bound=] to a value, return <code>true</code>.</li>
<li>If |a| is a [=variable=] [=bound=] to a value |v|, return <code>true</code> if |v| [=equals=] |b|, <code>false</code> otherwise.</li>
<li>If |b| is a [=variable=] [=bound=] to a value |v|, return <code>true</code> if |a| [=equals=] |v|, <code>false</code> otherwise.</li>
<li>If |a| and |b| are identical [=atomic values=], return <code>true</code>.</li>
<li>If |a] and |b| are lists of [=atomic values=], both lists have the same length, and [=atomic values=] at the same position in |a| and |b| are [=equal=], return <code>true</code>.</li>
<li>Otherwise, return <code>false</code>.</li>
</ul>
</section>
<section>
<h3>Chunk context</h3>
<p>A [=chunk=] may be scoped to a <dfn>context</dfn>, which identifies the specific situation under which the [=chunk=] should be considered to be true. This mechanism allows [=chunks=] to describe things that are only true in hypothetical situations.</p>
<p>[=Contexts=] can be used to express situations that involve the use of statements about statements, including beliefs, stories, reported speech, examples in lessons, abductive reasoning and even search query patterns. They are also useful for episodic memory when one wants to describe facts that are true in a given situation, for instance an episode when a person visited a restaurant for lunch, sat by the window, and had soup for starters followed by mushroom risotto for the main course. A sequence of episodes can then be modelled as relationships between contexts.</p>
<p>A [=chunk=] is associated with a specific [=context=] through an [=@context=] [=property=].</p>
<p>A [=chunk=] that is not explicitly associated with a [=context=] (i.e. in the absence of an [=@context=] property) belongs to the <dfn>default context</dfn>.</p>
<aside class="example" title="Expressing a belief">
<p>Here is an example from John Sowa's <a href="http://www.jfsowa.com/pubs/arch.htm">Architectures for Intelligent Systems</a>:</p>
<p><cite>Tom believes that Mary wants to marry a sailor.</cite></p>
<p>This example involves talking about a statement <cite>Mary wants to marry a sailor</cite> that is only known to be true according to Tom's belief. When represented as [=chunks=], the statement needs to be associated with a [=context=] that identifies Tom's belief, so that we cannot directly assert that the statement is true in general.</p>
<p>Similarly, the statement <cite>to marry a sailor</cite> is only known to be true according to Mary's desire. When represented as [=chunks=], the statement also needs to be associated with a [=context=] that identifies Mary's desire.</p>
<p>Here is one possible way to represent the overall statement with [=chunks=]:</p>
<pre class="chk">believes {
@subject tom
proposition tom-belief-1
}
wants {
@context tom-belief-1
@subject mary
situation mary-desire-1
}
married-to {
@context mary-desire-1
@subject mary
@object s1
}
a s1 {
@context mary-desire-1
profession sailor
}</pre>
</aside>
<p>As illustrated in the previous example, [=contexts=] can be chained, e.g. to describe the beliefs of someone in a fictional story or movie, and to indicate when a context is part of several other contexts, thus creating a tree of [=contexts=].</p>
<p>Practically speaking, [=contexts=] make it possible to filter out non relevant [=chunks=] in [=conditions=] and [=actions=]. Two [=chunks=] may only [=match=] when they belong to the same context. For instance, a [=chunk=] that belongs to the context <code>tom-belief-1</code> can only [=match=] [=chunks=] that also belong to that context, and de facto cannot match [=chunks=] that belong to the [=default context=]. In particular, a [=chunk=] that belongs to the [=default context=] can only [=match=] [=chunks=] that also belong to the [=default context=].</p>
<p class="issue">Is there a need for a limited form of automatic inheritance, e.g. when matching chunks in a context for a fictional account, should this also match chunks in the parent context? This would allow general knowledge to apply by default within fictional accounts.</p>
</section>
<section>
<h3>Links between chunks</h3>
<p>In this document, a <dfn>link</dfn> is a directed and labeled connection between two [=chunks=]. A [=link=] is automatically created whenever a chunk property [=value=] is a [=name=] that references an existing chunk [=identifier=].</p>
<p>The <dfn>subject</dfn> of the [=link=] identifies the [=chunk=] at the origin of the connection. The <dfn>object</dfn> of the [=link=] identifies the [=chunk=] targeted by the connection. The <dfn class="lint-ignore">label</dfn> of the [=link=] is the property [=name=].</p>
<aside class="example" title="A link between two chunks">
<pre class="chk"><code>friend f34 {
name Joan
}
friend f35 {
name Jenny
likes f34
}</code></pre>
<p>The above definition creates a link between <code>f35</code> and <code>f34</code> with the relationship <code>likes</code>.</p>
</aside>
<p>When a [=chunk=] links to another [=chunk=], this implicitly creates a third [=chunk=] whose [=type=] is the name of the [=property=] that creates the [=link=], and that has two [=properties=]:</p>
<ul>
<li><dfn><code>@subject</code></dfn>: references the [=subject=] of a [=link=]</li>
<li><dfn><code>@object</code></dfn>: references the [=object=] of a [=link=]</li>
</ul>
<aside class="example" title="Links as chunks">
<pre class="chk"><code>animal dog {
kindof mammal
}</code></pre>
<p>The previous definition implicitly creates the following [=chunk=]:</p>
<pre class="js">kindof {
@subject dog
@object mammal
}</pre>
</aside>
<aside class="note" title="Compact format for links">
<p>The <a href="#chunks-grammar">grammar</a> allows to express [=links=] in a compact format in a [=chunks document=], e.g.:</p>
<pre class="chk">dog kindof mammal
cat kindof mammal</pre>
<p>This is equivalent to:</p>
<pre class="chk">kindof {
@subject dog
@object mammal
}
kindof {
@subject cat
@object mammal
}</pre>
</aside>
</section>
<section>
<h3>Graph of chunks</h3>
<p>A <dfn data-lt="graphs of chunks">graph of chunks</dfn> is simply a collection of [=chunks=]. The vertices of the graph are the [=chunks=]. The edges of the graph are the [=links=] between the chunks.</p>
<p>Since [=links=] are directed, a [=graph of chunks=] is a directed graph.</p>
</section>
</section>
<section>
<h2>Rules and modules</h2>
<section>
<h3>Rules</h3>
<p>A <dfn>rule</dfn> is a [=chunk=] whose [=type=] is <code>rule</code> and that has:</p>
<ul>
<li>an <dfn><code>@condition</code></dfn> [=property=], whose value is a chunk [=identifier=] or a list thereof, and which is used to reference the rule's [=conditions=].</li>
<li>an <dfn><code>@action</code></dfn> [=property=], whose value is a chunk [=identifier=] or a list thereof, and which is used to reference the rule's [=actions=].</li>
</ul>
<p>A [=rule=] represents a unit of procedural knowledge. Rules consist of [=conditions=] and [=actions=].</p>
<aside class="example" title="Basic rule definition">
<p>The following [=rule=] has one [=condition=] (that holds true when the <code>goal</code> [=module buffer=] contains a [=chunk=] whose [=type=] is <code>remember</code>), and two [=actions=] that clears the <code>goal</code> [=module buffer=] and that loads a [=chunk=] whose type is <code>memory</code> in the <code>facts</code> [=module=]:</p>
<pre class="chk">rule r1 {
@condition c1
@action a1, a2
}
remember c1 {}
next a1 { @do clear }
memory a2 { @module facts }</pre>
</aside>
<aside class="note" title="Compact format for rules">
<p>The <a href="#chunks-grammar">grammar</a> allows to express [=rules=] in a compact format in a [=chunks document=]. For instance, the previous example may be written as:</p>
<pre class="chk">remember {} => next { @do clear }, memory { @module facts }</pre>
<p>This compact format makes the link between [=conditions=] and [=actions=] more explicit and avoids the need to provide chunk [=identifiers=].</p>
</aside>
<section>
<h4>Conditions</h4>
<p>A <dfn>condition</dfn> is a [=chunk=] that describes the premises that must hold true for a [=rule=] to apply. A [=condition=] identifies which [=module=] it relates to through an [=@module=] property, defaulting to the <code>goal</code> module. A [=condition=] holds true when the [=chunk=] in the related [=module buffer=] is a [=matching chunk=] for the [=condition=].</p>
</section>
<section>
<h4>Actions</h4>
<p>An <dfn>action</dfn> is a [=chunk=] that can directly update [=module buffers=], or can do so indirectly, e.g. by sending messages to the [=module=] to invoke graph algorithms, such as graph queries and updates, or to carry out operations, e.g. instructing a robot to move its arm. When the algorithm or operation is complete, a response can be sent back to update the module's buffer. This in turn can trigger further rules as needed. An [=action=] identifies which [=module=] it relates to through an [=@module=] property, defaulting to the <code>goal</code> module.</p>
<p>In many cases, the actual operation that an [=action=] will carry out will appear as an [=@do=] property. Built-in operations are always supported (see <a href="#built-in-operations"></a>). Other actions may be supported. See section [[[#scripting-api]]] for a means for applications to define additional actions, e.g. as a way to invoke external actions for operating a robot arm or camera.</p>
</section>
<section>
<h4>Matching chunks</h4>
<p>A [=chunk=] |A| <dfn data-lt="matching chunk">matches</dfn> [=chunk=] |B| if the conditions below are all met:</p>
<ul>
<li><i>Context</i>. One of the following conditions holds true:
<ul>
<li>Neither |A| nor |B| have [=@context=] properties.</li>
<li>Both |A| and |B| have [=@context=] properties and |A|'s [=@context=] property [=value=] [=equals=] |B|'s [=@context=] property [=value=].</li>
</ul>
</li>
<li><i>Identifier</i>. One of the following conditions holds true:
<ul>
<li>|A| has an [=@id=] property whose [=value=] is an [=atomic value=] that [=equals=] |B|'s [=identifier=].</li>
<li>|A| does not have an [=@id=] property.</li>
</ul>
</li>
<li><i>Inheritance</i>. One of the following conditions holds true:
<ul>
<li>|A| has an [=@kindof=] property whose [=value=] |V| is an [=atomic value=], and |B|'s [=type=] is a subclass of |V|, meaning that |B|'s [=type=] is |V| or there exists a chain of <code>kindof</code> links between |V| and |B|'s [=type=].</li>
<li>|A| does not have an [=@kindof=] property.</li>
</ul>
</li>
<li><i>Properties</i>. For each [=property=] |p| in |A| whose [=name=] does not start with <code>@</code>, either of the following holds true:
<ul>
<li>|p|'s [=value=] is <code>!</code> and there is no [=property=] in |B| with |p|'s [=name=].</li>
<li>|p|'s [=value=] is not <code>!</code> and there exits a [=property=] in |B| with the same [=name=] and [=equal=] [=value=] as |p|.</li>
</ul>
</li>
<li><i>Type</i>. One of the following conditions holds true:
<ul>
<li>|A| has an [=@type=] property whose [=value=] is an [=atomic value=] that [=equals=] |B|'s [=type=].</li>
<li>|A| does not have an [=@type=] property, and |A|'s [=type=] is <code>*</code>.</li>
<li>|A| does not have an [=@type=] property, and |A|'s [=type=] and |B|'s [=type=] are identical.</li>
</ul>
</li>
</ul>
</section>
<section>
<h4>@-properties for conditions and actions</h4>
<p>The [=reserved names=] defined in this section may be used as [=property=] names in [=conditions=] and [=actions=] to control their behavior.</p>
<section>
<h5>The <dfn><code>@compile</code></dfn> property</h5>
<p>This used in a rule action to compile a set of chunks in declarative memory into a set of rules in procedural memory. The process starts with the chunk that cites the chunks used for the conditions and actions, and then applies to those chunks. Note that <code>@compile</code> may cite a list of IDs for chunks to be compiled.</p>
<aside class="example" title="compile rule from declarative memory to procedural memory">
<pre class="chk">put {@compile rule1; @map map1}</pre>
<p>The above [=action=] looks for a chunk with ID <code>rule1</code> in the default module and compiles it using the mappings specified in the chunk with ID <code>map1</code> as specified with <code>@map</code>. The chunk type and ID are copied as is.</p>
</aside>
</section>
<section>
<h5>The <dfn><code>@context</code></dfn> property</h5>
<p>When used in a regular [=chunk=], identifies a chunk's [=context=]. When used in a [=condition=] or in an [=action=], [=matches=] a [=chunk=]'s [=context=].</p>
<aside class="example" title="Looks for a chunk in a given context">
<pre class="chk">recall { lunch ?restaurant }
=> lookup { @module facts; @do get; @type lunch; @context ?restaurant }</pre>
<p>The above [=rule=] defines an [=action=] that looks for a [=chunk=] in the <code>facts</code> [=module=] whose [=type=] is <code>lunch</code> and whose [=context=] is the identifier of the lunch matched by the <code>recall</code> [=condition=].</p>
</aside>
</section>
<section>
<h5>The <dfn><code>@do</code></dfn> property</h5>
<p>Specifies the graph algorithm or operation to execute. See <a href="#built-in-operations"></a> for a list of common operations that are supported across modules.</p>
</section>
<section>
<h5>The <dfn><code>@for</code></dfn> property</h5>
<p>Iterates over a set of items in a comma separated list. The [=@from=] and [=@to=] properties may be used to restrict the iteration range.</p>
</section>
<section>
<h5>The <dfn><code>@from</code></dfn> property</h5>
<p>Specifies the zero-based starting index of an [=@for=] iteration. Value must be an integer.</p>
<aside class="example" title="copy rule from procedural memory to declarative memory">
<pre class="chk"># a chunk in the facts module
person {name Wendy; friends Michael, Suzy, Janet, John}
# after having recalled the person chunk, the
# following rule iterates over the friends
person {@module facts; friends ?friends}
=> item {@module goal; @for ?friends; @from 1; @to 2}</pre>
<p>which will iterate over Suzy and Janet, updating the module buffer by setting properties for the item's value and its index, e.g.</p>
<pre class="chk">item {value Suzy; @index 1; @more true}</pre>
<p>The action's properties are copied over apart from those starting with an <code>@</code>. The item index in the list is copied into the chunk as [=@index=]. You can then use [=@do next=] in an action to load the next item into the buffer. The [=@more=] property is set to true in the buffer if there is more to come, and false for the last property in the iteration. Action chunks should use either [=@do=] or [=@for=], but not both. Neither implies <code>@do update</code>.</p>
</aside>
</section>
<section>
<h5>The <dfn><code>@id</code></dfn> property</h5>
<p>This is used in rule actions together with a value specify the chunk ID, e.g. to get a chunk with a given ID, or to add, update or replace an existing chunk with that ID.</p>
</section>
<section>
<h5>The <dfn><code>@index</code></dfn> property</h5>
<p>Used as part of an iteration over the values in a comma separated list with [=@for=].</p>
</section>
<section>
<h5>The <dfn><code>@kindof</code></dfn> property</h5>
<p>[=Matches=] a [=chunk=]'s [=type=] when that [=type=] is linked to the value of the [=@kindof=] property through a chain of <code>kindof</code> links. The property should be used in conjunction with a <code>*</code> type to match subclasses of a given class in a taxonomy.</p>
<aside class="example" title="Matching subclasses in a taxonomy">
<p>Given the following facts in a <code>facts</code> [=module=]:</p>
<pre class="chk">penguin kindof bird
eagle kindof bird
penguin p6 { name Pingou }</pre>
<p>The following [=condition=] would match the [=chunk=] <code>p6</code> if it was in the [=module buffer=] of the <code>facts</code> [=module=]:</p>
<pre class="chk">* cond1 {
@module facts
@kindof bird
}</code></pre>
</aside>
</section>
<section>
<h5>The <dfn><code>@map</code></dfn> property and chunk type</h5>
<p>This is used with [=@compile=] and [=@uncompile=] to reference a chunk of type [=@map=] that defines a map for property names and their meanings. See also the [=@unmap=] property.</p>
<aside class="example" title="term map for use in rule compilation and uncompilation">
<pre class="chk">@map map1 {do @do; condition @condition; action @action; module @module}</pre>
<p>The above [=chunk=] signifies that <code>do</code> is to be interpreted as [=@do=], <code>condition</code> is to be interpreted as [=@condition=], <code>action</code> is to be interpreted as [=@action=], and so forth. By mapping property names in this way, rules can be used to operate on chunks in declarative memory free of the difficulties posed by properties with the <code>@</code> prefix. The above example would be appropriate for a [=chunk=] such as the following:</p>
<pre class="chk">rule r1 {condition g1; action a1, a2, a3}</pre>
which is mapped to:
<pre class="chk">rule r1 {@condition g1; @action a1, a2, a3}</pre>
</aside>
</section>
<section>
<h5>The <dfn><code>@module</code></dfn> property</h5>
<p>References the [=module=] a [=condition=] or [=action=] relates to. Value must be the [=module name=] of the targeted [=module=]. In the absence of an [=@module=] property, [=conditions=] and [=actions=] apply to the <code>goal</code> module.</p>
</section>
<section>
<h5>The <dfn><code>@more</code></dfn> property</h5>
<p>Queries the [=boolean=] flag set to <code>true</code> by the [=rule engine=] on the current [=chunk=] in [=@for=] and [=@do properties=] iterations when there are remaining [=chunks=] to iterate over.</p>
</section>
<section>
<h5>The <dfn><code>@pop</code></dfn> property</h5>
<p>An [=action=] property that removes the last [=atomic value=] from a [=value=]. If the [=value=] to process is already an [=atomic value=], the underlying property is removed.</p>
<p>If a [=@to=] property is also present, the removed [=atomic value=] is assigned to the [=property=] identified by the [=@to=] property. In the absence of a [=@to=] property, the removed [=atomic value=] is discarded.</p>
<aside class="example" title="Remove the last element from a list">
<p>Given the following [=chunk=] and [=action=]:</p>
<pre class="chk">digits { list 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }
digits { @pop list, @to item }</pre>
<p>The [=action=] will update the [=chunk=] to:</p>
<pre class="chk">digits {
list 0, 1, 2, 3, 4, 5, 6, 7, 8
item 9
}</pre>
</aside>
</section>
<section>
<h5>The <dfn><code>@priority</code></dfn> property</h5>
<p>The @priority property lets actions set the [=priority=] of a [=chunk=] when they add it to the queue for a module buffer (see [=module buffer=]).</p>
</section>
<section>
<h5>The <dfn><code>@push</code></dfn> property</h5>
<p>An [=action=] property that pushes an [=atomic value=] to the end of the [=value=] of the property identified by a companion [=@to=] property. If the targeted property does not exist yet, it is created.</p>
<p>In the absence of a [=@to=] property, this operation has no effect.</p>
<aside class="example" title="Add an element to the end of a list">
<p>Given the following [=chunk=] and [=action=]:</p>
<pre class="chk">digits { list 0, 1, 2, 3, 4, 5, 6, 7, 8 }
digits { @push 9, @to list }</pre>
<p>The [=action=] will update the [=chunk=] to:</p>
<pre class="chk">digits { list 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }</pre>
</aside>
</section>
<section>
<h5>The <dfn><code>@shift</code></dfn> property</h5>
<p>An [=action=] property that removes the first [=atomic value=] from a [=value=]. If the [=value=] to process is already an [=atomic value=], the underlying property is removed.</p>
<p>If a [=@to=] property is also present, the removed [=atomic value=] is assigned to the [=property=] identified by the [=@to=] property. In the absence of a [=@to=] property, the removed [=atomic value=] is discarded.</p>
<aside class="example" title="Remove the first element from a list">
<p>Given the following [=chunk=] and [=action=]:</p>
<pre class="chk">digits { list 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }
digits { @shift list, @to item }</pre>
<p>The [=action=] will update the [=chunk=] to:</p>
<pre class="chk">digits {
list 1, 2, 3, 4, 5, 6, 7, 8, 9
item 0
}</pre>
</aside>
</section>
<section>
<h5>The <dfn><code>@status</code></dfn> property</h5>
<p>Queries the [=module buffer/status=] of a [=module buffer=]. The [=rule engine=] sets the status of a [=module buffer=] with the outcome of the [=rule=]'s execution. Most operations are asynchronous, except [=@do clear=], [=@do update=] and [=@do queue=].</p>
</section>
<section>
<h5>The <dfn><code>@tag</code></dfn> property</h5>
<p>This property provides a means for rule conditions to test a module buffer for the result from a preceding action. Use <code>@tag</code> in the action to pass an identifier to the subsequent asynchronous response where it can be accessed via <code>@tag</code> in a rule condition.</p>
</section>
<section>
<h5>The <dfn><code>@to</code></dfn> property</h5>
<p>Companion [=action=] property used in [=@do properties=], [=@for=], [=@pop=], [=@push=], [=@shift=], [=@unshift=] operations.</p>
<p>Meaning and value constraints depend on the operation. See individual operations for details. For instance, when used in a [=@for=] operation, the property specifies the zero-based ending index of the iteration. Value must be an integer. When used in a [=@do properties=] operation, the property specifies the name of the [=module buffer=] onto which to write the current [=chunk=].</p>
</section>
<section>
<h5>The <dfn><code>@type</code></dfn> property</h5>
<p>[=Matches=] a [=chunk=]'s [=type=], or binds a variable to the [=chunk=]'s [=type=].</p>
</section>
<section>
<h5>The <dfn><code>@unmap</code></dfn> property</h5>
<p>This MUST reference a chunk of type [=@map=] that defines a map for property names and their meanings, performing the inverse of the mapping specified by the [=@map=] property.</p>
</section>
<section>
<h5>The <dfn><code>@unshift</code></dfn> property</h5>
<p>An [=action=] property that pushes an [=atomic value=] to the beginning of the [=value=] of the property identified by a companion [=@to=] property. If the targeted property does not exist yet, it is created.</p>
<p>In the absence of a [=@to=] property, this operation has no effect.</p>
<aside class="example" title="Add an element to the beginning of a list">
<p>Given the following [=chunk=] and [=action=]:</p>
<pre class="chk">digits { list 1, 2, 3, 4, 5, 6, 7, 8 }
digits { @shift 0, @to list }</pre>
<p>The [=action=] will update the [=chunk=] to:</p>
<pre class="chk">digits { list 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }</pre>
</aside>
</section>
<section>
<h5>The <dfn><code>@uncompile</code></dfn> property</h5>
<p>This used in a rule action to copy a set of rules in procedural memory to a set of chunks in declarative memory into a set of rules in procedural memory. The process starts with the chunk that cites the chunks used for the conditions and actions, and then applies to those chunks. Note that <code>@uncompile</code> may cite a list of IDs for chunks to be uncompiled.</p>
<aside class="example" title="copy rule from procedural memory to declarative memory">
<pre class="chk">get {@uncompile rule1; @map map1}</pre>
<p>The above [=action=] looks for a rule chunk with ID <code>rule1</code> in the rule module and copies the associated chunks to the default module using the mappings specified in the chunk with ID <code>map1</code> as specified with [=@map=]. The chunk type and ID are copied as is.</p>
</aside>
</section>
</section>
<p class="issue">Is there a need for a means to map chunk IDs for use with [=@compile=] and [=@uncompile=]? A potential solution would be to introduce <code>@map-id</code> by analogy to [=@map=].</p>
</section>
<section>
<h3>Modules</h3>
<p>A <dfn>module</dfn> is a [=graph of chunks=] associated with one and only one [=module buffer=]. A [=module=] has a <dfn>module name</dfn> that follows the [=name=] data type, and that is typically used to target the [=module=] in [=@module=] properties.</p>
<p>A [=module=] supports [=built-in operations=], and may support additional operations defined by the application when the [=module=] is initialized.</p>
<p>A [=module=] represents a cognitive database on which the [=rule engine=] may operate. It may be viewed as a region in the cerebral cortex, where the [=module buffer=] corresponds to the bundle of nerve fibres connecting to that region.</p>
<p>The [=rule engine=] automatically creates a module named <code>goal</code>, which will therefore always exist in a rule execution context.</p>
<p>The [=@module=] property allows [=conditions=] and [=actions=] to reference the [=module name=] of the [=module=] they relate to. In the absence of an [=@module=] property, [=conditions=] and [=actions=] apply to the <code>goal</code> module.</p>
<section>
<h4>Module buffers</h4>
<p>A <dfn>module buffer</dfn> is a container for at most one [=chunk=]. The mammalian brain is richly connected locally, and weakly remotely. A [=module buffer=] mimics the constrained communication capacity of the mammalian brains for such long range communication.</p>
<p>The [=rule engine=] operates on a module's [=graph of chunks=] through its [=module buffer=].</p>
<p>A [=module buffer=] has a <dfn data-dfn-for="module buffer">status</dfn>, (accessible via [=@status=]), whose value is initially [=status/okay=], and which reflects the outcome of the last [=action=] held and performed by the [=module buffer=]. Values can be:</p>
<dl>
<dt><dfn class="lint-ignore"><code>pending</code></dfn></dt>
<dd>The operation is still pending.</dd>
<dt><dfn><code>okay</code></dfn></dt>
<dd>The operation completed successfully.</dd>
<dd><p class="issue">Switch to <code>ok</code>? This seems more common in technologies (e.g. HTTP) than <code>okay</code>.</p></dd>
<dt><dfnclass="lint-ignore"><code>forbidden</code></dfn></dt>
<dd>The operation was not allowed.</dd>
<dt><dfnclass="lint-ignore"><code>nomatch</code></dfn></dt>
<dd>The operation [=failed=] because there was no [=matching chunk=] for the [=action=] in the targeted [=module=].</dd>
<dt><dfn class="lint-ignore"><code>failed</code></dfn></dt>
<dd>The operation failed.</dd>
</dl>
<p>This is analogous to the hypertext transfer protocol (HTTP) and allows rule engines to work with remote cognitive databases. To relate particular request and response pairs, use [=@tag=] in the action to pass an identifier to the subsequent asynchronous response where it can be accessed via [=@tag=] in a rule condition.</p>
<p>A [=module buffer=] has a <dfn>queue</dfn>, which is a set of [=chunks=], initially empty. Each chunk in the [=queue=] has a <dfn>priority</dfn>, represented by an integer from 1 to 10, with 10 the highest priority. The default [=priority=] is 5. [=Chunks=] are ordered by descending [=priority=] in a [=queue=]. When [=priorities=] match, [=chunks=] are ordered by insertion order (first in, first out).</p>
<p>The [=@priority=] property lets [=actions=] set the [=priority=] of a [=chunk=] when they add it to a [=queue=].</p>
<aside class="note" title="Queue and sub-goals">
<p>A [=queue=] may be useful to create sub-goals. For instance, whilst [=@do update=] operations allow applications to switch to a new goal, they may prefer [=rules=] to propose multiple sub-goals instead. [=Queues=] enable this through [=@do queue=] operations which push the [=chunk=] specified by an [=action=] to the [=queue=] of a [=module buffer=].</p>
</aside>
<p>A [=module buffer=] is automatically cleared when the [=actions=] associated with the [=rule=] it contained did not update the contents of targeted [=module buffers=]. This pops the [=queue=] if it is not already empty.</p>
</section>
<section>
<h4>Built-in operations</h4>
<p>The [=@do=] property lets an [=action=] specify the graph algorithm or operation to execute. The default operation is to update the [=module buffer=], similar to calling [=@do update=].</p>
<p>All [=modules=] support the <dfn>built-in operations</dfn> defined in this section.</p>
<p>All [=modules=] also support the [=@for=] property to iterate over a set of items in a comma separated list. This has the effect of loading the [=module buffer=] with the first item in the list. The index range can optionally be specified with [=@from=] and [=@to=], where the first item in the list has index <code>0</code>.</p>
<aside class="note" title="Application-defined operations">
<p>Applications can define additional operations when initialising a [=module=]. This can be used to perform a variety of operations, e.g. to allow rules to command a robot to move its arm, by passing it the desired position and direction of the robot's hand. Operations can be defined to allow messages to be spoken aloud or to support complex graph algorithms, e.g. for data analytics and machine learning.</p>
<p>Applications cannot replace the [=built-in operations=].</p>
</aside>
<section>
<h5>The <dfn><code>@do clear</code></dfn> operation</h5>
<p>Clears the [=module buffer=] and pops the [=queue=].</p>
</section>
<section>
<h5>The <dfn class="lint-ignore"><code>@do delete</code></dfn> operation</h5>
<p>Removes [=matching chunks=] from the [=graph of chunks=].</p>
</section>
<section>
<h5>The <dfn class="lint-ignore"><code>@do get</code></dfn> operation</h5>
<p>Looks for a [=matching chunk=] in the module's [=graph of chunks=] and puts a copy of it in the [=module buffer=] if found. Modifying the [=properties=] of a [=chunk=] copied from a [=graph of chunks=] (e.g. through a [=@do update=] operation) will not alter the underlying [=graph of chunks=]. To save an updated [=chunk=], a [=@do put=] or [=@do patch=] command needs to be issued.</p>
</section>
<section>
<h5>The <dfn><code>@do next</code></dfn> operation</h5>
<p>Loads the next [=matching chunk=] to the targeted [=module buffer=] in an implementation dependent order.</p>
</section>
<section>
<h5>The <dfn><code>@do patch</code></dfn> operation</h5>
<p>If the [=chunk=] in the targeted [=module buffer=] has the same [=identifier=] as a [=chunk=] in the underlying [=graph of chunks=], patches the [=chunk=] in the [=graph of chunks=] with the [=properties=] that appear in the [=module buffer=], excluding [=properties=] prefixed with an <code>@</code> character.</p>
<p class="issue">What is the expected behavior when the action has an <code>@id</code> property? It would seem reasonable for the action to synchronously update the [=identifier=] for the chunk in the module buffer prior to applying that chunk to patch the module's [=graph of chunks=].</p>
</section>
<section>
<h5>The <dfn><code>@do properties</code></dfn> operation</h5>
<p>Initiates an iteration over the [=properties=] of the [=matching chunk=] that do not begin with <code>@</code>. Each [=property=] is mapped to a new [=chunk=] with the same [=type=] as the [=action=]. The action's properties are copied over, and <code>name</code> and <code>value</code> properties are used to pass the [=property=] name and value respectively. The [=@more=] property is given the value <code>true</code> unless this is the final [=chunk=] in the iteration, in which case [=@more=] is given the value false. By default, the iteration is written to the same [=module buffer=] as designated by the [=action=] that initiated it. However, you can designate a different [=module buffer=] with the [=@to=] property. By setting additional properties in the initiating action, you can ensure that the rules used to process the property name and value are distinct from other such iterations.</p>
<aside class="example" title="Iterate over properties">
<p>The following example first sets the <code>facts</code> [=module buffer=] to a [=chunk=] of [=type=] <code>foo</code>, and then initiates an iteration over all of the [=chunk=]'s properties:</p>
<pre class="chk">run {}
=>
foo {@module facts; a 1; c 2}, # set facts buffer to foo {a 1; c 2}
bar {@module facts; @do properties; loop prop18; @to goal} # launch iteration
# this rule is invoked with the name and value for each property
# note that 'loop prop18' is copied over from the initiating chunk
# (also note that "@do log" is an hypothetical operation to log a message)
bar {loop prop18; name ?name; value ?value}
=>
console {@do log; message ?name, is, ?value},
bar {@do next} # to load the next instance from the iteration</pre>
</aside>
</section>
<section>
<h5>The <dfn><code>@do put</code></dfn> operation</h5>
<p>Saves the contents of the [=module buffer=] as a [=chunk=] to the module's [=graph of chunks=]. If the [=action=] has an [=@id=] property, this operation will overwrite the [=chunk=] with the same [=identifier=] or will create a new [=chunk=] with the given [=identifier=] if it does not exist already. This operation will also create a new [=chunk=] in the absence of an [=@id=] property.</p>
<p class="issue">If a chunk was loaded with <code>@do get</code>, then updated with <code>@do update</code>, would a call to <code>@do patch</code> create a new chunk if <code>@id</code> is not set? Or would it rather update the chunk in the graph?</p>
</section>
<section>
<h5>The <dfn><code>@do queue</code></dfn> operation</h5>
<p>Pushes a [=chunk=] to the [=queue=] for the [=module buffer=]. If a [=@priority=] property is set to an integer value between 1 and 10, the [=priority=] of the [=chunk=] in the [=queue=] is set to that value.</p>
</section>
<section>
<h5>The <dfn><code>@do update</code></dfn> operation</h5>
<p>Directly updates the [=module buffer=] if the chunk [=type=] for the [=action=] is the same as the [=chunk=] currently held in the [=module buffer=]. The operation updates the properties given in the [=action=], leaving aside properties prefixed with an <code>@</code> character, and leaving other existing properties unchanged. If the chunk [=type=] for the action is not the same as the [=chunk=] currently held in the [=module buffer=], a new [=chunk=] is created with the properties given in the [=action=], excluding properties prefixed with an <code>@</code> character. This is the default action when an [=action=] has neither an [=@do=] property nor an [=@for=] property.</p>
<p class="issue">How can one update the properties prefixed with an <code>@</code> character in a [=chunk=] such as [=@context=], [=@subject=] or [=@object=]? A potential solution is to support the [=@map=] property as already supported for [=@compile=] and [=@uncompile=], along with an [=@unmap=] property. This would involve an asynchronous operation.</p>
</section>
</section>
</section>
</section>
<section>
<h2>Name operators</h2>
<p>Operators defined in this section may be used on their own as [=names=] or in front of [=names=] to alter their meaning.</p>
<section>
<h3>The variable operator <code>?</code></h3>
<p>The <dfn class="lint-ignore">variable operator</dfn> <code>?</code> may be prepended to a [=name=] when used as a [=property=] value to turn the [=name=] into a <dfn>variable</dfn> which represents a symbolic name to a [=value=]. A [=variable=] gets <dfn>bound</dfn> to a [=value=] in a [=condition=]. The [=value=] can then be referenced in [=actions=] using the [=variable=]'s name. Effectively, [=variables=] allow applications to copy information from rule [=conditions=] to rule [=actions=].</p>
<p>[=Variables=] are scoped to the [=rule=] where they appear.</p>
<aside class="example" title="Variable binding and referencing">
<pre class="chk">count { state start; from ?num1; to ?num2 }
=> increment { @module facts; @do get; number ?num1 }</pre>
<p>The above [=rule=] defines a [=condition=] that [=matches=] a [=chunk=] in the <code>goal</code> [=module buffer=] whose [=type=] is <code>count</code>, that has a <code>state</code> [=property=] whose value is <code>start</code>, and that has <code>from</code> and <code>to</code> [=properties=]. The [=condition=] binds the value of the [=variable=] <code>?num1</code> to the [=value=] of the <code>from</code> [=property=] in the matching chunk, and the value of the [=variable=] <code>?num2</code> to the [=value=] of the <code>to</code> [=property=].</p>
<p>The [=rule=] defines an [=action=] that looks for a [=chunk=] in the <code>facts</code> [=module=] whose [=type=] is <code>increment</code> and that has a [=property=] named <code>number</code> and whose [=value=] equals the value of the <code>?num1</code> [=variable=].</p>
</aside>
<p>[=Variables=] are [=bound=] to a [=value=] the first time they appear in a [=condition=]. Subsequent occurrences of the same [=variable=] in a [=condition=] reference their [=value=].</p>
<aside class="example" title="Variable binding and referencing in the same condition">
<pre class="chk">count { state start; from ?num1; to ?num1 }
=> console { @do log; message ?num1 }</pre>
<p>The above [=rule=] defines a [=condition=] that [=matches=] a [=chunk=] in the <code>goal</code> [=module buffer=] whose [=type=] is <code>count</code>, that has a <code>state</code> [=property=] whose value is <code>start</code>, and that has <code>from</code> and <code>to</code> [=properties=] that have identical values. The [=condition=] binds the value of the [=variable=] <code>?num1</code> to the [=value=] of the <code>from</code> [=property=] in the matching chunk.</p>
</aside>
<p>[=Variables=] may represent any type of [=value=]. In particular, a [=variable=] that [=matches=] a property whose value is a list of [=atomic values=] gets bound to the list of [=atomic values=].</p>
<aside class="example" title="Variable binding to a list of atomic values">
<pre class="chk">basket { fruit ?f }
=> console { @do log; message ?f }</pre>
<p>The above [=rule=] defines a [=condition=] that [=matches=] a [=chunk=] in the <code>goal</code> [=module buffer=] whose [=type=] is <code>basket</code> and that has a <code>fruit</code> [=property=]. Given the following [=chunk=] in the <code>goal</code> [=module buffer=], the [=condition=] binds variable <code>?f</code> to <code>apple, banana, orange</code>:</p>
<pre class="chk">basket { fruit apple, banana, orange }</pre>
</aside>
<p>A [=condition=] that contains a [=property=] with a list of [=variables=] [=matches=] a list of [=atomic values=] that has the same length. The [=condition=] does not [=match=] when the lengths of the lists differ.</p>
<aside class="example" title="Variable binding to atomic values in a list">
<pre class="chk">basket { fruit ?a, ?b, ?o }
=> console { @do log; message ?a, ?b, ?o }</pre>
<p>The above [=rule=] defines a [=condition=] that [=matches=] a [=chunk=] in the <code>goal</code> [=module buffer=] whose [=type=] is <code>basket</code> and that has a <code>fruit</code> [=property=] whose value is a list of <em>three</em> atomic values. Given the following [=chunk=] in the <code>goal</code> [=module buffer=], the [=condition=] binds variable <code>?a</code> to <code>apple</code>, <code>?b</code> to <code>banana</code>, and <code>?o</code> to <code>orange</code>:</p>
<pre class="chk"><code>basket { fruit apple, banana, orange }</code></pre>
</aside>
</section>
<section>
<h3>The wild card operator <code>*</code></h3>
<p>The <dfn>wild card operator</dfn> <code>*</code> may be used on its own in lieu of a [=name=] in one of the following cases:</p>
<ul>
<li>
As the [=type=] of a [=condition=] or [=action=] to denote that [=condition=] or [=action=] matches a [=chunk=] regardless of its [=type=].
<aside class="example" title="Condition that matches any chunk">
<pre class="chk">* {} => ...</pre>
<p>The <code>* {}</code> [=condition=] [=matches=] a [=chunk=] regardless of its [=type=] and [=properties=].</p>
</aside>
</li>
<li>
In a [=condition=] as the [=value=] of a [=property=] |p| to have the [=condition=] [=match=] a [=chunk=] that has a [=property=] whose [=name=] equals |p|'s [=name=], regardless of its [=value=].
<aside class="example" title="Match a property regardless of its value">
<pre class="chk">basket { fruit * } => ...</pre>
<p>The [=condition=] [=matches=] a [=chunk=] whose [=type=] is <code>basket</code> and which has a <code>fruit</code> [=property=] .</p>
</aside>
<p class="note">A [=variable=] may also be used to [=match=] on any [=value=]. The [=wild card operator=] avoids the need to provide a name for the [=variable=] when the actual [=value=] does not need to be captured.</p>
</li>
<li>
In a [=condition=] as an [=atomic value=] in a list to [=match=] any [=atomic value=] at the same position in a [=chunk=].
<aside class="example" title="Match an atomic value in a list">
<pre class="chk">basket { fruit apple, *, * } => ...</pre>
<p>The [=condition=] [=matches=] a [=chunk=] whose [=type=] is <code>basket</code> and which has a <code>fruit</code> [=property=] whose [=value=] is a list of three [=atomic values=] starting with <code>apple</code>.</p>
</aside>
</li>
</ul>
</section>
<section>
<h3>The negation operator <code>!</code></h3>
<p>The <dfn data-lt="negative operation">negation operator</dfn> <code>!</code> may be prepended to [=names=] to <dfn class="lint-ignore">negate</dfn> the outcome of their evaluation. The [=negation operator=] may be used in one of the following cases:</p>
<ul>
<li>
In a [=rule=] in front of a [=condition=] to negate it. A rule with a negated [=condition=] !|cond| applies if and only if |cond| does not hold true.
<aside class="example" title="Negate a rule condition">
<pre class="chk"># Rule with a negated condition
rule {
@condition !c1
@action a1
}
person c1 { @id John }
console a1 { @do log; message "Type is not person or id is not John" }
# Same rule defined using the compact format
!person { @id John }
=> console { @do log; message "Type is not person or id is not John" }</pre>
<p>The above example illustrates two equivalent ways to define a rule with a negated condition. In this example, the condition |c1| [=matches=] a [=chunk=] whose [=type=] is <code>person</code> and whose [=identifier=] is <code>John</code>. As such, the negated condition [=matches=] a [=chunk=] whose [=type=] is <em>not</em> <code>person</code> <em>or</em> whose [=identifier=] is <em>not</em> <code>John</code>.</p>
</aside>
</li>
<li>
In a [=condition=] in front of a [=property=] value to negate the result of a [=match=]. A negated [=property=] value !|val1| [=equals=] another [=property=] value |val2| if and only if |val1| does not [=equal=] |val2|.
<aside class="example" title="Negate a value match">
<pre class="chk">person { @id !John }
=> console { @do log; message "Type is person but id is not John" }</pre>
<p>The above [=condition=] [=matches=] a [=chunk=] whose [=type=] is <code>person</code> and whose [=identifier=] is <em>not</em> <code>John</code>.</p>
</aside>
<aside class="example" title="Negate an atomic value in a list">
<pre class="chk">basket { fruit ?a, !banana, ?o }
=> console { @do log; message "No banana in second position" }</pre>
<p>The above [=condition=] [=matches=] a [=chunk=] whose [=type=] is <code>basket</code> and which has a <code>fruit</code> [=property=] whose [=value=] is a list of three [=atomic values=]. First and third [=atomic values=] in that list can be anything. Second [=atomic value=] must <em>not</em> be <code>banana</code>.</p>
</aside>
</li>
<li>
On its own as a [=property=] value in a [=condition=] to test that a [=property=] is undefined. A [=condition=] with a [=property=] |p| whose value is <code>!</code> [=matches=] a [=chunk=] if and only if the [=chunk=] does not have a [=property=] whose [=name=] is |p|'s [=name=].
<aside class="example" title="Test that a property is undefined">
<pre class="chk">basket { fruit ! }
=> console { @do log; message "Basket without fruits" }</pre>
<p>The above [=condition=] [=matches=] a [=chunk=] whose [=type=] is <code>basket</code> and which does not have a <code>fruit</code> [=property=].</p>
</aside>
</li>
<li>
On its own as a [=property=] value in a [=@do patch=], [=@do update=] or similar [=action=] that updates a [=chunk=] to unset a [=property=].
<aside class="example" title="Unset a chunk property">
<pre class="chk"># Given the following chunk in the module buffer
basket { fruit apple, banana, orange }
# ... the following rule drops the fruit property
* {} => basket { @do update; fruit ! }
# Resulting chunk
basket {}</pre>
</aside>
</li>
</ul>
<p>The [=negation operator=] cannot be prepended to a [=variable=] that has not yet been [=bound=]. Similarly, the [=negation operator=] cannot be used on its own as an [=atomic value=] in a list. More generally, the [=negation operator=] cannot be used elsewhere than in the cases detailed above.</p>
<aside class="example" title="Some invalid uses of the negation operator">
<pre class="chk"># Invalid: variable ?num1 is unbound
count { state counting; start !?num1 } => ...
# Invalid: on its own in a list
basket { fruit ?a, !, ?o } => ...
# Invalid: in an update action but not on its own
* {} => basket { @do update; fruit !apple }</pre>
</aside>
<p>A second [=negation operator=] prepended to a [=name=] that starts with a [=negation operator=] cancels the effect of the first [=negation operator=].</p>
<aside class="example" title="Double negation">
<pre class="chk"># The following condition
person { @id !!John }
# ... is the same as this one:
person { @id John }</pre>
</aside>
</section>
<section>
<h3>The reserved name operator <code>@</code></h3>
<p>The <dfn class="lint-ignore">reserved name operator</dfn> <code>@</code> may be prepended to a [=name=] to denote a <dfn>reserved name</dfn> with specific meaning. Most [=reserved names=] are to be used as [=property=] names, typically in [=conditions=] and [=actions=] to control their behavior (see [[[#properties-for-conditions-and-actions]]]). Some of them may be used as chunk [=types=] to denote a chunk with specific meaning (see [[[#mapping-to-rdf]]]).</p>
</section>
</section>
<section>
<h2>Rule engine execution</h2>
<p>The rule engine is invoked whenever any of the module buffers are changed, including when [=queue=] is popped. It then searches for rules whose conditions match the current state of the buffers. If a rule has multiple conditions, they must all match the current state of the buffers. If there are multiple matching rules, a stochastic process is applied to select which one to execute. This process is based upon the activation of the rule's root chunk, i.e. the chunk with [=@condition=] and [=@action=]. The higher the activation, the more likely the rule will be selected. See Section [[[#mimicking-human-memory]]].</p>
<p>Executing a rule is a process in which the sequence of actions are applied in the same order that they appear in the rule. Actions are for the most part asynchronous with a few exceptions, see Section [[[#rules]]]. Implementations may index module buffers to speed the process of matching rule conditions to the buffers. One such approach involves a discrimination network akin to Charles Forgy's [[Rete Match Algorithm]].</p>
<p class="issue">Need to define requirements for how the rule engine supports reinforcement learning.</p>
</section>
<section>
<h2>Chunks documents</h2>
<section>
<h3>Parsing a chunks document</h3>
<p>Chunk documents are parsed one chunk at a time in document order, and asserted to the [=graph of chunks=] for the given module, see Section [[[#scripting-api]]]. If multiple chunk definitions share the same [=identifier=] in a set of chunks, the last definition overrides former definitions.</p>
</section>
<section>
<h3>Chunks grammar</h3>
<p>A [=chunks document=] MUST follow the grammar defined below.</p>
<pre class="chk"><code class="abnf" data-include="grammar/chunks.abnf" data-include-format="text"></code></pre>
</section>
<section class="informative">
<h3>Railroad diagrams</h3>
<p>This section presents an informative view of the tokens that the grammar defines, in the form of railroad diagrams. These diagrams are provided solely to make it easier to get an intuitive grasp of the syntax of each token.</p>
<div data-include="grammar/rr.html" data-include-replace="true"></div>
</section>
</section>
<section>
<h2>Mapping to RDF</h2>
<p>Linked Data [[LINKED-DATA]], at the basis of RDF [[RDF11-CONCEPTS]], is a way to create a network of standards-based machine interpretable data across different documents and Web sites. It allows an application to start at one piece of Linked Data, and follow embedded links to other pieces of Linked Data that are hosted on different sites across the Web.
<p>[=Names=] used in [=chunks=] are local to the [=graph of chunks=] in which they appear. For [=names=] to be usable as linked data, there needs to be a way to associate them to global identifiers. [=Reserved names=] defined in this section may be used to create such a mapping.</p>
<p>In turn, this mechanism can be used to map a [=graph of chunks=] to an <a data-cite="RDF11-CONCEPTS#dfn-rdf-graph">RDF graph</a> and vice versa.</p>
<p class="note">Algorithms to serialize/deserialize a [=graph of chunks=] to an <a data-cite="RDF11-CONCEPTS#dfn-rdf-graph">RDF graph</a> and vice versa are out of scope of this document but may be specified in future revisions of it.</p>
<aside class="example" title="Mapping a graph of chunks to an RDF graph">
<p>Given the following [=graph of chunks=]:</p>
<pre class="chk">@rdfmap {
dog http://example.com/ns/dog
cat http://example.com/ns/cat
age http://example.com/ns/age
name http://example.com/ns/name
}
dog { name "Youki"; age 5 }
cat { name "Isidore"; age 3 }</pre>
<p>The [=@rdfmap=] [=chunk=] creates a mapping between local names and a URL. This [=graph of chunks=] is equivalent to the following <a data-cite="RDF11-CONCEPTS#dfn-rdf-graph">RDF graph</a> expressed in Turtle [[TURTLE]]:</p>
<pre class="chk"><code><http://example.org/ns/dog>
<http://example.org/ns/name> "Youki";
<http://example.org/ns/age> 5.
<http://example.org/ns/cat>
<http://example.org/ns/name> "Isidore";
<http://example.org/ns/age> 3.</code></pre>
</aside>
<section>
<h3>The <dfn><code>@rdfmap</code></dfn> type</h3>
<p>The [=@rdfmap=] chunk [=type=] identifies a chunk that defines a mapping between [=names=] and <abbr title="Internationalized Resource Identifiers">IRIs</abbr> [[IRI]]. Each [=property=] it defines whose [=name=] does not start with one of the name operators (see [[[#name-operators]]]) creates a mapping between this [=name=] and the property [=value=], interpreted as an <abbr title="Internationalized Resource Identifier">IRI</abbr>.</p>
<aside class="example" title="Mapping a name to the schema.org vocabulary">
<pre class="chk"># Maps the name "thing" to the "Thing" item type in schema.org
@rdfmap {
thing http://schema.org/Thing
}</pre>
</aside>
<p class="note">The [=@rdfmap=] keyword plays the same role in [=chunks=] as the <code>@context</code> keyword in JSON-LD. See the notion of <a data-cite="JSON-LD#the-context">Context in JSON-LD</a> for details [[JSON-LD]]. The term [=context=] and the [=@context=] keyword have a different meaning in [=chunks=] where they identify the specific situation under which a [=chunk=] should be considered to be true. A distinct [=@rdfmap=] keyword is used here to avoid any confusion.</p>
<p>If multiple [=@rdfmap=] chunks create a mapping for the same [=name=], the last definition in overrides previous ones.</p>
<aside class="example" title="Conflicting mapping">
<pre class="chk"># Creates a mapping from image to the example.org namespace
@rdfmap { image http://example.org/ns/image }
# "image" gets mapped to http://schema.org/image
# due to the second mapping definition below that
# overrides the initial mapping defined above.
thing { image img1 }
# New mapping definition for image, overrides former one
@rdfmap { image http://schema.org/image }</pre>
</aside>
<p>An [=@rdfmap=] chunk may also contain a [=@base=] property to create a default <abbr title="Internationalized Resource Identifier">IRI</abbr> namespace for [=names=] and [=@prefix=] properties to define prefixes for compact <abbr title="Internationalized Resource Identifiers">IRIs</abbr>.</p>
</section>
<section>
<h3>The <dfn><code>@base</code></dfn> property</h3>
<p>The [=@base=] [=property=] defines a default <abbr title="Internationalized Resource Identifier">IRI</abbr> namespace for [=names=] that are not explicitly declared in an [=@rdfmap=].</p>
<aside class="example" title="Define a default IRI namespace">
<pre class="chk">@rdfmap {
@base http://schema.org/
dog http://example.org/ns/dog
}
dog { name "Youki"; birthDate 2021-07-09 }</pre>
<p>In this example, the [=@rdfmap=] chunk maps:</p>