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|
&quot;Leading term: &quot;,f.leading_term()
///
Leading term:  3*a[2]
}}}

{{{id=16|
print &quot;Leading monomial: &quot;,f.leading_monomial()
///
Leading monomial:  a[2]
}}}

{{{id=17|
print &quot;Leading support: &quot;,f.leading_support()
///
Leading support:  2
}}}

{{{id=18|
print &quot;Leading coefficient: &quot;,f.leading_coefficient()
///
Leading coefficient:  3
}}}

{{{id=19|
print &quot;Leading item: &quot;,f.leading_item()
///
Leading item:  (2, 3)
}}}

{{{id=20|
f.leading_term
print &quot;Support: &quot;,f.support()
///
Support:  [0, 1, 2]
}}}

{{{id=21|
print &quot;Monomials: &quot;,f.monomials()
///
Monomials:  [a[0], a[1], a[2]]
}}}

{{{id=22|
print &quot;Coefficients: &quot;,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 &quot;The coefficient of a_{%s} is %s&quot;%(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--&gt;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 &gt; 2)
///
a[3] + a[4]
}}}

{{{id=28|
A.sum_of_terms((i+1,i) for i in Zmod(5) if i &gt; 2)
///
4*a[0] + 3*a[4]
}}}

{{{id=29|
A.sum(ZZ(i)*a[i+1] for i in Zmod(5) if i &gt; 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,&quot;--&gt;&quot;, 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,&quot;--&gt;&quot;, 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,&quot;--&gt;&quot;, 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>