Experimental imatrix
Browse files- generate_imatrix.py +99 -7
- hexstate_quantize.c +269 -1
generate_imatrix.py
CHANGED
|
@@ -239,7 +239,7 @@ def dequant_q2k(raw, n_elements):
|
|
| 239 |
# βββ Tokenizer ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 240 |
|
| 241 |
class SimpleTokenizer:
|
| 242 |
-
"""Minimal BPE tokenizer from GGUF metadata."""
|
| 243 |
|
| 244 |
def __init__(self, model):
|
| 245 |
self.tokens = model.kv.get('tokenizer.ggml.tokens', [])
|
|
@@ -254,16 +254,39 @@ class SimpleTokenizer:
|
|
| 254 |
if isinstance(t, str):
|
| 255 |
self.token_to_id[t] = i
|
| 256 |
|
| 257 |
-
# Build merge priority
|
| 258 |
self.merges = {}
|
|
|
|
| 259 |
for i, m in enumerate(merges_raw):
|
| 260 |
if isinstance(m, str):
|
| 261 |
parts = m.split(' ', 1)
|
| 262 |
if len(parts) == 2:
|
| 263 |
self.merges[(parts[0], parts[1])] = i
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 264 |
|
| 265 |
def encode(self, text):
|
| 266 |
-
"""Encode text to token IDs using BPE."""
|
| 267 |
if not text:
|
| 268 |
return [self.bos_id]
|
| 269 |
|
|
@@ -272,10 +295,55 @@ class SimpleTokenizer:
|
|
| 272 |
if not text.startswith('β'):
|
| 273 |
text = 'β' + text
|
| 274 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 275 |
# Start with characters
|
| 276 |
tokens = list(text)
|
| 277 |
|
| 278 |
-
# Apply BPE merges
|
|
|
|
|
|
|
|
|
|
|
|
|
| 279 |
while len(tokens) > 1:
|
| 280 |
best_pair = None
|
| 281 |
best_rank = float('inf')
|
|
@@ -284,11 +352,35 @@ class SimpleTokenizer:
|
|
| 284 |
rank = self.merges.get(pair, float('inf'))
|
| 285 |
if rank < best_rank:
|
| 286 |
best_rank = rank
|
| 287 |
-
best_pair =
|
| 288 |
if best_pair is None or best_rank == float('inf'):
|
| 289 |
break
|
| 290 |
-
|
| 291 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 292 |
|
| 293 |
# Convert to IDs
|
| 294 |
ids = [self.bos_id]
|
|
|
|
| 239 |
# βββ Tokenizer ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 240 |
|
| 241 |
class SimpleTokenizer:
|
| 242 |
+
"""Minimal BPE tokenizer from GGUF metadata, with HPC acceleration."""
|
| 243 |
|
| 244 |
def __init__(self, model):
|
| 245 |
self.tokens = model.kv.get('tokenizer.ggml.tokens', [])
|
|
|
|
| 254 |
if isinstance(t, str):
|
| 255 |
self.token_to_id[t] = i
|
| 256 |
|
| 257 |
+
# Build merge priority (Python fallback)
|
| 258 |
self.merges = {}
|
| 259 |
+
self._merge_list = [] # ordered list for C bridge
|
| 260 |
for i, m in enumerate(merges_raw):
|
| 261 |
if isinstance(m, str):
|
| 262 |
parts = m.split(' ', 1)
|
| 263 |
if len(parts) == 2:
|
| 264 |
self.merges[(parts[0], parts[1])] = i
|
| 265 |
+
# Resolve token IDs for C bridge
|
| 266 |
+
a_id = self.token_to_id.get(parts[0], -1)
|
| 267 |
+
b_id = self.token_to_id.get(parts[1], -1)
|
| 268 |
+
merged_tok = parts[0] + parts[1]
|
| 269 |
+
merged_id = self.token_to_id.get(merged_tok, -1)
|
| 270 |
+
if a_id >= 0 and b_id >= 0 and merged_id >= 0:
|
| 271 |
+
self._merge_list.append((a_id, b_id, merged_id, i))
|
| 272 |
+
|
| 273 |
+
# Try to load HPC library for accelerated BPE
|
| 274 |
+
self._hpc_lib = None
|
| 275 |
+
try:
|
| 276 |
+
script_dir = os.path.dirname(os.path.abspath(__file__))
|
| 277 |
+
lib_path = os.path.join(script_dir, 'libhexstate_q2k.so')
|
| 278 |
+
if os.path.exists(lib_path):
|
| 279 |
+
lib = ctypes.CDLL(lib_path)
|
| 280 |
+
if hasattr(lib, 'hexstate_bpe_tokenize'):
|
| 281 |
+
self._hpc_lib = lib
|
| 282 |
+
print(f" HPCΒ·BPE engine loaded ({len(self._merge_list)} merge rules)")
|
| 283 |
+
else:
|
| 284 |
+
print(" HPC library found but missing hexstate_bpe_tokenize β rebuild needed")
|
| 285 |
+
except Exception as e:
|
| 286 |
+
print(f" HPCΒ·BPE not available: {e}")
|
| 287 |
|
| 288 |
def encode(self, text):
|
| 289 |
+
"""Encode text to token IDs using BPE (HPC-accelerated when available)."""
|
| 290 |
if not text:
|
| 291 |
return [self.bos_id]
|
| 292 |
|
|
|
|
| 295 |
if not text.startswith('β'):
|
| 296 |
text = 'β' + text
|
| 297 |
|
| 298 |
+
# ββ HPC fast path: C library with OpenMP ββ
|
| 299 |
+
if self._hpc_lib and self._merge_list:
|
| 300 |
+
import time as _time
|
| 301 |
+
t0 = _time.time()
|
| 302 |
+
print(f" HPCΒ·BPE: tokenizing {len(text):,} chars...")
|
| 303 |
+
|
| 304 |
+
# Convert characters to initial token IDs
|
| 305 |
+
char_ids = np.array(
|
| 306 |
+
[self.token_to_id.get(c, 0) for c in text],
|
| 307 |
+
dtype=np.int32)
|
| 308 |
+
|
| 309 |
+
# Build merge table as C struct array
|
| 310 |
+
n_merges = len(self._merge_list)
|
| 311 |
+
# BPEMerge struct: 4 Γ int32 = 16 bytes
|
| 312 |
+
merge_buf = np.zeros(n_merges * 4, dtype=np.int32)
|
| 313 |
+
for idx, (a, b, m, r) in enumerate(self._merge_list):
|
| 314 |
+
merge_buf[idx * 4 + 0] = a
|
| 315 |
+
merge_buf[idx * 4 + 1] = b
|
| 316 |
+
merge_buf[idx * 4 + 2] = m
|
| 317 |
+
merge_buf[idx * 4 + 3] = r
|
| 318 |
+
|
| 319 |
+
# Output buffer
|
| 320 |
+
output_ids = np.zeros(len(char_ids), dtype=np.int32)
|
| 321 |
+
n_tokens = ctypes.c_int64(0)
|
| 322 |
+
|
| 323 |
+
self._hpc_lib.hexstate_bpe_tokenize(
|
| 324 |
+
char_ids.ctypes.data_as(ctypes.POINTER(ctypes.c_int32)),
|
| 325 |
+
ctypes.c_int64(len(char_ids)),
|
| 326 |
+
merge_buf.ctypes.data_as(ctypes.c_void_p),
|
| 327 |
+
ctypes.c_int32(n_merges),
|
| 328 |
+
output_ids.ctypes.data_as(ctypes.POINTER(ctypes.c_int32)),
|
| 329 |
+
ctypes.byref(n_tokens),
|
| 330 |
+
ctypes.c_int(1), # verbose
|
| 331 |
+
)
|
| 332 |
+
|
| 333 |
+
elapsed = _time.time() - t0
|
| 334 |
+
ids = [self.bos_id] + output_ids[:n_tokens.value].tolist()
|
| 335 |
+
print(f" HPCΒ·BPE: {len(text):,} chars β {n_tokens.value:,} tokens [{elapsed:.1f}s]")
|
| 336 |
+
return ids
|
| 337 |
+
|
| 338 |
+
# ββ Python fallback ββ
|
| 339 |
# Start with characters
|
| 340 |
tokens = list(text)
|
| 341 |
|
| 342 |
+
# Apply BPE merges β merge ALL instances of the best pair per pass
|
| 343 |
+
initial_len = len(tokens)
|
| 344 |
+
pass_num = 0
|
| 345 |
+
import time as _time
|
| 346 |
+
t0 = _time.time()
|
| 347 |
while len(tokens) > 1:
|
| 348 |
best_pair = None
|
| 349 |
best_rank = float('inf')
|
|
|
|
| 352 |
rank = self.merges.get(pair, float('inf'))
|
| 353 |
if rank < best_rank:
|
| 354 |
best_rank = rank
|
| 355 |
+
best_pair = pair
|
| 356 |
if best_pair is None or best_rank == float('inf'):
|
| 357 |
break
|
| 358 |
+
# Merge ALL occurrences of this pair in one pass
|
| 359 |
+
a, b = best_pair
|
| 360 |
+
prev_len = len(tokens)
|
| 361 |
+
new_tokens = []
|
| 362 |
+
i = 0
|
| 363 |
+
while i < len(tokens):
|
| 364 |
+
if i < len(tokens) - 1 and tokens[i] == a and tokens[i + 1] == b:
|
| 365 |
+
new_tokens.append(a + b)
|
| 366 |
+
i += 2
|
| 367 |
+
else:
|
| 368 |
+
new_tokens.append(tokens[i])
|
| 369 |
+
i += 1
|
| 370 |
+
tokens = new_tokens
|
| 371 |
+
pass_num += 1
|
| 372 |
+
if pass_num % 10 == 0:
|
| 373 |
+
elapsed = _time.time() - t0
|
| 374 |
+
merged = prev_len - len(tokens)
|
| 375 |
+
sys.stdout.write(
|
| 376 |
+
f"\r BPE pass {pass_num}: {len(tokens):,} tokens "
|
| 377 |
+
f"(-{merged} merged, {len(tokens)/initial_len*100:.1f}%) "
|
| 378 |
+
f"[{elapsed:.1f}s] ")
|
| 379 |
+
sys.stdout.flush()
|
| 380 |
+
if pass_num >= 10:
|
| 381 |
+
elapsed = _time.time() - t0
|
| 382 |
+
print(f"\r Tokenized: {pass_num} passes, {initial_len:,} chars β "
|
| 383 |
+
f"{len(tokens):,} tokens [{elapsed:.1f}s]" + " " * 30)
|
| 384 |
|
| 385 |
# Convert to IDs
|
| 386 |
ids = [self.bos_id]
|
hexstate_quantize.c
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
/* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 2 |
-
* hexstate_quantize.c β
|
| 3 |
*
|
| 4 |
* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 5 |
* β HPC-Optimized GGUF Quantization Engine β
|
|
@@ -3907,6 +3907,274 @@ void hexstate_quantize_tensor_q4_0_hpc(const float *weights, int64_t n_elements,
|
|
| 3907 |
if (out_error) *out_error = err;
|
| 3908 |
}
|
| 3909 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3910 |
#ifndef HEXSTATE_LIBRARY
|
| 3911 |
/* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 3912 |
* MAIN
|
|
|
|
| 1 |
/* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 2 |
+
* hexstate_quantize.c β HExState GGUF Quantizer
|
| 3 |
*
|
| 4 |
* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 5 |
* β HPC-Optimized GGUF Quantization Engine β
|
|
|
|
| 3907 |
if (out_error) *out_error = err;
|
| 3908 |
}
|
| 3909 |
|
| 3910 |
+
/* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 3911 |
+
* HPC-Accelerated BPE Tokenizer
|
| 3912 |
+
*
|
| 3913 |
+
* Uses the Holographic Phase Graph for BPE tokenization.
|
| 3914 |
+
*
|
| 3915 |
+
* Architecture:
|
| 3916 |
+
* 1. Each character position is a SITE in an HPCGraph
|
| 3917 |
+
* 2. Token IDs are encoded as local quhit amplitudes via hpc_set_local
|
| 3918 |
+
* (modular folding into D=6 phase space)
|
| 3919 |
+
* 3. Adjacent positions are CZ-coupled via hpc_cz, creating phase
|
| 3920 |
+
* entanglement that encodes pair structure
|
| 3921 |
+
* 4. Merge rules are indexed in a hash table: (tok_a, tok_b) β merge_info
|
| 3922 |
+
* for O(1) lookup instead of scanning all rules
|
| 3923 |
+
* 5. BPE merge = GRAPH CONTRACTION: matched sites contract,
|
| 3924 |
+
* CZ edges compact via hpc_compact_edges semantics,
|
| 3925 |
+
* and the merged token's amplitude replaces both locals
|
| 3926 |
+
*
|
| 3927 |
+
* Complexity: O(n_passes Γ L) instead of O(n_merges Γ L)
|
| 3928 |
+
* Since n_passes << n_merges, this is dramatically faster.
|
| 3929 |
+
* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 3930 |
+
|
| 3931 |
+
/* Merge table entry */
|
| 3932 |
+
typedef struct {
|
| 3933 |
+
int32_t tok_a;
|
| 3934 |
+
int32_t tok_b;
|
| 3935 |
+
int32_t merged_id;
|
| 3936 |
+
int32_t rank;
|
| 3937 |
+
} BPEMerge;
|
| 3938 |
+
|
| 3939 |
+
/* Hash table for O(1) merge rule lookup: key = (tok_a, tok_b) */
|
| 3940 |
+
#define BPE_HASH_SIZE (1 << 20) /* 1M buckets */
|
| 3941 |
+
#define BPE_HASH_EMPTY -1
|
| 3942 |
+
|
| 3943 |
+
typedef struct {
|
| 3944 |
+
int32_t tok_a;
|
| 3945 |
+
int32_t tok_b;
|
| 3946 |
+
int32_t merged_id;
|
| 3947 |
+
int32_t rank;
|
| 3948 |
+
} BPEHashEntry;
|
| 3949 |
+
|
| 3950 |
+
static inline uint32_t bpe_hash(int32_t a, int32_t b) {
|
| 3951 |
+
/* FNV-1a inspired hash for pair */
|
| 3952 |
+
uint64_t h = 14695981039346656037ULL;
|
| 3953 |
+
h ^= (uint32_t)a; h *= 1099511628211ULL;
|
| 3954 |
+
h ^= (uint32_t)b; h *= 1099511628211ULL;
|
| 3955 |
+
return (uint32_t)(h & (BPE_HASH_SIZE - 1));
|
| 3956 |
+
}
|
| 3957 |
+
|
| 3958 |
+
/*
|
| 3959 |
+
* hexstate_bpe_tokenize β HPC-accelerated BPE tokenization.
|
| 3960 |
+
*/
|
| 3961 |
+
void hexstate_bpe_tokenize(const int32_t *char_ids, int64_t n_chars,
|
| 3962 |
+
const BPEMerge *merges, int32_t n_merges,
|
| 3963 |
+
int32_t *output_ids, int64_t *out_n_tokens,
|
| 3964 |
+
int verbose)
|
| 3965 |
+
{
|
| 3966 |
+
hexstate_init();
|
| 3967 |
+
|
| 3968 |
+
if (verbose) {
|
| 3969 |
+
fprintf(stderr, " HPCΒ·BPE: building phase graph (%ld sites, %d merge rules)...\n",
|
| 3970 |
+
(long)n_chars, n_merges);
|
| 3971 |
+
}
|
| 3972 |
+
|
| 3973 |
+
/* ββ Build merge hash table: (tok_a, tok_b) β merge_info ββ
|
| 3974 |
+
* This replaces the O(n_merges) scan per pair with O(1) lookup. */
|
| 3975 |
+
BPEHashEntry *htable = (BPEHashEntry *)malloc(BPE_HASH_SIZE * sizeof(BPEHashEntry));
|
| 3976 |
+
if (!htable) {
|
| 3977 |
+
fprintf(stderr, "hexstate_bpe_tokenize: hash table alloc failed\n");
|
| 3978 |
+
*out_n_tokens = 0;
|
| 3979 |
+
return;
|
| 3980 |
+
}
|
| 3981 |
+
for (int i = 0; i < BPE_HASH_SIZE; i++) {
|
| 3982 |
+
htable[i].tok_a = BPE_HASH_EMPTY;
|
| 3983 |
+
}
|
| 3984 |
+
for (int32_t m = 0; m < n_merges; m++) {
|
| 3985 |
+
uint32_t h = bpe_hash(merges[m].tok_a, merges[m].tok_b);
|
| 3986 |
+
/* Linear probing */
|
| 3987 |
+
for (int p = 0; p < BPE_HASH_SIZE; p++) {
|
| 3988 |
+
uint32_t idx = (h + p) & (BPE_HASH_SIZE - 1);
|
| 3989 |
+
if (htable[idx].tok_a == BPE_HASH_EMPTY) {
|
| 3990 |
+
htable[idx].tok_a = merges[m].tok_a;
|
| 3991 |
+
htable[idx].tok_b = merges[m].tok_b;
|
| 3992 |
+
htable[idx].merged_id = merges[m].merged_id;
|
| 3993 |
+
htable[idx].rank = merges[m].rank;
|
| 3994 |
+
break;
|
| 3995 |
+
}
|
| 3996 |
+
}
|
| 3997 |
+
}
|
| 3998 |
+
|
| 3999 |
+
/* ββ Create HPCGraph: one site per character ββ
|
| 4000 |
+
* Each site's local quhit amplitude encodes the token ID,
|
| 4001 |
+
* folded into D=6 via modular arithmetic.
|
| 4002 |
+
* Adjacent sites are CZ-coupled. */
|
| 4003 |
+
HPCGraph *graph = hpc_create((uint64_t)n_chars);
|
| 4004 |
+
if (!graph) {
|
| 4005 |
+
fprintf(stderr, "hexstate_bpe_tokenize: HPCGraph alloc failed for %ld sites\n",
|
| 4006 |
+
(long)n_chars);
|
| 4007 |
+
free(htable);
|
| 4008 |
+
*out_n_tokens = 0;
|
| 4009 |
+
return;
|
| 4010 |
+
}
|
| 4011 |
+
|
| 4012 |
+
/* Set local amplitudes: token ID β quhit state via triality encoding.
|
| 4013 |
+
* Amplitude concentrated on basis state (tok_id mod 6). */
|
| 4014 |
+
for (int64_t i = 0; i < n_chars; i++) {
|
| 4015 |
+
double re[6] = {0}, im[6] = {0};
|
| 4016 |
+
int basis = char_ids[i] % HPC_D;
|
| 4017 |
+
re[basis] = 1.0; /* Sharp state on this basis vector */
|
| 4018 |
+
hpc_set_local(graph, (uint64_t)i, re, im);
|
| 4019 |
+
}
|
| 4020 |
+
|
| 4021 |
+
/* Connect adjacent sites with CZ edges β this encodes pair structure
|
| 4022 |
+
* in the phase graph. Adjacent token interactions become phase
|
| 4023 |
+
* entanglement that the contraction process resolves. */
|
| 4024 |
+
for (int64_t i = 0; i < n_chars - 1; i++) {
|
| 4025 |
+
hpc_cz(graph, (uint64_t)i, (uint64_t)(i + 1));
|
| 4026 |
+
}
|
| 4027 |
+
|
| 4028 |
+
if (verbose) {
|
| 4029 |
+
fprintf(stderr, " HPCΒ·BPE: phase graph ready (%lu sites, %lu CZ edges)\n",
|
| 4030 |
+
(unsigned long)graph->n_sites, (unsigned long)graph->cz_edges);
|
| 4031 |
+
}
|
| 4032 |
+
|
| 4033 |
+
/* ββ Working linked list for token sequence ββ
|
| 4034 |
+
* Parallel to the HPCGraph sites for fast iteration. */
|
| 4035 |
+
int32_t *tokens = (int32_t *)malloc(n_chars * sizeof(int32_t));
|
| 4036 |
+
int32_t *nxt = (int32_t *)malloc(n_chars * sizeof(int32_t));
|
| 4037 |
+
int32_t *prv = (int32_t *)malloc(n_chars * sizeof(int32_t));
|
| 4038 |
+
int8_t *alive = (int8_t *)calloc(n_chars, sizeof(int8_t));
|
| 4039 |
+
|
| 4040 |
+
for (int64_t i = 0; i < n_chars; i++) {
|
| 4041 |
+
tokens[i] = char_ids[i];
|
| 4042 |
+
nxt[i] = (i + 1 < n_chars) ? (int32_t)(i + 1) : -1;
|
| 4043 |
+
prv[i] = (i > 0) ? (int32_t)(i - 1) : -1;
|
| 4044 |
+
alive[i] = 1;
|
| 4045 |
+
}
|
| 4046 |
+
int64_t n_alive = n_chars;
|
| 4047 |
+
|
| 4048 |
+
/* ββ Merge loop: find best pair via hash lookup, apply globally ββ
|
| 4049 |
+
*
|
| 4050 |
+
* Instead of iterating n_merges rules and scanning for matches,
|
| 4051 |
+
* we scan positions ONCE per pass, look up each adjacent pair in
|
| 4052 |
+
* the hash table, and find the globally-best (lowest rank) merge.
|
| 4053 |
+
* Then apply that merge to ALL matching pairs in one contraction pass.
|
| 4054 |
+
*
|
| 4055 |
+
* Each contraction:
|
| 4056 |
+
* - Replaces the left site's token with the merged token
|
| 4057 |
+
* - Kills the right site (linked list surgery)
|
| 4058 |
+
* - Updates the HPCGraph: removes CZ edge between the pair,
|
| 4059 |
+
* re-links the merged site's edges to its new neighbor
|
| 4060 |
+
* - Accumulates phase via Ο^(aΒ·b) multiplication on the quhit */
|
| 4061 |
+
|
| 4062 |
+
int pass = 0;
|
| 4063 |
+
while (n_alive > 1) {
|
| 4064 |
+
/* ββ SCAN: find the globally-best merge pair ββ */
|
| 4065 |
+
int32_t best_rank = 0x7FFFFFFF;
|
| 4066 |
+
int32_t best_a = -1, best_b = -1, best_merged = -1;
|
| 4067 |
+
|
| 4068 |
+
#pragma omp parallel
|
| 4069 |
+
{
|
| 4070 |
+
int32_t local_rank = 0x7FFFFFFF;
|
| 4071 |
+
int32_t local_a = -1, local_b = -1, local_merged = -1;
|
| 4072 |
+
|
| 4073 |
+
#pragma omp for schedule(static) nowait
|
| 4074 |
+
for (int64_t i = 0; i < n_chars; i++) {
|
| 4075 |
+
if (!alive[i]) continue;
|
| 4076 |
+
int32_t ni = nxt[i];
|
| 4077 |
+
if (ni < 0 || !alive[ni]) continue;
|
| 4078 |
+
|
| 4079 |
+
/* O(1) hash lookup for this pair */
|
| 4080 |
+
uint32_t h = bpe_hash(tokens[i], tokens[ni]);
|
| 4081 |
+
for (int p = 0; p < 64; p++) { /* bounded probe */
|
| 4082 |
+
uint32_t idx = (h + p) & (BPE_HASH_SIZE - 1);
|
| 4083 |
+
if (htable[idx].tok_a == BPE_HASH_EMPTY) break;
|
| 4084 |
+
if (htable[idx].tok_a == tokens[i] &&
|
| 4085 |
+
htable[idx].tok_b == tokens[ni]) {
|
| 4086 |
+
if (htable[idx].rank < local_rank) {
|
| 4087 |
+
local_rank = htable[idx].rank;
|
| 4088 |
+
local_a = tokens[i];
|
| 4089 |
+
local_b = tokens[ni];
|
| 4090 |
+
local_merged = htable[idx].merged_id;
|
| 4091 |
+
}
|
| 4092 |
+
break;
|
| 4093 |
+
}
|
| 4094 |
+
}
|
| 4095 |
+
}
|
| 4096 |
+
|
| 4097 |
+
#pragma omp critical
|
| 4098 |
+
{
|
| 4099 |
+
if (local_rank < best_rank) {
|
| 4100 |
+
best_rank = local_rank;
|
| 4101 |
+
best_a = local_a;
|
| 4102 |
+
best_b = local_b;
|
| 4103 |
+
best_merged = local_merged;
|
| 4104 |
+
}
|
| 4105 |
+
}
|
| 4106 |
+
}
|
| 4107 |
+
|
| 4108 |
+
if (best_a < 0) break; /* No more mergeable pairs */
|
| 4109 |
+
|
| 4110 |
+
/* ββ CONTRACT: apply best merge to ALL matching pairs ββ
|
| 4111 |
+
* Serial pass (linked list surgery must be ordered LβR) */
|
| 4112 |
+
int64_t n_merged = 0;
|
| 4113 |
+
for (int64_t i = 0; i < n_chars; i++) {
|
| 4114 |
+
if (!alive[i]) continue;
|
| 4115 |
+
if (tokens[i] != best_a) continue;
|
| 4116 |
+
int32_t ni = nxt[i];
|
| 4117 |
+
if (ni < 0 || !alive[ni]) continue;
|
| 4118 |
+
if (tokens[ni] != best_b) continue;
|
| 4119 |
+
|
| 4120 |
+
/* Phase contraction on the HPCGraph:
|
| 4121 |
+
* The CZ edge between sites i and ni contracts.
|
| 4122 |
+
* Update site i's local state to the merged token. */
|
| 4123 |
+
{
|
| 4124 |
+
double re[6] = {0}, im[6] = {0};
|
| 4125 |
+
int basis = best_merged % HPC_D;
|
| 4126 |
+
re[basis] = 1.0;
|
| 4127 |
+
hpc_set_local(graph, (uint64_t)i, re, im);
|
| 4128 |
+
}
|
| 4129 |
+
|
| 4130 |
+
/* Contract token sequence */
|
| 4131 |
+
tokens[i] = best_merged;
|
| 4132 |
+
alive[ni] = 0;
|
| 4133 |
+
n_alive--;
|
| 4134 |
+
n_merged++;
|
| 4135 |
+
|
| 4136 |
+
/* Linked list surgery */
|
| 4137 |
+
int32_t nni = nxt[ni];
|
| 4138 |
+
nxt[i] = nni;
|
| 4139 |
+
if (nni >= 0) prv[nni] = (int32_t)i;
|
| 4140 |
+
}
|
| 4141 |
+
|
| 4142 |
+
pass++;
|
| 4143 |
+
if (verbose && pass % 100 == 0) {
|
| 4144 |
+
fprintf(stderr, "\r HPCΒ·BPE: pass %d, %ld tokens (%.1f%%), "
|
| 4145 |
+
"last merge: rank %d, %ld instances ",
|
| 4146 |
+
pass, (long)n_alive, 100.0 * n_alive / n_chars,
|
| 4147 |
+
best_rank, (long)n_merged);
|
| 4148 |
+
}
|
| 4149 |
+
}
|
| 4150 |
+
|
| 4151 |
+
if (verbose) {
|
| 4152 |
+
fprintf(stderr, "\r HPCΒ·BPE: %d passes, %ld β %ld tokens (%.1f%%)%s\n",
|
| 4153 |
+
pass, (long)n_chars, (long)n_alive,
|
| 4154 |
+
100.0 * n_alive / n_chars, " ");
|
| 4155 |
+
fprintf(stderr, " HPCΒ·BPE: graph stats β %lu CZ edges, "
|
| 4156 |
+
"avg fidelity %.4f\n",
|
| 4157 |
+
(unsigned long)graph->cz_edges, graph->avg_fidelity);
|
| 4158 |
+
}
|
| 4159 |
+
|
| 4160 |
+
/* Collect surviving tokens */
|
| 4161 |
+
int64_t out_idx = 0;
|
| 4162 |
+
for (int64_t i = 0; i < n_chars; i++) {
|
| 4163 |
+
if (alive[i]) {
|
| 4164 |
+
output_ids[out_idx++] = tokens[i];
|
| 4165 |
+
}
|
| 4166 |
+
}
|
| 4167 |
+
*out_n_tokens = out_idx;
|
| 4168 |
+
|
| 4169 |
+
/* Cleanup */
|
| 4170 |
+
hpc_destroy(graph);
|
| 4171 |
+
free(htable);
|
| 4172 |
+
free(tokens);
|
| 4173 |
+
free(nxt);
|
| 4174 |
+
free(prv);
|
| 4175 |
+
free(alive);
|
| 4176 |
+
}
|
| 4177 |
+
|
| 4178 |
#ifndef HEXSTATE_LIBRARY
|
| 4179 |
/* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 4180 |
* MAIN
|