SyncMapRGCI is a research project towards self-organizing causal inference: a system that, without labels, discovers the hierarchical chunk structure hidden in a sequence and then infers the causal relations between those chunks. The long-term target is visual event sequences (research theme: Visual Causal Inference through Hierarchical Chunking via Self-Organizing Dynamics). It builds on SyncMap and SyncMapX from the Elrion project of the Laboratory of Intelligent Systems (LIS). This is my personal research and study vault, started in October 2025.
The project has two parts:
- RG, Recursive Grouping (implemented). Hierarchical chunking inside one geometric space. The same self-organizing kernel is applied again to the tokens produced by the level below, at a larger natural scale (x3.16 per level), so chunks and groups of chunks appear as nested clusters of one map.
- CI, Causal Inference (early experiments). Directed relations: directed transition statistics, edge recovery on synthetic DAGs, line-graph / edge-token representations.
Combining the two, causal relations between the chunks RG discovers, exists only as a rough prototype and is not part of this repository. All current experiments use synthetic graph-walk symbol sequences: a random walk over a .dot graph produces the input stream, and each model has to recover the graph's chunks (flat) or its nested chunk levels (hierarchy). On hierarchy graphs the walk is generated from the nodes' multi-level labels: it mostly stays inside a chunk, sometimes moves to a sibling chunk and rarely to another group. Labels are used only for scoring.
Left: the hidden structure that generates the walk. Right: RG's map after 100,000 steps in its own 3-D coordinates; the two groups are far apart, and zooming into each group shows its chunks as smaller clusters.
New here? The presentation (HTML slides with speaker notes; a single-file copy and a PDF are on the releases page) explains RG step by step, from the original SyncMap to the results. Without a SyncMap background, start with the beginner version. The documentation map lists everything else.
Main research lines:
NSGD(nsgd): first-order SyncMap dynamics. Exponentially weighted co-activity statistics define a thresholded k-nearest-neighbour relation graph; positions move by relation attraction and activity-dependent displacement, with per-point plasticity and bounded steps. It is the strongest baseline in the benchmark. File:syncmap/SyncMapX_NSGD.py.NS(runtimens, selected with--strategy ns; no preset): the hierarchy-capable first-order kernel that evolved from NSGD. It runs standalone and is the per-level engine of RG; its behaviour is no longer identical to NSGD. File:syncmap/SyncMapNS.py.RG(rg): recursive hierarchical extension built onSyncMapNS. Level 0 learns the raw symbols; each higher level receives tokens produced by unsupervised coarse-graining of the level below, with distance, update cadence and statistics memory growing geometrically across levels. Main forces: primitive contrastive force, transition-graph spring, local obstacle repulsion and bounded macro feedback. RG also keeps its own per-level partitions (cluster_level1is level 0 on the original symbols,cluster_levelNis level N-1 lifted back to them), shown in the viewer and snapshot JSON; they are not used for scoring. File:syncmap/SyncMapRG.py.CI(runtimeci, selected with--strategy ci; no preset): directed-transition baseline that runs independently from RG.syncmap/SyncMapCI.pyprovides directed transition statistics, edge-recovery evaluation, asymmetric node features and line-graph / edge-token representations;syncmap/SyncMapX_CI.pyclusters prototype embeddings built on them. It is a research scaffold, not a completed causal-inference method.
Comparison baselines:
SyncMap(syncmap): original SyncMap with a constant learning rate and its own DBSCAN readout. File:syncmap/SyncMap.py.Symmetric(symmetric): Symmetrical SyncMap with memory window, symmetric positive/negative sampling and its own moving-average readout. File:syncmap/SyncMapX_Symmetric.py.TSF(tsf): TSFMap-style centroid dynamics with its own post-hoc agglomerative hierarchy readout. File:syncmap/SyncMapTSF.py.
The models' own readouts are used by the viewer; every score in this repository comes from one shared readout of the coordinates (see Evaluation).
This work started in Prof. Danilo Vasconcellos Vargas's lab at Kyushu University, built on top of the lab's internal Elrion framework (unpublished). This repository contains only my own code and the synthetic datasets; the unpublished Elrion components are not included.
The comparison baselines come from published work:
- SyncMap: Vargas & Asabuki, "Continual General Chunking Problem and SyncMap", AAAI 2021.
syncmap/SyncMap.pyports the reference release at https://github.com/zweifel/SyncMap (MIT License, Copyright (c) 2021 zweifel), and the graph-walk and chunk environments undertest/derive from the same release. - Symmetrical SyncMap: Zhang & Vargas, "Symmetrical SyncMap for Imbalanced General Chunking Problems", arXiv:2310.10045.
- TSFMap: Vargas, Tham & Zhang, "Dynamical Equations with Bottom-up Self-Organizing Properties Learn Accurate Dynamical Hierarchies without any Loss Function", arXiv:2302.02140, 2023.
syncmap/SyncMapTSF.pyis an independent reimplementation of its dynamics.
Python 3.11. pygraphviz (used to read the .dot datasets) needs the Graphviz C library and headers first.
sudo apt install graphviz graphviz-dev
conda create -n syncmaprgci python=3.11
conda activate syncmaprgci
pip install -r requirements.txtWithout root access, conda install -c conda-forge pygraphviz installs Graphviz together with pygraphviz. PyQt5 and a display are only needed for the interactive viewer (task 1, and task 0 with --live). On a headless machine, set MPLBACKEND=Agg.
main.py runs every experiment task; the scripts in tools/ build the benchmark, the supplementary experiments and their reports on top of it. Run from the repository root. Dataset paths may omit datasets/.
Watch all five models learn the deep hierarchy side by side, with live ARI/NMI curves (needs Qt and a display):
python main.py --task 1 --strategy syncmap symmetric tsf nsgd rg --dataset hierarchy/IEH_fixed_chunk_deep_hierarchy.dot --steps 1000000 --record-interval 5000 --seed 0One RG run on DCH1 with the final map (PNG), the training trajectory (GIF) and its ARI curve, written to results/picture/, results/animations/ and results/snapshots/. Its result: line reads ... ari=0.8836 ... L1=0.7671 L2=1.0000:
python main.py --task 0 --strategy rg --dataset hierarchy/DCH1_fixed_chunk_6_3.dot --steps 100000 --seed 0 --save-png true --save-gif true --trace true --save-plot trueBatch comparison over the 39 flat graphs in datasets/ and the 10-graph hierarchy suite (--datasets flat hierarchy, 49 graphs), five seeds, CSV and Markdown report in results/experiment/<timestamp>/ (long-running):
python main.py --task 2 --datasets flat hierarchy --profiles syncmap symmetric tsf nsgd rg --comparison-sequence-lengths 5000 100000 --comparison-trials 5 --metric ari --seed 0Rebuild the benchmark shown below (8 graphs, 5 models, 5 seeds, with figures and GIFs):
python tools/benchmark.py run--set key=value overrides one model parameter for a run, and python main.py --list-profiles lists the presets. All tasks and flags are in docs/CLI_REFERENCE.md.
Shared input environment:
- Map dimension: 3.
- Input encoder: each node is held for 11 input steps (
TIME_DELAY = 10); the input vector holds the current node with decayexp(-0.1 t)plus a weaker trace of the previous node. On hierarchy graphs the walk jumps between chunks with probability 0.45, and between groups k levels further up with probability 0.45 × 0.25^k (details). - Learning rate (
adaptation_rate): NSGD and RG 0.05, TSF 0.001; SyncMap and Symmetric useclip(0.001 x number_of_symbols, 0.05, 0.1).--set adaptation_rate=...overrides any of them.
Profile parameters (tools/main_config.py, VARIANT_CONFIGS); the readout settings listed here are the models' own readouts, not the scoring readout:
nsgd:adaptation_rate=0.05,stats_memory_steps=100,plasticity_decay=0.99,plasticity_min=0.01,plasticity_recovery=1.0,knn=12,graph_theta=0.1,k_attr=1.0,k_pulse=2.0,k_repulse=0.0,max_step_norm=5.0,T_push=10, readout DBSCANeps=1.0,min_samples=3, re-clustered every 100 steps.rg: no overrides; usesSyncMapX_RG.DEFAULT_PARAMSinsyncmap/SyncMapRG.py. Key values:adaptation_rate=0.05,level_count=2(raised automatically to depth + 1 levels on hierarchy graphs, e.g. 3 on DCH1 and 5 on IEH; flat graphs disable the upper level),stats_mode=transition,stats_memory_steps=300withstats_memory_scale=10per level, distance scale x3.16 per level,warmup_steps=2000,k_attr=0.07,k_repulse=1.0,k_macro_repulse=0.1, readoutphysical_mst_gaps.syncmap: DBSCANeps=3.0,min_samples=2,space_size=10.symmetric:state_memory=3,stochastic_prob=0.3,moving_average_window=10000, DBSCANeps=4.5,min_samples=2.tsf:adaptation_rate=0.001,velocity_decay=0.999,mu_pos=6,mu_neg=3,mu_repulse=2, Ward agglomerative readout withtarget_levels=3and 2-16 clusters.- Sensitivity presets:
rg_shortmem,rg_shortmem_l0,tsf_longmem,tsf_velocity_longmem. These are controlled variants, not separate algorithms.
Task 2 defaults (MAIN_CONFIG): sequence lengths 5,000 and 100,000, 5 trials, metric ARI. Without --profiles, task 2 runs syncmap nsgd rg tsf as strategies with their class defaults, not the presets above; pass --profiles to use the presets.
Eight representative scenarios, all five models, 100,000 input steps, five seeds (0-4). Full report with per-level scores, latent maps, score curves and a GIF for every model on every graph: results/benchmark/REPORT.md.
| Scenario | Family | Nodes | Classes (fine to coarse) | What it tests |
|---|---|---|---|---|
fixed5_6 |
flat | 30 | 5 | reference case: equal fixed-order chunks |
UB_mixed_chunk_20_5_5 |
flat | 30 | 3 | chunks of very different sizes |
imbalanced_fixed_300 |
flat | 300 | 14 | large graph, imbalanced chunk sizes |
chain_mixed5_60 |
flat | 300 | 5 | long chain-like chunks, visited sparsely |
DCH1 |
hierarchy | 18 | 6 / 2 | two-level hierarchy |
IH |
hierarchy | 18 | 5 / 2 | unbalanced hierarchy |
EC |
hierarchy | 33 | 15 / 2 | many small chunks under two groups |
IEH |
hierarchy | 18 | 7 / 5 / 4 / 2 | four-level hierarchy |
ARI, mean ± std over five seeds (bold = best; hierarchy scores average all levels):
| Scenario | SyncMap | Symmetric | TSFMap | NSGD | RG |
|---|---|---|---|---|---|
| fixed5_6 | 0.516 ± 0.119 | 0.747 ± 0.141 | 0.788 ± 0.199 | 1.000 ± 0.000 | 0.957 ± 0.033 |
| UB_mixed_chunk_20_5_5 | 0.253 ± 0.170 | 0.594 ± 0.178 | 0.049 ± 0.148 | 0.357 ± 0.064 | 0.592 ± 0.296 |
| imbalanced_fixed_300 | 0.181 ± 0.041 | 0.367 ± 0.135 | 0.012 ± 0.006 | 0.202 ± 0.022 | 0.505 ± 0.090 |
| chain_mixed5_60 | 0.349 ± 0.121 | 0.320 ± 0.089 | 0.022 ± 0.012 | 0.340 ± 0.098 | 0.332 ± 0.079 |
| DCH1 | 0.632 ± 0.003 | 0.643 ± 0.018 | 0.691 ± 0.083 | 0.665 ± 0.033 | 0.795 ± 0.141 |
| IH | 0.221 ± 0.078 | -0.022 ± 0.050 | 0.346 ± 0.311 | 0.924 ± 0.000 | 0.920 ± 0.039 |
| EC | 0.542 ± 0.000 | 0.542 ± 0.000 | 0.281 ± 0.178 | 0.606 ± 0.084 | 0.700 ± 0.121 |
| IEH | 0.341 ± 0.143 | 0.220 ± 0.261 | 0.463 ± 0.082 | 0.654 ± 0.081 | 0.640 ± 0.129 |
Findings:
- Equal flat chunks (
fixed5_6): NSGD is perfect on every seed; RG is close. - Unequal and imbalanced chunks: RG is best on the 300-node imbalanced graph (0.505 against at most 0.367) and ties Symmetric on
UB_mixed_chunk_20_5_5, with a large spread between seeds. - Chains (
chain_mixed5_60): no model solves it. The SyncMap-family models stay around 0.32-0.35 and TSFMap fails, consistent with the known chain failure. - Hierarchies: on
DCH1andEC, SyncMap, Symmetric, NSGD and RG all recover the coarse groups (level-2 ARI 1.0). The difference is the fine level, where RG leads them (0.589 and 0.399 against at most 0.330 and 0.211). TSFMap shows the opposite pattern: best fine level (0.966, 0.498), weakest coarse level (0.416, 0.064). Overall RG is best on both. - Unbalanced hierarchy (
IH): NSGD and RG reach about 0.92; TSFMap varies between seeds and Symmetric fails. - Deep hierarchy (
IEH): NSGD and RG tie. RG leads on levels 1 and 3, SyncMap on level 2 and NSGD on the coarsest level. - Cost: RG takes 16-89 s per 100,000-step run against 4-9 s for NSGD (several runs in parallel).
- Single-seed score curves keep fluctuating late in training, which is why the table averages five seeds.
Final 3-D layouts on EC (seed 0, the models' own coordinates, coloured by true fine chunk). SyncMap, Symmetric, NSGD and RG put the chunks into two separated groups; TSFMap spreads its chunks evenly through the space, so the coarse level never appears:
Training on EC (seed 0; the camera turns slowly to show depth):
| SyncMap | Symmetric | TSFMap | NSGD | RG |
|---|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
Rerun everything (about 40 minutes with the default 3 workers; each batch process can take several GB on the 300-node graphs), or only rebuild figures and the report:
python tools/benchmark.py run
python tools/benchmark.py reportThe SyncMap and Symmetric baselines here use the constant learning rate of their papers.
Follow-ups designed after the benchmark, which could not say where NSGD or RG wins and whose hierarchies are too easy at the coarse level: 11 graphs (8 generated), the five models plus RG with recursion switched off, five paired seeds, 100,000 steps, scored as the mean of the last five checkpoints. Full report: results/supp/REPORT.md.
- Community orientation decides the flat winner. At a constant 300 states, RG beats NSGD on every seed from 3 communities of 100 to 15 of 20 (by 0.23-0.38 ARI); NSGD wins from 30 communities of 10 and is perfect on 60 of 5.
- Harder coarse levels separate the two. When the walk mixes the top-level groups more, NSGD collapses on the new hierarchies (0.06-0.10) while RG keeps 0.17-0.42. At easy mixing they tie on two graphs, RG leads on DCH1 and NSGD leads on the three-level graph.
- The recursion is what helps. RG without recursion is below full RG in all 12 hierarchy settings (by 0.05-0.31), more so the harder the mixing.
- The readout matters. With the true cluster count (oracle-K diagnostic), RG's maps match or beat NSGD's in 11 of 12 settings; the formal MST cut costs every model 0.07-0.40 ARI.
python tools/make_supp_datasets.py --stats
python tools/supp_run.py run --workers 3
python tools/supp_run.py showcase
python tools/supp_report.py- Every method is scored by the same unsupervised readout of its current coordinates; ground-truth labels are used only for scoring, never to pick a level.
- Flat graphs: DBSCAN on standardised coordinates (eps = 1.25 × the median k-distance,
min_samples=2); ARI / NMI of that partition. - Hierarchy graphs: cuts of the Euclidean minimum spanning tree at large neighbouring-edge gaps (ratio ≥ 1.05), one cut per required level. The formal ARI is the mean of
cluster_level1...cluster_levelNover the required depth, and a missing level scores zero. NMI stays a fixed-level diagnostic; cophenetic correlation and per-level scores give extra context. - Diagnostic only:
oracle_cluster_levelN_ari_scorecuts the same coordinates with Ward clustering at the true cluster count. A high oracle score with a low formal score means the map holds the structure and the readout misses it. - With
--seed, the input stream comes from an environment-private random stream, so every model sees the same sequence for a given seed.
main.py: command-line entry point and task dispatch.unified_experiments.py: model and environment construction, training loop, evaluation, batch comparison.live.py: interactive viewer backend (task 1).syncmap/: algorithm implementations.test/: runtime graph-walk and hierarchy environments, plus focused unit tests.tools/: profiles (main_config.py), readout and metrics, plotting, CSV summaries, the benchmark (benchmark.py), the supplementary experiments (make_supp_datasets.py,supp_run.py,supp_report.py) and the presentation diagrams (deck_figures.py).datasets/: synthetic.dotgraphs; hierarchical graphs indatasets/hierarchy/; graphs generated for the supplementary experiments indatasets/supp/.results/benchmark/: the benchmark report, comparison CSV, figures and GIFs.results/supp/: the supplementary report, comparison CSV and figures. Otherresults/folders are run outputs and are not tracked.docs/: documentation map, presentation, design reference, CLI reference, output locations, plan and limitations.
- Documentation map
- Presentation (HTML slides; single file and PDF on the releases page)
- Benchmark report and supplementary report
- Design and evaluation
- CLI reference
- Repository layout
- Output locations
- Open questions and known limitations
- Equal input steps do not mean equal compute or equal memory between methods.
- The benchmark covers eight synthetic graphs and the supplementary experiments eleven (eight of them generated for it); they show behaviour on representative and controlled cases, not general superiority.
- The hierarchy readout is a single-checkpoint MST gap cut. It can miss coarse groups that a map separates clearly; compare with the oracle-K columns before reading a low coarse-level score as a representation failure.
- RG's default level scheduler aliases the deep clocks, so levels above L1 receive little evidence within 100,000 steps (details).
- Hierarchy datasets are detected by path (
datasets/hierarchy/) or by.dotcontent (internal nodes or multi-level labels);--env-modeoverrides the detection. - CI is exploratory; a validated causal-inference system has not been established.









