In [9]:
from sympy import *
init_printing(use_unicode=True)

In [10]:
m = Matrix([1, 2, 3])

In [11]:
m = Matrix(["c"])

In [12]:
m


Out[12]:
$$\left[\begin{matrix}c\end{matrix}\right]$$

In [13]:
m*m


Out[13]:
$$\left[\begin{matrix}c^{2}\end{matrix}\right]$$

In [14]:
from sympy.abc import a,b,c

In [15]:
m


Out[15]:
$$\left[\begin{matrix}c\end{matrix}\right]$$

In [16]:
m = ImmutableMatrix([c,c**2])

In [17]:
m


Out[17]:
$$\left[\begin{matrix}c\\c^{2}\end{matrix}\right]$$

In [18]:
m*m.T


Out[18]:
$$\left[\begin{matrix}c^{2} & c^{3}\\c^{3} & c^{4}\end{matrix}\right]$$

In [26]:
(m*m.T)**2


Out[26]:
$$\left[\begin{matrix}c^{6} + c^{4} & c^{7} + c^{5}\\c^{7} + c^{5} & c^{8} + c^{6}\end{matrix}\right]$$

In [28]:
m[0,0]


Out[28]:
$$c$$

In [20]:
q = Matrix([[1,2],[3,4]])

In [21]:
q^2


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-21-996c8669606a> in <module>()
----> 1 q^2

TypeError: unsupported operand type(s) for ^: 'MutableDenseMatrix' and 'int'

In [25]:
q^-1


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-25-a9aa82ebe639> in <module>()
----> 1 q^-1

TypeError: unsupported operand type(s) for ^: 'MutableDenseMatrix' and 'int'

In [1]:
q**-1


---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-1-df05c56c4aa9> in <module>()
----> 1 q**-1

NameError: name 'q' is not defined

In [ ]:


In [4]:
import numpy as np
from bqplot import *
from bqplot.marks import Graph
from ipywidgets import Layout
from relmath import * 
type(M)

fig_layout = Layout(width='960px', height='500px')
def disp(expr):
    
    print(type(expr))
    if type(expr) is MatMul:
        binop = expr
        
        left =  binop.left.simp()
        right = binop.right.simp()
        
        if type(left) is not Rel:
            raise ValueError("Can't simplify left operand to a Rel ! Found %s " % left)

        if type(right) is not Rel:
            raise ValueError("Can't simplify right operand to a Rel ! Found %s " % right)
            
        print(left)
        print(right)
            
        node_data =  left.dom + left.cod + right.cod
        print(node_data)

        link_data = []
        n = len(left.dom)
        m = len(left.cod)
        w = len(right.cod)
        for i in range(n):
            for j in range(m):
                link_data.append({'source': i, 'target': n+j, 'value': left.g[i][j].val})

        for i in range(m):
            for j in range(w):
                link_data.append({'source': n+i, 'target': n+m+j, 'value': right.g[i][j].val})
                
                
        print(link_data)

        xs = LinearScale()
        ys = LinearScale()
        lcs = ColorScale(scheme='Greens')
        x = ([100] * n) + ([200]*m) + ([300]*w)
        y = list(range(n)) + list(range(m)) + list(range(w))
        print(x)
        print(y)
        graph = Graph(node_data=node_data, link_data=link_data, link_type='line',
                      colors=['orange'], directed=False, 
                      scales={'x': xs, 'y': ys, 'link_color': lcs}, 
                      x=x, y=y,  color=np.random.rand(len(node_data)))
        return Figure(marks=[graph], layout=fig_layout)    
        
    
    elif type(expr) is Rel:
        node_data = expr.dom() + expr.cod()
        #print(node_data)

        link_data = []
        for i in range(len(expr.dom)):
            for j in range(len(expr.cod)):
                link_data.append({'source': i, 'target': i+j, 'value': expr.g[i][j].val})

        #print(link_data)

        xs = LinearScale()
        ys = LinearScale()
        lcs = ColorScale(scheme='Greens')
        x = ([100] * len(expr.dom)) + ([200]*len(expr.cod))
        y = list(range(len(expr.dom))) + list(range(len(expr.cod)))
        #print(x)
        #print(y)
        graph = Graph(node_data=node_data, link_data=link_data, link_type='line',
                      colors=['orange'], directed=False, 
                      scales={'x': xs, 'y': ys, 'link_color': lcs}, 
                      x=x, y=y,  color=np.random.rand(len(node_data)))
        return Figure(marks=[graph], layout=fig_layout)    
    else:
        raise ValueError("not supported type: %s" % type(expr) )
    
disp(E)


M = 
[[9, 0, 6], [0, 5, 7]]
~M = 
[[9, 0], [0, 5], [6, 7]]
-M = 
[[-9, 0, -6], [0, -5, -7]]
M@~M=
[[36, 42], [42, 49]]
MatMul(M, T(M))
[[9, 0, 6], [0, 5, 7]]@~[[9, 0, 6], [0, 5, 7]]
MatMul(M, T(M)).simp()
[[36, 42], [42, 49]]
<class 'relmath.MatMul'>
[[9, 0, 6], [0, 5, 7]]
[[9, 0], [0, 5], [6, 7]]
['a', 'b', 'x', 'y', 'z', 'a', 'b']
[{'source': 0, 'target': 2, 'value': 9}, {'source': 0, 'target': 3, 'value': 0}, {'source': 0, 'target': 4, 'value': 6}, {'source': 1, 'target': 2, 'value': 0}, {'source': 1, 'target': 3, 'value': 5}, {'source': 1, 'target': 4, 'value': 7}, {'source': 2, 'target': 5, 'value': 9}, {'source': 2, 'target': 6, 'value': 0}, {'source': 3, 'target': 5, 'value': 0}, {'source': 3, 'target': 6, 'value': 5}, {'source': 4, 'target': 5, 'value': 6}, {'source': 4, 'target': 6, 'value': 7}]
[100, 100, 200, 200, 200, 300, 300]
[0, 1, 0, 1, 2, 0, 1]

In [ ]:


In [5]:
X = MatrixSymbol('X', 3, 4)

In [6]:
X


Out[6]:
$$X$$

In [35]:
X[0,0]


Out[35]:
$$X_{0, 0}$$

In [36]:
m


Out[36]:
$$\left[\begin{matrix}c\\c^{2}\end{matrix}\right]$$

In [31]:
srepr(m*m)


Out[31]:
"ImmutableDenseMatrix([[Pow(Symbol('c'), Integer(2)), Pow(Symbol('c'), Integer(3))], [Pow(Symbol('c'), Integer(3)), Pow(Symbol('c'), Integer(4))]])"

In [41]:
sympify("m * m.T", locals={'m':m}, evaluate=False)


Out[41]:
$$\left[\begin{matrix}c\\c^{2}\end{matrix}\right] \left[\begin{matrix}c & c^{2}\end{matrix}\right]$$

In [39]:
help(sympify)


Help on function sympify in module sympy.core.sympify:

sympify(a, locals=None, convert_xor=True, strict=False, rational=False, evaluate=None)
    Converts an arbitrary expression to a type that can be used inside SymPy.
    
    For example, it will convert Python ints into instances of sympy.Integer,
    floats into instances of sympy.Float, etc. It is also able to coerce symbolic
    expressions which inherit from Basic. This can be useful in cooperation
    with SAGE.
    
    It currently accepts as arguments:
       - any object defined in sympy
       - standard numeric python types: int, long, float, Decimal
       - strings (like "0.09" or "2e-19")
       - booleans, including ``None`` (will leave ``None`` unchanged)
       - lists, sets or tuples containing any of the above
    
    .. warning::
        Note that this function uses ``eval``, and thus shouldn't be used on
        unsanitized input.
    
    If the argument is already a type that SymPy understands, it will do
    nothing but return that value. This can be used at the beginning of a
    function to ensure you are working with the correct type.
    
    >>> from sympy import sympify
    
    >>> sympify(2).is_integer
    True
    >>> sympify(2).is_real
    True
    
    >>> sympify(2.0).is_real
    True
    >>> sympify("2.0").is_real
    True
    >>> sympify("2e-45").is_real
    True
    
    If the expression could not be converted, a SympifyError is raised.
    
    >>> sympify("x***2")
    Traceback (most recent call last):
    ...
    SympifyError: SympifyError: "could not parse u'x***2'"
    
    Locals
    ------
    
    The sympification happens with access to everything that is loaded
    by ``from sympy import *``; anything used in a string that is not
    defined by that import will be converted to a symbol. In the following,
    the ``bitcount`` function is treated as a symbol and the ``O`` is
    interpreted as the Order object (used with series) and it raises
    an error when used improperly:
    
    >>> s = 'bitcount(42)'
    >>> sympify(s)
    bitcount(42)
    >>> sympify("O(x)")
    O(x)
    >>> sympify("O + 1")
    Traceback (most recent call last):
    ...
    TypeError: unbound method...
    
    In order to have ``bitcount`` be recognized it can be imported into a
    namespace dictionary and passed as locals:
    
    >>> from sympy.core.compatibility import exec_
    >>> ns = {}
    >>> exec_('from sympy.core.evalf import bitcount', ns)
    >>> sympify(s, locals=ns)
    6
    
    In order to have the ``O`` interpreted as a Symbol, identify it as such
    in the namespace dictionary. This can be done in a variety of ways; all
    three of the following are possibilities:
    
    >>> from sympy import Symbol
    >>> ns["O"] = Symbol("O")  # method 1
    >>> exec_('from sympy.abc import O', ns)  # method 2
    >>> ns.update(dict(O=Symbol("O")))  # method 3
    >>> sympify("O + 1", locals=ns)
    O + 1
    
    If you want *all* single-letter and Greek-letter variables to be symbols
    then you can use the clashing-symbols dictionaries that have been defined
    there as private variables: _clash1 (single-letter variables), _clash2
    (the multi-letter Greek names) or _clash (both single and multi-letter
    names that are defined in abc).
    
    >>> from sympy.abc import _clash1
    >>> _clash1
    {'C': C, 'E': E, 'I': I, 'N': N, 'O': O, 'Q': Q, 'S': S}
    >>> sympify('I & Q', _clash1)
    I & Q
    
    Strict
    ------
    
    If the option ``strict`` is set to ``True``, only the types for which an
    explicit conversion has been defined are converted. In the other
    cases, a SympifyError is raised.
    
    >>> print(sympify(None))
    None
    >>> sympify(None, strict=True)
    Traceback (most recent call last):
    ...
    SympifyError: SympifyError: None
    
    Evaluation
    ----------
    
    If the option ``evaluate`` is set to ``False``, then arithmetic and
    operators will be converted into their SymPy equivalents and the
    ``evaluate=False`` option will be added. Nested ``Add`` or ``Mul`` will
    be denested first. This is done via an AST transformation that replaces
    operators with their SymPy equivalents, so if an operand redefines any
    of those operations, the redefined operators will not be used.
    
    >>> sympify('2**2 / 3 + 5')
    19/3
    >>> sympify('2**2 / 3 + 5', evaluate=False)
    2**2/3 + 5
    
    Extending
    ---------
    
    To extend ``sympify`` to convert custom objects (not derived from ``Basic``),
    just define a ``_sympy_`` method to your class. You can do that even to
    classes that you do not own by subclassing or adding the method at runtime.
    
    >>> from sympy import Matrix
    >>> class MyList1(object):
    ...     def __iter__(self):
    ...         yield 1
    ...         yield 2
    ...         return
    ...     def __getitem__(self, i): return list(self)[i]
    ...     def _sympy_(self): return Matrix(self)
    >>> sympify(MyList1())
    Matrix([
    [1],
    [2]])
    
    If you do not have control over the class definition you could also use the
    ``converter`` global dictionary. The key is the class and the value is a
    function that takes a single argument and returns the desired SymPy
    object, e.g. ``converter[MyList] = lambda x: Matrix(x)``.
    
    >>> class MyList2(object):   # XXX Do not do this if you control the class!
    ...     def __iter__(self):  #     Use _sympy_!
    ...         yield 1
    ...         yield 2
    ...         return
    ...     def __getitem__(self, i): return list(self)[i]
    >>> from sympy.core.sympify import converter
    >>> converter[MyList2] = lambda x: Matrix(x)
    >>> sympify(MyList2())
    Matrix([
    [1],
    [2]])
    
    Notes
    =====
    
    Sometimes autosimplification during sympification results in expressions
    that are very different in structure than what was entered. Until such
    autosimplification is no longer done, the ``kernS`` function might be of
    some use. In the example below you can see how an expression reduces to
    -1 by autosimplification, but does not do so when ``kernS`` is used.
    
    >>> from sympy.core.sympify import kernS
    >>> from sympy.abc import x
    >>> -2*(-(-x + 1/x)/(x*(x - 1/x)**2) - 1/(x*(x - 1/x))) - 1
    -1
    >>> s = '-2*(-(-x + 1/x)/(x*(x - 1/x)**2) - 1/(x*(x - 1/x))) - 1'
    >>> sympify(s)
    -1
    >>> kernS(s)
    -2*(-(-x + 1/x)/(x*(x - 1/x)**2) - 1/(x*(x - 1/x))) - 1


In [44]:
Matrix(['s',3])


Out[44]:
$$\left[\begin{matrix}s\\3\end{matrix}\right]$$

In [43]:
p


Out[43]:
$$\left[\begin{matrix}s\\3\end{matrix}\right]$$

In [45]:
Matrix(['s',{'a':'b'}])


Out[45]:
$$\left[\begin{matrix}s\\\left \{ a : b\right \}\end{matrix}\right]$$

In [54]:
p = Matrix(['s',['a']])
p


Out[54]:
$$\left[\begin{matrix}s\\\left [ a\right ]\end{matrix}\right]$$

In [56]:
p += Matrix(["c","d"])


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-56-a01113d62717> in <module>()
----> 1 p += Matrix(["c","d"])

~/.local/lib/python3.5/site-packages/sympy/core/decorators.py in binary_op_wrapper(self, other)
    130                     else:
    131                         return f(self)
--> 132             return func(self, other)
    133         return binary_op_wrapper
    134     return priority_decorator

~/.local/lib/python3.5/site-packages/sympy/matrices/common.py in __add__(self, other)
   1969             if a.__class__ != classof(a, b):
   1970                 b, a = a, b
-> 1971             return a._eval_add(b)
   1972         # Matrix-like objects can be passed to CommonMatrix routines directly.
   1973         if getattr(other, 'is_MatrixLike', False):

~/.local/lib/python3.5/site-packages/sympy/matrices/dense.py in _eval_add(self, other)
    157         # we assume both arguments are dense matrices since
    158         # sparse matrices have a higher priority
--> 159         mat = [a + b for a,b in zip(self._mat, other._mat)]
    160         return classof(self, other)._new(self.rows, self.cols, mat, copy=False)
    161 

~/.local/lib/python3.5/site-packages/sympy/matrices/dense.py in <listcomp>(.0)
    157         # we assume both arguments are dense matrices since
    158         # sparse matrices have a higher priority
--> 159         mat = [a + b for a,b in zip(self._mat, other._mat)]
    160         return classof(self, other)._new(self.rows, self.cols, mat, copy=False)
    161 

TypeError: can only concatenate list (not "Symbol") to list

In [51]:
p = Matrix([[['s'],'r'],['a','e']])


Out[51]:
$$\left[\begin{matrix}\left [ s\right ] & r\\a & e\end{matrix}\right]$$

In [58]:
p.c = 2

In [59]:
p


Out[59]:
$$\left[\begin{matrix}s\\\left [ a\right ]\end{matrix}\right]$$

In [60]:
p.c


Out[60]:
$$2$$

In [61]:
p.afdsf = 2

In [151]:
m = ImmutableMatrix([2,3])

In [317]:
isinstance(4, float)


Out[317]:
False

In [313]:
from sympy.core.singleton import S

    
    
        
class Dioid(AtomicExpr):
    
    is_number = True
    
    @cacheit
    def __new__(cls,*args):
        tmp = []
        for a in args:
            a = sympify(a,strict=True)
            if type(a) is cls:
                tmp.extend(a.args)
            else:
                tmp.append(a)
        return super().__new__(cls,*tmp)    
        
    def __mul__(self, other):
        return self._eval_mul(other)
    
    @decorators._sympifyit('other', NotImplemented)    
    def __add__(self, other):
        return self._eval_add(other)

    def __neg__(self):
        return self._eval_neg()

    def s(self):
        """ The set of discourse """
        raise NotImplementedError("IMPLEMENT ME!")    
                
    def zero(self):
        raise NotImplementedError("IMPLEMENT ME!")    
        
    def one(self):
        raise NotImplementedError("IMPLEMENT ME!")    
        
    def __str__(self):
        
        return "%s(%s)" % (self.__class__.__name__, str(self.args[0]))
    
    def __repr__(self):
        return self.__str__()    

    def _eval_neg(self, other):
        """ NOTE: in a dioid, negation is _not_ mandatory. See page 7 of Graphs, Dioids and Semirings book
        """
        raise NotImplemented("Not available for this dioid !")
        
        raise NotImplementedError("")
        
    def _eval_add(self, other):
        raise NotImplementedError("")
    
    def _eval_mul(self, other):
        raise NotImplementedError("")

    def __radd__(self, a):
        """Implementation of reverse add method."""
        return a.__add__(self)       
    
            
class RD(Dioid):
    def __init__(self, val):
        self.val = sympify(val)
        super().__init__()
    
    def zero(self):
        return S(0)
    
    def one(self):
        return S(1)
    
    def s(self):
        return "TODO R^ set "

    def _eval_neg(self):
        """ NOTE: in a dioid, negation is _not_ mandatory. See page 7 of Graphs, Dioids and Semirings book
        """
        return self.__class__(- self.args[0])
        
    def _eval_add(self, d2):
        
        if isinstance(d2,int) or isinstance(d2,float):
            return self.__class__(self.args[0] * d2)
        elif isinstance(d2, RD):
            return self.__class__(self.args[0] + d2.args[0])
        
    def _eval_mul(self, d2):
        if isinstance(d2,int) or isinstance(d2,float):
            return self.__class__(self.args[0] * d2)
        elif isinstance(d2, RD):
            return self.__class__(self.args[0] * d2.args[0])
        elif return NotImplemented
        
    
    #@classmethod
    #def eval(cls, arg):
        # Phi(x) + Phi(-x) == 1
        #if arg.could_extract_minus_sign():
        #    return 1-cls(-arg)
        
class Rel(ImmutableMatrix):
    def __init__(self, par, dom=[], cod=[]):
        super().__init__()
        self.dom=dom
        self.cod=cod
                
    def _eval_matrix_mul(self, other):
        r = super()._eval_matrix_mul(other)
        r.dom = self.dom
        r.cod = other.cod
        return r
    
    def _eval_transpose(self):
        r = super()._eval_transpose()
        r.dom = self.cod
        r.cod = self.dom
        return r
    
    T = property(transpose, None, None, "Matrix transposition.")

In [314]:
(Add(RD(3), RD(7))).evalf()


Out[314]:
$$RD(3) + RD(7)$$

In [315]:
simplify(Add(RD(3), RD(7)))


Out[315]:
$$RD(3) + RD(7)$$

In [291]:
RD(5)


Out[291]:
$$RD(5)$$

In [292]:
RD(5) == RD(5)


Out[292]:
True

In [293]:
-RD(5)


Out[293]:
$$RD(-5)$$

In [294]:
RD(3) + RD(7)


Out[294]:
$$RD(10)$$

In [295]:
w = Rel([RD(3)])

In [296]:
sympify(Add(RD(3), RD(7)))


Out[296]:
$$RD(3) + RD(7)$$

In [285]:
Add(RD(3), RD(7)).doit()


Out[285]:
$$RD(3) + RD(7)$$

In [286]:
simplify(Add(RD(3), RD(7)))


Out[286]:
$$RD(3) + RD(7)$$

In [300]:
(Add(Integer(3), Integer(7))).evalf()


Out[300]:
$$10.0$$

In [301]:
simplify(Add(Integer(3), Integer(7)))


Out[301]:
$$10$$

In [258]:
w = Rel([[RD(2),RD(5)]], dom=['a','b'], cod=['x','y','z'])

In [259]:
w


Out[259]:
$$\left[\begin{matrix}RD(2) & RD(5)\end{matrix}\right]$$

In [261]:
x = w*w.T

In [270]:
x


Out[270]:
$$\left[\begin{matrix}RD(4) + RD(25)\end{matrix}\right]$$

In [274]:
simplify(x[0])


Out[274]:
$$RD(4) + RD(25)$$

In [263]:
r = Rel([[2,5]], dom=['a','b'], cod=['x','y','z'])

In [268]:
p = r*r.T

In [269]:
p


Out[269]:
$$\left[\begin{matrix}29\end{matrix}\right]$$

In [265]:
type(p)


Out[265]:
__main__.Rel

In [266]:
p.dom


Out[266]:
['a', 'b']

In [267]:
p.cod


Out[267]:
['a', 'b']

In [160]:
r


Out[160]:
$$\left[\begin{matrix}2 & 5\end{matrix}\right]$$

In [106]:
r.dom


Out[106]:
['a', 'b']

In [107]:
Rel([2,5])


Out[107]:
$$\left[\begin{matrix}2\\5\end{matrix}\right]$$

In [109]:
s = sympify("r * r.T", locals={'r':r}, evaluate=False)

In [111]:
s


Out[111]:
$$\left[\begin{matrix}2\\5\end{matrix}\right] \left[\begin{matrix}2 & 5\end{matrix}\right]$$

In [113]:
s.args[0].dom


Out[113]:
['a', 'b']

In [115]:
s.args[0].cod


Out[115]:
['x', 'y', 'z']

In [ ]:
s.simplify

In [81]:
m


Out[81]:
$$\left[\begin{matrix}2\\3\end{matrix}\right]$$

In [82]:
m.prova = ['a','b']

In [83]:
m.prova


Out[83]:
['a', 'b']

In [84]:
s = sympify("m * m.T", locals={'m':m}, evaluate=False)

In [85]:
s


Out[85]:
$$\left[\begin{matrix}2\\3\end{matrix}\right] \left[\begin{matrix}2 & 3\end{matrix}\right]$$

In [86]:
s.args[0]


Out[86]:
$$\left[\begin{matrix}2\\3\end{matrix}\right]$$

In [87]:
s.args[0].prova


---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-87-35e336bb4cee> in <module>()
----> 1 s.args[0].prova

~/.local/lib/python3.5/site-packages/sympy/matrices/matrices.py in __getattr__(self, attr)
   1954         else:
   1955             raise AttributeError(
-> 1956                 "%s has no attribute %s." % (self.__class__.__name__, attr))
   1957 
   1958     def __len__(self):

AttributeError: ImmutableDenseMatrix has no attribute prova.

In [ ]: