def __new__(cls, name, base: CoordSys3D):
        x, y, z = symbols('x,y,z', cls=DummyVariable)

        q, r, s = symbols('q,r,s', cls=DummyVariable)

        tvec: vector.VectorAdd = x * base.i + y * base.j + z * base.k
        rvec: vector.VectorAdd = q * base.i + r * base.j + s * base.k

        rot_mat = ImmutableDenseMatrix([
        [                                                                            (q**2 + (r**2 + s**2)*cos(sqrt(q**2 + r**2 + s**2)))/(q**2 + r**2 + s**2),  (q*r*(1 - cos(sqrt(q**2 + r**2 + s**2)))*sqrt(q**2 + r**2 + s**2) + s*(q**2 + r**2 + s**2)*sin(sqrt(q**2 + r**2 + s**2)))/(q**2 + r**2 + s**2)**(3/2), (q*s*(1 - cos(sqrt(q**2 + r**2 + s**2)))*sqrt(q**2 + r**2 + s**2) - r*(q**2 + r**2 + s**2)*sin(sqrt(q**2 + r**2 + s**2)))/(q**2 + r**2 + s**2)**(3/2)],
        [(q*r*(1 - cos(sqrt(q**2 + r**2 + s**2)))*sqrt(q**2 + r**2 + s**2) - s*(q**2 + r**2 + s**2)*sin(sqrt(q**2 + r**2 + s**2)))/(q**2 + r**2 + s**2)**(3/2),                                                                              (r**2 + (q**2 + s**2)*cos(sqrt(q**2 + r**2 + s**2)))/(q**2 + r**2 + s**2), (q*(q**2 + r**2 + s**2)*sin(sqrt(q**2 + r**2 + s**2)) + r*s*(1 - cos(sqrt(q**2 + r**2 + s**2)))*sqrt(q**2 + r**2 + s**2))/(q**2 + r**2 + s**2)**(3/2)],
        [(q*s*(1 - cos(sqrt(q**2 + r**2 + s**2)))*sqrt(q**2 + r**2 + s**2) + r*(q**2 + r**2 + s**2)*sin(sqrt(q**2 + r**2 + s**2)))/(q**2 + r**2 + s**2)**(3/2), (-q*(q**2 + r**2 + s**2)*sin(sqrt(q**2 + r**2 + s**2)) + r*s*(1 - cos(sqrt(q**2 + r**2 + s**2)))*sqrt(q**2 + r**2 + s**2))/(q**2 + r**2 + s**2)**(3/2),                                                                             (s**2 + (q**2 + r**2)*cos(sqrt(q**2 + r**2 + s**2)))/(q**2 + r**2 + s**2)]])
        # obj = base.locate_new(name, tvec)
        obj = CoordSys3D.__new__(cls, name, location=tvec,
                                 rotation_matrix=rot_mat,
                                 vector_names=base._vector_names,
                                 variable_names=base._variable_names,
                                 parent=base)
        obj.x, obj.y, obj.z = x, y, z
        obj.q, obj.r, obj.s = q, r, s

        obj._tvec = tvec
        obj._rvec = rvec
        obj._rot_mat = rot_mat
        return obj
Ejemplo n.º 2
0
    def eval(cls, *_args):

        if not _args:
            return

        u = _args[0]

        return ImmutableDenseMatrix([[dy(u)], [-dx(u)]])
Ejemplo n.º 3
0
    def eval(cls, *_args):

        if not _args:
            return

        u = _args[0]

        return ImmutableDenseMatrix([[dy(u[2]) - dz(u[1])],
                                     [dz(u[0]) - dx(u[2])],
                                     [dx(u[1]) - dy(u[0])]])
Ejemplo n.º 4
0
    def __new__(cls, u, mapping=None):
        if not isinstance(u, (VectorTestFunction, ScalarTestFunction,
                              ScalarField, VectorField)):
            raise TypeError(
                '{} must be of type ScalarTestFunction or VectorTestFunction'.
                format(str(u)))

        if u.space.domain.mapping is None:
            raise ValueError(
                'The pull-back can be performed only to mapped domains')

        space = u.space
        kind = space.kind
        dim = space.ldim
        el = get_logical_test_function(u)

        if space.is_broken:
            assert mapping is not None
        else:
            mapping = space.domain.mapping

        J = mapping.jacobian
        if isinstance(kind, (UndefinedSpaceType, H1SpaceType)):
            expr = el
        elif isinstance(kind, HdivSpaceType):
            expr = (J / J.det()) * ImmutableDenseMatrix(
                tuple(el[i] for i in range(dim)))
        elif isinstance(kind, HcurlSpaceType):
            expr = J.inv().T * ImmutableDenseMatrix(
                tuple(el[i] for i in range(dim)))
        elif isinstance(kind, L2SpaceType):
            expr = J.det() * el
#        elif isinstance(kind, UndefinedSpaceType):
#            raise ValueError('kind must be specified in order to perform the pull-back transformation')
        else:
            raise ValueError("Unrecognized kind '{}' of space {}".format(
                kind, str(u.space)))

        obj = Expr.__new__(cls, u)
        obj._expr = expr
        obj._kind = kind
        obj._test = el
        return obj
Ejemplo n.º 5
0
def _to_matrix_form(expr, *, trials=None, tests=None):
    """
    Create a matrix representation of input expression, based on trial and
    test functions. We have three options:

    1. if both the trial and test functions are given, we treat the expression
       as a bilinear form and convert it to a (n_rows x n_cols) rectangular
       matrix with n_rows = len(tests) and n_cols = len(trials);

    2. if only the test functions are given, we treat the expression as a
       linear form and convert it to a (n_rows x 1) matrix (column vector) with
       n_rows = len(tests);

    3. if neither the trial nor the test functions are given, we treat the
       expression as a scalar functional and convert it to a 1x1 matrix.

    Parameters
    ----------
    expr : sympy.Expr
        Expression corresponding to a bilinear/linear form or functional.

    trials : iterable
        List of all scalar trial functions (after unpacking vector functions).

    tests : iterable
        List of all scalar test functions (after unpacking vector functions).

    Returns
    -------
    M : sympy.matrices.immutable.ImmutableDenseMatrix
        Matrix representation of input expression.

    """
    # Bilinear form
    if trials and tests:
        M = Matrix.zeros(len(tests), len(trials))
        for i, test in enumerate(tests):
            subs_i = {v: 0 for v in tests if v != test}
            expr_i = expr.subs(subs_i)
            for j, trial in enumerate(trials):
                subs_j = {u: 0 for u in trials if u != trial}
                M[i, j] = expr_i.subs(subs_j)

    # Linear form
    elif tests:
        M = Matrix.zeros(len(tests), 1)
        for i, test in enumerate(tests):
            subs_i = {v: 0 for v in tests if v != test}
            M[i, 0] = expr.subs(subs_i)

    # Functional
    else:
        M = [[expr]]

    return ImmutableDenseMatrix(M)
Ejemplo n.º 6
0
    def eval(cls, *_args):

        if not _args:
            return

        u = _args[0]
        if isinstance(u, (VectorTestFunction, VectorField)):
            raise NotImplementedError('TODO')

        return ImmutableDenseMatrix([[dx(dx(u)), dx(dy(u))],
                                     [dx(dy(u)), dy(dy(u))]])
Ejemplo n.º 7
0
    def eval(cls, *_args):

        if not _args:
            return

        u = _args[0]
        if isinstance(u, VectorFunction):
            raise NotImplementedError('TODO')

        return ImmutableDenseMatrix([[dx1(dx1(u)), dx1(dx2(u))],
                                     [dx1(dx2(u)), dx2(dx2(u))]])
Ejemplo n.º 8
0
    def eval(cls, *_args):

        if not _args:
            return

        u = _args[0]
        du = (dx1(u), dx2(u), dx3(u))

        if isinstance(du[0], (Tuple, Matrix, ImmutableDenseMatrix)):
            lines = [list(d[:]) for d in du]
        else:
            lines = [[d] for d in du]

        v = ImmutableDenseMatrix(lines)
        return v
    def __init__(self, n, link_length = 0.3, k_val = 1):
        
        l = symbols('l')  #the link length
        k = symbols('k')  #the liquid vicousness
        q = symbols('q:' + str(n - 1)) #the joint angle


        #################################################
        ################### Question  ###################
        #################################################
        assert(n==3)

        # #this is the swimmer matrix part
        # F1 = ImmutableDenseMatrix([k[0] * l[0] * (cos(q[0]) * dx0 - sin(q[0]) * dy0 + sin(q[0]) * l[0] * dtheta0),
        #             2 * k[0] * l[0] * (sin(q[0]) * dx0 + cos(q[0]) * dy0 - l[0] * (1 + cos(q[0])) * dtheta0 + l[0] * u[0]),
        #             2.0 / 3.0 * k[0] * l[0]**3.0 * (dtheta0 - u[0])])

        # F2 = ImmutableDenseMatrix([k[0] * l[0] * dx0, 2 * k[0] * l[0] * dy0, 2.0 / 3.0 * k[0] * l[0]**3 * dtheta0])

        # F3 = ImmutableDenseMatrix([k[0] * l[0] * (cos(q[1]) * dx0 + sin(q[1]) * dy0 + l[0] * sin(q[1]) * l[0] * dtheta0),
        #             2 * k[0] * l[0] * (-sin(q[1]) * dx0 + cos(q[1]) * dy0 + l[0] * (1 + cos(q[1])) * dtheta0 + l[0] * u[1]),
        #             2.0 / 3.0 * k[0] * l[0]**3.0 * (dtheta0 + u[1])])

        # Q1 = ImmutableDenseMatrix([[cos(q[0]), sin(q[0]), 0],
        #             [-sin(q[0]), cos(q[0]), 0],
        #             [l[0] * sin(q[0]), - l[0] * (1 + cos(q[0])), 1]])

        # Q2 = ImmutableDenseMatrix([[cos(q[1]), -sin(q[1]), 0],
        #             [sin(q[1]), cos(q[1]), 0],
        #             [l[0] * sin(q[1]), l[0] * (1 + cos(q[1])), 1]])

        # F = (Q1 * F1 + F2 + Q2 * F3).simplify()
        # w1 = ImmutableDenseMatrix(diff(flatten(F), dx0), diff(flatten(F), dy0, diff(flatten(F), dtheta0)))


        w1 = ImmutableDenseMatrix(
            [   
                [-1.0/2 * k * l * (cos(2 * q[0]) + cos(2 * q[1]) - 8),
                -1.0/2 * k * l * (sin(2 * q[1]) - 2 * cos(q[0]) * sin(q[0])),
                -1.0/2 * k * l * ( 2 * l * (cos(q[0])+2) * sin(q[0] + 4 * l * sin(q[1]) + l * sin(2*q[1])))],
                [1.0/2 * k * l * (sin(2 * q[0]) - sin(2 * q[1])),
                 1.0/2 * k * l * (cos(2 * q[0]) + cos(2 * q[1]) + 10),
                 1.0/2 * k * l**2 * ( -4 * cos(q[0]) - cos(2 * q[0]) + 4 * cos(q[1]) + cos(2 * q[1]))],
                [1.0/2 * k * l**2 * ( 4 * sin(q[0]) + sin(2 * q[0]) + 4 * sin(q[1]) + sin(2 * q[1])),
                 1.0/2 * k * l**2 * ( -4 * cos(q[0]) - cos(2 * q[0]) + 4 * cos(q[1]) + cos(2 * q[1])),
                 1.0/2 * k * l**3 * ( 8 * cos(q[0]) - cos(2 * q[0]) + 8 * cos(q[1]) + cos(2 * q[1]) + 18)
                ]
            ])

        w2 = ImmutableDenseMatrix(
            [
                [2 * k * l**2 * sin(q[0]), 
                 -2 * k * l**2 * sin(q[1])
                ],
                [2 * k * l**2 * cos(q[0]),
                 2 * k * l**2 * cos(q[1])
                ],
                [-2.0 / 3 * k * l**3 * (3 * cos(q[0]) + 4),
                 2.0 / 3 * k * l**3 * (3 * cos(q[1]) + 4)                
                ]
            ])

        #A = (w1.inv() * w2).simply()

        #A = w1.LUsolve(w2)
        #print(A)

        #A.simplify()
        #pprint(A)



        #initialize self objects
        self.l = l
        self.k = k
        self.q = q
        self.n = n              #the number of links


        self.link_length = link_length
        self.k_val = k_val

        #set the value for all the variables
        parameters = (self.k, self.l)
        self.parameter_vals = [self.k_val, self.link_length]
        #this can potentially be improved, probably through substituting in this function


        self.w1_func = lambdify(q + parameters, w1)
        self.w2_func = lambdify(q + parameters, w2) 
    def __init__(self, n, link_length = 0.3, k_val = 1):
        
        l = symbols('l')  #the link length
        k = symbols('k')  #the liquid vicousness
        q = symbols('q:' + str(n - 1)) #the joint angle


        #l and k are useless now

        assert(n==3)


        rho=1
        a=4
        b=1

        demonimator = (np.pi**3*rho**3*(-25*a**8 - 186*a**6*b**2 - 218*a**4*b**4 - 42*a**2*b**6 - 9*b**8 + (a - b)*(a + b)*(19*a**6 + 63*a**4*b**2 + a**2*b**4 - 3*b**6)*cos(2*q[1]) - 
               (a - b)*(a + b)*cos(2*q[0])*(-19*a**6 - 63*a**4*b**2 - a**2*b**4 + 3*b**6 + (13*a**6 - 31*a**4*b**2 - a**2*b**4 + 3*b**6)*cos(2*q[1])) + 
               32*b**2*cos(q[1])*(-9*a**4*b**2*cos(q[0])**2 - (2*a**3 + a*b**2)**2*sin(q[0])**2) + 32*a**2*b**4*(2*a**2 + b**2)*sin(q[0])*sin(q[1]) + 16*a**2*b**2*(-2*a**4 + a**2*b**2 + b**4)*sin(q[0])*sin(2*q[1]) + 
               2*cos(q[0])*(-8*a**2*b**2*(4*a**4 + 13*a**2*b**2 + b**4) - 48*a**4*b**4*cos(q[1]) + 
                  (a - b)*(a + b)*(8*a**2*b**2*((4*a**2 - b**2)*cos(2*q[1]) - 2*(2*a**2 + b**2)*sin(q[0])*sin(q[1])) + (-3*a**6 + a**4*b**2 - 17*a**2*b**4 + 3*b**6)*sin(q[0])*sin(2*q[1])))))/8.


        nominator = ImmutableDenseMatrix(
            np.array([
                [(a*np.pi**3*rho**3*(2*b**2*(19*a**6 + 37*a**4*b**2 + 9*a**2*b**4 + 3*b**6)*sin(q[0]) + (a**2 + b**2)*(a**2 + 2*b**2)*(a**4 + 4*a**2*b**2 - b**4)*sin(2*q[0]) - 16*a**6*b**2*sin(q[0] - 2*q[1]) + 
                   8*a**4*b**4*sin(q[0] - 2*q[1]) + 8*a**2*b**6*sin(q[0] - 2*q[1]) + 48*a**4*b**4*sin(q[0] - q[1]) + 24*a**2*b**6*sin(q[0] - q[1]) - 3*a**6*b**2*sin(q[1]) - 21*a**4*b**4*sin(q[1]) - 
                   13*a**2*b**6*sin(q[1]) - 3*b**8*sin(q[1]) + a**8*sin(2*q[1]) + 7*a**6*b**2*sin(2*q[1]) - 3*a**4*b**4*sin(2*q[1]) - 3*a**2*b**6*sin(2*q[1]) - 2*b**8*sin(2*q[1]) + 16*a**4*b**4*sin(q[0] + q[1]) + 
                   8*a**2*b**6*sin(q[0] + q[1]) - a**8*sin(2*(q[0] + q[1])) - 4*a**6*b**2*sin(2*(q[0] + q[1])) + 2*a**4*b**4*sin(2*(q[0] + q[1])) + 4*a**2*b**6*sin(2*(q[0] + q[1])) - b**8*sin(2*(q[0] + q[1])) + 
                   a**6*b**2*sin(2*q[0] + q[1]) + 5*a**4*b**4*sin(2*q[0] + q[1]) + 3*a**2*b**6*sin(2*q[0] + q[1]) - b**8*sin(2*q[0] + q[1]) + 2*b**2*(-9*a**6 + 7*a**4*b**2 - 3*a**2*b**4 + b**6)*sin(q[0] + 2*q[1])))/8.,
                  (a*np.pi**3*rho**3*(b**2*(3*a**6 + 21*a**4*b**2 + 13*a**2*b**4 + 3*b**6 + 16*a**2*b**2*(2*a**2 + b**2)*cos(q[1]) - (a**2 + b**2)*(a**4 + 4*a**2*b**2 - b**4)*cos(2*q[1]))*sin(q[0]) + 
                       (-a**8 - 7*a**6*b**2 + 3*a**4*b**4 + 3*a**2*b**6 + 2*b**8 + 2*b**2*(a**6 - 3*a**4*b**2 + 7*a**2*b**4 - b**6)*cos(q[1]) + (a**8 + 4*a**6*b**2 - 2*a**4*b**4 - 4*a**2*b**6 + b**8)*cos(2*q[1]))*sin(2*q[0]) - 
                       2*b**2*(19*a**6 + 37*a**4*b**2 + 9*a**2*b**4 + 3*b**6 + 16*a**2*b**2*(2*a**2 + b**2)*cos(q[0]) + (-17*a**6 + 11*a**4*b**2 + a**2*b**4 + b**6)*cos(2*q[0]))*sin(q[1]) + 
                       (a**2 + b**2)*(-a**4 - 4*a**2*b**2 + b**4)*(a**2 + 2*b**2 + b**2*cos(q[0]) + (-a**2 + b**2)*cos(2*q[0]))*sin(2*q[1])))/8.],
                [(a*np.pi**3*rho**3*(-24*a**4*b**4 - (a**2 + b**2)*(2*a**2 + b**2)*(a**4 + 4*a**2*b**2 - b**4)*cos(2*q[0]) + 
                        b**2*(-5*a**6 - 31*a**4*b**2 - 3*a**2*b**4 - b**6 - (a**2 + b**2)*(a**4 + 4*a**2*b**2 - b**4)*cos(2*q[0]))*cos(q[1]) + (a - b)*(a + b)*(2*a**6 + 13*a**4*b**2 + b**6)*cos(2*q[1]) + 
                        2*b**2*cos(q[0])*(-21*a**6 - 43*a**4*b**2 - 3*a**2*b**4 - b**6 - 72*a**4*b**2*cos(q[1]) + (15*a**6 - 17*a**4*b**2 - 3*a**2*b**4 + b**6)*cos(2*q[1])) + 
                        b**2*(a**2 + b**2)*(a**4 + 4*a**2*b**2 - b**4)*sin(2*q[0])*sin(q[1]) - 2*b**2*(-9*a**6 + 7*a**4*b**2 - 3*a**2*b**4 + b**6)*sin(q[0])*sin(2*q[1])))/8.,
                   (a*np.pi**3*rho**3*(-24*a**4*b**4 + (a - b)*(a + b)*(2*a**6 + 13*a**4*b**2 + b**6)*cos(2*q[0]) + 
                        2*b**2*(-21*a**6 - 43*a**4*b**2 - 3*a**2*b**4 - b**6 + (15*a**6 - 17*a**4*b**2 - 3*a**2*b**4 + b**6)*cos(2*q[0]))*cos(q[1]) - (a**2 + b**2)*(2*a**2 + b**2)*(a**4 + 4*a**2*b**2 - b**4)*cos(2*q[1]) + 
                        b**2*cos(q[0])*(-5*a**6 - 31*a**4*b**2 - 3*a**2*b**4 - b**6 - 144*a**4*b**2*cos(q[1]) - (a**2 + b**2)*(a**4 + 4*a**2*b**2 - b**4)*cos(2*q[1])) - 
                        2*b**2*(-9*a**6 + 7*a**4*b**2 - 3*a**2*b**4 + b**6)*sin(2*q[0])*sin(q[1]) + b**2*(a**2 + b**2)*(a**4 + 4*a**2*b**2 - b**4)*sin(q[0])*sin(2*q[1])))/8.],
                [(np.pi**3*rho**3*(-3*a**8 - 30*a**6*b**2 - 46*a**4*b**4 - 14*a**2*b**6 - 3*b**8 + 2*(a**8 + 4*a**6*b**2 - 2*a**4*b**4 - 4*a**2*b**6 + b**8)*cos(2*q[0])*cos(q[1])**2 + 
                        (a**2 - b**2)**2*(a**4 + 6*a**2*b**2 + b**4)*cos(2*q[1]) - 16*a**2*b**2*(2*a**2 + b**2)*(-b**2 + (a - b)*(a + b)*cos(q[1]))*sin(q[0])*sin(q[1]) + 
                        2*cos(q[0])*(-24*a**4*b**4*cos(q[1])*(1 + 3*cos(q[1])) - 8*a**2*b**2*(2*a**2 + b**2)**2*sin(q[1])**2 - (a**8 + 4*a**6*b**2 - 2*a**4*b**4 - 4*a**2*b**6 + b**8)*sin(q[0])*sin(2*q[1]))))/8.,
                   (np.pi**3*rho**3*(3*a**8 + 30*a**6*b**2 + 46*a**4*b**4 + 14*a**2*b**6 + 3*b**8 - (a**2 - b**2)**2*(a**4 + 6*a**2*b**2 + b**4)*cos(2*q[0]) + 
                        8*a**2*b**2*(4*a**4 + 13*a**2*b**2 + b**4 + 6*a**2*b**2*cos(q[0]) - (4*a**4 - 5*a**2*b**2 + b**4)*cos(2*q[0]))*cos(q[1]) - 
                        2*(a**8 + 4*a**6*b**2 - 2*a**4*b**4 - 4*a**2*b**6 + b**8)*cos(q[0])**2*cos(2*q[1]) + 16*a**2*b**2*(2*a**2 + b**2)*(-b**2 + (a - b)*(a + b)*cos(q[0]))*sin(q[0])*sin(q[1]) + 
                        (a**8 + 4*a**6*b**2 - 2*a**4*b**4 - 4*a**2*b**6 + b**8)*sin(2*q[0])*sin(2*q[1])))/8.]
           ])
        )

        
        A = nominator / demonimator



        #initialize self objects
        self.l = l
        self.k = k
        self.q = q
        self.n = n              #the number of links


        self.link_length = link_length
        self.k_val = k_val

        #set the value for all the variables
        parameters = (self.k, self.l)
        self.parameter_vals = [self.k_val, self.link_length]
        #this can potentially be improved, probably through substituting in this function
        

        self.A_func = lambdify(q, A)
Ejemplo n.º 11
0
    def __new__(cls,
                name,
                transformation=None,
                parent=None,
                location=None,
                rotation_matrix=None,
                vector_names=None,
                variable_names=None):
        """
        The orientation/location parameters are necessary if this system
        is being defined at a certain orientation or location wrt another.

        Parameters
        ==========

        name : str
            The name of the new CoordSys3D instance.

        transformation : Lambda, Tuple, str
            Transformation defined by transformation equations or chosen
            from predefined ones.

        location : Vector
            The position vector of the new system's origin wrt the parent
            instance.

        rotation_matrix : SymPy ImmutableMatrix
            The rotation matrix of the new coordinate system with respect
            to the parent. In other words, the output of
            new_system.rotation_matrix(parent).

        parent : CoordSys3D
            The coordinate system wrt which the orientation/location
            (or both) is being defined.

        vector_names, variable_names : iterable(optional)
            Iterables of 3 strings each, with custom names for base
            vectors and base scalars of the new system respectively.
            Used for simple str printing.

        """

        name = str(name)
        Vector = sympy.vector.Vector
        BaseVector = sympy.vector.BaseVector
        Point = sympy.vector.Point

        if not isinstance(name, string_types):
            raise TypeError("name should be a string")

        if transformation is not None:
            if (location is not None) or (rotation_matrix is not None):
                raise ValueError("specify either `transformation` or "
                                 "`location`/`rotation_matrix`")
            if isinstance(transformation, (Tuple, tuple, list)):
                if isinstance(transformation[0], MatrixBase):
                    rotation_matrix = transformation[0]
                    location = transformation[1]
                else:
                    transformation = Lambda(transformation[0],
                                            transformation[1])
            elif isinstance(transformation, Callable):
                x1, x2, x3 = symbols('x1 x2 x3', cls=Dummy)
                transformation = Lambda((x1, x2, x3),
                                        transformation(x1, x2, x3))
            elif isinstance(transformation, string_types):
                transformation = Symbol(transformation)
            elif isinstance(transformation, (Symbol, Lambda)):
                pass
            else:
                raise TypeError("transformation: "
                                "wrong type {0}".format(type(transformation)))

        # If orientation information has been provided, store
        # the rotation matrix accordingly
        if rotation_matrix is None:
            rotation_matrix = ImmutableDenseMatrix(eye(3))
        else:
            if not isinstance(rotation_matrix, MatrixBase):
                raise TypeError("rotation_matrix should be an Immutable" +
                                "Matrix instance")
            rotation_matrix = rotation_matrix.as_immutable()

        # If location information is not given, adjust the default
        # location as Vector.zero
        if parent is not None:
            if not isinstance(parent, CoordSys3D):
                raise TypeError("parent should be a " + "CoordSys3D/None")
            if location is None:
                location = Vector.zero
            else:
                if not isinstance(location, Vector):
                    raise TypeError("location should be a Vector")
                # Check that location does not contain base
                # scalars
                for x in location.free_symbols:
                    if isinstance(x, BaseScalar):
                        raise ValueError("location should not contain" +
                                         " BaseScalars")
            origin = parent.origin.locate_new(name + '.origin', location)
        else:
            location = Vector.zero
            origin = Point(name + '.origin')

        if transformation is None:
            transformation = Tuple(rotation_matrix, location)

        if isinstance(transformation, Tuple):
            lambda_transformation = CoordSys3D._compose_rotation_and_translation(
                transformation[0], transformation[1], parent)
            r, l = transformation
            l = l._projections
            lambda_lame = CoordSys3D._get_lame_coeff('cartesian')
            lambda_inverse = lambda x, y, z: r.inv() * Matrix(
                [x - l[0], y - l[1], z - l[2]])
        elif isinstance(transformation, Symbol):
            trname = transformation.name
            lambda_transformation = CoordSys3D._get_transformation_lambdas(
                trname)
            if parent is not None:
                if parent.lame_coefficients() != (S.One, S.One, S.One):
                    raise ValueError('Parent for pre-defined coordinate '
                                     'system should be Cartesian.')
            lambda_lame = CoordSys3D._get_lame_coeff(trname)
            lambda_inverse = CoordSys3D._set_inv_trans_equations(trname)
        elif isinstance(transformation, Lambda):
            if not CoordSys3D._check_orthogonality(transformation):
                raise ValueError("The transformation equation does not "
                                 "create orthogonal coordinate system")
            lambda_transformation = transformation
            lambda_lame = CoordSys3D._calculate_lame_coeff(
                lambda_transformation)
            lambda_inverse = None
        else:
            lambda_transformation = lambda x, y, z: transformation(x, y, z)
            lambda_lame = CoordSys3D._get_lame_coeff(transformation)
            lambda_inverse = None

        if variable_names is None:
            if isinstance(transformation, Lambda):
                variable_names = ["x1", "x2", "x3"]
            elif isinstance(transformation, Symbol):
                if transformation.name == 'spherical':
                    variable_names = ["r", "theta", "phi"]
                elif transformation.name == 'cylindrical':
                    variable_names = ["r", "theta", "z"]
                else:
                    variable_names = ["x", "y", "z"]
            else:
                variable_names = ["x", "y", "z"]
        if vector_names is None:
            vector_names = ["i", "j", "k"]

        # All systems that are defined as 'roots' are unequal, unless
        # they have the same name.
        # Systems defined at same orientation/position wrt the same
        # 'parent' are equal, irrespective of the name.
        # This is true even if the same orientation is provided via
        # different methods like Axis/Body/Space/Quaternion.
        # However, coincident systems may be seen as unequal if
        # positioned/oriented wrt different parents, even though
        # they may actually be 'coincident' wrt the root system.
        if parent is not None:
            obj = super(CoordSys3D, cls).__new__(cls, Symbol(name),
                                                 transformation, parent)
        else:
            obj = super(CoordSys3D, cls).__new__(cls, Symbol(name),
                                                 transformation)
        obj._name = name
        # Initialize the base vectors

        _check_strings('vector_names', vector_names)
        vector_names = list(vector_names)
        latex_vects = [(r'\mathbf{\hat{%s}_{%s}}' % (x, name))
                       for x in vector_names]
        pretty_vects = ['%s_%s' % (x, name) for x in vector_names]

        obj._vector_names = vector_names

        v1 = BaseVector(0, obj, pretty_vects[0], latex_vects[0])
        v2 = BaseVector(1, obj, pretty_vects[1], latex_vects[1])
        v3 = BaseVector(2, obj, pretty_vects[2], latex_vects[2])

        obj._base_vectors = (v1, v2, v3)

        # Initialize the base scalars

        _check_strings('variable_names', vector_names)
        variable_names = list(variable_names)
        latex_scalars = [(r"\mathbf{{%s}_{%s}}" % (x, name))
                         for x in variable_names]
        pretty_scalars = ['%s_%s' % (x, name) for x in variable_names]

        obj._variable_names = variable_names
        obj._vector_names = vector_names

        x1 = BaseScalar(0, obj, pretty_scalars[0], latex_scalars[0])
        x2 = BaseScalar(1, obj, pretty_scalars[1], latex_scalars[1])
        x3 = BaseScalar(2, obj, pretty_scalars[2], latex_scalars[2])

        obj._base_scalars = (x1, x2, x3)

        obj._transformation = transformation
        obj._transformation_lambda = lambda_transformation
        obj._lame_coefficients = lambda_lame(x1, x2, x3)
        obj._transformation_from_parent_lambda = lambda_inverse

        setattr(obj, variable_names[0], x1)
        setattr(obj, variable_names[1], x2)
        setattr(obj, variable_names[2], x3)

        setattr(obj, vector_names[0], v1)
        setattr(obj, vector_names[1], v2)
        setattr(obj, vector_names[2], v3)

        # Assign params
        obj._parent = parent
        if obj._parent is not None:
            obj._root = obj._parent._root
        else:
            obj._root = obj

        obj._parent_rotation_matrix = rotation_matrix
        obj._origin = origin

        # Return the instance
        return obj
Ejemplo n.º 12
0
def _to_matrix_form(expr, *, trials=None, tests=None, domain=None):
    """
    Create a matrix representation of input expression, based on trial and
    test functions. We have three options:

    1. if both the trial and test functions are given, we treat the expression
       as a bilinear form and convert it to a (n_rows x n_cols) rectangular
       matrix with n_rows = len(tests) and n_cols = len(trials);

    2. if only the test functions are given, we treat the expression as a
       linear form and convert it to a (n_rows x 1) matrix (column vector) with
       n_rows = len(tests);

    3. if neither the trial nor the test functions are given, we treat the
       expression as a scalar functional and convert it to a 1x1 matrix.

    The domain is needed when the expression is defined over an interface,
    to delete the plus/minus operators and the InterfaceMapping object.

    Parameters
    ----------
    expr : sympy.Expr
        Expression corresponding to a bilinear/linear form or functional.

    trials : iterable
        List of all scalar trial functions (after unpacking vector functions).

    tests : iterable
        List of all scalar test functions (after unpacking vector functions).

    domain : Domain
        domain of expr

    Returns
    -------
    M : sympy.matrices.immutable.ImmutableDenseMatrix
        Matrix representation of input expression.

    """

    if not isinstance(domain, Interface):
        atoms = expr.atoms(minus, plus)
        new_atoms = [e.args[0] for e in atoms]
        subs = tuple(zip(atoms, new_atoms))
        expr = expr.subs(subs)
        mapping = expr.atoms(InterfaceMapping)
        if mapping:
            mapping = list(mapping)[0]
            expr = expr.subs(mapping, mapping.minus)

    # Bilinear form
    if trials and tests:
        M = [[None for j in trials] for i in tests]
        for i, test in enumerate(tests):
            subs_i = {v: 0 for v in tests if v != test}
            expr_i = expr.subs(subs_i)
            for j, trial in enumerate(trials):
                subs_j = {u: 0 for u in trials if u != trial}
                M[i][j] = expr_i.subs(subs_j)
        M = Matrix(M)

    # Linear form
    elif tests:
        M = [[None] for i in tests]
        for i, test in enumerate(tests):
            subs_i = {v: 0 for v in tests if v != test}
            M[i][0] = expr.subs(subs_i)
        M = Matrix(M)
    # Functional
    else:
        M = [[expr]]

    return ImmutableDenseMatrix(M)
Ejemplo n.º 13
0
    def eval(cls, expr, domain):
        """."""

        dim = domain.dim
        if isinstance(expr, Add):
            args = [cls.eval(a, domain=domain) for a in expr.args]
            o = args[0]
            for arg in args[1:]:
                o = o + arg
            return o

        elif isinstance(expr, Mul):
            args = [cls.eval(a, domain=domain) for a in expr.args]
            o = args[0]
            for arg in args[1:]:
                o = o * arg
            return o

        elif isinstance(expr, Abs):
            return Abs(cls.eval(expr.args[0], domain=domain))

        elif isinstance(expr, Pow):
            base = cls.eval(expr.base, domain=domain)
            exp = cls.eval(expr.exp, domain=domain)
            return base**exp

        elif isinstance(expr, JacobianSymbol):
            axis = expr.axis
            J = expr.mapping.jacobian_expr
            if not axis is None:
                if expr.mapping.ldim > 1:
                    J = J.col_del(axis)
                if expr.mapping.ldim == 1:
                    J = J.eye(1)
            if isinstance(domain, Interface):
                mapping = expr.mapping
                assert mapping.is_plus is not mapping.is_minus
                if mapping.is_plus and mapping.is_analytical:
                    domain = domain.plus
                    axis = domain.axis
                    ext = domain.ext
                    domain = domain.domain
                    coordinates = domain.coordinates
                    if isinstance(domain, (NCube, NCubeInterior)):
                        bounds = domain.min_coords if ext == -1 else domain.max_coords
                        J = J.subs(coordinates[axis], bounds[axis])
                    newcoords = [Symbol(c.name + "_plus") for c in coordinates]
                    subs = list(zip(coordinates, newcoords))
                    J = J.subs(subs)

            return J

        elif isinstance(expr, JacobianInverseSymbol):
            axis = expr.axis
            J = expr.mapping.jacobian_inv_expr
            if not axis is None:
                J = J.col_del(axis)

            if isinstance(domain, Interface):
                mapping = expr.mapping
                assert mapping.is_plus is not mapping.is_minus
                if mapping.is_plus and mapping.is_analytical:
                    domain = domain.plus
                    axis = domain.axis
                    ext = domain.ext
                    domain = domain.domain
                    coordinates = domain.coordinates
                    if isinstance(domain, (NCube, NCubeInterior)):
                        bounds = domain.min_coords if ext == -1 else domain.max_coords
                        J = J.subs(coordinates[axis], bounds[axis])
                    newcoords = [Symbol(c.name + "_plus") for c in coordinates]
                    subs = list(zip(coordinates, newcoords))
                    J = J.subs(subs)

            return J

        elif isinstance(expr, SymbolicDeterminant):
            return cls.eval(expr.arg, domain=domain).det().factor()

        elif isinstance(expr, SymbolicTrace):
            return cls.eval(expr.arg, domain=domain).trace()

        elif isinstance(expr, Transpose):
            return cls.eval(expr.arg, domain=domain).T

        elif isinstance(expr, Inverse):
            return cls.eval(expr.arg, domain=domain).inv()

        elif isinstance(expr, ScalarFunction):
            return expr

        elif isinstance(expr, VectorFunction):
            return ImmutableDenseMatrix([[expr[i]] for i in range(dim)])

        elif isinstance(expr, (minus, plus)):
            newexpr = cls.eval(expr.args[0], domain=domain)
            return type(expr)(newexpr)

        elif isinstance(expr, PullBack):
            return cls.eval(expr.expr, domain=domain)

        elif isinstance(expr, MatrixElement):
            base = cls.eval(expr.base, domain=domain)
            return base[expr.indices]

        elif isinstance(expr, BasicForm):
            # ...
            dim = expr.ldim
            domains = expr.domain

            if not isinstance(domains, Union):
                domains = (domains, )
            # ...
            d_expr = {}
            d_int = {}
            for d in domains:
                d_expr[d] = S.Zero
            # ...
            if isinstance(expr.expr, Add):
                for a in expr.expr.args:
                    domains = _get_domain(a)
                    if not isinstance(domains, Union):
                        domains = (domains, )

                    # ...
                    for d in domains:
                        d_expr[d] += a
                    # ...
            else:
                # ...
                if isinstance(expr, Functional):
                    domains = expr.domain

                else:
                    domains = _get_domain(expr.expr)

                if isinstance(domains, Union):
                    domains = list(domains._args)

                elif not is_sequence(domains):
                    domains = (domains, )
                # ...

                # ...
                for d in domains:
                    d_expr[d] = expr.expr
                # ...

            trials, tests = _get_trials_tests(expr, flatten=False)
            # ... treating interfaces
            keys = [k for k in d_expr.keys() if isinstance(k, Interface)]
            for interface in keys:
                newexpr = d_expr.pop(interface)
                ls_int, d_bnd = _split_expr_over_interface(newexpr,
                                                           interface,
                                                           tests=tests,
                                                           trials=trials)
                # ...
                for a in ls_int:
                    if (a.target, a.trial, a.test) in d_int:
                        d_int[a.target, a.trial, a.test] += a.expr
                    else:
                        d_int[a.target, a.trial, a.test] = a.expr

                for k, v in d_bnd.items():
                    if k in d_expr.keys():
                        d_expr[k] += v

                    else:
                        d_expr[k] = v
            # ...
            trials, tests = _get_trials_tests(expr, flatten=True)
            d_new = {}
            for domain, a in d_expr.items():
                newexpr = cls.eval(a, domain=domain)
                if newexpr != 0:
                    # TODO ARA make sure thre is no problem with psydac
                    #      we should always take the interior of a domain
                    if not isinstance(domain,
                                      (Boundary, Interface, InteriorDomain)):
                        domain = domain.interior
                    d_new[domain] = _to_matrix_form(newexpr,
                                                    trials=trials,
                                                    tests=tests,
                                                    domain=domain)

            if len(d_new) == 0:
                # ... corner case where the expression is zero
                for domain, a in d_expr.items():
                    if not isinstance(domain,
                                      (Boundary, Interface, InteriorDomain)):
                        domain = domain.interior
                    d_new[domain] = _to_matrix_form(S.Zero,
                                                    trials=trials,
                                                    tests=tests,
                                                    domain=domain)

                    if isinstance(domain, Boundary):
                        return (BoundaryExpression(domain, d_new[domain]), )
                    elif isinstance(domain, BasicDomain):
                        return (DomainExpression(domain, d_new[domain]), )

            # ... treating subdomains
            keys = [k for k in d_new.keys() if isinstance(k, Union)]
            for domain in keys:
                newexpr = d_new.pop(domain)
                d = dict((interior, newexpr) for interior in domain.as_tuple())
                # ...
                for k, v in d.items():
                    if k in d_new.keys():
                        d_new[k] += v

                    else:
                        d_new[k] = v

            ls = []
            for key in d_int:
                domain, u, v = key
                expr = d_int[domain, u, v]

                newexpr = cls.eval(expr, domain=domain)
                if newexpr != 0:
                    newexpr = _to_matrix_form(newexpr,
                                              trials=trials,
                                              tests=tests,
                                              domain=domain)
                    ls += [InterfaceExpression(domain, u, v, newexpr)]

            for domain, newexpr in d_new.items():
                if isinstance(domain, Boundary):
                    ls += [BoundaryExpression(domain, newexpr)]
                elif isinstance(domain, BasicDomain):
                    ls += [DomainExpression(domain, newexpr)]

                else:
                    raise TypeError('not implemented for {}'.format(
                        type(domain)))
            # ...
            return tuple(ls)

        elif isinstance(expr, Integral):
            domain = expr.domain
            expr = cls.eval(expr._args[0], domain=domain)
            return expr

        elif isinstance(expr, NormalVector):
            lines = [[expr[i] for i in range(dim)]]
            return ImmutableDenseMatrix(lines)

        elif isinstance(expr, TangentVector):
            lines = [[expr[i] for i in range(dim)]]
            return ImmutableDenseMatrix(lines)

        elif isinstance(expr, BasicExpr):
            return cls.eval(expr.expr, domain=domain)

        elif isinstance(expr, _diff_ops):
            op = type(expr)
            if domain.mapping is None:
                new = eval('Logical{0}_{1}d'.format(op, dim))
            else:
                new = eval('{0}_{1}d'.format(op, dim))

            args = [cls.eval(i, domain=domain) for i in expr.args]
            return new(*args)

        elif isinstance(expr, _generic_ops):
            # if i = Dot(...) then type(i) is Grad
            op = type(expr)
            new = eval('{0}_{1}d'.format(op, dim))
            args = [cls.eval(i, domain=domain) for i in expr.args]
            return new(*args)

        elif isinstance(expr, Trace):
            # TODO treate different spaces
            if expr.order == 0:
                return cls.eval(expr.expr, domain=domain)

            elif expr.order == 1:
                # TODO give a name to normal vector
                normal_vector_name = 'n'
                n = NormalVector(normal_vector_name)
                M = cls.eval(expr.expr, domain=domain)

                if dim == 1:
                    return M
                else:
                    if isinstance(M, (Add, Mul)):
                        ls = M.atoms(Tuple)

                        for i in ls:
                            M = M.subs(i, Matrix(i))
                        M = simplify(M)
                    e = 0
                    for i in range(0, dim):
                        e += M[i] * n[i]
                    return e
            else:
                raise ValueError(
                    '> Only traces of order 0 and 1 are available')

        elif isinstance(expr, (Matrix, ImmutableDenseMatrix)):
            n, m = expr.shape
            lines = []
            for i in range(0, n):
                line = []
                for j in range(0, m):
                    line.append(cls.eval(expr[i, j], domain=domain))
                lines.append(line)
            return ImmutableDenseMatrix(lines)

        elif isinstance(expr, LogicalExpr):
            domain = expr.domain
            expr = cls(expr.expr, domain=domain)
            return LogicalExpr(expr, domain=domain)

        return expr
Ejemplo n.º 14
0
def test_DiscreteMarkovChain():

    # pass only the name
    X = DiscreteMarkovChain("X")
    assert isinstance(X.state_space, Range)
    assert X.index_set == S.Naturals0
    assert isinstance(X.transition_probabilities, MatrixSymbol)
    t = symbols('t', positive=True, integer=True)
    assert isinstance(X[t], RandomIndexedSymbol)
    assert E(X[0]) == Expectation(X[0])
    raises(TypeError, lambda: DiscreteMarkovChain(1))
    raises(NotImplementedError, lambda: X(t))
    raises(NotImplementedError, lambda: X.communication_classes())
    raises(NotImplementedError, lambda: X.canonical_form())
    raises(NotImplementedError, lambda: X.decompose())

    nz = Symbol('n', integer=True)
    TZ = MatrixSymbol('M', nz, nz)
    SZ = Range(nz)
    YZ = DiscreteMarkovChain('Y', SZ, TZ)
    assert P(Eq(YZ[2], 1), Eq(YZ[1], 0)) == TZ[0, 1]

    raises(ValueError, lambda: sample_stochastic_process(t))
    raises(ValueError, lambda: next(sample_stochastic_process(X)))
    # pass name and state_space
    # any hashable object should be a valid state
    # states should be valid as a tuple/set/list/Tuple/Range
    sym, rainy, cloudy, sunny = symbols('a Rainy Cloudy Sunny', real=True)
    state_spaces = [(1, 2, 3), [Str('Hello'), sym, DiscreteMarkovChain],
                    Tuple(1, exp(sym), Str('World'), sympify=False),
                    Range(-1, 5, 2), [rainy, cloudy, sunny]]
    chains = [
        DiscreteMarkovChain("Y", state_space) for state_space in state_spaces
    ]

    for i, Y in enumerate(chains):
        assert isinstance(Y.transition_probabilities, MatrixSymbol)
        assert Y.state_space == state_spaces[i] or Y.state_space == FiniteSet(
            *state_spaces[i])
        assert Y.number_of_states == 3

        with ignore_warnings(
                UserWarning):  # TODO: Restore tests once warnings are removed
            assert P(Eq(Y[2], 1), Eq(Y[0], 2),
                     evaluate=False) == Probability(Eq(Y[2], 1), Eq(Y[0], 2))
        assert E(Y[0]) == Expectation(Y[0])

        raises(ValueError, lambda: next(sample_stochastic_process(Y)))

    raises(TypeError, lambda: DiscreteMarkovChain("Y", dict((1, 1))))
    Y = DiscreteMarkovChain("Y", Range(1, t, 2))
    assert Y.number_of_states == ceiling((t - 1) / 2)

    # pass name and transition_probabilities
    chains = [
        DiscreteMarkovChain("Y", trans_probs=Matrix([[]])),
        DiscreteMarkovChain("Y", trans_probs=Matrix([[0, 1], [1, 0]])),
        DiscreteMarkovChain("Y",
                            trans_probs=Matrix([[pi, 1 - pi], [sym, 1 - sym]]))
    ]
    for Z in chains:
        assert Z.number_of_states == Z.transition_probabilities.shape[0]
        assert isinstance(Z.transition_probabilities, ImmutableDenseMatrix)

    # pass name, state_space and transition_probabilities
    T = Matrix([[0.5, 0.2, 0.3], [0.2, 0.5, 0.3], [0.2, 0.3, 0.5]])
    TS = MatrixSymbol('T', 3, 3)
    Y = DiscreteMarkovChain("Y", [0, 1, 2], T)
    YS = DiscreteMarkovChain("Y", ['One', 'Two', 3], TS)
    assert Y.joint_distribution(1, Y[2],
                                3) == JointDistribution(Y[1], Y[2], Y[3])
    raises(ValueError, lambda: Y.joint_distribution(Y[1].symbol, Y[2].symbol))
    assert P(Eq(Y[3], 2), Eq(Y[1], 1)).round(2) == Float(0.36, 2)
    assert (P(Eq(YS[3], 2), Eq(YS[1], 1)) -
            (TS[0, 2] * TS[1, 0] + TS[1, 1] * TS[1, 2] +
             TS[1, 2] * TS[2, 2])).simplify() == 0
    assert P(Eq(YS[1], 1), Eq(YS[2], 2)) == Probability(Eq(YS[1], 1))
    assert P(Eq(YS[3], 3), Eq(
        YS[1],
        1)) == TS[0, 2] * TS[1, 0] + TS[1, 1] * TS[1, 2] + TS[1, 2] * TS[2, 2]
    TO = Matrix([[0.25, 0.75, 0], [0, 0.25, 0.75], [0.75, 0, 0.25]])
    assert P(Eq(Y[3], 2),
             Eq(Y[1], 1) & TransitionMatrixOf(Y, TO)).round(3) == Float(
                 0.375, 3)
    with ignore_warnings(
            UserWarning):  ### TODO: Restore tests once warnings are removed
        assert E(Y[3], evaluate=False) == Expectation(Y[3])
        assert E(Y[3], Eq(Y[2], 1)).round(2) == Float(1.1, 3)
    TSO = MatrixSymbol('T', 4, 4)
    raises(
        ValueError,
        lambda: str(P(Eq(YS[3], 2),
                      Eq(YS[1], 1) & TransitionMatrixOf(YS, TSO))))
    raises(TypeError,
           lambda: DiscreteMarkovChain("Z", [0, 1, 2], symbols('M')))
    raises(
        ValueError,
        lambda: DiscreteMarkovChain("Z", [0, 1, 2], MatrixSymbol('T', 3, 4)))
    raises(ValueError, lambda: E(Y[3], Eq(Y[2], 6)))
    raises(ValueError, lambda: E(Y[2], Eq(Y[3], 1)))

    # extended tests for probability queries
    TO1 = Matrix([[Rational(1, 4), Rational(3, 4), 0],
                  [Rational(1, 3),
                   Rational(1, 3),
                   Rational(1, 3)], [0, Rational(1, 4),
                                     Rational(3, 4)]])
    assert P(
        And(Eq(Y[2], 1), Eq(Y[1], 1), Eq(Y[0], 0)),
        Eq(Probability(Eq(Y[0], 0)), Rational(1, 4))
        & TransitionMatrixOf(Y, TO1)) == Rational(1, 16)
    assert P(And(Eq(Y[2], 1), Eq(Y[1], 1), Eq(Y[0], 0)), TransitionMatrixOf(Y, TO1)) == \
            Probability(Eq(Y[0], 0))/4
    assert P(
        Lt(X[1], 2) & Gt(X[1], 0),
        Eq(X[0], 2) & StochasticStateSpaceOf(X, [0, 1, 2])
        & TransitionMatrixOf(X, TO1)) == Rational(1, 4)
    assert P(
        Lt(X[1], 2) & Gt(X[1], 0),
        Eq(X[0], 2) & StochasticStateSpaceOf(X, [None, 'None', 1])
        & TransitionMatrixOf(X, TO1)) == Rational(1, 4)
    assert P(
        Ne(X[1], 2) & Ne(X[1], 1),
        Eq(X[0], 2) & StochasticStateSpaceOf(X, [0, 1, 2])
        & TransitionMatrixOf(X, TO1)) is S.Zero
    assert P(
        Ne(X[1], 2) & Ne(X[1], 1),
        Eq(X[0], 2) & StochasticStateSpaceOf(X, [None, 'None', 1])
        & TransitionMatrixOf(X, TO1)) is S.Zero
    assert P(And(Eq(Y[2], 1), Eq(Y[1], 1), Eq(Y[0], 0)),
             Eq(Y[1], 1)) == 0.1 * Probability(Eq(Y[0], 0))

    # testing properties of Markov chain
    TO2 = Matrix([[S.One, 0, 0],
                  [Rational(1, 3),
                   Rational(1, 3),
                   Rational(1, 3)], [0, Rational(1, 4),
                                     Rational(3, 4)]])
    TO3 = Matrix([[Rational(1, 4), Rational(3, 4), 0],
                  [Rational(1, 3),
                   Rational(1, 3),
                   Rational(1, 3)], [0, Rational(1, 4),
                                     Rational(3, 4)]])
    Y2 = DiscreteMarkovChain('Y', trans_probs=TO2)
    Y3 = DiscreteMarkovChain('Y', trans_probs=TO3)
    assert Y3.fundamental_matrix() == ImmutableMatrix(
        [[176, 81, -132], [36, 141, -52], [-44, -39, 208]]) / 125
    assert Y2.is_absorbing_chain() == True
    assert Y3.is_absorbing_chain() == False
    assert Y2.canonical_form() == ([0, 1, 2], TO2)
    assert Y3.canonical_form() == ([0, 1, 2], TO3)
    assert Y2.decompose() == ([0, 1,
                               2], TO2[0:1, 0:1], TO2[1:3, 0:1], TO2[1:3, 1:3])
    assert Y3.decompose() == ([0, 1, 2], TO3, Matrix(0, 3,
                                                     []), Matrix(0, 0, []))
    TO4 = Matrix([[Rational(1, 5),
                   Rational(2, 5),
                   Rational(2, 5)], [Rational(1, 10), S.Half,
                                     Rational(2, 5)],
                  [Rational(3, 5),
                   Rational(3, 10),
                   Rational(1, 10)]])
    Y4 = DiscreteMarkovChain('Y', trans_probs=TO4)
    w = ImmutableMatrix([[Rational(11, 39),
                          Rational(16, 39),
                          Rational(4, 13)]])
    assert Y4.limiting_distribution == w
    assert Y4.is_regular() == True
    assert Y4.is_ergodic() == True
    TS1 = MatrixSymbol('T', 3, 3)
    Y5 = DiscreteMarkovChain('Y', trans_probs=TS1)
    assert Y5.limiting_distribution(w, TO4).doit() == True
    assert Y5.stationary_distribution(condition_set=True).subs(
        TS1, TO4).contains(w).doit() == S.true
    TO6 = Matrix([[S.One, 0, 0, 0, 0], [S.Half, 0, S.Half, 0, 0],
                  [0, S.Half, 0, S.Half, 0], [0, 0, S.Half, 0, S.Half],
                  [0, 0, 0, 0, 1]])
    Y6 = DiscreteMarkovChain('Y', trans_probs=TO6)
    assert Y6.fundamental_matrix() == ImmutableMatrix(
        [[Rational(3, 2), S.One, S.Half], [S.One, S(2), S.One],
         [S.Half, S.One, Rational(3, 2)]])
    assert Y6.absorbing_probabilities() == ImmutableMatrix(
        [[Rational(3, 4), Rational(1, 4)], [S.Half, S.Half],
         [Rational(1, 4), Rational(3, 4)]])
    TO7 = Matrix([[Rational(1, 2),
                   Rational(1, 4),
                   Rational(1, 4)], [Rational(1, 2), 0,
                                     Rational(1, 2)],
                  [Rational(1, 4),
                   Rational(1, 4),
                   Rational(1, 2)]])
    Y7 = DiscreteMarkovChain('Y', trans_probs=TO7)
    assert Y7.is_absorbing_chain() == False
    assert Y7.fundamental_matrix() == ImmutableDenseMatrix(
        [[Rational(86, 75),
          Rational(1, 25),
          Rational(-14, 75)],
         [Rational(2, 25), Rational(21, 25),
          Rational(2, 25)],
         [Rational(-14, 75),
          Rational(1, 25),
          Rational(86, 75)]])

    # test for zero-sized matrix functionality
    X = DiscreteMarkovChain('X', trans_probs=Matrix([[]]))
    assert X.number_of_states == 0
    assert X.stationary_distribution() == Matrix([[]])
    assert X.communication_classes() == []
    assert X.canonical_form() == ([], Matrix([[]]))
    assert X.decompose() == ([], Matrix([[]]), Matrix([[]]), Matrix([[]]))
    assert X.is_regular() == False
    assert X.is_ergodic() == False

    # test communication_class
    # see https://drive.google.com/drive/folders/1HbxLlwwn2b3U8Lj7eb_ASIUb5vYaNIjg?usp=sharing
    # tutorial 2.pdf
    TO7 = Matrix([[0, 5, 5, 0, 0], [0, 0, 0, 10, 0], [5, 0, 5, 0, 0],
                  [0, 10, 0, 0, 0], [0, 3, 0, 3, 4]]) / 10
    Y7 = DiscreteMarkovChain('Y', trans_probs=TO7)
    tuples = Y7.communication_classes()
    classes, recurrence, periods = list(zip(*tuples))
    assert classes == ([1, 3], [0, 2], [4])
    assert recurrence == (True, False, False)
    assert periods == (2, 1, 1)

    TO8 = Matrix([[0, 0, 0, 10, 0, 0], [5, 0, 5, 0, 0, 0], [0, 4, 0, 0, 0, 6],
                  [10, 0, 0, 0, 0, 0], [0, 10, 0, 0, 0, 0], [0, 0, 0, 5, 5, 0]
                  ]) / 10
    Y8 = DiscreteMarkovChain('Y', trans_probs=TO8)
    tuples = Y8.communication_classes()
    classes, recurrence, periods = list(zip(*tuples))
    assert classes == ([0, 3], [1, 2, 5, 4])
    assert recurrence == (True, False)
    assert periods == (2, 2)

    TO9 = Matrix(
        [[2, 0, 0, 3, 0, 0, 3, 2, 0, 0], [0, 10, 0, 0, 0, 0, 0, 0, 0, 0],
         [0, 2, 2, 0, 0, 0, 0, 0, 3, 3], [0, 0, 0, 3, 0, 0, 6, 1, 0, 0],
         [0, 0, 0, 0, 5, 5, 0, 0, 0, 0], [0, 0, 0, 0, 0, 10, 0, 0, 0, 0],
         [4, 0, 0, 5, 0, 0, 1, 0, 0, 0], [2, 0, 0, 4, 0, 0, 2, 2, 0, 0],
         [3, 0, 1, 0, 0, 0, 0, 0, 4, 2], [0, 0, 4, 0, 0, 0, 0, 0, 3, 3]]) / 10
    Y9 = DiscreteMarkovChain('Y', trans_probs=TO9)
    tuples = Y9.communication_classes()
    classes, recurrence, periods = list(zip(*tuples))
    assert classes == ([0, 3, 6, 7], [1], [2, 8, 9], [5], [4])
    assert recurrence == (True, True, False, True, False)
    assert periods == (1, 1, 1, 1, 1)

    # test canonical form
    # see https://www.dartmouth.edu/~chance/teaching_aids/books_articles/probability_book/Chapter11.pdf
    # example 11.13
    T = Matrix([[1, 0, 0, 0, 0], [S(1) / 2, 0, S(1) / 2, 0, 0],
                [0, S(1) / 2, 0, S(1) / 2, 0], [0, 0,
                                                S(1) / 2, 0,
                                                S(1) / 2], [0, 0, 0, 0,
                                                            S(1)]])
    DW = DiscreteMarkovChain('DW', [0, 1, 2, 3, 4], T)
    states, A, B, C = DW.decompose()
    assert states == [0, 4, 1, 2, 3]
    assert A == Matrix([[1, 0], [0, 1]])
    assert B == Matrix([[S(1) / 2, 0], [0, 0], [0, S(1) / 2]])
    assert C == Matrix([[0, S(1) / 2, 0], [S(1) / 2, 0, S(1) / 2],
                        [0, S(1) / 2, 0]])
    states, new_matrix = DW.canonical_form()
    assert states == [0, 4, 1, 2, 3]
    assert new_matrix == Matrix([[1, 0, 0, 0, 0], [0, 1, 0, 0, 0],
                                 [S(1) / 2, 0, 0, S(1) / 2, 0],
                                 [0, 0, S(1) / 2, 0,
                                  S(1) / 2], [0, S(1) / 2, 0,
                                              S(1) / 2, 0]])

    # test regular and ergodic
    # https://www.dartmouth.edu/~chance/teaching_aids/books_articles/probability_book/Chapter11.pdf
    T = Matrix([[0, 4, 0, 0, 0], [1, 0, 3, 0, 0], [0, 2, 0, 2, 0],
                [0, 0, 3, 0, 1], [0, 0, 0, 4, 0]]) / 4
    X = DiscreteMarkovChain('X', trans_probs=T)
    assert not X.is_regular()
    assert X.is_ergodic()
    T = Matrix([[0, 1], [1, 0]])
    X = DiscreteMarkovChain('X', trans_probs=T)
    assert not X.is_regular()
    assert X.is_ergodic()
    # http://www.math.wisc.edu/~valko/courses/331/MC2.pdf
    T = Matrix([[2, 1, 1], [2, 0, 2], [1, 1, 2]]) / 4
    X = DiscreteMarkovChain('X', trans_probs=T)
    assert X.is_regular()
    assert X.is_ergodic()
    # https://docs.ufpr.br/~lucambio/CE222/1S2014/Kemeny-Snell1976.pdf
    T = Matrix([[1, 1], [1, 1]]) / 2
    X = DiscreteMarkovChain('X', trans_probs=T)
    assert X.is_regular()
    assert X.is_ergodic()

    # test is_absorbing_chain
    T = Matrix([[0, 1, 0], [1, 0, 0], [0, 0, 1]])
    X = DiscreteMarkovChain('X', trans_probs=T)
    assert not X.is_absorbing_chain()
    # https://en.wikipedia.org/wiki/Absorbing_Markov_chain
    T = Matrix([[1, 1, 0, 0], [0, 1, 1, 0], [1, 0, 0, 1], [0, 0, 0, 2]]) / 2
    X = DiscreteMarkovChain('X', trans_probs=T)
    assert X.is_absorbing_chain()
    T = Matrix([[2, 0, 0, 0, 0], [1, 0, 1, 0, 0], [0, 1, 0, 1, 0],
                [0, 0, 1, 0, 1], [0, 0, 0, 0, 2]]) / 2
    X = DiscreteMarkovChain('X', trans_probs=T)
    assert X.is_absorbing_chain()

    # test custom state space
    Y10 = DiscreteMarkovChain('Y', [1, 2, 3], TO2)
    tuples = Y10.communication_classes()
    classes, recurrence, periods = list(zip(*tuples))
    assert classes == ([1], [2, 3])
    assert recurrence == (True, False)
    assert periods == (1, 1)
    assert Y10.canonical_form() == ([1, 2, 3], TO2)
    assert Y10.decompose() == ([1, 2, 3], TO2[0:1, 0:1], TO2[1:3,
                                                             0:1], TO2[1:3,
                                                                       1:3])

    # testing miscellaneous queries
    T = Matrix([[S.Half, Rational(1, 4),
                 Rational(1, 4)], [Rational(1, 3), 0,
                                   Rational(2, 3)], [S.Half, S.Half, 0]])
    X = DiscreteMarkovChain('X', [0, 1, 2], T)
    assert P(
        Eq(X[1], 2) & Eq(X[2], 1) & Eq(X[3], 0),
        Eq(P(Eq(X[1], 0)), Rational(1, 4))
        & Eq(P(Eq(X[1], 1)), Rational(1, 4))) == Rational(1, 12)
    assert P(Eq(X[2], 1) | Eq(X[2], 2), Eq(X[1], 1)) == Rational(2, 3)
    assert P(Eq(X[2], 1) & Eq(X[2], 2), Eq(X[1], 1)) is S.Zero
    assert P(Ne(X[2], 2), Eq(X[1], 1)) == Rational(1, 3)
    assert E(X[1]**2, Eq(X[0], 1)) == Rational(8, 3)
    assert variance(X[1], Eq(X[0], 1)) == Rational(8, 9)
    raises(ValueError, lambda: E(X[1], Eq(X[2], 1)))
    raises(ValueError, lambda: DiscreteMarkovChain('X', [0, 1], T))

    # testing miscellaneous queries with different state space
    X = DiscreteMarkovChain('X', ['A', 'B', 'C'], T)
    assert P(
        Eq(X[1], 2) & Eq(X[2], 1) & Eq(X[3], 0),
        Eq(P(Eq(X[1], 0)), Rational(1, 4))
        & Eq(P(Eq(X[1], 1)), Rational(1, 4))) == Rational(1, 12)
    assert P(Eq(X[2], 1) | Eq(X[2], 2), Eq(X[1], 1)) == Rational(2, 3)
    assert P(Eq(X[2], 1) & Eq(X[2], 2), Eq(X[1], 1)) is S.Zero
    assert P(Ne(X[2], 2), Eq(X[1], 1)) == Rational(1, 3)
    a = X.state_space.args[0]
    c = X.state_space.args[2]
    assert (E(X[1]**2, Eq(X[0], 1)) -
            (a**2 / 3 + 2 * c**2 / 3)).simplify() == 0
    assert (variance(X[1], Eq(X[0], 1)) -
            (2 * (-a / 3 + c / 3)**2 / 3 +
             (2 * a / 3 - 2 * c / 3)**2 / 3)).simplify() == 0
    raises(ValueError, lambda: E(X[1], Eq(X[2], 1)))

    #testing queries with multiple RandomIndexedSymbols
    T = Matrix([[Rational(5, 10),
                 Rational(3, 10),
                 Rational(2, 10)],
                [Rational(2, 10),
                 Rational(7, 10),
                 Rational(1, 10)],
                [Rational(3, 10),
                 Rational(3, 10),
                 Rational(4, 10)]])
    Y = DiscreteMarkovChain("Y", [0, 1, 2], T)
    assert P(Eq(Y[7], Y[5]), Eq(Y[2], 0)).round(5) == Float(0.44428, 5)
    assert P(Gt(Y[3], Y[1]), Eq(Y[0], 0)).round(2) == Float(0.36, 2)
    assert P(Le(Y[5], Y[10]), Eq(Y[4], 2)).round(6) == Float(0.583120, 6)
    assert Float(P(Eq(Y[10], Y[5]), Eq(Y[4], 1)),
                 14) == Float(1 - P(Ne(Y[10], Y[5]), Eq(Y[4], 1)), 14)
    assert Float(P(Gt(Y[8], Y[9]), Eq(Y[3], 2)),
                 14) == Float(1 - P(Le(Y[8], Y[9]), Eq(Y[3], 2)), 14)
    assert Float(P(Lt(Y[1], Y[4]), Eq(Y[0], 0)),
                 14) == Float(1 - P(Ge(Y[1], Y[4]), Eq(Y[0], 0)), 14)
    assert P(Eq(Y[5], Y[10]), Eq(Y[2], 1)) == P(Eq(Y[10], Y[5]), Eq(Y[2], 1))
    assert P(Gt(Y[1], Y[2]), Eq(Y[0], 1)) == P(Lt(Y[2], Y[1]), Eq(Y[0], 1))
    assert P(Ge(Y[7], Y[6]), Eq(Y[4], 1)) == P(Le(Y[6], Y[7]), Eq(Y[4], 1))

    #test symbolic queries
    a, b, c, d = symbols('a b c d')
    T = Matrix([[Rational(1, 10),
                 Rational(4, 10),
                 Rational(5, 10)],
                [Rational(3, 10),
                 Rational(4, 10),
                 Rational(3, 10)],
                [Rational(7, 10),
                 Rational(2, 10),
                 Rational(1, 10)]])
    Y = DiscreteMarkovChain("Y", [0, 1, 2], T)
    query = P(Eq(Y[a], b), Eq(Y[c], d))
    assert query.subs({
        a: 10,
        b: 2,
        c: 5,
        d: 1
    }).evalf().round(4) == P(Eq(Y[10], 2), Eq(Y[5], 1)).round(4)
    assert query.subs({
        a: 15,
        b: 0,
        c: 10,
        d: 1
    }).evalf().round(4) == P(Eq(Y[15], 0), Eq(Y[10], 1)).round(4)
    query_gt = P(Gt(Y[a], b), Eq(Y[c], d))
    query_le = P(Le(Y[a], b), Eq(Y[c], d))
    assert query_gt.subs({
        a: 5,
        b: 2,
        c: 1,
        d: 0
    }).evalf() + query_le.subs({
        a: 5,
        b: 2,
        c: 1,
        d: 0
    }).evalf() == 1
    query_ge = P(Ge(Y[a], b), Eq(Y[c], d))
    query_lt = P(Lt(Y[a], b), Eq(Y[c], d))
    assert query_ge.subs({
        a: 4,
        b: 1,
        c: 0,
        d: 2
    }).evalf() + query_lt.subs({
        a: 4,
        b: 1,
        c: 0,
        d: 2
    }).evalf() == 1
Ejemplo n.º 15
0
    def eval(cls, *_args, **kwargs):
        """."""

        if not _args:
            return

        if not len(_args) == 1:
            raise ValueError('Expecting one argument')

        expr = _args[0]
        d_atoms = kwargs.pop('d_atoms', {})
        domain = kwargs.pop('domain', None)
        expand = kwargs.pop('expand', False)

        if isinstance(expr, Add):
            args = [
                cls.eval(a, d_atoms=d_atoms, domain=domain) for a in expr.args
            ]
            return Add(*args)

        elif isinstance(expr, Mul):
            coeffs = [a for a in expr.args if isinstance(a, _coeffs_registery)]
            stests = [
                a for a in expr.args
                if not (a in coeffs) and a.atoms(ScalarFunction)
            ]
            vtests = [
                a for a in expr.args
                if not (a in coeffs) and a.atoms(VectorFunction)
            ]
            vectors = [
                a for a in expr.args if
                (not (a in coeffs) and not (a in stests) and not (a in vtests))
            ]

            a = S.One
            if coeffs:
                a = Mul(*coeffs)

            b = S.One
            if vectors:

                args = [cls(i, evaluate=False) for i in vectors]
                b = Mul(*args)

            sb = S.One
            if stests:
                args = [
                    cls.eval(i, d_atoms=d_atoms, domain=domain) for i in stests
                ]
                sb = Mul(*args)

            vb = S.One
            if vtests:
                args = [
                    cls.eval(i, d_atoms=d_atoms, domain=domain) for i in vtests
                ]
                vb = Mul(*args)

            return Mul(a, b, sb, vb)

        elif isinstance(expr, _coeffs_registery):
            return expr

        elif isinstance(expr, Pow):
            b = expr.base
            e = expr.exp
            return Pow(cls.eval(b), e)

        elif isinstance(expr, (Matrix, ImmutableDenseMatrix)):

            n_rows, n_cols = expr.shape

            lines = []
            for i_row in range(0, n_rows):
                line = []
                for i_col in range(0, n_cols):
                    line.append(
                        cls.eval(expr[i_row, i_col],
                                 d_atoms=d_atoms,
                                 domain=domain))

                lines.append(line)

            return ImmutableDenseMatrix(lines)

        elif isinstance(expr, DomainExpression):
            # TODO to be removed
            return cls.eval(expr.expr, d_atoms=d_atoms, domain=domain)

        elif isinstance(expr, BilinearForm):
            trials = expr.variables[0]
            tests = expr.variables[1]
            fields = expr.fields

            # ... # TODO improve
            terminal_expr = TerminalExpr(expr, domain)[0]
            # ...

            # ...
            # Collect all variables in the expression (fields must be excluded)
            variables = [
                e for e in terminal_expr.atoms(ScalarFunction)
                if e not in fields
            ]
            variables += [
                e for e in terminal_expr.atoms(IndexedVectorFunction)
                if e.base not in fields
            ]
            # ...

            # ...
            if domain is not None and domain.mapping is not None:
                terminal_expr = LogicalExpr(terminal_expr.expr, domain)
                variables = [LogicalExpr(e, domain) for e in variables]
                trials = [LogicalExpr(e, domain) for e in trials]
                tests = [LogicalExpr(e, domain) for e in tests]
            # ...

            # Prepare dictionary for '_tensorize_atomic_expr', which should
            # process all variables but leave fields unchanged:
            d_atoms = dict([(v, _split_test_function(v)[v])
                            for v in variables] + [(f, (f, )) for f in fields])

            # ...
            expr = cls.eval(terminal_expr, d_atoms=d_atoms, domain=domain)
            # ...

            # ...
            trials = [
                a for a in variables
                if ((isinstance(a, ScalarFunction) and a in trials) or (
                    isinstance(a, IndexedVectorFunction) and a.base in trials))
            ]

            tests = [
                a for a in variables
                if ((isinstance(a, ScalarFunction) and a in tests) or (
                    isinstance(a, IndexedVectorFunction) and a.base in tests))
            ]
            # ...

            expr = _replace_atomic_expr(expr,
                                        trials,
                                        tests,
                                        d_atoms,
                                        logical=True,
                                        expand=expand)

            return expr

        if expr.atoms(ScalarFunction) or expr.atoms(IndexedVectorFunction):
            return _tensorize_atomic_expr(expr, d_atoms)

        return cls(expr, evaluate=False)
Ejemplo n.º 16
0
    def __new__(cls, expr, domain, kind='l2', evaluate=True, **options):
        #        # ...
        #        tests = expr.atoms((ScalarTestFunction, VectorTestFunction))
        #        if tests:
        #            msg = '> Expecting an Expression without test functions'
        #            raise UnconsistentArgumentsError(msg)
        #
        #        if not isinstance(expr, (Expr, Matrix, ImmutableDenseMatrix)):
        #            msg = '> Expecting Expr, Matrix, ImmutableDenseMatrix'
        #            raise UnconsistentArgumentsError(msg)
        #        # ...

        # ...
        kind = kind.lower()
        if not (kind in ['l2', 'h1', 'h2']):
            raise ValueError('> Only L2, H1, H2 norms are available')
        # ...

        # ...
        is_vector = isinstance(
            expr, (Matrix, ImmutableDenseMatrix, Tuple, list, tuple))
        if is_vector:
            expr = ImmutableDenseMatrix(expr)
        # ...

        # ...
        exponent = None
        if kind == 'l2' and evaluate:
            exponent = 2

            if not is_vector:
                expr = expr * expr

            else:
                if not (expr.shape[1] == 1):
                    raise ValueError(
                        'Wrong expression for Matrix. must be a row')

                v = Tuple(*expr[:, 0])
                expr = Dot(v, v)

        elif kind == 'h1' and evaluate:
            exponent = 2

            if not is_vector:
                a = Grad(expr)
                expr = Dot(a, a)

            else:
                if not (expr.shape[1] == 1):
                    raise ValueError(
                        'Wrong expression for Matrix. must be a row')

                v = Tuple(*expr[:, 0])
                a = Grad(v)
                expr = Inner(a, a)

        elif kind == 'h2' and evaluate:
            exponent = 2

            if not is_vector:
                a = Hessian(expr)
                expr = Dot(a, a)

            else:
                raise NotImplementedError('TODO')
        # ...

        obj = Functional.__new__(cls, expr, domain, evaluate=evaluate)
        obj._exponent = exponent
        obj._kind = kind

        return obj
Ejemplo n.º 17
0
 def __init__(self, transformation=None, orientation=None):
     assert transformation.shape == (
         4, 4), "Invalid shape of transformation array"
     self.trans_sympy = ImmutableDenseMatrix(transformation)
     self.params = {'transformation': self.trans_sympy}
     self.orientation = orientation
Ejemplo n.º 18
0
 def func(self, *args):
     """
     These should never be interpretted as expressions, only roots.
     """
     return ImmutableDenseMatrix(*args)
Ejemplo n.º 19
0
    def __new__(cls, name, dim=None, **kwargs):

        ldim = kwargs.pop('ldim', cls._ldim)
        pdim = kwargs.pop('pdim', cls._pdim)
        coordinates = kwargs.pop('coordinates', None)
        evaluate = kwargs.pop('evaluate', True)

        dims = [dim, ldim, pdim]
        for i, d in enumerate(dims):
            if isinstance(d,
                          (tuple, list, Tuple, Matrix, ImmutableDenseMatrix)):
                if not len(d) == 1:
                    raise ValueError(
                        '> Expecting a tuple, list, Tuple of length 1')
                dims[i] = d[0]

        dim, ldim, pdim = dims

        if dim is None:
            assert ldim is not None
            assert pdim is not None
            assert pdim >= ldim
        else:
            ldim = dim
            pdim = dim

        obj = IndexedBase.__new__(cls, name, shape=pdim)

        if not evaluate:
            return obj

        if coordinates is None:
            _coordinates = [Symbol(name) for name in ['x', 'y', 'z'][:pdim]]
        else:
            if not isinstance(coordinates, (list, tuple, Tuple)):
                raise TypeError('> Expecting list, tuple, Tuple')

            for a in coordinates:
                if not isinstance(a, (str, Symbol)):
                    raise TypeError('> Expecting str or Symbol')

            _coordinates = [Symbol(u) for u in coordinates]

        obj._name = name
        obj._ldim = ldim
        obj._pdim = pdim
        obj._coordinates = tuple(_coordinates)
        obj._jacobian = kwargs.pop('jacobian', JacobianSymbol(obj))
        obj._is_minus = None
        obj._is_plus = None

        lcoords = ['x1', 'x2', 'x3'][:ldim]
        lcoords = [Symbol(i) for i in lcoords]
        obj._logical_coordinates = Tuple(*lcoords)
        # ...
        if not (obj._expressions is None):
            coords = ['x', 'y', 'z'][:pdim]

            # ...
            args = []
            for i in coords:
                x = obj._expressions[i]
                x = sympify(x)
                args.append(x)

            args = Tuple(*args)
            # ...
            zero_coords = ['x1', 'x2', 'x3'][ldim:]

            for i in zero_coords:
                x = sympify(i)
                args = args.subs(x, 0)
            # ...

            constants = list(set(args.free_symbols) - set(lcoords))
            constants_values = {a.name: Constant(a.name) for a in constants}
            # subs constants as Constant objects instead of Symbol
            constants_values.update(kwargs)
            d = {a: constants_values[a.name] for a in constants}
            args = args.subs(d)

            obj._expressions = args
            obj._constants = tuple(
                a for a in constants
                if isinstance(constants_values[a.name], Symbol))

            args = [obj[i] for i in range(pdim)]
            exprs = obj._expressions
            subs = list(zip(_coordinates, exprs))

            if obj._jac is None and obj._inv_jac is None:
                obj._jac = Jacobian(obj).subs(list(zip(args, exprs)))
                obj._inv_jac = obj._jac.inv()
            elif obj._inv_jac is None:
                obj._jac = ImmutableDenseMatrix(sympify(obj._jac)).subs(subs)
                obj._inv_jac = obj._jac.inv()

            elif obj._jac is None:
                obj._inv_jac = ImmutableDenseMatrix(sympify(
                    obj._inv_jac)).subs(subs)
                obj._jac = obj._inv_jac.inv()
            else:
                obj._jac = ImmutableDenseMatrix(sympify(obj._jac)).subs(subs)
                obj._inv_jac = ImmutableDenseMatrix(sympify(
                    obj._inv_jac)).subs(subs)

        else:
            obj._jac = Jacobian(obj)

        obj._metric = obj._jac.T * obj._jac
        obj._metric_det = obj._metric.det()

        return obj
Ejemplo n.º 20
0
    def eval(cls, expr, domain, **options):
        """."""

        from sympde.expr.evaluation import TerminalExpr, DomainExpression
        from sympde.expr.expr import BilinearForm, LinearForm, BasicForm, Norm
        from sympde.expr.expr import Integral

        types = (ScalarFunction, VectorFunction, DifferentialOperator, Trace,
                 Integral)

        mapping = domain.mapping
        dim = domain.dim
        assert mapping

        # TODO this is not the dim of the domain
        l_coords = ['x1', 'x2', 'x3'][:dim]
        ph_coords = ['x', 'y', 'z']

        if not has(expr, types):
            if has(expr, DiffOperator):
                return cls(expr, domain, evaluate=False)
            else:
                syms = symbols(ph_coords[:dim])
                if isinstance(mapping, InterfaceMapping):
                    mapping = mapping.minus
                    # here we assume that the two mapped domains
                    # are identical in the interface so we choose one of them
                Ms = [mapping[i] for i in range(dim)]
                expr = expr.subs(list(zip(syms, Ms)))

                if mapping.is_analytical:
                    expr = expr.subs(list(zip(Ms, mapping.expressions)))
                return expr

        if isinstance(expr, Symbol) and expr.name in l_coords:
            return expr

        if isinstance(expr, Symbol) and expr.name in ph_coords:
            return mapping[ph_coords.index(expr.name)]

        elif isinstance(expr, Add):
            args = [cls.eval(a, domain) for a in expr.args]
            v = S.Zero
            for i in args:
                v += i
            n, d = v.as_numer_denom()
            return n / d

        elif isinstance(expr, Mul):
            args = [cls.eval(a, domain) for a in expr.args]
            v = S.One
            for i in args:
                v *= i
            return v

        elif isinstance(expr, _logical_partial_derivatives):
            if mapping.is_analytical:
                Ms = [mapping[i] for i in range(dim)]
                expr = expr.subs(list(zip(Ms, mapping.expressions)))
            return expr

        elif isinstance(expr, IndexedVectorFunction):
            el = cls.eval(expr.base, domain)
            el = TerminalExpr(el, domain=domain.logical_domain)
            return el[expr.indices[0]]

        elif isinstance(expr, MinusInterfaceOperator):
            mapping = mapping.minus
            newexpr = PullBack(expr.args[0], mapping)
            test = newexpr.test
            newexpr = newexpr.expr.subs(test, MinusInterfaceOperator(test))
            return newexpr

        elif isinstance(expr, PlusInterfaceOperator):
            mapping = mapping.plus
            newexpr = PullBack(expr.args[0], mapping)
            test = newexpr.test
            newexpr = newexpr.expr.subs(test, PlusInterfaceOperator(test))
            return newexpr

        elif isinstance(expr, (VectorFunction, ScalarFunction)):
            return PullBack(expr, mapping).expr

        elif isinstance(expr, Transpose):
            arg = cls(expr.arg, domain)
            return Transpose(arg)

        elif isinstance(expr, grad):
            arg = expr.args[0]
            if isinstance(mapping, InterfaceMapping):
                if isinstance(arg, MinusInterfaceOperator):
                    a = arg.args[0]
                    mapping = mapping.minus
                elif isinstance(arg, PlusInterfaceOperator):
                    a = arg.args[0]
                    mapping = mapping.plus
                else:
                    raise TypeError(arg)

                arg = type(arg)(cls.eval(a, domain))
            else:
                arg = cls.eval(arg, domain)

            return mapping.jacobian.inv().T * grad(arg)

        elif isinstance(expr, curl):
            arg = expr.args[0]
            if isinstance(mapping, InterfaceMapping):
                if isinstance(arg, MinusInterfaceOperator):
                    arg = arg.args[0]
                    mapping = mapping.minus
                elif isinstance(arg, PlusInterfaceOperator):
                    arg = arg.args[0]
                    mapping = mapping.plus
                else:
                    raise TypeError(arg)

            if isinstance(arg, VectorFunction):
                arg = PullBack(arg, mapping)
            else:
                arg = cls.eval(arg, domain)

            if isinstance(arg, PullBack) and isinstance(
                    arg.kind, HcurlSpaceType):
                J = mapping.jacobian
                arg = arg.test
                if isinstance(expr.args[0],
                              (MinusInterfaceOperator, PlusInterfaceOperator)):
                    arg = type(expr.args[0])(arg)
                if expr.is_scalar:
                    return (1 / J.det()) * curl(arg)

                return (J / J.det()) * curl(arg)
            else:
                raise NotImplementedError('TODO')

        elif isinstance(expr, div):
            arg = expr.args[0]
            if isinstance(mapping, InterfaceMapping):
                if isinstance(arg, MinusInterfaceOperator):
                    arg = arg.args[0]
                    mapping = mapping.minus
                elif isinstance(arg, PlusInterfaceOperator):
                    arg = arg.args[0]
                    mapping = mapping.plus
                else:
                    raise TypeError(arg)

            if isinstance(arg, (ScalarFunction, VectorFunction)):
                arg = PullBack(arg, mapping)
            else:

                arg = cls.eval(arg, domain)

            if isinstance(arg, PullBack) and isinstance(
                    arg.kind, HdivSpaceType):
                J = mapping.jacobian
                arg = arg.test
                if isinstance(expr.args[0],
                              (MinusInterfaceOperator, PlusInterfaceOperator)):
                    arg = type(expr.args[0])(arg)
                return (1 / J.det()) * div(arg)
            elif isinstance(arg, PullBack):
                return SymbolicTrace(mapping.jacobian.inv().T * grad(arg.test))
            else:
                raise NotImplementedError('TODO')

        elif isinstance(expr, laplace):
            arg = expr.args[0]
            v = cls.eval(grad(arg), domain)
            v = mapping.jacobian.inv().T * grad(v)
            return SymbolicTrace(v)

#        elif isinstance(expr, hessian):
#           arg = expr.args[0]
#            if isinstance(mapping, InterfaceMapping):
#                if isinstance(arg, MinusInterfaceOperator):
#                    arg     = arg.args[0]
#                    mapping = mapping.minus
#                elif isinstance(arg, PlusInterfaceOperator):
#                    arg = arg.args[0]
#                    mapping = mapping.plus
#                else:
#                    raise TypeError(arg)
#            v   = cls.eval(grad(expr.args[0]), domain)
#            v   = mapping.jacobian.inv().T*grad(v)
#            return v

        elif isinstance(expr, (dot, inner, outer)):
            args = [cls.eval(arg, domain) for arg in expr.args]
            return type(expr)(*args)

        elif isinstance(expr, _diff_ops):
            raise NotImplementedError('TODO')

        # TODO MUST BE MOVED AFTER TREATING THE CASES OF GRAD, CURL, DIV IN FEEC
        elif isinstance(expr, (Matrix, ImmutableDenseMatrix)):
            n_rows, n_cols = expr.shape
            lines = []
            for i_row in range(0, n_rows):
                line = []
                for i_col in range(0, n_cols):
                    line.append(cls.eval(expr[i_row, i_col], domain))
                lines.append(line)
            return type(expr)(lines)

        elif isinstance(expr, dx):
            if expr.atoms(PlusInterfaceOperator):
                mapping = mapping.plus
            elif expr.atoms(MinusInterfaceOperator):
                mapping = mapping.minus

            arg = expr.args[0]
            arg = cls(arg, domain, evaluate=True)

            if isinstance(arg, PullBack):
                arg = TerminalExpr(arg, domain=domain.logical_domain)
            elif isinstance(arg, MatrixElement):
                arg = TerminalExpr(arg, domain=domain.logical_domain)
            # ...
            if dim == 1:
                lgrad_arg = LogicalGrad_1d(arg)

                if not isinstance(lgrad_arg, (list, tuple, Tuple, Matrix)):
                    lgrad_arg = Tuple(lgrad_arg)

            elif dim == 2:
                lgrad_arg = LogicalGrad_2d(arg)

            elif dim == 3:
                lgrad_arg = LogicalGrad_3d(arg)

            grad_arg = Covariant(mapping, lgrad_arg)
            expr = grad_arg[0]
            return expr

        elif isinstance(expr, dy):
            if expr.atoms(PlusInterfaceOperator):
                mapping = mapping.plus
            elif expr.atoms(MinusInterfaceOperator):
                mapping = mapping.minus

            arg = expr.args[0]
            arg = cls(arg, domain, evaluate=True)
            if isinstance(arg, PullBack):
                arg = TerminalExpr(arg, domain=domain.logical_domain)
            elif isinstance(arg, MatrixElement):
                arg = TerminalExpr(arg, domain=domain.logical_domain)

            # ..p
            if dim == 1:
                lgrad_arg = LogicalGrad_1d(arg)

            elif dim == 2:
                lgrad_arg = LogicalGrad_2d(arg)

            elif dim == 3:
                lgrad_arg = LogicalGrad_3d(arg)

            grad_arg = Covariant(mapping, lgrad_arg)

            expr = grad_arg[1]
            return expr

        elif isinstance(expr, dz):
            if expr.atoms(PlusInterfaceOperator):
                mapping = mapping.plus
            elif expr.atoms(MinusInterfaceOperator):
                mapping = mapping.minus

            arg = expr.args[0]
            arg = cls(arg, domain, evaluate=True)
            if isinstance(arg, PullBack):
                arg = TerminalExpr(arg, domain=domain.logical_domain)
            elif isinstance(arg, MatrixElement):
                arg = TerminalExpr(arg, domain=domain.logical_domain)
            # ...
            if dim == 1:
                lgrad_arg = LogicalGrad_1d(arg)

            elif dim == 2:
                lgrad_arg = LogicalGrad_2d(arg)

            elif dim == 3:
                lgrad_arg = LogicalGrad_3d(arg)

            grad_arg = Covariant(mapping, lgrad_arg)

            expr = grad_arg[2]

            return expr

        elif isinstance(expr, (Symbol, Indexed)):
            return expr

        elif isinstance(expr, NormalVector):
            return expr

        elif isinstance(expr, Pow):
            b = expr.base
            e = expr.exp
            expr = Pow(cls(b, domain), cls(e, domain))
            return expr

        elif isinstance(expr, Trace):
            e = cls.eval(expr.expr, domain)
            bd = expr.boundary.logical_domain
            order = expr.order
            return Trace(e, bd, order)

        elif isinstance(expr, Integral):
            domain = expr.domain
            mapping = domain.mapping

            assert domain is not None

            if expr.is_domain_integral:
                J = mapping.jacobian
                det = sqrt((J.T * J).det())
            else:
                axis = domain.axis
                J = JacobianSymbol(mapping, axis=axis)
                det = sqrt((J.T * J).det())

            body = cls.eval(expr.expr, domain) * det
            domain = domain.logical_domain
            return Integral(body, domain)

        elif isinstance(expr, BilinearForm):
            tests = [get_logical_test_function(a) for a in expr.test_functions]
            trials = [
                get_logical_test_function(a) for a in expr.trial_functions
            ]
            body = cls.eval(expr.expr, domain)
            return BilinearForm((trials, tests), body)

        elif isinstance(expr, LinearForm):
            tests = [get_logical_test_function(a) for a in expr.test_functions]
            body = cls.eval(expr.expr, domain)
            return LinearForm(tests, body)

        elif isinstance(expr, Norm):
            kind = expr.kind
            exponent = expr.exponent
            e = cls.eval(expr.expr, domain)
            domain = domain.logical_domain
            norm = Norm(e, domain, kind, evaluate=False)
            norm._exponent = exponent
            return norm

        elif isinstance(expr, DomainExpression):
            domain = expr.target
            J = domain.mapping.jacobian
            newexpr = cls.eval(expr.expr, domain)
            newexpr = TerminalExpr(newexpr, domain=domain)
            domain = domain.logical_domain
            det = TerminalExpr(sqrt((J.T * J).det()), domain=domain)
            return DomainExpression(domain,
                                    ImmutableDenseMatrix([[newexpr * det]]))

        elif isinstance(expr, Function):
            args = [cls.eval(a, domain) for a in expr.args]
            return type(expr)(*args)

        return cls(expr, domain, evaluate=False)
Ejemplo n.º 21
0
    def eval(cls, *_args, **kwargs):
        """."""

        if not _args:
            return

        if not len(_args) == 1:
            raise ValueError('Expecting one argument')

        expr = _args[0]
        d_atoms = kwargs.pop('d_atoms', OrderedDict())
        mapping = kwargs.pop('mapping', None)
        expand = kwargs.pop('expand', False)

        if isinstance(expr, Add):
            args = [
                cls.eval(a, d_atoms=d_atoms, mapping=mapping)
                for a in expr.args
            ]
            return Add(*args)

        elif isinstance(expr, Mul):
            coeffs = [a for a in expr.args if isinstance(a, _coeffs_registery)]
            stests = [
                a for a in expr.args
                if not (a in coeffs) and a.atoms(ScalarTestFunction)
            ]
            vtests = [
                a for a in expr.args
                if not (a in coeffs) and a.atoms(VectorTestFunction)
            ]
            vectors = [
                a for a in expr.args if
                (not (a in coeffs) and not (a in stests) and not (a in vtests))
            ]

            a = S.One
            if coeffs:
                a = Mul(*coeffs)

            b = S.One
            if vectors:

                args = [cls(i, evaluate=False) for i in vectors]
                b = Mul(*args)

            sb = S.One
            if stests:
                args = [
                    cls.eval(i, d_atoms=d_atoms, mapping=mapping)
                    for i in stests
                ]
                sb = Mul(*args)

            vb = S.One
            if vtests:
                args = [
                    cls.eval(i, d_atoms=d_atoms, mapping=mapping)
                    for i in vtests
                ]
                vb = Mul(*args)

            return Mul(a, b, sb, vb)

        elif isinstance(expr, _coeffs_registery):
            return expr

        elif isinstance(expr, Pow):
            b = expr.base
            e = expr.exp
            return Pow(cls.eval(b), e)

        elif isinstance(expr, (Matrix, ImmutableDenseMatrix)):

            n_rows, n_cols = expr.shape

            lines = []
            for i_row in range(0, n_rows):
                line = []
                for i_col in range(0, n_cols):
                    line.append(
                        cls.eval(expr[i_row, i_col],
                                 d_atoms=d_atoms,
                                 mapping=mapping))

                lines.append(line)

            return ImmutableDenseMatrix(lines)

        elif isinstance(expr, DomainExpression):
            # TODO to be removed
            target = expr.target
            expr = expr.expr
            return cls.eval(expr, d_atoms=d_atoms, mapping=mapping)

        elif isinstance(expr, BilinearForm):
            trials = list(expr.variables[0])
            tests = list(expr.variables[1])

            # ... # TODO improve
            terminal_expr = TerminalExpr(expr)[0]
            # ...

            # ...
            variables = list(terminal_expr.atoms(ScalarTestFunction))
            variables += list(terminal_expr.atoms(IndexedTestTrial))
            # ...

            # ...
            if not (mapping is None):
                dim = expr.ldim
                terminal_expr = LogicalExpr(terminal_expr.expr,
                                            mapping=mapping,
                                            dim=dim)
                variables = [
                    LogicalExpr(e, mapping=mapping, dim=dim) for e in variables
                ]
                trials = [
                    LogicalExpr(e, mapping=mapping, dim=dim) for e in trials
                ]
                tests = [
                    LogicalExpr(e, mapping=mapping, dim=dim) for e in tests
                ]
            # ...

            d_atoms = OrderedDict()
            for a in variables:
                new = _split_test_function(a)
                d_atoms[a] = new[a]

            # ...
            expr = cls.eval(terminal_expr, d_atoms=d_atoms, mapping=mapping)
            # ...

            # ...
            trials = [
                a for a in variables
                if ((isinstance(a, ScalarTestFunction) and a in trials) or (
                    isinstance(a, IndexedTestTrial) and a.base in trials))
            ]

            tests = [
                a for a in variables
                if ((isinstance(a, ScalarTestFunction) and a in tests) or (
                    isinstance(a, IndexedTestTrial) and a.base in tests))
            ]
            # ...

            expr = _replace_atomic_expr(expr,
                                        trials,
                                        tests,
                                        d_atoms,
                                        logical=True,
                                        expand=expand)

            return expr

        if expr.atoms(ScalarTestFunction) or expr.atoms(IndexedTestTrial):
            return _tensorize_atomic_expr(expr, d_atoms)

        return cls(expr, evaluate=False)
Ejemplo n.º 22
0
    def eval(cls, *_args, **kwargs):
        """."""

        if not _args:
            return

        if not len(_args) == 1:
            raise ValueError('Expecting one argument')

        expr = _args[0]
        n_rows = kwargs.pop('n_rows', None)
        n_cols = kwargs.pop('n_cols', None)
        dim = kwargs.pop('dim', None)
        logical = kwargs.pop('logical', None)

        if isinstance(expr, Add):
            args = [cls.eval(a, dim=dim, logical=logical) for a in expr.args]
            o = args[0]
            for arg in args[1:]:
                o = o + arg
            return o

        elif isinstance(expr, Mul):
            args = [cls.eval(a, dim=dim, logical=logical) for a in expr.args]
            o = args[0]
            for arg in args[1:]:
                o = o * arg
            return o

        elif isinstance(expr, Abs):
            return Abs(cls.eval(expr.args[0], dim=dim, logical=logical))

        elif isinstance(expr, Pow):
            base = cls.eval(expr.base, dim=dim, logical=logical)
            exp = cls.eval(expr.exp, dim=dim, logical=logical)
            return base**exp

        elif isinstance(expr, JacobianSymbol):
            axis = expr.axis
            J = Jacobian(expr.mapping)
            if axis is None:
                return J
            else:
                return J.col_del(axis)

        elif isinstance(expr, SymbolicDeterminant):
            return cls.eval(expr.arg, dim=dim, logical=logical).det().factor()

        elif isinstance(expr, SymbolicTrace):
            return cls.eval(expr.arg, dim=dim, logical=logical).trace()

        elif isinstance(expr, Transpose):
            return cls.eval(expr.arg, dim=dim, logical=logical).T

        elif isinstance(expr, Inverse):
            return cls.eval(expr.arg, dim=dim, logical=logical).inv()

        elif isinstance(expr, (ScalarTestFunction, VectorTestFunction)):
            return expr

        elif isinstance(expr, PullBack):
            return cls.eval(expr.expr, dim=dim, logical=True)

        elif isinstance(expr, MatrixElement):
            base = cls.eval(expr.base, dim=dim, logical=logical)
            return base[expr.indices]

        elif isinstance(expr, BasicForm):
            # ...
            dim = expr.ldim
            domain = expr.domain

            if not isinstance(domain, Union):
                logical = domain.mapping is None
                domain = (domain, )
            # ...
            d_expr = OrderedDict()
            for d in domain:
                d_expr[d] = S.Zero
            # ...
            if isinstance(expr.expr, Add):
                for a in expr.expr.args:
                    newexpr = cls.eval(a, dim=dim, logical=True)

                    # ...
                    try:
                        domain = _get_domain(a)
                        if not isinstance(domain, Union):
                            domain = (domain, )
                    except:
                        pass
                    # ...
                    for d in domain:
                        d_expr[d] += newexpr
                    # ...
            else:
                newexpr = cls.eval(expr.expr, dim=dim, logical=logical)
                # ...
                if isinstance(expr, Functional):
                    domain = expr.domain

                else:
                    domain = _get_domain(expr.expr)

                if isinstance(domain, Union):
                    domain = list(domain._args)

                elif not is_sequence(domain):
                    domain = [domain]
                # ...

                # ...
                for d in domain:
                    d_expr[d] = newexpr
                # ...

            trials, tests = _get_trials_tests_flattened(expr)

            d_new = OrderedDict()
            for domain, newexpr in d_expr.items():

                if newexpr != 0:

                    # TODO ARA make sure thre is no problem with psydac
                    #      we should always take the interior of a domain
                    if not isinstance(domain,
                                      (Boundary, Interface, InteriorDomain)):
                        domain = domain.interior

                    d_new[domain] = _to_matrix_form(newexpr,
                                                    trials=trials,
                                                    tests=tests)

            # ...
            ls = []
            d_all = OrderedDict()

            # ... treating interfaces
            keys = [k for k in d_new.keys() if isinstance(k, Interface)]
            for interface in keys:
                # ...
                trials = None
                tests = None
                if expr.is_bilinear:
                    trials = list(expr.variables[0])
                    tests = list(expr.variables[1])

                elif expr.is_linear:
                    tests = list(expr.variables)
                # ...

                # ...
                newexpr = d_new[interface]
                ls_int, d_bnd = _split_expr_over_interface(newexpr,
                                                           interface,
                                                           tests=tests,
                                                           trials=trials)
                # ...

                ls += ls_int
                # ...
                for k, v in d_bnd.items():
                    if k in d_all.keys():
                        d_all[k] += v

                    else:
                        d_all[k] = v
            # ...

            # ... treating subdomains
            keys = [k for k in d_new.keys() if isinstance(k, Union)]
            for domain in keys:

                newexpr = d_new[domain]
                d = OrderedDict(
                    (interior, newexpr) for interior in domain.as_tuple())
                # ...
                for k, v in d.items():
                    if k in d_all.keys():
                        d_all[k] += v

                    else:
                        d_all[k] = v

            d = OrderedDict()

            for k, v in d_new.items():
                if not isinstance(k, (Interface, Union)):
                    d[k] = d_new[k]

            for k, v in d_all.items():
                if k in d.keys():
                    d[k] += v
                else:
                    d[k] = v

            d_new = d
            # ...
            for domain, newexpr in d_new.items():
                if isinstance(domain, Boundary):
                    ls += [BoundaryExpression(domain, newexpr)]

                elif isinstance(domain, BasicDomain):
                    ls += [DomainExpression(domain, newexpr)]

                else:
                    raise TypeError('not implemented for {}'.format(
                        type(domain)))
            # ...
            return tuple(ls)

        elif isinstance(expr, Integral):
            dim = expr.domain.dim if dim is None else dim
            logical = expr.domain.mapping is None
            return cls.eval(expr._args[0], dim=dim, logical=logical)

        elif isinstance(expr, NormalVector):
            lines = [[expr[i] for i in range(dim)]]
            return ImmutableDenseMatrix(lines)

        elif isinstance(expr, TangentVector):
            lines = [[expr[i] for i in range(dim)]]
            return ImmutableDenseMatrix(lines)

        elif isinstance(expr, BasicExpr):
            return cls.eval(expr.expr, dim=dim, logical=logical)

        elif isinstance(expr, _diff_ops):
            op = type(expr)
            if logical:
                new = eval('Logical{0}_{1}d'.format(op, dim))
            else:
                new = eval('{0}_{1}d'.format(op, dim))

            args = [cls.eval(i, dim=dim, logical=logical) for i in expr.args]
            return new(*args)
        elif isinstance(expr, _generic_ops):
            # if i = Dot(...) then type(i) is Grad
            op = type(expr)
            new = eval('{0}_{1}d'.format(op, dim))
            args = [cls.eval(i, dim=dim, logical=logical) for i in expr.args]
            return new(*args)

        elif isinstance(expr, Trace):
            # TODO treate different spaces
            if expr.order == 0:
                return cls.eval(expr.expr, dim=dim, logical=logical)

            elif expr.order == 1:
                # TODO give a name to normal vector
                normal_vector_name = 'n'
                n = NormalVector(normal_vector_name)
                M = cls.eval(expr.expr, dim=dim, logical=logical)

                if dim == 1:
                    return M
                else:
                    if isinstance(M, (Add, Mul)):
                        ls = M.atoms(Tuple)

                        for i in ls:
                            M = M.subs(i, Matrix(i))
                        M = simplify(M)
                    e = 0
                    for i in range(0, dim):
                        e += M[i] * n[i]
                    return e
            else:
                raise ValueError(
                    '> Only traces of order 0 and 1 are available')

        elif isinstance(expr, (Matrix, ImmutableDenseMatrix)):
            n, m = expr.shape
            lines = []
            for i in range(0, n):
                line = []
                for j in range(0, m):
                    line.append(cls.eval(expr[i, j], dim=dim, logical=logical))
                lines.append(line)
            return ImmutableDenseMatrix(lines)

        elif isinstance(expr, LogicalExpr):
            M = expr.mapping
            dim = expr.dim
            expr = cls(expr.expr, dim=dim)
            dim = M.rdim
            return LogicalExpr(expr, mapping=M, dim=dim)
        return expr