On 28/04/2019 19:11, Gilles Sadowski wrote:
Le dim. 28 avr. 2019 à 17:02, Alex Herbert <alex.d.herb...@gmail.com> a écrit :


On 28 Apr 2019, at 00:59, Bernd Eckenfels <e...@zusammenkunft.net> wrote:

Hello,

Just a question, I am unclear on the terminology, is „jump“ (did I miss the 
discussion leading toot?) something invented here? It sounds to me like this is 
a generator where the state can be cloned and it is „seekable“. It probably 
makes sense to have those two dimensions separated anyway.
Hi Bernd, thanks for the input.

This thread started with the definition:
Jump:

To create a new instance of the generator that is deterministically based on 
the state of the current instance but advanced a set number of iterations.


However it is not required to create a new instance at the same time as 
jumping. You are correct in that this is two functionalities:

1. Jump forward in the sequence
2. Copy

However the two are coupled. Having jump on its own is useless (why move 
forward in the sequence without using it?). So a copy needs to be created 
somewhere before/after the jump.

The idea of a jump is to create a series of the generator at different points 
in the state. The generators can be used for parallel computations and will be 
ensured to not overlap in their output sequence for number of outputs skipped 
by the jump length.

FYI. The generators that support this have jump sizes of 2^64, 96, 128, 192, 
256 and 512. So this is a lot of output sequence to jump.

Copy on its own works but for what purpose? If you want a second generator at 
the moment you just create a new one (with a different seed). Duplicate copies 
of generators is prone to potential pitfalls where simulations are not as 
random as you intend. For a special use case where you wish to run multiple 
simulations with the same generator you can use the Restorable interface to 
save the state of one and re-create it in other instances.

The current thread came to the choice of:

So the options are (in all cases returning the copy):

1. createAndJumpCopy
2. copyAndJumpParent
3. jumpParentAndCopy
4. jump and copy separately
Jump and copy separately was ruled out to discourage misuse of copy.

The current suggestion is 1. Create a copy and jump that ahead. The current 
instance is not affected.

I now consider this to be weaker for a variety of use cases than 2. This copies 
the current state for use and then jumps the parent ahead. So this alters the 
state of the parent generator.

Note that all other methods of a generator alter its state. So having jump 
alter its state is reasonable.

The most flexible API is to separate jump and copy into two methods. We can 
still support helper functions that take in a Jumpable generator and create a 
jump series of generators for parallel work. Separating jump and copy allows 
the functionality to be used in a larger number of ways than any other 
interface that attempts to combine jump and copy.

I am fine with having separate jump and copy. If so the copy method, being part 
of the Jumpable interface, will be functionally coupled with the jump method 
and should be described in Javadoc with the intended purpose to use it to copy 
the parent state either before or after a jump into a child generator.

As a precursor this API is very flexible:

JumpableUniformRandomProvider extends UniformRandomProvider {
     /** Jump and return same instance. */
     JumpableUniformRandomProvider jump();
     /** Copy the instance. */
     JumpableUniformRandomProvider copy();
}

Returning the same instance in jump() allows method chaining such as either:

rng.jump().copy();
rng.copy().jump();

This potential pitfall is that a user may do this:

UniformRandomProvider rng1 = rng.copy().jump();
UniformRandomProvider rng2 = rng.copy().jump();

Where rng1 and 2 will be the same, 1 jump ahead of the parent state. Or:

UniformRandomProvider rng1 = rng.jump();
UniformRandomProvider rng2 = rng.jump();

Where rng, rng1 and rng2 are the same instance all 2 jumps ahead of the start 
point.

I think our purpose is to provide an API for the generators that can jump and 
that is not too restrictive given the use cases we have so far thought up. 
There may be other ideas of use cases that cannot be done with the coupled 
functionality of:

JumpableUniformRandomProvider extends UniformRandomProvider {
     /** Copy the instance, then jump ahead. Return the copy of the previous 
state. */
     JumpableUniformRandomProvider jump();
}

JumpableUniformRandomProvider extends UniformRandomProvider {
     /** Copy the instance, then jump the copy ahead. Return the copy. The 
current instance is not affected. */
     JumpableUniformRandomProvider jump();
}

So the split functions without allowing method chaining:

JumpableUniformRandomProvider extends UniformRandomProvider {
     /** Jump the current instance ahead. */
     void jump();
     /** Copy the instance. This is intended to be used either before or after 
a call to jump()
      * to create a series of generators. */
     JumpableUniformRandomProvider copy();
}
As you indicated above, there is no advantage in having separate
"jump()" and "copy()",
as counter-intuitive it may look at first sight.

So is the favoured approach now to make the jump method return a copy of the current state and then increment the state of the current instance with a jump, as in:

JumpableUniformRandomProvider extends UniformRandomProvider {
    /** Copy the instance, then jump ahead. Return the copy of the previous 
state. */
    JumpableUniformRandomProvider jump();
}

This would appear to solve more use cases than returning a copy that is further ahead. For example the dynamic generation of a jump sequence of an unknown size:

List<UniformRandomProvider> rngs = ...;
JumpableUniformRandomProvider rng;
for (Data data : Iterable<Data>) {
    rngs.add(rng.jump());
}
// Do something with all the Data and rngs

I note that if this is the functionality then the jump() method can be written to return a UniformRandomProvider:

JumpableUniformRandomProvider extends UniformRandomProvider {
    /** Copy the instance, then jump ahead. Return the copy of the previous 
state. */
    UniformRandomProvider jump();
}

It would not have to be enforced to remove jump functionality from the copy but should make it clear that the returned object is not to be jumped again.

Alex

Regards,
Gilles

WDYT?

Alex

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org
For additional commands, e-mail: dev-h...@commons.apache.org

Reply via email to