operator: explain
description:
explain[op] seq
given a cause structure, and an input sequence, find the possible cause
See here for why we would want to do this:
Parsimonious Covering Theory with Causal Chaining and Ordering Constraints:
https://github.com/garrettkatz/copct
examples:
-- given this knowledge:
cause |c> => |a> . |b>
cause |d> => |a> . |b>
cause |e> => |d> . |f>
-- given this sequence: |a> . |b> . |f> . |a> . |b>
-- find possible causes:
-- note that even though it prints them all out, it only returns the shortest sequence:
explain[cause] ssplit |abfab>
e . c
e . d
e . a . b
c . f . c
c . f . d
d . f . c
d . f . d
c . f . a . b
a . b . f . c
a . b . f . d
d . f . a . b
a . b . f . a . b
|e> . |c>
-- let's verify a couple of these:
-- NB: we don't use the ssplit operator to make it clear the input is really a sequence, not a string:
sexp[cause] (|e> . |c>)
|a> . |b> . |f> . |a> . |b>
sexp[cause] (|c> . |f> . |d>)
|a> . |b> . |f> . |a> . |b>
-- given this knowledge:
cause |p> => |g> . |m> . |r>
cause |t> => |p> . |p>
cause |x> => |p> . |g>
cause |z> => |r> . |p>
-- find possible causes for: |g> . |m> . |r> . |g> . |m> . |r>
explain[cause] ssplit[" . "] |g . m . r . g . m . r>
t
p . p
g . m . z
x . m . r
g . m . r . p
p . g . m . r
g . m . r . g . m . r
-- learn some knowledge about food:
-- see breakfast-menu.sw
seq |food: waffles> => |word: waffles>
seq |country: Belgium> => |word: belgian>
seq |food: strawberries> => |word: strawberries>
seq |food: berries> => |word: berries>
seq |country: France> => |word: french>
seq |food: toast> => |word: toast>
seq |meal: breakfast> => |word: breakfast>
seq |food: egg> => |word: egg>
seq |food: eggs> => |word: eggs>
seq |food: bacon> => |word: bacon>
seq |food: sausage> => |word: sausage>
seq |food: sausages> => |word: sausages>
seq |number: 2> => |word: two>
seq |food: cream> => |word: cream>
seq |food: belgian waffles> => |word: belgian> . |word: waffles>
seq |food: maple syrup> => |word: maple> . |word: syrup>
seq |food: whipped cream> => |word: whipped> . |word: cream>
seq |food: hash browns> => |word: hash> . |word: browns>
-- define our read operator:
apply-word |*> #=> |word:> __ |_self>
read |*> #=> apply-word ssplit[" "] replace[",", ""] remove-suffix[1] remove-prefix[1] remove-prefix["text: "] to-lower |_self>
-- test it out:
read |text: "Two eggs, bacon or sausage">
|word: two> . |word: eggs> . |word: bacon> . |word: or> . |word: sausage>
-- now use our explain[seq] operator:
explain[seq] read |text: "Two eggs, bacon or sausage">
|number: 2> . |food: eggs> . |food: bacon> . |word: or> . |food: sausage>
-- now a couple of bigger examples:
explain[seq] read |text: "Two eggs, bacon or sausage, toast, and our ever-popular hash browns">
|number: 2> . |food: eggs> . |food: bacon> . |word: or> . |food: sausage> . |food: toast> . |word: and> . |word: our> . |word: ever-popular> . |food: hash browns>
explain[seq] read |text: "Light Belgian waffles covered with strawberries and whipped cream">
|word: light> . |food: belgian waffles> . |word: covered> . |word: with> . |food: strawberries> . |word: and> . |food: whipped cream>
-- learn a different set of knowledge:
-- see cause3.sw
pattern |node: 1: 1> => |fred>
pattern |node: 1: 2> => |freddie>
pattern |node: 1: 3> => |smith>
pattern |node: 1: 4> => |smithie>
pattern |node: 1: 5> => |fred> . |smith>
then |node: 1: *> => |person: Fred Smith>
pattern |node: 2: 1> => |mazza>
then |node: 2: *> => |person: Mary>
pattern |node: 3: 1> => |hey>
then |node: 3: *> => |greeting: Hey!>
pattern |node: 4: 1> => |what's>
pattern |node: 4: 2> => |what> . |is>
then |node: 4: *> => |question: what is>
pattern |node: 5: 1> => |up>
then |node: 5: *> => |direction: up>
pattern |node: 6: 1> => |having> . |a> . |baby>
then |node: 6: *> => |phrase: having a baby>
pattern |node: 7: 1> => |in> . |the> . |family> . |way>
then |node: 7: *> => |phrase: in the family way>
pattern |node: 8: 1> => |up> . |the> . |duff>
then |node: 8: *> => |phrase: up the duff>
pattern |node: 9: 1> => |with> . |child>
then |node: 9: *> => |phrase: with child>
pattern |node: 10: 1> => |phrase: having a baby>
pattern |node: 10: 2> => |phrase: in the family way>
pattern |node: 10: 3> => |phrase: up the duff>
pattern |node: 10: 4> => |phrase: with child>
then |node: 10: *> => |concept: pregnancy>
-- our 'read' operator:
read |*> #=> ssplit[" "] replace[",?", ""] to-lower |_self>
-- if 'then' is not defined for a ket, then return itself:
then |*> #=> |_self>
-- now a quick test of our read operator:
-- yeah, we don't use apply-word this time.
read |Hey Freddie what's up?>
|hey> . |freddie> . |what's> . |up>
-- now 'explain':
explain[pattern] read |Hey Freddie what's up?>
|node: 3: 1> . |node: 1: 2> . |node: 4: 1> . |node: 5: 1>
-- now apply the 'then' operator, that maps nodes to concepts:
then explain[pattern] read |Hey Freddie what's up?>
|greeting: Hey!> . |person: Fred Smith> . |question: what is> . |direction: up>
-- another example:
then explain[pattern] read |Hey Mazza, you with child, up the duff, in the family way, having a baby?>
|greeting: Hey!> . |person: Mary> . |you> . |phrase: with child> . |phrase: up the duff> . |phrase: in the family way> . |phrase: having a baby>
-- then another layer of 'then explain[pattern]':
then explain[pattern] then explain[pattern] read |Hey Mazza, you with child, up the duff, in the family way, having a baby?>
|greeting: Hey!> . |person: Mary> . |you> . |concept: pregnancy> . |concept: pregnancy> . |concept: pregnancy> . |concept: pregnancy>
-- further, we could wrap 'then explain[pattern]' into a new operator:
explain (*) #=> then explain[pattern] |_self>
explain read |Hey Freddie what is up?>
explain read |Hey Mazza, you with child, up the duff, in the family way, having a baby?>
explain^2 read |Hey Mazza, you with child, up the duff, in the family way, having a baby?>
see also:
sexp, cause1.sw, cause2.sw, cause3.sw, breakfast-menu.sw, active-buffer
future:
an example with depth > 2.
Home