From 708afbe85957a755ebc86a1509b273afbf98da85 Mon Sep 17 00:00:00 2001 From: Lionel Zoubritzky Date: Wed, 5 Jul 2023 15:53:14 +0200 Subject: [PATCH] Detect supercell interpenetration in dimensionality --- Project.toml | 2 +- docs/Project.toml | 2 +- src/algorithms/dimensionality.jl | 37 ++++++++++++++++++++++++++------ test/runtests.jl | 35 +++++++++++++++++------------- 4 files changed, 52 insertions(+), 24 deletions(-) diff --git a/Project.toml b/Project.toml index 668bb83..723fc55 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "PeriodicGraphs" uuid = "18c5b727-b240-4874-878a-f2e242435bab" authors = ["Lionel Zoubritzky lionel.zoubritzky@gmail.com"] -version = "0.9.6" +version = "0.10.0" [deps] Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6" diff --git a/docs/Project.toml b/docs/Project.toml index 9eceeb2..b8c41c9 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,7 +1,7 @@ [deps] Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" -Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306" Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6" +Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306" [compat] Documenter = "0.27" diff --git a/src/algorithms/dimensionality.jl b/src/algorithms/dimensionality.jl index e6d61ba..05ffc9f 100644 --- a/src/algorithms/dimensionality.jl +++ b/src/algorithms/dimensionality.jl @@ -127,9 +127,9 @@ Given a list of integer vectors of dimension `N`, return a tuple `(mat, D)` wher invertible matrix whose `D` first columns form a basis of this spanned space, which does not depend on the exact input. -If `D ≠ N`, the remaining columns are set so that `mat` be invertible. Nothing -else is specified about these columns, and in particular you should not assume that -they are independent of the input. +If `D ≠ N`, the remaining columns are set so that `mat` be invertible. These additional +columns will only contain one coefficient equal to 1, and all others to 0. No other +assumption should be made about these columns; in particular, they may depend on the input. !!! warning If modifiable, the input list will be modified in-place during this process. @@ -236,14 +236,37 @@ end dimensionality(g::PeriodicGraph{N}) where N Determine the actual dimension of each connected component of `g`. -Return a dictionary where each entry `n => [l1, l2, ...]` means that -`li` is a list of vertices that form a connected component of dimension `n`. +Return a dictionary where each entry `n => [(l1,m1), (l2,m2), ...]` means that +`li` is a list of vertices that form a connected component of dimension `n`, and that +component is present `mi` times per unit cell. + +In other words, the connected component `li` has a periodicity that can only be expressed +in a unit cell `mi` times larger than the current one. + +## Examples +```jldoctest +julia> dimensionality(PeriodicGraph("2 1 1 1 0 2 2 -1 1 3 3 1 0 3 3 0 1")) +Dict{Int64, Vector{Tuple{Vector{Int64}, Int64}}} with 2 entries: + 2 => [([3], 1)] + 1 => [([1], 1), ([2], 1)] + +julia> dimensionality(PeriodicGraph("1 1 1 2")) +Dict{Int64, Vector{Tuple{Vector{Int64}, Int64}}} with 1 entry: + 1 => [([1], 2)] +``` """ function dimensionality(g::PeriodicGraph) dim = _dimensionality(g) - ret = Dict{Int,Vector{Vector{Int}}}() + ret = Dict{Int,Vector{Tuple{Vector{Int},Int}}}() @inbounds for (d, x) in dim - ret[d] = first.(x) + retd = Vector{Tuple{Vector{Int},Int}}(undef, length(x)) + for (k, (l, vec)) in enumerate(x) + nfoldmat, d2 = normal_basis(vec) + @assert d2 == d + nfold = abs(det(nfoldmat)) + retd[k] = (l, nfold) + end + ret[d] = retd end return ret end diff --git a/test/runtests.jl b/test/runtests.jl index 3c7b53a..04a8771 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -679,37 +679,42 @@ end @test g2 == gref end -function equivalent_dict(d1, d2) +function check_dimensionality(g, d2) + d1 = dimensionality(g) keys(d1) == keys(d2) || return false for k in keys(d1) - s1 = Set(Set(x) for x in d1[k]) - s2 = Set(Set(x) for x in d2[k]) + s1 = Set((Set(l), m) for (l,m) in d1[k]) + s2 = Set((Set(l), m) for (l,m) in d2[k]) s1 == s2 || return false end return true end @testset "Dimensionality" begin - @test dimensionality(PeriodicGraph{0}(5)) == Dict(0 => [collect(1:5)]) + @test dimensionality(PeriodicGraph{0}(5)) == Dict(0 => [(collect(1:5),1)]) g::PeriodicGraph3D = PeriodicGraph3D([PeriodicEdge3D(1, 3, (0, 0, 1)), PeriodicEdge3D(2, 3, (0, 1, 0)), - PeriodicEdge3D(2, 3, (0, -1, 0)), + PeriodicEdge3D(2, 3, (0, 0, 0)), PeriodicEdge3D(4, 4, (1, 1, 0))]) - @test equivalent_dict(dimensionality(g), Dict(1 => connected_components(g))) - @test add_edge!(g, PeriodicEdge(3, 2, (0,0,0))) - @test equivalent_dict(dimensionality(g), Dict(1 => connected_components(g))) + @test check_dimensionality(g, Dict(1 => [(x,1) for x in connected_components(g)])) + @test add_edge!(g, PeriodicEdge(2, 3, (0,-1,0))) + @test check_dimensionality(g, Dict(1 => [(x,1) for x in connected_components(g)])) @test add_edge!(g, PeriodicEdge(2, 2, (0,0,1))) - @test equivalent_dict(dimensionality(g), Dict(1 => [[4]], 2 => [[1,2,3]])) + @test check_dimensionality(g, Dict(1 => [([4],1)], 2 => [([1,2,3],1)])) @test rem_edge!(g, PeriodicEdge(1, 3, (0,0,1))) - @test equivalent_dict(dimensionality(g), Dict(0 => [[1]], 1 => [[4]], 2 => [[2,3]])) + @test check_dimensionality(g, Dict(0 => [([1],1)], 1 => [([4],1)], 2 => [([2,3],1)])) @test rem_edge!(g, 3, PeriodicVertex(2, (0,0,0))) - @test equivalent_dict(dimensionality(g), Dict(0 => [[1]], 1 => [[4]], 2 => [[2,3]])) + @test check_dimensionality(g, Dict(0 => [([1],1)], 1 => [([4],1)], 2 => [([2,3],2)])) @test rem_edge!(g, PeriodicEdge(2, 3, (0,1,0))) - @test equivalent_dict(dimensionality(g), Dict(0 => [[1]], 1 => [[2,3],[4]])) + @test check_dimensionality(g, Dict(0 => [([1],1)], 1 => [([2,3],1),([4],1)])) @test add_edge!(g, 2, PeriodicVertex3D(3, (1,0,-1))) - @test equivalent_dict(dimensionality(g), Dict(0 => [[1]], 1 => [[4]], 2 => [[2,3]])) + @test check_dimensionality(g, Dict(0 => [([1],1)], 1 => [([4],1)], 2 => [([2,3],1)])) @test add_edge!(g, 2, PeriodicVertex(3, (2,0,-1))) - @test equivalent_dict(dimensionality(g), Dict(0 => [[1]], 1 => [[4]], 3 => [[2,3]])) + @test check_dimensionality(g, Dict(0 => [([1],1)], 1 => [([4],1)], 3 => [([2,3],1)])) + + @test check_dimensionality(PeriodicGraph("2 1 1 2 0 1 1 0 1"), Dict(2 => [([1],2)])) + @test check_dimensionality(PeriodicGraph("3 1 1 2 0 0 1 1 0 2 0"), Dict(2 => [([1],4)])) + @test check_dimensionality(PeriodicGraph("3 1 1 0 0 1 1 2 -1 0 0 1 2 0 -1 0 1 2 1 0 0"), Dict(3 => [([1,2],2)])) end @testset "Dimension change" begin @@ -719,7 +724,7 @@ end 3 4 -1 0 0 4 1 0 0 1 4 4 0 0 1") - @test equivalent_dict(dimensionality(g), Dict(1 => [[1,2,3,4]])) + @test check_dimensionality(g, Dict(1 => [(1:4,1)])) gg = PeriodicGraph1D(g) @test string(gg) == "1 1 2 0 1 4 -1 2 3 0 3 4 0 4 4 1" @test PeriodicGraph2D(gg) == PeriodicGraph2D(g) ==