Flexible and Rigid Graphs¶
This module implements functionality for investigating rigidity and flexibility of graphs.
The following notions from Rigidity Theory are used:
Let \(G=(V_G,E_G)\) be a graph with an edge labeling $\lambda:E_G\rightarrow \mathbb{R}_+$.
A realization $\rho:V_G\rightarrow\mathbb{R}^2$ is called compatible with $\lambda$ if $||\rho(u)-\rho(v)||=\lambda(uv)$ for all $uv\in E_G$.
The labeling $\lambda$ is called
- (proper) flexible if the number of (injective) realizations of $G$ compatible with $\lambda$ is infinite,
- rigid if the number of realizations of $G$ compatible with $\lambda$ is infinite,
where the counting is up to direct Euclidean isometries.
A graph is called movable iff it has a proper flexible labeling.
A graph is generically rigid, i.e., a generic realization defines a rigid labeling, if and only if the graph contains a Laman subgraph with the same set of vertices [Lam1970], [Pol1927].
A graph $G=(V_G,E_G)$ is called Laman if $|E_G| = 2|V_G|-3$, and $|E_H|\leq 2|V_H|-3$ for all subgraphs $H$ of $G$, see Wikipedia.
Methods¶
FlexRiGraph
Graph properties
is_complete() |
Return if the graph is complete. |
triangle_connected_components() |
Return triangle connected components. |
Movability
has_injective_grid_construction() |
Return if there is a NAC-coloring with injective grid coordinates. |
has_injective_spatial_embedding() |
Return if there is a spatial embeddings for some pair of NAC-colorings. |
is_movable() |
Return if the graph is movable. |
spatial_embeddings_four_directions() |
Return injective embeddings in $\mathbb{R}^3$ with edges in 4 directions. |
NAC-colorings
NAC_colorings() |
Return NAC-colorings of the graph. |
NAC_colorings_isomorphism_classes() |
Return partition of NAC-colorings into isomorphism classes. |
are_NAC_colorings_named() |
Return if all NAC-colorings have a unique name. |
cdc_is_complete() |
Return if the constant distance closure is the complete graph. |
constant_distance_closure() |
Return the constant distance closure of the graph. |
has_NAC_coloring() |
Return if the graph has a NAC-coloring. |
has_flexible_labeling() |
Alias for has_NAC_coloring() . |
name2NAC_coloring() |
Return the NAC-coloring with the given name. |
set_NAC_colorings_names() |
Set names of NAC-colorings according to isomorphism classes. |
unicolor_pairs() |
Return pairs of non-adjacent vertices linked by a unicolor path. |
unicolor_path() |
Return a unicolor path from u to v . |
Other
graph2int() |
Return the integer representation of the graph. |
has_min_degree_at_least_three() |
Return if all vertices have degree at least three. |
Plotting
plot() |
Return the plot of the graph. |
print_tikz() |
Print TikZ code of the graph. |
show_all_NAC_colorings() |
Show all NAC-colorings of the graph. The parameter ncols specifies in how many columns are the NAC colorings displayed. |
Rigidity
Henneberg_sequence() |
Return Henneberg sequence(s) of the graph. |
Henneberg_sequence2graphs() |
Return graphs of Henneberg sequence. |
is_Laman() |
Return whether the graph is Laman. |
mixed_volume() |
Return the mixed volume of the system of equations if the graph is Laman. |
num_realizations() |
Return the number of complex realizations if the graph is Laman. |
random_realization() |
Return a random realization of the graph. |
realization2edge_lengths() |
Return the edge lengths for realization . |
realizations() |
Return the realizations for given edge lengths if the graph is Laman. |
system_of_equations() |
Return the system of equation for edge_lengths . |
Subgraphs
four_cycles() |
Return all 4-cycles in the graph. INPUT: |
induced_K23s() |
Return all induced $K_{2,3}$ subgraphs. |
triangles() |
Return all triangles in the graph. |
AUTHORS:
- Jan Legerský (2019-01-15): initial version
- Jan Legerský (2020-03-12): update to SageMath 9.0
TODO:
- missing documentation of methods
- missing doctests in methods
- tutorial notebooks (basics, flexibility, classification, animations…)
FlexRiGraph¶
-
class
flexrilog.flexible_rigid_graph.
FlexRiGraph
(data, pos=None, name=None, check=True)[source]¶ Bases:
sage.graphs.graph.Graph
The class FlexRiGraph is inherited from sage.graphs.graph.Graph. It is a simple undirected connected graph with at least one edge. It adds functionality for rigidity and flexibility of the graph. The graph is immutable in order to prevent adding/removing edges or vertices.
INPUT:
data
: provides the information about edges. There are three possibilities:FlexRiGraph(list_of_edges)
– return the graph with the edges given bylist_of_edges
.FlexRiGraph(number)
– build a graph whose adjacence matrix is given as follows: the binary expansion of the integernumber
is written row by row into the upper triangle, excluding the diagonal, and symmetrically also into the lower triangle.FlexRiGraph(graph)
– return the graph with the same edges, positions and name asgraph
.
name
– gives the graph a namepos
– a positioning dictionary. For example, to draw 4 vertices on a squarepos={0: [-1,-1], 1: [ 1,-1], 2: [ 1, 1], 3: [-1, 1]}
.check
(boolean) – IfTrue
(default), then it is checked whether the graph connected and has at least one edge.
EXAMPLES:
The single edge graph:
sage: from flexrilog import FlexRiGraph sage: G = FlexRiGraph(1); G FlexRiGraph with the vertices [0, 1] and edges [(0, 1)]
Graphs without edges are not allowed:
sage: G = FlexRiGraph([]); G Traceback (most recent call last): ... ValueError: The graph must have at least one edge.
A named graph given by integer representation with specified positions:
sage: G = FlexRiGraph(7916, name='3-prism', ....: pos={0: [0.6, 0.4], 1: [0, 1.4], 2: [1, 1.4], ....: 3: [1, 0], 4: [0, 0], 5: [0.6, 1]}); G 3-prism: FlexRiGraph with the vertices [0, 1, 2, 3, 4, 5] and edges [(0, 3), (0, 4), (0, 5), (1, 2), (1, 4), (1, 5), (2, 3), (2, 5), (3, 4)] sage: from flexrilog import GraphGenerator sage: G == GraphGenerator.ThreePrismGraph() True
The dictionary
pos
is used when plotting:The 3-cycle graph given by the list of edges:
sage: G = FlexRiGraph([[0,1],[1,2],[0,2]], name='3-cycle'); G 3-cycle: FlexRiGraph with the vertices [0, 1, 2] and edges [(0, 1), (0, 2), (1, 2)]
An instance of sage.graphs.graph.Graph can be used:
sage: L = FlexRiGraph(graphs.CompleteBipartiteGraph(2,3)); L Complete bipartite graph of order 2+3: FlexRiGraph with the vertices [0, 1, 2, 3, 4] and edges [(0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4)]
TODO:
Other inputs: adjacency matrix-
Henneberg_sequence
(onlyOne=True)[source]¶ Return Henneberg sequence(s) of the graph.
The graph is Laman if and only if it can be constructed using Henneberg steps, see Wikipedia.
INPUT:
onlyOne
– ifTrue
(default), then only one Henneberg sequence is returned (if exists). Otherwise, all sequences are found.
OUTPUT:
The sequence is reversed - it describes the order of removing vertices by undoing Henneberg steps :
('I',u)
denotes that the vertexu
of degree two is removed and('II', u, (v, w))
means that the vertexu
of degree three is removed and the edge[v, w]
is added. If there is no Henneberg sequence, then the output isNone
.EXAMPLES:
A Henneberg sequence for 3-prism:
sage: from flexrilog import FlexRiGraph sage: G = FlexRiGraph(7916); G FlexRiGraph with the vertices [0, 1, 2, 3, 4, 5] and edges [(0, 3), (0, 4), (0, 5), (1, 2), (1, 4), (1, 5), (2, 3), (2, 5), (3, 4)] sage: print(G.Henneberg_sequence()) [('II', 0, (3, 5)), ('I', 4), ('I', 1), ('I', 2)]
4-cycle is not Laman:
sage: G = FlexRiGraph([[0,1],[1,2],[2,3],[0,3]]) sage: G.Henneberg_sequence()==None True
The complete graph $K_4$ is not Laman:
sage: G = FlexRiGraph([(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]) sage: G.Henneberg_sequence()==None True
All Henneberg sequence of $K_4$ with one edge removed:
sage: G = FlexRiGraph([[0,1],[1,2],[2,3],[0,3],[0,2]]) sage: G.Henneberg_sequence() [('I', 1), ('I', 0)] sage: G.Henneberg_sequence(onlyOne=False) [[('I', 1), ('I', 0)], [('I', 1), ('I', 0)], [('I', 1), ('I', 0)], [('I', 1), ('I', 0)], [('I', 1), ('I', 0)], [('I', 1), ('I', 0)], [('II', 0, (1, 3)), ('I', 1)], [('II', 0, (1, 3)), ('I', 1)], [('II', 0, (1, 3)), ('I', 1)], [('II', 2, (3, 1)), ('I', 0)], [('II', 2, (3, 1)), ('I', 0)], [('II', 2, (3, 1)), ('I', 0)]]
-
Henneberg_sequence2graphs
(seq)[source]¶ Return graphs of Henneberg sequence.
INPUT:
seq
- sequence of Henneberg steps as outputted byHenneberg_sequence()
.
OUTPUT:
Graphs obtained by applying the Henneberg sequence
seq
.EXAMPLE:
sage: from flexrilog import GraphGenerator sage: G = GraphGenerator.ThreePrismGraph() sage: seq = G.Henneberg_sequence(); seq [('II', 0, (3, 5)), ('I', 4), ('I', 1), ('I', 2)] sage: G.Henneberg_sequence2graphs(seq) [3-prism: Graph on 2 vertices, 3-prism: Graph on 3 vertices, 3-prism: Graph on 4 vertices, 3-prism: Graph on 5 vertices, 3-prism: Graph on 6 vertices]
-
NAC_colorings
()[source]¶ Return NAC-colorings of the graph.
If the NAC-colorings are already stored, then they are just returned, otherwise computed.
OUTPUT:
Only one NAC-coloring per conjugacy class is return.
EXAMPLES:
sage: from flexrilog import GraphGenerator sage: G = GraphGenerator.ThreePrismGraph() sage: G.NAC_colorings() [NAC-coloring with red edges [[0, 3], [0, 4], [1, 2], [1, 5], [2, 5], [3, 4]] and blue edges [[0, 5], [1, 4], [2, 3]]]
sage: from flexrilog import FlexRiGraph sage: K = FlexRiGraph(graphs.CompleteGraph(4)) sage: K.NAC_colorings() []
sage: K = FlexRiGraph(graphs.CompleteBipartiteGraph(3,3)) sage: len(K.NAC_colorings()) 15
The NAC-colorings are cached:
sage: K = FlexRiGraph(graphs.CompleteBipartiteGraph(3,3)) sage: %time len(K.NAC_colorings()) # doctest: +SKIP CPU times: user 418 ms, sys: 22.4 ms, total: 440 ms Wall time: 411 ms 15 sage: %time len(K.NAC_colorings()) # doctest: +SKIP CPU times: user 36 µs, sys: 3 µs, total: 39 µs Wall time: 55.1 µs 15
TODO:
Implement as an iterator?
-
NAC_colorings_isomorphism_classes
()[source]¶ Return partition of NAC-colorings into isomorphism classes.
See
flexrilog.NAC_coloring.NACcoloring.is_isomorphic()
for the definition of two NAC-colorings being isomorphic.EXAMPLE:
sage: from flexrilog import FlexRiGraph sage: G = FlexRiGraph(graphs.CompleteBipartiteGraph(2,3)) sage: isomorphism_classes = G.NAC_colorings_isomorphism_classes() sage: len(isomorphism_classes) 3 sage: [len(cls) for cls in isomorphism_classes] [1, 3, 3] sage: for cls in isomorphism_classes: print(cls[0]) NAC-coloring with red edges [[0, 2], [0, 3], [0, 4]] and blue edges [[1, 2], [1, 3], [1, 4]] NAC-coloring with red edges [[0, 2], [0, 3], [1, 2], [1, 3]] and blue edges [[0, 4], [1, 4]] NAC-coloring with red edges [[0, 2], [0, 3], [1, 4]] and blue edges [[0, 4], [1, 2], [1, 3]]
-
cdc_is_complete
(active_colorings=None)[source]¶ Return if the constant distance closure is the complete graph.
Theorem [GLS2018a]
A graph $G$ is movable if and only the constant distance closure of $G$ is movable.
Corollary
If $G$ is movable, then the constant distance closure of $G$ is not complete.
EXAMPLES:
sage: from flexrilog import GraphGenerator sage: G = GraphGenerator.ThreePrismGraph() sage: G.cdc_is_complete() False
sage: G = GraphGenerator.SmallestFlexibleLamanGraph() sage: G.cdc_is_complete() True
sage: G = GraphGenerator.MaxEmbeddingsLamanGraph(7) sage: G.cdc_is_complete() True
-
constant_distance_closure
(active_colorings=None, save_colorings=False)[source]¶ Return the constant distance closure of the graph.
Let $\operatorname{U}(G)$ denote the set of all pairs $\{u,v\}\subset V_G$ such that $uv\notin E_G$ and there exists a path from $u$ to $v$ which is unicolor for all NAC-colorings $\delta$ of $G$. If there exists a sequence of graphs $G=G_0, \dots, G_n$ such that $G_i=(V_{G_{i-1}},E_{G_{i-1}} \cup \operatorname{U}(G_{i-1}))$ for $i\in\{1,\dots,n\}$ and $\operatorname{U}(G_n)=\emptyset$, then the graph $G_n$ is called the constant distance closure of $G$.
INPUT:
active_colorings
(defaultNone
) – if specified, then they are used instead of all NAC-colorings of the graph.save_colorings
(defaultFalse
) – ifTrue
, then the constant distance closure is returned with the NAC-colorings obtained during the computation.
EXAMPLES:
sage: from flexrilog import GraphGenerator sage: G = GraphGenerator.ThreePrismGraph() sage: CDC = G.constant_distance_closure() sage: CDC.is_isomorphic(G) True
sage: G = GraphGenerator.SmallestFlexibleLamanGraph() sage: CDC = G.constant_distance_closure() sage: CDC.is_isomorphic(graphs.CompleteGraph(5)) True
sage: from flexrilog import FlexRiGraph sage: G = FlexRiGraph(1256267) sage: CDC = G.constant_distance_closure() sage: len(CDC.edges())-len(G.edges()) 1
TODO:
An interesting example with less NAC-colorings.
Speed up using triangle-components?
-
four_cycles
(only_with_NAC=False)[source]¶ Return all 4-cycles in the graph.
INPUT:
only_with_NAC
(defaultFalse
) – ifTrue
, then a 4-cycle is in the returned list only if there exists a NAC-coloring of the graph which is not unicolor on the 4-cycle.
OUTPUT:
List of all (in terms of the vertex set) 4-cycles given by ordered tuples of their vertices.
EXAMPLES:
sage: from flexrilog import GraphGenerator sage: G = GraphGenerator.ThreePrismGraph() sage: G.four_cycles() [(0, 3, 2, 5), (0, 4, 1, 5), (1, 2, 3, 4)]
sage: from flexrilog import FlexRiGraph sage: len(FlexRiGraph(graphs.CompleteGraph(7)).four_cycles()) == binomial(7,4)*3 True
sage: FlexRiGraph(graphs.CycleGraph(7)).four_cycles() []
-
graph2int
(canonical=True)[source]¶ Return the integer representation of the graph.
The graph has integer representation N if the binary expansion of
N
equals the sequence obtained by concatenation of the rows of the upper triangle of the adjacency matrix, excluding the diagonal.INPUT:
canonical
(boolean) – ifTrue
(default), then the adjacency matrix of the isomorphic graph obtained by canonical_label() is used. In this case, the isomorphic graphs have the same integer representation.
EXAMPLES:
sage: from flexrilog import FlexRiGraph sage: G = FlexRiGraph(graphs.CycleGraph(4)); G Cycle graph: FlexRiGraph with the vertices [0, 1, 2, 3] and edges [(0, 1), (0, 3), (1, 2), (2, 3)] sage: G.graph2int(canonical=False) 45 sage: G.adjacency_matrix() [0 1 0 1] [1 0 1 0] [0 1 0 1] [1 0 1 0] sage: int('101101',2) 45 sage: G.graph2int() 30 sage: H = FlexRiGraph(30); H FlexRiGraph with the vertices [0, 1, 2, 3] and edges [(0, 2), (0, 3), (1, 2), (1, 3)] sage: H.graph2int() 30
-
has_NAC_coloring
(certificate=False)[source]¶ Return if the graph has a NAC-coloring.
INPUT:
certificate
(boolean) – ifFalse
(default), then only boolean value is returned. Otherwise, the output is(True, NACcoloring)
or(False, None)
.
EXAMPLES:
sage: from flexrilog import GraphGenerator sage: G = GraphGenerator.ThreePrismGraph() sage: G.has_NAC_coloring() True sage: G.has_NAC_coloring(certificate=True) (True, NAC-coloring with red edges [[0, 3], [0, 4], [1, 2], [1, 5], [2, 5], [3, 4]] and blue edges [[0, 5], [1, 4], [2, 3]])
sage: from flexrilog import FlexRiGraph sage: K = FlexRiGraph(graphs.CompleteGraph(4)) sage: K.has_NAC_coloring() False sage: K.has_NAC_coloring(certificate=True) (False, None)
sage: K = FlexRiGraph(graphs.CompleteBipartiteGraph(3,3)) sage: K.has_NAC_coloring(certificate=True) (True, NAC-coloring with red edges [[0, 3], [0, 4], [0, 5], [1, 3], [1, 4], [1, 5]] and blue edges [[2, 3], [2, 4], [2, 5]])
-
has_flexible_labeling
(certificate=False)[source]¶ Alias for
has_NAC_coloring()
.A flexible labeling exists if and only if a NAC-coloring exists (Theorem 3.1 in [GLS2018]).
-
has_injective_grid_construction
(certificate=False)[source]¶ Return if there is a NAC-coloring with injective grid coordinates.
See
flexrilog.NAC_coloring.NACcoloring.grid_coordinates()
.INPUT:
certificate
(boolean) – ifFalse
(default), then only boolean value is returned. Otherwise, the output is(True, delta)
or(False, None)
, where thedelta
is a NAC-coloring giving injective grid construction.
EXAMPLES:
sage: from flexrilog import GraphGenerator sage: G = GraphGenerator.ThreePrismGraph() sage: G.has_injective_grid_construction(certificate=True) (True, NAC-coloring with red edges [[0, 3], [0, 4], [1, 2], [1, 5], [2, 5], [3, 4]] and blue edges [[0, 5], [1, 4], [2, 3]])
sage: from flexrilog import GraphGenerator sage: G = GraphGenerator.SmallestFlexibleLamanGraph() sage: G.has_injective_grid_construction() False
-
has_injective_spatial_embedding
(certificate=False, onlyOne=True)[source]¶ Return if there is a spatial embeddings for some pair of NAC-colorings.
The method runs
spatial_embeddings_four_directions()
for all pairs of NAC-colorings of the graph.INPUT:
certificate
– ifFalse
(default), then only boolean is returned. Otherwise, the output contains also the pair of NAC-colorings giving an injective spatial embedding (if it exists, otherwiseNone
).onlyOne
– ifTrue
, then only one pair on NAC-colorings is returned as a certificate, otherwise a list of all posibble ones.
EXAMPLES:
sage: from flexrilog import GraphGenerator sage: G = GraphGenerator.ThreePrismGraph() sage: G.has_injective_spatial_embedding(certificate=True) (False, None)
sage: G = GraphGenerator.Q1Graph() sage: G.has_injective_spatial_embedding(certificate=True) (True, [eta: NAC-coloring with 7 red edges and 4 blue edges , epsilon24: NAC-coloring with 7 red edges and 4 blue edges ])
sage: G.has_injective_spatial_embedding(certificate=True, onlyOne=False) # long time (True, [[eta: NAC-coloring with 7 red edges and 4 blue edges , ... epsilon14: NAC-coloring with 7 red edges and 4 blue edges ]])
-
induced_K23s
()[source]¶ Return all induced $K_{2,3}$ subgraphs.
OUTPUT:
List of all induced $K_{2,3}$ subgraphs given by of their vertices.
EXAMPLES:
sage: from flexrilog import GraphGenerator sage: G = GraphGenerator.Q1Graph() sage: G.induced_K23s() [[1, 2, 7, 3, 4], [3, 4, 5, 1, 7], [3, 4, 6, 2, 7]]
sage: from flexrilog import FlexRiGraph sage: FlexRiGraph(graphs.CompleteGraph(7)).induced_K23s() []
sage: len(FlexRiGraph(graphs.CompleteBipartiteGraph(4,6)).induced_K23s()) == binomial(4,3)*binomial(6,2) + binomial(4,2)*binomial(6,3) True
-
is_Laman
(algorithm=None, certificate=False)[source]¶ Return whether the graph is Laman.
A graph $G=(V_G,E_G)$ is called Laman if $|E_G| = 2|V_G|-3$, and $|E_H|\leq 2|V_H|-3$ for all subgraphs $H$ of $G$, see Wikipedia.
INPUT:
algorithm
(string) – there are two options:- If
algorithm = "definition"
, then the Laman condition on subgraphs is checked naively (VERY SLOW!!). - If
algorithm = "Henneberg"
(default), then a sequence of Henneberg steps is attempted to be found (SLOW!!).
- If
certificate
(boolean) – Ifcertificate = False
(default), then the returns only boolean. Otherwise:- If
algorithm = "Henneberg"
, then it either answers(True, s)
when the graph is Laman and can be constructed by Henneberg sequences
, or(False, None)
when it is not Laman. SeeHenneberg_sequence()
. - If
algorithm = "definition"
, then the certificate isNone
if the graph is Laman, otherwise(False, H)
, whereH
is the graph that violates the condition.
- If
EXAMPLES:
3-prism is Laman:
sage: from flexrilog import GraphGenerator sage: G = GraphGenerator.ThreePrismGraph() sage: G.is_Laman() True sage: G.is_Laman(certificate=True) (True, [('II', 0, (3, 5)), ('I', 4), ('I', 1), ('I', 2)]) sage: G.is_Laman(algorithm='definition') True
4-cycle is not Laman:
sage: from flexrilog import FlexRiGraph sage: G = FlexRiGraph([[0,1],[1,2],[2,3],[0,3]]) sage: G.is_Laman(algorithm='definition', certificate=True) (False, Graph on 4 vertices) sage: G.is_Laman(algorithm='Henneberg', certificate=True) (False, None)
The complete graph $K_4$ is not Laman:
sage: G = FlexRiGraph([(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]) sage: G.is_Laman(algorithm='definition', certificate=True) (False, Graph on 4 vertices) sage: G.is_Laman(algorithm='Henneberg', certificate=True) (False, None)
TODO:
Implementation of pebble game algorithm.
-
is_movable
()[source]¶ Return if the graph is movable.
The method tests the necessary condition
cdc_is_complete()
and sufficient ones:has_injective_grid_construction()
,has_injective_spatial_embedding()
and is_bipartite().OUTPUT:
- If the graph has no NAC-coloring,
then
('no', 'no NAC-coloring')
is returned. - If the constant distance closure is the complete graph,
then
('no', 'CDC is complete')
is returned. - If the graph is bipartite, then
('yes', 'bipartite')
- If the graph has a NAC-coloring giving an injective grid construction,
then
('yes', 'grid construction')
. - If the graph has a pair of NAC-coloring giving an injective spatial embedding,
then
('yes', 'spatial embedding')
. - Otherwise,
('cannot decide','')
.
EXAMPLES:
sage: from flexrilog import GraphGenerator sage: GraphGenerator.LamanGraphs(4)[0].is_movable() ('no', 'no NAC-coloring')
sage: from flexrilog import GraphGenerator sage: GraphGenerator.MaxEmbeddingsLamanGraph(7).is_movable() ('no', 'CDC is complete')
sage: from flexrilog import FlexRiGraph sage: FlexRiGraph(graphs.CompleteBipartiteGraph(3,3)).is_movable() ('yes', 'bipartite')
sage: GraphGenerator.ThreePrismGraph().is_movable() ('yes', 'grid construction')
sage: GraphGenerator.Q1Graph().is_movable() # long time ('yes', 'spatial embedding')
sage: GraphGenerator.S1Graph().is_movable() # long time ('cannot decide', '')
sage: len([G for G in GraphGenerator.LamanGraphs(6) if G.is_movable()[0]=='yes']) 2
TODO:
Graphs with a generic flexible labeling (not spanned by a Laman graph).
- If the graph has no NAC-coloring,
then
-
mixed_volume
(fixed_edge=None, check=True, full_list=False)[source]¶ Return the mixed volume of the system of equations if the graph is Laman.
The method uses phcpy to compute the mixed volume of the system of equations (
phcpy
must be installed) This gives an upper bound on the number of realizations.INPUT:
fixed_edge
- the system of equations is constructed with this fixed edge. IfNone
(default), then the minimum mixed volume over all edges is returned.check
- ifTrue
(default), then it is checked that the graph is Laman.full_list
(defaultFalse
) - ifTrue
andfixed_edge==None
, then the list of pairs[edge, MV]
is returned.
EXAMPLES:
sage: import phcpy # random, optional - phcpy sage: # the previous import is just because of the message that phcpy prints when imported sage: from flexrilog import GraphGenerator sage: GraphGenerator.ThreePrismGraph().mixed_volume() # optional - phcpy 32
sage: GraphGenerator.MaxEmbeddingsLamanGraph(7).mixed_volume() # optional - phcpy 64 sage: GraphGenerator.MaxEmbeddingsLamanGraph(7).mixed_volume([1,5]) # optional - phcpy 96 sage: GraphGenerator.MaxEmbeddingsLamanGraph(7).mixed_volume(full_list=True) # optional - phcpy [[(1, 2), 128], ... [(6, 7), 64]]
-
name2NAC_coloring
(name)[source]¶ Return the NAC-coloring with the given name.
TODO:
Implement using a dictionary instead of traversing the whole list each time.
-
num_realizations
(check=True)[source]¶ Return the number of complex realizations if the graph is Laman.
The method uses the package lnumber by J. Capco, see also [CGGKLS2018a].
EXAMPLE:
sage: from flexrilog import GraphGenerator sage: [GraphGenerator.MaxEmbeddingsLamanGraph(i).num_realizations() for i in range(6,13)] # optional - lnumber [24, 56, 136, 344, 880, 2288, 6180]
-
plot
(NAC_coloring=None, show_triangle_components=False, name_in_title=True, **kwargs)[source]¶ Return the plot of the graph.
INPUT:
NAC_coloring
– if an instance ofNACcoloring
is provided, then the edges are colored accordingly.show_triangle_components
(defaultFalse
) – ifTrue
, then the edges in the same $\triangle$-component have the same color.- for other options, see sage.graphs.generic_graph.GenericGraph.plot().
For instance,
pos
specifies the positions of the vertices.
EXAMPLES:
sage: from flexrilog import GraphGenerator sage: G = GraphGenerator.ThreePrismGraph() sage: print(G.plot(NAC_coloring=G.NAC_colorings()[0])) Graphics object consisting of 16 graphics primitives
sage: G.triangle_connected_components() [[[0, 3], [0, 4], [3, 4]], [[1, 2], [1, 5], [2, 5]], [[0, 5]], [[1, 4]], [[2, 3]]] sage: print(G.plot(show_triangle_components=True)) Graphics object consisting of 16 graphics primitives
sage: print(G.plot(pos={0: [0.3, 0.5], 1: [0, 2], 2: [1, 1.4], 3: [1, 0], 4: [0, 0], 5: [0.7, 1]})) Graphics object consisting of 16 graphics primitives
-
print_tikz
(colored_edges=[], color_names=['edge'], vertex_style='vertex', scale=1)[source]¶ Print TikZ code of the graph.
-
random_realization
()[source]¶ Return a random realization of the graph.
EXAMPLE:
sage: from flexrilog import GraphGenerator sage: GraphGenerator.ThreePrismGraph().random_realization() # random {0: (1.2663140331566647, 6.798542831673373), ... 5: (1.938458777654558, 4.519218477998938)}
-
realization2edge_lengths
(realization)[source]¶ Return the edge lengths for
realization
.EXAMPLE:
sage: from flexrilog import GraphGenerator sage: G = GraphGenerator.ThreePrismGraph() sage: G.realization2edge_lengths(G.random_realization()) # random {(0, 3): 0.5656854249492381, ... (3, 4): 1}
-
realizations
(edge_lengths, fixed_edge=None, check=True, tolerance_real=1e-08, prec='d', num_tasks=2)[source]¶ Return the realizations for given edge lengths if the graph is Laman.
The method uses phcpy to compute the solutions of the system of equations (
phcpy
must be installed)INPUT:
edge_lengths
– a dictionary assigning a length to each edge.fixed_edge
(defaultNone
) – if specified, then it is used as the fixed edge. Otherwise, one of the edges giving the minimal mixed volume is usedtolerance_real
(default 1e-8) – a solution is considered real if the absolute value of the imaginary part of each coordinate is smaller than this number.prec
(default'd'
) – precision used inphcpy
:'d'
for double precision,'dd'
for double double preicsion (about 32 decimal places) and'qd'
for quad double precision (about 64 decimal places).num_tasks
– number of threads used.
OUTPUT:
A pair
[result_real, result_complex]
of two lists is returned. The first list contains dictionaries with real realizations, whereas the second one with the complex solutions. If thefixed_edge
is in a 3-cycle, then realizations only with one orienation of the triangle are returned.EXAMPLE:
sage: import phcpy # random, optional - phcpy sage: # the previous import is just because of the message that phcpy prints when imported sage: from flexrilog import GraphGenerator sage: L = {(1, 2): 3, (1, 5): 4, (0, 5): 5, (0, 4): 3, (2, 3): 5, (0, 3): 2, (3, 4): 4, (2, 5): 2, (1, 4): 5} sage: res_RR, res_CC = GraphGenerator.ThreePrismGraph().realizations(L,[4,3]); (len(res_RR), len(res_CC)) # optional - phcpy (10, 2) sage: res_RR # random, optional - phcpy [{0: (2.62500000000000, 1.45236875482778), 1: (-0.988599837464227, 4.90129272349303), 2: (1.99414754086938, 4.58001702095087), 3: (4, 0), 4: (0, 0), 5: (2.6986546781728, 6.45182622423216)}, ... 5: (7.47928649393724, 2.65066030314919)}]
Some of the realizations from the example above:
-
set_NAC_colorings_names
(cls_names=[])[source]¶ Set names of NAC-colorings according to isomorphism classes.
The NAC-colorings in the same class have the same name with a different index.
INPUT:
cls_names
(default[]
)– if specified, then these names are taken for the isomorphism classes. Otherwise, Greek letters are taken.
EXAMPLE:
sage: from flexrilog import FlexRiGraph sage: G = FlexRiGraph(graphs.CompleteBipartiteGraph(2,3)) sage: G.set_NAC_colorings_names() sage: G.NAC_colorings() [alpha: NAC-coloring with red edges [[0, 2], [0, 3], [0, 4]] and blue edges [[1, 2], [1, 3], [1, 4]], beta1: NAC-coloring with red edges [[0, 2], [0, 3], [1, 2], [1, 3]] and blue edges [[0, 4], [1, 4]], gamma1: NAC-coloring with red edges [[0, 2], [0, 3], [1, 4]] and blue edges [[0, 4], [1, 2], [1, 3]], beta2: NAC-coloring with red edges [[0, 2], [0, 4], [1, 2], [1, 4]] and blue edges [[0, 3], [1, 3]], gamma2: NAC-coloring with red edges [[0, 2], [0, 4], [1, 3]] and blue edges [[0, 3], [1, 2], [1, 4]], beta3: NAC-coloring with red edges [[0, 2], [1, 2]] and blue edges [[0, 3], [0, 4], [1, 3], [1, 4]], gamma3: NAC-coloring with red edges [[0, 2], [1, 3], [1, 4]] and blue edges [[0, 3], [0, 4], [1, 2]]]
-
show_all_NAC_colorings
(ncols=3, only_return=False)[source]¶ Show all NAC-colorings of the graph.
The parameter
ncols
specifies in how many columns are the NAC colorings displayed.
-
spatial_embeddings_four_directions
(delta_1, delta_2, vertex_at_origin=None)[source]¶ Return injective embeddings in $\mathbb{R}^3$ with edges in 4 directions.
The method attempts to embedd injectively the vertices of the graph into $\mathbb{R}^3$ so that two edges are parallel if and only if they obtain the same colors by
delta_1
anddelta_2
. The four possible directions are (1,0,0), (0,1,0), (0,0,1) and (-1,-1,-1). If such an embedding exists, then the graph is movable:Lemma [GLS2018a]
Let $G=(V,E)$ be a graph with an injective embedding $\omega:V\rightarrow\mathbb{R}^3$ such that for every edge $uvin E$, the vector $\omega(u)-\omega(v)$ is parallel to one of the four vectors $(1,0,0)$, $(0,1,0)$, $(0,0,1)$, $(-1,-1,-1)$, and all four directions are present. Then $G$ is movable.
Moreover, there exist two NAC-colorings such that two edges are parallel in the embedding $\omega$ if and only if they receive the same pair of colors.
INPUT:
delta_1
anddelta_2
– NAC-coloringsvertex_at_origin
– ifNone
(default), then the first vertex is placed to the origin.
OUTPUT:
A dictionary with parametrized positions of vertices, if the embedding exists, otherwise
None
.EXAMPLE:
sage: from flexrilog import GraphGenerator sage: G = GraphGenerator.Q1Graph() sage: G.spatial_embeddings_four_directions(G.name2NAC_coloring('epsilon13'), G.name2NAC_coloring('epsilon24')) {1: (0, 0, 0), 2: (2*a, a, a), 3: (a, a, a), 4: (a, 0, 0), 5: (0, -a, 0), 6: (2*a, a, 2*a), 7: (a, 0, a)}
-
system_of_equations
(edge_lengths, fixed_edge)[source]¶ Return the system of equation for
edge_lengths
.The method returns the system of equations for edge lengths with new variables for the squares of distances of vertices from the origin in order to decrease the mixed volume of the system.
INPUT:
edge_lengths
– a dictionary assigning every edge a length.fixed_edge
– the first vertex is placed to the origin whereas the second one on the x-axis.
OUTPUT:
A pair
[eqs, v]
is returned, whereeqs` are the equations and ``v
is a vertex adjacent to both vertices offixed_edge
if it exists, orNone
otherwise. If it exists, then the triangle is fixed instead of just the edge, in order to simplify the system.EXAMPLES:
sage: from flexrilog import GraphGenerator sage: G = GraphGenerator.ThreePrismGraph() sage: L = {(0, 3): 2, (0, 4): 3, (0, 5): 5, (1, 2): 3, (1, 4): 5, (1, 5): 4, (2, 3): 5, (2, 5): 2, (3, 4): 4 } sage: G.system_of_equations(L, [4,3]) # random [[s5 - 5.25000000000000*x5 - 2.90473750965556*y5 - 16.0000000000000, ... -x2^2 - y2^2 + s2, -x5^2 - y5^2 + s5], 0]
-
triangle_connected_components
()[source]¶ Return triangle connected components.
Two edges are in relation if they are in the same 3-cycle subgraph. The equivalence classes of the reflexive-transitive closure of this relation are called $\triangle$-connected components [GLS2018].
OUTPUT:
Partition of the edges into the $\triangle$-connected components.
EXAMPLE:
sage: from flexrilog import FlexRiGraph sage: G = FlexRiGraph([(1,6),(2,6),(0,6),(0, 3), (0, 4), ....: (0, 5), (1, 2), (1, 4), (1, 5), (2, 3), (2, 5), (3, 4)]); G FlexRiGraph with 7 vertices and 12 edges sage: G.triangle_connected_components() [[[0, 3], [0, 4], [3, 4]], [[1, 2], [1, 5], [1, 6], [2, 5], [2, 6]], [[0, 5]], [[0, 6]], [[1, 4]], [[2, 3]]]
sage: from flexrilog import GraphGenerator sage: G = GraphGenerator.ThreePrismGraph() sage: G.triangle_connected_components() [[[0, 3], [0, 4], [3, 4]], [[1, 2], [1, 5], [2, 5]], [[0, 5]], [[1, 4]], [[2, 3]]]
TODO:
Change so that the edge labels are not used (without creating extra copy).
-
triangles
()[source]¶ Return all triangles in the graph.
OUTPUT:
List of all triangles given by their vertices.
EXAMPLES:
Bipartite graphs have no triangles:
sage: from flexrilog import FlexRiGraph sage: G = FlexRiGraph(graphs.CompleteBipartiteGraph(2,3)) sage: G.triangles() []
The 3-prism graph has two triangles:
sage: from flexrilog import GraphGenerator sage: G = GraphGenerator.ThreePrismGraph() sage: G.triangles() [[0, 3, 4], [1, 2, 5]]
The complete graph on 5 vertices:
sage: len(FlexRiGraph(graphs.CompleteGraph(5)).triangles()) == binomial(5,3) True
-
unicolor_pairs
(active_colorings)[source]¶ Return pairs of non-adjacent vertices linked by a unicolor path.
INPUT:
active_colorings
– colorings considered for unicolor paths.
OUTPUT:
List of pairs of non-adjacent vertices
u
andv
connected by a unicolor pathpath
in the form[[u,v],path]
.
-
unicolor_path
(u, v, active_colorings=None)[source]¶ Return a unicolor path from
u
tov
.A path is unicolor if for all NAC-colorings $\delta$ of the graph, $|\{\delta(e):e\in E_G\}|=1$.
INPUT:
u
andv
– start and endpoint.active_colorings
(defaultNone
) – if specified, then only the given colorings are considered instead of all.
OUTPUT:
A path given by vertices or
[]
if there is none.EXAMPLES:
sage: from flexrilog import GraphGenerator sage: G = GraphGenerator.SmallestFlexibleLamanGraph() sage: G.unicolor_path(2,3) [2, 0, 1, 3]
sage: G = GraphGenerator.ThreePrismGraph() sage: G.unicolor_path(2,3) [2, 3] sage: G.has_edge(2,3) True sage: G.unicolor_path(1,3) []
sage: G = GraphGenerator.MaxEmbeddingsLamanGraph(8) sage: G.unicolor_path(2,4) [] sage: G.unicolor_path(2,4, active_colorings=G.NAC_colorings()[-2:]) [2, 1, 4]