Exemple #1
0
def test_Trace():
    assert isinstance(Trace(A), Trace)
    assert not isinstance(Trace(A), MatrixExpr)
    raises(ShapeError, lambda: Trace(C))
    assert trace(eye(3)) == 3
    assert trace(Matrix(3, 3, [1, 2, 3, 4, 5, 6, 7, 8, 9])) == 15

    assert adjoint(Trace(A)) == trace(Adjoint(A))
    assert conjugate(Trace(A)) == trace(Adjoint(A))
    assert transpose(Trace(A)) == Trace(A)

    A / Trace(A)  # Make sure this is possible

    # Some easy simplifications
    assert trace(Identity(5)) == 5
    assert trace(ZeroMatrix(5, 5)) == 0
    assert trace(2 * A * B) == 2 * Trace(A * B)
    assert trace(A.T) == trace(A)

    i, j = symbols('i j')
    F = FunctionMatrix(3, 3, Lambda((i, j), i + j))
    assert trace(F) == (0 + 0) + (1 + 1) + (2 + 2)

    raises(TypeError, lambda: Trace(S.One))

    assert Trace(A).arg is A

    assert str(trace(A)) == str(Trace(A).doit())
def test_Pow():
    assert rust_code(1 / x) == "x.recip()"
    assert rust_code(x**-1) == rust_code(x**-1.0) == "x.recip()"
    assert rust_code(sqrt(x)) == "x.sqrt()"
    assert rust_code(x**S.Half) == rust_code(x**0.5) == "x.sqrt()"

    assert rust_code(1 / sqrt(x)) == "x.sqrt().recip()"
    assert rust_code(x**-S.Half) == rust_code(x**-0.5) == "x.sqrt().recip()"

    assert rust_code(1 / pi) == "PI.recip()"
    assert rust_code(pi**-1) == rust_code(pi**-1.0) == "PI.recip()"
    assert rust_code(pi**-0.5) == "PI.sqrt().recip()"

    assert rust_code(x**Rational(1, 3)) == "x.cbrt()"
    assert rust_code(2**x) == "x.exp2()"
    assert rust_code(exp(x)) == "x.exp()"
    assert rust_code(x**3) == "x.powi(3)"
    assert rust_code(x**(y**3)) == "x.powf(y.powi(3))"
    assert rust_code(x**Rational(2, 3)) == "x.powf(2_f64/3.0)"

    g = implemented_function('g', Lambda(x, 2 * x))
    assert rust_code(1/(g(x)*3.5)**(x - y**x)/(x**2 + y)) == \
        "(3.5*2*x).powf(-x + y.powf(x))/(x.powi(2) + y)"
    _cond_cfunc = [(lambda base, exp: exp.is_integer, "dpowi", 1),
                   (lambda base, exp: not exp.is_integer, "pow", 1)]
    assert rust_code(x**3, user_functions={'Pow': _cond_cfunc}) == 'x.dpowi(3)'
    assert rust_code(x**3.2, user_functions={'Pow':
                                             _cond_cfunc}) == 'x.pow(3.2)'
Exemple #3
0
def test_glsl_code_Pow():
    g = implemented_function('g', Lambda(x, 2*x))
    assert glsl_code(x**3) == "pow(x, 3.0)"
    assert glsl_code(x**(y**3)) == "pow(x, pow(y, 3.0))"
    assert glsl_code(1/(g(x)*3.5)**(x - y**x)/(x**2 + y)) == \
        "pow(3.5*2*x, -x + pow(y, x))/(pow(x, 2.0) + y)"
    assert glsl_code(x**-1.0) == '1.0/x'
Exemple #4
0
def test_ccode_Pow():
    assert ccode(x**3) == "pow(x, 3)"
    assert ccode(x**(y**3)) == "pow(x, pow(y, 3))"
    g = implemented_function('g', Lambda(x, 2 * x))
    assert ccode(1/(g(x)*3.5)**(x - y**x)/(x**2 + y)) == \
        "pow(3.5*2*x, -x + pow(y, x))/(pow(x, 2) + y)"
    assert ccode(x**-1.0) == '1.0/x'
    assert ccode(x**Rational(2, 3)) == 'pow(x, 2.0/3.0)'
    assert ccode(x**Rational(2, 3),
                 type_aliases={real: float80}) == 'powl(x, 2.0L/3.0L)'
    _cond_cfunc = [(lambda base, exp: exp.is_integer, "dpowi"),
                   (lambda base, exp: not exp.is_integer, "pow")]
    assert ccode(x**3, user_functions={'Pow': _cond_cfunc}) == 'dpowi(x, 3)'
    assert ccode(x**0.5, user_functions={'Pow': _cond_cfunc}) == 'pow(x, 0.5)'
    assert ccode(x**Rational(16, 5),
                 user_functions={'Pow': _cond_cfunc}) == 'pow(x, 16.0/5.0)'
    _cond_cfunc2 = [(lambda base, exp: base == 2,
                     lambda base, exp: 'exp2(%s)' % exp),
                    (lambda base, exp: base != 2, 'pow')]
    # Related to gh-11353
    assert ccode(2**x, user_functions={'Pow': _cond_cfunc2}) == 'exp2(x)'
    assert ccode(x**2, user_functions={'Pow': _cond_cfunc2}) == 'pow(x, 2)'
    # For issue 14160
    assert ccode(
        Mul(-2,
            x,
            Pow(Mul(y, y, evaluate=False), -1, evaluate=False),
            evaluate=False)) == '-2*x/(y*y)'
def test_inline_function():
    x = symbols('x')
    g = implemented_function('g', Lambda(x, 2 * x))
    assert rust_code(g(x)) == "2*x"

    g = implemented_function('g', Lambda(x, 2 * x / Catalan))
    assert rust_code(g(x)) == ("const Catalan: f64 = %s;\n2*x/Catalan" %
                               Catalan.evalf(17))

    A = IndexedBase('A')
    i = Idx('i', symbols('n', integer=True))
    g = implemented_function('g', Lambda(x, x * (1 + x) * (2 + x)))
    assert rust_code(g(
        A[i]), assign_to=A[i]) == ("for i in 0..n {\n"
                                   "    A[i] = (A[i] + 1)*(A[i] + 2)*A[i];\n"
                                   "}")
Exemple #6
0
def test_Pow():
    assert mcode(x**3) == "x.^3"
    assert mcode(x**(y**3)) == "x.^(y.^3)"
    assert mcode(x**Rational(2, 3)) == 'x.^(2/3)'
    g = implemented_function('g', Lambda(x, 2 * x))
    assert mcode(1/(g(x)*3.5)**(x - y**x)/(x**2 + y)) == \
        "(3.5*2*x).^(-x + y.^x)./(x.^2 + y)"
def test_jscode_Pow():
    g = implemented_function('g', Lambda(x, 2 * x))
    assert jscode(x**3) == "Math.pow(x, 3)"
    assert jscode(x**(y**3)) == "Math.pow(x, Math.pow(y, 3))"
    assert jscode(1/(g(x)*3.5)**(x - y**x)/(x**2 + y)) == \
        "Math.pow(3.5*2*x, -x + Math.pow(y, x))/(Math.pow(x, 2) + y)"
    assert jscode(x**-1.0) == '1/x'
Exemple #8
0
def test_inline_function():
    from sympy.tensor import IndexedBase, Idx
    from sympy import symbols
    n, m = symbols('n m', integer=True)
    A, x, y = map(IndexedBase, 'Axy')
    i = Idx('i', m)
    p = FCodeGen()
    func = implemented_function('func', Lambda(n, n*(n + 1)))
    routine = make_routine('test_inline', Eq(y[i], func(x[i])))
    code = get_string(p.dump_f95, [routine])
    expected = (
        'subroutine test_inline(m, x, y)\n'
        'implicit none\n'
        'INTEGER*4, intent(in) :: m\n'
        'REAL*8, intent(in), dimension(1:m) :: x\n'
        'REAL*8, intent(out), dimension(1:m) :: y\n'
        'INTEGER*4 :: i\n'
        'do i = 1, m\n'
        '   y(i) = %s*%s\n'
        'end do\n'
        'end subroutine\n'
    )
    args = ('x(i)', '(x(i) + 1)')
    assert code == expected % args or\
        code == expected % args[::-1]
Exemple #9
0
    def cdf(self, x):
        """
        Return the cumulative density function as an expression in x

        Examples
        ========

            >>> from sympy.statistics.distributions import PDF
            >>> from sympy import exp, oo
            >>> from sympy.abc import x, y
            >>> PDF(exp(-x/y), (x,0,oo)).cdf(4)
            y - y*exp(-4/y)
            >>> PDF(2*x + y, (x, 10, oo)).cdf(0)
            -10*y - 100

        """
        x = sympify(x)
        if self._cdf is not None:
            return self._cdf(x)
        else:
            from sympy import integrate
            w = Dummy('w', real=True)
            self._cdf = integrate(self.pdf(w), w)
            self._cdf = Lambda(w, self._cdf - self._cdf.subs(w, self.domain[0]))
            return self._cdf(x)
Exemple #10
0
def test_rcode_inline_function():
    x = symbols('x')
    g = implemented_function('g', Lambda(x, 2*x))
    assert rcode(g(x)) == "2*x"
    g = implemented_function('g', Lambda(x, 2*x/Catalan))
    assert rcode(
        g(x)) == "Catalan = %s;\n2*x/Catalan" % Catalan.n()
    A = IndexedBase('A')
    i = Idx('i', symbols('n', integer=True))
    g = implemented_function('g', Lambda(x, x*(1 + x)*(2 + x)))
    res=rcode(g(A[i]), assign_to=A[i])
    ref=(
        "for (i in 1:n){\n"
        "   A[i] = (A[i] + 1)*(A[i] + 2)*A[i];\n"
        "}"
    )
    assert res == ref
Exemple #11
0
def test_funcmatrix():
    i, j = symbols('i,j')
    X = FunctionMatrix(3, 3, Lambda((i, j), i - j))
    assert X[1, 1] == 0
    assert X[1, 2] == -1
    assert X.shape == (3, 3)
    assert X.rows == X.cols == 3
    assert Matrix(X) == Matrix(3, 3, lambda i, j: i - j)
    assert isinstance(X*X + X, MatrixExpr)
Exemple #12
0
def test_Pow():
    assert mcode(x**3) == "x.^3"
    assert mcode(x**(y**3)) == "x.^(y.^3)"
    assert mcode(x**Rational(2, 3)) == 'x.^(2/3)'
    g = implemented_function('g', Lambda(x, 2*x))
    assert mcode(1/(g(x)*3.5)**(x - y**x)/(x**2 + y)) == \
        "(3.5*2*x).^(-x + y.^x)./(x.^2 + y)"
    # For issue 14160
    assert mcode(Mul(-2, x, Pow(Mul(y,y,evaluate=False), -1, evaluate=False),
                                                evaluate=False)) == '-2*x./(y.*y)'
Exemple #13
0
 def cdf(self, x):
     x = sympify(x)
     if self._cdf is not None:
         return self._cdf(x)
     else:
         from sympy import integrate
         w = Dummy('w', real=True)
         self._cdf = integrate(self.pdf(w), w)
         self._cdf = Lambda(w, self._cdf - self._cdf.subs(w, self.domain[0]))
         return self._cdf(x)
Exemple #14
0
def test_rcode_Pow():
    assert rcode(x**3) == "x^3"
    assert rcode(x**(y**3)) == "x^(y^3)"
    g = implemented_function('g', Lambda(x, 2*x))
    assert rcode(1/(g(x)*3.5)**(x - y**x)/(x**2 + y)) == \
        "(3.5*2*x)^(-x + y^x)/(x^2 + y)"
    assert rcode(x**-1.0) == '1.0/x'
    assert rcode(x**Rational(2, 3)) == 'x^(2.0/3.0)'
    _cond_cfunc = [(lambda base, exp: exp.is_integer, "dpowi"),
                   (lambda base, exp: not exp.is_integer, "pow")]
    assert rcode(x**3, user_functions={'Pow': _cond_cfunc}) == 'dpowi(x, 3)'
    assert rcode(x**3.2, user_functions={'Pow': _cond_cfunc}) == 'pow(x, 3.2)'
Exemple #15
0
def test_ccode_Pow():
    assert ccode(x**3) == "pow(x, 3)"
    assert ccode(x**(y**3)) == "pow(x, pow(y, 3))"
    g = implemented_function('g', Lambda(x, 2 * x))
    assert ccode(1/(g(x)*3.5)**(x - y**x)/(x**2 + y)) == \
        "pow(3.5*2*x, -x + pow(y, x))/(pow(x, 2) + y)"
    assert ccode(x**-1.0) == '1.0/x'
    assert ccode(x**Rational(2, 3)) == 'pow(x, 2.0L/3.0L)'
    _cond_cfunc = [(lambda base, exp: exp.is_integer, "dpowi"),
                   (lambda base, exp: not exp.is_integer, "pow")]
    assert ccode(x**3, user_functions={'Pow': _cond_cfunc}) == 'dpowi(x, 3)'
    assert ccode(x**3.2, user_functions={'Pow': _cond_cfunc}) == 'pow(x, 3.2)'
Exemple #16
0
def test_Pow():
    assert maple_code(x ** 3) == "x^3"
    assert maple_code(x ** (y ** 3)) == "x^(y^3)"

    assert maple_code((x ** 3) ** y) == "(x^3)^y"
    assert maple_code(x ** Rational(2, 3)) == 'x^(2/3)'

    g = implemented_function('g', Lambda(x, 2 * x))
    assert maple_code(1 / (g(x) * 3.5) ** (x - y ** x) / (x ** 2 + y)) == \
           "(3.5*2*x)^(-x + y^x)/(x^2 + y)"
    # For issue 14160
    assert maple_code(Mul(-2, x, Pow(Mul(y, y, evaluate=False), -1, evaluate=False),
                          evaluate=False)) == '-2*x/(y*y)'
Exemple #17
0
def test_rcode_Pow():
    assert rcode(x**3) == "x^3"
    assert rcode(x**(y**3)) == "x^(y^3)"
    g = implemented_function("g", Lambda(x, 2 * x))
    assert (rcode(1 / (g(x) * 3.5)**(x - y**x) /
                  (x**2 + y)) == "(3.5*2*x)^(-x + y^x)/(x^2 + y)")
    assert rcode(x**-1.0) == "1.0/x"
    assert rcode(x**Rational(2, 3)) == "x^(2.0/3.0)"
    _cond_cfunc = [
        (lambda base, exp: exp.is_integer, "dpowi"),
        (lambda base, exp: not exp.is_integer, "pow"),
    ]
    assert rcode(x**3, user_functions={"Pow": _cond_cfunc}) == "dpowi(x, 3)"
    assert rcode(x**3.2, user_functions={"Pow": _cond_cfunc}) == "pow(x, 3.2)"
Exemple #18
0
def assemble_partfrac_list(partial_list):
    r"""Reassemble a full partial fraction decomposition
    from a structured result obtained by the function ``apart_list``.

    Examples
    ========

    This example is taken from Bronstein's original paper:

    >>> from sympy.polys.partfrac import apart_list, assemble_partfrac_list
    >>> from sympy.abc import x

    >>> f = 36 / (x**5 - 2*x**4 - 2*x**3 + 4*x**2 + x - 2)
    >>> pfd = apart_list(f)
    >>> pfd
    (1,
    Poly(0, x, domain='ZZ'),
    [(Poly(_w - 2, _w, domain='ZZ'), Lambda(_a, 4), Lambda(_a, -_a + x), 1),
    (Poly(_w**2 - 1, _w, domain='ZZ'), Lambda(_a, -3*_a - 6), Lambda(_a, -_a + x), 2),
    (Poly(_w + 1, _w, domain='ZZ'), Lambda(_a, -4), Lambda(_a, -_a + x), 1)])

    >>> assemble_partfrac_list(pfd)
    -4/(x + 1) - 3/(x + 1)**2 - 9/(x - 1)**2 + 4/(x - 2)

    If we happen to know some roots we can provide them easily inside the structure:

    >>> pfd = apart_list(2/(x**2-2))
    >>> pfd
    (1,
    Poly(0, x, domain='ZZ'),
    [(Poly(_w**2 - 2, _w, domain='ZZ'),
    Lambda(_a, _a/2),
    Lambda(_a, -_a + x),
    1)])

    >>> pfda = assemble_partfrac_list(pfd)
    >>> pfda
    RootSum(_w**2 - 2, Lambda(_a, _a/(-_a + x)))/2

    >>> pfda.doit()
    -sqrt(2)/(2*(x + sqrt(2))) + sqrt(2)/(2*(x - sqrt(2)))

    >>> from sympy import Dummy, Poly, Lambda, sqrt
    >>> a = Dummy("a")
    >>> pfd = (1, Poly(0, x, domain='ZZ'), [([sqrt(2),-sqrt(2)], Lambda(a, a/2), Lambda(a, -a + x), 1)])

    >>> assemble_partfrac_list(pfd)
    -sqrt(2)/(2*(x + sqrt(2))) + sqrt(2)/(2*(x - sqrt(2)))

    See Also
    ========

    apart, apart_list
    """
    # Common factor
    common = partial_list[0]

    # Polynomial part
    polypart = partial_list[1]
    pfd = polypart.as_expr()

    # Rational parts
    for r, nf, df, ex in partial_list[2]:
        if isinstance(r, Poly):
            # Assemble in case the roots are given implicitly by a polynomials
            an, nu = nf.variables, nf.expr
            ad, de = df.variables, df.expr
            # Hack to make dummies equal because Lambda created new Dummies
            de = de.subs(ad[0], an[0])
            func = Lambda(tuple(an), nu/de**ex)
            pfd += RootSum(r, func, auto=False, quadratic=False)
        else:
            # Assemble in case the roots are given explicitly by a list of algebraic numbers
            for root in r:
                pfd += nf(root)/df(root)**ex

    return common*pfd
Exemple #19
0
def apart_list_full_decomposition(P, Q, dummygen):
    """
    Bronstein's full partial fraction decomposition algorithm.

    Given a univariate rational function ``f``, performing only GCD
    operations over the algebraic closure of the initial ground domain
    of definition, compute full partial fraction decomposition with
    fractions having linear denominators.

    Note that no factorization of the initial denominator of ``f`` is
    performed. The final decomposition is formed in terms of a sum of
    :class:`RootSum` instances.

    References
    ==========

    .. [1] [Bronstein93]_

    """
    f, x, U = P/Q, P.gen, []

    u = Function('u')(x)
    a = Dummy('a')

    partial = []

    for d, n in Q.sqf_list_include(all=True):
        b = d.as_expr()
        U += [ u.diff(x, n - 1) ]

        h = cancel(f*b**n) / u**n

        H, subs = [h], []

        for j in range(1, n):
            H += [ H[-1].diff(x) / j ]

        for j in range(1, n + 1):
            subs += [ (U[j - 1], b.diff(x, j) / j) ]

        for j in range(0, n):
            P, Q = cancel(H[j]).as_numer_denom()

            for i in range(0, j + 1):
                P = P.subs(*subs[j - i])

            Q = Q.subs(*subs[0])

            P = Poly(P, x)
            Q = Poly(Q, x)

            G = P.gcd(d)
            D = d.quo(G)

            B, g = Q.half_gcdex(D)
            b = (P * B.quo(g)).rem(D)

            Dw = D.subs(x, next(dummygen))
            numer = Lambda(a, b.as_expr().subs(x, a))
            denom = Lambda(a, (x - a))
            exponent = n-j

            partial.append((Dw, numer, denom, exponent))

    return partial
Exemple #20
0
def test_funcmatrix_creation():
    i, j, k = symbols('i j k')
    assert FunctionMatrix(2, 2, Lambda((i, j), 0))
    assert FunctionMatrix(0, 0, Lambda((i, j), 0))

    raises(ValueError, lambda: FunctionMatrix(-1, 0, Lambda((i, j), 0)))
    raises(ValueError, lambda: FunctionMatrix(2.0, 0, Lambda((i, j), 0)))
    raises(ValueError, lambda: FunctionMatrix(2j, 0, Lambda((i, j), 0)))
    raises(ValueError, lambda: FunctionMatrix(0, -1, Lambda((i, j), 0)))
    raises(ValueError, lambda: FunctionMatrix(0, 2.0, Lambda((i, j), 0)))
    raises(ValueError, lambda: FunctionMatrix(0, 2j, Lambda((i, j), 0)))

    raises(ValueError, lambda: FunctionMatrix(2, 2, Lambda(i, 0)))
    raises(ValueError, lambda: FunctionMatrix(2, 2, lambda i, j: 0))
    raises(ValueError, lambda: FunctionMatrix(2, 2, Lambda((i,), 0)))
    raises(ValueError, lambda: FunctionMatrix(2, 2, Lambda((i, j, k), 0)))
    raises(ValueError, lambda: FunctionMatrix(2, 2, i+j))
    assert FunctionMatrix(2, 2, "lambda i, j: 0") == \
        FunctionMatrix(2, 2, Lambda((i, j), 0))

    m = FunctionMatrix(2, 2, KroneckerDelta)
    assert m.as_explicit() == Identity(2).as_explicit()
    assert m.args[2] == Lambda((i, j), KroneckerDelta(i, j))

    n = symbols('n')
    assert FunctionMatrix(n, n, Lambda((i, j), 0))
    n = symbols('n', integer=False)
    raises(ValueError, lambda: FunctionMatrix(n, n, Lambda((i, j), 0)))
    n = symbols('n', negative=True)
    raises(ValueError, lambda: FunctionMatrix(n, n, Lambda((i, j), 0)))
Exemple #21
0
 def _eval_derivative(self, x):
     var, expr = self.fun.args
     func = Lambda(var, expr.diff(x))
     return self.new(self.poly, func, self.auto)
class PDF(ContinuousProbability):
    """
    PDF(func, (x, a, b)) represents continuous probability distribution
    with probability distribution function func(x) on interval (a, b)

    If func is not normalized so that integrate(func, (x, a, b)) == 1,
    it can be normalized using PDF.normalize() method

    Example usage:

        >>> from sympy import Symbol, exp, oo
        >>> from sympy.statistics.distributions import PDF
        >>> from sympy.abc import x
        >>> a = Symbol('a', positive=True)

        >>> exponential = PDF(exp(-x/a)/a, (x,0,oo))
        >>> exponential.pdf(x)
        exp(-x/a)/a
        >>> exponential.cdf(x)
        1 - exp(-x/a)
        >>> exponential.mean
        a
        >>> exponential.variance
        a**2

    """
    def __init__(self, pdf, var):
        #XXX maybe add some checking of parameters
        if isinstance(var, (tuple, list)):
            self.pdf = Lambda(var[0], pdf)
            self.domain = tuple(var[1:])
        else:
            self.pdf = Lambda(var, pdf)
            self.domain = (-oo, oo)
        self._cdf = None
        self._mean = None
        self._variance = None
        self._stddev = None

    def normalize(self):
        """
        Normalize the probability distribution function so that
        integrate(self.pdf(x), (x, a, b)) == 1

        Example usage:

            >>> from sympy import Symbol, exp, oo
            >>> from sympy.statistics.distributions import PDF
            >>> from sympy.abc import x
            >>> a = Symbol('a', positive=True)

            >>> exponential = PDF(exp(-x/a), (x,0,oo))
            >>> exponential.normalize().pdf(x)
            exp(-x/a)/a

        """

        norm = self.probability(*self.domain)
        if norm != 1:
            w = Dummy('w', real=True)
            return self.__class__(
                self.pdf(w) / norm, (w, self.domain[0], self.domain[1]))
            #self._cdf = Lambda(w, (self.cdf(w) - self.cdf(self.domain[0]))/norm)
            #if self._mean is not None:
            #    self._mean /= norm
            #if self._variance is not None:
            #    self._variance = (self._variance + (self._mean*norm)**2)/norm - self.mean**2
            #if self._stddev is not None:
            #    self._stddev = sqrt(self._variance)
        else:
            return self

    def cdf(self, x):
        x = sympify(x)
        if self._cdf is not None:
            return self._cdf(x)
        else:
            from sympy import integrate
            w = Dummy('w', real=True)
            self._cdf = integrate(self.pdf(w), w)
            self._cdf = Lambda(w,
                               self._cdf - self._cdf.subs(w, self.domain[0]))
            return self._cdf(x)

    def _get_mean(self):
        if self._mean is not None:
            return self._mean
        else:
            from sympy import integrate
            w = Dummy('w', real=True)
            self._mean = integrate(
                self.pdf(w) * w, (w, self.domain[0], self.domain[1]))
            return self._mean

    def _get_variance(self):
        if self._variance is not None:
            return self._variance
        else:
            from sympy import integrate, simplify
            w = Dummy('w', real=True)
            self._variance = integrate(
                self.pdf(w) * w**2,
                (w, self.domain[0], self.domain[1])) - self.mean**2
            self._variance = simplify(self._variance)
            return self._variance

    def _get_stddev(self):
        if self._stddev is not None:
            return self._stddev
        else:
            self._stddev = sqrt(self.variance)
            return self._stddev

    mean = property(_get_mean)
    variance = property(_get_variance)
    stddev = property(_get_stddev)

    def _random(s):
        raise NotImplementedError

    def transform(self, func, var):
        """Return a probability distribution of random variable func(x)
        currently only some simple injective functions are supported"""

        w = Dummy('w', real=True)

        from sympy import solve
        inverse = solve(func - w, var)
        newPdf = S.Zero
        funcdiff = func.diff(var)
        #TODO check if x is in domain
        for x in inverse:
            # this assignment holds only for x in domain
            # in general it would require implementing
            # piecewise defined functions in sympy
            newPdf += (self.pdf(var) / abs(funcdiff)).subs(var, x)

        return PDF(newPdf, (w, func.subs(
            var, self.domain[0]), func.subs(var, self.domain[1])))
Exemple #23
0
    def __new__(cls, expr, func=None, x=None, auto=True, quadratic=False):
        """Construct a new ``RootSum`` instance carrying all roots of a polynomial. """
        coeff, poly = cls._transform(expr, x)

        if not poly.is_univariate:
            raise MultivariatePolynomialError(
                "only univariate polynomials are allowed")

        if func is None:
            func = Lambda(poly.gen, poly.gen)
        else:
            try:
                is_func = func.is_Function
            except AttributeError:
                is_func = False

            if is_func and 1 in func.nargs:
                if not isinstance(func, Lambda):
                    func = Lambda(poly.gen, func(poly.gen))
            else:
                raise ValueError("expected a univariate function, got %s" %
                                 func)

        var, expr = func.variables[0], func.expr

        if coeff is not S.One:
            expr = expr.subs(var, coeff * var)

        deg = poly.degree()

        if not expr.has(var):
            return deg * expr

        if expr.is_Add:
            add_const, expr = expr.as_independent(var)
        else:
            add_const = S.Zero

        if expr.is_Mul:
            mul_const, expr = expr.as_independent(var)
        else:
            mul_const = S.One

        func = Lambda(var, expr)

        rational = cls._is_func_rational(poly, func)
        (_, factors), terms = poly.factor_list(), []

        for poly, k in factors:
            if poly.is_linear:
                term = func(roots_linear(poly)[0])
            elif quadratic and poly.is_quadratic:
                term = sum(map(func, roots_quadratic(poly)))
            else:
                if not rational or not auto:
                    term = cls._new(poly, func, auto)
                else:
                    term = cls._rational_case(poly, func)

            terms.append(k * term)

        return mul_const * Add(*terms) + deg * add_const
Exemple #24
0
def test_ccode_inline_function():
    g = implemented_function('g', Lambda(x, 2 * x))
    assert ccode(g(x)) == "2*x"
Exemple #25
0
def imageset(*args):
    r"""
    Image of set under transformation ``f``.

    If this function can't compute the image, it returns an
    unevaluated ImageSet object.

    .. math::
        { f(x) | x \in self }

    Examples
    ========

    >>> from sympy import Interval, Symbol, imageset, sin, Lambda
    >>> x = Symbol('x')

    >>> imageset(x, 2*x, Interval(0, 2))
    [0, 4]

    >>> imageset(lambda x: 2*x, Interval(0, 2))
    [0, 4]

    >>> imageset(Lambda(x, sin(x)), Interval(-2, 1))
    ImageSet(Lambda(x, sin(x)), [-2, 1])

    See Also
    ========

    sympy.sets.fancysets.ImageSet

    """
    from sympy.core import Dummy, Lambda
    from sympy.sets.fancysets import ImageSet
    if len(args) == 3:
        f = Lambda(*args[:2])
    else:
        # var and expr are being defined this way to
        # support Python lambda and not just sympy Lambda
        f = args[0]
        if not isinstance(f, Lambda):
            var = Dummy()
            expr = args[0](var)
            f = Lambda(var, expr)
    set = args[-1]

    r = set._eval_imageset(f)
    if isinstance(r, ImageSet):
        f, set = r.args

    if f.variables[0] == f.expr:
        return set

    if isinstance(set, ImageSet):
        if len(set.lamda.variables) == 1 and len(f.variables) == 1:
            return imageset(
                Lambda(set.lamda.variables[0],
                       f.expr.subs(f.variables[0], set.lamda.expr)),
                set.base_set)

    if r is not None:
        return r

    return ImageSet(f, set)
Exemple #26
0
def test_funcmatrix_creation():
    i, j, k = symbols('i j k')
    assert FunctionMatrix(2, 2, Lambda((i, j), 0))
    assert FunctionMatrix(0, 0, Lambda((i, j), 0))

    raises(ValueError, lambda: FunctionMatrix(-1, 0, Lambda((i, j), 0)))
    raises(ValueError, lambda: FunctionMatrix(2.0, 0, Lambda((i, j), 0)))
    raises(ValueError, lambda: FunctionMatrix(2j, 0, Lambda((i, j), 0)))
    raises(ValueError, lambda: FunctionMatrix(0, -1, Lambda((i, j), 0)))
    raises(ValueError, lambda: FunctionMatrix(0, 2.0, Lambda((i, j), 0)))
    raises(ValueError, lambda: FunctionMatrix(0, 2j, Lambda((i, j), 0)))

    raises(ValueError, lambda: FunctionMatrix(2, 2, Lambda(i, 0)))
    with warns(SymPyDeprecationWarning, test_stacklevel=False):
        # This raises a deprecation warning from sympify()
        raises(ValueError, lambda: FunctionMatrix(2, 2, lambda i, j: 0))
    raises(ValueError, lambda: FunctionMatrix(2, 2, Lambda((i,), 0)))
    raises(ValueError, lambda: FunctionMatrix(2, 2, Lambda((i, j, k), 0)))
    raises(ValueError, lambda: FunctionMatrix(2, 2, i+j))
    assert FunctionMatrix(2, 2, "lambda i, j: 0") == \
        FunctionMatrix(2, 2, Lambda((i, j), 0))

    m = FunctionMatrix(2, 2, KroneckerDelta)
    assert m.as_explicit() == Identity(2).as_explicit()
    assert m.args[2].dummy_eq(Lambda((i, j), KroneckerDelta(i, j)))

    n = symbols('n')
    assert FunctionMatrix(n, n, Lambda((i, j), 0))
    n = symbols('n', integer=False)
    raises(ValueError, lambda: FunctionMatrix(n, n, Lambda((i, j), 0)))
    n = symbols('n', negative=True)
    raises(ValueError, lambda: FunctionMatrix(n, n, Lambda((i, j), 0)))
Exemple #27
0
    def __new__(cls,
                name,
                transformation=None,
                parent=None,
                location=None,
                rotation_matrix=None,
                vector_names=None,
                variable_names=None):
        """
        The orientation/location parameters are necessary if this system
        is being defined at a certain orientation or location wrt another.

        Parameters
        ==========

        name : str
            The name of the new CoordSys3D instance.

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

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

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

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

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

        """

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

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

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

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

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

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

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

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

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

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

        obj._vector_names = vector_names

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

        obj._base_vectors = (v1, v2, v3)

        # Initialize the base scalars

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

        obj._variable_names = variable_names
        obj._vector_names = vector_names

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

        obj._base_scalars = (x1, x2, x3)

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

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

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

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

        obj._parent_rotation_matrix = rotation_matrix
        obj._origin = origin

        # Return the instance
        return obj
Exemple #28
0
def apart(f, z=None, **args):
    """Computes partial fraction decomposition of a rational function.

       Given a rational function 'f', performing only gcd operations
       over the algebraic closure of the initial field of definition,
       compute full partial fraction decomposition with fractions
       having linear denominators.

       For all other kinds of expressions the input is returned in an
       unchanged form. Note however, that `apart` function can thread
       over sums and relational operators.

       Note that no factorization of the initial denominator of `f` is
       needed.  The final decomposition is formed in terms of a sum of
       RootSum instances.  By default RootSum tries to compute all its
       roots to simplify itself. This behavior can be however avoided
       by setting the keyword flag evaluate=False, which will make this
       function return a formal decomposition.

           >>> from sympy import apart
           >>> from sympy.abc import x, y

           >>> apart(y/(x+2)/(x+1), x)
           y/(1 + x) - y/(2 + x)

           >>> apart(1/(1+x**5), x, evaluate=False)
           RootSum(Lambda(_a, -_a/(5*(x - _a))), x**5 + 1, x, domain='ZZ')

       References
       ==========

       .. [Bronstein93] M. Bronstein, B. Salvy, Full partial fraction
           decomposition of rational functions, Proceedings ISSAC '93,
           ACM Press, Kiev, Ukraine, 1993, pp. 157-160.

    """
    f = cancel(f)

    if z is None:
        symbols = f.atoms(Symbol)

        if not symbols:
            return f

        if len(symbols) == 1:
            z = list(symbols)[0]
        else:
            raise ValueError("multivariate partial fractions are not supported")

    P, Q = f.as_numer_denom()

    if not Q.has(z):
        return f

    partial, r = div(P, Q, z)
    f, q, U = r / Q, Q, []

    u = Function('u')(z)
    a = Dummy('a')

    q = Poly(q, z)

    for d, n in q.sqf_list(all=True, include=True):
        b = d.as_basic()
        U += [ u.diff(z, n-1) ]

        h = cancel(f*b**n) / u**n

        H, subs = [h], []

        for j in range(1, n):
            H += [ H[-1].diff(z) / j ]

        for j in range(1, n+1):
            subs += [ (U[j-1], b.diff(z, j) / j) ]

        for j in range(0, n):
            P, Q = cancel(H[j]).as_numer_denom()

            for i in range(0, j+1):
                P = P.subs(*subs[j-i])

            Q = Q.subs(*subs[0])

            P = Poly(P, z)
            Q = Poly(Q, z)

            G = P.gcd(d)
            D = d.exquo(G)

            B, g = Q.half_gcdex(D)
            b = (P * B.exquo(g)).rem(D)

            numer = b.as_basic()
            denom = (z-a)**(n-j)

            expr = numer.subs(z, a) / denom

            partial += RootSum(Lambda(a, expr), D, **args)

    return partial
Exemple #29
0
class PDF(ContinuousProbability):
    """
    PDF(func, (x, a, b)) represents continuous probability distribution
    with probability distribution function func(x) on interval (a, b)

    If func is not normalized so that integrate(func, (x, a, b)) == 1,
    it can be normalized using PDF.normalize() method

    Examples
    ========

        >>> from sympy import Symbol, exp, oo
        >>> from sympy.statistics.distributions import PDF
        >>> from sympy.abc import x
        >>> a = Symbol('a', positive=True)

        >>> exponential = PDF(exp(-x/a)/a, (x,0,oo))
        >>> exponential.pdf(x)
        exp(-x/a)/a
        >>> exponential.cdf(x)
        1 - exp(-x/a)
        >>> exponential.mean
        a
        >>> exponential.variance
        a**2

    """

    def __init__(self, pdf, var):
        #XXX maybe add some checking of parameters
        if isinstance(var, (tuple, list)):
            self.pdf = Lambda(var[0], pdf)
            self.domain = tuple(var[1:])
        else:
            self.pdf = Lambda(var, pdf)
            self.domain = (-oo, oo)
        self._cdf = None
        self._mean = None
        self._variance = None
        self._stddev = None


    def normalize(self):
        """
        Normalize the probability distribution function so that
        integrate(self.pdf(x), (x, a, b)) == 1

        Examples
        ========

            >>> from sympy import Symbol, exp, oo
            >>> from sympy.statistics.distributions import PDF
            >>> from sympy.abc import x
            >>> a = Symbol('a', positive=True)

            >>> exponential = PDF(exp(-x/a), (x,0,oo))
            >>> exponential.normalize().pdf(x)
            exp(-x/a)/a

        """

        norm = self.probability(*self.domain)
        if norm != 1:
            w = Dummy('w', real=True)
            return self.__class__(self.pdf(w)/norm, (w, self.domain[0], self.domain[1]))
            #self._cdf = Lambda(w, (self.cdf(w) - self.cdf(self.domain[0]))/norm)
            #if self._mean is not None:
            #    self._mean /= norm
            #if self._variance is not None:
            #    self._variance = (self._variance + (self._mean*norm)**2)/norm - self.mean**2
            #if self._stddev is not None:
            #    self._stddev = sqrt(self._variance)
        else:
            return self


    def cdf(self, x):
        """
        Return the cumulative density function as an expression in x

        Examples
        ========

            >>> from sympy.statistics.distributions import PDF
            >>> from sympy import exp, oo
            >>> from sympy.abc import x, y
            >>> PDF(exp(-x/y), (x,0,oo)).cdf(4)
            y - y*exp(-4/y)
            >>> PDF(2*x + y, (x, 10, oo)).cdf(0)
            -10*y - 100

        """
        x = sympify(x)
        if self._cdf is not None:
            return self._cdf(x)
        else:
            from sympy import integrate
            w = Dummy('w', real=True)
            self._cdf = integrate(self.pdf(w), w)
            self._cdf = Lambda(w, self._cdf - self._cdf.subs(w, self.domain[0]))
            return self._cdf(x)

    def _get_mean(self):
        if self._mean is not None:
            return self._mean
        else:
            from sympy import integrate
            w = Dummy('w', real=True)
            self._mean = integrate(self.pdf(w)*w,(w,self.domain[0],self.domain[1]))
            return self._mean

    def _get_variance(self):
        if self._variance is not None:
            return self._variance
        else:
            from sympy import integrate, simplify
            w = Dummy('w', real=True)
            self._variance = integrate(self.pdf(w)*w**2,(w,self.domain[0],self.domain[1])) - self.mean**2
            self._variance = simplify(self._variance)
            return self._variance

    def _get_stddev(self):
        if self._stddev is not None:
            return self._stddev
        else:
            self._stddev = sqrt(self.variance)
            return self._stddev

    mean = property(_get_mean)
    variance = property(_get_variance)
    stddev = property(_get_stddev)


    def _random(s):
        raise NotImplementedError

    def transform(self,func,var):
        """
        Return a probability distribution of random variable func(x)
        currently only some simple injective functions are supported

        Examples
        ========

            >>> from sympy.statistics.distributions import PDF
            >>> from sympy import oo
            >>> from sympy.abc import x, y
            >>> PDF(2*x + y, (x, 10, oo)).transform(x, y)
            PDF(0, ((_w,), x, x))

        """

        w = Dummy('w', real=True)

        from sympy import solve
        from sympy import S
        inverse = solve(func-w, var)
        newPdf = S.Zero
        funcdiff = func.diff(var)
        #TODO check if x is in domain
        for x in inverse:
            # this assignment holds only for x in domain
            # in general it would require implementing
            # piecewise defined functions in sympy
            newPdf += (self.pdf(var)/abs(funcdiff)).subs(var,x)

        return PDF(newPdf, (w, func.subs(var, self.domain[0]), func.subs(var, self.domain[1])))
Exemple #30
0
def test_coordsys_transform():
    # test inverse transforms
    p, q, r, s = symbols('p q r s')
    rel = {('first', 'second'): [(p, q), (q, -p)]}
    R2_pq = CoordSystem('first', R2_origin, [p, q], rel)
    R2_rs = CoordSystem('second', R2_origin, [r, s], rel)
    r, s = R2_rs.symbols
    assert R2_rs.transform(R2_pq) == Matrix([[-s], [r]])

    # inverse transform impossible case
    a, b = symbols('a b', positive=True)
    rel = {('first', 'second'): [(a,), (-a,)]}
    R2_a = CoordSystem('first', R2_origin, [a], rel)
    R2_b = CoordSystem('second', R2_origin, [b], rel)
    # This transformation is uninvertible because there is no positive a, b satisfying a = -b
    with raises(NotImplementedError):
        R2_b.transform(R2_a)

    # inverse transform ambiguous case
    c, d = symbols('c d')
    rel = {('first', 'second'): [(c,), (c**2,)]}
    R2_c = CoordSystem('first', R2_origin, [c], rel)
    R2_d = CoordSystem('second', R2_origin, [d], rel)
    # The transform method should throw if it finds multiple inverses for a coordinate transformation.
    with raises(ValueError):
        R2_d.transform(R2_c)

    # test indirect transformation
    a, b, c, d, e, f = symbols('a, b, c, d, e, f')
    rel = {('C1', 'C2'): [(a, b), (2*a, 3*b)],
        ('C2', 'C3'): [(c, d), (3*c, 2*d)]}
    C1 = CoordSystem('C1', R2_origin, (a, b), rel)
    C2 = CoordSystem('C2', R2_origin, (c, d), rel)
    C3 = CoordSystem('C3', R2_origin, (e, f), rel)
    a, b = C1.symbols
    c, d = C2.symbols
    e, f = C3.symbols
    assert C2.transform(C1) == Matrix([c/2, d/3])
    assert C1.transform(C3) == Matrix([6*a, 6*b])
    assert C3.transform(C1) == Matrix([e/6, f/6])
    assert C3.transform(C2) == Matrix([e/3, f/2])

    a, b, c, d, e, f = symbols('a, b, c, d, e, f')
    rel = {('C1', 'C2'): [(a, b), (2*a, 3*b + 1)],
        ('C3', 'C2'): [(e, f), (-e - 2, 2*f)]}
    C1 = CoordSystem('C1', R2_origin, (a, b), rel)
    C2 = CoordSystem('C2', R2_origin, (c, d), rel)
    C3 = CoordSystem('C3', R2_origin, (e, f), rel)
    a, b = C1.symbols
    c, d = C2.symbols
    e, f = C3.symbols
    assert C2.transform(C1) == Matrix([c/2, (d - 1)/3])
    assert C1.transform(C3) == Matrix([-2*a - 2, (3*b + 1)/2])
    assert C3.transform(C1) == Matrix([-e/2 - 1, (2*f - 1)/3])
    assert C3.transform(C2) == Matrix([-e - 2, 2*f])

    # old signature uses Lambda
    a, b, c, d, e, f = symbols('a, b, c, d, e, f')
    rel = {('C1', 'C2'): Lambda((a, b), (2*a, 3*b + 1)),
        ('C3', 'C2'): Lambda((e, f), (-e - 2, 2*f))}
    C1 = CoordSystem('C1', R2_origin, (a, b), rel)
    C2 = CoordSystem('C2', R2_origin, (c, d), rel)
    C3 = CoordSystem('C3', R2_origin, (e, f), rel)
    a, b = C1.symbols
    c, d = C2.symbols
    e, f = C3.symbols
    assert C2.transform(C1) == Matrix([c/2, (d - 1)/3])
    assert C1.transform(C3) == Matrix([-2*a - 2, (3*b + 1)/2])
    assert C3.transform(C1) == Matrix([-e/2 - 1, (2*f - 1)/3])
    assert C3.transform(C2) == Matrix([-e - 2, 2*f])