diff options
Diffstat (limited to 'docs')
| -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). 위 표의 여덟 후보 가운데 무엇을 어떤 모양으로 받을지 정한다. |
