diff --git a/Manifest.toml b/Manifest.toml new file mode 100644 index 0000000..9a6e443 --- /dev/null +++ b/Manifest.toml @@ -0,0 +1,168 @@ +# This file is machine-generated - editing it directly is not advised + +julia_version = "1.10.0" +manifest_format = "2.0" +project_hash = "e792fc9a842e3a58642984e85ced8d4167b179fd" + +[[deps.ArgTools]] +uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" +version = "1.1.1" + +[[deps.Artifacts]] +uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" + +[[deps.Base64]] +uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" + +[[deps.CompilerSupportLibraries_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" +version = "1.0.5+1" + +[[deps.Conda]] +deps = ["Downloads", "JSON", "VersionParsing"] +git-tree-sha1 = "51cab8e982c5b598eea9c8ceaced4b58d9dd37c9" +uuid = "8f4d0f93-b110-5947-807f-2305c1781a2d" +version = "1.10.0" + +[[deps.Dates]] +deps = ["Printf"] +uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" + +[[deps.Downloads]] +deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] +uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" +version = "1.6.0" + +[[deps.FileWatching]] +uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" + +[[deps.JSON]] +deps = ["Dates", "Mmap", "Parsers", "Unicode"] +git-tree-sha1 = "31e996f0a15c7b280ba9f76636b3ff9e2ae58c9a" +uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" +version = "0.21.4" + +[[deps.LibCURL]] +deps = ["LibCURL_jll", "MozillaCACerts_jll"] +uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" +version = "0.6.4" + +[[deps.LibCURL_jll]] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] +uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" +version = "8.4.0+0" + +[[deps.LibSSH2_jll]] +deps = ["Artifacts", "Libdl", "MbedTLS_jll"] +uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" +version = "1.11.0+1" + +[[deps.Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" + +[[deps.LinearAlgebra]] +deps = ["Libdl", "OpenBLAS_jll", "libblastrampoline_jll"] +uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" + +[[deps.MacroTools]] +deps = ["Markdown", "Random"] +git-tree-sha1 = "2fa9ee3e63fd3a4f7a9a4f4744a52f4856de82df" +uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" +version = "0.5.13" + +[[deps.Markdown]] +deps = ["Base64"] +uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" + +[[deps.MbedTLS_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" +version = "2.28.2+1" + +[[deps.Mmap]] +uuid = "a63ad114-7e13-5084-954f-fe012c677804" + +[[deps.MozillaCACerts_jll]] +uuid = "14a3606d-f60d-562e-9121-12d972cd8159" +version = "2023.1.10" + +[[deps.NetworkOptions]] +uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" +version = "1.2.0" + +[[deps.OpenBLAS_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] +uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" +version = "0.3.23+2" + +[[deps.Parsers]] +deps = ["Dates", "PrecompileTools", "UUIDs"] +git-tree-sha1 = "8489905bcdbcfac64d1daa51ca07c0d8f0283821" +uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" +version = "2.8.1" + +[[deps.PrecompileTools]] +deps = ["Preferences"] +git-tree-sha1 = "03b4c25b43cb84cee5c90aa9b5ea0a78fd848d2f" +uuid = "aea7be01-6a6a-4083-8856-8a6e6704d82a" +version = "1.2.0" + +[[deps.Preferences]] +deps = ["TOML"] +git-tree-sha1 = "00805cd429dcb4870060ff49ef443486c262e38e" +uuid = "21216c6a-2e73-6563-6e65-726566657250" +version = "1.4.1" + +[[deps.Printf]] +deps = ["Unicode"] +uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" + +[[deps.PyCall]] +deps = ["Conda", "Dates", "Libdl", "LinearAlgebra", "MacroTools", "Serialization", "VersionParsing"] +git-tree-sha1 = "9816a3826b0ebf49ab4926e2b18842ad8b5c8f04" +uuid = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" +version = "1.96.4" + +[[deps.Random]] +deps = ["SHA"] +uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" + +[[deps.SHA]] +uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" +version = "0.7.0" + +[[deps.Serialization]] +uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" + +[[deps.TOML]] +deps = ["Dates"] +uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" +version = "1.0.3" + +[[deps.UUIDs]] +deps = ["Random", "SHA"] +uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" + +[[deps.Unicode]] +uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" + +[[deps.VersionParsing]] +git-tree-sha1 = "58d6e80b4ee071f5efd07fda82cb9fbe17200868" +uuid = "81def892-9a0e-5fdd-b105-ffc91e053289" +version = "1.3.0" + +[[deps.Zlib_jll]] +deps = ["Libdl"] +uuid = "83775a58-1f1d-513f-b197-d71354ab007a" +version = "1.2.13+1" + +[[deps.libblastrampoline_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" +version = "5.8.0+1" + +[[deps.nghttp2_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" +version = "1.52.0+1" diff --git a/Project.toml b/Project.toml new file mode 100644 index 0000000..4cbd81d --- /dev/null +++ b/Project.toml @@ -0,0 +1,11 @@ +name = "PyQDecoders" +uuid = "17f5de1a-9b79-4409-a58d-4d45812840f7" +authors = ["Stefan Krastanov "] +version = "0.1.0" + +[deps] +Conda = "8f4d0f93-b110-5947-807f-2305c1781a2d" +PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" + +[compat] +PyCall = "1.96" diff --git a/README.md b/README.md new file mode 100644 index 0000000..f55475f --- /dev/null +++ b/README.md @@ -0,0 +1,122 @@ +A Julia meta-package for accessing the python libraries `pymatching` (for MWPM-like decoders) and `ldpc` (for BP-like decoders). + +# How to install + +If you plan to use a python environment you are managing yourself, just make sure that julia is started from that environment and run + +`] add https://github.com/QuantumSavory/PyQDecoders.jl#master` + +You might get error messages telling you that you need to install some python packages in that environment of yours. + +If you want julia to automatically take care of creating a hidden python environment that it manages itself, do `ENV["PYTHON"] = ""` before you install `PyQDecoders.jl` + +# How to use + +## `pymatching` + +The python pymatching module is immediately available: + +``` +julia> using PyQDecoders + +julia> PyQDecoders.pm +PyObject +``` + +Running the example from `pymatching`'s original Readme: + +``` +julia> using PyQDecoders: sps, np, pm + +julia> H = sps.csc_matrix( + [1 1 0 0 0; + 0 1 1 0 0; + 0 0 1 1 0; + 0 0 0 1 1]) +PyObject <4x5 sparse matrix of type '' + with 8 stored elements in Compressed Sparse Column format> + +julia> weights = [4, 3, 2, 3, 4] +5-element Vector{Int64}: + 4 + 3 + 2 + 3 + 4 + +julia> matching = pm.Matching(H, weights=weights) +PyObject + +julia> prediction = matching.decode([0, 1, 0, 1]) +5-element Vector{UInt8}: + 0x00 + 0x00 + 0x01 + 0x01 + 0x00 + +julia> prediction, solution_weight = matching.decode([0, 1, 0, 1], return_weight=true); + +julia> prediction +5-element Vector{UInt8}: + 0x00 + 0x00 + 0x01 + 0x01 + 0x00 + +julia> solution_weight +5.0 +``` + +## ldpc + +The python ldpc module is immediately available: + +``` +julia> using PyQDecoders + +julia> PyQDecoders.ldpc +PyObject +``` + +Running the example from `ldpc`'s original Readme: + + +``` +julia> using PyQDecoders: sps, np, ldpc + +julia> H = ldpc.codes.rep_code(3) # parity check matrix for the length-3 repetition code +2×3 Matrix{Int64}: + 1 1 0 + 0 1 1 + +julia> n = size(H, 2) # the codeword length +3 + +julia> bpd = ldpc.bp_decoder( + H, # the parity check matrix + error_rate=0.1, # the error rate on each bit + max_iter=n, # the maximum iteration depth for BP + bp_method="product_sum", # BP method. The other option is `minimum_sum' + channel_probs=[nothing] # channel probability probabilities. Will overide error rate. + ) +PyObject + +julia> error = [0,1,0] +3-element Vector{Int64}: + 0 + 1 + 0 + +julia> syndrome = H*error .% 2 +2-element Vector{Int64}: + 1 + 1 + +julia> decoding = bpd.decode(syndrome) +3-element Vector{Int64}: + 0 + 1 + 0 +``` \ No newline at end of file diff --git a/src/PyQDecoders.jl b/src/PyQDecoders.jl new file mode 100644 index 0000000..f0a5e19 --- /dev/null +++ b/src/PyQDecoders.jl @@ -0,0 +1,23 @@ +module PyQDecoders +import Conda +using PyCall + +const sps = PyNULL() +const np = PyNULL() +const pm = PyNULL() +const ldpc = PyNULL() + +function __init__() + copy!(sps, pyimport_conda("scipy.sparse", "scipy")) + copy!(np, pyimport_conda("numpy", "numpy")) + if PyCall.conda + Conda.pip_interop(true) + Conda.pip("install", "pymatching") + Conda.pip("install", "ldpc") + end + copy!(pm, pyimport_conda("pymatching", "pymatching")) + copy!(ldpc, pyimport_conda("ldpc", "ldpc")) + pyimport("ldpc.codes") +end + +end # module