Julia is another high-performance fast programming language that could be great for future quantum programmers as an option to code in. There are several resources available online for learning quantum through julia as well. - Error correction also exists for the Julia program - [HOQST ](https://uscqserver.github.io/OpenQuantumTools.jl/dev/)which is mainly an annealing tool but with the recent Nature paper proves that it may be better than qiskit pulse One great source is this article that explains how to [build a quantum circuit simulator in one day](https://blog.rogerluo.dev/2020/03/31/yany/)! ``` using LinearAlgebra function naive_broutine!(r::AbstractVector, U::AbstractMatrix, loc::Int) n = Int(log2(length(r))) # get the number of qubits return kron(I(1<<(n-loc+1)), U), I(1<<loc) end log2i(x::Int64) = !signbit(x) ? (63 - leading_zeros(x)) : throw(ErrorException("nonnegative expected ($x)")) log2i(x::UInt64) = 63 - leading_zeros(x) for N in [8, 16, 32, 64, 128] T = Symbol(:Int, N) UT = Symbol(:UInt, N) @eval begin log2i(x::$T) = !signbit(x) ? ($(N - 1) - leading_zeros(x)) : throw(ErrorException("nonnegative expected ($x)")) log2i(x::$UT) = $(N - 1) - leading_zeros(x) end end function broutine!(r::AbstractVector, U::AbstractMatrix, locs::NTuple{N, Int}) where N end function bmask(itr) isempty(itr) && return 0 ret = 0 for b in itr ret += 1 << (b - 1) end return ret end function bmask(range::UnitRange{Int}) ((1 << (range.stop - range.start + 1)) - 1) << (range.start - 1) end function bmask(::Type{T}, itr) where {T<:Integer} isempty(itr) && return 0 ret = zero(T) for b in itr ret += one(T) << (b - 1) end return ret end function bmask(::Type{T}, range::UnitRange{Int})::T where {T<:Integer} ((one(T) << (range.stop - range.start + 1)) - one(T)) << (range.start - 1) end bmask(args...) = bmask(Int, args...) # this is for removing the infinity call of the later function bmask(::Type{T}) where {T<:Integer} = zero(T) bmask(::Type{T}, positions::Int...) where {T<:Integer} = bmask(T, positions) bmask(args...) = bmask(Int, args...) bmask(::Type{T}) where {T<:Integer} = zero(T) bmask(::Type{T}, positions::Int...) where {T<:Integer} = bmask(T, positions) function bmask(::Type{T}, itr) where {T<:Integer} isempty(itr) && return 0 ret = zero(T) for b in itr ret += one(T) << (b - 1) end return ret end function bmask(::Type{T}, range::UnitRange{Int})::T where {T<:Integer} ((one(T) << (range.stop - range.start + 1)) - one(T)) << (range.start - 1) end (xxx & ~0b001) << 1 + (xxx & 0b001) # = xx00x @inline lmove(b::Int, mask::Int, k::Int)::Int = (b & ~mask) << k + (b & mask) function group_shift(locations) masks = Int[] region_lens = Int[] k_prv = -1 for k in locations # if current position in the contiguous region # since these bits will be moved together with # the first one, we don't need to generate a # new mask if k == k_prv + 1 region_lens[end] += 1 else # we generate a bit mask where the 1st to k-th bits are 1 push!(masks, bmask(0:k-1)) push!(region_lens, 1) end k_prv = k end return masks, region_lens end ```