Source code: Q-Matrix.js

Grid of numbers

A matrix is just a grid of numbers; rows and columns containing values. Matrices can be of any size. Here’s an example of a 3 × 2 matrix. It is 3 columns wide and 2 rows tall, containing the values 1 through 6.


When describing the dimensions of a matrix we always specify the number of rows first, then the number of columns. The above is an example of a 3 × 2 matrix, while below is a matrix containing similar data, but in a 2 × 3 configuration.


Order matters

Q thinks about matrices in row-major order. This means we read the values just as they are ordered above, starting with the top-most row, reading values from left to right, then proceeding to the next row down and repeating that process. Our choice of row-major order makes reading and writing matrix values more akin to reading and writing in English; easier to type and program here.

Row-major order.
Column-major order.

Vectors are slices

While a matrix is a two-dimensional grid of numbers, a vector is more like a slice of numbers—such as a “skinny” matrix that is only one column wide, or a “flat” matrix that is only one row high. Let’s look at some examples of matrices that are simultaneously vectors.

Any “flat” matrix is
a row vector.
Any “skinny” matrix is
a column vector.
But matrices with
more than one column
or more than one row
are not vectors.

While the above 2 × 2 matrix is not a vector, you could say that it contains vectors: Two column vectors or two row vectors.

Because vectors are just a type of matrix we can add them, multiply them, and so on—just like any other matrix. Vectors will play a prominent role in defining qubits and expressing the state of a quantum circuit.

Complex numbers

Instead of just storing regular old numbers, our matrices are geared to store complex numbers. (This is because qubits are really just a pair of complex numbers that we store in a 1 × 2 matrix. So, yes—the example matrices above are actually all larger than qubits are!) In general, we don’t even have to think about the fact that our matrices are storing complex numbers because Q.Matrix is happy to accept regular JavaScript Number values as input—and Q.ComplexNumber will silently handle the conversion for us.


Matrix Function([ size: Number ] or [ width: Number, height: Number ] or [ rows: arguments ]) => Q.Matrix
The Matrix class creates and operates on matrices of arbitrary dimensions. This is in contrast to some popular graphics libraries which optimize for specific sizes of matrices—with corresponding class names like Matrix3 (for 3 × 3 matrices) or Matrix4 (for 4 × 4 matrices). Q, meanwhile, is much more flexible. The constructor expects an argument list of equal-length arrays where each array represents a row of column values. Matrix then automatically determines the dimensions based on the number of arguments (rows) and length of each row (number of columns). The constructor will throw an error if the row lengths are not equal.

Upon creation Matrix converts all argument values of type Number to Q.ComplexNumber instances. Currently Matrix does not support recursion; a matrix cannot contain matrices as values. A matrix also cannot change its dimensions, making destructive properties that yield matrices of a different size (like multiply$, for example) impossible.

var a = new Q.Matrix(  
	[ 1, 2, 3 ],  
	[ 4, 5, 6 ])

Import and export formats

Getting data in and out of any system can be laborious. With that in mind, Q.Matrix comes with helper methods for importing and exporting the following common formats:

Static properties

Constants and constant creation

Constants — Example matrices

Static inspection

Creation from description

Creation from data import

Static maths

Prototype properties

Self inspection

Data export (non-destructive)

Data import (destructive)

Maths operations (non-destructive)

Maths operations (destructive)