Skip to main content

Section 5.2 Vectors and Matrices in Julia

As we have seen, vectors and matrices play an extremely important role in linear optimization. In this section, we will see how to create and manipulate vectors and matrices in Julia.

Subsection 5.2.1 Vectors in Julia

An array in Julia is a sequence of values of a single type in any number of dimensions. The most common are one-dimensional, called a Vector and two-dimensional, called a Matrix. We will use both to solve LOPs.
To produce an array with specific values, use []. For example, v = [1; 2; 3] returns a vector as
3-element Vector{Int64}:
  1
  2
  3
Notice that this is returned as a vector with type Vector{Int64}. This is called a parametric type (we saw this with rational numbers as well). The Vector part of the type is an alias for an 1-D array and the type within the {} is the subtype indicating that this is an array of integers (specifically 64-bit integers).
A row vector can be made like r=[1 2 3] (and can optionally have commas between the entries). This is returned as
1Γ—3 Matrix{Int64}:
 1  2  3
However notice that this is technically a matrix of size 1Γ—3. Matrices are in the next section.

Subsection 5.2.2 Matrices in Julia

A Matrix in Julia is a two-dimensional array, but can be used for many standard Matrix operations. If you have a specific matrix to enter, the numbers are entered line by line with lines separated by a ;. For example:
A = [ 1 2 3 4; 5 6 7 8; 9 10 11 12]
will produce the \(3 \times 4\) matrix which is returned:
3Γ—4 Matrix{Int64}:
 1   2   3   4
 5   6   7   8
 9  10  11  12
If you are entering a matrix in a notebook environment, you can put each line separately as in
A = [1 2 3 4;
     5 6 7 8;
     9 10 11 12]
where the ; ending lines is optional. Also, like in vectors, the entries in row can optionally be separated by commas ,.

Subsection 5.2.3 Accessing elements in a Vector or Matrix

Consider the vector v=[10; 5; 15; 20]. One can access the elements with [index], where index is the index of the value. v[2] will return 5, the 2nd element of the vector.
Accessing elements in a Matrix is similar. Consider the matrix A that was created above. If we way the element in the 3rd row, 2nd column, A[3,2] will do that.

Note 5.2.1.

The first index of a Julia vector is 1. This is different than many other languages like C, javascript, and Python, but more intuitive for students coming from Linear Algebra. Also, the upper left element of a matrix A will be A[1,1].

Subsection 5.2.4 Constructing Vectors and Matrices with Comprehensions

Another feature related to arrays in Julia is that of comprehensions. If a vector (or matrix) can be generated with a formula for each element, then a comprehension is often used to simplify its creation. For example, if we want to produce a vector of squares or v= [1; 4; 9; 16; 25; 36; 49; 64] , then
v = [i^2 for i=1:8]
will accomplish this. Matrices can be made with comprehensions with a two variable for loop as in [i+j for i=1:3, j=1:4]
which returns
3Γ—4 Matrix{Int64}:
 2  3  4  5
 3  4  5  6
 4  5  6  7
and if you need to make any vector or matrix with a pattern, then generally comprehensions is the easiest way to do this.

Subsection 5.2.5 Broadcasting

Because operations on arrays are very common there is a nice syntax for applying a function to array. Let’s say we have the array x=[2*i for i=1:5] which will be the even integers up to 10. To square each of these, we prepend a . to the ^ operator or
x.^2
which returns the array:
5-element Vector{Int64}:
   4
  16
  36
  64
 100
This can also be thought of a function that is applied to each element of the array.
Named functions can also be used with broadcasting. If we want to take the modulus 3 of these, use mod.(x,3) which returns the array [2,1,0,2,1].

Subsection 5.2.6 Concatenating Matrices in Julia

Hopefully the wheels are turning and you’re thinking about how to handle simplex tableaus in Julia. From the above sections, you can imagine how to enter a tableau, for example, the one in (3.2.1) can be entered directly by typing in the numbers directly, as in
T = [4 3 1 0 0 0 120
    1 2 0 1 0 0 40
    0 1 0 0 1 0 16
   -1 -3 0 0 0 1   0]
There is an alternative way to do this since the sections of the matrix have specific form, and in many cases it can be easier. If we define
A = [4 3; 1 2; 0 1]
b = [120; 40; 16]
c = [-1 -3]
we can construct the left two columns with the vcat command for a vertical concatenation like: vcat(A,c) which would create the matrix:
4Γ—2 Matrix{Int64}:
 4   3
 1   2
 0   1
-1  -3
There is an hcat function as well and we can construct the tableau in (3.2.1) with hcat(vcat(A,c), I(4), vcat(b,[0])), using the function I(4) that makes a 4Γ—4 identity matrix
 1 
If this doesn’t work, make sure that you have loaded the LinearAlgebra package with using LinearAlgebra.
. This returns the matrix
4Γ—7 Matrix{Int64}:
 4   3  1  0  0  0  120
 1   2  0  1  0  0   40
 0   1  0  0  1  0   16
-1  -3  0  0  0  1    0
which seems to be a straightforward way to do this. There is an alternative (and simpler) way to construct a matrix using blocks. The above can also be made with
ST = [A I zeros(Int, 3) b
  c zeros(Int,1,3) I [0]]
where the top row are all matrices or vectors with 3 rows. The bottom row above are all row vectors. Notice that in this case, we have just used I for the identity and the correct size is determined automatically and the function zeros(Int, 3) for a vector of length 3 and zeros(Int,1,3) for a row vector.
 2 
Alternatively the zeros can be made with [0; 0; 0] and [0 0 0] instead.

Subsection 5.2.7 Submatrices in Julia

We will see that is is quite nice to be able to do submatrices in Julia. That is, given a matrix, pull specific rows and columns. Let’s start with the simplex tableau ST above.
We can pull out a single column, say the 2nd, with the expression ST[:,2], and this returns
4-element Vector{Int64}:
  3
  2
  1
 -3
Notice that the first slot is a :, indicating to use all rows. If we wanted the column not including the last element (say, for example, to use this to calculate \(\boldsymbol{b}\)-ratios), we can do ST[1:end-1,2], where it is understood that end in this context is 4.
Similarly, if we want the last row, we can do ST[end,:] which returns:
7-element Vector{Int64}:
 -1
 -3
  0
  0
  0
  1
  0
which is the last row, however, notice that the result is a Vector, instead of a row vector, which is a Matrix with a single row. This has advantages and disadvantages, but just be aware of the result.
We can also extract a block or submatrix from an existing matrix. Using the matrix defined in ST, ST[1:3,1:2] returns
3Γ—2 Matrix{Int64}:
 4  3
 1  2
 0  1
which is rows 1 through 3 and columns 1 and 2.
Another nice feature is to extract specific rows or columns. We will see in ChapterΒ 8 that it is advantageous to get say columns 1,3 and 4 from the top rows of matrix. The expression ST[1:3,[1,3,4]] will return
3Γ—3 Matrix{Int64}:
 4  1  0
 1  0  1
 0  0  0

Subsection 5.2.8 Creating Rational Matrices in Julia

Everything we have done in this chapter was with Integer matrices and this corresponds to that in this text which has formulated the simplex tableaus with integers to prevent errors associated with round off in floating-point numbers. Another type of matrix that is built-in to Julia that won’t have roundoff are Rational numbers that we saw in SectionΒ 5.1.
If we have a matrix with rational entries, we can create one such as
A2 = [ 2//3 1//4 7//2; -3//2 5//3 9//4]
and notice that the type returned is Matrix{Rational{Int64}}: indicating that the numbers stored in the Matrix are of type Rational{Int64} or rational numbers with 64-bit integer parts.
If a matrix is integer, though and we would like to convert it to rational, then one way to accomplish this is
ST = rationalize.([A I zeros(Int, 3) b
  c zeros(Int,1,3) I [0]])
where the rationalize command is applied to each element of the created matrix with broadcasting.