-
Notifications
You must be signed in to change notification settings - Fork 235
/
filter.scm
362 lines (340 loc) · 11.4 KB
/
filter.scm
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
;
; filter.scm -- Using FilterLink to extract and rewrite.
;
; The FilterLink implements a link type analogous to the `filter-map`
; function commonly found in functional programming languages, such as
; the scheme srfi-1 `filter-map`, or `map` in haskell.
;
; In many ways, FilterLink is similar to BindLink, except that FilterLink
; does not search the entire AtomSpace for matching patterns; rather,
; it only examines the given input list/set, and applies the map to
; that.
;
; In many ways, FilterLink is the opposite of PutLink, in that it un-does
; a beta reduction, by extracting values from a matching pattern. Thus,
; FilterLink could have been named UnPutLink, CoPutLink or ExtractLink or
; UnBetaReduceLink. That is, FilterLink is an adjoint functor to PutLink.
;
; These ideas are illustrated below. The first 4 examples illustrate
; the extraction of values for a single variable; this is, of un-beta-
; reducing a single composition. This includes a demonstration of
; type checking, which can be used to implement filtering. The next
; few examples show how multi-variable extraction works, as a straight-
; forward extension of the single-variable case. The final examples
; illustrate actual "mapping", that is, graph re-writing or graph
; transformation as a result of applying a mapping function.
;
(use-modules (opencog) (opencog exec))
(define single
(Filter
; Define a pattern that will be used to extract a value
; from a pattern. The extracted value will correspond to
; the place-holder variable $x.
(Lambda
(Variable "$x")
(Evaluation
(Predicate "foo")
(List (Concept "bar") (Variable "$x"))))
; The graph from which a value is to be extracted. Clearly,
; the variable $x corresponds to Concept "baz"
(Evaluation
(Predicate "foo")
(List (Concept "bar") (Concept "baz"))))
)
; This should return (Concept "baz") as that is the extracted value
; for the variable $x.
(cog-execute! single)
(define single-set
(Filter
; The same pattern as above. Extracts values for variable $x.
(Lambda
(Variable "$x")
(Evaluation
(Predicate "foo")
(List (Concept "bar") (Variable "$x"))))
(Set
; A set of graphs to which the above pattern should
; be matched.
(Evaluation
(Predicate "foo")
(List (Concept "bar") (Number 3)))
(Evaluation
(Predicate "foo")
(List (Concept "bar") (Concept "ah two")))
(Evaluation
(Predicate "foo")
(List (Concept "bar") (Concept "ah one")))
))
)
; This should return
; (SetLink (Concept "ah one") (Concept "ah two") (Number 3))
; since these are the three values that correspond to the variable $x.
; Note that SetLinks are unordered links, and so the members of the
; set may be returned in a different order than in which they were
; specified as inputs.
(cog-execute! single-set)
; This example is like the above, except that a ListLink instead of
; a SetLink is used. The ListLink is an ordered link; the ordering
; of the list is preserved by the mapping.
(define single-list
(Filter
(Lambda
(Variable "$x")
(Evaluation
(Predicate "foo")
(List (Concept "bar") (Variable "$x"))))
(List
(Evaluation
(Predicate "foo")
(List (Concept "bar") (Concept "ah one")))
(Evaluation
(Predicate "foo")
(List (Concept "bar") (Number 3)))
(Evaluation
(Predicate "foo")
(List (Concept "bar") (Concept "ah two")))
))
)
; This should return
; (List (Concept "ah one") (Number 3) (Concept "ah two"))
; Note that the sequential order of the original list is preserved.
(cog-execute! single-list)
; Same as above, except that a type constraint is applied.
; This causes the input to be filtered, so that any graphs
; that don't match the type are discarded.
(define single-type
(Filter
(Lambda
; The type of the variable MUST be ConceptNode!!
(TypedVariable (Variable "$x") (Type "ConceptNode"))
(Evaluation
(Predicate "foo")
(List (Concept "bar") (Variable "$x"))))
(Set
; A set of graphs to which the above pattern should be
; applied. Note that, due to the type constraint, only
; two of the three can match. (Numbers not being Concepts)
(Evaluation
(Predicate "foo")
(List (Concept "bar") (Concept "ah one")))
(Evaluation
(Predicate "foo")
(List (Concept "bar") (Concept "ah two")))
(Evaluation
(Predicate "foo")
(List (Concept "bar") (Number 3)))
))
)
; The expected return value is
; (SetLink (ConceptNode "ah one") (ConceptNode "ah two"))
; Note that the NumberNode is no longer included in the result
; of the map.
(cog-execute! single-type)
; The type checking that can be performed during mapping can be
; quite sophisticated. In this example, a single variable $x is
; used to match *every* element in the input set. However, since
; the variable $x is typed to have a very specific form, some of
; the input set is rejected, as it does not match that type.
;
; This implements a kind of filtering, by returning a subset of
; the original input set, and discarding those values that don't
; match the desired type. A similar kind of filtering can be done
; using PutLink; see the `filter.scm` example for more.
;
(define single-signature
(Filter
(Lambda
; The variable $x must be an evaluation of a certain form!
(TypedVariable (Variable "$x")
(Signature
(Evaluation
(Predicate "foo")
(List (Concept "bar") (Type "ConceptNode")))))
(Variable "$x"))
(Set
; Of the three elements in this set, only two have the type
; that is specified above.
(Evaluation
(Predicate "foo")
(List (Concept "bar") (Concept "ah one")))
(Evaluation
(Predicate "foo")
(List (Concept "bar") (Concept "ah two")))
(Evaluation
(Predicate "foo")
(List (Concept "bar") (Number 3)))
))
)
; Executing this will filter the input set down to just two members.
; The return value should be this:
; (SetLink
; (EvaluationLink
; (Predicate "foo")
; (ListLink (Concept "bar") (Concept "ah one")))
; (EvaluationLink
; (Predicate "foo")
; (ListLink (Concept "bar") (Concept "ah two")))
; )
;
(cog-execute! single-signature)
; All of the previous examples demonstrated matching to a single
; variable. The below demonstrates matching to two variables, one of
; which is typed to be a concept, and the other a number.
(define double-num-set
(Filter
(Lambda
; Two variables, $x and $y, both typed.
(VariableList
(TypedVariable (Variable "$x") (Type "ConceptNode"))
(TypedVariable (Variable "$y") (Type "NumberNode")))
(Evaluation
(Predicate "foo")
(List (Variable "$x") (Variable "$y"))))
(Set
; Same input as always.
(Evaluation
(Predicate "foo")
(List (Concept "bar") (Concept "ah one")))
(Evaluation
(Predicate "foo")
(List (Concept "bar") (Concept "ah two")))
(Evaluation
(Predicate "foo")
(List (Concept "bar") (Number 3)))
))
)
; Extract values for both of the variables. The expected answer is:
;
; (SetLink
; (ListLink (Concept "bar") (Number 3)))
;
; There are four note-worthy things to observe about this answer:
; First, the outermost link is a SetLink; this corresponds to the fact
; that the input to the map was a SetLink. Next, we observe a single
; element in the set, because only one element of the input matched.
; That single element then specifies the values for the two variables.
; The variable values are ordered, in a ListLink, because we need to
; know which value corresponded to $x and which to $y (the first and
; the second, of course). Without the ListLink, we would not know which
; was which.
;
(cog-execute! double-num-set)
; Same as above, except the variables are typed differently, and
; sometimes, we expect two answers, not one.
(define double-con-set
(Filter
(Lambda
(VariableList
(TypedVariable (Variable "$x") (Type "ConceptNode"))
(TypedVariable (Variable "$y") (Type "ConceptNode")))
(Evaluation
(Predicate "foo")
(List (Variable "$x") (Variable "$y"))))
(Set
(Evaluation
(Predicate "foo")
(List (Concept "bar") (Concept "ah one")))
(Evaluation
(Predicate "foo")
(List (Concept "bar") (Concept "ah two")))
(Evaluation
(Predicate "foo")
(List (Concept "bar") (Number 3)))
))
)
; Much like the example previous, except that there are now two elements
; in the returned set (due to filtering on the types):
;
; (SetLink
; (ListLink (Concept "bar") (Concept "ah one"))
; (ListLink (Concept "bar") (Concept "ah two")))
;
(cog-execute! double-con-set)
; Finally, an example that shows actual mapping taking place!
; This is a variant of the example immediately above, except that,
; this time, instead of returning two values for two variables,
; the values are used in an RuleLink, to perform a graph
; rewrite. That is, an RuleLink is a function P(x)->Q(x),
; so that, if P(x) matches the input P(v), then Q(v) is returned
; (with the value `v` substituted for the variable `x` in Q(x)).
; Actually, this example uses two variables, so the implication
; link is in the form of P(x,y)->Q(x,y) and inputs P(a,b) are
; re-written to Q(a,b).
;
; Observe that the re-writing could also be achieved by combining
; the results of the FilterLink with a PutLink. The form below is
; slightly less verbose, and thus, maybe more convenient than
; using Filter and Put together.
;
(define imply-map
(Filter
; The Rule is the "map" that will be applied.
(Rule
; The implication has two variables in it, both typed.
(VariableList
(TypedVariable (Variable "$x") (Type "ConceptNode"))
(TypedVariable (Variable "$y") (Type "ConceptNode")))
; The P(x,y) part of the implication.
(Evaluation
(Predicate "foo")
(List (Variable "$x") (Variable "$y")))
; The Q(x,y) part of the implication.
(Evaluation
(Predicate "reverse-foo")
(List (Variable "$y") (Variable "$x"))))
(Set
(Evaluation
(Predicate "foo")
(List (Concept "bar") (Concept "ah one")))
(Evaluation
(Predicate "foo")
(List (Concept "bar") (Concept "ah two")))
(Evaluation
(Predicate "foo")
(List (Concept "bar") (Number 3)))
))
)
; Executing the implication P(x,y)->Q(x,y) on P(a,b) should return
; Q(a,b). In this example, P is `foo` and Q(x,y) is `reverse-foo(y,x)`
; i.e. the order of the arguments is switched. The expected result is:
;
; (SetLink
; (EvaluationLink
; (PredicateNode "reverse-foo")
; (ListLink (ConceptNode "ah one") (ConceptNode "bar")))
; (EvaluationLink
; (PredicateNode "reverse-foo")
; (ListLink (ConceptNode "ah two") (ConceptNode "bar")))
; )
;
(cog-execute! imply-map)
(define summation
(Filter
(Rule
(VariableList
(TypedVariable (Variable "$x") (Type "NumberNode"))
(TypedVariable (Variable "$y") (Type "NumberNode")))
(Evaluation
(Predicate "foo")
(List (Variable "$x") (Variable "$y")))
(Plus (Variable "$y") (Variable "$x")))
(Set
(Evaluation
(Predicate "foo")
(List (Concept "bar") (Concept "ah one")))
(Evaluation
(Predicate "foo")
(List (Number 2) (Number 3)))
(Evaluation
(Predicate "foo")
(List (Number 10) (Times (Number 3) (Number 2))))
))
)
; This example is currently broken, because lazy evaluation does not
; work!
(cog-execute! summation)
; Another (as yet unimplemented) design choice would be to use
; AccumulateLink. But this also is currently unsupported (because
; its not clear if Accumulate should act in parallel on Link contents,
; or if it should accumulate everything in the Link.)
; (cog-execute! (Accumulate summation))