Tutorial: Using Free Modules and Vector Spaces

<span id="tutorial-using-free-modules"></span>

<table class="docinfo" frame="void" rules="none">
<col class="docinfo-name">
<col class="docinfo-content">
<tbody valign="top">
<tr><th class="docinfo-name">Author:</th>
<td>Jason Bandlow</td></tr>
</tbody>
</table>
<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:
<tt class="docutils literal">FreeModule</tt> and <tt class="docutils literal">CombinatorialFreeModule`</tt>. 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 <tt class="docutils literal">FreeModule</tt>. In the mean time, we focus here on
<tt class="docutils literal">CombinatorialFreeModule</tt>. 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()
///
B[0] + 3*B[1] + 3*B[2]
}}}

<p>We can use any set whose elements are immutable to index the
basis. Here is the $\mathbb{Z}$ free module whose basis is indexed by complex
numbers:</p>

{{{id=2|
A = CombinatorialFreeModule(ZZ, CC); A.an_element()
///
B[1.00000000000000*I]
}}}

{{{id=3|
A = CombinatorialFreeModule(ZZ, Partitions(NonNegativeIntegers(), max_part=3)); A.an_element()
///
B[[]] + 2*B[[1]] + 3*B[[2]]
}}}

{{{id=4|
A = CombinatorialFreeModule(ZZ, ['spam', 'eggs', 42]); A.an_element()
///
2*B['eggs'] + 2*B['spam'] + 3*B[42]
}}}

{{{id=5|
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=6|
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=7|
f = A.an_element(); f
///
a[0] + 3*a[1] + 3*a[2]
}}}

{{{id=8|
2*f
///
2*a[0] + 6*a[1] + 6*a[2]
}}}

{{{id=9|
2*f - f
///
a[0] + 3*a[1] + 3*a[2]
}}}

{{{id=10|
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=11|
a = A.basis()
a[0] + 3*a[1]
///
a[0] + 3*a[1]
}}}

<p>copy-paste works if the prefix matches the name of the basis:</p>

{{{id=12|
a[0] + 3*a[1] + 3*a[2] == f
///
True
}}}

<p>Be careful, that the input is currently <em>not</em> checked:</p>

{{{id=13|
a['is'] + a['this'] + a['a'] + a['bug']
///
a['a'] + a['bug'] + a['is'] + a['this']
}}}

{{{id=14|
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">A.basis()</tt> models the family $(B_i)_{i \in \mathbb{Z}}$.  See the
documentation for <tt class="docutils literal">Family</tt> for more information:</p>

{{{id=15|
Family?
///
}}}

<p>The elements of our module come with many methods for
exploring and manipulating them:</p>

{{{id=16|
f.
///
}}}

<p>Some notation:</p>
<blockquote>
<ul class="simple">
<li><em>term</em>: <tt class="docutils literal">coefficient * basis_element</tt></li>
<li><em>monomial</em>: <tt class="docutils literal">basis_element</tt> <em>without</em> a coefficient</li>
<li><em>support</em>: the index of a <tt class="docutils literal">basis_element</tt></li>
<li><em>item</em> : a <tt class="docutils literal">tuple</tt> <tt class="docutils literal">(index, coefficient)</tt></li>
</ul>
</blockquote>
<p>Note that elements are printed starting with the (lexicographically by
default) <em>least</em> index. Leading/trailing refers to the greatest/least
index, respectively:</p>

{{{id=17|
f
///
a[0] + 3*a[1] + 3*a[2]
}}}

{{{id=18|
&quot;Leading term: &quot;,f.leading_term()
///
Leading term:  3*a[2]
}}}

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

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

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

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

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

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

{{{id=25|
print &quot;Coefficients: &quot;,f.coefficients()
///
Coefficients:  [1, 3, 3]
}}}

<p>We can iterate through the items in an element:</p>

{{{id=26|
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=27|
# 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=28|
# 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=29|
A.
A.zero()
///
0
}}}

{{{id=30|
A.sum_of_monomials(i for i in Zmod(5) if i &gt; 2)
///
a[3] + a[4]
}}}

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

{{{id=32|
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">A.sum()</tt> then to use <tt class="docutils literal">sum()</tt>, in
case the input is an empty iterable:</p>

{{{id=33|
print A.sum([]),':', parent(A.sum([]))
///
0 : Free module generated by Ring of integers modulo 5 over Integer Ring
}}}

{{{id=34|
print sum([]),':', parent(sum([]))
///
0 : <type 'int'>
}}}

<p>The <tt class="docutils literal">map</tt> methods are useful ways to transform elements:</p>

{{{id=35|
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=36|
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=37|
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">f.map_mc</tt> is a deprecated synonym for <tt class="docutils literal">f.map_term</tt>.</p>
<p>Note that <tt class="docutils literal">term</tt> and <tt class="docutils literal">item</tt> are not yet used completely consistently.</p>
<p>This fully functional $\mathbb{Z}$-module was created with the simple commands:</p>

{{{id=38|
A = CombinatorialFreeModule(ZZ, Zmod(5), prefix='a')
a = A.basis()
///
}}}

