diff options
| author | eunhhu <[email protected]> | 2026-10-19 05:42:00 +0100 |
|---|---|---|
| committer | eunhhu <[email protected]> | 2026-10-19 05:42:00 +0100 |
| commit | c545227f2461e92afc38a0e1317a288e8c653cc6 (patch) | |
| tree | f236f78a7c0770a5ab07df525d7403077d6b56b5 /docs/research | |
| parent | fe0e33b509b2e4a649647cccbecffa25c754c053 (diff) | |
| download | pure-c545227f2461e92afc38a0e1317a288e8c653cc6.tar.gz pure-c545227f2461e92afc38a0e1317a288e8c653cc6.zip | |
140's 5, line breaking (UAX #14, Unicode 16.0), written in aup with no new opcode (aup's examples/linebreak.aup, the properties as data: 2,787 ranges from the UCD 16.0 Vega's text is frozen at, built by Vega's text/unicode.py, loaded once): every line of LineBreakTest.txt (16,672) and 2,000 random lines (their boundaries as linebreak.py, the Python reference, which passes the test whole, works them out) right on the three paths, the paths' outputs the same; module_specs in make check: the ranges and the lines kept in tests/specs/linebreak (derived from the UCD, the Unicode License v3's notice), run by pure-run --views; bars: written, no workaround (three frictions: hex literals always i64, number no let's name, a let's list one a line), 176 lines against Python's 99, 6,920 ns a code point against Vega's C 34.7 (199x), pure Python 2,523 (Pure 2.7x slower), 1,774 instructions a code point (setup 260, the ranges' binary search 360, decide about 1,150 a boundary); the decisions before 8 (box layout: Taffy can be fetched by cargo, a subset to choose first; as a handler) and 10 (a one-shot timer is a core primitive one spec needs: noted, not made); the suite table's row 5; CHECKPOINT's direction row
Diffstat (limited to 'docs/research')
| -rw-r--r-- | docs/research/140-spec-suite.md | 66 |
1 files changed, 65 insertions, 1 deletions
diff --git a/docs/research/140-spec-suite.md b/docs/research/140-spec-suite.md index 1963c70..1e42a4c 100644 --- a/docs/research/140-spec-suite.md +++ b/docs/research/140-spec-suite.md @@ -51,7 +51,7 @@ | 2 | SHA-256(FIPS 180-4) | 해시 | 32비트 낱말, 회전, xor | NIST CAVP의 SHA 벡터 | 우회로만 될 것으로 보인다(써 보지 않음) | 썼다: NIST 벡터를 세 실행 길에서 지난다(1단계) | | 3 | inflate(RFC 1951) | 압축 | 비트 읽기, 허프만 표, 뒤 참조 | zlib로 압축한 말뭉치를 풀어 원본과 비교 | 못 쓴다(바이트, 비트) | 썼다: zlib 스트림 640개, 손상 240개가 파이썬 참조와 같다. 우회 없음, 줄 1.5배, C의 102배(아래) | | 4 | JSON(RFC 8259) → 트리와 질의 | 깊이를 모르는 데이터 | 글자 읽기, 중첩, 재귀, 갈래 | JSONTestSuite | 못 쓴다(글자, 중첩, 재귀, 갈래) | 썼다: JSONTestSuite와 무작위 문서가 파이썬과 같다(2a–2c) | -| 5 | UTF-8과 줄 나누기(UAX #14) | 텍스트 | 바이트, 코드 포인트, 속성 표 | Unicode의 `LineBreakTest.txt` | 못 쓴다(글자) | 글자 읽기가 컴파일된다(2c). 쓰지 않음 | +| 5 | UTF-8과 줄 나누기(UAX #14) | 텍스트 | 바이트, 코드 포인트, 속성 표 | Unicode의 `LineBreakTest.txt` | 못 쓴다(글자) | 썼다: LineBreakTest.txt 16,672줄 모두와 무작위 2,000줄이 맞다. 줄 1.8배, C의 199배(아래) | | 6 | 관계 질의, 그래프 탐색 | 데이터 모델 | 리스트, 키, 접기, 이벤트의 리스트 | TPC-C, 은행 질의, 파이썬 모델 | 된다(기준선: [092](092-tpcc.md), 040의 은행 질의, aup `routes.aup`) | 된다. TPC-C가 SQLite와 오차 없이 같다(5단계) | | 7 | 텍스트 편집 | UI 개념 | text, 커서 | 편집기의 참조 모델 대조(aup `make check`) | 된다 | 된다 | | 8 | 상자 배치(flex 같은) | UI 개념 | 중첩, 재귀 | 기존 배치 구현(Yoga, Taffy)의 결과와 대조 | 못 쓴다(중첩, 재귀) | 중첩과 재귀는 핸들러에서 된다. 보기에서 재귀 fn을 부르지 못한다(탐침). 쓰지 않음 | @@ -718,6 +718,70 @@ −0.16%, 묶음 BFS −0.12%, 나머지 ±0.03% 안이다(b48 대 b47). - 원본: `2026-10-19-inflate-after.jsonl`, `-dns-after.jsonl`, `-http-after.jsonl`(검사 한 줄과 세 길의 시간). +## 묶음의 5: 줄 나누기 (UAX #14, 2026-10-19) + +결정점 뒤에 처음 쓴 명세다. 새 명령도 코어의 C도 없이 aup와 Pure만으로 썼다(aup의 `examples/linebreak.aup`). 한 줄의 코드 +포인트마다 경계를 표준의 차례대로 첫 규칙이 정한다(Vega의 `text/linebreak.c`와 같은 길). 경계는 0(없음), 1(허락), 2(반드시)이고 +양 끝도 든다. +- **데이터는 입력이다.** 성질은 Vega의 텍스트가 고정한 UCD 16.0에서 짓는다. 범위 2,787개이고, 범위마다 LB1 뒤의 종류, 여는·닫는 + 인용(Pi, Pf), 동아시아(폭 F, W, H), 그림 문자이면서 미할당(Extended_Pictographic과 Cn)을 담는다. 앱은 그것을 load 메시지의 + 행으로 한 번 받아 시작점의 차례로 저장 리스트에 둔다. 코드 포인트의 범위는 위치로 읽는 이분 탐색(파이썬의 `bisect`)으로 찾는다. + 표를 리스트 리터럴로 모듈에 넣지 않은 까닭: 모듈이 곧 표가 되고, 표가 바뀌면 앱을 다시 짓게 된다. +- **위치마다의 값.** Vega의 C처럼 위치마다의 배열(종류, 단위의 종류, 붙은 표시, 단위의 시작, 공백 아닌 앞 단위, 수, 지역 표시의 + 수, 범위)을 레코드 `Text` 하나에 담아 `decide(t, i)`에 넘긴다(C의 `const Text *t`). +- **종류의 이름.** 인자 없는 식 fn(`fn BK = 0; fn CR = 1; ...`)을 한 줄에 여럿 쓴다. + +**맞음.** +- `linebreak_check.py`: LineBreakTest.txt의 16,672줄 모두와 무작위 2,000줄(종류마다의 범위와 규칙이 이름 대는 문자에서 뽑았고, 기대는 + 같은 규칙의 파이썬 참조 `linebreak.py`가 낸다)이 세 실행 길에서 모두 맞고, 세 길의 출력이 같다. 파이썬 참조도 시험 전체를 지난다. + Vega도 시험 전체를 지난다(Vega의 `make check`). +- pure-run은 이제 `--views`로 상태를 빼고 보기만 찍는다. 표를 담은 앱은 명령마다 표 전체를 찍으므로(2,787행 × 16,672줄), 그대로 + 출력을 모은 첫 실행이 메모리를 다 써 Pi가 재설정되었다. +- Pure의 `make check`(`module_specs`)에 들어갔다. 범위와 줄 전부를 `tests/specs/linebreak`에 두었다(UCD에서 파생, Unicode License + v3의 고지와 함께). + +**막대.** + +| 막대 | 잰 것 | | +|---|---|---| +| 쓸 수 있다 | aup와 Pure만. 새 명령 없음 | 지남 | +| 우회가 없다 | 마찰 셋(아래). 우회라 할 꼴은 없다 | 지남(마찰은 적는다) | +| 줄 수 ≤ 파이썬 참조 | aup 176줄(닫는 괄호만인 줄 19) 대 파이썬 99줄 | **못 미침** | +| C 대비 시간 | 줄 18,672개(코드 포인트 61,285개)에서 코드 포인트당 6,920 ns. Vega의 C(34.7 ns)의 **199배**. 순수 파이썬 2,523 ns(Pure가 **2.7배 느림**). 세 길이 같다 | 기록(막대 없음) | +| 견고하다 | 위의 맞음, 세 길이 같음. 세 기계는 아직 | 일부 | + +**마찰 셋.** +1. **16진 리터럴은 언제나 i64다.** 코드 포인트(수)와 견주는 `0x2010`이 섞이지 않아 십진수 `8208`로 썼다. `number(0x2010)`도 i64로 + 남는다. 리터럴이 만나는 것을 따르는 규칙(5단계)이 16진에도 서면 `0x2010`이 수 자리에서 수가 된다. aup의 일이다. +2. `number`는 타입의 이름이라 let의 이름으로 쓸 수 없다(`numeric`으로 썼다). +3. 리스트의 let은 한 줄에 하나다(`let a, b: list of number`가 안 된다). 아홉 줄이 들었다. + +**줄을 길게 한 것.** 176 대 99다. 닫는 괄호의 줄을 빼면 157이다. +- 레코드 셋(`Range`, `Point`, `Text`)이 26줄이다. 파이썬은 튜플과 리스트다. +- 종류의 상수가 5줄, 값의 상수가 1줄이다(파이썬은 2줄과 1줄). +- 위치마다의 리스트를 짓는 고리가 aup에서 리스트마다 `append` 한 줄이다(파이썬은 리스트를 미리 만들고 칸에 쓴다). 리스트의 let 9줄. +- `if … { return … }`의 규칙 줄은 파이썬과 거의 한 줄씩 맞는다. + +**시간이 가는 곳.** 코드 포인트당 Pure 명령이 1,774개이고, 명령 하나에 약 3.9 ns가 든다. +- 위치마다의 리스트 아홉 개를 짓고 레코드로 묶는 데 260개다. 레코드를 지을 때 let의 리스트마다 항목을 복사한다(LIST_VALUE). +- 범위의 이분 탐색이 360개다(열두 번 남짓 저장 리스트의 항목을 읽는다). C는 종류를 두 단계 표에서 한 번에 읽는다(다른 성질은 + 이분 탐색). +- `decide`가 경계마다 1,150개쯤이다. 레코드로 받은 리스트를 읽을 때마다 레지스터에 묶고, 레코드를 받는 작은 fn(`east`, `aksara`)은 + 인라인되지 않고 함수로 돈다. 그 fn들을 손으로 풀어 써도 명령은 1.8%만 준다(1,774 → 1,742). 규칙의 수가 그만큼 많다. +- 원본: `linebreak.py`(파이썬 참조), `linebreak_check.py`(맞음과 줄 수, 경로를 주면 표와 줄을 쓴다), `linebreak_time.c`(Vega의 C와 + Pure의 시간, 둘 다 줄마다의 답이 기대와 같아야 잰다), `2026-10-19-linebreak.jsonl`. + +## 묶음의 8과 10: 쓰기 전의 결정 (2026-10-19) + +- **8, 상자 배치.** 참조 구현이 필요하다. Yoga와 Taffy는 이 기계에 깔려 있지 않지만, cargo로 Taffy(0.15)를 받을 수 있다. 그래서 + Taffy로 무작위 트리의 배치를 내는 작은 Rust 도구가 알려진 구현이 될 수 있다. 다만 flexbox 알고리즘은 크다. 쓸 + 부분집합(방향, grow·shrink·basis, 고정 크기, padding, gap, justify, align, wrap 없이)을 먼저 정해야 막대를 셈할 + 수 있다. 보기로 쓰면 "보기가 블록 fn을 부르지 못한다"에 닿으므로, 핸들러의 꼴로 쓴다. 아직 쓰지 않았다. +- **10, 재시도·물러서기·시간 제한.** 4d 뒤의 타이머는 모듈에 박힌 주기의 입력(`input tick = every 1 second`)이다. 앱이 "T에 한 번"을 + 거는 길은 없다. 그래서 둘 중 하나다. 주기 틱마다 상태의 마감을 보는 꼴로 쓰면(140이 처음에 적은 우회) 새로 보이는 것이 없다. 앱이 + 자기에게 메시지를 걸어 두는 단발 타이머는 핵의 원시(호스트의 일정, 저장, 재생의 결정성)이고, 명세 하나(10)가 닿는다. 쌓임을 + 막는 규칙대로 적어 두고 만들지 않는다. + ## 착수 기준 (다음 일) - **바꿀 결정.** 계산의 핵을 설계한다(027). 위 표의 여덟 후보 가운데 무엇을 어떤 모양으로 받을지 정한다. |
