Add initial version of chapter 11, part 4
This commit is contained in:
parent
8dc67c5bdd
commit
85b7fd274c
9 changed files with 2927 additions and 222 deletions
|
|
@ -28,3 +28,7 @@ from sample_package.vector import Vector
|
|||
__name__ = "linear_algebra_tools"
|
||||
__version__ = "0.1.0" # see https://semver.org/ for how the format works
|
||||
__author__ = "Alexander Hess"
|
||||
|
||||
# Define what is imported with the "star import"
|
||||
# (i.e., with `from sample_package import *`).
|
||||
__all__ = ["Matrix", "Vector"]
|
||||
|
|
|
|||
|
|
@ -17,12 +17,14 @@ class Matrix:
|
|||
defaults to tuple
|
||||
typing (callable): type casting applied to all entries upon creation;
|
||||
defaults to float
|
||||
vector_cls (vector.Vector): a reference to the Vector class to work with
|
||||
zero_threshold (float): max. tolerance when comparing an entry to zero;
|
||||
defaults to 1e-12
|
||||
"""
|
||||
|
||||
storage = utils.DEFAULT_ENTRIES_STORAGE
|
||||
typing = utils.DEFAULT_ENTRY_TYPE
|
||||
# the `vector_cls` attribute is set at the bottom of this file
|
||||
zero_threshold = utils.ZERO_THRESHOLD
|
||||
|
||||
def __init__(self, data):
|
||||
|
|
@ -156,7 +158,7 @@ class Matrix:
|
|||
Returns:
|
||||
rows (generator): produces a Matrix's rows as Vectors
|
||||
"""
|
||||
return (Vector(r) for r in self._entries)
|
||||
return (self.vector_cls(r) for r in self._entries)
|
||||
|
||||
def cols(self):
|
||||
"""Loop over a Matrix's columns.
|
||||
|
|
@ -165,7 +167,7 @@ class Matrix:
|
|||
columns (generator): produces a Matrix's columns as Vectors
|
||||
"""
|
||||
return (
|
||||
Vector(self._entries[r][c] for r in range(self.n_rows))
|
||||
self.vector_cls(self._entries[r][c] for r in range(self.n_rows))
|
||||
for c in range(self.n_cols)
|
||||
)
|
||||
|
||||
|
|
@ -232,7 +234,7 @@ class Matrix:
|
|||
|
||||
def __radd__(self, other):
|
||||
"""See docstring for .__add__()."""
|
||||
if isinstance(other, Vector):
|
||||
if isinstance(other, self.vector_cls):
|
||||
raise TypeError("vectors and matrices cannot be added")
|
||||
# As both matrix and broadcasting addition are commutative,
|
||||
# we dispatch to .__add__().
|
||||
|
|
@ -260,7 +262,7 @@ class Matrix:
|
|||
|
||||
def __rsub__(self, other):
|
||||
"""See docstring for .__sub__()."""
|
||||
if isinstance(other, Vector):
|
||||
if isinstance(other, self.vector_cls):
|
||||
raise TypeError("vectors and matrices cannot be subtracted")
|
||||
# Same comments as in .__sub__() apply
|
||||
# with the roles of self and other swapped.
|
||||
|
|
@ -294,6 +296,8 @@ class Matrix:
|
|||
|
||||
Matrix-vector and vector-matrix multiplication are not commutative.
|
||||
|
||||
>>> from sample_package import Vector
|
||||
|
||||
>>> Matrix([(1, 2), (3, 4)]) * Vector([5, 6])
|
||||
Vector((17.000, 39.000))
|
||||
|
||||
|
|
@ -304,7 +308,7 @@ class Matrix:
|
|||
if isinstance(other, numbers.Number):
|
||||
return self.__class__((x * other for x in r) for r in self._entries)
|
||||
# Matrix-vector multiplication: Vector is a column Vector
|
||||
elif isinstance(other, Vector):
|
||||
elif isinstance(other, self.vector_cls):
|
||||
# First, cast the other Vector as a Matrix, then do matrix-matrix
|
||||
# multiplication, and lastly return the result as a Vector again.
|
||||
return self._matrix_multiply(other.as_matrix()).as_vector()
|
||||
|
|
@ -319,7 +323,7 @@ class Matrix:
|
|||
if isinstance(other, numbers.Number):
|
||||
return self * other
|
||||
# Vector-matrix multiplication: Vector is a row Vector
|
||||
elif isinstance(other, Vector):
|
||||
elif isinstance(other, self.vector_cls):
|
||||
return other.as_matrix(column=False)._matrix_multiply(self).as_vector()
|
||||
return NotImplemented
|
||||
|
||||
|
|
@ -375,7 +379,7 @@ class Matrix:
|
|||
|
||||
def __abs__(self):
|
||||
"""The Frobenius norm of a Matrix."""
|
||||
return utils.norm(self) # use the norm() function shared with the Vector class
|
||||
return utils.norm(self) # uses the norm() function shared vector.Vector
|
||||
|
||||
def __bool__(self):
|
||||
"""A Matrix is truthy if its Frobenius norm is strictly positive."""
|
||||
|
|
@ -398,7 +402,7 @@ class Matrix:
|
|||
"""Get a Vector representation of a Matrix.
|
||||
|
||||
Returns:
|
||||
vector (Vector)
|
||||
vector (vector.Vector)
|
||||
|
||||
Raises:
|
||||
RuntimeError: if one of the two dimensions, .n_rows or .n_cols, is not 1
|
||||
|
|
@ -409,7 +413,7 @@ class Matrix:
|
|||
"""
|
||||
if not (self.n_rows == 1 or self.n_cols == 1):
|
||||
raise RuntimeError("one dimension (m or n) must be 1")
|
||||
return Vector(x for x in self)
|
||||
return self.vector_cls(x for x in self)
|
||||
|
||||
def transpose(self):
|
||||
"""Switch the rows and columns of a Matrix.
|
||||
|
|
@ -432,4 +436,8 @@ class Matrix:
|
|||
# We call that a circular import. Whereas Python handles "circular" references
|
||||
# (e.g., both the Matrix and Vector classes have methods that reference the
|
||||
# respective other class), that is forbidden for imports.
|
||||
from sample_package.vector import Vector
|
||||
from sample_package import vector
|
||||
|
||||
# This attribute cannot be set in the class definition
|
||||
# as the vector module is only imported down here.
|
||||
Matrix.vector_cls = vector.Vector
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ import numbers
|
|||
# If third-party libraries are needed, they are
|
||||
# put into a group on their own in between.
|
||||
# Within a group, imports are sorted lexicographically.
|
||||
from sample_package import matrix
|
||||
from sample_package import utils
|
||||
from sample_package.matrix import Matrix
|
||||
|
||||
|
||||
class Vector:
|
||||
|
|
@ -17,6 +17,7 @@ class Vector:
|
|||
All entries are converted to floats, or whatever is set in the typing attribute.
|
||||
|
||||
Attributes:
|
||||
matrix_cls (matrix.Matrix): a reference to the Matrix class to work with
|
||||
storage (callable): data type used to store the entries internally;
|
||||
defaults to tuple
|
||||
typing (callable): type casting applied to all entries upon creation;
|
||||
|
|
@ -25,6 +26,7 @@ class Vector:
|
|||
defaults to 1e-12
|
||||
"""
|
||||
|
||||
matrix_cls = matrix.Matrix
|
||||
storage = utils.DEFAULT_ENTRIES_STORAGE
|
||||
typing = utils.DEFAULT_ENTRY_TYPE
|
||||
zero_threshold = utils.ZERO_THRESHOLD
|
||||
|
|
@ -219,7 +221,7 @@ class Vector:
|
|||
|
||||
def __abs__(self):
|
||||
"""The Euclidean norm of a vector."""
|
||||
return utils.norm(self) # use the norm() function shared with the Matrix class
|
||||
return utils.norm(self) # uses the norm() function shared matrix.Matrix
|
||||
|
||||
def __bool__(self):
|
||||
"""A Vector is truthy if its Euclidean norm is strictly positive."""
|
||||
|
|
@ -246,7 +248,7 @@ class Vector:
|
|||
column vector or a row vector; defaults to True
|
||||
|
||||
Returns:
|
||||
matrix (Matrix)
|
||||
matrix (matrix.Matrix)
|
||||
|
||||
Example Usage:
|
||||
>>> v = Vector([1, 2, 3])
|
||||
|
|
@ -256,5 +258,5 @@ class Vector:
|
|||
Matrix(((1.000, 2.000, 3.000,)))
|
||||
"""
|
||||
if column:
|
||||
return Matrix([x] for x in self)
|
||||
return Matrix([(x for x in self)])
|
||||
return self.matrix_cls([x] for x in self)
|
||||
return self.matrix_cls([(x for x in self)])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue