4 个版本

0.1.3 2021年2月5日
0.1.2 2021年2月5日
0.1.1 2021年2月5日
0.1.0 2021年2月5日

算法 中排名第 1404

MIT 许可证

27KB
365 行(不包括注释)

randomwalk

构建辉煌的随机游走。



use randomwalk::generators::NormalGenerator;

use randomwalk::translators::{
   UniformTranslator,
   ExponentialTranslator,
   LogNormalTranslator,
};

示例

示例中使用的辅助方法

// normal distribution between 0 and 1
let norm_dist = rand_distr::Normal::new(0.0, 1.0).unwrap();

// exponential distribution with lambda of 0.0055
let exp_dist = rand_distr::Exp::new(1.0 / 180.0).unwrap();

// uniform distribution between 0 and 1
let unif_dist = rand_distr::Uniform::new(0.0, 1.0);

let now = || chrono::Utc::now();

let mut rng = rand_hc::Hc128Rng::from_entropy();

带软边界的正态分布随机游走

本节演示如何创建一个软边界限制在均值附近的随机游走。为了近似无软边界的游走,请给方差赋予一个大的值,并在调用 NormalGenerator.next 之前使用 NormalGenerator.set 初始化游走。

let utc_now = now();

# Setup a random walk with mean 100.0 and variance 250.0.
# The variance controls how tightly the walk is held
# close to its mean and sigma_xx controls how rapidly
# it can wander away from its starting point.

let mut normal_gen =
    NormalGenerator::new(
        100.0,
        250.0,
        0.1,
        utc_now.timestamp() as u64,
    );

let mut current_time = utc_now.timestamp_millis() as f64;
let mut current_value = normal_gen.next(current_time).unwrap();

for i in 1..10 {
    # pretend time lapsed
    current_time = current_time + (i as f64 * 500f64);
    current_value = normal_gen.next(current_time).unwrap();

    println!(
        "Normal walk value {} time {}",
        current_value,
        current_time,
    );
}

带软边界和随机形状插值的正态分布随机游走

本节演示如何创建一个软边界限制在形状函数值附近的随机游走。

let utc_now = now();

// Setup a random walk with zero mean. Since we'll be
// adding the value of the walk to the shaping functions,
// using a walk with zero mean ensures that the walk will
// wander around but will keep returning to the vicinity
// of the shaping function. Reducing the variance will
// keep the walk closer to the shaping function and
// make its form more obvious.

let mut normal_gen =
   NormalGenerator::new(
       100.0,
       250.0,
       0.1,
       utc_now.timestamp() as u64,
   );

// The walk will consist of shaped transitions between
// random points. The start variable represent the
// starting point of a transition, which is usually
// the 'current' time and value and the target variables
// represent the end point of a transition - the value
// the walk need to walk to and the time at which it
// needs to be there.

let mut current_time = utc_now.timestamp_millis() as f64;
let mut current_value = 0.0;

let mut start_time = current_time;
let mut start_value = 100.0 + rng.sample(norm_dist) * 10.0;

let mut target_time = current_time + rng.sample(exp_dist) + 5.0;
let mut target_value = 100.0 + rng.sample(norm_dist) * 10.0;

for i in 1..10 {
   current_time = current_time + (i as f64 * 500f64);

   if current_time > target_time {
       start_time = current_time;
       start_value = current_value;

       target_time = current_time + rng.sample(exp_dist) + 5.0;
       target_value = 100.0 + rng.sample(norm_dist) * 10.0;
   }

   current_value =
       normal_gen.next_interpolant(
           current_time,
           target_time,
           0.0,
       ).unwrap();

   let normalized_time =
       (current_time - start_time)
           / (target_time - start_time);

   // linear
   //let shaping_value =
   //    target_value
   //    + normalized_time
   //    + start_value * (1.0 - normalized_time);

   // smoothstep
   let shaping_value =
       start_value
           + (target_value - start_value)
           * (
               3.0 * normalized_time * normalized_time
               - 2.0 * normalized_time * normalized_time * normalized_time);

   // quarter
   //let shaping_value =
   //    start_value
   //    + (target_value - start_value)
   //        * (
   //            1.0 - (1.0 - normalized_time)
   //                * (1.0 - normalized_time)
   //        ).sqrt();

   //println!(
   //    "Shaping function {}",
   //    shaping_value,
   //);

   //println!(
   //    "Raw normal walk {}",
   //    current_value,
   //);

   println!(
       "Normal shaped interpolated walk {} @ {} target {} @ {}",
       current_value + shaping_value,
       current_time,
       target_value,
       target_time,
   );
}

带软边界和随机无形状插值的正态分布随机游走

本节演示如何创建一个无需形状函数帮助即可在固定点之间自由插值的随机游走。

let utc_now = now();

// Setup a random walk with mean 100.0 and variance 250.0.
// The variance controls how tightly the walk is held
// close to its mean and sigma_xx controls how rapidly it
// can wander away from its starting point.

let mut normal_gen =
   NormalGenerator::new(
       100.0,
       250.0,
       0.1,
       utc_now.timestamp() as u64,
   );

// The walk will consist of unshaped transitions between
// random points. The start variable represent the
// starting point of a transition, which is usually
// the 'current' time and value and the target variables
// represent the end point of a transition - the value
// the walk need to walk to and the time at which it
// needs to be there.

let mut current_time = utc_now.timestamp_millis() as f64;
let mut current_value = normal_gen.next(current_time).unwrap();

let mut target_time = current_time + rng.sample(exp_dist) + 5.0;
let mut target_value = 100.0 + rng.sample(norm_dist) * 10.0;

for i in 1..10 {
   current_time = current_time + (i as f64 * 500f64);

   if current_time > target_time {
       target_time = current_time + rng.sample(exp_dist) + 5.0;
       target_value = 100.0 + rng.sample(norm_dist) * 10.0;
   }

   current_value =
       normal_gen.next_interpolant(
           current_time,
           target_time,
           target_value,
       ).unwrap();

   println!(
       "Normal unshaped interpolated walk {} @ {} target {} @ {}",
       current_value,
       current_time,
       target_value,
       target_time,
   );
}

带软边界的对数正态分布随机游走

本节演示如何创建对数正态分布的随机游走。这是通过生成一个正态分布的随机游走,并通过一个对数正态翻译器后处理以获得对数正态分布来实现的。

let utc_now = now();

// Generate a normally distributed random walk and attach
// it to a log-normal translator. Note that the
// log-normal translator raises the normal random walk
// to the power of e so we need to setup the mean
// and variance of the normal distribution so that
// the output of the log-normal translator has the
// properties that we want.

let mut normal_gen =
   NormalGenerator::new(
       100.0,
       250.0 / 100.0 / 100.0,
       0.1 / 100.0 / 100.0,
       utc_now.timestamp() as u64,
   );

let mut log_gen =
   LogNormalTranslator::new(
       normal_gen,
   );

let mut current_time = utc_now.timestamp_millis() as f64;
let mut current_value = log_gen.next(current_time).unwrap();

for i in 1..10 {
   current_time = current_time + (i as f64 * 500f64);

   current_value =
       log_gen.next(
           current_time,
       )
       .unwrap();

   println!(
       "Log-Normal walk {}",
       current_value,
   );
}

带软边界和随机插值的对数正态分布随机游走

本节演示如何创建带有无形状随机插值的对数正态分布随机游走。有关详细注释,请参阅对数正态分布随机游走和正态分布随机游走(无形状插值)的章节。

let utc_now = now();

let mut normal_gen =
   NormalGenerator::new(
       100.0,
       250.0 / 100.0 / 100.0,
       0.1 / 100.0 / 100.0,
       utc_now.timestamp() as u64,
   );

let mut log_gen =
   LogNormalTranslator::new(
       normal_gen,
   );

let mut current_time = utc_now.timestamp_millis() as f64;
let mut current_value = log_gen.next(current_time).unwrap();

for i in 1..10 {
   current_time = current_time + (i as f64 * 500f64);

   current_value =
       log_gen.next(
           current_time,
       )
           .unwrap();

   println!(
       "Log-Normal softbound walk {}",
       current_value,
   );
}

带软边界的均匀分布随机游走

本节演示如何创建均匀分布的随机游走。这是通过设置一个正态分布的随机游走并将其附加到一个均匀翻译器上,将其转换为均匀分布的随机游走来实现的。

let utc_now = now();

// This section demonstrates how to create a uniformly
// distributed random walk. This is achieved by setting
// up a normally-distributed random walk and attaching
// it to a uniform translator, which converts it into
// a uniformly distributed random walk.

let mut normal_gen =
   NormalGenerator::new(
       100.0,
       250.0,
       0.0001,
       utc_now.timestamp() as u64,
   );

let mut uniform_tx =
   UniformTranslator::new(
       normal_gen,
   );

let mut current_time =
   utc_now.timestamp_millis() as f64;

let mut current_value =
   uniform_tx.next(
       current_time,
   )
   .unwrap();

for i in 1..10 {
   current_time = current_time + (i as f64 * 500f64);

   current_value =
       uniform_tx.next(
           current_time,
       )
       .unwrap();

   println!(
       "Uniform walk with softbound {} @ {}",
       current_value,
       current_time,
   );
}

带软边界和随机插值的均匀分布随机游走

本节演示如何创建带有无形状随机插值的均匀分布随机游走。有关详细注释,请参阅均匀分布随机游走和正态分布随机游走(无形状插值)的章节。

let utc_now = now();

let mut normal_gen =
   NormalGenerator::new(
       100.0,
       250.0,
       0.0001,
       utc_now.timestamp() as u64,
   );

let mut uniform_tx =
   UniformTranslator::new(
       normal_gen,
   );

let mut current_time =
   utc_now.timestamp_millis() as f64;

let mut current_value =
   uniform_tx.next(
       current_time,
   )
   .unwrap();

let mut target_time =
   current_time + rng.sample(exp_dist) + 5.0;

let mut target_value =
   rng.sample(unif_dist);

for i in 1..10 {
   current_time = current_time + (i as f64 * 500f64);

   if current_time > target_time {
       target_time =
           current_time + rng.sample(exp_dist) + 5.0;

       target_value =
           rng.sample(unif_dist);
   }

   current_value =
       uniform_tx.next_interpolant(
           current_time,
           target_time,
           target_value,
       )
       .unwrap();

   println!(
       "Uniform interpolated walk with softbound {} @ {} target {} @ {}",
       current_value,
       current_time,
       target_value,
       target_time,
   );
}

带软边界的指数分布随机游走

本节演示了如何创建指数分布的随机游走。这是通过创建正态分布的随机游走并将其连接到均匀平移器来完成的,以便将其转换为均匀分布的游走。然后,均匀平移器连接到指数平移器,将均匀分布的游走转换为指数分布的随机游走。请注意,当指数分布的随机游走具有较大的值时,它会迈出更大的步子。

let utc_now = now();
let time = utc_now.timestamp() as u64;

let normal_gen =
   NormalGenerator::new(
       100.0,
       250.0,
       0.000001,
       time,
   );

let uniform_tx =
   UniformTranslator::new(
       normal_gen,
   );

let mut exp_tx =
   ExponentialTranslator::new(
       100.0,
       uniform_tx,
   ).unwrap();

let mut current_time = utc_now.timestamp_millis() as f64;

let mut current_value =
   exp_tx.next(
       current_time,
   )
   .unwrap();

for i in 1..10 {
   current_time = current_time + (i as f64 * 500f64);

   current_value =
       exp_tx.next(
           current_time,
       )
       .unwrap();

   println!(
       "Exponential walk with softbound {} @ {}",
       current_value,
       current_time,
   );
}

带有软边界和随机插值的指数分布随机游走

本节演示了如何创建带有未整形随机插值的指数分布随机游走。有关详细说明,请参阅指数分布随机游走和未整形插值的正态分布随机游走的章节。

let utc_now = now();
let time = utc_now.timestamp() as u64;

let normal_gen =
   NormalGenerator::new(
       100.0,
       250.0,
       0.000001,
       time,
   );

let uniform_tx =
   UniformTranslator::new(
       normal_gen,
   );

let mut exp_tx =
   ExponentialTranslator::new(
       100.0,
       uniform_tx,
   ).unwrap();

let mut current_time = utc_now.timestamp_millis() as f64;

let mut current_value =
   exp_tx.next(
       current_time,
   )
       .unwrap();

let mut target_time =
   current_time
       + rng.sample(
       exp_dist,
   )
       + 5.0;

let mut target_value =
   100.0
       + rng.sample(
       norm_dist,
   )
       * 10.0;

for i in 1..10 {
   current_time = current_time + (i as f64 * 500f64);

   if current_time > target_time {
       target_time =
           current_time
               + rng.sample(
               exp_dist,
           )
               + 5.0;

       target_value =
           100.0
               + rng.sample(
               norm_dist,
           )
               * 10.0;
   }

   current_value =
       exp_tx.next_interpolant(
           current_time,
           target_time,
           target_value,
       )
           .unwrap();

   println!(
       "Exponential interpolated walk with softbound {} @ {} target {} @ {}",
       current_value,
       current_time,
       target_value,
       target_time,
   );
}

依赖关系

~2MB
~36K SLoC