Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Smoothing Functions For Actors #594

Merged
merged 18 commits into from
Aug 7, 2020
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions vm/actor/src/builtin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ pub mod verifreg;
pub use self::codes::*;
pub(crate) use self::shared::*;
pub use self::singletons::*;
pub use network::*;
71 changes: 71 additions & 0 deletions vm/actor/src/util/alpha_beta_filter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Copyright 2020 ChainSafe Systems
// SPDX-License-Identifier: Apache-2.0, MIT

#![allow(dead_code)]
RajarupanSampanthan marked this conversation as resolved.
Show resolved Hide resolved
use super::math::PRECISION;

use clock::ChainEpoch;
RajarupanSampanthan marked this conversation as resolved.
Show resolved Hide resolved
use encoding::tuple::*;
use encoding::Cbor;
use num_bigint::{bigint_ser, BigInt};

#[derive(Default, Serialize_tuple, Deserialize_tuple)]
pub struct FilterEstimate {
#[serde(with = "bigint_ser")]
pub pos: BigInt,
#[serde(with = "bigint_ser")]
pub velo: BigInt,
RajarupanSampanthan marked this conversation as resolved.
Show resolved Hide resolved
}

impl FilterEstimate {
pub fn new(pos: BigInt, velo: BigInt) -> Self {
FilterEstimate {
pos: pos << PRECISION,
velo: velo << PRECISION,
}
}

pub fn estimate(&self) -> BigInt {
&self.pos >> PRECISION
}

pub fn extrapolate(&self, delta: ChainEpoch) -> BigInt {
RajarupanSampanthan marked this conversation as resolved.
Show resolved Hide resolved
let delta_t = BigInt::from(delta) << PRECISION;
let pos = &self.pos << PRECISION;
(&self.velo * delta_t) + pos
}
}

impl Cbor for FilterEstimate {}

#[derive(Default)]
pub struct AlphaBetaFilter {
alpha: BigInt,
beta: BigInt,
prev_est: FilterEstimate,
}

impl AlphaBetaFilter {
pub fn load_filter(prev_est: FilterEstimate, alpha: BigInt, beta: BigInt) -> Self {
AlphaBetaFilter {
alpha,
beta,
prev_est,
}
}

pub fn next_estimate(&self, obs: BigInt, epoch_delta: ChainEpoch) -> FilterEstimate {
let delta_t = BigInt::from(epoch_delta) << PRECISION;
let delta_x = (&delta_t * &self.prev_est.velo) >> PRECISION;
let mut pos = delta_x + &self.prev_est.pos;

let obs = obs << PRECISION;
let residual = obs - &pos;
let revision_x = (&self.alpha * &residual) >> PRECISION;
pos += &revision_x;

let revision_v = (residual * &self.beta) / delta_t;
let velo = revision_v + &self.prev_est.velo;
FilterEstimate { pos, velo }
}
}
22 changes: 22 additions & 0 deletions vm/actor/src/util/math.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2020 ChainSafe Systems
// SPDX-License-Identifier: Apache-2.0, MIT

use num_bigint::{BigInt, ParseBigIntError};

pub const PRECISION: u64 = 128;

/// polyval evaluates a polynomial given by coefficients `p` in Q.128 format
/// at point `x` in Q.128 format. Output is in Q.128.
/// Coefficients should be ordered from the highest order coefficient to the lowest.
pub fn poly_val(poly: &[BigInt], x: &BigInt) -> BigInt {
let mut res = BigInt::default();

for coeff in poly {
res = ((res * x) >> PRECISION) + coeff;
}
res
}

pub fn parse(coefs: &[&str]) -> Result<Vec<BigInt>, ParseBigIntError> {
RajarupanSampanthan marked this conversation as resolved.
Show resolved Hide resolved
coefs.iter().map(|c| c.parse()).collect()
}
3 changes: 3 additions & 0 deletions vm/actor/src/util/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
// Copyright 2020 ChainSafe Systems
// SPDX-License-Identifier: Apache-2.0, MIT

pub mod alpha_beta_filter;
mod balance_table;
pub mod math;
mod multimap;
mod set;
mod set_multimap;
pub mod smooth;
RajarupanSampanthan marked this conversation as resolved.
Show resolved Hide resolved

pub use self::balance_table::BalanceTable;
pub use self::multimap::*;
Expand Down
101 changes: 101 additions & 0 deletions vm/actor/src/util/smooth.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Copyright 2020 ChainSafe Systems
// SPDX-License-Identifier: Apache-2.0, MIT

use num_bigint::BigInt;

use super::alpha_beta_filter::*;

use crate::math::{parse, poly_val, PRECISION};
RajarupanSampanthan marked this conversation as resolved.
Show resolved Hide resolved
use clock::ChainEpoch;
use num_traits::sign::Signed;

lazy_static! {
pub static ref NUM: Vec<BigInt> = parse(&[
"261417938209272870992496419296200268025",
"7266615505142943436908456158054846846897",
"32458783941900493142649393804518050491988",
"17078670566130897220338060387082146864806",
"-35150353308172866634071793531642638290419",
"-20351202052858059355702509232125230498980",
"-1563932590352680681114104005183375350999",
])
.unwrap();
pub static ref DENOM: Vec<BigInt> = parse(&[
"49928077726659937662124949977867279384",
"2508163877009111928787629628566491583994",
"21757751789594546643737445330202599887121",
"53400635271583923415775576342898617051826",
"41248834748603606604000911015235164348839",
"9015227820322455780436733526367238305537",
"340282366920938463463374607431768211456",
])
.unwrap();
pub static ref LN_2: BigInt = "235865763225513294137944142764154484399".parse().unwrap();
pub static ref EPSILON: BigInt = "302231454903657293676544".parse().unwrap();
}

fn get_bit_len(z: &BigInt) -> usize {
z.abs().to_radix_le(2).1.len()
}
RajarupanSampanthan marked this conversation as resolved.
Show resolved Hide resolved

pub fn extrapolated_cum_sum_of_ratio(
delta: ChainEpoch,
relative_start: ChainEpoch,
est_num: &FilterEstimate,
est_denom: &FilterEstimate,
) -> BigInt {
let delta_t = BigInt::from(delta) << PRECISION;
let t0 = BigInt::from(relative_start) << PRECISION;

let pos_1 = &est_num.pos;
let pos_2 = &est_denom.pos;
let velo_1 = &est_num.velo;
let velo_2 = &est_denom.velo;

let squared_velo_2 = (velo_2 * velo_2) >> PRECISION;

if squared_velo_2 >= *EPSILON {
RajarupanSampanthan marked this conversation as resolved.
Show resolved Hide resolved
let mut x2a = ((velo_2 * t0) >> PRECISION) + pos_2;
let mut x2b = ((velo_2 * &delta_t) >> PRECISION) + &x2a;
x2a = ln(&x2a);
x2b = ln(&x2b);

let m1 = ((&x2b - &x2a) * pos_1 * velo_2) >> PRECISION;

let m2_l = (&x2a - &x2b) * pos_2;
let m2_r = velo_2 * &delta_t;
let m2 = ((m2_l + m2_r) * velo_1) >> PRECISION;

return (m2 + m1) / squared_velo_2;
}

let half_delta = &delta_t >> 1;
let mut x1m = velo_1 * (t0 + half_delta);
x1m = (x1m >> PRECISION) + pos_1;

(x1m * delta_t) / pos_2
}

pub fn ln(z: &BigInt) -> BigInt {
let k: i64 = get_bit_len(z) as i64 - 1 - PRECISION as i64;

let x: BigInt = if k > 0 { z >> k } else { z << k.abs() };

BigInt::from(k) * &*LN_2 + ln_between_one_and_two(x)
RajarupanSampanthan marked this conversation as resolved.
Show resolved Hide resolved
}

fn ln_between_one_and_two(x: BigInt) -> BigInt {
let num = poly_val(&NUM, &x) << PRECISION;
let denom = poly_val(&DENOM, &x);
num / denom
}

// Returns an estimate with position val and velocity 0
pub fn testing_constant_estimate(val: BigInt) -> FilterEstimate {
FilterEstimate::new(val, BigInt::from(0u8))
}

// Returns and estimate with postion x and velocity v
pub fn testing_estimate(x: BigInt, v: BigInt) -> FilterEstimate {
FilterEstimate::new(x, v)
}
RajarupanSampanthan marked this conversation as resolved.
Show resolved Hide resolved
Loading