IDSIA / crema

Crema: Credal Models Algorithms
https://crema-toolbox.readthedocs.io/
GNU Lesser General Public License v3.0
10 stars 4 forks source link

Lambda for RandomUtil.getRandom() #97

Closed cbonesana closed 3 years ago

cbonesana commented 3 years ago

Using crema in a concurrent environment has some issue, like the impossibility to run parallel code that uses the RandomUtil class.

In order to help mitigate this issue a new static method was added to the RandomUtil class: setRandom(Supplier<Random> random).

This method allows to change how the method getRandom() returns the static random number generator instance. The default behavior is to have the usual behavior of the class prior to this change.

With this method is now possible to use manage externally which random to use for each concurrent execution of crema's code in a controlled environment. An example is the following:

// we initialize a ConcurrentHashMap with the Random objec to use in each thread
final Map<String, Random> randoms = new ConcurrentHashMap<>(Map.of(
    "Thread0", new Random(0),
    "Thread1", new Random(1),
    "Thread2", new Random(0),
    "Thread3", new Random(1)
));

// to get the random to use, get current thread's name from the above map
RandomUtil.setRandom(() -> randoms.get(Thread.currentThread().getName()));

final List<Callable<int[]>> tasks = IntStream.range(0, 4)
    .mapToObj(i -> (Callable<int[]>) () -> {
        // set a name for the thread based, as an example, on the used seed
        final String tName = "Thread" + i;
        Thread.currentThread().setName(tName);

        // put on the map a new random with the thread's name
        randoms.put(tName, new Random(seed));

        // the supplier defined above will return the random based on the name of the current thread
        // so in this thread crema's will always use the same random number generator, also defined in the task
        return IntStream.generate(() -> RandomUtil.getRandom().nextInt(10))
                .limit(10)
                .toArray();
    })
    .collect(Collectors.toList());

This example was extracted from the RandomUtilTest#testConcurrentRandomExecution() test case.

To restore the original supplier function use the RandomUtil.reset() method.