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
def eval(cls, *_args): if not _args: return u = _args[0] return ImmutableDenseMatrix([[dy(u)], [-dx(u)]])
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])]])
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
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)
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))]])
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))]])
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 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
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)
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)
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)
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
def as_explicit(self): from sympy import ImmutableDenseMatrix return ImmutableDenseMatrix.ones(*self.shape)
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(1), S(1), S(1)): 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 is 'spherical': variable_names = ["r", "theta", "phi"] elif transformation.name is '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 = [(name + '_' + x) 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 = [(name + '_' + x) 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
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
def func(self, *args): """ These should never be interpretted as expressions, only roots. """ return ImmutableDenseMatrix(*args)
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
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
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)
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)
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
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
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 setup(self): self.M1 = MutableDenseMatrix.zeros(5, 5) self.M2 = ImmutableDenseMatrix.zeros(5, 5) self.M3 = MutableSparseMatrix.zeros(5, 5) self.M4 = ImmutableSparseMatrix.zeros(5, 5)