Notebook 2 – Math 2121, Fall 2020

Today we will see some plotting and random functions in Julia, as we explore the meaning of (reduced) echelon form and the row reduction algorithm.

13.9 μs

Running this notebook (optional)

If you have Pluto up and running, you can access the notebook we are currently viewing by entering this link (right click -> Copy Link) in the Open from file menu in Pluto.

17.8 μs

Plotting in Pluto

There are some good packages for making graphics in Julia. Today we'll use Plots.

11.2 μs
2.4 ms
455 μs

Echelon form and random matrices

Let's write some functions to determine whether a matrix is in echelon form.

9.9 μs
find_leading (generic function with 3 methods)
77.6 μs
3
10.9 ms
in_echelon_form (generic function with 2 methods)
85.2 μs
in_echelon_form_verbose (generic function with 2 methods)
52.8 μs
in_reduced_echelon_form (generic function with 2 methods)
71.6 μs
in_reduced_echelon_form_verbose (generic function with 2 methods)
109 μs
A
4×9 Array{Int64,2}:
 0  0  5  1  2  3  4  5  6
 0  0  0  6  8  9  0  2  0
 0  0  0  0  0  0  7  8  9
 0  0  0  0  0  0  0  0  0
9.7 μs
true
80.2 ms
true: matrix is in echelon form
27.5 ms
false
9.7 μs
false: leading entry in row 1 is not 1
12.5 μs

It's easy to make random matrices using the Random package.

10.2 μs
557 μs
B
3×5 Array{Int64,2}:
 3   2  3   2   2
 3   3  2   2  -3
 3  -1  0  -3   1
13.1 μs
false: leading entry in row 2 is not to the right of the leading entry in row 1
49.1 μs
false: not in echelon form
5.4 μs

If we generate a random matrix in this way, where each entry is chosen at random from a specified list or range, then what we get is almost never in echelon form. This is because too many entries are nonzero.

For a random matrix to have good chances of being in echelon form, we must make it more likely that a given entry is zero.

Whether a matrix is in echelon form does not depend on the values of its nonzero entries, only their positions (note that this is not true for reduced echelon form). So let's write a function that generates a random matrix with all entries either 0 (zero) or 1 (nonzero).

This function takes a parameter that controls how likely a given entry is to be zero.

12.8 μs
random_boolean_matrix (generic function with 1 method)
48.9 μs
C
3×5 Array{Float64,2}:
 0.0  1.0  0.0  0.0  1.0
 0.0  0.0  1.0  1.0  1.0
 0.0  1.0  0.0  1.0  1.0
11 μs
false: leading entry in row 3 is not to the right of the leading entry in row 2
13.3 μs

Now let's try the following experiment.

For different values of p between 0.0 and 1.0, we'll generate a bunch of random 01-matrices of a given size, where the chance that a given entry is 0 is p.

We'll graph what proportion of the time this matrix is in echelon form, as a function of p.

11.1 μs

Choose dimensions

nrows =2

ncols =3

391 μs
ntrials
1000
1.3 μs
R
2×2 Array{Float64,2}:
 0.0  0.0
 0.0  0.0
10.2 μs
true: matrix is in echelon form
7.7 μs
Plots.jl
0.000.250.500.751.000.000.250.500.751.00
Probablity p that individual matrix entry is zeroFraction of 2-by-2 matricesHow many random 01-matrices are in echelon form?
364 ms

If p == 1.0 then our random matrix is always the zero matrix which is in echelon form. This is why when p is 1.0 the value of the graph is 1.0.

16.9 μs
2×2 Array{Float64,2}:
 0.0  0.0
 0.0  0.0
8.1 μs
true: matrix is in echelon form
11.3 μs

If p == 0.0 then our random matrix is always the matrix of all ones which is never in echelon form if nrows > 1. This is why when p is 0.0 the value of the graph is 0.0.

15.5 μs
2×2 Array{Float64,2}:
 1.0  1.0
 1.0  1.0
8.9 μs
false: leading entry in row 2 is not to the right of the leading entry in row 1
16.1 μs

Reduction to reduced echelon form

Below is a function RREF that converts a matrix to its reduced echelon form. You can unhide the code by clicking the icon on the left, if you want to take a look.

8.7 μs
RREF (generic function with 2 methods)
276 μs

Here is some more code to compute and count the pivot positions in a matrix.

5.6 μs
pivot_positions (generic function with 2 methods)
58.9 μs
npivots (generic function with 2 methods)
27.1 μs
M
3×4 Array{Int64,2}:
 0   3  -6   6
 3  -7   8  -5
 3  -9  12  -9
9.5 μs
3×4 Array{Float64,2}:
 1.0  0.0  -2.0  3.0
 0.0  1.0  -2.0  2.0
 0.0  0.0  -0.0  0.0
9 μs
true
15.1 μs
9.7 μs
2
9.8 μs

How many pivot positions does a random N-by-N matrix have?

The possible values range from zero to N.

11.3 μs

M =5

N =6

105 μs
value_range
9.1 μs
28.6 ms
Plots.jl
4.1 ms

We see from these examples that almost every random matrix, of sufficiently large size with sufficiently unconstrained entries, has the largest possible number of pivot positions (which is the whichever of M or N is larger).

9.2 μs

Effort to compute RREF(A)

One final experiment for today.

Given a typical matrix A, how many row operations should we have to perform to compute RREF(A)? Could we get unlucky and have to do many more operations in one case compared to another?

To investigate, let's do the following. To simplify things, we'll just consider square matrices, and we'll just generate random 01-matrices as above.

For each probabilty p controlling how likely a given matrix entry is zero, we will generate a large number of random 01-matrices.

For these matrices A, we'll calculate the average number of row operations needed to compute RREF(A) and the standard deviation. Then we can plot both as a function of p.

15.6 μs
rtrials
1000
1.8 μs

N =2

73.3 μs
Plots.jl
0.000.250.500.751.000.00.20.40.60.81.01.2
meanstdProbablity p that individual matrix entry is zeroNumber of row operationsRowOps to compute RREF for 2-by-2 01-matrices
209 ms

Moral of the story: if the size N of our matrix is large, then at almost all values of p the average number of row operations needed to compute RREF(A) is nearly the same, and the standard deviation is also flat.

This means that if N is large then in some sense we can't get too unlucky: all computations of RREF(A) will take close to the same number of operations.

But this is only in the limit. When N is small, there is some interesting variation in the number of row operations needed.

13.8 μs
351 ns