From aeb326eb4f1654adbd42624728aeeba9db6f9f7c Mon Sep 17 00:00:00 2001 From: Zejin Shi Date: Wed, 27 Jun 2018 15:25:09 +0900 Subject: [PATCH 1/3] Add `vertex_enumeration`. --- src/Games.jl | 6 +- src/vertex_enumeration.jl | 97 +++++++++++++++++++++++++++++++++ test/runtests.jl | 1 + test/test_vertex_enumeration.jl | 91 +++++++++++++++++++++++++++++++ 4 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 src/vertex_enumeration.jl create mode 100644 test/test_vertex_enumeration.jl diff --git a/src/Games.jl b/src/Games.jl index ec377689..4fbe3f35 100644 --- a/src/Games.jl +++ b/src/Games.jl @@ -68,6 +68,7 @@ include("repeated_game.jl") include("random.jl") include("support_enumeration.jl") include("generators/Generators.jl") +include("vertex_enumeration.jl") export # Types @@ -101,6 +102,9 @@ export random_pure_actions, random_mixed_actions, # Support Enumeration - support_enumeration, support_enumeration_task + support_enumeration, support_enumeration_task, + + # Vertex Enumeration + vertex_enumeration, vertex_enumeration_task end # module diff --git a/src/vertex_enumeration.jl b/src/vertex_enumeration.jl new file mode 100644 index 00000000..f4983801 --- /dev/null +++ b/src/vertex_enumeration.jl @@ -0,0 +1,97 @@ +import Polyhedra: hyperplane + +function vertex_enumeration(g::NormalFormGame{2}; + plib=getlibraryfor(2, Float64)) + + c = Channel(0) + task = vertex_enumeration_task(c, g, plib) + bind(c, task) + schedule(task) + NEs = Tuple{Vector{Real}, Vector{Real}}[NE for NE in c] + + return NEs + +end + +function vertex_enumeration_task(c::Channel, + g::NormalFormGame{2}, + plib) + + task = Task( + () -> _vertex_enumeration_producer(c, g, plib) + ) + + return task + +end + +function _vertex_enumeration_producer{T}(c::Channel, + g::NormalFormGame{2, T}, + plib) + + n, m = size(g.players[1].payoff_array) + + # create Representation for player 1 + H1, V1, H2, V2 = construction_BRP(g, plib) + + ZERO_LABELING_BITS = (1 << (n+m)) - (1 << m) + COMPLETE_LABELING_BITS = 1 << (n+m) - 1 + + for v1 in vreps(V1) + labelings_bits1 = labelings_bits(v1, H1) + if labelings_bits1 == ZERO_LABELING_BITS + continue + end + for v2 in vreps(V2) + labelings_bits2 = labelings_bits(v2, H2) + if xor(labelings_bits1, labelings_bits2) == COMPLETE_LABELING_BITS + put!(c, (_get_mixed_action(v1), + _get_mixed_action(v2))) + end + end + end + +end + +function construction_BRP{T}(g::NormalFormGame{2, T}, plib) + + n, m = size(g.players[1].payoff_array) + + # create Representation for player 1 + C = Matrix{T}(n+m, n) + C[1:m, :] = g.players[2].payoff_array + C[m+1:end, :] = -eye(T, n) + b1 = Vector{T}(n+m) + b1[1:m] = one(T) + b1[m+1:end] = zero(T) + H1 = SimpleHRepresentation(C, b1) + p1 = polyhedron(H1, plib) + V1 = SimpleVRepresentation(p1) + + # create Representation for player 2 + D = Matrix{T}(n+m, m) + D[1:m, :] = -eye(T, m) + D[m+1:end, :] = g.players[1].payoff_array + b2 = Vector{T}(n+m) + b2[1:m] = zero(T) + b2[m+1:end] = one(T) + H2 = SimpleHRepresentation(D, b2) + p2 = polyhedron(H2, plib) + V2 = SimpleVRepresentation(p2) + + return H1, V1, H2, V2 +end + +function labelings_bits(v::VRepElement, p::HRep) + b = 0 + for (i, h) in enumerate(hreps(p)) + if v in hyperplane(h) + b += 1 << (i-1) + end + end + return b +end + +function _get_mixed_action(a::Vector) + return a ./ sum(a) +end diff --git a/test/runtests.jl b/test/runtests.jl index b3dfdbfc..885a3c3f 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -6,5 +6,6 @@ include("test_repeated_game.jl") include("test_normal_form_game.jl") include("test_random.jl") include("test_support_enumeration.jl") +include("test_vertex_enumeration.jl") include("generators/runtests.jl") diff --git a/test/test_vertex_enumeration.jl b/test/test_vertex_enumeration.jl new file mode 100644 index 00000000..d0ec655b --- /dev/null +++ b/test/test_vertex_enumeration.jl @@ -0,0 +1,91 @@ +@testset "Testing vertex Enumeration" begin + + @testset "test 3 by 2 non-degenerate normal form game(Float)" begin + g = NormalFormGame(Player([3.0 3.0; 2.0 5.0; 0.0 6.0]), + Player([3.0 2.0 3.0; 2.0 6.0 1.0])) + NEs = [([0.0, 1/3, 2/3], [1/3, 2/3]), + ([0.8, 0.2, 0.0], [2/3, 1/3]), + ([1.0, 0.0, 0.0], [1.0, 0.0])] + + for (actions_computed, actions) in zip(NEs, vertex_enumeration(g)) + for (action_computed, action) in zip(actions_computed, actions) + @test action_computed ≈ action + @test eltype(action_computed) <: AbstractFloat + end + end + end + + # @testset "test 3 by 2 non-degenerate normal form game(Int)" begin + # g = NormalFormGame(Player([3 3; 2 5; 0 6]), + # Player([3 2 3; 2 6 1])) + # NEs = [([1.0, 0.0, 0.0], [1.0, 0.0]), + # ([0.8, 0.2, 0.0], [2/3, 1/3]), + # ([0.0, 1/3, 2/3], [1/3, 2/3])] + + # for (actions_computed, actions) in zip(NEs, support_enumeration(g)) + # for (action_computed, action) in zip(actions_computed, actions) + # @test action_computed ≈ action + # @test eltype(action_computed) <: AbstractFloat + # end + # end + # end + + # @testset "test 3 by 2 non-degenerate normal form game(Rational)" begin + # g = NormalFormGame(Player([3//1 3//1; 2//1 5//1; 0//1 6//1]), + # Player([3//1 2//1 3//1; 2//1 6//1 1//1])) + # NEs = [([1//1, 0//1, 0//1], [1//1, 0//1]), + # ([4//5, 1//5, 0//1], [2//3, 1//3]), + # ([0//1, 1//3, 2//3], [1//3, 2//3])] + + # for (actions_computed, actions) in zip(NEs, support_enumeration(g)) + # for (action_computed, action) in zip(actions_computed, actions) + # @test action_computed ≈ action + # @test eltype(action_computed) <: Rational + # end + # end + # end + + @testset "test 3 by 2 degenerate normal form game(Float)" begin + g = NormalFormGame(Player([1.0 -1.0; -1.0 1.0; 0.0 0.0]), + Player([1.0 0.0 0.0; 0.0 0.0 0.0])) + NEs = [([1.0, 0.0, 0.0], [1.0, 0.0]), + ([0.0, 1.0, 0.0], [0.0, 1.0])] + + for (actions_computed, actions) in zip(NEs, vertex_enumeration(g)) + for (action_computed, action) in zip(actions_computed, actions) + @test action_computed ≈ action + @test eltype(action_computed) <: AbstractFloat + end + end + end + + # @testset "test 3 by 2 degenerate normal form game(Int)" begin + # g = NormalFormGame(Player([1 -1; -1 1; 0 0]), + # Player([1 0 0; 0 0 0])) + # NEs = [([1.0, 0.0, 0.0], [1.0, 0.0]), + # ([0.0, 1.0, 0.0], [0.0, 1.0])] + + # for (actions_computed, actions) in zip(NEs, support_enumeration(g)) + # for (action_computed, action) in zip(actions_computed, actions) + # @test action_computed ≈ action + # @test eltype(action_computed) <: AbstractFloat + # end + # end + # end + + # @testset "test 3 by 2 degenerate normal form game(Rational)" begin + # g = NormalFormGame(Player([1//1 -1//1; -1//1 1//1; 0//1 0//1]), + # Player([1//1 0//1 0//1; 0//1 0//1 0//1])) + # NEs = [([1//1, 0//1, 0//1], [1//1, 0//1]), + # ([0//1, 1//1, 0//1], [0//1, 1//1])] + + # for (actions_computed, actions) in zip(NEs, support_enumeration(g)) + # for (action_computed, action) in zip(actions_computed, actions) + # @test action_computed ≈ action + # @test eltype(action_computed) <: Rational + # end + # end + # end + + +end From 8c84d431e556878eb9dccff93ae5d8ac7f5126ae Mon Sep 17 00:00:00 2001 From: Zejin Shi Date: Wed, 27 Jun 2018 17:47:06 +0900 Subject: [PATCH 2/3] Update deprecations. --- src/vertex_enumeration.jl | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/vertex_enumeration.jl b/src/vertex_enumeration.jl index f4983801..984d991e 100644 --- a/src/vertex_enumeration.jl +++ b/src/vertex_enumeration.jl @@ -1,7 +1,7 @@ import Polyhedra: hyperplane function vertex_enumeration(g::NormalFormGame{2}; - plib=getlibraryfor(2, Float64)) + plib=SimplePolyhedraLibrary{Float64}()) c = Channel(0) task = vertex_enumeration_task(c, g, plib) @@ -37,12 +37,12 @@ function _vertex_enumeration_producer{T}(c::Channel, ZERO_LABELING_BITS = (1 << (n+m)) - (1 << m) COMPLETE_LABELING_BITS = 1 << (n+m) - 1 - for v1 in vreps(V1) + for v1 in points(V1) labelings_bits1 = labelings_bits(v1, H1) if labelings_bits1 == ZERO_LABELING_BITS continue end - for v2 in vreps(V2) + for v2 in points(V2) labelings_bits2 = labelings_bits(v2, H2) if xor(labelings_bits1, labelings_bits2) == COMPLETE_LABELING_BITS put!(c, (_get_mixed_action(v1), @@ -64,9 +64,9 @@ function construction_BRP{T}(g::NormalFormGame{2, T}, plib) b1 = Vector{T}(n+m) b1[1:m] = one(T) b1[m+1:end] = zero(T) - H1 = SimpleHRepresentation(C, b1) + H1 = hrep(C, b1) p1 = polyhedron(H1, plib) - V1 = SimpleVRepresentation(p1) + V1 = vrep(p1) # create Representation for player 2 D = Matrix{T}(n+m, m) @@ -75,16 +75,16 @@ function construction_BRP{T}(g::NormalFormGame{2, T}, plib) b2 = Vector{T}(n+m) b2[1:m] = zero(T) b2[m+1:end] = one(T) - H2 = SimpleHRepresentation(D, b2) + H2 = hrep(D, b2) p2 = polyhedron(H2, plib) - V2 = SimpleVRepresentation(p2) + V2 = vrep(p2) return H1, V1, H2, V2 end function labelings_bits(v::VRepElement, p::HRep) b = 0 - for (i, h) in enumerate(hreps(p)) + for (i, h) in enumerate(halfspaces(p)) if v in hyperplane(h) b += 1 << (i-1) end @@ -95,3 +95,4 @@ end function _get_mixed_action(a::Vector) return a ./ sum(a) end + From fd1f096f64bc5b489b11ec21ffaefe60d4c39eb8 Mon Sep 17 00:00:00 2001 From: Zejin Shi Date: Fri, 7 Sep 2018 23:04:01 -0700 Subject: [PATCH 3/3] Modifications. --- src/vertex_enumeration.jl | 48 +++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/src/vertex_enumeration.jl b/src/vertex_enumeration.jl index 984d991e..1abd50b2 100644 --- a/src/vertex_enumeration.jl +++ b/src/vertex_enumeration.jl @@ -1,5 +1,3 @@ -import Polyhedra: hyperplane - function vertex_enumeration(g::NormalFormGame{2}; plib=SimplePolyhedraLibrary{Float64}()) @@ -25,25 +23,36 @@ function vertex_enumeration_task(c::Channel, end -function _vertex_enumeration_producer{T}(c::Channel, - g::NormalFormGame{2, T}, - plib) +function _vertex_enumeration_producer(c::Channel, + g::NormalFormGame{2, T}, + plib) n, m = size(g.players[1].payoff_array) # create Representation for player 1 - H1, V1, H2, V2 = construction_BRP(g, plib) + p1, p2 = construction_BRP(g, plib) + V1 = points(p1) + simplex1 = [] + for pidx in eachindex(points(p1)) + push!(simplex1, [idx.value for idx in incidenthalfspaceindices(p1, pidx)]) + end + + V2 = points(p2) + simplex2 = [] + for pidx in eachindex(points(p2)) + push!(simplex2, [idx.value for idx in incidenthalfspaceindices(p2, pidx)]) + end ZERO_LABELING_BITS = (1 << (n+m)) - (1 << m) COMPLETE_LABELING_BITS = 1 << (n+m) - 1 - - for v1 in points(V1) - labelings_bits1 = labelings_bits(v1, H1) + + for (i, v1) in enumerate(V1) + labelings_bits1 = labelings_bits(simplex1[i]) if labelings_bits1 == ZERO_LABELING_BITS continue end - for v2 in points(V2) - labelings_bits2 = labelings_bits(v2, H2) + for (j, v2) in enumerate(V2) + labelings_bits2 = labelings_bits(simplex2[j]) if xor(labelings_bits1, labelings_bits2) == COMPLETE_LABELING_BITS put!(c, (_get_mixed_action(v1), _get_mixed_action(v2))) @@ -53,7 +62,7 @@ function _vertex_enumeration_producer{T}(c::Channel, end -function construction_BRP{T}(g::NormalFormGame{2, T}, plib) +function construction_BRP(g::NormalFormGame{2, T}, plib) n, m = size(g.players[1].payoff_array) @@ -66,7 +75,6 @@ function construction_BRP{T}(g::NormalFormGame{2, T}, plib) b1[m+1:end] = zero(T) H1 = hrep(C, b1) p1 = polyhedron(H1, plib) - V1 = vrep(p1) # create Representation for player 2 D = Matrix{T}(n+m, m) @@ -77,22 +85,18 @@ function construction_BRP{T}(g::NormalFormGame{2, T}, plib) b2[m+1:end] = one(T) H2 = hrep(D, b2) p2 = polyhedron(H2, plib) - V2 = vrep(p2) - return H1, V1, H2, V2 + return p1, p2 end -function labelings_bits(v::VRepElement, p::HRep) +function labelings_bits(inchalfindices::Vector{T}) where T <: Integer b = 0 - for (i, h) in enumerate(halfspaces(p)) - if v in hyperplane(h) - b += 1 << (i-1) - end + for i in inchalfindices + b += 1 << (i-1) end return b end -function _get_mixed_action(a::Vector) +function _get_mixed_action(a::Vector{T}) return a ./ sum(a) end -