def __new__(cls,dist, rvs): if not all([isinstance(rv, (Indexed, RandomSymbol))] for rv in rvs): raise ValueError(filldedent('''Marginal distribution can be intitialised only in terms of random variables or indexed random variables''')) rvs = Tuple.fromiter(rv for rv in rvs) if not isinstance(dist, JointDistribution) and len(random_symbols(dist)) == 0: return dist return Basic.__new__(cls, dist, rvs)
def bq(self): """ Combined denominator parameters. """ return Tuple(*(self.args[1][0] + self.args[1][1]))
def aother(self): """ Second set of numerator parameters. """ return Tuple(*self.args[0][1])
def an(self): """ First set of numerator parameters. """ return Tuple(*self.args[0][0])
def ap(self): """ Numerator parameters of the hypergeometric function. """ return Tuple(*self.args[0])
def __init__(self, data, **kwarg): """ Creates a TableForm. Parameters: data ... 2D data to be put into the table; data can be given as a Matrix headings ... gives the labels for rows and columns: Can be a single argument that applies to both dimensions: - None ... no labels - "automatic" ... labels are 1, 2, 3, ... Can be a list of labels for rows and columns: The labels for each dimension can be given as None, "automatic", or [l1, l2, ...] e.g. ["automatic", None] will number the rows [default: None] alignments ... alignment of the columns with: - "left" or "<" - "center" or "^" - "right" or ">" When given as a single value, the value is used for all columns. The row headings (if given) will be right justified unless an explicit alignment is given for it and all other columns. [default: "left"] formats ... a list of format strings or functions that accept 3 arguments (entry, row number, col number) and return a string for the table entry. (If a function returns None then the _print method will be used.) wipe_zeros ... Don't show zeros in the table. [default: True] pad ... the string to use to indicate a missing value (e.g. elements that are None or those that are missing from the end of a row (i.e. any row that is shorter than the rest is assumed to have missing values). When None, nothing will be shown for values that are missing from the end of a row; values that are None, however, will be shown. [default: None] Examples ======== >>> from sympy import TableForm, Symbol >>> TableForm([[5, 7], [4, 2], [10, 3]]) 5 7 4 2 10 3 >>> TableForm([list('.'*i) for i in range(1, 4)], headings='automatic') | 1 2 3 --------- 1 | . 2 | . . 3 | . . . >>> TableForm([[Symbol('.'*(j if not i%2 else 1)) for i in range(3)] ... for j in range(4)], alignments='rcl') . . . . .. . .. ... . ... """ from sympy.matrices.dense import Matrix # We only support 2D data. Check the consistency: if isinstance(data, Matrix): data = data.tolist() _h = len(data) # fill out any short lines pad = kwarg.get('pad', None) ok_None = False if pad is None: pad = " " ok_None = True pad = Symbol(pad) _w = max(len(line) for line in data) for i, line in enumerate(data): if len(line) != _w: line.extend([pad] * (_w - len(line))) for j, lj in enumerate(line): if lj is None: if not ok_None: lj = pad else: try: lj = S(lj) except SympifyError: lj = Symbol(str(lj)) line[j] = lj data[i] = line _lines = Tuple(*[Tuple(*d) for d in data]) headings = kwarg.get("headings", [None, None]) if headings == "automatic": _headings = [range(1, _h + 1), range(1, _w + 1)] else: h1, h2 = headings if h1 == "automatic": h1 = range(1, _h + 1) if h2 == "automatic": h2 = range(1, _w + 1) _headings = [h1, h2] allow = ('l', 'r', 'c') alignments = kwarg.get("alignments", "l") def _std_align(a): a = a.strip().lower() if len(a) > 1: return {'left': 'l', 'right': 'r', 'center': 'c'}.get(a, a) else: return {'<': 'l', '>': 'r', '^': 'c'}.get(a, a) std_align = _std_align(alignments) if std_align in allow: _alignments = [std_align] * _w else: _alignments = [] for a in alignments: std_align = _std_align(a) _alignments.append(std_align) if std_align not in ('l', 'r', 'c'): raise ValueError('alignment "%s" unrecognized' % alignments) if _headings[0] and len(_alignments) == _w + 1: _head_align = _alignments[0] _alignments = _alignments[1:] else: _head_align = 'r' if len(_alignments) != _w: raise ValueError( 'wrong number of alignments: expected %s but got %s' % (_w, len(_alignments))) _column_formats = kwarg.get("formats", [None] * _w) _wipe_zeros = kwarg.get("wipe_zeros", True) self._w = _w self._h = _h self._lines = _lines self._headings = _headings self._head_align = _head_align self._alignments = _alignments self._column_formats = _column_formats self._wipe_zeros = _wipe_zeros
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 _process_limits(*symbols): """Process the list of symbols and convert them to canonical limits, storing them as Tuple(symbol, lower, upper). The orientation of the function is also returned when the upper limit is missing so (x, 1, None) becomes (x, None, 1) and the orientation is changed. """ limits = [] orientation = 1 for V in symbols: if isinstance(V, (Relational, BooleanFunction)): variable = V.atoms(Symbol).pop() V = (variable, V.as_set()) if isinstance(V, Symbol) or getattr(V, '_diff_wrt', False): if isinstance(V, Idx): if V.lower is None or V.upper is None: limits.append(Tuple(V)) else: limits.append(Tuple(V, V.lower, V.upper)) else: limits.append(Tuple(V)) continue elif is_sequence(V, Tuple): if len(V) == 2 and isinstance(V[1], Range): lo = V[1].inf hi = V[1].sup dx = abs(V[1].step) V = [V[0]] + [0, (hi - lo) // dx, dx * V[0] + lo] V = sympify(flatten(V)) # a list of sympified elements if isinstance(V[0], (Symbol, Idx)) or getattr(V[0], '_diff_wrt', False): newsymbol = V[0] if len(V) == 2 and isinstance(V[1], Interval): # 2 -> 3 # Interval V[1:] = [V[1].start, V[1].end] elif len(V) == 3: # general case if V[2] is None and not V[1] is None: orientation *= -1 V = [newsymbol] + [i for i in V[1:] if i is not None] if not isinstance(newsymbol, Idx) or len(V) == 3: if len(V) == 4: limits.append(Tuple(*V)) continue if len(V) == 3: if isinstance(newsymbol, Idx): # Idx represents an integer which may have # specified values it can take on; if it is # given such a value, an error is raised here # if the summation would try to give it a larger # or smaller value than permitted. None and Symbolic # values will not raise an error. lo, hi = newsymbol.lower, newsymbol.upper try: if lo is not None and not bool(V[1] >= lo): raise ValueError( "Summation will set Idx value too low." ) except TypeError: pass try: if hi is not None and not bool(V[2] <= hi): raise ValueError( "Summation will set Idx value too high." ) except TypeError: pass limits.append(Tuple(*V)) continue if len(V) == 1 or (len(V) == 2 and V[1] is None): limits.append(Tuple(newsymbol)) continue elif len(V) == 2: limits.append(Tuple(newsymbol, V[1])) continue raise ValueError('Invalid limits given: %s' % str(symbols)) return limits, orientation
def test_factor_terms(): A = Symbol('A', commutative=False) assert factor_terms(9*(x + x*y + 1) + (3*x + 3)**(2 + 2*x)) == \ 9*x*y + 9*x + _keep_coeff(S(3), x + 1)**_keep_coeff(S(2), x + 1) + 9 assert factor_terms(9*(x + x*y + 1) + (3)**(2 + 2*x)) == \ _keep_coeff(S(9), 3**(2*x) + x*y + x + 1) assert factor_terms(3**(2 + 2*x) + a*3**(2 + 2*x)) == \ 9*3**(2*x)*(a + 1) assert factor_terms(x + x*A) == \ x*(1 + A) assert factor_terms(sin(x + x*A)) == \ sin(x*(1 + A)) assert factor_terms((3*x + 3)**((2 + 2*x)/3)) == \ _keep_coeff(S(3), x + 1)**_keep_coeff(Rational(2, 3), x + 1) assert factor_terms(x + (x*y + x)**(3*x + 3)) == \ x + (x*(y + 1))**_keep_coeff(S(3), x + 1) assert factor_terms(a*(x + x*y) + b*(x*2 + y*x*2)) == \ x*(a + 2*b)*(y + 1) i = Integral(x, (x, 0, oo)) assert factor_terms(i) == i assert factor_terms(x / 2 + y) == x / 2 + y # fraction doesn't apply to integer denominators assert factor_terms(x / 2 + y, fraction=True) == x / 2 + y # clear *does* apply to the integer denominators assert factor_terms(x / 2 + y, clear=True) == Mul(S.Half, x + 2 * y, evaluate=False) # check radical extraction eq = sqrt(2) + sqrt(10) assert factor_terms(eq) == eq assert factor_terms(eq, radical=True) == sqrt(2) * (1 + sqrt(5)) eq = root(-6, 3) + root(6, 3) assert factor_terms( eq, radical=True) == 6**(S.One / 3) * (1 + (-1)**(S.One / 3)) eq = [x + x * y] ans = [x * (y + 1)] for c in [list, tuple, set]: assert factor_terms(c(eq)) == c(ans) assert factor_terms(Tuple(x + x * y)) == Tuple(x * (y + 1)) assert factor_terms(Interval(0, 1)) == Interval(0, 1) e = 1 / sqrt(a / 2 + 1) assert factor_terms(e, clear=False) == 1 / sqrt(a / 2 + 1) assert factor_terms(e, clear=True) == sqrt(2) / sqrt(a + 2) eq = x / (x + 1 / x) + 1 / (x**2 + 1) assert factor_terms(eq, fraction=False) == eq assert factor_terms(eq, fraction=True) == 1 assert factor_terms((1/(x**3 + x**2) + 2/x**2)*y) == \ y*(2 + 1/(x + 1))/x**2 # if not True, then processesing for this in factor_terms is not necessary assert gcd_terms(-x - y) == -x - y assert factor_terms(-x - y) == Mul(-1, x + y, evaluate=False) # if not True, then "special" processesing in factor_terms is not necessary assert gcd_terms(exp(Mul(-1, x + 1))) == exp(-x - 1) e = exp(-x - 2) + x assert factor_terms(e) == exp(Mul(-1, x + 2, evaluate=False)) + x assert factor_terms(e, sign=False) == e assert factor_terms(exp(-4 * x - 2) - x) == -x + exp(Mul(-2, 2 * x + 1, evaluate=False)) # sum/integral tests for F in (Sum, Integral): assert factor_terms(F(x, (y, 1, 10))) == x * F(1, (y, 1, 10)) assert factor_terms(F(x, (y, 1, 10)) + x) == x * (1 + F(1, (y, 1, 10))) assert factor_terms(F(x * y + x * y**2, (y, 1, 10))) == x * F(y * (y + 1), (y, 1, 10))
def __new__(cls, *args): args = list(map(sympify, args)) for i in range(len(args)): if isinstance(args[i], list): args[i] = Tuple.fromiter(j for j in args[i]) return Basic.__new__(cls, *args)
def test_count_ops_visual(): ADD, MUL, POW, SIN, COS, EXP, AND, D, G, M = symbols( 'Add Mul Pow sin cos exp And Derivative Integral Sum'.upper()) DIV, SUB, NEG = symbols('DIV SUB NEG') LT, LE, GT, GE, EQ, NE = symbols('LT LE GT GE EQ NE') NOT, OR, AND, XOR, IMPLIES, EQUIVALENT, _ITE, BASIC, TUPLE = symbols( 'Not Or And Xor Implies Equivalent ITE Basic Tuple'.upper()) def count(val): return count_ops(val, visual=True) assert count(7) is S.Zero assert count(S(7)) is S.Zero assert count(-1) == NEG assert count(-2) == NEG assert count(S(2) / 3) == DIV assert count(Rational(2, 3)) == DIV assert count(pi / 3) == DIV assert count(-pi / 3) == DIV + NEG assert count(I - 1) == SUB assert count(1 - I) == SUB assert count(1 - 2 * I) == SUB + MUL assert count(x) is S.Zero assert count(-x) == NEG assert count(-2 * x / 3) == NEG + DIV + MUL assert count(Rational(-2, 3) * x) == NEG + DIV + MUL assert count(1 / x) == DIV assert count(1 / (x * y)) == DIV + MUL assert count(-1 / x) == NEG + DIV assert count(-2 / x) == NEG + DIV assert count(x / y) == DIV assert count(-x / y) == NEG + DIV assert count(x**2) == POW assert count(-x**2) == POW + NEG assert count(-2 * x**2) == POW + MUL + NEG assert count(x + pi / 3) == ADD + DIV assert count(x + S.One / 3) == ADD + DIV assert count(x + Rational(1, 3)) == ADD + DIV assert count(x + y) == ADD assert count(x - y) == SUB assert count(y - x) == SUB assert count(-1 / (x - y)) == DIV + NEG + SUB assert count(-1 / (y - x)) == DIV + NEG + SUB assert count(1 + x**y) == ADD + POW assert count(1 + x + y) == 2 * ADD assert count(1 + x + y + z) == 3 * ADD assert count(1 + x**y + 2 * x * y + y**2) == 3 * ADD + 2 * POW + 2 * MUL assert count(2 * z + y + x + 1) == 3 * ADD + MUL assert count(2 * z + y**17 + x + 1) == 3 * ADD + MUL + POW assert count(2 * z + y**17 + x + sin(x)) == 3 * ADD + POW + MUL + SIN assert count(2 * z + y**17 + x + sin(x**2)) == 3 * ADD + MUL + 2 * POW + SIN assert count(2 * z + y**17 + x + sin(x**2) + exp(cos(x))) == 4 * ADD + MUL + 2 * POW + EXP + COS + SIN assert count(Derivative(x, x)) == D assert count(Integral(x, x) + 2 * x / (1 + x)) == G + DIV + MUL + 2 * ADD assert count(Sum(x, (x, 1, x + 1)) + 2 * x / (1 + x)) == M + DIV + MUL + 3 * ADD assert count(Basic()) is S.Zero assert count({x + 1: sin(x)}) == ADD + SIN assert count([x + 1, sin(x) + y, None]) == ADD + SIN + ADD assert count({x + 1: sin(x), y: cos(x) + 1}) == SIN + COS + 2 * ADD assert count({}) is S.Zero assert count([x + 1, sin(x) * y, None]) == SIN + ADD + MUL assert count([]) is S.Zero assert count(Basic()) == 0 assert count(Basic(Basic(), Basic(x, x + y))) == ADD + 2 * BASIC assert count(Basic(x, x + y)) == ADD + BASIC assert [count(Rel(x, y, op)) for op in '< <= > >= == <> !='.split() ] == [LT, LE, GT, GE, EQ, NE, NE] assert count(Or(x, y)) == OR assert count(And(x, y)) == AND assert count(Or(x, Or(y, And(z, a)))) == AND + OR assert count(Nor(x, y)) == NOT + OR assert count(Nand(x, y)) == NOT + AND assert count(Xor(x, y)) == XOR assert count(Implies(x, y)) == IMPLIES assert count(Equivalent(x, y)) == EQUIVALENT assert count(ITE(x, y, z)) == _ITE assert count([Or(x, y), And(x, y), Basic(x + y)]) == ADD + AND + BASIC + OR assert count(Basic(Tuple(x))) == BASIC + TUPLE #It checks that TUPLE is counted as an operation. assert count(Eq(x + y, S(2))) == ADD + EQ
def newtons_method_function(expr, wrt, params=None, func_name="newton", attrs=Tuple(), *, delta=None, **kwargs): """ Generates an AST for a function implementing the Newton-Raphson method. Parameters ========== expr : expression wrt : Symbol With respect to, i.e. what is the variable params : iterable of symbols Symbols appearing in expr that are taken as constants during the iterations (these will be accepted as parameters to the generated function). func_name : str Name of the generated function. attrs : Tuple Attribute instances passed as ``attrs`` to ``FunctionDefinition``. \\*\\*kwargs : Keyword arguments passed to :func:`sympy.codegen.algorithms.newtons_method`. Examples ======== >>> from sympy import symbols, cos >>> from sympy.codegen.algorithms import newtons_method_function >>> from sympy.codegen.pyutils import render_as_module >>> x = symbols('x') >>> expr = cos(x) - x**3 >>> func = newtons_method_function(expr, x) >>> py_mod = render_as_module(func) # source code as string >>> namespace = {} >>> exec(py_mod, namespace, namespace) >>> res = eval('newton(0.5)', namespace) >>> abs(res - 0.865474033102) < 1e-12 True See Also ======== sympy.codegen.algorithms.newtons_method """ if params is None: params = (wrt, ) pointer_subs = { p.symbol: Symbol('(*%s)' % p.symbol.name) for p in params if isinstance(p, Pointer) } if delta is None: delta = Symbol('d_' + wrt.name) if expr.has(delta): delta = None # will use Dummy algo = newtons_method(expr, wrt, delta=delta, **kwargs).xreplace(pointer_subs) if isinstance(algo, Scope): algo = algo.body not_in_params = expr.free_symbols.difference( {_symbol_of(p) for p in params}) if not_in_params: raise ValueError("Missing symbols in params: %s" % ', '.join(map(str, not_in_params))) declars = tuple(Variable(p, real) for p in params) body = CodeBlock(algo, Return(wrt)) return FunctionDefinition(real, func_name, declars, body, attrs=attrs)
def test_trace_new(): a, b, c, d, Y = symbols('a b c d Y') A, B, C, D = symbols('A B C D', commutative=False) assert Tr(a + b) == a + b assert Tr(A + B) == Tr(A) + Tr(B) #check trace args not implicitly permuted assert Tr(C * D * A * B).args[0].args == (C, D, A, B) # check for mul and adds assert Tr((a * b) + (c * d)) == (a * b) + (c * d) # Tr(scalar*A) = scalar*Tr(A) assert Tr(a * A) == a * Tr(A) assert Tr(a * A * B * b) == a * b * Tr(A * B) # since A is symbol and not commutative assert isinstance(Tr(A), Tr) #POW assert Tr(pow(a, b)) == a**b assert isinstance(Tr(pow(A, a)), Tr) #Matrix M = Matrix([[1, 1], [2, 2]]) assert Tr(M) == 3 ##test indices in different forms #no index t = Tr(A) assert t.args[1] == Tuple() #single index t = Tr(A, 0) assert t.args[1] == Tuple(0) #index in a list t = Tr(A, [0]) assert t.args[1] == Tuple(0) t = Tr(A, [0, 1, 2]) assert t.args[1] == Tuple(0, 1, 2) #index is tuple t = Tr(A, (0)) assert t.args[1] == Tuple(0) t = Tr(A, (1, 2)) assert t.args[1] == Tuple(1, 2) #trace indices test t = Tr((A + B), [2]) assert t.args[0].args[1] == Tuple(2) and t.args[1].args[1] == Tuple(2) t = Tr(a * A, [2, 3]) assert t.args[1].args[1] == Tuple(2, 3) #class with trace method defined #to simulate numpy objects class Foo: def trace(self): return 1 assert Tr(Foo()) == 1 #argument test # check for value error, when either/both arguments are not provided raises(ValueError, lambda: Tr()) raises(ValueError, lambda: Tr(A, 1, 2))
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 Point = sympy.vector.Point if not isinstance(name, str): 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, str): transformation = Str(transformation) elif isinstance(transformation, (Str, Lambda)): pass else: raise TypeError("transformation: " "wrong type {}".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, Str): 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, Str): 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().__new__( cls, Str(name), transformation, parent) else: obj = super().__new__( cls, Str(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 eval(cls, *_args): """.""" expr = _args[0] if isinstance(expr, (IndexedTestTrial, IndexedVectorField, DifferentialOperator)): return cls(expr, evaluate=False) elif isinstance(expr, (ScalarField, ScalarTestFunction)): return cls(expr, evaluate=False) elif isinstance(expr, (VectorTestFunction, VectorField)): n = expr.shape[0] args = [cls(expr[i], evaluate=False) for i in range(0, n)] args = Tuple(*args) return Matrix([args]) elif isinstance(expr, Indexed) and isinstance(expr.base, BasicMapping): return cls(expr, evaluate=False) elif isinstance(expr, (list, tuple, Tuple)): args = [cls(i, evaluate=True) for i in expr] args = Tuple(*args) return Matrix([args]) elif isinstance(expr, Add): args = expr.args args = [cls.eval(a) for a in expr.args] return Add(*args) elif isinstance(expr, Mul): coeffs = [a for a in expr.args if isinstance(a, _coeffs_registery)] vectors = [a for a in expr.args if not(a in coeffs)] c = S.One if coeffs: c = Mul(*coeffs) V = S.One if vectors: if len(vectors) == 1: # do we need to use Mul? V = cls(Mul(vectors[0]), evaluate=True) elif len(vectors) == 2: a = vectors[0] b = vectors[1] fa = cls(a, evaluate=True) fb = cls(b, evaluate=True) V = a * fb + fa * b else: a = vectors[0] b = Mul(*vectors[1:]) fa = cls(a, evaluate=True) fb = cls(b, evaluate=True) V = a * fb + fa * b return Mul(c, V) elif isinstance(expr, Pow): b = expr.base e = expr.exp return (log(b)*cls.eval(e) + e*cls.eval(b)/b) * b**e elif isinstance(expr, Derivative): x = Symbol(cls.coordinate) f = expr.args[0] args = list(expr.args[1:]) args += [x] return Derivative(f, *args) elif isinstance(expr, UndefinedFunction): x = Symbol(cls.coordinate) return Derivative(expr, x) elif isinstance(expr, AppliedUndef): x = Symbol(cls.coordinate) return Derivative(expr, x) elif isinstance(expr, _coeffs_registery): return S.Zero elif isinstance(expr, Expr): x = Symbol(cls.coordinate) return diff(expr, x) else: msg = '{expr} of type {type}'.format(expr=expr, type=type(expr)) raise NotImplementedError(msg)
def _eval_subs(self, old, new): """ Perform substitutions over non-dummy variables of an expression with limits. Also, can be used to specify point-evaluation of an abstract antiderivative. Examples ======== >>> from sympy import Sum, oo >>> from sympy.abc import s, n >>> Sum(1/n**s, (n, 1, oo)).subs(s, 2) Sum(n**(-2), (n, 1, oo)) >>> from sympy import Integral >>> from sympy.abc import x, a >>> Integral(a*x**2, x).subs(x, 4) Integral(a*x**2, (x, 4)) See Also ======== variables : Lists the integration variables transform : Perform mapping on the dummy variable for integrals change_index : Perform mapping on the sum and product dummy variables """ from sympy.core.function import AppliedUndef, UndefinedFunction func, limits = self.function, list(self.limits) # If one of the expressions we are replacing is used as a func index # one of two things happens. # - the old variable first appears as a free variable # so we perform all free substitutions before it becomes # a func index. # - the old variable first appears as a func index, in # which case we ignore. See change_index. # Reorder limits to match standard mathematical practice for scoping limits.reverse() if not isinstance(old, Symbol) or \ old.free_symbols.intersection(self.free_symbols): sub_into_func = True for i, xab in enumerate(limits): if 1 == len(xab) and old == xab[0]: if new._diff_wrt: xab = (new, ) else: xab = (old, old) limits[i] = Tuple(xab[0], *[l._subs(old, new) for l in xab[1:]]) if len(xab[0].free_symbols.intersection( old.free_symbols)) != 0: sub_into_func = False break if isinstance(old, AppliedUndef) or isinstance( old, UndefinedFunction): sy2 = set(self.variables).intersection(set(new.atoms(Symbol))) sy1 = set(self.variables).intersection(set(old.args)) if not sy2.issubset(sy1): raise ValueError( "substitution can not create dummy dependencies") sub_into_func = True if sub_into_func: func = func.subs(old, new) else: # old is a Symbol and a dummy variable of some limit for i, xab in enumerate(limits): if len(xab) == 3: limits[i] = Tuple(xab[0], *[l._subs(old, new) for l in xab[1:]]) if old == xab[0]: break # simplify redundant limits (x, x) to (x, ) for i, xab in enumerate(limits): if len(xab) == 2 and (xab[0] - xab[1]).is_zero: limits[i] = Tuple(xab[0], ) # Reorder limits back to representation-form limits.reverse() return self.func(func, *limits)
def __new__(cls, base_dims, derived_dims=(), dimensional_dependencies={}): dimensional_dependencies = dict(dimensional_dependencies) def parse_dim(dim): if isinstance(dim, str): dim = Dimension(Symbol(dim)) elif isinstance(dim, Dimension): pass elif isinstance(dim, Symbol): dim = Dimension(dim) else: raise TypeError("%s wrong type" % dim) return dim base_dims = [parse_dim(i) for i in base_dims] derived_dims = [parse_dim(i) for i in derived_dims] for dim in base_dims: dim = dim.name if (dim in dimensional_dependencies and (len(dimensional_dependencies[dim]) != 1 or dimensional_dependencies[dim].get(dim, None) != 1)): raise IndexError("Repeated value in base dimensions") dimensional_dependencies[dim] = Dict({dim: 1}) def parse_dim_name(dim): if isinstance(dim, Dimension): return dim.name elif isinstance(dim, str): return Symbol(dim) elif isinstance(dim, Symbol): return dim else: raise TypeError("unrecognized type %s for %s" % (type(dim), dim)) for dim in dimensional_dependencies.keys(): dim = parse_dim(dim) if (dim not in derived_dims) and (dim not in base_dims): derived_dims.append(dim) def parse_dict(d): return Dict({parse_dim_name(i): j for i, j in d.items()}) # Make sure everything is a SymPy type: dimensional_dependencies = { parse_dim_name(i): parse_dict(j) for i, j in dimensional_dependencies.items() } for dim in derived_dims: if dim in base_dims: raise ValueError("Dimension %s both in base and derived" % dim) if dim.name not in dimensional_dependencies: # TODO: should this raise a warning? dimensional_dependencies[dim.name] = Dict({dim.name: 1}) base_dims.sort(key=default_sort_key) derived_dims.sort(key=default_sort_key) base_dims = Tuple(*base_dims) derived_dims = Tuple(*derived_dims) dimensional_dependencies = Dict( {i: Dict(j) for i, j in dimensional_dependencies.items()}) obj = Basic.__new__(cls, base_dims, derived_dims, dimensional_dependencies) return obj
def __new__(cls): x = C.Dummy('x') #construct "by hand" to avoid infinite loop return Expr.__new__(cls, Tuple(x), x)
def cse(exprs, symbols=None, optimizations=None, postprocess=None, order='canonical', ignore=()): """ Perform common subexpression elimination on an expression. Parameters ========== exprs : list of sympy expressions, or a single sympy expression The expressions to reduce. symbols : infinite iterator yielding unique Symbols The symbols used to label the common subexpressions which are pulled out. The ``numbered_symbols`` generator is useful. The default is a stream of symbols of the form "x0", "x1", etc. This must be an infinite iterator. optimizations : list of (callable, callable) pairs The (preprocessor, postprocessor) pairs of external optimization functions. Optionally 'basic' can be passed for a set of predefined basic optimizations. Such 'basic' optimizations were used by default in old implementation, however they can be really slow on larger expressions. Now, no pre or post optimizations are made by default. postprocess : a function which accepts the two return values of cse and returns the desired form of output from cse, e.g. if you want the replacements reversed the function might be the following lambda: lambda r, e: return reversed(r), e order : string, 'none' or 'canonical' The order by which Mul and Add arguments are processed. If set to 'canonical', arguments will be canonically ordered. If set to 'none', ordering will be faster but dependent on expressions hashes, thus machine dependent and variable. For large expressions where speed is a concern, use the setting order='none'. ignore : iterable of Symbols Substitutions containing any Symbol from ``ignore`` will be ignored. Returns ======= replacements : list of (Symbol, expression) pairs All of the common subexpressions that were replaced. Subexpressions earlier in this list might show up in subexpressions later in this list. reduced_exprs : list of sympy expressions The reduced expressions with all of the replacements above. Examples ======== >>> from sympy import cse, SparseMatrix >>> from sympy.abc import x, y, z, w >>> cse(((w + x + y + z)*(w + y + z))/(w + x)**3) ([(x0, y + z), (x1, w + x)], [(w + x0)*(x0 + x1)/x1**3]) Note that currently, y + z will not get substituted if -y - z is used. >>> cse(((w + x + y + z)*(w - y - z))/(w + x)**3) ([(x0, w + x)], [(w - y - z)*(x0 + y + z)/x0**3]) List of expressions with recursive substitutions: >>> m = SparseMatrix([x + y, x + y + z]) >>> cse([(x+y)**2, x + y + z, y + z, x + z + y, m]) ([(x0, x + y), (x1, x0 + z)], [x0**2, x1, y + z, x1, Matrix([ [x0], [x1]])]) Note: the type and mutability of input matrices is retained. >>> isinstance(_[1][-1], SparseMatrix) True The user may disallow substitutions containing certain symbols: >>> cse([y**2*(x + 1), 3*y**2*(x + 1)], ignore=(y,)) ([(x0, x + 1)], [x0*y**2, 3*x0*y**2]) """ from sympy.matrices import (MatrixBase, Matrix, ImmutableMatrix, SparseMatrix, ImmutableSparseMatrix) # Handle the case if just one expression was passed. if isinstance(exprs, (Basic, MatrixBase)): exprs = [exprs] copy = exprs temp = [] for e in exprs: if isinstance(e, (Matrix, ImmutableMatrix)): temp.append(Tuple(*e._mat)) elif isinstance(e, (SparseMatrix, ImmutableSparseMatrix)): temp.append(Tuple(*e._smat.items())) else: temp.append(e) exprs = temp del temp if optimizations is None: optimizations = list() elif optimizations == 'basic': optimizations = basic_optimizations # Preprocess the expressions to give us better optimization opportunities. reduced_exprs = [preprocess_for_cse(e, optimizations) for e in exprs] if symbols is None: symbols = numbered_symbols(cls=Symbol) else: # In case we get passed an iterable with an __iter__ method instead of # an actual iterator. symbols = iter(symbols) # Find other optimization opportunities. opt_subs = opt_cse(reduced_exprs, order) # Main CSE algorithm. replacements, reduced_exprs = tree_cse(reduced_exprs, symbols, opt_subs, order, ignore) # Postprocess the expressions to return the expressions to canonical form. exprs = copy for i, (sym, subtree) in enumerate(replacements): subtree = postprocess_for_cse(subtree, optimizations) replacements[i] = (sym, subtree) reduced_exprs = [ postprocess_for_cse(e, optimizations) for e in reduced_exprs ] # Get the matrices back for i, e in enumerate(exprs): if isinstance(e, (Matrix, ImmutableMatrix)): reduced_exprs[i] = Matrix(e.rows, e.cols, reduced_exprs[i]) if isinstance(e, ImmutableMatrix): reduced_exprs[i] = reduced_exprs[i].as_immutable() elif isinstance(e, (SparseMatrix, ImmutableSparseMatrix)): m = SparseMatrix(e.rows, e.cols, {}) for k, v in reduced_exprs[i]: m[k] = v if isinstance(e, ImmutableSparseMatrix): m = m.as_immutable() reduced_exprs[i] = m if postprocess is None: return replacements, reduced_exprs return postprocess(replacements, reduced_exprs)
def _construct_declarations(cls, args): return Tuple(*[Declaration(arg) for arg in args])
def __new__(cls, *args, **kwargs): evaluate = kwargs.get('evaluate', global_evaluate[0]) on_morph = kwargs.get('on_morph', 'ignore') # unpack into coords coords = args[0] if len(args) == 1 else args # check args and handle quickly handle Point instances if isinstance(coords, Point): # even if we're mutating the dimension of a point, we # don't reevaluate its coordinates evaluate = False if len(coords) == kwargs.get('dim', len(coords)): return coords if not is_sequence(coords): raise TypeError( filldedent(''' Expecting sequence of coordinates, not `{}`'''.format( func_name(coords)))) # A point where only `dim` is specified is initialized # to zeros. if len(coords) == 0 and kwargs.get('dim', None): coords = (S.Zero, ) * kwargs.get('dim') coords = Tuple(*coords) dim = kwargs.get('dim', len(coords)) if len(coords) < 2: raise ValueError( filldedent(''' Point requires 2 or more coordinates or keyword `dim` > 1.''')) if len(coords) != dim: message = ("Dimension of {} needs to be changed " "from {} to {}.").format(coords, len(coords), dim) if on_morph == 'ignore': pass elif on_morph == "error": raise ValueError(message) elif on_morph == 'warn': warnings.warn(message) else: raise ValueError( filldedent(''' on_morph value should be 'error', 'warn' or 'ignore'.''')) if any(coords[dim:]): raise ValueError('Nonzero coordinates cannot be removed.') if any(a.is_number and im(a) for a in coords): raise ValueError('Imaginary coordinates are not permitted.') if not all(isinstance(a, Expr) for a in coords): raise TypeError('Coordinates must be valid SymPy expressions.') # pad with zeros appropriately coords = coords[:dim] + (S.Zero, ) * (dim - len(coords)) # Turn any Floats into rationals and simplify # any expressions before we instantiate if evaluate: coords = coords.xreplace( dict([(f, simplify(nsimplify(f, rational=True))) for f in coords.atoms(Float)])) # return 2D or 3D instances if len(coords) == 2: kwargs['_nocheck'] = True return Point2D(*coords, **kwargs) elif len(coords) == 3: kwargs['_nocheck'] = True return Point3D(*coords, **kwargs) # the general Point return GeometryEntity.__new__(cls, *coords)
def __new__(cls, expr, *args, **kwargs): expr = sympify(expr) if not args: if expr.is_Order: variables = expr.variables point = expr.point else: variables = list(expr.free_symbols) point = [S.Zero] * len(variables) else: args = list(args if is_sequence(args) else [args]) variables, point = [], [] if is_sequence(args[0]): for a in args: v, p = list(map(sympify, a)) variables.append(v) point.append(p) else: variables = list(map(sympify, args)) point = [S.Zero] * len(variables) if not all(v.is_symbol for v in variables): raise TypeError('Variables are not symbols, got %s' % variables) if len(list(uniq(variables))) != len(variables): raise ValueError( 'Variables are supposed to be unique symbols, got %s' % variables) if expr.is_Order: expr_vp = dict(expr.args[1:]) new_vp = dict(expr_vp) vp = dict(zip(variables, point)) for v, p in vp.items(): if v in new_vp.keys(): if p != new_vp[v]: raise NotImplementedError( "Mixing Order at different points is not supported." ) else: new_vp[v] = p if set(expr_vp.keys()) == set(new_vp.keys()): return expr else: variables = list(new_vp.keys()) point = [new_vp[v] for v in variables] if expr is S.NaN: return S.NaN if any(x in p.free_symbols for x in variables for p in point): raise ValueError('Got %s as a point.' % point) if variables: if any(p != point[0] for p in point): raise NotImplementedError( "Multivariable orders at different points are not supported." ) if point[0] is S.Infinity: s = {k: 1 / Dummy() for k in variables} rs = {1 / v: 1 / k for k, v in s.items()} elif point[0] is S.NegativeInfinity: s = {k: -1 / Dummy() for k in variables} rs = {-1 / v: -1 / k for k, v in s.items()} elif point[0] is not S.Zero: s = dict((k, Dummy() + point[0]) for k in variables) rs = dict((v - point[0], k - point[0]) for k, v in s.items()) else: s = () rs = () expr = expr.subs(s) if expr.is_Add: from sympy import expand_multinomial expr = expand_multinomial(expr) if s: args = tuple([r[0] for r in rs.items()]) else: args = tuple(variables) if len(variables) > 1: # XXX: better way? We need this expand() to # workaround e.g: expr = x*(x + y). # (x*(x + y)).as_leading_term(x, y) currently returns # x*y (wrong order term!). That's why we want to deal with # expand()'ed expr (handled in "if expr.is_Add" branch below). expr = expr.expand() old_expr = None while old_expr != expr: old_expr = expr if expr.is_Add: lst = expr.extract_leading_order(args) expr = Add(*[f.expr for (e, f) in lst]) elif expr: expr = expr.as_leading_term(*args) expr = expr.as_independent(*args, as_Add=False)[1] expr = expand_power_base(expr) expr = expand_log(expr) if len(args) == 1: # The definition of O(f(x)) symbol explicitly stated that # the argument of f(x) is irrelevant. That's why we can # combine some power exponents (only "on top" of the # expression tree for f(x)), e.g.: # x**p * (-x)**q -> x**(p+q) for real p, q. x = args[0] margs = list( Mul.make_args( expr.as_independent(x, as_Add=False)[1])) for i, t in enumerate(margs): if t.is_Pow: b, q = t.args if b in (x, -x) and q.is_real and not q.has(x): margs[i] = x**q elif b.is_Pow and not b.exp.has(x): b, r = b.args if b in (x, -x) and r.is_real: margs[i] = x**(r * q) elif b.is_Mul and b.args[0] is S.NegativeOne: b = -b if b.is_Pow and not b.exp.has(x): b, r = b.args if b in (x, -x) and r.is_real: margs[i] = x**(r * q) expr = Mul(*margs) expr = expr.subs(rs) if expr.is_Order: expr = expr.expr if not expr.has(*variables) and not expr.is_zero: expr = S.One # create Order instance: vp = dict(zip(variables, point)) variables.sort(key=default_sort_key) point = [vp[v] for v in variables] args = (expr, ) + Tuple(*zip(variables, point)) obj = Expr.__new__(cls, *args) return obj
def signature(self): return Tuple(self._symbol)
def bq(self): """ Denominator parameters of the hypergeometric function. """ return Tuple(*self.args[1])
def test_residue(): assert n_order(2, 13) == 12 assert [n_order(a, 7) for a in range(1, 7)] == \ [1, 3, 6, 3, 6, 2] assert n_order(5, 17) == 16 assert n_order(17, 11) == n_order(6, 11) assert n_order(101, 119) == 6 assert n_order(11, (10**50 + 151)**2) == 10000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000022650 raises(ValueError, lambda: n_order(6, 9)) assert is_primitive_root(2, 7) is False assert is_primitive_root(3, 8) is False assert is_primitive_root(11, 14) is False assert is_primitive_root(12, 17) == is_primitive_root(29, 17) raises(ValueError, lambda: is_primitive_root(3, 6)) for p in primerange(3, 100): it = _primitive_root_prime_iter(p) assert len(list(it)) == totient(totient(p)) assert primitive_root(97) == 5 assert primitive_root(97**2) == 5 assert primitive_root(40487) == 5 # note that primitive_root(40487) + 40487 = 40492 is a primitive root # of 40487**2, but it is not the smallest assert primitive_root(40487**2) == 10 assert primitive_root(82) == 7 p = 10**50 + 151 assert primitive_root(p) == 11 assert primitive_root(2*p) == 11 assert primitive_root(p**2) == 11 raises(ValueError, lambda: primitive_root(-3)) assert is_quad_residue(3, 7) is False assert is_quad_residue(10, 13) is True assert is_quad_residue(12364, 139) == is_quad_residue(12364 % 139, 139) assert is_quad_residue(207, 251) is True assert is_quad_residue(0, 1) is True assert is_quad_residue(1, 1) is True assert is_quad_residue(0, 2) == is_quad_residue(1, 2) is True assert is_quad_residue(1, 4) is True assert is_quad_residue(2, 27) is False assert is_quad_residue(13122380800, 13604889600) is True assert [j for j in range(14) if is_quad_residue(j, 14)] == \ [0, 1, 2, 4, 7, 8, 9, 11] raises(ValueError, lambda: is_quad_residue(1.1, 2)) raises(ValueError, lambda: is_quad_residue(2, 0)) assert quadratic_residues(S.One) == [0] assert quadratic_residues(1) == [0] assert quadratic_residues(12) == [0, 1, 4, 9] assert quadratic_residues(13) == [0, 1, 3, 4, 9, 10, 12] assert [len(quadratic_residues(i)) for i in range(1, 20)] == \ [1, 2, 2, 2, 3, 4, 4, 3, 4, 6, 6, 4, 7, 8, 6, 4, 9, 8, 10] assert list(sqrt_mod_iter(6, 2)) == [0] assert sqrt_mod(3, 13) == 4 assert sqrt_mod(3, -13) == 4 assert sqrt_mod(6, 23) == 11 assert sqrt_mod(345, 690) == 345 assert sqrt_mod(67, 101) == None assert sqrt_mod(1020, 104729) == None for p in range(3, 100): d = defaultdict(list) for i in range(p): d[pow(i, 2, p)].append(i) for i in range(1, p): it = sqrt_mod_iter(i, p) v = sqrt_mod(i, p, True) if v: v = sorted(v) assert d[i] == v else: assert not d[i] assert sqrt_mod(9, 27, True) == [3, 6, 12, 15, 21, 24] assert sqrt_mod(9, 81, True) == [3, 24, 30, 51, 57, 78] assert sqrt_mod(9, 3**5, True) == [3, 78, 84, 159, 165, 240] assert sqrt_mod(81, 3**4, True) == [0, 9, 18, 27, 36, 45, 54, 63, 72] assert sqrt_mod(81, 3**5, True) == [9, 18, 36, 45, 63, 72, 90, 99, 117,\ 126, 144, 153, 171, 180, 198, 207, 225, 234] assert sqrt_mod(81, 3**6, True) == [9, 72, 90, 153, 171, 234, 252, 315,\ 333, 396, 414, 477, 495, 558, 576, 639, 657, 720] assert sqrt_mod(81, 3**7, True) == [9, 234, 252, 477, 495, 720, 738, 963,\ 981, 1206, 1224, 1449, 1467, 1692, 1710, 1935, 1953, 2178] for a, p in [(26214400, 32768000000), (26214400, 16384000000), (262144, 1048576), (87169610025, 163443018796875), (22315420166400, 167365651248000000)]: assert pow(sqrt_mod(a, p), 2, p) == a n = 70 a, p = 5**2*3**n*2**n, 5**6*3**(n+1)*2**(n+2) it = sqrt_mod_iter(a, p) for i in range(10): assert pow(next(it), 2, p) == a a, p = 5**2*3**n*2**n, 5**6*3**(n+1)*2**(n+3) it = sqrt_mod_iter(a, p) for i in range(2): assert pow(next(it), 2, p) == a n = 100 a, p = 5**2*3**n*2**n, 5**6*3**(n+1)*2**(n+1) it = sqrt_mod_iter(a, p) for i in range(2): assert pow(next(it), 2, p) == a assert type(next(sqrt_mod_iter(9, 27))) is int assert type(next(sqrt_mod_iter(9, 27, ZZ))) is type(ZZ(1)) assert type(next(sqrt_mod_iter(1, 7, ZZ))) is type(ZZ(1)) assert is_nthpow_residue(2, 1, 5) #issue 10816 assert is_nthpow_residue(1, 0, 1) is False assert is_nthpow_residue(1, 0, 2) is True assert is_nthpow_residue(3, 0, 2) is True assert is_nthpow_residue(0, 1, 8) is True assert is_nthpow_residue(2, 3, 2) is True assert is_nthpow_residue(2, 3, 9) is False assert is_nthpow_residue(3, 5, 30) is True assert is_nthpow_residue(21, 11, 20) is True assert is_nthpow_residue(7, 10, 20) is False assert is_nthpow_residue(5, 10, 20) is True assert is_nthpow_residue(3, 10, 48) is False assert is_nthpow_residue(1, 10, 40) is True assert is_nthpow_residue(3, 10, 24) is False assert is_nthpow_residue(1, 10, 24) is True assert is_nthpow_residue(3, 10, 24) is False assert is_nthpow_residue(2, 10, 48) is False assert is_nthpow_residue(81, 3, 972) is False assert is_nthpow_residue(243, 5, 5103) is True assert is_nthpow_residue(243, 3, 1240029) is False assert is_nthpow_residue(36010, 8, 87382) is True assert is_nthpow_residue(28552, 6, 2218) is True assert is_nthpow_residue(92712, 9, 50026) is True x = {pow(i, 56, 1024) for i in range(1024)} assert {a for a in range(1024) if is_nthpow_residue(a, 56, 1024)} == x x = { pow(i, 256, 2048) for i in range(2048)} assert {a for a in range(2048) if is_nthpow_residue(a, 256, 2048)} == x x = { pow(i, 11, 324000) for i in range(1000)} assert [ is_nthpow_residue(a, 11, 324000) for a in x] x = { pow(i, 17, 22217575536) for i in range(1000)} assert [ is_nthpow_residue(a, 17, 22217575536) for a in x] assert is_nthpow_residue(676, 3, 5364) assert is_nthpow_residue(9, 12, 36) assert is_nthpow_residue(32, 10, 41) assert is_nthpow_residue(4, 2, 64) assert is_nthpow_residue(31, 4, 41) assert not is_nthpow_residue(2, 2, 5) assert is_nthpow_residue(8547, 12, 10007) assert is_nthpow_residue(Dummy(even=True) + 3, 3, 2) == True assert nthroot_mod(Dummy(odd=True), 3, 2) == 1 assert nthroot_mod(29, 31, 74) == [45] assert nthroot_mod(1801, 11, 2663) == 44 for a, q, p in [(51922, 2, 203017), (43, 3, 109), (1801, 11, 2663), (26118163, 1303, 33333347), (1499, 7, 2663), (595, 6, 2663), (1714, 12, 2663), (28477, 9, 33343)]: r = nthroot_mod(a, q, p) assert pow(r, q, p) == a assert nthroot_mod(11, 3, 109) is None assert nthroot_mod(16, 5, 36, True) == [4, 22] assert nthroot_mod(9, 16, 36, True) == [3, 9, 15, 21, 27, 33] assert nthroot_mod(4, 3, 3249000) == [] assert nthroot_mod(36010, 8, 87382, True) == [40208, 47174] assert nthroot_mod(0, 12, 37, True) == [0] assert nthroot_mod(0, 7, 100, True) == [0, 10, 20, 30, 40, 50, 60, 70, 80, 90] assert nthroot_mod(4, 4, 27, True) == [5, 22] assert nthroot_mod(4, 4, 121, True) == [19, 102] assert nthroot_mod(2, 3, 7, True) == [] for p in range(5, 100): qv = range(3, p, 4) for q in qv: d = defaultdict(list) for i in range(p): d[pow(i, q, p)].append(i) for a in range(1, p - 1): res = nthroot_mod(a, q, p, True) if d[a]: assert d[a] == res else: assert res == [] assert legendre_symbol(5, 11) == 1 assert legendre_symbol(25, 41) == 1 assert legendre_symbol(67, 101) == -1 assert legendre_symbol(0, 13) == 0 assert legendre_symbol(9, 3) == 0 raises(ValueError, lambda: legendre_symbol(2, 4)) assert jacobi_symbol(25, 41) == 1 assert jacobi_symbol(-23, 83) == -1 assert jacobi_symbol(3, 9) == 0 assert jacobi_symbol(42, 97) == -1 assert jacobi_symbol(3, 5) == -1 assert jacobi_symbol(7, 9) == 1 assert jacobi_symbol(0, 3) == 0 assert jacobi_symbol(0, 1) == 1 assert jacobi_symbol(2, 1) == 1 assert jacobi_symbol(1, 3) == 1 raises(ValueError, lambda: jacobi_symbol(3, 8)) assert mobius(13*7) == 1 assert mobius(1) == 1 assert mobius(13*7*5) == -1 assert mobius(13**2) == 0 raises(ValueError, lambda: mobius(-3)) p = Symbol('p', integer=True, positive=True, prime=True) x = Symbol('x', positive=True) i = Symbol('i', integer=True) assert mobius(p) == -1 raises(TypeError, lambda: mobius(x)) raises(ValueError, lambda: mobius(i)) assert _discrete_log_trial_mul(587, 2**7, 2) == 7 assert _discrete_log_trial_mul(941, 7**18, 7) == 18 assert _discrete_log_trial_mul(389, 3**81, 3) == 81 assert _discrete_log_trial_mul(191, 19**123, 19) == 123 assert _discrete_log_shanks_steps(442879, 7**2, 7) == 2 assert _discrete_log_shanks_steps(874323, 5**19, 5) == 19 assert _discrete_log_shanks_steps(6876342, 7**71, 7) == 71 assert _discrete_log_shanks_steps(2456747, 3**321, 3) == 321 assert _discrete_log_pollard_rho(6013199, 2**6, 2, rseed=0) == 6 assert _discrete_log_pollard_rho(6138719, 2**19, 2, rseed=0) == 19 assert _discrete_log_pollard_rho(36721943, 2**40, 2, rseed=0) == 40 assert _discrete_log_pollard_rho(24567899, 3**333, 3, rseed=0) == 333 raises(ValueError, lambda: _discrete_log_pollard_rho(11, 7, 31, rseed=0)) raises(ValueError, lambda: _discrete_log_pollard_rho(227, 3**7, 5, rseed=0)) assert _discrete_log_pohlig_hellman(98376431, 11**9, 11) == 9 assert _discrete_log_pohlig_hellman(78723213, 11**31, 11) == 31 assert _discrete_log_pohlig_hellman(32942478, 11**98, 11) == 98 assert _discrete_log_pohlig_hellman(14789363, 11**444, 11) == 444 assert discrete_log(587, 2**9, 2) == 9 assert discrete_log(2456747, 3**51, 3) == 51 assert discrete_log(32942478, 11**127, 11) == 127 assert discrete_log(432751500361, 7**324, 7) == 324 args = 5779, 3528, 6215 assert discrete_log(*args) == 687 assert discrete_log(*Tuple(*args)) == 687 assert quadratic_congruence(400, 85, 125, 1600) == [295, 615, 935, 1255, 1575] assert quadratic_congruence(3, 6, 5, 25) == [3, 20] assert quadratic_congruence(120, 80, 175, 500) == [] assert quadratic_congruence(15, 14, 7, 2) == [1] assert quadratic_congruence(8, 15, 7, 29) == [10, 28] assert quadratic_congruence(160, 200, 300, 461) == [144, 431] assert quadratic_congruence(100000, 123456, 7415263, 48112959837082048697) == [30417843635344493501, 36001135160550533083] assert quadratic_congruence(65, 121, 72, 277) == [249, 252] assert quadratic_congruence(5, 10, 14, 2) == [0] assert quadratic_congruence(10, 17, 19, 2) == [1] assert quadratic_congruence(10, 14, 20, 2) == [0, 1] assert polynomial_congruence(6*x**5 + 10*x**4 + 5*x**3 + x**2 + x + 1, 972000) == [220999, 242999, 463999, 485999, 706999, 728999, 949999, 971999] assert polynomial_congruence(x**3 - 10*x**2 + 12*x - 82, 33075) == [30287] assert polynomial_congruence(x**2 + x + 47, 2401) == [785, 1615] assert polynomial_congruence(10*x**2 + 14*x + 20, 2) == [0, 1] assert polynomial_congruence(x**3 + 3, 16) == [5] assert polynomial_congruence(65*x**2 + 121*x + 72, 277) == [249, 252] assert polynomial_congruence(x**4 - 4, 27) == [5, 22] assert polynomial_congruence(35*x**3 - 6*x**2 - 567*x + 2308, 148225) == [86957, 111157, 122531, 146731] assert polynomial_congruence(x**16 - 9, 36) == [3, 9, 15, 21, 27, 33] assert polynomial_congruence(x**6 - 2*x**5 - 35, 6125) == [3257] raises(ValueError, lambda: polynomial_congruence(x**x, 6125)) raises(ValueError, lambda: polynomial_congruence(x**i, 6125)) raises(ValueError, lambda: polynomial_congruence(0.1*x**2 + 6, 100))
def ap(self): """ Combined numerator parameters. """ return Tuple(*(self.args[0][0] + self.args[0][1]))
def disambiguate(*iter): """ Return a Tuple containing the passed expressions with symbols that appear the same when printed replaced with numerically subscripted symbols, and all Dummy symbols replaced with Symbols. Parameters ========== iter: list of symbols or expressions. Examples ======== >>> from sympy.core.symbol import disambiguate >>> from sympy import Dummy, Symbol, Tuple >>> from sympy.abc import y >>> tup = Symbol('_x'), Dummy('x'), Dummy('x') >>> disambiguate(*tup) (x_2, x, x_1) >>> eqs = Tuple(Symbol('x')/y, Dummy('x')/y) >>> disambiguate(*eqs) (x_1/y, x/y) >>> ix = Symbol('x', integer=True) >>> vx = Symbol('x') >>> disambiguate(vx + ix) (x + x_1,) To make your own mapping of symbols to use, pass only the free symbols of the expressions and create a dictionary: >>> free = eqs.free_symbols >>> mapping = dict(zip(free, disambiguate(*free))) >>> eqs.xreplace(mapping) (x_1/y, x/y) """ new_iter = Tuple(*iter) key = lambda x: tuple(sorted(x.assumptions0.items())) syms = ordered(new_iter.free_symbols, keys=key) mapping = {} for s in syms: mapping.setdefault(str(s).lstrip('_'), []).append(s) reps = {} for k in mapping: # the first or only symbol doesn't get subscripted but make # sure that it's a Symbol, not a Dummy mapk0 = Symbol("%s" % (k), **mapping[k][0].assumptions0) if mapping[k][0] != mapk0: reps[mapping[k][0]] = mapk0 # the others get subscripts (and are made into Symbols) skip = 0 for i in range(1, len(mapping[k])): while True: name = "%s_%i" % (k, i + skip) if name not in mapping: break skip += 1 ki = mapping[k][i] reps[ki] = Symbol(name, **ki.assumptions0) return new_iter.xreplace(reps)
def bm(self): """ First set of denominator parameters. """ return Tuple(*self.args[1][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("Y", (1, 2, 3))], Tuple(S(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, ImmutableMatrix) # 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, [S(0), '0', 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, [S(0), '0', 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() == ImmutableMatrix( [[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 #test issue 20078 assert (2 * Y[1] + 3 * Y[1]).simplify() == 5 * Y[1] assert (2 * Y[1] - 3 * Y[1]).simplify() == -Y[1] assert (2 * (0.25 * Y[1])).simplify() == 0.5 * Y[1] assert ((2 * Y[1]) * (0.25 * Y[1])).simplify() == 0.5 * Y[1]**2 assert (Y[1]**2 + Y[1]**3).simplify() == (Y[1] + 1) * Y[1]**2
def bother(self): """ Second set of denominator parameters. """ return Tuple(*self.args[1][1])
def _visit_Tuple(self, expr, **kwargs): args = [self._visit(i) for i in expr] return Tuple(*args)