Skip to content

Commit b94e05a

Browse files
authored
Merge branch 'master' into feature/vinds
2 parents 2227b4b + 0c2ad3e commit b94e05a

20 files changed

+263
-140
lines changed

.github/workflows/CI.yml

+47-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ jobs:
4848
include-all-prereleases: true
4949
- uses: julia-actions/cache@v1
5050
with:
51-
cache-name: Unit Tests CI - Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }}
51+
cache-name: CI / ${{ matrix.test_group }} / Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }}
5252
- name: Add Julia registries
5353
run: |
5454
using Pkg
@@ -63,6 +63,52 @@ jobs:
6363
- uses: codecov/codecov-action@v3
6464
with:
6565
files: lcov.info
66+
python:
67+
name: ${{ matrix.test_group }} / Julia ${{ matrix.version }}
68+
runs-on: ubuntu-latest
69+
strategy:
70+
fail-fast: false
71+
matrix:
72+
version:
73+
- '1'
74+
test_group:
75+
- python
76+
os:
77+
- ubuntu-latest
78+
arch:
79+
- x64
80+
steps:
81+
- uses: actions/checkout@v4
82+
- uses: julia-actions/setup-julia@v1
83+
with:
84+
version: ${{ matrix.version }}
85+
arch: ${{ matrix.arch }}
86+
include-all-prereleases: true
87+
- uses: julia-actions/cache@v1
88+
with:
89+
cache-name: CI / ${{ matrix.test_group }} / Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }}
90+
- name: Set and export registry flavor preference
91+
run: echo "JULIA_PKG_SERVER_REGISTRY_PREFERENCE=${JULIA_PKG_SERVER_REGISTRY_PREFERENCE:-eager}" >> ${GITHUB_ENV}
92+
shell: bash
93+
- name: Add Julia registries
94+
run: |
95+
using Pkg
96+
pkg"registry add https://github.com/bsc-quantic/Registry.git"
97+
pkg"registry add General"
98+
shell: julia --color=yes {0}
99+
- name: Run tests
100+
run: |
101+
julia --color=yes --code-coverage=user --depwarn=yes --project=test/python/ -e '
102+
using Pkg
103+
Pkg.instantiate()
104+
Pkg.resolve()
105+
include("test/python/runtests.jl")'
106+
shell: bash
107+
- uses: julia-actions/julia-buildpkg@v1
108+
- uses: julia-actions/julia-processcoverage@v1
109+
- uses: codecov/codecov-action@v3
110+
with:
111+
files: lcov.info
66112
docs:
67113
name: Documentation
68114
runs-on: ubuntu-latest

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,6 @@ dist
420420
.julia
421421
*.excalidraw
422422
archive/
423-
test/.CondaPkg/
423+
**/*/.CondaPkg/
424424
.CondaPkg/
425425
CondaPkg.toml

src/Ansatz.jl

+47-2
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ function inds(kwargs::NamedTuple{(:bond,)}, tn::AbstractAnsatz)
165165
return only(inds(tensor1) inds(tensor2))
166166
end
167167

168-
# TODO fix this properly when we do the mapping
168+
# TODO fix this properly when we do the mapping
169169
function tensors(kwargs::NamedTuple{(:at,),Tuple{L}}, tn::AbstractAnsatz) where {L<:Lane}
170170
hassite(tn, Site(kwargs.at)) && return tensors(tn; at=Site(kwargs.at))
171171
hassite(tn, Site(kwargs.at; dual=true)) && return tensors(tn; at=Site(kwargs.at; dual=true))
@@ -379,7 +379,8 @@ Compute the expectation value of an observable on a [`AbstractAnsatz`](@ref) Ten
379379
function expect::AbstractAnsatz, observable; bra=adjoint(ψ))
380380
@assert socket(ψ) == State() "ψ must be a state"
381381
@assert socket(bra) == State(; dual=true) "bra must be a dual state"
382-
contract(merge(ψ, observable, bra))
382+
383+
return expect(form(ψ), ψ, observable; bra)
383384
end
384385

385386
function expect::AbstractAnsatz, observables::AbstractVecOrTuple; bra=adjoint(ψ))
@@ -388,6 +389,50 @@ function expect(ψ::AbstractAnsatz, observables::AbstractVecOrTuple; bra=adjoint
388389
end
389390
end
390391

392+
function expect(::NonCanonical, ψ::AbstractAnsatz, observable; bra=adjoint(ψ))
393+
return contract(merge(ψ, observable, bra))
394+
end
395+
396+
# TODO: Try to find a better way to do this
397+
function expect(::MixedCanonical, ψ::AbstractAnsatz, observable; bra=adjoint(ψ))
398+
return contract(merge(ψ, observable, bra))
399+
end
400+
401+
function expect(::Canonical, ψ::Tenet.AbstractAnsatz, observable; bra=adjoint(ψ))
402+
obs_sites = unique(id.(sites(observable)))
403+
404+
ket_Λ = []
405+
bra_Λ = []
406+
ket_tensors = []
407+
bra_tensors = []
408+
for i in obs_sites
409+
replace!(observable, inds(observable; at=Site(i)) => Symbol(:input, i))
410+
replace!(observable, inds(observable; at=Site(i; dual=true)) => Symbol(:output, i))
411+
replace!(ψ, inds(ψ; at=Site(i)) => Symbol(:input, i))
412+
replace!(bra, inds(bra; at=Site(i; dual=true)) => Symbol(:output, i))
413+
414+
replace!(bra, inds(bra; bond=(Lane(i), Lane(i + 1))) => inds(ψ; bond=(Lane(i), Lane(i + 1))))
415+
replace!(bra, inds(bra; bond=(Lane(i - 1), Lane(i))) => inds(ψ; bond=(Lane(i - 1), Lane(i))))
416+
417+
push!(ket_Λ, tensors(ψ; bond=(Lane(i - 1), Lane(i))))
418+
push!(bra_Λ, tensors(bra; bond=(Lane(i - 1), Lane(i))))
419+
420+
push!(ket_tensors, tensors(ψ; at=Site(i)))
421+
push!(bra_tensors, tensors(bra; at=Site(i; dual=true)))
422+
end
423+
424+
push!(ket_Λ, tensors(ψ; bond=(Lane(obs_sites[end]), Lane(obs_sites[end] + 1))))
425+
push!(bra_Λ, tensors(bra; bond=(Lane(obs_sites[end]), Lane(obs_sites[end] + 1))))
426+
427+
t = contract(
428+
contract(ket_Λ..., ket_tensors...; dims=[]),
429+
contract(bra_Λ..., bra_tensors...; dims=[]),
430+
tensors(Quantum(observable))[1],
431+
)
432+
433+
return t
434+
end
435+
391436
"""
392437
evolve!(ψ::AbstractAnsatz, gate; threshold = nothing, maxdim = nothing, normalize = false)
393438

src/TensorNetwork.jl

+2
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,8 @@ function Base.replace!(tn::AbstractTensorNetwork, pair::Pair{<:Tensor,<:Tensor})
507507
tn = TensorNetwork(tn)
508508
old_tensor, new_tensor = pair
509509

510+
old_tensor tn || throw(ArgumentError("Old tensor not found in TensorNetwork"))
511+
510512
old_tensor === new_tensor && return tn
511513

512514
issetequal(inds(new_tensor), inds(old_tensor)) || throw(ArgumentError("replacing tensor indices don't match"))

test/Project.toml

-5
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e"
55
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
66
ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
77
ChainRulesTestUtils = "cdddcdb0-9152-4a09-a978-84456f9df70a"
8-
CondaPkg = "992eb4ea-22a4-4c89-a5bb-47a3300528ab"
98
Dagger = "d58978e5-989f-55fb-8d15-ea34adc7bf54"
109
DeltaArrays = "10b0fc19-5ccc-4427-889b-d75dd6306188"
1110
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
@@ -19,17 +18,13 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
1918
Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a"
2019
NetworkLayout = "46757867-2c16-5918-afeb-47bfcb05e46a"
2120
OMEinsum = "ebe7aa44-baf0-506c-a96f-8464559b3922"
22-
Permutations = "2ae35dd2-176d-5d53-8349-f30d82d94d4f"
23-
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
24-
PythonCall = "6099a3de-0909-46bc-b1f4-468b9a2dfc0d"
2521
Quac = "b9105292-1415-45cf-bff1-d6ccf71e6143"
2622
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
2723
Reactant = "3c362404-f566-11ee-1572-e11a4b42c853"
2824
SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f"
2925
Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
3026
Tenet = "85d41934-b9cd-44e1-8730-56d86f15f3ec"
3127
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
32-
UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
3328
Yao = "5872b779-8223-5990-8dd0-5abbb0748c8c"
3429
YaoBlocks = "418bc28f-b43b-5e0b-a6e7-61bbc1a2c1df"
3530

test/integration/python/test_cirq.jl

-53
This file was deleted.

test/integration/python/test_qibo.jl

-22
This file was deleted.

test/integration/python/test_qiskit.jl

-22
This file was deleted.

test/integration/python/test_quimb.jl

-18
This file was deleted.

test/python/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
!CondaPkg.toml
File renamed without changes.

test/python/Project.toml

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[deps]
2+
CondaPkg = "992eb4ea-22a4-4c89-a5bb-47a3300528ab"
3+
PythonCall = "6099a3de-0909-46bc-b1f4-468b9a2dfc0d"
4+
SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f"
5+
Tenet = "85d41934-b9cd-44e1-8730-56d86f15f3ec"
6+
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
7+
8+
[sources]
9+
Tenet = {path = "../.."}

test/python/runtests.jl

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using Test
2+
using Tenet
3+
using SafeTestsets
4+
5+
# add python test dependencies
6+
run(`cp $(joinpath(@__DIR__, "CondaPkg.toml")) $(joinpath(@__DIR__, "..", "..", "CondaPkg.toml"))`)
7+
using CondaPkg
8+
CondaPkg.update()
9+
using PythonCall
10+
11+
@testset "Python" verbose = true begin
12+
@safetestset "Cirq" begin
13+
include("test_cirq.jl")
14+
end
15+
16+
@safetestset "Quimb" begin
17+
include("test_quimb.jl")
18+
end
19+
20+
@safetestset "Qiskit" begin
21+
include("test_qiskit.jl")
22+
end
23+
24+
@safetestset "Qibo" begin
25+
include("test_qibo.jl")
26+
end
27+
end
28+
29+
# cleaning
30+
run(`rm $(joinpath(@__DIR__, "..", "..", "CondaPkg.toml"))`)

test/python/test_cirq.jl

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
using Test
2+
using Tenet
3+
using PythonCall
4+
cirq = pyimport("cirq")
5+
6+
@testset "LineQubit" begin
7+
circuit = cirq.Circuit()
8+
qubits = cirq.LineQubit.range(3)
9+
circuit.append(cirq.H(qubits[0]))
10+
circuit.append(cirq.H(qubits[1]))
11+
circuit.append(cirq.CNOT(qubits[1], qubits[2]))
12+
circuit.append(cirq.CNOT(qubits[0], qubits[2]))
13+
circuit.append(cirq.H(qubits[0]))
14+
circuit.append(cirq.H(qubits[1]))
15+
circuit.append(cirq.H(qubits[2]))
16+
17+
circ = convert(Circuit, circuit)
18+
@test issetequal(sites(circ; set=:inputs), Site.([0, 1, 2]; dual=true))
19+
@test issetequal(sites(circ; set=:outputs), Site.([0, 1, 2]))
20+
@test Tenet.ntensors(circ) == 7
21+
@test issetequal(
22+
moments(circ),
23+
[Tenet.Moment.(Ref(Lane(0)), 1:4)..., Tenet.Moment.(Ref(Lane(1)), 1:4)..., Tenet.Moment.(Ref(Lane(2)), 1:4)...],
24+
)
25+
end
26+
27+
@testset "GridQubit" begin
28+
circuit = cirq.Circuit()
29+
qubits = cirq.GridQubit.rect(3, 1)
30+
circuit.append(cirq.H(qubits[0]))
31+
circuit.append(cirq.H(qubits[1]))
32+
circuit.append(cirq.CNOT(qubits[1], qubits[2]))
33+
circuit.append(cirq.CNOT(qubits[0], qubits[2]))
34+
circuit.append(cirq.H(qubits[0]))
35+
circuit.append(cirq.H(qubits[1]))
36+
circuit.append(cirq.H(qubits[2]))
37+
38+
circ = convert(Circuit, circuit)
39+
@test issetequal(sites(circ; set=:inputs), Site.([(0, 0), (1, 0), (2, 0)]; dual=true))
40+
@test issetequal(sites(circ; set=:outputs), Site.([(0, 0), (1, 0), (2, 0)]))
41+
@test Tenet.ntensors(circ) == 7
42+
@test issetequal(
43+
moments(circ),
44+
[
45+
Tenet.Moment.(Ref(Lane(0, 0)), 1:4)...,
46+
Tenet.Moment.(Ref(Lane(1, 0)), 1:4)...,
47+
Tenet.Moment.(Ref(Lane(2, 0)), 1:4)...,
48+
],
49+
)
50+
end

0 commit comments

Comments
 (0)