Ejemplo n.º 1
0
    def __eq__(self, other):
        if not isinstance(other, Subs):
            return False
        if (len(self.point) != len(other.point) or
            self.free_symbols != other.free_symbols or
            sorted(self.point) != sorted(other.point)):
            return False

        # non-repeated point args
        selfargs = [ v[0] for v in sorted(zip(self.variables, self.point),
            key = lambda v: v[1]) if list(self.point.args).count(v[1]) == 1 ]
        otherargs = [ v[0] for v in sorted(zip(other.variables, other.point),
            key = lambda v: v[1]) if list(other.point.args).count(v[1]) == 1 ]
        # find repeated point values and subs each associated variable
        # for a single symbol
        selfrepargs = []
        otherrepargs = []
        if uniq(self.point) != self.point:
            repeated = uniq([ v for v in self.point if
                                list(self.point.args).count(v) > 1 ])
            repswap = dict(zip(repeated, [ C.Dummy() for _ in
                                            xrange(len(repeated)) ]))
            selfrepargs = [ (self.variables[i], repswap[v]) for i, v in
                            enumerate(self.point) if v in repeated ]
            otherrepargs = [ (other.variables[i], repswap[v]) for i, v in
                            enumerate(other.point) if v in repeated ]

        return self.expr.subs(selfrepargs) == other.expr.subs(
                tuple(zip(otherargs, selfargs))).subs(otherrepargs)
Ejemplo n.º 2
0
    def _eval_extract(self, rowsList, colsList):
        urow = list(uniq(rowsList))
        ucol = list(uniq(colsList))
        smat = {}
        if len(urow)*len(ucol) < len(self._smat):
            # there are fewer elements requested than there are elements in the matrix
            for i, r in enumerate(urow):
                for j, c in enumerate(ucol):
                    smat[i, j] = self._smat.get((r, c), 0)
        else:
            # most of the request will be zeros so check all of self's entries,
            # keeping only the ones that are desired
            for rk, ck in self._smat:
                if rk in urow and ck in ucol:
                    smat[(urow.index(rk), ucol.index(ck))] = self._smat[(rk, ck)]

        rv = self._new(len(urow), len(ucol), smat)
        # rv is nominally correct but there might be rows/cols
        # which require duplication
        if len(rowsList) != len(urow):
            for i, r in enumerate(rowsList):
                i_previous = rowsList.index(r)
                if i_previous != i:
                    rv = rv.row_insert(i, rv.row(i_previous))
        if len(colsList) != len(ucol):
            for i, c in enumerate(colsList):
                i_previous = colsList.index(c)
                if i_previous != i:
                    rv = rv.col_insert(i, rv.col(i_previous))
        return rv
Ejemplo n.º 3
0
    def _eval_extract(self, rowsList, colsList):
        urow = list(uniq(rowsList))
        ucol = list(uniq(colsList))
        smat = {}
        if len(urow) * len(ucol) < len(self._smat):
            # there are fewer elements requested than there are elements in the matrix
            for i, r in enumerate(urow):
                for j, c in enumerate(ucol):
                    smat[i, j] = self._smat.get((r, c), 0)
        else:
            # most of the request will be zeros so check all of self's entries,
            # keeping only the ones that are desired
            for rk, ck in self._smat:
                if rk in urow and ck in ucol:
                    smat[urow.index(rk), ucol.index(ck)] = self._smat[rk, ck]

        rv = self._new(len(urow), len(ucol), smat)
        # rv is nominally correct but there might be rows/cols
        # which require duplication
        if len(rowsList) != len(urow):
            for i, r in enumerate(rowsList):
                i_previous = rowsList.index(r)
                if i_previous != i:
                    rv = rv.row_insert(i, rv.row(i_previous))
        if len(colsList) != len(ucol):
            for i, c in enumerate(colsList):
                i_previous = colsList.index(c)
                if i_previous != i:
                    rv = rv.col_insert(i, rv.col(i_previous))
        return rv
Ejemplo n.º 4
0
def bifid6_square(key):
    r"""
    6x6 Polybius square.

    Produces the Polybius square for the `6 \times 6` Bifid cipher.
    Assumes alphabet of symbols is "A", ..., "Z", "0", ..., "9".

    Examples
    ========

    >>> from sympy.crypto.crypto import bifid6_square
    >>> key = "encrypt"
    >>> bifid6_square(key)
    Matrix([
    [E, N, C, R, Y, P],
    [T, A, B, D, F, G],
    [H, I, J, K, L, M],
    [O, Q, S, U, V, W],
    [X, Z, 0, 1, 2, 3],
    [4, 5, 6, 7, 8, 9]])

    """
    A = alphabet_of_cipher() + [str(a) for a in range(10)]
    # first make sure the letters are capitalized
    # and text has no spaces
    key = uniq(key)
    key0 = [x.capitalize() for x in key if x.isalnum()]
    # create long key
    long_key = key0 + [x for x in A if not(x in key0)]
    f = lambda i, j: Symbol(long_key[6*i + j])
    M = Matrix(6, 6, f)
    return M
Ejemplo n.º 5
0
def decipher_vigenere(ct, key, symbols="ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
    """
    Decode using the Vigenère cipher.

    Examples
    ========

    >>> from sympy.crypto.crypto import decipher_vigenere
    >>> key = "encrypt"
    >>> ct = "QRGK kt HRZQE BPR"
    >>> decipher_vigenere(ct, key)
    'MEETMEONMONDAY'

    """
    symbols = "".join(symbols)
    A = alphabet_of_cipher(symbols)
    N = len(A)   # normally, 26
    key0 = uniq(key)
    key0 = [x.capitalize() for x in key0 if x.isalnum()]
    K = [A.index(x) for x in key0]
    k = len(K)
    ct0 = [x.capitalize() for x in ct if x.isalnum()]
    C = [A.index(x) for x in ct0]
    n = len(C)
    #m = n//k
    P = [(-K[i % k] + C[i]) % N for i in range(n)]
    return "".join([str(A[x]) for x in P])
Ejemplo n.º 6
0
def bifid7_square(key):
    r"""
    7x7 Polybius square.

    Produce the Polybius square for the `7 \times 7` Bifid cipher.
    Assumes alphabet of symbols is "A", ..., "Z", "0", ..., "22".
    (Also, assumes you have some way of distinguishing "22"
    from "2", "2" juxtaposed together for deciphering...)

    Examples
    ========

    >>> from sympy.crypto.crypto import bifid7_square
    >>> bifid7_square("gold bug")
    Matrix([
    [ G,  O,  L,  D,  B,  U,  A],
    [ C,  E,  F,  H,  I,  J,  K],
    [ M,  N,  P,  Q,  R,  S,  T],
    [ V,  W,  X,  Y,  Z,  0,  1],
    [ 2,  3,  4,  5,  6,  7,  8],
    [ 9, 10, 11, 12, 13, 14, 15],
    [16, 17, 18, 19, 20, 21, 22]])

    """
    A = alphabet_of_cipher() + [str(a) for a in range(23)]
    # first make sure the letters are capitalized
    # and text has no spaces
    key = uniq(key)
    key0 = [x.capitalize() for x in key if x.isalnum()]
    # create long key
    long_key = key0 + [x for x in A if (not(x in key0))]
    f = lambda i, j: Symbol(long_key[7*i + j])
    M = Matrix(7, 7, f)
    return M
Ejemplo n.º 7
0
 def _run(coeffs):
     # find runs in coeffs such that the difference in terms (mod 1)
     # of t1, t2, ..., tn is 1/n
     u = list(uniq(coeffs))
     for i in range(len(u)):
         dj = ([((u[j] - u[i]) % 1, j) for j in range(i + 1, len(u))])
         for one, j in dj:
             if one.p == 1 and one.q != 1:
                 n = one.q
                 got = [i]
                 get = list(range(1, n))
                 for d, j in dj:
                     m = n*d
                     if m.is_Integer and m in get:
                         get.remove(m)
                         got.append(j)
                         if not get:
                             break
                 else:
                     continue
                 for i, j in enumerate(got):
                     c = u[j]
                     coeffs.remove(c)
                     got[i] = c
                 return one.q, got[0], got[1:]
Ejemplo n.º 8
0
def decipher_vigenere(ct, key, symbols="ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
    """
    Decode using the Vigenere cipher.

    Examples
    ========

    >>> from sympy.crypto.crypto import decipher_vigenere
    >>> key = "encrypt"
    >>> ct = "QRGK kt HRZQE BPR"
    >>> decipher_vigenere(ct, key)
    'MEETMEONMONDAY'

    """
    symbols = "".join(symbols)
    A = alphabet_of_cipher(symbols)
    N = len(A)  # normally, 26
    key0 = uniq(key)
    key0 = [x.capitalize() for x in key0 if x.isalnum()]
    K = [A.index(x) for x in key0]
    k = len(K)
    ct0 = [x.capitalize() for x in ct if x.isalnum()]
    C = [A.index(x) for x in ct0]
    n = len(C)
    #m = n//k
    P = [(-K[i % k] + C[i]) % N for i in range(n)]
    return "".join([str(A[x]) for x in P])
Ejemplo n.º 9
0
def bifid6_square(key):
    r"""
    6x6 Polybius square.

    Produces the Polybius square for the `6 \times 6` Bifid cipher.
    Assumes alphabet of symbols is "A", ..., "Z", "0", ..., "9".

    Examples
    ========

    >>> from sympy.crypto.crypto import bifid6_square
    >>> key = "encrypt"
    >>> bifid6_square(key)
    Matrix([
    [E, N, C, R, Y, P],
    [T, A, B, D, F, G],
    [H, I, J, K, L, M],
    [O, Q, S, U, V, W],
    [X, Z, 0, 1, 2, 3],
    [4, 5, 6, 7, 8, 9]])

    """
    A = alphabet_of_cipher() + [str(a) for a in range(10)]
    # first make sure the letters are capitalized
    # and text has no spaces
    key = uniq(key)
    key0 = [x.capitalize() for x in key if x.isalnum()]
    # create long key
    long_key = key0 + [x for x in A if not (x in key0)]
    f = lambda i, j: Symbol(long_key[6 * i + j])
    M = Matrix(6, 6, f)
    return M
Ejemplo n.º 10
0
    def __new__(cls, expr, variables, point, **assumptions):
        if not ordered_iter(variables, Tuple):
            variables = [variables]
        variables = Tuple(*sympify(variables))

        if uniq(variables) != variables:
            repeated = repeated = [
                v for v in set(variables) if list(variables).count(v) > 1
            ]
            raise ValueError('cannot substitute expressions %s more than '
                             'once.' % repeated)

        if not ordered_iter(point, Tuple):
            point = [point]
        point = Tuple(*sympify(point))

        if len(point) != len(variables):
            raise ValueError('Number of point values must be the same as '
                             'the number of variables.')

        # it's necessary to use dummy variables internally
        new_variables = Tuple(*[
            arg.as_dummy() if arg.is_Symbol else C.Dummy(str(arg))
            for arg in variables
        ])
        expr = sympify(expr).subs(tuple(zip(variables, new_variables)))

        if expr.is_commutative:
            assumptions['commutative'] = True

        obj = Expr.__new__(cls, expr, new_variables, point, **assumptions)
        return obj
Ejemplo n.º 11
0
def bifid7_square(key):
    r"""
    7x7 Polybius square.

    Produce the Polybius square for the `7 \times 7` Bifid cipher.
    Assumes alphabet of symbols is "A", ..., "Z", "0", ..., "22".
    (Also, assumes you have some way of distinguishing "22"
    from "2", "2" juxtaposed together for deciphering...)

    Examples
    ========

    >>> from sympy.crypto.crypto import bifid7_square
    >>> bifid7_square("gold bug")
    Matrix([
    [ G,  O,  L,  D,  B,  U,  A],
    [ C,  E,  F,  H,  I,  J,  K],
    [ M,  N,  P,  Q,  R,  S,  T],
    [ V,  W,  X,  Y,  Z,  0,  1],
    [ 2,  3,  4,  5,  6,  7,  8],
    [ 9, 10, 11, 12, 13, 14, 15],
    [16, 17, 18, 19, 20, 21, 22]])

    """
    A = alphabet_of_cipher() + [str(a) for a in range(23)]
    # first make sure the letters are capitalized
    # and text has no spaces
    key = uniq(key)
    key0 = [x.capitalize() for x in key if x.isalnum()]
    # create long key
    long_key = key0 + [x for x in A if (not (x in key0))]
    f = lambda i, j: Symbol(long_key[7 * i + j])
    M = Matrix(7, 7, f)
    return M
Ejemplo n.º 12
0
 def _run(coeffs):
     # find runs in coeffs such that the difference in terms (mod 1)
     # of t1, t2, ..., tn is 1/n
     u = list(uniq(coeffs))
     for i in range(len(u)):
         dj = ([((u[j] - u[i]) % 1, j)
                for j in range(i + 1, len(u))])
         for one, j in dj:
             if one.p == 1 and one.q != 1:
                 n = one.q
                 got = [i]
                 get = list(range(1, n))
                 for d, j in dj:
                     m = n * d
                     if m.is_Integer and m in get:
                         get.remove(m)
                         got.append(j)
                         if not get:
                             break
                 else:
                     continue
                 for i, j in enumerate(got):
                     c = u[j]
                     coeffs.remove(c)
                     got[i] = c
                 return one.q, got[0], got[1:]
Ejemplo n.º 13
0
    def __new__(cls, expr, variables, point, **assumptions):
        if not ordered_iter(variables, Tuple):
            variables = [variables]
        variables = Tuple(*sympify(variables))

        if uniq(variables) != variables:
            repeated = repeated = [ v for v in set(variables)
                                    if list(variables).count(v) > 1 ]
            raise ValueError('cannot substitute expressions %s more than '
                             'once.' % repeated)

        if not ordered_iter(point, Tuple):
            point = [point]
        point = Tuple(*sympify(point))

        if len(point) != len(variables):
            raise ValueError('Number of point values must be the same as '
                             'the number of variables.')

        # it's necessary to use dummy variables internally
        new_variables = Tuple(*[ arg.as_dummy() if arg.is_Symbol else
            C.Dummy(str(arg)) for arg in variables ])
        expr = sympify(expr).subs(tuple(zip(variables, new_variables)))

        if expr.is_commutative:
            assumptions['commutative'] = True

        obj = Expr.__new__(cls, expr, new_variables, point, **assumptions)
        return obj
Ejemplo n.º 14
0
def bifid5_square(key):
    r"""
    5x5 Polybius square.

    Produce the Polybius square for the `5 \times 5` Bifid cipher.

    Examples
    ========

    >>> from sympy.crypto.crypto import bifid5_square
    >>> bifid5_square("gold bug")
    Matrix([
    [G, O, L, D, B],
    [U, A, C, E, F],
    [H, I, K, M, N],
    [P, Q, R, S, T],
    [V, W, X, Y, Z]])

    """
    A = alphabet_of_cipher()
    # first make sure the letters are capitalized
    # and key has no spaces or duplicates
    key = uniq(key)
    key0 = [x.capitalize() for x in key if x.isalnum()]
    # create long key
    long_key = key0 + [x for x in A if (not(x in key0) and x != "J")]
    f = lambda i, j: Symbol(long_key[5*i + j])
    M = Matrix(5, 5, f)
    return M
Ejemplo n.º 15
0
def bifid5_square(key):
    r"""
    5x5 Polybius square.

    Produce the Polybius square for the `5 \times 5` Bifid cipher.

    Examples
    ========

    >>> from sympy.crypto.crypto import bifid5_square
    >>> bifid5_square("gold bug")
    Matrix([
    [G, O, L, D, B],
    [U, A, C, E, F],
    [H, I, K, M, N],
    [P, Q, R, S, T],
    [V, W, X, Y, Z]])

    """
    A = alphabet_of_cipher()
    # first make sure the letters are capitalized
    # and key has no spaces or duplicates
    key = uniq(key)
    key0 = [x.capitalize() for x in key if x.isalnum()]
    # create long key
    long_key = key0 + [x for x in A if (not (x in key0) and x != "J")]
    f = lambda i, j: Symbol(long_key[5 * i + j])
    M = Matrix(5, 5, f)
    return M
Ejemplo n.º 16
0
def test_uniq():
    assert list(uniq(p.copy() for p in partitions(4))) == [{4: 1}, {1: 1, 3: 1}, {2: 2}, {1: 2, 2: 1}, {1: 4}]
    assert list(uniq(x % 2 for x in range(5))) == [0, 1]
    assert list(uniq("a")) == ["a"]
    assert list(uniq("ababc")) == list("abc")
    assert list(uniq([[1], [2, 1], [1]])) == [[1], [2, 1]]
    assert list(uniq(permutations(i for i in [[1], 2, 2]))) == [([1], 2, 2), (2, [1], 2), (2, 2, [1])]
    assert list(uniq([2, 3, 2, 4, [2], [1], [2], [3], [1]])) == [2, 3, 4, [2], [1], [3]]
Ejemplo n.º 17
0
def test_uniq():
    assert list(uniq(p for p in partitions(4))) == \
        [{4: 1}, {1: 1, 3: 1}, {2: 2}, {1: 2, 2: 1}, {1: 4}]
    assert list(uniq(x % 2 for x in range(5))) == [0, 1]
    assert list(uniq('a')) == ['a']
    assert list(uniq('ababc')) == list('abc')
    assert list(uniq([[1], [2, 1], [1]])) == [[1], [2, 1]]
    assert list(uniq(permutations(i for i in [[1], 2, 2]))) == \
        [([1], 2, 2), (2, [1], 2), (2, 2, [1])]
    assert list(uniq([2, 3, 2, 4, [2], [1], [2], [3], [1]])) == \
        [2, 3, 4, [2], [1], [3]]
    f = [1]
    raises(RuntimeError, lambda: [f.remove(i) for i in uniq(f)])
    f = [[1]]
    raises(RuntimeError, lambda: [f.remove(i) for i in uniq(f)])
Ejemplo n.º 18
0
    def _solve_even_degree_expr(expr, t, symbol, domain=S.Complexes):
        """Return the unique solutions of equations derived from
        ``expr`` by replacing ``t`` with ``+/- symbol``.

        Parameters
        ==========

        expr : Expr
            The expression which includes a dummy variable t to be
            replaced with +symbol and -symbol.

        symbol : Symbol
            The symbol for which a solution is being sought.

        Returns
        =======

        List of unique solution of the two equations generated by
        replacing ``t`` with positive and negative ``symbol``.

        Notes
        =====

        If ``expr = 2*log(t) + x/2` then solutions for
        ``2*log(x) + x/2 = 0`` and ``2*log(-x) + x/2 = 0`` are
        returned by this function. Though this may seem
        counter-intuitive, one must note that the ``expr`` being
        solved here has been derived from a different expression. For
        an expression like ``eq = x**2*g(x) = 1``, if we take the
        log of both sides we obtain ``log(x**2) + log(g(x)) = 0``. If
        x is positive then this simplifies to
        ``2*log(x) + log(g(x)) = 0``; the Lambert-solving routines will
        return solutions for this, but we must also consider the
        solutions for  ``2*log(-x) + log(g(x))`` since those must also
        be a solution of ``eq`` which has the same value when the ``x``
        in ``x**2`` is negated. If `g(x)` does not have even powers of
        symbol then we don't want to replace the ``x`` there with
        ``-x``. So the role of the ``t`` in the expression received by
        this function is to mark where ``+/-x`` should be inserted
        before obtaining the Lambert solutions.

        """
        nlhs, plhs = [
            expr.xreplace({t: sgn*symbol}) for sgn in (-1, 1)]
        sols = _solve_lambert(nlhs, symbol, gens, domain)
        if sols == S.EmptySet:
            return S.EmptySet
        if plhs != nlhs:
            sols.extend(_solve_lambert(plhs, symbol, gens, domain))
        # uniq is needed for a case like
        # 2*log(t) - log(-z**2) + log(z + log(x) + log(z))
        # where subtituting t with +/-x gives all the same solution;
        # uniq, rather than list(set()), is used to maintain canonical
        # order
        return list(uniq(sols))
Ejemplo n.º 19
0
    def is_concyclic(self, *args):
        """Do `self` and the given sequence of points lie in a circle?

        Returns True if the set of points are concyclic and
        False otherwise. A trivial value of True is returned
        if there are fewer than 2 other points.

        Parameters
        ==========

        args : sequence of Points

        Returns
        =======

        is_concyclic : boolean


        Examples
        ========

        >>> from sympy import Point

        Define 4 points that are on the unit circle:

        >>> p1, p2, p3, p4 = Point(1, 0), (0, 1), (-1, 0), (0, -1)

        >>> p1.is_concyclic() == p1.is_concyclic(p2, p3, p4) == True
        True

        Define a point not on that circle:

        >>> p = Point(1, 1)

        >>> p.is_concyclic(p1, p2, p3)
        False

        """
        points = (self,) + args
        points = Point._normalize_dimension(*[Point(i) for i in points])
        points = list(uniq(points))
        if not Point.affine_rank(*points) <= 2:
            return False
        origin = points[0]
        points = [p - origin for p in points]
        # points are concyclic if they are coplanar and
        # there is a point c so that ||p_i-c|| == ||p_j-c|| for all
        # i and j.  Rearranging this equation gives us the following
        # condition: the matrix `mat` must not a pivot in the last
        # column.
        mat = Matrix([list(i) + [i.dot(i)] for i in points])
        rref, pivots = mat.rref()
        if len(origin) not in pivots:
            return True
        return False
Ejemplo n.º 20
0
    def is_concyclic(self, *args):
        """Do `self` and the given sequence of points lie in a circle?

        Returns True if the set of points are concyclic and
        False otherwise. A trivial value of True is returned
        if there are fewer than 2 other points.

        Parameters
        ==========

        args : sequence of Points

        Returns
        =======

        is_concyclic : boolean


        Examples
        ========

        >>> from sympy import Point

        Define 4 points that are on the unit circle:

        >>> p1, p2, p3, p4 = Point(1, 0), (0, 1), (-1, 0), (0, -1)

        >>> p1.is_concyclic() == p1.is_concyclic(p2, p3, p4) == True
        True

        Define a point not on that circle:

        >>> p = Point(1, 1)

        >>> p.is_concyclic(p1, p2, p3)
        False

        """
        points = (self,) + args
        points = Point._normalize_dimension(*[Point(i) for i in points])
        points = list(uniq(points))
        if not Point.affine_rank(*points) <= 2:
            return False
        origin = points[0]
        points = [p - origin for p in points]
        # points are concyclic if they are coplanar and
        # there is a point c so that ||p_i-c|| == ||p_j-c|| for all
        # i and j.  Rearranging this equation gives us the following
        # condition: the matrix `mat` must not a pivot in the last
        # column.
        mat = Matrix([list(i) + [i.dot(i)] for i in points])
        rref, pivots = mat.rref()
        if len(origin) not in pivots:
            return True
        return False
Ejemplo n.º 21
0
def DirectProduct(*groups):
    """
    Returns the direct product of several groups as a permutation group.

    Explanation
    ===========

    This is implemented much like the __mul__ procedure for taking the direct
    product of two permutation groups, but the idea of shifting the
    generators is realized in the case of an arbitrary number of groups.
    A call to DirectProduct(G1, G2, ..., Gn) is generally expected to be faster
    than a call to G1*G2*...*Gn (and thus the need for this algorithm).

    Examples
    ========

    >>> from sympy.combinatorics.group_constructs import DirectProduct
    >>> from sympy.combinatorics.named_groups import CyclicGroup
    >>> C = CyclicGroup(4)
    >>> G = DirectProduct(C, C, C)
    >>> G.order()
    64

    See Also
    ========

    sympy.combinatorics.perm_groups.PermutationGroup.__mul__

    """
    degrees = []
    gens_count = []
    total_degree = 0
    total_gens = 0
    for group in groups:
        current_deg = group.degree
        current_num_gens = len(group.generators)
        degrees.append(current_deg)
        total_degree += current_deg
        gens_count.append(current_num_gens)
        total_gens += current_num_gens
    array_gens = []
    for i in range(total_gens):
        array_gens.append(list(range(total_degree)))
    current_gen = 0
    current_deg = 0
    for i in range(len(gens_count)):
        for j in range(current_gen, current_gen + gens_count[i]):
            gen = ((groups[i].generators)[j - current_gen]).array_form
            array_gens[j][current_deg:current_deg + degrees[i]] = \
                [x + current_deg for x in gen]
        current_gen += gens_count[i]
        current_deg += degrees[i]
    perm_gens = list(uniq([_af_new(list(a)) for a in array_gens]))
    return PermutationGroup(perm_gens, dups=False)
Ejemplo n.º 22
0
    def _do_ellipse_intersection(self, o):
        """The intersection of an ellipse with another ellipse or a circle.

        Private helper method for `intersection`.

        """

        x = Dummy('x', real=True)
        y = Dummy('y', real=True)
        seq = self.equation(x, y)
        oeq = o.equation(x, y)
        result = solve([seq, oeq], [x, y])
        return [Point(*r) for r in list(uniq(result))]
Ejemplo n.º 23
0
    def _do_ellipse_intersection(self, o):
        """The intersection of an ellipse with another ellipse or a circle.

        Private helper method for `intersection`.

        """

        x = Dummy('x', real=True)
        y = Dummy('y', real=True)
        seq = self.equation(x, y)
        oeq = o.equation(x, y)
        result = solve([seq, oeq], [x, y])
        return [Point(*r) for r in list(uniq(result))]
Ejemplo n.º 24
0
def test_uniq():
    assert list(uniq(p.copy() for p in partitions(4))) == \
        [{4: 1}, {1: 1, 3: 1}, {2: 2}, {1: 2, 2: 1}, {1: 4}]
    assert list(uniq(x % 2 for x in range(5))) == [0, 1]
    assert list(uniq('a')) == ['a']
    assert list(uniq('ababc')) == list('abc')
    assert list(uniq([[1], [2, 1], [1]])) == [[1], [2, 1]]
    assert list(uniq(permutations(i for i in [[1], 2, 2]))) == \
        [([1], 2, 2), (2, [1], 2), (2, 2, [1])]
    assert list(uniq([2, 3, 2, 4, [2], [1], [2], [3], [1]])) == \
        [2, 3, 4, [2], [1], [3]]
Ejemplo n.º 25
0
    def _do_ellipse_intersection(self, o):
        """The intersection of an ellipse with another ellipse or a circle.

        Private helper method for `intersection`.

        """
        x = Dummy('x', real=True)
        y = Dummy('y', real=True)
        seq = self.equation(x, y)
        oeq = o.equation(x, y)
        # TODO: Replace solve with nonlinsolve, when nonlinsolve will be able to solve in real domain
        result = solve([seq, oeq], x, y)
        return [Point(*r) for r in list(uniq(result))]
Ejemplo n.º 26
0
def DirectProduct(*groups):
    """
    Returns the direct product of several groups as a permutation group.

    This is implemented much like the __mul__ procedure for taking the direct
    product of two permutation groups, but the idea of shifting the
    generators is realized in the case of an arbitrary number of groups.
    A call to DirectProduct(G1, G2, ..., Gn) is generally expected to be faster
    than a call to G1*G2*...*Gn (and thus the need for this algorithm).

    Examples
    ========

    >>> from sympy.combinatorics.group_constructs import DirectProduct
    >>> from sympy.combinatorics.named_groups import CyclicGroup
    >>> C = CyclicGroup(4)
    >>> G = DirectProduct(C, C, C)
    >>> G.order()
    64

    See Also
    ========

    __mul__

    """
    degrees = []
    gens_count = []
    total_degree = 0
    total_gens = 0
    for group in groups:
        current_deg = group.degree
        current_num_gens = len(group.generators)
        degrees.append(current_deg)
        total_degree += current_deg
        gens_count.append(current_num_gens)
        total_gens += current_num_gens
    array_gens = []
    for i in range(total_gens):
        array_gens.append(list(range(total_degree)))
    current_gen = 0
    current_deg = 0
    for i in range(len(gens_count)):
        for j in range(current_gen, current_gen + gens_count[i]):
            gen = ((groups[i].generators)[j - current_gen]).array_form
            array_gens[j][current_deg:current_deg + degrees[i]] = \
                [x + current_deg for x in gen]
        current_gen += gens_count[i]
        current_deg += degrees[i]
    perm_gens = list(uniq([_af_new(list(a)) for a in array_gens]))
    return PermutationGroup(perm_gens, dups=False)
Ejemplo n.º 27
0
def test_uniq():
    assert list(uniq(p.copy() for p in partitions(4))) == \
        [{4: 1}, {1: 1, 3: 1}, {2: 2}, {1: 2, 2: 1}, {1: 4}]
    assert list(uniq(x % 2 for x in range(5))) == [0, 1]
    assert list(uniq('a')) == ['a']
    assert list(uniq('ababc')) == list('abc')
    assert list(uniq([[1], [2, 1], [1]])) == [[1], [2, 1], [1]]
    assert list(uniq(permutations(i for i in [[1], 2, 2]))) == \
        [([1], 2, 2), (2, [1], 2), (2, 2, [1]), (2, [1], 2), (2, 2, [1])]
Ejemplo n.º 28
0
    def __eq__(self, other):
        if not isinstance(other, Subs):
            return False
        if (len(self.point) != len(other.point)
                or self.free_symbols != other.free_symbols
                or sorted(self.point) != sorted(other.point)):
            return False

        # non-repeated point args
        selfargs = [
            v[0] for v in sorted(zip(self.variables, self.point),
                                 key=lambda v: v[1])
            if list(self.point.args).count(v[1]) == 1
        ]
        otherargs = [
            v[0] for v in sorted(zip(other.variables, other.point),
                                 key=lambda v: v[1])
            if list(other.point.args).count(v[1]) == 1
        ]
        # find repeated point values and subs each associated variable
        # for a single symbol
        selfrepargs = []
        otherrepargs = []
        if uniq(self.point) != self.point:
            repeated = uniq(
                [v for v in self.point if list(self.point.args).count(v) > 1])
            repswap = dict(
                zip(repeated, [C.Dummy() for _ in xrange(len(repeated))]))
            selfrepargs = [(self.variables[i], repswap[v])
                           for i, v in enumerate(self.point) if v in repeated]
            otherrepargs = [(other.variables[i], repswap[v])
                            for i, v in enumerate(other.point)
                            if v in repeated]

        return self.expr.subs(selfrepargs) == other.expr.subs(
            tuple(zip(otherargs, selfargs))).subs(otherrepargs)
Ejemplo n.º 29
0
    def are_concurrent(*planes):
        """Is a sequence of Planes concurrent?

        Two or more Planes are concurrent if their intersections
        are a common line.

        Parameters
        ==========

        planes: list

        Returns
        =======

        Boolean

        Examples
        ========

        >>> from sympy import Plane, Point3D
        >>> a = Plane(Point3D(5, 0, 0), normal_vector=(1, -1, 1))
        >>> b = Plane(Point3D(0, -2, 0), normal_vector=(3, 1, 1))
        >>> c = Plane(Point3D(0, -1, 0), normal_vector=(5, -1, 9))
        >>> Plane.are_concurrent(a, b)
        True
        >>> Plane.are_concurrent(a, b, c)
        False

        """
        planes = list(uniq(planes))
        for i in planes:
            if not isinstance(i, Plane):
                raise ValueError("All objects should be Planes but got %s" %
                                 i.func)
        if len(planes) < 2:
            return False
        planes = list(planes)
        first = planes.pop(0)
        sol = first.intersection(planes[0])
        if sol == []:
            return False
        else:
            line = sol[0]
            for i in planes[1:]:
                l = first.intersection(i)
                if not l or not l[0] in line:
                    return False
            return True
Ejemplo n.º 30
0
def decipher_bifid6(ct, key):
    r"""
    Performs the Bifid cipher decryption on ciphertext ``ct``, and returns the plaintext.

    This is the version of the Bifid cipher that uses the `6 \times 6` Polybius square.
    Assumes alphabet of symbols is "A", ..., "Z", "0", ..., "9".

    INPUT:

        ``ct``: ciphertext string (digits okay)

        ``key``: short string for key (no repetitions, digits okay)

    OUTPUT:

        plaintext from Bifid cipher (all caps, no spaces)

    Examples
    ========

    >>> from sympy.crypto.crypto import encipher_bifid6, decipher_bifid6
    >>> key = "encrypt"
    >>> pt = "meet me on monday at 8am"
    >>> encipher_bifid6(pt, key)
    'HNHOKNTA5MEPEGNQZYG'
    >>> ct = "HNHOKNTA5MEPEGNQZYG"
    >>> decipher_bifid6(ct, key)
    'MEETMEONMONDAYAT8AM'

    """
    A = alphabet_of_cipher() + [str(a) for a in range(10)]
    # first make sure the letters are capitalized
    # and text has no spaces
    key = uniq(key)
    key0 = [x.capitalize() for x in key if x.isalnum()]
    ct0 = [x.capitalize() for x in ct if x.isalnum()]
    # create long key
    long_key = key0 + [x for x in A if not (x in key0)]
    n = len(ct0)
    # the fractionalization
    pairs = flatten([[long_key.index(x) // 6,
                      long_key.index(x) % 6] for x in ct0])
    tmp_plain = flatten([[pairs[i], pairs[n + i]] for i in range(n)])
    pt = "".join([
        long_key[6 * tmp_plain[2 * i] + tmp_plain[2 * i + 1]] for i in range(n)
    ])
    return pt
Ejemplo n.º 31
0
    def are_concurrent(*planes):
        """Is a sequence of Planes concurrent?

        Two or more Planes are concurrent if their intersections
        are a common line.

        Parameters
        ==========

        planes: list

        Returns
        =======

        Boolean

        Examples
        ========

        >>> from sympy import Plane, Point3D
        >>> a = Plane(Point3D(5, 0, 0), normal_vector=(1, -1, 1))
        >>> b = Plane(Point3D(0, -2, 0), normal_vector=(3, 1, 1))
        >>> c = Plane(Point3D(0, -1, 0), normal_vector=(5, -1, 9))
        >>> Plane.are_concurrent(a, b)
        True
        >>> Plane.are_concurrent(a, b, c)
        False

        """
        planes = list(uniq(planes))
        for i in planes:
            if not isinstance(i, Plane):
                raise ValueError('All objects should be Planes but got %s' % i.func)
        if len(planes) < 2:
            return False
        planes = list(planes)
        first = planes.pop(0)
        sol = first.intersection(planes[0])
        if sol == []:
            return False
        else:
            line = sol[0]
            for i in planes[1:]:
                l = first.intersection(i)
                if not l or not l[0] in line:
                    return False
            return True
Ejemplo n.º 32
0
def decipher_bifid5(ct, key):
    r"""
    Performs the Bifid cipher decryption on ciphertext ``ct``, and returns the plaintext.

    This is the version of the Bifid cipher that uses the `5 \times 5` Polybius square.

    INPUT:

        ``ct``: ciphertext string (digits okay)

        ``key``: short string for key (no repetitions, digits okay)

    OUTPUT:

        plaintext from Bifid5 cipher (all caps, no spaces, no "J"s)

    Examples
    ========

    >>> from sympy.crypto.crypto import encipher_bifid5, decipher_bifid5
    >>> key = "encrypt"
    >>> pt = "meet me on monday"
    >>> encipher_bifid5(pt, key)
    'LNLLQNPPNPGADK'
    >>> ct = 'LNLLQNPPNPGADK'
    >>> decipher_bifid5(ct, key)
    'MEETMEONMONDAY'

    """
    A = alphabet_of_cipher()
    # first make sure the letters are capitalized
    # and text has no spaces
    key = uniq(key)
    key0 = [x.capitalize() for x in key if x.isalnum()]
    ct0 = [x.capitalize() for x in ct if x.isalnum()]
    # create long key
    long_key = key0 + [x for x in A if (not (x in key0) and x != "J")]
    n = len(ct0)
    # the fractionalization
    pairs = flatten([[long_key.index(x) // 5,
                      long_key.index(x) % 5] for x in ct0 if x != "J"])
    tmp_plain = flatten([[pairs[i], pairs[n + i]] for i in range(n)])
    pt = "".join([
        long_key[5 * tmp_plain[2 * i] + tmp_plain[2 * i + 1]] for i in range(n)
    ])
    return pt
Ejemplo n.º 33
0
def encipher_bifid7(pt, key):
    r"""
    Performs the Bifid cipher encryption on plaintext ``pt``, and returns the ciphertext.

    This is the version of the Bifid cipher that uses the `7 \times 7` Polybius square.
    Assumes alphabet of symbols is "A", ..., "Z", "0", ..., "22".
    (Also, assumes you have some way of distinguishing "22"
    from "2", "2" juxtaposed together for deciphering...)

    INPUT:

        ``pt``: plaintext string (digits okay)

        ``key``: short string for key (no repetitions, digits okay)

    OUTPUT:

        ciphertext from Bifid7 cipher (all caps, no spaces)

    Examples
    ========

    >>> from sympy.crypto.crypto import encipher_bifid7
    >>> key = "encrypt"
    >>> pt = "meet me on monday at 8am"
    >>> encipher_bifid7(pt, key)
    'JEJJLNAA3ME19YF3J222R'

    """
    A = alphabet_of_cipher() + [str(a) for a in range(23)]
    # first make sure the letters are capitalized
    # and text has no spaces
    key = uniq(key)
    key0 = [x.capitalize() for x in key if x.isalnum()]
    pt0 = [x.capitalize() for x in pt if x.isalnum()]
    # create long key
    long_key = key0 + [x for x in A if not (x in key0)]
    n = len(pt0)
    # the fractionalization
    pairs = [[long_key.index(x) // 7, long_key.index(x) % 7] for x in pt0]
    tmp_cipher = flatten([x[0] for x in pairs] + [x[1] for x in pairs])
    ct = "".join([
        long_key[7 * tmp_cipher[2 * i] + tmp_cipher[2 * i + 1]]
        for i in range(n)
    ])
    return ct
Ejemplo n.º 34
0
    def are_coplanar(cls, *points):
        """Return True if there exists a plane in which all the points
        lie.  A trivial True value is returned if `len(points) < 3` or
        all Points are 2-dimensional.

        Parameters
        ==========

        A set of points

        Raises
        ======

        ValueError : if less than 3 unique points are given

        Returns
        =======

        boolean

        Examples
        ========

        >>> from sympy import Point3D
        >>> p1 = Point3D(1, 2, 2)
        >>> p2 = Point3D(2, 7, 2)
        >>> p3 = Point3D(0, 0, 2)
        >>> p4 = Point3D(1, 1, 2)
        >>> Point3D.are_coplanar(p1, p2, p3, p4)
        True
        >>> p5 = Point3D(0, 1, 3)
        >>> Point3D.are_coplanar(p1, p2, p3, p5)
        False

        """
        if len(points) <= 1:
            return True

        points = cls._normalize_dimension(*[Point(i) for i in points])
        # quick exit if we are in 2D
        if points[0].ambient_dimension == 2:
            return True
        points = list(uniq(points))
        return Point.affine_rank(*points) <= 2
Ejemplo n.º 35
0
def decipher_bifid6(ct, key):
    r"""
    Performs the Bifid cipher decryption on ciphertext ``ct``, and returns the plaintext.

    This is the version of the Bifid cipher that uses the `6 \times 6` Polybius square.
    Assumes alphabet of symbols is "A", ..., "Z", "0", ..., "9".

    INPUT:

        ``ct``: ciphertext string (digits okay)

        ``key``: short string for key (no repetitions, digits okay)

    OUTPUT:

        plaintext from Bifid cipher (all caps, no spaces)

    Examples
    ========

    >>> from sympy.crypto.crypto import encipher_bifid6, decipher_bifid6
    >>> key = "encrypt"
    >>> pt = "meet me on monday at 8am"
    >>> encipher_bifid6(pt, key)
    'HNHOKNTA5MEPEGNQZYG'
    >>> ct = "HNHOKNTA5MEPEGNQZYG"
    >>> decipher_bifid6(ct, key)
    'MEETMEONMONDAYAT8AM'

    """
    A = alphabet_of_cipher() + [str(a) for a in range(10)]
    # first make sure the letters are capitalized
    # and text has no spaces
    key = uniq(key)
    key0 = [x.capitalize() for x in key if x.isalnum()]
    ct0 = [x.capitalize() for x in ct if x.isalnum()]
    # create long key
    long_key = key0 + [x for x in A if not(x in key0)]
    n = len(ct0)
    # the fractionalization
    pairs = flatten([[long_key.index(x)//6, long_key.index(x) % 6] for x in ct0])
    tmp_plain = flatten([[pairs[i], pairs[n + i]] for i in range(n)])
    pt = "".join([long_key[6*tmp_plain[2*i] + tmp_plain[2*i + 1]] for i in range(n)])
    return pt
Ejemplo n.º 36
0
    def are_coplanar(cls, *points):
        """Return True if there exists a plane in which all the points
        lie.  A trivial True value is returned if `len(points) < 3` or
        all Points are 2-dimensional.

        Parameters
        ==========

        A set of points

        Raises
        ======

        ValueError : if less than 3 unique points are given

        Returns
        =======

        boolean

        Examples
        ========

        >>> from sympy import Point3D
        >>> p1 = Point3D(1, 2, 2)
        >>> p2 = Point3D(2, 7, 2)
        >>> p3 = Point3D(0, 0, 2)
        >>> p4 = Point3D(1, 1, 2)
        >>> Point3D.are_coplanar(p1, p2, p3, p4)
        True
        >>> p5 = Point3D(0, 1, 3)
        >>> Point3D.are_coplanar(p1, p2, p3, p5)
        False

        """
        if len(points) <= 1:
            return True

        points = cls._normalize_dimension(*[Point(i) for i in points])
        # quick exit if we are in 2D
        if points[0].ambient_dimension == 2:
            return True
        points = list(uniq(points))
        return Point.affine_rank(*points) <= 2
Ejemplo n.º 37
0
def encipher_bifid7(pt, key):
    r"""
    Performs the Bifid cipher encryption on plaintext ``pt``, and returns the ciphertext.

    This is the version of the Bifid cipher that uses the `7 \times 7` Polybius square.
    Assumes alphabet of symbols is "A", ..., "Z", "0", ..., "22".
    (Also, assumes you have some way of distinguishing "22"
    from "2", "2" juxtaposed together for deciphering...)

    INPUT:

        ``pt``: plaintext string (digits okay)

        ``key``: short string for key (no repetitions, digits okay)

    OUTPUT:

        ciphertext from Bifid7 cipher (all caps, no spaces)

    Examples
    ========

    >>> from sympy.crypto.crypto import encipher_bifid7
    >>> key = "encrypt"
    >>> pt = "meet me on monday at 8am"
    >>> encipher_bifid7(pt, key)
    'JEJJLNAA3ME19YF3J222R'

    """
    A = alphabet_of_cipher() + [str(a) for a in range(23)]
    # first make sure the letters are capitalized
    # and text has no spaces
    key = uniq(key)
    key0 = [x.capitalize() for x in key if x.isalnum()]
    pt0 = [x.capitalize() for x in pt if x.isalnum()]
    # create long key
    long_key = key0 + [x for x in A if not(x in key0)]
    n = len(pt0)
    # the fractionalization
    pairs = [[long_key.index(x)//7, long_key.index(x) % 7] for x in pt0]
    tmp_cipher = flatten([x[0] for x in pairs] + [x[1] for x in pairs])
    ct = "".join([long_key[7*tmp_cipher[2*i] + tmp_cipher[2*i + 1]] for i in range(n)])
    return ct
Ejemplo n.º 38
0
def decipher_bifid5(ct, key):
    r"""
    Performs the Bifid cipher decryption on ciphertext ``ct``, and returns the plaintext.

    This is the version of the Bifid cipher that uses the `5 \times 5` Polybius square.

    INPUT:

        ``ct``: ciphertext string (digits okay)

        ``key``: short string for key (no repetitions, digits okay)

    OUTPUT:

        plaintext from Bifid5 cipher (all caps, no spaces, no "J"s)

    Examples
    ========

    >>> from sympy.crypto.crypto import encipher_bifid5, decipher_bifid5
    >>> key = "encrypt"
    >>> pt = "meet me on monday"
    >>> encipher_bifid5(pt, key)
    'LNLLQNPPNPGADK'
    >>> ct = 'LNLLQNPPNPGADK'
    >>> decipher_bifid5(ct, key)
    'MEETMEONMONDAY'

    """
    A = alphabet_of_cipher()
    # first make sure the letters are capitalized
    # and text has no spaces
    key = uniq(key)
    key0 = [x.capitalize() for x in key if x.isalnum()]
    ct0 = [x.capitalize() for x in ct if x.isalnum()]
    # create long key
    long_key = key0 + [x for x in A if (not(x in key0) and x != "J")]
    n = len(ct0)
    # the fractionalization
    pairs = flatten([[long_key.index(x)//5, long_key.index(x) % 5] for x in ct0 if x != "J"])
    tmp_plain = flatten([[pairs[i], pairs[n + i]] for i in range(n)])
    pt = "".join([long_key[5*tmp_plain[2*i] + tmp_plain[2*i + 1]] for i in range(n)])
    return pt
Ejemplo n.º 39
0
def test_uniq():
    assert list(uniq(p.copy() for p in partitions(4))) == [
        {4: 1},
        {1: 1, 3: 1},
        {2: 2},
        {1: 2, 2: 1},
        {1: 4},
    ]
    assert list(uniq(x % 2 for x in range(5))) == [0, 1]
    assert list(uniq("a")) == ["a"]
    assert list(uniq("ababc")) == list("abc")
    assert list(uniq([[1], [2, 1], [1]])) == [[1], [2, 1]]
    assert list(uniq(permutations(i for i in [[1], 2, 2]))) == [
        ([1], 2, 2),
        (2, [1], 2),
        (2, 2, [1]),
    ]
    assert list(uniq([2, 3, 2, 4, [2], [1], [2], [3], [1]])) == [2, 3, 4, [2], [1], [3]]
Ejemplo n.º 40
0
    def is_collinear(self, *args):
        """Returns `True` if there exists a line
        that contains `self` and `points`.  Returns `False` otherwise.
        A trivially True value is returned if no points are given.

        Parameters
        ==========

        args : sequence of Points

        Returns
        =======

        is_collinear : boolean

        See Also
        ========

        sympy.geometry.line.Line

        Examples
        ========

        >>> from sympy import Point
        >>> from sympy.abc import x
        >>> p1, p2 = Point(0, 0), Point(1, 1)
        >>> p3, p4, p5 = Point(2, 2), Point(x, x), Point(1, 2)
        >>> Point.is_collinear(p1, p2, p3, p4)
        True
        >>> Point.is_collinear(p1, p2, p3, p5)
        False

        """
        points = (self,) + args
        points = Point._normalize_dimension(*[Point(i) for i in points])
        points = list(uniq(points))
        return Point.affine_rank(*points) <= 1
Ejemplo n.º 41
0
    def is_collinear(self, *args):
        """Returns `True` if there exists a line
        that contains `self` and `points`.  Returns `False` otherwise.
        A trivially True value is returned if no points are given.

        Parameters
        ==========

        args : sequence of Points

        Returns
        =======

        is_collinear : boolean

        See Also
        ========

        sympy.geometry.line.Line

        Examples
        ========

        >>> from sympy import Point
        >>> from sympy.abc import x
        >>> p1, p2 = Point(0, 0), Point(1, 1)
        >>> p3, p4, p5 = Point(2, 2), Point(x, x), Point(1, 2)
        >>> Point.is_collinear(p1, p2, p3, p4)
        True
        >>> Point.is_collinear(p1, p2, p3, p5)
        False

        """
        points = (self,) + args
        points = Point._normalize_dimension(*[Point(i) for i in points])
        points = list(uniq(points))
        return Point.affine_rank(*points) <= 1
Ejemplo n.º 42
0
def heurisch_wrapper(f, x, rewrite=False, hints=None, mappings=None, retries=3,
                     degree_offset=0, unnecessary_permutations=None):
    """
    A wrapper around the heurisch integration algorithm.

    This method takes the result from heurisch and checks for poles in the
    denominator. For each of these poles, the integral is reevaluated, and
    the final integration result is given in terms of a Piecewise.

    Examples
    ========

    >>> from sympy.core import symbols
    >>> from sympy.functions import cos
    >>> from sympy.integrals.heurisch import heurisch, heurisch_wrapper
    >>> n, x = symbols('n x')
    >>> heurisch(cos(n*x), x)
    sin(n*x)/n
    >>> heurisch_wrapper(cos(n*x), x)
    Piecewise((x, n == 0), (sin(n*x)/n, True))

    See Also
    ========

    heurisch
    """
    f = sympify(f)
    if x not in f.free_symbols:
        return f*x

    res = heurisch(f, x, rewrite, hints, mappings, retries, degree_offset,
                   unnecessary_permutations)
    if not isinstance(res, Basic):
        return res
    # We consider each denominator in the expression, and try to find
    # cases where one or more symbolic denominator might be zero. The
    # conditions for these cases are stored in the list slns.
    slns = []
    for d in denoms(res):
        try:
            slns += solve(d, dict=True, exclude=(x,))
        except NotImplementedError:
            pass
    if not slns:
        return res
    slns = list(uniq(slns))
    # Remove the solutions corresponding to poles in the original expression.
    slns0 = []
    for d in denoms(f):
        try:
            slns0 += solve(d, dict=True, exclude=(x,))
        except NotImplementedError:
            pass
    slns = [s for s in slns if s not in slns0]
    if not slns:
        return res
    if len(slns) > 1:
        eqs = []
        for sub_dict in slns:
            eqs.extend([Eq(key, value) for key, value in sub_dict.items()])
        slns = solve(eqs, dict=True, exclude=(x,)) + slns
    # For each case listed in the list slns, we reevaluate the integral.
    pairs = []
    for sub_dict in slns:
        expr = heurisch(f.subs(sub_dict), x, rewrite, hints, mappings, retries,
                        degree_offset, unnecessary_permutations)
        cond = And(*[Eq(key, value) for key, value in sub_dict.items()])
        pairs.append((expr, cond))
    pairs.append((heurisch(f, x, rewrite, hints, mappings, retries,
                           degree_offset, unnecessary_permutations), True))
    return Piecewise(*pairs)
Ejemplo n.º 43
0
def test_uniq():
    assert list(uniq(p.copy() for p in partitions(4))) == \
        [{4: 1}, {1: 1, 3: 1}, {2: 2}, {1: 2, 2: 1}, {1: 4}]
    assert list(uniq(x % 2 for x in range(5))) == [0, 1]
    assert list(uniq('a')) == ['a']
    assert list(uniq('ababc')) == list('abc')
Ejemplo n.º 44
0
    def _intervals(self, sym):
        """Return a list of unique tuples, (a, b, e, i), where a and b
        are the lower and upper bounds in which the expression e of
        argument i in self is defined and a < b (when involving
        numbers) or a <= b when involving symbols.

        If there are any relationals not involving sym, or any
        relational cannot be solved for sym, NotImplementedError is
        raised. The calling routine should have removed such
        relationals before calling this routine.

        The evaluated conditions will be returned as ranges.
        Discontinuous ranges will be returned separately with
        identical expressions. The first condition that evaluates to
        True will be returned as the last tuple with a, b = -oo, oo.
        """
        from sympy.solvers.inequalities import _solve_inequality
        from sympy.logic.boolalg import to_cnf, distribute_or_over_and

        assert isinstance(self, Piecewise)

        def _solve_relational(r):
            if sym not in r.free_symbols:
                nonsymfail(r)
            rv = _solve_inequality(r, sym)
            if isinstance(rv, Relational):
                free = rv.args[1].free_symbols
                if rv.args[0] != sym or sym in free:
                    raise NotImplementedError(
                        filldedent('''
                        Unable to solve relational
                        %s for %s.''' % (r, sym)))
                if rv.rel_op == '==':
                    # this equality has been affirmed to have the form
                    # Eq(sym, rhs) where rhs is sym-free; it represents
                    # a zero-width interval which will be ignored
                    # whether it is an isolated condition or contained
                    # within an And or an Or
                    rv = S.false
                elif rv.rel_op == '!=':
                    try:
                        rv = Or(sym < rv.rhs, sym > rv.rhs)
                    except TypeError:
                        # e.g. x != I ==> all real x satisfy
                        rv = S.true
            elif rv == (S.NegativeInfinity < sym) & (sym < S.Infinity):
                rv = S.true
            return rv

        def nonsymfail(cond):
            raise NotImplementedError(
                filldedent('''
                A condition not involving
                %s appeared: %s''' % (sym, cond)))

        # make self canonical wrt Relationals
        reps = dict([(r, _solve_relational(r))
                     for r in self.atoms(Relational)])
        # process args individually so if any evaluate, their position
        # in the original Piecewise will be known
        args = [i.xreplace(reps) for i in self.args]

        # precondition args
        expr_cond = []
        default = idefault = None
        for i, (expr, cond) in enumerate(args):
            if cond is S.false:
                continue
            elif cond is S.true:
                default = expr
                idefault = i
                break

            cond = to_cnf(cond)
            if isinstance(cond, And):
                cond = distribute_or_over_and(cond)

            if isinstance(cond, Or):
                expr_cond.extend([(i, expr, o) for o in cond.args
                                  if not isinstance(o, Equality)])
            elif cond is not S.false:
                expr_cond.append((i, expr, cond))

        # determine intervals represented by conditions
        int_expr = []
        for iarg, expr, cond in expr_cond:
            if isinstance(cond, And):
                lower = S.NegativeInfinity
                upper = S.Infinity
                for cond2 in cond.args:
                    if isinstance(cond2, Equality):
                        lower = upper  # ignore
                        break
                    elif cond2.lts == sym:
                        upper = Min(cond2.gts, upper)
                    elif cond2.gts == sym:
                        lower = Max(cond2.lts, lower)
                    else:
                        nonsymfail(cond2)  # should never get here
            elif isinstance(cond, Relational):
                lower, upper = cond.lts, cond.gts  # part 1: initialize with givens
                if cond.lts == sym:  # part 1a: expand the side ...
                    lower = S.NegativeInfinity  # e.g. x <= 0 ---> -oo <= 0
                elif cond.gts == sym:  # part 1a: ... that can be expanded
                    upper = S.Infinity  # e.g. x >= 0 --->  oo >= 0
                else:
                    nonsymfail(cond)
            else:
                raise NotImplementedError('unrecognized condition: %s' % cond)

            lower, upper = lower, Max(lower, upper)
            if (lower >= upper) is not S.true:
                int_expr.append((lower, upper, expr, iarg))

        if default is not None:
            int_expr.append(
                (S.NegativeInfinity, S.Infinity, default, idefault))

        return list(uniq(int_expr))
Ejemplo n.º 45
0
 def _handle_irel(self, x, handler):
     """Return either None (if the conditions of self depend only on x) else
     a Piecewise expression whose expressions (handled by the handler that
     was passed) are paired with the governing x-independent relationals,
     e.g. Piecewise((A, a(x) & b(y)), (B, c(x) | c(y)) ->
     Piecewise(
         (handler(Piecewise((A, a(x) & True), (B, c(x) | True)), b(y) & c(y)),
         (handler(Piecewise((A, a(x) & True), (B, c(x) | False)), b(y)),
         (handler(Piecewise((A, a(x) & False), (B, c(x) | True)), c(y)),
         (handler(Piecewise((A, a(x) & False), (B, c(x) | False)), True))
     """
     # identify governing relationals
     rel = self.atoms(Relational)
     irel = list(
         ordered([
             r for r in rel
             if x not in r.free_symbols and r not in (S.true, S.false)
         ]))
     if irel:
         args = {}
         exprinorder = []
         for truth in product((1, 0), repeat=len(irel)):
             reps = dict(zip(irel, truth))
             # only store the true conditions since the false are implied
             # when they appear lower in the Piecewise args
             if 1 not in truth:
                 cond = None  # flag this one so it doesn't get combined
             else:
                 andargs = Tuple(*[i for i in reps if reps[i]])
                 free = list(andargs.free_symbols)
                 if len(free) == 1:
                     from sympy.solvers.inequalities import (
                         reduce_inequalities, _solve_inequality)
                     try:
                         t = reduce_inequalities(andargs, free[0])
                         # ValueError when there are potentially
                         # nonvanishing imaginary parts
                     except (ValueError, NotImplementedError):
                         # at least isolate free symbol on left
                         t = And(*[
                             _solve_inequality(a, free[0], linear=True)
                             for a in andargs
                         ])
                 else:
                     t = And(*andargs)
                 if t is S.false:
                     continue  # an impossible combination
                 cond = t
             expr = handler(self.xreplace(reps))
             if isinstance(expr, self.func) and len(expr.args) == 1:
                 expr, econd = expr.args[0]
                 cond = And(econd, True if cond is None else cond)
             # the ec pairs are being collected since all possibilities
             # are being enumerated, but don't put the last one in since
             # its expr might match a previous expression and it
             # must appear last in the args
             if cond is not None:
                 args.setdefault(expr, []).append(cond)
                 # but since we only store the true conditions we must maintain
                 # the order so that the expression with the most true values
                 # comes first
                 exprinorder.append(expr)
         # convert collected conditions as args of Or
         for k in args:
             args[k] = Or(*args[k])
         # take them in the order obtained
         args = [(e, args[e]) for e in uniq(exprinorder)]
         # add in the last arg
         args.append((expr, True))
         # if any condition reduced to True, it needs to go last
         # and there should only be one of them or else the exprs
         # should agree
         trues = [i for i in range(len(args)) if args[i][1] is S.true]
         if not trues:
             # make the last one True since all cases were enumerated
             e, c = args[-1]
             args[-1] = (e, S.true)
         else:
             assert len(set([e for e, c in [args[i] for i in trues]])) == 1
             args.append(args.pop(trues.pop()))
             while trues:
                 args.pop(trues.pop())
         return Piecewise(*args)
Ejemplo n.º 46
0
def encipher_bifid5(pt, key):
    r"""
    Performs the Bifid cipher encryption on plaintext ``pt``, and returns the ciphertext.

    This is the version of the Bifid cipher that uses the `5 \times 5` Polybius square.

    Notes
    =====

    The Bifid cipher was invented around 1901 by Felix Delastelle.
    It is a *fractional substitution* cipher, where letters are
    replaced by pairs of symbols from a smaller alphabet. The
    cipher uses a `5 \times 5` square filled with some ordering of the alphabet,
    except that "i"s and "j"s are identified (this is a so-called
    Polybius square; there is a `6 \times 6` analog if you add back in "j" and also
    append onto the usual 26 letter alphabet, the digits 0, 1, ..., 9).
    According to Helen Gaines' book *Cryptanalysis*, this type of cipher
    was used in the field by the German Army during World War I.

    ALGORITHM: (5x5 case)

        INPUT:

            ``pt``: plaintext string (no "j"s)

            ``key``: short string for key (no repetitions, no "j"s)

        OUTPUT:

            ciphertext (using Bifid5 cipher in all caps, no spaces, no "J"s)

        STEPS:
            1. Create the `5 \times 5` Polybius square ``S`` associated to the ``k`` as
               follows:

                a) starting top left, moving left-to-right, top-to-bottom,
                   place the letters of the key into a 5x5 matrix,
                b) when finished, add the letters of the alphabet
                   not in the key until the 5x5 square is filled

            2. Create a list ``P`` of pairs of numbers which are the coordinates
               in the Polybius square of the letters in ``pt``.
            3. Let ``L1`` be the list of all first coordinates of ``P`` (length
               of ``L1 = n``), let ``L2`` be the list of all second coordinates
               of ``P`` (so the length of ``L2`` is also ``n``).
            4. Let ``L`` be the concatenation of ``L1`` and ``L2`` (length ``L = 2*n``),
               except that consecutive numbers are paired ``(L[2*i], L[2*i + 1])``.
               You can regard ``L`` as a list of pairs of length ``n``.
            5. Let ``C`` be the list of all letters which are of the form
               ``S[i, j]``, for all ``(i, j)`` in ``L``. As a string, this
               is the ciphertext ``ct``.

    Examples
    ========

    >>> from sympy.crypto.crypto import encipher_bifid5
    >>> pt = "meet me on monday"
    >>> key = "encrypt"
    >>> encipher_bifid5(pt, key)
    'LNLLQNPPNPGADK'
    >>> pt = "meet me on friday"
    >>> encipher_bifid5(pt, key)
    'LNLLFGPPNPGRSK'

    """
    A = alphabet_of_cipher()
    # first make sure the letters are capitalized
    # and text has no spaces
    key = uniq(key)
    key0 = [x.capitalize() for x in key if x.isalnum()]
    pt0 = [x.capitalize() for x in pt if x.isalnum()]
    # create long key
    long_key = key0 + [x for x in A if (not(x in key0) and x != "J")]
    n = len(pt0)
    # the fractionalization
    pairs = [[long_key.index(x)//5, long_key.index(x) % 5] for x in pt0]
    tmp_cipher = flatten([x[0] for x in pairs] + [x[1] for x in pairs])
    ct = "".join([long_key[5*tmp_cipher[2*i] + tmp_cipher[2*i + 1]] for i in range(n)])
    return ct
Ejemplo n.º 47
0
 def _handle_irel(self, x, handler):
     """Return either None (if the conditions of self depend only on x) else
     a Piecewise expression whose expressions (handled by the handler that
     was passed) are paired with the governing x-independent relationals,
     e.g. Piecewise((A, a(x) & b(y)), (B, c(x) | c(y)) ->
     Piecewise(
         (handler(Piecewise((A, a(x) & True), (B, c(x) | True)), b(y) & c(y)),
         (handler(Piecewise((A, a(x) & True), (B, c(x) | False)), b(y)),
         (handler(Piecewise((A, a(x) & False), (B, c(x) | True)), c(y)),
         (handler(Piecewise((A, a(x) & False), (B, c(x) | False)), True))
     """
     # identify governing relationals
     rel = self.atoms(Relational)
     irel = list(ordered([r for r in rel if x not in r.free_symbols
         and r not in (S.true, S.false)]))
     if irel:
         args = {}
         exprinorder = []
         for truth in product((1, 0), repeat=len(irel)):
             reps = dict(zip(irel, truth))
             # only store the true conditions since the false are implied
             # when they appear lower in the Piecewise args
             if 1 not in truth:
                 cond = None  # flag this one so it doesn't get combined
             else:
                 andargs = Tuple(*[i for i in reps if reps[i]])
                 free = list(andargs.free_symbols)
                 if len(free) == 1:
                     from sympy.solvers.inequalities import (
                         reduce_inequalities, _solve_inequality)
                     try:
                         t = reduce_inequalities(andargs, free[0])
                         # ValueError when there are potentially
                         # nonvanishing imaginary parts
                     except (ValueError, NotImplementedError):
                         # at least isolate free symbol on left
                         t = And(*[_solve_inequality(
                             a, free[0], linear=True)
                             for a in andargs])
                 else:
                     t = And(*andargs)
                 if t is S.false:
                     continue  # an impossible combination
                 cond = t
             expr = handler(self.xreplace(reps))
             if isinstance(expr, self.func) and len(expr.args) == 1:
                 expr, econd = expr.args[0]
                 cond = And(econd, True if cond is None else cond)
             # the ec pairs are being collected since all possibilities
             # are being enumerated, but don't put the last one in since
             # its expr might match a previous expression and it
             # must appear last in the args
             if cond is not None:
                 args.setdefault(expr, []).append(cond)
                 # but since we only store the true conditions we must maintain
                 # the order so that the expression with the most true values
                 # comes first
                 exprinorder.append(expr)
         # convert collected conditions as args of Or
         for k in args:
             args[k] = Or(*args[k])
         # take them in the order obtained
         args = [(e, args[e]) for e in uniq(exprinorder)]
         # add in the last arg
         args.append((expr, True))
         # if any condition reduced to True, it needs to go last
         # and there should only be one of them or else the exprs
         # should agree
         trues = [i for i in range(len(args)) if args[i][1] is S.true]
         if not trues:
             # make the last one True since all cases were enumerated
             e, c = args[-1]
             args[-1] = (e, S.true)
         else:
             assert len(set([e for e, c in [args[i] for i in trues]])) == 1
             args.append(args.pop(trues.pop()))
             while trues:
                 args.pop(trues.pop())
         return Piecewise(*args)
Ejemplo n.º 48
0
    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(isinstance(v, 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 not all(p is S.Zero for p in point) and \
           not all(p is S.Infinity for p in point):
            raise NotImplementedError('Order at points other than 0 '
                'or oo not supported, got %s as a point.' % point)

        if 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()

            if expr.is_Add:
                lst = expr.extract_leading_order(variables, point)
                expr = Add(*[f.expr for (e, f) in lst])

            elif expr:
                if point[0] == S.Zero:
                    expr = expr.as_leading_term(*variables)
                expr = expr.as_independent(*variables, as_Add=False)[1]

                expr = expand_power_base(expr)
                expr = expand_log(expr)

                if len(variables) == 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 = variables[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)

        if expr is S.Zero:
            return expr

        if expr.is_Order:
            expr = expr.expr

        if not expr.has(*variables):
            expr = S.One

        # create Order instance:
        variables.sort(key=default_sort_key)
        args = (expr,) + Tuple(*zip(variables, point))
        obj = Expr.__new__(cls, *args)
        return obj
Ejemplo n.º 49
0
def encipher_vigenere(pt, key, symbols="ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
    """
    Performs the Vigenère cipher encryption on plaintext ``pt``, and returns the ciphertext.

    Notes
    =====

    The Vigenère cipher is named after Blaise de Vigenère, a sixteenth
    century diplomat and cryptographer, by a historical accident.
    Vigenère actually invented a different and more complicated cipher.
    The so-called *Vigenère cipher* was actually invented
    by Giovan Batista Belaso in 1553.

    This cipher was used in the 1800's, for example, during the American Civil War.
    The Confederacy used a brass cipher disk to implement the Vigenère cipher
    (now on display in the NSA Museum in Fort Meade) [1]_.

    The Vigenère cipher is a generalization of the shift cipher.
    Whereas the shift cipher shifts each letter by the same amount (that amount
    being the key of the shift cipher) the Vigenère cipher shifts
    a letter by an amount determined by the key (which is a word or
    phrase known only to the sender and receiver).

    For example, if the key was a single letter, such as "C", then the
    so-called Vigenere cipher is actually a shift cipher with a
    shift of `2` (since "C" is the 2nd letter of the alphabet, if
    you start counting at `0`). If the key was a word with two
    letters, such as "CA", then the so-called Vigenère cipher will
    shift letters in even positions by `2` and letters in odd positions
    are left alone (shifted by `0`, since "A" is the 0th letter, if
    you start counting at `0`).


    ALGORITHM:

        INPUT:

            ``key``: a string of upper-case letters (the secret key)

            ``m``: string of upper-case letters (the plaintext message)

        OUTPUT:

            ``c``: string of upper-case letters (the ciphertext message)

        STEPS:
            0. Identify the alphabet A, ..., Z with the integers 0, ..., 25.
            1. Compute from the string ``key`` a list ``L1`` of corresponding
               integers. Let ``n1 = len(L1)``.
            2. Compute from the string ``m`` a list ``L2`` of corresponding
               integers. Let ``n2 = len(L2)``.
            3. Break ``L2`` up sequencially into sublists of size ``n1``, and one sublist
               at the end of size smaller or equal to ``n1``.
            4. For each of these sublists ``L`` of ``L2``, compute a new list ``C`` given by
               ``C[i] = L[i] + L1[i] (mod 26)`` to the ``i``-th element in the sublist,
               for each ``i``.
            5. Assemble these lists ``C`` by concatenation into a new list of length ``n2``.
            6. Compute from the new list a string ``c`` of corresponding letters.

    Once it is known that the key is, say, `n` characters long, frequency analysis
    can be applied to every `n`-th letter of the ciphertext to determine the plaintext.
    This method is called *Kasiski examination* (although it was first discovered
    by Babbage).

    The cipher Vigenère actually discovered is an "auto-key" cipher
    described as follows.

    ALGORITHM:

        INPUT:

          ``key``: a string of upper-case letters (the secret key)

          ``m``: string of upper-case letters (the plaintext message)

        OUTPUT:

          ``c``: string of upper-case letters (the ciphertext message)

        STEPS:
            0. Identify the alphabet A, ..., Z with the integers 0, ..., 25.
            1. Compute from the string ``m`` a list ``L2`` of corresponding
               integers. Let ``n2 = len(L2)``.
            2. Let ``n1`` be the length of the key. Concatenate the string
               ``key`` with the first ``n2 - n1`` characters of the plaintext message.
               Compute from this string of length ``n2`` a list ``L1`` of corresponding
               integers. Note ``n2 = len(L1)``.
            3. Compute a new list ``C`` given by ``C[i] = L1[i] + L2[i] (mod 26)``,
               for each ``i``. Note ``n2 = len(C)``.
            4. Compute from the new list a string ``c`` of corresponding letters.

    References
    ==========

    .. [1] http://en.wikipedia.org/wiki/Vigenere_cipher

    Examples
    ========

    >>> from sympy.crypto.crypto import encipher_vigenere
    >>> key = "encrypt"
    >>> pt = "meet me on monday"
    >>> encipher_vigenere(pt, key)
    'QRGKKTHRZQEBPR'

    """
    symbols = "".join(symbols)
    A = alphabet_of_cipher(symbols)
    N = len(A)   # normally, 26
    key0 = uniq(key)
    key0 = [x.capitalize() for x in key0 if x.isalnum()]
    K = [A.index(x) for x in key0]
    k = len(K)
    pt0 = [x.capitalize() for x in pt if x.isalnum()]
    P = [A.index(x) for x in pt0]
    n = len(P)
    #m = n//k
    C = [(K[i % k] + P[i]) % N for i in range(n)]
    return "".join([str(A[x]) for x in C])
Ejemplo n.º 50
0
def encipher_vigenere(pt, key, symbols="ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
    """
    Performs the Vigenere cipher encryption on plaintext ``pt``, and returns the ciphertext.

    Notes
    =====

    The Vigenere cipher is named after Blaise de Vigenere, a sixteenth
    century diplomat and cryptographer, by a historical accident.
    Vigene`re actually invented a different and more complicated cipher.
    The so-called *Vigenere cipher* cipher was actually invented
    by Giovan Batista Belaso in 1553.

    This cipher was used in the 1700's, for example, during the American Civil War.
    The Confederacy used a brass cipher disk to implement the Vigenere cipher
    (now on display in the NSA Museum in Fort Meade) [1]_.

    The Vigenere cipher is a generalization of the shift cipher.
    Whereas the shift cipher shifts each letter by the same amount (that amount
    being the key of the shift cipher) the Vigenere cipher shifts
    a letter by an amount determined by the key, which is a word or
    phrase known only to the sender and receiver).

    For example, if the key was a single letter, such as "C", then the
    so-called Vigenere cipher is actually a shift cipher with a
    shift of `2` (since "C" is the 2nd letter of the alphabet, if
    you start counting at `0`). If the key was a word with two
    letters, such as "CA", then the so-called Vigenere cipher will
    shift letters in even positions by `2` and letters in odd positions
    are left alone (shifted by `0`, since "A" is the 0th letter, if
    you start counting at `0`).


    ALGORITHM:

        INPUT:

            ``key``: a string of upper-case letters (the secret key)

            ``m``: string of upper-case letters (the plaintext message)

        OUTPUT:

            ``c``: string of upper-case letters (the ciphertext message)

        STEPS:
            0. Identify the alphabet A, ..., Z with the integers 0, ..., 25.
            1. Compute from the string ``key`` a list ``L1`` of corresponding
               integers. Let ``n1 = len(L1)``.
            2. Compute from the string ``m`` a list ``L2`` of corresponding
               integers. Let ``n2 = len(L2)``.
            3. Break ``L2`` up sequencially into sublists of size ``n1``, and one sublist
               at the end of size smaller or equal to ``n1``.
            4. For each of these sublists ``L`` of ``L2``, compute a new list ``C`` given by
               ``C[i] = L[i] + L1[i] (mod 26)`` to the ``i``-th element in the sublist,
               for each ``i``.
            5. Assemble these lists ``C`` by concatenation into a new list of length ``n2``.
            6. Compute from the new list a string ``c`` of corresponding letters.

    Once it is known that the key is, say, `n` characters long, frequency analysis
    can be applied to every `n`-th letter of the ciphertext to determine the plaintext.
    This method is called *Kasiski examination* (although it was first discovered
    by Babbage).

    The cipher Vigenere actually discovered is an "auto-key" cipher
    described as follows.

    ALGORITHM:

        INPUT:

          ``key``: a string of upper-case letters (the secret key)

          ``m``: string of upper-case letters (the plaintext message)

        OUTPUT:

          ``c``: string of upper-case letters (the ciphertext message)

        STEPS:
            0. Identify the alphabet A, ..., Z with the integers 0, ..., 25.
            1. Compute from the string ``m`` a list ``L2`` of corresponding
               integers. Let ``n2 = len(L2)``.
            2. Let ``n1`` be the length of the key. Concatenate the string
               ``key`` with the first ``n2 - n1`` characters of the plaintext message.
               Compute from this string of length ``n2`` a list ``L1`` of corresponding
               integers. Note ``n2 = len(L1)``.
            3. Compute a new list ``C`` given by ``C[i] = L1[i] + L2[i] (mod 26)``,
               for each ``i``. Note ``n2 = len(C)``.
            4. Compute from the new list a string ``c`` of corresponding letters.

    References
    ==========

    .. [1] http://en.wikipedia.org/wiki/Vigenere_cipher

    Examples
    ========

    >>> from sympy.crypto.crypto import encipher_vigenere
    >>> key = "encrypt"
    >>> pt = "meet me on monday"
    >>> encipher_vigenere(pt, key)
    'QRGKKTHRZQEBPR'

    """
    symbols = "".join(symbols)
    A = alphabet_of_cipher(symbols)
    N = len(A)  # normally, 26
    key0 = uniq(key)
    key0 = [x.capitalize() for x in key0 if x.isalnum()]
    K = [A.index(x) for x in key0]
    k = len(K)
    pt0 = [x.capitalize() for x in pt if x.isalnum()]
    P = [A.index(x) for x in pt0]
    n = len(P)
    #m = n//k
    C = [(K[i % k] + P[i]) % N for i in range(n)]
    return "".join([str(A[x]) for x in C])
Ejemplo n.º 51
0
def test_uniq():
    assert list(uniq(p.copy() for p in partitions(4))) == [{4: 1}, {1: 1, 3: 1}, {2: 2}, {1: 2, 2: 1}, {1: 4}]
    assert list(uniq(x % 2 for x in range(5))) == [0, 1]
    assert list(uniq("a")) == ["a"]
    assert list(uniq("ababc")) == list("abc")
Ejemplo n.º 52
0
def encipher_bifid5(pt, key):
    r"""
    Performs the Bifid cipher encryption on plaintext ``pt``, and returns the ciphertext.

    This is the version of the Bifid cipher that uses the `5 \times 5` Polybius square.

    Notes
    =====

    The Bifid cipher was invented around 1901 by Felix Delastelle.
    It is a *fractional substitution* cipher, where letters are
    replaced by pairs of symbols from a smaller alphabet. The
    cipher uses a `5 \times 5` square filled with some ordering of the alphabet,
    except that "i"s and "j"s are identified (this is a so-called
    Polybius square; there is a `6 \times 6` analog if you add back in "j" and also
    append onto the usual 26 letter alphabet, the digits 0, 1, ..., 9).
    According to Helen Gaines' book *Cryptanalysis*, this type of cipher
    was used in the field by the German Army during World War I.

    ALGORITHM: (5x5 case)

        INPUT:

            ``pt``: plaintext string (no "j"s)

            ``key``: short string for key (no repetitions, no "j"s)

        OUTPUT:

            ciphertext (using Bifid5 cipher in all caps, no spaces, no "J"s)

        STEPS:
            1. Create the `5 \times 5` Polybius square ``S`` associated to the ``k`` as
               follows:

                a) starting top left, moving left-to-right, top-to-bottom,
                   place the letters of the key into a 5x5 matrix,
                b) when finished, add the letters of the alphabet
                   not in the key until the 5x5 square is filled

            2. Create a list ``P`` of pairs of numbers which are the coordinates
               in the Polybius square of the letters in ``pt``.
            3. Let ``L1`` be the list of all first coordinates of ``P`` (length
               of ``L1 = n``), let ``L2`` be the list of all second coordinates
               of ``P`` (so the length of ``L2`` is also ``n``).
            4. Let ``L`` be the concatenation of ``L1`` and ``L2`` (length ``L = 2*n``),
               except that consecutive numbers are paired ``(L[2*i], L[2*i + 1])``.
               You can regard ``L`` as a list of pairs of length ``n``.
            5. Let ``C`` be the list of all letters which are of the form
               ``S[i, j]``, for all ``(i, j)`` in ``L``. As a string, this
               is the ciphertext ``ct``.

    Examples
    ========

    >>> from sympy.crypto.crypto import encipher_bifid5
    >>> pt = "meet me on monday"
    >>> key = "encrypt"
    >>> encipher_bifid5(pt, key)
    'LNLLQNPPNPGADK'
    >>> pt = "meet me on friday"
    >>> encipher_bifid5(pt, key)
    'LNLLFGPPNPGRSK'

    """
    A = alphabet_of_cipher()
    # first make sure the letters are capitalized
    # and text has no spaces
    key = uniq(key)
    key0 = [x.capitalize() for x in key if x.isalnum()]
    pt0 = [x.capitalize() for x in pt if x.isalnum()]
    # create long key
    long_key = key0 + [x for x in A if (not (x in key0) and x != "J")]
    n = len(pt0)
    # the fractionalization
    pairs = [[long_key.index(x) // 5, long_key.index(x) % 5] for x in pt0]
    tmp_cipher = flatten([x[0] for x in pairs] + [x[1] for x in pairs])
    ct = "".join([
        long_key[5 * tmp_cipher[2 * i] + tmp_cipher[2 * i + 1]]
        for i in range(n)
    ])
    return ct
Ejemplo n.º 53
0
def heurisch_wrapper(f, x, rewrite=False, hints=None, mappings=None, retries=3,
                     degree_offset=0, unnecessary_permutations=None,
                     _try_heurisch=None):
    """
    A wrapper around the heurisch integration algorithm.

    Explanation
    ===========

    This method takes the result from heurisch and checks for poles in the
    denominator. For each of these poles, the integral is reevaluated, and
    the final integration result is given in terms of a Piecewise.

    Examples
    ========

    >>> from sympy import cos, symbols
    >>> from sympy.integrals.heurisch import heurisch, heurisch_wrapper
    >>> n, x = symbols('n x')
    >>> heurisch(cos(n*x), x)
    sin(n*x)/n
    >>> heurisch_wrapper(cos(n*x), x)
    Piecewise((sin(n*x)/n, Ne(n, 0)), (x, True))

    See Also
    ========

    heurisch
    """
    from sympy.solvers.solvers import solve, denoms
    f = sympify(f)
    if not f.has_free(x):
        return f*x

    res = heurisch(f, x, rewrite, hints, mappings, retries, degree_offset,
                   unnecessary_permutations, _try_heurisch)
    if not isinstance(res, Basic):
        return res
    # We consider each denominator in the expression, and try to find
    # cases where one or more symbolic denominator might be zero. The
    # conditions for these cases are stored in the list slns.
    slns = []
    for d in denoms(res):
        try:
            slns += solve(d, dict=True, exclude=(x,))
        except NotImplementedError:
            pass
    if not slns:
        return res
    slns = list(uniq(slns))
    # Remove the solutions corresponding to poles in the original expression.
    slns0 = []
    for d in denoms(f):
        try:
            slns0 += solve(d, dict=True, exclude=(x,))
        except NotImplementedError:
            pass
    slns = [s for s in slns if s not in slns0]
    if not slns:
        return res
    if len(slns) > 1:
        eqs = []
        for sub_dict in slns:
            eqs.extend([Eq(key, value) for key, value in sub_dict.items()])
        slns = solve(eqs, dict=True, exclude=(x,)) + slns
    # For each case listed in the list slns, we reevaluate the integral.
    pairs = []
    for sub_dict in slns:
        expr = heurisch(f.subs(sub_dict), x, rewrite, hints, mappings, retries,
                        degree_offset, unnecessary_permutations,
                        _try_heurisch)
        cond = And(*[Eq(key, value) for key, value in sub_dict.items()])
        generic = Or(*[Ne(key, value) for key, value in sub_dict.items()])
        if expr is None:
            expr = integrate(f.subs(sub_dict),x)
        pairs.append((expr, cond))
    # If there is one condition, put the generic case first. Otherwise,
    # doing so may lead to longer Piecewise formulas
    if len(pairs) == 1:
        pairs = [(heurisch(f, x, rewrite, hints, mappings, retries,
                              degree_offset, unnecessary_permutations,
                              _try_heurisch),
                              generic),
                 (pairs[0][0], True)]
    else:
        pairs.append((heurisch(f, x, rewrite, hints, mappings, retries,
                              degree_offset, unnecessary_permutations,
                              _try_heurisch),
                              True))
    return Piecewise(*pairs)
Ejemplo n.º 54
0
def ordered(seq, keys=None, default=True, warn=False):
    """Return an iterator of the seq where keys are used to break ties in
    a conservative fashion: if, after applying a key, there are no ties
    then no other keys will be computed.

    Two default keys will be applied if 1) keys are not provided or 2) the
    given keys don't resolve all ties (but only if `default` is True). The
    two keys are `_nodes` (which places smaller expressions before large) and
    `default_sort_key` which (if the `sort_key` for an object is defined
    properly) should resolve any ties.

    If ``warn`` is True then an error will be raised if there were no
    keys remaining to break ties. This can be used if it was expected that
    there should be no ties between items that are not identical.

    Examples
    ========

    >>> from sympy.utilities.iterables import ordered
    >>> from sympy import count_ops
    >>> from sympy.abc import x, y

    The count_ops is not sufficient to break ties in this list and the first
    two items appear in their original order (i.e. the sorting is stable):

    >>> list(ordered([y + 2, x + 2, x**2 + y + 3],
    ...    count_ops, default=False, warn=False))
    ...
    [y + 2, x + 2, x**2 + y + 3]

    The default_sort_key allows the tie to be broken:

    >>> list(ordered([y + 2, x + 2, x**2 + y + 3]))
    ...
    [x + 2, y + 2, x**2 + y + 3]

    Here, sequences are sorted by length, then sum:

    >>> seq, keys = [[[1, 2, 1], [0, 3, 1], [1, 1, 3], [2], [1]], [
    ...    lambda x: len(x),
    ...    lambda x: sum(x)]]
    ...
    >>> list(ordered(seq, keys, default=False, warn=False))
    [[1], [2], [1, 2, 1], [0, 3, 1], [1, 1, 3]]

    If ``warn`` is True, an error will be raised if there were not
    enough keys to break ties:

    >>> list(ordered(seq, keys, default=False, warn=True))
    Traceback (most recent call last):
    ...
    ValueError: not enough keys to break ties


    Notes
    =====

    The decorated sort is one of the fastest ways to sort a sequence for
    which special item comparison is desired: the sequence is decorated,
    sorted on the basis of the decoration (e.g. making all letters lower
    case) and then undecorated. If one wants to break ties for items that
    have the same decorated value, a second key can be used. But if the
    second key is expensive to compute then it is inefficient to decorate
    all items with both keys: only those items having identical first key
    values need to be decorated. This function applies keys successively
    only when needed to break ties. By yielding an iterator, use of the
    tie-breaker is delayed as long as possible.

    This function is best used in cases when use of the first key is
    expected to be a good hashing function; if there are no unique hashes
    from application of a key then that key should not have been used. The
    exception, however, is that even if there are many collisions, if the
    first group is small and one does not need to process all items in the
    list then time will not be wasted sorting what one was not interested
    in. For example, if one were looking for the minimum in a list and
    there were several criteria used to define the sort order, then this
    function would be good at returning that quickly if the first group
    of candidates is small relative to the number of items being processed.

    """
    d = defaultdict(list)
    if keys:
        if not isinstance(keys, (list, tuple)):
            keys = [keys]
        keys = list(keys)
        f = keys.pop(0)
        for a in seq:
            d[f(a)].append(a)
    else:
        if not default:
            raise ValueError('if default=False then keys must be provided')
        d[None].extend(seq)

    for k in sorted(d.keys()):
        if len(d[k]) > 1:
            if keys:
                d[k] = ordered(d[k], keys, default, warn)
            elif default:
                d[k] = ordered(d[k], (
                    _nodes,
                    default_sort_key,
                ),
                               default=False,
                               warn=warn)
            elif warn:
                from sympy.utilities.iterables import uniq
                u = list(uniq(d[k]))
                if len(u) > 1:
                    raise ValueError('not enough keys to break ties: %s' % u)
        for v in d[k]:
            yield v
        d.pop(k)
Ejemplo n.º 55
0
    def _intervals(self, sym):
        """Return a list of unique tuples, (a, b, e, i), where a and b
        are the lower and upper bounds in which the expression e of
        argument i in self is defined and a < b (when involving
        numbers) or a <= b when involving symbols.

        If there are any relationals not involving sym, or any
        relational cannot be solved for sym, NotImplementedError is
        raised. The calling routine should have removed such
        relationals before calling this routine.

        The evaluated conditions will be returned as ranges.
        Discontinuous ranges will be returned separately with
        identical expressions. The first condition that evaluates to
        True will be returned as the last tuple with a, b = -oo, oo.
        """
        from sympy.solvers.inequalities import _solve_inequality
        from sympy.logic.boolalg import to_cnf, distribute_or_over_and

        assert isinstance(self, Piecewise)

        def _solve_relational(r):
            if sym not in r.free_symbols:
                nonsymfail(r)
            rv = _solve_inequality(r, sym)
            if isinstance(rv, Relational):
                free = rv.args[1].free_symbols
                if rv.args[0] != sym or sym in free:
                    raise NotImplementedError(filldedent('''
                        Unable to solve relational
                        %s for %s.''' % (r, sym)))
                if rv.rel_op == '==':
                    # this equality has been affirmed to have the form
                    # Eq(sym, rhs) where rhs is sym-free; it represents
                    # a zero-width interval which will be ignored
                    # whether it is an isolated condition or contained
                    # within an And or an Or
                    rv = S.false
                elif rv.rel_op == '!=':
                    try:
                        rv = Or(sym < rv.rhs, sym > rv.rhs)
                    except TypeError:
                        # e.g. x != I ==> all real x satisfy
                        rv = S.true
            elif rv == (S.NegativeInfinity < sym) & (sym < S.Infinity):
                rv = S.true
            return rv

        def nonsymfail(cond):
            raise NotImplementedError(filldedent('''
                A condition not involving
                %s appeared: %s''' % (sym, cond)))

        # make self canonical wrt Relationals
        reps = dict([
            (r, _solve_relational(r)) for r in self.atoms(Relational)])
        # process args individually so if any evaluate, their position
        # in the original Piecewise will be known
        args = [i.xreplace(reps) for i in self.args]

        # precondition args
        expr_cond = []
        default = idefault = None
        for i, (expr, cond) in enumerate(args):
            if cond is S.false:
                continue
            elif cond is S.true:
                default = expr
                idefault = i
                break

            cond = to_cnf(cond)
            if isinstance(cond, And):
                cond = distribute_or_over_and(cond)

            if isinstance(cond, Or):
                expr_cond.extend(
                    [(i, expr, o) for o in cond.args
                    if not isinstance(o, Equality)])
            elif cond is not S.false:
                expr_cond.append((i, expr, cond))

        # determine intervals represented by conditions
        int_expr = []
        for iarg, expr, cond in expr_cond:
            if isinstance(cond, And):
                lower = S.NegativeInfinity
                upper = S.Infinity
                for cond2 in cond.args:
                    if isinstance(cond2, Equality):
                        lower = upper  # ignore
                        break
                    elif cond2.lts == sym:
                        upper = Min(cond2.gts, upper)
                    elif cond2.gts == sym:
                        lower = Max(cond2.lts, lower)
                    else:
                        nonsymfail(cond2)  # should never get here
            elif isinstance(cond, Relational):
                lower, upper = cond.lts, cond.gts  # part 1: initialize with givens
                if cond.lts == sym:                # part 1a: expand the side ...
                    lower = S.NegativeInfinity   # e.g. x <= 0 ---> -oo <= 0
                elif cond.gts == sym:            # part 1a: ... that can be expanded
                    upper = S.Infinity           # e.g. x >= 0 --->  oo >= 0
                else:
                    nonsymfail(cond)
            else:
                raise NotImplementedError(
                    'unrecognized condition: %s' % cond)

            lower, upper = lower, Max(lower, upper)
            if (lower >= upper) is not S.true:
                int_expr.append((lower, upper, expr, iarg))

        if default is not None:
            int_expr.append(
                (S.NegativeInfinity, S.Infinity, default, idefault))

        return list(uniq(int_expr))
Ejemplo n.º 56
0
def ordered(seq, keys=None, default=True, warn=False):
    """Return an iterator of the seq where keys are used to break ties in
    a conservative fashion: if, after applying a key, there are no ties
    then no other keys will be computed.

    Two default keys will be applied if 1) keys are not provided or 2) the
    given keys don't resolve all ties (but only if `default` is True). The
    two keys are `_nodes` (which places smaller expressions before large) and
    `default_sort_key` which (if the `sort_key` for an object is defined
    properly) should resolve any ties.

    If ``warn`` is True then an error will be raised if there were no
    keys remaining to break ties. This can be used if it was expected that
    there should be no ties between items that are not identical.

    Examples
    ========

    >>> from sympy.utilities.iterables import ordered
    >>> from sympy import count_ops
    >>> from sympy.abc import x, y

    The count_ops is not sufficient to break ties in this list and the first
    two items appear in their original order (i.e. the sorting is stable):

    >>> list(ordered([y + 2, x + 2, x**2 + y + 3],
    ...    count_ops, default=False, warn=False))
    ...
    [y + 2, x + 2, x**2 + y + 3]

    The default_sort_key allows the tie to be broken:

    >>> list(ordered([y + 2, x + 2, x**2 + y + 3]))
    ...
    [x + 2, y + 2, x**2 + y + 3]

    Here, sequences are sorted by length, then sum:

    >>> seq, keys = [[[1, 2, 1], [0, 3, 1], [1, 1, 3], [2], [1]], [
    ...    lambda x: len(x),
    ...    lambda x: sum(x)]]
    ...
    >>> list(ordered(seq, keys, default=False, warn=False))
    [[1], [2], [1, 2, 1], [0, 3, 1], [1, 1, 3]]

    If ``warn`` is True, an error will be raised if there were not
    enough keys to break ties:

    >>> list(ordered(seq, keys, default=False, warn=True))
    Traceback (most recent call last):
    ...
    ValueError: not enough keys to break ties


    Notes
    =====

    The decorated sort is one of the fastest ways to sort a sequence for
    which special item comparison is desired: the sequence is decorated,
    sorted on the basis of the decoration (e.g. making all letters lower
    case) and then undecorated. If one wants to break ties for items that
    have the same decorated value, a second key can be used. But if the
    second key is expensive to compute then it is inefficient to decorate
    all items with both keys: only those items having identical first key
    values need to be decorated. This function applies keys successively
    only when needed to break ties. By yielding an iterator, use of the
    tie-breaker is delayed as long as possible.

    This function is best used in cases when use of the first key is
    expected to be a good hashing function; if there are no unique hashes
    from application of a key then that key should not have been used. The
    exception, however, is that even if there are many collisions, if the
    first group is small and one does not need to process all items in the
    list then time will not be wasted sorting what one was not interested
    in. For example, if one were looking for the minimum in a list and
    there were several criteria used to define the sort order, then this
    function would be good at returning that quickly if the first group
    of candidates is small relative to the number of items being processed.

    """
    d = defaultdict(list)
    if keys:
        if not isinstance(keys, (list, tuple)):
            keys = [keys]
        keys = list(keys)
        f = keys.pop(0)
        for a in seq:
            d[f(a)].append(a)
    else:
        if not default:
            raise ValueError('if default=False then keys must be provided')
        d[None].extend(seq)

    for k in sorted(d.keys()):
        if len(d[k]) > 1:
            if keys:
                d[k] = ordered(d[k], keys, default, warn)
            elif default:
                d[k] = ordered(d[k], (_nodes, default_sort_key,),
                               default=False, warn=warn)
            elif warn:
                from sympy.utilities.iterables import uniq
                u = list(uniq(d[k]))
                if len(u) > 1:
                    raise ValueError(
                        'not enough keys to break ties: %s' % u)
        for v in d[k]:
            yield v
        d.pop(k)
Ejemplo n.º 57
0
    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()

            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_Power:
                            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_Power 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_Power 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 S.Zero:
            return expr

        if expr.is_Order:
            expr = expr.expr

        if not expr.has(*variables):
            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
Ejemplo n.º 58
0
def test_uniq():
    assert list(uniq(p.copy() for p in partitions(4))) == \
        [{4: 1}, {1: 1, 3: 1}, {2: 2}, {1: 2, 2: 1}, {1: 4}]
    assert list(uniq(x % 2 for x in range(5))) == [0, 1]
    assert list(uniq('a')) == ['a']
    assert list(uniq('ababc')) == list('abc')