8.1: Functions and Vectors
- Page ID
- 86221
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\( \newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\)
( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\)
\( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)
\( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\)
\( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)
\( \newcommand{\Span}{\mathrm{span}}\)
\( \newcommand{\id}{\mathrm{id}}\)
\( \newcommand{\Span}{\mathrm{span}}\)
\( \newcommand{\kernel}{\mathrm{null}\,}\)
\( \newcommand{\range}{\mathrm{range}\,}\)
\( \newcommand{\RealPart}{\mathrm{Re}}\)
\( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)
\( \newcommand{\Argument}{\mathrm{Arg}}\)
\( \newcommand{\norm}[1]{\| #1 \|}\)
\( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)
\( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\AA}{\unicode[.8,0]{x212B}}\)
\( \newcommand{\vectorA}[1]{\vec{#1}} % arrow\)
\( \newcommand{\vectorAt}[1]{\vec{\text{#1}}} % arrow\)
\( \newcommand{\vectorB}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vectorC}[1]{\textbf{#1}} \)
\( \newcommand{\vectorD}[1]{\overrightarrow{#1}} \)
\( \newcommand{\vectorDt}[1]{\overrightarrow{\text{#1}}} \)
\( \newcommand{\vectE}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash{\mathbf {#1}}}} \)
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\(\newcommand{\avec}{\mathbf a}\) \(\newcommand{\bvec}{\mathbf b}\) \(\newcommand{\cvec}{\mathbf c}\) \(\newcommand{\dvec}{\mathbf d}\) \(\newcommand{\dtil}{\widetilde{\mathbf d}}\) \(\newcommand{\evec}{\mathbf e}\) \(\newcommand{\fvec}{\mathbf f}\) \(\newcommand{\nvec}{\mathbf n}\) \(\newcommand{\pvec}{\mathbf p}\) \(\newcommand{\qvec}{\mathbf q}\) \(\newcommand{\svec}{\mathbf s}\) \(\newcommand{\tvec}{\mathbf t}\) \(\newcommand{\uvec}{\mathbf u}\) \(\newcommand{\vvec}{\mathbf v}\) \(\newcommand{\wvec}{\mathbf w}\) \(\newcommand{\xvec}{\mathbf x}\) \(\newcommand{\yvec}{\mathbf y}\) \(\newcommand{\zvec}{\mathbf z}\) \(\newcommand{\rvec}{\mathbf r}\) \(\newcommand{\mvec}{\mathbf m}\) \(\newcommand{\zerovec}{\mathbf 0}\) \(\newcommand{\onevec}{\mathbf 1}\) \(\newcommand{\real}{\mathbb R}\) \(\newcommand{\twovec}[2]{\left[\begin{array}{r}#1 \\ #2 \end{array}\right]}\) \(\newcommand{\ctwovec}[2]{\left[\begin{array}{c}#1 \\ #2 \end{array}\right]}\) \(\newcommand{\threevec}[3]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \end{array}\right]}\) \(\newcommand{\cthreevec}[3]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \end{array}\right]}\) \(\newcommand{\fourvec}[4]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \\ #4 \end{array}\right]}\) \(\newcommand{\cfourvec}[4]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \\ #4 \end{array}\right]}\) \(\newcommand{\fivevec}[5]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \\ #4 \\ #5 \\ \end{array}\right]}\) \(\newcommand{\cfivevec}[5]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \\ #4 \\ #5 \\ \end{array}\right]}\) \(\newcommand{\mattwo}[4]{\left[\begin{array}{rr}#1 \amp #2 \\ #3 \amp #4 \\ \end{array}\right]}\) \(\newcommand{\laspan}[1]{\text{Span}\{#1\}}\) \(\newcommand{\bcal}{\cal B}\) \(\newcommand{\ccal}{\cal C}\) \(\newcommand{\scal}{\cal S}\) \(\newcommand{\wcal}{\cal W}\) \(\newcommand{\ecal}{\cal E}\) \(\newcommand{\coords}[2]{\left\{#1\right\}_{#2}}\) \(\newcommand{\gray}[1]{\color{gray}{#1}}\) \(\newcommand{\lgray}[1]{\color{lightgray}{#1}}\) \(\newcommand{\rank}{\operatorname{rank}}\) \(\newcommand{\row}{\text{Row}}\) \(\newcommand{\col}{\text{Col}}\) \(\renewcommand{\row}{\text{Row}}\) \(\newcommand{\nul}{\text{Nul}}\) \(\newcommand{\var}{\text{Var}}\) \(\newcommand{\corr}{\text{corr}}\) \(\newcommand{\len}[1]{\left|#1\right|}\) \(\newcommand{\bbar}{\overline{\bvec}}\) \(\newcommand{\bhat}{\widehat{\bvec}}\) \(\newcommand{\bperp}{\bvec^\perp}\) \(\newcommand{\xhat}{\widehat{\xvec}}\) \(\newcommand{\vhat}{\widehat{\vvec}}\) \(\newcommand{\uhat}{\widehat{\uvec}}\) \(\newcommand{\what}{\widehat{\wvec}}\) \(\newcommand{\Sighat}{\widehat{\Sigma}}\) \(\newcommand{\lt}{<}\) \(\newcommand{\gt}{>}\) \(\newcommand{\amp}{&}\) \(\definecolor{fillinmathshade}{gray}{0.9}\)In this section we’ll look at common patterns involving functions and vectors, and you will learn how to write a single function that can work with vectors as well as scalars.
Vectors as Input Variables
Since many of the built-in functions take vectors as arguments, it should come as no surprise that you can write functions that take vectors as input. Here’s a simple (but not very useful) example:
function res = display_vector(X)
for i=1:length(X)
display(X(i))
end
end
There’s nothing special about this function. The only difference from the scalar functions we’ve seen is that this one uses a capital letter to remind us that X
is a vector.
Using display_vector
doesn’t actually return a value; it just displays the elements of the vector it gets as an input variable:
>> display_vector(1:3)
1
2
3
Here’s a more interesting example that encapsulates the code from Listing 4.2 on page 4.7 to add up the elements of a vector:
function res = mysum(X)
total = 0;
for i=1:length(X)
total = total + X(i);
end
res = total;
end
I called this function mysum
to avoid a collision with the built-in function sum
, which does pretty much the same thing.
Here’s how you call it from the Command Window:
>> total = mysum(1:3)
total = 6
Because this function has an output variable, I made a point of assigning it to a variable.
Vectors as Output Variables
There’s also nothing wrong with assigning a vector to an output variable. Here’s an example that encapsulates the code from Listing 4.3 on page 4.7:
function res = mysquare(X)
for i=1:length(X)
Y(i) = X(i)^2;
end
res = Y;
end
This function squares each element of X
and stores it as an element of Y
. Then it assigns Y
to the output variable, res
. Here’s how we use this function:
>> V = mysquare(1:3)
V = 1 4 9
The input variable is a vector with the elements 1,2,3
. The output variable is a vector with the elements 1,4,9
.
Vectorizing Functions
Functions that work on vectors will almost always work on scalars as well, because MATLAB considers a scalar to be a vector with length 1.
>> mysum(17)
ans = 17
>> mysquare(9)
ans = 81
Unfortunately, the converse isn’t always true. If you write a function with scalar inputs in mind, it might not work on vectors.
But it might! If the operators and functions you use in the body of your function work on vectors, then your function will probably work on vectors. For example, here’s the very first function we wrote:
function res = myfunc(x)
s = sin(x);
c = cos(x);
res = abs(s) + abs(c);
end
And lo! It turns out to work on vectors:
>> Y = myfunc(1:3)
Y = 1.3818 1.3254 1.1311
Some of the other functions we wrote don’t work on vectors, but they can be patched up with just a little effort. For example, here’s hypotenuse
from Section 5.1:
function res = hypotenuse(a, b)
res = sqrt(a^2 + b^2);
end
This doesn’t work on vectors because the ^
operator tries to do matrix exponentiation, which only works on square matrices.
>> hypotenuse(1:3, 1:3)
Error using ^ (line 51)
Incorrect dimensions for raising a matrix to a power.
Check that the matrix is square and the power is a scalar.
To perform element-wise matrix powers, use '.^'.
But if you replace ^
with the element-wise operator (.^
), it works!
>> A = [3,5,8];
>> B = [4,12,15];
>> C = hypotenuse(A, B)
C = 5 13 17
The function matches up corresponding elements from the two input vectors, so the elements of C
are the hypotenuses of the pairs \((3,4)\), \((5,12)\), and \((8,15)\), respectively.
In general, if you write a function using only element-wise operators and functions that work on vectors, the new function will also work on vectors.
Sums and Differences
Another common vector operation is cumulative sum, which takes a vector as an input and computes a new vector that contains all of the partial sums of the original. In math notation, if \(V\) is the original vector, the elements of the cumulative sum, \(C\), are
\[C_i = \sum_{j=1}^i V_j\notag\]
In other words, the \(i\)th element of \(C\) is the sum of the first \(i\) elements from \(V\). MATLAB provides a function named cumsum
that computes cumulative sums:
>> X = 1:5
X = 1 2 3 4 5
>> C = cumsum(X)
C = 1 3 6 10 15
The inverse operation of cumsum
is diff
, which computes the difference between successive elements of the input vector.
>> D = diff(C)
D = 2 3 4 5
Notice that the output vector is shorter by one than the input vector. As a result, MATLAB’s version of diff
is not exactly the inverse of cumsum
. If it were, we would expect cumsum(diff(X))
to be X
:
>> cumsum(diff(X))
ans = 1 2 3 4
But it isn’t.
Write a function named mydiff
that computes the inverse of cumsum
so that cumsum(mydiff(X))
and mydiff(cumsum(X))
both return X
.
Products and Ratios
The multiplicative version of cumsum
is cumprod
, which computes the cumulative product. In math notation, that’s
\[P_i = \prod_{j=1}^i V_j\notag\]
In MATLAB, that looks like
>> V = 1:5
V = 1 2 3 4 5
>> P = cumprod(V)
P = 1 2 6 24 120
MATLAB doesn’t provide the multiplicative version of diff
, which would be called ratio
, and which would compute the ratio of successive elements of the input vector.
Write a function named myratio
that computes the inverse of cumprod
, so that cumprod(myratio(X))
and myratio(cumprod(X))
both return X
.
You can use a loop, or if you want to be clever, you can take advantage of the fact that \(e^{\ln a + \ln b} = a b\).