@@ -10,14 +10,6 @@ export SparseMatrixExp,
10
10
get_column,
11
11
get_columns
12
12
13
- function load_expokit ()
14
- return quote
15
-
16
- using . Expokit: expmv
17
-
18
- end end # quote / load_expokit
19
-
20
-
21
13
# --- SparseMatrixExp & ExponentialMap ---
22
14
23
15
"""
@@ -39,7 +31,7 @@ julia> using SparseArrays
39
31
40
32
julia> A = sprandn(100, 100, 0.1);
41
33
42
- julia> using Expokit
34
+ julia> using ExponentialUtilities
43
35
44
36
julia> E = SparseMatrixExp(A);
45
37
@@ -64,10 +56,12 @@ julia> get_columns(E, [10]); # same as get_column(E, 10) but a 100x1 matrix is r
64
56
### Notes
65
57
66
58
This type is provided for use with very large and very sparse matrices.
67
- The evaluation of the exponential matrix action over vectors relies on the
68
- [Expokit](https://github.com/acroy/Expokit.jl) package. Hence, you will have to
69
- install and load this optional dependency to have access to the functionality
70
- of `SparseMatrixExp`.
59
+ The evaluation of the exponential matrix action over vectors relies on external
60
+ packages such as
61
+ [ExponentialUtilities](https://github.com/SciML/ExponentialUtilities.jl) or
62
+ [Expokit](https://github.com/acroy/Expokit.jl).
63
+ Hence, you will have to install and load such an optional dependency to have
64
+ access to the functionality of `SparseMatrixExp`.
71
65
"""
72
66
struct SparseMatrixExp{N, MN<: AbstractSparseMatrix{N} } <: AbstractMatrix{N}
73
67
M:: MN
@@ -92,38 +86,39 @@ function size(spmexp::SparseMatrixExp, ax::Int)
92
86
return size (spmexp. M, ax)
93
87
end
94
88
95
- function get_column (spmexp:: SparseMatrixExp{N} , j:: Int ) where {N}
96
- require (:Expokit ; fun_name= " get_column" )
97
-
89
+ function get_column (spmexp:: SparseMatrixExp{N} , j:: Int ;
90
+ backend= get_exponential_backend ()) where {N}
98
91
n = size (spmexp, 1 )
99
92
aux = zeros (N, n)
100
93
aux[j] = one (N)
101
- return expmv ( one (N), spmexp. M, aux)
94
+ return _expmv (backend, one (N), spmexp. M, aux)
102
95
end
103
96
104
- function get_columns (spmexp:: SparseMatrixExp{N} , J:: AbstractArray ) where {N}
105
- require (:Expokit ; fun_name= " get_columns" )
106
-
97
+ function get_columns (spmexp:: SparseMatrixExp{N} , J:: AbstractArray ;
98
+ backend= get_exponential_backend ()) where {N}
107
99
n = size (spmexp, 1 )
108
100
aux = zeros (N, n)
109
101
res = zeros (N, n, length (J))
110
102
@inbounds for (k, j) in enumerate (J)
111
103
aux[j] = one (N)
112
- res[:, k] = expmv ( one (N), spmexp. M, aux)
104
+ res[:, k] = _expmv (backend, one (N), spmexp. M, aux)
113
105
aux[j] = zero (N)
114
106
end
115
107
return res
116
108
end
117
109
118
110
"""
119
- get_row(spmexp::SparseMatrixExp{N}, i::Int) where {N}
111
+ get_row(spmexp::SparseMatrixExp{N}, i::Int;
112
+ [backend]=get_exponential_backend()) where {N}
120
113
121
114
Return a single row of a sparse matrix exponential.
122
115
123
116
### Input
124
117
125
- - `spmexp` -- sparse matrix exponential
126
- - `i` -- row index
118
+ - `spmexp` -- sparse matrix exponential
119
+ - `i` -- row index
120
+ - `backend` -- (optional; default: `get_exponential_backend()`) exponentiation
121
+ backend
127
122
128
123
### Output
129
124
@@ -135,25 +130,23 @@ This function uses Julia's `transpose` function to create the result.
135
130
The result is of type `Transpose`; in Julia versions older than v0.7, the result
136
131
was of type `RowVector`.
137
132
"""
138
- function get_row (spmexp:: SparseMatrixExp{N} , i:: Int ) where {N}
139
- require (:Expokit ; fun_name= " get_row" )
140
-
133
+ function get_row (spmexp:: SparseMatrixExp{N} , i:: Int ;
134
+ backend= get_exponential_backend ()) where {N}
141
135
n = size (spmexp, 1 )
142
136
aux = zeros (N, n)
143
137
aux[i] = one (N)
144
- return transpose (expmv ( one (N), transpose (spmexp. M), aux))
138
+ return transpose (_expmv (backend, one (N), transpose (spmexp. M), aux))
145
139
end
146
140
147
- function get_rows (spmexp:: SparseMatrixExp{N} , I:: AbstractArray{Int} ) where {N}
148
- require (:Expokit ; fun_name= " get_rows" )
149
-
141
+ function get_rows (spmexp:: SparseMatrixExp{N} , I:: AbstractArray{Int} ;
142
+ backend= get_exponential_backend ()) where {N}
150
143
n = size (spmexp, 1 )
151
144
aux = zeros (N, n)
152
145
res = zeros (N, length (I), n)
153
146
Mtranspose = transpose (spmexp. M)
154
147
@inbounds for (k, i) in enumerate (I)
155
148
aux[i] = one (N)
156
- res[k, :] = expmv ( one (N), Mtranspose, aux)
149
+ res[k, :] = _expmv (backend, one (N), Mtranspose, aux)
157
150
aux[i] = zero (N)
158
151
end
159
152
return res
@@ -287,14 +280,16 @@ function dim(em::ExponentialMap)
287
280
end
288
281
289
282
"""
290
- σ(d::AbstractVector, em::ExponentialMap)
283
+ σ(d::AbstractVector, em::ExponentialMap; [backend]=get_exponential_backend() )
291
284
292
285
Return the support vector of the exponential map.
293
286
294
287
### Input
295
288
296
- - `d` -- direction
297
- - `em` -- exponential map
289
+ - `d` -- direction
290
+ - `em` -- exponential map
291
+ - `backend` -- (optional; default: `get_exponential_backend()`) exponentiation
292
+ backend
298
293
299
294
### Output
300
295
@@ -305,28 +300,25 @@ If the direction has norm zero, the result depends on the wrapped set.
305
300
306
301
If ``E = \\ exp(M)⋅S``, where ``M`` is a matrix and ``S`` is a set, it
307
302
follows that ``σ(d, E) = \\ exp(M)⋅σ(\\ exp(M)^T d, S)`` for any direction ``d``.
308
-
309
- We allow sparse direction vectors, but will convert them to dense vectors to be
310
- able to use `expmv`.
311
303
"""
312
- function σ (d:: AbstractVector , em:: ExponentialMap )
313
- require (:Expokit ; fun_name= " σ" )
314
-
304
+ function σ (d:: AbstractVector , em:: ExponentialMap ;
305
+ backend= get_exponential_backend ())
315
306
N = promote_type (eltype (d), eltype (em))
316
- d_dense = d isa Vector ? d : Vector (d)
317
- v = expmv (one (N), transpose (em. spmexp. M), d_dense) # v <- exp(M^T) * d
318
- return expmv (one (N), em. spmexp. M, σ (v, em. X)) # res <- exp(M) * σ(v, S)
307
+ v = _expmv (backend, one (N), transpose (em. spmexp. M), d) # v <- exp(M^T) * d
308
+ return _expmv (backend, one (N), em. spmexp. M, σ (v, em. X)) # res <- exp(M) * σ(v, S)
319
309
end
320
310
321
311
"""
322
- ρ(d::AbstractVector, em::ExponentialMap)
312
+ ρ(d::AbstractVector, em::ExponentialMap; [backend]=get_exponential_backend() )
323
313
324
314
Return the support function of the exponential map.
325
315
326
316
### Input
327
317
328
- - `d` -- direction
329
- - `em` -- exponential map
318
+ - `d` -- direction
319
+ - `em` -- exponential map
320
+ - `backend` -- (optional; default: `get_exponential_backend()`) exponentiation
321
+ backend
330
322
331
323
### Output
332
324
@@ -336,16 +328,11 @@ The support function in the given direction.
336
328
337
329
If ``E = \\ exp(M)⋅S``, where ``M`` is a matrix and ``S`` is a set, it
338
330
follows that ``ρ(d, E) = ρ(\\ exp(M)^T d, S)`` for any direction ``d``.
339
-
340
- We allow sparse direction vectors, but will convert them to dense vectors to be
341
- able to use `expmv`.
342
331
"""
343
- function ρ (d:: AbstractVector , em:: ExponentialMap )
344
- require (:Expokit ; fun_name= " ρ" )
345
-
332
+ function ρ (d:: AbstractVector , em:: ExponentialMap ;
333
+ backend= get_exponential_backend ())
346
334
N = promote_type (eltype (d), eltype (em))
347
- d_dense = d isa Vector ? d : Vector (d)
348
- v = expmv (one (N), transpose (em. spmexp. M), d_dense) # v <- exp(M^T) * d
335
+ v = _expmv (backend, one (N), transpose (em. spmexp. M), d) # v <- exp(M^T) * d
349
336
return ρ (v, em. X)
350
337
end
351
338
@@ -354,14 +341,16 @@ function concretize(em::ExponentialMap)
354
341
end
355
342
356
343
"""
357
- ∈(x::AbstractVector, em::ExponentialMap)
344
+ ∈(x::AbstractVector, em::ExponentialMap; [backend]=get_exponential_backend() )
358
345
359
346
Check whether a given point is contained in an exponential map of a set.
360
347
361
348
### Input
362
349
363
- - `x` -- point/vector
364
- - `em` -- exponential map of a set
350
+ - `x` -- point/vector
351
+ - `em` -- exponential map of a set
352
+ - `backend` -- (optional; default: `get_exponential_backend()`) exponentiation
353
+ backend
365
354
366
355
### Output
367
356
@@ -387,24 +376,26 @@ julia> [1.0, 1.0] ∈ em
387
376
true
388
377
```
389
378
"""
390
- function ∈ (x:: AbstractVector , em:: ExponentialMap )
391
- require (:Expokit ; fun_name= " ∈" )
392
-
379
+ function ∈ (x:: AbstractVector , em:: ExponentialMap ;
380
+ backend= get_exponential_backend ())
393
381
@assert length (x) == dim (em) " a vector of length $(length (x)) is " *
394
382
" incompatible with a set of dimension $(dim (em)) "
395
383
N = promote_type (eltype (x), eltype (em))
396
- y = expmv ( - one (N), em. spmexp. M, x)
384
+ y = _expmv (backend, - one (N), em. spmexp. M, x)
397
385
return y ∈ em. X
398
386
end
399
387
400
388
"""
401
- vertices_list(em::ExponentialMap{N}) where {N}
389
+ vertices_list(em::ExponentialMap{N};
390
+ [backend]=get_exponential_backend()) where {N}
402
391
403
392
Return the list of vertices of a (polytopic) exponential map.
404
393
405
394
### Input
406
395
407
- - `em` -- exponential map
396
+ - `em` -- exponential map
397
+ - `backend` -- (optional; default: `get_exponential_backend()`) exponentiation
398
+ backend
408
399
409
400
### Output
410
401
@@ -415,16 +406,15 @@ A list of vertices.
415
406
We assume that the underlying set `X` is polytopic.
416
407
Then the result is just the exponential map applied to the vertices of `X`.
417
408
"""
418
- function vertices_list (em:: ExponentialMap{N} ) where {N}
419
- require (:Expokit ; fun_name= " vertices_list" )
420
-
409
+ function vertices_list (em:: ExponentialMap{N} ;
410
+ backend= get_exponential_backend ()) where {N}
421
411
# collect low-dimensional vertices lists
422
412
vlist_X = vertices_list (em. X)
423
413
424
414
# create resulting vertices list
425
415
vlist = Vector {Vector{N}} (undef, length (vlist_X))
426
416
@inbounds for (i, v) in enumerate (vlist_X)
427
- vlist[i] = expmv ( one (N), em. spmexp. M, v)
417
+ vlist[i] = _expmv (backend, one (N), em. spmexp. M, v)
428
418
end
429
419
430
420
return vlist
@@ -558,14 +548,17 @@ function dim(eprojmap::ExponentialProjectionMap)
558
548
end
559
549
560
550
"""
561
- σ(d::AbstractVector, eprojmap::ExponentialProjectionMap)
551
+ σ(d::AbstractVector, eprojmap::ExponentialProjectionMap;
552
+ [backend]=get_exponential_backend())
562
553
563
554
Return the support vector of a projection of an exponential map.
564
555
565
556
### Input
566
557
567
558
- `d` -- direction
568
559
- `eprojmap` -- projection of an exponential map
560
+ - `backend` -- (optional; default: `get_exponential_backend()`) exponentiation
561
+ backend
569
562
570
563
### Output
571
564
@@ -577,22 +570,17 @@ If the direction has norm zero, the result depends on the wrapped set.
577
570
If ``S = (L⋅M⋅R)⋅X``, where ``L`` and ``R`` are matrices, ``M`` is a matrix
578
571
exponential, and ``X`` is a set, it follows that
579
572
``σ(d, S) = L⋅M⋅R⋅σ(R^T⋅M^T⋅L^T⋅d, X)`` for any direction ``d``.
580
-
581
- We allow sparse direction vectors, but will convert them to dense vectors to be
582
- able to use `expmv`.
583
573
"""
584
- function σ (d:: AbstractVector , eprojmap:: ExponentialProjectionMap )
585
- require (:Expokit ; fun_name= " σ" )
586
-
587
- d_dense = d isa Vector ? d : Vector (d)
588
- daux = transpose (eprojmap. projspmexp. L) * d_dense
574
+ function σ (d:: AbstractVector , eprojmap:: ExponentialProjectionMap ;
575
+ backend= get_exponential_backend ())
576
+ daux = transpose (eprojmap. projspmexp. L) * d
589
577
N = promote_type (eltype (d), eltype (eprojmap))
590
- aux1 = expmv ( one (N), transpose (eprojmap. projspmexp. spmexp. M), daux)
578
+ aux1 = _expmv (backend, one (N), transpose (eprojmap. projspmexp. spmexp. M), daux)
591
579
daux = _At_mul_B (eprojmap. projspmexp. R, aux1)
592
580
svec = σ (daux, eprojmap. X)
593
581
594
582
aux2 = eprojmap. projspmexp. R * svec
595
- daux = expmv ( one (N), eprojmap. projspmexp. spmexp. M, aux2)
583
+ daux = _expmv (backend, one (N), eprojmap. projspmexp. spmexp. M, aux2)
596
584
return eprojmap. projspmexp. L * daux
597
585
end
598
586
0 commit comments