Merge tools/deps-reach 2a18d9b5: ludic deps' reach sets packed 60 states in a 32-bit int, so states 32 apart shared a bit - 30 a word now; reseeded
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
314b8ce194
6 changed files with 2894 additions and 2814 deletions
9
changes/deps-reach-32-bits.md
Normal file
9
changes/deps-reach-32-bits.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
bump: patch
|
||||
type: fix
|
||||
**`ludic deps`: a reach counts every state apart, however the states are numbered.** The reach and
|
||||
write-reach bitsets packed 60 states to a word, but an `int` is 32 bits, so `1 << 45` came back as bit
|
||||
13 and states 32 apart shared a bit: a function taking both counted one, fewer than it takes, and the
|
||||
counts (`widest_reach`, `widest_write_reach`, `--reach`, `--wreach`) rose and fell with how a program's
|
||||
states happened to be numbered. The sets now hold 30 to a word. On Maroon Lake `widest_reach` goes
|
||||
58 -> 76 and `widest_write_reach` 54 -> 64 - the real numbers, which the old count hid.
|
||||
`examples/state/reach_wide.ludic` (40 states, S00 and S32 taken together) holds it.
|
||||
58
examples/state/reach_wide.ludic
Normal file
58
examples/state/reach_wide.ludic
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
# ludic deps: states numbered past a word's 32 bits are still counted apart. S00 and S32 once shared
|
||||
# a bit (an int is 32 bits and `1 << 32` wrapped), so `pair` reached 1 and `all4` reached 2
|
||||
program ReachWide {
|
||||
state S00 { n: int = 0 }
|
||||
state S01 { n: int = 0 }
|
||||
state S02 { n: int = 0 }
|
||||
state S03 { n: int = 0 }
|
||||
state S04 { n: int = 0 }
|
||||
state S05 { n: int = 0 }
|
||||
state S06 { n: int = 0 }
|
||||
state S07 { n: int = 0 }
|
||||
state S08 { n: int = 0 }
|
||||
state S09 { n: int = 0 }
|
||||
state S10 { n: int = 0 }
|
||||
state S11 { n: int = 0 }
|
||||
state S12 { n: int = 0 }
|
||||
state S13 { n: int = 0 }
|
||||
state S14 { n: int = 0 }
|
||||
state S15 { n: int = 0 }
|
||||
state S16 { n: int = 0 }
|
||||
state S17 { n: int = 0 }
|
||||
state S18 { n: int = 0 }
|
||||
state S19 { n: int = 0 }
|
||||
state S20 { n: int = 0 }
|
||||
state S21 { n: int = 0 }
|
||||
state S22 { n: int = 0 }
|
||||
state S23 { n: int = 0 }
|
||||
state S24 { n: int = 0 }
|
||||
state S25 { n: int = 0 }
|
||||
state S26 { n: int = 0 }
|
||||
state S27 { n: int = 0 }
|
||||
state S28 { n: int = 0 }
|
||||
state S29 { n: int = 0 }
|
||||
state S30 { n: int = 0 }
|
||||
state S31 { n: int = 0 }
|
||||
state S32 { n: int = 0 }
|
||||
state S33 { n: int = 0 }
|
||||
state S34 { n: int = 0 }
|
||||
state S35 { n: int = 0 }
|
||||
state S36 { n: int = 0 }
|
||||
state S37 { n: int = 0 }
|
||||
state S38 { n: int = 0 }
|
||||
state S39 { n: int = 0 }
|
||||
function low(a: mut S00) -> void { a.n += 1 }
|
||||
function high(b: mut S32) -> void { b.n += 1 }
|
||||
function pair(a: mut S00, b: mut S32) -> void {
|
||||
low(a)
|
||||
high(b)
|
||||
}
|
||||
function reads(c: S01, d: S33) -> int { return c.n + d.n }
|
||||
function all4(a: mut S00, b: mut S32, c: S01, d: S33) -> int {
|
||||
pair(a, b)
|
||||
return reads(c, d)
|
||||
}
|
||||
entry (a: mut S00, b: mut S32, c: S01, d: S33) {
|
||||
print(`{all4(a, b, c, d)}`)
|
||||
}
|
||||
}
|
||||
|
|
@ -274,7 +274,7 @@ function deps_alias_write(t: Node) -> void {
|
|||
var g_dr_name: []pointer = new []pointer # the declarations a name can reach: functions, globals
|
||||
var g_dr_node: []Node = new []Node
|
||||
var g_dr_refs: [][]int = new [][]int # what each one names
|
||||
var g_dr_bits: [][]int = new [][]int # the states it reaches, 60 to a word
|
||||
var g_dr_bits: [][]int = new [][]int # the states it reaches, DR_BITS to a word
|
||||
var g_dr_wbits: [][]int = new [][]int # ... and of them the ones it takes `mut` somewhere down
|
||||
var g_dr_find_k: []pointer = new []pointer
|
||||
var g_dr_rl_name: []pointer = new []pointer # a local holding one entry of a registry ...
|
||||
|
|
@ -294,8 +294,11 @@ function dr_state_ix(t: pointer) -> int {
|
|||
}
|
||||
return -1
|
||||
}
|
||||
function dr_set(bits: []int, s: int) -> void { bits[s / 60] = bits[s / 60] | (1 << (s % 60)) }
|
||||
function dr_words() -> int { return len(g_state_names) / 60 + 1 }
|
||||
# an int is 32 bits: `1 << 45` is not bit 45, it came back as bit 13, so states 32 apart shared a bit
|
||||
# and a function that took both counted one - the counts rose and fell with how the states were numbered
|
||||
const DR_BITS: int = 30
|
||||
function dr_set(bits: []int, s: int) -> void { bits[s / DR_BITS] = bits[s / DR_BITS] | (1 << (s % DR_BITS)) }
|
||||
function dr_words() -> int { return len(g_state_names) / DR_BITS + 1 }
|
||||
function dr_index(name: pointer) -> int {
|
||||
let n = ck_tab_get(g_dr_find_k, g_dr_find_v, name)
|
||||
if n == null { return -1 }
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
|
|
@ -698,6 +698,15 @@ function deps_wreach_case() -> void {
|
|||
if not s_contains(top, " 0 2 2 changes (examples/state/write_reach.ludic:27)") or not s_contains(top, " 0 1 0 asks (examples/state/write_reach.ludic:22)") or s_contains(top, "asks_local") { bad2(lbl, s_trim(top)); return }
|
||||
ok(lbl)
|
||||
}
|
||||
# an int is 32 bits: states numbered 32 apart once shared a bit of the reach, so `pair` (S00 and S32)
|
||||
# reached 1 and could change 1; the counts must not depend on how the states are numbered
|
||||
function deps_reach_wide_case() -> void {
|
||||
let lbl = "ludic deps: a reach counts states past 32 apart (S00 and S32 are two states, not one)"
|
||||
let top = capture(`bin/ludic deps examples/state/reach_wide.ludic --wreach 2 2>&1`)
|
||||
if not s_contains(top, " 4 4 2 all4 (examples/state/reach_wide.ludic:51)\n 2 2 2 pair (examples/state/reach_wide.ludic:46)") { bad2(lbl, s_trim(top)); return }
|
||||
let sum = capture(`bin/ludic deps examples/state/reach_wide.ludic 2>&1`)
|
||||
if s_contains(sum, "widest_reach: 4") and s_contains(sum, "widest_write_reach: 2") { ok(lbl) } else { bad2(lbl, s_trim(sum)) }
|
||||
}
|
||||
# a program built headless with the toolchain and run: its first line
|
||||
function headless_case(path: pointer, exp: pointer, label: pointer) -> void {
|
||||
let out = `{tmp_dir()}/h_{flat(path)}`
|
||||
|
|
@ -1234,6 +1243,7 @@ function cmd_dev_test() -> int {
|
|||
actions_deps_case()
|
||||
deps_reach_case()
|
||||
deps_wreach_case()
|
||||
deps_reach_wide_case()
|
||||
feat_case("state/reach", "", "3", "reach.ludic (0.R4: a step list of fn values supplies each step its states)")
|
||||
feat_case("actions/phases", "dd a q", "1 0 2 0 2 1 1 1 1 2 1 2", "phases.ludic (0.R: the frame loop drains the queue after every phase - Input's actions are reduced before Update)")
|
||||
feat_case("actions/runaway", "", "actions: Ping is still being dispatched after 64 rounds of reducers - a reducer dispatches what dispatches it", "runaway.ludic (0.R: a reducer that dispatches what dispatches it is stopped by name)")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue