/ \ | | ___ _ __ | |__ __ __
/ _ \ | |/ _ \ '_ \| '_ \ ____\ \ /\ / /
/ ___ \| | __/ |_) | | | |_____\ V V /
/_/ \_\_|\___| .__/|_| |_| \_/\_/
|_|
Una biblioteca C++20 completa de estructuras de datos y algoritmos
Tabla de contenido
Resumen
Aleph-w es una biblioteca C++20 lista para producción que ofrece más de 90 estructuras de datos y 50+ algoritmos para ingenieros de software, investigadores y estudiantes. Con 238 archivos de cabecera y 80+ ejemplos, es una de las bibliotecas de algoritmos más completas disponibles.
¿Por qué Aleph-w?
| Característica | STL | Boost | Aleph-w |
| Árboles balanceados (AVL, RB, Splay, Treap) | Limitado | Parcial | 8 variantes |
| Estadística de orden (k-ésimo, rank) | Ninguna | Ninguna | Todos los árboles |
| Algoritmos de grafos | Ninguno | BGL | 50+ algoritmos |
| Flujos en redes (max-flow, min-cost) | Ninguno | Ninguno | Suite completa |
| Allocators tipo arena | Ninguno | Ninguno | Incluido |
| map/filter/fold paralelo | Limitado | Limitado | Soporte nativo |
| Programación funcional | Limitado | Parcial | Completa |
| Ejemplos educativos | Ninguno | Pocos | 80+ programas |
Estadísticas clave
- 238 archivos de cabecera cubriendo algoritmos clásicos y modernos
- 90+ estructuras de datos con múltiples variantes de implementación
- 50+ algoritmos de grafos incluyendo flujos, cortes y caminos
- 80+ programas de ejemplo con comentarios detallados
- 7,700+ casos de prueba con 99.98% de éxito
- Soporte multi-compilador: GCC 11+ y Clang 14+
Historia y filosofía
Orígenes (2002)
Aleph-w nació en 2002 en la Universidad de Los Andes en Mérida, Venezuela, creado por Leandro Rabindranath León como herramienta de enseñanza para cursos de algoritmos y estructuras de datos.
El nombre "**Aleph**" (א) referencia el cuento de Jorge Luis Borges "[El Aleph](https://en.wikipedia.org/wiki/The_Aleph_(short_story))" — un punto en el espacio que contiene todos los demás puntos. Esto simboliza la meta de la biblioteca: ser un punto único que contiene todos los algoritmos fundamentales.
El sufijo "**-w**" significa "**with**" (con) — enfatizando que esta biblioteca viene con todo lo que necesitas: implementaciones, ejemplos, pruebas y documentación.
Filosofía de diseño
"La mejor forma de aprender algoritmos es implementarlos,
y la mejor forma de enseñarlos es mostrar implementaciones limpias."
— Leandro R. León
Principios centrales:
- Transparencia sobre abstracción
- Los detalles de implementación son explícitos; no están ocultos
DynList<T> es simplemente ligada; DynDlist<T> es doblemente ligada
- Siempre sabes la complejidad de cada operación
- Completitud
- Múltiples implementaciones del mismo concepto (AVL vs RB vs Splay)
- Compara enfoques y entiende los trade-offs
- Todos los clásicos, no solo lo “más común”
- Valor educativo
- Código escrito para leerse y entenderse
- Ejemplos que enseñan, no solo demuestran
- Listo para producción
- Ampliamente probado (7,700+ tests)
- Usado en aplicaciones reales
- Rendimiento competitivo
- Estilo funcional
- Todos los contenedores soportan
map, filter, fold
- Operaciones composables
- Inmutabilidad cuando es práctico
Línea de tiempo de evolución
2002 ──────── Implementación original C++ para enseñanza en la ULA
│ Enfoque: árboles, listas y algoritmos básicos de grafos
│
2008 ──────── Expansión importante de algoritmos de grafos
│ Añadido: flujos en redes, min-cost flows, cortes
│
2012 ──────── Soporte de programación funcional
│ Añadido: map, filter, fold para todos los contenedores
│
2015 ──────── Modernización C++11/14
│ Añadido: move semantics, lambdas, auto
│
2020 ──────── C++17 y expansión de testing
│ Añadido: structured bindings, if-init, GoogleTest
│
2025 ──────── Migración C++20, allocators tipo arena
│ Añadido: concepts, ranges, constexpr, memoria arena
│
2026 ──────── Compatibilidad completa GCC/Clang (actual)
Corregido: 200+ warnings, issues de templates, ABI
Añadido: CI/CD, sanitizers, documentación
Impacto académico
Aleph-w ha sido usado para enseñar a miles de estudiantes en Latinoamérica. Su diseño educativo incluye:
- Implementaciones lado a lado: compara Kruskal vs Prim, Dijkstra vs Bellman-Ford
- Exportación de visualizaciones: salida LaTeX/EEPIC para papers y presentaciones
- Análisis de complejidad: cada operación documenta su Big-O
- Ejemplos extensos: 80+ programas demostrando uso real
Características de un vistazo
Estructuras de Datos
┌────────────────────────────────────────────────────────────────────────────┐
│ RESUMEN DE ESTRUCTURAS DE DATOS │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ ÁRBOLES TABLAS HASH HEAPS │
│ ├─ Árbol AVL ├─ Chaining ├─ Binary Heap │
│ ├─ Árbol Rojo-Negro ├─ Open Addressing ├─ Fibonacci Heap │
│ ├─ Árbol Splay ├─ Linear Probing └─ Array Heap │
│ ├─ Treap └─ Linear Hashing │
│ ├─ Rand Tree │
│ ├─ Skip List │
│ └─ Variantes con Rank │
│ │
│ LISTAS ARREGLOS GRAFOS │
│ ├─ Simplemente ligada ├─ Arreglo dinámico ├─ Lista de adyacencia │
│ ├─ Doblemente ligada ├─ Arreglo fijo ├─ Matriz de adyacencia │
│ ├─ Circular ├─ Matriz 2D ├─ Redes (flujos) │
│ └─ Skip List └─ BitArray └─ Euclidianos │
│ │
│ ESPECIALES ESPACIALES PROBABILÍSTICAS │
│ ├─ Union-Find ├─ Quadtree ├─ Bloom Filter │
│ ├─ LRU Cache ├─ 2D-Tree ├─ Cuckoo Filter │
│ └─ Prefix Tree (Trie) └─ K-d Tree └─ HyperLogLog/MinHash/SimHash/Reservoir/CMS │
│ │
│ CONSULTAS POR RANGO │
│ ├─ Fenwick Tree (BIT) │
│ ├─ Sparse Table (RMQ) │
│ ├─ Disjoint Sparse Table │
│ ├─ Segment Tree / Lazy / Beats │
│ ├─ Cartesian Tree RMQ (via LCA) │
│ ├─ Interval Tree (overlap/stabbing queries) │
│ ├─ Heavy-Light Decomposition (path/subtree) │
│ ├─ Centroid Decomposition (distance tricks) │
│ ├─ Link-Cut Tree (bosque dinámico + consultas de camino) │
│ └─ Mo's Algorithm (Offline) │
│ │
│ GEOMETRÍA │
│ ├─ Primitivas (Punto, Segmento, Polígono, Elipse) │
│ ├─ Predicados Exactos (orientación, intersección, in_circle) │
│ ├─ Convex Hull (Andrew, Graham, QuickHull) │
│ ├─ Triangulación (Ear-Cutting, Delaunay, CDT) │
│ ├─ Proximidad (Closest Pair, MEC, Rotating Calipers) │
│ ├─ Diagramas (Voronoi, Power Diagram) │
│ └─ Visualización (TikZ/PGF backend) │
│ │
└────────────────────────────────────────────────────────────────────────────┘
Algoritmos
┌────────────────────────────────────────────────────────────────────────────┐
│ RESUMEN DE ALGORITMOS │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ CAMINOS MÍNIMOS ÁRBOLES EXPANSORES CONECTIVIDAD │
│ ├─ Dijkstra ├─ Kruskal ├─ DFS / BFS │
│ ├─ Bellman-Ford └─ Prim ├─ Componentes Conexas │
│ ├─ Floyd-Warshall ├─ Tarjan / Kosaraju │
│ ├─ Johnson ├─ Puntos de Articulación│
│ ├─ A* Search ├─ Biconectividad │
│ └─ 0-1 BFS / Dial / Bidirectional / IDA* │ │
│ │
│ FLUJOS EN REDES CORTE MÍNIMO EMPAREJAMIENTO (MATCH) │
│ ├─ Ford-Fulkerson ├─ Karger ├─ Hopcroft-Karp │
│ ├─ Edmonds-Karp ├─ Karger-Stein ├─ Edmonds-Blossom │
│ ├─ Push-Relabel └─ Stoer-Wagner └─ Húngaro (Asignación) │
│ ├─ Dinic │
│ └─ Min-Cost Max-Flow │
│ │
│ ORDENAMIENTO BÚSQUEDA STRINGS │
│ ├─ Quicksort ├─ Búsqueda Binaria ├─ Pattern Matching │
│ ├─ Mergesort └─ Interpolación ├─ Suffix Structures │
│ ├─ Heapsort ├─ Edit Distance / LCS │
│ ├─ Introsort └─ Palíndromos (Manacher)│
│ └─ Shell Sort │
│ │
│ OTROS │
│ ├─ Union-Find ├─ Huffman Coding ├─ Simplex (LP) │
│ ├─ RMQ/LCA/HLD/Centroid ├─ BitArray │
│ └─ Sketches streaming └─ (HLL/CMS/MinHash/SimHash/Reservoir) │
│ └─ Aritmética de polinomios dispersos │
│ │
└────────────────────────────────────────────────────────────────────────────┘
Requisitos
Soporte de compiladores
| Compilador | Versión mínima | Recomendado | Estado |
| GCC | 11 | 13 | Totalmente probado |
| Clang | 14 | 16 | Totalmente probado |
| MSVC | No soportado | - | Planeado |
Dependencias
Esta rama construye una biblioteca estática (libAleph.a) más los headers.
| Librería | Paquete (Ubuntu/Debian) | Propósito | Requerida |
| GMP + gmpxx | libgmp-dev | Enteros/racionales multiprecisión (y bindings C++) | Sí |
| MPFR | libmpfr-dev | Punto flotante multiprecisión | Sí |
| GSL (+ gslcblas) | libgsl-dev | RNG/estadística usada por estructuras/algoritmos aleatorizados | Sí |
| X11 | libx11-dev | Dependencia de enlace | Sí |
| GoogleTest | libgtest-dev | Unit tests | Solo para BUILD_TESTS (auto-fetch soportado) |
Herramientas de build
- CMake 3.18+
- CMake presets:
CMakePresets.json requiere CMake 3.21+ (opcional)
- Ninja (recomendado) o Make
Instalación rápida (Ubuntu/Debian)
# Essential
sudo apt-get update
sudo apt-get install -y build-essential cmake ninja-build
# Compilers
sudo apt-get install -y g++ clang
# Required libraries (this branch)
sudo apt-get install -y libgmp-dev libmpfr-dev libgsl-dev libx11-dev
# Optional (only needed if you want to build tests without auto-fetch)
sudo apt-get install -y libgtest-dev
Instalación
Para instrucciones detalladas por plataforma y troubleshooting, ver INSTALL.md.
Método 1: build con CMake (recomendado)
# Clone the repository
git clone https://github.com/lrleon/Aleph-w.git
cd Aleph-w
# Configure (Release build, library + tests; disable examples for faster builds)
cmake -S . -B build -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_EXAMPLES=OFF \
-DBUILD_TESTS=ON
# Build
cmake --build build --parallel
# Run tests
ctest --test-dir build --output-on-failure
# Install system-wide (optional)
sudo cmake --install build
Nota: si GoogleTest no está instalado y estás offline, configura con -DALEPH_FETCH_GTEST=OFF (o desactiva tests con -DBUILD_TESTS=OFF) y/o instala libgtest-dev desde tu distro.
Método 2: compilación directa (sin instalar)
Si prefieres no instalar, puedes compilar Aleph una vez y luego enlazar directamente:
# Build the library
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=OFF -DBUILD_EXAMPLES=OFF
cmake --build build --parallel
# Compile and link against the static library
g++ -std=c++20 -I/path/to/Aleph-w your_code.cpp /path/to/Aleph-w/build/libAleph.a \
-lgmpxx -lgmp -lmpfr -lgsl -lgslcblas -lpthread -lX11 -lm \
-o your_program
Método 3: CMake FetchContent
include(FetchContent)
FetchContent_Declare(
aleph-w
GIT_REPOSITORY https://github.com/lrleon/Aleph-w.git
GIT_TAG v3
)
FetchContent_MakeAvailable(aleph-w)
target_link_libraries(your_target PRIVATE Aleph)
Opciones de CMake
| Opción | Default | Descripción |
ALEPH_CXX_STANDARD | 20 | Estándar C++ para la biblioteca core (17, 20, 23) |
BUILD_TESTS | ON | Compilar la suite de tests (Tests/) |
BUILD_EXAMPLES | ON | Compilar los ejemplos (Examples/) |
BUILD_OPTIMIZED | OFF | Si está en ON y CMAKE_BUILD_TYPE no se define, default a Release |
ALEPH_FETCH_GTEST | ON | (Tests) Auto-fetch GoogleTest si falta |
USE_SANITIZERS | OFF | (Tests) Habilitar ASan/UBSan para los binarios de test |
CMake Presets (opcional)
Si tienes CMake 3.21+, puedes usar los presets provistos:
cmake --preset default
cmake --build --preset default
ctest --preset default
Uso rápido
Ejemplos en 5 minutos
Ejemplo 1: set con árbol balanceado
#include <iostream>
DynSetTree<int, Avl_Tree> numbers;
numbers.insert(50);
numbers.insert(30);
numbers.insert(70);
numbers.insert(20);
numbers.insert(40);
if (numbers.contains(30))
std::cout << "Found 30!\n";
std::cout << "Sorted: ";
numbers.for_each([](int x) {
std::cout << x << " ";
});
auto doubled = numbers.map<DynList>([](int x) { return x * 2; });
auto big = numbers.filter([](int x) { return x > 35; });
return 0;
}
Dynamic set implementations based on balanced binary search trees.
Ejemplo 2: grafo con camino mínimo
#include <iostream>
using Node = Graph_Node<std::string>;
using Arc = Graph_Arc<double>;
using Graph = List_Graph<Node, Arc>;
Path<Graph> path(city_map);
double distance = dijkstra_min_path(city_map, ny, la, path);
std::cout << "Shortest distance: " << distance << "\n";
std::cout << "Path: ";
path.for_each_node([](auto* node) {
std::cout << node->get_info() << " → ";
});
return 0;
}
Dijkstra's shortest path algorithm.
WeightedDigraph::Node Node
virtual Node * insert_node(Node *node) noexcept
Insertion of a node already allocated.
Arc * insert_arc(Node *src_node, Node *tgt_node, void *a)
Generic graph and digraph implementations.
Ejemplo 3: asignación tipo arena
char buffer[64 * 1024];
DynSetTree<int> tree(buffer, sizeof(buffer));
int count = 0;
for (int i = 0; ; ++i) {
if (tree.insert(i) == nullptr) {
count = i;
break;
}
}
std::cout <<
"Inserted " <<
count <<
" elements\n";
std::cout << "Arena used: " << tree.arena_allocated_size() << " bytes\n";
std::cout << "Arena free: " << tree.arena_available_size() << " bytes\n";
return 0;
}
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Estructuras de datos
Árboles de búsqueda balanceados
Aleph-w ofrece 8 implementaciones diferentes de árboles balanceados, cada una optimizada para casos de uso específicos.
Comparación de árboles
┌─────────────────────────────────────────────────────────────────────────────────────────────┐
│ BALANCED TREE COMPARISON │
├──────────────┬──────────────┬──────────────┬──────────────┬──────────────┬──────────────────┤
│ Operation │ AVL Tree │ Red-Black │ Splay Tree │ Treap │ Rand Tree │
├──────────────┼──────────────┼──────────────┼──────────────┼──────────────┼──────────────────┤
│ Insert │ O(log n) │ O(log n) │ O(log n)* │ O(log n)** │ O(log n)** │
│ Search │ O(log n) │ O(log n) │ O(log n)* │ O(log n)** │ O(log n)** │
│ Delete │ O(log n) │ O(log n) │ O(log n)* │ O(log n)** │ O(log n)** │
│ Min/Max │ O(log n) │ O(log n) │ O(log n)* │ O(log n)** │ O(log n)** │
├──────────────┼──────────────┼──────────────┼──────────────┼──────────────┼──────────────────┤
│ Height │ ≤1.44 log n │ ≤2 log n │ Unbounded │ O(log n)** │ O(log n)** │
│ Balance │ Strict │ Relaxed │ None │ Randomized │ Randomized │
├──────────────┼──────────────┼──────────────┼──────────────┼──────────────┼──────────────────┤
│ Best For │ Read-heavy │ General │ Locality │ Simplicity │ Fast split/join │
│ │ workloads │ purpose │ patterns │ randomized │ randomized │
└──────────────┴──────────────┴──────────────┴──────────────┴──────────────┴──────────────────┘
* Amortized complexity.
\*\* Expected complexity (randomized).
Ejemplos de uso
DynSetTree<int, Avl_Tree> avl;
DynSetTree<int, Rb_Tree> rb;
DynSetTree<int, Splay_Tree> splay;
DynSetTree<int, Treap> treap;
DynSetTree<int, Rand_Tree> rand_tree;
DynSetTree<int, Avl_Tree_Rk> avl_rank;
int third = avl_rank.select(2);
size_t pos = avl_rank.position(42);
Estadísticas de orden con árboles Rank
Todos los tipos de árboles tienen variantes *Rk que soportan estadísticas de orden en O(log n):
DynSetTree<int, Avl_Tree_Rk> set;
for (int x : {50, 30, 70, 20, 40, 60, 80})
set.insert(x);
int first = set.select(0);
int third = set.select(2);
int last = set.select(6);
size_t rank_of_50 = set.position(50);
set.for_each_in_range(25, 65, [](int x) {
std::cout << x << " ";
});
return 0;
}
Diagrama de estructura
AVL Tree (height-balanced)
========================
[50] Height: 3
/ \ Balance factors
[30] [70] shown in ()
/ \ / \
[20] [40][60] [80]
After inserting: 20, 30, 40, 50, 60, 70, 80
Rotations performed: 2
Splay Tree (self-adjusting)
===========================
After accessing 20:
[20] Recently accessed
\ elements move to
[30] the root
\
[50]
/ \
[40] [70]
/ \
[60] [80]
Árboles Fenwick (Binary Indexed Trees)
Aleph-w ofrece tres variantes de árbol Fenwick para sumas de prefijo y consultas por rango:
┌───────────────────────────────────────────────────────────────────────────────┐
│ FENWICK TREE VARIANTS │
├──────────────────┬───────────────┬───────────────┬────────────────────────────┤
│ Operation │ Gen (Abelian) │ Fenwick_Tree │ Range_Fen │
├──────────────────┼───────────────┼───────────────┼────────────────────────────┤
│ update(i,delta) │ O(log n) │ O(log n) │ O(log n) │
│ prefix / get │ O(log n) │ O(log n) │ O(log n) │
│ range_query │ O(log n) │ O(log n) │ O(log n) │
│ range_update │ N/A │ N/A │ O(log n) │
│ find_kth │ N/A │ O(log n) │ N/A │
├──────────────────┼───────────────┼───────────────┼────────────────────────────┤
│ Group Operand │ Arbitrary │ operator+ │ operator+ │
│ │ (XOR, +mod) │ operator- │ operator- │
├──────────────────┼───────────────┼───────────────┼────────────────────────────┤
│ Best For │ Custom ops │ Order stats │ Promotions │
│ │ (XOR, etc) │ Find k-th │ Dividends │
└──────────────────┴───────────────┴───────────────┴────────────────────────────┘
Ejemplos de uso
Fenwick_Tree<int> ft = {3, 1, 4, 1, 5};
ft.update(2, 7);
int sum = ft.query(1, 4);
auto kth = ft.find_kth(5);
Range_Fenwick_Tree<int> rft(10);
rft.update(2, 5, 10);
int range_sum = rft.query(0, 7);
struct Xor {
int operator()(int a, int b) const { return a ^ b; }
};
Gen_Fenwick_Tree<int, Xor, Xor> xor_ft(8);
xor_ft.update(3, 0b1010);
int prefix_xor = xor_ft.prefix(5);
return 0;
}
Fenwick tree (Binary Indexed Tree) for prefix queries.
Aplicación en el mundo real: profundidad del libro de órdenes
Fenwick_Tree<int> ask_book(20);
ask_book.update(0, 120);
ask_book.update(3, 200);
ask_book.update(7, 300);
size_t worst_tick = ask_book.find_kth(250);
Segment Trees
Aleph-w ofrece tres variantes de segment tree para consultas por rango dinámicas:
┌───────────────────────────────────────────────────────────────────────────┐
│ SEGMENT TREE VARIANTS │
├──────────────────┬───────────────┬────────────────┬───────────────────────┤
│ Operation │ Gen_Segment │ Gen_Lazy_Seg │ Seg_Tree_Beats │
├──────────────────┼───────────────┼────────────────┼───────────────────────┤
│ point_update │ O(log n) │ O(log n) │ — │
│ range_update │ — │ O(log n) │ O(log n) amort. │
│ range_query │ O(log n) │ O(log n) │ O(log n) │
│ chmin / chmax │ — │ — │ O(log n) amort. │
│ build │ O(n) │ O(n) │ O(n) │
├──────────────────┼───────────────┼────────────────┼───────────────────────┤
│ Requirements │ Associative │ Policy-based │ Signed arithmetic │
│ │ monoid │ (lazy tags) │ │
├──────────────────┼───────────────┼────────────────┼───────────────────────┤
│ Best For │ Sum/min/max │ Range add/ │ Clamping with │
│ │ + point ops │ assign queries │ sum/min/max queries │
└──────────────────┴───────────────┴────────────────┴───────────────────────┘
Comparación de estructuras para consultas por rango:
| Structure | Build | Update | Query | Space | Requirements |
| Sparse Table | O(n lg n) | — | O(1) | O(n lg n) | Idempotent |
| Disjoint Sparse Table | O(n lg n) | — | O(1) | O(n lg n) | Associative |
| Fenwick Tree | O(n) | O(lg n) | O(lg n) | O(n) | Invertible (group) |
| Segment Tree | O(n) | O(lg n) | O(lg n) | O(n) | Associative (monoid) |
| Lazy Segment Tree | O(n) | O(lg n) range | O(lg n) | O(n) | Policy-based |
| Segment Tree Beats | O(n) | O(lg n) amort. | O(lg n) | O(n) | Signed arithmetic |
| Cartesian Tree RMQ | O(n lg n) | — | O(1) | O(n lg n) | Totally ordered |
| Mo's Algorithm | O(Q lg Q) | — | O((N+Q)√N) total | O(N+Q) | Offline, decomposable |
Ejemplos de uso
Sum_Segment_Tree<int> st = {3, 1, 4, 1, 5};
st.update(2, 10);
int sum = st.query(1, 3);
Min_Segment_Tree<int> mn = {5, 2, 4, 7, 1};
Lazy_Sum_Segment_Tree<int> lazy = {1, 2, 3, 4, 5};
lazy.update(1, 3, 10);
int s = lazy.query(0, 4);
Segment_Tree_Beats<int> beats = {75, 90, 45, 60};
beats.chmin(0, 3, 70);
beats.chmax(0, 3, 50);
int total = beats.query_sum(0, 3);
return 0;
}
FooMap m(5, fst_unit_pair_hash, snd_unit_pair_hash)
Segment trees for dynamic range queries with lazy propagation.
Aplicación en el mundo real: ajustes de salario (lazy propagation)
Lazy_Sum_Segment_Tree<int> payroll = {50, 45, 60, 55, 70, 48, 52, 65};
payroll.update(2, 5, 10);
int cost = payroll.query(0, 7);
Cartesian Trees & LCA
Aleph-w implementa la cadena clásica de reducciones RMQ ↔ LCA ↔ Cartesian Tree, confirmando que Range Minimum Query y Lowest Common Ancestor son problemas equivalentes:
┌─────────────────────────────────────────────────────────────────────┐
│ RMQ ←→ LCA ←→ Cartesian Tree │
├──────────────────────┬─────────────┬──────────┬─────────────────────┤
│ Class │ Build │ Query │ Space │
├──────────────────────┼─────────────┼──────────┼─────────────────────┤
│ Gen_Cartesian_Tree │ O(n) │ — │ O(n) │
│ Gen_Euler_Tour_LCA │ O(n log n) │ O(1) │ O(n log n) │
│ Gen_Cartesian_Tree_RMQ│ O(n log n) │ O(1) │ O(n log n) │
└──────────────────────┴─────────────┴──────────┴─────────────────────┘
- **
Gen_Cartesian_Tree<T, Comp>** — Árbol cartesiano explícito construido en O(n) con un stack monótono. Satisface la propiedad de heap bajo Comp e inorder = arreglo original.
- **
Gen_Euler_Tour_LCA<T, Comp>** — LCA en O(1) vía Euler Tour + Sparse Table sobre el árbol cartesiano.
- **
Gen_Cartesian_Tree_RMQ<T, Comp>** — Consultas estáticas en O(1) vía la reducción RMQ → LCA → Cartesian Tree.
Ejemplos de uso
Cartesian_Tree<int> ct = {3, 2, 6, 1, 9};
auto io = ct.inorder();
Euler_Tour_LCA<int> lca = {3, 2, 6, 1, 9};
size_t a = lca.lca(0, 2);
size_t d = lca.distance(0, 4);
Cartesian_Tree_RMQ<int> rmq = {5, 2, 4, 7, 1, 3, 6};
size_t idx = rmq.query_idx(2, 6);
Max_Cartesian_Tree<int> max_ct = {3, 2, 6, 1, 9};
Cartesian_Tree_RMaxQ<int> rmaxq = {5, 2, 4, 7, 1};
return 0;
}
Cartesian Tree, LCA via Euler Tour, and RMQ via Cartesian Tree.
LCA de árboles sobre backends de grafos
LCA.H provides two LCA engines for rooted trees represented as Aleph graphs:
| Class | Build | Query (lca) | Space |
Gen_Binary_Lifting_LCA<GT, SA> | O(n log n) | O(log n) | O(n log n) |
Gen_Euler_RMQ_LCA<GT, SA> | O(n log n) | O(1) | O(n log n) |
Highlights:
- Works with
List_Graph, List_SGraph, and Array_Graph.
- Supports arc filtering via
SA.
- Validates tree shape on the filtered graph (connected, acyclic, simple).
- Exposes
lca, distance, is_ancestor, depth_of, and id-based APIs.
using G = List_Graph<Graph_Node<int>, Graph_Arc<int>>;
Binary_Lifting_LCA<G> bl(g, n0);
Euler_RMQ_LCA<G> er(g, n0);
auto * a = bl.lca(n3, n2);
auto * b = er.lca(n3, n2);
size_t d = bl.distance(n3, n2);
bool ok = bl.is_ancestor(n0, n3);
(void)a; (void)b; (void)d; (void)ok;
}
Lowest Common Ancestor (LCA) on rooted trees represented as Aleph graphs.
Backend-specific constructors:
using G = List_Graph<Graph_Node<int>, Graph_Arc<int>>;
Binary_Lifting_LCA<G> bl(g, root_node);
Euler_RMQ_LCA<G> er(g, root_node);
using G = List_SGraph<Graph_Snode<int>, Graph_Sarc<int>>;
Binary_Lifting_LCA<G> bl(g, root_node);
Euler_RMQ_LCA<G> er(g, root_node);
Simple graph implementation with adjacency lists.
using G = Array_Graph<Graph_Anode<int>, Graph_Aarc<int>>;
Binary_Lifting_LCA<G> bl(g, root_node);
Euler_RMQ_LCA<G> er(g, root_node);
Array-based graph implementation.
Descomposiciones de árbol (Heavy-Light + Centroid)
Tree_Decomposition.H adds two advanced tree engines on Aleph graph backends:
| Class | Build | Typical Query/Update | Use case |
Gen_Heavy_Light_Decomposition<GT, SA> | O(n) | path split in O(log n) segments | Path/subtree decomposition |
Gen_HLD_Path_Query<GT, T, Op, SA> | O(n) + segment tree | O(log² n) path, O(log n) subtree | Dynamic path/subtree range queries |
Gen_Centroid_Decomposition<GT, SA> | O(n log n) | O(log n) ancestor chain scans | Dynamic nearest/farthest marked-node tricks |
Highlights:
- Works with
List_Graph, List_SGraph, and Array_Graph.
- Supports arc filters
SA.
- Exposes centroid-ancestor chains with distances (ideal for online distance queries).
- Integrates directly with segment trees for HLD path/subtree queries.
Problem patterns solved:
- Dynamic path aggregates:
sum/min/max/xor on path(u, v) with node point updates.
- Dynamic subtree aggregates: full subtree query
subtree(u) with node point updates.
- Dynamic nearest active node (unweighted distance in edges): mark nodes as active and query
min dist(u, active).
- Dynamic farthest/threshold-style distance queries by scanning centroid ancestor chains.
Quick decision guide:
| If your problem looks like... | Prefer | Why |
| Many online path queries + point updates | Gen_HLD_Path_Query | Path becomes O(log n) base-array segments |
| Many online subtree queries + point updates | Gen_HLD_Path_Query | Subtree is one contiguous base-array range |
| Nearest/farthest active node on a tree | Gen_Centroid_Decomposition | Query/update naturally map to centroid ancestor chain |
| Only LCA/ancestor/distance (no segment aggregate) | LCA.H | Simpler API, lower conceptual overhead |
| Offline custom path/subtree statistics (non-monoid) | tpl_mo_on_trees.H | Better fit for add/remove offline policies |
30-second diagnostic checklist:
- Is the tree static and you only need
lca, is_ancestor, or distance? Use LCA.H.
- Do you need online
path(u, v) or subtree(u) aggregates with an associative op and node point updates? Use Gen_HLD_Path_Query.
- Do you maintain a dynamic set of marked nodes and query nearest/farthest by tree distance? Use
Gen_Centroid_Decomposition.
- Are queries offline and maintained via add/remove (not monoid-friendly)? Use
tpl_mo_on_trees.H.
- Do you require weighted-edge distances?
Gen_Centroid_Decomposition is edge-count based today; adapt your workflow (or preprocess distances) before applying centroid-chain formulas.
Practical notes:
- The current implementations assume an unweighted tree topology for distance-based centroid workflows (
distance = #edges).
- They validate the filtered graph is a simple tree; construction fails fast on invalid topology.
- For range updates (not only point updates), combine HLD decomposition with a lazy segment tree policy.
Recetas listas para usar
Receta 1: Suma en camino con updates puntuales por nodo Cuándo usar: Muchas consultas online como “sum on path(u, v)” y cambios ocasionales de valores por nodo.
using G = List_Graph<Graph_Node<int>, Graph_Arc<int>>;
HLD_Path_Query<G, int, Aleph::plus<int>> q(g,
root, 0);
q.update_node(sensor_a, +3);
q.set_node(sensor_b, 42);
int risk = q.query_path(city_u, city_v);
Heavy-Light and Centroid decomposition on rooted trees represented as Aleph graphs.
__gmp_expr< T, __gmp_binary_expr< __gmp_expr< T, U >, unsigned long int, __gmp_root_function > > root(const __gmp_expr< T, U > &expr, unsigned long int l)
Receta 2: Agregado por subárbol (área de servicio completa) Cuándo usar: Totales en jerarquías enraizadas donde cada update toca un solo nodo.
using G = List_Graph<Graph_Node<int>, Graph_Arc<int>>;
HLD_Path_Query<G, int, Aleph::plus<int>> q(g, ceo, 0);
int area_cost = q.query_subtree(region_head);
q.update_node(team_node, -5);
int updated = q.query_subtree(region_head);
Receta 3: Nodo activo más cercano (centros dinámicos) Cuándo usar: Activar/marcar nodos con el tiempo y consultar repetidamente la distancia al nodo activo más cercano.
#include <algorithm>
#include <limits>
using G = List_Graph<Graph_Node<int>, Graph_Arc<int>>;
Centroid_Decomposition<G> cd(g,
root);
const size_t INF = std::numeric_limits<size_t>::max() / 4;
auto best = Array<size_t>::create(cd.size());
for (size_t i = 0; i < cd.size(); ++i) best(i) = INF;
cd.for_each_centroid_ancestor(x, [&](size_t c, size_t d, size_t) {
best(c) = std::min(best(c), d);
});
};
size_t ans = INF;
cd.for_each_centroid_ancestor(x, [&](size_t c, size_t d, size_t) {
if (best(c) != INF) ans = std::min(ans, best(c) + d);
});
return ans;
};
_Graph_Node Node
The graph type.
using G = List_Graph<Graph_Node<int>, Graph_Arc<int>>;
Heavy_Light_Decomposition<G> hld(g,
root);
HLD_Path_Query<G, int, Aleph::plus<int>> q(g,
root, 0);
int path_sum = q.query_path(u, v);
int subtree_sum = q.query_subtree(u);
q.update_node(u, +5);
q.set_node(v, 42);
Centroid_Decomposition<G> cd(g,
root);
cd.for_each_centroid_ancestor(x, [&](
size_t c,
size_t d,
size_t k) {
});
Link-Cut Trees (Bosques Dinámicos)
Un Link-Cut Tree mantiene un bosque de árboles enraizados bajo operaciones dinámicas link y cut, cada una en tiempo amortizado O(log n). Es la estructura estándar cuando se necesita:
- Conectividad dinámica — unir y separar árboles al vuelo
- Agregación sobre caminos — consultar cualquier monoide (suma, min, max, xor, ...) sobre caminos del árbol
- Re-enraizamiento — elegir cualquier vértice como raíz representada
- LCA — ancestro común más bajo bajo el enraizamiento actual
- Actualizaciones perezosas — actualizaciones diferidas sobre caminos
Link_Cut_Tree lct;
auto *a = lct.make_vertex(0), *b = lct.make_vertex(1);
lct.link(a, b);
bool ok = lct.connected(a, b);
lct.cut(a, b);
Gen_Link_Cut_Tree<int, SumMonoid<int>> sum_lct;
auto *u = sum_lct.make_vertex(10), *v = sum_lct.make_vertex(20);
sum_lct.link(u, v);
int s = sum_lct.path_query(u, v);
Gen_Link_Cut_Tree<long long, SumMonoid<long long>,
AddLazyTag<long long>> lazy_lct;
Link-Cut Tree: a dynamic forest with path queries.
Mo's Algorithm (Offline Range Queries)
Mo's algorithm responde Q consultas offline de rango sobre un arreglo estático de N elementos en tiempo O((N+Q)√N). Es útil cuando la función de consulta es “decomposable” (mantenible vía add/remove de un elemento) pero no tiene estructura algebraica (no es un monoid, no es invertible, no es idempotente).
La implementación usa un snake-optimized sweep (alternando la dirección del puntero derecho en bloques pares/impares) para mejor comportamiento de caché. El algoritmo se parametriza con una policy (concept MoPolicy), así que el usuario puede conectar lógica arbitraria de add/remove.
Policies incluidas
| Typedef | Policy | Description |
Distinct_Count_Mo<T> | Distinct_Count_Policy<T> | Count distinct elements in a range |
Powerful_Array_Mo<T> | Powerful_Array_Policy<T> | sum(cnt[x]² · x) for competitive programming |
Range_Mode_Mo<T> | Range_Mode_Policy<T> | Most frequent element (frequency, value) |
Ejemplos de uso
Distinct_Count_Mo<int> mo = {1, 2, 1, 3, 2, 1};
auto ans = mo.solve({{0, 2}, {1, 4}, {0, 5}});
Powerful_Array_Mo<int> pa = {1, 2, 1, 1, 2};
auto pa_ans = pa.solve({{0, 4}});
Range_Mode_Mo<int>
mode = {3, 1, 3, 3, 1, 2};
auto m =
mode.solve({{0, 5}});
return 0;
}
auto mode(const Container &data) -> std::decay_t< decltype(*std::begin(data))>
Compute the mode (most frequent value).
Mo's algorithm for offline range queries.
Policies personalizadas
struct Sum_Policy {
using answer_type =
long long;
long long sum = 0;
void init(
const Array<int> &,
size_t) { sum = 0; }
void add(const Array<int> & data, size_t idx) { sum += data(idx); }
void remove(
const Array<int> & data,
size_t idx) {
sum -= data(idx); }
answer_type answer()
const {
return sum; }
};
Gen_Mo_Algorithm<int, Sum_Policy> mo = {3, 1, 4, 1, 5};
auto ans = mo.solve({{0, 4}, {1, 3}});
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
Fw_Itor remove(Fw_Itor __first, const Fw_Itor &__last, const T &__value)
Remove elements equal to a value.
static std::atomic< bool > init
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
Geometría computacional
Aleph-w ofrece una suite robusta para geometría computacional 2D y 3D, construida sobre aritmética racional exacta (Geom_Number = mpq_class) para evitar errores de punto flotante en predicados geométricos.
Características clave:
- **Primitivas geométricas (
point.H, polygon.H)**: un conjunto completo de clases para puntos (2D/3D), segmentos, polígonos (simples y regulares), triángulos, rectángulos y elipses (axis-aligned y rotadas).
- Predicados exactos: funciones núcleo como
orientation(), segments_intersect() e in_circle() son exactas, asegurando comportamiento robusto y correcto para algoritmos de mayor nivel.
**Algoritmos (geom_algorithms.H):**
| Categoría | Algoritmos | Complejidad |
| Convex Hull | Andrew's Monotonic Chain, Graham Scan, QuickHull, Gift Wrapping (Jarvis March), Brute-Force | O(n log n) / O(nh) |
| Triangulation | Ear-Cutting, Monotone Polygon, Delaunay (Bowyer-Watson, Randomized Inc.), Constrained Delaunay (CDT) | O(n²), O(n log n) |
| Proximity | Closest Pair (Divide & Conquer), Minimum Enclosing Circle (Welzl), Rotating Calipers (Diameter/Width) | O(n log n), O(n) |
| Diagrams | Voronoi Diagram (from Delaunay), Power Diagram (Weighted Voronoi) | O(n log n) |
| Intersections | Segment Sweep (Bentley-Ottmann), Half-Plane Intersection, Convex Polygon Clipping, Boolean Polygon Ops (Greiner-Hormann) | O((n+k)log n), O(n log n) |
| Simplification | Douglas-Peucker, Visvalingam-Whyatt, Chaikin Smoothing | O(n log n), O(n*2^k) |
| Pathfinding | Shortest Path in Simple Polygon (Funnel Algorithm) | O(n) |
| Spatial Indexing | AABB Tree, KD-Tree | O(log n) queries |
**Visualización (tikzgeom.H, eepicgeom.H):**
- TikZ Backend: un backend moderno y flexible (
Tikz_Plane) para generar diagramas PGF/TikZ de alta calidad. Soporta capas, estilos y curvas Bézier nativas.
- Visualizadores de algoritmos: una suite de funciones en
tikzgeom_algorithms.H para renderizar salidas de algoritmos como Voronoi, convex hull y arrangements.
- Exportación de documentos: el helper
Tikz_Scene en tikzgeom_scene.H compone figuras complejas y las exporta como documentos LaTeX standalone, Beamer o handouts, incluyendo animaciones multi-paso usando overlays.
- Backend legado EEPIC: para compatibilidad con workflows LaTeX antiguos.
Ver Examples/ para más de una docena de programas específicos de geometría, incluyendo tikz_funnel_beamer_twocol_example.cc que genera slides Beamer animados del algoritmo funnel de camino más corto.
Header: point.H
Point a(0, 0), b(4, 0), c(2, 3);
Orientation o = orientation(a, b, c);
Segment s1(Point(0, 0), Point(2, 2));
Segment s2(Point(0, 2), Point(2, 0));
bool cross = segments_intersect(s1, s2);
Point p = segment_intersection_point(s1, s2);
Segment v(Point(3, 0), Point(3, 6));
Segment d(Point(0, 0), Point(6, 6));
Point q = segment_intersection_point(v, d);
Geom_Number area = area_of_triangle(a, b, c);
2D point and geometric utilities.
Álgebra lineal (estructuras sparse)
Aleph-w ofrece clases de vector y matriz dispersas con indexación basada en dominio, optimizadas para datos con muchos ceros:
┌────────────────────────────────────────────────────────────────────────────┐
│ SPARSE LINEAR ALGEBRA STRUCTURES │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ SPARSE VECTOR (al-vector.H) │
│ ──────────────────────────── │
│ Vector<T, NumType> │
│ │
│ • Domain-based indexing (any type T) │
│ • Stores only non-zero entries (hash-based) │
│ • Epsilon tolerance for near-zero removal │
│ • Operations: +, -, *, dot product, norms │
│ │
│ Memory: O(nonzeros) instead of O(dimension) │
│ │
│ SPARSE MATRIX (al-matrix.H) │
│ ──────────────────────────── │
│ Matrix<Trow, Tcol, NumType> │
│ │
│ • Arbitrary row/column domains │
│ • Stores only non-zero entries │
│ • Operations: +, -, *, transpose, row/col vectors │
│ • Integration with Vector class │
│ │
│ Memory: O(nonzeros) instead of O(rows × cols) │
│ │
│ WHEN TO USE SPARSE? │
│ • Sparsity > 90% (most entries are zero) │
│ • Large dimensions with few non-zeros │
│ • Need domain-based indexing (named rows/columns) │
│ │
│ Example: 1000×1000 matrix with 1000 non-zeros: │
│ Dense: 1,000,000 doubles = 8 MB │
│ Sparse: 1,000 entries = 8 KB (1000× savings!) │
│ │
└────────────────────────────────────────────────────────────────────────────┘
Ejemplos de uso
AlDomain<std::string> products;
products.insert("Laptop");
products.insert("Phone");
products.insert("Tablet");
Vector<std::string, double> inventory(products);
inventory.set_entry("Laptop", 150.0);
inventory.set_entry("Phone", 450.0);
std::cout << "Laptop inventory: " << inventory["Laptop"] << "\n";
AlDomain<std::string> stores;
stores.insert("NYC");
stores.insert("LA");
stores.insert("CHI");
Matrix<std::string, std::string, double> sales(products, stores);
sales.set_entry("Laptop", "NYC", 25);
sales.set_entry("Phone", "LA", 80);
Vector<std::string, double> total_by_product = sales * inventory;
auto sales_t = sales.transpose();
return 0;
}
Sparse matrix with generic domains.
Sparse vector with named elements.
Aplicación en el mundo real: análisis de ventas
AlDomain<std::string> products = {"Laptop", "Phone", "Tablet", "Monitor"};
AlDomain<std::string> stores = {"NYC", "LA", "CHI", "MIA", "SEA"};
Matrix<std::string, std::string, int> sales(products, stores);
sales.set_entry("Laptop", "NYC", 12);
sales.set_entry("Phone", "LA", 35);
sales.set_entry("Phone", "NYC", 28);
auto laptop_sales = sales.get_row("Laptop");
int total_laptops = laptop_sales.sum();
Tablas hash
Aleph-w ofrece múltiples implementaciones de tablas hash optimizadas para distintos escenarios:
┌─────────────────────────────────────────────────────────────────────────────┐
│ HASH TABLE IMPLEMENTATIONS │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ SEPARATE CHAINING OPEN ADDRESSING LINEAR HASHING │
│ (tpl_hash.H) (tpl_odhash.H) (tpl_lhash.H) │
│ │
│ ┌───┬───┬───┬───┐ ┌───┬───┬───┬───┐ Grows incrementally │
│ │ 0 │ 1 │ 2 │ 3 │ │ A │ B │ │ C │ one slot at a time │
│ └─┬─┴─┬─┴───┴─┬─┘ └───┴───┴───┴───┘ │
│ │ │ │ │
│ ▼ ▼ ▼ On collision: │
│ ┌───┐┌───┐ ┌───┐ probe next slot Best for: │
│ │ A ││ B │ │ E │ • Gradual growth │
│ └─┬─┘└─┬─┘ └───┘ Best for: • Memory-mapped │
│ │ │ • Cache locality • Persistent │
│ ▼ ▼ • Small elements │
│ ┌───┐┌───┐ • Read-heavy │
│ │ C ││ D │ │
│ └───┘└───┘ │
│ │
│ Best for: │
│ • Variable-size elements │
│ • High load factors │
│ • Easy deletion │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Uso básico
DynHashSet<std::string> words;
words.insert("algorithm");
words.insert("data");
words.insert("structure");
if (words.contains("algorithm"))
std::cout << "Found!\n";
DynHashMap<std::string, int> ages;
ages.insert("Alice", 30);
ages["Bob"] = 25;
int* age = ages.search("Alice");
if (age)
std::cout << "Alice is " << *age << "\n";
return 0;
}
Unified hash table interface.
Funciones hash personalizadas
struct Point {
int x, y;
return x ==
o.x && y ==
o.y;
}
};
struct PointHash {
size_t operator()(const Point& p) const {
return std::hash<int>{}(p.x) ^ (std::hash<int>{}(p.y) << 1);
}
};
DynHashSet<Point, PointHash> points;
points.insert({1, 2});
points.insert({3, 4});
std::cout << "Size: " << points.size() << "\n";
return 0;
}
bool operator==(const DynList< T > &l1, const DynList< T > &l2)
Equality operator for DynList.
Dynamic set implementations based on hash tables.
Heaps y colas de prioridad
┌─────────────────────────────────────────────────────────────────────────────┐
│ HEAP IMPLEMENTATIONS │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ BINARY HEAP FIBONACCI HEAP │
│ (tpl_binHeap.H) (tpl_fibonacci_heap.H) │
│ │
│ [10] Collection of heap-ordered trees │
│ / \ │
│ [15] [20] ○───○───○ │
│ / \ / \ │ │ │
│ [25][30][35][40] ○ ○───○ │
│ │ │
│ Array representation: ○ │
│ [10|15|20|25|30|35|40] │
│ │
├───────────────────────────────────────┬─────────────────────────────────────┤
│ Operation │ Binary │ Fibonacci │ Notes │
├────────────────┼──────────┼───────────┼─────────────────────────────────────┤
│ Insert │ O(log n) │ O(1)* │ * Amortized │
│ Find-Min │ O(1) │ O(1) │ │
│ Delete-Min │ O(log n) │ O(log n)* │ │
│ Decrease-Key │ O(log n) │ O(1)* │ Key advantage of Fibonacci │
│ Merge │ O(n) │ O(1) │ │
└────────────────┴──────────┴───────────┴─────────────────────────────────────┘
BinHeap<int> min_heap;
min_heap.insert(30);
min_heap.insert(10);
min_heap.insert(20);
while (!min_heap.is_empty())
std::cout << min_heap.getMin() << " ";
BinHeap<int, std::greater<int>> max_heap;
max_heap.insert(30);
max_heap.insert(10);
max_heap.insert(20);
while (!max_heap.is_empty())
std::cout << max_heap.getMin() << " ";
return 0;
}
Binary heap implementation using tree structure.
Listas y estructuras secuenciales
┌─────────────────────────────────────────────────────────────────────────────┐
│ LINEAR DATA STRUCTURES │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ SINGLY-LINKED LIST (DynList) DOUBLY-LINKED LIST (DynDlist) │
│ │
│ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │
│ │ A │──▶│ B │──▶│ C │──▶│ D │ │ A │◀─▶│ B │◀─▶│ C │◀─▶│ D │ │
│ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ │
│ │
│ Insert front: O(1) Insert anywhere: O(1) │
│ Insert back: O(n) Insert back: O(1) │
│ Remove front: O(1) Remove anywhere: O(1) │
│ Search: O(n) Search: O(n) │
│ │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ DYNAMIC ARRAY (DynArray) QUEUE (ArrayQueue) │
│ │
│ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
│ │ A │ │free│ │ B │ │free│ │ C │ Fragmented, scattered │
│ └────┘ └────┘ └────┘ └────┘ └────┘ │
│ 0 1 2 3 4 ▲ ▲ │
│ front back │
│ Access: O(1) │
│ Append: O(1) amortized Enqueue: O(1) │
│ Insert: O(n) Dequeue: O(1) │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
DynList<int> slist = {1, 2, 3, 4, 5};
slist.insert(0);
DynDlist<int> dlist = {1, 2, 3, 4, 5};
dlist.append(6);
DynArray<int> arr = {1, 2, 3, 4, 5};
arr.append(6);
int x = arr[2];
auto doubled = slist.map([](int x) { return x * 2; });
auto evens = dlist.filter([](int x) { return x % 2 == 0; });
int sum = arr.foldl(0, [](
int acc,
int x) {
return acc + x; });
return 0;
}
Lazy and scalable dynamic array implementation.
Dynamic doubly linked list implementation.
Alias for htlist.H (DynList implementation).
Estructuras para consultas por rango
Sparse Table — consultas O(1) sobre arreglos estáticos
Sparse Table ofrece consultas por rango en O(1) después de preprocesamiento O(n log n) para cualquier operación idempotente (min, max, gcd, bitwise AND/OR).
┌─────────────────────────────────────────────────────────────────────────────┐
│ SPARSE TABLE (RMQ) │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Original Array: [5, 2, 8, 1, 9, 3, 6, 4, 7] │
│ │
│ Level 0 (2^0=1): [5, 2, 8, 1, 9, 3, 6, 4, 7] │
│ Level 1 (2^1=2): [2, 2, 1, 1, 3, 3, 4, 4] │
│ Level 2 (2^2=4): [1, 1, 1, 1, 3, 3] │
│ Level 3 (2^3=8): [1, 1] │
│ │
│ Query [2, 7] (range length 6): │
│ k = floor(log2(6)) = 2, 2^k = 4 │
│ Result = min(table[2][2], table[2][4]) = min(1, 3) = 1 │
│ │
│ Build: O(n log n) Query: O(1) Space: O(n log n) │
│ Use case: Static arrays with many queries │
└─────────────────────────────────────────────────────────────────────────────┘
Sparse_Table<int> rmq = {5, 2, 8, 1, 9, 3, 6, 4, 7};
int min_val = rmq.query(2, 7);
Max_Sparse_Table<int> max_rmq = {5, 2, 8, 1, 9, 3, 6, 4, 7};
int max_val = max_rmq.query(0, 4);
int operator()(
int a,
int b)
const noexcept {
return std::gcd(a, b); }
};
Gen_Sparse_Table<int, Gcd_Op> gcd_rmq = {12, 18, 24, 36, 60};
int g = gcd_rmq.query(0, 3);
return 0;
}
int operator()(const int &a, const int &b) const noexcept
Sparse Table for static range queries in O(1).
Fenwick Tree — consultas dinámicas de prefijo
Para arreglos dinámicos con actualizaciones puntuales, usa Fenwick Tree (Binary Indexed Tree):
Fenwick_Tree<int> ft(10);
ft.update(3, 5);
int sum = ft.prefix(7);
ft.update(2, -3);
Mo's Algorithm — consultas offline por rango
Mo's algorithm responde Q consultas offline de rango sobre un arreglo estático de N elementos en tiempo O((N+Q)√N). Es ideal cuando tienes muchas consultas y puedes procesarlas todas juntas.
┌───────────────────────────────────────────────────────────────────────────┐
│ MO'S ALGORITHM OVERVIEW │
├──────────────────┬───────────────┬───────────────┬────────────────────────┤
│ Phase │ Time │ Space │ Description │
├──────────────────┼───────────────┼───────────────┼────────────────────────┤
│ Sort queries │ O(Q log Q) │ O(Q) │ Block + snake ordering │
│ Sweep window │ O((N+Q)√N) │ O(N+Q) │ Add/remove operations │
│ Total │ O((N+Q)√N) │ O(N+Q) │ All queries answered │
└──────────────────┴───────────────┴───────────────┴────────────────────────┘
Ventajas clave:
- Procesamiento por lotes: responde muchas consultas más rápido que operaciones individuales O(log n).
- Consultas descomponibles: cualquier operación en la que puedas agregar/remover elementos.
- Diseño basado en policies: el mismo algoritmo funciona para distintos tipos de consulta.
Policies incluidas:
Distinct_Count_Policy<T> — Cuenta elementos distintos en el rango
Powerful_Array_Policy<T> — Suma de (count² × value)
Range_Mode_Policy<T> — Elemento más frecuente
Ejemplos de uso
Array<int> arr = {1, 2, 1, 3, 2, 4, 1, 5};
Distinct_Count_Mo<int> mo(arr);
Array<std::pair<size_t, size_t>> queries = {
{0, 3}, {2, 6}, {1, 7}
};
auto answers = mo.solve(queries);
Array<int> data = {5, 2, 5, 1, 3, 2, 5, 1};
Range_Mode_Mo<int> mode_mo(data);
Array<std::pair<size_t, size_t>> ranges = {{0, 4}, {2, 7}};
auto modes = mode_mo.solve(ranges);
Mo's Algorithm sobre árboles
Aleph-w extiende Mo's algorithm a estructuras de árbol para consultas de subárbol y de paths:
List_Graph<Graph_Node<int>, Graph_Arc<Empty_Class>> g;
Distinct_Count_Mo_On_Trees<decltype(g)> mot(g, root_node);
auto subtree_answers = mot.subtree_solve({root_node, child1, child2});
auto path_answers = mot.path_solve({{node_a, node_b}, {node_c, node_d}});
EepicNode< long > * build_tree()
Mo's algorithm on trees: offline subtree and path queries.
Tree_Node<int> *
r =
new Tree_Node<int>(1);
Distinct_Count_Mo_On_Tree_Node<int> mot(
r);
auto answers = mot.subtree_solve({
r});
Escenarios del mundo real:
- Analítica de bases de datos: contar categorías distintas en rangos de fechas
- Genómica: encontrar k-mers más frecuentes en segmentos de ADN
- Monitoreo de redes: moda de clases de latencia en ventanas de tiempo
- Sistemas de archivos: tipos de archivo distintos en subárboles de directorios
- Redes sociales: intereses comunes a lo largo de paths entre usuarios
Grafos
Aleph-w ofrece múltiples representaciones de grafos optimizadas para distintos casos de uso:
┌─────────────────────────────────────────────────────────────────────────────┐
│ GRAPH REPRESENTATIONS │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ADJACENCY LIST (List_Graph) ADJACENCY MATRIX (Array_Graph) │
│ │
│ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┬───┬───┬───┐ │
│ │ A │───│ B │───│ C │───│ D │ │ A │ B │ C │ D │ │
│ └───┘ └───┘ └───┘ └───┘ └───┴───┴───┴───┘ │
│ │
│ Space: O(V + E) Space: O(V²) │
│ Add edge: O(1) Add edge: O(1) │
│ Check edge: O(degree) Check edge: O(1) │
│ Best for: Sparse graphs Best for: Dense graphs │
│ │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ NETWORK GRAPH (Net_Graph) DIGRAPH (List_Digraph) │
│ │
│ 10 A ──▶ B ──▶ C │
│ A ────▶ B │ │ │
│ │ 5 │ 15 │ ▼ │
│ ▼ ▼ └─────────▶ D │
│ C ────▶ D │
│ 20 Directed edges │
│ In-degree / Out-degree │
│ Capacities on edges │
│ For max-flow algorithms │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Creación y uso de grafos
using CityNode = Graph_Node<std::string>;
using RoadMap = List_Graph<CityNode, RoadArc>;
RoadMap map;
auto* paris = map.insert_node("Paris");
auto* london = map.insert_node("London");
auto* berlin = map.insert_node("Berlin");
auto* rome = map.insert_node("Rome");
map.insert_arc(paris, london, 344);
map.insert_arc(paris, berlin, 878);
map.insert_arc(london, berlin, 932);
map.insert_arc(berlin, rome, 1181);
map.insert_arc(paris, rome, 1106);
std::cout << "Cities: " << map.get_num_nodes() << "\n";
std::cout << "Roads: " << map.get_num_arcs() << "\n";
std::cout << "Cities connected to Paris:\n";
for (auto it = map.get_first_arc(paris);
it.has_curr(); it.next()) {
auto* arc = it.get_curr();
std::cout << " " << neighbor->get_info()
<< " (" << arc->get_info() << " km)\n";
}
return 0;
}
void * get_connected_node(void *node) noexcept
Node belonging to a graph implemented with a double linked adjacency list.
Grafos dirigidos
using Task = Graph_Node<std::string>;
using Dep = Graph_Arc<int>;
auto* design = project.insert_node("Design");
auto* implement = project.insert_node("Implement");
auto*
test = project.insert_node(
"Test");
auto* deploy = project.insert_node("Deploy");
project.insert_arc(design, implement, 5);
project.insert_arc(implement,
test, 10);
project.insert_arc(
test, deploy, 2);
project.insert_arc(design,
test, 3);
return 0;
}
Generic directed graph (digraph) wrapper template.
Task with priority for job scheduling.
Algoritmos
Algoritmos de caminos mínimos
┌─────────────────────────────────────────────────────────────────────────────┐
│ SHORTEST PATH ALGORITHMS │
├────────────────┬────────────┬────────────┬──────────────────────────────────┤
│ Algorithm │ Complexity │ Negative │ Best For │
├────────────────┼────────────┼────────────┼──────────────────────────────────┤
│ Dijkstra │O((V+E)logV)│ No │ Single source, non-negative │
│ Bellman-Ford │ O(VE) │ Yes │ Negative weights, cycle detection│
│ Floyd-Warshall │ O(V³) │ Yes │ All pairs, dense graphs │
│ Johnson │O(V²logV+VE)│ Yes │ All pairs, sparse graphs │
│ A* │ O(E) best │ No │ Pathfinding with heuristic │
│ K-shortest │O(K*V*(E+VlogV))│ No │ Top-K alternatives (simple/general) s→t │
└────────────────┴────────────┴────────────┴──────────────────────────────────┘
K_Shortest_Paths.H ofrece dos modos distintos:
yen_k_shortest_paths(): alternativas simples/sin ciclos (loopless).
eppstein_k_shortest_paths(): alternativas generales (pueden incluir ciclos).
Algoritmo de Dijkstra
Path<Graph> path(graph);
double distance = dijkstra_min_path(graph, source, target, path);
std::cout << "Shortest distance: " << distance << "\n";
std::cout << "Path: ";
path.for_each_node([](auto* node) {
std::cout << node->get_info() << " → ";
});
std::cout << "\n";
dijkstra_min_spanning_tree(graph, source, tree);
return 0;
}
Bellman-Ford (con aristas negativas)
Path<Graph> path(graph);
bool has_negative_cycle = false;
double dist = bellman_ford_min_path(
graph, source, target, path, has_negative_cycle
);
if (has_negative_cycle) {
std::cerr << "Warning: Negative cycle detected!\n";
} else {
std::cout << "Distance: " << dist << "\n";
}
return 0;
}
Bellman-Ford algorithm for single-source shortest paths.
Búsqueda A* (pathfinding heurístico)
double heuristic(
Node* current,
Node* goal) {
auto [x1,
y1] = current->get_info();
auto [x2, y2] = goal->get_info();
return std::sqrt((x2-x1)*(x2-x1) + (y2-
y1)*(y2-
y1));
}
Path<GridGraph> path(grid);
double dist = astar_search(grid, start, goal, path, heuristic);
std::cout << "Path length: " << dist << "\n";
return 0;
}
A* shortest path algorithm.
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_y1_function > > y1(const __gmp_expr< T, U > &expr)
K-caminos más cortos (Yen sin ciclos + API general estilo Eppstein)
Úsalo cuando un solo camino más corto no es suficiente:
- planificación de rutas con
k alternativas rankeadas de s a t
- failover resiliente (si la mejor ruta está bloqueada, pasar a la siguiente)
- generación de candidatos casi óptimos para restricciones posteriores
K_Shortest_Paths.H soporta ambos contratos:
yen_k_shortest_paths(): hasta k caminos simples (sin ciclos).
eppstein_k_shortest_paths(): hasta k caminos generales, donde pueden aparecer ciclos.
Yen_K_Shortest_Paths<...> y Eppstein_K_Shortest_Paths<...>: wrappers tipo functor para solvers reutilizables configurados (distancia + filtro de arcos).
Ambos se retornan en costo total no decreciente. Los pesos de arcos deben ser no negativos. Detalle de implementación:
- Yen hace recomputación iterativa de spur-path.
- El estilo Eppstein precomputa un árbol de caminos mínimos inverso y expande sidetracks.
Por qué mantener ambas APIs separadas:
- Usa Yen cuando la simplicidad del camino es un requisito estricto (ruteo sin vértices repetidos).
- Usa estilo Eppstein cuando necesitas alternativas rankeadas más amplias y quieres reusar más rápido la misma estructura source/target en espacios densos de desviaciones.
using Graph = List_Digraph<Graph_Node<int>, Graph_Arc<long long>>;
auto simple = yen_k_shortest_paths<Graph>(g, s, t,
k);
auto general = eppstein_k_shortest_paths<Graph>(g, s, t,
k);
for (decltype(simple)::Iterator it(simple); it.has_curr(); it.next_ne()) {
const auto& item = it.get_curr();
std::cout << "[simple] cost=" << item.total_cost << "\n";
}
for (decltype(general)::Iterator it(general); it.has_curr(); it.next_ne()) {
const auto& item = it.get_curr();
std::cout << "[general] cost=" << item.total_cost << "\n";
}
return 0;
}
K-shortest path algorithms (Yen and Eppstein-style API).
Ciclo de media mínima (Karp)
Úsalo cuando tu sistema tiene bucles repetidos y te importa el mejor costo promedio a largo plazo por paso, no solo un camino mínimo. Escenarios típicos:
- análisis de performance/latencia de pipelines cíclicos
- loops de pricing o recursos en sistemas en red
- optimización de estado estable en autómatas/máquinas de estados
Min_Mean_Cycle.H ofrece:
karp_minimum_mean_cycle(): Karp O(VE) para la media mínima de ciclos en grafos dirigidos.
minimum_mean_cycle(): alias con el mismo comportamiento.
karp_minimum_mean_cycle_value() / minimum_mean_cycle_value(): variante solo-valor (sin extracción de witness).
Karp_Minimum_Mean_Cycle<...>: wrapper tipo functor reutilizable.
Karp_Minimum_Mean_Cycle_Value<...>: wrapper reutilizable solo-valor.
Ambas variantes mantienen la complejidad de Karp O(VE). La variante solo-valor evita metadatos del witness y usualmente usa menos memoria en la práctica.
El resultado reporta:
has_cycle: si existe al menos un ciclo dirigido
minimum_mean: media mínima óptima
- información del witness walk (
cycle_nodes, cycle_arcs, cycle_total_cost, cycle_length)
Semántica del witness:
cycle_nodes es un recorrido cerrado (el primer nodo se repite al final).
- En grafos con muchos empates puede contener vértices internos repetidos; es un witness válido del valor mínimo de la media, no necesariamente un ciclo simple canónico.
using Graph = List_Digraph<Graph_Node<int>, Graph_Arc<long long>>;
auto result = karp_minimum_mean_cycle(g);
if (result.has_cycle) {
std::cout << "minimum mean: " << result.minimum_mean << "\n";
}
}
Minimum mean cycle in directed graphs (Karp algorithm).
Árboles de expansión mínima
┌─────────────────────────────────────────────────────────────────────────────┐
│ MINIMUM SPANNING TREE ALGORITHMS │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ KRUSKAL'S ALGORITHM PRIM'S ALGORITHM │
│ (Edge-based) (Vertex-based) │
│ │
│ 1. Sort all edges by weight 1. Start from any vertex │
│ 2. For each edge (u,v): 2. Add cheapest edge to tree │
│ If u,v in different sets: 3. Repeat until all vertices │
│ Add edge to MST are in tree │
│ Union the sets │
│ │
│ Uses: Union-Find Uses: Priority Queue │
│ Complexity: O(E log E) Complexity: O(E log V) │
│ Best for: Sparse graphs Best for: Dense graphs │
│ │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Example MST: │
│ │
│ [A]───2───[B] MST edges: A-B (2) │
│ │ \ / │ A-C (3) │
│ 3 4 5 6 B-D (4) │
│ │ X │ │
│ [C]───7───[D] Total weight: 9 │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
kruskal_min_spanning_tree(graph, mst_kruskal);
prim_min_spanning_tree(graph, mst_prim);
double total_weight = 0;
total_weight += arc->get_info();
});
std::cout << "MST weight: " << total_weight << "\n";
return 0;
}
Kruskal's minimum spanning tree algorithm.
Prim's algorithm for minimum spanning trees.
void for_each_arc(Operation &op) const
Unconditionally traverse all the arcs of graph and on each one perform an operation.
Flujos en redes
┌─────────────────────────────────────────────────────────────────────────────┐
│ NETWORK FLOW ALGORITHMS │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ MAXIMUM FLOW PROBLEM │
│ │
│ ┌─────10────▶[B]─────8─────┐ │
│ │ │ │ │
│ [Source] 2│ [Sink] │
│ │ ▼ │ │
│ └─────5─────▶[C]─────7─────┘ │
│ │
│ Maximum flow = 15 (10 through B, 5 through C) │
│ │
├──────────────────────┬────────────────┬─────────────────────────────────────┤
│ Algorithm │ Complexity │ Description │
├──────────────────────┼────────────────┼─────────────────────────────────────┤
│ Ford-Fulkerson │ O(E × maxflow)│ DFS for augmenting paths │
│ Edmonds-Karp │ O(VE²) │ BFS for shortest augmenting paths │
│ Push-Relabel │ O(V²E) │ Local push operations │
│ Dinic │ O(V²E) │ Blocking flows + level graph │
├──────────────────────┴────────────────┴─────────────────────────────────────┤
│ │
│ MIN-COST MAX-FLOW │
│ │
│ Each edge has: capacity AND cost │
│ Goal: Find max flow with minimum total cost │
│ │
│ Algorithms: Successive Shortest Path, Network Simplex │
└─────────────────────────────────────────────────────────────────────────────┘
Flujo máximo
Net_Graph<long, long> network;
auto* source = network.insert_node();
auto* sink = network.insert_node();
auto* a = network.insert_node();
auto* b = network.insert_node();
network.insert_arc(source, a, 10);
network.insert_arc(source, b, 5);
network.insert_arc(a, b, 15);
network.insert_arc(a, sink, 10);
network.insert_arc(b, sink, 10);
long max_flow = edmonds_karp_maximum_flow(network, source, sink);
std::cout << "Maximum flow: " << max_flow << "\n";
network.for_each_arc([](auto* arc) {
std::cout << "Flow: " << arc->flow << "/" << arc->cap << "\n";
});
return 0;
}
Advanced maximum flow algorithms.
Network flow graph structures.
Flujo máximo de costo mínimo
Net_Cost_Graph<long, long, long> network;
auto [flow, cost] = min_cost_max_flow(network, source, sink);
std::cout << "Max flow: " << flow << "\n";
std::cout << "Min cost: " << cost << "\n";
return 0;
}
Advanced minimum cost flow algorithms.
Maximum flow minimum cost network algorithms.
Conectividad en grafos
┌─────────────────────────────────────────────────────────────────────────────┐
│ CONNECTIVITY ALGORITHMS │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ CONNECTED COMPONENTS STRONGLY CONNECTED COMPONENTS (SCC) │
│ (Undirected graphs) (Directed graphs) │
│ │
│ ┌───┐ ┌───┐ A ──▶ B ──▶ C │
│ │ A │───│ B │ ▲ │ │
│ └───┘ └───┘ │ ┌────┘ │
│ │ ▼ │
│ ┌───┐ ┌───┐ └─── D ◀── E │
│ │ C │───│ D │ │
│ └───┘ └───┘ SCCs: {A,B,C,D}, {E} │
│ │
│ 2 components Tarjan's O(V+E) │
│ DFS/BFS O(V+E) Kosaraju's O(V+E) │
│ │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ARTICULATION POINTS BRIDGES │
│ (Cut vertices) (Cut edges) │
│ │
│ A ─── B ─── C A ─── B ═══ C │
│ │ ║ │
│ │ Bridge: edge whose removal │
│ D disconnects the graph │
│ │
│ B is articulation point: │
│ removing B disconnects graph │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
DynList<Graph> components;
size_t num_components = connected_components(g, components);
std::cout << "Found " << num_components << " components\n";
DynList<DynList<Node*>> sccs;
tarjan_scc(digraph, sccs);
auto cut_nodes = compute_cut_nodes(g);
std::cout << "Articulation points:\n";
cut_nodes.for_each([](auto* node) {
std::cout << " " << node->get_info() << "\n";
});
auto bridges = find_bridges(g);
std::cout << "Bridges:\n";
bridges.for_each([&g](auto* arc) {
});
Compute_Bridges<Graph> cb(g);
auto b2 = cb.find_bridges(
nodes[2]);
return 0;
}
Tarjan's algorithm for strongly connected components.
Node * get_src_node(Arc *arc) const noexcept
Return the source node of arc (only for directed graphs)
Node * get_tgt_node(Arc *arc) const noexcept
Return the target node of arc (only for directed graphs)
DynArray< Graph::Node * > nodes
Graph connectivity and connected components.
Articulation points (cut nodes), bridges, and biconnected components.
2-SAT (Satisfacibilidad)
El problema de 2-satisfacibilidad (2-SAT) determina si una fórmula booleana en CNF, con dos literales por cláusula, es satisfacible. Aleph-w ofrece un resolvedor en tiempo lineal O(V+E) basado en el grafo de implicación y el algoritmo de componentes fuertemente conexas (SCC) de Tarjan.
┌─────────────────────────────────────────────────────────────────────────────┐
│ RESUMEN DEL RESOLVEDOR 2-SAT │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ FÓRMULA: (x0 v x1) ∧ (~x0 v x2) ∧ (~x1 v ~x2) │
│ │
│ GRAFO DE IMPLICACIÓN: │
│ ~x0 ──▶ x1 x0 ──▶ x2 x1 ──▶ ~x2 │
│ ~x1 ──▶ x0 ~x2 ──▶ ~x0 x2 ──▶ ~x1 │
│ │
│ ALGORITMO: │
│ 1. Construir el grafo de implicación con 2N nodos. │
│ 2. Calcular Componentes Fuertemente Conexas (SCC). │
│ 3. La fórmula es SAT sii ningún par x y ~x están en la misma SCC. │
│ 4. Si es SAT, el orden topológico de las SCC da una asignación válida. │
│ │
│ Complejidad: O(n + m) para n variables y m cláusulas │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Ejemplos de uso
Two_Sat<> sat(3);
sat.add_clause(sat.pos_lit(0), sat.pos_lit(1));
sat.add_clause(sat.neg_lit(0), sat.pos_lit(2));
sat.add_clause(sat.neg_lit(1), sat.neg_lit(2));
auto [ok, assignment] = sat.solve();
if (ok) {
bool x0 = assignment(0);
bool x1 = assignment(1);
bool x2 = assignment(2);
}
Two_Sat<> sat2(3);
sat2.add_clause_signed(1, 2);
sat2.add_clause_signed(-1, 3);
sat2.add_clause_signed(-2, -3);
return 0;
}
2-SAT solver based on Tarjan's SCC algorithm.
Prueba de planaridad
Úsalo cuando tu problema depende de si un grafo puede embebirse en el plano sin cruces de aristas.
Escenarios típicos:
- decidir si una topología es físicamente dibujable sin cruces
- validar restricciones de grafos antes de usar algoritmos solo planares
- extraer evidencia verificable por máquina de no-planaridad
- obtener un embedding combinatorio para razonar sobre caras/rotaciones
Planarity_Test.H ofrece:
planarity_test(): resultado detallado (is_planar + metadata de normalización)
is_planar_graph(): API booleana de conveniencia
- wrappers
Planarity_Test<...> y Is_Planar_Graph<...>
La prueba se hace sobre el grafo simple no dirigido subyacente:
- se ignora la orientación de digrafos
- se ignoran self-loops
- se colapsan arcos paralelos
Las salidas avanzadas son opt-in mediante Planarity_Test_Options:
compute_embedding: embedding combinatorio (rotation system + caras)
- modo primario: construcción LR-first (
embedding_is_lr_linear = true) con reparación LR-local determinística (candidatos reversal/swap, multi-start coordinate descent)
- fallback opcional: búsqueda exacta acotada si el embedding LR falla validación
- perfil estricto (
embedding_allow_bruteforce_fallback = false) evita fallback exhaustivo y típicamente es más rápido (sin backtracking exponencial), pero puede retornar is_planar = true sin embedding (has_combinatorial_embedding = false, embedding_search_truncated = true)
embedding_max_combinations es el presupuesto de evaluación de LR local-repair en modo estricto (y el presupuesto de búsqueda exacta cuando se usa fallback)
- perfil robusto (recomendado para workflows de cara/dual): mantener fallback habilitado
compute_nonplanar_certificate: witness de no-planaridad
- primero reduce a una obstrucción mínima por pasadas de borrado de aristas/vértices
- luego busca patrones de Kuratowski en el branch-core
- retorna
K5_Subdivision, K33_Subdivision, o Minimal_NonPlanar_Obstruction si la clasificación no es posible bajo límites
- cada arista witness mantiene trazabilidad a los arcos de entrada originales (
representative_input_arc, input_arcs)
- cada camino witness incluye tanto nodos como secuencia de aristas trazable (
certificate_paths[i].nodes, certificate_paths[i].edges)
Modelo de garantía del embedding:
- la decisión de planaridad (
is_planar) viene de la prueba LR y se mantiene exacta.
- el modo estricto de embedding LR (
embedding_allow_bruteforce_fallback = false) es una estrategia constructiva acotada; si llega al presupuesto, el embedding puede faltar (has_combinatorial_embedding = false, embedding_search_truncated = true) incluso para grafos planares.
- si necesitas completitud del embedding, mantén el fallback habilitado y provee suficiente presupuesto
embedding_max_combinations.
APIs de cara y dual:
planar_dual_metadata(result):
- límites de caras como dart walks
- adyacencia entre caras
- relación arista-primal ↔ arista-dual
build_planar_dual_graph(result) / build_planar_dual_graph(metadata):
- construye un grafo dual de Aleph (
List_Graph por defecto)
- info de nodo dual: face id
- info de arco dual:
Planar_Dual_Edge_Info<GT>
API de dibujo geométrico consciente del embedding:
planar_geometric_drawing(result, drawing_options):
- computa coordenadas 2D para nodos del embedding
- usa relajación armónica sobre el embedding combinatorio
- puede validar cruces de segmentos (
drawing_validated_no_crossings)
APIs de exportación de certificados:
nonplanar_certificate_to_json(result):
- witness estructurado y legible por máquina (nodos, aristas de obstrucción, caminos)
nonplanar_certificate_to_dot(result):
- GraphViz DOT con obstrucción/caminos resaltados
nonplanar_certificate_to_graphml(result):
- formato GraphML de intercambio para herramientas/pipelines
nonplanar_certificate_to_gexf(result):
- formato GEXF de intercambio para tooling estilo Gephi
validate_nonplanar_certificate(result) / nonplanar_certificate_is_valid(result):
- validación de consistencia estructural para witnesses exportados
Adaptador de validación externa (artefactos end-to-end):
scripts/planarity_certificate_validator.rb
- valida archivos
GraphML / GEXF exportados directamente
- chequea consistencia XML, referencias de endpoints y presencia de aristas de obstrucción
- pass opcional
--networkx para chequeos de loadability a nivel de herramienta
- pass opcional
--gephi para chequeos del adaptador Gephi CLI/toolkit (--gephi-cmd soporta un template de comando custom con {input})
- pass opcional
--render-gephi para validación de render/export (--render-profile + --render-output-dir, con chequeos de artefactos SVG/PDF)
scripts/planarity_gephi_templates.json
- catálogo de templates de comando Gephi por OS/versión (más template CI portable)
scripts/planarity_gephi_render_profiles.json
- catálogo de perfiles de render/export Gephi (SVG/PDF) por OS/versión (más perfiles CI portables determinísticos)
scripts/planarity_certificate_ci_batch.rb
- wrapper reproducible de batch para CI que emite un reporte JSON determinístico
scripts/planarity_visual_golden_manifest.json
- baseline determinístico de golden digest para perfiles de render portables
scripts/planarity_certificate_ci_visual_diff.rb
- runner CI dedicado a visual-golden (render + SHA256 diff vs manifest)
scripts/planarity_gephi_weekly_comparison.rb
- agregador de runs para artefactos nocturnos + detección de regresiones (
overall_valid y deltas de exit-code)
scripts/planarity_gephi_regression_notify.rb
- notificador opcional para regresiones nocturnas (alerta Markdown + webhook dispatch)
scripts/fixtures/planarity_k33_certificate.graphml
- fixture de certificado no-planar generado por Aleph usado por CI/adapter probes
.github/workflows/planarity_gephi_nightly.yml
- probe real de empaquetado Gephi semanal + manual (Linux/macOS/Windows)
- auto-selecciona tags
0.9.x y 0.10.x más recientes (o override manual)
- descarga binarios oficiales de Gephi y valida integración del adaptador
- emite artefacto de reporte comparativo por run a través de matriz tags/OS
- aplica gate de regresión cuando tags nuevos regresan vs tags previos por OS
- notificaciones opcionales por webhook vía secret
ALEPH_PLANARITY_ALERT_WEBHOOK
ruby scripts/planarity_certificate_validator.rb \
--input /tmp/planarity_k33_certificate.graphml \
--input /tmp/planarity_k33_certificate.gexf
# Optional: also verify loadability through NetworkX
ruby scripts/planarity_certificate_validator.rb \
--input /tmp/planarity_k33_certificate.graphml \
--networkx
# Optional: Gephi adapter mode (portable; command template is user-configurable)
ruby scripts/planarity_certificate_validator.rb \
--input /tmp/planarity_k33_certificate.graphml \
--gephi \
--gephi-cmd "gephi --headless --import {input}"
# List template catalog (filterable by OS)
ruby scripts/planarity_certificate_validator.rb \
--list-gephi-templates --template-os linux --json
# Use template id from catalog
ruby scripts/planarity_certificate_validator.rb \
--input /tmp/planarity_k33_certificate.graphml \
--gephi --require-gephi \
--gephi-template portable.python-file-exists
# List render profile catalog (filterable by OS)
ruby scripts/planarity_certificate_validator.rb \
--list-gephi-render-profiles --render-os linux --json
# Run render profile and validate produced artifact
ruby scripts/planarity_certificate_validator.rb \
--input /tmp/planarity_k33_certificate.graphml \
--render-gephi --require-render \
--render-profile portable.python-render-svg \
--render-output-dir /tmp/aleph_planarity_renders
# CI batch report (deterministic JSON artifact)
ruby scripts/planarity_certificate_ci_batch.rb \
--input /tmp/planarity_k33_certificate.graphml \
--input /tmp/planarity_k33_certificate.gexf \
--gephi --require-gephi \
--gephi-template portable.python-file-exists \
--report /tmp/aleph_planarity_ci_report.json --print-summary
# CI batch report with render validation
ruby scripts/planarity_certificate_ci_batch.rb \
--input /tmp/planarity_k33_certificate.graphml \
--render-gephi --require-render \
--render-profile portable.python-render-svg \
--render-output-dir /tmp/aleph_planarity_renders \
--report /tmp/aleph_planarity_ci_render_report.json --print-summary
# Dedicated visual golden-diff runner (deterministic)
ruby scripts/planarity_certificate_ci_visual_diff.rb \
--input /tmp/planarity_k33_certificate.graphml \
--profile portable.python-render-svg \
--profile portable.python-render-pdf \
--render-output-dir /tmp/aleph_planarity_visual_renders \
--report /tmp/aleph_planarity_visual_diff_report.json --print-summary
# Real-Gephi local smoke check (without portable profiles)
ruby scripts/planarity_certificate_validator.rb \
--input scripts/fixtures/planarity_k33_certificate.graphml \
--gephi --require-gephi \
--gephi-cmd "\"/path/to/gephi\" --version"
# Nightly workflow manual override example:
# workflow_dispatch input gephi_tags="v0.9.7,v0.10.1"
# Local nightly artifact comparison/regression check (Ruby implementation)
ruby scripts/planarity_gephi_weekly_comparison.rb \
--artifacts-root /tmp/gephi-nightly-artifacts \
--resolved-tags v0.9.7,v0.10.1 \
--run-id local --run-attempt 1 --git-sha local \
--report-json /tmp/gephi_weekly_comparison.json \
--report-md /tmp/gephi_weekly_comparison.md \
--print-summary
# Optional regression notification (webhook)
ALEPH_PLANARITY_ALERT_WEBHOOK="https://example.invalid/webhook" \
ruby scripts/planarity_gephi_regression_notify.rb \
--report-json /tmp/gephi_weekly_comparison.json \
--output-md /tmp/gephi_nightly_alert.md \
--repository lrleon/Aleph-w \
--run-url https://github.com/lrleon/Aleph-w/actions/runs/123 \
--webhook-env ALEPH_PLANARITY_ALERT_WEBHOOK \
--print-summary
using Graph = List_Graph<Graph_Node<int>, Graph_Arc<int>>;
Planarity_Test_Options opts;
opts.compute_embedding = true;
opts.compute_nonplanar_certificate = true;
opts.embedding_prefer_lr_linear = true;
opts.embedding_allow_bruteforce_fallback = true;
auto result = planarity_test(g, opts);
std::cout << "Planar: " << result.is_planar << "\n";
std::cout << "Certificate: " << to_string(result.certificate_type) << "\n";
if (!result.certificate_obstruction_edges.is_empty())
std::cout << "First witness edge multiplicity: "
<< result.certificate_obstruction_edges[0].input_arcs.size()
<< "\n";
if (result.is_planar && result.has_combinatorial_embedding) {
auto md = planar_dual_metadata(result);
auto dual = build_planar_dual_graph<Graph>(md);
auto drawing = planar_geometric_drawing(result);
std::cout << "Dual faces: " << dual.get_num_nodes() << "\n";
std::cout << "Crossings: " << drawing.crossing_count << "\n";
} else if (result.has_nonplanar_certificate) {
auto vr = validate_nonplanar_certificate(result);
auto json = nonplanar_certificate_to_json(result);
auto dot = nonplanar_certificate_to_dot(result);
auto graphml = nonplanar_certificate_to_graphml(result);
auto gexf = nonplanar_certificate_to_gexf(result);
std::cout <<
"Certificate valid: " <<
vr.is_valid <<
"\n";
std::cout << "JSON bytes: " << json.size() << "\n";
std::cout << "DOT bytes: " << dot.size() << "\n";
std::cout << "GraphML bytes: " << graphml.size() << "\n";
std::cout << "GEXF bytes: " << gexf.size() << "\n";
}
}
Planarity testing on Aleph graphs.
Emparejamiento
┌─────────────────────────────────────────────────────────────────────────────┐
│ MATCHING ALGORITHMS │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ BIPARTITE MATCHING │
│ │
│ Hopcroft-Karp: O(E√V) │
│ Max-Flow Reduction: O(VE) │
│ │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ GENERAL GRAPH MATCHING (Edmonds-Blossom) │
│ │
│ Handles odd cycles (blossoms) in non-bipartite graphs │
│ Time: O(V³) │
│ │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ GENERAL GRAPH WEIGHTED MATCHING (Weighted Blossom) │
│ │
│ Maximizes total matching weight in non-bipartite graphs │
│ Optional: maximize cardinality first, then weight │
│ Backends: List_Graph, List_SGraph, Array_Graph │
│ Time: O(V³) │
│ │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ GENERAL GRAPH MINIMUM-COST MATCHING (Dedicated API) │
│ │
│ Minimizes total matching cost in non-bipartite graphs │
│ Optional: maximize cardinality first, then minimize cost │
│ Also supports minimum-cost perfect matching (feasibility-aware) │
│ API: blossom_minimum_cost_matching(), │
│ blossom_minimum_cost_perfect_matching() │
│ Time: O(V³) │
│ │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ASSIGNMENT PROBLEM (Hungarian / Munkres) │
│ │
│ Given an m×n cost matrix, find the minimum-cost perfect matching │
│ between rows and columns. │
│ │
│ Cost matrix: Optimal assignment: │
│ ┌──────────────┐ Worker 0 → Task 2 (cost 69) │
│ │ 82 83 69 │ Worker 1 → Task 1 (cost 37) │
│ │ 77 37 49 │ Worker 2 → Task 0 (cost 11) │
│ │ 11 69 5 │ Worker 3 → Task 3 (cost 23) │
│ │ 8 9 98 │ │
│ └──────────────┘ Total cost: 140 │
│ │
│ Algorithm: Shortest augmenting paths + dual variables (potentials) │
│ Time: O(n³) Space: O(n²) Handles: rectangular, negative costs │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Emparejamiento en grafos generales (Edmonds-Blossom)
size_t cardinality = blossom_maximum_cardinality_matching(g, matching);
std::cout << "Maximum matching size: " << cardinality << "\n";
return 0;
}
Edmonds' Blossom algorithm for maximum matching in general graphs.
Dynamic doubly linked list with O(1) size and bidirectional access.
Main namespace for Aleph-w library functions.
Emparejamiento ponderado en grafos generales (Weighted Blossom)
Blossom_Weighted.H es independiente del backend en Aleph. Se prueba en:
List_Graph<Graph_Node<int>, Graph_Arc<long long>>
List_SGraph<Graph_Snode<int>, Graph_Sarc<long long>>
Array_Graph<Graph_Anode<int>, Graph_Aarc<long long>>
Ver Tests/weighted_blossom_test.cc y Examples/weighted_blossom_example.cc.
auto result = blossom_maximum_weight_matching(g, matching);
std::cout << "Matching size: " << result.cardinality << "\n";
std::cout << "Total weight: " << result.total_weight << "\n";
return 0;
}
Maximum-weight matching in general undirected graphs.
Arc for graphs implemented with simple adjacency lists.
Graph class implemented with singly-linked adjacency lists.
Emparejamiento de costo mínimo en grafos generales (API dedicada)
Min_Cost_Matching.H provee una API dedicada para emparejamiento de costo mínimo no bipartito sobre backends de grafo Aleph (List_Graph, List_SGraph, Array_Graph).
También provee una variante dedicada de emparejamiento perfecto: blossom_minimum_cost_perfect_matching(), que reporta factibilidad y retorna el costo mínimo de emparejamiento perfecto cuando es factible.
auto pure = blossom_minimum_cost_matching(g, matching);
auto card_first = blossom_minimum_cost_matching(
std::cout << "Pure -> card: " << pure.cardinality
<< ", cost: " << pure.total_cost << "\n";
std::cout << "Card+ -> card: " << card_first.cardinality
<< ", cost: " << card_first.total_cost << "\n";
auto perfect = blossom_minimum_cost_perfect_matching(g, matching);
if (perfect.feasible)
std::cout << "Perfect -> card: " << perfect.cardinality
<< ", cost: " << perfect.total_cost << "\n";
else
std::cout << "Perfect -> infeasible\n";
return 0;
}
Minimum-cost matching in general undirected graphs.
Default distance accessor for arc weights.
Default filter for filtered iterators on arcs.
Asignación húngara (Munkres)
{82, 83, 69, 92},
{77, 37, 49, 92},
{11, 69, 5, 86},
{ 8, 9, 98, 23}
});
for (auto [worker, task] : ha.get_assignments())
std::cout <<
"Worker " << worker <<
" -> Task " << task <<
"\n";
profit.allocate();
std::cout << "Max profit: " << result.total_cost << "\n";
return 0;
}
Hungarian (Munkres) algorithm for the assignment problem.
Dynamic matrix with sparse storage.
Hungarian (Munkres) algorithm for optimal assignment.
Cost_Type get_total_cost() const noexcept
Get the optimal total cost.
Hungarian_Result< Cost_Type > hungarian_max_assignment(const DynMatrix< Cost_Type > &cost)
Compute maximum-profit assignment (free function).
Dynamic matrix with lazy allocation.
Algoritmos de cadenas
Aleph-w ahora incluye un toolkit clásico completo de cadenas dividido por propósito:
Algoritmos cubiertos
- Búsqueda de un solo patrón:
kmp_search, z_search, boyer_moore_horspool_search, rabin_karp_search
- Búsqueda multi-patrón:
Aho_Corasick
- Estructuras de sufijos:
suffix_array, lcp_array_kasai, Naive_Suffix_Tree, Suffix_Automaton
- Palíndromos:
manacher, longest_palindromic_substring
- Edición/similitud:
levenshtein_distance, damerau_levenshtein_distance
- Similitud de secuencias:
longest_common_subsequence, longest_common_substring
Ejemplo de uso
#include <iostream>
auto multi = ac.
search(
"ahishers");
std::cout << "kmp matches: " << kmp.size() << "\n";
std::cout << "aho matches: " << multi.size() << "\n";
std::cout << "sa size: " << sa.size() << ", lcp size: " << lcp.size() << "\n";
std::cout << "longest palindrome: " << pal.longest_palindrome << "\n";
std::cout << "lcs length: " << lcs.length << ", damerau: " << dist << "\n";
}
Umbrella header for classical string algorithms in Aleph-w.
Aho-Corasick multi-pattern automaton.
void build()
Build failure links and transition completion.
size_t add_pattern(std::string pattern)
Add one pattern to the automaton.
Array< Match > search(const std::string_view text) const
Search all patterns in a text.
LCS_Result longest_common_subsequence(const std::string_view a, const std::string_view b)
Compute Longest Common Subsequence.
Array< size_t > lcp_array_kasai(const std::string_view text, const Array< size_t > &sa)
Compute LCP array from text and suffix array using Kasai.
Array< size_t > kmp_search(const std::string_view text, const std::string_view pattern)
Find all occurrences of a pattern using KMP.
Manacher_Result manacher(const std::string_view text)
Compute palindromic radii and the longest palindrome with Manacher.
size_t damerau_levenshtein_distance(const std::string_view a, const std::string_view b)
Damerau-Levenshtein distance with adjacent transpositions.
Array< size_t > suffix_array(const std::string_view text)
Build suffix array with doubling algorithm.
Ejemplos de cadenas
Cada algoritmo tiene un ejemplo enfocado bajo Examples/:
Algoritmos de programación dinámica
Aleph-w también incluye un toolkit práctico de programación dinámica:
| Header | Alcance |
Knapsack.H | mochila 0/1, ilimitada y acotada (con reconstrucción) |
LIS.H | LIS y LNDS en O(n log n), con reconstrucción de la secuencia |
Matrix_Chain.H | parentización óptima de cadena de matrices (DP por intervalos) |
Subset_Sum.H | subset sum (existencia/reconstrucción/conteo) + MITM |
Tree_DP.H | DP genérica en árboles + rerooting DP (todas las raíces en O(n)) |
DP_Optimizations.H | D&C DP, Knuth, Convex Hull Trick, Li Chao, monotone queue |
APIs de DP cubiertas
- Mochila:
knapsack_01, knapsack_01_value, knapsack_unbounded, knapsack_bounded
- Subsecuencias:
longest_increasing_subsequence, lis_length, longest_nondecreasing_subsequence
- Cadena de matrices:
matrix_chain_order, matrix_chain_min_cost
- Subset sum:
subset_sum, subset_sum_exists, subset_sum_count, subset_sum_mitm
- Árboles:
Gen_Tree_DP, Gen_Reroot_DP, tree_subtree_sizes, tree_max_distance, tree_sum_of_distances
- Optimizaciones de DP:
divide_and_conquer_partition_dp, knuth_optimize_interval, optimal_merge_knuth, Convex_Hull_Trick, Li_Chao_Tree, monotone_queue_min_dp, min_weighted_squared_distance_1d
Ejemplo de uso de DP
return int(
k.optimal_value + lis.length + mc.min_multiplications + ss.exists + geo.size());
}
Classical DP optimization toolkit: D&C DP, Knuth, CHT, Li Chao, and monotone-queue transitions.
Classical knapsack problem variants (0/1, unbounded, bounded).
Longest Increasing Subsequence (LIS) via patience sorting.
Matrix-chain multiplication ordering via interval DP.
Subset sum algorithms: classical DP and meet-in-the-middle.
Simple dynamic array with automatic resizing and functional operations.
Matrix_Chain_Result matrix_chain_order(const Array< size_t > &dims)
Compute optimal matrix-chain multiplication order.
Array< T > min_weighted_squared_distance_1d(const Array< T > &xs, const Array< T > &weights)
Weighted squared-distance lower envelope on a line.
Knapsack_Result< V > knapsack_01(const Array< Knapsack_Item< W, V > > &items, W capacity)
0/1 Knapsack with item reconstruction.
LIS_Result< T > longest_increasing_subsequence(const Array< T > &seq, Compare cmp=Compare())
Compute the Longest Increasing Subsequence (patience sorting).
Subset_Sum_Result< T > subset_sum(const Array< T > &values, T target)
Subset sum via classical DP with reconstruction.
Ejemplos de DP
Algoritmos de ordenamiento
┌─────────────────────────────────────────────────────────────────────────────┐
│ SORTING ALGORITHMS │
├─────────────────┬──────────────┬──────────────┬──────────────┬──────────────┤
│ Algorithm │ Best │ Average │ Worst │ Stable? │
├─────────────────┼──────────────┼──────────────┼──────────────┼──────────────┤
│ Quicksort │ O(n log n) │ O(n log n) │ O(n²) │ No │
│ Mergesort │ O(n log n) │ O(n log n) │ O(n log n) │ Yes │
│ Heapsort │ O(n log n) │ O(n log n) │ O(n log n) │ No │
│ Introsort │ O(n log n) │ O(n log n) │ O(n log n) │ No │
│ Insertion Sort │ O(n) │ O(n²) │ O(n²) │ Yes │
│ Shell Sort │ O(n log n) │ O(n^1.3) │ O(n²) │ No │
└─────────────────┴──────────────┴──────────────┴──────────────┴──────────────┘
Introsort: Hybrid algorithm
- Starts with Quicksort
- Switches to Heapsort if recursion too deep
- Uses Insertion Sort for small subarrays
- Guarantees O(n log n) worst case
quicksort(arr);
quicksort(arr, [](int a, int b) { return a > b; });
return 0;
}
High-level sorting functions for Aleph containers.
Dynamic singly linked list with functional programming support.
void mergesort(T *a, const long l, const long r, std::vector< T > &buf, Compare cmp)
Sort an array using merge sort with a reusable buffer.
Procesamiento de señales (FFT)
Aleph-w incluye un completo toolkit de Transformada Rápida de Fourier y procesamiento digital de señales en fft.H. Capacidades principales:
- FFT/IFFT para señales reales y complejas (Cooley-Tukey radix-2/4, Bluestein para tamaños arbitrarios)
- STFT/ISTFT con procesadores streaming para análisis tiempo-frecuencia
- Diseño de filtros FIR: método de la ventana (
firwin), mínimos cuadrados (firls) y Remez
- Diseño de filtros IIR: familias Butterworth, Chebyshev I/II, Bessel y Elíptico (Cauer)
- Estimación espectral: PSD de Welch, densidad espectral cruzada, coherencia
- Convolución eficiente: Overlap-Add, Overlap-Save y convolución particionada para streaming de baja latencia
- Resampleo: resampleo racional polifásico (
resample_poly, upfirdn)
- Transformadas N-dimensionales (2-D, 3-D)
- Raíces de polinomios via eigenvalores de la matriz compañera
- Variantes paralelas de todos los métodos via
ThreadPool (prefijados con p)
- Despacho SIMD: selección automática AVX2/NEON en tiempo de ejecución
Para un recorrido detallado con ejemplos de código, ver el Tutorial FFT y Procesamiento Digital de Señales (English).
Transformada teórico-numérica (NTT)
Aleph-w también incluye una implementación industrial de la Number Theoretic Transform en ntt.H. Capacidades principales:
- Transformadas y productos modulares exactos bajo primos NTT-friendly
- Planes reutilizables via
NTT<MOD, ROOT>::Plan
- Soporte Bluestein para tamaños no potencia de dos cuando el módulo admite las raíces necesarias
- Butterflies Montgomery para el hot loop modular
- Variantes paralelas con
ThreadPool para transformadas, productos y lotes
- Dispatch SIMD con selección AVX2/NEON en tiempo de ejecución sobre el camino potencia-de-dos
- Reconstrucción CRT de tres primos en
__uint128_t mediante NTTExact
- Álgebra formal de polinomios: inversa, división, log, exp, sqrt, potencia, evaluación multipunto e interpolación
- Multiplicación de enteros grandes sobre dígitos en base
B con propagación de carry
- Convolución negacíclica módulo
x^N + 1
Para un recorrido detallado con ejemplos de código, consulta el Tutorial NTT (English).
Aritmética de polinomios
Aleph-w proporciona una clase genérica de polinomios univariados dispersos en tpl_polynomial.H. El tipo de coeficiente es un parámetro de plantilla (por defecto double). Solo los coeficientes no nulos se almacenan en un DynMapTree<size_t, Coefficient>, haciendo las operaciones eficientes en polinomios dispersos de alto grado como x^1000 + 1.
Aritmética: +, -, *, /, %, divmod, * y / escalar, negación unaria, variantes in-place (+=, -=, *=, /=, %=).
Cálculo: derivative, nth_derivative, integral (indefinida), definite_integral(a, b).
Evaluación: eval(x) adaptativa (Horner para densos, potencia directa para ultra-dispersos), horner_eval, sparse_eval, multi_eval(points), operator()(x).
Composición y potencia: compose(q) (Horner sparse-aware), pow(n) (cuadratura repetida).
Fábricas: zero(), one(), x_to(n), from_roots(lista), interpolate(puntos) (diferencias divididas de Newton).
Familia GCD: gcd(a, b), xgcd(a, b) (extendido, retorna coeficientes de Bezout), lcm(a, b), pseudo_divmod(d) para coeficientes enteros exactos.
Transformaciones algebraicas: to_monic(), square_free(), reverse(), negate_arg(), shift(k) (desplazamiento de Taylor p(x+k)), shift_up(k), shift_down(k), truncate(n), to_dense().
Análisis de raíces (punto flotante): cauchy_bound(), sign_variations() (Descartes), sturm_chain(), count_real_roots(a, b), count_all_real_roots(), bisect_root(a, b), newton_root(x0).
Alias de tipo: Polynomial (double), PolynomialF (float), PolynomialLD (long double).
auto q = Polynomial::from_roots({1.0, 2.0, 3.0});
std::cout << "p(5) = " << p(5.0) << "\n";
std::cout <<
"p'(x) = " << p.
derivative() <<
"\n";
double raiz = q.newton_root(0.5);
auto [cociente, resto] = q.divmod(
Polynomial({-1, 1}));
std::cout << cociente << "\n";
Univariate polynomial over a generic coefficient ring.
size_t count_all_real_roots() const
Total number of distinct real roots.
Gen_Polynomial derivative() const
Formal derivative .
Gestión de memoria
Asignadores arena
La asignación arena proporciona gestión de memoria ultrarrápida para estructuras de datos temporales.
┌─────────────────────────────────────────────────────────────────────────────┐
│ ARENA MEMORY LAYOUT │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Traditional Allocation (malloc): │
│ │
│ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
│ │ A │ │free│ │ B │ │free│ │ C │ Fragmented, scattered │
│ └────┘ └────┘ └────┘ └────┘ └────┘ │
│ 0 1 2 3 4 ▲ ▲ │
│ front back │
│ Access: O(1) │
│ Append: O(1) amortized Enqueue: O(1) │
│ Insert: O(n) Dequeue: O(1) │
│ │
│ Arena Allocation: │
│ │
│ ┌──────────────────────────────────────────────────────────────────────────┤
│ │ A │ B │ C │ D │ E │ available space │
│ └──────────────────────────────────────────────────────────────────────────┤
│ ▲ ▲ ▲ │
│ base current end │
│ │
│ Allocation: Just increment `current` pointer ────── O(1) │
│ Deallocation: Reset `current` to `base` ──────────── O(1) bulk │
│ │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ COMPARISON │
│ │
│ ┌────────────────┬─────────────┬──────────────────┐ │
│ │ Operation │ malloc │ Arena │ │
│ ├────────────────┼─────────────┼──────────────────┤ │
│ │ Allocate │ O(log n)* │ O(1) │ │
│ │ Deallocate │ O(log n)* │ O(1) bulk only │ │
│ │ Fragmentation│ High │ None │ │
│ │ Cache perf │ Poor │ Excellent │ │
│ │ Overhead │ 16+ bytes │ 0 bytes │ │
│ └────────────────┴─────────────┴──────────────────┘ │
│ * Depending on allocator implementation │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Uso básico de arena
char buffer[1024 * 1024];
int* numbers = static_cast<int*>(arena.alloc(100 * sizeof(int)));
void* aligned = arena.alloc_aligned(1024, 64);
std::cout << "Used: " << arena.allocated_size() << " bytes\n";
std::cout << "Free: " << arena.available_size() << " bytes\n";
struct MyClass {
std::string name;
int value;
MyClass(std::string n,
int v) : name(
std::move(n)), value(v) {}
};
MyClass* obj = allocate<MyClass>(arena, "test", 42);
dealloc<MyClass>(arena, obj);
return 0;
}
Memory arena for fast bulk allocations.
Arena allocator for fast bump-pointer allocation.
Árboles con asignación arena
char buffer[64 * 1024];
for (int i = 0; ; ++i) {
int* result = tree.insert(i);
if (result == nullptr) {
std::cout << "Arena full after " << i << " insertions\n";
break;
}
}
if (tree.uses_arena()) {
std::cout << "Allocated: " << tree.arena_allocated_size() << "\n";
std::cout << "Available: " << tree.arena_available_size() << "\n";
}
return 0;
}
Dynamic set backed by balanced binary search trees with automatic memory management.
Cuándo usar asignación arena
| Caso de uso | Tradicional | Arena | Recomendación |
| Computaciones temporales | Muchos mallocs | Un solo buffer | Arena |
| Tiempo de vida conocido | Rastrear cada objeto | Liberación en bloque | Arena |
| Sistemas en tiempo real | Latencia impredecible | alloc O(1) | Arena |
| Objetos de larga vida | Bien | No apto | Tradicional |
| Objetos con tiempos de vida variables | Bien | Difícil | Tradicional |
Computación paralela
Pool de hilos
#include <future>
#include <vector>
ThreadPool pool(std::thread::hardware_concurrency());
std::vector<std::future<int>> futures;
for (int i = 0; i < 100; ++i) {
futures.push_back(
pool.enqueue([i] {
return compute_something(i);
})
);
}
int total = 0;
for (auto& future : futures) {
total += future.get();
}
std::cout << "Total: " << total << "\n";
return 0;
}
A reusable thread pool for efficient parallel task execution.
A modern, efficient thread pool for parallel task execution.
Operaciones funcionales paralelas
auto squared = pmap(numbers, [](int x) {
return x * x;
});
auto evens =
pfilter(numbers, [](
int x) {
return x % 2 == 0;
});
int sum = pfold(numbers, 0, [](
int a,
int b) {
return a + b;
});
x *= 2;
});
return 0;
}
Parallel functional programming operations using ThreadPool.
void pfor_each(ThreadPool &pool, Container &c, Op op, size_t chunk_size=0)
Parallel for_each operation.
auto pfilter(ThreadPool &pool, const Container &c, Pred pred, size_t chunk_size=0)
Parallel filter operation.
Programación funcional
Todos los contenedores de Aleph-w soportan un conjunto rico de operaciones funcionales:
Operaciones centrales
| Operación | Descripción | Complejidad |
for_each(f) | Aplicar f a cada elemento | O(n) |
map(f) | Transformar elementos | O(n) |
filter(p) | Seleccionar elementos que cumplen el predicado | O(n) |
foldl(init, f) | Fold izquierdo (reduce) | O(n) |
foldr(init, f) | Fold derecho | O(n) |
all(p) | Verificar si todos cumplen | O(n) |
exists(p) | Verificar si alguno cumple | O(n) |
find_ptr(p) | Encontrar el primero que cumple | O(n) |
zip(other) | Emparejar elementos de dos contenedores | O(n) |
take(n) | Primeros n elementos | O(n) |
drop(n) | Omitir los primeros n elementos | O(n) |
partition(p) | Particionar por predicado | O(n) |
Ejemplos
auto squared = numbers.map([](int x) { return x * x; });
auto evens = numbers.
filter([](
int x) {
return x % 2 == 0; });
int sum = numbers.
foldl(0, [](
int acc,
int x) {
return acc + x; });
bool all_positive = numbers.
all([](
int x) {
return x > 0; });
bool has_negative = numbers.
exists([](
int x) {
return x < 0; });
int* found = numbers.
find_ptr([](
int x) {
return x > 5; });
if (found)
std::cout << "First > 5: " << *found << "\n";
auto [small, large] = numbers.
partition([](
int x) {
return x <= 5; });
auto pairs = names.zip(ages);
return 0;
}
__T foldl(const __T &init, Op &op) const
Fold the elements of the container to a specific result.
Aleph::DynList< T > filter(Operation &operation) const
Filter the elements of a container according to a matching criterion.
std::pair< Aleph::DynList< T >, Aleph::DynList< T > > partition(Operation &op) const
Exclusive partition of container according to a filter criterion.
bool exists(Operation &op) const
Test for existence in the container of an element satisfying a criterion.
bool all(Operation &operation) const
Check if all the elements of the container satisfy a condition.
Type * find_ptr(Operation &operation) noexcept(operation_is_noexcept< Operation >())
Find a pointer to an item in the container according to a searching criterion.
Integración con ranges de C++20
#include <ranges>
auto result = numbers
| std::views::filter([](int x) { return x % 2 == 0; })
| std::views::transform([](int x) { return x * 10; });
for (int x : result)
auto arr = std::views::iota(1, 10) | to_dynarray;
return 0;
}
C++20 Ranges support and adaptors for Aleph-w containers.
void to_dynlist(const DynArray< T > &arr, DynList< T > &list)
Framework de búsqueda en espacios de estados
Esta rama incluye la primera entrega pública de un framework reutilizable para búsqueda en espacios implícitos con poda, cotas y heurísticas adversarias. El diseño sigue la regla de “núcleo compartido y semánticas separadas”: solo compartimos infraestructura cuando las semánticas realmente coinciden (por ejemplo, DFS/backtracking frente a Branch and Bound frente a Negamax/Alpha-Beta adversario).
Qué ya está disponible
state_search_common.H – límites, políticas de exploración, estadísticas, rutas y contratos conceptuales compartidos para árboles/DAGs implícitos con generación lazy de sucesores y make/unmake incremental.
Backtracking.H – búsqueda en profundidad con detección de metas y evaluación incremental.
Branch_And_Bound.H – incumbentes, cotas optimistas, estrategias DFS y best-first, más ordenamiento opcional de hijos.
Negamax.H / Alpha_Beta.H – búsqueda adversaria para juegos de dos jugadores, suma cero e información perfecta, con ordenamiento opcional de movimientos (heurísticas killer/history), soporte para tablas de transposición y seguimiento de la variación principal.
Transposition_Table.H – backend de memoización sobre hash tables de Aleph que hoy usan los motores adversarios y que mañana respaldará la memoización de Branch and Bound cuando se formalicen sus reglas de dominancia.
State_Search.H – include paraguas y fachada Aleph::Search que elige el motor adecuado según el contrato del dominio.
Cada fase llega con código compilable, smoke tests, benchmarks y documentación breve para que puedas aprovechar el framework mientras completamos el resto del roadmap (búsqueda iterativa en profundidad, ventanas de aspiración, reutilización de buffers, memoización de B&B, políticas de frontera).
Documentación, ejemplos y pruebas
- docs/state_search_v1.md – resumen de arquitectura, metodología de benchmarks, notas de perfilado y hoja de ruta v2.
- docs/adversarial_search_framework.md – contrato Negamax/Alpha-Beta, hooks de ordenamiento de movimientos y protocolo de tablas de transposición.
- Ejemplos:
- Pruebas:
cmake --build build --target state_search_benchmark
ctest --test-dir build/Examples -R StateSearch
Tus comentarios son bienvenidos mientras completamos las fases restantes sin añadir sobre-ingeniería y reutilizando contenedores, hashing y utilidades de Aleph.
Tutorial
Ejemplo completo: construir una herramienta de análisis de redes sociales
Este tutorial demuestra múltiples características de Aleph-w trabajando juntas.
#include <iostream>
};
struct Connection {
int strength;
};
SocialNode* find_closest_friend(
SocialNetwork& network,
SocialNode* person,
const std::string& target_name
) {
SocialNode* target = nullptr;
if (node->get_info().name == target_name)
target = node;
});
if (!target) return nullptr;
dijkstra_min_path(network, person, target, path);
return target;
}
connected_components(network, components);
for (auto& component : components) {
component.for_each_node([&](auto* node) {
community.
append(node->get_info().name);
});
communities.
append(std::move(community));
}
return communities;
}
network.for_each_node([&](auto* node) {
int connections = 0;
for (auto it = network.get_first_arc(node);
it.has_curr(); it.next()) {
connections++;
}
influence.insert(node->get_info().name, connections);
});
return influence;
}
SocialNetwork network;
auto* alice = network.insert_node({"Alice", 30});
auto* bob = network.insert_node({"Bob", 25});
auto* charlie = network.insert_node({"Charlie", 35});
auto* david = network.insert_node({"David", 28});
auto* eve = network.insert_node({"Eve", 32});
network.insert_arc(alice, bob, {8});
network.insert_arc(bob, charlie, {6});
network.insert_arc(charlie, david, {9});
network.insert_arc(alice, eve, {4});
network.insert_arc(eve, david, {7});
auto communities = find_communities(network);
std::cout <<
"Communities found: " << communities.
size() <<
"\n";
auto influence = calculate_influence(network);
std::cout << "\nInfluence scores:\n";
influence.for_each([](const std::string& name, int score) {
std::cout << " " << name << ": " << score << "\n";
});
network.for_each_arc([&](auto* arc) {
strengths.
append(arc->get_info().strength);
});
int total_strength = pfold(strengths, 0,
[](int a, int b) { return a + b; });
std::cout << "\nAverage connection strength: "
<< (double)total_strength / strengths.
size() <<
"\n";
return 0;
}
T & append(const T &item)
size_t size() const noexcept
Count the number of elements of the list.
void for_each_node(Operation &operation) const
Unconditionally traverse all the nodes of graph and on each one perform an operation.
Referencia de API
Referencia rápida por categoría
Contenedores
| Header | Tipo | Descripción |
tpl_dynList.H | DynList<T> | Singly-linked list |
tpl_dynDlist.H | DynDlist<T> | Doubly-linked list |
tpl_dynArray.H | DynArray<T> | Dynamic array |
tpl_dynSetTree.H | DynSetTree<T, Tree> | Tree-based set |
tpl_dynMapTree.H | DynMapTree<K, V, Tree> | Tree-based map |
tpl_hash.H | DynHashSet<T> | Hash set |
tpl_hash.H | DynHashMap<K, V> | Hash map |
tpl_binHeap.H | BinHeap<T, Cmp> | Binary heap |
tpl_arrayQueue.H | ArrayQueue<T> | Queue (array-based) |
tpl_arrayStack.H | ArrayStack<T> | Stack (array-based) |
tpl_fenwick_tree.H | Fenwick_Tree<T> | Fenwick tree (BIT) |
tpl_fenwick_tree.H | Gen_Fenwick_Tree<T, Plus, Minus> | Fenwick over abelian groups |
tpl_fenwick_tree.H | Range_Fenwick_Tree<T> | Range update/query Fenwick |
tpl_sparse_table.H | Sparse_Table<T> | Static range min in O(1) |
tpl_sparse_table.H | Gen_Sparse_Table<T, Op> | Static range query (idempotent op) |
tpl_disjoint_sparse_table.H | Sum_Disjoint_Sparse_Table<T> | Static range sum in O(1) |
tpl_disjoint_sparse_table.H | Product_Disjoint_Sparse_Table<T> | Static range product in O(1) |
tpl_disjoint_sparse_table.H | Gen_Disjoint_Sparse_Table<T, Op> | Static range query (associative op) |
tpl_segment_tree.H | Sum_Segment_Tree<T> | Range sum with point updates |
tpl_segment_tree.H | Min_Segment_Tree<T> | Range min with point updates |
tpl_segment_tree.H | Max_Segment_Tree<T> | Range max with point updates |
tpl_segment_tree.H | Gen_Segment_Tree<T, Op> | Range query (associative monoid) |
tpl_segment_tree.H | Lazy_Sum_Segment_Tree<T> | Range add + range sum (lazy) |
tpl_segment_tree.H | Lazy_Min_Segment_Tree<T> | Range add + range min (lazy) |
tpl_segment_tree.H | Lazy_Max_Segment_Tree<T> | Range add + range max (lazy) |
tpl_segment_tree.H | Gen_Lazy_Segment_Tree<Policy> | Lazy segment tree (custom policy) |
tpl_segment_tree.H | Segment_Tree_Beats<T> | Ji Driver's segment tree (chmin/chmax) |
tpl_mo_algorithm.H | Gen_Mo_Algorithm<T, Policy> | Mo's offline range queries (snake opt.) |
tpl_mo_algorithm.H | Distinct_Count_Mo<T> | Count distinct elements in ranges |
tpl_mo_algorithm.H | Powerful_Array_Mo<T> | Powerful array query (sum cnt²·x) |
tpl_mo_algorithm.H | Range_Mode_Mo<T> | Range mode (most frequent element) |
tpl_interval_tree.H | DynIntervalTree<T> | Interval tree (overlap/stabbing queries) |
tpl_interval_tree.H | Interval_Tree<T> | Low-level interval treap (raw nodes) |
tpl_link_cut_tree.H | Gen_Link_Cut_Tree<T, Monoid, LazyTag> | Link-Cut Tree (bosque dinámico + consultas de camino) |
tpl_link_cut_tree.H | Link_Cut_Tree | Link-Cut Tree solo conectividad (valores int) |
al-vector.H | Vector<T, NumType> | Sparse vector with domain indexing |
al-matrix.H | Matrix<Trow, Tcol, NumType> | Sparse matrix with domain indexing |
al-domain.H | AlDomain<T> | Domain for vector/matrix indices |
Tipos de árboles
Algoritmos de cadenas
| Header | Functions / Classes | Description |
String_Search.H | kmp_search(), z_search(), boyer_moore_horspool_search(), rabin_karp_search() | Pattern matching algorithms |
Aho_Corasick.H | Aho_Corasick | Multi-pattern search |
Suffix_Structures.H | suffix_array(), lcp_array_kasai(), Naive_Suffix_Tree, Suffix_Automaton | Text indexing structures |
String_Palindromes.H | manacher(), longest_palindromic_substring() | Palindrome detection in O(n) |
String_DP.H | levenshtein_distance(), damerau_levenshtein_distance(), longest_common_subsequence(), longest_common_substring() | Sequence similarity and edit distance |
String_Algorithms.H | *(all above)* | Umbrella include for string classical toolkit |
Programación dinámica
Por favor, consulta la sección canónica de Algoritmos de programación dinámica para una lista completa de headers, funciones y ejemplos.
Combinatoria y enumeración
| Header | Functions / Classes | Description |
ah-comb.H | next_permutation(), next_combination_indices(), next_combination_mask(), for_each_combination(), build_combinations(), combination_count(), bin_to_gray(), gray_to_bin(), build_gray_code() | Lexicographic permutation, k-combination enumeration, and Gray code utilities |
Matemática y teoría de números
| Header | Functions / Classes | Description |
fft.H | FFT<Real> | Transformada rápida de Fourier (FFT): Cooley-Tukey radix-2/4 y Bluestein para tamaños arbitrarios, STFT/ISTFT, diseño de filtros FIR/IIR (Butterworth, Chebyshev, Bessel, Elíptico), PSD de Welch, resampleo, raíces de polinomios, transformadas N-D y APIs paralelas con ThreadPool. Ver el Tutorial FFT y DSP |
modular_arithmetic.H | mod_mul(), mod_exp(), ext_gcd(), mod_inv(), crt() | Safe 64-bit modular arithmetic, extended GCD, modular inverse, and Chinese Remainder Theorem |
primality.H | miller_rabin() | Deterministic 64-bit Miller-Rabin primality testing |
pollard_rho.H | pollard_rho() | Integer factorization using Pollard's rho with random fallback |
ntt.H | NTT, NTTExact | Number Theoretic Transform para multiplicacion exacta de polinomios modulares, con planes reutilizables, soporte Bluestein para tamanos no potencia de dos cuando el modulo lo permite, dispatch SIMD AVX2/NEON en tiempo de ejecucion sobre el butterfly potencia-de-dos, lotes, butterflies basados en Montgomery, APIs paralelas con ThreadPool, algebra formal de polinomios (poly_inverse, poly_divmod, poly_log, poly_exp, poly_sqrt, poly_power, evaluacion multipunto e interpolacion), multiplicacion exacta de enteros grandes sobre digitos en base B, convolucion negaciclica modulo x^N + 1 y reconstruccion CRT de tres primos en __uint128_t cuando la cota de coeficientes cabe. Ver el Tutorial NTT |
tpl_polynomial.H | Gen_Polynomial<C>, Polynomial | Anillo de polinomios univariados dispersos: aritmética (+, -, *, /, %), cálculo (derivada, integral), evaluación (Horner/dispersa adaptativa), composición, GCD/XGCD/LCM, factorización libre de cuadrados, conteo de raíces (Sturm), búsqueda de raíces (bisección/Newton), interpolación polinómica (diferencias divididas de Newton) |
modular_combinatorics.H | ModularCombinatorics | \( nCk \pmod p \) with precomputed factorials and Lucas Theorem |
modular_linalg.H | ModularMatrix | Gaussian elimination, determinant, and inverse modulo a prime |
Algoritmos de grafos
| Header | Function | Description |
Dijkstra.H | dijkstra_min_path() | Single-source shortest path |
Bellman_Ford.H | bellman_ford_min_path() | Shortest path (negative edges) |
Floyd_Warshall.H | floyd_all_shortest_paths() | All-pairs shortest paths |
Johnson.H | johnson_all_pairs() | All-pairs (sparse graphs) |
AStar.H | astar_search() | Heuristic pathfinding |
K_Shortest_Paths.H | yen_k_shortest_paths(), eppstein_k_shortest_paths() | K shortest alternatives (loopless/simple and general) between source and target |
Kruskal.H | kruskal_min_spanning_tree() | MST (edge-based) |
Prim.H | prim_min_spanning_tree() | MST (vertex-based) |
Blossom.H | blossom_maximum_cardinality_matching() | Maximum matching (general graph) |
Blossom_Weighted.H | blossom_maximum_weight_matching() | Maximum-weight matching (general graph; List/SGraph/Array backends) |
Min_Cost_Matching.H | blossom_minimum_cost_matching(), blossom_minimum_cost_perfect_matching() | Minimum-cost matching in general graphs (including perfect-matching feasibility/cost) |
Hungarian.H | hungarian_assignment(), hungarian_max_assignment() | Assignment problem (min-cost / max-profit) |
LCA.H | Gen_Binary_Lifting_LCA, Gen_Euler_RMQ_LCA | Lowest common ancestor on rooted trees (binary lifting / Euler+RMQ) |
Tree_Decomposition.H | Gen_Heavy_Light_Decomposition, Gen_HLD_Path_Query | Heavy-Light decomposition + path/subtree dynamic queries |
Tree_Decomposition.H | Gen_Centroid_Decomposition | Centroid decomposition with centroid-ancestor distance chains |
HLD.H | Gen_HLD, HLD_Sum, HLD_Max, HLD_Min | Self-contained HLD with typed convenience wrappers + edge-weighted path queries |
tpl_maxflow.H | *_maximum_flow() | Maximum flow algorithms |
tpl_mincost.H | min_cost_max_flow() | Min-cost max-flow |
Tarjan.H | tarjan_scc() | Strongly connected components |
tpl_components.H | connected_components() | Connected components |
tpl_cut_nodes.H | compute_cut_nodes(), Compute_Cut_Nodes | Articulation points and biconnected components |
tpl_cut_nodes.H | find_bridges(), Compute_Bridges | Bridge edges (cut edges) — Tarjan O(V+E) |
Planarity_Test.H | planarity_test(), planar_dual_metadata(), planar_geometric_drawing(), validate_nonplanar_certificate(), nonplanar_certificate_to_json(), nonplanar_certificate_to_dot(), nonplanar_certificate_to_graphml(), nonplanar_certificate_to_gexf() | LR planarity test + embedding/dual metadata + geometric drawing + validated non-planar witness export |
topological_sort.H | topological_sort() | DAG ordering |
Karger.H | karger_min_cut() | Probabilistic min-cut |
Dominators.H | compute_dominators(), build_dominator_tree(), compute_dominance_frontiers(), compute_post_dominators(), build_post_dominator_tree(), compute_post_dominance_frontiers() | Dominator & post-dominator trees (Lengauer-Tarjan) + dominance/post-dominance frontiers |
Stoer_Wagner.H | stoer_wagner_min_cut() | Deterministic min-cut |
Gestión de memoria
| Header | Type/Function | Description |
ah-arena.H | AhArenaAllocator | Arena allocator |
ah-arena.H | allocate<T>() | Construct object in arena |
ah-arena.H | dealloc<T>() | Destroy object from arena |
Computación paralela
Programación funcional
| Header | Functions | Description |
ahFunctional.H | map, filter, fold, ... | Core FP operations |
ah-ranges.H | to_dynlist, to_dynarray | Range adaptors |
ah-zip.H | zip, unzip | Tuple operations |
Benchmarks
Rendimiento de árboles (1 millón de operaciones)
┌────────────────────────────────────────────────────────────────────────────┐
│ INSERT PERFORMANCE (ns/operation) │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ AVL Tree ████████████████████████ 156 ns │
│ Red-Black ██████████████████████████ 178 ns │
│ std::set ██████████████████████████ 183 ns │
│ Treap ██████████████████████████████ 212 ns │
│ Splay Tree ████████████████████████████████ 234 ns │
│ │
├────────────────────────────────────────────────────────────────────────────┤
│ SEARCH PERFORMANCE (ns/operation) │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ Splay (warm) ████████████████ 67 ns (after repeated access) │
│ AVL Tree ████████████████████ 89 ns │
│ std::set ██████████████████████ 95 ns │
│ Red-Black ██████████████████████ 98 ns │
│ Treap ██████████████████████████ 112 ns │
│ │
└────────────────────────────────────────────────────────────────────────────┘
Arena vs asignación tradicional
┌────────────────────────────────────────────────────────────────────────────┐
│ ALLOCATION PERFORMANCE (1M allocations) │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ Arena ██ 12 ns/alloc │
│ malloc ████████████████████████████████████████ 156 ns/alloc │
│ new ████████████████████████████████████████ 168 ns/alloc │
│ │
│ Speedup: ~13x faster than malloc │
│ │
├────────────────────────────────────────────────────────────────────────────┤
│ TREE WITH ARENA (10K insertions) │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ With Arena ████████████████ 1.2 ms │
│ Without Arena ████████████████████████████████████████ 3.8 ms │
│ │
│ Speedup: 3.2x faster │
│ │
└────────────────────────────────────────────────────────────────────────────┘
Escalado de Dijkstra
┌────────────────────────────────────────────────────────────────────────────┐
│ DIJKSTRA PERFORMANCE vs GRAPH SIZE │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ V=1K, E=10K ████ 2.3 ms │
│ V=10K, E=100K ████████████████████ 28 ms │
│ V=100K, E=1M ████████████████████████████████████████ 380 ms │
│ │
│ Confirmed: O((V+E) log V) scaling │
│ │
└────────────────────────────────────────────────────────────────────────────┘
Comparación de algoritmos de flujo máximo
┌────────────────────────────────────────────────────────────────────────────┐
│ MAX FLOW PERFORMANCE (V=1000, E=5000) │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ Ford-Fulkerson ████████████████████████████████████████ 180 ms │
│ Edmonds-Karp ██████████████████████████ 89 ms │
│ Push-Relabel ██████████████████ 45 ms │
│ Dinic ████████████████ 38 ms │
│ │
│ Recommendation: Use Dinic for large graphs │
│ │
└────────────────────────────────────────────────────────────────────────────┘
Aceleración de operaciones paralelas
┌────────────────────────────────────────────────────────────────────────────┐
│ pmap() SPEEDUP (8-core system) │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ 1 thread ████████████████████████████████████████ 100% (baseline) │
│ 2 threads ████████████████████ 52% (1.9x speedup) │
│ 4 threads ██████████████ 28% (3.6x speedup) │
│ 8 threads ████████ 15% (6.7x speedup) │
│ │
│ Parallel efficiency: 84% │
│ │
└────────────────────────────────────────────────────────────────────────────┘
Ejemplos
El directorio Examples/ contiene 80+ programas que demuestran el uso de la biblioteca:
Compilar ejemplos
cmake -S . -B build -DBUILD_EXAMPLES=ON
cmake --build build
Ejemplos clave por categoría
| Ejemplo | Archivo | Descripción |
| Estructuras de datos | | |
| Listas dinámicas | linear_structures_example.C | Listas, colas, pilas |
| Tablas hash | hash_tables_example.C | Conjuntos y mapas |
| Árboles | dynset_trees.C | Todas las variantes de árboles |
| Montículos | heap_example.C | Colas de prioridad |
| Consultas de rango | sparse_table_example.cc | Sparse Table (RMQ) |
| Suma/producto en rango | disjoint_sparse_table_example.cc | Disjoint Sparse Table |
| Árboles de segmentos | segment_tree_example.cc | Actualizaciones puntuales/en rango, propagación lazy, Beats |
| Árbol de intervalos | interval_tree_example.cc | Scheduler de reuniones, intersección de segmentos 1D |
| Árbol cartesiano/LCA/RMQ | cartesian_tree_example.cc | Árbol cartesiano, LCA, reducciones RMQ |
| Descomposición Heavy-Light | heavy_light_decomposition_example.cc | Consultas de camino/subárbol con actualizaciones dinámicas puntuales |
| Descomposición por centroides | centroid_decomposition_example.cc | Consultas dinámicas de centro activo más cercano en árboles |
| Link-Cut Trees | link_cut_tree_example.cc | Conectividad dinámica, re-enraizamiento, LCA, agregados de camino, actualizaciones perezosas |
| Algoritmo de Mo | mo_algorithm_example.cc | Consultas offline de rango (distinct count, powerful array, mode) |
| Caja de herramientas de combinatoria | comb_example.C | Recorrido de producto cartesiano, transposición y auxiliares de combinatoria |
| Utilidades de código Gray | gray_code_example.cc | Conversión binario a Gray y generación de secuencias |
| Transformada rápida de Fourier | fft_example.cc | Análisis espectral de señales reales, convolución real/compleja secuencial optimizada, concurrencia explícita con ThreadPool y uso directo con contenedores iterables compatibles como std::vector. Tutorial completo: Tutorial FFT y DSP |
| Number Theoretic Transform | ntt_example.cc | Transformadas modulares exactas, reporte del backend SIMD activo, planes reutilizables, tamanos arbitrarios soportados via Bluestein, multiplicacion exacta CRT de tres primos en __uint128_t, algebra formal de polinomios, multiplicacion de enteros grandes en base 10, convolucion negaciclica modulo x^N + 1, ejecucion por lotes y multiplicacion paralela explicita de polinomios. Tutorial completo: Tutorial NTT |
| Aritmética de polinomios | polynomial_example.cc | Álgebra de polinomios dispersos, cálculo simbólico, análisis de raíces (Sturm/bisección/Newton), interpolación de Newton, funciones de transferencia y operaciones dispersas de alto grado |
| Caja de herramientas de teoría de números | math_nt_example.cc | Multiplicación modular segura, Miller-Rabin, Pollard's Rho, NTT, combinatoria modular y álgebra lineal |
| Algoritmos de streaming | streaming_demo.cc | Reservoir Sampling, Count-Min Sketch, HyperLogLog, MinHash |
| Enumeración lexicográfica de permutaciones/combinaciones | combinatorics_enumeration_example.cc | next_permutation extendida, k-combinaciones por índices/bitmask y enumeración materializada |
| Básicos de grafos | | |
| BFS/DFS | bfs_dfs_example.C | Algoritmos de recorrido |
| Componentes | graph_components_example.C | Encontrar componentes |
| Grafos aleatorios | random_graph_example.C | Generación de grafos |
| Caminos mínimos | | |
| Dijkstra | dijkstra_example.cc | Fuente única |
| Bellman-Ford | bellman_ford_example.cc | Pesos negativos |
| Johnson | johnson_example.cc | Todos los pares sparse |
| A* | astar_example.cc | Búsqueda heurística |
| K caminos más cortos | k_shortest_paths_example.cc | Yen (sin ciclos) vs alternativas generales estilo Eppstein |
| Algoritmos de cadenas | | |
| KMP | kmp_example.cc | Búsqueda de un solo patrón en tiempo lineal basada en función prefijo |
| Z-algorithm | z_algorithm_example.cc | Array de similitud de prefijos y búsqueda de patrón |
| Boyer-Moore-Horspool | horspool_example.cc | Búsqueda práctica rápida con desplazamiento por mal carácter |
| Rabin-Karp | rabin_karp_example.cc | Búsqueda con rolling-hash con verificación exacta |
| Aho-Corasick | aho_corasick_example.cc | Matching con autómata multi-patrón |
| Suffix Array + LCP | suffix_array_lcp_example.cc | Orden lexicográfico de sufijos y LCP de Kasai |
| Suffix Tree | suffix_tree_example.cc | Búsquedas en árbol de sufijos comprimido naive |
| Suffix Automaton | suffix_automaton_example.cc | Autómata de substrings, conteo de substrings distintos, LCS |
| Manacher | manacher_example.cc | Substring palíndromo más largo en tiempo lineal |
| Levenshtein | edit_distance_example.cc | Distancia de edición vía programación dinámica |
| Damerau-Levenshtein | damerau_levenshtein_example.cc | Distancia de edición con transposiciones adyacentes |
| LCS / Longest Common Substring | lcs_longest_common_substring_example.cc | Extracción de subsecuencia y superposición contigua |
| Programación dinámica | (ver Algoritmos de programación dinámica) | Toolkit completo y ejemplos de optimización |
| Flujos en redes | | |
| Flujo máximo | network_flow_example.C | Flujo máximo básico |
| Flujo de costo mínimo | mincost_flow_example.cc | Optimización de costo |
| Corte mínimo | min_cut_example.cc | Karger, Stoer-Wagner |
| Algoritmos especiales | | |
| MST | mst_example.C | Kruskal, Prim |
| Matching general | blossom_example.cc | Edmonds-Blossom + exportaciones TikZ |
| Matching general ponderado | weighted_blossom_example.cc | Blossom ponderado + comparación de objetivo + exportaciones TikZ |
| Matching general de costo mínimo | min_cost_matching_example.cc | API dedicada de costo mínimo + factibilidad de matching perfecto + comparación de backends |
| Asignación (Húngaro) | hungarian_example.cc | Asignación Húngara/Munkres de costo mínimo y de máxima ganancia |
| LCA en árboles | lca_example.cc | Binary lifting + Euler/RMQ LCA con paridad cross-backend (List/SGraph/Array) |
| Descomposición de árboles | heavy_light_decomposition_example.cc, centroid_decomposition_example.cc | Consultas Heavy-Light de camino/subárbol y consultas dinámicas de distancia a centroides |
| Conveniencia HLD | hld_example.cc | Consultas de camino HLD_Sum/Max/Min, consultas de subárbol, actualizaciones puntuales, consultas con pesos en aristas |
| Link-Cut Tree | link_cut_tree_example.cc | Bosque dinámico: link, cut, reroot, LCA, path sum/min/max, actualizaciones perezosas |
| Planaridad + certificados | planarity_test_example.cc | Planaridad LR, metadatos del dual, dibujo geométrico, exportación de certificados JSON/DOT/GraphML/GEXF + validación estructural |
| SCC | tarjan_example.C | Fuertemente conexas |
| Ordenamiento topológico | topological_sort_example.C | Ordenamiento de DAG |
| Geometría | | | | Predicados robustos | robust_predicates_example.cc | Orientación, intersección, aritmética exacta | | Intersección de segmentos dedicada | segment_segment_intersection_example.cc | Intersección de segmentos por pares en O(1) (none/point/overlap) | | Algoritmos de geometría | geom_example.C | Convex hull, triangulación y -s advanced (Delaunay/Voronoi/PIP/HPI) | | Celdas de Voronoi recortadas | voronoi_clipped_cells_example.cc | Celdas de Voronoi recortadas indexadas por sitio con exportación CSV/WKT | | Delaunay + Voronoi | delaunay_voronoi_example.cc | Triangulación de Delaunay, dual de Voronoi, celdas recortadas | | Point-in-polygon | point_in_polygon_example.cc | Winding-number inside/boundary/outside | | Intersección de polígonos | polygon_intersection_example.cc | Intersección convexo-convexo (Sutherland-Hodgman) | | Intersección de semiplanos | halfplane_intersection_example.cc | Región factible acotada para restricciones lineales 2D | | Comparación de hull | convex_hull_comparison_example.cc | Comparar 5 algoritmos de hull con el mismo dataset | | Par más cercano | closest_pair_example.cc | Divide-and-conquer del par más cercano + verificación | | Rotating calipers | rotating_calipers_example.cc | Diámetro y ancho mínimo de un polígono convexo | | Polígonos TikZ | tikz_polygons_example.cc | Visualización estilizada de polígonos en PGF/TikZ | | Convex hull TikZ | tikz_convex_hull_example.cc | Nube de entrada + overlay del hull | | Intersecciones TikZ | tikz_intersection_example.cc | Overlays de intersección convexa y booleana | | Voronoi/power TikZ | tikz_voronoi_power_example.cc | Overlay Voronoi+Delaunay y power diagram | | Algoritmos avanzados TikZ | tikz_advanced_algorithms_example.cc | Arreglo de segmentos (caras coloreadas), camino mínimo con funnel portals, descomposición convexa y alpha shape | | Animación de funnel TikZ | tikz_funnel_animation_example.cc | Funnel multipágina (SSFA) con frames paso a paso para camino mínimo | | Funnel beamer TikZ | tikz_funnel_beamer_example.cc | Una diapositiva Beamer con overlays SSFA vía Tikz_Scene::draw_beamer_overlays() | | Funnel beamer TikZ (2-col) | tikz_funnel_beamer_twocol_example.cc | Overlays Beamer con frame visual izquierdo + panel de estado derecho (apex/left/right/event) | | Funnel handout TikZ | tikz_funnel_beamer_handout_example.cc | Salida beamer[handout] con un frame imprimible por paso del funnel (layout 2-columnas) | | Compositor de escenas TikZ | tikz_scene_example.cc | Composición Tikz_Scene de arreglo, hull y overlays de camino mínimo en una exportación | | Escena beamer/handout TikZ | tikz_scene_beamer_example.cc | Exportaciones single-frame Tikz_Scene::draw_beamer() y draw_handout() | | Overlays de escena TikZ | tikz_scene_overlays_example.cc | Tikz_Scene::draw_beamer_overlays() / draw_handout_overlays() para slides de polígonos paso a paso | | Paralelo | | | | Thread pool | thread_pool_example.cc | Tareas concurrentes | | Operaciones paralelas | ah_parallel_example.cc | pmap, pfilter | | Memoria | | | | Arena | map_arena_example.C | Arena allocator |
Algoritmos probabilísticos de streaming
Aleph-w proporciona un conjunto de algoritmos modernos para procesar flujos de datos con baja huella de memoria:
| Header | Class | Purpose |
reservoir-sampling.H | Reservoir_Sampler | Muestreo aleatorio de k elementos en un flujo de datos |
bloom-filter.H | Bloom_Filter | Membresía probabilística estándar (sin eliminación) |
cuckoo-filter.H | Cuckoo_Filter | Membresía de alto rendimiento con soporte de eliminación |
count-min-sketch.H | Count_Min_Sketch | Estimación de frecuencia aproximada (O(1)) |
hyperloglog.H | HyperLogLog | Estimación de cardinalidad (conteo de elementos únicos) con bajo error |
minhash.H | MinHash | Estimación de similitud de Jaccard entre conjuntos |
simhash.H | SimHash | Estimación de similitud de coseno usando huellas digitales de bits |
Ejemplo de uso de streaming
cms.update("event_type_a");
size_t freq = cms.estimate("event_type_a");
for (int i = 0; i < 1000000; ++i) hll.update(i % 1000);
double unique = hll.estimate();
}
static Count_Min_Sketch from_error_bounds(const double epsilon, const double delta)
Create a sketch with target error bounds.
HyperLogLog cardinality estimator.
Count-Min Sketch for frequency estimation in streams.
HyperLogLog for approximate cardinality estimation.
Testing
Ejecutar tests
# Build with tests (default)
cmake -S . -B build -DBUILD_TESTS=ON
cmake --build build
# Run all tests
ctest --test-dir build --output-on-failure
# Run specific test
./build/Tests/dynlist
./build/Tests/test_dijkstra
./build/Tests/latex_floyd_test
# Run exhaustive / performance-heavy example tests (marked with _test suffix)
# NOTE: ./build/Examples/sparse_table_test includes large performance benchmarks that
# can take a long time and use significant memory, especially on constrained machines.
# Consider running it only on suitable hardware if you need to evaluate its performance-related behavior.
#
./build/Examples/sparse_table_test
./build/Examples/disjoint_sparse_table_test
./build/Examples/min_cut_test
# Verbose output
ctest --test-dir build -V
Ejecutar con sanitizers
# AddressSanitizer + UndefinedBehaviorSanitizer
cmake -S . -B build-asan \
-DBUILD_TESTS=ON \
-DUSE_SANITIZERS=ON \
-DCMAKE_BUILD_TYPE=Debug
cmake --build build-asan
ctest --test-dir build-asan --output-on-failure
Cobertura de tests
- 7,700+ casos de test
- 99.98% tasa de aprobación
- Tests para todas las estructuras de datos y algoritmos
- Cobertura de casos borde
- Tests de regresión de rendimiento
- Algunos tests de larga duración/rendimiento se marcan intencionalmente como Disabled/Skipped y serán reportados por
ctest.
Contribuir
¡Las contribuciones son bienvenidas! Así es como puedes empezar:
Configuración de desarrollo
git clone https://github.com/lrleon/Aleph-w.git
cd Aleph-w
# Build with debug symbols
cmake -S . -B build-debug \
-DBUILD_TESTS=ON \
-DCMAKE_BUILD_TYPE=Debug \
-DUSE_SANITIZERS=ON
cmake --build build-debug
ctest --test-dir build-debug
Guías de estilo de código
- Indentación: 2 espacios
- Nombres:
snake_case para funciones, PascalCase para clases
- Documentación: comentarios Doxygen para todas las APIs públicas
- Testing: agregar tests para nuevas características
Proceso de Pull Request
- Fork del repositorio
- Crear rama de feature:
git checkout -b feature/amazing-feature
- Hacer cambios con tests
- Asegurar que CI pase:
ctest --output-on-failure
- Enviar Pull Request
Reportes de bugs
Si encuentras un bug, ¡por favor repórtalo!
Si es posible, por favor incluye un ejemplo mínimo reproducible.
Únete a la comunidad
Imagina una biblioteca que crece con tus necesidades. Aleph-w está construida por desarrolladores, para desarrolladores.
Tu contribución importa. Ya sea arreglar un typo, optimizar un algoritmo o agregar una estructura de datos completamente nueva, tienes el poder de dar forma al futuro de este proyecto.
- ¿Tienes una idea? Compártela en Discussions.
- ¿Encontraste una mejor forma? Envía un Pull Request.
- ¿Quieres aprender? Explora el código y haz preguntas.
Juntos, podemos construir la biblioteca de algoritmos en C++ más completa del mundo. ¡Únete!
Licencia
Aleph-w está licenciado bajo la Licencia MIT.
Copyright (C) 2002-2026 Leandro Rabindranath León
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Autores
- Leandro Rabindranath León - Creador y mantenedor - Universidad de Los Andes, Venezuela
- Alejandro Mujica - Colaborador
Agradecimientos
- Universidad de Los Andes (Mérida, Venezuela) - Lugar de nacimiento de Aleph-w
- Miles de estudiantes que aprendieron algoritmos con esta biblioteca
- Comunidad de código abierto por retroalimentación continua
- SYMYL RESEARCH por apoyar el desarrollo y avance de Aleph-w
Hecho con pasión por los algoritmos y las estructuras de datos