Quazim0t0 commited on
Commit
947f8cf
·
verified ·
1 Parent(s): 77ab752

Upload folder using huggingface_hub

Browse files
Files changed (12) hide show
  1. README.md +20 -8
  2. app.py +205 -0
  3. config.py +158 -0
  4. daisychain.py +126 -0
  5. examples.json +1 -0
  6. model.py +1011 -0
  7. registry.py +54 -0
  8. requirements.txt +6 -0
  9. router2.pt +3 -0
  10. specialist_presets.py +69 -0
  11. spike_tokenizer.py +82 -0
  12. tokenizer.json +1 -0
README.md CHANGED
@@ -1,13 +1,25 @@
1
  ---
2
- title: Daisychain Demo
3
- emoji: 😻
4
- colorFrom: indigo
5
- colorTo: indigo
6
  sdk: gradio
7
- sdk_version: 6.19.0
8
- python_version: '3.13'
9
  app_file: app.py
10
- pinned: false
 
 
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: DaisyChain
3
+ emoji: 🌼
4
+ colorFrom: purple
5
+ colorTo: green
6
  sdk: gradio
7
+ sdk_version: 4.44.0
 
8
  app_file: app.py
9
+ pinned: true
10
+ license: apache-2.0
11
+ short_description: Real-time DNA routing across modular specialists
12
  ---
13
 
14
+ # 🌼 DaisyChain interactive routing
15
+
16
+ Four ~74M DNA/RNA specialists (≈295M total, **under Carbon-500M**) + a learned router.
17
+ Each specialist is distilled per-domain from Carbon-500M; the router reads how
18
+ *surprised* each one is by a sequence (bits/base) plus its hidden state, and hands the
19
+ work to the home specialist.
20
+
21
+ Paste a DNA sequence and watch the chain light up specialist-by-specialist, then the
22
+ router pick its home domain in real time — and optionally generate a continuation from
23
+ the chosen specialist.
24
+
25
+ Model weights: [DaisyChainAI/daisychain-genomics](https://huggingface.co/DaisyChainAI/daisychain-genomics).
app.py ADDED
@@ -0,0 +1,205 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ DaisyChain — interactive routing demo (HuggingFace Space).
3
+
4
+ Paste DNA; the learned router reads how *surprised* each ~74M specialist is (bits/base)
5
+ plus its hidden state and hands the sequence to its home specialist — then that specialist
6
+ streams a continuation live. Styled after the Modular-Mind panel: animated routing cards,
7
+ a first-run loading notice, live token streaming. Every handler is a generator.
8
+ """
9
+ import html as _h
10
+ import os
11
+ import json
12
+
13
+ import gradio as gr
14
+
15
+ # ZeroGPU: @spaces.GPU allocates a GPU only for the decorated call. Falls back to a no-op
16
+ # decorator when `spaces` isn't installed (local / plain CPU).
17
+ try:
18
+ import spaces
19
+ _gpu = spaces.GPU
20
+ except Exception:
21
+ def _gpu(fn=None, **kw):
22
+ return fn if callable(fn) else (lambda f: f)
23
+
24
+ from daisychain import DaisyChain
25
+
26
+ HERE = os.path.dirname(os.path.abspath(__file__))
27
+ MODEL_REPO = os.environ.get("DAISYCHAIN_REPO", "DaisyChainAI/daisychain-genomics")
28
+ DEVICE = os.environ.get("DAISYCHAIN_DEVICE", "cpu")
29
+
30
+ # code + tokenizer + router are bundled here; pull the big specialist weights from the
31
+ # model repo on first launch (keeps the Space repo light).
32
+ if not os.path.exists(os.path.join(HERE, "eukaryote", "model.safetensors")):
33
+ try:
34
+ from huggingface_hub import snapshot_download
35
+ snapshot_download(MODEL_REPO, local_dir=HERE,
36
+ allow_patterns=["*/model.safetensors", "tokenizer.json", "router2.pt"])
37
+ except Exception:
38
+ pass
39
+
40
+ _DC = {"m": None} # lazy-loaded so CUDA is never touched at import
41
+ _WARMED = {"done": False} # so the "loading" notice only shows on the first run
42
+
43
+ EMOJI = {"eukaryote": "🧬 Eukaryote", "prokaryote": "🦠 Prokaryote",
44
+ "mrna": "📜 mRNA", "mrna_splice": "✂️ mRNA-splice"}
45
+ COLOR = {"eukaryote": "#7c5cff", "prokaryote": "#22b8cf",
46
+ "mrna": "#e64980", "mrna_splice": "#37b24d"}
47
+ DESC = DaisyChain.DESCRIPTIONS
48
+
49
+
50
+ def _moe():
51
+ if _DC["m"] is None:
52
+ _DC["m"] = DaisyChain(root=HERE, device=DEVICE)
53
+ return _DC["m"]
54
+
55
+
56
+ # ---- HTML rendering (ported from the Modular-Mind panel) --------------------------
57
+ _CSS = """<style>
58
+ .dcx{font-family:system-ui,sans-serif;color:#dde;margin:4px 0}
59
+ .dcx .note{background:#14141c;border:1px solid #2a2a35;border-radius:10px;padding:12px 14px;color:#9bd;font-size:14px}
60
+ .dcx .h{font-size:17px;font-weight:800;margin:4px 0 8px}
61
+ .dcx .p{color:#8892a8}
62
+ .dcx .g{color:#eef2ff;font-weight:600}
63
+ .dcx .chain{display:flex;gap:8px;align-items:stretch;flex-wrap:wrap;margin:6px 0}
64
+ .dcx .link{align-self:center;color:#445;font-size:20px;margin-bottom:18px}
65
+ .dcx .card{flex:1;min-width:190px;background:#14141c;border:1px solid #2a2a35;border-radius:12px;padding:11px 13px;position:relative;overflow:hidden}
66
+ .dcx .card .nm{font-weight:800;font-size:15px}
67
+ .dcx .card .meta{color:#99a;font-size:11px;margin-top:2px;min-height:26px}
68
+ .dcx .card .bar{height:10px;background:#23232e;border-radius:6px;margin-top:8px;overflow:hidden}
69
+ .dcx .card .fill{height:100%;border-radius:6px;animation:dcxw .7s ease}
70
+ .dcx .card .pct{font-size:12px;color:#bcd;margin-top:4px}
71
+ .dcx .badge{position:absolute;top:9px;right:10px;font-size:10px;font-weight:800;letter-spacing:.08em;padding:3px 8px;border-radius:99px;color:#0a1410}
72
+ @keyframes dcxw{from{width:0}}
73
+ .dcx .gen{background:#101018;border:1px solid #2a2a35;border-radius:12px;padding:13px 15px;margin:10px 0;font-size:15px;line-height:1.7;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;word-break:break-all}
74
+ .dcx .caret{display:inline-block;width:9px;height:17px;border-radius:2px;background:#7ad1ff;margin-left:2px;vertical-align:text-bottom;animation:dcxb .8s steps(1) infinite}
75
+ @keyframes dcxb{50%{opacity:0}}
76
+ .dcx .sub{color:#889;font-size:12px;line-height:1.5;margin-top:8px}
77
+ </style>"""
78
+
79
+
80
+ def _wrap(body):
81
+ return _CSS + "<div class='dcx'>" + body + "</div>"
82
+
83
+
84
+ def _esc(s):
85
+ return _h.escape(s or "").replace("\n", "<br>")
86
+
87
+
88
+ def _notice(action="Routing"):
89
+ if not _WARMED["done"]:
90
+ try:
91
+ gr.Info("First run — loading the four ~74M specialists (~20–40s on CPU). After this it's quick.")
92
+ except Exception:
93
+ pass
94
+ return _wrap(f"<div class='note'>⏳ Loading the four ~74M specialists + {action.lower()}… "
95
+ "first run can take ~20–40s on CPU; every run after is fast.</div>")
96
+ return _wrap(f"<div class='note'>⏳ {action}…</div>")
97
+
98
+
99
+ def _msg(title, body):
100
+ return _wrap(f"<div class='note'><b>{title}</b><br>{body}</div>")
101
+
102
+
103
+ def _cards(bpb, winner=None):
104
+ """One animated card per specialist: surprise (bits/base), confidence bar, winner badge + glow.
105
+ bpb values may be None (not computed yet). Lower bits/base = more 'at home' = fuller bar."""
106
+ cells = []
107
+ doms = list(bpb.keys())
108
+ for i, n in enumerate(doms):
109
+ c = COLOR.get(n, "#9b59b6")
110
+ v = bpb[n]
111
+ win = (n == winner)
112
+ conf = max(0.0, min(1.0, (2.02 - v) / 0.5)) if v is not None else 0.0 # ~1.52..2.02 -> 1..0
113
+ style = f"border-color:{c};box-shadow:0 0 16px {c}40" if win else ""
114
+ badge = f"<span class='badge' style='background:{c}'>ROUTED ✓</span>" if win else ""
115
+ meta = (f"{DESC.get(n,'')}<br>{v:.3f} bits/base (lower = more at home)"
116
+ if v is not None else f"{DESC.get(n,'')}<br>…")
117
+ bar = (f"<div class='bar'><div class='fill' style='width:{conf*100:.1f}%;background:{c}'></div></div>"
118
+ f"<div class='pct'>confidence {conf*100:.0f}%</div>") if v is not None else \
119
+ "<div class='bar'></div><div class='pct'>…</div>"
120
+ cells.append(
121
+ f"<div class='card' style='{style}'>{badge}"
122
+ f"<div class='nm' style='color:{c}'>{EMOJI.get(n, n)}</div>"
123
+ f"<div class='meta'>{meta}</div>{bar}</div>")
124
+ if i < len(doms) - 1:
125
+ cells.append("<div class='link'>⬭</div>")
126
+ return "<div class='chain'>" + "".join(cells) + "</div>"
127
+
128
+
129
+ def _gen_box(prompt, gen, live=False):
130
+ caret = "<span class='caret'></span>" if live else ""
131
+ return (f"<div class='gen'><span class='p'>{_esc(prompt)}</span>"
132
+ f"<span class='g'>{_esc(gen)}</span>{caret}</div>")
133
+
134
+
135
+ FOOTER = ("Four ~74M DNA/RNA specialists (≈295M total, <b>under Carbon-500M</b>), each distilled "
136
+ "per-domain from Carbon-500M. A learned router reads every specialist's surprise + hidden "
137
+ "state and routes to the home specialist — held-out routing accuracy <b>94.8%</b>. Only one "
138
+ "specialist runs per query (~7× cheaper than the 500M monolith).")
139
+
140
+
141
+ # ---- handler ----------------------------------------------------------------------
142
+ @_gpu(duration=120)
143
+ def route_run(seq, n_bases, do_gen):
144
+ yield _notice("Routing & generating")
145
+ seq = (seq or "").strip()
146
+ if len(seq) < 18:
147
+ yield _msg("🧬 Enter a DNA sequence", "Paste at least 18 bases (A/C/G/T) — try an example below.")
148
+ return
149
+ dc = _moe()
150
+ doms = dc.domains
151
+ bpb = {d: None for d in doms}
152
+ # progressively reveal each specialist's surprise (the chain lighting up)
153
+ sc, hd = dc._scores_hidden(seq)
154
+ for d in doms:
155
+ bpb[d] = sc[d] / 6 / 0.6931
156
+ yield _wrap("<div class='h'>🔗 Sending the sequence down the chain…</div>" + _cards(bpb))
157
+ home, _ = dc.route(seq)
158
+ c = COLOR.get(home, "#9b59b6")
159
+ head = (f"<div class='h'>🧭 Routed to <span style='color:{c}'>{EMOJI.get(home, home)}</span>"
160
+ f" — the specialist most at home with your sequence</div>" + _cards(bpb, winner=home))
161
+ if do_gen:
162
+ for gen in dc.generate_stream(home, length=int(n_bases), temperature=0.9, top_k=20, prompt=seq[-60:]):
163
+ yield _wrap(head + _gen_box(seq[-60:], gen, live=True))
164
+ _WARMED["done"] = True
165
+ yield _wrap(head + _gen_box(seq[-60:], gen, live=False) + f"<div class='sub'>{FOOTER}</div>")
166
+ else:
167
+ _WARMED["done"] = True
168
+ yield _wrap(head + f"<div class='sub'>{FOOTER}</div>")
169
+
170
+
171
+ HERO = """# 🌼 DaisyChain — a modular genomic mind
172
+ **Four ~74M DNA/RNA specialists (≈295M total, under Carbon-500M)** — 🧬 Eukaryote, 🦠 Prokaryote,
173
+ 📜 mRNA, ✂️ mRNA-splice — each **distilled per-domain from Carbon-500M**. A learned router reads how
174
+ *surprised* each specialist is by your sequence (bits/base) plus its hidden state, and hands the work
175
+ to its **home specialist**. Paste DNA and watch it route in real time.
176
+
177
+ > ℹ️ *Research demo: tiny specialists trained on a slice of the Carbon corpus — the **routing** (which
178
+ > specialist is most at home) and the **sub-500M modular architecture** are the point, not Carbon-level
179
+ > generation.*"""
180
+
181
+
182
+ def build():
183
+ with gr.Blocks(title="DaisyChain — modular genomic mind", theme=gr.themes.Soft()) as demo:
184
+ with gr.Accordion("🌼 DaisyChain — independent DNA specialists behind a learned router", open=True):
185
+ gr.Markdown(HERO)
186
+ with gr.Row():
187
+ seq = gr.Textbox(label="DNA sequence", lines=3, scale=4,
188
+ placeholder="ACGT… (eukaryotic, bacterial, mRNA, or splice-site DNA)")
189
+ n = gr.Slider(60, 300, value=150, step=30, label="generate bases", scale=1)
190
+ with gr.Row():
191
+ gen_ck = gr.Checkbox(value=True, label="stream a continuation from the routed specialist")
192
+ btn = gr.Button("🔗 Route through the DaisyChain", variant="primary")
193
+ out = gr.HTML(_wrap(_cards({d: None for d in DaisyChain.DESCRIPTIONS})))
194
+ btn.click(route_run, [seq, n, gen_ck], out)
195
+ try:
196
+ ex = json.load(open(os.path.join(HERE, "examples.json")))
197
+ gr.Examples([[v, 150, True] for v in ex.values()], inputs=[seq, n, gen_ck],
198
+ label="Example sequences (one per domain)")
199
+ except Exception:
200
+ pass
201
+ return demo
202
+
203
+
204
+ if __name__ == "__main__":
205
+ build().launch()
config.py ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ config.py -- SpikeWhale: combined config from SpikeTransformer (My Project) + NanoWhale (DeepSeek-V4).
3
+
4
+ Features carried from My Project (not in NanoWhale):
5
+ - DERF attention: erf(alpha*score+bias)*gamma replaces softmax
6
+ - XSA (Exclusive Self-Attention): orthogonality correction removes self-echo from attn output
7
+ - Engram N-gram module: hash-table N-gram lookup with DERF gate injected into embeddings
8
+ - Three-tier optimizer: embed/table params trained at lower LR
9
+
10
+ Features carried from NanoWhale (not in My Project):
11
+ - MLA (Multi-Head Latent Attention): low-rank Q projection + direct K,V (MQA)
12
+ - Partial RoPE: rotary embeddings on only qk_rope_head_dim dims of Q and K
13
+ - Low-rank grouped output projection (o_lora_rank)
14
+ - Hyper-Connections: hc_mult residual streams with learned routing between layers
15
+ - Shared expert in MoE (always-active expert alongside routed experts)
16
+ - sqrtsoftplus expert scoring (vs softmax in My Project)
17
+ - Hash-based routing for first num_hash_layers layers
18
+ - norm_topk_prob + routed_scaling_factor
19
+ - Multi-Token Prediction (MTP): extra heads predict k steps ahead
20
+ - torch.compile, FineWeb-Edu streaming, Trackio, YAML configs in train.py
21
+ """
22
+
23
+ from transformers import PretrainedConfig
24
+
25
+
26
+ class SpikeWhaleConfig(PretrainedConfig):
27
+ model_type = "spike_whale"
28
+
29
+ def __init__(
30
+ self,
31
+ # Standard
32
+ vocab_size: int = 129280,
33
+ hidden_size: int = 2048,
34
+ num_hidden_layers: int = 11,
35
+ max_position_embeddings: int = 8192,
36
+ rms_norm_eps: float = 1e-6,
37
+ initializer_range: float = 0.02,
38
+ tie_word_embeddings: bool = False,
39
+ hidden_dropout: float = 0.0,
40
+ bos_token_id: int = 0,
41
+ eos_token_id: int = 1,
42
+ # MLA Attention (NanoWhale)
43
+ num_attention_heads: int = 8,
44
+ num_key_value_heads: int = 1, # 1 = MQA; >1 = GQA
45
+ q_lora_rank: int = 160, # low-rank Q: hidden -> q_lora_rank -> num_heads*head_dim
46
+ head_dim: int = 96, # total per-head dim = nope_head_dim + qk_rope_head_dim
47
+ qk_rope_head_dim: int = 32, # RoPE applied only to these dims
48
+ o_lora_rank: int = 80, # low-rank output: num_heads*head_dim -> o_lora_rank -> hidden
49
+ attention_dropout: float = 0.0,
50
+ rope_theta: float = 10000.0,
51
+ # DERF + XSA (My Project)
52
+ use_derf: bool = True,
53
+ use_xsa: bool = True,
54
+ # MoE (combined)
55
+ use_moe: bool = True,
56
+ moe_intermediate_size: int = 640,
57
+ n_routed_experts: int = 4,
58
+ n_shared_experts: int = 1, # NanoWhale: always-active shared expert
59
+ num_experts_per_tok: int = 2,
60
+ norm_topk_prob: bool = True, # NanoWhale: normalize top-k routing weights
61
+ scoring_func: str = "sqrtsoftplus", # NanoWhale: sqrt(softplus(x)) vs softmax
62
+ routed_scaling_factor: float = 1.0, # NanoWhale: scale routed expert weights
63
+ num_hash_layers: int = 2, # NanoWhale: first N layers use hash routing
64
+ moe_aux_loss_coef: float = 0.01,
65
+ moe_layers: list = None,
66
+ # Hyper-Connections (NanoWhale)
67
+ use_hyper_connections: bool = True,
68
+ hc_mult: int = 4, # number of parallel residual streams
69
+ hc_sinkhorn_iters: int = 20,
70
+ hc_eps: float = 1e-6,
71
+ # Multi-Token Prediction (NanoWhale)
72
+ num_nextn_predict_layers: int = 1, # extra MTP heads (0 = disabled)
73
+ # Engram N-gram module (My Project)
74
+ use_engram: bool = True,
75
+ engram_compress_dim: int = 64,
76
+ engram_num_heads: int = 4,
77
+ engram_table_size: int = 8192,
78
+ engram_max_ngram: int = 3,
79
+ engram_gate_init_bias: float = -4.0,
80
+ use_hrm_refine: bool = False,
81
+ hrm_refine_steps: int = 3,
82
+ hrm_refine_dim: int = 256,
83
+ # --- ModularMind-on-V2 additions (off/unused unless enabled) ---
84
+ use_latent_io: bool = False, # add latent output head + injection input path
85
+ d_latent: int = 256, # RecursiveLink contract dim (fixed across chain)
86
+ chain_position: int = 0, # context-doubling slot: ctx & theta scale by 2^pos
87
+ base_context: int = 8192, # ctx at position 0 (>= training --seq-len)
88
+ base_rope_theta: float = 10000.0,
89
+ **kwargs,
90
+ ):
91
+ super().__init__(
92
+ bos_token_id=bos_token_id,
93
+ eos_token_id=eos_token_id,
94
+ tie_word_embeddings=tie_word_embeddings,
95
+ **kwargs,
96
+ )
97
+ self.vocab_size = vocab_size
98
+ self.hidden_size = hidden_size
99
+ self.num_hidden_layers = num_hidden_layers
100
+ self.max_position_embeddings = max_position_embeddings
101
+ self.rms_norm_eps = rms_norm_eps
102
+ self.initializer_range = initializer_range
103
+ self.hidden_dropout = hidden_dropout
104
+
105
+ self.num_attention_heads = num_attention_heads
106
+ self.num_key_value_heads = num_key_value_heads
107
+ self.q_lora_rank = q_lora_rank
108
+ self.head_dim = head_dim
109
+ self.qk_rope_head_dim = qk_rope_head_dim
110
+ self.nope_head_dim = head_dim - qk_rope_head_dim
111
+ self.o_lora_rank = o_lora_rank
112
+ self.attention_dropout = attention_dropout
113
+ self.rope_theta = rope_theta
114
+ self.use_derf = use_derf
115
+ self.use_xsa = use_xsa
116
+
117
+ self.use_moe = use_moe
118
+ self.moe_intermediate_size = moe_intermediate_size
119
+ self.n_routed_experts = n_routed_experts
120
+ self.n_shared_experts = n_shared_experts
121
+ self.num_experts_per_tok = num_experts_per_tok
122
+ self.norm_topk_prob = norm_topk_prob
123
+ self.scoring_func = scoring_func
124
+ self.routed_scaling_factor = routed_scaling_factor
125
+ self.num_hash_layers = num_hash_layers
126
+ self.moe_aux_loss_coef = moe_aux_loss_coef
127
+ self.moe_layers = moe_layers if moe_layers is not None else list(range(num_hidden_layers))
128
+
129
+ self.use_hyper_connections = use_hyper_connections
130
+ self.hc_mult = hc_mult
131
+ self.hc_sinkhorn_iters = hc_sinkhorn_iters
132
+ self.hc_eps = hc_eps
133
+
134
+ self.num_nextn_predict_layers = num_nextn_predict_layers
135
+
136
+ self.use_engram = use_engram
137
+ self.engram_compress_dim = engram_compress_dim
138
+ self.engram_num_heads = engram_num_heads
139
+ self.engram_table_size = engram_table_size
140
+ self.engram_max_ngram = engram_max_ngram
141
+ self.engram_gate_init_bias = engram_gate_init_bias
142
+ self.use_hrm_refine = use_hrm_refine
143
+ self.hrm_refine_steps = hrm_refine_steps
144
+ self.hrm_refine_dim = hrm_refine_dim
145
+ # --- ModularMind-on-V2 additions ---
146
+ self.use_latent_io = use_latent_io
147
+ self.d_latent = d_latent
148
+ self.chain_position = chain_position
149
+ self.base_context = base_context
150
+ self.base_rope_theta = base_rope_theta
151
+ # Context-doubling: each chain slot doubles ctx and rope theta.
152
+ # position 0 -> (8192, 10000); position 1 -> (16384, 20000); etc.
153
+ # Applied only when latent IO is on (i.e. this is a ModularMind specialist),
154
+ # so plain V2 keeps its own max_position_embeddings/rope_theta untouched.
155
+ if use_latent_io:
156
+ scale = 2 ** chain_position
157
+ self.max_position_embeddings = base_context * scale
158
+ self.rope_theta = base_rope_theta * scale
daisychain.py ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ daisychain.py -- self-contained inference for the DaisyChain genomic modular mind.
3
+
4
+ 4 dense ~74M DNA/RNA specialists (eukaryote, prokaryote, mrna, mrna_splice), each
5
+ per-domain-distilled from Carbon-500M, behind a learned router (MLP on PCA(hidden)
6
+ + per-specialist surprise). route() picks the home specialist; generate() / surprise()
7
+ expose the rest. No training/datasets dependency -- only model.py, specialist_presets.py,
8
+ spike_tokenizer.py, registry.py + the bundled tokenizer.json / *.safetensors / router2.pt.
9
+ """
10
+ from __future__ import annotations
11
+ import os, math
12
+ import torch
13
+ import torch.nn.functional as F
14
+
15
+ HERE = os.path.dirname(os.path.abspath(__file__))
16
+ from model import SpikeWhaleLM
17
+ from specialist_presets import generic_specialist_config
18
+ from spike_tokenizer import SpikeTokenizer
19
+ import registry
20
+
21
+ TOK_JSON = os.path.join(HERE, "tokenizer.json")
22
+ _TRANS = str.maketrans({"U": "T", "u": "T", "a": "A", "c": "C", "g": "G", "t": "T"})
23
+ LN2 = math.log(2)
24
+
25
+
26
+ def clean(seq: str) -> str:
27
+ seq = seq.translate(_TRANS).upper()
28
+ return "".join(c if c in "ACGT" else "N" for c in seq)
29
+
30
+
31
+ class _RouterMLP(torch.nn.Module):
32
+ def __init__(self, dim, h=64):
33
+ super().__init__()
34
+ self.net = torch.nn.Sequential(torch.nn.Linear(dim, h), torch.nn.ReLU(),
35
+ torch.nn.Dropout(0.0), torch.nn.Linear(h, 4))
36
+ def forward(self, x): return self.net(x)
37
+
38
+
39
+ class DaisyChain:
40
+ DESCRIPTIONS = {
41
+ "eukaryote": "Eukaryotic genomic DNA",
42
+ "prokaryote": "Bacterial / prokaryotic DNA",
43
+ "mrna": "Mature mRNA (coding transcript)",
44
+ "mrna_splice": "Pre-mRNA / splice-site regions",
45
+ }
46
+
47
+ def __init__(self, root=HERE, device="cpu"):
48
+ self.dev = device
49
+ self.tok = SpikeTokenizer(vocab_file=os.path.join(root, "tokenizer.json"))
50
+ self.bos, self.eos = self.tok._vocab["<bos>"], self.tok._vocab["<eos>"]
51
+ self.models = {}
52
+ from safetensors.torch import load_file
53
+ for d in registry.ACTIVE:
54
+ ckpt = os.path.join(root, d, "model.safetensors")
55
+ if not os.path.exists(ckpt):
56
+ continue
57
+ cfg = generic_specialist_config(self.tok.vocab_size, position=registry.spec(d)["position"])
58
+ m = SpikeWhaleLM(cfg).to(device).eval()
59
+ sd = load_file(ckpt, device=device)
60
+ m.load_state_dict({k: (v.float() if v.is_floating_point() else v) for k, v in sd.items()})
61
+ for p in m.parameters():
62
+ p.requires_grad_(False)
63
+ self.models[d] = m
64
+ self.domains = list(self.models)
65
+ self.router2 = None
66
+ r2 = os.path.join(root, "router2.pt")
67
+ if os.path.exists(r2):
68
+ d = torch.load(r2, map_location="cpu")
69
+ if all(x in self.models for x in d["domains"]):
70
+ mlp = _RouterMLP(d["k"] + 4, d["h"]); mlp.load_state_dict(d["mlp"]); mlp.eval()
71
+ d["net"] = mlp; self.router2 = d
72
+
73
+ @torch.no_grad()
74
+ def _scores_hidden(self, seq):
75
+ ids = [self.bos] + self.tok.encode(clean(seq), add_special_tokens=False) + [self.eos]
76
+ t = torch.tensor([ids], device=self.dev)
77
+ scores, hids = {}, {}
78
+ for d, m in self.models.items():
79
+ hids[d] = m.model(input_ids=t)[0][0].mean(0)
80
+ scores[d] = float(m(input_ids=t, labels=t).loss)
81
+ return scores, hids
82
+
83
+ def surprise(self, seq):
84
+ """Per-specialist bits/base (lower = more 'at home')."""
85
+ s, _ = self._scores_hidden(seq)
86
+ return {d: s[d] / 6 / LN2 for d in self.domains}
87
+
88
+ @torch.no_grad()
89
+ def route(self, seq):
90
+ """Return (home_domain, bits_per_base_dict). Uses the learned MLP router."""
91
+ scores, hids = self._scores_hidden(seq)
92
+ bpb = {d: scores[d] / 6 / LN2 for d in self.domains}
93
+ if self.router2 is not None:
94
+ r = self.router2
95
+ hidden = torch.cat([hids[d] for d in r["domains"]])
96
+ bits = torch.tensor([scores[d] for d in r["domains"]])
97
+ z = (hidden - r["pca_mu"]) @ r["P"]
98
+ feat = ((torch.cat([z, bits]) - r["mu"]) / r["sd"])
99
+ best = r["domains"][int(r["net"](feat.unsqueeze(0)).argmax(1))]
100
+ else:
101
+ best = min(scores, key=scores.get)
102
+ return best, bpb
103
+
104
+ @torch.no_grad()
105
+ def generate_stream(self, domain, length=180, temperature=0.9, top_k=20, prompt=""):
106
+ """Yield the growing continuation base-by-base (for live streaming UIs)."""
107
+ m = self.models[domain]
108
+ ids = [self.bos] + (self.tok.encode(clean(prompt), add_special_tokens=False) if prompt else [])
109
+ t = torch.tensor([ids], device=self.dev)
110
+ bases = []
111
+ while sum(len(b) for b in bases) < length:
112
+ logits = m(input_ids=t).logits[:, -1, :] / max(temperature, 1e-6)
113
+ logits[:, :4] = -1e9
114
+ if top_k > 0:
115
+ v, _ = torch.topk(logits, top_k)
116
+ logits[logits < v[:, [-1]]] = -1e9
117
+ nxt = torch.multinomial(F.softmax(logits, dim=-1), 1)
118
+ t = torch.cat([t, nxt], dim=1)
119
+ bases.append(self.tok._ids_to_tokens[int(nxt)])
120
+ yield "".join(bases)[:length]
121
+
122
+ def generate(self, domain, length=180, temperature=0.9, top_k=20, prompt=""):
123
+ out = ""
124
+ for out in self.generate_stream(domain, length, temperature, top_k, prompt):
125
+ pass
126
+ return out
examples.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {"eukaryote": "CATCTTCTTTCCTCATCAATGTCTGTTCGAGCAAAAAGCAAAGTCTGCCTCATGTATGTTTCGGATCTGCGAACGACGTAAATCTTATTTCAGCTGTGAATAGAGTTCACGATGGCTGGGGTATTGCCGCAAAGAAAGGCTTAGACGGCAATGCCATCGAGGCTGCAGACACTACGAACATGGATAGCATCGCTAATGATCATTCTTTCCGCACCCTTCATGCCTCTGGAACTGCAGTGG", "prokaryote": "CGTGCCGCAGTGCCCCACCTTTTTGATGCGAAACAGATTGCGGACGATGTCCACGATGTCGTGCGAGGTGGGCCCGGCGGGTTTGTCGATGAGCAACGCGCCGTTGAGTTCGGATTCCGGTTGAGGATGGGGCATCAGACTTTTCCGTTGGCTTGGCGAAGGGCGGATTTTACCGCAGCGATGACCGCGCGTTGGGTGGCGAGTTGGCCGCCCTCAATGCGCGCGCCGGCGGCGGACATA", "mrna": "GATCAAAATGCCACCACAGGCACAAATTTAACCCAATCAACATTTCCCGCTTGCTAACTATTTCCGGAAAGTATGTGTCTTGCAACACAAATACAAAGTAACAGGCAAACTTGAATTAAAACCATACATAACGAAATCGTTCAGAAATCCATTTAAAATAAGCATAATAATGCATCTCAGGATCCTAGACTGTAAACTTAAAATTAATAGCCCATGCTATGGACAGCATAACAATAAAAT", "mrna_splice": "TTTTCTATAAAAAGTGAAATTATATTTTGCCCTTGTGAAATTGTGTTGATTGGTCCTGTAGTTTATGCACTGTAAAATGATATTGAACTTGCTTATGCATCTACTCTTTGACTGTGATTTGATTTGAAACTACACACTTGTAATGTAGGAACTCTATTCCTGAATTATTTTGCCACTTGAGTAGCTAGCTTATGACTTATGTTTTGTTCAGCAGTGTACAAGTATGCTAATGTGTCGATT"}
model.py ADDED
@@ -0,0 +1,1011 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ model.py -- SpikeWhaleLM: combined architecture from SpikeTransformer (My Project) + NanoWhale.
3
+
4
+ Architecture flow:
5
+ Embedding
6
+ -> Engram delta (N-gram memory, My Project)
7
+ -> [expand to hc_mult copies if HC enabled]
8
+ -> N x TransformerBlock:
9
+ HC pre-op (NanoWhale) -> RMSNorm -> MLA+DERF+XSA Attention (combined)
10
+ -> HC post-op
11
+ HC pre-op -> RMSNorm -> MoE FFN w/ shared expert (NanoWhale)
12
+ -> HC post-op
13
+ -> [mean-pool hc_mult copies if HC enabled]
14
+ -> RMSNorm
15
+ -> LM head + MTP heads (NanoWhale)
16
+
17
+ Component origins:
18
+ RMSNorm, RotaryEmbedding -- both (standard)
19
+ Engram / DERFContextGate -- My Project
20
+ MLADerfXSAAttention -- MLA from NanoWhale + DERF+XSA from My Project
21
+ SparseMoEFFN w/ shared expert -- NanoWhale MoE structure + My Project aux loss
22
+ HyperConnectionLayer -- NanoWhale
23
+ SpikeWhaleLM + MTP heads -- NanoWhale
24
+ """
25
+
26
+ import math
27
+ import torch
28
+ import torch.nn as nn
29
+ import torch.nn.functional as F
30
+ from typing import Optional, Tuple, List
31
+ from transformers import PreTrainedModel
32
+ from transformers.modeling_outputs import CausalLMOutputWithPast
33
+ from torch.utils.checkpoint import checkpoint as gradient_checkpoint
34
+
35
+ from config import SpikeWhaleConfig
36
+
37
+
38
+ # ---------------------------------------------------------------------------
39
+ # Primitives
40
+ # ---------------------------------------------------------------------------
41
+
42
+ class RMSNorm(nn.Module):
43
+ def __init__(self, dim: int, eps: float = 1e-6):
44
+ super().__init__()
45
+ self.eps = eps
46
+ self.weight = nn.Parameter(torch.ones(dim))
47
+
48
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
49
+ return x * torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps) * self.weight
50
+
51
+
52
+ class RotaryEmbedding(nn.Module):
53
+ """RoPE for the rope partition of Q and K (qk_rope_head_dim dims only)."""
54
+
55
+ def __init__(self, dim: int, max_positions: int = 4096, theta: float = 10000.0):
56
+ super().__init__()
57
+ inv_freq = 1.0 / (theta ** (torch.arange(0, dim, 2).float() / dim))
58
+ self.register_buffer("inv_freq", inv_freq)
59
+ t = torch.arange(max_positions).float()
60
+ freqs = torch.outer(t, inv_freq)
61
+ self.register_buffer("cos_cache", freqs.cos())
62
+ self.register_buffer("sin_cache", freqs.sin())
63
+
64
+ def forward(self, x: torch.Tensor, position_ids: torch.Tensor) -> torch.Tensor:
65
+ """
66
+ x: [B, H, S, rope_dim]
67
+ position_ids: [B, S]
68
+ """
69
+ cos = self.cos_cache[position_ids].unsqueeze(1) # [B, 1, S, rope_dim//2]
70
+ sin = self.sin_cache[position_ids].unsqueeze(1)
71
+ d = cos.shape[-1]
72
+ x1, x2 = x[..., :d], x[..., d:]
73
+ return torch.cat([x1 * cos - x2 * sin, x1 * sin + x2 * cos], dim=-1)
74
+
75
+
76
+ # ---------------------------------------------------------------------------
77
+ # Engram: N-gram hash lookup + DERF gate (My Project, preserved)
78
+ # ---------------------------------------------------------------------------
79
+
80
+ class TokenCompressor(nn.Module):
81
+ def __init__(self, embed_dim: int, compress_dim: int):
82
+ super().__init__()
83
+ self.proj = nn.Linear(embed_dim, compress_dim, bias=False)
84
+ nn.init.normal_(self.proj.weight, std=0.02)
85
+ # BUGFIX: this projection feeds ONLY the integer hash index
86
+ # (idx = h.abs().long() % table_size) in MultiHeadHashLookup. The .long()
87
+ # cast is non-differentiable, so no gradient ever reaches this weight --
88
+ # it can never learn. Worse, _classify_params put it in the weight-decay
89
+ # group, so AdamW was steadily shrinking it toward zero and degrading the
90
+ # hash projection over a long run. Freeze it: a fixed random projection is
91
+ # exactly the right behavior for an LSH-style hash, and freezing drops it
92
+ # from the optimizer (saves state) and from weight decay. Checkpoint-safe:
93
+ # the parameter still exists and is still saved/loaded in state_dict.
94
+ self.proj.weight.requires_grad_(False)
95
+
96
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
97
+ return self.proj(x)
98
+
99
+
100
+ class MultiHeadHashLookup(nn.Module):
101
+ def __init__(self, num_heads: int, table_size: int,
102
+ compress_dim: int, out_dim: int, max_ngram: int = 3):
103
+ super().__init__()
104
+ self.num_heads = num_heads
105
+ self.table_size = table_size
106
+ self.max_ngram = max_ngram
107
+ self.out_dim = out_dim
108
+
109
+ self.tables = nn.ModuleList([
110
+ nn.Embedding(table_size, out_dim) for _ in range(num_heads)
111
+ ])
112
+ for t in self.tables:
113
+ nn.init.normal_(t.weight, std=0.01)
114
+
115
+ for n in range(1, max_ngram + 1):
116
+ for k in range(n):
117
+ proj = torch.randn(num_heads, compress_dim)
118
+ proj = proj / (proj.norm(dim=1, keepdim=True) + 1e-8)
119
+ self.register_buffer(f"hash_proj_n{n}_p{k}", proj)
120
+
121
+ def forward(self, compressed: torch.Tensor) -> torch.Tensor:
122
+ """
123
+ compressed: [B, S, compress_dim]
124
+ returns: [B, S, out_dim]
125
+
126
+ All positions are processed in parallel. The outer loop runs max_ngram
127
+ times (≤3), not S times (≤2048). Each iteration is a single matmul +
128
+ embedding lookup across the whole sequence, making this GPU-friendly
129
+ and compatible with torch.compile.
130
+ """
131
+ B, S, _ = compressed.shape
132
+ device = compressed.device
133
+ out = torch.zeros(B, S, self.out_dim, device=device, dtype=compressed.dtype)
134
+ # Per-position normalization: tracks how many (n-gram × head) contributions
135
+ # each position receives. Positions near the start get fewer contributions
136
+ # because shorter n-grams don't exist yet (matches original causal behavior).
137
+ norm = torch.zeros(S, device=device)
138
+
139
+ for n in range(1, self.max_ngram + 1):
140
+ if S < n:
141
+ continue
142
+ valid_len = S - n + 1 # positions [n-1 .. S-1] are valid for order-n
143
+ start = n - 1
144
+
145
+ # Accumulate position-k contribution to the order-n hash.
146
+ # compressed[:, k : k+valid_len, :] is the k-th token of every n-gram
147
+ # window simultaneously → [B, valid_len, num_heads] after projection.
148
+ h = torch.zeros(B, valid_len, self.num_heads, device=device)
149
+ for k in range(n):
150
+ proj = getattr(self, f"hash_proj_n{n}_p{k}") # [num_heads, compress_dim]
151
+ h = h + torch.matmul(compressed[:, k:k + valid_len, :].float(), proj.t())
152
+
153
+ idx = h.abs().long() % self.table_size # [B, valid_len, num_heads]
154
+
155
+ for head_idx, table in enumerate(self.tables):
156
+ out[:, start:, :] = out[:, start:, :] + table(idx[:, :, head_idx])
157
+
158
+ norm[start:] += self.num_heads
159
+
160
+ # Cast back to input dtype: the norm division promotes bf16→float32 under autocast.
161
+ # Keeping the output in the same dtype as the input avoids a silent dtype mismatch
162
+ # when EngramModule adds this result back onto the (bf16) embedding tensor.
163
+ return (out / norm.view(1, -1, 1).clamp(min=1)).to(compressed.dtype)
164
+
165
+
166
+ class DERFContextGate(nn.Module):
167
+ """
168
+ DERF gate: gate = gamma * erf(alpha * proj([retrieved, x]) + bias)
169
+ Positive probability = (gate + 1) / 2 applied to retrieved embedding.
170
+ Large negative init_bias keeps gate closed at start of training.
171
+ """
172
+ def __init__(self, obs_size: int, init_bias: float = -4.0):
173
+ super().__init__()
174
+ self.proj = nn.Linear(obs_size * 2, obs_size)
175
+ self.alpha = nn.Parameter(torch.ones(obs_size))
176
+ self.bias = nn.Parameter(torch.full((obs_size,), init_bias))
177
+ self.gamma = nn.Parameter(torch.ones(obs_size))
178
+
179
+ def forward(self, retrieved: torch.Tensor, x: torch.Tensor) -> torch.Tensor:
180
+ logits = self.proj(torch.cat([retrieved, x], dim=-1))
181
+ gate = self.gamma * ((torch.erf(self.alpha * logits + self.bias) + 1.0) / 2.0)
182
+ return retrieved * gate
183
+
184
+
185
+ class EngramModule(nn.Module):
186
+ """
187
+ N-gram hash lookup with DERF gate (My Project), fully vectorized.
188
+ All S positions are processed in parallel — the sequential Python loop
189
+ over sequence positions has been eliminated. The lookup now accepts the
190
+ full [B, S, compress_dim] compressed tensor and returns [B, S, H] in one pass.
191
+ """
192
+ def __init__(self, cfg: SpikeWhaleConfig):
193
+ super().__init__()
194
+ self.compressor = TokenCompressor(cfg.hidden_size, cfg.engram_compress_dim)
195
+ self.lookup = MultiHeadHashLookup(
196
+ cfg.engram_num_heads, cfg.engram_table_size,
197
+ cfg.engram_compress_dim, cfg.hidden_size, cfg.engram_max_ngram,
198
+ )
199
+ self.gate = DERFContextGate(cfg.hidden_size, cfg.engram_gate_init_bias)
200
+
201
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
202
+ """x: [B, S, H] -> engram_delta: [B, S, H]"""
203
+ compressed = self.compressor(x.detach()) # [B, S, compress_dim]
204
+ retrieved = self.lookup(compressed) # [B, S, H]
205
+ return self.gate(retrieved, x) # [B, S, H]
206
+
207
+
208
+ # ---------------------------------------------------------------------------
209
+ # Hyper-Connections (NanoWhale, simplified)
210
+ # ---------------------------------------------------------------------------
211
+
212
+ class HyperConnectionLayer(nn.Module):
213
+ """
214
+ Simplified Hyper-Connections for one sublayer (attention or FFN).
215
+
216
+ Maintains hc_mult parallel residual streams.
217
+ Pre-op: learned weighted average of hc_mult copies -> single hidden state for sublayer.
218
+ Post-op: sublayer output added to each copy with learned per-stream weights.
219
+
220
+ Full HC uses Sinkhorn-normalized 2D routing matrices; this uses softmax-normalized
221
+ 1D weights for pre/post routing -- captures the same multi-stream routing spirit.
222
+ """
223
+ def __init__(self, hidden_size: int, hc_mult: int,
224
+ sinkhorn_iters: int = 20, eps: float = 1e-6):
225
+ super().__init__()
226
+ self.hc_mult = hc_mult
227
+ # pre_weight: how to mix hc_mult copies into one sublayer input
228
+ # post_weight: how to distribute the sublayer delta to each copy
229
+ #
230
+ # BUGFIX: these must NOT be initialized identically across streams.
231
+ # The model expands the hidden state into hc_mult *identical* copies.
232
+ # With uniform pre/post weights, pre_op produces sum_i copy_i * w_i =
233
+ # copy * sum(softmax)=copy (all copies equal), and post_op adds the same
234
+ # delta to every copy -- so the streams stay byte-for-byte identical at
235
+ # every layer. When all streams are equal, the softmax Jacobian applied
236
+ # to the (equal) per-stream gradients is exactly zero, so pre_weight and
237
+ # post_weight receive ZERO gradient and never move off 1/hc_mult. The HC
238
+ # routing then learns nothing and just burns hc_mult x memory/compute.
239
+ #
240
+ # Breaking the post_weight symmetry at init makes the streams diverge
241
+ # after the first sublayer, which restores gradient flow to all HC
242
+ # weights. We center post_weight so softmax starts near-uniform (keeps
243
+ # the residual baseline ~unchanged) but with a distinct value per stream.
244
+ self.pre_weight = nn.Parameter(
245
+ torch.linspace(0.5, -0.5, hc_mult) / max(hc_mult, 1)
246
+ )
247
+ self.post_weight = nn.Parameter(
248
+ torch.linspace(-0.5, 0.5, hc_mult) / max(hc_mult, 1)
249
+ )
250
+
251
+ def pre_op(self, copies: torch.Tensor) -> torch.Tensor:
252
+ """copies: [B, hc_mult, S, H] -> [B, S, H]"""
253
+ w = F.softmax(self.pre_weight, dim=0) # [hc_mult]
254
+ return (copies * w.view(1, -1, 1, 1)).sum(dim=1)
255
+
256
+ def post_op(self, copies: torch.Tensor, delta: torch.Tensor) -> torch.Tensor:
257
+ """
258
+ copies: [B, hc_mult, S, H]
259
+ delta: [B, S, H]
260
+ Returns updated copies: [B, hc_mult, S, H]
261
+ """
262
+ w = F.softmax(self.post_weight, dim=0) # [hc_mult]
263
+ return copies + delta.unsqueeze(1) * w.view(1, -1, 1, 1)
264
+
265
+
266
+ # ---------------------------------------------------------------------------
267
+ # MLA + DERF + XSA Attention (combined)
268
+ # ---------------------------------------------------------------------------
269
+
270
+ class MLADerfXSAAttention(nn.Module):
271
+ """
272
+ Multi-Head Latent Attention (NanoWhale) with DERF scores + XSA correction (My Project).
273
+
274
+ MLA (from NanoWhale):
275
+ Q: hidden -> q_lora_rank (RMSNorm) -> num_heads * head_dim (low-rank projection)
276
+ K, V: hidden -> num_kv_heads * head_dim (direct, MQA by default with num_kv_heads=1)
277
+ Output: num_heads * head_dim -> o_lora_rank -> hidden (low-rank output)
278
+ Partial RoPE: applied only to the last qk_rope_head_dim dims of Q and K
279
+
280
+ DERF (from My Project):
281
+ Replaces softmax: erf(alpha * scores + bias) * gamma, shifted to [0,1] then normalized.
282
+ Per-head learnable alpha, bias, gamma.
283
+
284
+ XSA (from My Project):
285
+ After computing the weighted value sum y, subtract the component of y that
286
+ projects onto each position's own value vector. Forces the output to carry
287
+ only cross-position information, not echo the current token back.
288
+ """
289
+
290
+ def __init__(self, cfg: SpikeWhaleConfig):
291
+ super().__init__()
292
+ self.num_heads = cfg.num_attention_heads
293
+ self.num_kv_heads = cfg.num_key_value_heads
294
+ self.head_dim = cfg.head_dim
295
+ self.qk_rope_head_dim = cfg.qk_rope_head_dim
296
+ self.nope_head_dim = cfg.nope_head_dim
297
+ self.hidden_size = cfg.hidden_size
298
+ self.use_derf = cfg.use_derf
299
+ self.use_xsa = cfg.use_xsa
300
+ self.dropout_p = cfg.attention_dropout
301
+ self.kv_groups = self.num_heads // self.num_kv_heads
302
+
303
+ # Low-rank Q projection (MLA)
304
+ self.q_a_proj = nn.Linear(cfg.hidden_size, cfg.q_lora_rank, bias=False)
305
+ self.q_a_norm = RMSNorm(cfg.q_lora_rank, cfg.rms_norm_eps)
306
+ self.q_b_proj = nn.Linear(cfg.q_lora_rank, self.num_heads * self.head_dim, bias=False)
307
+
308
+ # Direct K, V projections (MQA/GQA)
309
+ self.k_proj = nn.Linear(cfg.hidden_size, self.num_kv_heads * self.head_dim, bias=False)
310
+ self.v_proj = nn.Linear(cfg.hidden_size, self.num_kv_heads * self.head_dim, bias=False)
311
+
312
+ # Low-rank output projection (MLA)
313
+ self.o_a_proj = nn.Linear(self.num_heads * self.head_dim, cfg.o_lora_rank, bias=False)
314
+ self.o_b_proj = nn.Linear(cfg.o_lora_rank, cfg.hidden_size, bias=False)
315
+
316
+ # Partial RoPE: applied to qk_rope_head_dim dims only
317
+ self.rope = RotaryEmbedding(
318
+ self.qk_rope_head_dim,
319
+ max_positions=cfg.max_position_embeddings,
320
+ theta=cfg.rope_theta,
321
+ )
322
+
323
+ # DERF parameters: one per query head (My Project)
324
+ if self.use_derf:
325
+ self.derf_alpha = nn.Parameter(torch.ones(self.num_heads))
326
+ self.derf_bias = nn.Parameter(torch.zeros(self.num_heads))
327
+ self.derf_gamma = nn.Parameter(torch.ones(self.num_heads))
328
+
329
+ nn.init.normal_(self.q_a_proj.weight, std=cfg.initializer_range)
330
+ nn.init.normal_(self.q_b_proj.weight, std=cfg.initializer_range)
331
+ nn.init.normal_(self.k_proj.weight, std=cfg.initializer_range)
332
+ nn.init.normal_(self.v_proj.weight, std=cfg.initializer_range)
333
+ nn.init.normal_(self.o_a_proj.weight, std=cfg.initializer_range)
334
+ nn.init.normal_(self.o_b_proj.weight, std=cfg.initializer_range)
335
+
336
+ def forward(
337
+ self,
338
+ x: torch.Tensor,
339
+ position_ids: torch.Tensor,
340
+ attention_mask: Optional[torch.Tensor] = None,
341
+ past_key_value: Optional[Tuple[torch.Tensor, torch.Tensor]] = None,
342
+ use_cache: bool = False,
343
+ ) -> Tuple[torch.Tensor, Optional[Tuple[torch.Tensor, torch.Tensor]]]:
344
+ B, S, _ = x.shape
345
+
346
+ # Q via low-rank projection with intermediate norm (MLA)
347
+ q = self.q_a_norm(self.q_a_proj(x))
348
+ q = self.q_b_proj(q).view(B, S, self.num_heads, self.head_dim).transpose(1, 2)
349
+ # [B, num_heads, S, head_dim]
350
+
351
+ # K, V direct projections
352
+ k = self.k_proj(x).view(B, S, self.num_kv_heads, self.head_dim).transpose(1, 2)
353
+ v = self.v_proj(x).view(B, S, self.num_kv_heads, self.head_dim).transpose(1, 2)
354
+
355
+ # Partial RoPE: split into nope and rope partitions, rotate only the rope part
356
+ q_nope = q[..., :self.nope_head_dim]
357
+ q_rope = q[..., self.nope_head_dim:] # qk_rope_head_dim dims
358
+ k_nope = k[..., :self.nope_head_dim]
359
+ k_rope = k[..., self.nope_head_dim:]
360
+
361
+ q_rope = self.rope(q_rope, position_ids)
362
+ k_rope = self.rope(k_rope, position_ids)
363
+
364
+ q = torch.cat([q_nope, q_rope], dim=-1)
365
+ k = torch.cat([k_nope, k_rope], dim=-1)
366
+
367
+ # KV cache for inference
368
+ if past_key_value is not None:
369
+ k = torch.cat([past_key_value[0], k], dim=2)
370
+ v = torch.cat([past_key_value[1], v], dim=2)
371
+ present = (k, v) if use_cache else None
372
+ N = k.shape[2] # total key positions (past + current)
373
+
374
+ # Expand KV heads for MQA/GQA
375
+ if self.kv_groups > 1:
376
+ k = k.unsqueeze(2).expand(-1, -1, self.kv_groups, -1, -1).reshape(
377
+ B, self.num_heads, N, self.head_dim)
378
+ v = v.unsqueeze(2).expand(-1, -1, self.kv_groups, -1, -1).reshape(
379
+ B, self.num_heads, N, self.head_dim)
380
+
381
+ # Scaled dot-product attention.
382
+ if self.use_derf:
383
+ # DERF replaces softmax with a custom erf nonlinearity, so it cannot
384
+ # use the fused kernel and must materialize scores explicitly.
385
+ scores = torch.matmul(q, k.transpose(-2, -1)) / math.sqrt(self.head_dim)
386
+
387
+ # Build boolean mask for causality (this avoids the -inf math errors)
388
+ if attention_mask is None and past_key_value is None:
389
+ is_masked = torch.triu(torch.ones(S, N, dtype=torch.bool, device=scores.device), diagonal=N - S + 1).unsqueeze(0).unsqueeze(0)
390
+ else:
391
+ is_masked = (attention_mask < -1.0) if attention_mask is not None else torch.zeros_like(scores, dtype=torch.bool)
392
+
393
+ # FIX 2: Do NOT use float('-inf'). If alpha ever hits 0.0, 0.0 * -inf = NaN.
394
+ # Use a safe negative scalar (-10000.0) for masked positions.
395
+ safe_scores = scores.masked_fill(is_masked, -10000.0)
396
+
397
+ a = self.derf_alpha.view(1, -1, 1, 1)
398
+ b = self.derf_bias.view(1, -1, 1, 1)
399
+ g = self.derf_gamma.view(1, -1, 1, 1)
400
+
401
+ attn_weights = g * torch.erf(a * safe_scores + b) # [-gamma, gamma]
402
+ attn_weights = (attn_weights + g) / 2.0 # shift to [0, gamma]
403
+ attn_weights = attn_weights.masked_fill(is_masked, 0.0) # enforce causal mask safely
404
+ attn_weights = attn_weights / (attn_weights.sum(dim=-1, keepdim=True) + 1e-8)
405
+
406
+ if self.dropout_p > 0 and self.training:
407
+ attn_weights = F.dropout(attn_weights, p=self.dropout_p)
408
+
409
+ y = torch.matmul(attn_weights, v) # [B, num_heads, S, head_dim]
410
+ else:
411
+ # OPTIMIZATION: standard (softmax) attention goes through the fused
412
+ # scaled_dot_product_attention kernel (FlashAttention / mem-efficient
413
+ # backends). This is the hot path during pretraining (use_derf=False)
414
+ # and is much faster + lower memory than materializing [B,H,S,N]
415
+ # scores and a softmax. SDPA already scales by 1/sqrt(head_dim).
416
+ #
417
+ # CONTIGUITY FIX: with MQA/GQA, k and v above are built via
418
+ # .unsqueeze(2).expand(...).reshape(...). Under torch.compile, inductor
419
+ # can trace the broadcasted (zero-stride) view through to the fused
420
+ # flash-attention BACKWARD kernel, whose meta-kernel then asserts on the
421
+ # mismatched stride (e.g. "stride 120==245760 at dim=1") and aborts.
422
+ # Forcing contiguity guarantees standard strides into the fused kernel.
423
+ q = q.contiguous()
424
+ k = k.contiguous()
425
+ v = v.contiguous()
426
+ drop = self.dropout_p if self.training else 0.0
427
+ if past_key_value is None and attention_mask is None:
428
+ # Prefill / training: pure causal mask, no materialization needed.
429
+ y = F.scaled_dot_product_attention(q, k, v, is_causal=True, dropout_p=drop)
430
+ else:
431
+ # Incremental decode or a provided mask: pass an explicit boolean
432
+ # keep-mask (True = attend). SDPA fills masked positions with -inf.
433
+ if attention_mask is not None:
434
+ is_masked = (attention_mask < -1.0)
435
+ else:
436
+ is_masked = torch.triu(
437
+ torch.ones(S, N, dtype=torch.bool, device=q.device),
438
+ diagonal=N - S + 1,
439
+ ).unsqueeze(0).unsqueeze(0)
440
+ y = F.scaled_dot_product_attention(
441
+ q, k, v, attn_mask=~is_masked, dropout_p=drop)
442
+
443
+ # XSA: remove self-projection from output (My Project)
444
+ # For each query position s, subtract the component of y[:,:,s,:] that
445
+ # projects onto the normalized value vector at the same position.
446
+ if self.use_xsa:
447
+ past_len = N - S
448
+ v_self = v[:, :, past_len:past_len + S, :] # [B, H, S, D]
449
+ vn = v_self / (v_self.norm(dim=-1, keepdim=True) + 1e-8)
450
+ projection = (y * vn).sum(dim=-1, keepdim=True) * vn
451
+ y = y - projection
452
+
453
+ # Low-rank output projection (MLA)
454
+ y = y.transpose(1, 2).contiguous().view(B, S, self.num_heads * self.head_dim)
455
+ y = self.o_b_proj(self.o_a_proj(y))
456
+ return y, present
457
+
458
+
459
+ # ---------------------------------------------------------------------------
460
+ # MoE FFN: shared expert + sqrtsoftplus + hash routing (NanoWhale) + aux loss (My Project)
461
+ # ---------------------------------------------------------------------------
462
+
463
+ class ExpertFFN(nn.Module):
464
+ """Single SwiGLU expert."""
465
+ def __init__(self, hidden_size: int, intermediate_size: int):
466
+ super().__init__()
467
+ self.gate_proj = nn.Linear(hidden_size, intermediate_size, bias=False)
468
+ self.up_proj = nn.Linear(hidden_size, intermediate_size, bias=False)
469
+ self.down_proj = nn.Linear(intermediate_size, hidden_size, bias=False)
470
+
471
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
472
+ return self.down_proj(F.silu(self.gate_proj(x)) * self.up_proj(x))
473
+
474
+
475
+ def sqrtsoftplus(x: torch.Tensor) -> torch.Tensor:
476
+ """sqrt(softplus(x)) = sqrt(log(1+exp(x))). NanoWhale expert scoring."""
477
+ # FIX 1: Added 1e-8. If F.softplus(x) evaluates to 0.0, torch.sqrt(0) produces NaN gradients on backward pass.
478
+ return torch.sqrt(F.softplus(x) + 1e-8)
479
+
480
+
481
+ class SparseMoEFFN(nn.Module):
482
+ """
483
+ Combines NanoWhale MoE structure with My Project aux loss:
484
+ - n_shared_experts always-active experts (NanoWhale)
485
+ - n_routed_experts sparse routed experts, top-k activation
486
+ - sqrtsoftplus scoring (NanoWhale) vs softmax
487
+ - hash routing for early layers (NanoWhale)
488
+ - norm_topk_prob + routed_scaling_factor (NanoWhale)
489
+ - load-balancing aux loss (My Project)
490
+ """
491
+ def __init__(self, cfg: SpikeWhaleConfig, layer_idx: int = 0):
492
+ super().__init__()
493
+ self.n_routed_experts = cfg.n_routed_experts
494
+ self.n_shared_experts = cfg.n_shared_experts
495
+ self.num_experts_per_tok = cfg.num_experts_per_tok
496
+ self.norm_topk_prob = cfg.norm_topk_prob
497
+ self.scoring_func = cfg.scoring_func
498
+ self.routed_scaling_factor = cfg.routed_scaling_factor
499
+ self.use_hash_routing = layer_idx < cfg.num_hash_layers
500
+ self.aux_loss_coef = cfg.moe_aux_loss_coef
501
+
502
+ self.router = nn.Linear(cfg.hidden_size, cfg.n_routed_experts, bias=False)
503
+ self.experts = nn.ModuleList([
504
+ ExpertFFN(cfg.hidden_size, cfg.moe_intermediate_size)
505
+ for _ in range(cfg.n_routed_experts)
506
+ ])
507
+ self.shared_experts = nn.ModuleList([
508
+ ExpertFFN(cfg.hidden_size, cfg.moe_intermediate_size)
509
+ for _ in range(cfg.n_shared_experts)
510
+ ]) if cfg.n_shared_experts > 0 else None
511
+
512
+ self._last_aux_loss: Optional[torch.Tensor] = None
513
+
514
+ def forward(self, x: torch.Tensor, position_ids: Optional[torch.Tensor] = None) -> torch.Tensor:
515
+ B, S, H = x.shape
516
+ x_flat = x.view(B * S, H)
517
+ T = B * S
518
+
519
+ # Shared experts: always active (NanoWhale)
520
+ shared_out = torch.zeros_like(x_flat)
521
+ if self.shared_experts:
522
+ for expert in self.shared_experts:
523
+ shared_out = shared_out + expert(x_flat)
524
+ if len(self.shared_experts) > 1:
525
+ shared_out = shared_out / len(self.shared_experts)
526
+
527
+ # Router
528
+ if self.use_hash_routing:
529
+ # Hash routing: deterministic assignment without learned router (NanoWhale).
530
+ # Assign each of the num_experts_per_tok slots a DISTINCT expert by cycling:
531
+ # token at absolute position p -> experts [p%n, (p+1)%n, ..., (p+k-1)%n].
532
+ #
533
+ # BUGFIX: the assignment must key off the token's ABSOLUTE sequence
534
+ # position, not torch.arange(T) (its index in the current flattened
535
+ # batch). With arange(T), incremental KV-cache decoding (S=1) always
536
+ # sees index 0 and routes every token to expert 0, so generation used
537
+ # a different expert assignment than training and silently diverged.
538
+ # Using position_ids makes prefill, full-sequence training, and
539
+ # step-by-step generation all agree. (For S divisible by n_experts,
540
+ # this matches the previous training-time behavior exactly, so existing
541
+ # checkpoints stay valid.)
542
+ if position_ids is not None:
543
+ base = (position_ids.reshape(T, 1) % self.n_routed_experts).long()
544
+ else:
545
+ base = (torch.arange(T, device=x.device) % self.n_routed_experts).unsqueeze(1)
546
+ offsets = torch.arange(self.num_experts_per_tok, device=x.device) # [k]
547
+ top_k_indices = (base + offsets.unsqueeze(0)) % self.n_routed_experts # [T, k]
548
+ top_k_weights = torch.ones(T, self.num_experts_per_tok, device=x.device) / self.num_experts_per_tok
549
+ self._last_aux_loss = None
550
+ else:
551
+ router_logits = self.router(x_flat)
552
+
553
+ if self.scoring_func == "sqrtsoftplus":
554
+ routing_scores = sqrtsoftplus(router_logits)
555
+ else:
556
+ routing_scores = F.softmax(router_logits, dim=-1)
557
+
558
+ top_k_scores, top_k_indices = torch.topk(routing_scores, self.num_experts_per_tok, dim=-1)
559
+
560
+ if self.norm_topk_prob:
561
+ top_k_weights = top_k_scores / (top_k_scores.sum(dim=-1, keepdim=True) + 1e-8)
562
+ else:
563
+ top_k_weights = top_k_scores
564
+ top_k_weights = top_k_weights * self.routed_scaling_factor
565
+
566
+ # Load-balancing aux loss (My Project)
567
+ softmax_probs = F.softmax(router_logits, dim=-1)
568
+ expert_mask = torch.zeros_like(softmax_probs)
569
+ expert_mask.scatter_(1, top_k_indices, 1.0)
570
+ f_e = expert_mask.mean(0)
571
+ p_e = softmax_probs.mean(0)
572
+ self._last_aux_loss = self.n_routed_experts * (f_e * p_e).sum() * self.aux_loss_coef
573
+
574
+ # Dispatch tokens to routed experts
575
+ out = torch.zeros_like(x_flat)
576
+ for expert_idx, expert in enumerate(self.experts):
577
+ token_mask = (top_k_indices == expert_idx).any(dim=-1)
578
+ if not token_mask.any():
579
+ continue
580
+ expert_input = x_flat[token_mask]
581
+ expert_output = expert(expert_input)
582
+ k_pos = (top_k_indices[token_mask] == expert_idx).nonzero(as_tuple=False)
583
+ weights = top_k_weights[token_mask][k_pos[:, 0], k_pos[:, 1]].unsqueeze(-1)
584
+ out[token_mask] = out[token_mask] + expert_output * weights
585
+
586
+ out = out + shared_out
587
+ return out.view(B, S, H)
588
+
589
+ def get_aux_loss(self) -> Optional[torch.Tensor]:
590
+ # Return None when hash routing (no aux loss) or when forward hasn't run yet.
591
+ # Returning torch.tensor(0.0) here would be a CPU tensor and cause a device
592
+ # mismatch when added to the CUDA total_aux_loss in SpikeWhaleModel.
593
+ return self._last_aux_loss
594
+
595
+
596
+ class DenseFFN(nn.Module):
597
+ """Dense SwiGLU FFN for non-MoE layers."""
598
+ def __init__(self, cfg: SpikeWhaleConfig):
599
+ super().__init__()
600
+ self.gate_proj = nn.Linear(cfg.hidden_size, cfg.moe_intermediate_size, bias=False)
601
+ self.up_proj = nn.Linear(cfg.hidden_size, cfg.moe_intermediate_size, bias=False)
602
+ self.down_proj = nn.Linear(cfg.moe_intermediate_size, cfg.hidden_size, bias=False)
603
+
604
+ def forward(self, x: torch.Tensor, position_ids: Optional[torch.Tensor] = None) -> torch.Tensor:
605
+ return self.down_proj(F.silu(self.gate_proj(x)) * self.up_proj(x))
606
+
607
+ def get_aux_loss(self) -> Optional[torch.Tensor]:
608
+ return None # dense layers have no aux loss; None avoids CPU-tensor device mismatch
609
+
610
+
611
+ # ---------------------------------------------------------------------------
612
+ # Transformer block with Hyper-Connections
613
+ # ---------------------------------------------------------------------------
614
+
615
+ class TransformerBlock(nn.Module):
616
+ """
617
+ Transformer block combining all features:
618
+ - Hyper-Connections: pre/post routing through hc_mult streams (NanoWhale)
619
+ - MLA + DERF + XSA attention (combined)
620
+ - MoE FFN with shared expert (NanoWhale) + aux loss (My Project)
621
+ """
622
+ def __init__(self, cfg: SpikeWhaleConfig, layer_idx: int):
623
+ super().__init__()
624
+ self.use_hc = cfg.use_hyper_connections
625
+ self.hidden_dropout = cfg.hidden_dropout
626
+
627
+ self.attn_norm = RMSNorm(cfg.hidden_size, cfg.rms_norm_eps)
628
+ self.attn = MLADerfXSAAttention(cfg)
629
+ self.ffn_norm = RMSNorm(cfg.hidden_size, cfg.rms_norm_eps)
630
+
631
+ if cfg.use_moe and layer_idx in cfg.moe_layers:
632
+ self.ffn = SparseMoEFFN(cfg, layer_idx)
633
+ self.is_moe = True
634
+ else:
635
+ self.ffn = DenseFFN(cfg)
636
+ self.is_moe = False
637
+
638
+ if self.use_hc:
639
+ self.hc_attn = HyperConnectionLayer(cfg.hidden_size, cfg.hc_mult,
640
+ cfg.hc_sinkhorn_iters, cfg.hc_eps)
641
+ self.hc_ffn = HyperConnectionLayer(cfg.hidden_size, cfg.hc_mult,
642
+ cfg.hc_sinkhorn_iters, cfg.hc_eps)
643
+
644
+ def forward(
645
+ self,
646
+ x: torch.Tensor, # [B, hc_mult, S, H] if HC else [B, S, H]
647
+ position_ids: torch.Tensor,
648
+ attention_mask: Optional[torch.Tensor] = None,
649
+ past_key_value: Optional[Tuple] = None,
650
+ use_cache: bool = False,
651
+ ) -> Tuple[torch.Tensor, Optional[Tuple], Optional[torch.Tensor]]:
652
+
653
+ # --- Attention sub-layer ---
654
+ if self.use_hc:
655
+ h = self.hc_attn.pre_op(x) # [B, S, H]
656
+ else:
657
+ h = x
658
+
659
+ attn_out, present = self.attn(
660
+ self.attn_norm(h), position_ids, attention_mask, past_key_value, use_cache
661
+ )
662
+ attn_out = F.dropout(attn_out, p=self.hidden_dropout, training=self.training)
663
+
664
+ if self.use_hc:
665
+ x = self.hc_attn.post_op(x, attn_out)
666
+ h = self.hc_ffn.pre_op(x) # [B, S, H]
667
+ else:
668
+ h = h + attn_out
669
+
670
+ # --- FFN sub-layer ---
671
+ ffn_out = self.ffn(self.ffn_norm(h), position_ids)
672
+ ffn_out = F.dropout(ffn_out, p=self.hidden_dropout, training=self.training)
673
+
674
+ if self.use_hc:
675
+ x = self.hc_ffn.post_op(x, ffn_out)
676
+ else:
677
+ x = h + ffn_out
678
+
679
+ return x, present, self.ffn.get_aux_loss()
680
+
681
+
682
+ # ---------------------------------------------------------------------------
683
+ # Full model
684
+ # ---------------------------------------------------------------------------
685
+
686
+ class HRMRefinementBlock(nn.Module):
687
+ """
688
+ HRM-INSPIRED iterative refinement (EXPERIMENTAL, off by default). NOT the full
689
+ Hierarchical Reasoning Model -- only the iterative-refinement mechanism that the
690
+ independent ARC-Prize ablation found carried most of HRM's benefit, adapted to a
691
+ causal LM's final hidden state.
692
+
693
+ Runs N inner steps; each computes a small gated update conditioned on the current
694
+ state AND the original ('anchor') input. Per-step gate inits at 0 and up.weight is
695
+ zero-init -> the block is an EXACT identity at init, so enabling it cannot hurt a
696
+ fresh model; it only contributes if training opens the gate. Pointwise over
697
+ positions -> causal-safe (no future-token leakage). In/out [B,S,H].
698
+ """
699
+ def __init__(self, hidden_size: int, refine_dim: int, steps: int, eps: float = 1e-6):
700
+ super().__init__()
701
+ self.steps = steps
702
+ self.norm = RMSNorm(hidden_size, eps)
703
+ self.down = nn.Linear(hidden_size * 2, refine_dim, bias=False)
704
+ self.up = nn.Linear(refine_dim, hidden_size, bias=False)
705
+ self.gate = nn.Parameter(torch.zeros(steps))
706
+ nn.init.normal_(self.down.weight, std=0.02)
707
+ nn.init.zeros_(self.up.weight)
708
+
709
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
710
+ anchor = x
711
+ h = x
712
+ for t in range(self.steps):
713
+ inp = torch.cat([self.norm(h), anchor], dim=-1)
714
+ update = self.up(F.silu(self.down(inp)))
715
+ h = h + torch.tanh(self.gate[t]) * update
716
+ return h
717
+
718
+
719
+ class LatentProjection(nn.Module):
720
+ """ModularMind-on-V2: pool final hidden state -> d_latent output vector.
721
+ Mirrors ModularMind's contract: mean-pool over sequence, ReLU^2 activation
722
+ (sparse latent codes), Xavier init (NOT zero) so the latent carries signal
723
+ from step 1 — zero-init would make the chain unable to bootstrap."""
724
+ def __init__(self, hidden_size: int, d_latent: int, eps: float = 1e-6):
725
+ super().__init__()
726
+ self.proj1 = nn.Linear(hidden_size, hidden_size, bias=False)
727
+ self.proj2 = nn.Linear(hidden_size, d_latent, bias=False)
728
+ self.norm = RMSNorm(d_latent, eps)
729
+ nn.init.xavier_uniform_(self.proj1.weight)
730
+ nn.init.xavier_uniform_(self.proj2.weight)
731
+
732
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
733
+ pooled = x.mean(dim=1) # [B, S, H] -> [B, H]
734
+ h = torch.relu(self.proj1(pooled)) ** 2
735
+ return self.norm(self.proj2(h)) # [B, d_latent]
736
+
737
+
738
+ class LatentInjection(nn.Module):
739
+ """ModularMind-on-V2: fold an incoming d_latent vector into embeddings.
740
+ Broadcast across positions, ReGLU-gated add. Gate starts SMALL (not exactly
741
+ zero): the injection is near-identity at init (stable) while still passing a
742
+ little gradient, so the upstream RecursiveLink + specialist can bootstrap from
743
+ step 1. (Exact-zero gate would block all gradient to the link -- the
744
+ bootstrapping problem ModularMind's LatentProjection docstring warns about.)
745
+ This is the INPUT side of RecursiveLink (the prev specialist's latent)."""
746
+ def __init__(self, hidden_size: int, d_latent: int, eps: float = 1e-6,
747
+ gate_init: float = 1e-3):
748
+ super().__init__()
749
+ self.up = nn.Linear(d_latent, hidden_size, bias=False)
750
+ self.norm = RMSNorm(hidden_size, eps)
751
+ self.value_proj = nn.Linear(hidden_size, hidden_size, bias=False)
752
+ self.gate_proj = nn.Linear(hidden_size, hidden_size, bias=False)
753
+ self.gate_init = gate_init
754
+ nn.init.xavier_uniform_(self.up.weight)
755
+ nn.init.xavier_uniform_(self.value_proj.weight)
756
+ nn.init.normal_(self.gate_proj.weight, std=gate_init) # small, not zero
757
+
758
+ def forward(self, x: torch.Tensor, latent: torch.Tensor) -> torch.Tensor:
759
+ # x: [B, S, H], latent: [B, d_latent]
760
+ inj = self.norm(self.up(latent)).unsqueeze(1) # [B, 1, H] broadcast over S
761
+ value = self.value_proj(inj)
762
+ gate = torch.relu(self.gate_proj(inj))
763
+ return x + value * gate
764
+
765
+
766
+ class RecursiveLink(nn.Module):
767
+ """ModularMind cross-specialist bridge, V2 build. Converts one specialist's
768
+ output latent into the next specialist's input latent. ReGLU + residual,
769
+ single shared module reused for every hop. Fully differentiable."""
770
+ def __init__(self, d_latent: int = 256, expansion: float = 2.0):
771
+ super().__init__()
772
+ d_hidden = int(d_latent * expansion)
773
+ self.norm = nn.LayerNorm(d_latent)
774
+ self.value_proj = nn.Linear(d_latent, d_hidden, bias=False)
775
+ self.gate_proj = nn.Linear(d_latent, d_hidden, bias=False)
776
+ self.down = nn.Linear(d_hidden, d_latent, bias=False)
777
+ self.residual_gate = nn.Parameter(torch.ones(1))
778
+ nn.init.xavier_uniform_(self.value_proj.weight)
779
+ nn.init.xavier_uniform_(self.gate_proj.weight)
780
+ nn.init.xavier_uniform_(self.down.weight)
781
+
782
+ def forward(self, z: torch.Tensor) -> torch.Tensor:
783
+ n = self.norm(z)
784
+ h = self.value_proj(n) * torch.relu(self.gate_proj(n))
785
+ return z + self.residual_gate * self.down(h)
786
+
787
+
788
+ class SpikeWhaleModel(nn.Module):
789
+ """Decoder stack without LM head."""
790
+
791
+ def __init__(self, cfg: SpikeWhaleConfig):
792
+ super().__init__()
793
+ self.cfg = cfg
794
+ self.embed_tokens = nn.Embedding(cfg.vocab_size, cfg.hidden_size)
795
+ nn.init.normal_(self.embed_tokens.weight, std=cfg.initializer_range)
796
+
797
+ self.engram = EngramModule(cfg) if cfg.use_engram else None
798
+ self.layers = nn.ModuleList([
799
+ TransformerBlock(cfg, layer_idx=i)
800
+ for i in range(cfg.num_hidden_layers)
801
+ ])
802
+ self.norm = RMSNorm(cfg.hidden_size, cfg.rms_norm_eps)
803
+ self.hrm_refine = (
804
+ HRMRefinementBlock(cfg.hidden_size, cfg.hrm_refine_dim,
805
+ cfg.hrm_refine_steps, cfg.rms_norm_eps)
806
+ if getattr(cfg, "use_hrm_refine", False) else None
807
+ )
808
+ # ModularMind-on-V2: latent input/output (off unless use_latent_io)
809
+ if getattr(cfg, "use_latent_io", False):
810
+ self.latent_inject = LatentInjection(cfg.hidden_size, cfg.d_latent, cfg.rms_norm_eps)
811
+ self.latent_out = LatentProjection(cfg.hidden_size, cfg.d_latent, cfg.rms_norm_eps)
812
+ else:
813
+ self.latent_inject = None
814
+ self.latent_out = None
815
+ self.gradient_checkpointing = False
816
+
817
+ def reset_latent_gate(self):
818
+ """Re-init the injection gate SMALL (not zero). Must be called AFTER any HF
819
+ post_init/_init_weights pass, which otherwise re-randomizes the gate to full
820
+ scale. Small-but-nonzero keeps injection near-identity at start while letting
821
+ gradient reach the upstream RecursiveLink (so the chain can bootstrap)."""
822
+ if self.latent_inject is not None:
823
+ nn.init.normal_(self.latent_inject.gate_proj.weight,
824
+ std=self.latent_inject.gate_init)
825
+
826
+ def forward(
827
+ self,
828
+ input_ids: torch.Tensor,
829
+ attention_mask: Optional[torch.Tensor] = None,
830
+ position_ids: Optional[torch.Tensor] = None,
831
+ past_key_values: Optional[List[Tuple]] = None,
832
+ use_cache: bool = False,
833
+ inject_latent: Optional[torch.Tensor] = None,
834
+ ) -> Tuple[torch.Tensor, Optional[List[Tuple]], torch.Tensor]:
835
+ B, S = input_ids.shape
836
+ device = input_ids.device
837
+
838
+ if position_ids is None:
839
+ past_len = past_key_values[0][0].shape[2] if past_key_values else 0
840
+ position_ids = torch.arange(
841
+ past_len, past_len + S, device=device
842
+ ).unsqueeze(0).expand(B, -1)
843
+
844
+ # Token embedding
845
+ x = self.embed_tokens(input_ids) # [B, S, H]
846
+
847
+ # Engram N-gram delta (My Project)
848
+ if self.engram is not None:
849
+ x = x + self.engram(x)
850
+
851
+ # ModularMind-on-V2: inject the previous specialist's latent (broadcast
852
+ # across positions, ReGLU-gated). No-op at init (gate zero) and skipped
853
+ # entirely if no latent is passed.
854
+ if self.latent_inject is not None and inject_latent is not None:
855
+ x = self.latent_inject(x, inject_latent)
856
+
857
+ # Expand to hc_mult streams for Hyper-Connections (NanoWhale)
858
+ if self.cfg.use_hyper_connections:
859
+ x = x.unsqueeze(1).expand(-1, self.cfg.hc_mult, -1, -1).clone()
860
+ # [B, hc_mult, S, H]
861
+
862
+ present_key_values = [] if use_cache else None
863
+ total_aux_loss = torch.tensor(0.0, device=device)
864
+
865
+ for layer_idx, layer in enumerate(self.layers):
866
+ pkv = past_key_values[layer_idx] if past_key_values else None
867
+
868
+ if self.gradient_checkpointing and self.training:
869
+ # Gradient checkpointing with use_reentrant=False (NanoWhale)
870
+ x, present, aux_loss = gradient_checkpoint(
871
+ layer, x, position_ids, attention_mask, None, False,
872
+ use_reentrant=False,
873
+ )
874
+ else:
875
+ x, present, aux_loss = layer(x, position_ids, attention_mask, pkv, use_cache)
876
+
877
+ if use_cache:
878
+ present_key_values.append(present)
879
+ if aux_loss is not None:
880
+ total_aux_loss = total_aux_loss + aux_loss
881
+
882
+ # Reduce HC streams to single hidden state
883
+ if self.cfg.use_hyper_connections:
884
+ x = x.mean(dim=1) # [B, S, H]
885
+
886
+ if self.hrm_refine is not None:
887
+ x = self.hrm_refine(x)
888
+
889
+ x = self.norm(x)
890
+
891
+ # ModularMind-on-V2: emit this specialist's output latent (for RecursiveLink).
892
+ out_latent = self.latent_out(x) if self.latent_out is not None else None
893
+ return x, present_key_values, total_aux_loss, out_latent
894
+
895
+
896
+ class SpikeWhaleLM(PreTrainedModel):
897
+ """
898
+ Full causal LM combining all SpikeTransformer + NanoWhale features.
899
+
900
+ Training (forward with labels):
901
+ out = model(input_ids=ids, labels=ids)
902
+ loss = out.loss # CE + MTP loss + MoE aux loss
903
+
904
+ Generation:
905
+ out = model(input_ids=ids, use_cache=True)
906
+ past = out.past_key_values
907
+ out2 = model(input_ids=next_id, past_key_values=past, use_cache=True)
908
+ """
909
+ config_class = SpikeWhaleConfig
910
+ base_model_prefix = "model"
911
+ supports_gradient_checkpointing = True
912
+ _no_split_modules = ["TransformerBlock"]
913
+
914
+ def __init__(self, cfg: SpikeWhaleConfig):
915
+ super().__init__(cfg)
916
+ self.model = SpikeWhaleModel(cfg)
917
+ self.lm_head = nn.Linear(cfg.hidden_size, cfg.vocab_size, bias=False)
918
+ nn.init.normal_(self.lm_head.weight, std=cfg.initializer_range)
919
+
920
+ if cfg.tie_word_embeddings:
921
+ self.lm_head.weight = self.model.embed_tokens.weight
922
+
923
+ # Multi-Token Prediction heads (NanoWhale): predict token at position+k
924
+ self.mtp_heads = nn.ModuleList([
925
+ nn.Linear(cfg.hidden_size, cfg.vocab_size, bias=False)
926
+ for _ in range(cfg.num_nextn_predict_layers)
927
+ ]) if cfg.num_nextn_predict_layers > 0 else None
928
+
929
+ self.post_init()
930
+ # HF post_init re-randomizes Linear weights, clobbering the zero-init
931
+ # injection gate. Restore it so the latent injection is identity-at-start.
932
+ self.model.reset_latent_gate()
933
+
934
+ def get_input_embeddings(self):
935
+ return self.model.embed_tokens
936
+
937
+ def set_input_embeddings(self, value):
938
+ self.model.embed_tokens = value
939
+
940
+ def get_output_embeddings(self):
941
+ return self.lm_head
942
+
943
+ def set_output_embeddings(self, new_embeddings):
944
+ self.lm_head = new_embeddings
945
+
946
+ def _set_gradient_checkpointing(self, module, value=False):
947
+ if isinstance(module, SpikeWhaleModel):
948
+ module.gradient_checkpointing = value
949
+
950
+ def forward(
951
+ self,
952
+ input_ids: Optional[torch.Tensor] = None,
953
+ attention_mask: Optional[torch.Tensor] = None,
954
+ position_ids: Optional[torch.Tensor] = None,
955
+ past_key_values: Optional[List[Tuple]] = None,
956
+ labels: Optional[torch.Tensor] = None,
957
+ use_cache: bool = False,
958
+ inject_latent: Optional[torch.Tensor] = None,
959
+ **kwargs,
960
+ ) -> CausalLMOutputWithPast:
961
+ hidden, present_kvs, aux_loss, out_latent = self.model(
962
+ input_ids=input_ids,
963
+ attention_mask=attention_mask,
964
+ position_ids=position_ids,
965
+ past_key_values=past_key_values,
966
+ use_cache=use_cache,
967
+ inject_latent=inject_latent,
968
+ )
969
+
970
+ logits = self.lm_head(hidden)
971
+ loss = None
972
+
973
+ if labels is not None:
974
+ # Standard next-token CE loss (shifted by 1)
975
+ shift_logits = logits[..., :-1, :].contiguous()
976
+ shift_labels = labels[..., 1:].contiguous()
977
+ loss = F.cross_entropy(
978
+ shift_logits.view(-1, shift_logits.size(-1)),
979
+ shift_labels.view(-1),
980
+ ignore_index=-100,
981
+ )
982
+
983
+ # Multi-Token Prediction loss (NanoWhale)
984
+ # Each MTP head k predicts token at position + k+1 (beyond the standard +1)
985
+ if self.mtp_heads is not None:
986
+ mtp_total = torch.tensor(0.0, device=loss.device)
987
+ for k, head in enumerate(self.mtp_heads, start=1):
988
+ offset = k + 1 # predicts position + offset
989
+ if hidden.size(1) > offset:
990
+ mtp_logits = head(hidden[..., :-offset, :].contiguous())
991
+ mtp_labels = labels[..., offset:].contiguous()
992
+ mtp_total = mtp_total + F.cross_entropy(
993
+ mtp_logits.view(-1, mtp_logits.size(-1)),
994
+ mtp_labels.view(-1),
995
+ ignore_index=-100,
996
+ )
997
+ loss = loss + mtp_total / max(len(self.mtp_heads), 1)
998
+
999
+ # MoE load-balancing aux loss (My Project)
1000
+ loss = loss + aux_loss
1001
+
1002
+ out = CausalLMOutputWithPast(
1003
+ loss=loss,
1004
+ logits=logits,
1005
+ past_key_values=present_kvs,
1006
+ )
1007
+ out.latent = out_latent # ModularMind-on-V2: this specialist's output latent
1008
+ return out
1009
+
1010
+ def count_parameters(self) -> int:
1011
+ return sum(p.numel() for p in self.parameters())
registry.py ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ registry.py -- SINGLE SOURCE OF TRUTH for the GENOMIC specialists.
3
+
4
+ The Carbon analogue of agents/modmind/registry.py. Each entry is one mini
5
+ specialist trained on PURE domain data from HuggingFaceBio/carbon-pretraining-corpus
6
+ (the same corpus the 500M / 3B / 8B Carbon models were pretrained on).
7
+
8
+ The pitch: 4 dense ~80M DNA/RNA specialists (~320M total) + a zero-param
9
+ orchestrator < Carbon-500M on parameter count, while keeping per-domain
10
+ specialization crisp (one model never sees another domain's bases).
11
+
12
+ All specialists share ONE tokenizer (genomics/tokenizer.json), a Carbon-style
13
+ 6-mer + single-base "length-max" vocab, so their latents live in the same space
14
+ and the RecursiveLink bridge / orchestrator can compare them directly.
15
+
16
+ To add a domain: add ONE entry here, then
17
+ python genomics/build_tokenizer.py # (only once; shared vocab)
18
+ python genomics/train_specialist.py --domain <name>
19
+ """
20
+
21
+ # Carbon corpus subsets -> mini specialists.
22
+ # `config` : the dataset config (subset) name on the Hub
23
+ # `field` : which column holds the sequence string (eukaryote uses `sequence`,
24
+ # the evo2 subsets use `text`)
25
+ # `molecule`: DNA or RNA -- metadata only (same ACGT/ACGU vocab, U folded to T)
26
+ # `position`: chain slot (context-doubling order in the V2 config)
27
+ DATASET = "HuggingFaceBio/carbon-pretraining-corpus"
28
+
29
+ SPECIALISTS = {
30
+ "eukaryote": dict(config="eukaryote_generator_10B_subset", field="sequence",
31
+ molecule="DNA", vocab=4105, position=0),
32
+ "prokaryote": dict(config="prokaryote_evo2", field="text",
33
+ molecule="DNA", vocab=4105, position=1),
34
+ "mrna": dict(config="mrna_evo2", field="text",
35
+ molecule="RNA", vocab=4105, position=2),
36
+ "mrna_splice": dict(config="mrna_splice_evo2", field="text",
37
+ molecule="RNA", vocab=4105, position=3),
38
+ }
39
+
40
+ # The specialists we are actively training (the genomic "foundation" set).
41
+ ACTIVE = ["eukaryote", "prokaryote", "mrna", "mrna_splice"]
42
+
43
+
44
+ def spec(name):
45
+ if name not in SPECIALISTS:
46
+ raise KeyError(f"unknown genomic specialist {name!r}; add it to "
47
+ f"registry.SPECIALISTS. known: {list(SPECIALISTS)}")
48
+ return SPECIALISTS[name]
49
+
50
+
51
+ def text_of(name_or_spec, ex):
52
+ """Extract the raw sequence string from a streamed example."""
53
+ s = name_or_spec if isinstance(name_or_spec, dict) else spec(name_or_spec)
54
+ return ex.get(s["field"], "") or ""
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ torch>=2.2
2
+ transformers>=4.44
3
+ safetensors>=0.4
4
+ gradio>=4.44
5
+ huggingface_hub>=0.24
6
+ numpy
router2.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:7cfd733ed1b0903382cfc10491fd00624aec5fbbd5f7c14f3c523b07fa655885
3
+ size 26246784
specialist_presets.py ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ specialist_presets.py -- ModularMind-on-V2 specialist sizing.
3
+
4
+ DENSE ~80M specialists (Supra-50M-style, scaled up): a dense Llama-ish transformer with
5
+ NO MoE / Engram / Hyper-Connections / HRM, so the parameters go into language modeling
6
+ instead of machinery -> coherent generation (the lesson from SupraLabs/Supra-50M-Base,
7
+ a dense model that produces coherent multi-paragraph text on FineWeb-Edu).
8
+
9
+ Shape (shared across domains; only the vocab differs, read from registry.py):
10
+ hidden 640, 16 layers, 10 heads / 5 KV (GQA), dense FFN 1728, ctx 1024, d_latent 256.
11
+ -> ~81.5M params at vocab 16384 (the shared length-max tokenizer).
12
+
13
+ The bridge bus (d_latent=256) and latent IO are kept, so train_link.py / the Gradio
14
+ adapter still work after retraining.
15
+ """
16
+ from config import SpikeWhaleConfig
17
+ from registry import spec
18
+
19
+
20
+ def _dense_80m(vocab_size: int) -> SpikeWhaleConfig:
21
+ """A dense ~80M specialist for the given vocab."""
22
+ return SpikeWhaleConfig(
23
+ vocab_size=vocab_size,
24
+ hidden_size=640,
25
+ num_hidden_layers=16,
26
+ num_attention_heads=10,
27
+ num_key_value_heads=5, # GQA
28
+ head_dim=64,
29
+ qk_rope_head_dim=16,
30
+ q_lora_rank=320,
31
+ o_lora_rank=160,
32
+ tie_word_embeddings=True,
33
+ # DENSE: no MoE. moe_intermediate_size still sizes the DenseFFN (model.py).
34
+ use_moe=False,
35
+ moe_intermediate_size=1728,
36
+ # strip the heavy extras -> params go to the LM, not machinery
37
+ use_engram=False,
38
+ use_hyper_connections=False,
39
+ hc_mult=1,
40
+ use_hrm_refine=False,
41
+ num_nextn_predict_layers=0,
42
+ use_derf=False,
43
+ use_xsa=True,
44
+ # keep the ModularMind bridge bus so train_link.py / the adapter still work
45
+ use_latent_io=True,
46
+ d_latent=256,
47
+ # uniform 1024 context (Supra used 1024). base_context MUST be >= training --seq-len.
48
+ chain_position=0,
49
+ base_context=4096,
50
+ base_rope_theta=10000.0,
51
+ )
52
+
53
+
54
+ def specialist_config(domain: str = "language", position: int = 0) -> SpikeWhaleConfig:
55
+ """A dense ~80M specialist; vocab comes from registry.py (single source of truth)."""
56
+ return _dense_80m(spec(domain)["vocab"])
57
+
58
+
59
+ def generic_specialist_config(vocab_size: int, position: int = 0) -> SpikeWhaleConfig:
60
+ """Same dense ~80M shape for an arbitrary vocab (new domains 'just work')."""
61
+ return _dense_80m(vocab_size)
62
+
63
+
64
+ # Foundation chain ordering (derived from the registry, so it grows automatically)
65
+ try:
66
+ from registry import SPECIALISTS as _REG
67
+ FOUNDATION_ORDER = {v["position"]: k for k, v in _REG.items()}
68
+ except Exception:
69
+ FOUNDATION_ORDER = {0: "language", 1: "reasoning", 2: "tool_use"}
spike_tokenizer.py ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ spike_tokenizer.py -- HuggingFace-compatible wrapper for the custom
3
+ byte-level "length-max" (greedy longest-match) tokenizer in tokenizer.json.
4
+
5
+ The raw tokenizer.json is NOT a HuggingFace `tokenizers` file; it is a plain
6
+ dict {vocab, vocab_size, max_token_len, algorithm:"length-max"}. This wrapper
7
+ makes it loadable by AutoTokenizer.from_pretrained / save_pretrained and
8
+ exposes encode/decode + the bos/eos/pad/unk ids the training scripts expect.
9
+
10
+ Encoding scheme (verified): byte-level. Text is UTF-8 encoded, each byte mapped
11
+ to its latin-1 character, then greedily matched against the vocab using the
12
+ longest key that matches at each position (max key length = max_token_len).
13
+ """
14
+ import json, os
15
+ from typing import List, Optional
16
+ from transformers import PreTrainedTokenizer
17
+
18
+
19
+ class SpikeTokenizer(PreTrainedTokenizer):
20
+ vocab_files_names = {"vocab_file": "tokenizer.json"}
21
+ model_input_names = ["input_ids"]
22
+
23
+ def __init__(self, vocab_file=None, **kwargs):
24
+ with open(vocab_file, "r", encoding="utf-8") as f:
25
+ data = json.load(f)
26
+ self._vocab = data["vocab"] # str -> id
27
+ self._ids_to_tokens = {i: t for t, i in self._vocab.items()}
28
+ self.max_token_len = int(data.get("max_token_len", 24))
29
+ # length-bucketed keys for fast greedy match (longest length first)
30
+ self._lengths = sorted({len(k) for k in self._vocab}, reverse=True)
31
+
32
+ kwargs.setdefault("bos_token", "<bos>")
33
+ kwargs.setdefault("eos_token", "<eos>")
34
+ kwargs.setdefault("unk_token", "<unk>")
35
+ kwargs.setdefault("pad_token", "<pad>")
36
+ super().__init__(**kwargs)
37
+
38
+ @property
39
+ def vocab_size(self) -> int:
40
+ return len(self._vocab)
41
+
42
+ def get_vocab(self):
43
+ return dict(self._vocab)
44
+
45
+ # --- core byte-level greedy tokenization ---
46
+ def _tokenize(self, text: str) -> List[str]:
47
+ s = text.encode("utf-8").decode("latin-1") # one char per byte
48
+ out, i, n = [], 0, len(s)
49
+ while i < n:
50
+ matched = None
51
+ hi = min(self.max_token_len, n - i)
52
+ for L in range(hi, 0, -1):
53
+ sub = s[i:i + L]
54
+ if sub in self._vocab:
55
+ matched = sub
56
+ break
57
+ if matched is None: # single byte always exists in vocab
58
+ matched = s[i]
59
+ out.append(matched)
60
+ i += len(matched)
61
+ return out
62
+
63
+ def _convert_token_to_id(self, token: str) -> int:
64
+ return self._vocab.get(token, self._vocab["<unk>"])
65
+
66
+ def _convert_id_to_token(self, index: int) -> str:
67
+ return self._ids_to_tokens.get(index, "<unk>")
68
+
69
+ def convert_tokens_to_string(self, tokens: List[str]) -> str:
70
+ specials = {"<pad>", "<unk>", "<bos>", "<eos>"}
71
+ byte_str = "".join(t for t in tokens if t not in specials)
72
+ return byte_str.encode("latin-1").decode("utf-8", errors="replace")
73
+
74
+ def save_vocabulary(self, save_directory: str, filename_prefix: Optional[str] = None):
75
+ os.makedirs(save_directory, exist_ok=True)
76
+ fn = (filename_prefix + "-" if filename_prefix else "") + "tokenizer.json"
77
+ path = os.path.join(save_directory, fn)
78
+ with open(path, "w", encoding="utf-8") as f:
79
+ json.dump({"vocab": self._vocab, "vocab_size": self.vocab_size,
80
+ "max_token_len": self.max_token_len,
81
+ "algorithm": "length-max"}, f, ensure_ascii=False)
82
+ return (path,)
tokenizer.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {"vocab": {"<bos>": 0, "<eos>": 1, "<pad>": 2, "<unk>": 3, "A": 4, "C": 5, "G": 6, "T": 7, "N": 8, "AAAAAA": 9, "AAAAAC": 10, "AAAAAG": 11, "AAAAAT": 12, "AAAACA": 13, "AAAACC": 14, "AAAACG": 15, "AAAACT": 16, "AAAAGA": 17, "AAAAGC": 18, "AAAAGG": 19, "AAAAGT": 20, "AAAATA": 21, "AAAATC": 22, "AAAATG": 23, "AAAATT": 24, "AAACAA": 25, "AAACAC": 26, "AAACAG": 27, "AAACAT": 28, "AAACCA": 29, "AAACCC": 30, "AAACCG": 31, "AAACCT": 32, "AAACGA": 33, "AAACGC": 34, "AAACGG": 35, "AAACGT": 36, "AAACTA": 37, "AAACTC": 38, "AAACTG": 39, "AAACTT": 40, "AAAGAA": 41, "AAAGAC": 42, "AAAGAG": 43, "AAAGAT": 44, "AAAGCA": 45, "AAAGCC": 46, "AAAGCG": 47, "AAAGCT": 48, "AAAGGA": 49, "AAAGGC": 50, "AAAGGG": 51, "AAAGGT": 52, "AAAGTA": 53, "AAAGTC": 54, "AAAGTG": 55, "AAAGTT": 56, "AAATAA": 57, "AAATAC": 58, "AAATAG": 59, "AAATAT": 60, "AAATCA": 61, "AAATCC": 62, "AAATCG": 63, "AAATCT": 64, "AAATGA": 65, "AAATGC": 66, "AAATGG": 67, "AAATGT": 68, "AAATTA": 69, "AAATTC": 70, "AAATTG": 71, "AAATTT": 72, "AACAAA": 73, "AACAAC": 74, "AACAAG": 75, "AACAAT": 76, "AACACA": 77, "AACACC": 78, "AACACG": 79, "AACACT": 80, "AACAGA": 81, "AACAGC": 82, "AACAGG": 83, "AACAGT": 84, "AACATA": 85, "AACATC": 86, "AACATG": 87, "AACATT": 88, "AACCAA": 89, "AACCAC": 90, "AACCAG": 91, "AACCAT": 92, "AACCCA": 93, "AACCCC": 94, "AACCCG": 95, "AACCCT": 96, "AACCGA": 97, "AACCGC": 98, "AACCGG": 99, "AACCGT": 100, "AACCTA": 101, "AACCTC": 102, "AACCTG": 103, "AACCTT": 104, "AACGAA": 105, "AACGAC": 106, "AACGAG": 107, "AACGAT": 108, "AACGCA": 109, "AACGCC": 110, "AACGCG": 111, "AACGCT": 112, "AACGGA": 113, "AACGGC": 114, "AACGGG": 115, "AACGGT": 116, "AACGTA": 117, "AACGTC": 118, "AACGTG": 119, "AACGTT": 120, "AACTAA": 121, "AACTAC": 122, "AACTAG": 123, "AACTAT": 124, "AACTCA": 125, "AACTCC": 126, "AACTCG": 127, "AACTCT": 128, "AACTGA": 129, "AACTGC": 130, "AACTGG": 131, "AACTGT": 132, "AACTTA": 133, "AACTTC": 134, "AACTTG": 135, "AACTTT": 136, "AAGAAA": 137, "AAGAAC": 138, "AAGAAG": 139, "AAGAAT": 140, "AAGACA": 141, "AAGACC": 142, "AAGACG": 143, "AAGACT": 144, "AAGAGA": 145, "AAGAGC": 146, "AAGAGG": 147, "AAGAGT": 148, "AAGATA": 149, "AAGATC": 150, "AAGATG": 151, "AAGATT": 152, "AAGCAA": 153, "AAGCAC": 154, "AAGCAG": 155, "AAGCAT": 156, "AAGCCA": 157, "AAGCCC": 158, "AAGCCG": 159, "AAGCCT": 160, "AAGCGA": 161, "AAGCGC": 162, "AAGCGG": 163, "AAGCGT": 164, "AAGCTA": 165, "AAGCTC": 166, "AAGCTG": 167, "AAGCTT": 168, "AAGGAA": 169, "AAGGAC": 170, "AAGGAG": 171, "AAGGAT": 172, "AAGGCA": 173, "AAGGCC": 174, "AAGGCG": 175, "AAGGCT": 176, "AAGGGA": 177, "AAGGGC": 178, "AAGGGG": 179, "AAGGGT": 180, "AAGGTA": 181, "AAGGTC": 182, "AAGGTG": 183, "AAGGTT": 184, "AAGTAA": 185, "AAGTAC": 186, "AAGTAG": 187, "AAGTAT": 188, "AAGTCA": 189, "AAGTCC": 190, "AAGTCG": 191, "AAGTCT": 192, "AAGTGA": 193, "AAGTGC": 194, "AAGTGG": 195, "AAGTGT": 196, "AAGTTA": 197, "AAGTTC": 198, "AAGTTG": 199, "AAGTTT": 200, "AATAAA": 201, "AATAAC": 202, "AATAAG": 203, "AATAAT": 204, "AATACA": 205, "AATACC": 206, "AATACG": 207, "AATACT": 208, "AATAGA": 209, "AATAGC": 210, "AATAGG": 211, "AATAGT": 212, "AATATA": 213, "AATATC": 214, "AATATG": 215, "AATATT": 216, "AATCAA": 217, "AATCAC": 218, "AATCAG": 219, "AATCAT": 220, "AATCCA": 221, "AATCCC": 222, "AATCCG": 223, "AATCCT": 224, "AATCGA": 225, "AATCGC": 226, "AATCGG": 227, "AATCGT": 228, "AATCTA": 229, "AATCTC": 230, "AATCTG": 231, "AATCTT": 232, "AATGAA": 233, "AATGAC": 234, "AATGAG": 235, "AATGAT": 236, "AATGCA": 237, "AATGCC": 238, "AATGCG": 239, "AATGCT": 240, "AATGGA": 241, "AATGGC": 242, "AATGGG": 243, "AATGGT": 244, "AATGTA": 245, "AATGTC": 246, "AATGTG": 247, "AATGTT": 248, "AATTAA": 249, "AATTAC": 250, "AATTAG": 251, "AATTAT": 252, "AATTCA": 253, "AATTCC": 254, "AATTCG": 255, "AATTCT": 256, "AATTGA": 257, "AATTGC": 258, "AATTGG": 259, "AATTGT": 260, "AATTTA": 261, "AATTTC": 262, "AATTTG": 263, "AATTTT": 264, "ACAAAA": 265, "ACAAAC": 266, "ACAAAG": 267, "ACAAAT": 268, "ACAACA": 269, "ACAACC": 270, "ACAACG": 271, "ACAACT": 272, "ACAAGA": 273, "ACAAGC": 274, "ACAAGG": 275, "ACAAGT": 276, "ACAATA": 277, "ACAATC": 278, "ACAATG": 279, "ACAATT": 280, "ACACAA": 281, "ACACAC": 282, "ACACAG": 283, "ACACAT": 284, "ACACCA": 285, "ACACCC": 286, "ACACCG": 287, "ACACCT": 288, "ACACGA": 289, "ACACGC": 290, "ACACGG": 291, "ACACGT": 292, "ACACTA": 293, "ACACTC": 294, "ACACTG": 295, "ACACTT": 296, "ACAGAA": 297, "ACAGAC": 298, "ACAGAG": 299, "ACAGAT": 300, "ACAGCA": 301, "ACAGCC": 302, "ACAGCG": 303, "ACAGCT": 304, "ACAGGA": 305, "ACAGGC": 306, "ACAGGG": 307, "ACAGGT": 308, "ACAGTA": 309, "ACAGTC": 310, "ACAGTG": 311, "ACAGTT": 312, "ACATAA": 313, "ACATAC": 314, "ACATAG": 315, "ACATAT": 316, "ACATCA": 317, "ACATCC": 318, "ACATCG": 319, "ACATCT": 320, "ACATGA": 321, "ACATGC": 322, "ACATGG": 323, "ACATGT": 324, "ACATTA": 325, "ACATTC": 326, "ACATTG": 327, "ACATTT": 328, "ACCAAA": 329, "ACCAAC": 330, "ACCAAG": 331, "ACCAAT": 332, "ACCACA": 333, "ACCACC": 334, "ACCACG": 335, "ACCACT": 336, "ACCAGA": 337, "ACCAGC": 338, "ACCAGG": 339, "ACCAGT": 340, "ACCATA": 341, "ACCATC": 342, "ACCATG": 343, "ACCATT": 344, "ACCCAA": 345, "ACCCAC": 346, "ACCCAG": 347, "ACCCAT": 348, "ACCCCA": 349, "ACCCCC": 350, "ACCCCG": 351, "ACCCCT": 352, "ACCCGA": 353, "ACCCGC": 354, "ACCCGG": 355, "ACCCGT": 356, "ACCCTA": 357, "ACCCTC": 358, "ACCCTG": 359, "ACCCTT": 360, "ACCGAA": 361, "ACCGAC": 362, "ACCGAG": 363, "ACCGAT": 364, "ACCGCA": 365, "ACCGCC": 366, "ACCGCG": 367, "ACCGCT": 368, "ACCGGA": 369, "ACCGGC": 370, "ACCGGG": 371, "ACCGGT": 372, "ACCGTA": 373, "ACCGTC": 374, "ACCGTG": 375, "ACCGTT": 376, "ACCTAA": 377, "ACCTAC": 378, "ACCTAG": 379, "ACCTAT": 380, "ACCTCA": 381, "ACCTCC": 382, "ACCTCG": 383, "ACCTCT": 384, "ACCTGA": 385, "ACCTGC": 386, "ACCTGG": 387, "ACCTGT": 388, "ACCTTA": 389, "ACCTTC": 390, "ACCTTG": 391, "ACCTTT": 392, "ACGAAA": 393, "ACGAAC": 394, "ACGAAG": 395, "ACGAAT": 396, "ACGACA": 397, "ACGACC": 398, "ACGACG": 399, "ACGACT": 400, "ACGAGA": 401, "ACGAGC": 402, "ACGAGG": 403, "ACGAGT": 404, "ACGATA": 405, "ACGATC": 406, "ACGATG": 407, "ACGATT": 408, "ACGCAA": 409, "ACGCAC": 410, "ACGCAG": 411, "ACGCAT": 412, "ACGCCA": 413, "ACGCCC": 414, "ACGCCG": 415, "ACGCCT": 416, "ACGCGA": 417, "ACGCGC": 418, "ACGCGG": 419, "ACGCGT": 420, "ACGCTA": 421, "ACGCTC": 422, "ACGCTG": 423, "ACGCTT": 424, "ACGGAA": 425, "ACGGAC": 426, "ACGGAG": 427, "ACGGAT": 428, "ACGGCA": 429, "ACGGCC": 430, "ACGGCG": 431, "ACGGCT": 432, "ACGGGA": 433, "ACGGGC": 434, "ACGGGG": 435, "ACGGGT": 436, "ACGGTA": 437, "ACGGTC": 438, "ACGGTG": 439, "ACGGTT": 440, "ACGTAA": 441, "ACGTAC": 442, "ACGTAG": 443, "ACGTAT": 444, "ACGTCA": 445, "ACGTCC": 446, "ACGTCG": 447, "ACGTCT": 448, "ACGTGA": 449, "ACGTGC": 450, "ACGTGG": 451, "ACGTGT": 452, "ACGTTA": 453, "ACGTTC": 454, "ACGTTG": 455, "ACGTTT": 456, "ACTAAA": 457, "ACTAAC": 458, "ACTAAG": 459, "ACTAAT": 460, "ACTACA": 461, "ACTACC": 462, "ACTACG": 463, "ACTACT": 464, "ACTAGA": 465, "ACTAGC": 466, "ACTAGG": 467, "ACTAGT": 468, "ACTATA": 469, "ACTATC": 470, "ACTATG": 471, "ACTATT": 472, "ACTCAA": 473, "ACTCAC": 474, "ACTCAG": 475, "ACTCAT": 476, "ACTCCA": 477, "ACTCCC": 478, "ACTCCG": 479, "ACTCCT": 480, "ACTCGA": 481, "ACTCGC": 482, "ACTCGG": 483, "ACTCGT": 484, "ACTCTA": 485, "ACTCTC": 486, "ACTCTG": 487, "ACTCTT": 488, "ACTGAA": 489, "ACTGAC": 490, "ACTGAG": 491, "ACTGAT": 492, "ACTGCA": 493, "ACTGCC": 494, "ACTGCG": 495, "ACTGCT": 496, "ACTGGA": 497, "ACTGGC": 498, "ACTGGG": 499, "ACTGGT": 500, "ACTGTA": 501, "ACTGTC": 502, "ACTGTG": 503, "ACTGTT": 504, "ACTTAA": 505, "ACTTAC": 506, "ACTTAG": 507, "ACTTAT": 508, "ACTTCA": 509, "ACTTCC": 510, "ACTTCG": 511, "ACTTCT": 512, "ACTTGA": 513, "ACTTGC": 514, "ACTTGG": 515, "ACTTGT": 516, "ACTTTA": 517, "ACTTTC": 518, "ACTTTG": 519, "ACTTTT": 520, "AGAAAA": 521, "AGAAAC": 522, "AGAAAG": 523, "AGAAAT": 524, "AGAACA": 525, "AGAACC": 526, "AGAACG": 527, "AGAACT": 528, "AGAAGA": 529, "AGAAGC": 530, "AGAAGG": 531, "AGAAGT": 532, "AGAATA": 533, "AGAATC": 534, "AGAATG": 535, "AGAATT": 536, "AGACAA": 537, "AGACAC": 538, "AGACAG": 539, "AGACAT": 540, "AGACCA": 541, "AGACCC": 542, "AGACCG": 543, "AGACCT": 544, "AGACGA": 545, "AGACGC": 546, "AGACGG": 547, "AGACGT": 548, "AGACTA": 549, "AGACTC": 550, "AGACTG": 551, "AGACTT": 552, "AGAGAA": 553, "AGAGAC": 554, "AGAGAG": 555, "AGAGAT": 556, "AGAGCA": 557, "AGAGCC": 558, "AGAGCG": 559, "AGAGCT": 560, "AGAGGA": 561, "AGAGGC": 562, "AGAGGG": 563, "AGAGGT": 564, "AGAGTA": 565, "AGAGTC": 566, "AGAGTG": 567, "AGAGTT": 568, "AGATAA": 569, "AGATAC": 570, "AGATAG": 571, "AGATAT": 572, "AGATCA": 573, "AGATCC": 574, "AGATCG": 575, "AGATCT": 576, "AGATGA": 577, "AGATGC": 578, "AGATGG": 579, "AGATGT": 580, "AGATTA": 581, "AGATTC": 582, "AGATTG": 583, "AGATTT": 584, "AGCAAA": 585, "AGCAAC": 586, "AGCAAG": 587, "AGCAAT": 588, "AGCACA": 589, "AGCACC": 590, "AGCACG": 591, "AGCACT": 592, "AGCAGA": 593, "AGCAGC": 594, "AGCAGG": 595, "AGCAGT": 596, "AGCATA": 597, "AGCATC": 598, "AGCATG": 599, "AGCATT": 600, "AGCCAA": 601, "AGCCAC": 602, "AGCCAG": 603, "AGCCAT": 604, "AGCCCA": 605, "AGCCCC": 606, "AGCCCG": 607, "AGCCCT": 608, "AGCCGA": 609, "AGCCGC": 610, "AGCCGG": 611, "AGCCGT": 612, "AGCCTA": 613, "AGCCTC": 614, "AGCCTG": 615, "AGCCTT": 616, "AGCGAA": 617, "AGCGAC": 618, "AGCGAG": 619, "AGCGAT": 620, "AGCGCA": 621, "AGCGCC": 622, "AGCGCG": 623, "AGCGCT": 624, "AGCGGA": 625, "AGCGGC": 626, "AGCGGG": 627, "AGCGGT": 628, "AGCGTA": 629, "AGCGTC": 630, "AGCGTG": 631, "AGCGTT": 632, "AGCTAA": 633, "AGCTAC": 634, "AGCTAG": 635, "AGCTAT": 636, "AGCTCA": 637, "AGCTCC": 638, "AGCTCG": 639, "AGCTCT": 640, "AGCTGA": 641, "AGCTGC": 642, "AGCTGG": 643, "AGCTGT": 644, "AGCTTA": 645, "AGCTTC": 646, "AGCTTG": 647, "AGCTTT": 648, "AGGAAA": 649, "AGGAAC": 650, "AGGAAG": 651, "AGGAAT": 652, "AGGACA": 653, "AGGACC": 654, "AGGACG": 655, "AGGACT": 656, "AGGAGA": 657, "AGGAGC": 658, "AGGAGG": 659, "AGGAGT": 660, "AGGATA": 661, "AGGATC": 662, "AGGATG": 663, "AGGATT": 664, "AGGCAA": 665, "AGGCAC": 666, "AGGCAG": 667, "AGGCAT": 668, "AGGCCA": 669, "AGGCCC": 670, "AGGCCG": 671, "AGGCCT": 672, "AGGCGA": 673, "AGGCGC": 674, "AGGCGG": 675, "AGGCGT": 676, "AGGCTA": 677, "AGGCTC": 678, "AGGCTG": 679, "AGGCTT": 680, "AGGGAA": 681, "AGGGAC": 682, "AGGGAG": 683, "AGGGAT": 684, "AGGGCA": 685, "AGGGCC": 686, "AGGGCG": 687, "AGGGCT": 688, "AGGGGA": 689, "AGGGGC": 690, "AGGGGG": 691, "AGGGGT": 692, "AGGGTA": 693, "AGGGTC": 694, "AGGGTG": 695, "AGGGTT": 696, "AGGTAA": 697, "AGGTAC": 698, "AGGTAG": 699, "AGGTAT": 700, "AGGTCA": 701, "AGGTCC": 702, "AGGTCG": 703, "AGGTCT": 704, "AGGTGA": 705, "AGGTGC": 706, "AGGTGG": 707, "AGGTGT": 708, "AGGTTA": 709, "AGGTTC": 710, "AGGTTG": 711, "AGGTTT": 712, "AGTAAA": 713, "AGTAAC": 714, "AGTAAG": 715, "AGTAAT": 716, "AGTACA": 717, "AGTACC": 718, "AGTACG": 719, "AGTACT": 720, "AGTAGA": 721, "AGTAGC": 722, "AGTAGG": 723, "AGTAGT": 724, "AGTATA": 725, "AGTATC": 726, "AGTATG": 727, "AGTATT": 728, "AGTCAA": 729, "AGTCAC": 730, "AGTCAG": 731, "AGTCAT": 732, "AGTCCA": 733, "AGTCCC": 734, "AGTCCG": 735, "AGTCCT": 736, "AGTCGA": 737, "AGTCGC": 738, "AGTCGG": 739, "AGTCGT": 740, "AGTCTA": 741, "AGTCTC": 742, "AGTCTG": 743, "AGTCTT": 744, "AGTGAA": 745, "AGTGAC": 746, "AGTGAG": 747, "AGTGAT": 748, "AGTGCA": 749, "AGTGCC": 750, "AGTGCG": 751, "AGTGCT": 752, "AGTGGA": 753, "AGTGGC": 754, "AGTGGG": 755, "AGTGGT": 756, "AGTGTA": 757, "AGTGTC": 758, "AGTGTG": 759, "AGTGTT": 760, "AGTTAA": 761, "AGTTAC": 762, "AGTTAG": 763, "AGTTAT": 764, "AGTTCA": 765, "AGTTCC": 766, "AGTTCG": 767, "AGTTCT": 768, "AGTTGA": 769, "AGTTGC": 770, "AGTTGG": 771, "AGTTGT": 772, "AGTTTA": 773, "AGTTTC": 774, "AGTTTG": 775, "AGTTTT": 776, "ATAAAA": 777, "ATAAAC": 778, "ATAAAG": 779, "ATAAAT": 780, "ATAACA": 781, "ATAACC": 782, "ATAACG": 783, "ATAACT": 784, "ATAAGA": 785, "ATAAGC": 786, "ATAAGG": 787, "ATAAGT": 788, "ATAATA": 789, "ATAATC": 790, "ATAATG": 791, "ATAATT": 792, "ATACAA": 793, "ATACAC": 794, "ATACAG": 795, "ATACAT": 796, "ATACCA": 797, "ATACCC": 798, "ATACCG": 799, "ATACCT": 800, "ATACGA": 801, "ATACGC": 802, "ATACGG": 803, "ATACGT": 804, "ATACTA": 805, "ATACTC": 806, "ATACTG": 807, "ATACTT": 808, "ATAGAA": 809, "ATAGAC": 810, "ATAGAG": 811, "ATAGAT": 812, "ATAGCA": 813, "ATAGCC": 814, "ATAGCG": 815, "ATAGCT": 816, "ATAGGA": 817, "ATAGGC": 818, "ATAGGG": 819, "ATAGGT": 820, "ATAGTA": 821, "ATAGTC": 822, "ATAGTG": 823, "ATAGTT": 824, "ATATAA": 825, "ATATAC": 826, "ATATAG": 827, "ATATAT": 828, "ATATCA": 829, "ATATCC": 830, "ATATCG": 831, "ATATCT": 832, "ATATGA": 833, "ATATGC": 834, "ATATGG": 835, "ATATGT": 836, "ATATTA": 837, "ATATTC": 838, "ATATTG": 839, "ATATTT": 840, "ATCAAA": 841, "ATCAAC": 842, "ATCAAG": 843, "ATCAAT": 844, "ATCACA": 845, "ATCACC": 846, "ATCACG": 847, "ATCACT": 848, "ATCAGA": 849, "ATCAGC": 850, "ATCAGG": 851, "ATCAGT": 852, "ATCATA": 853, "ATCATC": 854, "ATCATG": 855, "ATCATT": 856, "ATCCAA": 857, "ATCCAC": 858, "ATCCAG": 859, "ATCCAT": 860, "ATCCCA": 861, "ATCCCC": 862, "ATCCCG": 863, "ATCCCT": 864, "ATCCGA": 865, "ATCCGC": 866, "ATCCGG": 867, "ATCCGT": 868, "ATCCTA": 869, "ATCCTC": 870, "ATCCTG": 871, "ATCCTT": 872, "ATCGAA": 873, "ATCGAC": 874, "ATCGAG": 875, "ATCGAT": 876, "ATCGCA": 877, "ATCGCC": 878, "ATCGCG": 879, "ATCGCT": 880, "ATCGGA": 881, "ATCGGC": 882, "ATCGGG": 883, "ATCGGT": 884, "ATCGTA": 885, "ATCGTC": 886, "ATCGTG": 887, "ATCGTT": 888, "ATCTAA": 889, "ATCTAC": 890, "ATCTAG": 891, "ATCTAT": 892, "ATCTCA": 893, "ATCTCC": 894, "ATCTCG": 895, "ATCTCT": 896, "ATCTGA": 897, "ATCTGC": 898, "ATCTGG": 899, "ATCTGT": 900, "ATCTTA": 901, "ATCTTC": 902, "ATCTTG": 903, "ATCTTT": 904, "ATGAAA": 905, "ATGAAC": 906, "ATGAAG": 907, "ATGAAT": 908, "ATGACA": 909, "ATGACC": 910, "ATGACG": 911, "ATGACT": 912, "ATGAGA": 913, "ATGAGC": 914, "ATGAGG": 915, "ATGAGT": 916, "ATGATA": 917, "ATGATC": 918, "ATGATG": 919, "ATGATT": 920, "ATGCAA": 921, "ATGCAC": 922, "ATGCAG": 923, "ATGCAT": 924, "ATGCCA": 925, "ATGCCC": 926, "ATGCCG": 927, "ATGCCT": 928, "ATGCGA": 929, "ATGCGC": 930, "ATGCGG": 931, "ATGCGT": 932, "ATGCTA": 933, "ATGCTC": 934, "ATGCTG": 935, "ATGCTT": 936, "ATGGAA": 937, "ATGGAC": 938, "ATGGAG": 939, "ATGGAT": 940, "ATGGCA": 941, "ATGGCC": 942, "ATGGCG": 943, "ATGGCT": 944, "ATGGGA": 945, "ATGGGC": 946, "ATGGGG": 947, "ATGGGT": 948, "ATGGTA": 949, "ATGGTC": 950, "ATGGTG": 951, "ATGGTT": 952, "ATGTAA": 953, "ATGTAC": 954, "ATGTAG": 955, "ATGTAT": 956, "ATGTCA": 957, "ATGTCC": 958, "ATGTCG": 959, "ATGTCT": 960, "ATGTGA": 961, "ATGTGC": 962, "ATGTGG": 963, "ATGTGT": 964, "ATGTTA": 965, "ATGTTC": 966, "ATGTTG": 967, "ATGTTT": 968, "ATTAAA": 969, "ATTAAC": 970, "ATTAAG": 971, "ATTAAT": 972, "ATTACA": 973, "ATTACC": 974, "ATTACG": 975, "ATTACT": 976, "ATTAGA": 977, "ATTAGC": 978, "ATTAGG": 979, "ATTAGT": 980, "ATTATA": 981, "ATTATC": 982, "ATTATG": 983, "ATTATT": 984, "ATTCAA": 985, "ATTCAC": 986, "ATTCAG": 987, "ATTCAT": 988, "ATTCCA": 989, "ATTCCC": 990, "ATTCCG": 991, "ATTCCT": 992, "ATTCGA": 993, "ATTCGC": 994, "ATTCGG": 995, "ATTCGT": 996, "ATTCTA": 997, "ATTCTC": 998, "ATTCTG": 999, "ATTCTT": 1000, "ATTGAA": 1001, "ATTGAC": 1002, "ATTGAG": 1003, "ATTGAT": 1004, "ATTGCA": 1005, "ATTGCC": 1006, "ATTGCG": 1007, "ATTGCT": 1008, "ATTGGA": 1009, "ATTGGC": 1010, "ATTGGG": 1011, "ATTGGT": 1012, "ATTGTA": 1013, "ATTGTC": 1014, "ATTGTG": 1015, "ATTGTT": 1016, "ATTTAA": 1017, "ATTTAC": 1018, "ATTTAG": 1019, "ATTTAT": 1020, "ATTTCA": 1021, "ATTTCC": 1022, "ATTTCG": 1023, "ATTTCT": 1024, "ATTTGA": 1025, "ATTTGC": 1026, "ATTTGG": 1027, "ATTTGT": 1028, "ATTTTA": 1029, "ATTTTC": 1030, "ATTTTG": 1031, "ATTTTT": 1032, "CAAAAA": 1033, "CAAAAC": 1034, "CAAAAG": 1035, "CAAAAT": 1036, "CAAACA": 1037, "CAAACC": 1038, "CAAACG": 1039, "CAAACT": 1040, "CAAAGA": 1041, "CAAAGC": 1042, "CAAAGG": 1043, "CAAAGT": 1044, "CAAATA": 1045, "CAAATC": 1046, "CAAATG": 1047, "CAAATT": 1048, "CAACAA": 1049, "CAACAC": 1050, "CAACAG": 1051, "CAACAT": 1052, "CAACCA": 1053, "CAACCC": 1054, "CAACCG": 1055, "CAACCT": 1056, "CAACGA": 1057, "CAACGC": 1058, "CAACGG": 1059, "CAACGT": 1060, "CAACTA": 1061, "CAACTC": 1062, "CAACTG": 1063, "CAACTT": 1064, "CAAGAA": 1065, "CAAGAC": 1066, "CAAGAG": 1067, "CAAGAT": 1068, "CAAGCA": 1069, "CAAGCC": 1070, "CAAGCG": 1071, "CAAGCT": 1072, "CAAGGA": 1073, "CAAGGC": 1074, "CAAGGG": 1075, "CAAGGT": 1076, "CAAGTA": 1077, "CAAGTC": 1078, "CAAGTG": 1079, "CAAGTT": 1080, "CAATAA": 1081, "CAATAC": 1082, "CAATAG": 1083, "CAATAT": 1084, "CAATCA": 1085, "CAATCC": 1086, "CAATCG": 1087, "CAATCT": 1088, "CAATGA": 1089, "CAATGC": 1090, "CAATGG": 1091, "CAATGT": 1092, "CAATTA": 1093, "CAATTC": 1094, "CAATTG": 1095, "CAATTT": 1096, "CACAAA": 1097, "CACAAC": 1098, "CACAAG": 1099, "CACAAT": 1100, "CACACA": 1101, "CACACC": 1102, "CACACG": 1103, "CACACT": 1104, "CACAGA": 1105, "CACAGC": 1106, "CACAGG": 1107, "CACAGT": 1108, "CACATA": 1109, "CACATC": 1110, "CACATG": 1111, "CACATT": 1112, "CACCAA": 1113, "CACCAC": 1114, "CACCAG": 1115, "CACCAT": 1116, "CACCCA": 1117, "CACCCC": 1118, "CACCCG": 1119, "CACCCT": 1120, "CACCGA": 1121, "CACCGC": 1122, "CACCGG": 1123, "CACCGT": 1124, "CACCTA": 1125, "CACCTC": 1126, "CACCTG": 1127, "CACCTT": 1128, "CACGAA": 1129, "CACGAC": 1130, "CACGAG": 1131, "CACGAT": 1132, "CACGCA": 1133, "CACGCC": 1134, "CACGCG": 1135, "CACGCT": 1136, "CACGGA": 1137, "CACGGC": 1138, "CACGGG": 1139, "CACGGT": 1140, "CACGTA": 1141, "CACGTC": 1142, "CACGTG": 1143, "CACGTT": 1144, "CACTAA": 1145, "CACTAC": 1146, "CACTAG": 1147, "CACTAT": 1148, "CACTCA": 1149, "CACTCC": 1150, "CACTCG": 1151, "CACTCT": 1152, "CACTGA": 1153, "CACTGC": 1154, "CACTGG": 1155, "CACTGT": 1156, "CACTTA": 1157, "CACTTC": 1158, "CACTTG": 1159, "CACTTT": 1160, "CAGAAA": 1161, "CAGAAC": 1162, "CAGAAG": 1163, "CAGAAT": 1164, "CAGACA": 1165, "CAGACC": 1166, "CAGACG": 1167, "CAGACT": 1168, "CAGAGA": 1169, "CAGAGC": 1170, "CAGAGG": 1171, "CAGAGT": 1172, "CAGATA": 1173, "CAGATC": 1174, "CAGATG": 1175, "CAGATT": 1176, "CAGCAA": 1177, "CAGCAC": 1178, "CAGCAG": 1179, "CAGCAT": 1180, "CAGCCA": 1181, "CAGCCC": 1182, "CAGCCG": 1183, "CAGCCT": 1184, "CAGCGA": 1185, "CAGCGC": 1186, "CAGCGG": 1187, "CAGCGT": 1188, "CAGCTA": 1189, "CAGCTC": 1190, "CAGCTG": 1191, "CAGCTT": 1192, "CAGGAA": 1193, "CAGGAC": 1194, "CAGGAG": 1195, "CAGGAT": 1196, "CAGGCA": 1197, "CAGGCC": 1198, "CAGGCG": 1199, "CAGGCT": 1200, "CAGGGA": 1201, "CAGGGC": 1202, "CAGGGG": 1203, "CAGGGT": 1204, "CAGGTA": 1205, "CAGGTC": 1206, "CAGGTG": 1207, "CAGGTT": 1208, "CAGTAA": 1209, "CAGTAC": 1210, "CAGTAG": 1211, "CAGTAT": 1212, "CAGTCA": 1213, "CAGTCC": 1214, "CAGTCG": 1215, "CAGTCT": 1216, "CAGTGA": 1217, "CAGTGC": 1218, "CAGTGG": 1219, "CAGTGT": 1220, "CAGTTA": 1221, "CAGTTC": 1222, "CAGTTG": 1223, "CAGTTT": 1224, "CATAAA": 1225, "CATAAC": 1226, "CATAAG": 1227, "CATAAT": 1228, "CATACA": 1229, "CATACC": 1230, "CATACG": 1231, "CATACT": 1232, "CATAGA": 1233, "CATAGC": 1234, "CATAGG": 1235, "CATAGT": 1236, "CATATA": 1237, "CATATC": 1238, "CATATG": 1239, "CATATT": 1240, "CATCAA": 1241, "CATCAC": 1242, "CATCAG": 1243, "CATCAT": 1244, "CATCCA": 1245, "CATCCC": 1246, "CATCCG": 1247, "CATCCT": 1248, "CATCGA": 1249, "CATCGC": 1250, "CATCGG": 1251, "CATCGT": 1252, "CATCTA": 1253, "CATCTC": 1254, "CATCTG": 1255, "CATCTT": 1256, "CATGAA": 1257, "CATGAC": 1258, "CATGAG": 1259, "CATGAT": 1260, "CATGCA": 1261, "CATGCC": 1262, "CATGCG": 1263, "CATGCT": 1264, "CATGGA": 1265, "CATGGC": 1266, "CATGGG": 1267, "CATGGT": 1268, "CATGTA": 1269, "CATGTC": 1270, "CATGTG": 1271, "CATGTT": 1272, "CATTAA": 1273, "CATTAC": 1274, "CATTAG": 1275, "CATTAT": 1276, "CATTCA": 1277, "CATTCC": 1278, "CATTCG": 1279, "CATTCT": 1280, "CATTGA": 1281, "CATTGC": 1282, "CATTGG": 1283, "CATTGT": 1284, "CATTTA": 1285, "CATTTC": 1286, "CATTTG": 1287, "CATTTT": 1288, "CCAAAA": 1289, "CCAAAC": 1290, "CCAAAG": 1291, "CCAAAT": 1292, "CCAACA": 1293, "CCAACC": 1294, "CCAACG": 1295, "CCAACT": 1296, "CCAAGA": 1297, "CCAAGC": 1298, "CCAAGG": 1299, "CCAAGT": 1300, "CCAATA": 1301, "CCAATC": 1302, "CCAATG": 1303, "CCAATT": 1304, "CCACAA": 1305, "CCACAC": 1306, "CCACAG": 1307, "CCACAT": 1308, "CCACCA": 1309, "CCACCC": 1310, "CCACCG": 1311, "CCACCT": 1312, "CCACGA": 1313, "CCACGC": 1314, "CCACGG": 1315, "CCACGT": 1316, "CCACTA": 1317, "CCACTC": 1318, "CCACTG": 1319, "CCACTT": 1320, "CCAGAA": 1321, "CCAGAC": 1322, "CCAGAG": 1323, "CCAGAT": 1324, "CCAGCA": 1325, "CCAGCC": 1326, "CCAGCG": 1327, "CCAGCT": 1328, "CCAGGA": 1329, "CCAGGC": 1330, "CCAGGG": 1331, "CCAGGT": 1332, "CCAGTA": 1333, "CCAGTC": 1334, "CCAGTG": 1335, "CCAGTT": 1336, "CCATAA": 1337, "CCATAC": 1338, "CCATAG": 1339, "CCATAT": 1340, "CCATCA": 1341, "CCATCC": 1342, "CCATCG": 1343, "CCATCT": 1344, "CCATGA": 1345, "CCATGC": 1346, "CCATGG": 1347, "CCATGT": 1348, "CCATTA": 1349, "CCATTC": 1350, "CCATTG": 1351, "CCATTT": 1352, "CCCAAA": 1353, "CCCAAC": 1354, "CCCAAG": 1355, "CCCAAT": 1356, "CCCACA": 1357, "CCCACC": 1358, "CCCACG": 1359, "CCCACT": 1360, "CCCAGA": 1361, "CCCAGC": 1362, "CCCAGG": 1363, "CCCAGT": 1364, "CCCATA": 1365, "CCCATC": 1366, "CCCATG": 1367, "CCCATT": 1368, "CCCCAA": 1369, "CCCCAC": 1370, "CCCCAG": 1371, "CCCCAT": 1372, "CCCCCA": 1373, "CCCCCC": 1374, "CCCCCG": 1375, "CCCCCT": 1376, "CCCCGA": 1377, "CCCCGC": 1378, "CCCCGG": 1379, "CCCCGT": 1380, "CCCCTA": 1381, "CCCCTC": 1382, "CCCCTG": 1383, "CCCCTT": 1384, "CCCGAA": 1385, "CCCGAC": 1386, "CCCGAG": 1387, "CCCGAT": 1388, "CCCGCA": 1389, "CCCGCC": 1390, "CCCGCG": 1391, "CCCGCT": 1392, "CCCGGA": 1393, "CCCGGC": 1394, "CCCGGG": 1395, "CCCGGT": 1396, "CCCGTA": 1397, "CCCGTC": 1398, "CCCGTG": 1399, "CCCGTT": 1400, "CCCTAA": 1401, "CCCTAC": 1402, "CCCTAG": 1403, "CCCTAT": 1404, "CCCTCA": 1405, "CCCTCC": 1406, "CCCTCG": 1407, "CCCTCT": 1408, "CCCTGA": 1409, "CCCTGC": 1410, "CCCTGG": 1411, "CCCTGT": 1412, "CCCTTA": 1413, "CCCTTC": 1414, "CCCTTG": 1415, "CCCTTT": 1416, "CCGAAA": 1417, "CCGAAC": 1418, "CCGAAG": 1419, "CCGAAT": 1420, "CCGACA": 1421, "CCGACC": 1422, "CCGACG": 1423, "CCGACT": 1424, "CCGAGA": 1425, "CCGAGC": 1426, "CCGAGG": 1427, "CCGAGT": 1428, "CCGATA": 1429, "CCGATC": 1430, "CCGATG": 1431, "CCGATT": 1432, "CCGCAA": 1433, "CCGCAC": 1434, "CCGCAG": 1435, "CCGCAT": 1436, "CCGCCA": 1437, "CCGCCC": 1438, "CCGCCG": 1439, "CCGCCT": 1440, "CCGCGA": 1441, "CCGCGC": 1442, "CCGCGG": 1443, "CCGCGT": 1444, "CCGCTA": 1445, "CCGCTC": 1446, "CCGCTG": 1447, "CCGCTT": 1448, "CCGGAA": 1449, "CCGGAC": 1450, "CCGGAG": 1451, "CCGGAT": 1452, "CCGGCA": 1453, "CCGGCC": 1454, "CCGGCG": 1455, "CCGGCT": 1456, "CCGGGA": 1457, "CCGGGC": 1458, "CCGGGG": 1459, "CCGGGT": 1460, "CCGGTA": 1461, "CCGGTC": 1462, "CCGGTG": 1463, "CCGGTT": 1464, "CCGTAA": 1465, "CCGTAC": 1466, "CCGTAG": 1467, "CCGTAT": 1468, "CCGTCA": 1469, "CCGTCC": 1470, "CCGTCG": 1471, "CCGTCT": 1472, "CCGTGA": 1473, "CCGTGC": 1474, "CCGTGG": 1475, "CCGTGT": 1476, "CCGTTA": 1477, "CCGTTC": 1478, "CCGTTG": 1479, "CCGTTT": 1480, "CCTAAA": 1481, "CCTAAC": 1482, "CCTAAG": 1483, "CCTAAT": 1484, "CCTACA": 1485, "CCTACC": 1486, "CCTACG": 1487, "CCTACT": 1488, "CCTAGA": 1489, "CCTAGC": 1490, "CCTAGG": 1491, "CCTAGT": 1492, "CCTATA": 1493, "CCTATC": 1494, "CCTATG": 1495, "CCTATT": 1496, "CCTCAA": 1497, "CCTCAC": 1498, "CCTCAG": 1499, "CCTCAT": 1500, "CCTCCA": 1501, "CCTCCC": 1502, "CCTCCG": 1503, "CCTCCT": 1504, "CCTCGA": 1505, "CCTCGC": 1506, "CCTCGG": 1507, "CCTCGT": 1508, "CCTCTA": 1509, "CCTCTC": 1510, "CCTCTG": 1511, "CCTCTT": 1512, "CCTGAA": 1513, "CCTGAC": 1514, "CCTGAG": 1515, "CCTGAT": 1516, "CCTGCA": 1517, "CCTGCC": 1518, "CCTGCG": 1519, "CCTGCT": 1520, "CCTGGA": 1521, "CCTGGC": 1522, "CCTGGG": 1523, "CCTGGT": 1524, "CCTGTA": 1525, "CCTGTC": 1526, "CCTGTG": 1527, "CCTGTT": 1528, "CCTTAA": 1529, "CCTTAC": 1530, "CCTTAG": 1531, "CCTTAT": 1532, "CCTTCA": 1533, "CCTTCC": 1534, "CCTTCG": 1535, "CCTTCT": 1536, "CCTTGA": 1537, "CCTTGC": 1538, "CCTTGG": 1539, "CCTTGT": 1540, "CCTTTA": 1541, "CCTTTC": 1542, "CCTTTG": 1543, "CCTTTT": 1544, "CGAAAA": 1545, "CGAAAC": 1546, "CGAAAG": 1547, "CGAAAT": 1548, "CGAACA": 1549, "CGAACC": 1550, "CGAACG": 1551, "CGAACT": 1552, "CGAAGA": 1553, "CGAAGC": 1554, "CGAAGG": 1555, "CGAAGT": 1556, "CGAATA": 1557, "CGAATC": 1558, "CGAATG": 1559, "CGAATT": 1560, "CGACAA": 1561, "CGACAC": 1562, "CGACAG": 1563, "CGACAT": 1564, "CGACCA": 1565, "CGACCC": 1566, "CGACCG": 1567, "CGACCT": 1568, "CGACGA": 1569, "CGACGC": 1570, "CGACGG": 1571, "CGACGT": 1572, "CGACTA": 1573, "CGACTC": 1574, "CGACTG": 1575, "CGACTT": 1576, "CGAGAA": 1577, "CGAGAC": 1578, "CGAGAG": 1579, "CGAGAT": 1580, "CGAGCA": 1581, "CGAGCC": 1582, "CGAGCG": 1583, "CGAGCT": 1584, "CGAGGA": 1585, "CGAGGC": 1586, "CGAGGG": 1587, "CGAGGT": 1588, "CGAGTA": 1589, "CGAGTC": 1590, "CGAGTG": 1591, "CGAGTT": 1592, "CGATAA": 1593, "CGATAC": 1594, "CGATAG": 1595, "CGATAT": 1596, "CGATCA": 1597, "CGATCC": 1598, "CGATCG": 1599, "CGATCT": 1600, "CGATGA": 1601, "CGATGC": 1602, "CGATGG": 1603, "CGATGT": 1604, "CGATTA": 1605, "CGATTC": 1606, "CGATTG": 1607, "CGATTT": 1608, "CGCAAA": 1609, "CGCAAC": 1610, "CGCAAG": 1611, "CGCAAT": 1612, "CGCACA": 1613, "CGCACC": 1614, "CGCACG": 1615, "CGCACT": 1616, "CGCAGA": 1617, "CGCAGC": 1618, "CGCAGG": 1619, "CGCAGT": 1620, "CGCATA": 1621, "CGCATC": 1622, "CGCATG": 1623, "CGCATT": 1624, "CGCCAA": 1625, "CGCCAC": 1626, "CGCCAG": 1627, "CGCCAT": 1628, "CGCCCA": 1629, "CGCCCC": 1630, "CGCCCG": 1631, "CGCCCT": 1632, "CGCCGA": 1633, "CGCCGC": 1634, "CGCCGG": 1635, "CGCCGT": 1636, "CGCCTA": 1637, "CGCCTC": 1638, "CGCCTG": 1639, "CGCCTT": 1640, "CGCGAA": 1641, "CGCGAC": 1642, "CGCGAG": 1643, "CGCGAT": 1644, "CGCGCA": 1645, "CGCGCC": 1646, "CGCGCG": 1647, "CGCGCT": 1648, "CGCGGA": 1649, "CGCGGC": 1650, "CGCGGG": 1651, "CGCGGT": 1652, "CGCGTA": 1653, "CGCGTC": 1654, "CGCGTG": 1655, "CGCGTT": 1656, "CGCTAA": 1657, "CGCTAC": 1658, "CGCTAG": 1659, "CGCTAT": 1660, "CGCTCA": 1661, "CGCTCC": 1662, "CGCTCG": 1663, "CGCTCT": 1664, "CGCTGA": 1665, "CGCTGC": 1666, "CGCTGG": 1667, "CGCTGT": 1668, "CGCTTA": 1669, "CGCTTC": 1670, "CGCTTG": 1671, "CGCTTT": 1672, "CGGAAA": 1673, "CGGAAC": 1674, "CGGAAG": 1675, "CGGAAT": 1676, "CGGACA": 1677, "CGGACC": 1678, "CGGACG": 1679, "CGGACT": 1680, "CGGAGA": 1681, "CGGAGC": 1682, "CGGAGG": 1683, "CGGAGT": 1684, "CGGATA": 1685, "CGGATC": 1686, "CGGATG": 1687, "CGGATT": 1688, "CGGCAA": 1689, "CGGCAC": 1690, "CGGCAG": 1691, "CGGCAT": 1692, "CGGCCA": 1693, "CGGCCC": 1694, "CGGCCG": 1695, "CGGCCT": 1696, "CGGCGA": 1697, "CGGCGC": 1698, "CGGCGG": 1699, "CGGCGT": 1700, "CGGCTA": 1701, "CGGCTC": 1702, "CGGCTG": 1703, "CGGCTT": 1704, "CGGGAA": 1705, "CGGGAC": 1706, "CGGGAG": 1707, "CGGGAT": 1708, "CGGGCA": 1709, "CGGGCC": 1710, "CGGGCG": 1711, "CGGGCT": 1712, "CGGGGA": 1713, "CGGGGC": 1714, "CGGGGG": 1715, "CGGGGT": 1716, "CGGGTA": 1717, "CGGGTC": 1718, "CGGGTG": 1719, "CGGGTT": 1720, "CGGTAA": 1721, "CGGTAC": 1722, "CGGTAG": 1723, "CGGTAT": 1724, "CGGTCA": 1725, "CGGTCC": 1726, "CGGTCG": 1727, "CGGTCT": 1728, "CGGTGA": 1729, "CGGTGC": 1730, "CGGTGG": 1731, "CGGTGT": 1732, "CGGTTA": 1733, "CGGTTC": 1734, "CGGTTG": 1735, "CGGTTT": 1736, "CGTAAA": 1737, "CGTAAC": 1738, "CGTAAG": 1739, "CGTAAT": 1740, "CGTACA": 1741, "CGTACC": 1742, "CGTACG": 1743, "CGTACT": 1744, "CGTAGA": 1745, "CGTAGC": 1746, "CGTAGG": 1747, "CGTAGT": 1748, "CGTATA": 1749, "CGTATC": 1750, "CGTATG": 1751, "CGTATT": 1752, "CGTCAA": 1753, "CGTCAC": 1754, "CGTCAG": 1755, "CGTCAT": 1756, "CGTCCA": 1757, "CGTCCC": 1758, "CGTCCG": 1759, "CGTCCT": 1760, "CGTCGA": 1761, "CGTCGC": 1762, "CGTCGG": 1763, "CGTCGT": 1764, "CGTCTA": 1765, "CGTCTC": 1766, "CGTCTG": 1767, "CGTCTT": 1768, "CGTGAA": 1769, "CGTGAC": 1770, "CGTGAG": 1771, "CGTGAT": 1772, "CGTGCA": 1773, "CGTGCC": 1774, "CGTGCG": 1775, "CGTGCT": 1776, "CGTGGA": 1777, "CGTGGC": 1778, "CGTGGG": 1779, "CGTGGT": 1780, "CGTGTA": 1781, "CGTGTC": 1782, "CGTGTG": 1783, "CGTGTT": 1784, "CGTTAA": 1785, "CGTTAC": 1786, "CGTTAG": 1787, "CGTTAT": 1788, "CGTTCA": 1789, "CGTTCC": 1790, "CGTTCG": 1791, "CGTTCT": 1792, "CGTTGA": 1793, "CGTTGC": 1794, "CGTTGG": 1795, "CGTTGT": 1796, "CGTTTA": 1797, "CGTTTC": 1798, "CGTTTG": 1799, "CGTTTT": 1800, "CTAAAA": 1801, "CTAAAC": 1802, "CTAAAG": 1803, "CTAAAT": 1804, "CTAACA": 1805, "CTAACC": 1806, "CTAACG": 1807, "CTAACT": 1808, "CTAAGA": 1809, "CTAAGC": 1810, "CTAAGG": 1811, "CTAAGT": 1812, "CTAATA": 1813, "CTAATC": 1814, "CTAATG": 1815, "CTAATT": 1816, "CTACAA": 1817, "CTACAC": 1818, "CTACAG": 1819, "CTACAT": 1820, "CTACCA": 1821, "CTACCC": 1822, "CTACCG": 1823, "CTACCT": 1824, "CTACGA": 1825, "CTACGC": 1826, "CTACGG": 1827, "CTACGT": 1828, "CTACTA": 1829, "CTACTC": 1830, "CTACTG": 1831, "CTACTT": 1832, "CTAGAA": 1833, "CTAGAC": 1834, "CTAGAG": 1835, "CTAGAT": 1836, "CTAGCA": 1837, "CTAGCC": 1838, "CTAGCG": 1839, "CTAGCT": 1840, "CTAGGA": 1841, "CTAGGC": 1842, "CTAGGG": 1843, "CTAGGT": 1844, "CTAGTA": 1845, "CTAGTC": 1846, "CTAGTG": 1847, "CTAGTT": 1848, "CTATAA": 1849, "CTATAC": 1850, "CTATAG": 1851, "CTATAT": 1852, "CTATCA": 1853, "CTATCC": 1854, "CTATCG": 1855, "CTATCT": 1856, "CTATGA": 1857, "CTATGC": 1858, "CTATGG": 1859, "CTATGT": 1860, "CTATTA": 1861, "CTATTC": 1862, "CTATTG": 1863, "CTATTT": 1864, "CTCAAA": 1865, "CTCAAC": 1866, "CTCAAG": 1867, "CTCAAT": 1868, "CTCACA": 1869, "CTCACC": 1870, "CTCACG": 1871, "CTCACT": 1872, "CTCAGA": 1873, "CTCAGC": 1874, "CTCAGG": 1875, "CTCAGT": 1876, "CTCATA": 1877, "CTCATC": 1878, "CTCATG": 1879, "CTCATT": 1880, "CTCCAA": 1881, "CTCCAC": 1882, "CTCCAG": 1883, "CTCCAT": 1884, "CTCCCA": 1885, "CTCCCC": 1886, "CTCCCG": 1887, "CTCCCT": 1888, "CTCCGA": 1889, "CTCCGC": 1890, "CTCCGG": 1891, "CTCCGT": 1892, "CTCCTA": 1893, "CTCCTC": 1894, "CTCCTG": 1895, "CTCCTT": 1896, "CTCGAA": 1897, "CTCGAC": 1898, "CTCGAG": 1899, "CTCGAT": 1900, "CTCGCA": 1901, "CTCGCC": 1902, "CTCGCG": 1903, "CTCGCT": 1904, "CTCGGA": 1905, "CTCGGC": 1906, "CTCGGG": 1907, "CTCGGT": 1908, "CTCGTA": 1909, "CTCGTC": 1910, "CTCGTG": 1911, "CTCGTT": 1912, "CTCTAA": 1913, "CTCTAC": 1914, "CTCTAG": 1915, "CTCTAT": 1916, "CTCTCA": 1917, "CTCTCC": 1918, "CTCTCG": 1919, "CTCTCT": 1920, "CTCTGA": 1921, "CTCTGC": 1922, "CTCTGG": 1923, "CTCTGT": 1924, "CTCTTA": 1925, "CTCTTC": 1926, "CTCTTG": 1927, "CTCTTT": 1928, "CTGAAA": 1929, "CTGAAC": 1930, "CTGAAG": 1931, "CTGAAT": 1932, "CTGACA": 1933, "CTGACC": 1934, "CTGACG": 1935, "CTGACT": 1936, "CTGAGA": 1937, "CTGAGC": 1938, "CTGAGG": 1939, "CTGAGT": 1940, "CTGATA": 1941, "CTGATC": 1942, "CTGATG": 1943, "CTGATT": 1944, "CTGCAA": 1945, "CTGCAC": 1946, "CTGCAG": 1947, "CTGCAT": 1948, "CTGCCA": 1949, "CTGCCC": 1950, "CTGCCG": 1951, "CTGCCT": 1952, "CTGCGA": 1953, "CTGCGC": 1954, "CTGCGG": 1955, "CTGCGT": 1956, "CTGCTA": 1957, "CTGCTC": 1958, "CTGCTG": 1959, "CTGCTT": 1960, "CTGGAA": 1961, "CTGGAC": 1962, "CTGGAG": 1963, "CTGGAT": 1964, "CTGGCA": 1965, "CTGGCC": 1966, "CTGGCG": 1967, "CTGGCT": 1968, "CTGGGA": 1969, "CTGGGC": 1970, "CTGGGG": 1971, "CTGGGT": 1972, "CTGGTA": 1973, "CTGGTC": 1974, "CTGGTG": 1975, "CTGGTT": 1976, "CTGTAA": 1977, "CTGTAC": 1978, "CTGTAG": 1979, "CTGTAT": 1980, "CTGTCA": 1981, "CTGTCC": 1982, "CTGTCG": 1983, "CTGTCT": 1984, "CTGTGA": 1985, "CTGTGC": 1986, "CTGTGG": 1987, "CTGTGT": 1988, "CTGTTA": 1989, "CTGTTC": 1990, "CTGTTG": 1991, "CTGTTT": 1992, "CTTAAA": 1993, "CTTAAC": 1994, "CTTAAG": 1995, "CTTAAT": 1996, "CTTACA": 1997, "CTTACC": 1998, "CTTACG": 1999, "CTTACT": 2000, "CTTAGA": 2001, "CTTAGC": 2002, "CTTAGG": 2003, "CTTAGT": 2004, "CTTATA": 2005, "CTTATC": 2006, "CTTATG": 2007, "CTTATT": 2008, "CTTCAA": 2009, "CTTCAC": 2010, "CTTCAG": 2011, "CTTCAT": 2012, "CTTCCA": 2013, "CTTCCC": 2014, "CTTCCG": 2015, "CTTCCT": 2016, "CTTCGA": 2017, "CTTCGC": 2018, "CTTCGG": 2019, "CTTCGT": 2020, "CTTCTA": 2021, "CTTCTC": 2022, "CTTCTG": 2023, "CTTCTT": 2024, "CTTGAA": 2025, "CTTGAC": 2026, "CTTGAG": 2027, "CTTGAT": 2028, "CTTGCA": 2029, "CTTGCC": 2030, "CTTGCG": 2031, "CTTGCT": 2032, "CTTGGA": 2033, "CTTGGC": 2034, "CTTGGG": 2035, "CTTGGT": 2036, "CTTGTA": 2037, "CTTGTC": 2038, "CTTGTG": 2039, "CTTGTT": 2040, "CTTTAA": 2041, "CTTTAC": 2042, "CTTTAG": 2043, "CTTTAT": 2044, "CTTTCA": 2045, "CTTTCC": 2046, "CTTTCG": 2047, "CTTTCT": 2048, "CTTTGA": 2049, "CTTTGC": 2050, "CTTTGG": 2051, "CTTTGT": 2052, "CTTTTA": 2053, "CTTTTC": 2054, "CTTTTG": 2055, "CTTTTT": 2056, "GAAAAA": 2057, "GAAAAC": 2058, "GAAAAG": 2059, "GAAAAT": 2060, "GAAACA": 2061, "GAAACC": 2062, "GAAACG": 2063, "GAAACT": 2064, "GAAAGA": 2065, "GAAAGC": 2066, "GAAAGG": 2067, "GAAAGT": 2068, "GAAATA": 2069, "GAAATC": 2070, "GAAATG": 2071, "GAAATT": 2072, "GAACAA": 2073, "GAACAC": 2074, "GAACAG": 2075, "GAACAT": 2076, "GAACCA": 2077, "GAACCC": 2078, "GAACCG": 2079, "GAACCT": 2080, "GAACGA": 2081, "GAACGC": 2082, "GAACGG": 2083, "GAACGT": 2084, "GAACTA": 2085, "GAACTC": 2086, "GAACTG": 2087, "GAACTT": 2088, "GAAGAA": 2089, "GAAGAC": 2090, "GAAGAG": 2091, "GAAGAT": 2092, "GAAGCA": 2093, "GAAGCC": 2094, "GAAGCG": 2095, "GAAGCT": 2096, "GAAGGA": 2097, "GAAGGC": 2098, "GAAGGG": 2099, "GAAGGT": 2100, "GAAGTA": 2101, "GAAGTC": 2102, "GAAGTG": 2103, "GAAGTT": 2104, "GAATAA": 2105, "GAATAC": 2106, "GAATAG": 2107, "GAATAT": 2108, "GAATCA": 2109, "GAATCC": 2110, "GAATCG": 2111, "GAATCT": 2112, "GAATGA": 2113, "GAATGC": 2114, "GAATGG": 2115, "GAATGT": 2116, "GAATTA": 2117, "GAATTC": 2118, "GAATTG": 2119, "GAATTT": 2120, "GACAAA": 2121, "GACAAC": 2122, "GACAAG": 2123, "GACAAT": 2124, "GACACA": 2125, "GACACC": 2126, "GACACG": 2127, "GACACT": 2128, "GACAGA": 2129, "GACAGC": 2130, "GACAGG": 2131, "GACAGT": 2132, "GACATA": 2133, "GACATC": 2134, "GACATG": 2135, "GACATT": 2136, "GACCAA": 2137, "GACCAC": 2138, "GACCAG": 2139, "GACCAT": 2140, "GACCCA": 2141, "GACCCC": 2142, "GACCCG": 2143, "GACCCT": 2144, "GACCGA": 2145, "GACCGC": 2146, "GACCGG": 2147, "GACCGT": 2148, "GACCTA": 2149, "GACCTC": 2150, "GACCTG": 2151, "GACCTT": 2152, "GACGAA": 2153, "GACGAC": 2154, "GACGAG": 2155, "GACGAT": 2156, "GACGCA": 2157, "GACGCC": 2158, "GACGCG": 2159, "GACGCT": 2160, "GACGGA": 2161, "GACGGC": 2162, "GACGGG": 2163, "GACGGT": 2164, "GACGTA": 2165, "GACGTC": 2166, "GACGTG": 2167, "GACGTT": 2168, "GACTAA": 2169, "GACTAC": 2170, "GACTAG": 2171, "GACTAT": 2172, "GACTCA": 2173, "GACTCC": 2174, "GACTCG": 2175, "GACTCT": 2176, "GACTGA": 2177, "GACTGC": 2178, "GACTGG": 2179, "GACTGT": 2180, "GACTTA": 2181, "GACTTC": 2182, "GACTTG": 2183, "GACTTT": 2184, "GAGAAA": 2185, "GAGAAC": 2186, "GAGAAG": 2187, "GAGAAT": 2188, "GAGACA": 2189, "GAGACC": 2190, "GAGACG": 2191, "GAGACT": 2192, "GAGAGA": 2193, "GAGAGC": 2194, "GAGAGG": 2195, "GAGAGT": 2196, "GAGATA": 2197, "GAGATC": 2198, "GAGATG": 2199, "GAGATT": 2200, "GAGCAA": 2201, "GAGCAC": 2202, "GAGCAG": 2203, "GAGCAT": 2204, "GAGCCA": 2205, "GAGCCC": 2206, "GAGCCG": 2207, "GAGCCT": 2208, "GAGCGA": 2209, "GAGCGC": 2210, "GAGCGG": 2211, "GAGCGT": 2212, "GAGCTA": 2213, "GAGCTC": 2214, "GAGCTG": 2215, "GAGCTT": 2216, "GAGGAA": 2217, "GAGGAC": 2218, "GAGGAG": 2219, "GAGGAT": 2220, "GAGGCA": 2221, "GAGGCC": 2222, "GAGGCG": 2223, "GAGGCT": 2224, "GAGGGA": 2225, "GAGGGC": 2226, "GAGGGG": 2227, "GAGGGT": 2228, "GAGGTA": 2229, "GAGGTC": 2230, "GAGGTG": 2231, "GAGGTT": 2232, "GAGTAA": 2233, "GAGTAC": 2234, "GAGTAG": 2235, "GAGTAT": 2236, "GAGTCA": 2237, "GAGTCC": 2238, "GAGTCG": 2239, "GAGTCT": 2240, "GAGTGA": 2241, "GAGTGC": 2242, "GAGTGG": 2243, "GAGTGT": 2244, "GAGTTA": 2245, "GAGTTC": 2246, "GAGTTG": 2247, "GAGTTT": 2248, "GATAAA": 2249, "GATAAC": 2250, "GATAAG": 2251, "GATAAT": 2252, "GATACA": 2253, "GATACC": 2254, "GATACG": 2255, "GATACT": 2256, "GATAGA": 2257, "GATAGC": 2258, "GATAGG": 2259, "GATAGT": 2260, "GATATA": 2261, "GATATC": 2262, "GATATG": 2263, "GATATT": 2264, "GATCAA": 2265, "GATCAC": 2266, "GATCAG": 2267, "GATCAT": 2268, "GATCCA": 2269, "GATCCC": 2270, "GATCCG": 2271, "GATCCT": 2272, "GATCGA": 2273, "GATCGC": 2274, "GATCGG": 2275, "GATCGT": 2276, "GATCTA": 2277, "GATCTC": 2278, "GATCTG": 2279, "GATCTT": 2280, "GATGAA": 2281, "GATGAC": 2282, "GATGAG": 2283, "GATGAT": 2284, "GATGCA": 2285, "GATGCC": 2286, "GATGCG": 2287, "GATGCT": 2288, "GATGGA": 2289, "GATGGC": 2290, "GATGGG": 2291, "GATGGT": 2292, "GATGTA": 2293, "GATGTC": 2294, "GATGTG": 2295, "GATGTT": 2296, "GATTAA": 2297, "GATTAC": 2298, "GATTAG": 2299, "GATTAT": 2300, "GATTCA": 2301, "GATTCC": 2302, "GATTCG": 2303, "GATTCT": 2304, "GATTGA": 2305, "GATTGC": 2306, "GATTGG": 2307, "GATTGT": 2308, "GATTTA": 2309, "GATTTC": 2310, "GATTTG": 2311, "GATTTT": 2312, "GCAAAA": 2313, "GCAAAC": 2314, "GCAAAG": 2315, "GCAAAT": 2316, "GCAACA": 2317, "GCAACC": 2318, "GCAACG": 2319, "GCAACT": 2320, "GCAAGA": 2321, "GCAAGC": 2322, "GCAAGG": 2323, "GCAAGT": 2324, "GCAATA": 2325, "GCAATC": 2326, "GCAATG": 2327, "GCAATT": 2328, "GCACAA": 2329, "GCACAC": 2330, "GCACAG": 2331, "GCACAT": 2332, "GCACCA": 2333, "GCACCC": 2334, "GCACCG": 2335, "GCACCT": 2336, "GCACGA": 2337, "GCACGC": 2338, "GCACGG": 2339, "GCACGT": 2340, "GCACTA": 2341, "GCACTC": 2342, "GCACTG": 2343, "GCACTT": 2344, "GCAGAA": 2345, "GCAGAC": 2346, "GCAGAG": 2347, "GCAGAT": 2348, "GCAGCA": 2349, "GCAGCC": 2350, "GCAGCG": 2351, "GCAGCT": 2352, "GCAGGA": 2353, "GCAGGC": 2354, "GCAGGG": 2355, "GCAGGT": 2356, "GCAGTA": 2357, "GCAGTC": 2358, "GCAGTG": 2359, "GCAGTT": 2360, "GCATAA": 2361, "GCATAC": 2362, "GCATAG": 2363, "GCATAT": 2364, "GCATCA": 2365, "GCATCC": 2366, "GCATCG": 2367, "GCATCT": 2368, "GCATGA": 2369, "GCATGC": 2370, "GCATGG": 2371, "GCATGT": 2372, "GCATTA": 2373, "GCATTC": 2374, "GCATTG": 2375, "GCATTT": 2376, "GCCAAA": 2377, "GCCAAC": 2378, "GCCAAG": 2379, "GCCAAT": 2380, "GCCACA": 2381, "GCCACC": 2382, "GCCACG": 2383, "GCCACT": 2384, "GCCAGA": 2385, "GCCAGC": 2386, "GCCAGG": 2387, "GCCAGT": 2388, "GCCATA": 2389, "GCCATC": 2390, "GCCATG": 2391, "GCCATT": 2392, "GCCCAA": 2393, "GCCCAC": 2394, "GCCCAG": 2395, "GCCCAT": 2396, "GCCCCA": 2397, "GCCCCC": 2398, "GCCCCG": 2399, "GCCCCT": 2400, "GCCCGA": 2401, "GCCCGC": 2402, "GCCCGG": 2403, "GCCCGT": 2404, "GCCCTA": 2405, "GCCCTC": 2406, "GCCCTG": 2407, "GCCCTT": 2408, "GCCGAA": 2409, "GCCGAC": 2410, "GCCGAG": 2411, "GCCGAT": 2412, "GCCGCA": 2413, "GCCGCC": 2414, "GCCGCG": 2415, "GCCGCT": 2416, "GCCGGA": 2417, "GCCGGC": 2418, "GCCGGG": 2419, "GCCGGT": 2420, "GCCGTA": 2421, "GCCGTC": 2422, "GCCGTG": 2423, "GCCGTT": 2424, "GCCTAA": 2425, "GCCTAC": 2426, "GCCTAG": 2427, "GCCTAT": 2428, "GCCTCA": 2429, "GCCTCC": 2430, "GCCTCG": 2431, "GCCTCT": 2432, "GCCTGA": 2433, "GCCTGC": 2434, "GCCTGG": 2435, "GCCTGT": 2436, "GCCTTA": 2437, "GCCTTC": 2438, "GCCTTG": 2439, "GCCTTT": 2440, "GCGAAA": 2441, "GCGAAC": 2442, "GCGAAG": 2443, "GCGAAT": 2444, "GCGACA": 2445, "GCGACC": 2446, "GCGACG": 2447, "GCGACT": 2448, "GCGAGA": 2449, "GCGAGC": 2450, "GCGAGG": 2451, "GCGAGT": 2452, "GCGATA": 2453, "GCGATC": 2454, "GCGATG": 2455, "GCGATT": 2456, "GCGCAA": 2457, "GCGCAC": 2458, "GCGCAG": 2459, "GCGCAT": 2460, "GCGCCA": 2461, "GCGCCC": 2462, "GCGCCG": 2463, "GCGCCT": 2464, "GCGCGA": 2465, "GCGCGC": 2466, "GCGCGG": 2467, "GCGCGT": 2468, "GCGCTA": 2469, "GCGCTC": 2470, "GCGCTG": 2471, "GCGCTT": 2472, "GCGGAA": 2473, "GCGGAC": 2474, "GCGGAG": 2475, "GCGGAT": 2476, "GCGGCA": 2477, "GCGGCC": 2478, "GCGGCG": 2479, "GCGGCT": 2480, "GCGGGA": 2481, "GCGGGC": 2482, "GCGGGG": 2483, "GCGGGT": 2484, "GCGGTA": 2485, "GCGGTC": 2486, "GCGGTG": 2487, "GCGGTT": 2488, "GCGTAA": 2489, "GCGTAC": 2490, "GCGTAG": 2491, "GCGTAT": 2492, "GCGTCA": 2493, "GCGTCC": 2494, "GCGTCG": 2495, "GCGTCT": 2496, "GCGTGA": 2497, "GCGTGC": 2498, "GCGTGG": 2499, "GCGTGT": 2500, "GCGTTA": 2501, "GCGTTC": 2502, "GCGTTG": 2503, "GCGTTT": 2504, "GCTAAA": 2505, "GCTAAC": 2506, "GCTAAG": 2507, "GCTAAT": 2508, "GCTACA": 2509, "GCTACC": 2510, "GCTACG": 2511, "GCTACT": 2512, "GCTAGA": 2513, "GCTAGC": 2514, "GCTAGG": 2515, "GCTAGT": 2516, "GCTATA": 2517, "GCTATC": 2518, "GCTATG": 2519, "GCTATT": 2520, "GCTCAA": 2521, "GCTCAC": 2522, "GCTCAG": 2523, "GCTCAT": 2524, "GCTCCA": 2525, "GCTCCC": 2526, "GCTCCG": 2527, "GCTCCT": 2528, "GCTCGA": 2529, "GCTCGC": 2530, "GCTCGG": 2531, "GCTCGT": 2532, "GCTCTA": 2533, "GCTCTC": 2534, "GCTCTG": 2535, "GCTCTT": 2536, "GCTGAA": 2537, "GCTGAC": 2538, "GCTGAG": 2539, "GCTGAT": 2540, "GCTGCA": 2541, "GCTGCC": 2542, "GCTGCG": 2543, "GCTGCT": 2544, "GCTGGA": 2545, "GCTGGC": 2546, "GCTGGG": 2547, "GCTGGT": 2548, "GCTGTA": 2549, "GCTGTC": 2550, "GCTGTG": 2551, "GCTGTT": 2552, "GCTTAA": 2553, "GCTTAC": 2554, "GCTTAG": 2555, "GCTTAT": 2556, "GCTTCA": 2557, "GCTTCC": 2558, "GCTTCG": 2559, "GCTTCT": 2560, "GCTTGA": 2561, "GCTTGC": 2562, "GCTTGG": 2563, "GCTTGT": 2564, "GCTTTA": 2565, "GCTTTC": 2566, "GCTTTG": 2567, "GCTTTT": 2568, "GGAAAA": 2569, "GGAAAC": 2570, "GGAAAG": 2571, "GGAAAT": 2572, "GGAACA": 2573, "GGAACC": 2574, "GGAACG": 2575, "GGAACT": 2576, "GGAAGA": 2577, "GGAAGC": 2578, "GGAAGG": 2579, "GGAAGT": 2580, "GGAATA": 2581, "GGAATC": 2582, "GGAATG": 2583, "GGAATT": 2584, "GGACAA": 2585, "GGACAC": 2586, "GGACAG": 2587, "GGACAT": 2588, "GGACCA": 2589, "GGACCC": 2590, "GGACCG": 2591, "GGACCT": 2592, "GGACGA": 2593, "GGACGC": 2594, "GGACGG": 2595, "GGACGT": 2596, "GGACTA": 2597, "GGACTC": 2598, "GGACTG": 2599, "GGACTT": 2600, "GGAGAA": 2601, "GGAGAC": 2602, "GGAGAG": 2603, "GGAGAT": 2604, "GGAGCA": 2605, "GGAGCC": 2606, "GGAGCG": 2607, "GGAGCT": 2608, "GGAGGA": 2609, "GGAGGC": 2610, "GGAGGG": 2611, "GGAGGT": 2612, "GGAGTA": 2613, "GGAGTC": 2614, "GGAGTG": 2615, "GGAGTT": 2616, "GGATAA": 2617, "GGATAC": 2618, "GGATAG": 2619, "GGATAT": 2620, "GGATCA": 2621, "GGATCC": 2622, "GGATCG": 2623, "GGATCT": 2624, "GGATGA": 2625, "GGATGC": 2626, "GGATGG": 2627, "GGATGT": 2628, "GGATTA": 2629, "GGATTC": 2630, "GGATTG": 2631, "GGATTT": 2632, "GGCAAA": 2633, "GGCAAC": 2634, "GGCAAG": 2635, "GGCAAT": 2636, "GGCACA": 2637, "GGCACC": 2638, "GGCACG": 2639, "GGCACT": 2640, "GGCAGA": 2641, "GGCAGC": 2642, "GGCAGG": 2643, "GGCAGT": 2644, "GGCATA": 2645, "GGCATC": 2646, "GGCATG": 2647, "GGCATT": 2648, "GGCCAA": 2649, "GGCCAC": 2650, "GGCCAG": 2651, "GGCCAT": 2652, "GGCCCA": 2653, "GGCCCC": 2654, "GGCCCG": 2655, "GGCCCT": 2656, "GGCCGA": 2657, "GGCCGC": 2658, "GGCCGG": 2659, "GGCCGT": 2660, "GGCCTA": 2661, "GGCCTC": 2662, "GGCCTG": 2663, "GGCCTT": 2664, "GGCGAA": 2665, "GGCGAC": 2666, "GGCGAG": 2667, "GGCGAT": 2668, "GGCGCA": 2669, "GGCGCC": 2670, "GGCGCG": 2671, "GGCGCT": 2672, "GGCGGA": 2673, "GGCGGC": 2674, "GGCGGG": 2675, "GGCGGT": 2676, "GGCGTA": 2677, "GGCGTC": 2678, "GGCGTG": 2679, "GGCGTT": 2680, "GGCTAA": 2681, "GGCTAC": 2682, "GGCTAG": 2683, "GGCTAT": 2684, "GGCTCA": 2685, "GGCTCC": 2686, "GGCTCG": 2687, "GGCTCT": 2688, "GGCTGA": 2689, "GGCTGC": 2690, "GGCTGG": 2691, "GGCTGT": 2692, "GGCTTA": 2693, "GGCTTC": 2694, "GGCTTG": 2695, "GGCTTT": 2696, "GGGAAA": 2697, "GGGAAC": 2698, "GGGAAG": 2699, "GGGAAT": 2700, "GGGACA": 2701, "GGGACC": 2702, "GGGACG": 2703, "GGGACT": 2704, "GGGAGA": 2705, "GGGAGC": 2706, "GGGAGG": 2707, "GGGAGT": 2708, "GGGATA": 2709, "GGGATC": 2710, "GGGATG": 2711, "GGGATT": 2712, "GGGCAA": 2713, "GGGCAC": 2714, "GGGCAG": 2715, "GGGCAT": 2716, "GGGCCA": 2717, "GGGCCC": 2718, "GGGCCG": 2719, "GGGCCT": 2720, "GGGCGA": 2721, "GGGCGC": 2722, "GGGCGG": 2723, "GGGCGT": 2724, "GGGCTA": 2725, "GGGCTC": 2726, "GGGCTG": 2727, "GGGCTT": 2728, "GGGGAA": 2729, "GGGGAC": 2730, "GGGGAG": 2731, "GGGGAT": 2732, "GGGGCA": 2733, "GGGGCC": 2734, "GGGGCG": 2735, "GGGGCT": 2736, "GGGGGA": 2737, "GGGGGC": 2738, "GGGGGG": 2739, "GGGGGT": 2740, "GGGGTA": 2741, "GGGGTC": 2742, "GGGGTG": 2743, "GGGGTT": 2744, "GGGTAA": 2745, "GGGTAC": 2746, "GGGTAG": 2747, "GGGTAT": 2748, "GGGTCA": 2749, "GGGTCC": 2750, "GGGTCG": 2751, "GGGTCT": 2752, "GGGTGA": 2753, "GGGTGC": 2754, "GGGTGG": 2755, "GGGTGT": 2756, "GGGTTA": 2757, "GGGTTC": 2758, "GGGTTG": 2759, "GGGTTT": 2760, "GGTAAA": 2761, "GGTAAC": 2762, "GGTAAG": 2763, "GGTAAT": 2764, "GGTACA": 2765, "GGTACC": 2766, "GGTACG": 2767, "GGTACT": 2768, "GGTAGA": 2769, "GGTAGC": 2770, "GGTAGG": 2771, "GGTAGT": 2772, "GGTATA": 2773, "GGTATC": 2774, "GGTATG": 2775, "GGTATT": 2776, "GGTCAA": 2777, "GGTCAC": 2778, "GGTCAG": 2779, "GGTCAT": 2780, "GGTCCA": 2781, "GGTCCC": 2782, "GGTCCG": 2783, "GGTCCT": 2784, "GGTCGA": 2785, "GGTCGC": 2786, "GGTCGG": 2787, "GGTCGT": 2788, "GGTCTA": 2789, "GGTCTC": 2790, "GGTCTG": 2791, "GGTCTT": 2792, "GGTGAA": 2793, "GGTGAC": 2794, "GGTGAG": 2795, "GGTGAT": 2796, "GGTGCA": 2797, "GGTGCC": 2798, "GGTGCG": 2799, "GGTGCT": 2800, "GGTGGA": 2801, "GGTGGC": 2802, "GGTGGG": 2803, "GGTGGT": 2804, "GGTGTA": 2805, "GGTGTC": 2806, "GGTGTG": 2807, "GGTGTT": 2808, "GGTTAA": 2809, "GGTTAC": 2810, "GGTTAG": 2811, "GGTTAT": 2812, "GGTTCA": 2813, "GGTTCC": 2814, "GGTTCG": 2815, "GGTTCT": 2816, "GGTTGA": 2817, "GGTTGC": 2818, "GGTTGG": 2819, "GGTTGT": 2820, "GGTTTA": 2821, "GGTTTC": 2822, "GGTTTG": 2823, "GGTTTT": 2824, "GTAAAA": 2825, "GTAAAC": 2826, "GTAAAG": 2827, "GTAAAT": 2828, "GTAACA": 2829, "GTAACC": 2830, "GTAACG": 2831, "GTAACT": 2832, "GTAAGA": 2833, "GTAAGC": 2834, "GTAAGG": 2835, "GTAAGT": 2836, "GTAATA": 2837, "GTAATC": 2838, "GTAATG": 2839, "GTAATT": 2840, "GTACAA": 2841, "GTACAC": 2842, "GTACAG": 2843, "GTACAT": 2844, "GTACCA": 2845, "GTACCC": 2846, "GTACCG": 2847, "GTACCT": 2848, "GTACGA": 2849, "GTACGC": 2850, "GTACGG": 2851, "GTACGT": 2852, "GTACTA": 2853, "GTACTC": 2854, "GTACTG": 2855, "GTACTT": 2856, "GTAGAA": 2857, "GTAGAC": 2858, "GTAGAG": 2859, "GTAGAT": 2860, "GTAGCA": 2861, "GTAGCC": 2862, "GTAGCG": 2863, "GTAGCT": 2864, "GTAGGA": 2865, "GTAGGC": 2866, "GTAGGG": 2867, "GTAGGT": 2868, "GTAGTA": 2869, "GTAGTC": 2870, "GTAGTG": 2871, "GTAGTT": 2872, "GTATAA": 2873, "GTATAC": 2874, "GTATAG": 2875, "GTATAT": 2876, "GTATCA": 2877, "GTATCC": 2878, "GTATCG": 2879, "GTATCT": 2880, "GTATGA": 2881, "GTATGC": 2882, "GTATGG": 2883, "GTATGT": 2884, "GTATTA": 2885, "GTATTC": 2886, "GTATTG": 2887, "GTATTT": 2888, "GTCAAA": 2889, "GTCAAC": 2890, "GTCAAG": 2891, "GTCAAT": 2892, "GTCACA": 2893, "GTCACC": 2894, "GTCACG": 2895, "GTCACT": 2896, "GTCAGA": 2897, "GTCAGC": 2898, "GTCAGG": 2899, "GTCAGT": 2900, "GTCATA": 2901, "GTCATC": 2902, "GTCATG": 2903, "GTCATT": 2904, "GTCCAA": 2905, "GTCCAC": 2906, "GTCCAG": 2907, "GTCCAT": 2908, "GTCCCA": 2909, "GTCCCC": 2910, "GTCCCG": 2911, "GTCCCT": 2912, "GTCCGA": 2913, "GTCCGC": 2914, "GTCCGG": 2915, "GTCCGT": 2916, "GTCCTA": 2917, "GTCCTC": 2918, "GTCCTG": 2919, "GTCCTT": 2920, "GTCGAA": 2921, "GTCGAC": 2922, "GTCGAG": 2923, "GTCGAT": 2924, "GTCGCA": 2925, "GTCGCC": 2926, "GTCGCG": 2927, "GTCGCT": 2928, "GTCGGA": 2929, "GTCGGC": 2930, "GTCGGG": 2931, "GTCGGT": 2932, "GTCGTA": 2933, "GTCGTC": 2934, "GTCGTG": 2935, "GTCGTT": 2936, "GTCTAA": 2937, "GTCTAC": 2938, "GTCTAG": 2939, "GTCTAT": 2940, "GTCTCA": 2941, "GTCTCC": 2942, "GTCTCG": 2943, "GTCTCT": 2944, "GTCTGA": 2945, "GTCTGC": 2946, "GTCTGG": 2947, "GTCTGT": 2948, "GTCTTA": 2949, "GTCTTC": 2950, "GTCTTG": 2951, "GTCTTT": 2952, "GTGAAA": 2953, "GTGAAC": 2954, "GTGAAG": 2955, "GTGAAT": 2956, "GTGACA": 2957, "GTGACC": 2958, "GTGACG": 2959, "GTGACT": 2960, "GTGAGA": 2961, "GTGAGC": 2962, "GTGAGG": 2963, "GTGAGT": 2964, "GTGATA": 2965, "GTGATC": 2966, "GTGATG": 2967, "GTGATT": 2968, "GTGCAA": 2969, "GTGCAC": 2970, "GTGCAG": 2971, "GTGCAT": 2972, "GTGCCA": 2973, "GTGCCC": 2974, "GTGCCG": 2975, "GTGCCT": 2976, "GTGCGA": 2977, "GTGCGC": 2978, "GTGCGG": 2979, "GTGCGT": 2980, "GTGCTA": 2981, "GTGCTC": 2982, "GTGCTG": 2983, "GTGCTT": 2984, "GTGGAA": 2985, "GTGGAC": 2986, "GTGGAG": 2987, "GTGGAT": 2988, "GTGGCA": 2989, "GTGGCC": 2990, "GTGGCG": 2991, "GTGGCT": 2992, "GTGGGA": 2993, "GTGGGC": 2994, "GTGGGG": 2995, "GTGGGT": 2996, "GTGGTA": 2997, "GTGGTC": 2998, "GTGGTG": 2999, "GTGGTT": 3000, "GTGTAA": 3001, "GTGTAC": 3002, "GTGTAG": 3003, "GTGTAT": 3004, "GTGTCA": 3005, "GTGTCC": 3006, "GTGTCG": 3007, "GTGTCT": 3008, "GTGTGA": 3009, "GTGTGC": 3010, "GTGTGG": 3011, "GTGTGT": 3012, "GTGTTA": 3013, "GTGTTC": 3014, "GTGTTG": 3015, "GTGTTT": 3016, "GTTAAA": 3017, "GTTAAC": 3018, "GTTAAG": 3019, "GTTAAT": 3020, "GTTACA": 3021, "GTTACC": 3022, "GTTACG": 3023, "GTTACT": 3024, "GTTAGA": 3025, "GTTAGC": 3026, "GTTAGG": 3027, "GTTAGT": 3028, "GTTATA": 3029, "GTTATC": 3030, "GTTATG": 3031, "GTTATT": 3032, "GTTCAA": 3033, "GTTCAC": 3034, "GTTCAG": 3035, "GTTCAT": 3036, "GTTCCA": 3037, "GTTCCC": 3038, "GTTCCG": 3039, "GTTCCT": 3040, "GTTCGA": 3041, "GTTCGC": 3042, "GTTCGG": 3043, "GTTCGT": 3044, "GTTCTA": 3045, "GTTCTC": 3046, "GTTCTG": 3047, "GTTCTT": 3048, "GTTGAA": 3049, "GTTGAC": 3050, "GTTGAG": 3051, "GTTGAT": 3052, "GTTGCA": 3053, "GTTGCC": 3054, "GTTGCG": 3055, "GTTGCT": 3056, "GTTGGA": 3057, "GTTGGC": 3058, "GTTGGG": 3059, "GTTGGT": 3060, "GTTGTA": 3061, "GTTGTC": 3062, "GTTGTG": 3063, "GTTGTT": 3064, "GTTTAA": 3065, "GTTTAC": 3066, "GTTTAG": 3067, "GTTTAT": 3068, "GTTTCA": 3069, "GTTTCC": 3070, "GTTTCG": 3071, "GTTTCT": 3072, "GTTTGA": 3073, "GTTTGC": 3074, "GTTTGG": 3075, "GTTTGT": 3076, "GTTTTA": 3077, "GTTTTC": 3078, "GTTTTG": 3079, "GTTTTT": 3080, "TAAAAA": 3081, "TAAAAC": 3082, "TAAAAG": 3083, "TAAAAT": 3084, "TAAACA": 3085, "TAAACC": 3086, "TAAACG": 3087, "TAAACT": 3088, "TAAAGA": 3089, "TAAAGC": 3090, "TAAAGG": 3091, "TAAAGT": 3092, "TAAATA": 3093, "TAAATC": 3094, "TAAATG": 3095, "TAAATT": 3096, "TAACAA": 3097, "TAACAC": 3098, "TAACAG": 3099, "TAACAT": 3100, "TAACCA": 3101, "TAACCC": 3102, "TAACCG": 3103, "TAACCT": 3104, "TAACGA": 3105, "TAACGC": 3106, "TAACGG": 3107, "TAACGT": 3108, "TAACTA": 3109, "TAACTC": 3110, "TAACTG": 3111, "TAACTT": 3112, "TAAGAA": 3113, "TAAGAC": 3114, "TAAGAG": 3115, "TAAGAT": 3116, "TAAGCA": 3117, "TAAGCC": 3118, "TAAGCG": 3119, "TAAGCT": 3120, "TAAGGA": 3121, "TAAGGC": 3122, "TAAGGG": 3123, "TAAGGT": 3124, "TAAGTA": 3125, "TAAGTC": 3126, "TAAGTG": 3127, "TAAGTT": 3128, "TAATAA": 3129, "TAATAC": 3130, "TAATAG": 3131, "TAATAT": 3132, "TAATCA": 3133, "TAATCC": 3134, "TAATCG": 3135, "TAATCT": 3136, "TAATGA": 3137, "TAATGC": 3138, "TAATGG": 3139, "TAATGT": 3140, "TAATTA": 3141, "TAATTC": 3142, "TAATTG": 3143, "TAATTT": 3144, "TACAAA": 3145, "TACAAC": 3146, "TACAAG": 3147, "TACAAT": 3148, "TACACA": 3149, "TACACC": 3150, "TACACG": 3151, "TACACT": 3152, "TACAGA": 3153, "TACAGC": 3154, "TACAGG": 3155, "TACAGT": 3156, "TACATA": 3157, "TACATC": 3158, "TACATG": 3159, "TACATT": 3160, "TACCAA": 3161, "TACCAC": 3162, "TACCAG": 3163, "TACCAT": 3164, "TACCCA": 3165, "TACCCC": 3166, "TACCCG": 3167, "TACCCT": 3168, "TACCGA": 3169, "TACCGC": 3170, "TACCGG": 3171, "TACCGT": 3172, "TACCTA": 3173, "TACCTC": 3174, "TACCTG": 3175, "TACCTT": 3176, "TACGAA": 3177, "TACGAC": 3178, "TACGAG": 3179, "TACGAT": 3180, "TACGCA": 3181, "TACGCC": 3182, "TACGCG": 3183, "TACGCT": 3184, "TACGGA": 3185, "TACGGC": 3186, "TACGGG": 3187, "TACGGT": 3188, "TACGTA": 3189, "TACGTC": 3190, "TACGTG": 3191, "TACGTT": 3192, "TACTAA": 3193, "TACTAC": 3194, "TACTAG": 3195, "TACTAT": 3196, "TACTCA": 3197, "TACTCC": 3198, "TACTCG": 3199, "TACTCT": 3200, "TACTGA": 3201, "TACTGC": 3202, "TACTGG": 3203, "TACTGT": 3204, "TACTTA": 3205, "TACTTC": 3206, "TACTTG": 3207, "TACTTT": 3208, "TAGAAA": 3209, "TAGAAC": 3210, "TAGAAG": 3211, "TAGAAT": 3212, "TAGACA": 3213, "TAGACC": 3214, "TAGACG": 3215, "TAGACT": 3216, "TAGAGA": 3217, "TAGAGC": 3218, "TAGAGG": 3219, "TAGAGT": 3220, "TAGATA": 3221, "TAGATC": 3222, "TAGATG": 3223, "TAGATT": 3224, "TAGCAA": 3225, "TAGCAC": 3226, "TAGCAG": 3227, "TAGCAT": 3228, "TAGCCA": 3229, "TAGCCC": 3230, "TAGCCG": 3231, "TAGCCT": 3232, "TAGCGA": 3233, "TAGCGC": 3234, "TAGCGG": 3235, "TAGCGT": 3236, "TAGCTA": 3237, "TAGCTC": 3238, "TAGCTG": 3239, "TAGCTT": 3240, "TAGGAA": 3241, "TAGGAC": 3242, "TAGGAG": 3243, "TAGGAT": 3244, "TAGGCA": 3245, "TAGGCC": 3246, "TAGGCG": 3247, "TAGGCT": 3248, "TAGGGA": 3249, "TAGGGC": 3250, "TAGGGG": 3251, "TAGGGT": 3252, "TAGGTA": 3253, "TAGGTC": 3254, "TAGGTG": 3255, "TAGGTT": 3256, "TAGTAA": 3257, "TAGTAC": 3258, "TAGTAG": 3259, "TAGTAT": 3260, "TAGTCA": 3261, "TAGTCC": 3262, "TAGTCG": 3263, "TAGTCT": 3264, "TAGTGA": 3265, "TAGTGC": 3266, "TAGTGG": 3267, "TAGTGT": 3268, "TAGTTA": 3269, "TAGTTC": 3270, "TAGTTG": 3271, "TAGTTT": 3272, "TATAAA": 3273, "TATAAC": 3274, "TATAAG": 3275, "TATAAT": 3276, "TATACA": 3277, "TATACC": 3278, "TATACG": 3279, "TATACT": 3280, "TATAGA": 3281, "TATAGC": 3282, "TATAGG": 3283, "TATAGT": 3284, "TATATA": 3285, "TATATC": 3286, "TATATG": 3287, "TATATT": 3288, "TATCAA": 3289, "TATCAC": 3290, "TATCAG": 3291, "TATCAT": 3292, "TATCCA": 3293, "TATCCC": 3294, "TATCCG": 3295, "TATCCT": 3296, "TATCGA": 3297, "TATCGC": 3298, "TATCGG": 3299, "TATCGT": 3300, "TATCTA": 3301, "TATCTC": 3302, "TATCTG": 3303, "TATCTT": 3304, "TATGAA": 3305, "TATGAC": 3306, "TATGAG": 3307, "TATGAT": 3308, "TATGCA": 3309, "TATGCC": 3310, "TATGCG": 3311, "TATGCT": 3312, "TATGGA": 3313, "TATGGC": 3314, "TATGGG": 3315, "TATGGT": 3316, "TATGTA": 3317, "TATGTC": 3318, "TATGTG": 3319, "TATGTT": 3320, "TATTAA": 3321, "TATTAC": 3322, "TATTAG": 3323, "TATTAT": 3324, "TATTCA": 3325, "TATTCC": 3326, "TATTCG": 3327, "TATTCT": 3328, "TATTGA": 3329, "TATTGC": 3330, "TATTGG": 3331, "TATTGT": 3332, "TATTTA": 3333, "TATTTC": 3334, "TATTTG": 3335, "TATTTT": 3336, "TCAAAA": 3337, "TCAAAC": 3338, "TCAAAG": 3339, "TCAAAT": 3340, "TCAACA": 3341, "TCAACC": 3342, "TCAACG": 3343, "TCAACT": 3344, "TCAAGA": 3345, "TCAAGC": 3346, "TCAAGG": 3347, "TCAAGT": 3348, "TCAATA": 3349, "TCAATC": 3350, "TCAATG": 3351, "TCAATT": 3352, "TCACAA": 3353, "TCACAC": 3354, "TCACAG": 3355, "TCACAT": 3356, "TCACCA": 3357, "TCACCC": 3358, "TCACCG": 3359, "TCACCT": 3360, "TCACGA": 3361, "TCACGC": 3362, "TCACGG": 3363, "TCACGT": 3364, "TCACTA": 3365, "TCACTC": 3366, "TCACTG": 3367, "TCACTT": 3368, "TCAGAA": 3369, "TCAGAC": 3370, "TCAGAG": 3371, "TCAGAT": 3372, "TCAGCA": 3373, "TCAGCC": 3374, "TCAGCG": 3375, "TCAGCT": 3376, "TCAGGA": 3377, "TCAGGC": 3378, "TCAGGG": 3379, "TCAGGT": 3380, "TCAGTA": 3381, "TCAGTC": 3382, "TCAGTG": 3383, "TCAGTT": 3384, "TCATAA": 3385, "TCATAC": 3386, "TCATAG": 3387, "TCATAT": 3388, "TCATCA": 3389, "TCATCC": 3390, "TCATCG": 3391, "TCATCT": 3392, "TCATGA": 3393, "TCATGC": 3394, "TCATGG": 3395, "TCATGT": 3396, "TCATTA": 3397, "TCATTC": 3398, "TCATTG": 3399, "TCATTT": 3400, "TCCAAA": 3401, "TCCAAC": 3402, "TCCAAG": 3403, "TCCAAT": 3404, "TCCACA": 3405, "TCCACC": 3406, "TCCACG": 3407, "TCCACT": 3408, "TCCAGA": 3409, "TCCAGC": 3410, "TCCAGG": 3411, "TCCAGT": 3412, "TCCATA": 3413, "TCCATC": 3414, "TCCATG": 3415, "TCCATT": 3416, "TCCCAA": 3417, "TCCCAC": 3418, "TCCCAG": 3419, "TCCCAT": 3420, "TCCCCA": 3421, "TCCCCC": 3422, "TCCCCG": 3423, "TCCCCT": 3424, "TCCCGA": 3425, "TCCCGC": 3426, "TCCCGG": 3427, "TCCCGT": 3428, "TCCCTA": 3429, "TCCCTC": 3430, "TCCCTG": 3431, "TCCCTT": 3432, "TCCGAA": 3433, "TCCGAC": 3434, "TCCGAG": 3435, "TCCGAT": 3436, "TCCGCA": 3437, "TCCGCC": 3438, "TCCGCG": 3439, "TCCGCT": 3440, "TCCGGA": 3441, "TCCGGC": 3442, "TCCGGG": 3443, "TCCGGT": 3444, "TCCGTA": 3445, "TCCGTC": 3446, "TCCGTG": 3447, "TCCGTT": 3448, "TCCTAA": 3449, "TCCTAC": 3450, "TCCTAG": 3451, "TCCTAT": 3452, "TCCTCA": 3453, "TCCTCC": 3454, "TCCTCG": 3455, "TCCTCT": 3456, "TCCTGA": 3457, "TCCTGC": 3458, "TCCTGG": 3459, "TCCTGT": 3460, "TCCTTA": 3461, "TCCTTC": 3462, "TCCTTG": 3463, "TCCTTT": 3464, "TCGAAA": 3465, "TCGAAC": 3466, "TCGAAG": 3467, "TCGAAT": 3468, "TCGACA": 3469, "TCGACC": 3470, "TCGACG": 3471, "TCGACT": 3472, "TCGAGA": 3473, "TCGAGC": 3474, "TCGAGG": 3475, "TCGAGT": 3476, "TCGATA": 3477, "TCGATC": 3478, "TCGATG": 3479, "TCGATT": 3480, "TCGCAA": 3481, "TCGCAC": 3482, "TCGCAG": 3483, "TCGCAT": 3484, "TCGCCA": 3485, "TCGCCC": 3486, "TCGCCG": 3487, "TCGCCT": 3488, "TCGCGA": 3489, "TCGCGC": 3490, "TCGCGG": 3491, "TCGCGT": 3492, "TCGCTA": 3493, "TCGCTC": 3494, "TCGCTG": 3495, "TCGCTT": 3496, "TCGGAA": 3497, "TCGGAC": 3498, "TCGGAG": 3499, "TCGGAT": 3500, "TCGGCA": 3501, "TCGGCC": 3502, "TCGGCG": 3503, "TCGGCT": 3504, "TCGGGA": 3505, "TCGGGC": 3506, "TCGGGG": 3507, "TCGGGT": 3508, "TCGGTA": 3509, "TCGGTC": 3510, "TCGGTG": 3511, "TCGGTT": 3512, "TCGTAA": 3513, "TCGTAC": 3514, "TCGTAG": 3515, "TCGTAT": 3516, "TCGTCA": 3517, "TCGTCC": 3518, "TCGTCG": 3519, "TCGTCT": 3520, "TCGTGA": 3521, "TCGTGC": 3522, "TCGTGG": 3523, "TCGTGT": 3524, "TCGTTA": 3525, "TCGTTC": 3526, "TCGTTG": 3527, "TCGTTT": 3528, "TCTAAA": 3529, "TCTAAC": 3530, "TCTAAG": 3531, "TCTAAT": 3532, "TCTACA": 3533, "TCTACC": 3534, "TCTACG": 3535, "TCTACT": 3536, "TCTAGA": 3537, "TCTAGC": 3538, "TCTAGG": 3539, "TCTAGT": 3540, "TCTATA": 3541, "TCTATC": 3542, "TCTATG": 3543, "TCTATT": 3544, "TCTCAA": 3545, "TCTCAC": 3546, "TCTCAG": 3547, "TCTCAT": 3548, "TCTCCA": 3549, "TCTCCC": 3550, "TCTCCG": 3551, "TCTCCT": 3552, "TCTCGA": 3553, "TCTCGC": 3554, "TCTCGG": 3555, "TCTCGT": 3556, "TCTCTA": 3557, "TCTCTC": 3558, "TCTCTG": 3559, "TCTCTT": 3560, "TCTGAA": 3561, "TCTGAC": 3562, "TCTGAG": 3563, "TCTGAT": 3564, "TCTGCA": 3565, "TCTGCC": 3566, "TCTGCG": 3567, "TCTGCT": 3568, "TCTGGA": 3569, "TCTGGC": 3570, "TCTGGG": 3571, "TCTGGT": 3572, "TCTGTA": 3573, "TCTGTC": 3574, "TCTGTG": 3575, "TCTGTT": 3576, "TCTTAA": 3577, "TCTTAC": 3578, "TCTTAG": 3579, "TCTTAT": 3580, "TCTTCA": 3581, "TCTTCC": 3582, "TCTTCG": 3583, "TCTTCT": 3584, "TCTTGA": 3585, "TCTTGC": 3586, "TCTTGG": 3587, "TCTTGT": 3588, "TCTTTA": 3589, "TCTTTC": 3590, "TCTTTG": 3591, "TCTTTT": 3592, "TGAAAA": 3593, "TGAAAC": 3594, "TGAAAG": 3595, "TGAAAT": 3596, "TGAACA": 3597, "TGAACC": 3598, "TGAACG": 3599, "TGAACT": 3600, "TGAAGA": 3601, "TGAAGC": 3602, "TGAAGG": 3603, "TGAAGT": 3604, "TGAATA": 3605, "TGAATC": 3606, "TGAATG": 3607, "TGAATT": 3608, "TGACAA": 3609, "TGACAC": 3610, "TGACAG": 3611, "TGACAT": 3612, "TGACCA": 3613, "TGACCC": 3614, "TGACCG": 3615, "TGACCT": 3616, "TGACGA": 3617, "TGACGC": 3618, "TGACGG": 3619, "TGACGT": 3620, "TGACTA": 3621, "TGACTC": 3622, "TGACTG": 3623, "TGACTT": 3624, "TGAGAA": 3625, "TGAGAC": 3626, "TGAGAG": 3627, "TGAGAT": 3628, "TGAGCA": 3629, "TGAGCC": 3630, "TGAGCG": 3631, "TGAGCT": 3632, "TGAGGA": 3633, "TGAGGC": 3634, "TGAGGG": 3635, "TGAGGT": 3636, "TGAGTA": 3637, "TGAGTC": 3638, "TGAGTG": 3639, "TGAGTT": 3640, "TGATAA": 3641, "TGATAC": 3642, "TGATAG": 3643, "TGATAT": 3644, "TGATCA": 3645, "TGATCC": 3646, "TGATCG": 3647, "TGATCT": 3648, "TGATGA": 3649, "TGATGC": 3650, "TGATGG": 3651, "TGATGT": 3652, "TGATTA": 3653, "TGATTC": 3654, "TGATTG": 3655, "TGATTT": 3656, "TGCAAA": 3657, "TGCAAC": 3658, "TGCAAG": 3659, "TGCAAT": 3660, "TGCACA": 3661, "TGCACC": 3662, "TGCACG": 3663, "TGCACT": 3664, "TGCAGA": 3665, "TGCAGC": 3666, "TGCAGG": 3667, "TGCAGT": 3668, "TGCATA": 3669, "TGCATC": 3670, "TGCATG": 3671, "TGCATT": 3672, "TGCCAA": 3673, "TGCCAC": 3674, "TGCCAG": 3675, "TGCCAT": 3676, "TGCCCA": 3677, "TGCCCC": 3678, "TGCCCG": 3679, "TGCCCT": 3680, "TGCCGA": 3681, "TGCCGC": 3682, "TGCCGG": 3683, "TGCCGT": 3684, "TGCCTA": 3685, "TGCCTC": 3686, "TGCCTG": 3687, "TGCCTT": 3688, "TGCGAA": 3689, "TGCGAC": 3690, "TGCGAG": 3691, "TGCGAT": 3692, "TGCGCA": 3693, "TGCGCC": 3694, "TGCGCG": 3695, "TGCGCT": 3696, "TGCGGA": 3697, "TGCGGC": 3698, "TGCGGG": 3699, "TGCGGT": 3700, "TGCGTA": 3701, "TGCGTC": 3702, "TGCGTG": 3703, "TGCGTT": 3704, "TGCTAA": 3705, "TGCTAC": 3706, "TGCTAG": 3707, "TGCTAT": 3708, "TGCTCA": 3709, "TGCTCC": 3710, "TGCTCG": 3711, "TGCTCT": 3712, "TGCTGA": 3713, "TGCTGC": 3714, "TGCTGG": 3715, "TGCTGT": 3716, "TGCTTA": 3717, "TGCTTC": 3718, "TGCTTG": 3719, "TGCTTT": 3720, "TGGAAA": 3721, "TGGAAC": 3722, "TGGAAG": 3723, "TGGAAT": 3724, "TGGACA": 3725, "TGGACC": 3726, "TGGACG": 3727, "TGGACT": 3728, "TGGAGA": 3729, "TGGAGC": 3730, "TGGAGG": 3731, "TGGAGT": 3732, "TGGATA": 3733, "TGGATC": 3734, "TGGATG": 3735, "TGGATT": 3736, "TGGCAA": 3737, "TGGCAC": 3738, "TGGCAG": 3739, "TGGCAT": 3740, "TGGCCA": 3741, "TGGCCC": 3742, "TGGCCG": 3743, "TGGCCT": 3744, "TGGCGA": 3745, "TGGCGC": 3746, "TGGCGG": 3747, "TGGCGT": 3748, "TGGCTA": 3749, "TGGCTC": 3750, "TGGCTG": 3751, "TGGCTT": 3752, "TGGGAA": 3753, "TGGGAC": 3754, "TGGGAG": 3755, "TGGGAT": 3756, "TGGGCA": 3757, "TGGGCC": 3758, "TGGGCG": 3759, "TGGGCT": 3760, "TGGGGA": 3761, "TGGGGC": 3762, "TGGGGG": 3763, "TGGGGT": 3764, "TGGGTA": 3765, "TGGGTC": 3766, "TGGGTG": 3767, "TGGGTT": 3768, "TGGTAA": 3769, "TGGTAC": 3770, "TGGTAG": 3771, "TGGTAT": 3772, "TGGTCA": 3773, "TGGTCC": 3774, "TGGTCG": 3775, "TGGTCT": 3776, "TGGTGA": 3777, "TGGTGC": 3778, "TGGTGG": 3779, "TGGTGT": 3780, "TGGTTA": 3781, "TGGTTC": 3782, "TGGTTG": 3783, "TGGTTT": 3784, "TGTAAA": 3785, "TGTAAC": 3786, "TGTAAG": 3787, "TGTAAT": 3788, "TGTACA": 3789, "TGTACC": 3790, "TGTACG": 3791, "TGTACT": 3792, "TGTAGA": 3793, "TGTAGC": 3794, "TGTAGG": 3795, "TGTAGT": 3796, "TGTATA": 3797, "TGTATC": 3798, "TGTATG": 3799, "TGTATT": 3800, "TGTCAA": 3801, "TGTCAC": 3802, "TGTCAG": 3803, "TGTCAT": 3804, "TGTCCA": 3805, "TGTCCC": 3806, "TGTCCG": 3807, "TGTCCT": 3808, "TGTCGA": 3809, "TGTCGC": 3810, "TGTCGG": 3811, "TGTCGT": 3812, "TGTCTA": 3813, "TGTCTC": 3814, "TGTCTG": 3815, "TGTCTT": 3816, "TGTGAA": 3817, "TGTGAC": 3818, "TGTGAG": 3819, "TGTGAT": 3820, "TGTGCA": 3821, "TGTGCC": 3822, "TGTGCG": 3823, "TGTGCT": 3824, "TGTGGA": 3825, "TGTGGC": 3826, "TGTGGG": 3827, "TGTGGT": 3828, "TGTGTA": 3829, "TGTGTC": 3830, "TGTGTG": 3831, "TGTGTT": 3832, "TGTTAA": 3833, "TGTTAC": 3834, "TGTTAG": 3835, "TGTTAT": 3836, "TGTTCA": 3837, "TGTTCC": 3838, "TGTTCG": 3839, "TGTTCT": 3840, "TGTTGA": 3841, "TGTTGC": 3842, "TGTTGG": 3843, "TGTTGT": 3844, "TGTTTA": 3845, "TGTTTC": 3846, "TGTTTG": 3847, "TGTTTT": 3848, "TTAAAA": 3849, "TTAAAC": 3850, "TTAAAG": 3851, "TTAAAT": 3852, "TTAACA": 3853, "TTAACC": 3854, "TTAACG": 3855, "TTAACT": 3856, "TTAAGA": 3857, "TTAAGC": 3858, "TTAAGG": 3859, "TTAAGT": 3860, "TTAATA": 3861, "TTAATC": 3862, "TTAATG": 3863, "TTAATT": 3864, "TTACAA": 3865, "TTACAC": 3866, "TTACAG": 3867, "TTACAT": 3868, "TTACCA": 3869, "TTACCC": 3870, "TTACCG": 3871, "TTACCT": 3872, "TTACGA": 3873, "TTACGC": 3874, "TTACGG": 3875, "TTACGT": 3876, "TTACTA": 3877, "TTACTC": 3878, "TTACTG": 3879, "TTACTT": 3880, "TTAGAA": 3881, "TTAGAC": 3882, "TTAGAG": 3883, "TTAGAT": 3884, "TTAGCA": 3885, "TTAGCC": 3886, "TTAGCG": 3887, "TTAGCT": 3888, "TTAGGA": 3889, "TTAGGC": 3890, "TTAGGG": 3891, "TTAGGT": 3892, "TTAGTA": 3893, "TTAGTC": 3894, "TTAGTG": 3895, "TTAGTT": 3896, "TTATAA": 3897, "TTATAC": 3898, "TTATAG": 3899, "TTATAT": 3900, "TTATCA": 3901, "TTATCC": 3902, "TTATCG": 3903, "TTATCT": 3904, "TTATGA": 3905, "TTATGC": 3906, "TTATGG": 3907, "TTATGT": 3908, "TTATTA": 3909, "TTATTC": 3910, "TTATTG": 3911, "TTATTT": 3912, "TTCAAA": 3913, "TTCAAC": 3914, "TTCAAG": 3915, "TTCAAT": 3916, "TTCACA": 3917, "TTCACC": 3918, "TTCACG": 3919, "TTCACT": 3920, "TTCAGA": 3921, "TTCAGC": 3922, "TTCAGG": 3923, "TTCAGT": 3924, "TTCATA": 3925, "TTCATC": 3926, "TTCATG": 3927, "TTCATT": 3928, "TTCCAA": 3929, "TTCCAC": 3930, "TTCCAG": 3931, "TTCCAT": 3932, "TTCCCA": 3933, "TTCCCC": 3934, "TTCCCG": 3935, "TTCCCT": 3936, "TTCCGA": 3937, "TTCCGC": 3938, "TTCCGG": 3939, "TTCCGT": 3940, "TTCCTA": 3941, "TTCCTC": 3942, "TTCCTG": 3943, "TTCCTT": 3944, "TTCGAA": 3945, "TTCGAC": 3946, "TTCGAG": 3947, "TTCGAT": 3948, "TTCGCA": 3949, "TTCGCC": 3950, "TTCGCG": 3951, "TTCGCT": 3952, "TTCGGA": 3953, "TTCGGC": 3954, "TTCGGG": 3955, "TTCGGT": 3956, "TTCGTA": 3957, "TTCGTC": 3958, "TTCGTG": 3959, "TTCGTT": 3960, "TTCTAA": 3961, "TTCTAC": 3962, "TTCTAG": 3963, "TTCTAT": 3964, "TTCTCA": 3965, "TTCTCC": 3966, "TTCTCG": 3967, "TTCTCT": 3968, "TTCTGA": 3969, "TTCTGC": 3970, "TTCTGG": 3971, "TTCTGT": 3972, "TTCTTA": 3973, "TTCTTC": 3974, "TTCTTG": 3975, "TTCTTT": 3976, "TTGAAA": 3977, "TTGAAC": 3978, "TTGAAG": 3979, "TTGAAT": 3980, "TTGACA": 3981, "TTGACC": 3982, "TTGACG": 3983, "TTGACT": 3984, "TTGAGA": 3985, "TTGAGC": 3986, "TTGAGG": 3987, "TTGAGT": 3988, "TTGATA": 3989, "TTGATC": 3990, "TTGATG": 3991, "TTGATT": 3992, "TTGCAA": 3993, "TTGCAC": 3994, "TTGCAG": 3995, "TTGCAT": 3996, "TTGCCA": 3997, "TTGCCC": 3998, "TTGCCG": 3999, "TTGCCT": 4000, "TTGCGA": 4001, "TTGCGC": 4002, "TTGCGG": 4003, "TTGCGT": 4004, "TTGCTA": 4005, "TTGCTC": 4006, "TTGCTG": 4007, "TTGCTT": 4008, "TTGGAA": 4009, "TTGGAC": 4010, "TTGGAG": 4011, "TTGGAT": 4012, "TTGGCA": 4013, "TTGGCC": 4014, "TTGGCG": 4015, "TTGGCT": 4016, "TTGGGA": 4017, "TTGGGC": 4018, "TTGGGG": 4019, "TTGGGT": 4020, "TTGGTA": 4021, "TTGGTC": 4022, "TTGGTG": 4023, "TTGGTT": 4024, "TTGTAA": 4025, "TTGTAC": 4026, "TTGTAG": 4027, "TTGTAT": 4028, "TTGTCA": 4029, "TTGTCC": 4030, "TTGTCG": 4031, "TTGTCT": 4032, "TTGTGA": 4033, "TTGTGC": 4034, "TTGTGG": 4035, "TTGTGT": 4036, "TTGTTA": 4037, "TTGTTC": 4038, "TTGTTG": 4039, "TTGTTT": 4040, "TTTAAA": 4041, "TTTAAC": 4042, "TTTAAG": 4043, "TTTAAT": 4044, "TTTACA": 4045, "TTTACC": 4046, "TTTACG": 4047, "TTTACT": 4048, "TTTAGA": 4049, "TTTAGC": 4050, "TTTAGG": 4051, "TTTAGT": 4052, "TTTATA": 4053, "TTTATC": 4054, "TTTATG": 4055, "TTTATT": 4056, "TTTCAA": 4057, "TTTCAC": 4058, "TTTCAG": 4059, "TTTCAT": 4060, "TTTCCA": 4061, "TTTCCC": 4062, "TTTCCG": 4063, "TTTCCT": 4064, "TTTCGA": 4065, "TTTCGC": 4066, "TTTCGG": 4067, "TTTCGT": 4068, "TTTCTA": 4069, "TTTCTC": 4070, "TTTCTG": 4071, "TTTCTT": 4072, "TTTGAA": 4073, "TTTGAC": 4074, "TTTGAG": 4075, "TTTGAT": 4076, "TTTGCA": 4077, "TTTGCC": 4078, "TTTGCG": 4079, "TTTGCT": 4080, "TTTGGA": 4081, "TTTGGC": 4082, "TTTGGG": 4083, "TTTGGT": 4084, "TTTGTA": 4085, "TTTGTC": 4086, "TTTGTG": 4087, "TTTGTT": 4088, "TTTTAA": 4089, "TTTTAC": 4090, "TTTTAG": 4091, "TTTTAT": 4092, "TTTTCA": 4093, "TTTTCC": 4094, "TTTTCG": 4095, "TTTTCT": 4096, "TTTTGA": 4097, "TTTTGC": 4098, "TTTTGG": 4099, "TTTTGT": 4100, "TTTTTA": 4101, "TTTTTC": 4102, "TTTTTG": 4103, "TTTTTT": 4104}, "vocab_size": 4105, "max_token_len": 6, "algorithm": "length-max"}