How does an algebraic behave?

  • Neutral element of addition is 0 or {} ?
  • neutral element of multiplication is what?
  • what is a unit vector?
In [44]:
from __future__ import print_function
from archery import *
from json import dumps
a = mdict(p=mdict(x=1, y=1, z=1), c = mdict(r=34, g=45, b=1, a=.4))

pp = lambda d : print(dumps(d, indent=4))
pp(a)
{
    "p": {
        "y": 1, 
        "x": 1, 
        "z": 1
    }, 
    "c": {
        "a": 0.4, 
        "r": 34, 
        "b": 1, 
        "g": 45
    }
}
In [45]:
pp(a+{})
pp(a+0)
assert(a+0==a+{})
print(0=={} and "Youpi" or "Humm")
{
    "p": {
        "y": 1, 
        "x": 1, 
        "z": 1
    }, 
    "c": {
        "a": 0.4, 
        "r": 34, 
        "b": 1, 
        "g": 45
    }
}
{
    "p": {
        "y": 1, 
        "x": 1, 
        "z": 1
    }, 
    "c": {
        "a": 0.4, 
        "r": 34, 
        "b": 1, 
        "g": 45
    }
}
Humm
In [46]:
assert(a+{}==a+0==1+a-1)
print("it is true")
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-46-7405f7f5a8d0> in <module>()
----> 1 assert(a+{}==a+0==1+a-1)
      2 print("it is true")

AssertionError: 

What happened?

In [47]:
pp(1+a-1)
{
    "p": {
        "y": 1, 
        "x": 1, 
        "z": 1
    }, 
    "c": {
        "a": 0.3999999999999999, 
        "r": 34, 
        "b": 1, 
        "g": 45
    }
}

I HATE FLOATS since ana num 101

They introduce non commutative behaviours when symbol leads me to think otherwhise.

In [48]:
pp(a*1)
print("hum")
pp(a*mdict(p=1, c=1))
print("hum "*2)
pp(a*a/a)
{
    "p": {
        "y": 1, 
        "x": 1, 
        "z": 1
    }, 
    "c": {
        "a": 0.4, 
        "r": 34, 
        "b": 1, 
        "g": 45
    }
}
hum
{
    "p": {
        "y": 1, 
        "x": 1, 
        "z": 1
    }, 
    "c": {
        "a": 0.4, 
        "r": 34, 
        "b": 1, 
        "g": 45
    }
}
hum hum 
{
    "p": {
        "y": 1.0, 
        "x": 1.0, 
        "z": 1.0
    }, 
    "c": {
        "a": 0.4000000000000001, 
        "r": 34.0, 
        "b": 1.0, 
        "g": 45.0
    }
}
In [49]:
pp(a+a)
assert(a+a == 2*a)
print("it is true")
{
    "p": {
        "y": 2, 
        "x": 2, 
        "z": 2
    }, 
    "c": {
        "a": 0.8, 
        "r": 68, 
        "b": 2, 
        "g": 90
    }
}
it is true

Why are your coordinate so conveniently non null?

In [50]:
pp(1/(a-1))
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-50-1626f73473a5> in <module>()
----> 1 pp(1/(a-1))

/usr/home/jul/src/archery/archery/trait.py in __rdiv__(self, other)
     90 
     91     def __rdiv__(self, other):
---> 92         return self.__rtruediv__(other)
     93 
     94     def __truediv__(self, other):

/usr/home/jul/src/archery/archery/trait.py in __rtruediv__(self, other)
    123         copy = self.copy()
    124         if not isinstance(other, MutableMapping):
--> 125             return copy.__iinv__().__iscalmul__(other)
    126         return copy / other
    127 

/usr/home/jul/src/archery/archery/trait.py in __iinv__(self)
    117         """in place inversion 1/a"""
    118         for k, v in self.items():
--> 119             self[k] = 1/v
    120         return self
    121 

/usr/home/jul/src/archery/archery/trait.py in __rtruediv__(self, other)
    123         copy = self.copy()
    124         if not isinstance(other, MutableMapping):
--> 125             return copy.__iinv__().__iscalmul__(other)
    126         return copy / other
    127 

/usr/home/jul/src/archery/archery/trait.py in __iinv__(self)
    117         """in place inversion 1/a"""
    118         for k, v in self.items():
--> 119             self[k] = 1/v
    120         return self
    121 

ZeroDivisionError: division by zero

BUG!!!

Not a bug : a feature. let's see. 1/0 make a division by 0 error. But a float is an implicit 1 dimnesional value like this:

In [51]:
b=mdict(IAmAReal=0.0)
1/b
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-51-7f17207597c8> in <module>()
      1 b=mdict(IAmAReal=0.0)
----> 2 1/b

/usr/home/jul/src/archery/archery/trait.py in __rdiv__(self, other)
     90 
     91     def __rdiv__(self, other):
---> 92         return self.__rtruediv__(other)
     93 
     94     def __truediv__(self, other):

/usr/home/jul/src/archery/archery/trait.py in __rtruediv__(self, other)
    123         copy = self.copy()
    124         if not isinstance(other, MutableMapping):
--> 125             return copy.__iinv__().__iscalmul__(other)
    126         return copy / other
    127 

/usr/home/jul/src/archery/archery/trait.py in __iinv__(self)
    117         """in place inversion 1/a"""
    118         for k, v in self.items():
--> 119             self[k] = 1/v
    120         return self
    121 

ZeroDivisionError: float division by zero

Can we have an intuition of + / * - in eucledian geometry with this dict?

Did we invented stuff that have no meanings here?!

  • add is translation no?
  • mult is homothetia

How can we make sense of this?

Given an endomorphism in matrice calculus 0 matrice is 0 on all diagonal 1 is 1 on the all the diagonal and if you work with eigenvalues vector if we work with x, y, z then 1 is:

{ x=1, y=1, z=1}
In [52]:
a+0 == a
Out[52]:
True
In [53]:
a*1 == a
Out[53]:
True
In [54]:
pp(a*mdict(p=1,c=1))
u = mdict(p=mdict(x=1,y=1,z=1), c = mdict(r=1,g=1,b=1, a=1))

assert(a*u==a*1)
{
    "p": {
        "y": 1, 
        "x": 1, 
        "z": 1
    }, 
    "c": {
        "a": 0.4, 
        "r": 34, 
        "b": 1, 
        "g": 45
    }
}
In [55]:
a-a == a + (-1 *a)
Out[55]:
True

Basically we just linked translation to homothetia.

We have : adding a vector of opposite direction to itself result in a null vector

So + is a translation of n in every declared direction

ex let's translate p of 1

In [56]:
a+mdict(p=1)
Out[56]:
{'c': {'a': 0.4, 'b': 1, 'g': 45, 'r': 34}, 'p': {'x': 2, 'y': 2, 'z': 2}}

What does * means?

In [57]:
pp(a*mdict(p=1))
{
    "p": {
        "y": 1, 
        "x": 1, 
        "z": 1
    }
}

multiplying by a subpath = 1 is equivalent to get a vector in the sub dimension

We have a pretty intuitional behaviour that match what is known of linear algebra

Of course, I could have implemented other algebra for the fun...

what about cos?

Let's implement "Tanimoto" coefficient cf https://en.wikipedia.org/wiki/Cosine_similarity

$$T(A,B) = \frac{A \cdot B}{\|A\|^2 +\|B\|^2 - A \cdot B}$$
In [43]:
cos_sim = lambda a,b : dot(a,b) / (vabs(a*a) + vabs(b*b) - dot(a,b))
this_theme=mdict(foss=.2, math=1, python=1, perl=1)
python_fosdem=mdict(foss=1, python=2, )
fosdem=mdict(python=1, ruby=1, php=1, perl=1, foss=1, crypto=1)
print(vcos(python_fosdem, fosdem))
print(cos_sim(python_fosdem,fosdem))
print("-"*10)
print(vcos(python_fosdem, this_theme))
print(cos_sim(python_fosdem,this_theme))
print("-"*10)
print(vcos(fosdem, this_theme))
print(cos_sim(fosdem,this_theme))
0.547722557505
0.83972565898
----------
0.564288093647
0.601813386531
----------
0.51512219637
1.10998858246

Is there a trick to algebra-ize non algebric types?

In this case cos will not work we use:

$$\forall (u,v) \in E\times E,\ d(u,v) = \|u-v\|.$$

(math don't follow PEP8)

For the distance

You can thus define - \o/

type overload sub with
string levensthein/hamming
sets len(a&b)/len(u or b)
tuple/lists Hamming/levenstehin
int as bits ....
fallback 1 - (self==other)

PS : distance must stay symmetric |a-b| == |b-a|

We may not now what is a+b but we may know |a-b|

Conclusion

We may define for every algebraic dict (object?!) a distance as long as equal operator is defined

In [ ]: