{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Number Theory with Sympy's Sieve\n", "\n", "An infinite list of prime numbers, implemented as a dynamically growing sieve of Eratosthenes. When a lookup is requested involving an odd number that has not been sieved, the sieve is automatically extended up to that number." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": true }, "outputs": [], "source": [ "from sympy import sieve" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sieve._reset()\n", "25 in sieve" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array('l', [2, 3, 5, 7, 11, 13, 17, 19, 23])" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sieve._list" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Grow the sieve to cover all primes <= n\n", "sieve._reset()\n", "sieve.extend(30)\n", "sieve[10] == 28" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sieve[10] == 29" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sieve[10] == 23" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array('l', [2, 3, 5, 7, 11, 13, 17, 19, 23])" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Extend to include the ith prime number\n", "sieve._reset()\n", "sieve.extend_to_no(9)\n", "sieve._list" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[7, 11, 13, 17, 19]\n" ] } ], "source": [ "# $primerange(a,b)$\n", "\n", "print([i for i in sieve.primerange(7, 23)])" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(9, 10)" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Search = returns the indice i, j of the primes that bound n\n", "#if n is prime then i = j\n", "\n", "sieve.search(25)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(9, 9)" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sieve.search(23)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "29" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Prime\n", "# Return the nth prime, with the primes indexed as prime(1) = 2, prime(2) = 3, etc…. \n", "# The nth prime is approximately n*log(n).\n", "from sympy import prime\n", "prime(10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Primes " ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "prime(1)" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CPU times: user 3 µs, sys: 0 ns, total: 3 µs\n", "Wall time: 6.91 µs\n" ] }, { "data": { "text/plain": [ "15485863" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "%time\n", "prime(1000000)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "9" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# primepi(n) - gives n number of primes\n", "\n", "from sympy import primepi\n", "primepi(25)" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CPU times: user 3 µs, sys: 0 ns, total: 3 µs\n", "Wall time: 6.91 µs\n" ] }, { "data": { "text/plain": [ "78498" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "%time\n", "primepi(1000000)" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[(10, 11), (11, 13), (12, 13), (13, 17), (14, 17)]" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from sympy import nextprime\n", "[(i, nextprime(i)) for i in range(10, 15)]" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[(10, 7), (11, 7), (12, 11), (13, 11), (14, 13)]" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from sympy import prevprime\n", "[(i, prevprime(i)) for i in range(10, 15)]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Prime Ranges\n", "\n", "Some famous conjectures about the occurence of primes in a given range are [1]:\n", "\n", "**Twin primes**: though often not, the following will give 2 primes\n", "an infinite number of times:\n", "primerange(6*n - 1, 6*n + 2)\n", "\n", "**Legendre’s**: the following always yields at least one prime\n", "`primerange(n**2, (n+1)**2+1)`\n", "\n", "**Bertrand’s (proven)**: there is always a prime in the range\n", "`primerange(n, 2*n)`\n", "\n", "**Brocard’s**: there are at least four primes in the range\n", "`primerange(prime(n)**2, prime(n+1)**2)`\n", "\n", "The average gap between primes is log(n) [2]; the gap between primes can be arbitrarily large since sequences of composite numbers are arbitrarily large, e.g. the numbers in the sequence `n! + 2, n! + 3 … n! + n` are all composite." ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]\n" ] } ], "source": [ "from sympy import primerange, sieve\n", "print([i for i in primerange(1, 30)])" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "list(sieve.primerange(1, 30))" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "19" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# randprime\n", "from sympy import randprime, isprime\n", "randprime(1, 30)" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "isprime(randprime(1, 30))" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2310" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# This returns the product of the first n primes or teh primes <= n (when nth=False)\n", "from sympy.ntheory.generate import primorial, randprime, primerange\n", "from sympy import factorint, Mul, primefactors, sqrt\n", "primorial(5) # product of 2, 3, 5, 7, 11" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2310" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "2*3*5*7*11" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "6" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "primorial(2)" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "6" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "primorial(3, nth=False) # primes <= 3 are 2 and 3" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "30" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "primorial(5, nth=False) # product of 2*3*5" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "210" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "primorial(sqrt(100), nth=False)" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{2309: 1}" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Adding or subtracting by 1 of a primorial product gives you a prime\n", "factorint(primorial(5) - 1)" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{61: 1, 8369: 1}" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# here we get two new primes that are factors\n", "factorint(primorial(7) - 1)" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[2, 5, 31, 149]" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Some primes smaller and larger than the primes multiplied together\n", "p = list(primerange(10, 20))\n", "sorted(set(primefactors(Mul(*p) + 1)).difference(set(p)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### cycle_length\n", "\n", "$cycle_length(f, x0, nmax=None, values=False)$\n", "\n", "For a given iterated sequence, return a generator that gives the length of the iterated cycle (lambda) and the length of terms before the cycle begins (mu); if values is True then the terms of the sequence will be returned instead. The sequence is started with value x0.\n", "\n", "Note: more than the first lambda + mu terms may be returned and this is the cost of cycle detection with Brent’s method; there are, however, generally less terms calculated than would have been calculated if the proper ending point were determined, e.g. by using Floyd’s method." ] }, { "cell_type": "code", "execution_count": 42, "metadata": { "collapsed": true }, "outputs": [], "source": [ "from sympy.ntheory.generate import cycle_length # will give succesive values of i <- func(i)\n" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [], "source": [ "def iter(func, i):\n", " while 1:\n", " ii = func(1)\n", " yield ii\n", " i = ii\n", "# give a seed of 4 and the mu and lambda terms\n", "func = lambda i: (i**2 + 1) % 51" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(6, 2)" ] }, "execution_count": 50, "metadata": {}, "output_type": "execute_result" } ], "source": [ "next(cycle_length(func, 4))" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[17, 35, 2, 5, 26, 14, 44, 50, 2, 5, 26, 14]" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "n = cycle_length(func, 4, values=True)\n", "list(ni for ni in n)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### composite(nth)\n", "\n", "Return the nth composite number, with the composite numbers indexed as composite(1) = 4, composite(2) = 6, etc…. " ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "36" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from sympy import composite\n", "composite(24)" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "composite(1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### compositepi" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "11" ] }, "execution_count": 58, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from sympy import compositepi\n", "compositepi(20)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### smoothness_p(n, m=-1, power=0, visual=None)\n", "\n", "Return a list of $[m, (p, (M, sm(p + m), psm(p + m)))…]$ where:\n", "\n", "1. $p**M$ is the base-p divisor of n\n", "2. $sm(p + m)$ is the smoothness of $p + m (m = -1 by default)$\n", "3. $psm(p + m)$ is the power smoothness of $p + m$\n", "\n", "The list is sorted according to smoothness (default) or by power smoothness if power=1.\n", "\n", "The smoothness of the numbers to the left (m = -1) or right (m = 1) of a factor govern the results that are obtained from the p +/- 1 type factoring methods." ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(1, [(5, (1, 3, 3)), (2069, (1, 23, 23))])" ] }, "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from sympy.ntheory.factor_ import smoothness_p, factorint\n", "smoothness_p(10345, m=1)" ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(-1, [(5, (1, 2, 4)), (2069, (1, 47, 47))])" ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "smoothness_p(10345)" ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(-1, [(5, (1, 2, 4)), (2069, (1, 47, 47))])" ] }, "execution_count": 61, "metadata": {}, "output_type": "execute_result" } ], "source": [ "smoothness_p(10345, power=1)" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "p**i=2**1 has p-1 B=1, B-pow=1\n", "p**i=172278288338939**1 has p-1 B=18836462753, B-pow=18836462753\n" ] } ], "source": [ "print(smoothness_p(344556576677878, visual=1))" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{3: 1, 5: 1, 11: 1}" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "factorint(15*11)" ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'p**i=3**1 has p-1 B=2, B-pow=2\\np**i=5**1 has p-1 B=2, B-pow=4\\np**i=11**1 has p-1 B=5, B-pow=5'" ] }, "execution_count": 67, "metadata": {}, "output_type": "execute_result" } ], "source": [ "smoothness_p(_)" ] }, { "cell_type": "code", "execution_count": 68, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{3: 1, 5: 1, 11: 1}" ] }, "execution_count": 68, "metadata": {}, "output_type": "execute_result" } ], "source": [ "smoothness_p(_)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Table for output logic is like this\n", "\n", "#### Visual\n", "\n", "| Input | True | False | Other |\n", "|---------------|-------------|-------------|-------------|\n", "| ``str`` |``str`` |``tuple`` |``str`` |\n", "| ``str`` |``str`` |``tuple`` |``dict`` |\n", "| ``tuple`` |``str`` |``tuple`` |``str`` |\n", "| ``n`` |``str`` |``tuple`` |``tuple`` |\n", "| ``mul`` |``str`` |``tuple`` |``tuple`` |" ] }, { "cell_type": "code", "execution_count": 69, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "7" ] }, "execution_count": 69, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# training(n)\n", "# Count the number of trailing zero digits in the binary representation of n, \n", "# i.e. determine the largest power of 2 that divides n.\n", "from sympy import trailing\n", "trailing(128)" ] }, { "cell_type": "code", "execution_count": 70, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0" ] }, "execution_count": 70, "metadata": {}, "output_type": "execute_result" } ], "source": [ "trailing(51)" ] }, { "cell_type": "code", "execution_count": 71, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, 1, 2, 3, 3]" ] }, "execution_count": 71, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# multiplicity\n", "# Find the greatest integer m such that p**m divides n.\n", "from sympy.ntheory import multiplicity\n", "from sympy.core.numbers import Rational as R\n", "[multiplicity(5, n) for n in [8, 5, 25, 125, 250]]" ] }, { "cell_type": "code", "execution_count": 72, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "-2" ] }, "execution_count": 72, "metadata": {}, "output_type": "execute_result" } ], "source": [ "multiplicity(3, R(1, 9))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### sympy.ntheory.factor_.perfect_power\n", "\n", "sympy.ntheory.factor_.perfect_power(n, candidates=None, big=True, factor=True)\n", "\n", "Return `(b, e)` such that `n == b**e` if n is a perfect power; otherwise return False.\n", "\n", "By default, the base is recursively decomposed and the exponents collected so the largest possible e is sought. If big=False then the smallest possible e (thus prime) will be chosen.\n", "\n", "If `candidates` for exponents are given, they are assumed to be sorted and the first one that is larger than the computed maximum will signal failure for the routine.\n", "\n", "If `factor=True` then simultaneous factorization of n is attempted since finding a factor indicates the only possible root for n. This is True by default since only a few small factors will be tested in the course of searching for the perfect power.\n", "\n" ] }, { "cell_type": "code", "execution_count": 73, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(2, 4)" ] }, "execution_count": 73, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from sympy import perfect_power\n", "perfect_power(16)" ] }, { "cell_type": "code", "execution_count": 74, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(5, 2)" ] }, "execution_count": 74, "metadata": {}, "output_type": "execute_result" } ], "source": [ "perfect_power(25, big=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Pollard_rho\n", "\n", "Use Pollard’s rho method to try to extract a nontrivial factor of n. The returned factor may be a composite number. If no factor is found, None is returned.\n", "\n", "The algorithm generates pseudo-random values of x with a generator function, replacing x with F(x). If F is not supplied then the function x**2 + a is used. The first value supplied to F(x) is s. Upon failure (if retries is > 0) a new a and s will be supplied; the a will be ignored if F was supplied.\n", "\n", "The sequence of numbers generated by such functions generally have a a lead-up to some number and then loop around back to that number and begin to repeat the sequence, e.g. 1, 2, 3, 4, 5, 3, 4, 5 – this leader and loop look a bit like the Greek letter rho, and thus the name, ‘rho’.\n", "\n", "For a given function, very different leader-loop values can be obtained so it is a good idea to allow for retries:" ] }, { "cell_type": "code", "execution_count": 79, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "loop length = 660; leader length = 19\n", "loop length = 660; leader length = 19\n", "loop length = 120; leader length = 26\n", "loop length = 660; leader length = 6\n", "loop length = 660; leader length = 17\n" ] } ], "source": [ "from sympy.ntheory.generate import cycle_length\n", "n = 14345656\n", "F = lambda x:(2048*pow(x, 2, n) + 32767) % n\n", "for s in range(5):\n", " print('loop length = %4i; leader length = %3i' % next(cycle_length(F, s)))" ] }, { "cell_type": "code", "execution_count": 78, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "16\n", "13\n", "11\n", "14\n", "4\n", "11\n", "14\n", "4\n", "11\n" ] } ], "source": [ "# An explicit example where there is a two element leadup to a seq of 3 numbers\n", "x = 2\n", "for i in range(9):\n", " x = (x**2 + 12)%17\n", " print(x)" ] }, { "cell_type": "code", "execution_count": 80, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(3, 2)" ] }, "execution_count": 80, "metadata": {}, "output_type": "execute_result" } ], "source": [ "next(cycle_length(lambda x:(x**2+12)%17, 2))" ] }, { "cell_type": "code", "execution_count": 81, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[16, 13, 11, 14, 4]" ] }, "execution_count": 81, "metadata": {}, "output_type": "execute_result" } ], "source": [ "list(cycle_length(lambda x: (x**2+12)%17, 2, values=True))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Note\n", "\n", "Instead of checking the differences of all generated values for a gcd with n, only the $kth$ and $2*kth$ numbers are checked, e.g. 1st and 2nd, 2nd and 4th, 3rd and 6th until it has been detected that the loop has been traversed. Loops may be many thousands of steps long before rho finds a factor or reports failure. If max_steps is specified, the iteration is cancelled with a failure after the specified number of steps." ] }, { "cell_type": "code", "execution_count": 82, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "8" ] }, "execution_count": 82, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from sympy import pollard_rho\n", "n = 14345656\n", "F = lambda x:(2048*pow(x,2,n) + 32767) % n\n", "pollard_rho(n, F=F)" ] }, { "cell_type": "code", "execution_count": 83, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "8" ] }, "execution_count": 83, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pollard_rho(n, a=n-2, retries=1)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.1" } }, "nbformat": 4, "nbformat_minor": 2 }