From 8091f17f6fa006ad4fc2967fd6f8e9c7ba2ffda7 Mon Sep 17 00:00:00 2001 From: Brian Doolittle Date: Tue, 29 Jun 2021 14:23:30 -0400 Subject: [PATCH 1/5] adding user guide --- .../classical_chsh_scenario.png | Bin 0 -> 32887 bytes docs/src/user_guide.md | 102 +++++++++++++++++- src/Nonlocality/optimize_measurements.jl | 28 ++--- src/quantum_strategies.jl | 83 ++++++++++++-- src/scenarios.jl | 1 - test/unit/quantum_strategies.jl | 60 +++++++++++ 6 files changed, 247 insertions(+), 27 deletions(-) create mode 100644 docs/src/assets/scenario_images/classical_chsh_scenario.png diff --git a/docs/src/assets/scenario_images/classical_chsh_scenario.png b/docs/src/assets/scenario_images/classical_chsh_scenario.png new file mode 100644 index 0000000000000000000000000000000000000000..c6234130788a268c57282ea3e86898beeb81e6a6 GIT binary patch literal 32887 zcmdRWg1kpO-rSyF;f#{#_b)mk#x(G!!@;`p+|D;!CyhUG+TRhF~MEY7YT{gZc7-G)@}> zhAjvo@loijGvq-ET=HwttM27jj=hpYUtlm0pkBRhV

5z@mIT@PvZP#Tv*1jhMHy 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 literal 0 HcmV?d00001 diff --git a/docs/src/user_guide.md b/docs/src/user_guide.md index 7171baf..a8ea2d6 100644 --- a/docs/src/user_guide.md +++ b/docs/src/user_guide.md @@ -1,5 +1,105 @@ # User Guide +## Quickstart + ```julia -using Pkg; Pkg.add("BellScenario") +julia> using Pkg; Pkg.add("BellScenario") +``` + +```@example tutorial +using BellScenario +``` + +## CHSH Scenario + +The CHSH scenario is a [`BipartiteNonSignaling`](@ref) scenario where Alice and Bob +each have a black-box with binary inputs and outputs. + +![Classical CHSH Scenario](../assets/scenario_images/classical_chsh_scenario.png) + +This scenario is significant because it is the simplest Bell scenario in which +quantum nonlocality can be observed. +We will use BellScenario.jl to compute the CH Bell inequality and optimize quantum +measurements to violate the CH inequality. +First, create a CHSH `Scenario` to specify the black-box arrangement in the figure +above. + +```@example tutorial +# (num_out_A, num_out_B, num_in_A, num_in_B) +chsh_scenario = BipartiteNonSignaling(2,2,2,2) +``` + +Bell inequalities bound the set of local (classical) correlations. +The local set is a convex polytope referred to as the *local polytope* and the +facets of the local polytope are Bell inequalities. +The standard method of computing Bell inequalities is to first compute the local +polytope vertices, then apply a polytope transformation algorithm to compute the +Bell inequalities. + +The BellScenario.jl package provides the [`LocalPolytope`](@ref) module to compute +Bell inequalities. +The first step is to enumerate the vertices for the CHSH scenario. + +```@example tutorial +chsh_vertices = LocalPolytope.vertices(chsh_scenario) +``` + +Then, the Bell inequalities can computed using the [`LocalPolytope.facets`](@ref) +function. + +```@example tutorial +chsh_facets = LocalPolytope.facets(chsh_vertices)["facets"] +``` + +We'll take ``15^{th}`` facet as it represents the CH inequality + +```math +- P_A(1|2) - P_B(1|1) + P(11|11) - P(11|12) + P(11|21) + P(11|22) \leq 0. +``` + +In fact, this inequality is equivalent to the more celebrated CHSH inequality. +The difference is that the CH inequality is expressed in terms of probabilities +whereas the CHSH inequality is expressed in terms of bipartite correlators. + +```@example tutorial +ch_inequality = chsh_facets[15] +``` + +Now that we have computed a Bell inequality, we can find a quantum violation using +the [`Nonlocality`](@ref) module. +This will require the use of the [QBase.jl](https://github.com/ChitambarLab/QBase.jl) package. +In this example, we will fix Alice's measurement and the quantum state shared +between Alice and Bob. + +```@example tutorial +using QBase + +# maximally entangled state +ρ_AB = State([1 0 0 1;0 0 0 0;0 0 0 0;1 0 0 1]/2) + +# Alice's measurement +A_POVMs = [ + POVM([ [1 0;0 0], [0 0;0 1] ]), + POVM([ [1 1;1 1]/2, [1 -1;-1 1]/2 ]) +] +``` + +Then, we convert the `ch_inequality` into a general representation of a [`BellGame`](@ref). + +```@example tutorial +ch_game = convert(BellGame, ch_inequality, chsh_scenario) +``` + +Finally, we optimize Bob's measurement with respect to the fixed state and measurements. + +```@example tutorial +opt_dict = Nonlocality.optimize_measurement( + chsh_scenario, ch_game, ρ_AB, A_POVMs=A_POVMs +) +``` + +We see that the inequality is violated for the optimized measurement and states. + +```@example tutorial +opt_dict["violation"] ``` diff --git a/src/Nonlocality/optimize_measurements.jl b/src/Nonlocality/optimize_measurements.jl index 0a12a1e..db995b4 100644 --- a/src/Nonlocality/optimize_measurements.jl +++ b/src/Nonlocality/optimize_measurements.jl @@ -1,6 +1,6 @@ export optimize_measurement -@doc raw""" +""" [`LocalSignaling`](@ref) scenario: optimize_measurement( @@ -14,10 +14,10 @@ the set of quantum states `ρ_states`. The optimization is performed with the following semi-definite program: ```math -\begin{aligned} -&\max_{\{\Pi_y\}} \sum_{x,y} G_{x,y} \text{Tr}[\Pi_y \rho_x] \\ -&s.t. \quad \sum_y \Pi_y = \mathbb{I}, \quad \Pi_y \geq 0 -\end{aligned} +\\begin{aligned} +&\\max_{\\{\\Pi_y\\}} \\sum_{x,y} G_{x,y} \\text{Tr}[\\Pi_y \\rho_x] \\\\ +&s.t. \\quad \\sum_y \\Pi_y = \\mathbb{I}, \\quad \\Pi_y \\geq 0 +\\end{aligned} ``` """ function optimize_measurement( @@ -65,7 +65,7 @@ function optimize_measurement( ) end -@doc raw""" +""" [`BipartiteNonSignaling`](@ref) scenario: optimize_measurement( @@ -80,10 +80,10 @@ state `ρ_AB` and POVM measurement applied by Alice. The following semi-definite program optimizes the Bob's POVM: ```math -\begin{aligned} - &\max_{\{\Pi_b^y\}} \sum_{a,b,x,y} G_{a,b,x,y}\text{Tr}[(\Pi_a^x \otimes \Pi_b^y)\rho_AB] \\ - &s.t. \quad \sum_b \Pi_b^y = \mathbb{I},\quad \Pi_b^y \geq 0 \quad \forall\; y -\end{aligned} +\\begin{aligned} + &\\max_{\\{\\Pi_b^y\\}} \\sum_{a,b,x,y} G_{a,b,x,y}\\text{Tr}[(\\Pi_a^x \\otimes \\Pi_b^y)\\rho_{AB}] \\\\ + &s.t. \\quad \\sum_b \\Pi_b^y = \\mathbb{I},\\quad \\Pi_b^y \\geq 0 \\quad \\forall\\; y +\\end{aligned} ``` optimize_measurement( @@ -98,10 +98,10 @@ state `ρ_{AB}` and POVM measurement applied by Bob. The following semi-definite program optimizes the Alice's POVM: ```math -\begin{aligned} -&\max_{\{\Pi_a^x\}} \sum_{a,b,x,y} G_{a,b,x,y}\text{Tr}[(\Pi_a^x \otimes \Pi_b^y)\rho_{AB}] \\ -&s.t. \quad \sum_a \Pi_a^x = \mathbb{I},\quad \Pi_a^x \geq 0 \quad \forall \;x -\end{aligned} +\\begin{aligned} +&\\max_{\\{\\Pi_a^x\\}} \\sum_{a,b,x,y} G_{a,b,x,y}\\text{Tr}[(\\Pi_a^x \\otimes \\Pi_b^y)\\rho_{AB}] \\\\ +&s.t. \\quad \\sum_a \\Pi_a^x = \\mathbb{I},\\quad \\Pi_a^x \\geq 0 \\quad \\forall \\;x +\\end{aligned} ``` """ function optimize_measurement( diff --git a/src/quantum_strategies.jl b/src/quantum_strategies.jl index 3c02828..460c575 100644 --- a/src/quantum_strategies.jl +++ b/src/quantum_strategies.jl @@ -4,23 +4,18 @@ export quantum_strategy Constructs a strategy matrix given quantum states and measurements. The supported scenarios include: -`BlackBox` scenarios +[`BlackBox`](@ref) scenarios: quantum_strategy( Π :: POVM, - ρ_states :: Vector{<:State} + ρ_states :: Vector{<:State}; ) :: Strategy -`LocalSignaling` scenarios +For a quantum system the conditional proabilities are constructed as - quantum_strategy( - Π :: POVM, - ρ_states :: Vector{<:State}, - scenario :: LocalSignaling - ) :: Strategy - -A `DomainError` is thrown if the provided states and measurements are not compatible -with the specified scenario. +```math + P(y|x) = \\text{Tr}[\\Pi_y\\rho_x]. +``` """ function quantum_strategy( Π :: POVM, @@ -31,6 +26,24 @@ function quantum_strategy( Strategy(conditionals, scenario) end +""" +[`LocalSignaling`](@ref) scenarios: + + quantum_strategy( + Π :: POVM, + ρ_states :: Vector{<:State}, + scenario :: LocalSignaling + ) :: Strategy + +For quantum systems the conditional probabilities are construct as + +```math + P(y|x) = \\text{Tr}[\\Pi_y\\rho_x]. +``` + +A `DomainError` is thrown if the provided states and measurements are not compatible +with the specified scenario. +""" function quantum_strategy( Π :: POVM, ρ_states :: Vector{<:State}, @@ -42,3 +55,51 @@ function quantum_strategy( conditionals = measure(Π, ρ_states) Strategy(conditionals, scenario) end + +""" +[`BipartiteNonSignaling`](@ref) scenarios: + + quantum_strategy( + ρ_AB :: State, + Π_Ax :: Vector{<:POVM}, + Π_By :: Vector{<:POVM}, + scenario :: BipartiteNonSignaling; + atol::Float64 = 1e-7 + ) + +Constructs a strategy matrix in the generalized representation for the quantum +system with conditional probabilities. + +```math + P(ab|xy) = \\text{Tr}[(\\Pi_a^x\\otimes\\Pi_b^y)\\rho_{AB}] +``` + +A `DomainError` is thrown if +* The length of each POVM does not match the scenarios number of outputs +* The number of each party's POVMS doesn't match the the number of inputs. +""" +function quantum_strategy( + ρ_AB :: State, + Π_Ax :: Vector{<:POVM}, + Π_By :: Vector{<:POVM}, + scenario :: BipartiteNonSignaling; + atol::Float64 = 1e-7 +) :: Strategy + if scenario.X != length(Π_Ax) + throw(DomainError(Π_Ax, "`length(Π_Ax) == $(scenario.X)` is not satisfied.")) + elseif scenario.Y != length(Π_By) + throw(DomainError(Π_By, "`length(Π_By) == $(scenario.Y)` is not satisfied.")) + elseif all(Π -> length(Π) != scenario.A , Π_Ax) + throw(DomainError(Π_Ax, "Each POVM in Π_Ax must have $(scenario.A) elements")) + elseif all(Π -> length(Π) != scenario.B, Π_By) + throw(DomainError(Π_By, "Each POVM in Π_By must have $(scenario.B) elements")) + end + + strat_mat = zeros(Float64, (scenario.A,scenario.B,scenario.X,scenario.Y)) + for a in 1:scenario.A, b in 1:scenario.B, x in 1:scenario.X, y in 1:scenario.Y + Π_AB = kron(Π_Ax[x][a].M, Π_By[y][b].M) + strat_mat[b,a,y,x] = tr(Π_AB * ρ_AB) + end + + Strategy(reshape(strat_mat, strategy_dims(scenario)), scenario, atol=atol) +end diff --git a/src/scenarios.jl b/src/scenarios.jl index b12c195..960b8a4 100644 --- a/src/scenarios.jl +++ b/src/scenarios.jl @@ -95,7 +95,6 @@ struct BipartiteNonSignaling <: Scenario ) ? new(A, B, X, Y) : throw( DomainError((A, B, X, Y), "inputs must be ≥ 1") ) - end """ diff --git a/test/unit/quantum_strategies.jl b/test/unit/quantum_strategies.jl index 1320f17..538b08b 100644 --- a/test/unit/quantum_strategies.jl +++ b/test/unit/quantum_strategies.jl @@ -34,4 +34,64 @@ end ) end +@testset "quantum_strategy(BipartiteNonSignaling)" begin + @testset "ch violation" begin + scenario = BipartiteNonSignaling(2,2,2,2) + ρ_AB = State([1 0 0 1;0 0 0 0;0 0 0 0;1 0 0 1]/2) + Π_Ax = [ + POVM([[1. 0;0 0],[0 0;0 1.]]), + POVM([[1 1;1 1]/2,[1 -1;-1 1]/2]) + ] + Π_By = [ + POVM([bloch_qubit_state(π/4),bloch_qubit_state(-3π/4)]), + POVM([bloch_qubit_state(3π/4),bloch_qubit_state(-π/4)]) + ] + + q_strat = quantum_strategy(ρ_AB, Π_Ax, Π_By, scenario) + @test q_strat isa Strategy + @test q_strat.scenario isa BipartiteNonSignaling + + # generalized rep of CH inequality + g = BellGame([1 0 1 1;1 1 0 0;0 1 1 0;1 1 1 0], 3) + @test sum(g .* q_strat) ≈ 3.207 atol=2e-4 + end + + @testset "classical states" begin + scenario = BipartiteNonSignaling(2,2,2,2) + ρ_AB = State(kron([1 0;0 0],[0 0;0 1])) + Π_Ax = [ + POVM([[1 0;0 0],[0 0;0 1]]), + POVM([[0 0;0 1],[1 0;0 0]]) + ] + Π_By = [ + POVM([[1 0;0 0],[0 0;0 1]]), + POVM([[0 0;0 1],[1 0;0 0]]) + ] + + q_strat = quantum_strategy(ρ_AB, Π_Ax, Π_By, scenario) + @test q_strat isa Strategy + @test q_strat == [0 1 0 0;1 0 0 0;0 0 0 1;0 0 1 0] + @test q_strat.scenario == scenario + end + + @testset "Domain Errors" begin + ρ_AB = State(kron([1 0;0 0],[0 0;0 1])) + Π = POVM([[1 0;0 0],[0 0;0 1]]) + Π_Ax = [Π, Π] + Π_By = [Π, Π] + + scenario = BipartiteNonSignaling(3,2,2,2) + @test_throws DomainError quantum_strategy(ρ_AB, Π_Ax, Π_By, scenario) + + scenario = BipartiteNonSignaling(2,3,2,2) + @test_throws DomainError quantum_strategy(ρ_AB, Π_Ax, Π_By, scenario) + + scenario = BipartiteNonSignaling(2,2,3,2) + @test_throws DomainError quantum_strategy(ρ_AB, Π_Ax, Π_By, scenario) + + scenario = BipartiteNonSignaling(2,2,2,3) + @test_throws DomainError quantum_strategy(ρ_AB, Π_Ax, Π_By, scenario) + end +end + end From 55dc4be3bb1f9b3deabd4988e9928ba7bba3db3b Mon Sep 17 00:00:00 2001 From: Brian Doolittle Date: Tue, 29 Jun 2021 14:24:12 -0400 Subject: [PATCH 2/5] bumping version --- CITATION.bib | 2 +- Project.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CITATION.bib b/CITATION.bib index fc4d008..1194c3e 100644 --- a/CITATION.bib +++ b/CITATION.bib @@ -3,7 +3,7 @@ @misc{BellScenario.jl title = {BellScenario.jl}, howpublished = {\url{https://github.com/ChitambarLab/BellScenario.jl}}, url = {https://github.com/ChitambarLab/BellScenario.jl}, - version = {v0.1.1}, + version = {v0.1.2}, year = {2020}, month = {6} } diff --git a/Project.toml b/Project.toml index 69efd13..cdbcf78 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "BellScenario" uuid = "4e58fcc1-4405-48af-b0f2-42df636d9190" authors = ["Brian Doolittle"] -version = "0.1.1" +version = "0.1.2" [deps] Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa" From 6dc2477aa2d95e426bb7e0795f8aa47a0f0c86f9 Mon Sep 17 00:00:00 2001 From: Brian Doolittle Date: Thu, 1 Jul 2021 10:38:48 -0400 Subject: [PATCH 3/5] allowing abstract matrix types instead of QBase --- src/Nonlocality/optimize_measurements.jl | 68 ++++++++------ src/quantum_strategies.jl | 58 +++++++----- .../unit/Nonlocality/optimize_measurements.jl | 49 ++++++++++ test/unit/quantum_strategies.jl | 94 +++++++++++++------ 4 files changed, 185 insertions(+), 84 deletions(-) diff --git a/src/Nonlocality/optimize_measurements.jl b/src/Nonlocality/optimize_measurements.jl index db995b4..a23c23a 100644 --- a/src/Nonlocality/optimize_measurements.jl +++ b/src/Nonlocality/optimize_measurements.jl @@ -6,7 +6,7 @@ export optimize_measurement optimize_measurement( scenario :: LocalSignaling, game :: BellGame, - ρ_states :: Vector{<:State} + ρ_states :: Vector{<:AbstractMatrix} ) Finds the measurement that optimizes the score of the [`BellGame`](@ref) against @@ -23,16 +23,17 @@ The optimization is performed with the following semi-definite program: function optimize_measurement( scenario::LocalSignaling, game::BellGame, - ρ_states::Vector{<:State}, + ρ_states::Vector{<:AbstractMatrix}; + atol=1e-7::Float64 ) :: Dict if scenario.X != length(ρ_states) throw(DomainError(scenario, "expected length of `ρ_states` is $(scenario.X)), but got $(length(ρ_states)) instead")) - end - - if size(ρ_states[1]) != (scenario.d,scenario.d) + elseif size(ρ_states[1]) != (scenario.d,scenario.d) throw(DomainError(ρ_states, "dimension of `ρ_states` is not $(scenario.d)")) end + states = map(ρ -> ρ isa State ? ρ : State(ρ, atol=atol), ρ_states) + norm_game_vector = convert(Vector{Int64}, game) norm_bound = norm_game_vector[end] norm_game = reshape(norm_game_vector[1:(end-1)], (scenario.Y-1, scenario.X)) @@ -43,7 +44,7 @@ function optimize_measurement( constraints += (sum(map(Π_y -> imag(Π_y), Π_vars)) == zeros(Float64, scenario.d, scenario.d)) # sum up the state contibutions for each row - H_y = map(row_id -> sum(norm_game[row_id,:] .* ρ_states), 1:scenario.Y-1) + H_y = map(row_id -> sum(norm_game[row_id,:] .* states), 1:scenario.Y-1) # add the objective objective = maximize(real(tr(sum(Π_vars[1:end-1] .* H_y))), constraints) @@ -61,7 +62,7 @@ function optimize_measurement( "povm" => Π_opt, "game" => game, "scenario" => scenario, - "states" => ρ_states + "states" => states ) end @@ -71,8 +72,8 @@ end optimize_measurement( game :: BellGame, scenario :: BipartiteNonSignaling, - ρ_AB :: State; - A_POVMs :: Vector{<:POVM}, + ρ_AB :: AbstractMatrix; + A_POVMs :: Vector{<:AbstractVector{<:AbstractMatrix}}, ) :: Dict Find Bob's measurement which optimizes a `BellGame`'s score for the shared quantum @@ -89,8 +90,8 @@ The following semi-definite program optimizes the Bob's POVM: optimize_measurement( game :: BellGame, scenario :: BipartiteNonSignaling, - ρ_AB :: State; - B_POVMs :: Vector{<:POVM}, + ρ_AB :: AbstractMatrix; + B_POVMs :: Vector{<:AbstractVector{<:AbstractMatrix}}, ) :: Dict Find Alice's measurement which optimizes a `BellGame`'s score for the shared quantum @@ -107,14 +108,17 @@ The following semi-definite program optimizes the Alice's POVM: function optimize_measurement( scenario::BipartiteNonSignaling, game::BellGame, - ρ_AB :: State; - A_POVMs=Vector{POVM}(undef,0) :: Vector{<:POVM}, - B_POVMs=Vector{POVM}(undef,0) :: Vector{<:POVM} + ρ_AB :: AbstractMatrix; + A_POVMs=Vector{POVM}(undef,0) :: Vector{<:AbstractVector{<:AbstractMatrix}}, + B_POVMs=Vector{POVM}(undef,0) :: Vector{<:AbstractVector{<:AbstractMatrix}}, + atol=1e-7::Float64 ) :: Dict + ρ = ρ_AB isa State ? ρ_AB : State(ρ_AB, atol=atol) + if length(A_POVMs) > 0 - return _optimize_measurement_B(scenario, game, ρ_AB, A_POVMs) + return _optimize_measurement_B(scenario, game, ρ, A_POVMs, atol=atol) elseif length(B_POVMs) > 0 - return _optimize_measurement_A(scenario, game, ρ_AB, B_POVMs) + return _optimize_measurement_A(scenario, game, ρ, B_POVMs, atol=atol) else throw(DomainError((A_POVMs,B_POVMs), "either `A_POVMs` or `B_POVMs` must be specified.")) end @@ -126,22 +130,23 @@ end function _optimize_measurement_B( scenario::BipartiteNonSignaling, game::BellGame, - ρ_AB :: State, - A_POVMs :: Vector{<:POVM} + ρ_AB :: AbstractMatrix, + A_POVMs :: Vector{<:AbstractVector{<:AbstractMatrix}}; + atol=1e-7::Float64 ) :: Dict if !(scenario.X == length(A_POVMs)) throw( DomainError( (scenario.X, " != length(A_POVMs)"), "A distinct POVM is not specified for input `X` of `BipartiteNonSignaling` scenario" )) - end - - if !(all(i -> scenario.A == length(A_POVMs[i]), 1:scenario.X )) + elseif !(all(i -> scenario.A == length(A_POVMs[i]), 1:scenario.X )) throw( DomainError( A_POVMs, "Each POVM must have $(scenario.A) outputs." )) end + Π_Ax = map(Π -> Π isa POVM ? Π : POVM(Π, atol=atol), A_POVMs) + ρ_dim = size(ρ_AB,1) Π_A_dim = size(A_POVMs[1][1],1) @@ -156,7 +161,7 @@ function _optimize_measurement_B( # Objective function problem = maximize(real( sum(x -> sum(y -> sum(a -> sum(b -> - game[(a-1)*scenario.B+b,(x-1)*scenario.Y+y]*tr(kron(A_POVMs[x][a],B_POVMs[y][b])*ρ_AB.M), + game[(a-1)*scenario.B+b,(x-1)*scenario.Y+y]*tr(kron(Π_Ax[x][a],B_POVMs[y][b])*ρ_AB.M), 1:scenario.B), 1:scenario.A), 1:scenario.Y), 1:scenario.X) )) @@ -181,7 +186,7 @@ function _optimize_measurement_B( "game" => game, "scenario" => scenario, "state" => ρ_AB, - "A_POVMs" => A_POVMs, + "A_POVMs" => Π_Ax, "B_POVMs" => Π_B_opt ) end @@ -192,22 +197,23 @@ end function _optimize_measurement_A( scenario::BipartiteNonSignaling, game::BellGame, - ρ_AB :: State, - B_POVMs :: Vector{<:POVM} + ρ_AB :: AbstractMatrix, + B_POVMs :: Vector{<:AbstractVector{<:AbstractMatrix}}; + atol=1e-7::Float64 ) :: Dict if !(scenario.Y == length(B_POVMs)) throw( DomainError( (scenario.Y, " != length(B_POVMs)"), "A distinct POVM is not specified for input `Y` of `BipartiteNonSignaling` scenario" )) - end - - if !(all(i -> scenario.B == length(B_POVMs[i]), 1:scenario.Y )) + elseif !(all(i -> scenario.B == length(B_POVMs[i]), 1:scenario.Y )) throw( DomainError( B_POVMs, "Each POVM must have $(scenario.B) outputs." )) end + Π_By = map(Π -> Π isa POVM ? Π : POVM(Π, atol=atol), B_POVMs) + ρ_dim = size(ρ_AB,1) Π_B_dim = size(B_POVMs[1][1],1) @@ -222,7 +228,7 @@ function _optimize_measurement_A( # objective function problem = maximize(real( sum(x -> sum(y -> sum(a -> sum(b -> - game[(a-1)*scenario.B+b,(x-1)*scenario.Y+y]*tr(kron(A_POVMs[x][a],B_POVMs[y][b])*ρ_AB.M), + game[(a-1)*scenario.B+b,(x-1)*scenario.Y+y]*tr(kron(A_POVMs[x][a],Π_By[y][b])*ρ_AB.M), 1:scenario.B), 1:scenario.A), 1:scenario.Y), 1:scenario.X) )) @@ -248,14 +254,14 @@ function _optimize_measurement_A( "scenario" => scenario, "state" => ρ_AB, "A_POVMs" => Π_A_opt, - "B_POVMs" => B_POVMs + "B_POVMs" => Π_By ) end # """ # Helper function for converting POVM optimization variables to a POVM # """ -function _opt_vars_to_povm(povm::Vector{Matrix{Complex{Float64}}}; atol=1) :: POVM +function _opt_vars_to_povm(povm::Vector{<:AbstractMatrix}; atol=1) :: POVM Π = is_povm(povm,atol=atol) ? POVM(povm,atol=atol) : throw(DomainError(povm, "not a povm")) Π diff --git a/src/quantum_strategies.jl b/src/quantum_strategies.jl index 460c575..10bbc0f 100644 --- a/src/quantum_strategies.jl +++ b/src/quantum_strategies.jl @@ -7,8 +7,9 @@ scenarios include: [`BlackBox`](@ref) scenarios: quantum_strategy( - Π :: POVM, + Π :: AbstractVector{<:AbstractMatrix}, ρ_states :: Vector{<:State}; + atol=1e-7::Float64 ) :: Strategy For a quantum system the conditional proabilities are constructed as @@ -18,21 +19,25 @@ For a quantum system the conditional proabilities are constructed as ``` """ function quantum_strategy( - Π :: POVM, - ρ_states :: Vector{<:State} + Π :: AbstractVector{<:AbstractMatrix}, + ρ_states :: Vector{<:AbstractMatrix}; + atol=1e-7::Float64 ) :: Strategy - conditionals = measure(Π, ρ_states) - scenario = BlackBox(length(ρ_states), length(Π)) - Strategy(conditionals, scenario) + povm = Π isa POVM ? Π : POVM(Π, atol=atol) + states = map(ρ -> ρ isa State ? ρ : State(ρ, atol=atol), ρ_states) + + conditionals = measure(povm, states) + Strategy(conditionals.distribution, atol=atol) end """ [`LocalSignaling`](@ref) scenarios: quantum_strategy( - Π :: POVM, - ρ_states :: Vector{<:State}, - scenario :: LocalSignaling + Π :: AbstractVector{<:AbstractMatrix}, + ρ_states :: Vector{<:AbstractMatrix}, + scenario :: LocalSignaling; + atol=1e-7::Float64 ) :: Strategy For quantum systems the conditional probabilities are construct as @@ -45,24 +50,29 @@ A `DomainError` is thrown if the provided states and measurements are not compat with the specified scenario. """ function quantum_strategy( - Π :: POVM, - ρ_states :: Vector{<:State}, - scenario :: LocalSignaling + Π :: AbstractVector{<:AbstractMatrix}, + ρ_states :: Vector{<:AbstractMatrix}, + scenario :: LocalSignaling; + atol=1e-7::Float64 ) :: Strategy if (size(Π[1]) != (scenario.d, scenario.d)) || (size(ρ_states[1]) != (scenario.d, scenario.d)) throw(DomainError((Π, ρ_states), "POVM or States are not dimension `d=$(scenario.d)`.")) end - conditionals = measure(Π, ρ_states) - Strategy(conditionals, scenario) + + povm = Π isa POVM ? Π : POVM(Π, atol=atol) + states = map(ρ -> ρ isa State ? ρ : State(ρ, atol=atol), ρ_states) + + conditionals = measure(povm, states) + Strategy(conditionals.distribution, scenario, atol=atol) end """ [`BipartiteNonSignaling`](@ref) scenarios: quantum_strategy( - ρ_AB :: State, - Π_Ax :: Vector{<:POVM}, - Π_By :: Vector{<:POVM}, + ρ_AB :: AbstractMatrix, + Π_Ax :: Vector{<:AbstractVector{<:AbstractMatrix}}, + Π_By :: Vector{<:AbstractVector{<:AbstractMatrix}}, scenario :: BipartiteNonSignaling; atol::Float64 = 1e-7 ) @@ -79,9 +89,9 @@ A `DomainError` is thrown if * The number of each party's POVMS doesn't match the the number of inputs. """ function quantum_strategy( - ρ_AB :: State, - Π_Ax :: Vector{<:POVM}, - Π_By :: Vector{<:POVM}, + ρ_AB :: AbstractMatrix, + Π_Ax :: Vector{<:AbstractVector{<:AbstractMatrix}}, + Π_By :: Vector{<:AbstractVector{<:AbstractMatrix}}, scenario :: BipartiteNonSignaling; atol::Float64 = 1e-7 ) :: Strategy @@ -95,10 +105,14 @@ function quantum_strategy( throw(DomainError(Π_By, "Each POVM in Π_By must have $(scenario.B) elements")) end + povm_Ax = map(Π -> Π isa POVM ? Π : POVM(Π, atol=atol), Π_Ax) + povm_By = map(Π -> Π isa POVM ? Π : POVM(Π, atol=atol), Π_By) + state = ρ_AB isa State ? ρ_AB : State(ρ_AB, atol=atol) + strat_mat = zeros(Float64, (scenario.A,scenario.B,scenario.X,scenario.Y)) for a in 1:scenario.A, b in 1:scenario.B, x in 1:scenario.X, y in 1:scenario.Y - Π_AB = kron(Π_Ax[x][a].M, Π_By[y][b].M) - strat_mat[b,a,y,x] = tr(Π_AB * ρ_AB) + Π_AB = kron(povm_Ax[x][a].M, povm_By[y][b].M) + strat_mat[b,a,y,x] = tr(Π_AB * state) end Strategy(reshape(strat_mat, strategy_dims(scenario)), scenario, atol=atol) diff --git a/test/unit/Nonlocality/optimize_measurements.jl b/test/unit/Nonlocality/optimize_measurements.jl index 71e6591..ee326eb 100644 --- a/test/unit/Nonlocality/optimize_measurements.jl +++ b/test/unit/Nonlocality/optimize_measurements.jl @@ -5,6 +5,17 @@ using Test, QBase using BellScenario @testset "Nonlocality.optimize_measurement(LocalSignaling)" begin + @testset "non State types" begin + scenario = LocalSignaling(3,3,2) + game = BellGame([1 0 0;0 1 0;0 0 1], 2) + ρ_states = [[1 0;0 0],[0 0;0 1],[0 0;0 1]] + + dict = Nonlocality.optimize_measurement(scenario, game, ρ_states) + + @test isapprox(dict["violation"], 0.0, atol=1e-6) + @test dict["povm"] ≈ [[1 0;0 0],[0 0;0 0.5],[0 0;0 0.5]] + end + @testset "trine states" begin scenario = LocalSignaling(3,3,2) game = BellGame([1 0 0;0 1 0;0 0 1], 2) @@ -59,10 +70,38 @@ using BellScenario scenario = LocalSignaling(4,4,3) @test_throws DomainError Nonlocality.optimize_measurement(scenario, game, states) + + scenario = LocalSignaling(3,3,2) + game = BellGame([1 0 0;0 1 0;0 0 1],2) + states = [[1 0;0 1],[0 0;0 1],[0.5 0;0 0.5]] + @test_throws DomainError Nonlocality.optimize_measurement(scenario, game, states) end end @testset "Nonlocality.optimize_measurement(::BipartiteNonSignaling)" begin + @testset "matrix states and povms" begin + scenario = BipartiteNonSignaling(2,2,2,2) + game = BellGame([0 1 1 0;0 0 0 1;0 0 0 1;1 0 0 1],2) + ρ_AB = [1 0 0 1;0 0 0 0;0 0 0 0;1 0 0 1]/2 + POVMs = [ + [[1 0;0 0],[0 0;0 1]], + [[0.5 0.5;0.5 0.5],[0.5 -0.5;-0.5 0.5]] + ] + + opt_dictA = Nonlocality.optimize_measurement(scenario, game, ρ_AB, A_POVMs=POVMs) + opt_dictB = Nonlocality.optimize_measurement(scenario, game, ρ_AB, B_POVMs=POVMs) + + @test opt_dictA["score"] ≈ 2.20710279 + @test opt_dictA["violation"] ≈ 0.207102796 + @test opt_dictA["A_POVMs"] isa Vector{<:POVM} + @test opt_dictA["state"] isa State + + @test opt_dictB["score"] ≈ 2.20710279 + @test opt_dictB["violation"] ≈ 0.207102796 + @test opt_dictB["B_POVMs"] isa Vector{<:POVM} + @test opt_dictB["state"] isa State + end + @testset "CHSH inequality" begin scenario = BipartiteNonSignaling(2,2,2,2) game = BellGame([0 1 1 0;0 0 0 1;0 0 0 1;1 0 0 1],2) @@ -127,6 +166,16 @@ end @test_throws DomainError Nonlocality.optimize_measurement(scenarioA, game, ρ_AB, A_POVMs=POVMs) @test_throws DomainError Nonlocality.optimize_measurement(scenarioB, game, ρ_AB, B_POVMs=POVMs) + + @test_throws DomainError Nonlocality.optimize_measurement( + scenario, game, [1 0 0 1;0 0 0 0;0 0 0 0;1 0 0 1],A_POVMs=POVMs + ) + @test_throws DomainError Nonlocality.optimize_measurement( + scenario, game, ρ_AB, A_POVMs = [[[1 0;0 1],[1 0;0 1]],[[1 0;0 0],[1 0;0 0]]] + ) + @test_throws DomainError Nonlocality.optimize_measurement( + scenario, game, ρ_AB, B_POVMs = [[[1 0;0 1],[1 0;0 1]],[[1 0;0 0],[1 0;0 0]]] + ) end end diff --git a/test/unit/quantum_strategies.jl b/test/unit/quantum_strategies.jl index 538b08b..55ed50e 100644 --- a/test/unit/quantum_strategies.jl +++ b/test/unit/quantum_strategies.jl @@ -5,37 +5,69 @@ using Test, QBase using BellScenario @testset "quantum_strategy()" begin - q_strat = quantum_strategy( - POVM([[1 0 0;0 0 0;0 0 0],[0 0 0;0 1 0;0 0 0],[0 0 0;0 0 0;0 0 1]]), - State.([[1 0 0;0 0 0;0 0 0],[0 0 0;0 1 0;0 0 0],[0 0 0;0 0 0;0 0 1]]) - ) - - @test q_strat isa Strategy - @test q_strat.scenario == BlackBox(3,3) - @test q_strat == [1 0 0;0 1 0;0 0 1] + @testset "QBase types" begin + q_strat = quantum_strategy( + POVM([[1 0 0;0 0 0;0 0 0],[0 0 0;0 1 0;0 0 0],[0 0 0;0 0 0;0 0 1]]), + State.([[1 0 0;0 0 0;0 0 0],[0 0 0;0 1 0;0 0 0],[0 0 0;0 0 0;0 0 1]]) + ) + + @test q_strat isa Strategy + @test q_strat.scenario == BlackBox(3,3) + @test q_strat == [1 0 0;0 1 0;0 0 1] + end + + @testset "matrix types" begin + q_strat = quantum_strategy( + [[1 0;0 0],[0 0;0 1]], + [[1 0;0 0],[0 0;0 1]] + ) + + @test q_strat isa Strategy + @test q_strat.scenario == BlackBox(2,2) + @test q_strat == [1 0;0 1] + end end @testset "quantum_strategy(LocalSignaling)" begin - scenario = LocalSignaling(3,3,2) - q_strat = quantum_strategy( - mirror_symmetric_qubit_3povm(π/3), - trine_qubit_states(), - scenario - ) - - @test q_strat isa Strategy - @test q_strat ≈ [2/3 1/6 1/6;1/6 2/3 1/6;1/6 1/6 2/3] - @test q_strat.scenario isa LocalSignaling - - @test_throws DomainError quantum_strategy( - POVM([[1 0 0;0 0 0;0 0 0],[0 0 0;0 1 0;0 0 0],[0 0 0;0 0 0;0 0 1]]), - State.([[1 0 0;0 0 0;0 0 0],[0 0 0;0 1 0;0 0 0],[0 0 0;0 0 0;0 0 1]]), - scenario - ) + @testset "QBase types" begin + scenario = LocalSignaling(3,3,2) + q_strat = quantum_strategy( + mirror_symmetric_qubit_3povm(π/3), + trine_qubit_states(), + scenario + ) + + @test q_strat isa Strategy + @test q_strat ≈ [2/3 1/6 1/6;1/6 2/3 1/6;1/6 1/6 2/3] + @test q_strat.scenario isa LocalSignaling + end + + @testset "Matrix types" begin + scenario = LocalSignaling(2,2,2) + + q_strat = quantum_strategy( + [[1 0;0 0],[0 0;0 1]], + [[1 0;0 0],[0 0;0 1]], + scenario + ) + + @test q_strat isa Strategy + @test q_strat.scenario == LocalSignaling(2,2,2) + @test q_strat == [1 0;0 1] + end + + @testset "DomainErrors" begin + scenario = LocalSignaling(3,3,2) + @test_throws DomainError quantum_strategy( + POVM([[1 0 0;0 0 0;0 0 0],[0 0 0;0 1 0;0 0 0],[0 0 0;0 0 0;0 0 1]]), + State.([[1 0 0;0 0 0;0 0 0],[0 0 0;0 1 0;0 0 0],[0 0 0;0 0 0;0 0 1]]), + scenario + ) + end end @testset "quantum_strategy(BipartiteNonSignaling)" begin - @testset "ch violation" begin + @testset "QBase types ch violation" begin scenario = BipartiteNonSignaling(2,2,2,2) ρ_AB = State([1 0 0 1;0 0 0 0;0 0 0 0;1 0 0 1]/2) Π_Ax = [ @@ -56,16 +88,16 @@ end @test sum(g .* q_strat) ≈ 3.207 atol=2e-4 end - @testset "classical states" begin + @testset "matrix types classical states" begin scenario = BipartiteNonSignaling(2,2,2,2) - ρ_AB = State(kron([1 0;0 0],[0 0;0 1])) + ρ_AB = kron([1 0;0 0],[0 0;0 1]) Π_Ax = [ - POVM([[1 0;0 0],[0 0;0 1]]), - POVM([[0 0;0 1],[1 0;0 0]]) + [[1 0;0 0],[0 0;0 1]], + [[0 0;0 1],[1 0;0 0]] ] Π_By = [ - POVM([[1 0;0 0],[0 0;0 1]]), - POVM([[0 0;0 1],[1 0;0 0]]) + [[1 0;0 0],[0 0;0 1]], + [[0 0;0 1],[1 0;0 0]] ] q_strat = quantum_strategy(ρ_AB, Π_Ax, Π_By, scenario) From 207ef60bc8c9e165316e883e1dfd0e425e2aef6b Mon Sep 17 00:00:00 2001 From: Brian Doolittle Date: Fri, 2 Jul 2021 07:59:34 -0400 Subject: [PATCH 4/5] Polyhedra.jl interface --- Project.toml | 2 ++ docs/src/LocalPolytope/vertices.md | 9 ++++++- docs/src/user_guide.md | 21 +++++++-------- src/LocalPolytope/LocalPolytope.jl | 34 ++++++++++++++++++++---- src/LocalPolytope/facets.jl | 12 +++++++++ test/Project.toml | 8 ++++++ test/unit/LocalPolytope.jl | 42 +++++++++++++++++++++++------- test/unit/LocalPolytope/facets.jl | 19 +++++++++++++- 8 files changed, 119 insertions(+), 28 deletions(-) diff --git a/Project.toml b/Project.toml index cdbcf78..aa10ed3 100644 --- a/Project.toml +++ b/Project.toml @@ -9,6 +9,7 @@ Convex = "f65535da-76fb-5f13-bab9-19810c17039a" Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +Polyhedra = "67491407-f73d-577b-9b50-8179a7c68029" QBase = "e52e8ede-12bf-4731-8af7-b01f6064cb11" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" SCS = "c946c3f1-0d1f-5ce8-9dea-7daa1f7e2d13" @@ -18,6 +19,7 @@ XPORTA = "8c143463-af6f-456f-8aed-72447cb569d2" Combinatorics = "1" Convex = "0.14" JSON = "0.21" +Polyhedra = "0.6" QBase = "0.2" SCS = "0.7" XPORTA = "0.1" diff --git a/docs/src/LocalPolytope/vertices.md b/docs/src/LocalPolytope/vertices.md index e8b1dfd..b5a8d22 100644 --- a/docs/src/LocalPolytope/vertices.md +++ b/docs/src/LocalPolytope/vertices.md @@ -5,10 +5,17 @@ CurrentModule = LocalPolytope Vertices are extreme points of the local polytope. They correspond to deterministic strategies. +The vertex representation of a convex polytope can be computed via the +[Polyhedra.jl](https://github.com/JuliaPolyhedra/Polyhedra.jl) interface. + +```@docs +vrep +``` ## Vertex Enumeration -Enumerate the local polytope vertices for the specified Bell [`Scenario`](@ref). +The vertices of each local polytope can be enumerated for the specified +Bell [`Scenario`](@ref). ```@docs vertices diff --git a/docs/src/user_guide.md b/docs/src/user_guide.md index a8ea2d6..b06274d 100644 --- a/docs/src/user_guide.md +++ b/docs/src/user_guide.md @@ -38,17 +38,17 @@ Bell inequalities. The BellScenario.jl package provides the [`LocalPolytope`](@ref) module to compute Bell inequalities. -The first step is to enumerate the vertices for the CHSH scenario. +The first step is to commpute the vertex representation for the CHSH scenario. ```@example tutorial -chsh_vertices = LocalPolytope.vertices(chsh_scenario) +chsh_polytope = LocalPolytope.vrep(chsh_scenario) ``` Then, the Bell inequalities can computed using the [`LocalPolytope.facets`](@ref) function. ```@example tutorial -chsh_facets = LocalPolytope.facets(chsh_vertices)["facets"] +chsh_facets = LocalPolytope.facets(chsh_polytope) ``` We'll take ``15^{th}`` facet as it represents the CH inequality @@ -67,20 +67,17 @@ ch_inequality = chsh_facets[15] Now that we have computed a Bell inequality, we can find a quantum violation using the [`Nonlocality`](@ref) module. -This will require the use of the [QBase.jl](https://github.com/ChitambarLab/QBase.jl) package. In this example, we will fix Alice's measurement and the quantum state shared between Alice and Bob. ```@example tutorial -using QBase - # maximally entangled state -ρ_AB = State([1 0 0 1;0 0 0 0;0 0 0 0;1 0 0 1]/2) +ρ_AB = [1 0 0 1;0 0 0 0;0 0 0 0;1 0 0 1]/2 -# Alice's measurement -A_POVMs = [ - POVM([ [1 0;0 0], [0 0;0 1] ]), - POVM([ [1 1;1 1]/2, [1 -1;-1 1]/2 ]) +# Alice's measurement bases +Π_ax = [ + [[1 0;0 0], [0 0;0 1]], # Pauli Z basis + [[1 1;1 1]/2, [1 -1;-1 1]/2] # Pauli X basis ] ``` @@ -94,7 +91,7 @@ Finally, we optimize Bob's measurement with respect to the fixed state and measu ```@example tutorial opt_dict = Nonlocality.optimize_measurement( - chsh_scenario, ch_game, ρ_AB, A_POVMs=A_POVMs + chsh_scenario, ch_game, ρ_AB, A_POVMs=Π_ax ) ``` diff --git a/src/LocalPolytope/LocalPolytope.jl b/src/LocalPolytope/LocalPolytope.jl index 1020e09..53a5279 100644 --- a/src/LocalPolytope/LocalPolytope.jl +++ b/src/LocalPolytope/LocalPolytope.jl @@ -45,21 +45,45 @@ however, it is important to note that a Bell violation can simply mean that more resources were used than anticipated. ### Module Exports: -* [`vertices`](@ref) - Compute the set of extreme-points for the Local Polytope. -* [`facets`](@ref) - Compute the linear inequalities which bound the Local Polytope. +* [`vertices`](@ref) - Compute the set of extreme-points for the local polytope. +* [`num_vertices`](@ref) - The number of vertices for the local polytope. +* [`vrep`](@ref) - Construct a [`Polyhedron`](https://juliapolyhedra.github.io/Polyhedra.jl/stable/polyhedron/) + in the vertex representation. +* [`facets`](@ref) - Compute the linear inequalities which bound the local polytope. * [`generator_vertex`](@ref) - Provide a canonical form for a vertex. * [`generator_facet`](@ref) - Provide a canonical form for a facet. -* [`adjacency_decomposition`](@ref) - Efficiently compute the generating facets for the Local - Polytope using the adjacency decomposition technique. +* [`adjacency_decomposition`](@ref) - Efficiently compute the generator facets for the local + polytope using the adjacency decomposition technique. """ module LocalPolytope using LinearAlgebra, Combinatorics -using XPORTA +using XPORTA, Polyhedra + +import Polyhedra: vrep using ..BellScenario include("./vertices.jl") + +""" + vrep(scenario::Scenario; vertices_kwargs...) :: XPORTA.Polyhedron + +Constructs a `Polyhedron` using the vertex representation. +See [Polyhedra.jl](https://github.com/JuliaPolyhedra/Polyhedra.jl) +for more details. +The `vertices_kwargs` keyword arguments are passed through to the `vertices` +function for each `Scenario`. + +!!! note "Return Type" + This function differs from the Polyhedra.jl implementation in that it returns + a `Polyhedron` type rather than a `V-Representation`. + This is done to reduce the number of steps required to construct a polyhedron. +""" +function vrep(scenario::Scenario; vertices_kwargs...) :: XPORTA.Polyhedron + polyhedron(vrep(vertices(scenario; vertices_kwargs...)), XPORTA.Library()) +end + include("./facets.jl") include("./generators.jl") include("./adjacency_decomposition.jl") diff --git a/src/LocalPolytope/facets.jl b/src/LocalPolytope/facets.jl index b9ddfb9..11c6dbb 100644 --- a/src/LocalPolytope/facets.jl +++ b/src/LocalPolytope/facets.jl @@ -55,3 +55,15 @@ function facets( "equalities" => map(row_id -> equalities[row_id,:], 1:size(equalities,1)) ) end + +""" + facets(poly::Polyhedron) :: Vector{Vector{Int64}} + +Returns the facets of the local polytope `poly`. If the facets have not already +been computed, then they are transformed into the half-space representation from +the vertex representation. +""" +function facets(poly::Polyhedron) :: Vector{Vector{Int64}} + inequalities = convert.(Int64, hrep(poly).inequalities) + map(row_id -> inequalities[row_id,:] , 1:size(inequalities,1)) +end diff --git a/test/Project.toml b/test/Project.toml index 1f3215b..911d5f0 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -1,7 +1,15 @@ [deps] JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +Polyhedra = "67491407-f73d-577b-9b50-8179a7c68029" QBase = "e52e8ede-12bf-4731-8af7-b01f6064cb11" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" XPORTA = "8c143463-af6f-456f-8aed-72447cb569d2" + +[compat] +JSON = "0.21" +Polyhedra = "0.6" +QBase = "0.2" +XPORTA = "0.1" +julia = "1.4" diff --git a/test/unit/LocalPolytope.jl b/test/unit/LocalPolytope.jl index 18cfe1a..2a3519b 100644 --- a/test/unit/LocalPolytope.jl +++ b/test/unit/LocalPolytope.jl @@ -1,4 +1,4 @@ -using Test, LinearAlgebra +using Test, LinearAlgebra, Polyhedra, XPORTA @testset "test/unit/LocalPolytope.jl" begin @@ -6,14 +6,38 @@ using BellScenario @testset "running all tests for module LocalPolytope.jl" begin - println("running LocalPolytope.jl unit tests:") - for test in readdir("./test/unit/LocalPolytope/") - # run only julia files in test directory - if occursin(r"^.*\.jl$", test) - println("./unit/LocalPolytope/$test") - @time include("./LocalPolytope/$test") - end - end + @testset "LocalPolytope.vrep()" begin + @testset "no arguments" begin + scenario = LocalSignaling(3,3,2) + local_poly = vrep(scenario) + + @test local_poly isa XPORTA.Polyhedron + @test npoints(local_poly) == 21 + + vertices = map(p -> convert.(Int64,p), points(local_poly)) + @test LocalPolytope.vertices(scenario) == vertices + end + + @testset "passing arguments" begin + scenario = LocalSignaling(3,3,2) + local_poly = vrep(scenario, rank_d_only=true) + + @test local_poly isa XPORTA.Polyhedron + @test npoints(local_poly) == 18 + + vertices = map(p -> convert.(Int64,p), points(local_poly)) + @test LocalPolytope.vertices(scenario, rank_d_only=true) == vertices + end + end + + println("running LocalPolytope.jl unit tests:") + for test in readdir("./test/unit/LocalPolytope/") + # run only julia files in test directory + if occursin(r"^.*\.jl$", test) + println("./unit/LocalPolytope/$test") + @time include("./LocalPolytope/$test") + end + end end diff --git a/test/unit/LocalPolytope/facets.jl b/test/unit/LocalPolytope/facets.jl index 1e55302..c0472e7 100644 --- a/test/unit/LocalPolytope/facets.jl +++ b/test/unit/LocalPolytope/facets.jl @@ -1,4 +1,4 @@ -using Test +using Test, Polyhedra @testset "./src/LocalPolytope/facets.jl" begin @@ -47,4 +47,21 @@ using BellScenario end end +@testset "facets(::Polyhedron)" begin + scenario = LocalSignaling(3,3,2) + local_poly = LocalPolytope.vrep(scenario) + + @test !hrepiscomputed(local_poly) + + facets = LocalPolytope.facets(local_poly) + @test length(facets) == 15 + + @test hrepiscomputed(local_poly) + + match_vertices = LocalPolytope.vertices(scenario) + match_facets = LocalPolytope.facets(match_vertices)["facets"] + + @test facets == match_facets +end + end From 9e7117eaa0c92c9a275d8994874d98965916282e Mon Sep 17 00:00:00 2001 From: Brian Doolittle Date: Fri, 2 Jul 2021 08:50:51 -0400 Subject: [PATCH 5/5] fixing image link --- docs/src/user_guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/user_guide.md b/docs/src/user_guide.md index b06274d..48190e2 100644 --- a/docs/src/user_guide.md +++ b/docs/src/user_guide.md @@ -15,7 +15,7 @@ using BellScenario The CHSH scenario is a [`BipartiteNonSignaling`](@ref) scenario where Alice and Bob each have a black-box with binary inputs and outputs. -![Classical CHSH Scenario](../assets/scenario_images/classical_chsh_scenario.png) +![Classical CHSH Scenario](assets/scenario_images/classical_chsh_scenario.png) This scenario is significant because it is the simplest Bell scenario in which quantum nonlocality can be observed.