Python and Cython
system:sage


<p style="text-align: center;"><span style="font-size: x-large;">Python</span></p>
<p style="text-align: left;"><span style="font-size: large;">1. List Comprehensions</span></p>
<p style="text-align: left;"><span style="font-size: medium;">First, a list is defined by square brackets and can contain anything:</span></p>

{{{id=11|
[1, PolynomialRing(QQ,2,'x,y'), 'a string']
///
[1, Multivariate Polynomial Ring in x, y over Rational Field, 'a string']
}}}

{{{id=13|
primes20 = primes_first_n(20)
primes20
///
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71]
}}}

<p>List comprehensions make new lists from old. For example, the squares of the entries:</p>

{{{id=14|
[i^2 for i in primes20]
///
[4, 9, 25, 49, 121, 169, 289, 361, 529, 841, 961, 1369, 1681, 1849, 2209, 2809, 3481, 3721, 4489, 5041]
}}}

<p>List comprehensions are usually more readable than the equivalent functional programming:</p>

{{{id=32|
map(lambda i:i^2, primes20)
///
[4, 9, 25, 49, 121, 169, 289, 361, 529, 841, 961, 1369, 1681, 1849, 2209, 2809, 3481, 3721, 4489, 5041]
}}}

<p>The "if" clause lets you use only some list elements:</p>

{{{id=16|
[p for i,p in enumerate(primes_first_20) if i%2 == 0]
///
[2, 5, 11, 17, 23, 31, 41, 47, 59, 67]
}}}

{{{id=17|
primes_first_20[0::2]    # can also be done with the slicing operator
///
[2, 5, 11, 17, 23, 31, 41, 47, 59, 67]
}}}

<p><span style="font-size: large;">2. Flow Control</span></p>
<p>I'll just mention the for loop. Note that blocks are marked by indentation!</p>

{{{id=19|
for i in range(0,10):
    temporary_variable = 1
    print 'i = '+str(i)
print 'End of loop'
///
i = 0
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9
End of loop
}}}

<p><span style="font-size: large;">3. Functions</span></p>

{{{id=22|
def hello_world():
    print 'Hello, World!'
///
}}}

{{{id=24|
hello_world()
///
Hello, World!
}}}

<p><span style="font-size: large;">4. Classes</span></p>

{{{id=23|
class Foo(object):
    def bar(self):
        print('method bar() of class Foo.')
    j = 1    # data member
///
}}}

{{{id=26|
x = Foo()
x
///
<__main__.Foo object at 0x5745490>
}}}

{{{id=27|
x.bar()
///
method bar() of class Foo.
}}}

{{{id=28|
x.j
///
1
}}}

<ul>
<li>Use tab-completion to discover attributes of objects</li>
<li>Questionmark at the end -&gt; online help</li>
<li>Two questionmarks -&gt; show source</li>
</ul>

{{{id=44|
p = 5
///
}}}

{{{id=43|
p.is_prime?
///
<html><!--notruncate-->

<div class="docstring">
    
  <p><strong>File:</strong> /home/vbraun/Code/sage.git/src/sage/rings/integer.pyx</p>
<p><strong>Type:</strong> &lt;type &#8216;builtin_function_or_method&#8217;&gt;</p>
<p><strong>Definition:</strong> p.is_prime(proof=None)</p>
<p><strong>Docstring:</strong></p>
<blockquote>
<div><p>Returns <tt class="docutils literal"><span class="pre">True</span></tt> if <tt class="docutils literal"><span class="pre">self</span></tt> is prime.</p>
<p>INPUT:</p>
<ul class="simple">
<li><tt class="docutils literal"><span class="pre">proof</span></tt> &#8211; If False, use a strong pseudo-primality test.
If True, use a provable primality test.  If unset, use the
default arithmetic proof flag.</li>
</ul>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">Integer primes are by definition <em>positive</em>! This is
different than Magma, but the same as in PARI. See also the
<tt class="xref py py-meth docutils literal"><span class="pre">is_irreducible()</span></tt> method.</p>
</div>
<p>EXAMPLES:</p>
<div class="highlight-python"><div class="highlight"><pre class="literal-block"><span class="gp">sage: </span><span class="n">z</span> <span class="o">=</span> <span class="mi">2</span><span class="o">^</span><span class="mi">31</span> <span class="o">-</span> <span class="mi">1</span>
<span class="gp">sage: </span><span class="n">z</span><span class="o">.</span><span class="n">is_prime</span><span class="p">()</span>
<span class="go">True</span>
<span class="gp">sage: </span><span class="n">z</span> <span class="o">=</span> <span class="mi">2</span><span class="o">^</span><span class="mi">31</span>
<span class="gp">sage: </span><span class="n">z</span><span class="o">.</span><span class="n">is_prime</span><span class="p">()</span>
<span class="go">False</span>
<span class="gp">sage: </span><span class="n">z</span> <span class="o">=</span> <span class="mi">7</span>
<span class="gp">sage: </span><span class="n">z</span><span class="o">.</span><span class="n">is_prime</span><span class="p">()</span>
<span class="go">True</span>
<span class="gp">sage: </span><span class="n">z</span> <span class="o">=</span> <span class="o">-</span><span class="mi">7</span>
<span class="gp">sage: </span><span class="n">z</span><span class="o">.</span><span class="n">is_prime</span><span class="p">()</span>
<span class="go">False</span>
<span class="gp">sage: </span><span class="n">z</span><span class="o">.</span><span class="n">is_irreducible</span><span class="p">()</span>
<span class="go">True</span>
</pre></div>
</div>
<div class="highlight-python"><div class="highlight"><pre class="literal-block"><span class="gp">sage: </span><span class="n">z</span> <span class="o">=</span> <span class="mi">10</span><span class="o">^</span><span class="mi">80</span> <span class="o">+</span> <span class="mi">129</span>
<span class="gp">sage: </span><span class="n">z</span><span class="o">.</span><span class="n">is_prime</span><span class="p">(</span><span class="n">proof</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="go">True</span>
<span class="gp">sage: </span><span class="n">z</span><span class="o">.</span><span class="n">is_prime</span><span class="p">(</span><span class="n">proof</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="go">True</span>
</pre></div>
</div>
<p>IMPLEMENTATION: Calls the PARI <tt class="docutils literal"><span class="pre">isprime</span></tt> function.</p>
</div></blockquote>


</div>
</html>
}}}

<p><span style="font-size: large;">5. Inheritance</span></p>

{{{id=38|
class Derived(Foo):
    def __init__(self, i):
        self.i = i
///
}}}

{{{id=37|
y = Derived(123)
y
///
<__main__.Derived object at 0x5745390>
}}}

{{{id=36|
y.i, y.j
///
(123, 1)
}}}

{{{id=35|
y.bar()
///
method bar() of class Foo.
}}}

<p><span style="font-size: large;">6. Mutability and Immutability</span></p>
<p><span style="font-size: medium;">Variables are labels for objects</span></p>

{{{id=46|
x = [1, 2, 3]
y = x
x[1] = 'changed'
print(y)
///
[1, 'changed', 3]
}}}

<p>A tuple is like a list but immutable</p>

{{{id=49|
x = (1, 2, 3)     # equivalent to x = tuple([1, 2, 3])
y = x
x[1] = 'changed'
///
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "_sage_input_41.py", line 10, in <module>
    exec compile(u'open("___code___.py","w").write("# -*- coding: utf-8 -*-\\n" + _support_.preparse_worksheet_cell(base64.b64decode("eCA9IHR1cGxlKFsxLCAyLCAzXSkKeSA9IHgKeFsxXSA9ICdjaGFuZ2VkJw=="),globals())+"\\n"); execfile(os.path.abspath("___code___.py"))' + '\n', '', 'single')
  File "", line 1, in <module>
    
  File "/tmp/tmpltOuXs/___code___.py", line 5, in <module>
    exec compile(u"x[_sage_const_1 ] = 'changed'" + '\n', '', 'single')
  File "", line 1, in <module>
    
TypeError: 'tuple' object does not support item assignment
}}}

<p>If you are writing a class, it is up to you to decide if it has a mutable or immutable interface. Sage sometimes implements both:</p>

{{{id=51|
v = vector(ZZ, [1, 2, 3])
v[2] = 5
v
///
(1, 2, 5)
}}}

{{{id=53|
v.is_immutable()
///
False
}}}

{{{id=54|
v.set_immutable()
v[2] = 2
///
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "_sage_input_44.py", line 10, in <module>
    exec compile(u'open("___code___.py","w").write("# -*- coding: utf-8 -*-\\n" + _support_.preparse_worksheet_cell(base64.b64decode("di5zZXRfaW1tdXRhYmxlKCkKdlsyXSA9IDI="),globals())+"\\n"); execfile(os.path.abspath("___code___.py"))' + '\n', '', 'single')
  File "", line 1, in <module>
    
  File "/tmp/tmpAtPzoW/___code___.py", line 4, in <module>
    exec compile(u'v[_sage_const_2 ] = _sage_const_2 ' + '\n', '', 'single')
  File "", line 1, in <module>
    
  File "vector_integer_dense.pyx", line 185, in sage.modules.vector_integer_dense.Vector_integer_dense.__setitem__ (sage/modules/vector_integer_dense.c:3624)
ValueError: vector is immutable; please change a copy instead (use copy())
}}}

<p style="text-align: center;"><span style="font-size: x-large;">Sage Extensions</span></p>
<p>There are a few Magma-inspired language extensions to Python</p>

{{{id=68|
R.<x, y> = QQ[]
R
///
Multivariate Polynomial Ring in x, y over Rational Field
}}}

<p>is equivalent to the Python commands</p>

{{{id=66|
R = PolynomialRing(QQ, 2, names='x, y')
R.inject_variables()
R
///
Defining x, y
Multivariate Polynomial Ring in x, y over Rational Field
}}}

{{{id=71|
%python
1/2    # division in Python is C division
///
0
}}}

{{{id=72|
1/2
///
1/2
}}}

<p style="text-align: center;"><span style="font-size: x-large;">Cython</span></p>
<p style="text-align: left;"><span style="font-size: large;">1. Speeding up Python</span></p>
<p style="text-align: left;"><span style="font-size: medium;">Here is a simple Python function:</span></p>

{{{id=2|
def python_sum_0_99():
    s = 0
    for i in range(0,100):
        s += i
    return s

python_sum_0_99()
///
4950
}}}

<p>The <span style="font-family: 'courier new', courier;">%cython</span> magic tells the worksheet that the cell contains Cython code:</p>

{{{id=1|
%cython
def cython_sum_0_99():
    cdef int i, s
    s = 0
    for i in range(0,100):
        s += i
    return s
///
}}}

<p>Finally, we compare the two versions:</p>

{{{id=3|
timeit('python_sum_0_99()')
///
625 loops, best of 3: 108 µs per loop
}}}

{{{id=4|
timeit('cython_sum_0_99()')
///
625 loops, best of 3: 89.6 ns per loop
}}}

<p><span style="font-size: large;">2. Interface with C libraries</span></p>

{{{id=5|
%cython
cdef extern from "math.h":
    double modf(double value, double* iptr)
    
def py_modf(x):
    cdef double iptr
    cdef double result = modf(x, &iptr)
    return (result, iptr)
///
}}}

{{{id=56|
py_modf(pi)
///
(0.14159265358979312, 3.0)
}}}

<p><span style="font-size: large;">3. The C++ standard library</span></p>

{{{id=61|
%cython
#clang c++

from libcpp.vector cimport vector

def using_vector(data):
    cdef vector[int] v
    for x in data:
        v.push_back(x)
    return v.size()
///
}}}

{{{id=63|
using_vector([1, 3, 5])
///
3
}}}

<p><span style="font-size: large;">4. Wrapping C++ Code</span></p>

{{{id=58|

///
}}}

{{{id=73|

///
}}}

{{{id=74|

///
}}}

{{{id=75|

///
}}}