Thursday 21 January 2016

new operators: mod[k] and is-mod[k]

Just a couple more simple arithmetic operators, mod[k] and is-mod[k]. They do pretty much what they say they do. One for example usage, is the fizz-buzz exercise.

Quick look in the console:
sa: mod[3] |number: 12>
|number: 0>

sa: mod[3] |8>
|2>

sa: is-mod[7] |50>
|no>

sa: is-mod[7] |96889010407>
|yes>

sa: is-mod[3] |category 1: category 2: category 3: 286725>
|yes>
And I guess we should note that they work independent of the category/data-type (as do the other simple arithmetic operators). Here the first one has data-type "number". Those in the middle have no data-type. And the last one has "category 1: category 2: category 3".

Now, on to FizzBuzz. Here are the exercise details:
-- task:
-- For numbers 1 through 100,

-- if the number is divisible by 3 print Fizz;
-- if the number is divisible by 5 print Buzz;
-- if the number is divisible by 3 and 5 (15) print FizzBuzz;
-- else, print the number.
Here are three alternate potential ways to do it, but the incomplete parser meant only the third version actually worked:
|context> => |context: Fizz Buzz exercise in BKO: v1>
|list> => range(|1>,|100>)
fizz-buzz-0 |*> #=> |_self>
fizz-buzz-1 |*> #=> if(arithmetic(|_self>,|%>,|3>) == |0>,|Fizz>,|>)
fizz-buzz-2 |*> #=> if(arithmetic(|_self>,|%>,|5>) == |0>,|Buzz>,|>)
fizz-buzz-3 |*> #=> if(arithmetic(|_self>,|%>,|15>) == |0>,|FizzBuzz>,|>)

map[fizz-buzz-0,fizz-buzz] "" |list>
map[fizz-buzz-1,fizz-buzz] "" |list>
map[fizz-buzz-2,fizz-buzz] "" |list>
map[fizz-buzz-3,fizz-buzz] "" |list>



|context> => |context: Fizz Buzz exercise in BKO: v2>
|list> => range(|1>,|100>)
is-zero |*> => |False>
is-zero |0> => |True>
fizz-buzz-0 |*> #=> |_self>
-- current parser can't handle the nested ()
fizz-buzz-1 |*> #=> if(is-zero arithmetic(|_self>,|%>,|3>),|Fizz>,|>)
fizz-buzz-2 |*> #=> if(is-zero arithmetic(|_self>,|%>,|5>),|Buzz>,|>)
fizz-buzz-3 |*> #=> if(is-zero arithmetic(|_self>,|%>,|15>),|FizzBuzz>,|>)

map[fizz-buzz-0,fizz-buzz] "" |list>
map[fizz-buzz-1,fizz-buzz] "" |list>
map[fizz-buzz-2,fizz-buzz] "" |list>
map[fizz-buzz-3,fizz-buzz] "" |list>



|context> => |context: Fizz Buzz exercise in BKO: v3>
-- define our list
|list> => range(|1>,|100>)

-- define is-zero function
is-zero |*> => |False>
is-zero |0> => |True>

-- define is-mod functions
is-mod-3 |*> #=> is-zero arithmetic(|_self>,|%>,|3>)
is-mod-5 |*> #=> is-zero arithmetic(|_self>,|%>,|5>)
is-mod-15 |*> #=> is-zero arithmetic(|_self>,|%>,|15>)

-- apply them
map[is-mod-3] "" |list>
map[is-mod-5] "" |list>
map[is-mod-15] "" |list>

-- define fizz-buzz functions
fizz-buzz-0 |*> #=> |_self>
fizz-buzz-1 |*> #=> if(is-mod-3 |_self>,|Fizz>,|>)
fizz-buzz-2 |*> #=> if(is-mod-5 |_self>,|Buzz>,|>)
fizz-buzz-3 |*> #=> if(is-mod-15 |_self>,|FizzBuzz>,|>)

-- apply them
map[fizz-buzz-0,fizz-buzz] "" |list>
map[fizz-buzz-1,fizz-buzz] "" |list>
map[fizz-buzz-2,fizz-buzz] "" |list>
map[fizz-buzz-3,fizz-buzz] "" |list>
Now we have is-mod[k] we can give a nice pretty and tidy version:
|context> => |context: Fizz Buzz exercise, is-mod version>
the |list> => range(|1>,|100>)

fizz-buzz-0 |*> #=> |_self>
fizz-buzz-1 |*> #=> if(is-mod[3] |_self>,|Fizz>,|>)
fizz-buzz-2 |*> #=> if(is-mod[5] |_self>,|Buzz>,|>)
fizz-buzz-3 |*> #=> if(is-mod[15] |_self>,|FizzBuzz>,|>)

|null> => map[fizz-buzz-0,fizz-buzz] the |list>
|null> => map[fizz-buzz-1,fizz-buzz] the |list>
|null> => map[fizz-buzz-2,fizz-buzz] the |list>
|null> => map[fizz-buzz-3,fizz-buzz] the |list>
And here is the result:
sa: load fizz-buzz--is-mod.sw
sa: dump
----------------------------------------
|context> => |context: Fizz Buzz exercise, is-mod version>

the |list> => |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>

fizz-buzz-0 |*> #=> |_self>
fizz-buzz-1 |*> #=> if(is-mod[3] |_self>,|Fizz>,|>)
fizz-buzz-2 |*> #=> if(is-mod[5] |_self>,|Buzz>,|>)
fizz-buzz-3 |*> #=> if(is-mod[15] |_self>,|FizzBuzz>,|>)

fizz-buzz |1> => |1>
fizz-buzz |2> => |2>
fizz-buzz |3> => |Fizz>
fizz-buzz |4> => |4>
fizz-buzz |5> => |Buzz>
fizz-buzz |6> => |Fizz>
fizz-buzz |7> => |7>
fizz-buzz |8> => |8>
fizz-buzz |9> => |Fizz>
fizz-buzz |10> => |Buzz>
fizz-buzz |11> => |11>
fizz-buzz |12> => |Fizz>
fizz-buzz |13> => |13>
fizz-buzz |14> => |14>
fizz-buzz |15> => |FizzBuzz>
fizz-buzz |16> => |16>
fizz-buzz |17> => |17>
fizz-buzz |18> => |Fizz>
fizz-buzz |19> => |19>
fizz-buzz |20> => |Buzz>
fizz-buzz |21> => |Fizz>
fizz-buzz |22> => |22>
fizz-buzz |23> => |23>
fizz-buzz |24> => |Fizz>
fizz-buzz |25> => |Buzz>
fizz-buzz |26> => |26>
fizz-buzz |27> => |Fizz>
fizz-buzz |28> => |28>
fizz-buzz |29> => |29>
fizz-buzz |30> => |FizzBuzz>
fizz-buzz |31> => |31>
fizz-buzz |32> => |32>
fizz-buzz |33> => |Fizz>
fizz-buzz |34> => |34>
fizz-buzz |35> => |Buzz>
fizz-buzz |36> => |Fizz>
fizz-buzz |37> => |37>
fizz-buzz |38> => |38>
fizz-buzz |39> => |Fizz>
fizz-buzz |40> => |Buzz>
fizz-buzz |41> => |41>
fizz-buzz |42> => |Fizz>
fizz-buzz |43> => |43>
fizz-buzz |44> => |44>
fizz-buzz |45> => |FizzBuzz>
fizz-buzz |46> => |46>
fizz-buzz |47> => |47>
fizz-buzz |48> => |Fizz>
fizz-buzz |49> => |49>
fizz-buzz |50> => |Buzz>
fizz-buzz |51> => |Fizz>
fizz-buzz |52> => |52>
fizz-buzz |53> => |53>
fizz-buzz |54> => |Fizz>
fizz-buzz |55> => |Buzz>
fizz-buzz |56> => |56>
fizz-buzz |57> => |Fizz>
fizz-buzz |58> => |58>
fizz-buzz |59> => |59>
fizz-buzz |60> => |FizzBuzz>
fizz-buzz |61> => |61>
fizz-buzz |62> => |62>
fizz-buzz |63> => |Fizz>
fizz-buzz |64> => |64>
fizz-buzz |65> => |Buzz>
fizz-buzz |66> => |Fizz>
fizz-buzz |67> => |67>
fizz-buzz |68> => |68>
fizz-buzz |69> => |Fizz>
fizz-buzz |70> => |Buzz>
fizz-buzz |71> => |71>
fizz-buzz |72> => |Fizz>
fizz-buzz |73> => |73>
fizz-buzz |74> => |74>
fizz-buzz |75> => |FizzBuzz>
fizz-buzz |76> => |76>
fizz-buzz |77> => |77>
fizz-buzz |78> => |Fizz>
fizz-buzz |79> => |79>
fizz-buzz |80> => |Buzz>
fizz-buzz |81> => |Fizz>
fizz-buzz |82> => |82>
fizz-buzz |83> => |83>
fizz-buzz |84> => |Fizz>
fizz-buzz |85> => |Buzz>
fizz-buzz |86> => |86>
fizz-buzz |87> => |Fizz>
fizz-buzz |88> => |88>
fizz-buzz |89> => |89>
fizz-buzz |90> => |FizzBuzz>
fizz-buzz |91> => |91>
fizz-buzz |92> => |92>
fizz-buzz |93> => |Fizz>
fizz-buzz |94> => |94>
fizz-buzz |95> => |Buzz>
fizz-buzz |96> => |Fizz>
fizz-buzz |97> => |97>
fizz-buzz |98> => |98>
fizz-buzz |99> => |Fizz>
fizz-buzz |100> => |Buzz>

 |null> => |map>
----------------------------------------
And I guess that is it for this post.

Tuesday 19 January 2016

new feature: list 2 sp

Just a quick bit of code to improve context.learn(). We can now learn a rule that is a list.

Here is the python:
def list_2_sp(one):
  r = superposition()
  if type(one) == list:
    for x in one:                                # what do we want to do if type(x) is not int, float or string?
      if type(x) == int or type(x) == float:
        r += ket("number: " + str(x))
      elif type(x) == str:
        r += ket(x)
  return r
And a quick demonstration of it in action:
# define some example lists:
list1 = [2,3,5,7,11,13]
list2 = ["cat","dog","horse","rat","mouse","lion","horse"]
list3 = ["a","b",37,2.1828,"a","fish","a",37]

# test learn code:
context.learn("list-of","small primes",list1)
context.learn("list-of","common animals",list2)
context.learn("list-of","test elements",list3)

# see what we have learnt:
context.print_universe()
Outputs (NB: the repeated elements with coeff > 1):
list-of |small primes> => |number: 2> + |number: 3> + |number: 5> + |number: 7> + |number: 11> + |number: 13>
list-of |common animals> => |cat> + |dog> + 2|horse> + |rat> + |mouse> + |lion>
list-of |test elements> => 3|a> + |b> + 2|number: 37> + |number: 2.1828> + |fish>
So, simple enough. Just makes using the python context.learn() a little cleaner. eg, instead of:
context.learn("friends","Fred",ket("Sam") + ket("Frank") + ket("Jim") + ket("Rob"))
we can now do:
context.learn("friends","Fred",["Sam","Frank","Jim","Rob"])
Of course, if you need your kets to have coeff other than 1, then you need to do it the old way, with the explicit ket(string,value). Though I suspect most of the time we can get away with just using lists.

Monday 18 January 2016

new operators: times-by, divide-by, plus, minus

So, I've had times[k] for quite a while now, but not the rest. And it was implemented in an ugly, and not perfect, way. Anyway, all tidied now. And using the same code we can now also do divide, plus and minus. This means we can now do a few things in a neater way.

First up, factorial.
The old way:
fact |0> => |1>
n-1 |*> #=> arithmetic(|_self>,|->,|1>)
fact |*> #=> arithmetic( |_self>, |*>, fact n-1 |_self>)
The new way:
fact |0> => |1>
fact |*> #=> arithmetic( |_self>, |*>, fact minus[1] |_self>)
Fibonacci the old way:
fib |0> => |0>
fib |1> => |1>
n-1 |*> #=> arithmetic(|_self>,|->,|1>)
n-2 |*> #=> arithmetic(|_self>,|->,|2>)
fib |*> #=> arithmetic( fib n-1 |_self>, |+>, fib n-2 |_self>)
The new way:
fib |0> => |0>
fib |1> => |1>
fib |*> #=> arithmetic( fib minus[1] |_self>, |+>, fib minus[2] |_self>)
And from a long, long time ago we have this aspirational code to implement currency exchange information:
to-USD |currency: USD: _x> => |currency: USD: _x>
to-USD |currency: GBP: _x > => |currency: USD: _x*1.62>

to-GBP |currency: USD: _x> => | currency: GBP: _x*0.62>
to-GBP |currency: GBP: _x> => | currency: GBP: _x >
I say aspirational since I never found a clean way to implement this. I thought I might have had to change the parser and a bunch of other things. Now we can do it simply enough:
to-USD |currency: USD: *> #=> |_self>
to-USD |currency: GBP: *> #=> merge-labels(|currency: USD: > + times-by[1.62] extract-value |_self>)

to-GBP |currency: USD: *> #=> merge-labels(|currency: GBP: > + divide-by[1.62] extract-value |_self>)
to-GBP |currency: GBP: *> #=> |_self>
Again from long ago I had this for temperature conversion:
to-Kelvin |temperature: Kelvin: _x > => |temperature: Kelvin: _x >
to-Celsius |temperature: Kelvin: _x > => |temperature: Celsius: (_x - 273.15) >
to-Fahrenheit |temperature: Kelvin: _x> => |temperature: Fahrenheit: (_x*9/5 - 459.67) >

to-Kelvin |temperature: Celsius: _x > => |temperature: Kelvin: (_x + 273.15) >
to-Celsius |temperature: Celsius: _x> => |temperature: Celsius: _x >
to-Fahrenheit |temperature: Celsius: _x> => |temperature: Fahrenheit: (_x*9/5 + 32) >

to-Kelvin |temperature: Fahrenheit: _x > => |temperature: Kelvin: (_x + 459.67)*5/9 >
to-Celsius |temperature: Fahrenheit: _x > => |temperature: Celsius: (_x - 32)*5/9 >
to-Fahrenheit |temperature: Fahrenheit: _x > => |temperature: Fahrenheit: _x >
Now we can do it like this:
to-Kelvin |temperature: Kelvin: *> #=> |_self>
to-Celsius |temperature: Kelvin: *> #=> merge-labels(|temperature: Celsius: > + minus[273.15] extract-value |_self>)
to-Fahrenheit |temperature: Kelvin: *> #=> merge-labels(|temperature: Fahrenheit: > + minus[459.67] times-by[9/5] extract-value |_self>)

to-Kelvin |temperature: Celsius: *> #=> merge-labels(|temperature: Kelvin: > + plus[273.15] extract-value |_self>)
to-Celsius |temperature: Celsius: *> #=> |_self>
to-Fahrenheit |temperature: Celsius: *> #=> merge-labels(|temperature: Fahrenheit: > + plus[32] times-by[9/5] extract-value |_self>)

to-Kelvin |temperature: Fahrenheit: *> #=> merge-labels(|temperature: Kelvin: > + times-by[5/9] plus[459.67] extract-value |_self>)
to-Celsius |temperature: Fahrenheit: *> #=> merge-labels(|temperature: Celsius: > + times-by[5/9] minus[32] extract-value |_self>)
to-Fahrenheit |temperature: Fahrenheit: *> #=> |_self>
Yeah, a bit ugly I'm afraid. Though when we swap in "|a> _ |b>" for "merge-labels(|a> + |b>)" in the parser, that should make it a bit cleaner.

This is what that would look like:
to-Kelvin |temperature: Kelvin: *> #=> |_self>
to-Celsius |temperature: Kelvin: *> #=> |temperature: Celsius: > _ minus[273.15] extract-value |_self>
to-Fahrenheit |temperature: Kelvin: *> #=> |temperature: Fahrenheit: > _ minus[459.67] times-by[9/5] extract-value |_self>

to-Kelvin |temperature: Celsius: *> #=> |temperature: Kelvin: > _ plus[273.15] extract-value |_self>
to-Celsius |temperature: Celsius: *> #=> |_self>
to-Fahrenheit |temperature: Celsius: *> #=> |temperature: Fahrenheit: > _ plus[32] times-by[9/5] extract-value |_self>

to-Kelvin |temperature: Fahrenheit: *> #=> |temperature: Kelvin: > _ times-by[5/9] plus[459.67] extract-value |_self>
to-Celsius |temperature: Fahrenheit: *> #=> |temperature: Celsius: > _ times-by[5/9] minus[32] extract-value |_self>
to-Fahrenheit |temperature: Fahrenheit: *> #=> |_self>
And if the above looks like too much work. Well, that shouldn't be a problem. It only needs to be written once, and then we can web-load it. eg:
sa: web-load http://semantic-db.org/sw-examples/gbp-usd-exchange-rate.sw
sa: web-load http://semantic-db.org/sw-examples/temperature-conversion.sw
Though another reason why it looks ugly is the explicit data-type. We could leave that off and it would be a bit cleaner. eg:
to-Kelvin |Kelvin: *> #=> |_self>
to-Celsius |Kelvin: *> #=> |Celsius: > _ minus[273.15] extract-value |_self>
to-Fahrenheit |Kelvin: *> #=> |Fahrenheit: > _ minus[459.67] times-by[9/5] extract-value |_self>

to-Kelvin |Celsius: *> #=> |Kelvin: > _ plus[273.15] extract-value |_self>
to-Celsius |Celsius: *> #=> |_self>
to-Fahrenheit |Celsius: *> #=> |Fahrenheit: > _ plus[32] times-by[9/5] extract-value |_self>

to-Kelvin |Fahrenheit: *> #=> |Kelvin: > _ times-by[5/9] plus[459.67] extract-value |_self>
to-Celsius |Fahrenheit: *> #=> |Celsius: > _ times-by[5/9] minus[32] extract-value |_self>
to-Fahrenheit |Fahrenheit: *> #=> |_self>
And we could abbreviate it even more:
to-K |K: *> #=> |_self>
to-C |K: *> #=> |C: > _ minus[273.15] extract-value |_self>
to-F |K: *> #=> |F: > _ minus[459.67] times-by[9/5] extract-value |_self>

to-K |C: *> #=> |K: > _ plus[273.15] extract-value |_self>
to-C |C: *> #=> |_self>
to-F |C: *> #=> |F: > _ plus[32] times-by[9/5] extract-value |_self>

to-K |F: *> #=> |K: > _ times-by[5/9] plus[459.67] extract-value |_self>
to-C |F: *> #=> |C: > _ times-by[5/9] minus[32] extract-value |_self>
to-F |F: *> #=> |_self>
And I think that is enough for today! Though BTW, the above general scheme can be used for conversions of other units. Say distances, weights, etc.

ket arithmetic

OK, a slightly weird one today. We can actually do some simple arithmetic just using the coeffs of kets. Though they are fixed numbers, rather than parameters, so you can't do all that much interesting with them.

Anyway, some examples:
-- 3.2 + 5.3 + 7
sa: 3.2|x> + 5.3|x> + 7|x>
15.5|x>

-- 3.2 + 5.3 - 7
sa: 3.2|x> + 5.3|x> + -7 |x>
1.5|x>

-- 5 * 11 * 17
sa: 5 11 17 |x>
935|x>

-- 9/5 * 10
sa: 9/5 10 |x>
18|x>

-- 13^9
sa: 13^9 |x>
10604499373|x>

-- 5.2^2 (3 + 7.1 + 9.8)
sa: 5.2^2 (3|x> + 7.1|x> + 9.8|x>)
538.096|x>

-- 2 * 3 * 7^7 (5 + 9.2)
sa: 2 3 7^7 (5|x> + 9.2|x>)
70165863.6|x>
And I guess that is it. It should be obvious from there how to do arbitrary arithmetic using ket coeffs.

Sunday 17 January 2016

is BKO related to category theory?

I don't know for sure, since I am a long, long way from being a mathematician. But by the wikipedia definition, it just might be the case.

Wikipedia gives this definition for a category and a functor:

A category C consists of the following three mathematical entities:

    A class ob(C), whose elements are called objects;
    A class hom(C), whose elements are called morphisms or maps or arrows. Each morphism f has a source object a and target object b.
    The expression f : a → b, would be verbally stated as "f is a morphism from a to b".
    The expression hom(a, b) — alternatively expressed as homC(a, b), mor(a, b), or C(a, b) — denotes the hom-class of all morphisms from a to b.
    A binary operation ∘, called composition of morphisms, such that for any three objects a, b, and c, we have hom(b, c) × hom(a, b) → hom(a, c). The composition of f : a → b and g : b → c is written as g ∘ f or gf,[4] governed by two axioms:
        Associativity: If f : a → b, g : b → c and h : c → d then h ∘ (g ∘ f) = (h ∘ g) ∘ f, and
        Identity: For every object x, there exists a morphism 1x : x → x called the identity morphism for x, such that for every morphism f : a → b, we have 1b ∘ f = f = f ∘ 1a.

Functors are structure-preserving maps between categories. They can be thought of as morphisms in the category of all (small) categories.

A (covariant) functor F from a category C to a category D, written F : C → D, consists of:

    for each object x in C, an object F(x) in D; and
    for each morphism f : x → y in C, a morphism F(f) : F(x) → F(y),

such that the following two properties hold:

    For every object x in C, F(1x) = 1F(x);
    For all morphisms f : x → y and g : y → z, F(g ∘ f) = F(g) ∘ F(f).

with the mapping:
objects -> kets
morphisms -> operators
morphism composition -> operator composition
category -> sw file
functor -> code that maps one sw file to another, with the same network structure, but different ket and operator names.
noting that our operators naturally satisfy the associativity requirement, and it is easy to create identity morphisms.

So, a for example in BKO:
f |a> => |b>
id-a |a> => |a>

g |b> => |c>
id-b |b> => |b>

h |c> => |d>
id-c |c> => |c>

id |*> #=> |_self>
And then a demonstration of operator composition:
sa: f |a>
|b>

sa: f id-a |a>
|b>

sa: id-b f |a>
|b>

sa: g f |a>
|c>

sa: h g f |a>
|d>
Perhaps we should not be surprised by this correspondence (providing it is true). Why? Well the project is trying to demonstrate BKO is a general representation for knowledge, and that representation has a natural interpretation of being manipulating network state. Maths is a subset of human knowledge, so there must be a way to represent that in BKO. The question is how compact is that representation? I don't know. Consider group theory. And say we want to represent that in BKO. By what we just said, there must be a representation of that in terms of networks. But how big or how small is this network? I suspect it is on the smaller side. My hunch being that abstract things have a smaller network structure than concrete things. I say this because concrete things have all these links to specific examples, and their related networks. An abstract maths idea can exist on its own without this. And the other reason is the very definition of abstract mathematics. It is abstracting the essence from a series of examples with the same structure. The essence of a thing being smaller than the thing. Though all the in-brain/in-mathematician machinery to manipulate mathematical objects adds to the size of the network!

A thing to wonder is, what is the category theory equivalent of mapping a ket to a superposition, or to a superposition with coeffs other than 1? eg:
f |x> => |a> + |b> + |c> + |d> + |e>
g |y> => 3.7|a> + |b> + 2.2218|c> + 13|e>
Though I don't want to tread too far into real mathematics, I'm not a mathematician and would make a fool of myself.

Update: a couple of comments:
1) standard semantic web is somewhat close to a category too, with the mapping:
objects -> URI's
morphisms -> URI's
category -> RDF file
however, RDF, as far as I know, doesn't have morphism composition, or identity morphisms.

2) metaphors and analogies are approximately like functors. Though only approximate, in most cases, since analogies are rarely perfect. You can usually push them too far, to a point where the two systems have different properties.

Update: a demonstration of 3 ways that we have "commuting" operators:
-- trivial, f is essentially the same as g:
f |a> => |b>
f |b> => |c>
g |a> => |b>
g |b> => |c>

-- now test:
sa: g f |a>
|c>

sa: f g |a>
|c>

-- this time, make use of float commutation:
f |a> => 0.71 |b>
f |b> => 0.71 |c>
g |a> => 3.5 |b>
g |b> => 3.5 |c>

-- now test:
sa: g f |a>
2.485|c>

sa: f g |a>
2.485|c>

-- finally, "g f" and "f g" use different pathways, but end at the same spot:
f |a> = |x>
f |y> => |b>
g |a> => |y>
g |x> => |b>

-- now test:
sa: g f |a>
|b>

sa: f g |a>
|b>