diff --git a/lib/YaoBlocks/src/blocktools.jl b/lib/YaoBlocks/src/blocktools.jl index 261fa7ce..fb9425cf 100644 --- a/lib/YaoBlocks/src/blocktools.jl +++ b/lib/YaoBlocks/src/blocktools.jl @@ -1,4 +1,4 @@ -export postwalk, prewalk, blockfilter!, blockfilter, collect_blocks, gatecount +export postwalk, prewalk, blockfilter!, blockfilter, collect_blocks, gatecount, circuit_depth """ parse_block(n, ex) @@ -102,7 +102,7 @@ function expect(op::AbstractBlock, dm::DensityMatrix) end function expect(op::AbstractAdd, reg::DensityMatrix) # NOTE: this is faster in e.g. when the op is Heisenberg - invoke(expect, Tuple{AbstractBlock, DensityMatrix}, op, reg) + invoke(expect, Tuple{AbstractBlock,DensityMatrix}, op, reg) end function expect(op::Scale, reg::DensityMatrix) factor(op) * expect(content(op), reg) @@ -135,7 +135,7 @@ end function conjsumprod1(A::AbstractArray, C::AbstractArray) Na, B = size(A) res = zeros(eltype(C), B) - @inbounds for b=1:B, i=1:Na + @inbounds for b = 1:B, i = 1:Na res[b] += conj(A[i, b]) * C[i, b] end res @@ -145,7 +145,7 @@ end function conjsumprod2(A::AbstractArray, C::AbstractArray) B, Na = size(A) res = zeros(eltype(C), B) - @inbounds for i=1:Na, b=1:B + @inbounds for i = 1:Na, b = 1:B res[b] += conj(A[b, i]) * C[b, i] end res @@ -155,7 +155,7 @@ end function conjsumprod13(A::AbstractArray, C::AbstractArray) Nr, B, Na = size(A) res = zeros(eltype(C), B) - @inbounds for i=1:Na, b=1:B, r=1:size(C, 1) + @inbounds for i = 1:Na, b = 1:B, r = 1:size(C, 1) res[b] += conj(A[r, b, i]) * C[r, b, i] end res @@ -213,7 +213,7 @@ function gatecount!(c::RepeatedBlock, storage::AbstractDict) end # NOTE: static scale defines a gate, dynamic scale is parameter. -function gatecount!(c::Scale{S}, storage::AbstractDict) where S +function gatecount!(c::Scale{S}, storage::AbstractDict) where {S} if S <: Val k = typeof(c) storage[k] = get(storage, k, 0) + 1 @@ -229,3 +229,27 @@ function gatecount!(c::AbstractBlock, storage::AbstractDict) storage[k] = get(storage, k, 0) + 1 storage end + +""" + circuit_depth(c::ChainBlock, count_measure::Bool=true) -> Int64 + +The depth of a circuit is a metric that calculates the longest path between the data input and the output. +Each Block counts as taking the same depth (1 unit). + +If `count_measure` is true, `Measure` blocks are also counted. +""" +# TODO: define a TimedBlock that wraps around other blocks, and adds that much time to `currdepth` + +function circuit_depth(c::ChainBlock; count_measure::Bool=true) + deptharr = fill(0, c.n) + touches = collect ∘ occupied_locs + for g in c + if !count_measure && g isa Measure + continue + end + r = touches(g) + currdepth = maximum(getindex.(Ref(deptharr), r)) + deptharr[r] .= currdepth + 1 + end + return maximum(deptharr) +end diff --git a/lib/YaoBlocks/test/blocktools.jl b/lib/YaoBlocks/test/blocktools.jl index b818e7ac..8aa5c8df 100644 --- a/lib/YaoBlocks/test/blocktools.jl +++ b/lib/YaoBlocks/test/blocktools.jl @@ -97,3 +97,38 @@ end res = gatecount(repeat(5, X, (2, 3))) @test res |> values |> sum == 2 end + +@testset "circuit depth" begin + @const_gate cd_U4 = rand(ComplexF64, 4, 4) + @const_gate cd_U2 = rand(ComplexF64, 4, 4) + @const_gate cd_U = rand(ComplexF64, 4, 4) + cd_test_circuit = chain( + 5, + put(1=>X), + put(2=>X), + put(3=>X), + control(1, (4, 5)=>cd_U4), + control(2, (4,5)=>cd_U2), + put(1=>H), + control(1, 2=>T), + put(2=>H), + control(3, (4,5)=>cd_U), + control(1, 3=>T), + control(2, 3=>T), + put(3=>H), + Measure(locs=[1,2,3]) + ) + cd_test_GHZ = chain( + 4, + put(1=>X), + repeat(H, 2:4), + control(2, 1=>X), + control(4, 3=>X), + control(3, 1=>X), + control(4, 3=>X), + repeat(H, 1:4), + ) + @test circuit_depth(cd_test_GHZ) == 5 + @test circuit_depth(cd_test_circuit) == 8 + @test circuit_depth(cd_test_circuit, count_measure=false) == 7 +end