Skip to content

Commit 690fff2

Browse files
committed
Tests for arithmetic of Lazy operators
Added test for addition and substraction of LazyTensor and LazyProduct. Also tensor of LazyTensor, LazySum, and LazyProduct.
1 parent f4b872e commit 690fff2

9 files changed

+173
-120
lines changed

src/QuantumOpticsBase.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,6 @@ include("metrics.jl")
8080
include("spinors.jl")
8181
include("phasespace.jl")
8282
include("printing.jl")
83-
include("operators_lazyaritmetic.jl")
83+
#include("operators_lazyaritmetic.jl")
8484

8585
end # module

src/operators_lazyaritmetic.jl

Lines changed: 0 additions & 99 deletions
This file was deleted.

src/operators_lazyproduct.jl

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,26 @@ isequal(x::LazyProduct{B1,B2}, y::LazyProduct{B1,B2}) where {B1,B2} = (samebases
5656
# Arithmetic operations
5757
-(a::T) where T<:LazyProduct = T(a.operators,a.ket_l,a.bra_r, -a.factor)
5858

59+
60+
function +(a::LazyProduct{B1,B2},b::Operator{B1,B2}) where {B1,B2}
61+
LazySum(a) + b
62+
end
63+
function +(a::Operator{B1,B2},b::LazyProduct{B1,B2}) where {B1,B2}
64+
+(b,a)
65+
end
66+
function -(a::LazyProduct{B1,B2},b::LazyProduct{B1,B2}) where {B1,B2}
67+
LazySum(a) - b
68+
end
69+
function +(a::LazyProduct{B1,B2},b::LazyProduct{B1,B2}) where {B1,B2}
70+
LazySum(a) + LazySum(b)
71+
end
72+
function -(a::LazyProduct{B1,B2},b::Operator{B1,B2}) where {B1,B2}
73+
LazySum(a) - b
74+
end
75+
function -(a::Operator{B1,B2},b::LazyProduct{B1,B2}) where {B1,B2}
76+
a - LazySum(b)
77+
end
78+
5979
*(a::LazyProduct{B1,B2}, b::LazyProduct{B2,B3}) where {B1,B2,B3} = LazyProduct((a.operators..., b.operators...), a.factor*b.factor)
6080
*(a::LazyProduct, b::Number) = LazyProduct(a.operators, a.factor*b)
6181
*(a::Number, b::LazyProduct) = LazyProduct(b.operators, a*b.factor)
@@ -74,6 +94,16 @@ permutesystems(op::LazyProduct, perm::Vector{Int}) = LazyProduct(([permutesystem
7494
identityoperator(::Type{LazyProduct}, ::Type{S}, b1::Basis, b2::Basis) where S<:Number = LazyProduct(identityoperator(S, b1, b2))
7595

7696

97+
#Assume same basis
98+
function tensor(a::Operator{B1,B1},b::LazyProduct{B, B, F, T, KTL, BTR}) where {B1,B, F, T, KTL, BTR}
99+
ops = ([(i == 1 ? a : identityoperator(a)) op for (i,op) in enumerate(b.operators)]...,)
100+
LazyProduct(ops,b.factor)
101+
end
102+
function tensor(a::LazyProduct{B, B, F, T, KTL, BTR},b::Operator{B1,B1}) where {B1,B, F, T, KTL, BTR}
103+
ops = ([op (i == 1 ? b : identityoperator(b)) for (i,op) in enumerate(a.operators)]...,)
104+
LazyProduct(ops,a.factor)
105+
end
106+
77107
function mul!(result::Ket{B1},a::LazyProduct{B1,B2},b::Ket{B2},alpha,beta) where {B1,B2}
78108
if length(a.operators)==1
79109
mul!(result,a.operators[1],b,a.factor*alpha,beta)

src/operators_lazysum.jl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,19 @@ function /(a::LazySum, b::Number)
106106
@samebases LazySum(a.basis_l, a.basis_r, factors, a.operators)
107107
end
108108

109+
function tensor(a::Operator,b::LazySum)
110+
btotal_l = a.basis_l b.basis_l
111+
btotal_r = a.basis_r b.basis_r
112+
ops = ([a op for op in b.operators]...,)
113+
LazySum(btotal_l,btotal_r,b.factors,ops)
114+
end
115+
function tensor(a::LazySum,b::Operator)
116+
btotal_l = a.basis_l b.basis_l
117+
btotal_r = a.basis_r b.basis_r
118+
ops = ([op b for op in a.operators]...,)
119+
LazySum(btotal_l,btotal_r,a.factors,ops)
120+
end
121+
109122
function dagger(op::LazySum)
110123
ops = dagger.(op.operators)
111124
@samebases LazySum(op.basis_r, op.basis_l, conj.(op.factors), ops)

src/operators_lazytensor.jl

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -96,22 +96,48 @@ isequal(x::LazyTensor, y::LazyTensor) = samebases(x,y) && isequal(x.indices, y.i
9696
# Arithmetic operations
9797
-(a::LazyTensor) = LazyTensor(a, -a.factor)
9898

99-
function +(a::LazyTensor{B1,B2}, b::LazyTensor{B1,B2}) where {B1,B2}
100-
if length(a.indices) == 1 && a.indices == b.indices
101-
op = a.operators[1] * a.factor + b.operators[1] * b.factor
102-
return LazyTensor(a.basis_l, a.basis_r, a.indices, (op,))
103-
end
104-
throw(ArgumentError("Addition of LazyTensor operators is only defined in case both operators act nontrivially on the same, single tensor factor."))
99+
function +(a::LazyTensor{B1,B2},b::LazyTensor{B1,B2}) where {B1,B2}
100+
LazySum(a,b)
101+
end
102+
function -(a::LazyTensor{B1,B2},b::LazyTensor{B1,B2}) where {B1,B2}
103+
LazySum((1,-1),(a,b))
104+
end
105+
function +(a::LazyTensor{B1,B2},b::Operator{B1,B2}) where {B1,B2}
106+
LazySum(a) + b
107+
end
108+
function +(a::Operator{B1,B2},b::LazyTensor{B1,B2}) where {B1,B2}
109+
+(b,a)
110+
end
111+
function -(a::LazyTensor{B1,B2},b::Operator{B1,B2}) where {B1,B2}
112+
LazySum(a) - b
113+
end
114+
function -(a::Operator{B1,B2},b::LazyTensor{B1,B2}) where {B1,B2}
115+
a - LazySum(b)
105116
end
106117

107-
function -(a::LazyTensor{B1,B2}, b::LazyTensor{B1,B2}) where {B1,B2}
108-
if length(a.indices) == 1 && a.indices == b.indices
109-
op = a.operators[1] * a.factor - b.operators[1] * b.factor
110-
return LazyTensor(a.basis_l, a.basis_r, a.indices, (op,))
118+
function tensor(a::LazyTensor{B1,B1},b::Operator{B2,B2}) where {B1,B2}
119+
if isequal(b,identityoperator(basis(b)))
120+
btotal = basis(a) basis(b)
121+
LazyTensor(btotal,btotal,a.indices,(a.operators...,),a.factor)
122+
elseif B2 <: CompositeBasis
123+
throw(ArgumentError("tensor(a::LazyTensor{B1,B1},b::Operator{B2,B2}) is not implemented for B2 being CompositeBasis "))
124+
else
125+
a LazyTensor(b.basis_l,b.basis_r,[1],(b,),1)
126+
end
127+
end
128+
function tensor(a::Operator{B1,B1},b::LazyTensor{B2,B2}) where {B1,B2}
129+
if isequal(a,identityoperator(basis(a)))
130+
btotal = basis(a) basis(b)
131+
LazyTensor(btotal,btotal,b.indices.+length(basis(a).shape) ,(b.operators...,),b.factor)
132+
elseif B1 <: CompositeBasis
133+
throw(ArgumentError("tensor(a::Operator{B1,B1},b::LazyTensor{B2,B2}) is not implemented for B1 being CompositeBasis "))
134+
else
135+
LazyTensor(a.basis_l,a.basis_r,[1],(a,),1) b
111136
end
112-
throw(ArgumentError("Subtraction of LazyTensor operators is only defined in case both operators act nontrivially on the same, single tensor factor."))
113137
end
114138

139+
140+
115141
function *(a::LazyTensor{B1,B2}, b::LazyTensor{B2,B3}) where {B1,B2,B3}
116142
indices = sort(union(a.indices, b.indices))
117143
# ops = Vector{AbstractOperator}(undef, length(indices))

test/test_abstractdata.jl

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -412,9 +412,9 @@ x2 = Ket(b_r, rand(ComplexF64, length(b_r)))
412412
xbra1 = Bra(b_l, rand(ComplexF64, length(b_l)))
413413
xbra2 = Bra(b_l, rand(ComplexF64, length(b_l)))
414414

415-
# Addition
416-
@test_throws ArgumentError op1 + op2
417-
@test_throws ArgumentError op1 - op2
415+
# Addition Addition of LazyTensor now returns LazySum
416+
#@test_throws ArgumentError op1 + op2
417+
#@test_throws ArgumentError op1 - op2
418418
@test D(-op1_, -op1, 1e-12)
419419

420420
# Test multiplication
@@ -448,7 +448,9 @@ xbra1 = Bra(b_l, rand(ComplexF64, length(b_l)))
448448
xbra2 = Bra(b_l, rand(ComplexF64, length(b_l)))
449449

450450
# Addition
451-
@test_throws ArgumentError op1 + op2
451+
#Commented following line since addition of LazyProduct returns LazySum and is allowed.
452+
#@test_throws ArgumentError op1 + op2
453+
@test D(2.1*op1 + 0.3*op2, 2.1*op1_+0.3*op2_)
452454
@test D(-op1_, -op1)
453455

454456
# Test multiplication

test/test_operators_lazyproduct.jl

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,22 @@ x2 = Ket(b_l, rand(ComplexF64, length(b_l)))
6262
xbra1 = Bra(b_l, rand(ComplexF64, length(b_l)))
6363
xbra2 = Bra(b_l, rand(ComplexF64, length(b_l)))
6464

65-
# Addition
66-
@test_throws ArgumentError op1 + op2
65+
#Following is commented since addition between LazyProduct now returns LazySum
66+
#@test_throws ArgumentError op1 + op2
67+
68+
# Test Addition
6769
@test 1e-14 > D(-op1_, -op1)
70+
@test 1e-14 > D(op1+op2, op1_+op2_)
71+
@test 1e-14 > D(op1+op2_, op1_+op2_)
72+
@test 1e-14 > D(op1_+op2, op1_+op2_)
73+
74+
# Test Subtraction
75+
@test 1e-14 > D(op1 - op2, op1_ - op2_)
76+
@test 1e-14 > D(op1 - op2_, op1_ - op2_)
77+
@test 1e-14 > D(op1_ - op2, op1_ - op2_)
78+
@test 1e-14 > D(op1 + (-op2), op1_ - op2_)
79+
@test 1e-14 > D(op1 + (-1*op2), op1_ - op2_)
80+
6881

6982
# Test multiplication
7083
@test_throws DimensionMismatch op1a*op1a
@@ -78,6 +91,17 @@ xbra2 = Bra(b_l, rand(ComplexF64, length(b_l)))
7891
# Test division
7992
@test 1e-14 > D(op1/7, op1_/7)
8093

94+
#Test Tensor product (NOTE: it is assumed that BL == BR of both involved operators.)
95+
op1_l = randoperator(b_l, b_l)
96+
op2_l = randoperator(b_l, b_l)
97+
op_r = randoperator(b_r, b_r)
98+
op = op_r LazyProduct([op1_l, sparse(op2_l)])*0.1
99+
op_ = op_r (0.1*op1_l*op2_l)
100+
@test 1e-11 > D(op,op_)
101+
op = LazyProduct([op1_l, sparse(op2_l)])*0.1 op_r
102+
op_ = (0.1*op1_l*op2_l) op_r
103+
@test 1e-11 > D(op,op_)
104+
81105
# Test identityoperator
82106
Idense = identityoperator(DenseOpType, b_l)
83107
id = identityoperator(LazyProduct, b_l)

test/test_operators_lazysum.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,15 @@ xbra1 = Bra(b_l, rand(ComplexF64, length(b_l)))
105105
# Test division
106106
@test 1e-14 > D(op1/7, op1_/7)
107107

108+
#Test Tensor
109+
op1_tensor = op1a op1
110+
op2_tensor = op1 op1a
111+
op1_tensor_ = op1a op1_
112+
op2_tensor_ = op1_ op1a
113+
@test 1e-14 > D(op1_tensor,op1_tensor_)
114+
@test 1e-14 > D(op1_tensor_,op1_tensor)
115+
116+
108117
# Test tuples vs. vectors
109118
@test (op1+op1).operators isa Tuple
110119
@test (op1+op2).operators isa Tuple

test/test_operators_lazytensor.jl

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,25 @@ fac = randn()
113113
@test dense(op3 + fac * op3) dense(op3) * (1 + fac)
114114
@test dense(op3 - fac * op3) dense(op3) * (1 - fac)
115115

116-
# Forbidden addition
117-
@test_throws ArgumentError op1 + op2
118-
@test_throws ArgumentError op1 - op2
116+
#Commented since addition between lazytensors now return LazySum and its therefore always allowed.
117+
# Forbidden addition.
118+
#@test_throws ArgumentError op1 + op2
119+
#@test_throws ArgumentError op1 - op2
119120
@test 1e-14 > D(-op1_, -op1)
120121

122+
#Test addition
123+
@test 1e-14 > D(op1+op2, op1_+op2_)
124+
@test 1e-14 > D(op1+op2_, op1_+op2_)
125+
@test 1e-14 > D(op1_+op2, op1_+op2_)
126+
127+
#Test substraction
128+
@test 1e-14 > D(op1 - op2, op1_ - op2_)
129+
@test 1e-14 > D(op1 - op2_, op1_ - op2_)
130+
@test 1e-14 > D(op1_ - op2, op1_ - op2_)
131+
@test 1e-14 > D(op1 + (-op2), op1_ - op2_)
132+
@test 1e-14 > D(op1 + (-1*op2), op1_ - op2_)
133+
134+
121135
# Test multiplication
122136
@test_throws DimensionMismatch op1*op2
123137
@test 1e-11 > D(op1*(x1 + 0.3*x2), op1_*(x1 + 0.3*x2))
@@ -413,4 +427,38 @@ Lop1 = LazyTensor(b1^2, b2^2, 2, sparse(randoperator(b1, b2)))
413427
@test_throws DimensionMismatch Lop1*dense(Lop1)
414428
@test_throws DimensionMismatch Lop1*sparse(Lop1)
415429

430+
431+
#Test Tensor (only bl == br allowed)
432+
subop1 = randoperator(b1a, b1a)
433+
subop2 = randoperator(b2a, b2a)
434+
subop3 = randoperator(b3a, b3a)
435+
I1 = dense(identityoperator(b1a, b1a))
436+
I2 = dense(identityoperator(b2a, b2a))
437+
I3 = dense(identityoperator(b3a, b3a))
438+
op1 = LazyTensor(b_l, b_l, [1, 3], (subop1, sparse(subop3)), 0.1)
439+
op1_ = 0.1*subop1 I2 subop3
440+
op2 = LazyTensor(b_l, b_l, [2, 3], (sparse(subop2), subop3), 0.7)
441+
op2_ = 0.7*I1 subop2 subop3
442+
op3 = 0.3*LazyTensor(b_l, b_l, 3, subop3)
443+
op3_ = 0.3*I1 I2 subop3
444+
445+
#Cannot tensor CompositeBasis with LazyTensor if its not identity:
446+
@test_throws ArgumentError op1 op1_
447+
@test_throws ArgumentError op2_ op2
448+
449+
op1_tensor = subop1 op1
450+
op1_tensor_ = subop1 op1_
451+
op2_tensor = op1 subop1
452+
op2_tensor_ = op1_ subop1
453+
@test 1e-14 > D(op1_tensor,op1_tensor_)
454+
@test 1e-14 > D(op1_tensor_,op1_tensor)
455+
456+
op1_tensor = (I1 I3) op1
457+
op1_tensor_ = (I1 I3) op1_
458+
op2_tensor = op1 (I1 I3)
459+
op2_tensor_ = op1_ (I1 I3)
460+
@test 1e-14 > D(op1_tensor,op1_tensor_)
461+
@test 1e-14 > D(op1_tensor_,op1_tensor)
462+
463+
416464
end # testset

0 commit comments

Comments
 (0)