Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new Circuit, Gate, Lane, Moment types #282

Merged
merged 13 commits into from
Jan 14, 2025
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ TenetYaoBlocksExt = "YaoBlocks"
[compat]
AbstractTrees = "0.4"
Adapt = "4"
BijectiveDicts = "0.1"
BijectiveDicts = "0.2.1"
ChainRules = "1.0"
ChainRulesCore = "1.0"
ChainRulesTestUtils = "1"
Expand Down
2 changes: 1 addition & 1 deletion ext/TenetChainRulesCoreExt/non_diff.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

@non_differentiable Tenet.currindex(::Tenet.IndexCounter)
@non_differentiable Tenet.nextindex!(::Tenet.IndexCounter)
@non_differentiable Tenet.resetindex!(::Tenet.IndexCounter)
@non_differentiable Tenet.resetinds!(::Tenet.IndexCounter)

# WARN type-piracy
@non_differentiable Base.setdiff(::Vector{Symbol}, ::Base.ValueIterator)
Expand Down
39 changes: 12 additions & 27 deletions ext/TenetPythonCallExt/Cirq.jl
Original file line number Diff line number Diff line change
@@ -1,45 +1,30 @@
function Base.convert(::Type{Site}, ::Val{Symbol("cirq.devices.line_qubit.LineQubit")}, pyobj::Py)
Site(pyconvert(Int, pyobj.x))
function Base.convert(::Type{Lane}, ::Val{Symbol("cirq.devices.line_qubit.LineQubit")}, pyobj::Py)
Lane(pyconvert(Int, pyobj.x))
end

function Base.convert(::Type{Site}, ::Val{Symbol("cirq.devices.grid_qubit.GridQubit")}, pyobj::Py)
Site((pyconvert(Int, pyobj.row), pyconvert(Int, pyobj.col)))
function Base.convert(::Type{Lane}, ::Val{Symbol("cirq.devices.grid_qubit.GridQubit")}, pyobj::Py)
Lane((pyconvert(Int, pyobj.row), pyconvert(Int, pyobj.col)))
end

function Base.convert(::Type{Quantum}, ::Val{:cirq}, pyobj::Py)
function Base.convert(::Type{Circuit}, ::Val{:cirq}, pyobj::Py)
cirq = pyimport("cirq")
if !pyissubclass(pytype(pyobj), cirq.circuits.circuit.Circuit)
throw(ArgumentError("Expected a cirq.circuits.circuit.Circuit object, got $(pyfullyqualname(pyobj))"))
end

gen = Tenet.IndexCounter()

wire = Dict(qubit => [Tenet.nextindex!(gen)] for qubit in pyobj.all_qubits())
tn = TensorNetwork()
circuit = Circuit()

for moment in pyobj
for gate in moment.operations
matrix = pyconvert(Array, cirq.unitary(gate))

array = reshape(matrix, fill(2, 2 * length(gate.qubits))...)
gatelanes = convert.(Lane, gate.qubits)
gatesites = [Site.(gatelanes; dual=true)..., Site.(gatelanes)...]

inds = (x -> collect(Iterators.flatten(zip(x...))))(
map(gate.qubits) do l
from, to = last(wire[l]), Tenet.nextindex!(gen)
push!(wire[l], to)
(from, to)
end,
)
matrix = pyconvert(Array, cirq.unitary(gate))
array = reshape(matrix, fill(2, length(gatesites))...)

tensor = Tensor(array, Tuple(inds))
push!(tn, tensor)
push!(circuit, Gate(array, gatesites))
end
end

sites = merge(
Dict([convert(Site, qubit)' => first(indices) for (qubit, indices) in wire if first(indices) ∈ tn]),
Dict([convert(Site, qubit) => last(indices) for (qubit, indices) in wire if last(indices) ∈ tn]),
)

return Quantum(tn, sites)
return circuit
end
33 changes: 9 additions & 24 deletions ext/TenetPythonCallExt/Qibo.jl
Original file line number Diff line number Diff line change
@@ -1,40 +1,25 @@
function Base.convert(::Type{Quantum}, ::Val{:qibo}, pyobj::Py)
using Tenet: Gate

function Base.convert(::Type{Circuit}, ::Val{:qibo}, pyobj::Py)
qibo = pyimport("qibo")
qibo.set_backend("numpy")
if !pyissubclass(pytype(pyobj), qibo.models.circuit.Circuit)
throw(ArgumentError("Expected a qibo.models.circuit.Circuit object, got $(pyfullyqualname(pyobj))"))
end

n = pyconvert(Int, pyobj.nqubits)
gen = Tenet.IndexCounter()

wire = [[Tenet.nextindex!(gen)] for _ in 1:n]
tn = TensorNetwork()
circuit = Circuit()
circgates = pyobj.queue

for gate in circgates
matrix = pyconvert(Array, gate.matrix())

qubits = map(x -> pyconvert(Int, x), gate.qubits)
array = reshape(matrix, fill(2, 2 * length(qubits))...)
gatelanes = map(x -> Lane(pyconvert(Int, x)), gate.qubits)
gatesites = [Site.(gatelanes; dual=true)..., Site.(gatelanes)...]

inds = (x -> collect(Iterators.flatten(zip(x...))))(
map(qubits) do l
l += 1
from, to = last(wire[l]), Tenet.nextindex!(gen)
push!(wire[l], to)
(from, to)
end,
)
array = reshape(matrix, fill(2, length(gatesites))...)

tensor = Tensor(array, Tuple(inds))
push!(tn, tensor)
push!(circuit, Gate(array, gatesites))
end

sites = merge(
Dict([Site(site; dual=true) => first(index) for (site, index) in enumerate(wire) if first(index) ∈ tn]),
Dict([Site(site; dual=false) => last(index) for (site, index) in enumerate(wire) if last(index) ∈ tn]),
)

return Quantum(tn, sites)
return circuit
end
33 changes: 7 additions & 26 deletions ext/TenetPythonCallExt/Qiskit.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,12 @@ function Base.convert(::Type{Quantum}, ::Val{:qiskit}, pyobj::Py)
)
end

n = length(pyobj.qregs[0])
gen = Tenet.IndexCounter()

wire = [[Tenet.nextindex!(gen)] for _ in 1:n]
tn = TensorNetwork()
circuit = Circuit()

for instr in pyobj
gatelanes = map(x -> Lane(pyconvert(Int, x._index)), instr.qubits)
gatesites = [Site.(gatelanes; dual=true)..., Site.(gatelanes)...]

# if unassigned parameters, throw
matrix = if pyhasattr(instr, Py("matrix"))
instr.matrix
Expand All @@ -24,29 +23,11 @@ function Base.convert(::Type{Quantum}, ::Val{:qiskit}, pyobj::Py)
if pyisnone(matrix)
throw(ArgumentError("Expected parameters already assigned, but got $(pyobj.params)"))
end

matrix = pyconvert(Array, matrix)
array = reshape(matrix, fill(2, length(gatesites))...)

qubits = map(x -> pyconvert(Int, x._index), instr.qubits)
array = reshape(matrix, fill(2, 2 * length(qubits))...)

inds = (x -> collect(Iterators.flatten(zip(x...))))(
map(qubits) do l
l += 1
from, to = last(wire[l]), Tenet.nextindex!(gen)
push!(wire[l], to)
(from, to)
end,
)

tensor = Tensor(array, Tuple(inds))
push!(tn, tensor)
push!(circuit, Gate(array, gatesites))
end

sites = merge(
Dict([Site(site; dual=true) => first(index) for (site, index) in enumerate(wire) if first(index) ∈ tn]),
Dict([Site(site; dual=false) => last(index) for (site, index) in enumerate(wire) if last(index) ∈ tn]),
)

return Quantum(tn, sites)
return circuit
end
43 changes: 14 additions & 29 deletions ext/TenetYaoBlocksExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@ function flatten_circuit(x)
end
end

function Tenet.Quantum(circuit::AbstractBlock)
n = nqubits(circuit)
gen = Tenet.IndexCounter()
wire = [[Tenet.nextindex!(gen)] for _ in 1:n]
tensors = Tensor[]
function Base.convert(::Type{Circuit}, yaocirc::AbstractBlock)
circuit = Circuit()

for gate in flatten_circuit(circuit)
if gate isa Swap
(a, b) = occupied_locs(gate)
wire[a], wire[b] = wire[b], wire[a]
continue
end
# if gate isa Swap
# (a, b) = occupied_locs(gate)
# wire[a], wire[b] = wire[b], wire[a]
# continue
# end

gatelanes = Lane.(occupied_locs(gate))
gatesites = [Site.(gatelanes; dual=true)..., Site.(gatelanes)...]

# NOTE `YaoBlocks.mat` on m-site qubits still returns the operator on the full Hilbert space
m = length(occupied_locs(gate))
Expand All @@ -31,27 +31,12 @@ function Tenet.Quantum(circuit::AbstractBlock)
else
content(gate)
end
array = reshape(collect(mat(operator)), fill(nlevel(operator), 2 * nqubits(operator))...)

inds = (x -> collect(Iterators.flatten(zip(x...))))(
map(occupied_locs(gate)) do l
from, to = last(wire[l]), Tenet.nextindex!(gen)
push!(wire[l], to)
(to, from)
end,
)

tensor = Tensor(array, inds)
push!(tensors, tensor)
end
array = reshape(collect(mat(operator)), fill(nlevel(operator), length(gatesites))...)

# if a wire has only one index, no gates have been applied to it
sites = merge(
Dict([Site(site; dual=true) => first(index) for (site, index) in enumerate(wire) if length(index) > 1]),
Dict([Site(site; dual=false) => last(index) for (site, index) in enumerate(wire) if length(index) > 1]),
)
push!(circuit, Gate(array, gatesites))
end

return Quantum(Tenet.TensorNetwork(tensors), sites)
return circuit
end

end
Loading
Loading