Tutorial: Using Free Modules and Vector Spaces <span id="tutorial-using-free-modules"></span> <p>In this tutorial, we show how to construct and manipulate free modules and vector spaces and their elements.</p> <p>Sage currently provides two implementations of free modules: <a href="#id1"><span class="problematic" id="id2">:class:`FreeModule`</span></a> and <a href="#id3"><span class="problematic" id="id4">:class:`CombinatorialFreeModule`</span></a>. The distinction between the two is mostly an accident in history. The later allows for the basis to be indexed by any kind of objects, instead of just $0,1,2,...$. They also differ by feature set and efficiency. Eventually, both implementations will be merged under the name <a href="#id5"><span class="problematic" id="id6">:class:`FreeModule`</span></a>. In the mean time, we focus here on <a href="#id7"><span class="problematic" id="id8">:class:`CombinatorialFreeModule`</span></a>. We recommend to start by browsing the documentation.</p> {{{id=0| CombinatorialFreeModule? /// }}} <p>We begin with a minimal example. What does this give us?</p> {{{id=1| G = Zmod(5) A = CombinatorialFreeModule(ZZ, G) A.an_element() /// 2*B[0] + 2*B[1] + 3*B[2] }}} <p>We can use any set whose elements are immutable to index the basis. Here are some $ZZ$-free modules; what is the indexing set for the basis in each case?</p> <blockquote> sage: A = CombinatorialFreeModule(ZZ, CC); A.an_element() B[1.00000000000000*I] sage: A = CombinatorialFreeModule(ZZ, Partitions(NonNegativeIntegers(), max_part=3)); A.an_element() B[[]] + 2*B[[1]] + 3*B[[2]] sage: A = CombinatorialFreeModule(ZZ, ['spam', 'eggs', 42]); A.an_element() 2*B['eggs'] + 2*B['spam'] + 3*B[42]</blockquote> {{{id=2| A = CombinatorialFreeModule(ZZ, ([1],[2],[3])); A.an_element() /// Traceback (most recent call last): TypeError: unhashable type: 'list' }}} <p>We can customize the name of the basis however we want:</p> {{{id=3| A = CombinatorialFreeModule(ZZ, Zmod(5), prefix='a'); A.an_element() /// a[0] + 3*a[1] + 3*a[2] }}} <p>Let us do some arithmetic with elements of $A$:</p> {{{id=4| f = A.an_element(); f /// a[0] + 3*a[1] + 3*a[2] }}} {{{id=5| 2*f /// 2*a[0] + 6*a[1] + 6*a[2] }}} {{{id=6| 2*f - f /// a[0] + 3*a[1] + 3*a[2] }}} <p>This does not work yet:</p> {{{id=7| a[0] + 3*a[1] /// Traceback (most recent call last): NameError: name 'a' is not defined }}} <p>To construct elements directly, we must first get the basis for the module:</p> {{{id=8| a = A.basis() a[0] + 3*a[1] /// a[0] + 3*a[1] }}} <p>Copy-pasting works if the prefix matches the name of the basis:</p> {{{id=9| a[0] + 3*a[1] + 3*a[2] == f /// True }}} <p>Be careful, that the input is currently <em>not</em> checked:</p> {{{id=10| a['is'] + a['this'] + a['a'] + a['bug'] /// a['a'] + a['bug'] + a['is'] + a['this'] }}} {{{id=11| a /// Lazy family (Term map from Ring of integers modulo 5 to Free module generated by Ring of integers modulo 5 over Integer Ring(i))_{i in Ring of integers modulo 5} }}} <p><tt class="docutils literal"><span class="pre">A.basis()</span></tt> models the family $(B_i)_{i in ZZ_5}$. See the documentation for <a href="#id9"><span class="problematic" id="id10">:class:`Family`</span></a> for more information:</p> {{{id=12| Family? /// }}} <p>The elements of our module come with many methods for exploring and manipulating them:</p> <!-- skip: --> {{{id=13| f. /// }}} <p>Some notation:</p> <blockquote> <ul> <li><p class="first"><em>term</em>: <tt class="docutils literal"><span class="pre">coefficient</span> <span class="pre">*</span> <span class="pre">basis_element</span></tt></p> </li> <li><p class="first"><em>monomial</em>: <tt class="docutils literal"><span class="pre">basis_element</span></tt> <em>without</em> a coefficient</p> </li> <li><p class="first"><em>support</em>: the index of a <tt class="docutils literal"><span class="pre">basis_element</span></tt></p> </li> <li><p class="first"><em>item</em> : a <a href="#id11"><span class="problematic" id="id12">:class:`tuple`</span></a> <tt class="docutils literal"><span class="pre">(index,</span> <span class="pre">coefficient)</span></tt></p> </li> </ul> </blockquote> <p>Note that elements are printed starting with the <em>least</em> index (for lexicographic order by default). Leading/trailing refers to the greatest/least index, respectively:</p> {{{id=14| f /// a[0] + 3*a[1] + 3*a[2] }}} {{{id=15| "Leading term: ",f.leading_term() /// Leading term: 3*a[2] }}} {{{id=16| print "Leading monomial: ",f.leading_monomial() /// Leading monomial: a[2] }}} {{{id=17| print "Leading support: ",f.leading_support() /// Leading support: 2 }}} {{{id=18| print "Leading coefficient: ",f.leading_coefficient() /// Leading coefficient: 3 }}} {{{id=19| print "Leading item: ",f.leading_item() /// Leading item: (2, 3) }}} {{{id=20| f.leading_term print "Support: ",f.support() /// Support: [0, 1, 2] }}} {{{id=21| print "Monomials: ",f.monomials() /// Monomials: [a[0], a[1], a[2]] }}} {{{id=22| print "Coefficients: ",f.coefficients() /// Coefficients: [1, 3, 3] }}} <p>We can iterate through the items in an element:</p> {{{id=23| for index, coeff in f: print "The coefficient of a_{%s} is %s"%(index, coeff) /// The coefficient of a_{0} is 1The coefficient of a_{1} is 3The coefficient of a_{2} is 3 }}} {{{id=24| # This uses the fact that f can be thought of as a dictionary index-->coefficient print f[0], f[1], f[2] /// 1 3 3 }}} {{{id=25| # This dictionary can be accessed explicitly with the monomial_coefficients method f.monomial_coefficients() /// {0: 1, 1: 3, 2: 3} }}} <p>The parent ($A$ in our example) has several utility methods for constructing elements:</p> {{{id=26| A. A.zero() /// 0 }}} {{{id=27| A.sum_of_monomials(i for i in Zmod(5) if i > 2) /// a[3] + a[4] }}} {{{id=28| A.sum_of_terms((i+1,i) for i in Zmod(5) if i > 2) /// 4*a[0] + 3*a[4] }}} {{{id=29| A.sum(ZZ(i)*a[i+1] for i in Zmod(5) if i > 2) # Note coeff is not (currently) implicitly coerced /// 4*a[0] + 3*a[4] }}} <p>Note that it is safer to use <tt class="docutils literal"><span class="pre">A.sum()</span></tt> than to use <tt class="docutils literal"><span class="pre">sum()</span></tt>, in case the input is an empty iterable:</p> {{{id=30| print A.sum([]),':', parent(A.sum([])) /// 0 : Free module generated by Ring of integers modulo 5 over Integer Ring }}} {{{id=31| print sum([]),':', parent(sum([])) /// 0 : <type 'int'> }}} <p>The <tt class="docutils literal"><span class="pre">map</span></tt> methods are useful to transform elements:</p> {{{id=32| f.map_ print f,"-->", f.map_support (lambda i : i+3) /// a[0] + 3*a[1] + 3*a[2] --> 3*a[0] + a[3] + 3*a[4] }}} {{{id=33| print f,"-->", f.map_coefficients(lambda c : c-1) /// a[0] + 3*a[1] + 3*a[2] --> 2*a[1] + 2*a[2] }}} {{{id=34| print f,"-->", f.map_term (lambda i,c: (i+3,c-1)) /// a[0] + 3*a[1] + 3*a[2] --> 2*a[0] + 2*a[4] }}} <p><tt class="docutils literal"><span class="pre">f.map_mc</span></tt> is a deprecated synonym for <tt class="docutils literal"><span class="pre">f.map_term</span></tt>.</p> <p>Note that <tt class="docutils literal"><span class="pre">term</span></tt> and <tt class="docutils literal"><span class="pre">item</span></tt> are not yet used completely consistently.</p>