Download scripts/huffman_model.py from nmarshall/urt-rs: direct link, hf CLI and curl.
- Browser
- Download file 4.92 kB
-
https://huggingface.co/nmarshall/urt-rs/resolve/main/scripts/huffman_model.py
- Command line
-
hf download hf://nmarshall/urt-rs/scripts/huffman_model.py
-
curl -L -o huffman_model.py https://huggingface.co/nmarshall/urt-rs/resolve/main/scripts/huffman_model.py
4.92 kB
| #!/usr/bin/env python3 | |
| """Provisional node-level recoding of observed Linux Huff_addRef/increment semantics.""" | |
| class Node: | |
| __slots__=('index','left','right','parent','next','previous','head','weight','symbol') | |
| def __init__(self,index,symbol=0,weight=0): | |
| self.index=index;self.symbol=symbol;self.weight=weight | |
| self.left=self.right=self.parent=self.next=self.previous=self.head=None | |
| class Huffman: | |
| def __init__(self,second=False): | |
| self.nodes=[Node(0,256)];self.root=self.nyt=self.nodes[0];self.lookup={256:self.nyt};self.cells=[];self.free=None;self.second=second;self.events={} | |
| def event(self,name):self.events[name]=self.events.get(name,0)+1 | |
| def allocate_cell(self,node): | |
| if self.free is None:i=len(self.cells);self.cells.append(node);self.event('cell_allocate') | |
| else:i=self.free;self.free=self.cells[i];self.cells[i]=node;self.event('cell_reuse') | |
| return i | |
| def free_cell(self,i):self.cells[i]=self.free;self.free=i;self.event('cell_free') | |
| def swap_tree(self,a,b): | |
| pa,pb=a.parent,b.parent | |
| if pa: | |
| if pa.left is a:pa.left=b | |
| else:pa.right=b | |
| else:self.root=b | |
| if pb: | |
| if pb.left is b:pb.left=a | |
| else:pb.right=a | |
| else:self.root=a | |
| a.parent,b.parent=pb,pa;self.event('tree_swap') | |
| def swap_list(self,a,b): | |
| a.next,b.next=b.next,a.next;a.previous,b.previous=b.previous,a.previous | |
| if a.next is a:a.next=b | |
| if b.next is b:b.next=a | |
| for n in [a,b]: | |
| if n.next:n.next.previous=n | |
| if n.previous:n.previous.next=n | |
| self.event('list_swap') | |
| def increment(self,node): | |
| if node is None:self.event('null_increment');return | |
| if node.next and node.next.weight==node.weight: | |
| self.event('equal_next');leader=self.cells[node.head] | |
| if leader is not node.parent:self.swap_tree(leader,node) | |
| else:self.event('leader_is_parent') | |
| self.swap_list(leader,node) | |
| if node.previous and node.previous.weight==node.weight:self.cells[node.head]=node.previous;self.event('old_head_previous') | |
| else:self.free_cell(node.head) | |
| node.weight=(node.weight+1)&0xffffffff | |
| if node.next and node.next.weight==node.weight:node.head=node.next.head;self.event('new_head_shared') | |
| else:node.head=self.allocate_cell(node) | |
| if node.parent: | |
| self.increment(node.parent) | |
| if node.previous is node.parent: | |
| self.event('post_parent_adjacent');parent=node.parent;self.swap_list(node,parent) | |
| if self.cells[node.head] is node:self.cells[node.head]=parent;self.event('post_parent_head') | |
| def add(self,symbol): | |
| symbol&=255 | |
| if symbol in self.lookup:self.event('existing');self.increment(self.lookup[symbol]);return | |
| self.event('new');leaf=Node(len(self.nodes),symbol,1);internal=Node(len(self.nodes)+1,257,1);self.nodes.extend([leaf,internal]);nyt=self.nyt | |
| internal.next=nyt.next | |
| if internal.next: | |
| internal.next.previous=internal | |
| if internal.next.weight==1:internal.head=internal.next.head | |
| else:internal.head=self.allocate_cell(internal) | |
| else:internal.head=self.allocate_cell(internal) | |
| nyt.next=internal;internal.previous=nyt | |
| leaf.next=nyt.next;leaf.next.previous=leaf;leaf.head=leaf.next.head;nyt.next=leaf;leaf.previous=nyt | |
| parent=nyt.parent | |
| if parent: | |
| if parent.left is nyt:parent.left=internal | |
| else:parent.right=internal | |
| else:self.root=internal | |
| internal.left=nyt;internal.right=leaf;internal.parent=parent;leaf.parent=nyt.parent=internal;self.lookup[symbol]=leaf;self.increment(parent) | |
| def codewords(self): | |
| out={} | |
| def walk(n,bits): | |
| if n.symbol!=257:out[n.symbol]=bits;return | |
| walk(n.left,bits+[0]);walk(n.right,bits+[1]) | |
| walk(self.root,[]);return out | |
| def state(self,base=0x10000): | |
| def addr(n):return 0 if n is None else base+0x830+56*n.index | |
| def cell(i):return 0 if i is None else base+0xb030+8*i | |
| nodes=[{'index':n.index,'address':addr(n),'left':addr(n.left),'right':addr(n.right),'parent':addr(n.parent),'next':addr(n.next),'previous':addr(n.previous),'head_cell':cell(n.head),'weight':n.weight,'symbol':n.symbol} for n in self.nodes] | |
| heads=sorted({n.head for n in self.nodes if n.head is not None}) | |
| values=[addr(v) if isinstance(v,Node) else cell(v) for v in self.cells] | |
| return {'node_count':len(nodes),'pointer_cell_count':len(self.cells),'root':addr(self.root),'list_start':addr(self.nyt),'tail_slot':addr(self.nyt) if self.second else 0,'free_head':cell(self.free),'nodes':nodes,'heads':[[cell(i),addr(self.cells[i])] for i in heads],'pointer_cells':values,'lookup':[[s,addr(n)] for s,n in sorted(self.lookup.items())]} | |