From 8aec9922ff774e4d3dc8dc31809a733edbecc610 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Thu, 5 Dec 2024 17:49:52 +0100 Subject: [PATCH] Improve `iter_possible_adjacencies` (#175) --- src/ArcDiagram.jl | 124 +++++++++++++++++++++++++++++----------------- 1 file changed, 79 insertions(+), 45 deletions(-) diff --git a/src/ArcDiagram.jl b/src/ArcDiagram.jl index 27ff5e49..ba8e4c60 100644 --- a/src/ArcDiagram.jl +++ b/src/ArcDiagram.jl @@ -631,14 +631,27 @@ function all_arc_diagrams( end end if isodd(n_upper_verts + n_lower_verts) - return ArcDiagramIterator{Undirected}([], 0) + return ArcDiagramIterator{Undirected}(ArcDiagramUndirected[], 0) + end + forbidden_neighbors = Dict{Int, Vector{Int}}() + for i in 1:n_upper_verts + i = -i + forbidden_neighbors[i] = Vector{Int}() + end + for i in 1:n_lower_verts + forbidden_neighbors[i] = Vector{Int}() + end + for is in indep_sets + for i in is + union!(forbidden_neighbors[i], is) + end end iter, len = iter_possible_adjacencies_undir( n_upper_verts, n_lower_verts, [0 for _ in 1:n_upper_verts], [0 for _ in 1:n_lower_verts], - indep_sets, + forbidden_neighbors, ) return ArcDiagramIterator{Undirected}(iter, len) end @@ -648,36 +661,46 @@ function iter_possible_adjacencies_undir( n_lower_verts::Int, partial_upper::Vector{Int}, partial_lower::Vector{Int}, - indep_sets::AbstractVector{<:AbstractVector{Int}}, + forbidden_neighbors::Dict{Int, Vector{Int}}, ) - i = findfirst(==(0), partial_upper) + i = findfirst(iszero, partial_upper) if !isnothing(i) i = -i - relevant_indep_sets = filter(is -> i in is, indep_sets) - poss_upper_adjs = setdiff(setdiff(map(j -> -j, findall(==(0), partial_upper)), i), relevant_indep_sets...) - poss_lower_adjs = setdiff(findall(==(0), partial_lower), relevant_indep_sets...) - choices = Iterators.map([poss_upper_adjs; poss_lower_adjs]) do j - partial_upper2 = deepcopy(partial_upper) - partial_lower2 = deepcopy(partial_lower) + poss_upper_adjs = (-j for j in findall(iszero, partial_upper) if i != -j && !(-j in forbidden_neighbors[i])) + poss_lower_adjs = (j for j in findall(iszero, partial_lower) if !(j in forbidden_neighbors[i])) + choices = Iterators.map(Iterators.flatten([poss_upper_adjs, poss_lower_adjs])) do j + partial_upper2 = copy(partial_upper) + partial_lower2 = copy(partial_lower) partial_upper2[-i] = j if j < 0 partial_upper2[-j] = i else partial_lower2[j] = i end - iter_possible_adjacencies_undir(n_upper_verts, n_lower_verts, partial_upper2, partial_lower2, indep_sets) + iter_possible_adjacencies_undir( + n_upper_verts, + n_lower_verts, + partial_upper2, + partial_lower2, + forbidden_neighbors, + ) end return Iterators.flatten(Iterators.map(first, choices)), sum(last, choices; init=0) else - i = findfirst(==(0), partial_lower) + i = findfirst(iszero, partial_lower) if !isnothing(i) - relevant_indep_sets = filter(is -> i in is, indep_sets) - poss_lower_adjs = setdiff(setdiff(findall(==(0), partial_lower), i), relevant_indep_sets...) + poss_lower_adjs = (j for j in findall(iszero, partial_lower) if i != j && !(j in forbidden_neighbors[i])) choices = Iterators.map(poss_lower_adjs) do j - partial_lower2 = deepcopy(partial_lower) + partial_lower2 = copy(partial_lower) partial_lower2[i] = j partial_lower2[j] = i - iter_possible_adjacencies_undir(n_upper_verts, n_lower_verts, partial_upper, partial_lower2, indep_sets) + iter_possible_adjacencies_undir( + n_upper_verts, + n_lower_verts, + partial_upper, + partial_lower2, + forbidden_neighbors, + ) end return Iterators.flatten(Iterators.map(first, choices)), sum(last, choices; init=0) else @@ -704,7 +727,7 @@ function all_arc_diagrams( end end if isodd(n_upper_verts + n_lower_verts) - return ArcDiagramIterator{Directed}([], 0) + return ArcDiagramIterator{Directed}(ArcDiagramDirected[], 0) end rets = if n_upper_verts == 0 [all_arc_diagrams(Directed, BitVector([]), n_lower_verts; indep_sets, check=false)] @@ -734,10 +757,10 @@ function all_arc_diagrams( end end if isodd(n_upper_verts + n_lower_verts) - return ArcDiagramIterator{Directed}([], 0) + return ArcDiagramIterator{Directed}(ArcDiagramDirected[], 0) end if abs(parity_diff(parity_upper_verts)) > n_lower_verts - return ArcDiagramIterator{Directed}([], 0) + return ArcDiagramIterator{Directed}(ArcDiagramDirected[], 0) end rets = if n_lower_verts == 0 [all_arc_diagrams(Directed, parity_upper_verts, BitVector([]); indep_sets, check=false)] @@ -770,10 +793,23 @@ function all_arc_diagrams( end end if isodd(n_upper_verts + n_lower_verts) - return ArcDiagramIterator{Directed}([], 0) + return ArcDiagramIterator{Directed}(ArcDiagramDirected[], 0) end if parity_diff(parity_upper_verts) != parity_diff(parity_lower_verts) - return ArcDiagramIterator{Directed}([], 0) + return ArcDiagramIterator{Directed}(ArcDiagramDirected[], 0) + end + forbidden_neighbors = Dict{Int, Vector{Int}}() + for i in 1:n_upper_verts + i = -i + forbidden_neighbors[i] = Vector{Int}() + end + for i in 1:n_lower_verts + forbidden_neighbors[i] = Vector{Int}() + end + for is in indep_sets + for i in is + union!(forbidden_neighbors[i], is) + end end iter, len = iter_possible_adjacencies_dir( n_upper_verts, @@ -782,7 +818,7 @@ function all_arc_diagrams( parity_lower_verts, [0 for _ in 1:n_upper_verts], [0 for _ in 1:n_lower_verts], - indep_sets, + forbidden_neighbors, ) return ArcDiagramIterator{Directed}(iter, len) end @@ -794,23 +830,22 @@ function iter_possible_adjacencies_dir( parity_lower_verts::BitVector, partial_upper::Vector{Int}, partial_lower::Vector{Int}, - indep_sets::AbstractVector{<:AbstractVector{Int}}, + forbidden_neighbors::Dict{Int, Vector{Int}}, ) - i = findfirst(==(0), partial_upper) + i = findfirst(iszero, partial_upper) if !isnothing(i) i = -i - relevant_indep_sets = filter(is -> i in is, indep_sets) - poss_upper_adjs = [ - j for j in setdiff(setdiff(map(j -> -j, findall(==(0), partial_upper)), i), relevant_indep_sets...) if - parity_upper_verts[-i] != parity_upper_verts[-j] - ] - poss_lower_adjs = [ - j for j in setdiff(findall(==(0), partial_lower), relevant_indep_sets...) if - parity_upper_verts[-i] == parity_lower_verts[j] - ] - choices = Iterators.map([poss_upper_adjs; poss_lower_adjs]) do j - partial_upper2 = deepcopy(partial_upper) - partial_lower2 = deepcopy(partial_lower) + poss_upper_adjs = ( + -j for j in findall(iszero, partial_upper) if + i != -j && !(-j in forbidden_neighbors[i]) && parity_upper_verts[-i] != parity_upper_verts[j] + ) + poss_lower_adjs = ( + j for j in findall(iszero, partial_lower) if + !(j in forbidden_neighbors[i]) && parity_upper_verts[-i] == parity_lower_verts[j] + ) + choices = Iterators.map(Iterators.flatten([poss_upper_adjs, poss_lower_adjs])) do j + partial_upper2 = copy(partial_upper) + partial_lower2 = copy(partial_lower) partial_upper2[-i] = j if j < 0 partial_upper2[-j] = i @@ -824,20 +859,19 @@ function iter_possible_adjacencies_dir( parity_lower_verts, partial_upper2, partial_lower2, - indep_sets, + forbidden_neighbors, ) end return Iterators.flatten(Iterators.map(first, choices)), sum(last, choices; init=0) else - i = findfirst(==(0), partial_lower) + i = findfirst(iszero, partial_lower) if !isnothing(i) - relevant_indep_sets = filter(is -> i in is, indep_sets) - poss_lower_adjs = [ - j for j in setdiff(setdiff(findall(==(0), partial_lower), i), relevant_indep_sets...) if - parity_lower_verts[i] != parity_lower_verts[j] - ] + poss_lower_adjs = ( + j for j in findall(iszero, partial_lower) if + i != j && !(j in forbidden_neighbors[i]) && parity_lower_verts[i] != parity_lower_verts[j] + ) choices = Iterators.map(poss_lower_adjs) do j - partial_lower2 = deepcopy(partial_lower) + partial_lower2 = copy(partial_lower) partial_lower2[i] = j partial_lower2[j] = i iter_possible_adjacencies_dir( @@ -847,7 +881,7 @@ function iter_possible_adjacencies_dir( parity_lower_verts, partial_upper, partial_lower2, - indep_sets, + forbidden_neighbors, ) end return Iterators.flatten(Iterators.map(first, choices)), sum(last, choices; init=0)