44## Matrix creation example
55An ` ExtendableSparseMatrix ` can serve as a drop-in replacement for
66` SparseMatrixCSC ` , albeit with faster assembly during the buildup
7- phase when using index based access. That means that code similar
8- to the following example should be fast enough to avoid the assembly
9- steps using the coordinate format:
10-
11- ``` @example
7+ phase when using index based access.
8+
9+ Let us define a simple assembly loop
10+ ``` @example 1
1211using ExtendableSparse # hide
13- n=3
14- A=ExtendableSparseMatrix(n,n)
15- for i=1:n-1
16- A[i,i+1]=i
17- end
18- A
12+ using SparseArrays # hide
13+ using BenchmarkTools # hide
14+ BenchmarkTools.DEFAULT_PARAMETERS.seconds = 1 # hide
15+ function assemble(A)
16+ n=size(A,1)
17+ for i=1:n-1
18+ A[i+1,i]+=-1
19+ A[i,i+1]+=-1
20+ A[i,i]+=1
21+ A[i+1,i+1]+=1
22+ end
23+ end;
24+ ```
25+
26+ Measure the time (in seconds) for assembling a SparseMatrixCSC:
27+ ``` @example 1
28+ t_csc= @belapsed begin
29+ A=spzeros(10_000,10_000)
30+ assemble(A)
31+ end
32+ ```
33+
34+ An ` ExtendableSparseMatrix ` can be used as a drop-in replacement.
35+ However, before any other use, this needs an internal
36+ structure rebuild which is invoked by the flush! method.
37+ ``` @example 1
38+ t_ext=@belapsed begin
39+ A=ExtendableSparseMatrix(10_000,10_000)
40+ assemble(A)
41+ flush!(A)
42+ end
43+ ```
44+ All specialized methods of linear algebra functions (e.g. ` \ ` )
45+ for ` ExtendableSparseMatrix ` call ` flush! ` before proceeding.
46+
47+ The overall time gain from using ` ExtendableSparse ` is:
48+ ``` @example 1
49+ t_ext/t_csc
50+ ```
51+
52+
53+ The reason for this situation is that the ` SparseMatrixCSC ` struct
54+ just contains the data for storing the matrix in the compressed
55+ column format. Inserting a new entry in this storage scheme is
56+ connected with serious bookkeeping and shifts of large portions
57+ of array content.
58+
59+ Julia provides the
60+ [ ` sparse ` ] ( https://docs.julialang.org/en/v1/stdlib/SparseArrays/#SparseArrays.sparse )
61+ method which uses an intermediate storage of the data in two index
62+ arrays and a value array, the so called coordinate (or COO) format:
63+
64+ ``` @example 1
65+ function assemble_coo(n)
66+ I=zeros(Int64,0)
67+ J=zeros(Int64,0)
68+ V=zeros(0)
69+ function update(i,j,v)
70+ push!(I,i)
71+ push!(J,j)
72+ push!(V,v)
73+ end
74+ for i=1:n-1
75+ update(i+1,i,-1)
76+ update(i,i+1,-1)
77+ update(i,i,1)
78+ update(i+1,i+1,1)
79+ end
80+ sparse(I,J,V)
81+ end;
82+
83+ t_coo=@belapsed assemble_coo(10_000)
84+ ```
85+
86+ While more convenient to use, the assembly based on ` ExtendableSparseMatrix ` is only slightly
87+ slower:
88+
89+ ``` @example 1
90+ t_ext/t_coo
1991```
2092
2193
94+
95+ Below one finds a more elaborate discussion for a quasi-3D problem.
96+
2297## Matrix creation benchmark
2398
2499The method [ ` fdrand ` ] ( @ref ) creates a matrix similar to the discretization
@@ -35,12 +110,8 @@ inserting elements via `A[i,j]+=v`,
35110using an intermediate linked list structure which upon return
36111ist flushed into a SparseMatrixCSC structure.
37112
38- ``` @example
39- using ExtendableSparse # hide
40- using SparseArrays # hide
41- using BenchmarkTools # hide
42-
43- t=@belapsed fdrand(30,30,30, matrixtype=ExtendableSparseMatrix)
113+ ``` @example 1
114+ @belapsed fdrand(30,30,30, matrixtype=ExtendableSparseMatrix)
44115```
45116
46117### Benchmark for SparseMatrixCSC
@@ -51,8 +122,8 @@ entries via `A[i,j]+=v`.
51122using ExtendableSparse # hide
52123using SparseArrays # hide
53124using BenchmarkTools # hide
54-
55- t= @belapsed fdrand(30,30,30, matrixtype=SparseMatrixCSC)
125+ BenchmarkTools.DEFAULT_PARAMETERS.seconds = 1 # hide
126+ @belapsed fdrand(30,30,30, matrixtype=SparseMatrixCSC)
56127```
57128
58129### Benchmark for intermediate coordinate format
@@ -63,8 +134,8 @@ calling `sparse(I,J,A)`
63134using ExtendableSparse # hide
64135using SparseArrays # hide
65136using BenchmarkTools # hide
66-
67- t= @belapsed fdrand(30,30,30, matrixtype=:COO)
137+ BenchmarkTools.DEFAULT_PARAMETERS.seconds = 1 # hide
138+ @belapsed fdrand(30,30,30, matrixtype=:COO)
68139```
69140
70141This is nearly on par with matrix creation via ` ExtendableSparseMatrix ` , but the
@@ -79,8 +150,8 @@ entries via `updateindex(A,+,v,i,j)`, see the discussion below.
79150using ExtendableSparse # hide
80151using SparseArrays # hide
81152using BenchmarkTools # hide
82-
83- t= @belapsed fdrand(30,30,30,
153+ BenchmarkTools.DEFAULT_PARAMETERS.seconds = 1 # hide
154+ @belapsed fdrand(30,30,30,
84155 matrixtype=ExtendableSparseMatrix,
85156 update=(A,v,i,j)-> updateindex!(A,+,v,i,j))
86157```
@@ -90,7 +161,7 @@ t=@belapsed fdrand(30,30,30,
90161## Matrix update benchmark
91162For repeated calculations on the same sparsity structure (e.g. for time dependent
92163problems or Newton iterations) it is convenient to skip all but the first creation steps
93- and to just replace the values in the matrix after setting then elements of the ` nzval `
164+ and to just replace the values in the matrix after setting the elements of the ` nzval `
94165vector to zero. Typically in finite element and finite volume methods this step updates
95166matrix entries (most of them several times) by adding values. In this case, the current indexing
96167interface of Julia requires to access the matrix twice:
@@ -110,38 +181,38 @@ for `ExtendableSparse` which allows to update a matrix element with just one ind
110181using ExtendableSparse # hide
111182using SparseArrays # hide
112183using BenchmarkTools # hide
113-
184+ BenchmarkTools.DEFAULT_PARAMETERS.seconds = 1 # hide
114185A=fdrand(30,30,30, matrixtype=SparseMatrixCSC)
115- t= @belapsed fdrand!(A,30,30,30,
186+ @belapsed fdrand!(A,30,30,30,
116187 update=(A,v,i,j)-> A[i,j]+=v)
117188```
118189
119190``` @example
120191using ExtendableSparse # hide
121192using SparseArrays # hide
122193using BenchmarkTools # hide
123-
194+ BenchmarkTools.DEFAULT_PARAMETERS.seconds = 1 # hide
124195A=fdrand(30,30,30, matrixtype=SparseMatrixCSC)
125- t= @belapsed fdrand!(A,30,30,30,
196+ @belapsed fdrand!(A,30,30,30,
126197 update=(A,v,i,j)-> updateindex!(A,+,v,i,j))
127198```
128199
129200### Benchmark for ` ExtendableSparseMatrix `
130201``` @example
131202using ExtendableSparse # hide
132203using BenchmarkTools # hide
133-
204+ BenchmarkTools.DEFAULT_PARAMETERS.seconds = 1 # hide
134205A=fdrand(30,30,30, matrixtype=ExtendableSparseMatrix)
135- t= @belapsed fdrand!(A,30,30,30,
206+ @belapsed fdrand!(A,30,30,30,
136207 update=(A,v,i,j)-> A[i,j]+=v)
137208```
138209
139210``` @example
140211using ExtendableSparse # hide
141212using BenchmarkTools # hide
142-
213+ BenchmarkTools.DEFAULT_PARAMETERS.seconds = 1 # hide
143214A=fdrand(30,30,30, matrixtype=ExtendableSparseMatrix)
144- t= @belapsed fdrand!(A,30,30,30,
215+ @belapsed fdrand!(A,30,30,30,
145216 update=(A,v,i,j)-> updateindex!(A,+,v,i,j))
146217```
147218
0 commit comments