Skip to content
switham edited this page Jan 31, 2014 · 5 revisions

A place to list applications you know of where treeprng might be useful, how well it does or doesn't fit, etc.

To discuss whether treeprng is even a good idea (at least in its present state), TheWholeIdea.


Two actual use-cases of my own

Composing melodies

My program creates them faster than I can listen to them. Most are pretty boring but some are fantastic. I want to create an "album" on a given day full of melodies I can listen to while driving. Later, if I find a piece I like I want the ability to regenerate it at home by remembering its "track name". Within the algorithm the songs are broken down hierarchically by time, and across different parameters of the notes, not all of which apply to every instrument. So, differently-named songs within each album, and criss-crossing groupings of random numbers for each song. Currently there's a problem, the ad-hoc (in retrospect) way I cascaded seeds causes similar songs to be produced sometimes. I think Python's 32-bit hashing on the way to the seed may have contributed.

testing a data compression module.

I want some random input "files" that match various statistics; I run them through various tests and a) check that the decompressed output matches the original, b) check the compression ratio, c) run the same tests on the same data with another algorithm and compare compression ratios. I would rather not store a large random file for each set of input statistics.


Imaginary cases

virtual / procedurally generated worlds

The most fitting use case I think. You want to visit places at random, seeing them at various zoom levels. Especially if they contain artifacts or things like plants that would naturally have a hierarchical structure.

regression tests on a changing program

Say this is the first version of a procedure that generates one of many test cases:

def create_widget(prng):
    widget = Widget()
    widget.x = prng.random()
    widget.y = prng.random()
    return widget

Now someone decides that a widget has more fields.

def create_widget(prng):
     widget = Widget()
     widget.x = prng.random()
     widget.x_vel = prng.random() - .5
     widget.y = prng.random()
     widget.y_vel = prng.random() - .5
     return widget

Oops, y isn't the same value anymore, gimme a minute...

def create_widget(prng):
     widget = Widget()
     widget.x = prng.random()
     widget.y = prng.random()
     widget.x_vel = prng.random() - .5
     widget.y_vel = prng.random() - .5
     return widget

Now y is the same, better, except that there were more widgets...

widgets = [create_widget(prng), create_widget(prng)]

So now the first widget is the same as before (with additions), but the second widget is completely different. Which could also be fixed, but think about a piece of code with a long sequence of these fixes. You have to pull code out of its hierarchical structure in layers, one for each revision. And also, now I want to revisit case 363, but that case is no longer derived from a contiguous part of the sequence.

The reason any fixes at all are needed is that a sequence of random numbers was never what I wanted. I want random numbers to go in their logical places and stay there, regardless of what sequence I happen to fetch them in, whether I lose interest in some, or whether I add new, related ones.

Using a sequential prng is like having to manually assign a permanent physical address to each variable or field, which you won't be allowed to change in revisions of the code. It's like being asked to give each file a contiguous sequence of disk blocks you can't change. That's what dynamic memory allocators and file systems are for, and by analogy TreePRNG.

The TreePRNG version of my function gives names to the numbers, relative to a "local prng"...

def create_widget(tprng):
     widget = Widget()
     widget.x = tprng["x"].random()
     widget.x_vel = tprng["x_vel"].random() - .5
     widget.y = tprng["y"].random()
     widget.y_vel = tprng["y_vel"].random() - .5
     return widget

...which in turn is a sub-prng of another prng:

widgets = [create_widget(prng_root[0]), create_widget(prng_root[1])

--SteveWitham


Clone this wiki locally