NLD-Uni / pmj.py
gheinrich's picture
Release NLD-Uni
300c478
Raw History Blame Contribute Delete
2.55 kB
# ADOBE CONFIDENTIAL
# Copyright 2025 Adobe
# All Rights Reserved.
# NOTICE: All information contained herein is, and remains
# the property of Adobe and its suppliers, if any. The intellectual
# and technical concepts contained herein are proprietary to Adobe
# and its suppliers and are protected by all applicable intellectual
# property laws, including trade secret and copyright laws.
# Dissemination of this information or reproduction of this material
# is strictly forbidden unless prior written permission is obtained
# from Adobe.
from __future__ import annotations
from typing import List, Tuple, Optional
import random
def stratified_random(n: int=64, seed: Optional[int]=None, shuffle_blocks: bool=True) -> List[int]:
if n <= 0 or n & n - 1 != 0:
raise ValueError('n must be a positive power of two (e.g., 64)')
rng = random.Random(seed)
occupied = [[False] * n for _ in range(n)]
seq: List[int] = []
blocks: List[Tuple[int, int, int]] = [(0, 0, n)]
def block_has_sample(x0: int, y0: int, size: int) -> bool:
for yy in range(y0, y0 + size):
row = occupied[yy]
for xx in range(x0, x0 + size):
if row[xx]:
return True
return False
def place_random_in_block(x0: int, y0: int, size: int):
x = rng.randrange(x0, x0 + size)
y = rng.randrange(y0, y0 + size)
attempts = 0
while occupied[y][x]:
x = rng.randrange(x0, x0 + size)
y = rng.randrange(y0, y0 + size)
attempts += 1
if attempts > 10000:
raise RuntimeError('Too many attempts to place a sample; logic error?')
occupied[y][x] = True
seq.append(y * n + x)
size = n
while size > 1:
half = size // 2
children: List[Tuple[int, int, int]] = []
for (x0, y0, s) in blocks:
assert s == size
children.extend([(x0, y0, half), (x0 + half, y0, half), (x0, y0 + half, half), (x0 + half, y0 + half, half)])
if shuffle_blocks:
rng.shuffle(children)
for (x0, y0, s) in children:
if not block_has_sample(x0, y0, s):
place_random_in_block(x0, y0, s)
blocks = children
size = half
remaining: List[int] = []
for y in range(n):
for x in range(n):
if not occupied[y][x]:
remaining.append(y * n + x)
rng.shuffle(remaining)
seq.extend(remaining)
assert len(seq) == n * n, (len(seq), n * n)
return seq