diff --git a/dev/dimension/index.html b/dev/dimension/index.html index a77d1fe..6ff2d50 100644 --- a/dev/dimension/index.html +++ b/dev/dimension/index.html @@ -1,12 +1,31 @@ -Dimensionality · PeriodicGraphs.jl

Dimensionality

A periodic graph g of type PeriodicGraph{N} has dimension N, which means that its unit cell is repeated across N independent axes. However, this number may be larger than the actual number of independent axes necessary to describe the repeating unit of the graph, which we will call the dimensionality. For example, consider an infinite set of identical 2-periodic graphs stacked across a third dimension: the resulting graph is of dimension 3, but its dimensionality is 2 (or below) because all the topological information is stored in the 2-periodic subgraph.

The connected components of g can be separated and sorted by dimensionality using the dimensionality function:

PeriodicGraphs.dimensionalityFunction
dimensionality(g::PeriodicGraph{N}) where N

Determine the actual dimension of each connected component of g. 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

julia> dimensionality(PeriodicGraph("2   1 1  1 0   2 2  -1 1   3 3  1 0   3 3  0 1"))
+Dimensionality · PeriodicGraphs.jl

Dimensionality

A periodic graph g of type PeriodicGraph{N} has dimension N, which means that its unit cell is repeated across N independent axes. However, this number may be larger than the actual number of independent axes necessary to describe the repeating unit of the graph, which we will call the dimensionality. For example, consider an infinite set of identical 2-periodic graphs stacked across a third dimension: the resulting graph is of dimension 3, but its dimensionality is 2 (or below) because all the topological information is stored in the 2-periodic subgraph.

The connected components of g can be separated and sorted by dimensionality using the dimensionality function:

PeriodicGraphs.dimensionalityFunction
dimensionality(g::PeriodicGraph{N}) where N

Determine the actual dimension of each connected component of g. 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. See also split_catenation.

Examples

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)]
source

To transpose a graph from one dimension N to another D, call the type constructor PeriodicGraph{D} directly on g::PeriodicGraph{N}. This can be useful to manipulate a graph of dimensionality D as a graph of actual dimension D, which often reduces computational costs.

PeriodicGraphs.PeriodicGraphMethod
PeriodicGraph{D}(graph::PeriodicGraph{N}) where {D,N}

Return a graph that has the same structural information as the input graph but embedded in D dimensions instead of N. It will fail if the dimensionality of the graph is greater than D.

Note

The behaviour is undefined if D < N and there are multiple non-identical connected components. In particular, the function is expected to fail if these components do not share the same orientation.

source

For example, the following function extracts the list of 1-dimensional components from a given PeriodicGraph:

julia> function extract_1D_components(g::PeriodicGraph{D}) where D
+  1 => [([1], 2)]
source

See also split_catenation to split connected components in a more detailed fashion, when multiple components can share the same vertex indices:

PeriodicGraphs.split_catenationFunction
split_catenation(graph::PeriodicGraph{N}) where N

Return a list of tuples (sublist, mat, dim). Each sublist is made of a list of pairs (subgraph, vmap) where subgraph is a connected component of the input graph, whose vertices are given by vmap from graph. dim is the dimensionality of these connected components, and mat is the transformation matrix between the input cell and the component's cell.

Each sublist contains connected components that share the same vertex indices.

Example

julia> g = PeriodicGraph("2    1 1  3 0   1 1  0 1   2 3  1 0   3 2  1 0");
+
+julia> dimensionality(g)
+Dict{Int64, Vector{Tuple{Vector{Int64}, Int64}}} with 2 entries:
+  2 => [([1], 3)]
+  1 => [([2, 3], 2)]
+
+julia> splits = split_catenation(g);
+
+julia> last.(splits) # One 2-dimensional catenation (vertex 1), one 1-dimensional (vertices 2 and 3)
+2-element Vector{Int64}:
+ 2
+ 1
+
+julia> sublist, mat, dim = last(splits); # the 1-dimensional connected components
+
+julia> sublist # first sublist takes vertex 2 from the reference unit cell, second one takes vertex 3.
+2-element Vector{Tuple{PeriodicGraph2D, Vector{PeriodicVertex2D}}}:
+ (PeriodicGraph2D(2, PeriodicEdge2D[(1, 2, (0,0)), (1, 2, (1,0))]), [(2, (0,0)), (3, (-1,0))])
+ (PeriodicGraph2D(2, PeriodicEdge2D[(1, 2, (0,0)), (1, 2, (1,0))]), [(3, (0,0)), (2, (-1,0))])
source

To transpose a graph from one dimension N to another D, call the type constructor PeriodicGraph{D} directly on g::PeriodicGraph{N}. This can be useful to manipulate a graph of dimensionality D as a graph of actual dimension D, which often reduces computational costs.

PeriodicGraphs.PeriodicGraphMethod
PeriodicGraph{D}(graph::PeriodicGraph{N}) where {D,N}

Return a graph that has the same structural information as the input graph but embedded in D dimensions instead of N. It will fail if the dimensionality of the graph is greater than D.

Note

The behaviour is undefined if D < N and there are multiple non-identical connected components. In particular, the function is expected to fail if these components do not share the same orientation.

source

For example, the following function extracts the list of 1-dimensional components from a given PeriodicGraph:

julia> function extract_1D_components(g::PeriodicGraph{D}) where D
            d = dimensionality(g)
            components1D = get(d, 1, Vector{Int}[])
            return [PeriodicGraph1D(g[l]) for l in components1D]
@@ -21,4 +40,4 @@
 julia> extract_1D_components(g)
 2-element Vector{PeriodicGraph1D}:
  PeriodicGraph1D(1, PeriodicEdge1D[(1, 1, (1,))])
- PeriodicGraph1D(2, PeriodicEdge1D[(1, 2, (-1,)), (1, 2, (1,))])

The first subgraph corresponds to g[[3]] and the second to g[[6,7]], both converted to PeriodicGraph1D.

The dimension of a graph can also be reduced with loss of information through the slice_graph function.

+ PeriodicGraph1D(2, PeriodicEdge1D[(1, 2, (-1,)), (1, 2, (1,))])

The first subgraph corresponds to g[[3]] and the second to g[[6,7]], both converted to PeriodicGraph1D.

The dimension of a graph can also be reduced with loss of information through the slice_graph function.

diff --git a/dev/index.html b/dev/index.html index fbd8194..9c23c41 100644 --- a/dev/index.html +++ b/dev/index.html @@ -1,2 +1,2 @@ -Home · PeriodicGraphs.jl

PeriodicGraphs.jl

A Julia package for the manipulation of periodic graphs.

Usages

PeriodicGraphs.jl defines types and algorithms useful for the manipulation of N-periodic undirected graphs, with N known at compile-time. It extends Graphs.jl by providing the new PeriodicGraph type which implements the AbstractGraph API. It also provides an API for the manipulation of symmetries.

This package serves as support for the PeriodicGraphEmbeddings.jl library, which focuses on euclidean embeddings of periodic graphs, and for CrystalNets.jl for the manipulation and identification of crystal nets, which are 2 or 3-periodic graphs.

Package installation

The installation follows the usual procedure. Start by downloading and installing Julia (v1.6 or higher for PeriodicGraphs.jl). Then, either

  • open the Julia REPL and enter the package manager by typing ], then install PeriodicGraphs.jl by entering:
    pkg> add PeriodicGraphs
  • alternatively, you can do it from a shell by executing:
    julia -e 'import Pkg; Pkg.add("PeriodicGraphs")

To use the package, open a REPL and enter

julia> using PeriodicGraphs
+Home · PeriodicGraphs.jl

PeriodicGraphs.jl

A Julia package for the manipulation of periodic graphs.

Usages

PeriodicGraphs.jl defines types and algorithms useful for the manipulation of N-periodic undirected graphs, with N known at compile-time. It extends Graphs.jl by providing the new PeriodicGraph type which implements the AbstractGraph API. It also provides an API for the manipulation of symmetries.

This package serves as support for the PeriodicGraphEmbeddings.jl library, which focuses on euclidean embeddings of periodic graphs, and for CrystalNets.jl for the manipulation and identification of crystal nets, which are 2 or 3-periodic graphs.

Package installation

The installation follows the usual procedure. Start by downloading and installing Julia (v1.6 or higher for PeriodicGraphs.jl). Then, either

  • open the Julia REPL and enter the package manager by typing ], then install PeriodicGraphs.jl by entering:
    pkg> add PeriodicGraphs
  • alternatively, you can do it from a shell by executing:
    julia -e 'import Pkg; Pkg.add("PeriodicGraphs")

To use the package, open a REPL and enter

julia> using PeriodicGraphs
diff --git a/dev/neighborhood/index.html b/dev/neighborhood/index.html index 302d5d0..642d3b5 100644 --- a/dev/neighborhood/index.html +++ b/dev/neighborhood/index.html @@ -16,5 +16,5 @@ # return something end

In some cases however, the Set-interface can end up being the bottleneck. In this kind of situation, it may be better to:

  1. replace the initialization of visited by

    width = PeriodicGraphs.graph_width!(g)
     seen_size = nv(g)*(2*(1 + fld(depth-1, width)) + 1)^N
    -visited = falses(seen_size)
  2. replace x ∈ visited by visited[hash_position(x, g)] and

  3. replace push!(x, visited) by visited[hash_position(x, g)] = true

although some care should be taken since PeriodicGraphs.graph_width! is only a heuristic.

Such algorithms can be used to compute the topological invariants like coordination_sequence for example.

API

PeriodicGraphs.PeriodicEdgeIterType
PeriodicEdgeIter{N} <: AbstractEdgeIter

Edge iterator type for undirected N-periodic graphs.

The iterator only yields edges in the form (u, v, ofs) with either u < v or u == v && ofs > zero(ofs). This is possible because PeriodicGraphs are undirected, hence to each edge (u, v, ofs) in the graph corresponds its reverse edge (v, u, .-ofs). The iterator thus yields each edge of the graph exactly once.

source
PeriodicGraphs.OffsetVertexIteratorType
OffsetVertexIterator{D} <: AbstractVector{PeriodicVertex{D}}
-OffsetVertexIterator(ofs::SVector{D,Int}, list::AbstractVector{PeriodicVertex{D}}) where D

Iterator type that yields the sequence of PeriodicVertex in list, each offset by the input ofs.

source
PeriodicGraphs.graph_width!Function
graph_width!(g::PeriodicGraph{N}) where N

Set the width internal field of the graph so that the for most n ∈ N*, the n-th neighbor of any vertex v of the initial cell is in a cell (i_1, i_2, ..., i_N) such that max(abs.((i_1, i_2, ..., i_N))) ≤ 1 + fld((n - 1), width). Return the new width.

This function is only a heuristic, it may produce a width that does not satisfy the condition.

This function returns the current width if it is not equal to -1 (internal value used to mark an unset width). If you decide to modify the other internal fields of g, it is probably a good idea to do g.width[] = -1 so that this function gets automatically called when needed, unless you are sure the width will not be affected by your change.

source
+visited = falses(seen_size)
  • replace x ∈ visited by visited[hash_position(x, g)] and

  • replace push!(x, visited) by visited[hash_position(x, g)] = true

  • although some care should be taken since PeriodicGraphs.graph_width! is only a heuristic.

    Such algorithms can be used to compute the topological invariants like coordination_sequence for example.

    API

    PeriodicGraphs.PeriodicEdgeIterType
    PeriodicEdgeIter{N} <: AbstractEdgeIter

    Edge iterator type for undirected N-periodic graphs.

    The iterator only yields edges in the form (u, v, ofs) with either u < v or u == v && ofs > zero(ofs). This is possible because PeriodicGraphs are undirected, hence to each edge (u, v, ofs) in the graph corresponds its reverse edge (v, u, .-ofs). The iterator thus yields each edge of the graph exactly once.

    source
    PeriodicGraphs.OffsetVertexIteratorType
    OffsetVertexIterator{D} <: AbstractVector{PeriodicVertex{D}}
    +OffsetVertexIterator(ofs::SVector{D,Int}, list::AbstractVector{PeriodicVertex{D}}) where D

    Iterator type that yields the sequence of PeriodicVertex in list, each offset by the input ofs.

    source
    PeriodicGraphs.graph_width!Function
    graph_width!(g::PeriodicGraph{N}) where N

    Set the width internal field of the graph so that the for most n ∈ N*, the n-th neighbor of any vertex v of the initial cell is in a cell (i_1, i_2, ..., i_N) such that max(abs.((i_1, i_2, ..., i_N))) ≤ 1 + fld((n - 1), width). Return the new width.

    This function is only a heuristic, it may produce a width that does not satisfy the condition.

    This function returns the current width if it is not equal to -1 (internal value used to mark an unset width). If you decide to modify the other internal fields of g, it is probably a good idea to do g.width[] = -1 so that this function gets automatically called when needed, unless you are sure the width will not be affected by your change.

    source
    diff --git a/dev/rings/index.html b/dev/rings/index.html index b22ed7a..107384a 100644 --- a/dev/rings/index.html +++ b/dev/rings/index.html @@ -1,5 +1,5 @@ -Rings · PeriodicGraphs.jl

    Ring statistics

    Definitions

    In this section, we use the terminology recommended by Blatov, O’Keeffe and Proserpio. In particular:

    • a cycle is a sequence of vertices v₁, v₂, ..., vₙ such that for all i between 2 and n, vᵢ₋₁ and vᵢ are neighbors, as well as v₁ and vₙ, and no vᵢ occurs more than once in the sequence. It can be equivalently represented by the sequence of edges between two consecutive vertices and between v₁ and vₙ.
    • the sum of two or more cycles is the set of edges occurring only an odd number of times in the set of input cycles. The sum of two cycles is thus the symmetric difference of their edges. Note that the sum of cycles may be empty, or may be the juxtaposition of several edge-disjoint cycles.
    • the length of a cycle is its number of edges. It is also equal to its number of vertices since no vertex is repeated in the sequence. A cycle a is strictly smaller than another b when the length of a is strictly lower than that of b.
    • a ring is a cycle which is not the sum of two strictly smaller cycles. An equivalent definition is that a ring is a cycle which does not admit a short-circuit: between two vertices of the ring, there is no path of the graph strictly smaller than both branches of the ring linking the two vertices.
    • a strong ring is a cycle which is not the sum of any number of strictly smaller cycles.

    Manual

    PeriodicGraphs.jl provides an algorithm for the determination of all rings and strong rings up to a given size in a PeriodicGraph. It can also be used on finite graphs by converting them to PeriodicGraph{0}, although the code is not optimized for this case.

    The rings (respectively strong_rings) function returns the list of all rings (respectively strong rings) in the graph up to a given size:

    PeriodicGraphs.ringsFunction
    rings(g::PeriodicGraph{D}, [depth::Integer=15,] symmetries::AbstractSymmetryGroup=NoSymmetryGroup(g), dist::DistanceRecord=DistanceRecord(g,depth)) where D

    Compute the list of rings in g, up to length 2*depth+3. Return the list of Vector{Int} where each sublist is a ring whose vertices are the reverse_hash_positions of the sublist elements. Also return an AbstractSymmetryGroup acting on the returned rings.

    A ring is a cycle of the graph for which there is no shortcut, i.e. no path in the graph between two vertices of the cycle that is shorter than either path connecting the vertices in the cycle.

    If provided, symmetries should represent the symmetries of the graph as a AbstractSymmetryGroup object respecting its documented interface.

    A PeriodicGraphs.DistanceRecord dist can be optionally provided to track the distances between pairs of vertices in the graph.

    source
    PeriodicGraphs.strong_ringsFunction
    strong_rings([rs::Vector{Vector{Int}},] g::PeriodicGraph{D}, [depth::Integer=15,] symmetries::AbstractSymmetryGroup=NoSymmetryGroup(g), dist::DistanceRecord=DistanceRecord(g,depth)) where D

    Compute the list of strong rings in g, up to length 2*depth+3. Return them with their symmetry group. Each ring is represented by the list of hash_position of its vertices.

    The optional first argument rs is the list of rings which can be provided if previously computed.

    See rings for the meaning of the other arguments.

    A strong ring is a cycle of the graph which cannot be decomposed into a sum of any number of smaller cycles. By comparison, a ring is a cycle which cannot be decomposed into a sum of two smaller cycles. In particular, all strong rings are rings.

    See also strong_erings to obtain the rings as a list of integers representing the edges of the ring, instead of a list of integers representing its vertices.

    source

    A few notes on the output:

    • The output is a pair (rs, symm) where rs is the list of rings (respectively strong rings) and symm is an AbstractSymmetryGroup which contains symmetries of rs. symm is always a NoSymmetryGroup if the optional argument symmetries is not provided.
    • The returned list of rings rs is generally unsorted.
    • All translations of the same ring are represented by a unique ring, which means that a ring crossing through different unit cells will only appear once in the list, even though it may appear several times in a single unit cell.
    • The symmetries optional argument reduces the computational cost of the algorithm. The output lists rs with and without the optional argument are identical except for the order of their elements.

    The optional argument depth defaults to 15, which means that rings containing up to 33 edges will be considered. This default value is chosen to accomodate the vast majority of periodic nets encountered as crystal nets, for which the ring size rarely exceeds 20.

    Let's take as example an aperiodic graph representing a small house, made of a cube with a pyramid on top:

    julia> house = PeriodicGraph{0}("0 "*
    +Rings · PeriodicGraphs.jl

    Ring statistics

    Definitions

    In this section, we use the terminology recommended by Blatov, O’Keeffe and Proserpio. In particular:

    • a cycle is a sequence of vertices v₁, v₂, ..., vₙ such that for all i between 2 and n, vᵢ₋₁ and vᵢ are neighbors, as well as v₁ and vₙ, and no vᵢ occurs more than once in the sequence. It can be equivalently represented by the sequence of edges between two consecutive vertices and between v₁ and vₙ.
    • the sum of two or more cycles is the set of edges occurring only an odd number of times in the set of input cycles. The sum of two cycles is thus the symmetric difference of their edges. Note that the sum of cycles may be empty, or may be the juxtaposition of several edge-disjoint cycles.
    • the length of a cycle is its number of edges. It is also equal to its number of vertices since no vertex is repeated in the sequence. A cycle a is strictly smaller than another b when the length of a is strictly lower than that of b.
    • a ring is a cycle which is not the sum of two strictly smaller cycles. An equivalent definition is that a ring is a cycle which does not admit a short-circuit: between two vertices of the ring, there is no path of the graph strictly smaller than both branches of the ring linking the two vertices.
    • a strong ring is a cycle which is not the sum of any number of strictly smaller cycles.

    Manual

    PeriodicGraphs.jl provides an algorithm for the determination of all rings and strong rings up to a given size in a PeriodicGraph. It can also be used on finite graphs by converting them to PeriodicGraph{0}, although the code is not optimized for this case.

    The rings (respectively strong_rings) function returns the list of all rings (respectively strong rings) in the graph up to a given size:

    PeriodicGraphs.ringsFunction
    rings(g::PeriodicGraph{D}, [depth::Integer=15,] symmetries::AbstractSymmetryGroup=NoSymmetryGroup(g), dist::DistanceRecord=DistanceRecord(g,depth)) where D

    Compute the list of rings in g, up to length 2*depth+3. Return the list of Vector{Int} where each sublist is a ring whose vertices are the reverse_hash_positions of the sublist elements. Also return an AbstractSymmetryGroup acting on the returned rings.

    A ring is a cycle of the graph for which there is no shortcut, i.e. no path in the graph between two vertices of the cycle that is shorter than either path connecting the vertices in the cycle.

    If provided, symmetries should represent the symmetries of the graph as a AbstractSymmetryGroup object respecting its documented interface.

    A PeriodicGraphs.DistanceRecord dist can be optionally provided to track the distances between pairs of vertices in the graph.

    source
    PeriodicGraphs.strong_ringsFunction
    strong_rings([rs::Vector{Vector{Int}},] g::PeriodicGraph{D}, [depth::Integer=15,] symmetries::AbstractSymmetryGroup=NoSymmetryGroup(g), dist::DistanceRecord=DistanceRecord(g,depth)) where D

    Compute the list of strong rings in g, up to length 2*depth+3. Return them with their symmetry group. Each ring is represented by the list of hash_position of its vertices.

    The optional first argument rs is the list of rings which can be provided if previously computed.

    See rings for the meaning of the other arguments.

    A strong ring is a cycle of the graph which cannot be decomposed into a sum of any number of smaller cycles. By comparison, a ring is a cycle which cannot be decomposed into a sum of two smaller cycles. In particular, all strong rings are rings.

    See also strong_erings to obtain the rings as a list of integers representing the edges of the ring, instead of a list of integers representing its vertices.

    source

    A few notes on the output:

    • The output is a pair (rs, symm) where rs is the list of rings (respectively strong rings) and symm is an AbstractSymmetryGroup which contains symmetries of rs. symm is always a NoSymmetryGroup if the optional argument symmetries is not provided.
    • The returned list of rings rs is generally unsorted.
    • All translations of the same ring are represented by a unique ring, which means that a ring crossing through different unit cells will only appear once in the list, even though it may appear several times in a single unit cell.
    • The symmetries optional argument reduces the computational cost of the algorithm. The output lists rs with and without the optional argument are identical except for the order of their elements.

    The optional argument depth defaults to 15, which means that rings containing up to 33 edges will be considered. This default value is chosen to accomodate the vast majority of periodic nets encountered as crystal nets, for which the ring size rarely exceeds 20.

    Let's take as example an aperiodic graph representing a small house, made of a cube with a pyramid on top:

    julia> house = PeriodicGraph{0}("0 "*
                         "1 2  2 3  3 4  4 1 "* # square base of the house
                         "1 5  2 6  3 7  4 8 "* # 4 vertical pillars
                         "5 6  6 7  7 8  8 5 "* # square ceiling
    @@ -33,7 +33,7 @@
      [5, 6, 9]
      [5, 8, 9]
      [6, 7, 9]
    - [7, 8, 9]

    We can see that the house has four weak rings of size 6, six rings of size 4 among which five are strong, and four strong rings of size 3.

    The strong rings are the faces of the house: there are four triangles that make the roof, four squares that make the walls and one last square for the base of the house. The square corresponding to the ceiling is actually the sum of the four triangles of the roof, which is why it is not a strong ring. The four weak rings of size 6 are those that go through each vertex of the cube except for one of the four opposite pairs.

    To explore the ring distributions around individual vertices, the RingAttributions struct factors the ring distribution by vertex. The list of rings including a particular vertex is factored into a RingIncluding struct:

    PeriodicGraphs.RingAttributionsType
    RingAttributions{D} <: AbstractVector{RingIncluding{D}}

    Represent a set of rings of a PeriodicGraph{D}.

    For ra of type RingAttributions{D}, ra[i] is a RingIncluding{D} object representing the set of rings including PeriodicVertex{D}(i).

    source
    PeriodicGraphs.RingIncludingType
    RingIncluding{D} <: AbstractVector{OffsetVertexIterator{D}}

    The list of rings of a PeriodicGraph{D} including a particular vertex PeriodicVertex{D}(i).

    The object is iterable and indexable by an integer: for ri of type RingIncluding{D}, ri[j] is an iterable over the vertices of the j-th ring including vertex i.

    source

    To avoid useless computations, the lists of rings and the rings themselves are returned as iterables instead of Vector{PeriodicVertex{N}} and such, so they should be collected if required.

    Let's look all the rings on our little house:

    julia> ras = RingAttributions(house)
    + [7, 8, 9]

    We can see that the house has four weak rings of size 6, six rings of size 4 among which five are strong, and four strong rings of size 3.

    The strong rings are the faces of the house: there are four triangles that make the roof, four squares that make the walls and one last square for the base of the house. The square corresponding to the ceiling is actually the sum of the four triangles of the roof, which is why it is not a strong ring. The four weak rings of size 6 are those that go through each vertex of the cube except for one of the four opposite pairs.

    To explore the ring distributions around individual vertices, the RingAttributions struct factors the ring distribution by vertex. The list of rings including a particular vertex is factored into a RingIncluding struct:

    PeriodicGraphs.RingAttributionsType
    RingAttributions{D} <: AbstractVector{RingIncluding{D}}

    Represent a set of rings of a PeriodicGraph{D}.

    For ra of type RingAttributions{D}, ra[i] is a RingIncluding{D} object representing the set of rings including PeriodicVertex{D}(i).

    source
    PeriodicGraphs.RingIncludingType
    RingIncluding{D} <: AbstractVector{OffsetVertexIterator{D}}

    The list of rings of a PeriodicGraph{D} including a particular vertex PeriodicVertex{D}(i).

    The object is iterable and indexable by an integer: for ri of type RingIncluding{D}, ri[j] is an iterable over the vertices of the j-th ring including vertex i.

    source

    To avoid useless computations, the lists of rings and the rings themselves are returned as iterables instead of Vector{PeriodicVertex{N}} and such, so they should be collected if required.

    Let's look all the rings on our little house:

    julia> ras = RingAttributions(house)
     RingAttributions{0}(rings per node: [6, 6, 6, 6, 8, 8, 8, 8, 4])
     
     julia> roofpeak = ras[9] # the list of rings including the top of the roof
    @@ -63,15 +63,15 @@
      [5, 8, 9]
      [5, 6, 9]
      [1, 2, 6, 5]
    - [1, 4, 8, 5]

    Internal API

    Here is a collection of internal utilities used for the algorithms of rings and strong_rings:

    PeriodicGraphs.JunctionNodeType
    JunctionNode{T}

    Element of the DAG representing the set of arcs linking each vertex x to a fixed vertex i of graph g. Each JunctionNode contains information on the arcs passing through a particular vertex x:

    • num is the length of the shortest path between x and i. Since we only collect rings, only the shortest paths are of interest, as well as the path of length num+1 which may form an odd-length ring when combined with a shortest path.
    • heads is a list of neighbors of x such that the lastshort first are at distance num - 1 from i, and the rest are at distance num and have a lower value than x.
    • shortroots is the set of roots reachable on a shortest path from x to i. A root is the neighbor of i on that path, a.k.a. the second-to-last vertex on that path.
    • longroots is the set of roots reachable on a path of length num+1 from x to i.
    source
    PeriodicGraphs.PhantomJunctionNodeType
    PhantomJunctionNode{D}

    Element of the phantom DAG.

    Similarly to the DAG of JunctionNode, the phantom DAG tracks arcs linking vertices x to a fixed vertex i, except that the vertices x are those that should be ignored in the returned list of rings. Thus, only the shortest distance between x and i needs to be recorded, since the arcs themselves will be discarded eventually.

    source
    PeriodicGraphs.arcs_listFunction
    arcs_list(g::PeriodicGraph{D}, i, depth::T, ringavoid=nothing, cycleavoid=nothing) where {D,T}

    Compute the list of shortest arcs starting from vertex i up to length depth+1. Vertices in ringavoid are not included in the returned arcs, but considered still part of the graph for distance computations. Vertices in cycleavoid are considered removed from the graph completely.

    Return (dag, vertexnums) where dag is a Vector{JunctionNode{T}} representing, for each visited node, the DAG of all arcs from that node back to i, in a compact representation. vertexnums is a Vector{PeriodicVertex{D}} whose k-th value is the vertex represented by number k in dag.

    If ringavoid !== nothing, dag will also not include arcs that pass through nodes of the form PeriodicVertex{D}(j, ofs) with j == i and ofs < zero(SVector{Int,D}): this allows eagerly pruning cycles that are translations of others. Note that this can result in missing cycles if those pass through at least three nodes with j == i, but that situation should be exceptionally rare.

    Note

    The type T of depth is used as type parameter to the JunctionNode, just to avoid having a dedicated argument (since depth should be at most 62 for the rest of the algorithm to work). This size controls the maximal degree a vertex of g should have : for example, T == UInt32 indicates that all vertices must have degree at most 31.

    source
    PeriodicGraphs.RingsEndingAtType
    RingsEndingAt(dag, midnode, record)

    Iterable over the rings of graph g around node i with midnode as vertex furthest from i. If there are two such vertices (odd ring), midnode is the higher of the two.

    record should be set to (dist, vertexnums) where dist == DistanceRecord(g, depth) and dag, vertexnums == first(arcs_list(g, i, depth, ...)), otherwise the iterator will return many more cycles that may not be rings.

    Warning

    In order to efficiently cycle through the rings, the iterator reuses a buffer on which the rings are written. This means that performing an iteration will change the value of the previously returned result: for example, collect(RingsEndingAt(...)) will yield a list containing the same sublist (unlikely to be an actual ring) repeated over. To actually obtain the list of rings, copy the result as they arrive by doing map(copy, RingsEndingAt(...)) or [copy(x) for x in RingsEndingAt(...)] for example.

    This also means that the list returned at each iteration should never be modified directly: copy it before.

    source
    PeriodicGraphs.normalize_cycle!Function
    normalize_cycle!(cycle::Vector{Int}, n, v::Val{D}) where D

    In-place rotate and possibly reverse cycle, a Vector{Int} whose elements are the hash_position of vertices of g so that the result is the same for all such vectors that represent the same cycle, possibly translated to a different unit cell or rotated.

    The graph g::PeriodicGraph{D} is represented as n = nv(g) and v = Val(D)

    source
    PeriodicGraphs.symdiff_cyclesFunction
    symdiff_cycles(a, b)

    Symmetric difference between two sorted lists a and b. Return the sorted list of elements belonging to a or to b but not to both.

    Use PeriodicGraphs.symdiff_cycles! to provide a pre-allocated destination.

    Example

    julia> PeriodicGraphs.symdiff_cycles([3,4,5], [4,5,6])
    + [1, 4, 8, 5]

    Internal API

    Here is a collection of internal utilities used for the algorithms of rings and strong_rings:

    PeriodicGraphs.JunctionNodeType
    JunctionNode{T}

    Element of the DAG representing the set of arcs linking each vertex x to a fixed vertex i of graph g. Each JunctionNode contains information on the arcs passing through a particular vertex x:

    • num is the length of the shortest path between x and i. Since we only collect rings, only the shortest paths are of interest, as well as the path of length num+1 which may form an odd-length ring when combined with a shortest path.
    • heads is a list of neighbors of x such that the lastshort first are at distance num - 1 from i, and the rest are at distance num and have a lower value than x.
    • shortroots is the set of roots reachable on a shortest path from x to i. A root is the neighbor of i on that path, a.k.a. the second-to-last vertex on that path.
    • longroots is the set of roots reachable on a path of length num+1 from x to i.
    source
    PeriodicGraphs.PhantomJunctionNodeType
    PhantomJunctionNode{D}

    Element of the phantom DAG.

    Similarly to the DAG of JunctionNode, the phantom DAG tracks arcs linking vertices x to a fixed vertex i, except that the vertices x are those that should be ignored in the returned list of rings. Thus, only the shortest distance between x and i needs to be recorded, since the arcs themselves will be discarded eventually.

    source
    PeriodicGraphs.arcs_listFunction
    arcs_list(g::PeriodicGraph{D}, i, depth::T, ringavoid=nothing, cycleavoid=nothing) where {D,T}

    Compute the list of shortest arcs starting from vertex i up to length depth+1. Vertices in ringavoid are not included in the returned arcs, but considered still part of the graph for distance computations. Vertices in cycleavoid are considered removed from the graph completely.

    Return (dag, vertexnums) where dag is a Vector{JunctionNode{T}} representing, for each visited node, the DAG of all arcs from that node back to i, in a compact representation. vertexnums is a Vector{PeriodicVertex{D}} whose k-th value is the vertex represented by number k in dag.

    If ringavoid !== nothing, dag will also not include arcs that pass through nodes of the form PeriodicVertex{D}(j, ofs) with j == i and ofs < zero(SVector{Int,D}): this allows eagerly pruning cycles that are translations of others. Note that this can result in missing cycles if those pass through at least three nodes with j == i, but that situation should be exceptionally rare.

    Note

    The type T of depth is used as type parameter to the JunctionNode, just to avoid having a dedicated argument (since depth should be at most 62 for the rest of the algorithm to work). This size controls the maximal degree a vertex of g should have : for example, T == UInt32 indicates that all vertices must have degree at most 31.

    source
    PeriodicGraphs.RingsEndingAtType
    RingsEndingAt(dag, midnode, record)

    Iterable over the rings of graph g around node i with midnode as vertex furthest from i. If there are two such vertices (odd ring), midnode is the higher of the two.

    record should be set to (dist, vertexnums) where dist == DistanceRecord(g, depth) and dag, vertexnums == first(arcs_list(g, i, depth, ...)), otherwise the iterator will return many more cycles that may not be rings.

    Warning

    In order to efficiently cycle through the rings, the iterator reuses a buffer on which the rings are written. This means that performing an iteration will change the value of the previously returned result: for example, collect(RingsEndingAt(...)) will yield a list containing the same sublist (unlikely to be an actual ring) repeated over. To actually obtain the list of rings, copy the result as they arrive by doing map(copy, RingsEndingAt(...)) or [copy(x) for x in RingsEndingAt(...)] for example.

    This also means that the list returned at each iteration should never be modified directly: copy it before.

    source
    PeriodicGraphs.normalize_cycle!Function
    normalize_cycle!(cycle::Vector{Int}, n, v::Val{D}) where D

    In-place rotate and possibly reverse cycle, a Vector{Int} whose elements are the hash_position of vertices of g so that the result is the same for all such vectors that represent the same cycle, possibly translated to a different unit cell or rotated.

    The graph g::PeriodicGraph{D} is represented as n = nv(g) and v = Val(D)

    source
    PeriodicGraphs.symdiff_cyclesFunction
    symdiff_cycles(a, b)

    Symmetric difference between two sorted lists a and b. Return the sorted list of elements belonging to a or to b but not to both.

    Use PeriodicGraphs.symdiff_cycles! to provide a pre-allocated destination.

    Example

    julia> PeriodicGraphs.symdiff_cycles([3,4,5], [4,5,6])
     2-element Vector{Int64}:
      3
    - 6
    source
    PeriodicGraphs.IterativeGaussianEliminationType
    IterativeGaussianElimination{T}

    Struct containing the list of sparse columns of the matrix under gaussian elimination on the 𝔽₂ finite field.

    To be used with PeriodicGraphs.gaussian_elimination! as one of the three concrete types:

    • PeriodicGraphs.IterativeGaussianEliminationNone for simple gaussian elimination,
    • PeriodicGraphs.IterativeGaussianEliminationLength to detect when a new column can be expressed as a sum of strictly smaller columns of the matrix.
    • PeriodicGraphs.IterativeGaussianEliminationDecomposition to detect when a new column can be expressed as a sum of other columns of the matrix and keep track of which.
    source
    PeriodicGraphs.gaussian_elimination!Function
    gaussian_elimination!(gauss::IterativeGaussianElimination, r::Vector{Int})

    Test whether r can be expressed as a sum of vectors stored in gauss, and store r if not. "sum" refers to the symmetric difference of boolean vectors, represented in sparse format as the ordered list of non-zero indices.

    If gauss isa IterativeGaussianEliminationLength, return whether r can be expressed as a sum of strictly smaller vectors.

    Otherwise, return true when r is a sum of any previously encoutered vectors. If gauss isa IterativeGaussianEliminationDecomposition, query retrieve_track(gauss) to obtain the sorted list of indices of such previously encountered vectors.

    See also gaussian_elimination to test r without storing it.

    source
    PeriodicGraphs.gaussian_eliminationFunction
    gaussian_elimination(gauss::IterativeGaussianElimination, r::Vector{Int})

    Return notindependent, info where notindependent is true if r can be expressed as a sum of vectors stored in gauss.

    See PeriodicGraphs.gaussian_elimination! to store r in gauss if not, and for more details dependending on the type of gauss.

    Call PeriodicGraphs.gaussian_elimination!(gauss, r, notindependent, info) to obtain the result of PeriodicGraphs.gaussian_elimination!(gauss, r) without duplicating computation.

    source
    PeriodicGraphs.IterativeGaussianEliminationType
    IterativeGaussianElimination{T}

    Struct containing the list of sparse columns of the matrix under gaussian elimination on the 𝔽₂ finite field.

    To be used with PeriodicGraphs.gaussian_elimination! as one of the three concrete types:

    • PeriodicGraphs.IterativeGaussianEliminationNone for simple gaussian elimination,
    • PeriodicGraphs.IterativeGaussianEliminationLength to detect when a new column can be expressed as a sum of strictly smaller columns of the matrix.
    • PeriodicGraphs.IterativeGaussianEliminationDecomposition to detect when a new column can be expressed as a sum of other columns of the matrix and keep track of which.
    source
    PeriodicGraphs.gaussian_elimination!Function
    gaussian_elimination!(gauss::IterativeGaussianElimination, r::Vector{Int})

    Test whether r can be expressed as a sum of vectors stored in gauss, and store r if not. "sum" refers to the symmetric difference of boolean vectors, represented in sparse format as the ordered list of non-zero indices.

    If gauss isa IterativeGaussianEliminationLength, return whether r can be expressed as a sum of strictly smaller vectors.

    Otherwise, return true when r is a sum of any previously encoutered vectors. If gauss isa IterativeGaussianEliminationDecomposition, query retrieve_track(gauss) to obtain the sorted list of indices of such previously encountered vectors.

    See also gaussian_elimination to test r without storing it.

    source
    PeriodicGraphs.gaussian_eliminationFunction
    gaussian_elimination(gauss::IterativeGaussianElimination, r::Vector{Int})

    Return notindependent, info where notindependent is true if r can be expressed as a sum of vectors stored in gauss.

    See PeriodicGraphs.gaussian_elimination! to store r in gauss if not, and for more details dependending on the type of gauss.

    Call PeriodicGraphs.gaussian_elimination!(gauss, r, notindependent, info) to obtain the result of PeriodicGraphs.gaussian_elimination!(gauss, r) without duplicating computation.

    source
    PeriodicGraphs.intersect_cyclesFunction
    intersect_cycles(a, b)

    Intersection between two sorted lists a and b. Return the sorted list of elements belonging to both a and b.

    Use PeriodicGraphs.intersect_cycles! to provide a pre-allocated destination.

    Example

    julia> PeriodicGraphs.intersect_cycles([3,4,5], [4,5,6])
     2-element Vector{Int64}:
      4
    - 5
    source
    PeriodicGraphs.union_cyclesFunction
    union_cycles(a, b)

    Union between two sorted lists a and b. Return the sorted list of elements belonging to a or b or both.

    Use PeriodicGraphs.union_cycles! to provide a pre-allocated destination.

    Example

    julia> PeriodicGraphs.union_cycles([3,4,5], [4,5,6])
     4-element Vector{Int64}:
      3
      4
      5
    - 6
    source
    PeriodicGraphs.retrieve_track!Function
    retrieve_track!([ret::Vector{Int32}, buffer::Vector{Int32},] gauss::IterativeGaussianEliminationDecomposition)

    To be called consecutive to a call to gaussian_elimination!(gauss, x) that returned true. In that case, x was found to be the sum of previously encountered vectors: return the (reverse-sorted) list of their indices.

    Warning

    Calling retrieve_track! after a call to gaussian_elimination! that returned false will produce an invalid result. Calling it twice will also produce an invalid result.

    source
    PeriodicGraphs.rings_aroundFunction
    rings_around(g::PeriodicGraph{D}, i, depth=15, dist::DistanceRecord=DistanceRecord(g,depth), visited=nothing) where D

    Return the list of all rings around node i in graph g up to length 2*depth+3.

    The returned rings are the list of hash_position of the corresponding vertices. To get back the list of actual PeriodicVertex of a returned ring in the list, do

    [reverse_hash_position(x, g) for x in ring]

    If the offsets of the corresponding vertices are not needed, simply do

    [mod1(x, n) for x in ring]   # n should be nv(g)

    visited is interpreted as the ringavoid argument of arcs_list unless dist === nothing, in which case it is interpreted as the cycleavoid argument. In particular, unless dist === nothing, only one ring will appear in the list even if some of its translated images also pass through PeriodicVertex{D}(i).

    source
    PeriodicGraphs.EdgeDictType
    EdgeDict{D}

    Map from pairs of PeriodicVertex{D} to the identifier of the corresponding edge.

    kp::EdgeDict{D} should be queried by either get!(kp, minmax(v1, v2)) where v1 and v2 are PeriodicVertex{D} to obtain the identifier of the edge and store a new identifier if absent, or by kp[i] where i is an Integer to obtain the pair of vertices corresponding to identifier i.

    kp is built by calling EdgeDict(g) where g is a PeriodicGraph.

    source
    PeriodicGraphs.strong_eringsFunction
    strong_erings([rs::Vector{Vector{Int}},], g::PeriodicGraph{D}, [depth=15,] ringsymms::AbstractSymmetryGroup=NoSymmetryGroup(length(rs))) where D

    Compute the list of strong edge rings in g, up to length 2*depth+3. See strong_rings and rings for the meaning of the optional arguments.

    Return a quadruplet of values:

    • the two first values are the list of rings and their symmetry group, identical to the result of strong_rings, unless rs is provided (see below).
    • the third is the list of edge rings: each edge of the periodic graph is mapped to an integer and each ring is represented by the sorted list of its edges.
    • the last is the mapping from edges to integers, given as an EdgeDict.

    If rs is provided, the first returned value is the list of indices keep of rs such that rs[keep] is the list of strong rings.

    source
    + 6
    source
    PeriodicGraphs.retrieve_track!Function
    retrieve_track!([ret::Vector{Int32}, buffer::Vector{Int32},] gauss::IterativeGaussianEliminationDecomposition)

    To be called consecutive to a call to gaussian_elimination!(gauss, x) that returned true. In that case, x was found to be the sum of previously encountered vectors: return the (reverse-sorted) list of their indices.

    Warning

    Calling retrieve_track! after a call to gaussian_elimination! that returned false will produce an invalid result. Calling it twice will also produce an invalid result.

    source
    PeriodicGraphs.rings_aroundFunction
    rings_around(g::PeriodicGraph{D}, i, depth=15, dist::DistanceRecord=DistanceRecord(g,depth), visited=nothing) where D

    Return the list of all rings around node i in graph g up to length 2*depth+3.

    The returned rings are the list of hash_position of the corresponding vertices. To get back the list of actual PeriodicVertex of a returned ring in the list, do

    [reverse_hash_position(x, g) for x in ring]

    If the offsets of the corresponding vertices are not needed, simply do

    [mod1(x, n) for x in ring]   # n should be nv(g)

    visited is interpreted as the ringavoid argument of arcs_list unless dist === nothing, in which case it is interpreted as the cycleavoid argument. In particular, unless dist === nothing, only one ring will appear in the list even if some of its translated images also pass through PeriodicVertex{D}(i).

    source
    PeriodicGraphs.EdgeDictType
    EdgeDict{D}

    Map from pairs of PeriodicVertex{D} to the identifier of the corresponding edge.

    kp::EdgeDict{D} should be queried by either get!(kp, minmax(v1, v2)) where v1 and v2 are PeriodicVertex{D} to obtain the identifier of the edge and store a new identifier if absent, or by kp[i] where i is an Integer to obtain the pair of vertices corresponding to identifier i.

    kp is built by calling EdgeDict(g) where g is a PeriodicGraph.

    source
    PeriodicGraphs.strong_eringsFunction
    strong_erings([rs::Vector{Vector{Int}},], g::PeriodicGraph{D}, [depth=15,] ringsymms::AbstractSymmetryGroup=NoSymmetryGroup(length(rs))) where D

    Compute the list of strong edge rings in g, up to length 2*depth+3. See strong_rings and rings for the meaning of the optional arguments.

    Return a quadruplet of values:

    • the two first values are the list of rings and their symmetry group, identical to the result of strong_rings, unless rs is provided (see below).
    • the third is the list of edge rings: each edge of the periodic graph is mapped to an integer and each ring is represented by the sorted list of its edges.
    • the last is the mapping from edges to integers, given as an EdgeDict.

    If rs is provided, the first returned value is the list of indices keep of rs such that rs[keep] is the list of strong rings.

    source
    PeriodicGraphs.convert_to_ering!Function
    convert_to_ering!(buffer::Vector{Int}, ring::Vector{PeriodicVertex{D}}, kp::EdgeDict{D}, ofs, len) where D

    Return the edge ring corresponding to OffsetVertexIterator{D}(ring[1:len], ofs) inside buffer, resized to length len.

    See also PeriodicGraphs.convert_to_ering.

    source
    PeriodicGraphs.convert_to_eringFunction
    convert_to_ering(ring::Vector{PeriodicVertex{D}}, kp::EdgeDict{D}, ofs=zero(SVector{D,Int}), len=length(ring)) where D

    Return the edge ring corresponding to OffsetVertexIterator{D}(ring[1:len], ofs).

    See also PeriodicGraphs.convert_to_ering! to provide a buffer.

    source
    diff --git a/dev/search/index.html b/dev/search/index.html index 2e4e5c5..80dc733 100644 --- a/dev/search/index.html +++ b/dev/search/index.html @@ -1,2 +1,2 @@ -Search · PeriodicGraphs.jl

    Loading search...

      +Search · PeriodicGraphs.jl

      Loading search...

        diff --git a/dev/search_index.js b/dev/search_index.js index 0780eaa..517ff25 100644 --- a/dev/search_index.js +++ b/dev/search_index.js @@ -1,3 +1,3 @@ var documenterSearchIndex = {"docs": -[{"location":"types/#Basic-types-and-definitions","page":"Types","title":"Basic types and definitions","text":"","category":"section"},{"location":"types/","page":"Types","title":"Types","text":"DocTestSetup = quote\n using PeriodicGraphs, Graphs\nend\nDocTestFilters = r\"Int..\"","category":"page"},{"location":"types/#Introduction","page":"Types","title":"Introduction","text":"","category":"section"},{"location":"types/","page":"Types","title":"Types","text":"A PeriodicGraph{N} g is the representation of an N-periodic graph.","category":"page"},{"location":"types/","page":"Types","title":"Types","text":"Each vertex has a unique representative, indexed from 1 to n = nv(g). Each vertex x of the graph is represented by a PeriodicVertex{N} containing both the representative v and the offset o between the unit cell containing the vertex and a reference unit cell, accessible through the syntax v, o = x, or with v = first(x) and o = last(x). The offset is a N-uplet of integers, stored as a SVector{N,Int}.","category":"page"},{"location":"types/","page":"Types","title":"Types","text":"Each edge e is represented by a PeriodicEdge{N} defined by its source vertex inside the reference unit cell and of representative s, and its destination vertex d, a PeriodicVertex{N}, which can be accessed through the syntax s, d = e, or with s = first(e) and d = last(e) (or d = Graphs.dst(e)).","category":"page"},{"location":"types/","page":"Types","title":"Types","text":"For convenience, aliases are exported for 1D, 2D and 3D (N = 1, N = 2 and N = 3) under the names PeriodicGraph1D, PeriodicEdge2D, PeriodicVertex3D, etc.","category":"page"},{"location":"types/#PeriodicVertex","page":"Types","title":"PeriodicVertex","text":"","category":"section"},{"location":"types/","page":"Types","title":"Types","text":"A PeriodicVertex can be built like so:","category":"page"},{"location":"types/","page":"Types","title":"Types","text":"julia> PeriodicVertex1D(5, (-1,))\nPeriodicVertex1D(5, (-1,))\n\njulia> PeriodicVertex{4}(2) # shorthand for the vertices of the reference cell\nPeriodicVertex{4}(2, (0,0,0,0))","category":"page"},{"location":"types/#PeriodicEdge","page":"Types","title":"PeriodicEdge","text":"","category":"section"},{"location":"types/","page":"Types","title":"Types","text":"A PeriodicEdge, can be defined from src and dst or, equivalently, be the identifiers of both source and destination vertices, and the cell offset between source and destination. For example, in 3D, the edge between vertex 1 and vertex 4 in cell (0, 1, 0) is PeriodicEdge3D(1, PeriodicVertex3D(4, (0,1,0))), or, equivalently, PeriodicEdge3D(1, 4, (0,1,0)). Since PeriodicEdge(u, v, ofs) and PeriodicEdge(v, u, .-ofs) represent the same edge, one of them is called the direct edge, when it has either u < v or u == v && ofs > zero(ofs), and the other is the indirect edge. Functions isdirectedge and directedge are used for this.","category":"page"},{"location":"types/","page":"Types","title":"Types","text":"More examples:","category":"page"},{"location":"types/","page":"Types","title":"Types","text":"julia> e = PeriodicEdge(3, PeriodicVertex(2, (0,1,0,0))) # dimensions are inferred from the input\nPeriodicEdge{4}(3, 2, (0,1,0,0))\n\njulia> isdirectedge(e)\nfalse\n\njulia> directedge(e)\nPeriodicEdge{4}(2, 3, (0,-1,0,0))\n\njulia> src, (dstv, ofs) = PeriodicEdge3D(5, 6, (1,0,2));\n\njulia> src\n5\n\njulia> dstv\n6\n\njulia> ofs\n3-element StaticArrays.SVector{3, Int64} with indices SOneTo(3):\n 1\n 0\n 2\n\njulia> PeriodicEdge2D(5, 5, (0,0))\nERROR: LoopException: a loop from vertex 5 to itself in the same unit cell is a forbidden edges. Maybe the offset is wrong?","category":"page"},{"location":"types/","page":"Types","title":"Types","text":"Note that loops (that is, edges of the form (u, u, (0,0,0,...,0))) are forbidden and will throw a PeriodicGraphs.LoopException if created. To bypass this check, use the unexported PeriodicGraphs.unsafe_edge function.","category":"page"},{"location":"types/#PeriodicGraph","page":"Types","title":"PeriodicGraph","text":"","category":"section"},{"location":"types/","page":"Types","title":"Types","text":"Finally, N-periodic graphs, represented by the type PeriodicGraph{N}, are defined by the number of vertices in the reference cell and the set of edges starting from the reference cell. When the number of vertices is simply the highest number appearing in the list of edges, it can be omitted. Periodic graphs can be built through several methods:","category":"page"},{"location":"types/","page":"Types","title":"Types","text":"julia> PeriodicGraph{5}() # create the empty graph\nPeriodicGraph{5}(0, PeriodicEdge{5}[])\n\njulia> PeriodicGraph1D(4) # create a graph with 4 vertices but no edge\nPeriodicGraph1D(4, PeriodicEdge1D[])\n\njulia> PeriodicGraph(2, PeriodicEdge{4}[(1, 1, (0,0,1,1)), (1, 1, (0,1,0,-1))]) # the dimension can be inferred\nPeriodicGraph{4}(2, PeriodicEdge{4}[(1, 1, (0,0,1,1)), (1, 1, (0,1,0,-1))])\n\njulia> PeriodicGraph3D(PeriodicEdge3D[(1, 3, (0,1,0)), (2, 2, (0,0,-1)), (1, 2, (1,0,0)), (2, 3, (0,1,1))])\nPeriodicGraph3D(3, PeriodicEdge3D[(1, 2, (1,0,0)), (1, 3, (0,1,0)), (2, 2, (0,0,1)), (2, 3, (0,1,1))])\n\njulia> parse(PeriodicGraph3D, \"3 1 2 1 0 0 1 3 0 1 0 2 2 0 0 1 2 3 0 1 1\") # compact representation of the previous graph\nPeriodicGraph3D(3, PeriodicEdge3D[(1, 2, (1,0,0)), (1, 3, (0,1,0)), (2, 2, (0,0,1)), (2, 3, (0,1,1))])\n\njulia> string(ans) # to obtain the compact representation from the graph\n\"3 1 2 1 0 0 1 3 0 1 0 2 2 0 0 1 2 3 0 1 1\"\n\njulia> string(PeriodicGraph(\"2 1 2 0 0 2 3 0 0 3 1 0 0 3 1 1 0 2 1 0 1 2 3 0 1\"))\n\"2 1 2 0 -1 1 2 0 0 1 3 -1 0 1 3 0 0 2 3 0 0 2 3 0 1\"","category":"page"},{"location":"types/#API","page":"Types","title":"API","text":"","category":"section"},{"location":"types/#Type-definitions","page":"Types","title":"Type definitions","text":"","category":"section"},{"location":"types/","page":"Types","title":"Types","text":"PeriodicVertex\nPeriodicEdge\nPeriodicGraph\nPeriodicGraph{N}(nv::Integer=0) where N\nPeriodicGraph(nv::Integer, edge_list::AbstractVector{PeriodicEdge{N}}) where N\nPeriodicGraph{N}(s::AbstractString) where N\nBase.parse(::Type{PeriodicGraph{N}}, s::AbstractString) where N","category":"page"},{"location":"types/#PeriodicGraphs.PeriodicVertex","page":"Types","title":"PeriodicGraphs.PeriodicVertex","text":"PeriodicVertex{N}\n\nVertex type for an N-periodic graph.\n\nA vertex is uniquely determined by the identifier of its representative in the a fixed initial cell, and the offset of the cell containing the vertex compared to the the initial cell. Vertex identifiers start at 1.\n\n\n\n\n\n","category":"type"},{"location":"types/#PeriodicGraphs.PeriodicEdge","page":"Types","title":"PeriodicGraphs.PeriodicEdge","text":"PeriodicEdge{N} <: Graphs.SimpleGraphs.AbstractSimpleEdge{Int}\n\nEdge type for an N-periodic graph.\n\nAn edge is uniquely determined by the vertex identifiers of its source and destination, and the cell offset between the source vertex and the destination vertex.\n\n\n\n\n\n","category":"type"},{"location":"types/#PeriodicGraphs.PeriodicGraph","page":"Types","title":"PeriodicGraphs.PeriodicGraph","text":"PeriodicGraph{N} <: AbstractGraph{Int}\n\nType representing an undirected N-periodic graph.\n\n\n\n\n\n","category":"type"},{"location":"types/#PeriodicGraphs.PeriodicGraph-Union{Tuple{}, Tuple{Integer}, Tuple{N}} where N","page":"Types","title":"PeriodicGraphs.PeriodicGraph","text":"PeriodicGraph{N}(nv::Integer=0)\n\nConstruct a PeriodicGraph{N} with nv vertices and 0 edge.\n\n\n\n\n\n","category":"method"},{"location":"types/#PeriodicGraphs.PeriodicGraph-Union{Tuple{N}, Tuple{Integer, AbstractArray{PeriodicEdge{N}, 1}}} where N","page":"Types","title":"PeriodicGraphs.PeriodicGraph","text":"PeriodicGraph([nv::Integer, ]edge_list::AbstractVector{PeriodicEdge{N}})\nPeriodicGraph{N}([nv::Integer, ]edge_list::AbstractVector{PeriodicEdge{N}})\n\nConstruct a PeriodicGraph{N} from a vector of edges. If nv is unspecified, the number of vertices is the highest that is used in an edge in edge_list.\n\nImplementation Notes\n\nThis constructor works the fastest when edge_list is sorted by the lexical ordering and does not contain any duplicates.\n\nExamples\n\njulia> el = PeriodicEdge2D[(1, 1, (1,0)), (1, 3, (0,1)), (3, 1, (0,-1))];\n\njulia> g = PeriodicGraph(el)\nPeriodicGraph2D(3, PeriodicEdge2D[(1, 1, (1,0)), (1, 3, (0,1))])\n\njulia> ne(g)\n2\n\n\n\n\n\n","category":"method"},{"location":"types/#PeriodicGraphs.PeriodicGraph-Union{Tuple{AbstractString}, Tuple{N}} where N","page":"Types","title":"PeriodicGraphs.PeriodicGraph","text":"PeriodicGraph(key::AbstractString)\nPeriodicGraph{N}(key::AbstractString)\n\nConstruct a PeriodicGraph{N} from a key, which is a string of whitespace-separated values of the form \"N src1 dst1 ofs1_1 ofs1_2 ... ofs1_N src2 dst2 ofs2_1 ofs2_2 ... ofs2_N ... srcm dstm ofsm_1 ofsm_2 ... ofsm_N\" where N is the number of repeating dimensions of the graph, m is the number of edges and for all i between 1 and m, the number of edges, the i-th edge is described as\n\nsrci, the vertex identifier of the source vertex,\ndsti, the vertex identifier of the destination vertex and\n(ofsi_1, ofsi_2, ..., ofsi_N) the offset of the edge.\n\nThis compact representation of a graph can be obtained simply by printing the graph or with string.\n\nnote: Note\nUse parse(PeriodicGraph, key) or parse(PeriodicGraph{N}, key) for a faster implementation if key was obtained from string(g) with g a PeriodicGraph{N}.\n\nExamples\n\njulia> PeriodicGraph(\"2 1 2 0 0 2 1 1 0 1 1 0 -1\")\nPeriodicGraph2D(2, PeriodicEdge2D[(1, 1, (0,1)), (1, 2, (-1,0)), (1, 2, (0,0))])\n\njulia> PeriodicGraph3D(\"3 1 1 0 0 1 1 1 0 1 0 1 1 1 0 0\")\nPeriodicGraph3D(1, PeriodicEdge3D[(1, 1, (0,0,1)), (1, 1, (0,1,0)), (1, 1, (1,0,0))])\n\njulia> string(ans)\n\"3 1 1 0 0 1 1 1 0 1 0 1 1 1 0 0\"\n\njulia> string(parse(PeriodicGraph3D, ans)) == ans\ntrue\n\n\n\n\n\n","category":"method"},{"location":"types/#Base.parse-Union{Tuple{N}, Tuple{Type{PeriodicGraph{N}}, AbstractString}} where N","page":"Types","title":"Base.parse","text":"parse(::Type{PeriodicGraph}, key::AbstractString)\nparse(::Type{PeriodicGraph{N}}, key::AbstractString)\n\nParse a string representation of a PeriodicGraph back to a PeriodicGraph.\n\nSee PeriodicGraph(key::AbstractString) or PeriodicGraph{N}(key::AbstractString) for details on the string representations of a PeriodicGraph.\n\nwarning: Warning\nThis function assumes that the string is a valid representation of a PeriodicGraph with all its edges direct, sorted in lexicographical order and unique, as obtained from string(g) or print(g) where g is a PeriodicGraph. No check is performed to ensure this condition.If the input string may not obey these conditions, use PeriodicGraph(key) or PeriodicGraph{N}(key) instead.\n\n\n\n\n\n","category":"method"},{"location":"types/#Other-basic-functions","page":"Types","title":"Other basic functions","text":"","category":"section"},{"location":"types/","page":"Types","title":"Types","text":"isdirectedge\ndirectedge\nPeriodicGraphs.unsafe_edge\nPeriodicGraphs.LoopException","category":"page"},{"location":"types/#PeriodicGraphs.isdirectedge","page":"Types","title":"PeriodicGraphs.isdirectedge","text":"isdirectedge(e::PeriodicEdge)\n\nReturn true if e is direct, in the sense being of the form (u, v, ofs) with either u < v or u == v && ofs > zero(ofs).\n\nAn edge e is indirect iff reverse(e) is not.\n\nExamples\n\njulia> isdirectedge(PeriodicEdge1D(3, 4, (0,)))\ntrue\n\njulia> isdirectedge(PeriodicEdge2D(5, 2, (0,0)))\nfalse\n\njulia> isdirectedge(PeriodicEdge3D(3, 3, (0,-1,2)))\nfalse\n\nSee also directedge\n\n\n\n\n\n","category":"function"},{"location":"types/#PeriodicGraphs.directedge","page":"Types","title":"PeriodicGraphs.directedge","text":"directedge(e::PeriodicEdge{D}) where D\ndirectedge(src::PeriodicVertex{D}, dst::PeriodicVertex{D}) where D\ndirectedge(src, dst, ofs::Union{SVector{D,T},NTuple{D,T}}) where {D,T}\n\nReturn the direct edge corresponding to e = PeriodicEdge{D}(src, dst), i.e. e itself if e is direct, or reverse(e) otherwise.\n\nExamples\n\njulia> directedge(PeriodicEdge1D(3, 4, (0,)))\nPeriodicEdge1D(3, 4, (0,))\n\njulia> directedge(PeriodicEdge2D(5, 2, (0,0)))\nPeriodicEdge2D(2, 5, (0,0))\n\njulia> directedge(PeriodicEdge3D(3, 3, (0,-1,2)))\nPeriodicEdge3D(3, 3, (0,1,-2))\n\nSee also isdirectedge\n\n\n\n\n\n","category":"function"},{"location":"types/#PeriodicGraphs.unsafe_edge","page":"Types","title":"PeriodicGraphs.unsafe_edge","text":"unsafe_edge{N}\n\nInternal constructor for PeriodicEdge{N} that bypasses the loop check.\n\n\n\n\n\n","category":"type"},{"location":"types/#PeriodicGraphs.LoopException","page":"Types","title":"PeriodicGraphs.LoopException","text":"LoopException <: Exception\n\nError type for constructing an invalid PeriodicEdge{N} of the form (u, u, zeros(Int,N)). Loops are not expected in the algorithms implemented in PeriodicGraphs.jl. If you still want to construct them, use the unsafe_edge{N} constructor instead of PeriodicEdge{N}.\n\n\n\n\n\n","category":"type"},{"location":"neighborhood/#Neighborhoods-and-graph-traversals","page":"Neighborhood","title":"Neighborhoods and graph traversals","text":"","category":"section"},{"location":"neighborhood/#Manual","page":"Neighborhood","title":"Manual","text":"","category":"section"},{"location":"neighborhood/","page":"Neighborhood","title":"Neighborhood","text":"The AbstractGraph API for exploring neighbors and traversing graphs has to be somewhat adapted to account for the specific aspects of PeriodicGraphs. Here, we present a list of notes relative to these aspects, where g is a PeriodicGraph{N}:","category":"page"},{"location":"neighborhood/","page":"Neighborhood","title":"Neighborhood","text":"neighbors(g, i) where i::Integer is the list of neighbors of PeriodicVertex{N}(i). Performance-wise, this operation is a simple access on the underlying structure of g so it is very fast, but the returned Vector{PeriodicVertex{N}} should not be modified.\nneighbors(g, x) where x::PeriodicVertex{N} is an iterator over the neighbors of x but not an array. The iterator object is a PeriodicGraphs.OffsetVertexIterator.\nedges(g) is an iterator over the direct edges of g. Every edge representative will thus be visited exactly once. It is invalidated by any change to g, so g should not be modified while iterating over edges(g). The iterator object is a PeriodicGraphs.PeriodicEdgeIter.\nGraphs._neighborhood has a specialization for PeriodicGraph if required.","category":"page"},{"location":"neighborhood/","page":"Neighborhood","title":"Neighborhood","text":"A typical BFS algorithm on g can be implemented like so:","category":"page"},{"location":"neighborhood/","page":"Neighborhood","title":"Neighborhood","text":"function bfs(g::PeriodicGraph{N}, starting_vertex, depth) where N\n visited = Set{PeriodicVertex{N}}(starting_vertex)\n Q = Tuple{Int,PeriodicVertex{N}}[(0, starting_vertex)]\n for (distance, u) in Q\n distance > depth && break\n # do stuff with u\n for x in neighbors(g, u)\n x ∈ visited && continue\n push!(x, visited)\n # do stuff with x\n push!(Q, (distance+1, x))\n end\n # do more stuff\n end\n # return something\nend","category":"page"},{"location":"neighborhood/","page":"Neighborhood","title":"Neighborhood","text":"In some cases however, the Set-interface can end up being the bottleneck. In this kind of situation, it may be better to:","category":"page"},{"location":"neighborhood/","page":"Neighborhood","title":"Neighborhood","text":"replace the initialization of visited by\nwidth = PeriodicGraphs.graph_width!(g)\nseen_size = nv(g)*(2*(1 + fld(depth-1, width)) + 1)^N\nvisited = falses(seen_size)\nreplace x ∈ visited by visited[hash_position(x, g)] and\nreplace push!(x, visited) by visited[hash_position(x, g)] = true","category":"page"},{"location":"neighborhood/","page":"Neighborhood","title":"Neighborhood","text":"although some care should be taken since PeriodicGraphs.graph_width! is only a heuristic.","category":"page"},{"location":"neighborhood/","page":"Neighborhood","title":"Neighborhood","text":"Such algorithms can be used to compute the topological invariants like coordination_sequence for example.","category":"page"},{"location":"neighborhood/#API","page":"Neighborhood","title":"API","text":"","category":"section"},{"location":"neighborhood/","page":"Neighborhood","title":"Neighborhood","text":"PeriodicGraphs.PeriodicEdgeIter\nPeriodicGraphs.OffsetVertexIterator\nPeriodicGraphs.graph_width!","category":"page"},{"location":"neighborhood/#PeriodicGraphs.PeriodicEdgeIter","page":"Neighborhood","title":"PeriodicGraphs.PeriodicEdgeIter","text":"PeriodicEdgeIter{N} <: AbstractEdgeIter\n\nEdge iterator type for undirected N-periodic graphs.\n\nThe iterator only yields edges in the form (u, v, ofs) with either u < v or u == v && ofs > zero(ofs). This is possible because PeriodicGraphs are undirected, hence to each edge (u, v, ofs) in the graph corresponds its reverse edge (v, u, .-ofs). The iterator thus yields each edge of the graph exactly once.\n\n\n\n\n\n","category":"type"},{"location":"neighborhood/#PeriodicGraphs.OffsetVertexIterator","page":"Neighborhood","title":"PeriodicGraphs.OffsetVertexIterator","text":"OffsetVertexIterator{D} <: AbstractVector{PeriodicVertex{D}}\nOffsetVertexIterator(ofs::SVector{D,Int}, list::AbstractVector{PeriodicVertex{D}}) where D\n\nIterator type that yields the sequence of PeriodicVertex in list, each offset by the input ofs.\n\n\n\n\n\n","category":"type"},{"location":"neighborhood/#PeriodicGraphs.graph_width!","page":"Neighborhood","title":"PeriodicGraphs.graph_width!","text":"graph_width!(g::PeriodicGraph{N}) where N\n\nSet the width internal field of the graph so that the for most n ∈ N*, the n-th neighbor of any vertex v of the initial cell is in a cell (i_1, i_2, ..., i_N) such that max(abs.((i_1, i_2, ..., i_N))) ≤ 1 + fld((n - 1), width). Return the new width.\n\nThis function is only a heuristic, it may produce a width that does not satisfy the condition.\n\nThis function returns the current width if it is not equal to -1 (internal value used to mark an unset width). If you decide to modify the other internal fields of g, it is probably a good idea to do g.width[] = -1 so that this function gets automatically called when needed, unless you are sure the width will not be affected by your change.\n\n\n\n\n\n","category":"function"},{"location":"rings/#Ring-statistics","page":"Rings","title":"Ring statistics","text":"","category":"section"},{"location":"rings/#Definitions","page":"Rings","title":"Definitions","text":"","category":"section"},{"location":"rings/","page":"Rings","title":"Rings","text":"In this section, we use the terminology recommended by Blatov, O’Keeffe and Proserpio. In particular:","category":"page"},{"location":"rings/","page":"Rings","title":"Rings","text":"a cycle is a sequence of vertices v₁, v₂, ..., vₙ such that for all i between 2 and n, vᵢ₋₁ and vᵢ are neighbors, as well as v₁ and vₙ, and no vᵢ occurs more than once in the sequence. It can be equivalently represented by the sequence of edges between two consecutive vertices and between v₁ and vₙ.\nthe sum of two or more cycles is the set of edges occurring only an odd number of times in the set of input cycles. The sum of two cycles is thus the symmetric difference of their edges. Note that the sum of cycles may be empty, or may be the juxtaposition of several edge-disjoint cycles.\nthe length of a cycle is its number of edges. It is also equal to its number of vertices since no vertex is repeated in the sequence. A cycle a is strictly smaller than another b when the length of a is strictly lower than that of b.\na ring is a cycle which is not the sum of two strictly smaller cycles. An equivalent definition is that a ring is a cycle which does not admit a short-circuit: between two vertices of the ring, there is no path of the graph strictly smaller than both branches of the ring linking the two vertices.\na strong ring is a cycle which is not the sum of any number of strictly smaller cycles.","category":"page"},{"location":"rings/#Manual","page":"Rings","title":"Manual","text":"","category":"section"},{"location":"rings/","page":"Rings","title":"Rings","text":"PeriodicGraphs.jl provides an algorithm for the determination of all rings and strong rings up to a given size in a PeriodicGraph. It can also be used on finite graphs by converting them to PeriodicGraph{0}, although the code is not optimized for this case.","category":"page"},{"location":"rings/","page":"Rings","title":"Rings","text":"The rings (respectively strong_rings) function returns the list of all rings (respectively strong rings) in the graph up to a given size:","category":"page"},{"location":"rings/","page":"Rings","title":"Rings","text":"rings\nstrong_rings","category":"page"},{"location":"rings/#PeriodicGraphs.rings","page":"Rings","title":"PeriodicGraphs.rings","text":"rings(g::PeriodicGraph{D}, [depth::Integer=15,] symmetries::AbstractSymmetryGroup=NoSymmetryGroup(g), dist::DistanceRecord=DistanceRecord(g,depth)) where D\n\nCompute the list of rings in g, up to length 2*depth+3. Return the list of Vector{Int} where each sublist is a ring whose vertices are the reverse_hash_positions of the sublist elements. Also return an AbstractSymmetryGroup acting on the returned rings.\n\nA ring is a cycle of the graph for which there is no shortcut, i.e. no path in the graph between two vertices of the cycle that is shorter than either path connecting the vertices in the cycle.\n\nIf provided, symmetries should represent the symmetries of the graph as a AbstractSymmetryGroup object respecting its documented interface.\n\nA PeriodicGraphs.DistanceRecord dist can be optionally provided to track the distances between pairs of vertices in the graph.\n\n\n\n\n\n","category":"function"},{"location":"rings/#PeriodicGraphs.strong_rings","page":"Rings","title":"PeriodicGraphs.strong_rings","text":"strong_rings([rs::Vector{Vector{Int}},] g::PeriodicGraph{D}, [depth::Integer=15,] symmetries::AbstractSymmetryGroup=NoSymmetryGroup(g), dist::DistanceRecord=DistanceRecord(g,depth)) where D\n\nCompute the list of strong rings in g, up to length 2*depth+3. Return them with their symmetry group. Each ring is represented by the list of hash_position of its vertices.\n\nThe optional first argument rs is the list of rings which can be provided if previously computed.\n\nSee rings for the meaning of the other arguments.\n\nA strong ring is a cycle of the graph which cannot be decomposed into a sum of any number of smaller cycles. By comparison, a ring is a cycle which cannot be decomposed into a sum of two smaller cycles. In particular, all strong rings are rings.\n\nSee also strong_erings to obtain the rings as a list of integers representing the edges of the ring, instead of a list of integers representing its vertices.\n\n\n\n\n\n","category":"function"},{"location":"rings/","page":"Rings","title":"Rings","text":"A few notes on the output:","category":"page"},{"location":"rings/","page":"Rings","title":"Rings","text":"The output is a pair (rs, symm) where rs is the list of rings (respectively strong rings) and symm is an AbstractSymmetryGroup which contains symmetries of rs. symm is always a NoSymmetryGroup if the optional argument symmetries is not provided.\nThe returned list of rings rs is generally unsorted.\nAll translations of the same ring are represented by a unique ring, which means that a ring crossing through different unit cells will only appear once in the list, even though it may appear several times in a single unit cell.\nThe symmetries optional argument reduces the computational cost of the algorithm. The output lists rs with and without the optional argument are identical except for the order of their elements.","category":"page"},{"location":"rings/","page":"Rings","title":"Rings","text":"The optional argument depth defaults to 15, which means that rings containing up to 33 edges will be considered. This default value is chosen to accomodate the vast majority of periodic nets encountered as crystal nets, for which the ring size rarely exceeds 20.","category":"page"},{"location":"rings/","page":"Rings","title":"Rings","text":"Let's take as example an aperiodic graph representing a small house, made of a cube with a pyramid on top:","category":"page"},{"location":"rings/","page":"Rings","title":"Rings","text":"julia> house = PeriodicGraph{0}(\"0 \"*\n \"1 2 2 3 3 4 4 1 \"* # square base of the house\n \"1 5 2 6 3 7 4 8 \"* # 4 vertical pillars\n \"5 6 6 7 7 8 8 5 \"* # square ceiling\n \"5 9 6 9 7 9 8 9 \" # pyramidal roof\n );\n\njulia> sort!(first(rings(house)))\n14-element Vector{Vector{Int64}}:\n [1, 2, 3, 4]\n [1, 2, 3, 7, 8, 5]\n [1, 2, 6, 5]\n [1, 2, 6, 7, 8, 4]\n [1, 4, 3, 7, 6, 5]\n [1, 4, 8, 5]\n [2, 3, 4, 8, 5, 6]\n [2, 3, 7, 6]\n [3, 4, 8, 7]\n [5, 6, 7, 8]\n [5, 6, 9]\n [5, 8, 9]\n [6, 7, 9]\n [7, 8, 9]\n\njulia> sort!(first(strong_rings(house)))\n9-element Vector{Vector{Int64}}:\n [1, 2, 3, 4]\n [1, 2, 6, 5]\n [1, 4, 8, 5]\n [2, 3, 7, 6]\n [3, 4, 8, 7]\n [5, 6, 9]\n [5, 8, 9]\n [6, 7, 9]\n [7, 8, 9]","category":"page"},{"location":"rings/","page":"Rings","title":"Rings","text":"We can see that the house has four weak rings of size 6, six rings of size 4 among which five are strong, and four strong rings of size 3.","category":"page"},{"location":"rings/","page":"Rings","title":"Rings","text":"The strong rings are the faces of the house: there are four triangles that make the roof, four squares that make the walls and one last square for the base of the house. The square corresponding to the ceiling is actually the sum of the four triangles of the roof, which is why it is not a strong ring. The four weak rings of size 6 are those that go through each vertex of the cube except for one of the four opposite pairs.","category":"page"},{"location":"rings/","page":"Rings","title":"Rings","text":"To explore the ring distributions around individual vertices, the RingAttributions struct factors the ring distribution by vertex. The list of rings including a particular vertex is factored into a RingIncluding struct:","category":"page"},{"location":"rings/","page":"Rings","title":"Rings","text":"RingAttributions\nRingIncluding","category":"page"},{"location":"rings/#PeriodicGraphs.RingAttributions","page":"Rings","title":"PeriodicGraphs.RingAttributions","text":"RingAttributions{D} <: AbstractVector{RingIncluding{D}}\n\nRepresent a set of rings of a PeriodicGraph{D}.\n\nFor ra of type RingAttributions{D}, ra[i] is a RingIncluding{D} object representing the set of rings including PeriodicVertex{D}(i).\n\n\n\n\n\n","category":"type"},{"location":"rings/#PeriodicGraphs.RingIncluding","page":"Rings","title":"PeriodicGraphs.RingIncluding","text":"RingIncluding{D} <: AbstractVector{OffsetVertexIterator{D}}\n\nThe list of rings of a PeriodicGraph{D} including a particular vertex PeriodicVertex{D}(i).\n\nThe object is iterable and indexable by an integer: for ri of type RingIncluding{D}, ri[j] is an iterable over the vertices of the j-th ring including vertex i.\n\n\n\n\n\n","category":"type"},{"location":"rings/","page":"Rings","title":"Rings","text":"To avoid useless computations, the lists of rings and the rings themselves are returned as iterables instead of Vector{PeriodicVertex{N}} and such, so they should be collected if required.","category":"page"},{"location":"rings/","page":"Rings","title":"Rings","text":"Let's look all the rings on our little house:","category":"page"},{"location":"rings/","page":"Rings","title":"Rings","text":"julia> ras = RingAttributions(house)\nRingAttributions{0}(rings per node: [6, 6, 6, 6, 8, 8, 8, 8, 4])\n\njulia> roofpeak = ras[9] # the list of rings including the top of the roof\n4-element RingIncluding{0}:\n [5, 8, 9]\n [5, 6, 9]\n [7, 8, 9]\n [6, 7, 9]\n\njulia> roofpeak[2] # the second ring including the top of the roof\n3-element PeriodicGraphs.OffsetVertexIterator{0}:\n 5\n 6\n 9\n\njulia> rasstrong = RingAttributions(house, true)\nRingAttributions{0}(rings per node: [3, 3, 3, 3, 4, 4, 4, 4, 4])\n\njulia> rasstrong[1] # the base and two walls make the strong rings around vertex 1\n3-element RingIncluding{0}:\n [1, 2, 6, 5]\n [1, 4, 8, 5]\n [1, 2, 3, 4]\n\njulia> collect(rasstrong[5]) # two rooftiles and two walls make the strong rings around vertex 5\n4-element Vector{PeriodicGraphs.OffsetVertexIterator{0}}:\n [5, 8, 9]\n [5, 6, 9]\n [1, 2, 6, 5]\n [1, 4, 8, 5]","category":"page"},{"location":"rings/#Internal-API","page":"Rings","title":"Internal API","text":"","category":"section"},{"location":"rings/","page":"Rings","title":"Rings","text":"Here is a collection of internal utilities used for the algorithms of rings and strong_rings:","category":"page"},{"location":"rings/","page":"Rings","title":"Rings","text":"PeriodicGraphs.ConstMiniBitSet\nPeriodicGraphs.DistanceRecord\nPeriodicGraphs.JunctionNode\nPeriodicGraphs.PhantomJunctionNode\nPeriodicGraphs.arcs_list\nPeriodicGraphs.RingsEndingAt\nPeriodicGraphs.normalize_cycle!\nPeriodicGraphs.symdiff_cycles!\nPeriodicGraphs.symdiff_cycles\nPeriodicGraphs.IterativeGaussianElimination\nPeriodicGraphs.gaussian_elimination!\nPeriodicGraphs.gaussian_elimination\nPeriodicGraphs.intersect_cycles!\nPeriodicGraphs.intersect_cycles\nPeriodicGraphs.union_cycles!\nPeriodicGraphs.union_cycles\nPeriodicGraphs.retrieve_track!\nPeriodicGraphs.rings_around\nPeriodicGraphs.EdgeDict\nstrong_erings\nPeriodicGraphs.convert_to_ering!\nPeriodicGraphs.convert_to_ering","category":"page"},{"location":"rings/#PeriodicGraphs.ConstMiniBitSet","page":"Rings","title":"PeriodicGraphs.ConstMiniBitSet","text":"ConstMiniBitSet{T} <: AbstractSet{Int}\n\nFixed-size bitset stored on a single word of type T, typically a UInt64 or a UInt32.\n\n\n\n\n\n","category":"type"},{"location":"rings/#PeriodicGraphs.DistanceRecord","page":"Rings","title":"PeriodicGraphs.DistanceRecord","text":"DistanceRecord{D}\n\nRecord of the computed distances between vertices of a graph.\n\n\n\n\n\n","category":"type"},{"location":"rings/#PeriodicGraphs.JunctionNode","page":"Rings","title":"PeriodicGraphs.JunctionNode","text":"JunctionNode{T}\n\nElement of the DAG representing the set of arcs linking each vertex x to a fixed vertex i of graph g. Each JunctionNode contains information on the arcs passing through a particular vertex x:\n\nnum is the length of the shortest path between x and i. Since we only collect rings, only the shortest paths are of interest, as well as the path of length num+1 which may form an odd-length ring when combined with a shortest path.\nheads is a list of neighbors of x such that the lastshort first are at distance num - 1 from i, and the rest are at distance num and have a lower value than x.\nshortroots is the set of roots reachable on a shortest path from x to i. A root is the neighbor of i on that path, a.k.a. the second-to-last vertex on that path.\nlongroots is the set of roots reachable on a path of length num+1 from x to i.\n\n\n\n\n\n","category":"type"},{"location":"rings/#PeriodicGraphs.PhantomJunctionNode","page":"Rings","title":"PeriodicGraphs.PhantomJunctionNode","text":"PhantomJunctionNode{D}\n\nElement of the phantom DAG.\n\nSimilarly to the DAG of JunctionNode, the phantom DAG tracks arcs linking vertices x to a fixed vertex i, except that the vertices x are those that should be ignored in the returned list of rings. Thus, only the shortest distance between x and i needs to be recorded, since the arcs themselves will be discarded eventually.\n\n\n\n\n\n","category":"type"},{"location":"rings/#PeriodicGraphs.arcs_list","page":"Rings","title":"PeriodicGraphs.arcs_list","text":"arcs_list(g::PeriodicGraph{D}, i, depth::T, ringavoid=nothing, cycleavoid=nothing) where {D,T}\n\nCompute the list of shortest arcs starting from vertex i up to length depth+1. Vertices in ringavoid are not included in the returned arcs, but considered still part of the graph for distance computations. Vertices in cycleavoid are considered removed from the graph completely.\n\nReturn (dag, vertexnums) where dag is a Vector{JunctionNode{T}} representing, for each visited node, the DAG of all arcs from that node back to i, in a compact representation. vertexnums is a Vector{PeriodicVertex{D}} whose k-th value is the vertex represented by number k in dag.\n\nIf ringavoid !== nothing, dag will also not include arcs that pass through nodes of the form PeriodicVertex{D}(j, ofs) with j == i and ofs < zero(SVector{Int,D}): this allows eagerly pruning cycles that are translations of others. Note that this can result in missing cycles if those pass through at least three nodes with j == i, but that situation should be exceptionally rare.\n\nnote: Note\nThe type T of depth is used as type parameter to the JunctionNode, just to avoid having a dedicated argument (since depth should be at most 62 for the rest of the algorithm to work). This size controls the maximal degree a vertex of g should have : for example, T == UInt32 indicates that all vertices must have degree at most 31.\n\n\n\n\n\n","category":"function"},{"location":"rings/#PeriodicGraphs.RingsEndingAt","page":"Rings","title":"PeriodicGraphs.RingsEndingAt","text":"RingsEndingAt(dag, midnode, record)\n\nIterable over the rings of graph g around node i with midnode as vertex furthest from i. If there are two such vertices (odd ring), midnode is the higher of the two.\n\nrecord should be set to (dist, vertexnums) where dist == DistanceRecord(g, depth) and dag, vertexnums == first(arcs_list(g, i, depth, ...)), otherwise the iterator will return many more cycles that may not be rings.\n\nwarning: Warning\nIn order to efficiently cycle through the rings, the iterator reuses a buffer on which the rings are written. This means that performing an iteration will change the value of the previously returned result: for example, collect(RingsEndingAt(...)) will yield a list containing the same sublist (unlikely to be an actual ring) repeated over. To actually obtain the list of rings, copy the result as they arrive by doing map(copy, RingsEndingAt(...)) or [copy(x) for x in RingsEndingAt(...)] for example.This also means that the list returned at each iteration should never be modified directly: copy it before.\n\n\n\n\n\n","category":"type"},{"location":"rings/#PeriodicGraphs.normalize_cycle!","page":"Rings","title":"PeriodicGraphs.normalize_cycle!","text":"normalize_cycle!(cycle::Vector{Int}, n, v::Val{D}) where D\n\nIn-place rotate and possibly reverse cycle, a Vector{Int} whose elements are the hash_position of vertices of g so that the result is the same for all such vectors that represent the same cycle, possibly translated to a different unit cell or rotated.\n\nThe graph g::PeriodicGraph{D} is represented as n = nv(g) and v = Val(D)\n\n\n\n\n\n","category":"function"},{"location":"rings/#PeriodicGraphs.symdiff_cycles!","page":"Rings","title":"PeriodicGraphs.symdiff_cycles!","text":"symdiff_cycles!(c::Vector{T}, a::Vector{T}, b::Vector{T}) where T\n\nLike PeriodicGraphs.symdiff_cycles but stores the result in c.\n\nc will be resized accordingly so its initial length does not matter.\n\n\n\n\n\n","category":"function"},{"location":"rings/#PeriodicGraphs.symdiff_cycles","page":"Rings","title":"PeriodicGraphs.symdiff_cycles","text":"symdiff_cycles(a, b)\n\nSymmetric difference between two sorted lists a and b. Return the sorted list of elements belonging to a or to b but not to both.\n\nUse PeriodicGraphs.symdiff_cycles! to provide a pre-allocated destination.\n\nExample\n\njulia> PeriodicGraphs.symdiff_cycles([3,4,5], [4,5,6])\n2-element Vector{Int64}:\n 3\n 6\n\n\n\n\n\n","category":"function"},{"location":"rings/#PeriodicGraphs.IterativeGaussianElimination","page":"Rings","title":"PeriodicGraphs.IterativeGaussianElimination","text":"IterativeGaussianElimination{T}\n\nStruct containing the list of sparse columns of the matrix under gaussian elimination on the 𝔽₂ finite field.\n\nTo be used with PeriodicGraphs.gaussian_elimination! as one of the three concrete types:\n\nPeriodicGraphs.IterativeGaussianEliminationNone for simple gaussian elimination,\nPeriodicGraphs.IterativeGaussianEliminationLength to detect when a new column can be expressed as a sum of strictly smaller columns of the matrix.\nPeriodicGraphs.IterativeGaussianEliminationDecomposition to detect when a new column can be expressed as a sum of other columns of the matrix and keep track of which.\n\n\n\n\n\n","category":"type"},{"location":"rings/#PeriodicGraphs.gaussian_elimination!","page":"Rings","title":"PeriodicGraphs.gaussian_elimination!","text":"gaussian_elimination!(gauss::IterativeGaussianElimination, r::Vector{Int})\n\nTest whether r can be expressed as a sum of vectors stored in gauss, and store r if not. \"sum\" refers to the symmetric difference of boolean vectors, represented in sparse format as the ordered list of non-zero indices.\n\nIf gauss isa IterativeGaussianEliminationLength, return whether r can be expressed as a sum of strictly smaller vectors.\n\nOtherwise, return true when r is a sum of any previously encoutered vectors. If gauss isa IterativeGaussianEliminationDecomposition, query retrieve_track(gauss) to obtain the sorted list of indices of such previously encountered vectors.\n\nSee also gaussian_elimination to test r without storing it.\n\n\n\n\n\n","category":"function"},{"location":"rings/#PeriodicGraphs.gaussian_elimination","page":"Rings","title":"PeriodicGraphs.gaussian_elimination","text":"gaussian_elimination(gauss::IterativeGaussianElimination, r::Vector{Int})\n\nReturn notindependent, info where notindependent is true if r can be expressed as a sum of vectors stored in gauss.\n\nSee PeriodicGraphs.gaussian_elimination! to store r in gauss if not, and for more details dependending on the type of gauss.\n\nCall PeriodicGraphs.gaussian_elimination!(gauss, r, notindependent, info) to obtain the result of PeriodicGraphs.gaussian_elimination!(gauss, r) without duplicating computation.\n\n\n\n\n\n","category":"function"},{"location":"rings/#PeriodicGraphs.intersect_cycles!","page":"Rings","title":"PeriodicGraphs.intersect_cycles!","text":"intersect_cycles!(c::Vector{T}, a::Vector{T}, b::Vector{T}) where T\n\nLike PeriodicGraphs.intersect_cycles but stores the result in c.\n\nc will be resized accordingly so its initial length does not matter as long as it is at least as large as the resulting list.\n\n\n\n\n\n","category":"function"},{"location":"rings/#PeriodicGraphs.intersect_cycles","page":"Rings","title":"PeriodicGraphs.intersect_cycles","text":"intersect_cycles(a, b)\n\nIntersection between two sorted lists a and b. Return the sorted list of elements belonging to both a and b.\n\nUse PeriodicGraphs.intersect_cycles! to provide a pre-allocated destination.\n\nExample\n\njulia> PeriodicGraphs.intersect_cycles([3,4,5], [4,5,6])\n2-element Vector{Int64}:\n 4\n 5\n\n\n\n\n\n","category":"function"},{"location":"rings/#PeriodicGraphs.union_cycles!","page":"Rings","title":"PeriodicGraphs.union_cycles!","text":"union_cycles!(c::Vector{T}, a::Vector{T}, b::Vector{T}) where T\n\nLike PeriodicGraphs.union_cycles but stores the result in c.\n\nc will be resized accordingly so its initial length does not matter as long as it is at least as large as the resulting list.\n\n\n\n\n\n","category":"function"},{"location":"rings/#PeriodicGraphs.union_cycles","page":"Rings","title":"PeriodicGraphs.union_cycles","text":"union_cycles(a, b)\n\nUnion between two sorted lists a and b. Return the sorted list of elements belonging to a or b or both.\n\nUse PeriodicGraphs.union_cycles! to provide a pre-allocated destination.\n\nExample\n\njulia> PeriodicGraphs.union_cycles([3,4,5], [4,5,6])\n4-element Vector{Int64}:\n 3\n 4\n 5\n 6\n\n\n\n\n\n","category":"function"},{"location":"rings/#PeriodicGraphs.retrieve_track!","page":"Rings","title":"PeriodicGraphs.retrieve_track!","text":"retrieve_track!([ret::Vector{Int32}, buffer::Vector{Int32},] gauss::IterativeGaussianEliminationDecomposition)\n\nTo be called consecutive to a call to gaussian_elimination!(gauss, x) that returned true. In that case, x was found to be the sum of previously encountered vectors: return the (reverse-sorted) list of their indices.\n\nwarning: Warning\nCalling retrieve_track! after a call to gaussian_elimination! that returned false will produce an invalid result. Calling it twice will also produce an invalid result.\n\n\n\n\n\n","category":"function"},{"location":"rings/#PeriodicGraphs.rings_around","page":"Rings","title":"PeriodicGraphs.rings_around","text":"rings_around(g::PeriodicGraph{D}, i, depth=15, dist::DistanceRecord=DistanceRecord(g,depth), visited=nothing) where D\n\nReturn the list of all rings around node i in graph g up to length 2*depth+3.\n\nThe returned rings are the list of hash_position of the corresponding vertices. To get back the list of actual PeriodicVertex of a returned ring in the list, do\n\n[reverse_hash_position(x, g) for x in ring]\n\nIf the offsets of the corresponding vertices are not needed, simply do\n\n[mod1(x, n) for x in ring] # n should be nv(g)\n\nvisited is interpreted as the ringavoid argument of arcs_list unless dist === nothing, in which case it is interpreted as the cycleavoid argument. In particular, unless dist === nothing, only one ring will appear in the list even if some of its translated images also pass through PeriodicVertex{D}(i).\n\n\n\n\n\n","category":"function"},{"location":"rings/#PeriodicGraphs.EdgeDict","page":"Rings","title":"PeriodicGraphs.EdgeDict","text":"EdgeDict{D}\n\nMap from pairs of PeriodicVertex{D} to the identifier of the corresponding edge.\n\nkp::EdgeDict{D} should be queried by either get!(kp, minmax(v1, v2)) where v1 and v2 are PeriodicVertex{D} to obtain the identifier of the edge and store a new identifier if absent, or by kp[i] where i is an Integer to obtain the pair of vertices corresponding to identifier i.\n\nkp is built by calling EdgeDict(g) where g is a PeriodicGraph.\n\n\n\n\n\n","category":"type"},{"location":"rings/#PeriodicGraphs.strong_erings","page":"Rings","title":"PeriodicGraphs.strong_erings","text":"strong_erings([rs::Vector{Vector{Int}},], g::PeriodicGraph{D}, [depth=15,] ringsymms::AbstractSymmetryGroup=NoSymmetryGroup(length(rs))) where D\n\nCompute the list of strong edge rings in g, up to length 2*depth+3. See strong_rings and rings for the meaning of the optional arguments.\n\nReturn a quadruplet of values:\n\nthe two first values are the list of rings and their symmetry group, identical to the result of strong_rings, unless rs is provided (see below).\nthe third is the list of edge rings: each edge of the periodic graph is mapped to an integer and each ring is represented by the sorted list of its edges.\nthe last is the mapping from edges to integers, given as an EdgeDict.\n\nIf rs is provided, the first returned value is the list of indices keep of rs such that rs[keep] is the list of strong rings.\n\n\n\n\n\n","category":"function"},{"location":"rings/#PeriodicGraphs.convert_to_ering!","page":"Rings","title":"PeriodicGraphs.convert_to_ering!","text":"convert_to_ering!(buffer::Vector{Int}, ring::Vector{PeriodicVertex{D}}, kp::EdgeDict{D}, ofs, len) where D\n\nReturn the edge ring corresponding to OffsetVertexIterator{D}(ring[1:len], ofs) inside buffer, resized to length len.\n\nSee also PeriodicGraphs.convert_to_ering.\n\n\n\n\n\n","category":"function"},{"location":"rings/#PeriodicGraphs.convert_to_ering","page":"Rings","title":"PeriodicGraphs.convert_to_ering","text":"convert_to_ering(ring::Vector{PeriodicVertex{D}}, kp::EdgeDict{D}, ofs=zero(SVector{D,Int}), len=length(ring)) where D\n\nReturn the edge ring corresponding to OffsetVertexIterator{D}(ring[1:len], ofs).\n\nSee also PeriodicGraphs.convert_to_ering! to provide a buffer.\n\n\n\n\n\n","category":"function"},{"location":"utilities/#Utilities","page":"Utilities","title":"Utilities","text":"","category":"section"},{"location":"utilities/#Hashing","page":"Utilities","title":"Hashing","text":"","category":"section"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"It is sometimes convenient to be able to associate to each vertex of periodic graph g an integer hash, such that the hashes of vertices in the reference unit cell are between 1 and nv(g), the hashes of the vertices in the unit cells around the reference are next, then the vertices of the unit cells around those, etc. To do so, PeriodicGraphs.jl export the hash_position function as follows:","category":"page"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"hash_position","category":"page"},{"location":"utilities/#PeriodicGraphs.hash_position","page":"Utilities","title":"PeriodicGraphs.hash_position","text":"hash_position(x::PeriodicVertex{N}, n::Integer) where N\n\nGiven x, a PeriodicVertex{N}, and the number n of vertex identifiers in a graph, compute a unique positive integer hash for the given vertex.\n\nThis hash function is a bijection between the set of all the vertices of the periodic graph and the set of positive integers. Its value is an integer between 1+n*(2d-1)^N (or 1 if d == 0) and n*(2d+1)^N, where d = maximum(abs.(x.ofs)).\n\nIn particular, this means that when one unit cell B is further than another A from the origin (for the Manhattan distance), all vertices in B have a larger hash than all vertices in A.\n\n\n\n\n\n","category":"function"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"The reciproque function is also exported:","category":"page"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"reverse_hash_position","category":"page"},{"location":"utilities/#PeriodicGraphs.reverse_hash_position","page":"Utilities","title":"PeriodicGraphs.reverse_hash_position","text":"reverse_hash_position(hash::Integer, n::Integer, ::Val{N}) where N\n\nGiven a hash obtained from hash_position(x, n) where x is a PeriodicVertex{N}, return the corresponding x.\n\nIf the offset of the returned PeriodicVertex is not needed, simply doing mod1(x, n) yields the identifier of the vertex and is faster.\n\n\n\n\n\n","category":"function"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"Both functions are optimized for dimensions 1, 2 and 3, especially for unit cells not too far from the reference.","category":"page"},{"location":"utilities/#Isomorphic-transformations","page":"Utilities","title":"Isomorphic transformations","text":"","category":"section"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"Several functions transform a periodic graph into another isomorphic to the input, by renumbering the vertices (vertex_permutation) or the axes (swap_axes!), or by offsetting the chosen representatives for each vertex (offset_representatives!). It is also possible to make an isomorphic graph with more vertices per unit cell by using a supercell (make_supercell).","category":"page"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"PeriodicGraphs.vertex_permutation\nswap_axes!\noffset_representatives!\nmake_supercell","category":"page"},{"location":"utilities/#PeriodicGraphs.vertex_permutation","page":"Utilities","title":"PeriodicGraphs.vertex_permutation","text":"vertex_permutation(g::PeriodicGraph, vlist)\n\nReturn the PeriodicGraph corresponding to g with its vertices identifiers permuted according to vlist. isperm(vlist) must hold and will not be checked.\n\nSee also Graphs.induced_subgraph for the more general case where vlist is not a permutation.\n\nnote: Note\nThe resulting graph is isomorphic to the initial one, only the representation has changed.\n\n\n\n\n\n","category":"function"},{"location":"utilities/#PeriodicGraphs.swap_axes!","page":"Utilities","title":"PeriodicGraphs.swap_axes!","text":"swap_axes!(g::PeriodicGraph, t)\n\nIn-place modifies graph g so that the new initial cell corresponds to the previous one with its axes swapped according to the permutation t.\n\nnote: Note\nThe resulting graph is isomorphic to the initial one, only the representation has changed.\n\n\n\n\n\n","category":"function"},{"location":"utilities/#PeriodicGraphs.offset_representatives!","page":"Utilities","title":"PeriodicGraphs.offset_representatives!","text":"offset_representatives!(g::PeriodicGraph, offsets)\n\nIn-place modifies graph g so that the i-th vertex of the new initial cell corresponds to the i-th vertex in cell offsets[i] compared to the previous initial cell.\n\nnote: Note\nThe resulting graph is isomorphic to the initial one, only the representation has changed.\n\n\n\n\n\n","category":"function"},{"location":"utilities/#PeriodicGraphs.make_supercell","page":"Utilities","title":"PeriodicGraphs.make_supercell","text":"make_supercell(g::PeriodicGraph, t)\n\nReturn a graph isomorphic to the input g whose its unit cell is a repetition of that of g, each dimension i being repeated t[i] times. It follows that the number of vertices of make_supercell(g, t) is prod(t)*nv(g)\n\nt must be an interator over positive integers.\n\n\n\n\n\n","category":"function"},{"location":"utilities/#Dimension-reduction","page":"Utilities","title":"Dimension reduction","text":"","category":"section"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"Any PeriodicGraph can be naturally reduced to an aperiodic graph by removing all offsets from the edges and either keeping (quotient_graph) or removing (truncated_graph) edges crossing from one unit cell to another.","category":"page"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"quotient_graph\ntruncated_graph","category":"page"},{"location":"utilities/#PeriodicGraphs.quotient_graph","page":"Utilities","title":"PeriodicGraphs.quotient_graph","text":"quotient_graph(g::PeriodicGraph)\n\nExtract a simple graph from g by removing all indications of offset in the edges. This means that edges that used to cross the boundaries of the initial cell now bind the source vertex to the representative of the destination vertex that is in the initial cell.\n\nNote that these modified edges may turn into loops.\n\nSee also truncated_graph to remove all of these edges and slice_graph to keep only some of these edges.\n\n\n\n\n\n","category":"function"},{"location":"utilities/#PeriodicGraphs.truncated_graph","page":"Utilities","title":"PeriodicGraphs.truncated_graph","text":"truncated_graph(g::PeriodicGraph)\n\nExtract a simple graph from g by only keeping the edges that are strictly within the initial cell.\n\nSee also quotient_graph to keep all of these edges and slice_graph to keep only some of these edges.\n\n\n\n\n\n","category":"function"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"It is also possible to reduce the dimension of a graph by removing only some selected offsets with the slice_graph function.","category":"page"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"slice_graph","category":"page"},{"location":"utilities/#PeriodicGraphs.slice_graph","page":"Utilities","title":"PeriodicGraphs.slice_graph","text":"slice_graph(g::PeriodicGraph{D}, remove::Union{SVector{N},NTuple{N}}) where {D,N}\n\nExtract a PeriodicGraph{D-N} from g by removing all edges that have an offset o such that !iszero(o[remove]) and shrinking the resulting offsets. In other words, remove the dimensions in remove.\n\nTo only remove the edges while keeping the same number of dimensions, use slice_graph(g, collect(remove))\n\nremove is assumed to be sorted and to contain unique elements.\n\nwarning: Warning\nNo verification of the previous assumption will be performed.\n\n\n\n\n\nslice_graph(g::PeriodicGraph{D}, remove::Vector{<:Integer}) where D\n\nExtract a PeriodicGraph{D} from g by removing all edges that have an offset o such that !iszero(o[remove]).\n\nContrarily to the slice_graph(g::PeriodicGraph{D}, remove::Union{SVector{N},NTuple{N}}) where {D,N} method, the dimensions along which the edges are erased are still kept here.\n\nremove is assumed to be sorted and to contain unique elements.\n\nwarning: Warning\nNo verification of the previous assumption will be performed.\n\n\n\n\n\n","category":"function"},{"location":"utilities/#Arithmetics","page":"Utilities","title":"Arithmetics","text":"","category":"section"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"These utilities are internally used for dimensionality computations, but may be useful in other contexts.","category":"page"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"PeriodicGraphs.extended_gcd\nPeriodicGraphs.normal_basis","category":"page"},{"location":"utilities/#PeriodicGraphs.extended_gcd","page":"Utilities","title":"PeriodicGraphs.extended_gcd","text":"extended_gcd(s)::Tuple{BigInt, Vector{BigInt}}\n\nGiven a list of integers, return a tuple (d, coefs) where d is the gcd of these integers and coefs is a list of integers such that dot(s, coefs) == d.\n\n\n\n\n\n","category":"function"},{"location":"utilities/#PeriodicGraphs.normal_basis","page":"Utilities","title":"PeriodicGraphs.normal_basis","text":"normal_basis(l::AbstractVector{<:StaticVector{N,T}}) where {N,T<:Integer}\n\nGiven a list of integer vectors of dimension N, return a tuple (mat, D) where D is the dimension of the space spanned by the input vectors, and mat is an invertible matrix whose D first columns form a basis of this spanned space, which does not depend on the exact input.\n\nIf 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.\n\nwarning: Warning\nIf modifiable, the input list will be modified in-place during this process.\n\n\n\n\n\n","category":"function"},{"location":"utilities/#Unclassified-other-utilities","page":"Utilities","title":"Unclassified other utilities","text":"","category":"section"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"These other convenience functions may be useful for the manipulation of PeriodicGraphs:","category":"page"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"find_edges\ncoordination_sequence","category":"page"},{"location":"utilities/#PeriodicGraphs.find_edges","page":"Utilities","title":"PeriodicGraphs.find_edges","text":"find_edges(g::PeriodicGraph, s::Int, d::Int)\n\nReturn the set of PeriodicVertex v of graph g such that there is an edge between a source vertex of identifier s and v, and the identifier of v is d.\n\n\n\n\n\n","category":"function"},{"location":"utilities/#PeriodicGraphs.coordination_sequence","page":"Utilities","title":"PeriodicGraphs.coordination_sequence","text":"coordination_sequence(g::PeriodicGraph, v::Integer, dmax)\n\nCompute the list of numbers of n-th neighbors of vertex v in graph g, for 1 ≤ n ≤ dmax.\n\n\n\n\n\n","category":"function"},{"location":"dimension/#Dimensionality","page":"Dimensionality","title":"Dimensionality","text":"","category":"section"},{"location":"dimension/","page":"Dimensionality","title":"Dimensionality","text":"A periodic graph g of type PeriodicGraph{N} has dimension N, which means that its unit cell is repeated across N independent axes. However, this number may be larger than the actual number of independent axes necessary to describe the repeating unit of the graph, which we will call the dimensionality. For example, consider an infinite set of identical 2-periodic graphs stacked across a third dimension: the resulting graph is of dimension 3, but its dimensionality is 2 (or below) because all the topological information is stored in the 2-periodic subgraph.","category":"page"},{"location":"dimension/","page":"Dimensionality","title":"Dimensionality","text":"The connected components of g can be separated and sorted by dimensionality using the dimensionality function:","category":"page"},{"location":"dimension/","page":"Dimensionality","title":"Dimensionality","text":"dimensionality","category":"page"},{"location":"dimension/#PeriodicGraphs.dimensionality","page":"Dimensionality","title":"PeriodicGraphs.dimensionality","text":"dimensionality(g::PeriodicGraph{N}) where N\n\nDetermine the actual dimension of each connected component of g. 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.\n\nIn 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.\n\nExamples\n\njulia> dimensionality(PeriodicGraph(\"2 1 1 1 0 2 2 -1 1 3 3 1 0 3 3 0 1\"))\nDict{Int64, Vector{Tuple{Vector{Int64}, Int64}}} with 2 entries:\n 2 => [([3], 1)]\n 1 => [([1], 1), ([2], 1)]\n\njulia> dimensionality(PeriodicGraph(\"1 1 1 2\"))\nDict{Int64, Vector{Tuple{Vector{Int64}, Int64}}} with 1 entry:\n 1 => [([1], 2)]\n\n\n\n\n\n","category":"function"},{"location":"dimension/","page":"Dimensionality","title":"Dimensionality","text":"To transpose a graph from one dimension N to another D, call the type constructor PeriodicGraph{D} directly on g::PeriodicGraph{N}. This can be useful to manipulate a graph of dimensionality D as a graph of actual dimension D, which often reduces computational costs.","category":"page"},{"location":"dimension/","page":"Dimensionality","title":"Dimensionality","text":"PeriodicGraph{D}(graph::PeriodicGraph{N}, dims=_dimensionality(graph)) where {D,N}","category":"page"},{"location":"dimension/#PeriodicGraphs.PeriodicGraph-Union{Tuple{PeriodicGraph{N}}, Tuple{N}, Tuple{D}, Tuple{PeriodicGraph{N}, Any}} where {D, N}","page":"Dimensionality","title":"PeriodicGraphs.PeriodicGraph","text":"PeriodicGraph{D}(graph::PeriodicGraph{N}) where {D,N}\n\nReturn a graph that has the same structural information as the input graph but embedded in D dimensions instead of N. It will fail if the dimensionality of the graph is greater than D.\n\nnote: Note\nThe behaviour is undefined if D < N and there are multiple non-identical connected components. In particular, the function is expected to fail if these components do not share the same orientation.\n\n\n\n\n\n","category":"method"},{"location":"dimension/","page":"Dimensionality","title":"Dimensionality","text":"For example, the following function extracts the list of 1-dimensional components from a given PeriodicGraph:","category":"page"},{"location":"dimension/","page":"Dimensionality","title":"Dimensionality","text":"julia> function extract_1D_components(g::PeriodicGraph{D}) where D\n d = dimensionality(g)\n components1D = get(d, 1, Vector{Int}[])\n return [PeriodicGraph1D(g[l]) for l in components1D]\n end\nextract_1D_components (generic function with 1 method)","category":"page"},{"location":"dimension/","page":"Dimensionality","title":"Dimensionality","text":"Let's test it on the following 2-periodic graph, which has one 0D component (vertices 4 and 5), two 1D components (vertex 3 alone and vertices 6 and 7 together) and one 2D component (vertices 1 and 2):","category":"page"},{"location":"dimension/","page":"Dimensionality","title":"Dimensionality","text":"julia> g = PeriodicGraph2D(\"2 1 2 0 0 2 1 1 0 2 1 0 1\n 3 3 1 0\n 4 5 0 0\n 6 7 1 0 7 6 1 0\n \")\nPeriodicGraph2D(7, PeriodicEdge2D[(1, 2, (-1,0)), (1, 2, (0,-1)), (1, 2, (0,0)), (3, 3, (1,0)), (4, 5, (0,0)), (6, 7, (-1,0)), (6, 7, (1,0))])\n\njulia> extract_1D_components(g)\n2-element Vector{PeriodicGraph1D}:\n PeriodicGraph1D(1, PeriodicEdge1D[(1, 1, (1,))])\n PeriodicGraph1D(2, PeriodicEdge1D[(1, 2, (-1,)), (1, 2, (1,))])","category":"page"},{"location":"dimension/","page":"Dimensionality","title":"Dimensionality","text":"The first subgraph corresponds to g[[3]] and the second to g[[6,7]], both converted to PeriodicGraph1D.","category":"page"},{"location":"dimension/","page":"Dimensionality","title":"Dimensionality","text":"The dimension of a graph can also be reduced with loss of information through the slice_graph function.","category":"page"},{"location":"#PeriodicGraphs.jl","page":"Home","title":"PeriodicGraphs.jl","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"A Julia package for the manipulation of periodic graphs.","category":"page"},{"location":"#Usages","page":"Home","title":"Usages","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"PeriodicGraphs.jl defines types and algorithms useful for the manipulation of N-periodic undirected graphs, with N known at compile-time. It extends Graphs.jl by providing the new PeriodicGraph type which implements the AbstractGraph API. It also provides an API for the manipulation of symmetries.","category":"page"},{"location":"","page":"Home","title":"Home","text":"This package serves as support for the PeriodicGraphEmbeddings.jl library, which focuses on euclidean embeddings of periodic graphs, and for CrystalNets.jl for the manipulation and identification of crystal nets, which are 2 or 3-periodic graphs.","category":"page"},{"location":"#Package-installation","page":"Home","title":"Package installation","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"The installation follows the usual procedure. Start by downloading and installing Julia (v1.6 or higher for PeriodicGraphs.jl). Then, either","category":"page"},{"location":"","page":"Home","title":"Home","text":"open the Julia REPL and enter the package manager by typing ], then install PeriodicGraphs.jl by entering:\npkg> add PeriodicGraphs\nalternatively, you can do it from a shell by executing:\njulia -e 'import Pkg; Pkg.add(\"PeriodicGraphs\")","category":"page"},{"location":"","page":"Home","title":"Home","text":"To use the package, open a REPL and enter","category":"page"},{"location":"","page":"Home","title":"Home","text":"julia> using PeriodicGraphs","category":"page"},{"location":"symmetries/#Symmetries","page":"Symmetries","title":"Symmetries","text":"","category":"section"},{"location":"symmetries/","page":"Symmetries","title":"Symmetries","text":"PeriodicGraphs.jl comes with a general API for the manipulation of symmetries. Concrete implementations of the API can be found in PeriodicGraphEmbeddings.jl.","category":"page"},{"location":"symmetries/#Single-symmetry-operations","page":"Symmetries","title":"Single symmetry operations","text":"","category":"section"},{"location":"symmetries/","page":"Symmetries","title":"Symmetries","text":"AbstractSymmetry\nIdentitySymmetry\nSimpleSymmetry\nSimpleSymmetry(map::T, dict::D) where {T,D}\nSimpleSymmetry(map)","category":"page"},{"location":"symmetries/#PeriodicGraphs.AbstractSymmetry","page":"Symmetries","title":"PeriodicGraphs.AbstractSymmetry","text":"abstract type AbstractSymmetry end\n\nAn abstract type representing a symmetry.\n\nInterface\n\nSubtypes T of AbstractSymmetry should implement a method to make their objects symm callable on any object upon which the symmetry can act. For example, if T represents a symmetry of a 3D embedding of a graph:\n\nif x represents a 3D point, then symm(x) should be the image of that point.\nif x represents a 3D basis of space, then symm(x) should be the image of that basis.\n\nWhen the symmetry is naturally defined on a discrete set of objects, their image should be accessible by indexing on the symmetry. With the same example as before:\n\nif x is a vertex, symm[x] is the image of x by the symmetry.\nif i is the integer identifier of vertex x, symm[i] is the identifier of symm[x].\n\n\n\n\n\n","category":"type"},{"location":"symmetries/#PeriodicGraphs.IdentitySymmetry","page":"Symmetries","title":"PeriodicGraphs.IdentitySymmetry","text":"IdentitySymmetry <: AbstractSymmetry\n\nIdentity symmetry, i.e. such that for s::IdentitySymmetry, ∀x, s[x] == x.\n\n\n\n\n\n","category":"type"},{"location":"symmetries/#PeriodicGraphs.SimpleSymmetry","page":"Symmetries","title":"PeriodicGraphs.SimpleSymmetry","text":"SimpleSymmetry{K,T,D} <: AbstractSymmetry\n\nSymmetry operation defined by a map of type T and an optional dict of type D accepting keys of type K.\n\n\n\n\n\n","category":"type"},{"location":"symmetries/#PeriodicGraphs.SimpleSymmetry-Union{Tuple{D}, Tuple{T}, Tuple{T, D}} where {T, D}","page":"Symmetries","title":"PeriodicGraphs.SimpleSymmetry","text":"SimpleSymmetry(map::T, dict::D) where {T,D}\n\nCreate a SimpleSymmetry{keytype(D),T,D} object symm such that symm[x] is\n\nmap[dict[x]] if x isa keytype(D).\nmap[x] otherwise, if x isa Integer.\n\n\n\n\n\n","category":"method"},{"location":"symmetries/#PeriodicGraphs.SimpleSymmetry-Tuple{Any}","page":"Symmetries","title":"PeriodicGraphs.SimpleSymmetry","text":"SimpleSymmetry(map)\n\nCreate a SimpleSymmetry object symm such that symm[x] == map[x] for all x.\n\n\n\n\n\n","category":"method"},{"location":"symmetries/#Symmetry-group","page":"Symmetries","title":"Symmetry group","text":"","category":"section"},{"location":"symmetries/","page":"Symmetries","title":"Symmetries","text":"AbstractSymmetryGroup\nNoSymmetryGroup\nIncludingIdentity","category":"page"},{"location":"symmetries/#PeriodicGraphs.AbstractSymmetryGroup","page":"Symmetries","title":"PeriodicGraphs.AbstractSymmetryGroup","text":"AbstractSymmetryGroup{T<:AbstractSymmetry}\n\nAn abstract type representing the set of symmetries of a graph.\n\nInterface\n\nAny AbstractSymmetryGroup type must define methods for Base functions unique, iterate, length and one such that, for any s of type <: AbstractSymmetryGroup{T}:\n\ns(i) is a representative on the symmetry orbit of i such that all elements on the orbit share the same representative. The representative should be an integer.\nunique(s) is an iterator over such representatives.\niterating over s yields the list of symmetry operations symm, each represented as an object of type T (where T <:AbstractSymmetry is the parameter to typeof(s)). The identity symmetry should not be part of these yielded symm, except for the specific IncludingIdentity subtype of AbstractSymmetryGroup.\none(s) is the identity symmetry of type T.\n\n\n\n\n\n","category":"type"},{"location":"symmetries/#PeriodicGraphs.NoSymmetryGroup","page":"Symmetries","title":"PeriodicGraphs.NoSymmetryGroup","text":"NoSymmetryGroup <: AbstractSymmetryGroup{IdentitySymmetry}\n\nThe trivial AbstractSymmetryGroup devoid of any symmetry operation. NoSymmetryGroup(num) creates a NoSymmetryGroup over num unique representatives.\n\n\n\n\n\n","category":"type"},{"location":"symmetries/#PeriodicGraphs.IncludingIdentity","page":"Symmetries","title":"PeriodicGraphs.IncludingIdentity","text":"IncludingIdentity{S<:AbstractSymmetry,T<:AbstractSymmetryGroup{S}} <: AbstractSymmetryGroup{S}\n\nWrapper around an AbstractSymmetry that explicitly includes the identity operation.\n\n\n\n\n\n","category":"type"}] +[{"location":"types/#Basic-types-and-definitions","page":"Types","title":"Basic types and definitions","text":"","category":"section"},{"location":"types/","page":"Types","title":"Types","text":"DocTestSetup = quote\n using PeriodicGraphs, Graphs\nend\nDocTestFilters = r\"Int..\"","category":"page"},{"location":"types/#Introduction","page":"Types","title":"Introduction","text":"","category":"section"},{"location":"types/","page":"Types","title":"Types","text":"A PeriodicGraph{N} g is the representation of an N-periodic graph.","category":"page"},{"location":"types/","page":"Types","title":"Types","text":"Each vertex has a unique representative, indexed from 1 to n = nv(g). Each vertex x of the graph is represented by a PeriodicVertex{N} containing both the representative v and the offset o between the unit cell containing the vertex and a reference unit cell, accessible through the syntax v, o = x, or with v = first(x) and o = last(x). The offset is a N-uplet of integers, stored as a SVector{N,Int}.","category":"page"},{"location":"types/","page":"Types","title":"Types","text":"Each edge e is represented by a PeriodicEdge{N} defined by its source vertex inside the reference unit cell and of representative s, and its destination vertex d, a PeriodicVertex{N}, which can be accessed through the syntax s, d = e, or with s = first(e) and d = last(e) (or d = Graphs.dst(e)).","category":"page"},{"location":"types/","page":"Types","title":"Types","text":"For convenience, aliases are exported for 1D, 2D and 3D (N = 1, N = 2 and N = 3) under the names PeriodicGraph1D, PeriodicEdge2D, PeriodicVertex3D, etc.","category":"page"},{"location":"types/#PeriodicVertex","page":"Types","title":"PeriodicVertex","text":"","category":"section"},{"location":"types/","page":"Types","title":"Types","text":"A PeriodicVertex can be built like so:","category":"page"},{"location":"types/","page":"Types","title":"Types","text":"julia> PeriodicVertex1D(5, (-1,))\nPeriodicVertex1D(5, (-1,))\n\njulia> PeriodicVertex{4}(2) # shorthand for the vertices of the reference cell\nPeriodicVertex{4}(2, (0,0,0,0))","category":"page"},{"location":"types/#PeriodicEdge","page":"Types","title":"PeriodicEdge","text":"","category":"section"},{"location":"types/","page":"Types","title":"Types","text":"A PeriodicEdge, can be defined from src and dst or, equivalently, be the identifiers of both source and destination vertices, and the cell offset between source and destination. For example, in 3D, the edge between vertex 1 and vertex 4 in cell (0, 1, 0) is PeriodicEdge3D(1, PeriodicVertex3D(4, (0,1,0))), or, equivalently, PeriodicEdge3D(1, 4, (0,1,0)). Since PeriodicEdge(u, v, ofs) and PeriodicEdge(v, u, .-ofs) represent the same edge, one of them is called the direct edge, when it has either u < v or u == v && ofs > zero(ofs), and the other is the indirect edge. Functions isdirectedge and directedge are used for this.","category":"page"},{"location":"types/","page":"Types","title":"Types","text":"More examples:","category":"page"},{"location":"types/","page":"Types","title":"Types","text":"julia> e = PeriodicEdge(3, PeriodicVertex(2, (0,1,0,0))) # dimensions are inferred from the input\nPeriodicEdge{4}(3, 2, (0,1,0,0))\n\njulia> isdirectedge(e)\nfalse\n\njulia> directedge(e)\nPeriodicEdge{4}(2, 3, (0,-1,0,0))\n\njulia> src, (dstv, ofs) = PeriodicEdge3D(5, 6, (1,0,2));\n\njulia> src\n5\n\njulia> dstv\n6\n\njulia> ofs\n3-element StaticArrays.SVector{3, Int64} with indices SOneTo(3):\n 1\n 0\n 2\n\njulia> PeriodicEdge2D(5, 5, (0,0))\nERROR: LoopException: a loop from vertex 5 to itself in the same unit cell is a forbidden edges. Maybe the offset is wrong?","category":"page"},{"location":"types/","page":"Types","title":"Types","text":"Note that loops (that is, edges of the form (u, u, (0,0,0,...,0))) are forbidden and will throw a PeriodicGraphs.LoopException if created. To bypass this check, use the unexported PeriodicGraphs.unsafe_edge function.","category":"page"},{"location":"types/#PeriodicGraph","page":"Types","title":"PeriodicGraph","text":"","category":"section"},{"location":"types/","page":"Types","title":"Types","text":"Finally, N-periodic graphs, represented by the type PeriodicGraph{N}, are defined by the number of vertices in the reference cell and the set of edges starting from the reference cell. When the number of vertices is simply the highest number appearing in the list of edges, it can be omitted. Periodic graphs can be built through several methods:","category":"page"},{"location":"types/","page":"Types","title":"Types","text":"julia> PeriodicGraph{5}() # create the empty graph\nPeriodicGraph{5}(0, PeriodicEdge{5}[])\n\njulia> PeriodicGraph1D(4) # create a graph with 4 vertices but no edge\nPeriodicGraph1D(4, PeriodicEdge1D[])\n\njulia> PeriodicGraph(2, PeriodicEdge{4}[(1, 1, (0,0,1,1)), (1, 1, (0,1,0,-1))]) # the dimension can be inferred\nPeriodicGraph{4}(2, PeriodicEdge{4}[(1, 1, (0,0,1,1)), (1, 1, (0,1,0,-1))])\n\njulia> PeriodicGraph3D(PeriodicEdge3D[(1, 3, (0,1,0)), (2, 2, (0,0,-1)), (1, 2, (1,0,0)), (2, 3, (0,1,1))])\nPeriodicGraph3D(3, PeriodicEdge3D[(1, 2, (1,0,0)), (1, 3, (0,1,0)), (2, 2, (0,0,1)), (2, 3, (0,1,1))])\n\njulia> parse(PeriodicGraph3D, \"3 1 2 1 0 0 1 3 0 1 0 2 2 0 0 1 2 3 0 1 1\") # compact representation of the previous graph\nPeriodicGraph3D(3, PeriodicEdge3D[(1, 2, (1,0,0)), (1, 3, (0,1,0)), (2, 2, (0,0,1)), (2, 3, (0,1,1))])\n\njulia> string(ans) # to obtain the compact representation from the graph\n\"3 1 2 1 0 0 1 3 0 1 0 2 2 0 0 1 2 3 0 1 1\"\n\njulia> string(PeriodicGraph(\"2 1 2 0 0 2 3 0 0 3 1 0 0 3 1 1 0 2 1 0 1 2 3 0 1\"))\n\"2 1 2 0 -1 1 2 0 0 1 3 -1 0 1 3 0 0 2 3 0 0 2 3 0 1\"","category":"page"},{"location":"types/#API","page":"Types","title":"API","text":"","category":"section"},{"location":"types/#Type-definitions","page":"Types","title":"Type definitions","text":"","category":"section"},{"location":"types/","page":"Types","title":"Types","text":"PeriodicVertex\nPeriodicEdge\nPeriodicGraph\nPeriodicGraph{N}(nv::Integer=0) where N\nPeriodicGraph(nv::Integer, edge_list::AbstractVector{PeriodicEdge{N}}) where N\nPeriodicGraph{N}(s::AbstractString) where N\nBase.parse(::Type{PeriodicGraph{N}}, s::AbstractString) where N","category":"page"},{"location":"types/#PeriodicGraphs.PeriodicVertex","page":"Types","title":"PeriodicGraphs.PeriodicVertex","text":"PeriodicVertex{N}\n\nVertex type for an N-periodic graph.\n\nA vertex is uniquely determined by the identifier of its representative in the a fixed initial cell, and the offset of the cell containing the vertex compared to the the initial cell. Vertex identifiers start at 1.\n\n\n\n\n\n","category":"type"},{"location":"types/#PeriodicGraphs.PeriodicEdge","page":"Types","title":"PeriodicGraphs.PeriodicEdge","text":"PeriodicEdge{N} <: Graphs.SimpleGraphs.AbstractSimpleEdge{Int}\n\nEdge type for an N-periodic graph.\n\nAn edge is uniquely determined by the vertex identifiers of its source and destination, and the cell offset between the source vertex and the destination vertex.\n\n\n\n\n\n","category":"type"},{"location":"types/#PeriodicGraphs.PeriodicGraph","page":"Types","title":"PeriodicGraphs.PeriodicGraph","text":"PeriodicGraph{N} <: AbstractGraph{Int}\n\nType representing an undirected N-periodic graph.\n\n\n\n\n\n","category":"type"},{"location":"types/#PeriodicGraphs.PeriodicGraph-Union{Tuple{}, Tuple{Integer}, Tuple{N}} where N","page":"Types","title":"PeriodicGraphs.PeriodicGraph","text":"PeriodicGraph{N}(nv::Integer=0)\n\nConstruct a PeriodicGraph{N} with nv vertices and 0 edge.\n\n\n\n\n\n","category":"method"},{"location":"types/#PeriodicGraphs.PeriodicGraph-Union{Tuple{N}, Tuple{Integer, AbstractArray{PeriodicEdge{N}, 1}}} where N","page":"Types","title":"PeriodicGraphs.PeriodicGraph","text":"PeriodicGraph([nv::Integer, ]edge_list::AbstractVector{PeriodicEdge{N}})\nPeriodicGraph{N}([nv::Integer, ]edge_list::AbstractVector{PeriodicEdge{N}})\n\nConstruct a PeriodicGraph{N} from a vector of edges. If nv is unspecified, the number of vertices is the highest that is used in an edge in edge_list.\n\nImplementation Notes\n\nThis constructor works the fastest when edge_list is sorted by the lexical ordering and does not contain any duplicates.\n\nExamples\n\njulia> el = PeriodicEdge2D[(1, 1, (1,0)), (1, 3, (0,1)), (3, 1, (0,-1))];\n\njulia> g = PeriodicGraph(el)\nPeriodicGraph2D(3, PeriodicEdge2D[(1, 1, (1,0)), (1, 3, (0,1))])\n\njulia> ne(g)\n2\n\n\n\n\n\n","category":"method"},{"location":"types/#PeriodicGraphs.PeriodicGraph-Union{Tuple{AbstractString}, Tuple{N}} where N","page":"Types","title":"PeriodicGraphs.PeriodicGraph","text":"PeriodicGraph(key::AbstractString)\nPeriodicGraph{N}(key::AbstractString)\n\nConstruct a PeriodicGraph{N} from a key, which is a string of whitespace-separated values of the form \"N src1 dst1 ofs1_1 ofs1_2 ... ofs1_N src2 dst2 ofs2_1 ofs2_2 ... ofs2_N ... srcm dstm ofsm_1 ofsm_2 ... ofsm_N\" where N is the number of repeating dimensions of the graph, m is the number of edges and for all i between 1 and m, the number of edges, the i-th edge is described as\n\nsrci, the vertex identifier of the source vertex,\ndsti, the vertex identifier of the destination vertex and\n(ofsi_1, ofsi_2, ..., ofsi_N) the offset of the edge.\n\nThis compact representation of a graph can be obtained simply by printing the graph or with string.\n\nnote: Note\nUse parse(PeriodicGraph, key) or parse(PeriodicGraph{N}, key) for a faster implementation if key was obtained from string(g) with g a PeriodicGraph{N}.\n\nExamples\n\njulia> PeriodicGraph(\"2 1 2 0 0 2 1 1 0 1 1 0 -1\")\nPeriodicGraph2D(2, PeriodicEdge2D[(1, 1, (0,1)), (1, 2, (-1,0)), (1, 2, (0,0))])\n\njulia> PeriodicGraph3D(\"3 1 1 0 0 1 1 1 0 1 0 1 1 1 0 0\")\nPeriodicGraph3D(1, PeriodicEdge3D[(1, 1, (0,0,1)), (1, 1, (0,1,0)), (1, 1, (1,0,0))])\n\njulia> string(ans)\n\"3 1 1 0 0 1 1 1 0 1 0 1 1 1 0 0\"\n\njulia> string(parse(PeriodicGraph3D, ans)) == ans\ntrue\n\n\n\n\n\n","category":"method"},{"location":"types/#Base.parse-Union{Tuple{N}, Tuple{Type{PeriodicGraph{N}}, AbstractString}} where N","page":"Types","title":"Base.parse","text":"parse(::Type{PeriodicGraph}, key::AbstractString)\nparse(::Type{PeriodicGraph{N}}, key::AbstractString)\n\nParse a string representation of a PeriodicGraph back to a PeriodicGraph.\n\nSee PeriodicGraph(key::AbstractString) or PeriodicGraph{N}(key::AbstractString) for details on the string representations of a PeriodicGraph.\n\nwarning: Warning\nThis function assumes that the string is a valid representation of a PeriodicGraph with all its edges direct, sorted in lexicographical order and unique, as obtained from string(g) or print(g) where g is a PeriodicGraph. No check is performed to ensure this condition.If the input string may not obey these conditions, use PeriodicGraph(key) or PeriodicGraph{N}(key) instead.\n\n\n\n\n\n","category":"method"},{"location":"types/#Other-basic-functions","page":"Types","title":"Other basic functions","text":"","category":"section"},{"location":"types/","page":"Types","title":"Types","text":"isdirectedge\ndirectedge\nPeriodicGraphs.unsafe_edge\nPeriodicGraphs.LoopException","category":"page"},{"location":"types/#PeriodicGraphs.isdirectedge","page":"Types","title":"PeriodicGraphs.isdirectedge","text":"isdirectedge(e::PeriodicEdge)\n\nReturn true if e is direct, in the sense being of the form (u, v, ofs) with either u < v or u == v && ofs > zero(ofs).\n\nAn edge e is indirect iff reverse(e) is not.\n\nExamples\n\njulia> isdirectedge(PeriodicEdge1D(3, 4, (0,)))\ntrue\n\njulia> isdirectedge(PeriodicEdge2D(5, 2, (0,0)))\nfalse\n\njulia> isdirectedge(PeriodicEdge3D(3, 3, (0,-1,2)))\nfalse\n\nSee also directedge\n\n\n\n\n\n","category":"function"},{"location":"types/#PeriodicGraphs.directedge","page":"Types","title":"PeriodicGraphs.directedge","text":"directedge(e::PeriodicEdge{D}) where D\ndirectedge(src::PeriodicVertex{D}, dst::PeriodicVertex{D}) where D\ndirectedge(src, dst, ofs::Union{SVector{D,T},NTuple{D,T}}) where {D,T}\n\nReturn the direct edge corresponding to e = PeriodicEdge{D}(src, dst), i.e. e itself if e is direct, or reverse(e) otherwise.\n\nExamples\n\njulia> directedge(PeriodicEdge1D(3, 4, (0,)))\nPeriodicEdge1D(3, 4, (0,))\n\njulia> directedge(PeriodicEdge2D(5, 2, (0,0)))\nPeriodicEdge2D(2, 5, (0,0))\n\njulia> directedge(PeriodicEdge3D(3, 3, (0,-1,2)))\nPeriodicEdge3D(3, 3, (0,1,-2))\n\nSee also isdirectedge\n\n\n\n\n\n","category":"function"},{"location":"types/#PeriodicGraphs.unsafe_edge","page":"Types","title":"PeriodicGraphs.unsafe_edge","text":"unsafe_edge{N}\n\nInternal constructor for PeriodicEdge{N} that bypasses the loop check.\n\n\n\n\n\n","category":"type"},{"location":"types/#PeriodicGraphs.LoopException","page":"Types","title":"PeriodicGraphs.LoopException","text":"LoopException <: Exception\n\nError type for constructing an invalid PeriodicEdge{N} of the form (u, u, zeros(Int,N)). Loops are not expected in the algorithms implemented in PeriodicGraphs.jl. If you still want to construct them, use the unsafe_edge{N} constructor instead of PeriodicEdge{N}.\n\n\n\n\n\n","category":"type"},{"location":"neighborhood/#Neighborhoods-and-graph-traversals","page":"Neighborhood","title":"Neighborhoods and graph traversals","text":"","category":"section"},{"location":"neighborhood/#Manual","page":"Neighborhood","title":"Manual","text":"","category":"section"},{"location":"neighborhood/","page":"Neighborhood","title":"Neighborhood","text":"The AbstractGraph API for exploring neighbors and traversing graphs has to be somewhat adapted to account for the specific aspects of PeriodicGraphs. Here, we present a list of notes relative to these aspects, where g is a PeriodicGraph{N}:","category":"page"},{"location":"neighborhood/","page":"Neighborhood","title":"Neighborhood","text":"neighbors(g, i) where i::Integer is the list of neighbors of PeriodicVertex{N}(i). Performance-wise, this operation is a simple access on the underlying structure of g so it is very fast, but the returned Vector{PeriodicVertex{N}} should not be modified.\nneighbors(g, x) where x::PeriodicVertex{N} is an iterator over the neighbors of x but not an array. The iterator object is a PeriodicGraphs.OffsetVertexIterator.\nedges(g) is an iterator over the direct edges of g. Every edge representative will thus be visited exactly once. It is invalidated by any change to g, so g should not be modified while iterating over edges(g). The iterator object is a PeriodicGraphs.PeriodicEdgeIter.\nGraphs._neighborhood has a specialization for PeriodicGraph if required.","category":"page"},{"location":"neighborhood/","page":"Neighborhood","title":"Neighborhood","text":"A typical BFS algorithm on g can be implemented like so:","category":"page"},{"location":"neighborhood/","page":"Neighborhood","title":"Neighborhood","text":"function bfs(g::PeriodicGraph{N}, starting_vertex, depth) where N\n visited = Set{PeriodicVertex{N}}(starting_vertex)\n Q = Tuple{Int,PeriodicVertex{N}}[(0, starting_vertex)]\n for (distance, u) in Q\n distance > depth && break\n # do stuff with u\n for x in neighbors(g, u)\n x ∈ visited && continue\n push!(x, visited)\n # do stuff with x\n push!(Q, (distance+1, x))\n end\n # do more stuff\n end\n # return something\nend","category":"page"},{"location":"neighborhood/","page":"Neighborhood","title":"Neighborhood","text":"In some cases however, the Set-interface can end up being the bottleneck. In this kind of situation, it may be better to:","category":"page"},{"location":"neighborhood/","page":"Neighborhood","title":"Neighborhood","text":"replace the initialization of visited by\nwidth = PeriodicGraphs.graph_width!(g)\nseen_size = nv(g)*(2*(1 + fld(depth-1, width)) + 1)^N\nvisited = falses(seen_size)\nreplace x ∈ visited by visited[hash_position(x, g)] and\nreplace push!(x, visited) by visited[hash_position(x, g)] = true","category":"page"},{"location":"neighborhood/","page":"Neighborhood","title":"Neighborhood","text":"although some care should be taken since PeriodicGraphs.graph_width! is only a heuristic.","category":"page"},{"location":"neighborhood/","page":"Neighborhood","title":"Neighborhood","text":"Such algorithms can be used to compute the topological invariants like coordination_sequence for example.","category":"page"},{"location":"neighborhood/#API","page":"Neighborhood","title":"API","text":"","category":"section"},{"location":"neighborhood/","page":"Neighborhood","title":"Neighborhood","text":"PeriodicGraphs.PeriodicEdgeIter\nPeriodicGraphs.OffsetVertexIterator\nPeriodicGraphs.graph_width!","category":"page"},{"location":"neighborhood/#PeriodicGraphs.PeriodicEdgeIter","page":"Neighborhood","title":"PeriodicGraphs.PeriodicEdgeIter","text":"PeriodicEdgeIter{N} <: AbstractEdgeIter\n\nEdge iterator type for undirected N-periodic graphs.\n\nThe iterator only yields edges in the form (u, v, ofs) with either u < v or u == v && ofs > zero(ofs). This is possible because PeriodicGraphs are undirected, hence to each edge (u, v, ofs) in the graph corresponds its reverse edge (v, u, .-ofs). The iterator thus yields each edge of the graph exactly once.\n\n\n\n\n\n","category":"type"},{"location":"neighborhood/#PeriodicGraphs.OffsetVertexIterator","page":"Neighborhood","title":"PeriodicGraphs.OffsetVertexIterator","text":"OffsetVertexIterator{D} <: AbstractVector{PeriodicVertex{D}}\nOffsetVertexIterator(ofs::SVector{D,Int}, list::AbstractVector{PeriodicVertex{D}}) where D\n\nIterator type that yields the sequence of PeriodicVertex in list, each offset by the input ofs.\n\n\n\n\n\n","category":"type"},{"location":"neighborhood/#PeriodicGraphs.graph_width!","page":"Neighborhood","title":"PeriodicGraphs.graph_width!","text":"graph_width!(g::PeriodicGraph{N}) where N\n\nSet the width internal field of the graph so that the for most n ∈ N*, the n-th neighbor of any vertex v of the initial cell is in a cell (i_1, i_2, ..., i_N) such that max(abs.((i_1, i_2, ..., i_N))) ≤ 1 + fld((n - 1), width). Return the new width.\n\nThis function is only a heuristic, it may produce a width that does not satisfy the condition.\n\nThis function returns the current width if it is not equal to -1 (internal value used to mark an unset width). If you decide to modify the other internal fields of g, it is probably a good idea to do g.width[] = -1 so that this function gets automatically called when needed, unless you are sure the width will not be affected by your change.\n\n\n\n\n\n","category":"function"},{"location":"rings/#Ring-statistics","page":"Rings","title":"Ring statistics","text":"","category":"section"},{"location":"rings/#Definitions","page":"Rings","title":"Definitions","text":"","category":"section"},{"location":"rings/","page":"Rings","title":"Rings","text":"In this section, we use the terminology recommended by Blatov, O’Keeffe and Proserpio. In particular:","category":"page"},{"location":"rings/","page":"Rings","title":"Rings","text":"a cycle is a sequence of vertices v₁, v₂, ..., vₙ such that for all i between 2 and n, vᵢ₋₁ and vᵢ are neighbors, as well as v₁ and vₙ, and no vᵢ occurs more than once in the sequence. It can be equivalently represented by the sequence of edges between two consecutive vertices and between v₁ and vₙ.\nthe sum of two or more cycles is the set of edges occurring only an odd number of times in the set of input cycles. The sum of two cycles is thus the symmetric difference of their edges. Note that the sum of cycles may be empty, or may be the juxtaposition of several edge-disjoint cycles.\nthe length of a cycle is its number of edges. It is also equal to its number of vertices since no vertex is repeated in the sequence. A cycle a is strictly smaller than another b when the length of a is strictly lower than that of b.\na ring is a cycle which is not the sum of two strictly smaller cycles. An equivalent definition is that a ring is a cycle which does not admit a short-circuit: between two vertices of the ring, there is no path of the graph strictly smaller than both branches of the ring linking the two vertices.\na strong ring is a cycle which is not the sum of any number of strictly smaller cycles.","category":"page"},{"location":"rings/#Manual","page":"Rings","title":"Manual","text":"","category":"section"},{"location":"rings/","page":"Rings","title":"Rings","text":"PeriodicGraphs.jl provides an algorithm for the determination of all rings and strong rings up to a given size in a PeriodicGraph. It can also be used on finite graphs by converting them to PeriodicGraph{0}, although the code is not optimized for this case.","category":"page"},{"location":"rings/","page":"Rings","title":"Rings","text":"The rings (respectively strong_rings) function returns the list of all rings (respectively strong rings) in the graph up to a given size:","category":"page"},{"location":"rings/","page":"Rings","title":"Rings","text":"rings\nstrong_rings","category":"page"},{"location":"rings/#PeriodicGraphs.rings","page":"Rings","title":"PeriodicGraphs.rings","text":"rings(g::PeriodicGraph{D}, [depth::Integer=15,] symmetries::AbstractSymmetryGroup=NoSymmetryGroup(g), dist::DistanceRecord=DistanceRecord(g,depth)) where D\n\nCompute the list of rings in g, up to length 2*depth+3. Return the list of Vector{Int} where each sublist is a ring whose vertices are the reverse_hash_positions of the sublist elements. Also return an AbstractSymmetryGroup acting on the returned rings.\n\nA ring is a cycle of the graph for which there is no shortcut, i.e. no path in the graph between two vertices of the cycle that is shorter than either path connecting the vertices in the cycle.\n\nIf provided, symmetries should represent the symmetries of the graph as a AbstractSymmetryGroup object respecting its documented interface.\n\nA PeriodicGraphs.DistanceRecord dist can be optionally provided to track the distances between pairs of vertices in the graph.\n\n\n\n\n\n","category":"function"},{"location":"rings/#PeriodicGraphs.strong_rings","page":"Rings","title":"PeriodicGraphs.strong_rings","text":"strong_rings([rs::Vector{Vector{Int}},] g::PeriodicGraph{D}, [depth::Integer=15,] symmetries::AbstractSymmetryGroup=NoSymmetryGroup(g), dist::DistanceRecord=DistanceRecord(g,depth)) where D\n\nCompute the list of strong rings in g, up to length 2*depth+3. Return them with their symmetry group. Each ring is represented by the list of hash_position of its vertices.\n\nThe optional first argument rs is the list of rings which can be provided if previously computed.\n\nSee rings for the meaning of the other arguments.\n\nA strong ring is a cycle of the graph which cannot be decomposed into a sum of any number of smaller cycles. By comparison, a ring is a cycle which cannot be decomposed into a sum of two smaller cycles. In particular, all strong rings are rings.\n\nSee also strong_erings to obtain the rings as a list of integers representing the edges of the ring, instead of a list of integers representing its vertices.\n\n\n\n\n\n","category":"function"},{"location":"rings/","page":"Rings","title":"Rings","text":"A few notes on the output:","category":"page"},{"location":"rings/","page":"Rings","title":"Rings","text":"The output is a pair (rs, symm) where rs is the list of rings (respectively strong rings) and symm is an AbstractSymmetryGroup which contains symmetries of rs. symm is always a NoSymmetryGroup if the optional argument symmetries is not provided.\nThe returned list of rings rs is generally unsorted.\nAll translations of the same ring are represented by a unique ring, which means that a ring crossing through different unit cells will only appear once in the list, even though it may appear several times in a single unit cell.\nThe symmetries optional argument reduces the computational cost of the algorithm. The output lists rs with and without the optional argument are identical except for the order of their elements.","category":"page"},{"location":"rings/","page":"Rings","title":"Rings","text":"The optional argument depth defaults to 15, which means that rings containing up to 33 edges will be considered. This default value is chosen to accomodate the vast majority of periodic nets encountered as crystal nets, for which the ring size rarely exceeds 20.","category":"page"},{"location":"rings/","page":"Rings","title":"Rings","text":"Let's take as example an aperiodic graph representing a small house, made of a cube with a pyramid on top:","category":"page"},{"location":"rings/","page":"Rings","title":"Rings","text":"julia> house = PeriodicGraph{0}(\"0 \"*\n \"1 2 2 3 3 4 4 1 \"* # square base of the house\n \"1 5 2 6 3 7 4 8 \"* # 4 vertical pillars\n \"5 6 6 7 7 8 8 5 \"* # square ceiling\n \"5 9 6 9 7 9 8 9 \" # pyramidal roof\n );\n\njulia> sort!(first(rings(house)))\n14-element Vector{Vector{Int64}}:\n [1, 2, 3, 4]\n [1, 2, 3, 7, 8, 5]\n [1, 2, 6, 5]\n [1, 2, 6, 7, 8, 4]\n [1, 4, 3, 7, 6, 5]\n [1, 4, 8, 5]\n [2, 3, 4, 8, 5, 6]\n [2, 3, 7, 6]\n [3, 4, 8, 7]\n [5, 6, 7, 8]\n [5, 6, 9]\n [5, 8, 9]\n [6, 7, 9]\n [7, 8, 9]\n\njulia> sort!(first(strong_rings(house)))\n9-element Vector{Vector{Int64}}:\n [1, 2, 3, 4]\n [1, 2, 6, 5]\n [1, 4, 8, 5]\n [2, 3, 7, 6]\n [3, 4, 8, 7]\n [5, 6, 9]\n [5, 8, 9]\n [6, 7, 9]\n [7, 8, 9]","category":"page"},{"location":"rings/","page":"Rings","title":"Rings","text":"We can see that the house has four weak rings of size 6, six rings of size 4 among which five are strong, and four strong rings of size 3.","category":"page"},{"location":"rings/","page":"Rings","title":"Rings","text":"The strong rings are the faces of the house: there are four triangles that make the roof, four squares that make the walls and one last square for the base of the house. The square corresponding to the ceiling is actually the sum of the four triangles of the roof, which is why it is not a strong ring. The four weak rings of size 6 are those that go through each vertex of the cube except for one of the four opposite pairs.","category":"page"},{"location":"rings/","page":"Rings","title":"Rings","text":"To explore the ring distributions around individual vertices, the RingAttributions struct factors the ring distribution by vertex. The list of rings including a particular vertex is factored into a RingIncluding struct:","category":"page"},{"location":"rings/","page":"Rings","title":"Rings","text":"RingAttributions\nRingIncluding","category":"page"},{"location":"rings/#PeriodicGraphs.RingAttributions","page":"Rings","title":"PeriodicGraphs.RingAttributions","text":"RingAttributions{D} <: AbstractVector{RingIncluding{D}}\n\nRepresent a set of rings of a PeriodicGraph{D}.\n\nFor ra of type RingAttributions{D}, ra[i] is a RingIncluding{D} object representing the set of rings including PeriodicVertex{D}(i).\n\n\n\n\n\n","category":"type"},{"location":"rings/#PeriodicGraphs.RingIncluding","page":"Rings","title":"PeriodicGraphs.RingIncluding","text":"RingIncluding{D} <: AbstractVector{OffsetVertexIterator{D}}\n\nThe list of rings of a PeriodicGraph{D} including a particular vertex PeriodicVertex{D}(i).\n\nThe object is iterable and indexable by an integer: for ri of type RingIncluding{D}, ri[j] is an iterable over the vertices of the j-th ring including vertex i.\n\n\n\n\n\n","category":"type"},{"location":"rings/","page":"Rings","title":"Rings","text":"To avoid useless computations, the lists of rings and the rings themselves are returned as iterables instead of Vector{PeriodicVertex{N}} and such, so they should be collected if required.","category":"page"},{"location":"rings/","page":"Rings","title":"Rings","text":"Let's look all the rings on our little house:","category":"page"},{"location":"rings/","page":"Rings","title":"Rings","text":"julia> ras = RingAttributions(house)\nRingAttributions{0}(rings per node: [6, 6, 6, 6, 8, 8, 8, 8, 4])\n\njulia> roofpeak = ras[9] # the list of rings including the top of the roof\n4-element RingIncluding{0}:\n [5, 8, 9]\n [5, 6, 9]\n [7, 8, 9]\n [6, 7, 9]\n\njulia> roofpeak[2] # the second ring including the top of the roof\n3-element PeriodicGraphs.OffsetVertexIterator{0}:\n 5\n 6\n 9\n\njulia> rasstrong = RingAttributions(house, true)\nRingAttributions{0}(rings per node: [3, 3, 3, 3, 4, 4, 4, 4, 4])\n\njulia> rasstrong[1] # the base and two walls make the strong rings around vertex 1\n3-element RingIncluding{0}:\n [1, 2, 6, 5]\n [1, 4, 8, 5]\n [1, 2, 3, 4]\n\njulia> collect(rasstrong[5]) # two rooftiles and two walls make the strong rings around vertex 5\n4-element Vector{PeriodicGraphs.OffsetVertexIterator{0}}:\n [5, 8, 9]\n [5, 6, 9]\n [1, 2, 6, 5]\n [1, 4, 8, 5]","category":"page"},{"location":"rings/#Internal-API","page":"Rings","title":"Internal API","text":"","category":"section"},{"location":"rings/","page":"Rings","title":"Rings","text":"Here is a collection of internal utilities used for the algorithms of rings and strong_rings:","category":"page"},{"location":"rings/","page":"Rings","title":"Rings","text":"PeriodicGraphs.ConstMiniBitSet\nPeriodicGraphs.DistanceRecord\nPeriodicGraphs.JunctionNode\nPeriodicGraphs.PhantomJunctionNode\nPeriodicGraphs.arcs_list\nPeriodicGraphs.RingsEndingAt\nPeriodicGraphs.normalize_cycle!\nPeriodicGraphs.symdiff_cycles!\nPeriodicGraphs.symdiff_cycles\nPeriodicGraphs.IterativeGaussianElimination\nPeriodicGraphs.gaussian_elimination!\nPeriodicGraphs.gaussian_elimination\nPeriodicGraphs.intersect_cycles!\nPeriodicGraphs.intersect_cycles\nPeriodicGraphs.union_cycles!\nPeriodicGraphs.union_cycles\nPeriodicGraphs.retrieve_track!\nPeriodicGraphs.rings_around\nPeriodicGraphs.EdgeDict\nstrong_erings\nPeriodicGraphs.convert_to_ering!\nPeriodicGraphs.convert_to_ering","category":"page"},{"location":"rings/#PeriodicGraphs.ConstMiniBitSet","page":"Rings","title":"PeriodicGraphs.ConstMiniBitSet","text":"ConstMiniBitSet{T} <: AbstractSet{Int}\n\nFixed-size bitset stored on a single word of type T, typically a UInt64 or a UInt32.\n\n\n\n\n\n","category":"type"},{"location":"rings/#PeriodicGraphs.DistanceRecord","page":"Rings","title":"PeriodicGraphs.DistanceRecord","text":"DistanceRecord{D}\n\nRecord of the computed distances between vertices of a graph.\n\n\n\n\n\n","category":"type"},{"location":"rings/#PeriodicGraphs.JunctionNode","page":"Rings","title":"PeriodicGraphs.JunctionNode","text":"JunctionNode{T}\n\nElement of the DAG representing the set of arcs linking each vertex x to a fixed vertex i of graph g. Each JunctionNode contains information on the arcs passing through a particular vertex x:\n\nnum is the length of the shortest path between x and i. Since we only collect rings, only the shortest paths are of interest, as well as the path of length num+1 which may form an odd-length ring when combined with a shortest path.\nheads is a list of neighbors of x such that the lastshort first are at distance num - 1 from i, and the rest are at distance num and have a lower value than x.\nshortroots is the set of roots reachable on a shortest path from x to i. A root is the neighbor of i on that path, a.k.a. the second-to-last vertex on that path.\nlongroots is the set of roots reachable on a path of length num+1 from x to i.\n\n\n\n\n\n","category":"type"},{"location":"rings/#PeriodicGraphs.PhantomJunctionNode","page":"Rings","title":"PeriodicGraphs.PhantomJunctionNode","text":"PhantomJunctionNode{D}\n\nElement of the phantom DAG.\n\nSimilarly to the DAG of JunctionNode, the phantom DAG tracks arcs linking vertices x to a fixed vertex i, except that the vertices x are those that should be ignored in the returned list of rings. Thus, only the shortest distance between x and i needs to be recorded, since the arcs themselves will be discarded eventually.\n\n\n\n\n\n","category":"type"},{"location":"rings/#PeriodicGraphs.arcs_list","page":"Rings","title":"PeriodicGraphs.arcs_list","text":"arcs_list(g::PeriodicGraph{D}, i, depth::T, ringavoid=nothing, cycleavoid=nothing) where {D,T}\n\nCompute the list of shortest arcs starting from vertex i up to length depth+1. Vertices in ringavoid are not included in the returned arcs, but considered still part of the graph for distance computations. Vertices in cycleavoid are considered removed from the graph completely.\n\nReturn (dag, vertexnums) where dag is a Vector{JunctionNode{T}} representing, for each visited node, the DAG of all arcs from that node back to i, in a compact representation. vertexnums is a Vector{PeriodicVertex{D}} whose k-th value is the vertex represented by number k in dag.\n\nIf ringavoid !== nothing, dag will also not include arcs that pass through nodes of the form PeriodicVertex{D}(j, ofs) with j == i and ofs < zero(SVector{Int,D}): this allows eagerly pruning cycles that are translations of others. Note that this can result in missing cycles if those pass through at least three nodes with j == i, but that situation should be exceptionally rare.\n\nnote: Note\nThe type T of depth is used as type parameter to the JunctionNode, just to avoid having a dedicated argument (since depth should be at most 62 for the rest of the algorithm to work). This size controls the maximal degree a vertex of g should have : for example, T == UInt32 indicates that all vertices must have degree at most 31.\n\n\n\n\n\n","category":"function"},{"location":"rings/#PeriodicGraphs.RingsEndingAt","page":"Rings","title":"PeriodicGraphs.RingsEndingAt","text":"RingsEndingAt(dag, midnode, record)\n\nIterable over the rings of graph g around node i with midnode as vertex furthest from i. If there are two such vertices (odd ring), midnode is the higher of the two.\n\nrecord should be set to (dist, vertexnums) where dist == DistanceRecord(g, depth) and dag, vertexnums == first(arcs_list(g, i, depth, ...)), otherwise the iterator will return many more cycles that may not be rings.\n\nwarning: Warning\nIn order to efficiently cycle through the rings, the iterator reuses a buffer on which the rings are written. This means that performing an iteration will change the value of the previously returned result: for example, collect(RingsEndingAt(...)) will yield a list containing the same sublist (unlikely to be an actual ring) repeated over. To actually obtain the list of rings, copy the result as they arrive by doing map(copy, RingsEndingAt(...)) or [copy(x) for x in RingsEndingAt(...)] for example.This also means that the list returned at each iteration should never be modified directly: copy it before.\n\n\n\n\n\n","category":"type"},{"location":"rings/#PeriodicGraphs.normalize_cycle!","page":"Rings","title":"PeriodicGraphs.normalize_cycle!","text":"normalize_cycle!(cycle::Vector{Int}, n, v::Val{D}) where D\n\nIn-place rotate and possibly reverse cycle, a Vector{Int} whose elements are the hash_position of vertices of g so that the result is the same for all such vectors that represent the same cycle, possibly translated to a different unit cell or rotated.\n\nThe graph g::PeriodicGraph{D} is represented as n = nv(g) and v = Val(D)\n\n\n\n\n\n","category":"function"},{"location":"rings/#PeriodicGraphs.symdiff_cycles!","page":"Rings","title":"PeriodicGraphs.symdiff_cycles!","text":"symdiff_cycles!(c::Vector{T}, a::Vector{T}, b::Vector{T}) where T\n\nLike PeriodicGraphs.symdiff_cycles but stores the result in c.\n\nc will be resized accordingly so its initial length does not matter.\n\n\n\n\n\n","category":"function"},{"location":"rings/#PeriodicGraphs.symdiff_cycles","page":"Rings","title":"PeriodicGraphs.symdiff_cycles","text":"symdiff_cycles(a, b)\n\nSymmetric difference between two sorted lists a and b. Return the sorted list of elements belonging to a or to b but not to both.\n\nUse PeriodicGraphs.symdiff_cycles! to provide a pre-allocated destination.\n\nExample\n\njulia> PeriodicGraphs.symdiff_cycles([3,4,5], [4,5,6])\n2-element Vector{Int64}:\n 3\n 6\n\n\n\n\n\n","category":"function"},{"location":"rings/#PeriodicGraphs.IterativeGaussianElimination","page":"Rings","title":"PeriodicGraphs.IterativeGaussianElimination","text":"IterativeGaussianElimination{T}\n\nStruct containing the list of sparse columns of the matrix under gaussian elimination on the 𝔽₂ finite field.\n\nTo be used with PeriodicGraphs.gaussian_elimination! as one of the three concrete types:\n\nPeriodicGraphs.IterativeGaussianEliminationNone for simple gaussian elimination,\nPeriodicGraphs.IterativeGaussianEliminationLength to detect when a new column can be expressed as a sum of strictly smaller columns of the matrix.\nPeriodicGraphs.IterativeGaussianEliminationDecomposition to detect when a new column can be expressed as a sum of other columns of the matrix and keep track of which.\n\n\n\n\n\n","category":"type"},{"location":"rings/#PeriodicGraphs.gaussian_elimination!","page":"Rings","title":"PeriodicGraphs.gaussian_elimination!","text":"gaussian_elimination!(gauss::IterativeGaussianElimination, r::Vector{Int})\n\nTest whether r can be expressed as a sum of vectors stored in gauss, and store r if not. \"sum\" refers to the symmetric difference of boolean vectors, represented in sparse format as the ordered list of non-zero indices.\n\nIf gauss isa IterativeGaussianEliminationLength, return whether r can be expressed as a sum of strictly smaller vectors.\n\nOtherwise, return true when r is a sum of any previously encoutered vectors. If gauss isa IterativeGaussianEliminationDecomposition, query retrieve_track(gauss) to obtain the sorted list of indices of such previously encountered vectors.\n\nSee also gaussian_elimination to test r without storing it.\n\n\n\n\n\n","category":"function"},{"location":"rings/#PeriodicGraphs.gaussian_elimination","page":"Rings","title":"PeriodicGraphs.gaussian_elimination","text":"gaussian_elimination(gauss::IterativeGaussianElimination, r::Vector{Int})\n\nReturn notindependent, info where notindependent is true if r can be expressed as a sum of vectors stored in gauss.\n\nSee PeriodicGraphs.gaussian_elimination! to store r in gauss if not, and for more details dependending on the type of gauss.\n\nCall PeriodicGraphs.gaussian_elimination!(gauss, r, notindependent, info) to obtain the result of PeriodicGraphs.gaussian_elimination!(gauss, r) without duplicating computation.\n\n\n\n\n\n","category":"function"},{"location":"rings/#PeriodicGraphs.intersect_cycles!","page":"Rings","title":"PeriodicGraphs.intersect_cycles!","text":"intersect_cycles!(c::Vector{T}, a::Vector{T}, b::Vector{T}) where T\n\nLike PeriodicGraphs.intersect_cycles but stores the result in c.\n\nc will be resized accordingly so its initial length does not matter as long as it is at least as large as the resulting list.\n\n\n\n\n\n","category":"function"},{"location":"rings/#PeriodicGraphs.intersect_cycles","page":"Rings","title":"PeriodicGraphs.intersect_cycles","text":"intersect_cycles(a, b)\n\nIntersection between two sorted lists a and b. Return the sorted list of elements belonging to both a and b.\n\nUse PeriodicGraphs.intersect_cycles! to provide a pre-allocated destination.\n\nExample\n\njulia> PeriodicGraphs.intersect_cycles([3,4,5], [4,5,6])\n2-element Vector{Int64}:\n 4\n 5\n\n\n\n\n\n","category":"function"},{"location":"rings/#PeriodicGraphs.union_cycles!","page":"Rings","title":"PeriodicGraphs.union_cycles!","text":"union_cycles!(c::Vector{T}, a::Vector{T}, b::Vector{T}) where T\n\nLike PeriodicGraphs.union_cycles but stores the result in c.\n\nc will be resized accordingly so its initial length does not matter as long as it is at least as large as the resulting list.\n\n\n\n\n\n","category":"function"},{"location":"rings/#PeriodicGraphs.union_cycles","page":"Rings","title":"PeriodicGraphs.union_cycles","text":"union_cycles(a, b)\n\nUnion between two sorted lists a and b. Return the sorted list of elements belonging to a or b or both.\n\nUse PeriodicGraphs.union_cycles! to provide a pre-allocated destination.\n\nExample\n\njulia> PeriodicGraphs.union_cycles([3,4,5], [4,5,6])\n4-element Vector{Int64}:\n 3\n 4\n 5\n 6\n\n\n\n\n\n","category":"function"},{"location":"rings/#PeriodicGraphs.retrieve_track!","page":"Rings","title":"PeriodicGraphs.retrieve_track!","text":"retrieve_track!([ret::Vector{Int32}, buffer::Vector{Int32},] gauss::IterativeGaussianEliminationDecomposition)\n\nTo be called consecutive to a call to gaussian_elimination!(gauss, x) that returned true. In that case, x was found to be the sum of previously encountered vectors: return the (reverse-sorted) list of their indices.\n\nwarning: Warning\nCalling retrieve_track! after a call to gaussian_elimination! that returned false will produce an invalid result. Calling it twice will also produce an invalid result.\n\n\n\n\n\n","category":"function"},{"location":"rings/#PeriodicGraphs.rings_around","page":"Rings","title":"PeriodicGraphs.rings_around","text":"rings_around(g::PeriodicGraph{D}, i, depth=15, dist::DistanceRecord=DistanceRecord(g,depth), visited=nothing) where D\n\nReturn the list of all rings around node i in graph g up to length 2*depth+3.\n\nThe returned rings are the list of hash_position of the corresponding vertices. To get back the list of actual PeriodicVertex of a returned ring in the list, do\n\n[reverse_hash_position(x, g) for x in ring]\n\nIf the offsets of the corresponding vertices are not needed, simply do\n\n[mod1(x, n) for x in ring] # n should be nv(g)\n\nvisited is interpreted as the ringavoid argument of arcs_list unless dist === nothing, in which case it is interpreted as the cycleavoid argument. In particular, unless dist === nothing, only one ring will appear in the list even if some of its translated images also pass through PeriodicVertex{D}(i).\n\n\n\n\n\n","category":"function"},{"location":"rings/#PeriodicGraphs.EdgeDict","page":"Rings","title":"PeriodicGraphs.EdgeDict","text":"EdgeDict{D}\n\nMap from pairs of PeriodicVertex{D} to the identifier of the corresponding edge.\n\nkp::EdgeDict{D} should be queried by either get!(kp, minmax(v1, v2)) where v1 and v2 are PeriodicVertex{D} to obtain the identifier of the edge and store a new identifier if absent, or by kp[i] where i is an Integer to obtain the pair of vertices corresponding to identifier i.\n\nkp is built by calling EdgeDict(g) where g is a PeriodicGraph.\n\n\n\n\n\n","category":"type"},{"location":"rings/#PeriodicGraphs.strong_erings","page":"Rings","title":"PeriodicGraphs.strong_erings","text":"strong_erings([rs::Vector{Vector{Int}},], g::PeriodicGraph{D}, [depth=15,] ringsymms::AbstractSymmetryGroup=NoSymmetryGroup(length(rs))) where D\n\nCompute the list of strong edge rings in g, up to length 2*depth+3. See strong_rings and rings for the meaning of the optional arguments.\n\nReturn a quadruplet of values:\n\nthe two first values are the list of rings and their symmetry group, identical to the result of strong_rings, unless rs is provided (see below).\nthe third is the list of edge rings: each edge of the periodic graph is mapped to an integer and each ring is represented by the sorted list of its edges.\nthe last is the mapping from edges to integers, given as an EdgeDict.\n\nIf rs is provided, the first returned value is the list of indices keep of rs such that rs[keep] is the list of strong rings.\n\n\n\n\n\n","category":"function"},{"location":"rings/#PeriodicGraphs.convert_to_ering!","page":"Rings","title":"PeriodicGraphs.convert_to_ering!","text":"convert_to_ering!(buffer::Vector{Int}, ring::Vector{PeriodicVertex{D}}, kp::EdgeDict{D}, ofs, len) where D\n\nReturn the edge ring corresponding to OffsetVertexIterator{D}(ring[1:len], ofs) inside buffer, resized to length len.\n\nSee also PeriodicGraphs.convert_to_ering.\n\n\n\n\n\n","category":"function"},{"location":"rings/#PeriodicGraphs.convert_to_ering","page":"Rings","title":"PeriodicGraphs.convert_to_ering","text":"convert_to_ering(ring::Vector{PeriodicVertex{D}}, kp::EdgeDict{D}, ofs=zero(SVector{D,Int}), len=length(ring)) where D\n\nReturn the edge ring corresponding to OffsetVertexIterator{D}(ring[1:len], ofs).\n\nSee also PeriodicGraphs.convert_to_ering! to provide a buffer.\n\n\n\n\n\n","category":"function"},{"location":"utilities/#Utilities","page":"Utilities","title":"Utilities","text":"","category":"section"},{"location":"utilities/#Hashing","page":"Utilities","title":"Hashing","text":"","category":"section"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"It is sometimes convenient to be able to associate to each vertex of periodic graph g an integer hash, such that the hashes of vertices in the reference unit cell are between 1 and nv(g), the hashes of the vertices in the unit cells around the reference are next, then the vertices of the unit cells around those, etc. To do so, PeriodicGraphs.jl export the hash_position function as follows:","category":"page"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"hash_position","category":"page"},{"location":"utilities/#PeriodicGraphs.hash_position","page":"Utilities","title":"PeriodicGraphs.hash_position","text":"hash_position(x::PeriodicVertex{N}, n::Integer) where N\n\nGiven x, a PeriodicVertex{N}, and the number n of vertex identifiers in a graph, compute a unique positive integer hash for the given vertex.\n\nThis hash function is a bijection between the set of all the vertices of the periodic graph and the set of positive integers. Its value is an integer between 1+n*(2d-1)^N (or 1 if d == 0) and n*(2d+1)^N, where d = maximum(abs.(x.ofs)).\n\nIn particular, this means that when one unit cell B is further than another A from the origin (for the Manhattan distance), all vertices in B have a larger hash than all vertices in A.\n\n\n\n\n\n","category":"function"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"The reciproque function is also exported:","category":"page"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"reverse_hash_position","category":"page"},{"location":"utilities/#PeriodicGraphs.reverse_hash_position","page":"Utilities","title":"PeriodicGraphs.reverse_hash_position","text":"reverse_hash_position(hash::Integer, n::Integer, ::Val{N}) where N\n\nGiven a hash obtained from hash_position(x, n) where x is a PeriodicVertex{N}, return the corresponding x.\n\nIf the offset of the returned PeriodicVertex is not needed, simply doing mod1(x, n) yields the identifier of the vertex and is faster.\n\n\n\n\n\n","category":"function"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"Both functions are optimized for dimensions 1, 2 and 3, especially for unit cells not too far from the reference.","category":"page"},{"location":"utilities/#Isomorphic-transformations","page":"Utilities","title":"Isomorphic transformations","text":"","category":"section"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"Several functions transform a periodic graph into another isomorphic to the input, by renumbering the vertices (vertex_permutation) or the axes (swap_axes!), or by offsetting the chosen representatives for each vertex (offset_representatives!). It is also possible to make an isomorphic graph with more vertices per unit cell by using a supercell (make_supercell).","category":"page"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"PeriodicGraphs.vertex_permutation\nswap_axes!\noffset_representatives!\nmake_supercell","category":"page"},{"location":"utilities/#PeriodicGraphs.vertex_permutation","page":"Utilities","title":"PeriodicGraphs.vertex_permutation","text":"vertex_permutation(g::PeriodicGraph, vlist)\n\nReturn the PeriodicGraph corresponding to g with its vertices identifiers permuted according to vlist. isperm(vlist) must hold and will not be checked.\n\nSee also Graphs.induced_subgraph for the more general case where vlist is not a permutation.\n\nnote: Note\nThe resulting graph is isomorphic to the initial one, only the representation has changed.\n\n\n\n\n\n","category":"function"},{"location":"utilities/#PeriodicGraphs.swap_axes!","page":"Utilities","title":"PeriodicGraphs.swap_axes!","text":"swap_axes!(g::PeriodicGraph, t)\n\nIn-place modifies graph g so that the new initial cell corresponds to the previous one with its axes swapped according to the permutation t.\n\nnote: Note\nThe resulting graph is isomorphic to the initial one, only the representation has changed.\n\n\n\n\n\n","category":"function"},{"location":"utilities/#PeriodicGraphs.offset_representatives!","page":"Utilities","title":"PeriodicGraphs.offset_representatives!","text":"offset_representatives!(g::PeriodicGraph, offsets)\n\nIn-place modifies graph g so that the i-th vertex of the new initial cell corresponds to the i-th vertex in cell offsets[i] compared to the previous initial cell.\n\nnote: Note\nThe resulting graph is isomorphic to the initial one, only the representation has changed.\n\n\n\n\n\n","category":"function"},{"location":"utilities/#PeriodicGraphs.make_supercell","page":"Utilities","title":"PeriodicGraphs.make_supercell","text":"make_supercell(g::PeriodicGraph, t)\n\nReturn a graph isomorphic to the input g whose its unit cell is a repetition of that of g, each dimension i being repeated t[i] times. It follows that the number of vertices of make_supercell(g, t) is prod(t)*nv(g)\n\nt must be an interator over positive integers.\n\n\n\n\n\n","category":"function"},{"location":"utilities/#Dimension-reduction","page":"Utilities","title":"Dimension reduction","text":"","category":"section"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"Any PeriodicGraph can be naturally reduced to an aperiodic graph by removing all offsets from the edges and either keeping (quotient_graph) or removing (truncated_graph) edges crossing from one unit cell to another.","category":"page"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"quotient_graph\ntruncated_graph","category":"page"},{"location":"utilities/#PeriodicGraphs.quotient_graph","page":"Utilities","title":"PeriodicGraphs.quotient_graph","text":"quotient_graph(g::PeriodicGraph)\n\nExtract a simple graph from g by removing all indications of offset in the edges. This means that edges that used to cross the boundaries of the initial cell now bind the source vertex to the representative of the destination vertex that is in the initial cell.\n\nNote that these modified edges may turn into loops.\n\nSee also truncated_graph to remove all of these edges and slice_graph to keep only some of these edges.\n\n\n\n\n\n","category":"function"},{"location":"utilities/#PeriodicGraphs.truncated_graph","page":"Utilities","title":"PeriodicGraphs.truncated_graph","text":"truncated_graph(g::PeriodicGraph)\n\nExtract a simple graph from g by only keeping the edges that are strictly within the initial cell.\n\nSee also quotient_graph to keep all of these edges and slice_graph to keep only some of these edges.\n\n\n\n\n\n","category":"function"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"It is also possible to reduce the dimension of a graph by removing only some selected offsets with the slice_graph function.","category":"page"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"slice_graph","category":"page"},{"location":"utilities/#PeriodicGraphs.slice_graph","page":"Utilities","title":"PeriodicGraphs.slice_graph","text":"slice_graph(g::PeriodicGraph{D}, remove::Union{SVector{N},NTuple{N}}) where {D,N}\n\nExtract a PeriodicGraph{D-N} from g by removing all edges that have an offset o such that !iszero(o[remove]) and shrinking the resulting offsets. In other words, remove the dimensions in remove.\n\nTo only remove the edges while keeping the same number of dimensions, use slice_graph(g, collect(remove))\n\nremove is assumed to be sorted and to contain unique elements.\n\nwarning: Warning\nNo verification of the previous assumption will be performed.\n\n\n\n\n\nslice_graph(g::PeriodicGraph{D}, remove::Vector{<:Integer}) where D\n\nExtract a PeriodicGraph{D} from g by removing all edges that have an offset o such that !iszero(o[remove]).\n\nContrarily to the slice_graph(g::PeriodicGraph{D}, remove::Union{SVector{N},NTuple{N}}) where {D,N} method, the dimensions along which the edges are erased are still kept here.\n\nremove is assumed to be sorted and to contain unique elements.\n\nwarning: Warning\nNo verification of the previous assumption will be performed.\n\n\n\n\n\n","category":"function"},{"location":"utilities/#Arithmetics","page":"Utilities","title":"Arithmetics","text":"","category":"section"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"These utilities are internally used for dimensionality computations, but may be useful in other contexts.","category":"page"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"PeriodicGraphs.extended_gcd\nPeriodicGraphs.normal_basis","category":"page"},{"location":"utilities/#PeriodicGraphs.extended_gcd","page":"Utilities","title":"PeriodicGraphs.extended_gcd","text":"extended_gcd(s)::Tuple{BigInt, Vector{BigInt}}\n\nGiven a list of integers, return a tuple (d, coefs) where d is the gcd of these integers and coefs is a list of integers such that dot(s, coefs) == d.\n\n\n\n\n\n","category":"function"},{"location":"utilities/#PeriodicGraphs.normal_basis","page":"Utilities","title":"PeriodicGraphs.normal_basis","text":"normal_basis(l::AbstractVector{<:StaticVector{N,T}}) where {N,T<:Integer}\n\nGiven a list of integer vectors of dimension N, return a tuple (mat, D) where D is the dimension of the space spanned by the input vectors, and mat is an invertible matrix whose D first columns form a basis of this spanned space, which does not depend on the exact input.\n\nIf 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.\n\nwarning: Warning\nIf modifiable, the input list will be modified in-place during this process.\n\n\n\n\n\n","category":"function"},{"location":"utilities/#Unclassified-other-utilities","page":"Utilities","title":"Unclassified other utilities","text":"","category":"section"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"These other convenience functions may be useful for the manipulation of PeriodicGraphs:","category":"page"},{"location":"utilities/","page":"Utilities","title":"Utilities","text":"find_edges\ncoordination_sequence","category":"page"},{"location":"utilities/#PeriodicGraphs.find_edges","page":"Utilities","title":"PeriodicGraphs.find_edges","text":"find_edges(g::PeriodicGraph, s::Int, d::Int)\n\nReturn the set of PeriodicVertex v of graph g such that there is an edge between a source vertex of identifier s and v, and the identifier of v is d.\n\n\n\n\n\n","category":"function"},{"location":"utilities/#PeriodicGraphs.coordination_sequence","page":"Utilities","title":"PeriodicGraphs.coordination_sequence","text":"coordination_sequence(g::PeriodicGraph, v::Integer, dmax)\n\nCompute the list of numbers of n-th neighbors of vertex v in graph g, for 1 ≤ n ≤ dmax.\n\n\n\n\n\n","category":"function"},{"location":"dimension/#Dimensionality","page":"Dimensionality","title":"Dimensionality","text":"","category":"section"},{"location":"dimension/","page":"Dimensionality","title":"Dimensionality","text":"A periodic graph g of type PeriodicGraph{N} has dimension N, which means that its unit cell is repeated across N independent axes. However, this number may be larger than the actual number of independent axes necessary to describe the repeating unit of the graph, which we will call the dimensionality. For example, consider an infinite set of identical 2-periodic graphs stacked across a third dimension: the resulting graph is of dimension 3, but its dimensionality is 2 (or below) because all the topological information is stored in the 2-periodic subgraph.","category":"page"},{"location":"dimension/","page":"Dimensionality","title":"Dimensionality","text":"The connected components of g can be separated and sorted by dimensionality using the dimensionality function:","category":"page"},{"location":"dimension/","page":"Dimensionality","title":"Dimensionality","text":"dimensionality","category":"page"},{"location":"dimension/#PeriodicGraphs.dimensionality","page":"Dimensionality","title":"PeriodicGraphs.dimensionality","text":"dimensionality(g::PeriodicGraph{N}) where N\n\nDetermine the actual dimension of each connected component of g. 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.\n\nIn 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. See also split_catenation.\n\nExamples\n\njulia> dimensionality(PeriodicGraph(\"2 1 1 1 0 2 2 -1 1 3 3 1 0 3 3 0 1\"))\nDict{Int64, Vector{Tuple{Vector{Int64}, Int64}}} with 2 entries:\n 2 => [([3], 1)]\n 1 => [([1], 1), ([2], 1)]\n\njulia> dimensionality(PeriodicGraph(\"1 1 1 2\"))\nDict{Int64, Vector{Tuple{Vector{Int64}, Int64}}} with 1 entry:\n 1 => [([1], 2)]\n\n\n\n\n\n","category":"function"},{"location":"dimension/","page":"Dimensionality","title":"Dimensionality","text":"See also split_catenation to split connected components in a more detailed fashion, when multiple components can share the same vertex indices:","category":"page"},{"location":"dimension/","page":"Dimensionality","title":"Dimensionality","text":"split_catenation","category":"page"},{"location":"dimension/#PeriodicGraphs.split_catenation","page":"Dimensionality","title":"PeriodicGraphs.split_catenation","text":"split_catenation(graph::PeriodicGraph{N}) where N\n\nReturn a list of tuples (sublist, mat, dim). Each sublist is made of a list of pairs (subgraph, vmap) where subgraph is a connected component of the input graph, whose vertices are given by vmap from graph. dim is the dimensionality of these connected components, and mat is the transformation matrix between the input cell and the component's cell.\n\nEach sublist contains connected components that share the same vertex indices.\n\nExample\n\njulia> g = PeriodicGraph(\"2 1 1 3 0 1 1 0 1 2 3 1 0 3 2 1 0\");\n\njulia> dimensionality(g)\nDict{Int64, Vector{Tuple{Vector{Int64}, Int64}}} with 2 entries:\n 2 => [([1], 3)]\n 1 => [([2, 3], 2)]\n\njulia> splits = split_catenation(g);\n\njulia> last.(splits) # One 2-dimensional catenation (vertex 1), one 1-dimensional (vertices 2 and 3)\n2-element Vector{Int64}:\n 2\n 1\n\njulia> sublist, mat, dim = last(splits); # the 1-dimensional connected components\n\njulia> sublist # first sublist takes vertex 2 from the reference unit cell, second one takes vertex 3.\n2-element Vector{Tuple{PeriodicGraph2D, Vector{PeriodicVertex2D}}}:\n (PeriodicGraph2D(2, PeriodicEdge2D[(1, 2, (0,0)), (1, 2, (1,0))]), [(2, (0,0)), (3, (-1,0))])\n (PeriodicGraph2D(2, PeriodicEdge2D[(1, 2, (0,0)), (1, 2, (1,0))]), [(3, (0,0)), (2, (-1,0))])\n\n\n\n\n\n","category":"function"},{"location":"dimension/","page":"Dimensionality","title":"Dimensionality","text":"To transpose a graph from one dimension N to another D, call the type constructor PeriodicGraph{D} directly on g::PeriodicGraph{N}. This can be useful to manipulate a graph of dimensionality D as a graph of actual dimension D, which often reduces computational costs.","category":"page"},{"location":"dimension/","page":"Dimensionality","title":"Dimensionality","text":"PeriodicGraph{D}(graph::PeriodicGraph{N}, dims=_dimensionality(graph)) where {D,N}","category":"page"},{"location":"dimension/#PeriodicGraphs.PeriodicGraph-Union{Tuple{PeriodicGraph{N}}, Tuple{N}, Tuple{D}, Tuple{PeriodicGraph{N}, Any}} where {D, N}","page":"Dimensionality","title":"PeriodicGraphs.PeriodicGraph","text":"PeriodicGraph{D}(graph::PeriodicGraph{N}) where {D,N}\n\nReturn a graph that has the same structural information as the input graph but embedded in D dimensions instead of N. It will fail if the dimensionality of the graph is greater than D.\n\nnote: Note\nThe behaviour is undefined if D < N and there are multiple non-identical connected components. In particular, the function is expected to fail if these components do not share the same orientation.\n\n\n\n\n\n","category":"method"},{"location":"dimension/","page":"Dimensionality","title":"Dimensionality","text":"For example, the following function extracts the list of 1-dimensional components from a given PeriodicGraph:","category":"page"},{"location":"dimension/","page":"Dimensionality","title":"Dimensionality","text":"julia> function extract_1D_components(g::PeriodicGraph{D}) where D\n d = dimensionality(g)\n components1D = get(d, 1, Vector{Int}[])\n return [PeriodicGraph1D(g[l]) for l in components1D]\n end\nextract_1D_components (generic function with 1 method)","category":"page"},{"location":"dimension/","page":"Dimensionality","title":"Dimensionality","text":"Let's test it on the following 2-periodic graph, which has one 0D component (vertices 4 and 5), two 1D components (vertex 3 alone and vertices 6 and 7 together) and one 2D component (vertices 1 and 2):","category":"page"},{"location":"dimension/","page":"Dimensionality","title":"Dimensionality","text":"julia> g = PeriodicGraph2D(\"2 1 2 0 0 2 1 1 0 2 1 0 1\n 3 3 1 0\n 4 5 0 0\n 6 7 1 0 7 6 1 0\n \")\nPeriodicGraph2D(7, PeriodicEdge2D[(1, 2, (-1,0)), (1, 2, (0,-1)), (1, 2, (0,0)), (3, 3, (1,0)), (4, 5, (0,0)), (6, 7, (-1,0)), (6, 7, (1,0))])\n\njulia> extract_1D_components(g)\n2-element Vector{PeriodicGraph1D}:\n PeriodicGraph1D(1, PeriodicEdge1D[(1, 1, (1,))])\n PeriodicGraph1D(2, PeriodicEdge1D[(1, 2, (-1,)), (1, 2, (1,))])","category":"page"},{"location":"dimension/","page":"Dimensionality","title":"Dimensionality","text":"The first subgraph corresponds to g[[3]] and the second to g[[6,7]], both converted to PeriodicGraph1D.","category":"page"},{"location":"dimension/","page":"Dimensionality","title":"Dimensionality","text":"The dimension of a graph can also be reduced with loss of information through the slice_graph function.","category":"page"},{"location":"#PeriodicGraphs.jl","page":"Home","title":"PeriodicGraphs.jl","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"A Julia package for the manipulation of periodic graphs.","category":"page"},{"location":"#Usages","page":"Home","title":"Usages","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"PeriodicGraphs.jl defines types and algorithms useful for the manipulation of N-periodic undirected graphs, with N known at compile-time. It extends Graphs.jl by providing the new PeriodicGraph type which implements the AbstractGraph API. It also provides an API for the manipulation of symmetries.","category":"page"},{"location":"","page":"Home","title":"Home","text":"This package serves as support for the PeriodicGraphEmbeddings.jl library, which focuses on euclidean embeddings of periodic graphs, and for CrystalNets.jl for the manipulation and identification of crystal nets, which are 2 or 3-periodic graphs.","category":"page"},{"location":"#Package-installation","page":"Home","title":"Package installation","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"The installation follows the usual procedure. Start by downloading and installing Julia (v1.6 or higher for PeriodicGraphs.jl). Then, either","category":"page"},{"location":"","page":"Home","title":"Home","text":"open the Julia REPL and enter the package manager by typing ], then install PeriodicGraphs.jl by entering:\npkg> add PeriodicGraphs\nalternatively, you can do it from a shell by executing:\njulia -e 'import Pkg; Pkg.add(\"PeriodicGraphs\")","category":"page"},{"location":"","page":"Home","title":"Home","text":"To use the package, open a REPL and enter","category":"page"},{"location":"","page":"Home","title":"Home","text":"julia> using PeriodicGraphs","category":"page"},{"location":"symmetries/#Symmetries","page":"Symmetries","title":"Symmetries","text":"","category":"section"},{"location":"symmetries/","page":"Symmetries","title":"Symmetries","text":"PeriodicGraphs.jl comes with a general API for the manipulation of symmetries. Concrete implementations of the API can be found in PeriodicGraphEmbeddings.jl.","category":"page"},{"location":"symmetries/#Single-symmetry-operations","page":"Symmetries","title":"Single symmetry operations","text":"","category":"section"},{"location":"symmetries/","page":"Symmetries","title":"Symmetries","text":"AbstractSymmetry\nIdentitySymmetry\nSimpleSymmetry\nSimpleSymmetry(map::T, dict::D) where {T,D}\nSimpleSymmetry(map)","category":"page"},{"location":"symmetries/#PeriodicGraphs.AbstractSymmetry","page":"Symmetries","title":"PeriodicGraphs.AbstractSymmetry","text":"abstract type AbstractSymmetry end\n\nAn abstract type representing a symmetry.\n\nInterface\n\nSubtypes T of AbstractSymmetry should implement a method to make their objects symm callable on any object upon which the symmetry can act. For example, if T represents a symmetry of a 3D embedding of a graph:\n\nif x represents a 3D point, then symm(x) should be the image of that point.\nif x represents a 3D basis of space, then symm(x) should be the image of that basis.\n\nWhen the symmetry is naturally defined on a discrete set of objects, their image should be accessible by indexing on the symmetry. With the same example as before:\n\nif x is a vertex, symm[x] is the image of x by the symmetry.\nif i is the integer identifier of vertex x, symm[i] is the identifier of symm[x].\n\n\n\n\n\n","category":"type"},{"location":"symmetries/#PeriodicGraphs.IdentitySymmetry","page":"Symmetries","title":"PeriodicGraphs.IdentitySymmetry","text":"IdentitySymmetry <: AbstractSymmetry\n\nIdentity symmetry, i.e. such that for s::IdentitySymmetry, ∀x, s[x] == x.\n\n\n\n\n\n","category":"type"},{"location":"symmetries/#PeriodicGraphs.SimpleSymmetry","page":"Symmetries","title":"PeriodicGraphs.SimpleSymmetry","text":"SimpleSymmetry{K,T,D} <: AbstractSymmetry\n\nSymmetry operation defined by a map of type T and an optional dict of type D accepting keys of type K.\n\n\n\n\n\n","category":"type"},{"location":"symmetries/#PeriodicGraphs.SimpleSymmetry-Union{Tuple{D}, Tuple{T}, Tuple{T, D}} where {T, D}","page":"Symmetries","title":"PeriodicGraphs.SimpleSymmetry","text":"SimpleSymmetry(map::T, dict::D) where {T,D}\n\nCreate a SimpleSymmetry{keytype(D),T,D} object symm such that symm[x] is\n\nmap[dict[x]] if x isa keytype(D).\nmap[x] otherwise, if x isa Integer.\n\n\n\n\n\n","category":"method"},{"location":"symmetries/#PeriodicGraphs.SimpleSymmetry-Tuple{Any}","page":"Symmetries","title":"PeriodicGraphs.SimpleSymmetry","text":"SimpleSymmetry(map)\n\nCreate a SimpleSymmetry object symm such that symm[x] == map[x] for all x.\n\n\n\n\n\n","category":"method"},{"location":"symmetries/#Symmetry-group","page":"Symmetries","title":"Symmetry group","text":"","category":"section"},{"location":"symmetries/","page":"Symmetries","title":"Symmetries","text":"AbstractSymmetryGroup\nNoSymmetryGroup\nIncludingIdentity","category":"page"},{"location":"symmetries/#PeriodicGraphs.AbstractSymmetryGroup","page":"Symmetries","title":"PeriodicGraphs.AbstractSymmetryGroup","text":"AbstractSymmetryGroup{T<:AbstractSymmetry}\n\nAn abstract type representing the set of symmetries of a graph.\n\nInterface\n\nAny AbstractSymmetryGroup type must define methods for Base functions unique, iterate, length and one such that, for any s of type <: AbstractSymmetryGroup{T}:\n\ns(i) is a representative on the symmetry orbit of i such that all elements on the orbit share the same representative. The representative should be an integer.\nunique(s) is an iterator over such representatives.\niterating over s yields the list of symmetry operations symm, each represented as an object of type T (where T <:AbstractSymmetry is the parameter to typeof(s)). The identity symmetry should not be part of these yielded symm, except for the specific IncludingIdentity subtype of AbstractSymmetryGroup.\none(s) is the identity symmetry of type T.\n\n\n\n\n\n","category":"type"},{"location":"symmetries/#PeriodicGraphs.NoSymmetryGroup","page":"Symmetries","title":"PeriodicGraphs.NoSymmetryGroup","text":"NoSymmetryGroup <: AbstractSymmetryGroup{IdentitySymmetry}\n\nThe trivial AbstractSymmetryGroup devoid of any symmetry operation. NoSymmetryGroup(num) creates a NoSymmetryGroup over num unique representatives.\n\n\n\n\n\n","category":"type"},{"location":"symmetries/#PeriodicGraphs.IncludingIdentity","page":"Symmetries","title":"PeriodicGraphs.IncludingIdentity","text":"IncludingIdentity{S<:AbstractSymmetry,T<:AbstractSymmetryGroup{S}} <: AbstractSymmetryGroup{S}\n\nWrapper around an AbstractSymmetry that explicitly includes the identity operation.\n\n\n\n\n\n","category":"type"}] } diff --git a/dev/symmetries/index.html b/dev/symmetries/index.html index c440c63..b704ad3 100644 --- a/dev/symmetries/index.html +++ b/dev/symmetries/index.html @@ -1,2 +1,2 @@ -Symmetries · PeriodicGraphs.jl

        Symmetries

        PeriodicGraphs.jl comes with a general API for the manipulation of symmetries. Concrete implementations of the API can be found in PeriodicGraphEmbeddings.jl.

        Single symmetry operations

        PeriodicGraphs.AbstractSymmetryType
        abstract type AbstractSymmetry end

        An abstract type representing a symmetry.

        Interface

        Subtypes T of AbstractSymmetry should implement a method to make their objects symm callable on any object upon which the symmetry can act. For example, if T represents a symmetry of a 3D embedding of a graph:

        • if x represents a 3D point, then symm(x) should be the image of that point.
        • if x represents a 3D basis of space, then symm(x) should be the image of that basis.

        When the symmetry is naturally defined on a discrete set of objects, their image should be accessible by indexing on the symmetry. With the same example as before:

        • if x is a vertex, symm[x] is the image of x by the symmetry.
        • if i is the integer identifier of vertex x, symm[i] is the identifier of symm[x].
        source
        PeriodicGraphs.SimpleSymmetryType
        SimpleSymmetry{K,T,D} <: AbstractSymmetry

        Symmetry operation defined by a map of type T and an optional dict of type D accepting keys of type K.

        source
        PeriodicGraphs.SimpleSymmetryMethod
        SimpleSymmetry(map::T, dict::D) where {T,D}

        Create a SimpleSymmetry{keytype(D),T,D} object symm such that symm[x] is

        • map[dict[x]] if x isa keytype(D).
        • map[x] otherwise, if x isa Integer.
        source

        Symmetry group

        PeriodicGraphs.AbstractSymmetryGroupType
        AbstractSymmetryGroup{T<:AbstractSymmetry}

        An abstract type representing the set of symmetries of a graph.

        Interface

        Any AbstractSymmetryGroup type must define methods for Base functions unique, iterate, length and one such that, for any s of type <: AbstractSymmetryGroup{T}:

        • s(i) is a representative on the symmetry orbit of i such that all elements on the orbit share the same representative. The representative should be an integer.
        • unique(s) is an iterator over such representatives.
        • iterating over s yields the list of symmetry operations symm, each represented as an object of type T (where T <:AbstractSymmetry is the parameter to typeof(s)). The identity symmetry should not be part of these yielded symm, except for the specific IncludingIdentity subtype of AbstractSymmetryGroup.
        • one(s) is the identity symmetry of type T.
        source
        +Symmetries · PeriodicGraphs.jl

        Symmetries

        PeriodicGraphs.jl comes with a general API for the manipulation of symmetries. Concrete implementations of the API can be found in PeriodicGraphEmbeddings.jl.

        Single symmetry operations

        PeriodicGraphs.AbstractSymmetryType
        abstract type AbstractSymmetry end

        An abstract type representing a symmetry.

        Interface

        Subtypes T of AbstractSymmetry should implement a method to make their objects symm callable on any object upon which the symmetry can act. For example, if T represents a symmetry of a 3D embedding of a graph:

        • if x represents a 3D point, then symm(x) should be the image of that point.
        • if x represents a 3D basis of space, then symm(x) should be the image of that basis.

        When the symmetry is naturally defined on a discrete set of objects, their image should be accessible by indexing on the symmetry. With the same example as before:

        • if x is a vertex, symm[x] is the image of x by the symmetry.
        • if i is the integer identifier of vertex x, symm[i] is the identifier of symm[x].
        source
        PeriodicGraphs.SimpleSymmetryType
        SimpleSymmetry{K,T,D} <: AbstractSymmetry

        Symmetry operation defined by a map of type T and an optional dict of type D accepting keys of type K.

        source
        PeriodicGraphs.SimpleSymmetryMethod
        SimpleSymmetry(map::T, dict::D) where {T,D}

        Create a SimpleSymmetry{keytype(D),T,D} object symm such that symm[x] is

        • map[dict[x]] if x isa keytype(D).
        • map[x] otherwise, if x isa Integer.
        source

        Symmetry group

        PeriodicGraphs.AbstractSymmetryGroupType
        AbstractSymmetryGroup{T<:AbstractSymmetry}

        An abstract type representing the set of symmetries of a graph.

        Interface

        Any AbstractSymmetryGroup type must define methods for Base functions unique, iterate, length and one such that, for any s of type <: AbstractSymmetryGroup{T}:

        • s(i) is a representative on the symmetry orbit of i such that all elements on the orbit share the same representative. The representative should be an integer.
        • unique(s) is an iterator over such representatives.
        • iterating over s yields the list of symmetry operations symm, each represented as an object of type T (where T <:AbstractSymmetry is the parameter to typeof(s)). The identity symmetry should not be part of these yielded symm, except for the specific IncludingIdentity subtype of AbstractSymmetryGroup.
        • one(s) is the identity symmetry of type T.
        source
        diff --git a/dev/types/index.html b/dev/types/index.html index 086a326..8dc63a8 100644 --- a/dev/types/index.html +++ b/dev/types/index.html @@ -46,14 +46,14 @@ "3 1 2 1 0 0 1 3 0 1 0 2 2 0 0 1 2 3 0 1 1" julia> string(PeriodicGraph("2 1 2 0 0 2 3 0 0 3 1 0 0 3 1 1 0 2 1 0 1 2 3 0 1")) -"2 1 2 0 -1 1 2 0 0 1 3 -1 0 1 3 0 0 2 3 0 0 2 3 0 1"

        API

        Type definitions

        PeriodicGraphs.PeriodicVertexType
        PeriodicVertex{N}

        Vertex type for an N-periodic graph.

        A vertex is uniquely determined by the identifier of its representative in the a fixed initial cell, and the offset of the cell containing the vertex compared to the the initial cell. Vertex identifiers start at 1.

        source
        PeriodicGraphs.PeriodicEdgeType
        PeriodicEdge{N} <: Graphs.SimpleGraphs.AbstractSimpleEdge{Int}

        Edge type for an N-periodic graph.

        An edge is uniquely determined by the vertex identifiers of its source and destination, and the cell offset between the source vertex and the destination vertex.

        source
        PeriodicGraphs.PeriodicGraphType
        PeriodicGraph{N} <: AbstractGraph{Int}

        Type representing an undirected N-periodic graph.

        source
        PeriodicGraphs.PeriodicGraphMethod
        PeriodicGraph{N}(nv::Integer=0)

        Construct a PeriodicGraph{N} with nv vertices and 0 edge.

        source
        PeriodicGraphs.PeriodicGraphMethod
        PeriodicGraph([nv::Integer, ]edge_list::AbstractVector{PeriodicEdge{N}})
        +"2 1 2 0 -1 1 2 0 0 1 3 -1 0 1 3 0 0 2 3 0 0 2 3 0 1"

        API

        Type definitions

        PeriodicGraphs.PeriodicVertexType
        PeriodicVertex{N}

        Vertex type for an N-periodic graph.

        A vertex is uniquely determined by the identifier of its representative in the a fixed initial cell, and the offset of the cell containing the vertex compared to the the initial cell. Vertex identifiers start at 1.

        source
        PeriodicGraphs.PeriodicEdgeType
        PeriodicEdge{N} <: Graphs.SimpleGraphs.AbstractSimpleEdge{Int}

        Edge type for an N-periodic graph.

        An edge is uniquely determined by the vertex identifiers of its source and destination, and the cell offset between the source vertex and the destination vertex.

        source
        PeriodicGraphs.PeriodicGraphMethod
        PeriodicGraph([nv::Integer, ]edge_list::AbstractVector{PeriodicEdge{N}})
         PeriodicGraph{N}([nv::Integer, ]edge_list::AbstractVector{PeriodicEdge{N}})

        Construct a PeriodicGraph{N} from a vector of edges. If nv is unspecified, the number of vertices is the highest that is used in an edge in edge_list.

        Implementation Notes

        This constructor works the fastest when edge_list is sorted by the lexical ordering and does not contain any duplicates.

        Examples

        julia> el = PeriodicEdge2D[(1, 1, (1,0)), (1, 3, (0,1)), (3, 1, (0,-1))];
         
         julia> g = PeriodicGraph(el)
         PeriodicGraph2D(3, PeriodicEdge2D[(1, 1, (1,0)), (1, 3, (0,1))])
         
         julia> ne(g)
        -2
        source
        PeriodicGraphs.PeriodicGraphMethod
        PeriodicGraph(key::AbstractString)
         PeriodicGraph{N}(key::AbstractString)

        Construct a PeriodicGraph{N} from a key, which is a string of whitespace-separated values of the form "N src1 dst1 ofs1_1 ofs1_2 ... ofs1_N src2 dst2 ofs2_1 ofs2_2 ... ofs2_N ... srcm dstm ofsm_1 ofsm_2 ... ofsm_N" where N is the number of repeating dimensions of the graph, m is the number of edges and for all i between 1 and m, the number of edges, the i-th edge is described as

        • srci, the vertex identifier of the source vertex,
        • dsti, the vertex identifier of the destination vertex and
        • (ofsi_1, ofsi_2, ..., ofsi_N) the offset of the edge.

        This compact representation of a graph can be obtained simply by printing the graph or with string.

        Note

        Use parse(PeriodicGraph, key) or parse(PeriodicGraph{N}, key) for a faster implementation if key was obtained from string(g) with g a PeriodicGraph{N}.

        Examples

        julia> PeriodicGraph("2  1 2 0 0  2 1 1 0  1 1 0 -1")
         PeriodicGraph2D(2, PeriodicEdge2D[(1, 1, (0,1)), (1, 2, (-1,0)), (1, 2, (0,0))])
         
        @@ -64,15 +64,15 @@
         "3 1 1 0 0 1 1 1 0 1 0 1 1 1 0 0"
         
         julia> string(parse(PeriodicGraph3D, ans)) == ans
        -true
        source
        Base.parseMethod
        parse(::Type{PeriodicGraph}, key::AbstractString)
        -parse(::Type{PeriodicGraph{N}}, key::AbstractString)

        Parse a string representation of a PeriodicGraph back to a PeriodicGraph.

        See PeriodicGraph(key::AbstractString) or PeriodicGraph{N}(key::AbstractString) for details on the string representations of a PeriodicGraph.

        Warning

        This function assumes that the string is a valid representation of a PeriodicGraph with all its edges direct, sorted in lexicographical order and unique, as obtained from string(g) or print(g) where g is a PeriodicGraph. No check is performed to ensure this condition.

        If the input string may not obey these conditions, use PeriodicGraph(key) or PeriodicGraph{N}(key) instead.

        source

        Other basic functions

        PeriodicGraphs.isdirectedgeFunction
        isdirectedge(e::PeriodicEdge)

        Return true if e is direct, in the sense being of the form (u, v, ofs) with either u < v or u == v && ofs > zero(ofs).

        An edge e is indirect iff reverse(e) is not.

        Examples

        julia> isdirectedge(PeriodicEdge1D(3, 4, (0,)))
        +true
        source
        Base.parseMethod
        parse(::Type{PeriodicGraph}, key::AbstractString)
        +parse(::Type{PeriodicGraph{N}}, key::AbstractString)

        Parse a string representation of a PeriodicGraph back to a PeriodicGraph.

        See PeriodicGraph(key::AbstractString) or PeriodicGraph{N}(key::AbstractString) for details on the string representations of a PeriodicGraph.

        Warning

        This function assumes that the string is a valid representation of a PeriodicGraph with all its edges direct, sorted in lexicographical order and unique, as obtained from string(g) or print(g) where g is a PeriodicGraph. No check is performed to ensure this condition.

        If the input string may not obey these conditions, use PeriodicGraph(key) or PeriodicGraph{N}(key) instead.

        source

        Other basic functions

        PeriodicGraphs.isdirectedgeFunction
        isdirectedge(e::PeriodicEdge)

        Return true if e is direct, in the sense being of the form (u, v, ofs) with either u < v or u == v && ofs > zero(ofs).

        An edge e is indirect iff reverse(e) is not.

        Examples

        julia> isdirectedge(PeriodicEdge1D(3, 4, (0,)))
         true
         
         julia> isdirectedge(PeriodicEdge2D(5, 2, (0,0)))
         false
         
         julia> isdirectedge(PeriodicEdge3D(3, 3, (0,-1,2)))
        -false

        See also directedge

        source
        PeriodicGraphs.directedgeFunction
        directedge(e::PeriodicEdge{D}) where D
         directedge(src::PeriodicVertex{D}, dst::PeriodicVertex{D}) where D
         directedge(src, dst, ofs::Union{SVector{D,T},NTuple{D,T}}) where {D,T}

        Return the direct edge corresponding to e = PeriodicEdge{D}(src, dst), i.e. e itself if e is direct, or reverse(e) otherwise.

        Examples

        julia> directedge(PeriodicEdge1D(3, 4, (0,)))
         PeriodicEdge1D(3, 4, (0,))
        @@ -81,4 +81,4 @@
         PeriodicEdge2D(2, 5, (0,0))
         
         julia> directedge(PeriodicEdge3D(3, 3, (0,-1,2)))
        -PeriodicEdge3D(3, 3, (0,1,-2))

        See also isdirectedge

        source
        PeriodicGraphs.LoopExceptionType
        LoopException <: Exception

        Error type for constructing an invalid PeriodicEdge{N} of the form (u, u, zeros(Int,N)). Loops are not expected in the algorithms implemented in PeriodicGraphs.jl. If you still want to construct them, use the unsafe_edge{N} constructor instead of PeriodicEdge{N}.

        source
        +PeriodicEdge3D(3, 3, (0,1,-2))

        See also isdirectedge

        source
        PeriodicGraphs.unsafe_edgeType
        unsafe_edge{N}

        Internal constructor for PeriodicEdge{N} that bypasses the loop check.

        source
        PeriodicGraphs.LoopExceptionType
        LoopException <: Exception

        Error type for constructing an invalid PeriodicEdge{N} of the form (u, u, zeros(Int,N)). Loops are not expected in the algorithms implemented in PeriodicGraphs.jl. If you still want to construct them, use the unsafe_edge{N} constructor instead of PeriodicEdge{N}.

        source
        diff --git a/dev/utilities/index.html b/dev/utilities/index.html index f3a3488..c50b3dc 100644 --- a/dev/utilities/index.html +++ b/dev/utilities/index.html @@ -1,2 +1,2 @@ -Utilities · PeriodicGraphs.jl

        Utilities

        Hashing

        It is sometimes convenient to be able to associate to each vertex of periodic graph g an integer hash, such that the hashes of vertices in the reference unit cell are between 1 and nv(g), the hashes of the vertices in the unit cells around the reference are next, then the vertices of the unit cells around those, etc. To do so, PeriodicGraphs.jl export the hash_position function as follows:

        PeriodicGraphs.hash_positionFunction
        hash_position(x::PeriodicVertex{N}, n::Integer) where N

        Given x, a PeriodicVertex{N}, and the number n of vertex identifiers in a graph, compute a unique positive integer hash for the given vertex.

        This hash function is a bijection between the set of all the vertices of the periodic graph and the set of positive integers. Its value is an integer between 1+n*(2d-1)^N (or 1 if d == 0) and n*(2d+1)^N, where d = maximum(abs.(x.ofs)).

        In particular, this means that when one unit cell B is further than another A from the origin (for the Manhattan distance), all vertices in B have a larger hash than all vertices in A.

        source

        The reciproque function is also exported:

        PeriodicGraphs.reverse_hash_positionFunction
        reverse_hash_position(hash::Integer, n::Integer, ::Val{N}) where N

        Given a hash obtained from hash_position(x, n) where x is a PeriodicVertex{N}, return the corresponding x.

        If the offset of the returned PeriodicVertex is not needed, simply doing mod1(x, n) yields the identifier of the vertex and is faster.

        source

        Both functions are optimized for dimensions 1, 2 and 3, especially for unit cells not too far from the reference.

        Isomorphic transformations

        Several functions transform a periodic graph into another isomorphic to the input, by renumbering the vertices (vertex_permutation) or the axes (swap_axes!), or by offsetting the chosen representatives for each vertex (offset_representatives!). It is also possible to make an isomorphic graph with more vertices per unit cell by using a supercell (make_supercell).

        PeriodicGraphs.vertex_permutationFunction
        vertex_permutation(g::PeriodicGraph, vlist)

        Return the PeriodicGraph corresponding to g with its vertices identifiers permuted according to vlist. isperm(vlist) must hold and will not be checked.

        See also Graphs.induced_subgraph for the more general case where vlist is not a permutation.

        Note

        The resulting graph is isomorphic to the initial one, only the representation has changed.

        source
        PeriodicGraphs.swap_axes!Function
        swap_axes!(g::PeriodicGraph, t)

        In-place modifies graph g so that the new initial cell corresponds to the previous one with its axes swapped according to the permutation t.

        Note

        The resulting graph is isomorphic to the initial one, only the representation has changed.

        source
        PeriodicGraphs.offset_representatives!Function
        offset_representatives!(g::PeriodicGraph, offsets)

        In-place modifies graph g so that the i-th vertex of the new initial cell corresponds to the i-th vertex in cell offsets[i] compared to the previous initial cell.

        Note

        The resulting graph is isomorphic to the initial one, only the representation has changed.

        source
        PeriodicGraphs.make_supercellFunction
        make_supercell(g::PeriodicGraph, t)

        Return a graph isomorphic to the input g whose its unit cell is a repetition of that of g, each dimension i being repeated t[i] times. It follows that the number of vertices of make_supercell(g, t) is prod(t)*nv(g)

        t must be an interator over positive integers.

        source

        Dimension reduction

        Any PeriodicGraph can be naturally reduced to an aperiodic graph by removing all offsets from the edges and either keeping (quotient_graph) or removing (truncated_graph) edges crossing from one unit cell to another.

        PeriodicGraphs.quotient_graphFunction
        quotient_graph(g::PeriodicGraph)

        Extract a simple graph from g by removing all indications of offset in the edges. This means that edges that used to cross the boundaries of the initial cell now bind the source vertex to the representative of the destination vertex that is in the initial cell.

        Note that these modified edges may turn into loops.

        See also truncated_graph to remove all of these edges and slice_graph to keep only some of these edges.

        source

        It is also possible to reduce the dimension of a graph by removing only some selected offsets with the slice_graph function.

        PeriodicGraphs.slice_graphFunction
        slice_graph(g::PeriodicGraph{D}, remove::Union{SVector{N},NTuple{N}}) where {D,N}

        Extract a PeriodicGraph{D-N} from g by removing all edges that have an offset o such that !iszero(o[remove]) and shrinking the resulting offsets. In other words, remove the dimensions in remove.

        To only remove the edges while keeping the same number of dimensions, use slice_graph(g, collect(remove))

        remove is assumed to be sorted and to contain unique elements.

        Warning

        No verification of the previous assumption will be performed.

        source
        slice_graph(g::PeriodicGraph{D}, remove::Vector{<:Integer}) where D

        Extract a PeriodicGraph{D} from g by removing all edges that have an offset o such that !iszero(o[remove]).

        Contrarily to the slice_graph(g::PeriodicGraph{D}, remove::Union{SVector{N},NTuple{N}}) where {D,N} method, the dimensions along which the edges are erased are still kept here.

        remove is assumed to be sorted and to contain unique elements.

        Warning

        No verification of the previous assumption will be performed.

        source

        Arithmetics

        These utilities are internally used for dimensionality computations, but may be useful in other contexts.

        PeriodicGraphs.extended_gcdFunction
        extended_gcd(s)::Tuple{BigInt, Vector{BigInt}}

        Given a list of integers, return a tuple (d, coefs) where d is the gcd of these integers and coefs is a list of integers such that dot(s, coefs) == d.

        source
        PeriodicGraphs.normal_basisFunction
        normal_basis(l::AbstractVector{<:StaticVector{N,T}}) where {N,T<:Integer}

        Given a list of integer vectors of dimension N, return a tuple (mat, D) where D is the dimension of the space spanned by the input vectors, and mat is an 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. 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.

        source

        Unclassified other utilities

        These other convenience functions may be useful for the manipulation of PeriodicGraphs:

        PeriodicGraphs.find_edgesFunction
        find_edges(g::PeriodicGraph, s::Int, d::Int)

        Return the set of PeriodicVertex v of graph g such that there is an edge between a source vertex of identifier s and v, and the identifier of v is d.

        source
        +Utilities · PeriodicGraphs.jl

        Utilities

        Hashing

        It is sometimes convenient to be able to associate to each vertex of periodic graph g an integer hash, such that the hashes of vertices in the reference unit cell are between 1 and nv(g), the hashes of the vertices in the unit cells around the reference are next, then the vertices of the unit cells around those, etc. To do so, PeriodicGraphs.jl export the hash_position function as follows:

        PeriodicGraphs.hash_positionFunction
        hash_position(x::PeriodicVertex{N}, n::Integer) where N

        Given x, a PeriodicVertex{N}, and the number n of vertex identifiers in a graph, compute a unique positive integer hash for the given vertex.

        This hash function is a bijection between the set of all the vertices of the periodic graph and the set of positive integers. Its value is an integer between 1+n*(2d-1)^N (or 1 if d == 0) and n*(2d+1)^N, where d = maximum(abs.(x.ofs)).

        In particular, this means that when one unit cell B is further than another A from the origin (for the Manhattan distance), all vertices in B have a larger hash than all vertices in A.

        source

        The reciproque function is also exported:

        PeriodicGraphs.reverse_hash_positionFunction
        reverse_hash_position(hash::Integer, n::Integer, ::Val{N}) where N

        Given a hash obtained from hash_position(x, n) where x is a PeriodicVertex{N}, return the corresponding x.

        If the offset of the returned PeriodicVertex is not needed, simply doing mod1(x, n) yields the identifier of the vertex and is faster.

        source

        Both functions are optimized for dimensions 1, 2 and 3, especially for unit cells not too far from the reference.

        Isomorphic transformations

        Several functions transform a periodic graph into another isomorphic to the input, by renumbering the vertices (vertex_permutation) or the axes (swap_axes!), or by offsetting the chosen representatives for each vertex (offset_representatives!). It is also possible to make an isomorphic graph with more vertices per unit cell by using a supercell (make_supercell).

        PeriodicGraphs.vertex_permutationFunction
        vertex_permutation(g::PeriodicGraph, vlist)

        Return the PeriodicGraph corresponding to g with its vertices identifiers permuted according to vlist. isperm(vlist) must hold and will not be checked.

        See also Graphs.induced_subgraph for the more general case where vlist is not a permutation.

        Note

        The resulting graph is isomorphic to the initial one, only the representation has changed.

        source
        PeriodicGraphs.swap_axes!Function
        swap_axes!(g::PeriodicGraph, t)

        In-place modifies graph g so that the new initial cell corresponds to the previous one with its axes swapped according to the permutation t.

        Note

        The resulting graph is isomorphic to the initial one, only the representation has changed.

        source
        PeriodicGraphs.offset_representatives!Function
        offset_representatives!(g::PeriodicGraph, offsets)

        In-place modifies graph g so that the i-th vertex of the new initial cell corresponds to the i-th vertex in cell offsets[i] compared to the previous initial cell.

        Note

        The resulting graph is isomorphic to the initial one, only the representation has changed.

        source
        PeriodicGraphs.make_supercellFunction
        make_supercell(g::PeriodicGraph, t)

        Return a graph isomorphic to the input g whose its unit cell is a repetition of that of g, each dimension i being repeated t[i] times. It follows that the number of vertices of make_supercell(g, t) is prod(t)*nv(g)

        t must be an interator over positive integers.

        source

        Dimension reduction

        Any PeriodicGraph can be naturally reduced to an aperiodic graph by removing all offsets from the edges and either keeping (quotient_graph) or removing (truncated_graph) edges crossing from one unit cell to another.

        PeriodicGraphs.quotient_graphFunction
        quotient_graph(g::PeriodicGraph)

        Extract a simple graph from g by removing all indications of offset in the edges. This means that edges that used to cross the boundaries of the initial cell now bind the source vertex to the representative of the destination vertex that is in the initial cell.

        Note that these modified edges may turn into loops.

        See also truncated_graph to remove all of these edges and slice_graph to keep only some of these edges.

        source

        It is also possible to reduce the dimension of a graph by removing only some selected offsets with the slice_graph function.

        PeriodicGraphs.slice_graphFunction
        slice_graph(g::PeriodicGraph{D}, remove::Union{SVector{N},NTuple{N}}) where {D,N}

        Extract a PeriodicGraph{D-N} from g by removing all edges that have an offset o such that !iszero(o[remove]) and shrinking the resulting offsets. In other words, remove the dimensions in remove.

        To only remove the edges while keeping the same number of dimensions, use slice_graph(g, collect(remove))

        remove is assumed to be sorted and to contain unique elements.

        Warning

        No verification of the previous assumption will be performed.

        source
        slice_graph(g::PeriodicGraph{D}, remove::Vector{<:Integer}) where D

        Extract a PeriodicGraph{D} from g by removing all edges that have an offset o such that !iszero(o[remove]).

        Contrarily to the slice_graph(g::PeriodicGraph{D}, remove::Union{SVector{N},NTuple{N}}) where {D,N} method, the dimensions along which the edges are erased are still kept here.

        remove is assumed to be sorted and to contain unique elements.

        Warning

        No verification of the previous assumption will be performed.

        source

        Arithmetics

        These utilities are internally used for dimensionality computations, but may be useful in other contexts.

        PeriodicGraphs.extended_gcdFunction
        extended_gcd(s)::Tuple{BigInt, Vector{BigInt}}

        Given a list of integers, return a tuple (d, coefs) where d is the gcd of these integers and coefs is a list of integers such that dot(s, coefs) == d.

        source
        PeriodicGraphs.normal_basisFunction
        normal_basis(l::AbstractVector{<:StaticVector{N,T}}) where {N,T<:Integer}

        Given a list of integer vectors of dimension N, return a tuple (mat, D) where D is the dimension of the space spanned by the input vectors, and mat is an 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. 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.

        source

        Unclassified other utilities

        These other convenience functions may be useful for the manipulation of PeriodicGraphs:

        PeriodicGraphs.find_edgesFunction
        find_edges(g::PeriodicGraph, s::Int, d::Int)

        Return the set of PeriodicVertex v of graph g such that there is an edge between a source vertex of identifier s and v, and the identifier of v is d.

        source