This repository contains the course materials from Math 157: Intro to Mathematical Software.
Creative Commons BY-SA 4.0 license.
License: OTHER
January 31, 2018: Linear algebra (part 2 of 2)
Math 157: Intro to Mathematical Software
UC San Diego, winter 2018
Administrivia:
Please fill out the week 4 questionnaire.
We are continuing to monitor the course waitlist. If you are on it and still want to join the course, please continue to keep up with lectures and homework, and watch your email for further instructions.
Here is a more precise link for the documentary screening next Monday that I mentioned last time.
Octave from Sage
So far we have seen Octave and Sage being accessed from a Jupyter notebook by switching kernels back and forth. However, this approach does not allow for any communication between the two kernels: all state is lost when one switches the kernel from Sage to Octave or vice versa.
It was asked whether there is a way to combine the functionality of the two kernels. The answer is yes, in one direction: Sage can call into Octave, but not vice versa. Some examples from the reference manual:
Vector spaces
So far we have been talking about linear algebra solely in terms of matrices. However, Sage can also handle the language of vector spaces, as long as we are talking about subspaces of a "standard" vector space over some field.
---------------------------------------------------------------------------
ArithmeticError Traceback (most recent call last)
<ipython-input-42-eff670de8383> in <module>()
1 M = span(QQ, [vector([Integer(1),Integer(0),Integer(0)])])
2 M
----> 3 A.restrict(M) # A doesn't leave the subspace M invariant... so this will fail!
/ext/sage/sage-8.1/src/sage/matrix/matrix2.pyx in sage.matrix.matrix2.Matrix.restrict (build/cythonized/sage/matrix/matrix2.c:41441)()
5056 C = [V.coordinate_vector(b*self) for b in V.basis()]
5057 except ArithmeticError:
-> 5058 raise ArithmeticError("subspace is not invariant under matrix")
5059 return self.new_matrix(n, n, C, sparse=False)
5060
ArithmeticError: subspace is not invariant under matrix
Sparse vs. dense matrices
In computational linear algebra, it is important to distinguish between sparse matrices, in which all but a few entries are zero, and dense matrices, where most of the entries are nonzero. This is not a formal mathematical distinction among matrices, but rather a distinction between two different classes of algorithms for handling matrices.
Note that in the previous examples, Sage tried to guess the dimension of the matrix. If it is guessing wrong, you may need to fix this by specifying dimensions.
Warning: Not all operations make sense to do in the sparse model. For example, passing from a matrix to its inverse does not preserve sparsity in general. Many operations on sparse matrices involve an implicit coercion to a dense matrix.
Operations on matrices
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-3-ce7578e55d8d> in <module>()
1 A = matrix(QQ, [[Integer(1),Integer(2)],[Integer(3),Integer(4)]])
2 __tmp__=var("x"); f = symbolic_expression(x**Integer(3) - Integer(2)*x + Integer(1)).function(x)
----> 3 f(A) # FAIL -- this should work, but doesn't
/ext/sage/sage-8.1/src/sage/symbolic/expression.pyx in sage.symbolic.expression.Expression.__call__ (build/cythonized/sage/symbolic/expression.cpp:32775)()
5273 z^2 + x^y
5274 """
-> 5275 return self._parent._call_element_(self, *args, **kwds)
5276
5277 def variables(self):
/ext/sage/sage-8.1/local/lib/python2.7/site-packages/sage/symbolic/callable.pyc in _call_element_(self, _the_element, *args, **kwds)
462 d = dict(zip([repr(_) for _ in self.arguments()], args))
463 d.update(kwds)
--> 464 return SR(_the_element.substitute(**d))
465
466 # __reduce__ gets replaced by the CallableSymbolicExpressionRingFactory
/ext/sage/sage-8.1/src/sage/symbolic/expression.pyx in sage.symbolic.expression.Expression.substitute (build/cythonized/sage/symbolic/expression.cpp:32085)()
5171 for k, v in sdict.iteritems():
5172 smap.insert(make_pair((<Expression>self.coerce_in(k))._gobj,
-> 5173 (<Expression>self.coerce_in(v))._gobj))
5174 sig_on()
5175 try:
/ext/sage/sage-8.1/src/sage/symbolic/expression.pyx in sage.symbolic.expression.Expression.coerce_in (build/cythonized/sage/symbolic/expression.cpp:23189)()
3042 return <Expression?>z
3043 except TypeError:
-> 3044 return self._parent._coerce_(z)
3045
3046 cpdef _add_(left, right):
/ext/sage/sage-8.1/src/sage/structure/parent_old.pyx in sage.structure.parent_old.Parent._coerce_ (build/cythonized/sage/structure/parent_old.c:4962)()
228 def _coerce_(self, x): # Call this from Python (do not override!)
229 if self._element_constructor is not None:
--> 230 return self.coerce(x)
231 check_old_coerce(self)
232 return self._coerce_c(x)
/ext/sage/sage-8.1/src/sage/structure/parent.pyx in sage.structure.parent.Parent.coerce (build/cythonized/sage/structure/parent.c:10941)()
1178 except Exception:
1179 _record_exception()
-> 1180 raise TypeError("no canonical coercion from %s to %s" % (parent(x), self))
1181 else:
1182 return (<map.Map>mor)._call_(x)
TypeError: no canonical coercion from Full MatrixSpace of 2 by 2 dense matrices over Rational Field to Callable function ring with argument x
More on NumPy
Notice that I typed a.shape
rather than a.shape()
as you may have expected if you have gotten accustomed to Python syntax. The point is that shape
is not a method of a NumPy array but rather an attribute, essentially a private variable belonging to the array.
The following is an example of a vectorized operation, where we apply a function to an array, which applies that function componentwise. NumPy is set up to do this sort of thing very efficiently (a la Fortran).
Let's test out the speed using the Python function timeit
.
Observe the difference:
This is just an arbitrary choice, made differently by mathematicians and engineers, so you have to be aware of it.