ultragraph-1bit 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. ultragraph_1bit-0.1.0/.github/workflows/ci.yml +27 -0
  2. ultragraph_1bit-0.1.0/.github/workflows/publish.yml +25 -0
  3. ultragraph_1bit-0.1.0/.gitignore +8 -0
  4. ultragraph_1bit-0.1.0/CHANGELOG.md +37 -0
  5. ultragraph_1bit-0.1.0/CONTRIBUTING.md +44 -0
  6. ultragraph_1bit-0.1.0/LICENSE +21 -0
  7. ultragraph_1bit-0.1.0/PKG-INFO +135 -0
  8. ultragraph_1bit-0.1.0/README.md +123 -0
  9. ultragraph_1bit-0.1.0/assets/architecture.png +0 -0
  10. ultragraph_1bit-0.1.0/assets/fig_architecture.png +0 -0
  11. ultragraph_1bit-0.1.0/assets/fig_attention.png +0 -0
  12. ultragraph_1bit-0.1.0/assets/fig_ternary_weights.png +0 -0
  13. ultragraph_1bit-0.1.0/assets/make_figures.py +201 -0
  14. ultragraph_1bit-0.1.0/docs/references.md +34 -0
  15. ultragraph_1bit-0.1.0/docs/superpowers/specs/2026-07-10-ultragraph-design.md +169 -0
  16. ultragraph_1bit-0.1.0/examples/char_lm.py +55 -0
  17. ultragraph_1bit-0.1.0/examples/mini_gpt.py +82 -0
  18. ultragraph_1bit-0.1.0/examples/render_viz.py +54 -0
  19. ultragraph_1bit-0.1.0/examples/transformer_lm.py +68 -0
  20. ultragraph_1bit-0.1.0/justfile +29 -0
  21. ultragraph_1bit-0.1.0/pyproject.toml +34 -0
  22. ultragraph_1bit-0.1.0/tests/run_all.py +47 -0
  23. ultragraph_1bit-0.1.0/tests/test_advanced.py +136 -0
  24. ultragraph_1bit-0.1.0/tests/test_attention.py +74 -0
  25. ultragraph_1bit-0.1.0/tests/test_autograd.py +214 -0
  26. ultragraph_1bit-0.1.0/tests/test_core.py +109 -0
  27. ultragraph_1bit-0.1.0/tests/test_e2e.py +82 -0
  28. ultragraph_1bit-0.1.0/tests/test_io.py +70 -0
  29. ultragraph_1bit-0.1.0/tests/test_quant.py +36 -0
  30. ultragraph_1bit-0.1.0/tests/test_viz.py +57 -0
  31. ultragraph_1bit-0.1.0/ultragraph/__init__.py +35 -0
  32. ultragraph_1bit-0.1.0/ultragraph/autograd.py +282 -0
  33. ultragraph_1bit-0.1.0/ultragraph/core.py +316 -0
  34. ultragraph_1bit-0.1.0/ultragraph/io.py +88 -0
  35. ultragraph_1bit-0.1.0/ultragraph/nn.py +152 -0
  36. ultragraph_1bit-0.1.0/ultragraph/optim.py +113 -0
  37. ultragraph_1bit-0.1.0/ultragraph/quant.py +45 -0
  38. ultragraph_1bit-0.1.0/ultragraph/viz.py +491 -0
  39. ultragraph_1bit-0.1.0/uv.lock +689 -0
@@ -0,0 +1,27 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ python-version: ["3.11", "3.12", "3.13"]
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ - name: Install uv
19
+ uses: astral-sh/setup-uv@v5
20
+ with:
21
+ enable-cache: true
22
+ - name: Sync environment (incl. viz extra for matplotlib tests)
23
+ run: uv sync --extra viz --python ${{ matrix.python-version }}
24
+ - name: Lint (ruff)
25
+ run: uv run ruff check ultragraph tests examples assets
26
+ - name: Test (pytest)
27
+ run: uv run pytest
@@ -0,0 +1,25 @@
1
+ name: Publish to PyPI
2
+
3
+ # Publishes `ultragraph-1bit` via PyPI Trusted Publishing (OIDC) — no API token
4
+ # stored in the repo. Fires when a GitHub Release is published, or manually.
5
+ # One-time setup on PyPI: add a "pending" trusted publisher for project
6
+ # `ultragraph-1bit`, owner `peterlodri-sec`, repo `ultra-graph`, workflow
7
+ # `publish.yml` (no environment).
8
+
9
+ on:
10
+ release:
11
+ types: [published]
12
+ workflow_dispatch:
13
+
14
+ jobs:
15
+ publish:
16
+ runs-on: ubuntu-latest
17
+ permissions:
18
+ id-token: write # required for trusted publishing
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - uses: astral-sh/setup-uv@v5
22
+ - name: Build sdist + wheel
23
+ run: uv build
24
+ - name: Publish to PyPI (trusted publishing)
25
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,8 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .pytest_cache/
4
+ *.ug
5
+ *.svg
6
+ .venv/
7
+ out/
8
+ dist/
@@ -0,0 +1,37 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project. Format follows
4
+ [Keep a Changelog](https://keepachangelog.com/); this project uses
5
+ [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [0.1.0] — 2026-07-11
8
+
9
+ The byte-graph that is a 1-bit (ternary) LLM.
10
+
11
+ ### Added
12
+ - **Core** (`core.py`) — `Node`/`Edge`/`Tree`/`UltraEdge`/`UltraGraph`, the byte
13
+ buffers, the ad-hoc side store, and the dunder API (`node >> node` micro-edge,
14
+ `tree >> tree` ultra-edge, `len`/`iter`/`in`, `_repr_svg_`).
15
+ - **Quantization** (`quant.py`) — ternary weights (absmean) + int8 activations
16
+ (absmax), with the small-`eps` / finite guards.
17
+ - **Autograd** (`autograd.py`) — n-D reverse-mode tape: `+ - * / @`, `transpose`,
18
+ `swapaxes`, `reshape`, `relu`, `sqrt`, `sum`, `mean(axis)`, `softmax`,
19
+ `cross_entropy`; and `ternary_linear` with a straight-through estimator and
20
+ per-token int8 activation quantization.
21
+ - **nn** (`nn.py`) — `linear_tree`, `mlp`, single-head `Attention`, batched
22
+ `MultiHeadAttention` (causal), `RMSNorm`, `LayerNorm`.
23
+ - **Optimizers** (`optim.py`) — `SGD` and `Adam`, both with global-norm gradient
24
+ clipping; re-quantize the ternary buffers after each step.
25
+ - **Visualization** (`viz.py`) — pure-SVG micro/macro/byte-heatmap views plus an
26
+ optional matplotlib backend (`[viz]` extra).
27
+ - **I/O** (`io.py`) — byte-exact save/load.
28
+ - **Examples** — `char_lm.py`, `transformer_lm.py`, `mini_gpt.py` (batched
29
+ multi-head transformer that memorizes a toy corpus), `render_viz.py`,
30
+ `make_figures.py`.
31
+ - **Tests** — numeric-gradient checks for every op, an attention causality proof,
32
+ save/load byte-exactness, and end-to-end training; a dependency-free runner.
33
+ - **Tooling & docs** — `ruff` (config in `pyproject.toml`), GitHub Actions CI
34
+ (`ruff` + `pytest` on Python 3.11–3.13), `CONTRIBUTING.md`, `CHANGELOG.md`, and
35
+ `docs/references.md` (an Erdős graph-theory reading list).
36
+
37
+ [0.1.0]: https://github.com/peterlodri-sec/ultra-graph/releases/tag/v0.1.0
@@ -0,0 +1,44 @@
1
+ # Contributing to ultragraph
2
+
3
+ Thanks for poking at a byte-graph. It's a small, pure-Python (+ numpy) library, so
4
+ the loop is short.
5
+
6
+ ## Setup
7
+
8
+ Uses [uv](https://github.com/astral-sh/uv) and Python ≥ 3.11.
9
+
10
+ ```sh
11
+ uv sync --extra viz # core + dev (pytest, ruff) + matplotlib for viz tests
12
+ ```
13
+
14
+ ## The loop
15
+
16
+ ```sh
17
+ just test # pytest (or: uv run pytest)
18
+ just test-fast # dependency-free runner (stdlib + numpy only)
19
+ uv run ruff check ultragraph tests examples assets # lint
20
+ just demo # end-to-end ternary mini-GPT
21
+ just viz # render example graphs
22
+ ```
23
+
24
+ CI (`.github/workflows/ci.yml`) runs `ruff check` + `pytest` on Python 3.11–3.13.
25
+ Both must be green before merge.
26
+
27
+ ## Conventions
28
+
29
+ - **Correctness first.** New autograd ops need a numeric-gradient test
30
+ (`tests/test_autograd.py` has the pattern: analytic backward vs central finite
31
+ differences). Quantized paths are checked against their unquantized surrogate
32
+ (that's what STE claims).
33
+ - **The byte contract holds.** One node = one byte (`int8` activation), one edge =
34
+ one byte (ternary weight). Anything bigger than a byte lives in the ad-hoc side
35
+ store, not the hot buffers.
36
+ - **Keep files focused.** Match the surrounding style: `ruff` config in
37
+ `pyproject.toml` (`select = F, E7, E9, I`); imports sorted.
38
+ - **numpy is the only runtime dependency.** `matplotlib` is optional (`[viz]`
39
+ extra); the SVG backend stays stdlib-only.
40
+
41
+ ## Pull requests
42
+
43
+ Small, focused PRs. Include tests. Run `ruff check` + `pytest` locally first. Say
44
+ what you changed and why in the description.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Peter Lodri
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,135 @@
1
+ Metadata-Version: 2.4
2
+ Name: ultragraph-1bit
3
+ Version: 0.1.0
4
+ Summary: A pure-Python (+numpy) byte-graph that is a 1-bit (ternary) LLM: dunder API, autograd, ultra-edges, visualization.
5
+ License: MIT
6
+ License-File: LICENSE
7
+ Requires-Python: >=3.11
8
+ Requires-Dist: numpy>=2.0
9
+ Provides-Extra: viz
10
+ Requires-Dist: matplotlib>=3.8; extra == 'viz'
11
+ Description-Content-Type: text/markdown
12
+
13
+ # ultragraph
14
+
15
+ [![CI](https://github.com/peterlodri-sec/ultra-graph/actions/workflows/ci.yml/badge.svg)](https://github.com/peterlodri-sec/ultra-graph/actions/workflows/ci.yml)
16
+ [![python](https://img.shields.io/badge/python-3.11%2B-00d4ff)](pyproject.toml)
17
+ [![license](https://img.shields.io/badge/license-MIT-b48bff)](LICENSE)
18
+
19
+ A pure-Python (+ numpy) **byte-graph that is a 1-bit (ternary) LLM**.
20
+
21
+ > **genesis** `251e6ea` · themed after [pocoo.vaked.dev](https://pocoo.vaked.dev)
22
+
23
+ ![ultragraph architecture — micro (node/edge, 1 byte each) → meso (tree) → macro (ultra-graph)](assets/architecture.png)
24
+
25
+ Three levels:
26
+
27
+ | level | unit | storage |
28
+ |-------|------|---------|
29
+ | micro | **node** / **edge** | **1 byte each** — `int8` activation / ternary weight `{-1,0,+1}` |
30
+ | meso | **tree** | a whole graph == one net/module (a Linear/MLP block) |
31
+ | macro | **ultra-edge** (`===`) | typed wiring between trees → the **ultra-graph** = the model |
32
+
33
+ Weights are ternary (BitNet b1.58 style); activations are int8. Full-precision
34
+ "master" weights live in an ad-hoc side store during training; the byte buffers are
35
+ the deployed state. Training uses a straight-through estimator (STE).
36
+
37
+ ## Illustrations
38
+
39
+ Real outputs from a trained ternary mini-GPT — regenerate with `uv run python assets/make_figures.py`:
40
+
41
+ | ultra-graph | causal attention | ternary weight bytes |
42
+ |:---:|:---:|:---:|
43
+ | ![architecture](assets/fig_architecture.png) | ![attention](assets/fig_attention.png) | ![weights](assets/fig_ternary_weights.png) |
44
+
45
+ Left: the model as an **ultra-graph** — trees wired by ultra-edges (`===`), with residual skips.
46
+ Middle: **real** causal self-attention weights (lower-triangular → no peeking at the future).
47
+ Right: a trained query projection's weight bytes, each ∈ {−1, 0, +1}.
48
+
49
+ ## Install
50
+
51
+ ```sh
52
+ pip install ultragraph-1bit # then: import ultragraph
53
+ # or from source (Python >=3.11):
54
+ uv sync
55
+ ```
56
+
57
+ ## Dunder API
58
+
59
+ `>>` is overloaded by operand type:
60
+
61
+ ```python
62
+ import numpy as np
63
+ from ultragraph import Tree, UltraGraph, Tensor, mlp, SGD
64
+
65
+ # micro-edges inside a sparse tree
66
+ g = Tree(4, "g")
67
+ g[0] >> g[1] # node >> node -> micro-edge
68
+ g[2] = 7 # set a node byte
69
+ print(len(g), 2 in g, list(g))
70
+
71
+ # ultra-edges between trees
72
+ ug = UltraGraph()
73
+ a = ug.add(Tree.dense(8, 16, "a"))
74
+ b = ug.add(Tree.dense(16, 4, "b", act="none"))
75
+ a >> b # tree >> tree -> ultra-edge (plain)
76
+ a.wire(b, "residual")
77
+ ```
78
+
79
+ ## Train a tiny ternary net
80
+
81
+ ```python
82
+ ug = mlp([4, 16, 2]) # dense ternary linear trees wired plain
83
+ opt = SGD(ug, lr=0.3, momentum=0.9)
84
+ x = Tensor(np.random.randn(32, 4).astype("float32"))
85
+ for _ in range(300):
86
+ loss = ug.forward(x).cross_entropy(y)
87
+ opt.zero_grad(); loss.backward(); opt.step() # step() re-quantizes weights
88
+ ```
89
+
90
+ See `examples/char_lm.py` (MLP LM), `examples/transformer_lm.py` (single-head attention),
91
+ and `examples/mini_gpt.py` (batched **multi-head** attention + **RMSNorm** + **Adam**) for
92
+ end-to-end char-level ternary language models.
93
+
94
+ ```python
95
+ from ultragraph import Embedding, MultiHeadAttention, RMSNorm, linear_tree, Adam
96
+ # pre-norm transformer block over a [B, T, d_model] sequence:
97
+ # x = x + mha(norm1(x)); x = x + ff2(ff1(norm2(x)))
98
+ ```
99
+
100
+ ## Tasks
101
+
102
+ ```sh
103
+ just test # pytest
104
+ just test-fast # dependency-free runner (stdlib + numpy)
105
+ just demo # char-LM end-to-end
106
+ just viz # render example SVGs
107
+ ```
108
+
109
+ ## Layout
110
+
111
+ ```
112
+ ultragraph/quant.py ternary + int8 quantization, STE
113
+ ultragraph/autograd.py numpy autograd tape; ternary_linear (STE)
114
+ ultragraph/core.py Node/Edge/Tree/UltraEdge/UltraGraph + dunder API
115
+ ultragraph/nn.py linear_tree, mlp, Attention, MultiHeadAttention, RMSNorm, LayerNorm
116
+ ultragraph/optim.py SGD + Adam over fp32 masters (grad clip), re-quantize after step
117
+ ultragraph/viz.py pure-SVG + optional matplotlib (micro / macro / byte-heatmap)
118
+ ultragraph/io.py byte-exact save / load
119
+ ```
120
+
121
+ Design spec: `docs/superpowers/specs/2026-07-10-ultragraph-design.md`.
122
+ Graph-theory reading list (Erdős classics): [`docs/references.md`](docs/references.md).
123
+
124
+ ## Install from source
125
+
126
+ ```sh
127
+ git clone https://github.com/peterlodri-sec/ultra-graph
128
+ cd ultra-graph
129
+ uv sync
130
+ just test
131
+ ```
132
+
133
+ ## License
134
+
135
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,123 @@
1
+ # ultragraph
2
+
3
+ [![CI](https://github.com/peterlodri-sec/ultra-graph/actions/workflows/ci.yml/badge.svg)](https://github.com/peterlodri-sec/ultra-graph/actions/workflows/ci.yml)
4
+ [![python](https://img.shields.io/badge/python-3.11%2B-00d4ff)](pyproject.toml)
5
+ [![license](https://img.shields.io/badge/license-MIT-b48bff)](LICENSE)
6
+
7
+ A pure-Python (+ numpy) **byte-graph that is a 1-bit (ternary) LLM**.
8
+
9
+ > **genesis** `251e6ea` · themed after [pocoo.vaked.dev](https://pocoo.vaked.dev)
10
+
11
+ ![ultragraph architecture — micro (node/edge, 1 byte each) → meso (tree) → macro (ultra-graph)](assets/architecture.png)
12
+
13
+ Three levels:
14
+
15
+ | level | unit | storage |
16
+ |-------|------|---------|
17
+ | micro | **node** / **edge** | **1 byte each** — `int8` activation / ternary weight `{-1,0,+1}` |
18
+ | meso | **tree** | a whole graph == one net/module (a Linear/MLP block) |
19
+ | macro | **ultra-edge** (`===`) | typed wiring between trees → the **ultra-graph** = the model |
20
+
21
+ Weights are ternary (BitNet b1.58 style); activations are int8. Full-precision
22
+ "master" weights live in an ad-hoc side store during training; the byte buffers are
23
+ the deployed state. Training uses a straight-through estimator (STE).
24
+
25
+ ## Illustrations
26
+
27
+ Real outputs from a trained ternary mini-GPT — regenerate with `uv run python assets/make_figures.py`:
28
+
29
+ | ultra-graph | causal attention | ternary weight bytes |
30
+ |:---:|:---:|:---:|
31
+ | ![architecture](assets/fig_architecture.png) | ![attention](assets/fig_attention.png) | ![weights](assets/fig_ternary_weights.png) |
32
+
33
+ Left: the model as an **ultra-graph** — trees wired by ultra-edges (`===`), with residual skips.
34
+ Middle: **real** causal self-attention weights (lower-triangular → no peeking at the future).
35
+ Right: a trained query projection's weight bytes, each ∈ {−1, 0, +1}.
36
+
37
+ ## Install
38
+
39
+ ```sh
40
+ pip install ultragraph-1bit # then: import ultragraph
41
+ # or from source (Python >=3.11):
42
+ uv sync
43
+ ```
44
+
45
+ ## Dunder API
46
+
47
+ `>>` is overloaded by operand type:
48
+
49
+ ```python
50
+ import numpy as np
51
+ from ultragraph import Tree, UltraGraph, Tensor, mlp, SGD
52
+
53
+ # micro-edges inside a sparse tree
54
+ g = Tree(4, "g")
55
+ g[0] >> g[1] # node >> node -> micro-edge
56
+ g[2] = 7 # set a node byte
57
+ print(len(g), 2 in g, list(g))
58
+
59
+ # ultra-edges between trees
60
+ ug = UltraGraph()
61
+ a = ug.add(Tree.dense(8, 16, "a"))
62
+ b = ug.add(Tree.dense(16, 4, "b", act="none"))
63
+ a >> b # tree >> tree -> ultra-edge (plain)
64
+ a.wire(b, "residual")
65
+ ```
66
+
67
+ ## Train a tiny ternary net
68
+
69
+ ```python
70
+ ug = mlp([4, 16, 2]) # dense ternary linear trees wired plain
71
+ opt = SGD(ug, lr=0.3, momentum=0.9)
72
+ x = Tensor(np.random.randn(32, 4).astype("float32"))
73
+ for _ in range(300):
74
+ loss = ug.forward(x).cross_entropy(y)
75
+ opt.zero_grad(); loss.backward(); opt.step() # step() re-quantizes weights
76
+ ```
77
+
78
+ See `examples/char_lm.py` (MLP LM), `examples/transformer_lm.py` (single-head attention),
79
+ and `examples/mini_gpt.py` (batched **multi-head** attention + **RMSNorm** + **Adam**) for
80
+ end-to-end char-level ternary language models.
81
+
82
+ ```python
83
+ from ultragraph import Embedding, MultiHeadAttention, RMSNorm, linear_tree, Adam
84
+ # pre-norm transformer block over a [B, T, d_model] sequence:
85
+ # x = x + mha(norm1(x)); x = x + ff2(ff1(norm2(x)))
86
+ ```
87
+
88
+ ## Tasks
89
+
90
+ ```sh
91
+ just test # pytest
92
+ just test-fast # dependency-free runner (stdlib + numpy)
93
+ just demo # char-LM end-to-end
94
+ just viz # render example SVGs
95
+ ```
96
+
97
+ ## Layout
98
+
99
+ ```
100
+ ultragraph/quant.py ternary + int8 quantization, STE
101
+ ultragraph/autograd.py numpy autograd tape; ternary_linear (STE)
102
+ ultragraph/core.py Node/Edge/Tree/UltraEdge/UltraGraph + dunder API
103
+ ultragraph/nn.py linear_tree, mlp, Attention, MultiHeadAttention, RMSNorm, LayerNorm
104
+ ultragraph/optim.py SGD + Adam over fp32 masters (grad clip), re-quantize after step
105
+ ultragraph/viz.py pure-SVG + optional matplotlib (micro / macro / byte-heatmap)
106
+ ultragraph/io.py byte-exact save / load
107
+ ```
108
+
109
+ Design spec: `docs/superpowers/specs/2026-07-10-ultragraph-design.md`.
110
+ Graph-theory reading list (Erdős classics): [`docs/references.md`](docs/references.md).
111
+
112
+ ## Install from source
113
+
114
+ ```sh
115
+ git clone https://github.com/peterlodri-sec/ultra-graph
116
+ cd ultra-graph
117
+ uv sync
118
+ just test
119
+ ```
120
+
121
+ ## License
122
+
123
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,201 @@
1
+ """Generate themed illustrations for the README from a REAL trained model.
2
+
3
+ Palette matches pocoo.vaked.dev: deep navy background with cyan / green / purple
4
+ accents. Figures are produced from an actual mini-GPT forward pass (ternary
5
+ weights, causal attention matrix) plus an architecture diagram.
6
+
7
+ Run: uv run python assets/make_figures.py
8
+ """
9
+ from __future__ import annotations
10
+
11
+ import math
12
+ import os
13
+
14
+ import matplotlib
15
+ import numpy as np
16
+
17
+ matplotlib.use("Agg")
18
+ import matplotlib.pyplot as plt
19
+ from matplotlib.colors import LinearSegmentedColormap
20
+ from matplotlib.patches import FancyArrowPatch, FancyBboxPatch
21
+
22
+ from ultragraph import Adam, Embedding, MultiHeadAttention, RMSNorm, Tensor, UltraGraph, linear_tree
23
+
24
+ BG = "#070b16"
25
+ PANEL = "#0b1120"
26
+ CYAN = "#00d4ff"
27
+ GREEN = "#00e660"
28
+ PURPLE = "#b48bff"
29
+ FG = "#c8d3e6"
30
+ MUTED = "#4a5a80"
31
+
32
+ OUT = os.path.join(os.path.dirname(__file__))
33
+
34
+ # purple -> navy -> cyan, for ternary weights in {-1, 0, +1}
35
+ TERNARY_CMAP = LinearSegmentedColormap.from_list("ug_ternary", [PURPLE, "#0e1730", CYAN])
36
+ # navy -> cyan, sequential, for attention weights in [0, 1]
37
+ ATTN_CMAP = LinearSegmentedColormap.from_list("ug_attn", ["#0a1024", "#0f5c78", CYAN])
38
+
39
+
40
+ def _style(ax):
41
+ ax.set_facecolor(BG)
42
+ for s in ax.spines.values():
43
+ s.set_color(MUTED)
44
+ ax.tick_params(colors=FG, labelsize=8)
45
+ ax.xaxis.label.set_color(FG)
46
+ ax.yaxis.label.set_color(FG)
47
+ ax.title.set_color(FG)
48
+
49
+
50
+ def _save(fig, name):
51
+ path = os.path.join(OUT, name)
52
+ fig.savefig(path, dpi=150, bbox_inches="tight", facecolor=BG)
53
+ plt.close(fig)
54
+ print("wrote", path)
55
+ return path
56
+
57
+
58
+ def train_model():
59
+ np.random.seed(0)
60
+ text = "hello ultra graph world " * 4
61
+ chars = sorted(set(text))
62
+ stoi = {c: i for i, c in enumerate(chars)}
63
+ vocab = len(chars)
64
+ d_model, n_heads, T = 24, 4, 8
65
+ ids = np.array([stoi[c] for c in text], dtype=np.int64)
66
+ seqs = np.stack([ids[i : i + T + 1] for i in range(len(ids) - T)])
67
+ inputs, targets = seqs[:, :-1], seqs[:, 1:]
68
+ B = inputs.shape[0]
69
+
70
+ emb = Embedding(vocab, d_model, "emb")
71
+ n1 = RMSNorm(d_model, name="n1")
72
+ mha = MultiHeadAttention(d_model, n_heads, causal=True)
73
+ n2 = RMSNorm(d_model, name="n2")
74
+ ff1 = linear_tree(d_model, 4 * d_model, "ff1", act="relu")
75
+ ff2 = linear_tree(4 * d_model, d_model, "ff2", act="none")
76
+ unembed = linear_tree(d_model, vocab, "unembed", act="none")
77
+ model = UltraGraph("mini_gpt")
78
+ for m in (emb, n1, mha, n2):
79
+ model.register(m)
80
+ for t in (ff1, ff2, unembed):
81
+ model.add(t)
82
+ opt = Adam(model, lr=0.02, clip=1.0)
83
+
84
+ def forward(idx):
85
+ x = emb(idx.reshape(-1)).reshape(B, idx.shape[1], d_model)
86
+ x = x + mha(n1(x))
87
+ x = x + ff2.forward(ff1.forward(n2(x)))
88
+ return unembed.forward(x)
89
+
90
+ for _ in range(300):
91
+ loss = forward(inputs).cross_entropy(targets)
92
+ opt.zero_grad()
93
+ loss.backward()
94
+ opt.step()
95
+ return dict(mha=mha, n1=n1, emb=emb, inputs=inputs, T=T, d_model=d_model, n_heads=n_heads, B=B)
96
+
97
+
98
+ def fig_ternary_weights(m):
99
+ """Real ternary weight matrix from the trained attention query projection."""
100
+ wq = m["mha"].wq.wq # int8 {-1,0,1}, shape [d_model, d_model]
101
+ fig, ax = plt.subplots(figsize=(4.6, 4.2))
102
+ fig.patch.set_facecolor(BG)
103
+ im = ax.imshow(wq, cmap=TERNARY_CMAP, vmin=-1, vmax=1, interpolation="nearest")
104
+ _style(ax)
105
+ ax.set_title("ternary weight bytes · W_q ∈ {-1, 0, +1}", fontsize=10)
106
+ ax.set_xlabel("in")
107
+ ax.set_ylabel("out")
108
+ cb = fig.colorbar(im, ax=ax, fraction=0.046, pad=0.04, ticks=[-1, 0, 1])
109
+ cb.ax.yaxis.set_tick_params(color=FG)
110
+ plt.setp(plt.getp(cb.ax.axes, "yticklabels"), color=FG)
111
+ return _save(fig, "fig_ternary_weights.png")
112
+
113
+
114
+ def fig_attention(m):
115
+ """Real causal attention weights (head 0) from a forward pass."""
116
+ mha, n1, emb = m["mha"], m["n1"], m["emb"]
117
+ T, d, H = m["T"], m["d_model"], m["n_heads"]
118
+ dh = d // H
119
+ x = emb(m["inputs"][0]).reshape(1, T, d)
120
+ xn = n1(x)
121
+ q = mha.wq.forward(xn).reshape(1, T, H, dh).swapaxes(1, 2)
122
+ k = mha.wk.forward(xn).reshape(1, T, H, dh).swapaxes(1, 2)
123
+ scores = (q @ k.swapaxes(-1, -2)) * (1.0 / math.sqrt(dh))
124
+ mask = np.triu(np.full((T, T), -1e9, dtype=np.float32), k=1)
125
+ attn = (scores + Tensor(mask)).softmax(axis=-1).data[0, 0] # [T, T]
126
+
127
+ fig, ax = plt.subplots(figsize=(4.6, 4.2))
128
+ fig.patch.set_facecolor(BG)
129
+ im = ax.imshow(attn, cmap=ATTN_CMAP, vmin=0, vmax=1, interpolation="nearest")
130
+ _style(ax)
131
+ ax.set_title("causal self-attention · softmax(QKᵀ/√d)", fontsize=10)
132
+ ax.set_xlabel("key position")
133
+ ax.set_ylabel("query position")
134
+ cb = fig.colorbar(im, ax=ax, fraction=0.046, pad=0.04)
135
+ cb.ax.yaxis.set_tick_params(color=FG)
136
+ plt.setp(plt.getp(cb.ax.axes, "yticklabels"), color=FG)
137
+ return _save(fig, "fig_attention.png")
138
+
139
+
140
+ def fig_architecture():
141
+ """Ultra-graph view of the mini-GPT block: trees wired by ultra-edges."""
142
+ fig, ax = plt.subplots(figsize=(5.2, 6.4))
143
+ fig.patch.set_facecolor(BG)
144
+ ax.set_facecolor(BG)
145
+ ax.set_xlim(0, 10)
146
+ ax.set_ylim(0, 13)
147
+ ax.axis("off")
148
+
149
+ def box(y, label, color, sub=""):
150
+ b = FancyBboxPatch((2.6, y), 4.8, 1.0, boxstyle="round,pad=0.08,rounding_size=0.18",
151
+ linewidth=1.6, edgecolor=color, facecolor=PANEL)
152
+ ax.add_patch(b)
153
+ ax.text(5.0, y + 0.62, label, ha="center", va="center", color=FG, fontsize=10, fontweight="bold")
154
+ if sub:
155
+ ax.text(5.0, y + 0.28, sub, ha="center", va="center", color=MUTED, fontsize=7.5)
156
+ return y
157
+
158
+ layers = [
159
+ (11.4, "Embedding", GREEN, "vocab → d_model"),
160
+ (9.6, "RMSNorm", PURPLE, ""),
161
+ (8.2, "MultiHeadAttention", CYAN, "ternary Q·K·V·O, causal"),
162
+ (6.4, "RMSNorm", PURPLE, ""),
163
+ (5.0, "MLP (ternary)", CYAN, "ff1 relu · ff2"),
164
+ (3.0, "Unembed", GREEN, "d_model → vocab"),
165
+ ]
166
+ for y, lab, col, sub in layers:
167
+ box(y, lab, col, sub)
168
+
169
+ def arrow(y0, y1, color=FG, curve=0.0, lw=1.4):
170
+ a = FancyArrowPatch((5.0, y0), (5.0, y1), connectionstyle=f"arc3,rad={curve}",
171
+ arrowstyle="-|>", mutation_scale=12, color=color, lw=lw)
172
+ ax.add_patch(a)
173
+
174
+ arrow(11.4, 10.6) # emb -> norm
175
+ arrow(9.6, 9.2) # norm -> attn
176
+ arrow(8.2, 7.4) # attn -> norm2
177
+ arrow(6.4, 6.0) # norm2 -> mlp
178
+ arrow(5.0, 4.0) # mlp -> unembed
179
+ # residual ultra-edges (curved, on the right)
180
+ for y0, y1, c in [(11.4, 8.2, CYAN), (8.2, 5.0, CYAN)]:
181
+ a = FancyArrowPatch((7.4, y0 + 0.5), (7.4, y1 + 0.5), connectionstyle="arc3,rad=-0.5",
182
+ arrowstyle="-|>", mutation_scale=11, color=c, lw=1.2, linestyle=(0, (4, 2)))
183
+ ax.add_patch(a)
184
+ ax.text(9.0, (y0 + y1) / 2 + 0.5, "===", ha="center", va="center", color=c, fontsize=9, rotation=90)
185
+
186
+ ax.text(5.0, 12.5, "ultra-graph · trees wired by ultra-edges (===)", ha="center",
187
+ color=FG, fontsize=11, fontweight="bold")
188
+ ax.text(5.0, 2.2, "every weight = 1 ternary byte · every activation = 1 int8 byte",
189
+ ha="center", color=MUTED, fontsize=8)
190
+ return _save(fig, "fig_architecture.png")
191
+
192
+
193
+ def main():
194
+ m = train_model()
195
+ fig_ternary_weights(m)
196
+ fig_attention(m)
197
+ fig_architecture()
198
+
199
+
200
+ if __name__ == "__main__":
201
+ main()
@@ -0,0 +1,34 @@
1
+ # References — a graph theory reading list
2
+
3
+ `ultragraph` is a byte-graph, so it owes a debt to graph theory. This is a short,
4
+ opinionated reading list of Paul Erdős's most important graph-theory (and
5
+ graph-theorist-adjacent combinatorics) publications — the classics every graph
6
+ person eventually meets.
7
+
8
+ Citation details were checked against the Wikipedia articles for the named
9
+ theorems, the journals (Oxford Academic / Cambridge Core / Springer / AMS), and
10
+ the Rényi Institute's Erdős archive. A few conjecture citations are flagged where
11
+ a canonical volume/page could not be confirmed.
12
+
13
+ ### Foundational papers
14
+
15
+ - **Erdős, P. & Szekeres, G. (1935).** "A combinatorial problem in geometry." *Compositio Mathematica*, 2, 463–470. [numdam](http://www.numdam.org/item/CM_1935__2__463_0/) — The Erdős–Szekeres theorem: any sequence longer than $(r-1)(s-1)$ has a monotone subsequence of length $r$ or $s$. A founding result of Ramsey theory (the "happy ending problem").
16
+ - **Erdős, P. & Stone, A. H. (1946).** "On the structure of linear graphs." *Bulletin of the AMS*, 52(12), 1087–1091. [doi:10.1090/S0002-9904-1946-08715-7](https://doi.org/10.1090/S0002-9904-1946-08715-7) — The Erdős–Stone theorem fixes the asymptotic maximum edge count of graphs forbidding a fixed subgraph — the "fundamental theorem of extremal graph theory," generalizing Turán.
17
+ - **Erdős, P. (1947).** "Some remarks on the theory of graphs." *Bulletin of the AMS*, 53(4), 292–294. [doi:10.1090/S0002-9904-1947-08785-1](https://doi.org/10.1090/S0002-9904-1947-08785-1) — The probabilistic lower bound $R(k,k) > 2^{k/2}$ for Ramsey numbers; launched the probabilistic method.
18
+ - **Erdős, P. & Rényi, A. (1959).** "On random graphs. I." *Publicationes Mathematicae Debrecen*, 6, 290–297. [doi:10.5486/PMD.1959.6.3-4.12](https://doi.org/10.5486/PMD.1959.6.3-4.12) — Introduced the $G(n,m)$ random-graph model; founded the theory of random graphs.
19
+ - **Erdős, P. & Rényi, A. (1960).** "On the evolution of random graphs." *Publ. Math. Inst. Hungar. Acad. Sci.*, 5, 17–61. [PDF](https://www.renyi.hu/~p_erdos/1960-10.pdf) (no DOI) — The phase-transition / giant-component paper; foundational for modern network science.
20
+ - **Erdős, P. & Gallai, T. (1960).** "Gráfok előírt fokszámú pontokkal" [Graphs with vertices of prescribed degrees]. *Matematikai Lapok*, 11, 264–274. [PDF](https://www.renyi.hu/~p_erdos/1961-05.pdf) (no DOI) — The Erdős–Gallai theorem: the inequalities that decide when an integer sequence is *graphic* (a degree sequence of a simple graph).
21
+ - **Erdős, P. (1959).** "Graph theory and probability." *Canadian Journal of Mathematics*, 11, 34–38. [doi:10.4153/CJM-1959-003-9](https://doi.org/10.4153/CJM-1959-003-9) — Graphs with simultaneously arbitrarily high girth *and* high chromatic number exist — a celebrated nonconstructive result.
22
+ - **Erdős, P., Ko, C. & Rado, R. (1961).** "Intersection theorems for systems of finite sets." *Quarterly J. of Mathematics* (Oxford, 2nd Ser.), 12, 313–320. [doi:10.1093/qmath/12.1.313](https://doi.org/10.1093/qmath/12.1.313) — The Erdős–Ko–Rado theorem bounds the largest intersecting family of $k$-subsets; a cornerstone of extremal set theory.
23
+ - **Erdős, P., Rényi, A. & Sós, V. T. (1966).** "On a problem of graph theory." *Studia Sci. Math. Hungar.*, 1, 215–235. [PDF](https://www.renyi.hu/~p_erdos/1966-06.pdf) (no DOI) — The friendship theorem: if every two vertices share exactly one common neighbour, the graph is a windmill.
24
+
25
+ ### Conjectures
26
+
27
+ - **Erdős–Faber–Lovász** (1972; recorded in Erdős, P. (1981), "On the combinatorial problems which I would most like to see solved," *Combinatorica*, 1(1), 25–42, [doi:10.1007/BF02579174](https://doi.org/10.1007/BF02579174)). [wiki](https://en.wikipedia.org/wiki/Erd%C5%91s%E2%80%93Faber%E2%80%93Lov%C3%A1sz_conjecture) — The union of $k$ cliques of size $k$ pairwise sharing ≤1 vertex is $k$-colourable. Proved for all large $k$ in 2023 (Kang–Kelly–Kühn–Methuku–Osthus).
28
+ - **Erdős–Sós** (posed ~1962; stated in Erdős, P. (1964), "Extremal problems in graph theory," in *Theory of Graphs and Its Applications* (Proc. Sympos. Smolenice 1963), Czechoslovak Acad. Sci., pp. 29–36; no DOI). [Erdős list](https://www.emis.de/classics/Erdos/extrram.htm) — Any graph with more than $(k-1)n/2$ edges contains every tree with $k$ edges. *(Exact page range as commonly cited; volume not viewed directly.)*
29
+ - **Erdős–Hajnal** (Erdős, P. & Hajnal, A. (1977), "On spanned subgraphs of graphs," in *Contributions to Graph Theory and Its Applications*, Ilmenau, pp. 80–96; often cited via their (1989) "Ramsey-type theorems," *Discrete Applied Mathematics*, 25(1–2), 37–52). [wiki](https://en.wikipedia.org/wiki/Erd%C5%91s%E2%80%93Hajnal_conjecture) — Graphs omitting a fixed induced subgraph contain a clique or independent set of polynomial size $n^{c}$. Major open problem.
30
+ - **Erdős–Gyárfás** (Erdős & Gyárfás, 1995). [wiki](https://en.wikipedia.org/wiki/Erd%C5%91s%E2%80%93Gy%C3%A1rf%C3%A1s_conjecture) · [West](http://dwest.web.illinois.edu/openp/2powcyc.html) — Every graph with minimum degree ≥ 3 has a cycle whose length is a power of two. *(Posed at a conference; no single origin paper — citation details unverified.)*
31
+
32
+ ---
33
+
34
+ Compiled 2026-07-11; verify anything you plan to cite. `ultragraph` genesis `251e6ea`.