Git Product home page Git Product logo

quantumclifford.jl's Introduction

QuantumClifford.jl

Documentation Documentation of latest stable version Documentation of dev version
Continuous integration GitHub Workflow Status Buildkite Workflow Status
Code coverage Test coverage from codecov
Static analysis with JET static analysis Aqua QA

A Julia package for working with quantum stabilizer states and Clifford circuits that act on them. Graphs states are also supported. The package is already very fast for the majority of common operations, but there are still many low-hanging fruits performance-wise. See the detailed suggested readings & references page for background on the various algorithms.

To install it use:

] add QuantumClifford

Works efficiently with pure and mixed stabilizer states of thousands of qubits as well as sparse or dense Clifford operations acting upon them.

Implements Pauli frames for fast sampling.

Provides canonicalization, projection, and generation operations, as well as partial traces.

julia> P"X" * P"Z"
-iY

julia> P"X" ⊗ P"Z"
+ XZ

julia> S"-XX
         +ZZ"
- XX
+ ZZ

julia> tCNOT * S"-XX
                 +ZZ"
- X_
+ _Z

The code is vectorized and multithreaded.

Fast, in-place, allocation free implementations.

Quick Benchmarks (click to expand)

Comparison against other Clifford simulators

The only other simulator of similar performance I know of is Stim.

The "low level" functionality is of similar performance in Stim and QuantumClifford but different tradeoffs are made at the higher levels: to multiply in-place 1M-qubit Pauli operators Stim and QuantumClifford.jl both need around 15μs. The difference is inconsequential and depends on compilers and hardware.

Of note is that Stim achieved this performance through high-quality C++ SIMD code of significant sophistication, while QuantumClifford.jl is implemented in pure and simple Julia.

Multiplying two 1 gigaqubit Paulis in 13 ms

julia> a = random_pauli(1_000_000_000);
julia> b = random_pauli(1_000_000_000);
julia> @benchmark QuantumClifford.mul_left!(a,b)
BenchmarkTools.Trial: 373 samples with 1 evaluation.
 Range (min … max):  13.209 ms …  14.304 ms  ┊ GC (min … max): 0.00% … 0.00%
 Time  (median):     13.355 ms               ┊ GC (median):    0.00%
 Time  (mean ± σ):   13.427 ms ± 173.503 μs  ┊ GC (mean ± σ):  0.00% ± 0.00%

 Memory estimate: 0 bytes, allocs estimate: 0.

Canonicalization of a random 1000-qubit stabilizer in 9 ms

julia> @benchmark canonicalize!(s) setup=(s=random_stabilizer(1000))
BenchmarkTools.Trial: 6 samples with 1 evaluation.
 Range (min … max):  8.516 ms …  8.614 ms  ┊ GC (min … max): 0.00% … 0.00%
 Time  (median):     8.536 ms              ┊ GC (median):    0.00%
 Time  (mean ± σ):   8.550 ms ± 35.883 μs  ┊ GC (mean ± σ):  0.00% ± 0.00%

 Memory estimate: 0 bytes, allocs estimate: 0.

Dense tableaux multiplication (tensor product of 500 CNOT gates acting 1000 qubits) in 17 ms

julia> @benchmark apply!(s, gate) setup=(s=random_stabilizer(1000); gate=tensor_pow(tCNOT,500))
BenchmarkTools.Trial: 6 samples with 1 evaluation.
 Range (min … max):  16.879 ms … 17.064 ms  ┊ GC (min … max): 0.00% … 0.00%
 Time  (median):     17.010 ms              ┊ GC (median):    0.00%
 Time  (mean ± σ):   16.997 ms ± 63.050 μs  ┊ GC (mean ± σ):  0.00% ± 0.00%

 Memory estimate: 800 bytes, allocs estimate: 4.

Sparse gate application to only specified qubits in a 1000 qubit tableau in 3 μs

julia> @benchmark apply!(s, sCNOT(32,504)) setup=(s=random_stabilizer(1000))
BenchmarkTools.Trial: 6 samples with 8 evaluations.
 Range (min … max):  2.867 μs …   3.228 μs  ┊ GC (min … max): 0.00% … 0.00%
 Time  (median):     3.043 μs               ┊ GC (median):    0.00%
 Time  (mean ± σ):   3.049 μs ± 119.106 ns  ┊ GC (mean ± σ):  0.00% ± 0.00%

 Memory estimate: 0 bytes, allocs estimate: 0.

Measuring a dense 1000 qubit Pauli operator in 18 μs

julia> s=random_destabilizer(1000); p=random_pauli(1000);

julia> @benchmark project!(_s,_p) setup=(_s=copy(s);_p=copy(p)) evals=1
BenchmarkTools.Trial: 10000 samples with 1 evaluation.
 Range (min … max):  17.753 μs … 39.444 μs  ┊ GC (min … max): 0.00% … 0.00%
 Time  (median):     21.971 μs              ┊ GC (median):    0.00%
 Time  (mean ± σ):   21.893 μs ±  2.234 μs  ┊ GC (mean ± σ):  0.00% ± 0.00%

 Memory estimate: 480 bytes, allocs estimate: 4.

Measuring a single qubit in a 1000 qubit tableau in 15 μs

julia> s=MixedDestabilizer(random_destabilizer(1000));

julia> @benchmark projectY!(_s,42) setup=(_s=copy(s)) evals=1
BenchmarkTools.Trial: 10000 samples with 1 evaluation.
 Range (min … max):  15.379 μs … 37.630 μs  ┊ GC (min … max): 0.00% … 0.00%
 Time  (median):     16.912 μs              ┊ GC (median):    0.00%
 Time  (mean ± σ):   17.120 μs ±  1.335 μs  ┊ GC (mean ± σ):  0.00% ± 0.00%

 Memory estimate: 464 bytes, allocs estimate: 5.

Benchmarks executed on a single thread on Ryzen Zen4 16-core CPU:

julia> versioninfo()
Julia Version 1.9.1
Commit 147bdf428cd (2023-06-07 08:27 UTC)
Platform Info:
  OS: Linux (x86_64-linux-gnu)
  CPU: 32 × AMD Ryzen 9 7950X 16-Core Processor
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-14.0.6 (ORCJIT, znver3)
  Threads: 1 on 32 virtual cores

More detailed benchmarks can be seen at github.com/QuantumSavory/QuantumCliffordBenchmarksLog.

quantumclifford.jl's People

Contributors

abhishek-1bhatt avatar adrianariton avatar amicciche avatar benzillaist avatar chenzhao44 avatar dependabot[bot] avatar dmtrung14 avatar fe-r-oz avatar github-actions[bot] avatar gsommers avatar ismoldayev avatar jlapeyre avatar krastanov avatar pravissw avatar royess avatar shayan-p avatar shuge-mit avatar timholy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

quantumclifford.jl's Issues

partial trace of mixeddestabilizer

Hi

I have a problem calculating the partial trace of a mixed destabilizer. I tried

julia> state = MixedDestabilizer(random_destabilizer(5))
Rank 5 stabilizer
+ _Z_YX
+ _Z_XZ
- ZZ___
- YYX_Y
+ Z_YZY
═══════
- Z_ZYY
+ YXYYY
- _X_XX
- XXXXX
- __XZY
═══════

Then I try to trace out the first qubit

julia> traceout!(copy(state),[1])
Rank 3 stabilizer
- YYX_Y
+ Z_YZY
- ZZ___
━━━━━━━
+ ___ZY
+ YXXXX
━━━━━━━
- ___XX
- __XZY
- _X_XX
━━━━━━━
- Z_ZYY
+ XXX__

Why do I have a rank 3 stabilizer state rather than rank 2.

I think the stabilizers are

julia> stabilizerview(state)
- Z_ZYY
+ YXYYY
- _X_XX
- XXXXX
- __XZY

Only two of them are nonzero after I trace out the first qubit, right?

Thanks

Adding amplitude damping channel in Clifford circuit.

Hi,

I just start learning the use of this package. My attempt is to use Clifford circuit to simulate a quantum circuit with random unitary evolution, projective measurement and amplitude damping. Is it possible to achieve this or at least some approximation of the amplitude damping channel? By the way, if this is not the correct place to ask this kind of question, I apologize for it. (Is there any forum for beginners of this package?)

Dephasing implementation in QuantumCliffford.jl

Here, I have written a code for the implementation of dephasing. I am not sure if I have to make more modifications to my code in order to have a better speed. I am yet to benchmark it. The definition of dephasing is defined in page 4 of supplemental material of the paper https://arxiv.org/pdf/2202.12905.pdf. Please have a look:

function rowswapping(mixdstat,row1,row2)
    tabl1 = tab(mixdstat)
    if row1 == row2
        return tabl1
    else
        tabl1[row1], tabl1[row2] = tabl1[row2], tabl1[row1]
        numq = nqubits(mixdstat)
        tabl1[row1+numq], tabl1[row2+numq] = tabl1[row2+numq], tabl1[row1+numq]
        return tabl1
    end
end

function dephasingch(sysstate, qloc, syssize)
    orgrank = sysstate.rank
    prostate, indx, results = projectZ!(copy(sysstate), qloc) 
    if indx == 0 || indx > orgrank
        return sysstate
    else
        swappedtabl = rowswapping(sysstate, indx, orgrank)
        updatstate = MixedDestabilizer(swappedtabl, orgrank-1)
        return updatstate
    end
end

Clifford Operation to Clifford Circuit transformation

There are many ways to synthesize a circuit (with nothing bigger than 2-qubit gates) out of given Clifford Operation. They are also equivalent to a canonicalization procedure.

Track and implement them.

Implement sparse versions for each of the "assembler" gates.

Make test files selfcontained

Some julia projects have taken to the style of having each test file be a self contained module that can be copy pasted directly into a REPL. See for instance https://github.com/Krastanov/QuantumSavory.jl/blob/master/test/test_register_interface.jl which uses @safetestset. This style would make it easier to debug failing tests: currently we need to find what constants are defined and what libraries are imported outside of the test file, before rerunning the test interactively; with this change it would be easy to just copy-paste one single file.

Inconsistency when calculating entanglement, possibly because of wrong graphs from stabilizers

I implemented two ways of calculating bipartite entanglement entropy base on this repo. One is by clipping algorithm. (Ref: Phys. Rev. B 100, 134306 (2019).) The other is by calculating the rank of bipartite adjacency matrix obtained by Graphs.Graph(s::AbstractStabilizer). (Ref: arXiv:quant-ph/0602096.) And I also used Qiskit to cross check my results, using "statevector_simulator" backend.

In my 800 test cases, clipping algorithm agrees with Qiskit simulation. But there are 30 cases that entropy values from graphs differ by 1 or 2. So I think this may be a result of wrong graphs with more or less edges between two subsystems.

To help reproduce the issue:

I know the issue involves many implementation details. I am willing to do more checks if needed.

`Polyester` causes TTFX issues

num_threads causes invalidations

using SnoopCompileCore
invalidations = @snoopr begin
    using QuantumClifford
    #QuantumClifford._precompile()
end
using SnoopCompile
##
length(uinvalidated(invalidations))
##
trees = invalidation_trees(invalidations)
##
ftrees = filtermod(QuantumClifford, trees) # ← a lot of num_threads issues
#tinf = @snoopi_deep QuantumClifford._my_precompile_()
#Core.Compiler.Timings.ROOT() with 54 direct children

Minimize allocations in `project!`

image

ds = random_destabilizer(1000)
s = copy(stabilizerview(ds))
p = random_pauli(1000)#(de)stabilizerview(ds)[end-10]
@benchmark project!(s_,$p) setup=(s_=copy(s)) evals=1
@benchmark project!(ds_,$p) setup=(ds_=copy(ds)) evals=1

Measuring Pauli in N(S) Throws Exception

I've noticed that, when trying to measure an operator which is in the logical group of a MixedDestabilizer, a BoundsError is thrown. I've tried to run the following minimal example:

using QuantumClifford
using QuantumClifford.Experimental.NoisyCircuits
using Test

state = Register(MixedDestabilizer(S"ZZ"), zeros(Bool, 1))
meas = DenseMeasurement(P"ZI", 1)

@test_throws nothing state, flag = applyop!(state, meas)

The result I see is:

Test Failed at REPL[98]:1
  Expression: (state, flag) = applyop!(state, op)
    Expected: nothing
      Thrown: BoundsError(UInt8[0x00, 0x00], (0,))
ERROR: There was an error during testing

I think that this is happening because this case involves a random measurement result, without the measured operator anticommuting with a stabilizer.

Taking a look around the codebase, I've noticed a few things. First, the BoundsError is coming from either line 436 or 438 of NoisyCircuits.jl, which attempts to set stabilizerview(stab).phases[anticom], where stab and anticom come from stab,anticom,r = project!(stab, op.pauli) on line 433.
In project!(d::MixedDestabilizer,pauli::PauliOperator;keep_result::Bool=true,phases::Bool=true) (beginning line 356, project_trace_reset.jl), there's some logic to determine the index of the stabilizer that pauli anticommutes with. There's a separate variable called anticomlog which gets set to j if pauli anticommutes with logical j (or something like this), but this index never gets returned.
This means that, when we get to the if isnothing(r) that determines whether we're going to put a phase on a row of the tableau, we've correctly determined that the measurement result is random, but the index of the new stabilizer that needs a phase update is set to 0, rather than the index of the new stabilizer which is proportional to pauli.
This is a little tricky to deal with, since it's not clear that the index of the anticommuting logical will be the same as the index of the new stabilizer that needs its phase set.

a lot of manual loops instead of `findfirst` in `project!` and others

Weirdly, findfirst seems slower...

function f1(stabilizer, qubit)
    anticommutes = 0
    r = length(stabilizer)
    for i in 1:r # The explicit loop is faster than anticommutes = findfirst(row->comm(pauli,stabilizer,row)!=0x0, 1:r); both do not allocate.
        if isZ(stabilizer,i,qubit)
            anticommutes = i
            break
        end
    end
    return anticommutes
end

function f2(stabilizer, qubit)
    r = length(stabilizer)
    findfirst(i->isZ(stabilizer,i,qubit), 1:r)
end
##
N = 1000
s = ghz(N);
##
@benchmark f1(_s, N) setup=(_s=copy(s))
##
@benchmark f2(_s, N) setup=(_s=copy(s))

track down and fix broken tests

There are a number of broken tests in the unit tests (marked with @test_broken). Clean them up and either fix the issues or implement throw(...) error messages explaining why there is an issue (switching from @test_broken to @test_throws).

add clipping algorithm and bipartite entanglement calculation

As I mentioned in #57 , I have created a fork https://github.com/royess/QuantumClifford.jl/tree/dev-clipping to add clipping algorithm and entanglement entropy calculation. (Ref: Phys. Rev. B 100, 134306 (2019).) And I think it will be great if I can merge them into the original repo.

My implementations allow us to do following things:

  1. Clipping algorithm. Briefly speaking, the algorithm can turn a stabilizer state into clipped gauge, where at each qubit the number of left and right endpoints of stabilizers stay are 2. And the two endpoints at each qubit is different Pauli operator. (Ref: Phys. Rev. X 7, 031016 (2017).)
  2. Bigram. Based on clipping algorithm, we can collect a table of locations of endpoints, called the bigram. Bigram is unique for a stabilizer state. And the length distribution from bigram also gives some physical information in the first reference paper.
  3. Bipartite entanglement entropy. Based on bigram, we can easily calculate bipartite entanglement entropy of a contiguous subregion.

The implementations are tested by random stabilizer states. For entanglement entropy, @Krastanov and I have cross checked with a pure-Julia and a Qiskit implementation.

Besides, as dicussed in #57 , @Krastanov and I proposed three ways (including clipping algorithm) to calculate entanglement entropy. And I think we need find a good way to arrange them.

If @Krastanov agrees, we may dicuss in details about a PR. Thanks!

canonicalize_clip! for mixed stabilizer states

In the function canonicalize_clip!, on line entanglement.jl, if you change

 k2 = findfirst(let j=j, k1=k1; k->
                           (|(tab[k,j]...) & # not identity
                           (tab[k,j]!=tab[k1,j])) end, # not same as k1
                           k1+1:columns)

to

 k2 = findfirst(let j=j, k1=k1; k->
                           (|(tab[k,j]...) & # not identity
                           (tab[k,j]!=tab[k1,j])) end, # not same as k1
                           k1+1:rows)

then the clipped gauge construction works for mixed states as well. Then the associated entanglement_entropy function needs to be modified (line 188):

length(subsystem_range) - count(r->(r[1] in subsystem_range && r[2] in subsystem_range, eachrow(bg))

Calculating entropy or negavity

Hi,

Is there a function which can calculate the entropy like Renyi entropy or von Neuman entropy? Do we have a function to calculate negativity? Suppose I want to divide the system into A and B. Then I want to trace out the part of B and use the partial density operator of A to calculate these quantities, how to do it?

Thanks

petrajectories is slow

good_bell_state = S"XX
                    ZZ"
canonicalize_rref!(good_bell_state)[1]

function state_tensor_pow(state::Stabilizer{Vector{UInt8}, Matrix{UInt64}},power::Integer)
    result=state
    for i in 1:power-1
        result=result⊗state
    end
    return result
end

function append_permutation_op!(circuit,permutation,qubit)
    if permutation==2
        gate=Hadamard⊗Hadamard
    elseif permutation==3
        gate=(Hadamard*Phase*Hadamard)⊗(Phase*Hadamard*Phase)
    elseif permutation==4
        gate=(Phase*Hadamard)⊗(Hadamard*Phase*Hadamard*Phase)
    elseif permutation==5
        gate=(Phase*Hadamard*Phase*Hadamard)⊗(Hadamard*Phase*Hadamard*Phase*Hadamard*Phase*Hadamard*Phase)
    elseif permutation==6
        gate=(Hadamard*Phase*Hadamard*Phase*Hadamard)⊗(Hadamard*Hadamard*Phase*Hadamard*Phase*Hadamard*Phase*Hadamard*Phase)
    end
    if permutation!=1
        circuit=append!(circuit,[SparseGate(gate,[qubit*2-1,qubit*2])])
    end
    return circuit
end 

function append_permutation_cnot!(circuit,permutation,pair)
    a,b=pair
    circuit=append_permutation_op!(circuit,permutation[1],a)
    circuit=append_permutation_op!(circuit,permutation[2],b)
    circuit=append!(circuit,[SparseGate(CNOT,[a*2-1,b*2-1]),SparseGate(CNOT,[a*2,b*2])])
    return circuit
end

function convert(abstract_circuit,netnoise_value,N)
    #convert abstract circuit representation to complete representation
    circuit=[]
    netnoise = UnbiasedUncorrelatedNoise(netnoise_value/N)
    for i in abstract_circuit
        if i[1]=="M"
            if i[2][1]==1
                measurement1=X
                measurement2=X
            elseif i[1][1]==2
                measurement1=Y
                measurement2=-Y
            else
                measurement1=Z
                measurement2=Z
            end
            for q in i[3]
                circuit=append!(circuit,[BellMeasurement([measurement1,measurement2],[q*2-1,q*2])])
                circuit=append!(circuit,[Reset(good_bell_state,[q*2-1,q*2])])
                circuit=append!(circuit,[NoiseOp(netnoise,[q*2-1,q*2])])
            end
        else
            circuit=append_permutation_cnot!(circuit,i[2],i[3])
        end
    end
    circuit=append!(circuit,[VerifyOp(good_bell_state, [1,2])])
    return circuit
end

make_noisy(g::SparseGate, noise) = NoisyGate(g, UnbiasedUncorrelatedNoise(1//3*noise))
make_noisy(m::BellMeasurement, noise) = NoisyBellMeasurement(m, noise)
make_noisy(other_op, noise) = other_op
make_noisy(circuit::AbstractVector, noise) = [make_noisy(op, noise) for op in circuit];

circuit=convert([("CN", [1, 6], [1, 3]), ("CN", [4, 1], [1, 2]), ("CN", [5, 3], [3, 2]), ("CN", [5, 5], [2, 3]), ("M", [1], [3]), ("CN", [5, 1], [1, 3]), ("CN", [6, 6], [3, 2]), ("M", [2], [3]), ("CN", [1, 3], [1, 2]), ("CN", [1, 1], [2, 3]), ("CN", [4, 6], [1, 2]), ("CN", [4, 4], [2, 3]), ("CN", [5, 4], [3, 2]), ("M", [2], [2, 3])],0.1,3)
N=3
netnoise_value=0.1
localnoise_value=0.01
initial_state=state_tensor_pow(good_bell_state,N)
netnoise = UnbiasedUncorrelatedNoise(netnoise_value/N)
netnoise_opall = NoiseOpAll(netnoise);
c = [netnoise_opall,circuit...]
c = make_noisy(c, localnoise_value)
@time pe_allnoise = petrajectories(initial_state, c)

output:

4.772920 seconds (8.90 M allocations: 517.571 MiB, 3.64% gc time, 43.27% compilation time)
Dict{Symbol, Float64} with 3 entries:
  :undetected_failure => 0.0220938
  :detected_failure   => 0.401384
  :true_success       => 0.15239

problem:
petrajectories takes long time when calling long circuits. This step takes the majority of time of the optimization circuits.

More intuitive documentation around applying gates to tableaux with apply!()

When I first looked through the documentation, I found this example on the Manual page:
apply!(s, tCNOT, [4,2])

This became the basis for how I thought to use apply!(). For a while, I could not figure out how to use apply!() to apply a simple X gate to qubit (let's say qubit 2). The documentation says that sX is supported by apply!(), but using only the aforementioned example as a base, you'd get an error if you tried:
apply!(s, sX, [2])

I now know that I should do apply!(s, sX(2)), but this perhaps is unintuitive to some people. My suggestion is to either make applying various gates with apply!() uniform in how to provide arguments, or at least provide some more explanations and simple examples early in the documentation so that it's more clear how to apply gates.

higher test coverage

The test coverage is only 80%. While it covers most of the "math" algorithms, it does not cover well the various warnings and error messages raised on inconsistent input. Both can be improved (but improving the Experimental modules is not worth it yet).

Conversion of `Stabilizer` to canonical `CliffordOperator`

CliffordOperator(s::Stabilizer) = CliffordOperator(tab(MixedDestabilizer(s))) would be wrong because the row operations involved in creating a MixedDestabilizer changes the order of the qubits. Create a version of canonicalize_gott! that knows how to undo row operations and use it for the creation of CliffordOperator. Check that there are no lingering bugs in logdot.

Code encoding/decoding unitaries

For each stabilizer code there is a encoding and decoding Clifford operator. Provide functionality that gives these circuits.

Error in Jupyter notebook tutorial

In the code block

initial_state = good_bell_stategood_bell_state
circuit = [
    SparseGate(CPHASE, [1,3]),
    SparseGate(CPHASE, [2,4]),
    BellMeasurement([X,X], [3,4]),
    VerifyOp(good_bell_state, [1,2])
]
displaycircuit(circuit)

The following error occurs:

MethodError: no method matching length(::SparseGate)

Stacktrace:
[1] _similar_for(::UnitRange{Int64}, ::Type{Any}, ::SparseGate, ::Base.HasLength) at .\array.jl:597
[2] _collect(::UnitRange{Int64}, ::SparseGate, ::Base.HasEltype, ::Base.HasLength) at .\array.jl:630
[3] collect(::SparseGate) at .\array.jl:624
[4] broadcastable(::SparseGate) at .\broadcast.jl:682
[5] broadcasted at .\broadcast.jl:1255 [inlined]
[6] circuitwidth(::SparseGate) at C:\Users\lcg75.julia\packages\Quantikz\Ni7Ey\src\Quantikz.jl:321
[7] _broadcast_getindex_evalf at .\broadcast.jl:648 [inlined]
[8] _broadcast_getindex at .\broadcast.jl:621 [inlined]
[9] getindex at .\broadcast.jl:575 [inlined]
[10] copy at .\broadcast.jl:876 [inlined]
[11] materialize at .\broadcast.jl:837 [inlined]
[12] circuitwidth(::Array{AbstractOperation,1}) at C:\Users\lcg75.julia\packages\Quantikz\Ni7Ey\src\Quantikz.jl:321
[13] displaycircuit(::Array{AbstractOperation,1}; scale::Int64, kw::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}) at C:\Users\lcg75.julia\packages\Quantikz\Ni7Ey\src\Quantikz.jl:449
[14] displaycircuit(::Array{AbstractOperation,1}) at C:\Users\lcg75.julia\packages\Quantikz\Ni7Ey\src\Quantikz.jl:449
[15] top-level scope at In[38]:8
[16] include_string(::Function, ::Module, ::String, ::String) at .\loading.jl:1091

boundchecking in `apply!` and better out-of-bounds handling

When I tried apply!(state,tHadamard,[2,3]), I got an error due to using [2,3]. This was my mistake, however afterwards, the state had changed. Perhaps checking for this error before modifying the state would allow for greater robustness?

スクリーンショット 2023-04-06 16 16 29

Problem about using enumerate_cliffords

Hi Stefan:

I just update QuantumClifford to v"0.5.2". But now I face a problem when I try to generate all 2-qubit gates by collect(enumerate_cliffords(2)). The error I got is

julia> cliffords = collect(enumerate_cliffords(2))
ERROR: MethodError: no method matching var"#rowswap!#43"(::Bool, ::typeof(QuantumClifford.rowswap!)                                                             , ::Stabilizer{Vector{UInt8}, Matrix{UInt64}}, ::Int64, ::Int64)
Closest candidates are:
  var"#rowswap!#43"(::Val{B}, ::typeof(QuantumClifford.rowswap!), ::Stabilizer, ::Any, ::Any) where                                                              B at ~/.julia/packages/QuantumClifford/jpKJt/src/QuantumClifford.jl:895
Stacktrace:
 [1] symplecticGS(pauli::PauliOperator{Array{UInt8, 0}, Vector{UInt64}}; padded_n::Int64)
   @ QuantumClifford ~/.julia/packages/QuantumClifford/jpKJt/src/enumeration.jl:107
 [2] enumerate_cliffords_slow(n::Int64, i::BigInt; padded_n::Int64, onlycoset::Bool)
   @ QuantumClifford ~/.julia/packages/QuantumClifford/jpKJt/src/enumeration.jl:133
 [3] #enumerate_cliffords#148
   @ ~/.julia/packages/QuantumClifford/jpKJt/src/enumeration.jl:124 [inlined]
 [4] #152
   @ ./none:0 [inlined]
 [5] iterate
   @ ./generator.jl:47 [inlined]
 [6] collect(itr::Base.Generator{UnitRange{BigInt}, QuantumClifford.var"#152#154"{Int64, Int64}})
   @ Base ./array.jl:724
 [7] top-level scope
   @ REPL[6]:1

Is anything changed in the new version of QuantumClifford?

Thanks.

Make an interface to QEC libraries, specifically so that you have access to predefined codes

This can be based around package extensions and PythonCall interfaces, similar to how we are doing python-based decoders. E.g. see how we have implemented the pymatching decoder interface:

More detailed method descriptions for package

As a newbie, I have some problems understanding a few of the descriptions. Some of the methods could be documented based on their actions and the expected results.

  • the MixedDestabilizer could be phrased as:
    "Keeping track of the r constraints over n qubits, resulting in r qubits that trigger check on the unique corresponding constraint in the matrix, and (n-r) qubits that do not trigger check in any of the constraints"

  • the sMZ gate, make_noisy, and UnbiasedUncorrelatedNoise can also be defined more specifically

OSX compilation

It seems that Quantiks does not compile because Tectronic does not compile on OSX M1 chip (arm64)


      Info Packages marked with ⌃ and ⌅ have new versions available, but those with ⌅ are restricted by compatibility constraints from upgrading. To see why use `status --outdated -m`
    Building GR → `~/.julia/scratchspaces/44cfe95a-1eb2-52ea-b672-e2afdf69b78f/cf0a9940f250dc3cb6cc6c6821b4bf8a4286cf9c/build.log`
Precompiling project...
  ✗ QuantumClifford
  ✗ QuantumCliffordPlots
  71 dependencies successfully precompiled in 56 seconds. 366 already precompiled. 2 skipped during auto due to previous errors.
  2 dependencies errored. To see a full report either run `import Pkg; Pkg.precompile()` or load the packages
[ Info: Precompiling QuantumClifford [0525e862-1e90-11e9-3e4d-1b39d7109de1]
ERROR: LoadError: Cannot locate artifact 'tectonic_bin' for aarch64-apple-darwin-libgfortran5-cxx11-julia_version+1.8.

TagBot trigger issue

This issue is used to trigger TagBot; feel free to unsubscribe.

If you haven't already, you should update your TagBot.yml to include issue comment triggers.
Please see this post on Discourse for instructions and more details.

If you'd like for me to do this for you, comment TagBot fix on this issue.
I'll open a PR within a few hours, please be patient!

simplify random operator generation

Currently the code branches a lot on the size of the operator being generated (using ints for n<30, float for n<500, bigint ootherwise). ILog2 takes care of some of that branching. See how much you can simplify the code by using it. See #47 (comment)

inference of `random_destabilizer`

random_destabilizer causes high TTFX

using SnoopCompileCore
invalidations = @snoopr begin
    using QuantumClifford
    #QuantumClifford._precompile()
end
using SnoopCompile
##
length(uinvalidated(invalidations))
##
trees = invalidation_trees(invalidations)
##
ftrees = filtermod(QuantumClifford, trees)
##
tinf = @snoopi_deep QuantumClifford._my_precompile_() # InferenceTimingNode: 6.178558/22.063535 on Core.Compiler.Timings.ROOT() with 54 direct children
##
staletrees = precompile_blockers(trees, tinf) 
##
@time using SnoopCompile
@time using QuantumClifford
@time using ProfileView
##
fg = flamegraph(tinf)
ProfileView.view(fg)

image

The large bunch at the start is due to random_destabilizer.

bug in `reset_qubits!`

using QuantumClifford
using QuantumClifford: mixed_stab_looks_good, mixed_destab_looks_good
using Random
using LinearAlgebra
##
test_sizes = [10]
for N in test_sizes, lala in 1:100
    for R in [rand(N÷2:N*2÷3), N]
        if N<10
            @test_broken error("can not process empty stab")
            continue
        end
        s = random_stabilizer(R,N)
        newstate = random_stabilizer(rand(N÷4:N*2÷3))
        perm = randperm(N)[1:nqubits(newstate)]
        # Testing MixedDestabilizer
        md = MixedDestabilizer(s)
        mdr1 = reset_qubits!(copy(md), newstate,perm)
        if !mixed_destab_looks_good(mdr1)
            error("bug")
        end
    end
end

caught by the CI

How to get a maximally mixed state

Hi,

How to get a maximally mixed state? I think this is a stabilizer state, right? The code state = one(MixedDestabilier,n,n) gives me a pure state with all spins up, right? (I apologize if I made mistakes. I am still slowly learning this field). Also, which reference talks about the destabilizers of mixed state? I understand the pure state case but for the mixed state case, it is not quite clear to me. Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.