this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Expand grammar: cal(), logic/sequent, vec, overbrace, tables, bra-ket, intervals

generate_typeset.py:
- Add _CALLIGRAPHIC pool; cal(X) appears in _atom() at ~10% and cal(P)(expr) in tail
- Add phi.alt, epsilon.alt, theta.alt (LaTeX \varphi, \varepsilon, \vartheta variants)
- Add logic/sequent block (3%): tack.r, and/or/=>/<=>/xor, not, models, top/bot, type judgments
- Add vec(a,b) / vec(a,b,c) column vectors
- Add underbrace/overbrace/underbracket/overbracket/underparen/overparen with atom labels
- Add bra-ket Dirac notation: lr(|ψ⟩), lr(⟨ψ|), lr(⟨φ|ψ⟩), lr(⟨A⟩)
- Add intervals via lr(): closed [a,b], open (a,b), half-open [a,b) and (a,b]
- 3x3 matrices (35% of matrix branch, was 2x2 only)
- Cartesian product type signatures: f: A×B→C, f: A×B×C→D
- _atom() now includes calligraphic letters

generate_mixed.py:
- Add _generate_table(): 15% of bodies; 2-4 cols, 2-5 rows; cell complexity
inversely proportional to table size; delegates to _inline_seq for unified
content (inherits emoji, math/text mix automatically)
- Table inset (x:5pt, y:7pt) to prevent underbrace/overbrace label clipping

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

+84 -13
+33 -1
src/generate_mixed.py
··· 193 193 return lines 194 194 195 195 196 + def _generate_table(rng: random.Random) -> str: 197 + ncols = rng.randint(2, 4) 198 + nrows = rng.randint(2, 5) 199 + ncells = ncols * nrows 200 + 201 + # Larger tables get shorter cells -- this is fragment OCR, not big documents 202 + if ncells <= 6: 203 + max_tok = rng.choices([1, 2, 3], weights=[3, 4, 2])[0] 204 + elif ncells <= 12: 205 + max_tok = rng.choices([1, 2], weights=[4, 3])[0] 206 + else: 207 + max_tok = 1 208 + 209 + cells: list[str] = [] 210 + 211 + # Optional header row (bold text labels) 212 + if rng.random() < 0.6: 213 + words = rng.sample(_WORDS, k=ncols) 214 + cells.extend(f"[*{w}*]" for w in words) 215 + 216 + for _ in range(nrows): 217 + for _ in range(ncols): 218 + n = rng.randint(1, max_tok) 219 + content = _inline_seq(rng, n, require_math=rng.random() < 0.6) 220 + cells.append(f"[{content}]") 221 + 222 + return f"#table(columns: {ncols}, inset: (x: 5pt, y: 7pt), {', '.join(cells)})" 223 + 224 + 196 225 def generate_body(rng: random.Random) -> str: 197 - if rng.random() < 0.3: 226 + r = rng.random() 227 + if r < 0.15: 228 + return _generate_table(rng) 229 + elif r < 0.42: # ~27% lists (was 30%) 198 230 return "\n".join(_list_body(rng)) 199 231 n = rng.choices([2, 3, 4, 5, 6, 7], weights=[4, 8, 7, 5, 3, 1])[0] 200 232 return _inline_seq(rng, n, require_math=True)
+51 -12
src/generate_typeset.py
··· 193 193 194 194 # ── Sets and types ──────────────────────────────────────────────────────── 195 195 196 - elif c < 0.87: 196 + elif c < 0.865: 197 197 # membership: x in RR, k in ZZ, ... 198 198 return f"{_atom(rng)} in {rng.choice(_BLACKBOARD)}" 199 - elif c < 0.89: 199 + elif c < 0.875: 200 200 op = rng.choice(_SET_OPS) 201 201 return f"({_expr(rng, depth+1)} {op} {_expr(rng, depth+1)})" 202 202 203 + # ── Vectors and annotated expressions ───────────────────────────────────── 204 + 205 + elif c < 0.885: 206 + # Column vector: vec(a, b) or vec(a, b, c) 207 + n = rng.choices([2, 3], weights=[3, 2])[0] 208 + return f"vec({', '.join(_atom(rng) for _ in range(n))})" 209 + elif c < 0.895: 210 + # Over/under brace, bracket, paren with annotation label 211 + fn = rng.choice(["underbrace", "overbrace", 212 + "underbracket", "overbracket", 213 + "underparen", "overparen"]) 214 + label = _atom(rng) if rng.random() < 0.6 else f"{_atom(rng)} + {_atom(rng)}" 215 + return f"{fn}({_expr(rng, depth+1)}, {label})" 216 + 203 217 # ── Function signatures / arrows ────────────────────────────────────────── 204 218 205 - elif c < 0.91: 219 + elif c < 0.915: 206 220 # f: RR^n -> RR or f: A -> B or f: A times B -> C 207 221 fname = rng.choice(_VARS) 208 222 dom = rng.choice(_BLACKBOARD) ··· 223 237 224 238 # ── Logic / type theory ─────────────────────────────────────────────────── 225 239 226 - elif c < 0.93: 240 + elif c < 0.935: 227 241 q = rng.choice(["forall", "exists"]) 228 242 v = rng.choice(_VARS) 229 243 return f"({q} {v}, {_expr(rng, depth+1)})" 230 - elif c < 0.94: 244 + elif c < 0.945: 231 245 v = rng.choice(_VARS) 232 246 return f"lambda {v}. {_expr(rng, depth+1)}" 233 247 ··· 272 286 273 287 # ── Miscellaneous useful constructs ─────────────────────────────────────── 274 288 275 - elif c < 0.975: 289 + elif c < 0.974: 276 290 fn = rng.choice(["abs", "floor", "ceil"]) 277 291 return f"{fn}({_expr(rng, depth+1)})" 278 - elif c < 0.985: 292 + elif c < 0.979: 279 293 # piecewise / cases 280 294 e1 = _expr(rng, depth+1) 281 295 e2 = _expr(rng, depth+1) 282 296 cond = f"{_atom(rng)} > {_atom(rng)}" 283 297 return f'cases({e1} "if" {cond}, {e2} "otherwise")' 284 - elif c < 0.992: 298 + elif c < 0.984: 299 + # Bra-ket / Dirac notation: ket |ψ⟩, bra ⟨ψ|, braket ⟨φ|ψ⟩, expectation ⟨A⟩ 300 + # lr() auto-sizes delimiters; | is a plain vertical bar in math 301 + r2 = rng.random() 302 + psi = _atom(rng) 303 + if r2 < 0.30: 304 + return f"lr(| {psi} chevron.r)" 305 + elif r2 < 0.60: 306 + return f"lr(chevron.l {psi} |)" 307 + elif r2 < 0.82: 308 + return f"lr(chevron.l {_atom(rng)} | {psi} chevron.r)" 309 + else: 310 + return f"lr(chevron.l {_expr(rng, depth+1)} chevron.r)" 311 + elif c < 0.988: 312 + # Intervals: lr() handles mismatched delimiters for half-open forms 313 + a, b = _atom(rng), _atom(rng) 314 + r2 = rng.random() 315 + if r2 < 0.25: 316 + return f"lr([{a}, {b}])" # closed [a, b] 317 + elif r2 < 0.50: 318 + return f"lr(({a}, {b}))" # open (a, b) 319 + elif r2 < 0.75: 320 + return f"lr([{a}, {b}))" # half-open [a, b) 321 + else: 322 + return f"lr(({a}, {b}])" # half-open (a, b] 323 + elif c < 0.993: 285 324 # indexed sequence with ellipsis: (a_1, dots.c, a_n) 286 325 # parens required -- bare commas break multi-arg contexts (sqrt, norm, etc.) 287 326 v = rng.choice(_VARS) 288 327 n = rng.choice(["n", "m", "N", "k"]) 289 328 return f"({v}_1, dots.c, {v}_{n})" 290 - elif c < 0.994: 329 + elif c < 0.995: 291 330 # chevron bracket pair (inner product, type constructors) 292 331 # outer parens prevent comma from being parsed as extra function arg 293 332 return f"(chevron.l {_expr(rng, depth+1)}, {_expr(rng, depth+1)} chevron.r)" 294 - elif c < 0.997: 333 + elif c < 0.9975: 295 334 # custom math operators: op("rank")(x) gives proper operatorname spacing 296 335 return f'op("{rng.choice(_CUSTOM_OPS)}")({_expr(rng, depth+1)})' 297 - elif c < 0.9985: 336 + elif c < 0.999: 298 337 # calligraphic applied to expr: cal(P)(X) powerset, cal(H) Hilbert space, etc. 299 338 return f"cal({rng.choice(['P', 'F', 'H', 'L', 'B'])})({_expr(rng, depth+1)})" 300 - elif c < 0.999: 339 + elif c < 0.9999: 301 340 # explicit math spacing between two sub-expressions 302 341 sp = rng.choice(_SPACES) 303 342 return f"{_atom(rng)} {sp} {_atom(rng)}"