| Title: | Topological Connectivity Analysis for Numeric Data |
|---|---|
| Description: | Topological data analysis methods based on graph-theoretic approaches for discovering topological structures in data. Constructs topological spaces from graphs following Nada et al. (2018) <doi:10.1002/mma.4726>, with visibility graph construction for time series following Lacasa et al. (2008) <doi:10.1073/pnas.0709247105>. Supports directed visibility graphs for bitopological analysis of temporal irreversibility (Kelly, 1963), and Alexandrov topology construction from reachability preorders. |
| Authors: | José Mauricio Gómez Julián [aut, cre] |
| Maintainer: | José Mauricio Gómez Julián <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.2.0 |
| Built: | 2026-05-29 19:30:56 UTC |
| Source: | https://github.com/IsadoreNabi/topologyR |
Analyzes how different IQR factors affect topology characteristics. Helps determine the optimal factor by showing how the factor choice impacts base size and set sizes.
Note: This function uses threshold-based neighborhoods (metric
approximation), not the graph-theoretic approach of Nada et al. (2018).
For the theoretically faithful approach, use visibility graphs with
generate_topology.
analyze_topology_factors(data, factors = NULL, plot = TRUE)analyze_topology_factors(data, factors = NULL, plot = TRUE)
data |
Numeric vector containing the data to analyze. |
factors |
Numeric vector of factors to test
(default: |
plot |
Logical, whether to return a plot object (default: |
A data.frame with columns:
Numeric. The IQR factor used.
Numeric. The calculated threshold (IQR/factor).
Integer. Number of sets in the base.
Integer. Size of the largest set.
Integer. Size of the smallest set.
If plot = TRUE, the data.frame carries an attribute "plot"
containing a ggplot object.
data <- rnorm(50) results <- analyze_topology_factors(data) print(results)data <- rnorm(50) results <- analyze_topology_factors(data) print(results)
Given the forward topology and backward topology
(as returned by generate_topology), computes bitopological
invariants that quantify temporal irreversibility and structural asymmetry.
bitopology_invariants( forward, backward, n_elements, undirected = NULL, alexandrov = NULL )bitopology_invariants( forward, backward, n_elements, undirected = NULL, alexandrov = NULL )
forward |
The forward Nada topology |
backward |
The backward Nada topology |
n_elements |
Integer. Total number of elements in the ground set V. |
undirected |
The undirected Nada topology (optional, for comparison). |
alexandrov |
The Alexandrov topology (optional, for resolution comparison). |
Pairwise connectedness (Kelly, 1963): the bitopological space
is pairwise disconnected if there exists a
proper non-empty subset that is simultaneously
-open and -closed (its complement is
-open). This is checked by iterating over all
open sets and testing whether their complement is
-open.
Irreversibility prediction (Lacasa & Toral, 2010): for a time
series with asymmetric dynamics (e.g., gradual expansions and abrupt
recessions), the forward topology should be more connected
than , because forward visibility is less obstructed during
gradual rises than backward visibility after abrupt drops.
Resolution gain: the difference
quantifies how
much additional structure the Nada intersection/union closure captures
beyond the pure Alexandrov order structure. A large gain means the
Nada pipeline is extracting genuinely new topological information.
A list with:
Integer. Number of connected components in
.
Integer. Number of connected components in
.
Logical. Whether is connected.
Logical. Whether is connected.
Integer. Number of base elements in
.
Integer. Number of base elements in
.
Numeric in the range 0 to 1. Normalized
asymmetry of component counts:
.
Zero means equal component counts (necessary for reversibility).
Numeric in the range 0 to 1. Normalized asymmetry of base sizes.
Integer. . Positive means
the forward topology is more connected (fewer components) than the
backward topology, consistent with gradual expansions (forward
visibility) and abrupt contractions (backward obstruction).
A list with pairwise connectedness results. Contains
pairwise_connected (logical or NA),
clopen_forward (integer vector, the forward-open / backward-
closed set if disconnected), and clopen_backward (its
complement). Requires both topologies to be fully enumerated
(max_open_sets > 0 and complete = TRUE).
A list comparing the Nada and Alexandrov topologies
(if alexandrov is provided). Contains base size comparisons
and relative resolution gains.
A list with undirected topology summary (if
undirected is provided).
Kelly, J. C. (1963). Bitopological spaces. Proceedings of the London Mathematical Society, 3(1), 71-89.
generate_bitopology for the complete pipeline.
series <- c(3, 1, 4, 1, 5, 9, 2, 6) g <- horizontal_visibility_graph(series, directed = TRUE) tf <- generate_topology(g$out_adjacency, g$n, max_open_sets = 0L) tb <- generate_topology(g$in_adjacency, g$n, max_open_sets = 0L) inv <- bitopology_invariants(tf, tb, g$n) inv$asymmetry_directionseries <- c(3, 1, 4, 1, 5, 9, 2, 6) g <- horizontal_visibility_graph(series, directed = TRUE) tf <- generate_topology(g$out_adjacency, g$n, max_open_sets = 0L) tb <- generate_topology(g$in_adjacency, g$n, max_open_sets = 0L) inv <- bitopology_invariants(tf, tb, g$n) inv$asymmetry_direction
Computes five different threshold methods for defining neighborhoods in threshold-based topology construction.
Note: Threshold-based methods produce metric topologies, not
the graph-induced topologies of Nada et al. (2018). See
generate_topology for the theoretically faithful approach.
calculate_thresholds(data)calculate_thresholds(data)
data |
Numeric vector to calculate thresholds for. |
A named list with five threshold values:
Mean of absolute differences between adjacent sorted values.
Median of absolute differences between adjacent sorted values.
Standard deviation of the data.
IQR divided by 4.
k-th nearest neighbor distance (k = ceiling(log(n))).
calculate_thresholds(rnorm(100))calculate_thresholds(rnorm(100))
Calculate topology base size for a given threshold
calculate_topology(data, threshold)calculate_topology(data, threshold)
data |
Numeric vector to analyze. |
threshold |
Numeric value for the threshold parameter. Must be non-negative. |
integer scalar. The number of sets in the topological base.
calculate_topology(rnorm(30), threshold = 0.5)calculate_topology(rnorm(30), threshold = 0.5)
Constructs a topology from the complete graph on the data points.
In the complete graph, every vertex is a neighbor of every other vertex,
so each neighborhood is . The resulting
topology is generated using the fixed-point closure algorithm.
Note: The complete graph produces trivial neighborhoods
(all vertices except self). For meaningful topological structure,
use visibility graphs with generate_topology.
complete_topology(data, verify_axioms = FALSE)complete_topology(data, verify_axioms = FALSE)
data |
Numeric vector containing the data points. Length must be between 2 and 64. |
verify_axioms |
Logical. Whether to verify topology axioms
(default: |
A list with the same structure as generate_topology.
result <- complete_topology(c(1, 2, 3, 4, 5)) result$n_open_sets result$connectedresult <- complete_topology(c(1, 2, 3, 4, 5)) result$n_open_sets result$connected
Computes the Alexandrov topology induced by a directed acyclic graph (DAG)
via bitset-based reachability propagation. The open sets are the upsets of
the reachability relation: vertex 's minimal open set is the set of
all vertices reachable from via directed paths (including
itself).
The Alexandrov topology is a lower bound on the resolution of
the Nada et al. (2018) topology: .
The difference in base sizes quantifies how much additional structure
the intersection/union closure of Nada et al. captures beyond the pure
order structure.
generate_alexandrov_topology( out_adjacency, n_elements, max_open_sets = 0L, check_connected = TRUE, verify_axioms = FALSE )generate_alexandrov_topology( out_adjacency, n_elements, max_open_sets = 0L, check_connected = TRUE, verify_axioms = FALSE )
out_adjacency |
A list of integer vectors, where element |
n_elements |
Integer. Total number of elements in the ground set V. |
max_open_sets |
Integer. Maximum number of open sets to enumerate
(default: 0, meaning skip enumeration). The Alexandrov topology can have
up to |
check_connected |
Logical. Whether to compute exact topological
connectivity via the specialization preorder (default: |
verify_axioms |
Logical. Whether to verify topology axioms after
enumeration (default: |
The algorithm computes reachability in time by
processing vertices in reverse topological order (= reverse time order
for visibility graphs) and propagating reachability sets as multi-word
bitsets with OR operations. This reuses the same bitset infrastructure
as the Nada engine with compile-time template dispatch for
.
The Alexandrov topology on a finite set equipped with a preorder is canonical: there is a bijection between preorders and Alexandrov topologies (Alexandrov, 1937). For directed visibility graphs, the reachability preorder captures the temporal ordering structure of the time series.
A list with the same structure as
generate_topology:
List of integer vectors. The upsets (= base for Alexandrov).
List of integer vectors. Same as subbase (upsets are already closed under intersection).
Always TRUE (no iteration needed).
Logical. Exact topological connectivity.
List of integer vectors. Exact connected components.
List of integer vectors, or NULL. Open sets if
enumerated.
Integer, or NA. Number of open sets if enumerated.
Logical. Whether enumeration finished.
Alexandrov, P. (1937). Diskrete Raume. Matematicheskii Sbornik, 2(44), 501-519.
generate_topology for the Nada et al. topology,
generate_bitopology for the complete bitopological analysis.
series <- c(3, 1, 4, 1, 5) g <- horizontal_visibility_graph(series, directed = TRUE) alex <- generate_alexandrov_topology(g$out_adjacency, g$n) alex$connected length(alex$base)series <- c(3, 1, 4, 1, 5) g <- horizontal_visibility_graph(series, directed = TRUE) alex <- generate_alexandrov_topology(g$out_adjacency, g$n) alex$connected length(alex$base)
Performs a complete bitopological analysis of a time series by constructing directed visibility graphs and computing four topological spaces:
Undirected Nada topology : from the symmetric
(undirected) visibility graph (standard Nada et al. 2018).
Forward Nada topology : from closed forward
neighborhoods .
Backward Nada topology : from closed backward
neighborhoods .
Alexandrov topology : from reachability upsets
of the directed graph.
The pair forms a bitopological space
(Kelly, 1963). The divergence between and
quantifies temporal irreversibility: in a reversible process,
; in an irreversible process (e.g., asymmetric
business cycles), they diverge.
generate_bitopology( series, graph_type = c("hvg", "nvg"), max_open_sets = 0L, max_base_sets = 100000L, alexandrov = TRUE )generate_bitopology( series, graph_type = c("hvg", "nvg"), max_open_sets = 0L, max_base_sets = 100000L, alexandrov = TRUE )
series |
Numeric vector representing the time series. |
graph_type |
Character. Either |
max_open_sets |
Integer. Maximum open sets to enumerate per topology (default: 0, skip enumeration). Required for pairwise connectedness check. |
max_base_sets |
Integer. Maximum base elements during intersection closure for the Nada topologies (default: 100,000). |
alexandrov |
Logical. Whether to also compute the Alexandrov topology
for resolution comparison (default: |
The existing undirected engine is called three times (undirected, forward,
backward) and the Alexandrov engine once. No new C++ code is needed for the
forward and backward topologies: passing directed adjacency lists to the
existing generate_topology produces the correct closed
neighborhoods or automatically (the engine
always adds the self-loop ).
A list with:
The directed visibility graph (output of
horizontal_visibility_graph or
natural_visibility_graph with directed = TRUE).
The undirected Nada topology
(output of generate_topology).
The forward Nada topology .
The backward Nada topology .
The Alexandrov topology (if requested).
Bitopological invariants (output of
bitopology_invariants).
Kelly, J. C. (1963). Bitopological spaces. Proceedings of the London Mathematical Society, 3(1), 71-89.
Lacasa, L., & Toral, R. (2010). Description of stochastic and chaotic series using visibility graphs. Physical Review E, 82(3), 036120.
bitopology_invariants for computing invariants
from pre-computed topologies.
series <- c(3, 1, 4, 1, 5, 9, 2, 6) bt <- generate_bitopology(series, graph_type = "hvg") bt$invariants$forward_components bt$invariants$backward_components bt$invariants$irreversibility_componentsseries <- c(3, 1, 4, 1, 5, 9, 2, 6) bt <- generate_bitopology(series, graph_type = "hvg") bt$invariants$forward_components bt$invariants$backward_components bt$invariants$irreversibility_components
Given a graph (represented by its adjacency list of neighborhoods), generates the induced topology following Nada et al. (2018). The procedure is:
The neighborhoods form the subbase.
The base is the closure of the subbase under finite intersections (wavefront propagation in C++).
Topological connectivity is determined exactly via the specialization preorder on the base (Alexandrov theorem for finite spaces), without requiring topology enumeration.
Optionally, the full topology (closure under arbitrary unions) is
enumerated, subject to a max_open_sets limit.
The connectivity result is exact: the connected components returned are the true topological connected components, not approximations.
generate_topology( adjacency, n_elements, max_open_sets = 1000000L, max_base_sets = 100000L, check_connected = TRUE, verify_axioms = FALSE )generate_topology( adjacency, n_elements, max_open_sets = 1000000L, max_base_sets = 100000L, check_connected = TRUE, verify_axioms = FALSE )
adjacency |
A list of integer vectors, where element |
n_elements |
Integer. Total number of elements in the ground set V. |
max_open_sets |
Integer. Maximum number of open sets to enumerate
(default: 1,000,000). If the topology exceeds this limit, enumeration
stops and |
max_base_sets |
Integer. Maximum number of base elements during
intersection closure (default: 100,000). If exceeded, closure stops
early and |
check_connected |
Logical. Whether to compute exact topological
connectivity via the specialization preorder (default: |
verify_axioms |
Logical. Whether to verify topology axioms after
enumeration (default: |
A list with:
List of integer vectors. The neighborhoods used as subbase.
List of integer vectors. The base (closure under intersections).
Logical. Whether the base closure finished within
the max_base_sets limit.
Logical. Whether the topological space is connected.
This is an exact result based on the specialization preorder.
NA if check_connected = FALSE.
List of integer vectors. The exact topological connected components. Each component is a vector of 1-based element indices.
List of integer vectors, or NULL. The open sets,
if enumeration was requested and feasible.
Integer, or NA. Number of open sets if enumerated.
Logical. Whether the topology enumeration finished
within the max_open_sets limit.
Integer. Wavefront iterations for base closure.
Integer. Wavefront iterations for union closure.
Logical (only if verify_axioms = TRUE and
complete = TRUE).
Character (only if axiom verification fails).
Nada, S., El Atik, A. E. F., & Atef, M. (2018). New types of topological structures via graphs. Mathematical Methods in the Applied Sciences, 41(15), 5801-5810. doi:10.1002/mma.4726
# From a small visibility graph series <- c(3, 1, 4, 1, 5) g <- horizontal_visibility_graph(series) topo <- generate_topology(g$adjacency, g$n) topo$connected length(topo$components)# From a small visibility graph series <- c(3, 1, 4, 1, 5) g <- horizontal_visibility_graph(series) topo <- generate_topology(g$adjacency, g$n) topo$connected length(topo$components)
Constructs the Horizontal Visibility Graph (HVG) from a time series.
Two observations and with
are connected if and only if every intermediate observation
satisfies .
The HVG is parameter-free and captures structural properties of the series
dynamics. It is computed in time using a stack-based algorithm.
horizontal_visibility_graph(series, directed = FALSE)horizontal_visibility_graph(series, directed = FALSE)
series |
Numeric vector representing the time series. The position index is used as the time coordinate. |
directed |
Logical. If |
The algorithm uses a monotone stack with time and space
complexity. Each element is pushed and popped at most once.
The adjacency list returned as adjacency provides the neighborhood
structure for each vertex, which serves as the subbase for
inducing a topology following Nada et al. (2018).
When directed = TRUE, the function additionally returns directed
adjacency lists. By construction, all edges satisfy from < to
(earlier time to later time), so the directed graph is a DAG with the
time index as topological order.
A list with:
A data.frame with columns from and to
(integer, 1-based indices) representing undirected edges.
Integer. Number of observations in the series.
Integer. Number of edges in the graph.
A list of integer vectors, where element i
contains the indices of all neighbors of node i. This is
the neighborhood structure used as subbase for topology induction.
(Only if directed = TRUE.) A list of integer
vectors, where element i contains the indices of all forward
(later-in-time) neighbors. Used as subbase for the forward Nada
topology or as input for the Alexandrov topology.
(Only if directed = TRUE.) A list of integer
vectors, where element i contains the indices of all backward
(earlier-in-time) neighbors. Used as subbase for the backward Nada
topology .
Luque, B., Lacasa, L., Ballesteros, F., & Luque, J. (2009). Horizontal visibility graphs: exact results for random time series. Physical Review E, 80(4), 046103. doi:10.1103/PhysRevE.80.046103
series <- c(3, 1, 4, 1, 5, 9, 2, 6) g <- horizontal_visibility_graph(series) g$n_edges head(g$edges) # Directed graph for bitopological analysis gd <- horizontal_visibility_graph(series, directed = TRUE) gd$out_adjacency[[1]] # forward neighbors of first observationseries <- c(3, 1, 4, 1, 5, 9, 2, 6) g <- horizontal_visibility_graph(series) g$n_edges head(g$edges) # Directed graph for bitopological analysis gd <- horizontal_visibility_graph(series, directed = TRUE) gd$out_adjacency[[1]] # forward neighbors of first observation
Converts the topology into an undirected graph (two elements share an edge if they appear together in any open set) and checks graph connectivity via depth-first search.
Note: This is a necessary but not sufficient condition for
topological connectivity. For an exact check, use
is_topology_connected_exact.
is_topology_connected(topology)is_topology_connected(topology)
topology |
A list of integer vectors representing the open sets. |
logical scalar. TRUE if the derived graph is connected,
FALSE otherwise or if the topology is empty.
topology <- list(c(1, 2, 3), c(3, 4, 5)) is_topology_connected(topology)topology <- list(c(1, 2, 3), c(3, 4, 5)) is_topology_connected(topology)
Checks whether a topological space is connected by verifying
the exact definition: no proper non-empty open set has an open complement.
Uses multi-word bitset representation and hash lookup.
is_topology_connected_exact(topology, n_elements)is_topology_connected_exact(topology, n_elements)
topology |
A list of integer vectors representing the open sets. |
n_elements |
Integer. Total number of elements in V. |
A list with:
Logical. TRUE if the space is topologically
connected.
Integer vector (only if disconnected). One component.
Integer vector (only if disconnected). The complement.
# A connected topology tau <- list(integer(0), 1:3, c(1L, 2L), c(2L, 3L)) is_topology_connected_exact(tau, 3L) # A disconnected topology tau2 <- list(integer(0), 1:4, c(1L, 2L), c(3L, 4L)) is_topology_connected_exact(tau2, 4L)# A connected topology tau <- list(integer(0), 1:3, c(1L, 2L), c(2L, 3L)) is_topology_connected_exact(tau, 3L) # A disconnected topology tau2 <- list(integer(0), 1:4, c(1L, 2L), c(3L, 4L)) is_topology_connected_exact(tau2, 4L)
Checks whether every integer from 1 to the maximum value in the topology
appears in at least one open set. This verifies coverage
(), not topological connectivity.
Note: A space can have full coverage and be maximally disconnected
(e.g., the discrete topology). For connectivity, use
is_topology_connected_exact.
is_topology_connected_manual(topology)is_topology_connected_manual(topology)
topology |
A list of integer vectors representing the open sets. |
logical scalar. TRUE if all elements from 1 to the
maximum are present in at least one set.
topology <- list(c(1, 2, 3), c(3, 4, 5)) is_topology_connected_manual(topology)topology <- list(c(1, 2, 3), c(3, 4, 5)) is_topology_connected_manual(topology)
Converts the topology into a directed graph (sequential edges between sorted elements within each set) and checks reachability via DFS.
Note: This is a necessary but not sufficient condition for
topological connectivity. For an exact check, use
is_topology_connected_exact.
is_topology_connected2(topology)is_topology_connected2(topology)
topology |
A list of integer vectors representing the open sets. |
logical scalar. TRUE if all elements are reachable
from the minimum element via directed edges, FALSE otherwise.
topology <- list(c(1, 2, 3), c(3, 4, 5)) is_topology_connected2(topology)topology <- list(c(1, 2, 3), c(3, 4, 5)) is_topology_connected2(topology)
Constructs the Natural Visibility Graph (NVG) from a time series.
Two observations and with
are connected if and only if every intermediate observation
satisfies:
The NVG is parameter-free and richer in structure than the HVG (more edges),
preserving dynamical properties such as periodicity, chaoticity, and
long-range correlations. Computed in expected time.
natural_visibility_graph(series, directed = FALSE)natural_visibility_graph(series, directed = FALSE)
series |
Numeric vector representing the time series. The position index is used as the time coordinate. |
directed |
Logical. If |
The algorithm uses divide-and-conquer on the global maximum. The maximum
point blocks all cross-edges between the left and right halves, so the
problem decomposes cleanly. Edges from the pivot are found by a linear
slope scan. Expected time is ; worst case (monotone data)
is .
When directed = TRUE, the function additionally returns directed
adjacency lists. By construction, all edges satisfy from < to
(earlier time to later time), so the directed graph is a DAG.
A list with the same structure as
horizontal_visibility_graph.
Lacasa, L., Luque, B., Ballesteros, F., Luque, J., & Nuno, J. C. (2008). From time series to complex networks: The visibility graph. Proceedings of the National Academy of Sciences, 105(13), 4972-4975. doi:10.1073/pnas.0709247105
series <- c(3, 1, 4, 1, 5, 9, 2, 6) g <- natural_visibility_graph(series) g$n_edges head(g$edges) # Directed graph for bitopological analysis gd <- natural_visibility_graph(series, directed = TRUE) gd$out_adjacency[[1]] # forward neighbors of first observationseries <- c(3, 1, 4, 1, 5, 9, 2, 6) g <- natural_visibility_graph(series) g$n_edges head(g$edges) # Directed graph for bitopological analysis gd <- natural_visibility_graph(series, directed = TRUE) gd$out_adjacency[[1]] # forward neighbors of first observation
Generates the discrete topology on n elements, where the base
consists of all singleton sets .
The full topology is the power set , but only the base is
returned explicitly (enumerating sets is impractical for
large n).
simplest_topology(data)simplest_topology(data)
data |
Numeric vector containing the data points. |
A list with:
List of singleton sets.
Same as subbase (singletons are already a base).
Character: "discrete".
Integer. Number of elements.
Logical. Always FALSE for
(the discrete topology is maximally disconnected).
result <- simplest_topology(c(1, 2, 3, 4, 5)) result$connectedresult <- simplest_topology(c(1, 2, 3, 4, 5)) result$connected
Visualize and compare different threshold methods
visualize_topology_thresholds(data, plot = TRUE)visualize_topology_thresholds(data, plot = TRUE)
data |
Numeric vector to analyze. |
plot |
Logical indicating whether to return plot objects
(default: |
A data.frame with columns method, threshold,
and base_size. If plot = TRUE, carries an attribute
"plots" containing a list of three ggplot objects.
data <- rnorm(50) results <- visualize_topology_thresholds(data)data <- rnorm(50) results <- visualize_topology_thresholds(data)