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

Convert Quimb TensorNetwork types to TensorNetwork, Quantum #207

Merged
merged 10 commits into from
Sep 23, 2024
164 changes: 164 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,167 @@ $RECYCLE.BIN/
.julia
*.excalidraw
archive/
test/.CondaPkg/

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
.pybuilder/
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock

# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
.pdm.toml
.pdm-python
.pdm-build/

# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# pytype static type analyzer
.pytype/

# Cython debug symbols
cython_debug/

# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
5 changes: 5 additions & 0 deletions CondaPkg.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[deps]
qiskit = ""

[pip.deps]
quimb = ""
22 changes: 8 additions & 14 deletions ext/TenetPythonCallExt.jl → ext/TenetPythonCallExt/Qiskit.jl
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
module TenetPythonCallExt

using Tenet
using PythonCall
using PythonCall.Core: pyisnone

pyfullyqualname(pyobj) = join([pytype(pyobj).__module__, pytype(pyobj).__qualname__], '.')

function Tenet.Quantum(pyobj::Py)
pyclassname = pyfullyqualname(pyobj)
if pyclassname != "qiskit.circuit.quantumcircuit.QuantumCircuit"
throw(ArgumentError("Expected a Qiskit's QuantumCircuit object, got $pyclassname"))
function Tenet.Quantum(::Val{:qiskit}, pyobj::Py)
qiskit = pyimport("qiskit")
if !pyissubclass(pytype(pyobj), qiskit.circuit.quantumcircuit.QuantumCircuit)
throw(

Check warning on line 4 in ext/TenetPythonCallExt/Qiskit.jl

View check run for this annotation

Codecov / codecov/patch

ext/TenetPythonCallExt/Qiskit.jl#L1-L4

Added lines #L1 - L4 were not covered by tests
ArgumentError(
"Expected a qiskit.circuit.quantumcircuit.QuantumCircuit object, got $(pyfullyqualname(pyobj))"
),
)
end

n = length(pyobj.qregs[0])
Expand Down Expand Up @@ -54,5 +50,3 @@

return Quantum(tn, sites)
end

end
44 changes: 44 additions & 0 deletions ext/TenetPythonCallExt/Quimb.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
function Tenet.TensorNetwork(::Val{:quimb}, pyobj::Py)
quimb = pyimport("quimb")
if !pyissubclass(pytype(pyobj), quimb.tensor.tensor_core.TensorNetwork)
throw(ArgumentError("Expected a quimb.tensor.tensor_core.TensorNetwork object, got $(pyfullyqualname(pyobj))"))

Check warning on line 4 in ext/TenetPythonCallExt/Quimb.jl

View check run for this annotation

Codecov / codecov/patch

ext/TenetPythonCallExt/Quimb.jl#L1-L4

Added lines #L1 - L4 were not covered by tests
end

ts = map(pyobj.tensors) do tensor
array = pyconvert(Array, tensor.data)
inds = Symbol.(pyconvert(Array, tensor.inds))
Tensor(array, inds)

Check warning on line 10 in ext/TenetPythonCallExt/Quimb.jl

View check run for this annotation

Codecov / codecov/patch

ext/TenetPythonCallExt/Quimb.jl#L7-L10

Added lines #L7 - L10 were not covered by tests
end

return TensorNetwork(ts)

Check warning on line 13 in ext/TenetPythonCallExt/Quimb.jl

View check run for this annotation

Codecov / codecov/patch

ext/TenetPythonCallExt/Quimb.jl#L13

Added line #L13 was not covered by tests
end

function Tenet.Quantum(::Val{:quimb}, pyobj::Py)
quimb = pyimport("quimb")
if pyissubclass(pytype(pyobj), quimb.tensor.circuit.Circuit)
return Quantum(pyobj.get_uni())
elseif pyissubclass(pytype(pyobj), quimb.tensor.tensor_arbgeom.TensorNetworkGenVector)
return Quantum(Val(Symbol("quimb.tensor.tensor_arbgeom.TensorNetworkGenVector")), pyobj)
elseif pyissubclass(pytype(pyobj), quimb.tensor.tensor_arbgeom.TensorNetworkGenOperator)
return Quantum(Val(Symbol("quimb.tensor.tensor_arbgeom.TensorNetworkGenOperator")), pyobj)

Check warning on line 23 in ext/TenetPythonCallExt/Quimb.jl

View check run for this annotation

Codecov / codecov/patch

ext/TenetPythonCallExt/Quimb.jl#L16-L23

Added lines #L16 - L23 were not covered by tests
else
throw(ArgumentError("Unknown treatment for object of class $(pyfullyqualname(pyobj))"))

Check warning on line 25 in ext/TenetPythonCallExt/Quimb.jl

View check run for this annotation

Codecov / codecov/patch

ext/TenetPythonCallExt/Quimb.jl#L25

Added line #L25 was not covered by tests
end
end

function Tenet.Quantum(::Val{Symbol("quimb.tensor.tensor_arbgeom.TensorNetworkGenVector")}, pyobj::Py)
tn = TensorNetwork(pyobj)
sitedict = Dict(Site(pyconvert(Int, i)) => pyconvert(Symbol, pyobj.site_ind(i)) for i in pyobj.sites)
return Quantum(tn, sitedict)

Check warning on line 32 in ext/TenetPythonCallExt/Quimb.jl

View check run for this annotation

Codecov / codecov/patch

ext/TenetPythonCallExt/Quimb.jl#L29-L32

Added lines #L29 - L32 were not covered by tests
end

function Tenet.Quantum(::Val{Symbol("quimb.tensor.tensor_arbgeom.TensorNetworkGenOperator")}, pyobj::Py)
tn = TensorNetwork(pyobj)

Check warning on line 36 in ext/TenetPythonCallExt/Quimb.jl

View check run for this annotation

Codecov / codecov/patch

ext/TenetPythonCallExt/Quimb.jl#L35-L36

Added lines #L35 - L36 were not covered by tests

sitedict = merge!(

Check warning on line 38 in ext/TenetPythonCallExt/Quimb.jl

View check run for this annotation

Codecov / codecov/patch

ext/TenetPythonCallExt/Quimb.jl#L38

Added line #L38 was not covered by tests
Dict(Site(pyconvert(Int, i)) => pyconvert(Symbol, pyobj.lower_ind(i)) for i in pyobj.sites),
Dict(Site(pyconvert(Int, i); dual=true) => pyconvert(Symbol, pyobj.upper_ind(i)) for i in pyobj.sites),
)

return Quantum(tn, sitedict)

Check warning on line 43 in ext/TenetPythonCallExt/Quimb.jl

View check run for this annotation

Codecov / codecov/patch

ext/TenetPythonCallExt/Quimb.jl#L43

Added line #L43 was not covered by tests
end
22 changes: 22 additions & 0 deletions ext/TenetPythonCallExt/TenetPythonCallExt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module TenetPythonCallExt

using Tenet
using PythonCall
using PythonCall.Core: pyisnone

pyfullyqualname(pyobj) = join([pytype(pyobj).__module__, pytype(pyobj).__qualname__], '.')

Check warning on line 7 in ext/TenetPythonCallExt/TenetPythonCallExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/TenetPythonCallExt/TenetPythonCallExt.jl#L7

Added line #L7 was not covered by tests

function Tenet.TensorNetwork(pyobj::Py)
pymodule, _ = split(pyconvert(String, pytype(pyobj).__module__), "."; limit=2)
return TensorNetwork(Val(Symbol(pymodule)), pyobj)

Check warning on line 11 in ext/TenetPythonCallExt/TenetPythonCallExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/TenetPythonCallExt/TenetPythonCallExt.jl#L9-L11

Added lines #L9 - L11 were not covered by tests
end

function Tenet.Quantum(pyobj::Py)
pymodule, _ = split(pyconvert(String, pytype(pyobj).__module__), "."; limit=2)
return Quantum(Val(Symbol(pymodule)), pyobj)

Check warning on line 16 in ext/TenetPythonCallExt/TenetPythonCallExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/TenetPythonCallExt/TenetPythonCallExt.jl#L14-L16

Added lines #L14 - L16 were not covered by tests
end

include("Qiskit.jl")
include("Quimb.jl")

end
1 change: 1 addition & 0 deletions test/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ NetworkLayout = "46757867-2c16-5918-afeb-47bfcb05e46a"
OMEinsum = "ebe7aa44-baf0-506c-a96f-8464559b3922"
Permutations = "2ae35dd2-176d-5d53-8349-f30d82d94d4f"
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
PythonCall = "6099a3de-0909-46bc-b1f4-468b9a2dfc0d"
Quac = "b9105292-1415-45cf-bff1-d6ccf71e6143"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Expand Down
18 changes: 18 additions & 0 deletions test/integration/python/test_qiskit.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
@testset "qiskit" begin
using PythonCall
qiskit = pyimport("qiskit")

circuit = qiskit.QuantumCircuit(3)
circuit.h(0)
circuit.h(1)
circuit.cx(1, 2)
circuit.cx(0, 2)
circuit.h(0)
circuit.h(1)
circuit.h(2)

tn = Tenet.Quantum(circuit)
@test issetequal(sites(tn; set=:inputs), adjoint.(Site.([1, 2, 3])))
@test issetequal(sites(tn; set=:outputs), Site.([1, 2, 3]))
@test Tenet.ntensors(tn) == 7
end
19 changes: 19 additions & 0 deletions test/integration/python/test_quimb.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
@testset "quimb" begin
using PythonCall
qtn = pyimport("quimb.tensor")

# NOTE quimb.circuit.Circuit splits gates by default
qc = qtn.Circuit(3; gate_opts=Dict(["contract" => false]))
gates = [("H", 0), ("H", 1), ("CNOT", 1, 2), ("CNOT", 0, 2), ("H", 0), ("H", 1), ("H", 2)]
qc.apply_gates(gates)

tn = Tenet.Quantum(qc)
@test issetequal(sites(tn; set=:inputs), adjoint.(Site.([0, 1, 2])))
@test issetequal(sites(tn; set=:outputs), Site.([0, 1, 2]))
@test Tenet.ntensors(tn) == 7

tn = Tenet.Quantum(qc.psi)
@test isempty(sites(tn; set=:inputs))
@test issetequal(sites(tn; set=:outputs), Site.([0, 1, 2]))
@test Tenet.ntensors(tn) == 10
end
5 changes: 5 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ if VERSION >= v"1.10"
include("integration/Quac_test.jl")
include("integration/ITensors_test.jl")
include("integration/ITensorNetworks_test.jl")

@testset "Python" begin
include("integration/python/test_quimb.jl")
include("integration/python/test_qiskit.jl")
end
end
end

Expand Down
Loading