Contact Us!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.

| Download

Math 208 Interactive Notebooks © 2024 by Soham Bhosale, Sara Billey, Herman Chau, Zihan Chen, Isaac Hartin Pasco, Jennifer Huang, Snigdha Mahankali, Clare Minerath, and Anna Willis is licensed under CC BY-ND 4.0

Views: 928
License: OTHER
Image: ubuntu2204

Chapter 2 Euclidean Space

by Snigdha Mahankali

snigsm@uw.edu

This Sage Worksheet is a part of a linear algebra tutorial created by Sara Billey's 2024 WXML group. It follows Chapter 8 of Holt's Linear Algebra with Applications. This section introduces on how to work with vectors, find their spans and determine linear independence.

 

Vectors

The way to create a vector is to use the vector keyword followed by the vector you wish to make. Sage will use context clues to figure out whether a vector is a row or column vector,
but all vectors will be rendered horizontally. For the purposes of this tutorial, all matrices will be inputed with column vectors and then transposed to look correct!
(Note: QQ and other specifiers denote which domain the vector will live in (ZZ: Integers, QQ: Rational, RR: Reals, CC: Complex, SR: Symbolic Ring aka variable expressions))

rowVector = vector([1,2,3]); rowVector
(1, 2, 3)
colVector = vector(QQ,[1,2,3]); colVector
(1, 2, 3)

Vector addition works simply with the + operator and scalar multiplication works simply with the * operator. Here, any vector can be refered to by its variable name and can be used in arithmetic operations just as you would with normal intgers. These arithmetic operations are fomally called Linear Combinations where you combine vectors to create new ones.

v = vector([1,0,0]); w = vector([0,1,0]); print(v+w)
(1, 1, 0)
v = vector([1,0,0]); print(2*v)
(2, 0, 0)
v = vector([1,0,0]); w = vector([0,1,0]); x = vector([1, -4, 3]); print(2*v, " + ", 3*w, " - ", x) print(2*v + 3*w - x)
(2, 0, 0) + (0, 3, 0) - (1, -4, 3) (1, 7, -3)

Vectors can also be used to represent solutions to systems of equations (i.e Vector Form or General Solution Form).
Based on Textbook 2.1 Example 3 (open the next dropdown for the reference)

def toEquations (A, b): if (len(A.rows()) != len(b)): raise Exception("A and b don't have the correct number of elements") print(A, "x = ", b) print() numOfrows = len(A.rows()); numOfcols = len(A.columns()); equations = [] for i in range(numOfrows): equation = "" for j in range(numOfcols): equation = equation + " + " + str(A[i][j] * xVect[j]) equation = equation[2:] + " == " + str(b[i]) equations.append(equation) return equations
x, y, z, a, c, d, e = var("x y z a c d e") #can add up to 7 COLUMN vectors to A before you need to add more variables to xVect! #if you add/remove elements to each of A's column vectors, make sure the vector b has the same number of elements #Uncomment each of the following A, b, s, and solutionVector (they correspond in order) or make your own! A = matrix([[2, 1, -1], [-3, -2, 3], [10, 3, 1]]).transpose(); # A = matrix([[1, 1], [0,1]]).transpose(); b = vector([-2, -2, 4]) # b = vector([2, 1]) #toEquations takes in a transposed matrix and a vectors and returns a list of corresponding linear equations equations = toEquations(A, b); print("Generated Equations: ", equations, "\n") print("Make sure you pass in: ", len(equations), " equations and ", len(A.columns()), " variables") #solve(eval[equation], eval[equation]..., var1, var2, var3, solution_dict=True) passes in all the equations and variables needed # and returns a dictionary in the form s = [{x: ..., y:..., z: ..., etc.}] # Make sure to change parameters of solve as number of equations and parameters change! s = solve([eval(equations[0]), eval(equations[1]), eval(equations[2])], x, y, z, solution_dict=True); # s = solve([eval(equations[0]), eval(equations[1])], xVect[0], xVect[1], solution_dict=True); # NOTE: solutions have not been seperated out into multiple vectors! solutionVector = vector([s[0].get(x), s[0].get(y), s[0].get(z)]) # solutionVector = vector([s[0].get(xVect[0]), s[0].get(xVect[1])]) print("Solution vector (x, y, z, ...): ",solutionVector)
[ 2 -3 10] [ 1 -2 3] [-1 3 1] x = (-2, -2, 4) Generated Equations: [' 2*x + -3*y + 10*z == -2', ' x + -2*y + 3*z == -2', ' -x + 3*y + z == 4'] Make sure you pass in: 3 equations and 3 variables Solution vector (x, y, z, ...): (-11*r1 + 2, -4*r1 + 2, r1)

Vectors look like arrows, always starting from (0,0) and extending outward.

p = arrow((0,0), (-2, 5)) p.show(xmin=-5, xmax=5, ymin=-5, ymax=5, aspect_ratio=1)

You can determine u + v using the tip to tail method.

p = arrow((0,0), (1,7), color="red", legend_label="u") + arrow((0,0), (3,1), legend_label="v") + arrow((1,7), (4, 8)) + arrow((0,0), (4, 8), color="green", legend_label="u+v") p.show(xmin=-1, xmax=7, ymin=-1, ymax=10, aspect_ratio=1)

You can also determine u + v using the parallelogram method.

q = arrow((0,0), (3,3), color="red", legend_label="u") + arrow((0,0), (-2,-5), legend_label="v") + arrow((0,0), (1,-2), color="green", legend_label="u+v") + line([(3, 3), (1, -2)]) + line([(-2, -5), (1, -2)]) q.show()

Scaling a vector moves it along a fixed line.

sum(arrow2d((0,0), (2*x, 5*x), hue=x/(2*pi)) for x in [-2..2, step=0.4])

The vector below is an example of putting a 2 dimentional vector in a 3 dimesional space

p=arrow((0,0),(1,1))[0].plot3d() p.show(aspect_ratio=[5,5,5])
3D rendering not yet implemented
arrow((0,0,0), (1,1,-3))
3D rendering not yet implemented

 

Span

Next, let's explore how to use these vectors to describe the space they live.

Span can be defined by all the linear combinations of vectors, typically given as a series of vectors {[1, 2, 3], [4, 5, 6]} or as a dimention (R2)

#declare variables x, y, a, b = var("x y a b") v = vector([0, 1]); w = vector([2, 1]); s = vector([a, b]); #Span is all of the vectors (a, b) the two vectors can reach (in this case, they can reach any 2 dimentional vector) print("x *", v, " + y *", w, " = ", s)
x * (0, 1) + y * (2, 1) = (a, b)

By solving an augmented matrix, we can test whether a matrix is in the span of others
Based on Textbook 2.2 Example 2 (open the next drop down for the reference)
(Note that the matrix used has been transposed for ease of computation)

def checkVectorinSpan (m, vector): try: x = m.solve_right(vector); print(vector, ": vector in the span!") printing = str(x[0]) + " * " + str(m.transpose()[0]) + " + " for i in range(1, len(m.columns())): printing = printing + str(x[i]) + " * " + str(m.transpose()[i]) + " " print(printing, "= ", vector) print() except: print(vector, ": vector is not in span!")
m = matrix([[2, 1, 1],[1, 2, 3]]); # m = matrix([[2, 1, 0, 0],[1, 0, 1, 0], [0, 0, 1, 3]]); mTranspose = m.transpose(); mTranspose print() checkSpanV = vector([8, 2, 1]) # checkSpanV = vector([8, 0, 2, 1]) checkSpanW = vector([-1, 4, 7]) # checkSpanW = vector([3, 1, 2, 3]) #sage will throw an exception if the augmented matrix doesn't have a unique solution checkVectorinSpan(mTranspose, checkSpanV) checkVectorinSpan(mTranspose, checkSpanW)
[2 1] [1 2] [1 3] (8, 2, 1) : vector is not in span! (-1, 4, 7) : vector in the span! -2 * (2, 1, 1) + 3 * (1, 2, 3) = (-1, 4, 7)

Let's explore what span looks like visually. Two vectors that have different spans in R2 will span the entire space. This pattern continues for n independent vectors in Rn

The span of one vector is a line.
Any dependent (vectors in the span of others) vectors in R2 will also form a line like the one below.

sum(arrow2d((0,0), (4*x, 5*x), hue=x/(2*pi)) for x in [-2..2, step=0.4])

Span of two vectors in R3 forms a plane like the one below.
Note: This plane extends to infinity, even if it is shown as aa bounded shape onscreen.

s,t = var('s,t') v1 = vector([1,1,1]); v2 = vector([1,2,3]); #forms a line since the two vectors are scalar multiples of each other! # v1 = vector([1,1,1]); # v2 = vector([2,2,2]); graph = parametric_plot3d(s*v1 + t*v2, (s,-2,2), (t,-2,2), color="yellow") + arrow((0,0,0), (v1[0],v1[1],v1[2]), color="red") + arrow((0,0,0), (v2[0],v2[1],v2[2]), color="green") graph.show()
3D rendering not yet implemented

Vectors in the span of the others will lie on the plane made by independent vectors. Vectors not in the span will not be bounded by that plane.

s,t = var('s,t') v1 = vector([1,1,1]) #red v2 = vector([1,2,3]) #green vInSpan = vector([2, 3, 4]) #dark blue vNotInSpan = vector([5, 0, 5]) #light blue #forms a line since the two vectors are scalar multiples of each other! # v1 = vector([1,1,1]); # v2 = vector([2,2,2]); graph = parametric_plot3d(s*v1 + t*v2, (s,-2,2), (t,-2,2), color="yellow") + arrow((0,0,0), (v1[0],v1[1],v1[2]), color="red") + arrow((0,0,0), (v2[0],v2[1],v2[2]), color="green") + arrow((0,0,0), (vInSpan[0],vInSpan[1],vInSpan[2]), color="blue", label="[2, 3, 4]") + arrow((0,0,0), (vNotInSpan[0],vNotInSpan[1],vNotInSpan[2])) graph.show()
3D rendering not yet implemented

The following code calculates span from a matrix of vectors. Feel free to experiment!
Note: Matrices in Sage are usually made row wise. For the matrix to be comprised of columnn vectors, simply transpose the matrix when you use it.

def colAndRowSpan (m) : vectors = m.echelon_form().rank() result = {} colspan = [] rowspan = [] for i in range(vectors): colspan.append(m.transpose()[i]) rowspan.append(m[i]) result["colspan"] = colspan result["rowspan"] = rowspan return result
m = matrix([[1,-1,2], [2,-1,2], [-2,5,-10], [3,-4,8]]); # m = matrix([[1,0], [3,-1], [5,2]]); # m = matrix([[1,-1,2, 0], [2,3,-1,2], [0,-2,5,-10], [1, 3,-4,8]]); mTrans = m.transpose() print(mTrans, "\n") print(mTrans.echelon_form(), "\n") r = colAndRowSpan(mTrans); r
[ 1 2 -2 3] [ -1 -1 5 -4] [ 2 2 -10 8] [ 1 0 -8 5] [ 0 1 3 -1] [ 0 0 0 0] {'colspan': [(1, -1, 2), (2, -1, 2)], 'rowspan': [(1, 2, -2, 3), (-1, -1, 5, -4)]}

TIP: The span of a set of vectors are the vectors corresponding to pivots in the ROWS of the solved matrix.
A set of n vectors span Rn if there is something in each ROW of the solved matrix (no 0 rows)!

def spanRn (m) : cols = len(m.columns()); rows = len(m.rows()); print("the set lives in R", rows) if(rank(m) == rows) : print("The set spans R", rows) return True else: print("The set doesn't span R", rows) return False
m = matrix([[1,7], [2,14], [1, 0]]).transpose(); # m = matrix([[1,7, 5, 9], [9, 0, 2,14]]); # m = matrix([[1,7,0], [0,3,0], [5,6, 2]]); print(m,"\n") print(m.echelon_form(), "\n") b = spanRn(m); b
[ 1 2 1] [ 7 14 0] [1 2 1] [0 0 7] the set lives in R 2 The set spans R 2 True

Any system of equations can be made into the form Ax = b where A is some matrix and x and b are vectors. Experiment with the code below to see how that works!

def toEquations (A, b): if (len(A.rows()) != len(b)): raise Exception("A and b don't have the correct number of elements") print(A, "x = ", b) print() numOfrows = len(A.rows()); numOfcols = len(A.columns()); equations = [] for i in range(numOfrows): equation = "" for j in range(numOfcols): equation = equation + " + " + str(A[i][j] * xVect[j]) equation = equation[2:] + " == " + str(b[i]) equations.append(equation) return equations
x, y, z, a, c, d, e = var("x y z a c d e") #can add up to 7 vectors to A before you need to add more variables to xVect! #if you add more elements to each vector, make sure the vector b has the same number of elements A = matrix([[1, -2, 9, -4], [3,1,1,-2], [-6, 1,2,3], [2,5, 1, -1]]).transpose(); b = vector([6, 16, 0, 1]) e = toEquations(A, b); e
[ 1 3 -6 2] [-2 1 1 5] [ 9 1 2 1] [-4 -2 3 -1] x = (6, 16, 0, 1) [' x + 3*y + -6*z + 2*a == 6', ' -2*x + y + z + 5*a == 16', ' 9*x + y + 2*z + a == 0', ' -4*x + -2*y + 3*z + -a == 1']

 

Linear Independence

Next, let's describe our sets of vectors.

A set of vectors is independent if you are able to solve the augmented matrix and back-substitute towards one single unique solution. But if at least one vector is in the span of any other vectors in the set, the set is linearly dependent and has infinite solutions. Try different vectors below to explore!
Note: A set of vectors containing the 0 vector is always linearly dependent since any vector in the set can be scaled by a factor of 0 to get the 0 vector.

def isIndependent(m) : solved = m.echelon_form(); print(solved,"\n") cols = len(m.columns()) for i in range(cols): if solved[i][i] == 0: print(str(m.transpose()[i]), " is in the span of another vector in the set! \nThe set is Linearly Dependent\n") return False; print("The set is Linearly Independent!\n") return True;
m = matrix([[-1, 4, -2, -3], [3, -13, 7, 7], [1, 1, 1, 1], [2, 2, 2, 2]]).transpose(); print(m) b =isIndependent(m); b
[ -1 3 1 2] [ 4 -13 1 2] [ -2 7 1 2] [ -3 7 1 2] [1 0 0 0] [0 1 3 6] [0 0 4 8] [0 0 0 0] (2, 2, 2, 2) is in the span of another vector in the set! The set is Linearly Dependent False

TIP: A set of vectors are linearly independent if there is a pivot in each COLUMN down the diagonal of the solved matrix!

If a set of vectors is lineraly independent, then Ax = b (written as a series of equations or as an augmented matrix) has at most one unique solution for every b
Based on Textbook 2.3 Example 4 (open the next drown down for the reference)
Based on that example, since the the solution to Ax = b or Ax = 0 has free variables, the set is not linearly independent!)

def toEquations (A, b): if (len(A.rows()) != len(b)): raise Exception("A and b don't have the correct number of elements") print(A, "x = ", b) print() numOfrows = len(A.rows()); numOfcols = len(A.columns()); equations = [] for i in range(numOfrows): equation = "" for j in range(numOfcols): equation = equation + " + " + str(A[i][j] * xVect[j]) equation = equation[2:] + " == " + str(b[i]) equations.append(equation) return equations
x, y, z, a, c, d, e = var("x y z a c d e") xVect = vector([x, y, z, a, c, d, e]) #can add up to 7 COLUMN vectors to A before you need to add more variables to xVect! #if you add more elements to each vector, make sure the vector b has the same number of elements A = matrix([[2, 1, -1], [-6, -3, 3], [-1, -1, -1], [8, 6, 2]]).transpose(); # A = matrix([[1, -2], [3,1], [5,4]]); b = vector([7, 6, 4]) equations = toEquations(A, b); print(equations) #Make sure to change parameters as number of equations and parameters change! (or your solution will be incorrect) solve([eval(equations[0]), eval(equations[1]), eval(equations[2])], xVect[0], xVect[1], xVect[2], xVect[3]) print() C = matrix([[2, 1, -1], [-6, -3, 3], [-1, -1, -1], [8, 6, 2]]).transpose(); d = vector([0, 0, 0]) equations = toEquations(C, d); print(equations) #change parameters as number of equationa and parameters change! solve([eval(equations[0]), eval(equations[1]), eval(equations[2])], xVect[0], xVect[1], xVect[2], xVect[3])
[ 2 -6 -1 8] [ 1 -3 -1 6] [-1 3 -1 2] x = (7, 6, 4) [' 2*x + -6*y + -z + 8*a == 7', ' x + -3*y + -z + 6*a == 6', ' -x + 3*y + -z + 2*a == 4'] [[x == -2*r10 + 3*r11 + 1, y == r11, z == 4*r10 - 5, a == r10]] [ 2 -6 -1 8] [ 1 -3 -1 6] [-1 3 -1 2] x = (0, 0, 0) [' 2*x + -6*y + -z + 8*a == 0', ' x + -3*y + -z + 6*a == 0', ' -x + 3*y + -z + 2*a == 0'] [[x == -2*r12 + 3*r13, y == r13, z == 4*r12, a == r12]]

Independent vectors are not in the span of another vector (or set of vectors)!

v1 = vector([4,4,4]) #red Dependent = vector([1, 1, 1]) #dark blue Independent = vector([0, 2, 1]) #light blue #forms a line since the two vectors are scalar multiples of each other! # v1 = vector([1,1,1]); # v2 = vector([2,2,2]); graph = arrow((0,0,0), (v1[0],v1[1],v1[2]), color="red")+ arrow((0,0,0), (Dependent[0],Dependent[1],Dependent[2]), color="green") + arrow((0,0,0), (Independent[0],Independent[1],Independent[2])) graph.show()
3D rendering not yet implemented
s,t = var('s,t') v1 = vector([1,0,0]) #red v2 = vector([0,2,1]) #green Dependent = vector([1, 2, 1]) #dark blue Independent = vector([3, 1, 5]) #light blue graph = parametric_plot3d(s*v1 + t*v2, (s,-2,2), (t,-2,2), color="yellow") + arrow((0,0,0), (v1[0],v1[1],v1[2]), color="red") + arrow((0,0,0), (v2[0],v2[1],v2[2]), color="green") + arrow((0,0,0), (Dependent[0],Dependent[1],Dependent[2]), color="blue") + arrow((0,0,0), (Independent[0],Independent[1],Independent[2])) graph.show()
3D rendering not yet implemented

Unifying Theorum Part 1 (If you know one is true, you automatically know the others are true):
~ A set of n vectors spans Rn
~ A set of n vectors is lineraly independent
~ Ax = b (written as a series of equations or as an augmented matrix) has one unique solution for every b


Function Reference Sheet:

#functions reference sheet x, y, z, a, c, d, e = var("x y z a c d e") xVect = vector([x, y, z, a, c, d, e]) # Takes in a transposed matrix (matrix[[col][col]].transpose()) and a vector b # Throws an exception if b's elements is not equal to A's rows # returns a list of equations def toEquations (A, b): if (len(A.rows()) != len(b)): raise Exception("A and b don't have the correct number of elements") print(A, "x = ", b) print() numOfrows = len(A.rows()); numOfcols = len(A.columns()); equations = [] for i in range(numOfrows): equation = "" for j in range(numOfcols): equation = equation + " + " + str(A[i][j] * xVect[j]) equation = equation[2:] + " == " + str(b[i]) equations.append(equation) return equations # Takes in a transposed matrix m and a vector and prints out whether the matrix is in span or not # if the matrix is in span, the function will print out the linear combination of m's vectors that results in the vector def checkVectorinSpan (m, vector): try: x = m.solve_right(vector); print(vector, ": vector in the span!") printing = str(x[0]) + " * " + str(m.transpose()[0]) + " + " for i in range(1, len(m.columns())): printing = printing + str(x[i]) + " * " + str(m.transpose()[i]) + " " print(printing, "= ", vector) print() except: print(vector, ": vector is not in span!") #Takes in a transposed matrix and returns the column and row span as a dictionary {colspan: ..., rowspan: ...} def colAndRowSpan (m) : vectors = m.echelon_form().rank() result = {} colspan = [] rowspan = [] for i in range(vectors): colspan.append(m.transpose()[i]) rowspan.append(m[i]) result["colspan"] = colspan result["rowspan"] = rowspan return result #Takes in a transposed matrix and prints whether the set of vectors spans the space it lives in # returns true if the set spans the space and false otherwise def spanRn (m) : cols = len(m.columns()); rows = len(m.rows()); print("the set lives in R", rows) if(rank(m) == rows) : print("The set spans R", rows) return True else: print("The set doesn't span R", rows) return False #Takes in a transposed matrix and returns True if the set is linearly independent and false if linearly dependent def isIndependent(m) : solved = m.echelon_form(); print(solved,"\n") cols = len(m.columns()) for i in range(cols): if solved[i][i] == 0: print(str(m.transpose()[i]), " is in the span of another vector in the set! \nThe set is Linearly Dependent\n") return False; print("The set is Linearly Independent!\n") return True;