-
-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathbasic.jl
366 lines (288 loc) · 8.96 KB
/
basic.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
using SciMLOperators, LinearAlgebra
using Random
using SciMLOperators: IdentityOperator,
NullOperator,
ScaledOperator,
AddedOperator,
ComposedOperator,
AdjointOperator,
TransposedOperator,
InvertedOperator,
AbstractAdjointVecOrMat,
AbstractTransposedVecOrMat,
getops,
cache_operator
Random.seed!(0)
N = 8
K = 12
@testset "IdentityOperator" begin
A = rand(N, N) |> MatrixOperator
u = rand(N,K)
α = rand()
β = rand()
Id = IdentityOperator(N)
@test issquare(Id)
@test islinear(Id)
@test IdentityOperator(u) isa IdentityOperator
@test one(A) isa IdentityOperator
@test convert(AbstractMatrix, Id) == Matrix(I, N, N)
@test iscached(Id)
@test size(Id) == (N, N)
@test Id' isa IdentityOperator
@test isconstant(Id)
for op in (
*, \,
)
@test op(Id, u) ≈ u
end
v=rand(N,K); @test mul!(v, Id, u) ≈ u
v=rand(N,K); w=copy(v); @test mul!(v, Id, u, α, β) ≈ α*(I*u) + β*w
v=rand(N,K); @test ldiv!(v, Id, u) ≈ u
v=copy(u); @test ldiv!(Id, u) ≈ v
for op in (
*, ∘,
)
@test op(Id, A) isa MatrixOperator
@test op(A, Id) isa MatrixOperator
end
end
@testset "NullOperator" begin
A = rand(N, N) |> MatrixOperator
u = rand(N,K)
α = rand()
β = rand()
Z = NullOperator(N)
@test issquare(Z)
@test islinear(Z)
@test NullOperator(u) isa NullOperator
@test isconstant(Z)
@test zero(A) isa NullOperator
@test convert(AbstractMatrix, Z) == zeros(size(Z))
@test iscached(Z)
@test size(Z) == (N, N)
@test Z' isa NullOperator
@test Z * u ≈ zero(u)
v=rand(N,K); @test mul!(v, Z, u) ≈ zero(u)
v=rand(N,K); w=copy(v); @test mul!(v, Z, u, α, β) ≈ α*(0*u) + β*w
for op in (
*, ∘,
)
@test op(Z, A) isa NullOperator
@test op(A, Z) isa NullOperator
end
for op in (
+, -,
)
@test op(Z, A) isa MatrixOperator
@test op(A, Z) isa MatrixOperator
end
end
@testset "ScaledOperator" begin
A = rand(N,N)
D = Diagonal(rand(N))
u = rand(N,K)
α = rand()
β = rand()
a = rand()
b = rand()
op = ScaledOperator(α, MatrixOperator(A))
@test op isa ScaledOperator
@test isconstant(op)
@test iscached(op)
@test issquare(op)
@test islinear(op)
@test α * A * u ≈ op * u
@test (β * op) * u ≈ β * α * A * u
opF = factorize(op)
@test opF isa ScaledOperator
@test isconstant(opF)
@test iscached(opF)
@test α * A ≈ convert(AbstractMatrix, op) ≈ convert(AbstractMatrix, opF)
v=rand(N,K); @test mul!(v, op, u) ≈ α * A * u
v=rand(N,K); w=copy(v); @test mul!(v, op, u, a, b) ≈ a*(α*A*u) + b*w
op = ScaledOperator(α, MatrixOperator(D))
v=rand(N,K); @test ldiv!(v, op, u) ≈ (α * D) \ u
v=copy(u); @test ldiv!(op, u) ≈ (α * D) \ v
end
@testset "AddedOperator" begin
A = rand(N,N) |> MatrixOperator
B = rand(N,N) |> MatrixOperator
C = rand(N,N) |> MatrixOperator
α = rand()
β = rand()
u = rand(N,K)
for op in (
+, -
)
op1 = op(A , B )
op2 = op(α*A, B )
op3 = op(A , β*B)
op4 = op(α*A, β*B)
@test op1 isa AddedOperator
@test op2 isa AddedOperator
@test op3 isa AddedOperator
@test op4 isa AddedOperator
@test isconstant(op1)
@test isconstant(op2)
@test isconstant(op3)
@test isconstant(op4)
@test op1 * u ≈ op( A*u, B*u)
@test op2 * u ≈ op(α*A*u, B*u)
@test op3 * u ≈ op( A*u, β*B*u)
@test op4 * u ≈ op(α*A*u, β*B*u)
end
op = AddedOperator(A, B)
@test iscached(op)
v=rand(N,K); @test mul!(v, op, u) ≈ (A+B) * u
v=rand(N,K); w=copy(v); @test mul!(v, op, u, α, β) ≈ α*(A+B)*u + β*w
end
@testset "ComposedOperator" begin
A = rand(N,N)
B = rand(N,N)
C = rand(N,N)
u = rand(N,K)
α = rand()
β = rand()
ABCmulu = (A * B * C) * u
ABCdivu = (A * B * C) \ u
op = ∘(MatrixOperator.((A, B, C))...)
@test op isa ComposedOperator
@test isconstant(op)
@test *(op.ops...) isa ComposedOperator
@test issquare(op)
@test islinear(op)
opF = factorize(op)
@test opF isa ComposedOperator
@test isconstant(opF)
@test issquare(opF)
@test islinear(opF)
@test ABCmulu ≈ op * u
@test ABCdivu ≈ op \ u ≈ opF \ u
@test !iscached(op)
op = cache_operator(op, u)
@test iscached(op)
v=rand(N,K); @test mul!(v, op, u) ≈ ABCmulu
v=rand(N,K); w=copy(v); @test mul!(v, op, u, α, β) ≈ α*ABCmulu + β*w
A = rand(N) |> Diagonal
B = rand(N) |> Diagonal
C = rand(N) |> Diagonal
op = ∘(MatrixOperator.((A, B, C))...)
@test !iscached(op)
op = cache_operator(op, u)
@test iscached(op)
v=rand(N,K); @test ldiv!(v, op, u) ≈ (A * B * C) \ u
v=copy(u); @test ldiv!(op, u) ≈ (A * B * C) \ v
# Test caching of composed operator when inner ops do not support Base.:*
# See issue #129
inner_op = qr(MatrixOperator(rand(N, N)))
# We use the QR factorization of a non-square matrix, which does
# not support * as verified below.
@test !has_mul(inner_op)
@test has_ldiv(inner_op)
@test_throws MethodError inner_op * u
# We can now test that caching does not rely on matmul
op = inner_op * factorize(MatrixOperator(rand(N, N)))
@test !iscached(op)
@test_nowarn op = cache_operator(op, rand(N))
@test iscached(op)
u = rand(N)
@test ldiv!(rand(N), op, u) ≈ op \ u
end
@testset "ComposedOperator nonlinear operator composition test" begin
u = rand(N)
p = nothing
t = 0.0
square(u) = u .^ 2
square(u, p, t) = u .^ 2
square(v, u, p, t) = v .= u .* u
root(u) = u .^ 2
root(u, p, t) = u .^ 2
root(v, u, p, t) = v .= u .* u
F = FunctionOperator(square, u; islinear = false, op_inverse = root)
A = DiagonalOperator(zeros(N); update_func = (d, u, p, t) -> copy!(d, u)) # u .^2
B = DiagonalOperator(zeros(N); update_func = (d, u, p, t) -> copy!(d, u))
C = DiagonalOperator(zeros(N); update_func = (d, u, p, t) -> copy!(d, u))
L = A ∘ B ∘ C
F3 = F ∘ F ∘ F
sq = u |> square |> square |> square
@test A(B(C(u, p, t), p, t), p, t) ≈ sq
@test L(u, p, t) ≈ sq
@test F3(u, p, t) ≈ sq
L = cache_operator(L, u)
v = rand(N); @test L(v, u, p, t) ≈ sq
Fi = inv(F)
F3i = inv(F3)
rt = u |> root |> root |> root
@test F3i(u, p, t) ≈ rt
Ai = inv(A)
Bi = inv(B)
Ci = inv(C)
Li = inv(L)
Fi = inv(F)
for op in (Ai, Bi, Ci, Li)
@test op isa SciMLOperators.InvertedOperator
end
rt = Ai(Bi(Ci(u, p, t), p, t), p, t)
@test Ai(u, p, t) ≈ ones(N)
# TODO - overwrite L(u, p, t) for InvertedOperator
@test_broken Li(u, p, t) ≈ ones(N)
v = rand(N); @test_broken Li(v, u, p, t) ≈ ones(N)
end
@testset "Adjoint, Transpose" begin
for (op,
LType,
VType
) in (
(adjoint, AdjointOperator, AbstractAdjointVecOrMat ),
(transpose, TransposedOperator, AbstractTransposedVecOrMat),
)
A = rand(N,N)
D = Bidiagonal(rand(N,N), :L)
u = rand(N,K)
α = rand()
β = rand()
a = rand()
b = rand()
At = op(A)
Dt = op(D)
@test issquare(At)
@test issquare(Dt)
@test islinear(At)
@test islinear(Dt)
AA = MatrixOperator(A)
DD = MatrixOperator(D)
AAt = LType(AA)
DDt = LType(DD)
@test isconstant(AAt)
@test isconstant(DDt)
@test AAt.L === AA
@test op(u) isa VType
@test op(u) * AAt ≈ op(A * u)
@test op(u) / AAt ≈ op(A \ u)
v=rand(N,K); @test mul!(op(v), op(u), AAt) ≈ op(A * u)
v=rand(N,K); w=copy(v); @test mul!(op(v), op(u), AAt, α, β) ≈ α*op(A * u) + β*op(w)
v=rand(N,K); @test ldiv!(op(v), op(u), DDt) ≈ op(D \ u)
v=copy(u); @test ldiv!(op(u), DDt) ≈ op(D \ v)
end
end
@testset "InvertedOperator" begin
s = rand(N)
D = Diagonal(s) |> MatrixOperator
Di = InvertedOperator(D)
u = rand(N)
α = rand()
β = rand()
@test !iscached(Di)
Di = cache_operator(Di, u)
@test isconstant(Di)
@test iscached(Di)
@test issquare(Di)
@test islinear(Di)
@test Di * u ≈ u ./ s
v=rand(N); @test mul!(v, Di, u) ≈ u ./ s
v=rand(N); w=copy(v); @test mul!(v, Di, u, α, β) ≈ α *(u ./ s) + β*w
@test Di \ u ≈ u .* s
v=rand(N); @test ldiv!(v, Di, u) ≈ u .* s
v=copy(u); @test ldiv!(Di, u) ≈ v .* s
end
#