11cb0ef41Sopenharmony_ci// Copyright 2020 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci/**
61cb0ef41Sopenharmony_ci * @fileoverview Random helpers.
71cb0ef41Sopenharmony_ci */
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ci'use strict';
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_ciconst assert = require('assert');
121cb0ef41Sopenharmony_ci
131cb0ef41Sopenharmony_cifunction randInt(min, max) {
141cb0ef41Sopenharmony_ci  return Math.floor(Math.random() * (max - min + 1)) + min;
151cb0ef41Sopenharmony_ci}
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_cifunction choose(probability) {
181cb0ef41Sopenharmony_ci  return Math.random() < probability;
191cb0ef41Sopenharmony_ci}
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_cifunction random() {
221cb0ef41Sopenharmony_ci  return Math.random();
231cb0ef41Sopenharmony_ci}
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_cifunction uniform(min, max) {
261cb0ef41Sopenharmony_ci  return Math.random() * (max - min) + min;
271cb0ef41Sopenharmony_ci}
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_cifunction sample(iterable, count) {
301cb0ef41Sopenharmony_ci  const result = new Array(count);
311cb0ef41Sopenharmony_ci  let index = 0;
321cb0ef41Sopenharmony_ci
331cb0ef41Sopenharmony_ci  for (const item of iterable) {
341cb0ef41Sopenharmony_ci    if (index < count) {
351cb0ef41Sopenharmony_ci      result[index] = item;
361cb0ef41Sopenharmony_ci    } else {
371cb0ef41Sopenharmony_ci      const randIndex = randInt(0, index);
381cb0ef41Sopenharmony_ci      if (randIndex < count) {
391cb0ef41Sopenharmony_ci        result[randIndex] = item;
401cb0ef41Sopenharmony_ci      }
411cb0ef41Sopenharmony_ci    }
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ci    index++;
441cb0ef41Sopenharmony_ci  }
451cb0ef41Sopenharmony_ci
461cb0ef41Sopenharmony_ci  if (index < count) {
471cb0ef41Sopenharmony_ci    // Not enough items.
481cb0ef41Sopenharmony_ci    result.length = index;
491cb0ef41Sopenharmony_ci  }
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_ci  return result;
521cb0ef41Sopenharmony_ci}
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_cifunction swap(array, p1, p2) {
551cb0ef41Sopenharmony_ci  [array[p1], array[p2]] = [array[p2], array[p1]];
561cb0ef41Sopenharmony_ci}
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci/**
591cb0ef41Sopenharmony_ci * Returns "count" elements, randomly selected from "highProbArray" and
601cb0ef41Sopenharmony_ci * "lowProbArray". Elements from highProbArray have a "factor" times
611cb0ef41Sopenharmony_ci * higher chance to be chosen. As a side effect, this swaps the chosen
621cb0ef41Sopenharmony_ci * elements to the end of the respective input arrays. The complexity is
631cb0ef41Sopenharmony_ci * O(count).
641cb0ef41Sopenharmony_ci */
651cb0ef41Sopenharmony_cifunction twoBucketSample(lowProbArray, highProbArray, factor, count) {
661cb0ef41Sopenharmony_ci  // Track number of available elements for choosing.
671cb0ef41Sopenharmony_ci  let low = lowProbArray.length;
681cb0ef41Sopenharmony_ci  let high = highProbArray.length;
691cb0ef41Sopenharmony_ci  assert(low + high >= count);
701cb0ef41Sopenharmony_ci  const result = [];
711cb0ef41Sopenharmony_ci  for (let i = 0; i < count; i++) {
721cb0ef41Sopenharmony_ci    // Map a random number to the summarized indices of both arrays. Give
731cb0ef41Sopenharmony_ci    // highProbArray elements a "factor" times higher probability.
741cb0ef41Sopenharmony_ci    const p = random();
751cb0ef41Sopenharmony_ci    const index = Math.floor(p * (high * factor + low));
761cb0ef41Sopenharmony_ci    if (index < low) {
771cb0ef41Sopenharmony_ci      // If the index is in the low part, draw the element and discard it.
781cb0ef41Sopenharmony_ci      result.push(lowProbArray[index]);
791cb0ef41Sopenharmony_ci      swap(lowProbArray, index, --low);
801cb0ef41Sopenharmony_ci    } else {
811cb0ef41Sopenharmony_ci      // Same as above but for a highProbArray element. The index is first
821cb0ef41Sopenharmony_ci      // mapped back to the array's range.
831cb0ef41Sopenharmony_ci      const highIndex = Math.floor((index - low) / factor);
841cb0ef41Sopenharmony_ci      result.push(highProbArray[highIndex]);
851cb0ef41Sopenharmony_ci      swap(highProbArray, highIndex, --high);
861cb0ef41Sopenharmony_ci    }
871cb0ef41Sopenharmony_ci  }
881cb0ef41Sopenharmony_ci  return result;
891cb0ef41Sopenharmony_ci}
901cb0ef41Sopenharmony_ci
911cb0ef41Sopenharmony_cifunction single(array) {
921cb0ef41Sopenharmony_ci  return array[randInt(0, array.length - 1)];
931cb0ef41Sopenharmony_ci}
941cb0ef41Sopenharmony_ci
951cb0ef41Sopenharmony_cifunction shuffle(array) {
961cb0ef41Sopenharmony_ci  for (let i = 0; i < array.length - 1; i++) {
971cb0ef41Sopenharmony_ci    const j = randInt(i, array.length - 1);
981cb0ef41Sopenharmony_ci    swap(array, i, j);
991cb0ef41Sopenharmony_ci  }
1001cb0ef41Sopenharmony_ci
1011cb0ef41Sopenharmony_ci  return array;
1021cb0ef41Sopenharmony_ci}
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_cimodule.exports = {
1051cb0ef41Sopenharmony_ci  choose: choose,
1061cb0ef41Sopenharmony_ci  randInt: randInt,
1071cb0ef41Sopenharmony_ci  random: random,
1081cb0ef41Sopenharmony_ci  sample: sample,
1091cb0ef41Sopenharmony_ci  shuffle: shuffle,
1101cb0ef41Sopenharmony_ci  single: single,
1111cb0ef41Sopenharmony_ci  twoBucketSample: twoBucketSample,
1121cb0ef41Sopenharmony_ci  uniform: uniform,
1131cb0ef41Sopenharmony_ci}
114