Wednesday, 3 December 2014

random greetings in BKO

This time, an example of random greetings. Makes use of general rules, stored rules, merge-labels(), the self ket and pick-elt.

Let's define our greetings:
|context> => |context: greetings play>

hello |*> #=> merge-labels(|Hello, > + |_self> + |!>)
hey |*> #=> merge-labels(|Hey Ho! > + |_self> + |.>)
wat-up |*> #=> merge-labels (|Wat up my homie! > + |_self> + | right?>)
greetings |*> #=> merge-labels(|Greetings fine Sir. I believe they call you > + |_self> + |.>)
howdy |*> => |Howdy partner!>
good-morning |*> #=> merge-labels(|Good morning > + |_self> + |.>)
gday |*> #=> merge-labels(|G'day > + |_self> + |.>)
random-greet |*> #=> pick-elt ( hello |_self> + hey |_self> + wat-up |_self> + greetings |_self> + howdy |_self> + good-morning |_self> + gday |_self>)
Now, let's put it to use:
sa: random-greet |Fred>
|Greetings fine Sir. I believe they call you Fred.>

sa: random-greet |John>
|Good morning John.>

sa: random-greet |Emma>
|Hello, Emma!>

-- define who we are talking with:
sa: |you> => |Tim>
-- greet them:
sa: random-greet "" |you>
|G'day Tim.>
Next, with a little work, we can greet a list of people.
-- define this beasty first:
sa: friends-list |*> #=> extract-value list-to-words friends |_self>

-- define some friends:
sa: friends |Sam> => |Charlie> + |George> + |Emma> + |Jack> + |Robert> + |Frank> + |Julie>
sa: friends |Emma> => |Liz> + |Bob>

-- check the output of the friends-list operator:
sa: friends-list |Sam>
|Charlie, George, Emma, Jack, Robert, Frank and Julie>

sa: friends-list |Emma>
|Liz and Bob>
-- notice that "list-to-words" has converted a superposition of names into an English like list of names.
-- eg: 
sa: list-to-words (|a> + |b> + |c> + |d>)
|text: a, b, c and d>

-- now, let's greet them:
sa: random-greet friends-list |Emma>
|Wat up my homie! Liz and Bob right?>

sa: random-greet friends-list |Sam>
|G'day Charlie, George, Emma, Jack, Robert, Frank and Julie.>
Anyway, I think that is cool! More to come. Also, a lol at the vast amount of debugging noise this generates! An addition: the above is a good reason why merge-labels() should be built into the parser. One idea is to introduce the _ character to represent merge-labels():
hello |*> #=> |Hello, > _ |_self> _ |!>
hey |*> #=> |Hey Ho! > _ |_self> _ |.>
wat-up |*> #=> |Wat up my homie! > _ |_self> _ | right?>
greetings |*> #=> |Greetings fine Sir. I believe they call you > _ |_self> _ |.>
howdy |*> => |Howdy partner!>
good-morning |*> #=> |Good morning > _ |_self> _ |.>
gday |*> #=> |G'day > _ |_self> _ |.>
This is much cleaner than the merge-labels() version! Indeed, there are other possibilities. I haven't given it much thought yet.
eg: something like this perhaps:
hello |*> #=> insert-self |Hello, ${_self}!>
And then plurals would look like:
plural |word: *> #=> insert-self |${_self}s>
Anyway, some thinking to do.
Update: I'm thinking of going for something like this:
hey |*> #=> insert[|_self>] |Hey ${1}!>
hello-fred-and |*> #=> insert[|Fred>,|_self>] |Hey ${1} and ${2}! How is it going?>
A couple of notes:
1) Everywhere else in the project my numbers start from 1 not the comp-sci convention of 0. So it would break that convention if I used ${0} and ${1} here.
2) The current parser can't handle an operator like insert[] with ket parameters. On the long to-do list!

Update: Wrote an improved version of random-greet. This time the list of greet operators has been separated out. Key changes are these two lines:
|greet list> => |op: hello> + |op: hey> + |op: wat-up> + |op: greetings> + |op: howdy> + |op: good-morning> + |op: gday>
random-greet |*> #=> apply(pick-elt "" |greet list>,|_self>) 
This change has a couple of advantages:
1) we can dynamically change our list of greetings without having to redefine the random-greet operator, instead we now redefine |greet list>. I think this is an improvement.
2) the old version calculated the greetings in full, and then picked from the results. In the new method only the chosen greeting is calculated. So in this case, not a super big win, but if we use a similar technique on a larger example, then it will be a win.

introducing pick-elt

So, we are slowly trying to work towards what humans do. eg, the plurals, the easy definition of close relatives and so on. Today, random greetings. Makes use of merge-labels() and pick-elt. First, let's introduce pick-elt.

The definition of pick-elt is simply, given a superposition randomly return a ket in that superposition. Currently it is unweighted. ie, there is no bias in choice of ket. It is probably useful later to define a weighted pick-elt.

Anyway, a pick-elt example:

sa: pick-elt (|a> + |b> + |c> + |d> + |e> + |f> + |g> + |h>)
|e>
where dot "." in the console means repeat last computation.
sa: .
|a>

sa: .
|c>

sa: .
|h>

sa: .
|g>

So that should be clear enough. Each time it randomly picks kets.

I guess I should also note that it preserves coeffs:
sa: pick-elt (10|a> + 3.141592|pi> + |fred> + 7|cats>)
7.000|cats>
sa: .
7.000|cats>
sa: .
10.000|a>
sa: .
7.000|cats>
sa: .
3.142|pi>

And I suppose you could say pick-elt has a little similarity with the idea of wave-function collapse in QM. Just a little. Indeed, for the QM case you would need a weighted-pick-elt.
eg, Schrodinger's cat in BKO might look like:
sa: is-alive |cat> #=> normalize pick-elt (0.5|yes> + 0.5|no>)
-- ask if the cat is alive?
sa: is-alive |cat>
|no>
sa: .
|no>
sa: .
|yes>

where "normalize" sets the sum of the coeffs of the superposition it is applied to to 1.
eg:
sa: normalize (3|a> + 10|b> + |c>)
0.214|a> + 0.714|b> + 0.071|c>

And that's about it for pick-elt. Very useful all over the place.

Tuesday, 2 December 2014

learning plurals in BKO

Now, between general rules, stored rules, the self ket, and merge-labels() we can now give an example of learning plurals.
-- before we have defined anything:
sa: plural |word: cat>
|>
-- recall in English |> means "I don't know anything about that".

-- define a general rule:
sa: plural |word: *> #=> merge-labels(|_self> + |s>)

-- test it:
sa: plural |word: cat>
|word: cats>

sa: plural |word: dog>
|word: dogs>

-- ok. But what about the irregular forms?
sa: plural |word: mouse>
|word: mouses>

sa: plural |word: foot>
|word: foots>

-- ok. we have a general rule, now define specific rules:
-- learn mouse specific rule:
sa: plural |word: mouse> => |word: mice>

-- learn foot specific rule:
sa: plural |word: foot> => |word: feet>

-- now, try again:
sa: plural |word: mouse>
|word: mice>

sa: plural |word: foot>
|word: feet>
And of course, we can define plurals for other words too.
eg, I suppose:
sa: plural |word: radius> => |word: radii>
Now again. Knowledge representation comes with the idea that there are multiple representations for the same knowledge.
Here we give the matrix representation of the above:
sa: matrix[plural]
[ word: *s    ] = [  1.00  0     0     0     ] [ word: *      ]
[ word: feet  ]   [  0     1.00  0     0     ] [ word: foot   ]
[ word: mice  ]   [  0     0     1.00  0     ] [ word: mouse  ]
[ word: radii ]   [  0     0     0     1.00  ] [ word: radius ]
I guess that is it for now.

the merge-labels() function

Now, so far virtually all of the operators have been literal operators. The only two non-literal operators I have used are "pick-elt" and "apply()".
Today, briefly mention merge-labels().

Does pretty much what it says:
sa: merge-labels(|a> + |b> + |c>)
|abc>
ie, it merges the labels of the kets in the superposition into one ket.
Simple, but turns out to be relatively useful.

There is a hidden problem though!
Kets in superpositions add, so for example:
sa: merge-labels(|a> + |b> + |c> + |a> + |a>)
|abc>
When you might legitimately expect |abcaa>.

We can't currently solve this, but I'm thinking of promoting merge-labels to a built in feature of the parser.
Maybe using _ to separate kets.
eg, something like:
sa: |a> _ |b> _  |c> _ |a> _ |a>
returning:
|abcaa>
That would certainly be much cleaner than the current notation, and solve the superposition bug.

That's it for now. One use of merge-label() in the next post!

the methanol molecule in sw format

Relatively short one this time. Just representing a molecule in sw format. Here, methanol, but the idea should generalize to other molecules easily enough. This is just an example representation. There are probably better ones, depending on what you are trying to do.

|context> => |context: methanol>

molecular-pieces |molecule: methanol> => |methanol: 1> + |methanol: 2> + |methanol: 3> + |methanol: 4> + |methanol: 5> + |methanol: 6>

atom-type |methanol: 1> => |atom: H>
bonds-to |methanol: 1> => |methanol: 4>

atom-type |methanol: 2> => |atom: H>
bonds-to |methanol: 2> => |methanol: 4>

atom-type |methanol: 3> => |atom: H>
bonds-to |methanol: 3> => |methanol: 4>

atom-type |methanol: 4> => |atom: C>
bonds-to |methanol: 4> => |methanol: 1> + |methanol: 2> + |methanol: 3> + |methanol: 5>

atom-type |methanol: 5> => |atom: O>
bonds-to |methanol: 5> => |methanol: 4> + |methanol: 6>

atom-type |methanol: 6> => |atom: H>
bonds-to |methanol: 6> => |methanol: 5>
Not much to say, really. I guess a mildly interesting observation is we can auto-count the atom types:
sa: load methanol.sw
sa: atom-type molecular-pieces |molecule: methanol>
4|atom: H> + |atom: C> + |atom: O>
That's it for now!

Update: now with the magic of tables:
sa: load methanol.sw
sa: table[piece,atom-type,bonds-to] molecular-pieces |molecule: methanol>
+-------+-----------+------------+
| piece | atom-type | bonds-to   |
+-------+-----------+------------+
| 1     | H         | 4          |
| 2     | H         | 4          |
| 3     | H         | 4          |
| 4     | C         | 1, 2, 3, 5 |
| 5     | O         | 4, 6       |
| 6     | H         | 5          |
+-------+-----------+------------+
Pretty!

some general people rules

OK. Now we have |_self>, general rules, and stored rules, we can give this example.
Basically a set of rules that apply to all people. I was going to put it in the George example post, but I think it deserves its own post.

Simply:
-- some general rules that apply to all people:
siblings |person: *> #=> brothers |_self> + sisters |_self>
children |person: *> #=> sons |_self> + daughters |_self>
parents |person: *> #=> mother |_self> + father |_self>
uncles |person: *> #=> brothers parents |_self>
aunts |person: *> #=> sisters parents |_self>
aunts-and-uncles |person: *> #=> siblings parents |_self>
cousins |person: *> #=> children siblings parents |_self>
grand-fathers |person: *> #=> father parents |_self>
grand-mothers |person: *> #=> mother parents |_self>
grand-parents |person: *> #=> parents parents |_self>
grand-children |person: *> #=> children children |_self>
great-grand-parents |person: *> #=> parents parents parents |_self>
great-grand-children |person: *> #=> children children children |_self>
immediate-family |person: *> #=> siblings |_self> + parents |_self> + children |_self>
friends-and-family |person: *> #=> friends |_self> + family |_self>
Let's call the above "general-people-rules.sw" and load it in the console:
(note that we haven't defined context, so it happily loads into your current context -- this is often a useful trick)
sa: load general-people-rules.sw

-- now, let's define some knowledge about Fred:
sa: mother |person: Fred> => |person: Judith>
sa: father |person: Fred> => |person: Frank>
sa: sisters |person: Fred> => |person: Liz> + |person: Emma> + |person: Jane>
OK. So what?
Well, using the general rules, we can now answer who Fred's parents and siblings are:
(without having to specify them manually. mother/father/sisters/brothers is sufficient)
sa: parents |person: Fred>
|person: Judith> + |person: Frank>

sa: siblings |person: Fred>
|person: Liz> + |person: Emma> + |person: Jane>

-- OK. Learn Fred has a brother Jack:
sa: brothers |person: Fred> => |person: Jack>

-- now we know that, ask again who Fred's siblings are:
sa: siblings |person: Fred>
|person: Jack> + |person: Liz> + |person: Emma> + |person: Jane>

-- now, how about Fred's immediate-family?
sa: immediate-family |person: Fred>
|person: Jack> + |person: Liz> + |person: Emma> + |person: Jane> + |person: Judith> + |person: Frank>
Also, a LOL. The console spat out a page of debugging info just to provide that last example. So what I haven't told you is that currently the console is very noisy, and I have been chomping out the debugging info by hand. Eventually when I'm 100% happy with everything I guess I will switch off debugging. Probably also a hint that my code is far more inefficient than it needs to be!

So there you have it!
The self ket, "person: *" general rules, and stored rules, all in one example.
And the "person: *" thing is one reason why categories/data-types are often useful to use. We can define general rules that apply to a category of objects, rather than to all objects.

Also, I guess in other projects, the above might be called "an inference engine". I mean, yeah, sort of. But BKO is in some sense more direct, while most inference engines try to use chains of logic.

More to come!

a fictional George in sw format

Let's define what we know about a fictional character we call George.
Really is quite simple.
|context> => |context: George>
source |context: George> => |sw-url: http://semantic-db.org/sw-examples/new-george.sw>

-- George is just some fictional character

|person: George> => |word: george>
age |person: George> => |age: 29>
dob |person: George> => |date: 1984-05-23>
hair-colour |person: George> => |hair-colour: brown>
eye-colour |person: George> => |eye-colour: blue>
gender |person: George> => |gender: male>
height |person: George> => |height: cm: 176>
wife |person: George> => |person: Beth>
occupation |person: George> => |occupation: car salesman>
friends |person: George> => |person: Fred> + |person: Jane> + |person: Liz> + |person: Andrew>
mother |person: George> => |person: Sarah>
father |person: George> => |person: David>
sisters |person: George> => |person: Emily>
brothers |person: George> => |person: Frank> + |person: Tim> + |person: Sam>
email |person: George> => |email: george.douglas@gmail.com>
education |person: George> => |education: high-school> 
My favourite thing about this example is that it shows we can describe all types of "molecules of knowledge" using 1 line, and all in the format:
OP KET => SUPERPOSITION

One advantage of the 1 line thing is that when we have large sw files, it is trivial to grep down to the rules of interest. I will give an example of that in the future, probably using the IMDB data I have in sw format. Indeed, there is not a single construct in BKO that is multi-line. I think this gives it some power, eg, being able to grep, and easier to parse.

Fine, let's give a simple example:
$ grep "person: Jane" blog-george.sw
friends |person: George> => |person: Fred> + |person: Jane> + |person: Liz> + |person: Andrew>
Now, let's load it up and give the pretty-print display:
sa: load blog-george.sw
sa: display
  context: George

  context: George
  supported-ops: op: source
         source: sw-url: http://semantic-db.org/sw-examples/new-george.sw

  person: George
  supported-ops: op: , op: age, op: dob, op: hair-colour, op: eye-colour, op: gender, op: height, op: wife, op: occupation, op: friends, op: mother, op: father, op: sisters, op: brothers, op: email, op: education
               : word: george
            age: age: 29
            dob: date: 1984-05-23
    hair-colour: hair-colour: brown
     eye-colour: eye-colour: blue
         gender: gender: male
         height: height: cm: 176
           wife: person: Beth
     occupation: occupation: car salesman
        friends: person: Fred, person: Jane, person: Liz, person: Andrew
         mother: person: Sarah
         father: person: David
        sisters: person: Emily
       brothers: person: Frank, person: Tim, person: Sam
          email: email: george.douglas@gmail.com
      education: education: high-school
And that's it for now. I was going to put the general people rules here too, but now I will put them in the next post.

Update: now with the magic of tables:
sa: load blog-george.sw
sa: George |*> #=> apply(|_self>,|person: George>)
sa: table[op,George] supported-ops |person: George>
+-------------+--------------------------+
| op          | George                   |
+-------------+--------------------------+
|             | george                   |
| age         | 29                       |
| dob         | 1984-05-23               |
| hair-colour | brown                    |
| eye-colour  | blue                     |
| gender      | male                     |
| height      | 176                      |
| wife        | Beth                     |
| occupation  | car salesman             |
| friends     | Fred, Jane, Liz, Andrew  |
| mother      | Sarah                    |
| father      | David                    |
| sisters     | Emily                    |
| brothers    | Frank, Tim, Sam          |
| email       | george.douglas@gmail.com |
| education   | high-school              |
+-------------+--------------------------+

the |_self> ket

Next feature I want to mention is the |_self> ket.
I use it all the time, and hopefully is not too hard to describe.

Recall my standard learn rule:
OP KET => SUPERPOSITION
well, simply enough, if |_self> is mentioned in the SUPERPOSITION (on the right), then substitute in the value KET.

Simple example I suppose:
sa: op |x> => 100 |_self>
sa: dump
----------------------------------------
|context> => |context: sw console>

op |x> => 100.000|x>
----------------------------------------
See? We have 100 |x> on the right of our learn-rule, not 100 |_self>
And that's about it. Nothing complicated about it at all.

More to come!

label descent

Here is a little beasty that adds a lot of power to BKO.
And it is usually used in conjunction with stored_rules.

The idea is, if you are trying to do:
context.recall(a,b), and no match is found with the specific value of b, try more and more general rules.

Here is some of the python:
def label_descent(x):
  print("x:",x)
  result = [x]
  if x == "*":
    return result
  if x.endswith(": *"):
    x = x[:-3]
  while True:
    try:
      x,null = x.rsplit(": ",1)
      result.append(x + ": *")
    except:
      result.append("*")
      return result

eg, if you feed in this label "a: b: c: d: fred", it returns these trail labels:
a: b: c: d: fred
a: b: c: d: *
a: b: c: *
a: b: *
a: *
*
So given something like this:
op |a: b: c>
if that has no match, then the code next tries:
op |a: b: *>
if that has no match, then the code next tries:
op |a: *>
if that has no match, then the code next tries:
op |*>
if that has no match, then return |>.

Where we consider:
op |a: b: c>
to be a more specific rule than the more general rule:
op |a: b: *>
which is more specific than say:
op |*>

Anyway, the key code in context.recall() is (though without knowing the details of the context class it probably doesn't make a lot of sense):
    match = False
    for trial_label in label_descent(label):
      if trial_label in self.known_kets:
        if op in self.rules[trial_label]:
          rule = self.rules[trial_label][op]
          match = True
          break
    if not match:
      print("recall not found")               
      rule = ket("",0)
Take home message, this thing is seriously powerful, and useful. That's it for now.

current weather in Adelaide in sw format

So a fictional sw file that represents the current weather in my city, Adelaide.
Data is from the Bureau of Meteorology website.
|context> => |context: BOM: Adelaide: current-weather>
-- fictional source. Though maybe one day something like this will be real? 
source |context: BOM: Adelaide: current-weather> => |sw-url: http://www.bom.gov.au/current-adelaide.sw>

description |context: BOM: Adelaide: current-weather> => |text: "Morning shower or two">
date |context: BOM: Adelaide: current-weather> => |date: 2/12/2014>
time  |context: BOM: Adelaide: current-weather> => |time: 5:15pm>

current |temperature> => |C: 25.2>
max |temperature> => |C: 29>
min |temperature> => |C: 20>

direction |wind> => |direction: south>
speed |wind> => |km/h: 6>

|rain> => |mm: 0.0>
Indeed, structurally this is quite clean. I imagine a script working with a back-end data-base could produce files like this very easily.
The harder component is coming up with applications for this information, once we have it in sw format.

Monday, 1 December 2014

add_learn and stored_rules

Next, a couple of additions to the standard learn rule:
OP KET => SUPERPOSITION

First one is just a notational short-cut for something that is common.
Say you have a list of objects (say friends) and you want to append one or more on the end of that list.

Currently, you would have to do:
sa: friends |Fred> => |Mary> + |Liz>
sa: friends |Fred> => friends |Fred> + |Sam> + |Rob> + |Emma>

But I am very lazy, and like to abbreviate common constructs.
And hence, now we can do:
sa: friends |Fred> => |Mary> + |Liz>
sa: friends |Fred> +=> |Sam> + |Rob> + |Emma>
Note the "+=>" in there.

A couple of properties though:
1) it ignores elements if they are already in the list.
eg:
friends |Fred> +=> |Liz>
leaves the friends list unmodified.
2) it (currently) ignores elements even if they have a different coeff.
eg:
|shopping list> => 2|apples> + 5 |oranges>
|shopping list> +=> 7 |apples> -- this line does not affect our shopping list.
Now, I'm just saying that is how it currently works. I might change this in the future.

So all in all, add-learn "+=>" is not a super big win, but useful every now and then.
And perhaps a more appropriate name is "append learn", but too late now!

Next is stored rules. They have notation:
OP KET #=> SUPERPOSITION
and are seriously useful!

Standard "=>" is evaluated at definition time.
"#=>" is evaluated at recall time (and we call them stored_rules).
(heh, I guess a mnemonic is # looks like a barrier that stops you evaluating straight away).

I guess an example might be the best way to explain:

-- define an initial value for "a":
sa: |a> => |start value>

-- define r1 and r2:
-- set r1 to current value of a:
sa: |r1> => "" |a>
-- set r2 to invoke-time value of a:
sa: |r2> #=> "" |a>

sa: "" |r1>
|start value>

sa: "" |r2>
|start value>


-- change the value of a:
sa: |a> => |next value>

-- r1 still has original definition:
sa: "" |r1>
|start value>

-- r2 returns the current value of a:
sa: "" |r2>
|next value>

And that is about it. Just know that they are very, very useful!
More to come tomorrow, probably.

Update:
I think it would be useful to give examples to show these map to the underlying python context.learn().
So we have these examples in BKO:
friends |Fred> => |Jack>
friends |Fred> => |Jack> + |Jill>
friends |Fred> +=> |Emma> + |Liz>
siblings |person: *> #=> sisters |_self> + brothers |_self>
And they look like this in python:
-- NB: auto-casts "Jack" to ket("Jack"). Implemented because it saves typing and is neater to read.
context.learn("friends","Fred","Jack")
context.learn("friends","Fred",ket("Jack") + ket("Jill"))
-- NB: "add_learn":
context.add_learn("friends","Fred",ket("Emma") + ket("Liz"))
-- NB: stored_rule():
context.learn("siblings","person: *",stored_rule("sisters |_self> + brothers |_self>"))
Update: Just a teaser: using a big nest of stored rules you should be able to construct some large functions that are only activated at run time. I plan to give an example of this eventually!

train of thought

Now I have explained supported-ops, apply(), and create inverse, I can show you "train of thought".
Way back when I first started this project, it looked like this:
-- simple code to approximately represent the concept of "train of thought"
train-of-thought[|X>,n] ::= [
|ket> => |X>
repeat[n][
  |op> => pick-elt:supported-ops|ket>
  |ket> => pick-elt:apply(|op>,|ket>)
  Output:|ket>
]
return |ket>
]
(yeah, for a while operators were separated by colons, now by spaces) 

Now, in python it looks like:
# train-of-thought[n] some-superposition
# eg: train-of-thought[20] |colour: red>
#
# where n is an int.
def console_train_of_thought(one,context,n):
  try:
    n = int(n)
  except:
    return ket("",0)

  print("context:",context.name)
  print("one:",one)
  print("n:",n)
  X = one.pick_elt()
  print("|X>:",X)
  print()
  result = superposition()

  for k in range(n):
    op = X.apply_op(context,"supported-ops").pick_elt()  #   |op> => pick-elt supported-ops |X>
    X = X.apply_op(context,op).pick_elt()                #   |X> => pick-elt apply(|op>,|X>)
    result.data.append(X)                   
    print(X.display())
  return result                             # return a record of the train-of-thought 
 
I guess in words, start with a ket.
Look up the list of supported-ops.
Pick one (that's what pick-elt does).
Apply that operator to your starting ket.
Pick one element from that resulting superposition.
Loop.

The note is that for it to work well, you first need lots of data, and you need to have run create inverse.
The reason that is important is, if you don't have inverses you rapidly run into |>, and your train stops!
With inverses, it happily goes round in circles.

Let's give an example. Let's use the early US presidents data:
sa: load early-us-presidents.sw
sa: train-of-thought[20] |Washington>
context: sw console
one: |Washington>
n: 20
|X>: |Washington>
|year: 1793>
0.000|>
0.000|>
0.000|>
...
Doh! We forgot to run "create inverse" and our train of thought died.

Let's try again:
sa: create inverse
sa: train-of-thought[20] |Washington>
context: sw console
one: |Washington>
n: 20
|X>: |Washington>

|early US Presidents: _list>
|Adams>
|party: Federalist>
|Adams>
|number: 2>
|Adams>
|person: John Adams>
|US President: John Adams>
|person: John Adams>
|Adams>
|person: John Adams>
|Adams>
|early US Presidents: _list>
|Q Adams>
|early US Presidents: _list>
|Adams>
|party: Federalist>
|Adams>
|early US Presidents: _list>
|Jefferson>
4.000|early US Presidents: _list> + 7.000|Adams> + 2.000|party: Federalist> + |number: 2> + 3.000|person: John Adams> + |US President: John Adams> + |Q Adams> + |Jefferson>
So, it works, but is not super great. We really need a very large data-set for best results.

That's it for now!

inverse

So, one driving idea of the project is to get the computer to do as much learning by itself that it can. If we can automate some learning task, then we should try to do so.

The other idea behind "inverse" is that it seems biologically plausible.
Say a face.
A face links one way to the name of that face.
But it links the other way too. The name of the face (usually) invokes the mental image of that face.
Another example is the child/parent relation.
A child relation maps a mother to her children.
But the inverse-child relation maps a child to the mother.
So maybe we can do that a little here?

Again, a simple example:
-- learn a simple rule:
sa: op |x> => |a> + |b> + |c>

-- create the set of inverses:
sa: create inverse
sa: dump
----------------------------------------
|context> => |context: sw console>

op |x> => |a> + |b> + |c>

inverse-supported-ops |op: op> => |x>

inverse-op |a> => |x>

inverse-op |b> => |x>

inverse-op |c> => |x>

inverse-supported-ops |op: inverse-supported-ops> => |op: op> + |op: inverse-supported-ops> + |op: inverse-op>

inverse-supported-ops |op: inverse-op> => |a> + |b> + |c>
----------------------------------------
Hrmm... that is kind of a mess. Unfortunately, the output after "create inverse" usually is.
But let's try and explain what's going on.
Say we have:
OP KET-1 => SUPERPOSITION
then when we run "create inverse" for all rules (in the current context) we learn:
inverse-OP ket => KET-1
for all ket's in SUPERPOSITION.

Maybe this example will be clearer:
-- learn the children of Mary and James:
sa: child |Mary> => |Tim> + |Liz> + |Jane> + |Rob>
sa: child |James> => |Tim> + |Liz> + |Jane> + |Rob>

sa: create inverse
sa: dump
----------------------------------------
|context> => |context: sw console>

child |Mary> => |Tim> + |Liz> + |Jane> + |Rob>

child |James> => |Tim> + |Liz> + |Jane> + |Rob>

inverse-supported-ops |op: child> => |Mary> + |James>

inverse-child |Tim> => |Mary> + |James>

inverse-child |Liz> => |Mary> + |James>

inverse-child |Jane> => |Mary> + |James>

inverse-child |Rob> => |Mary> + |James>

inverse-supported-ops |op: inverse-supported-ops> => |op: child> + |op: inverse-supported-ops> + |op: inverse-child>

inverse-supported-ops |op: inverse-child> => |Tim> + |Liz> + |Jane> + |Rob>
----------------------------------------
So given just data on who Mary and Jame's children are, it auto-learnt the inverse relation. eg, Tim's parents (ie inverse-child) are Mary and James.

Here is another example, in a different region of knowledge, primes.
Start with this data:
-- load data from file:
sa: load short-list-primes.sw
sa: dump
----------------------------------------
|context> => |context: sw console>

is-prime |2> => |yes>
is-prime |3> => |yes>
is-prime |4> => |no>
is-prime |5> => |yes>
is-prime |6> => |no>
is-prime |7> => |yes>
is-prime |8> => |no>
is-prime |9> => |no>
is-prime |10> => |no>
is-prime |11> => |yes>
is-prime |12> => |no>
is-prime |13> => |yes>
is-prime |14> => |no>
is-prime |15> => |no>
is-prime |16> => |no>
is-prime |17> => |yes>
is-prime |18> => |no>
is-prime |19> => |yes>
is-prime |20> => |no>
----------------------------------------

Now, create inverses:
sa: create inverse
sa: dump
----------------------------------------
|context> => |context: sw console>

is-prime |2> => |yes>
is-prime |3> => |yes>
is-prime |4> => |no>
is-prime |5> => |yes>
is-prime |6> => |no>
is-prime |7> => |yes>
is-prime |8> => |no>
is-prime |9> => |no>
is-prime |10> => |no>
is-prime |11> => |yes>
is-prime |12> => |no>
is-prime |13> => |yes>
is-prime |14> => |no>
is-prime |15> => |no>
is-prime |16> => |no>
is-prime |17> => |yes>
is-prime |18> => |no>
is-prime |19> => |yes>
is-prime |20> => |no>

inverse-supported-ops |op: is-prime> => |2> + |3> + |4> + |5> + |6> + |7> + |8> + |9> + |10> + |11> + |12> + |13> + |14> + |15> + |16> + |17> + |18> + |19> + |20>

inverse-is-prime |yes> => |2> + |3> + |5> + |7> + |11> + |13> + |17> + |19>

inverse-is-prime |no> => |4> + |6> + |8> + |9> + |10> + |12> + |14> + |15> + |16> + |18> + |20>

inverse-supported-ops |op: inverse-supported-ops> => |op: is-prime> + |op: inverse-supported-ops> + |op: inverse-is-prime>

inverse-supported-ops |op: inverse-is-prime> => |yes> + |no>
----------------------------------------
(note, some new-lines chomped from the dump for readability)

Anyway, the coolness is in these two lines:
inverse-is-prime |yes> => |2> + |3> + |5> + |7> + |11> + |13> + |17> + |19>
inverse-is-prime |no> => |4> + |6> + |8> + |9> + |10> + |12> + |14> + |15> + |16> + |18> + |20>

So, given just yes/no on primes for each number, the create inverse automatically spits out a list of primes, and non-primes. I personally think that is quite cool!

Technical note: it would be nice if "create inverse" was idempotent, but every now and then it is not.

More to come!

supported-ops and apply()

So a couple of key components today.
Let's start with "supported-ops".
The idea is for every ket, to keep a record of operators that are supported by that ket.
This BTW is built into the context.learn() code, so we never generate it manually, and (the parser) ignores you if you try.

The convention is simply, use "op: " as the category/data-type for operators.
So, a simple example:
sa: name |Fred> => |Fred Roberts>
sa: height |Fred> => |cm: 176>
-- use "dump exact" else supported-ops lines are left out for readability reasons.
sa: dump exact
----------------------------------------
|context> => |context: sw console>

supported-ops |Fred> => |op: name> + |op: height>
name |Fred> => |Fred Roberts>
height |Fred> => |cm: 176>
----------------------------------------
So we see the "name" operator is called |op: name>
And the "height" operator is called |op: height>

Now, add in a little more knowledge:
sa: dob |Fred> => |date: 17/5/1986>
sa: friends |Fred> => |Mary> + |Liz> + |Tom> + |Frank>
sa: mother |Fred> => |Sarah Roberts>
sa: father |Fred> => |James Roberts>

-- see the supported-ops for Fred:
sa: supported-ops |Fred>
|op: name> + |op: height> + |op: dob> + |op: friends> + |op: mother> + |op: father>

So, what is the use of this thing?
Well, one example usage (there are others) is to make use of it in the apply() function (more on functions in BKO later!)

sa: apply(|op: father> + |op: mother>,|Fred>)
|James Roberts> + |Sarah Roberts>

And here is one way to see everything we know about Fred in one superposition:
sa: apply(supported-ops |Fred>,|Fred>)
|Fred Roberts> + |cm: 176> + |date: 17/5/1986> + |Mary> + |Liz> + |Tom> + |Frank> + |Sarah Roberts> + |James Roberts>

And once more for luck, here is everything we now know about Fred:
sa: dump exact
----------------------------------------
|context> => |context: sw console>

supported-ops |Fred> => |op: name> + |op: height> + |op: dob> + |op: friends> + |op: mother> + |op: father>
name |Fred> => |Fred Roberts>
height |Fred> => |cm: 176>
dob |Fred> => |date: 17/5/1986>
friends |Fred> => |Mary> + |Liz> + |Tom> + |Frank>
mother |Fred> => |Sarah Roberts>
father |Fred> => |James Roberts>
----------------------------------------
And once more! We are working on knowledge representation, right? Well, one component of that is there are multiple possible representations of the same knowledge. Here is a more readable version (compared to standard BKO), the display function:
sa: display |Fred>
  Fred
  supported-ops: op: name, op: height, op: dob, op: friends, op: mother, op: father
           name: Fred Roberts
         height: cm: 176
            dob: date: 17/5/1986
        friends: Mary, Liz, Tom, Frank
         mother: Sarah Roberts
         father: James Roberts

I will write up inverse in the next post. Decided they needed separate posts.

Update: apply() is really quite useful. I probably should have put it in its own post, but too late now. Anyway, one common usage is this thing:
star |*> #=> apply(supported-ops |_self>,|_self>)
which returns everything we know about a ket in one superposition. Alternatively, we could call it:
what-do-you-know-about |*> #=> apply(supported-ops |_self>,|_self>)
Update: for a quick guide to how well you understand something (in this case "x"), you can do:
how-many supported-ops |x>

Update: now with the magic of tables:
  name |Fred> => |Fred Roberts>
  height |Fred> => |cm: 176>
  dob |Fred> => |date: 17/5/1986>
  friends |Fred> => |Mary> + |Liz> + |Tom> + |Frank>
  mother |Fred> => |Sarah Roberts>
  father |Fred> => |James Roberts>
  Fred |*> #=> apply(|_self>,|Fred>)

sa: table[op,Fred] ops |Fred>
+---------+-----------------------+
| op      | Fred                  |
+---------+-----------------------+
| name    | Fred Roberts          |
| height  | 176                   |
| dob     | 17/5/1986             |
| friends | Mary, Liz, Tom, Frank |
| mother  | Sarah Roberts         |
| father  | James Roberts         |
+---------+-----------------------+

Sunday, 30 November 2014

learning indirectly

A common thing when having a conversation is to have a set of variables keeping track of who you are talking about. The simplest is "you".
So, in my scheme how can we learn something about you?
We can't simply do:
-- first define context:
sa: context learn you
sa: |you> => |Fred>
sa: age |you> => |age: 29>

Here is why:
sa: dump
----------------------------------------
|context> => |context: learn you>

 |you> => |Fred>
age |you> => |age: 29>
----------------------------------------
We really wanted Fred to be 29, not "you".

So, it took some coding! but we have a new construct:
OP SUPERPOSITION-1 => SUPERPOSITION-2
which maps to:
OP KET => SUPERPOSITION-2
for all kets in SUPERPOSITION-1

Example:
-- see the current definition of "you"
sa: "" |you>
|Fred>
-- so it is "Fred"

-- let's learn his age:
sa: age "" |you> => |age: 29>

-- see what we know:
sa: dump
----------------------------------------
|context> => |context: learn you>

 |you> => |Fred>
age |you> => |age: 29>

age |Fred> => |age: 29>
----------------------------------------
-- success!

Now, swap "you" to "Sam", and learn his age:
sa: |you> => |Sam>
sa: age "" |you> => |age: 34>

sa: dump
----------------------------------------
|context> => |context: learn you>

age |you> => |age: 29>
 |you> => |Sam>

age |Fred> => |age: 29>

age |Sam> => |age: 34>
----------------------------------------
-- again, success!

Now for another example, learn daily closing times for a shop:
sa: context shop closing time

sa: |weekday: _list> => |Monday> + |Tuesday> + |Wednesday> + |Thursday> + |Friday>
sa: |weekend: _list> => |Saturday> + |Sunday>

sa: closing-time "" |weekday: _list> => |time: 6pm>
sa: closing-time "" |weekend: _list> => |time: 4:30pm>

sa: dump
----------------------------------------
|context> => |context: shop closing time>

 |weekday: _list> => |Monday> + |Tuesday> + |Wednesday> + |Thursday> + |Friday>

 |weekend: _list> => |Saturday> + |Sunday>

closing-time |Monday> => |time: 6pm>

closing-time |Tuesday> => |time: 6pm>

closing-time |Wednesday> => |time: 6pm>

closing-time |Thursday> => |time: 6pm>

closing-time |Friday> => |time: 6pm>

closing-time |Saturday> => |time: 4:30pm>

closing-time |Sunday> => |time: 4:30pm>
----------------------------------------

More later!

Update: with my new pretty print table code, we can now do this:
sa: table[day,closing-time] ("" |weekday: _list> + "" |weekend: _list>)
+-----------+--------------+
| day       | closing-time |
+-----------+--------------+
| Monday    | time: 6pm    |
| Tuesday   | time: 6pm    |
| Wednesday | time: 6pm    |
| Thursday  | time: 6pm    |
| Friday    | time: 6pm    |
| Saturday  | time: 4:30pm |
| Sunday    | time: 4:30pm |
+-----------+--------------+
Update: we can tidy up the operator names a little so they are more like natural English:
  list-of |week days> => |Monday> + |Tuesday> + |Wednesday> + |Thursday> + |Friday>
  list-of |weekend days> => |Saturday> + |Sunday>
  closing-time list-of |week days> => |time: 6pm>
  closing-time list-of |weekend days> => |time: 4:30pm>
  table[day,closing-time] list-of (|week days> + |weekend days>)
+-----------+--------------+
| day       | closing-time |
+-----------+--------------+
| Monday    | 6pm          |
| Tuesday   | 6pm          |
| Wednesday | 6pm          |
| Thursday  | 6pm          |
| Friday    | 6pm          |
| Saturday  | 4:30pm       |
| Sunday    | 4:30pm       |
+-----------+--------------+
Update: we can also make the learn-you more like natural English:
  name-of |you> => |Fred>
  age-of name-of |you> => |age: 29>
  name-of |you> => |Sam>
  age-of name-of |you> => |age: 34>
  dump
----------------------------------------
|context> => |context: sw console>

name-of |you> => |Sam>

age-of |Fred> => |age: 29>

age-of |Sam> => |age: 34>
----------------------------------------
Update: another more interesting learning indirectly example. This time one extra operator deep:
  the-third |US President> => |Thomas Jefferson>
  the-party-of the-third |US President> => |party: Democratic-Republican>
  the-dissolution-date-of the-party-of the-third |US President> => |year: 1825>

sa: dump
----------------------------------------
|context> => |context: sw console>

the-third |US President> => |Thomas Jefferson>

the-party-of |Thomas Jefferson> => |party: Democratic-Republican>

the-dissolution-date-of |party: Democratic-Republican> => |year: 1825>
----------------------------------------
ie, inching ever closer to natural language. And I think we can get even closer still!

exponentiating operators

So, it is a common thing to apply the same operator over and over again.
say:
op op op op op |x>
So that motivates a short cut:
op^5 |x>

Let's give an example using a simple binary tree:
left |x> => |0>
right |x> => |1>
child |x> => |0> + |1>

left |0> => |00>
right |0> => |10>
child |0> => |00> + |10>

left |1> => |01>
right |1> => |11>
child |1> => |01> + |11>

left |00> => |000>
right |00> => |100>
child |00> => |000> + |100>

left |10> => |010>
right |10> => |110>
child |10> => |010> + |110>

left |01> => |001>
right |01> => |101>
child |01> => |001> + |101>

left |11> => |011>
right |11> => |111>
child |11> => |011> + |111>

Now, lets use it:
sa: child |x>
|0> + |1>

-- without using the notational short-cut:
sa: child child |x>
|00> + |10> + |01> + |11>

-- using it:
sa: child^2 |x>
|00> + |10> + |01> + |11>

sa: child^3 |x>
|000> + |100> + |010> + |110> + |001> + |101> + |011> + |111>

sa: child^4 |x>
|>
-- we are past the bottom of the tree!

Note that child^k only gives you horizontal slices through the tree.
What if you want a vertical component too?
We can do that.

First recall from maths: exp(x)
And that exp(x) has the Taylor Series:
exp(x) = 1 + x + x^2/2 + x^3/3! + x^4/4! + x^5/5! + ...

If we tidy that up (we don't need the n! denominators), we have:
exp[op,n] |x>
is equivalent to:
(1 + op + op^2 + op^3 + ... + op^n) |x>

eg:
-- equivalent to:
-- |x> + child |x> + child^2 |x>
sa: exp[child,2] |x>
|x> + |0> + |1> + |00> + |10> + |01> + |11>

sa: exp[child,3] |x>
|x> + |0> + |1> + |00> + |10> + |01> + |11> + |000> + |100> + |010> + |110> + |001> + |101> + |011> + |111>

sa: exp[child,2] |1>
|1> + |01> + |11> + |001> + |101> + |011> + |111>

sa: exp[left,2] |1>
|1> + |01> + |001>

Finally, what if you want everything, but you don't know how deep to go?
Hence:
exp-max[op] |x>
which is equivalent to:
exp[op,n] |x> such that exp[op,n] |x> == exp[op,n+1] |x>

eg:
sa: exp-max[child] |x>
|x> + |0> + |1> + |00> + |10> + |01> + |11> + |000> + |100> + |010> + |110> + |001> + |101> + |011> + |111>

sa: exp-max[child] |0>
|0> + |00> + |10> + |000> + |100> + |010> + |110>

Finally, the idea of "six degrees of separation"
If we had the data, then eg:
sa: friends^6 |Fred>
sa: exp[friends,6] |Fred>
sa: exp-max[friends] |Fred>

That's more than enough for now. More later!

Update: now with the magic of tables:
sa: load binary-tree-with-child.sw
sa: table[node,child,text] exp-max[child] |x>
+------+----------+-------------------+
| node | child    | text              |
+------+----------+-------------------+
| x    | 0, 1     | start node        |
| 0    | 00, 10   | first child node  |
| 1    | 01, 11   | second child node |
| 00   | 000, 100 | third child node  |
| 10   | 010, 110 | fourth child node |
| 01   | 001, 101 | fifth child node  |
| 11   | 011, 111 | sixth child node  |
| 000  |          |                   |
| 100  |          |                   |
| 010  |          |                   |
| 110  |          |                   |
| 001  |          |                   |
| 101  |          |                   |
| 011  |          |                   |
| 111  |          |                   |
+------+----------+-------------------+

Saturday, 29 November 2014

linearity of operators

One of the powerful features of BKO is the linearity of (most) operators.
eg, say we start with:
  op1 |x> => |a> + |b> + |c>
Then:
  op2 op1 |x>
  = op2 (|a> + |b> + |c>)
  = op2 |a> + op2 |b> + op2 |c>

Let's do a simple example in the console:
-- enter in some knowledge:
sa: friends |Fred> => |Sam> + |Mary> + |Bella>
sa: age |Sam> => |age: 39>
sa: age |Mary> => |age: 42>
sa: age |Bella> => |age: 36>

-- see what we know:
-- who are Fred's friends?
sa: friends |Fred>
|Sam> + |Mary> + |Bella>

-- how old are Fred's friends?
sa: age friends |Fred>
|age: 39> + |age: 42> + |age: 36>

-- enter in some more knowledge:
sa: friends |Sam> => |Liz> + |Rob>
sa: friends |Bella> => |Joan> + |Tom>

-- who are Sam's friends?
sa: friends |Sam>
|Liz> + |Rob>

-- who are Mary's friends?
sa: friends |Mary>
|>
-- in English |> means "I don't know anything about that".
-- so instead of bugging out if you ask it something it doesn't know, it just quietly returns |> (the empty ket)

-- who are Bella's friends?
sa: friends |Bella>
|Joan> + |Tom>

And now finally:
-- who are Fred's friends of friends?
sa: friends friends |Fred>
|Liz> + |Rob> + |Joan> + |Tom>

And note that it quietly made use of:
"superposition + |> = |> + superposition = superposition"
ie, |> is the identity element for superpositions.
So even though we don't know who's Mary's friends are, the code didn't bug out, and replied best it could.
I like to think humans do something similar.

-- what are the ages of Fred's friends of friends?
sa: age friends friends |Fred>
|>
-- ie, we don't know!


Then finally, let's look at what we now know:
sa: dump
----------------------------------------
|context> => |context: sw console>

friends |Fred> => |Sam> + |Mary> + |Bella>

age |Sam> => |age: 39>
friends |Sam> => |Liz> + |Rob>

age |Mary> => |age: 42>

age |Bella> => |age: 36>
friends |Bella> => |Joan> + |Tom>
----------------------------------------
(and we forgot to set context when we started, so it used the default context "sw console")

And that's it for now!

introducing the semantic agent console

So, we have a general scheme to represent knowledge:
OP KET => SUPERPOSITION
Now we need some method to make use of it.
And hence the semantic agent console.
From here on, anything that starts with "sa: " can be assumed to be in the console.
$ ./the_semantic_db_console.py
Welcome!

sa: h

  q, quit, exit                quit the agent.
  h, help                      print this message
  context                      print list of context's
  context string               set current context to string
  reset                        reset back to completely empty console
                               Warning! you will lose all unsaved work!
  dump                         print current context
  dump exact                   print current context in exact mode
  dump multi                   print context list
  dump self                    print what we know about the default ket/sp
  dump ket/sp                  print what we know about the given ket/sp
  display                      (relatively) readable display of current context
  display ket/sp               (relatively) readable display about what we know for the ket/sp
  freq                         convert current context to frequency list
  mfreq                        convert context list to frequency list
  load file.sw                 load file.sw
  save file.sw                 save current context to file.sw
  save multi file.sw           save context list to file.sw
  files                        show the available .sw files
  cd                           change and create if necessary the .sw directory
  ls, dir, dirs                show the available directories
  create inverse               create inverse for current context
  create multi inverse         create inverse for all context in context list
  x = foo: bah                 set x (the default ket) to |foo: bah>
  id                           display the default ket/superposition
  s, store                     set x to the result of the last computation
  .                            repeat last computation
  i                            interactive history
  history                      show last 30 commands
  history n                    show last n commands
  save history                 save console history to file
  -- comment                   ignore, this is just a comment line.
  if none of the above         process_input_line(C,line,x)


personality profile for a bot called bella

This is just an example of the kind of knowledge a bot might need to try the Loebner contest.
First, we build up a data set of personality details.
Then we choose elements randomly, and we get something like this:
name |bot: Bella> => |Bella>
mother |bot: Bella> => |Mia>
father |bot: Bella> => |William>
birth-sign |bot: Bella> => |birth-sign: Cancer>
number-siblings |bot: Bella> => |number: 1>
wine-preference |bot: Bella> => |wine: Merlot>
favourite-fruit |bot: Bella> => |fruit: pineapples>
favourite-music |bot: Bella> => |music: genre: punk>
favourite-play |bot: Bella> => |play: Endgame>
hair-colour |bot: Bella> => |hair-colour: gray>
eye-colour |bot: Bella> => |eye-colour: hazel>
where-live |bot: Bella> => |location: Sydney>
favourite-holiday-spot |bot: Bella> => |location: Paris>
make-of-car |bot: Bella> => |car: Porsche>
religion |bot: Bella> => |religion: Christianity>
personality-type |bot: Bella> => |personality-type: the guardian>
current-emotion |bot: Bella> => |emotion: fear>
bed-time |bot: Bella> => |time: 8pm>

some ket label conventions

Now, as I said previously, ket labels can be anything except <, |, > and \r and \n.
But we have some conventions.

For a start we separate categories from sub-categories using ": ".
eg:
|plant: tree>
|plant: tree: elm>
also with the convention that the sub-categories are a subset of the parent category.
(though perhaps in some cases it is useful to break this convention).
So in this case, tree is clearly a subset of the concept plant.
And elm is clearly a subset of the concept tree, and plant.

Note that we are not forced to use categories (which I guess could equally validly be called "data-types").
eg:
closing-time |monday> => |5pm>
vs:
closing-time |day: monday> => |time: 5pm>
So, while categories/data-types are not mandated, they are often useful.

Next, we have _list.
We use this (again by convention) to define a list of objects.
eg, the states in Australia:
|Australia: state: _list> => |state: Western Australia> + |state: South Australia> + |state: Queensland> + |state: New South Wales> + |state: Victoria> + |state: Tasmania>

eg, shopping list:
|shopping: _list> => 4|apples> + 6|bananas> + 2|tomatos> + |coffee> + |milk> + |bread>

Finally, we have *.
|category: *> matches all members of "category".
And |*> matches everything!
(we have some "magic" behind the scenes to make this work. More on that later)

Here is an example, learning that all plants die:
will-die |plant> => |yes>
will-die |plant: *> => |yes>

Then if we ask the system:
will-die |plant: tree> we get |yes>
And if we ask:
will-die |plant: tree: elm> we get |yes>

More to come!

Update: we have conventions for operator names too!
There are two main types of operators, those that step from one ket to other kets, and those that only change the coeff of the ket. It is sometimes useful to distinguish between these two cases. eg:
op |x> => |a> + |b> + |c> is type 1.
op |x> => 3.14159|x> is type 2.
The convention (though sometimes ignored) is the for this second type to have -self appended to its name. eg, a common usage:
population |Adelaide> => |population: 1200000>
vs:
population-self |Adelaide> => 1200000|Adelaide>
Type 2 operators are very useful when working with lists of objects. Examples of this later!
The other thing to note is that in general type 1 operators do not commute, but type 2 operators always commute. op2-self op1-self |x> == op1-self op2-self |x> for example.

Friday, 28 November 2014

Tim Berners-Lee flowchart in BKO

So, the standard learn rule is already quite powerful (though we add more power later).
OP KET => SUPERPOSITION

Certainly powerful enough to map a flow chart to a relatively readable BKO.
Consider the flow chart from the original html proposal:
In BKO is simply:
|context> => |context: www proposal>

describes |document: www proposal> => |"Hypertext"> + |A Proposal "Mesh">
refers-to |document: www proposal> => |Comms ACM>

describes |Comms ACM> => |"Hypertext"> 

includes |"Hypertext"> => |Linked information> + |Hypermedia>

for-example |Linked information> => |Hyper Card> + |ENQUIRE> + |A Proposal "Mesh">

describes |a proposal "mesh"> => |CERN>
unifies |a proposal "mesh"> => |ENQUIRE> + |VAX/NOTES> + |uucp News> + |CERNDOC>

examples |Computer conferencing> => |IBM GroupTalk> + |uucp News> + |VAX/NOTES> + |A Proposal "Mesh">

for-example |Hierarchical systems> => |CERN> + |CERNDOC> + |Vax/Notes> + |uucp News> + |IBM GroupTalk>

includes |CERNDOC> => |document: www proposal>

wrote |person: Tim Berners-Lee> => |document: www proposal>

 
So, if we study the flow-chart vs the BKO we observe that nodes in the chart map to kets, and arrows map to operators. eg, |document: www proposal> and "describes" respectively.
Indeed, if text was not 1D, we could actually put the operators above the => symbol, to make the mapping even clearer.

I guess the final thing to note is that all the coeffs are 1, since in this flow-chart the arrows do not specify weights.

And that's it for now!

context, learn and recall

At the very heart of this project are two functions:
context.learn(a,b,c)
context.recall(a,b)

First thing to note is the context variable.
Every thing we learn is with respect to a particular context.
In one context, everything must be (sort of) self consistent (though the nature of superpositions means we can tolerate ambiguity/inconsistency somewhat).
In different context, well, they are fully independent, so you can define anything.

The convention to define context is this learn rule:
|context> => |context: a sample context>

Perhaps a small example, consider 2 shops with different closing times on Mondays:
|context> => |context: shop 1>
closing-time |monday> => |time: 5pm>

|context> => |context: shop 2>
closing-time |monday> => |time: 6pm>

Now, if these were defined in the same context, then the second closing-time rule would over-write the first. But since they are in different context, it is perfectly fine.

Next, I have the assumption that all knowledge can be represented by triples (a,b,c):
context.learn(a,b,c)
And context.recall(a,b) returns c.

Maybe this assumption is wrong, or not the entire picture, but we can certainly go a long way using it.

For example:
|context> => |context: shop 1>
has:
a = ""
b = "context"
c = "context: shop 1"

closing-time |monday> => |time: 5pm>
has:
a = "closing-time"
b = "monday"
c = "time: 5pm"

Currently in the project we only handle a few data-types for a,b,c (and I don't currently see the need to add any more).
a must be a string.
b is a string or a ket
c is a string (auto cast to a ket), a ket, a superposition, or a stored_rule

And the back-end for context.learn() and context.recall() is currently a convoluted hash-table. But it shouldn't be too hard to swap that out for something better (eg a database or something) if we have to.

That's it for now.

Update: I rewrote the context.learn() and context.recall() code. Much simpler, more memory efficient and faster than the old one. eg, converting the geonames 15000 cities data to sw format was a full 24 times faster with the new code. And this also means loading Moby synonyms or loading geonames cities 1000 into the console, and working with it, is now practical.

Thursday, 27 November 2014

Defining some terms

So, the notation I use is motivated by the bra-ket notation as used in quantum mechanics, and invented by the famous physicist Paul Dirac. Note though that the mathematics of my scheme and that of QM are vastly different.

Let's define the terms:
<x| is called a bra
|x> is called a ket
Essentially any text (currently ASCII only) can be inside bra/kets except <, |, > and \r and \n. Though we do have some conventions, more on that later.

Next, we have operators, that are again text.
The python defining valid operators is:
def valid_op(op):
  if not op[0].isalpha() and not op[0] == '!':
    return False
  return all(c in ascii_letters + '0123456789-+!?' for c in op) 
Next, we have what I call "superpositions" (again borrowed from QM). A superposition is just the sum of one or more kets.
eg:
|a> + |b> + |c>
But a full superposition can also have coeffs (I almost always write coefficients as coeffs).
3|a> + 7.25|b> + 21|e> + 9|d>

The name superpositions is partly motivated by Schrodinger's poor cat:
is-alive |cat> => 0.5 |yes> + 0.5 |no>

This BTW, is what we call a "learn rule" (though there are a couple of other variants).
They have the general form:
OP KET => SUPERPOSITION

Next, we have some math rules for all this, though for now it will suffice to mention only these:
1) <x||y> == 0 if x != y.  
2) <x||y> == 1 if x == y.
7) applying bra's is linear. <x|(|a> + |b> + |c>) == <x||a> + <x||b> + <x||c>
8) if a coeff is not given, then it is 1. eg, <x| == <x|1 and 1|x> == |x>
9) bra's and ket's commute with the coefficients. eg, <x|7 == 7 <x| and 13|x> == |x>13  
13) kets in superpositions commute. |a> + |b> == |b> + |a>
18) |> is the identity element for superpositions. sp + |> == |> + sp == sp.
19) the + sign in superpositions is literal. ie, kets add.
|a> + |a> + |a> = 3|a>
|a> + |b> + |c> + 6|b> = |a> + 7|b> + |c>

And that is it for now. Heaps more to come!

Update: I guess you could call superpositions labelled, sparse vectors. By giving each element in a vector a name, it gives us the freedom to drop elements with coeff = 0. For large sparse vectors, this is a big win. For large dense vectors, there is of course a price to pay for all those labels. And since we have labels we can change the order of the elements without changing the meaning of the superposition. Say if we want to sort by coeff size. This is harder if you use standard unlabeled vectors. I guess the other thing to note about superpositions is that they allow you to define operators with respect to vector labels, and not vector positions.

Announcing the Semantic DB Project

So, I've been tinkering/coding some ideas for knowledge representation and semantic web for about a year now. Roughly 14,000 lines of python for the whole project. Anyway, I think now is the time to try and get others interested in my project. I like to think I have some interesting ideas, let's see if others do.

In terms of describing what I'm trying to do, I currently only have this though it is rather minimalist when it comes to words. Its really just a series of examples of my notation, rather than a decent write-up. Maybe this blog will help explain my ideas.

More to come!