Sparse Linear Algebra
ADCME augments TensorFlow APIs by adding sparse linear algebra support. In ADCME, sparse matrices are represented by SparseTensor. This data structure stores indices, rows and cols of the sparse matrices and keep track of relevant information such as whether it is diagonal for performance consideration. The default is row major (due to TensorFlow backend).
When evaluating SparseTensor, the output will be SparseMatrixCSC, the native Julia representation of sparse matrices
A = run(sess, s) # A has type SparseMatrixCSC{Float64,Int64}Sparse Matrix Construction
- By passing columns (
Int64), rows (Int64) and values (Float64) arrays
ii = [1;2;3;4]
jj = [1;2;3;4]
vv = [1.0;1.0;1.0;1.0]
s = SparseTensor(ii, jj, vv, 4, 4)- By passing a
SparseMatrixCSC
using SparseArrays
s = SparseTensor(sprand(10,10,0.3))- By passing a dense array (tensor or numerical array)
D = Array(sprand(10,10,0.3)) # a dense array
d = constant(D)
s = dense_to_sparse(d)There are also special constructors.
| Description | Code |
|---|---|
Diagonal matrix with diagonal v | spdiag(v) |
Empty matrix with size m, n | spzero(m, n) |
Identity matrix with size m | spdiag(m) |
Matrix Traits
Size of the matrices
size(s) # (10,20) size(s,1) # 10Return
row,col,valarrays (also known as COO arrays)ii,jj,vv = find(s)
Arithmetic Operations
Add Subtract
s = s1 + s2 s = s1 - s2Scalar Product
s = 2.0 * s1 s = s1 / 2.0Sparse Product
s = s1 * s2Transposition
s = s1'
Sparse Solvers
Solve a linear system (
sis a square matrix)sol = s\rhsSolve a least square system (
sis a tall matrix)sol = s\rhs
The least square solvers are implemented using Eigen sparse linear packages, and the gradients are also implemented. Thus, the following codes will work as expected (the gradients functions will correctly compute the gradients):
ii = [1;2;3;4]
jj = [1;2;3;4]
vv = constant([1.0;1.0;1.0;1.0])
rhs = constant(rand(4))
s = SparseTensor(ii, jj, vv, 4, 4)
sol = s\rhs
run(sess, sol)
run(sess, gradients(sum(sol), rhs))
run(sess, gradients(sum(sol), vv))Assembling Sparse Matrix
In many applications, we want to accumulate row, col and val to assemble a sparse matrix in iterations. For this purpose, we provide the SparseAssembler utilities.
ADCME.SparseAssembler — FunctionSparseAssembler(handle::Union{PyObject, <:Integer}, n::Union{PyObject, <:Integer}, tol::Union{PyObject, <:Real}=0.0)Creates a SparseAssembler for accumulating row, col, val for sparse matrices.
handle: an integer handle for creating a sparse matrix. If the handle already exists,SparseAssemblerreturn the existing sparse matrix handle. If you are creating different sparse matrices, the handles should be different.n: Number of rows of the sparse matrix.tol(optional): Tolerance.SparseAssemblerwill treats any values less thantolas zero.
Example 1
handle = SparseAssembler(100, 5, 1e-8)
op1 = accumulate(handle, 1, [1;2;3], [1.0;2.0;3.0])
op2 = accumulate(handle, 2, [1;2;3], [1.0;2.0;3.0])
J = assemble(5, 5, [op1;op2])J will be a SparseTensor object.
Example 2
handle = SparseAssembler(0, 5)
op1 = accumulate(handle, 1, [1;2;3], ones(3))
op2 = accumulate(handle, 1, [3], [1.])
op3 = accumulate(handle, 2, [1;3], ones(2))
J = assemble(5, 5, [op1;op2;op3]) # op1, op2, op3 are parallel
Array(run(sess, J))≈[1.0 1.0 2.0 0.0 0.0
1.0 0.0 1.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0]Base.accumulate — Functionaccumulate(handle::PyObject, row::Union{PyObject, <:Integer}, cols::Union{PyObject, Array{<:Integer}}, vals::Union{PyObject, Array{<:Real}})Accumulates row-th row. It adds the value to the sparse matrix
for k = 1:length(cols)
A[row, cols[k]] += vals[k]
endhandle is the handle created by SparseAssembler.
See SparseAssembler for an example.
The function accumulate returns a op::PyObject. Only when op is executed, the nonzero values are populated into the sparse matrix.
ADCME.assemble — Functionassemble(m::Union{PyObject, <:Integer}, n::Union{PyObject, <:Integer}, ops::PyObject)Assembles the sparse matrix from the ops created by accumulate. ops is either a single output from accumulate, or concated from several ops
op1 = accumulate(handle, 1, [1;2;3], [1.0;2.0;3.0])
op2 = accumulate(handle, 2, [1;2;3], [1.0;2.0;3.0])
op = [op1;op2] # equivalent to `vcat([op1, op2]...)`m and n are rows and columns of the sparse matrix.
See SparseAssembler for an example.