Skip to content

Commit aeee99a

Browse files
authored
Fix/add objfun deriv bounds; rename vars (#8)
We do two things: first, we fix an erroneous bound on the n'th order derivatives of the transfer fidelity objective function (which previously looser than intended), concurrently adding a bound on the n'th order derivatives of the mixing uniformity objective function. Second, we rename a few variables across the existing codebase for clarity/brevity (e.g., lipschitz_constant -> lipschitz_const).
1 parent 4cdac95 commit aeee99a

4 files changed

Lines changed: 44 additions & 30 deletions

File tree

src/EpsilonOptimization/solvers/lipschitz_branch_and_bound.jl

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,20 @@ struct LipschitzBranchAndBound <: AbstractEpsilonSolver
1313
epsilon::Real
1414
target::Union{<:Real,Nothing}
1515
max_iterations::Union{<:Integer,Nothing}
16-
lipschitz_constant::Real
16+
lipschitz_const::Real
1717

1818
function LipschitzBranchAndBound(
1919
epsilon::Real,
20-
lipschitz_constant::Real;
20+
lipschitz_const::Real;
2121
target::Union{<:Real,Nothing}=nothing,
2222
max_iterations::Union{<:Integer,Nothing}=nothing,
2323
)
24-
solver = new(epsilon, target, max_iterations, lipschitz_constant)
24+
solver = new(epsilon, target, max_iterations, lipschitz_const)
2525
validate_solver_params(solver)
2626

27-
if lipschitz_constant <= 0
27+
if lipschitz_const <= 0
2828
throw(
29-
ArgumentError(
30-
"Lipschitz constant must be positive, got $lipschitz_constant"
31-
),
29+
ArgumentError("Lipschitz constant must be positive, got $lipschitz_const")
3230
)
3331
end
3432

@@ -49,12 +47,12 @@ struct LBBHyperrectangle{Tx<:AbstractVector{<:Real},Tf<:Real}
4947
lower_bound::Tf
5048

5149
function LBBHyperrectangle(
52-
lower::Tx, upper::Tx, f::Function, lipschitz_constant::Real
50+
lower::Tx, upper::Tx, f::Function, lipschitz_const::Real
5351
) where {Tx<:AbstractVector{<:Real}}
5452
center = lower .+ (upper .- lower) ./ 2
5553
f_center = f(center)
5654
diameter = norm(upper .- lower)
57-
lower_bound = f_center - (lipschitz_constant / 2) * diameter
55+
lower_bound = f_center - (lipschitz_const / 2) * diameter
5856
return new{Tx,typeof(f_center)}(lower, upper, center, f_center, lower_bound)
5957
end
6058
end
@@ -67,7 +65,7 @@ function _epsilon_minimize_impl(
6765
f::Function, lower::Tx, upper::Tx, solver::LipschitzBranchAndBound
6866
) where {Tx<:AbstractVector{<:Real}}
6967
epsilon = solver.epsilon
70-
lipschitz_constant = solver.lipschitz_constant
68+
lipschitz_const = solver.lipschitz_const
7169

7270
if isnothing(solver.target)
7371
target = -Inf
@@ -81,7 +79,7 @@ function _epsilon_minimize_impl(
8179
max_iterations = solver.max_iterations
8280
end
8381

84-
rect_init = LBBHyperrectangle(lower, upper, f, solver.lipschitz_constant)
82+
rect_init = LBBHyperrectangle(lower, upper, f, solver.lipschitz_const)
8583
rects_cand = BinaryMinHeap{LBBHyperrectangle{Tx,typeof(rect_init.f_center)}}()
8684
push!(rects_cand, rect_init)
8785

@@ -107,7 +105,7 @@ function _epsilon_minimize_impl(
107105
minimum = rect.f_center
108106
end
109107

110-
children = _lbb_split_hyperrectangle(rect, f, lipschitz_constant)
108+
children = _lbb_split_hyperrectangle(rect, f, lipschitz_const)
111109

112110
for child in children
113111
if child.f_center < minimum
@@ -146,7 +144,7 @@ function _epsilon_minimize_impl(
146144
end
147145

148146
function _lbb_split_hyperrectangle(
149-
rect::LBBHyperrectangle, f::Function, lipschitz_constant::Real
147+
rect::LBBHyperrectangle, f::Function, lipschitz_const::Real
150148
)
151149
lower = rect.lower
152150
upper = rect.upper
@@ -157,12 +155,12 @@ function _lbb_split_hyperrectangle(
157155
lower1 = copy(lower)
158156
upper1 = copy(upper)
159157
upper1[dim_split] = mid
160-
child1 = LBBHyperrectangle(lower1, upper1, f, lipschitz_constant)
158+
child1 = LBBHyperrectangle(lower1, upper1, f, lipschitz_const)
161159

162160
lower2 = copy(lower)
163161
upper2 = copy(upper)
164162
lower2[dim_split] = mid
165-
child2 = LBBHyperrectangle(lower2, upper2, f, lipschitz_constant)
163+
child2 = LBBHyperrectangle(lower2, upper2, f, lipschitz_const)
166164

167165
return child1, child2
168166
end

src/QuantumStateTransfer.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ include("core/uniform_mixing.jl")
2727
include("core/fractional_revival.jl")
2828

2929
# TODO: Exports (add more later)
30-
export max_state_transfer, check_state_transfer
30+
export maximize_state_transfer, check_state_transfer
3131

3232
include("startup.jl")
3333

src/core/state_transfer.jl

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ struct StateTransferMaximizationResult{
2424
end
2525

2626
function Base.show(io::IO, res::StateTransferMaximizationResult{Tn,Int}) where {Tn}
27-
println(io, "Vertex State Transfer Maximization:")
27+
println(io, "Results of Vertex State Transfer Maximization")
2828
println(io, " * Network: $(summary(res.network))")
2929
println(io, " * Source vertex: $(res.src)")
3030
println(io, " * Destination vertex: $(res.dst)")
@@ -39,7 +39,7 @@ end
3939
function Base.show(
4040
io::IO, res::StateTransferMaximizationResult{Tn,Tuple{Int,Int}}
4141
) where {Tn}
42-
println(io, "Pair State Transfer Maximization:")
42+
println(io, "Results of Pair State Transfer Maximization")
4343
println(io, " * Network: $(summary(res.network))")
4444
println(io, " * Source vertices: $(res.src)")
4545
println(io, " * Destination vertices: $(res.dst)")
@@ -72,7 +72,7 @@ struct StateTransferRecognitionResult{
7272
end
7373

7474
function Base.show(io::IO, res::StateTransferRecognitionResult{Tn,Int}) where {Tn}
75-
println(io, "Vertex State Transfer Recognition:")
75+
println(io, "Results of Vertex State Transfer Recognition")
7676
println(io, " * Network: $(summary(res.network))")
7777
println(io, " * Source vertex: $(res.src)")
7878
println(io, " * Destination vertex: $(res.dst)")
@@ -92,7 +92,7 @@ end
9292
function Base.show(
9393
io::IO, res::StateTransferRecognitionResult{Tn,Tuple{Int,Int}}
9494
) where {Tn}
95-
println(io, "Pair State Transfer Recognition:")
95+
println(io, "Results of Pair State Transfer Recognition")
9696
println(io, " * Network: $(summary(res.network))")
9797
println(io, " * Source vertices: $(res.src)")
9898
println(io, " * Destination vertices: $(res.dst)")
@@ -110,8 +110,8 @@ function Base.show(
110110
end
111111

112112
"""
113-
max_state_transfer(g::AbstractGraph, args...) -> StateTransferMaximizationResult
114-
max_state_transfer(A::AbstractMatrix{<:Real}, args...) -> StateTransferMaximizationResult
113+
maximize_state_transfer(g::AbstractGraph, args...) -> StateTransferMaximizationResult
114+
maximize_state_transfer(A::AbstractMatrix{<:Real}, args...) -> StateTransferMaximizationResult
115115
116116
[TODO: Write here]
117117
@@ -133,15 +133,15 @@ end
133133
# Notes
134134
[TODO: Refer to [`transfer_fidelity_deriv_bound`](@ref) for proof sketch of bounds]
135135
"""
136-
function max_state_transfer(g::AbstractGraph, args...)
136+
function maximize_state_transfer(g::AbstractGraph, args...)
137137
if !is_simple(g)
138138
throw(ArgumentError("Graph must be undirected with no self-loops"))
139139
end
140140

141-
return max_state_transfer(adjacency_matrix(g), args...)
141+
return maximize_state_transfer(adjacency_matrix(g), args...)
142142
end
143143

144-
function max_state_transfer(
144+
function maximize_state_transfer(
145145
A::AbstractMatrix{<:Real},
146146
src::Tl,
147147
dst::Tl,
@@ -350,10 +350,8 @@ function _optimize_state_transfer_impl(input::_StateTransferProblemInput)
350350
end
351351

352352
if method == :lipschitz_bb
353-
lipschitz_constant = transfer_fidelity_deriv_bound(A, 1)
354-
solver = LipschitzBranchAndBound(
355-
epsilon, lipschitz_constant; target=target_infidelity
356-
)
353+
lipschitz_const = transfer_fidelity_deriv_bound(A, 1)
354+
solver = LipschitzBranchAndBound(epsilon, lipschitz_const; target=target_infidelity)
357355
elseif method == :alpha_bb
358356
alpha = transfer_fidelity_deriv_bound(A, 2) / 2
359357
solver = AlphaBranchAndBound(epsilon, alpha; target=target_infidelity)

src/utils.jl

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,5 +70,23 @@ end
7070
[TODO: Proof sketch of bound, plus further relevant references?]
7171
"""
7272
function transfer_fidelity_deriv_bound(A::Matrix{Float64}, order::Int)
73-
return maximum(norm.eachcol(A^order))
73+
return opnorm(A)^order # Equivalent to `opnorm(A^order)`, since `A` is symmetric
74+
end
75+
76+
"""
77+
mixing_uniformity_deriv_bound(A, order) -> Float64
78+
79+
[TODO: Write here]
80+
81+
# Arguments
82+
[TODO: Write here]
83+
84+
# Returns
85+
[TODO: Write here]
86+
87+
# Notes
88+
[TODO: Proof sketch of bound, plus further relevant references?]
89+
"""
90+
function mixing_uniformity_deriv_bound(A::Matrix{Float64}, order::Int)
91+
return 2 * opnorm(A)^order # Equivalent to `2 * opnorm(A^order)`, since `A` is symmetric
7492
end

0 commit comments

Comments
 (0)