computer: simplified a bunch of things

This commit is contained in:
nym21
2026-02-26 19:37:22 +01:00
parent 9e4fe62de2
commit cccaf6b206
252 changed files with 3788 additions and 7279 deletions

View File

@@ -1,309 +0,0 @@
//! Lazy binary transform from two SumCum sources, producing Last (cumulative) ratios only.
use brk_traversable::Traversable;
use brk_types::{Height, Version};
use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use vecdb::{BinaryTransform, ReadableBoxedVec, ReadableCloneableVec, LazyVecFrom2};
use crate::{
indexes_from,
internal::{
ComputedFromHeightLast, ComputedFromHeightSumCum, ComputedHeightDerivedLast,
ComputedVecValue, LazyBinaryComputedFromHeightLast, LazyBinaryHeightDerivedLast,
LazyBinaryTransformLast, LazyFromHeightLast, NumericValue,
},
};
#[derive(Clone, Deref, DerefMut, Traversable)]
#[traversable(merge)]
pub struct LazyBinaryFromHeightLast<T, S1T = T, S2T = T>
where
T: ComputedVecValue + PartialOrd + JsonSchema,
S1T: ComputedVecValue,
S2T: ComputedVecValue,
{
pub height: LazyVecFrom2<Height, T, Height, S1T, Height, S2T>,
#[deref]
#[deref_mut]
pub rest: Box<LazyBinaryHeightDerivedLast<T, S1T, S2T>>,
}
const VERSION: Version = Version::ZERO;
/// Helper macro: given two deref-able sources whose `.$p` fields implement
/// `ReadableCloneableVec`, build all 17 period fields of a `LazyBinaryHeightDerivedLast`.
macro_rules! build_rest {
($name:expr, $v:expr, $source1:expr, $source2:expr) => {{
macro_rules! period {
($p:ident) => {
LazyBinaryTransformLast::from_vecs::<F>(
$name,
$v,
$source1.$p.read_only_boxed_clone(),
$source2.$p.read_only_boxed_clone(),
)
};
}
Box::new(LazyBinaryHeightDerivedLast(indexes_from!(period)))
}};
}
impl<T, S1T, S2T> LazyBinaryFromHeightLast<T, S1T, S2T>
where
T: ComputedVecValue + JsonSchema + 'static,
S1T: ComputedVecValue + JsonSchema,
S2T: ComputedVecValue + JsonSchema,
{
pub(crate) fn from_computed_sum_cum<F: BinaryTransform<S1T, S2T, T>>(
name: &str,
version: Version,
source1: &ComputedFromHeightSumCum<S1T>,
source2: &ComputedFromHeightSumCum<S2T>,
) -> Self
where
S1T: PartialOrd,
S2T: PartialOrd,
{
let v = version + VERSION;
Self {
height: LazyVecFrom2::transformed::<F>(
name,
v,
source1.height_cumulative.read_only_boxed_clone(),
source2.height_cumulative.read_only_boxed_clone(),
),
rest: Box::new(LazyBinaryHeightDerivedLast::from_computed_sum_cum::<F>(name, v, source1, source2)),
}
}
pub(crate) fn from_computed_last<F: BinaryTransform<S1T, S2T, T>>(
name: &str,
version: Version,
source1: &ComputedFromHeightLast<S1T>,
source2: &ComputedFromHeightLast<S2T>,
) -> Self
where
S1T: NumericValue,
S2T: NumericValue,
{
let v = version + VERSION;
Self {
height: LazyVecFrom2::transformed::<F>(
name,
v,
source1.height.read_only_boxed_clone(),
source2.height.read_only_boxed_clone(),
),
rest: Box::new(LazyBinaryHeightDerivedLast::from_computed_last::<F>(name, v, source1, source2)),
}
}
pub(crate) fn from_block_last_and_lazy_block_last<F, S2SourceT>(
name: &str,
version: Version,
source1: &ComputedFromHeightLast<S1T>,
source2: &LazyFromHeightLast<S2T, S2SourceT>,
) -> Self
where
F: BinaryTransform<S1T, S2T, T>,
S1T: NumericValue,
S2SourceT: ComputedVecValue + JsonSchema,
{
let v = version + VERSION;
Self {
height: LazyVecFrom2::transformed::<F>(
name,
v,
source1.height.read_only_boxed_clone(),
source2.height.read_only_boxed_clone(),
),
rest: Box::new(LazyBinaryHeightDerivedLast::from_block_last_and_lazy_block_last::<F, _>(
name, v, source1, source2,
)),
}
}
pub(crate) fn from_lazy_block_last_and_block_last<F, S1SourceT>(
name: &str,
version: Version,
source1: &LazyFromHeightLast<S1T, S1SourceT>,
source2: &ComputedFromHeightLast<S2T>,
) -> Self
where
F: BinaryTransform<S1T, S2T, T>,
S2T: NumericValue,
S1SourceT: ComputedVecValue + JsonSchema,
{
let v = version + VERSION;
Self {
height: LazyVecFrom2::transformed::<F>(
name,
v,
source1.height.read_only_boxed_clone(),
source2.height.read_only_boxed_clone(),
),
rest: Box::new(LazyBinaryHeightDerivedLast::from_lazy_block_last_and_block_last::<F, _>(
name, v, source1, source2,
)),
}
}
/// Create from a ComputedFromHeightLast and a LazyBinaryFromHeightLast.
pub(crate) fn from_block_last_and_binary_block<F, S2aT, S2bT>(
name: &str,
version: Version,
source1: &ComputedFromHeightLast<S1T>,
source2: &LazyBinaryFromHeightLast<S2T, S2aT, S2bT>,
) -> Self
where
F: BinaryTransform<S1T, S2T, T>,
S1T: NumericValue,
S2aT: ComputedVecValue + JsonSchema,
S2bT: ComputedVecValue + JsonSchema,
{
let v = version + VERSION;
Self {
height: LazyVecFrom2::transformed::<F>(
name,
v,
source1.height.read_only_boxed_clone(),
source2.height.read_only_boxed_clone(),
),
rest: build_rest!(name, v, source1, source2),
}
}
/// Create from two LazyBinaryFromHeightLast sources.
pub(crate) fn from_both_binary_block<F, S1aT, S1bT, S2aT, S2bT>(
name: &str,
version: Version,
source1: &LazyBinaryFromHeightLast<S1T, S1aT, S1bT>,
source2: &LazyBinaryFromHeightLast<S2T, S2aT, S2bT>,
) -> Self
where
F: BinaryTransform<S1T, S2T, T>,
S1aT: ComputedVecValue + JsonSchema,
S1bT: ComputedVecValue + JsonSchema,
S2aT: ComputedVecValue + JsonSchema,
S2bT: ComputedVecValue + JsonSchema,
{
let v = version + VERSION;
Self {
height: LazyVecFrom2::transformed::<F>(
name,
v,
source1.height.read_only_boxed_clone(),
source2.height.read_only_boxed_clone(),
),
rest: build_rest!(name, v, source1, source2),
}
}
/// Create from separate height sources and two `ComputedHeightDerivedLast` structs.
pub(crate) fn from_height_and_derived_last<F: BinaryTransform<S1T, S2T, T>>(
name: &str,
version: Version,
height_source1: ReadableBoxedVec<Height, S1T>,
height_source2: ReadableBoxedVec<Height, S2T>,
derived1: &ComputedHeightDerivedLast<S1T>,
derived2: &ComputedHeightDerivedLast<S2T>,
) -> Self
where
S1T: NumericValue,
S2T: NumericValue,
{
let v = version + VERSION;
Self {
height: LazyVecFrom2::transformed::<F>(name, v, height_source1, height_source2),
rest: build_rest!(name, v, derived1, derived2),
}
}
/// Create from a ComputedFromHeightLast and a LazyBinaryComputedFromHeightLast.
pub(crate) fn from_block_last_and_lazy_binary_computed_block_last<F, S2aT, S2bT>(
name: &str,
version: Version,
source1: &ComputedFromHeightLast<S1T>,
source2: &LazyBinaryComputedFromHeightLast<S2T, S2aT, S2bT>,
) -> Self
where
F: BinaryTransform<S1T, S2T, T>,
S1T: NumericValue,
S2aT: ComputedVecValue + JsonSchema,
S2bT: ComputedVecValue + JsonSchema,
{
let v = version + VERSION;
Self {
height: LazyVecFrom2::transformed::<F>(
name,
v,
source1.height.read_only_boxed_clone(),
source2.height.read_only_boxed_clone(),
),
rest: build_rest!(name, v, source1, source2),
}
}
/// Create from two LazyBinaryComputedFromHeightLast sources.
pub(crate) fn from_both_lazy_binary_computed_block_last<F, S1aT, S1bT, S2aT, S2bT>(
name: &str,
version: Version,
source1: &LazyBinaryComputedFromHeightLast<S1T, S1aT, S1bT>,
source2: &LazyBinaryComputedFromHeightLast<S2T, S2aT, S2bT>,
) -> Self
where
F: BinaryTransform<S1T, S2T, T>,
S1aT: ComputedVecValue + JsonSchema,
S1bT: ComputedVecValue + JsonSchema,
S2aT: ComputedVecValue + JsonSchema,
S2bT: ComputedVecValue + JsonSchema,
{
let v = version + VERSION;
Self {
height: LazyVecFrom2::transformed::<F>(
name,
v,
source1.height.read_only_boxed_clone(),
source2.height.read_only_boxed_clone(),
),
rest: build_rest!(name, v, source1, source2),
}
}
/// Create from a LazyBinaryFromHeightLast and a LazyBinaryComputedFromHeightLast.
pub(crate) fn from_binary_block_and_lazy_binary_block_last<F, S1aT, S1bT, S2aT, S2bT>(
name: &str,
version: Version,
source1: &LazyBinaryFromHeightLast<S1T, S1aT, S1bT>,
source2: &LazyBinaryComputedFromHeightLast<S2T, S2aT, S2bT>,
) -> Self
where
F: BinaryTransform<S1T, S2T, T>,
S1aT: ComputedVecValue + JsonSchema,
S1bT: ComputedVecValue + JsonSchema,
S2aT: ComputedVecValue + JsonSchema,
S2bT: ComputedVecValue + JsonSchema,
{
let v = version + VERSION;
Self {
height: LazyVecFrom2::transformed::<F>(
name,
v,
source1.height.read_only_boxed_clone(),
source2.height.read_only_boxed_clone(),
),
rest: build_rest!(name, v, source1, source2),
}
}
}

View File

@@ -1,38 +1,34 @@
//! ComputedFromHeightCum - stored height + LazyLast + cumulative (from height).
//! ComputedFromHeightCumulative - stored height + LazyAggVec + cumulative (from height).
//!
//! Like ComputedFromHeightCumSum but without RollingWindows.
//! Like ComputedFromHeightCumulativeSum but without RollingWindows.
//! Used for distribution metrics where rolling is optional per cohort.
//! Cumulative gets its own ComputedFromHeightLast so it has LazyLast index views.
//! Cumulative gets its own ComputedFromHeightLast so it has LazyAggVec index views.
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Height, Version};
use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use vecdb::{Database, EagerVec, Exit, PcoVec, Rw, StorageMode};
use vecdb::{Database, EagerVec, Exit, ImportableVec, PcoVec, Rw, StorageMode};
use crate::{
indexes,
internal::{ComputedFromHeightLast, NumericValue},
};
#[derive(Deref, DerefMut, Traversable)]
#[derive(Traversable)]
#[traversable(merge)]
pub struct ComputedFromHeightCum<T, M: StorageMode = Rw>
pub struct ComputedFromHeightCumulative<T, M: StorageMode = Rw>
where
T: NumericValue + JsonSchema,
{
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub last: ComputedFromHeightLast<T, M>,
pub height: M::Stored<EagerVec<PcoVec<Height, T>>>,
#[traversable(flatten)]
pub cumulative: ComputedFromHeightLast<T, M>,
}
const VERSION: Version = Version::ZERO;
impl<T> ComputedFromHeightCum<T>
impl<T> ComputedFromHeightCumulative<T>
where
T: NumericValue + JsonSchema,
{
@@ -44,15 +40,11 @@ where
) -> Result<Self> {
let v = version + VERSION;
let last = ComputedFromHeightLast::forced_import(db, name, v, indexes)?;
let cumulative = ComputedFromHeightLast::forced_import(
db,
&format!("{name}_cumulative"),
v,
indexes,
)?;
let height: EagerVec<PcoVec<Height, T>> = EagerVec::forced_import(db, name, v)?;
let cumulative =
ComputedFromHeightLast::forced_import(db, &format!("{name}_cumulative"), v, indexes)?;
Ok(Self { last, cumulative })
Ok(Self { height, cumulative })
}
/// Compute height data via closure, then cumulative only (no rolling).
@@ -65,25 +57,18 @@ where
where
T: Default,
{
compute_height(&mut self.last.height)?;
self.cumulative
.height
.compute_cumulative(max_from, &self.last.height, exit)?;
Ok(())
compute_height(&mut self.height)?;
self.compute_rest(max_from, exit)
}
/// Compute cumulative from already-filled height vec.
pub(crate) fn compute_cumulative(
&mut self,
max_from: Height,
exit: &Exit,
) -> Result<()>
pub(crate) fn compute_rest(&mut self, max_from: Height, exit: &Exit) -> Result<()>
where
T: Default,
{
self.cumulative
.height
.compute_cumulative(max_from, &self.last.height, exit)?;
.compute_cumulative(max_from, &self.height, exit)?;
Ok(())
}
}

View File

@@ -1,32 +1,28 @@
//! ComputedFromHeightCumFull - stored height + LazyLast + cumulative (from height) + RollingFull.
//! ComputedFromHeightCumulativeFull - stored height + LazyAggVec + cumulative (from height) + RollingFull.
//!
//! For metrics with stored per-block data, cumulative sums, and rolling windows.
//! Cumulative gets its own ComputedFromHeightLast so it has LazyLast index views too.
//! Cumulative gets its own ComputedFromHeightLast so it has LazyAggVec index views too.
use std::ops::SubAssign;
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Height, Version};
use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use vecdb::{Database, EagerVec, Exit, PcoVec, Rw, StorageMode};
use vecdb::{Database, EagerVec, Exit, ImportableVec, PcoVec, Rw, StorageMode};
use crate::{
indexes,
internal::{ComputedFromHeightLast, NumericValue, RollingFull, WindowStarts},
};
#[derive(Deref, DerefMut, Traversable)]
#[derive(Traversable)]
#[traversable(merge)]
pub struct ComputedFromHeightCumFull<T, M: StorageMode = Rw>
pub struct ComputedFromHeightCumulativeFull<T, M: StorageMode = Rw>
where
T: NumericValue + JsonSchema,
{
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub last: ComputedFromHeightLast<T, M>,
pub height: M::Stored<EagerVec<PcoVec<Height, T>>>,
#[traversable(flatten)]
pub cumulative: ComputedFromHeightLast<T, M>,
#[traversable(flatten)]
@@ -35,7 +31,7 @@ where
const VERSION: Version = Version::ZERO;
impl<T> ComputedFromHeightCumFull<T>
impl<T> ComputedFromHeightCumulativeFull<T>
where
T: NumericValue + JsonSchema,
{
@@ -47,17 +43,13 @@ where
) -> Result<Self> {
let v = version + VERSION;
let last = ComputedFromHeightLast::forced_import(db, name, v, indexes)?;
let cumulative = ComputedFromHeightLast::forced_import(
db,
&format!("{name}_cumulative"),
v,
indexes,
)?;
let height: EagerVec<PcoVec<Height, T>> = EagerVec::forced_import(db, name, v)?;
let cumulative =
ComputedFromHeightLast::forced_import(db, &format!("{name}_cumulative"), v, indexes)?;
let rolling = RollingFull::forced_import(db, name, v, indexes)?;
Ok(Self {
last,
height,
cumulative,
rolling,
})
@@ -75,12 +67,12 @@ where
T: From<f64> + Default + SubAssign + Copy + Ord,
f64: From<T>,
{
compute_height(&mut self.last.height)?;
compute_height(&mut self.height)?;
self.cumulative
.height
.compute_cumulative(max_from, &self.last.height, exit)?;
.compute_cumulative(max_from, &self.height, exit)?;
self.rolling
.compute(max_from, windows, &self.last.height, exit)?;
.compute(max_from, windows, &self.height, exit)?;
Ok(())
}
}

View File

@@ -1,33 +1,29 @@
//! ComputedFromHeightCumSum - stored height + LazyLast + cumulative (from height) + RollingWindows (sum).
//! ComputedFromHeightCumulativeSum - stored height + LazyAggVec + cumulative (from height) + RollingWindows (sum).
//!
//! Like ComputedFromHeightCumFull but with rolling sum only (no distribution).
//! Like ComputedFromHeightCumulativeFull but with rolling sum only (no distribution).
//! Used for count metrics where distribution stats aren't meaningful.
//! Cumulative gets its own ComputedFromHeightLast so it has LazyLast index views too.
//! Cumulative gets its own ComputedFromHeightLast so it has LazyAggVec index views too.
use std::ops::SubAssign;
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Height, Version};
use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use vecdb::{Database, EagerVec, Exit, PcoVec, Rw, StorageMode};
use vecdb::{Database, EagerVec, Exit, ImportableVec, PcoVec, Rw, StorageMode};
use crate::{
indexes,
internal::{ComputedFromHeightLast, NumericValue, RollingWindows, WindowStarts},
};
#[derive(Deref, DerefMut, Traversable)]
#[derive(Traversable)]
#[traversable(merge)]
pub struct ComputedFromHeightCumSum<T, M: StorageMode = Rw>
pub struct ComputedFromHeightCumulativeSum<T, M: StorageMode = Rw>
where
T: NumericValue + JsonSchema,
{
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub last: ComputedFromHeightLast<T, M>,
pub height: M::Stored<EagerVec<PcoVec<Height, T>>>,
#[traversable(flatten)]
pub cumulative: ComputedFromHeightLast<T, M>,
#[traversable(flatten)]
@@ -36,7 +32,7 @@ where
const VERSION: Version = Version::ZERO;
impl<T> ComputedFromHeightCumSum<T>
impl<T> ComputedFromHeightCumulativeSum<T>
where
T: NumericValue + JsonSchema,
{
@@ -48,17 +44,13 @@ where
) -> Result<Self> {
let v = version + VERSION;
let last = ComputedFromHeightLast::forced_import(db, name, v, indexes)?;
let cumulative = ComputedFromHeightLast::forced_import(
db,
&format!("{name}_cumulative"),
v,
indexes,
)?;
let height: EagerVec<PcoVec<Height, T>> = EagerVec::forced_import(db, name, v)?;
let cumulative =
ComputedFromHeightLast::forced_import(db, &format!("{name}_cumulative"), v, indexes)?;
let rolling = RollingWindows::forced_import(db, name, v, indexes)?;
Ok(Self {
last,
height,
cumulative,
rolling,
})
@@ -75,12 +67,12 @@ where
where
T: Default + SubAssign,
{
compute_height(&mut self.last.height)?;
compute_height(&mut self.height)?;
self.cumulative
.height
.compute_cumulative(max_from, &self.last.height, exit)?;
.compute_cumulative(max_from, &self.height, exit)?;
self.rolling
.compute_rolling_sum(max_from, windows, &self.last.height, exit)?;
.compute_rolling_sum(max_from, windows, &self.height, exit)?;
Ok(())
}
}

View File

@@ -1,5 +1,6 @@
//! ComputedFromHeight using Distribution aggregation (no sum/cumulative).
//!
//! Stored height data + LazyAggVec index views + rolling distribution windows.
//! Use for block-based metrics where sum/cumulative would be misleading
//! (e.g., activity counts that can't be deduplicated across blocks).
@@ -7,25 +8,22 @@ use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Height, Version};
use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use vecdb::{Database, EagerVec, ImportableVec, PcoVec, ReadableCloneableVec, Rw, StorageMode};
use vecdb::{Database, EagerVec, Exit, ImportableVec, PcoVec, Rw, StorageMode};
use crate::indexes;
use crate::internal::{ComputedHeightDerivedDistribution, ComputedVecValue, NumericValue};
use crate::internal::{ComputedVecValue, NumericValue, RollingDistribution, WindowStarts};
#[derive(Deref, DerefMut, Traversable)]
#[derive(Traversable)]
#[traversable(merge)]
pub struct ComputedFromHeightDistribution<T, M: StorageMode = Rw>
where
T: ComputedVecValue + PartialOrd + JsonSchema,
{
#[traversable(rename = "base")]
pub height: M::Stored<EagerVec<PcoVec<Height, T>>>,
#[deref]
#[deref_mut]
pub rest: Box<ComputedHeightDerivedDistribution<T>>,
#[traversable(flatten)]
pub rolling: RollingDistribution<T, M>,
}
const VERSION: Version = Version::ZERO;
@@ -43,14 +41,26 @@ where
let v = version + VERSION;
let height: EagerVec<PcoVec<Height, T>> = EagerVec::forced_import(db, name, v)?;
let rolling = RollingDistribution::forced_import(db, name, v, indexes)?;
let rest = ComputedHeightDerivedDistribution::forced_import(
name,
height.read_only_boxed_clone(),
v,
indexes,
);
Ok(Self { height, rolling })
}
Ok(Self { height, rest: Box::new(rest) })
/// Compute height data via closure, then rolling distribution.
pub(crate) fn compute(
&mut self,
max_from: Height,
windows: &WindowStarts<'_>,
exit: &Exit,
compute_height: impl FnOnce(&mut EagerVec<PcoVec<Height, T>>) -> Result<()>,
) -> Result<()>
where
T: Copy + Ord + From<f64> + Default,
f64: From<T>,
{
compute_height(&mut self.height)?;
self.rolling
.compute_distribution(max_from, windows, &self.height, exit)?;
Ok(())
}
}

View File

@@ -1,57 +0,0 @@
//! ComputedFromHeight with full stats aggregation.
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Height, Version};
use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use vecdb::{Database, EagerVec, ImportableVec, PcoVec, ReadableCloneableVec, Rw, StorageMode};
use crate::indexes;
use crate::internal::{ComputedHeightDerivedFull, ComputedVecValue, NumericValue};
#[derive(Deref, DerefMut, Traversable)]
#[traversable(merge)]
pub struct ComputedFromHeightFull<T, M: StorageMode = Rw>
where
T: ComputedVecValue + PartialOrd + JsonSchema,
{
#[traversable(rename = "base")]
pub height: M::Stored<EagerVec<PcoVec<Height, T>>>,
#[deref]
#[deref_mut]
pub rest: Box<ComputedHeightDerivedFull<T, M>>,
}
const VERSION: Version = Version::ZERO;
impl<T> ComputedFromHeightFull<T>
where
T: NumericValue + JsonSchema,
{
pub(crate) fn forced_import(
db: &Database,
name: &str,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
let v = version + VERSION;
let height: EagerVec<PcoVec<Height, T>> = EagerVec::forced_import(db, name, v)?;
let rest = ComputedHeightDerivedFull::forced_import(
db,
name,
height.read_only_boxed_clone(),
v,
indexes,
)?;
Ok(Self {
height,
rest: Box::new(rest),
})
}
}

View File

@@ -6,7 +6,10 @@ use brk_traversable::Traversable;
use brk_types::{Height, Version};
use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use vecdb::{Database, EagerVec, ImportableVec, PcoVec, ReadableCloneableVec, Rw, StorageMode};
use vecdb::{
BinaryTransform, Database, EagerVec, Exit, ImportableVec, PcoVec, ReadableCloneableVec,
ReadableVec, Rw, StorageMode, VecValue,
};
use crate::indexes;
@@ -41,9 +44,39 @@ where
let height: EagerVec<PcoVec<Height, T>> = EagerVec::forced_import(db, name, v)?;
let rest =
ComputedHeightDerivedLast::forced_import(name, height.read_only_boxed_clone(), v, indexes);
let rest = ComputedHeightDerivedLast::forced_import(
name,
height.read_only_boxed_clone(),
v,
indexes,
);
Ok(Self { height, rest: Box::new(rest) })
Ok(Self {
height,
rest: Box::new(rest),
})
}
/// Eagerly compute this vec as a binary transform of two sources.
pub(crate) fn compute_binary<S1T, S2T, F>(
&mut self,
max_from: Height,
source1: &impl ReadableVec<Height, S1T>,
source2: &impl ReadableVec<Height, S2T>,
exit: &Exit,
) -> Result<()>
where
S1T: VecValue,
S2T: VecValue,
F: BinaryTransform<S1T, S2T, T>,
{
self.height.compute_transform2(
max_from,
source1,
source2,
|(h, s1, s2, ..)| (h, F::apply(s1, s2)),
exit,
)?;
Ok(())
}
}

View File

@@ -1,61 +0,0 @@
//! LazyBinaryComputedFromHeightDistribution - lazy binary transform with distribution stats.
//!
//! Height-level values are lazy: `transform(source1[h], source2[h])`.
//! Uses Distribution aggregation (no sum/cumulative) - appropriate for ratios.
use brk_traversable::Traversable;
use brk_types::{Height, Version};
use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use vecdb::{BinaryTransform, ReadableBoxedVec, ReadableCloneableVec, LazyVecFrom2};
use crate::{
indexes,
internal::{ComputedHeightDerivedDistribution, ComputedVecValue, NumericValue},
};
const VERSION: Version = Version::ZERO;
/// Lazy binary transform at height with distribution stats (no sum/cumulative).
#[derive(Clone, Deref, DerefMut, Traversable)]
#[traversable(merge)]
pub struct LazyBinaryComputedFromHeightDistribution<T, S1T = T, S2T = T>
where
T: ComputedVecValue + PartialOrd + JsonSchema,
S1T: ComputedVecValue,
S2T: ComputedVecValue,
{
#[traversable(rename = "base")]
pub height: LazyVecFrom2<Height, T, Height, S1T, Height, S2T>,
#[deref]
#[deref_mut]
pub rest: Box<ComputedHeightDerivedDistribution<T>>,
}
impl<T, S1T, S2T> LazyBinaryComputedFromHeightDistribution<T, S1T, S2T>
where
T: NumericValue + JsonSchema,
S1T: ComputedVecValue + JsonSchema,
S2T: ComputedVecValue + JsonSchema,
{
pub(crate) fn forced_import<F: BinaryTransform<S1T, S2T, T>>(
name: &str,
version: Version,
source1: ReadableBoxedVec<Height, S1T>,
source2: ReadableBoxedVec<Height, S2T>,
indexes: &indexes::Vecs,
) -> Self {
let v = version + VERSION;
let height = LazyVecFrom2::transformed::<F>(name, v, source1, source2);
let rest = ComputedHeightDerivedDistribution::forced_import(
name,
height.read_only_boxed_clone(),
v,
indexes,
);
Self { height, rest: Box::new(rest) }
}
}

View File

@@ -1,69 +0,0 @@
//! LazyBinaryComputedFromHeightFull - block full with lazy binary transform at height level.
//!
//! Height-level values are lazy: `transform(source1[h], source2[h])`.
//! Cumulative, day1 stats, and difficultyepoch are stored since they
//! require aggregation across heights.
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Height, Version};
use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use vecdb::{BinaryTransform, Database, Exit, ReadableBoxedVec, ReadableCloneableVec, LazyVecFrom2, Rw, StorageMode};
use crate::{
ComputeIndexes, indexes,
internal::{ComputedHeightDerivedFull, ComputedVecValue, NumericValue},
};
const VERSION: Version = Version::ZERO;
/// Block full aggregation with lazy binary transform at height + computed derived indexes.
#[derive(Deref, DerefMut, Traversable)]
#[traversable(merge)]
pub struct LazyBinaryComputedFromHeightFull<T, S1T = T, S2T = T, M: StorageMode = Rw>
where
T: ComputedVecValue + PartialOrd + JsonSchema,
S1T: ComputedVecValue,
S2T: ComputedVecValue,
{
#[traversable(rename = "base")]
pub height: LazyVecFrom2<Height, T, Height, S1T, Height, S2T>,
#[deref]
#[deref_mut]
pub rest: Box<ComputedHeightDerivedFull<T, M>>,
}
impl<T, S1T, S2T> LazyBinaryComputedFromHeightFull<T, S1T, S2T>
where
T: NumericValue + JsonSchema,
S1T: ComputedVecValue + JsonSchema,
S2T: ComputedVecValue + JsonSchema,
{
pub(crate) fn forced_import<F: BinaryTransform<S1T, S2T, T>>(
db: &Database,
name: &str,
version: Version,
source1: ReadableBoxedVec<Height, S1T>,
source2: ReadableBoxedVec<Height, S2T>,
indexes: &indexes::Vecs,
) -> Result<Self> {
let v = version + VERSION;
let height = LazyVecFrom2::transformed::<F>(name, v, source1, source2);
let rest =
ComputedHeightDerivedFull::forced_import(db, name, height.read_only_boxed_clone(), v, indexes)?;
Ok(Self { height, rest: Box::new(rest) })
}
pub(crate) fn compute_cumulative(
&mut self,
starting_indexes: &ComputeIndexes,
exit: &Exit,
) -> Result<()> {
self.rest
.compute_cumulative(starting_indexes, &self.height, exit)
}
}

View File

@@ -1,58 +0,0 @@
//! LazyBinaryComputedFromHeightLast - block last with lazy binary transform at height level.
//!
//! Height-level value is lazy: `transform(source1[h], source2[h])`.
//! Day1 last is stored since it requires finding the last value within each date
//! (which may span multiple heights with varying prices).
use brk_traversable::Traversable;
use brk_types::{Height, Version};
use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use vecdb::{BinaryTransform, ReadableBoxedVec, ReadableCloneableVec, LazyVecFrom2};
use crate::{
indexes,
internal::{ComputedHeightDerivedLast, ComputedVecValue, NumericValue},
};
const VERSION: Version = Version::ZERO;
/// Block last aggregation with lazy binary transform at height + computed derived indexes.
#[derive(Clone, Deref, DerefMut, Traversable)]
#[traversable(merge)]
pub struct LazyBinaryComputedFromHeightLast<T, S1T = T, S2T = T>
where
T: ComputedVecValue + PartialOrd + JsonSchema,
S1T: ComputedVecValue,
S2T: ComputedVecValue,
{
pub height: LazyVecFrom2<Height, T, Height, S1T, Height, S2T>,
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub rest: Box<ComputedHeightDerivedLast<T>>,
}
impl<T, S1T, S2T> LazyBinaryComputedFromHeightLast<T, S1T, S2T>
where
T: NumericValue + JsonSchema,
S1T: ComputedVecValue + JsonSchema,
S2T: ComputedVecValue + JsonSchema,
{
pub(crate) fn forced_import<F: BinaryTransform<S1T, S2T, T>>(
name: &str,
version: Version,
source1: ReadableBoxedVec<Height, S1T>,
source2: ReadableBoxedVec<Height, S2T>,
indexes: &indexes::Vecs,
) -> Self {
let v = version + VERSION;
let height = LazyVecFrom2::transformed::<F>(name, v, source1, source2);
let rest =
ComputedHeightDerivedLast::forced_import(name, height.read_only_boxed_clone(), v, indexes);
Self { height, rest: Box::new(rest) }
}
}

View File

@@ -1,71 +0,0 @@
//! LazyBinaryComputedFromHeightSumCum - block sum_cum with lazy binary transform at height level.
//!
//! Height-level sum is lazy: `transform(source1[h], source2[h])`.
//! Cumulative and day1 stats are stored since they require aggregation
//! across heights.
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Height, Version};
use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use vecdb::{BinaryTransform, Database, Exit, ReadableBoxedVec, ReadableCloneableVec, LazyVecFrom2, Rw, StorageMode};
use crate::{
ComputeIndexes,
indexes,
internal::{ComputedHeightDerivedSumCum, ComputedVecValue, NumericValue},
};
const VERSION: Version = Version::ZERO;
/// Block sum_cum aggregation with lazy binary transform at height + computed derived indexes.
#[derive(Deref, DerefMut, Traversable)]
#[traversable(merge)]
pub struct LazyBinaryComputedFromHeightSumCum<T, S1T = T, S2T = T, M: StorageMode = Rw>
where
T: ComputedVecValue + PartialOrd + JsonSchema,
S1T: ComputedVecValue,
S2T: ComputedVecValue,
{
#[traversable(rename = "sum")]
pub height: LazyVecFrom2<Height, T, Height, S1T, Height, S2T>,
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub rest: Box<ComputedHeightDerivedSumCum<T, M>>,
}
impl<T, S1T, S2T> LazyBinaryComputedFromHeightSumCum<T, S1T, S2T>
where
T: NumericValue + JsonSchema,
S1T: ComputedVecValue + JsonSchema,
S2T: ComputedVecValue + JsonSchema,
{
pub(crate) fn forced_import<F: BinaryTransform<S1T, S2T, T>>(
db: &Database,
name: &str,
version: Version,
source1: ReadableBoxedVec<Height, S1T>,
source2: ReadableBoxedVec<Height, S2T>,
indexes: &indexes::Vecs,
) -> Result<Self> {
let v = version + VERSION;
let height = LazyVecFrom2::transformed::<F>(name, v, source1, source2);
let rest =
ComputedHeightDerivedSumCum::forced_import(db, name, height.read_only_boxed_clone(), v, indexes)?;
Ok(Self { height, rest: Box::new(rest) })
}
pub(crate) fn compute_cumulative(
&mut self,
starting_indexes: &ComputeIndexes,
exit: &Exit,
) -> Result<()> {
self.rest
.derive_from(starting_indexes, &self.height, exit)
}
}

View File

@@ -1,33 +1,34 @@
//! LazyComputedFromHeightFull - block full with lazy height transform.
//! LazyComputedFromHeightCumulativeFull - block full with lazy height transform + cumulative + rolling.
use std::ops::SubAssign;
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Height, Version};
use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use vecdb::{Database, Exit, ReadableCloneableVec, LazyVecFrom1, UnaryTransform, Rw, StorageMode};
use vecdb::{Database, Exit, LazyVecFrom1, ReadableCloneableVec, Rw, StorageMode, UnaryTransform};
use crate::{
ComputeIndexes,
indexes,
internal::{ComputedVecValue, ComputedHeightDerivedFull, NumericValue},
internal::{ComputedHeightDerivedCumulativeFull, ComputedVecValue, NumericValue, WindowStarts},
};
const VERSION: Version = Version::ZERO;
/// Block full aggregation with lazy height transform + computed derived indexes.
/// Block full aggregation with lazy height transform + cumulative + rolling windows.
#[derive(Deref, DerefMut, Traversable)]
#[traversable(merge)]
pub struct LazyComputedFromHeightFull<T, S = T, M: StorageMode = Rw>
where
T: ComputedVecValue + PartialOrd + JsonSchema,
T: NumericValue + JsonSchema,
S: ComputedVecValue,
{
#[traversable(rename = "base")]
pub height: LazyVecFrom1<Height, T, Height, S>,
#[deref]
#[deref_mut]
pub rest: Box<ComputedHeightDerivedFull<T, M>>,
pub rest: Box<ComputedHeightDerivedCumulativeFull<T, M>>,
}
impl<T, S> LazyComputedFromHeightFull<T, S>
@@ -46,18 +47,29 @@ where
let height = LazyVecFrom1::transformed::<F>(name, v, source.read_only_boxed_clone());
let rest =
ComputedHeightDerivedFull::forced_import(db, name, height.read_only_boxed_clone(), v, indexes)?;
let rest = ComputedHeightDerivedCumulativeFull::forced_import(
db,
name,
v,
indexes,
)?;
Ok(Self { height, rest: Box::new(rest) })
Ok(Self {
height,
rest: Box::new(rest),
})
}
pub(crate) fn compute_cumulative(
pub(crate) fn compute(
&mut self,
starting_indexes: &ComputeIndexes,
max_from: Height,
windows: &WindowStarts<'_>,
exit: &Exit,
) -> Result<()> {
self.rest
.compute_cumulative(starting_indexes, &self.height, exit)
) -> Result<()>
where
T: From<f64> + Default + SubAssign + Copy + Ord,
f64: From<T>,
{
self.rest.compute(max_from, windows, &self.height, exit)
}
}

View File

@@ -1,75 +0,0 @@
//! LazyComputedFromHeightSumCum - block sum+cumulative with lazy height transform.
//!
//! Use this when you need:
//! - Lazy height (binary transform from two sources)
//! - Stored cumulative and day1 aggregates
//! - Lazy coarser period lookups
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Height, Version};
use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use vecdb::{Database, Exit, ReadableCloneableVec, LazyVecFrom2, Rw, StorageMode};
use crate::{indexes, ComputeIndexes};
use crate::internal::{ComputedVecValue, ComputedHeightDerivedSumCum, NumericValue};
/// Block sum+cumulative with lazy binary height transform + computed derived indexes.
///
/// Height is a lazy binary transform (e.g., mask × source, or price × sats).
/// Cumulative and day1 are stored (computed from lazy height).
/// Coarser periods are lazy lookups.
#[derive(Deref, DerefMut, Traversable)]
#[traversable(merge)]
pub struct LazyComputedFromHeightSumCum<T, S1T = T, S2T = T, M: StorageMode = Rw>
where
T: ComputedVecValue + PartialOrd + JsonSchema,
S1T: ComputedVecValue,
S2T: ComputedVecValue,
{
#[traversable(rename = "sum")]
pub height: LazyVecFrom2<Height, T, Height, S1T, Height, S2T>,
#[deref]
#[deref_mut]
pub rest: Box<ComputedHeightDerivedSumCum<T, M>>,
}
const VERSION: Version = Version::ZERO;
impl<T, S1T, S2T> LazyComputedFromHeightSumCum<T, S1T, S2T>
where
T: NumericValue + JsonSchema,
S1T: ComputedVecValue + JsonSchema,
S2T: ComputedVecValue + JsonSchema,
{
pub(crate) fn forced_import(
db: &Database,
name: &str,
version: Version,
indexes: &indexes::Vecs,
height: LazyVecFrom2<Height, T, Height, S1T, Height, S2T>,
) -> Result<Self> {
let v = version + VERSION;
let rest = ComputedHeightDerivedSumCum::forced_import(
db,
name,
height.read_only_boxed_clone(),
v,
indexes,
)?;
Ok(Self { height, rest: Box::new(rest) })
}
pub(crate) fn compute_cumulative(
&mut self,
starting_indexes: &ComputeIndexes,
exit: &Exit,
) -> Result<()> {
self.rest
.derive_from(starting_indexes, &self.height, exit)
}
}

View File

@@ -1,50 +0,0 @@
//! Lazy unary transform from height with Full aggregation.
use brk_traversable::Traversable;
use brk_types::{Height, Version};
use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use vecdb::{ReadableBoxedVec, LazyVecFrom1, UnaryTransform};
use crate::internal::{
ComputedFromHeightFull, ComputedVecValue, LazyHeightDerivedFull,
NumericValue,
};
#[derive(Clone, Deref, DerefMut, Traversable)]
#[traversable(merge)]
pub struct LazyFromHeightFull<T, S1T = T>
where
T: ComputedVecValue + PartialOrd + JsonSchema,
S1T: ComputedVecValue,
{
#[traversable(rename = "base")]
pub height: LazyVecFrom1<Height, T, Height, S1T>,
#[deref]
#[deref_mut]
pub rest: Box<LazyHeightDerivedFull<T, S1T>>,
}
const VERSION: Version = Version::ZERO;
impl<T, S1T> LazyFromHeightFull<T, S1T>
where
T: ComputedVecValue + JsonSchema + 'static,
S1T: ComputedVecValue + JsonSchema,
{
pub(crate) fn from_computed<F: UnaryTransform<S1T, T>>(
name: &str,
version: Version,
height_source: ReadableBoxedVec<Height, S1T>,
source: &ComputedFromHeightFull<S1T>,
) -> Self
where
S1T: NumericValue,
{
let v = version + VERSION;
Self {
height: LazyVecFrom1::transformed::<F>(name, v, height_source),
rest: Box::new(LazyHeightDerivedFull::from_derived_computed::<F>(name, v, &source.rest)),
}
}
}

View File

@@ -6,10 +6,11 @@ use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use vecdb::{ReadableBoxedVec, ReadableCloneableVec, LazyVecFrom1, UnaryTransform};
use crate::internal::{
ComputedFromHeightLast,
ComputedVecValue, LazyBinaryComputedFromHeightLast, LazyBinaryFromHeightLast,
LazyHeightDerivedLast, NumericValue,
use crate::{
indexes,
internal::{
ComputedFromHeightLast, ComputedVecValue, LazyHeightDerivedLast, NumericValue,
},
};
#[derive(Clone, Deref, DerefMut, Traversable)]
#[traversable(merge)]
@@ -48,22 +49,19 @@ where
}
}
pub(crate) fn from_lazy_binary_computed<F, S1aT, S1bT>(
pub(crate) fn from_height_source<F: UnaryTransform<S1T, T>>(
name: &str,
version: Version,
height_source: ReadableBoxedVec<Height, S1T>,
source: &LazyBinaryComputedFromHeightLast<S1T, S1aT, S1bT>,
indexes: &indexes::Vecs,
) -> Self
where
F: UnaryTransform<S1T, T>,
S1T: NumericValue,
S1aT: ComputedVecValue + JsonSchema,
S1bT: ComputedVecValue + JsonSchema,
{
let v = version + VERSION;
Self {
height: LazyVecFrom1::transformed::<F>(name, v, height_source),
rest: Box::new(LazyHeightDerivedLast::from_derived_computed::<F>(name, v, &source.rest)),
height: LazyVecFrom1::transformed::<F>(name, v, height_source.clone()),
rest: Box::new(LazyHeightDerivedLast::from_height_source::<F>(name, v, height_source, indexes)),
}
}
@@ -84,21 +82,4 @@ where
}
}
/// Create by unary-transforming a LazyBinaryFromHeightLast source.
pub(crate) fn from_binary<F, S1aT, S1bT>(
name: &str,
version: Version,
source: &LazyBinaryFromHeightLast<S1T, S1aT, S1bT>,
) -> Self
where
F: UnaryTransform<S1T, T>,
S1aT: ComputedVecValue + JsonSchema,
S1bT: ComputedVecValue + JsonSchema,
{
let v = version + VERSION;
Self {
height: LazyVecFrom1::transformed::<F>(name, v, source.height.read_only_boxed_clone()),
rest: Box::new(LazyHeightDerivedLast::from_binary::<F, _, _>(name, v, &source.rest)),
}
}
}

View File

@@ -1,66 +0,0 @@
//! Lazy unary transform from height with SumCum aggregation.
use brk_traversable::Traversable;
use brk_types::{Height, Version};
use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use vecdb::{ReadableBoxedVec, LazyVecFrom1, UnaryTransform};
use crate::internal::{
ComputedFromHeightSumCum, ComputedHeightDerivedSumCum, ComputedVecValue,
LazyHeightDerivedSumCum, NumericValue,
};
#[derive(Clone, Deref, DerefMut, Traversable)]
#[traversable(merge)]
pub struct LazyFromHeightSumCum<T, S1T = T>
where
T: ComputedVecValue + PartialOrd + JsonSchema,
S1T: ComputedVecValue,
{
#[traversable(rename = "sum")]
pub height: LazyVecFrom1<Height, T, Height, S1T>,
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub rest: Box<LazyHeightDerivedSumCum<T, S1T>>,
}
const VERSION: Version = Version::ZERO;
impl<T, S1T> LazyFromHeightSumCum<T, S1T>
where
T: ComputedVecValue + JsonSchema + 'static,
S1T: ComputedVecValue + JsonSchema,
{
pub(crate) fn from_computed<F: UnaryTransform<S1T, T>>(
name: &str,
version: Version,
height_source: ReadableBoxedVec<Height, S1T>,
source: &ComputedFromHeightSumCum<S1T>,
) -> Self
where
S1T: NumericValue,
{
let v = version + VERSION;
Self {
height: LazyVecFrom1::transformed::<F>(name, v, height_source),
rest: Box::new(LazyHeightDerivedSumCum::from_derived_computed::<F>(name, v, &source.rest)),
}
}
pub(crate) fn from_derived<F: UnaryTransform<S1T, T>>(
name: &str,
version: Version,
height_source: ReadableBoxedVec<Height, S1T>,
source: &ComputedHeightDerivedSumCum<S1T>,
) -> Self
where
S1T: NumericValue,
{
let v = version + VERSION;
Self {
height: LazyVecFrom1::transformed::<F>(name, v, height_source),
rest: Box::new(LazyHeightDerivedSumCum::from_derived_computed::<F>(name, v, source)),
}
}
}

View File

@@ -1,54 +0,0 @@
use brk_traversable::Traversable;
use brk_types::{Bitcoin, Dollars, Height, Sats, Version};
use derive_more::{Deref, DerefMut};
use vecdb::{BinaryTransform, ReadableBoxedVec, LazyVecFrom1, LazyVecFrom2, UnaryTransform};
use crate::internal::LazyDerivedValuesHeight;
const VERSION: Version = Version::ZERO;
#[derive(Clone, Deref, DerefMut, Traversable)]
#[traversable(merge)]
pub struct LazyFromHeightValue {
#[traversable(rename = "sats")]
pub sats: LazyVecFrom1<Height, Sats, Height, Sats>,
#[deref]
#[deref_mut]
pub rest: LazyDerivedValuesHeight,
}
impl LazyFromHeightValue {
pub(crate) fn from_sources<SatsTransform, BitcoinTransform, DollarsTransform>(
name: &str,
sats_source: ReadableBoxedVec<Height, Sats>,
price_source: ReadableBoxedVec<Height, Dollars>,
version: Version,
) -> Self
where
SatsTransform: UnaryTransform<Sats, Sats>,
BitcoinTransform: UnaryTransform<Sats, Bitcoin>,
DollarsTransform: BinaryTransform<Dollars, Sats, Dollars>,
{
let v = version + VERSION;
let sats = LazyVecFrom1::transformed::<SatsTransform>(name, v, sats_source.clone());
let btc = LazyVecFrom1::transformed::<BitcoinTransform>(
&format!("{name}_btc"),
v,
sats_source.clone(),
);
let usd = LazyVecFrom2::transformed::<DollarsTransform>(
&format!("{name}_usd"),
v,
price_source,
sats_source,
);
Self {
sats,
rest: LazyDerivedValuesHeight { btc, usd },
}
}
}

View File

@@ -1,67 +1,41 @@
mod binary_last;
mod constant;
mod cum;
mod cum_rolling_full;
mod cum_rolling_sum;
mod cumulative;
mod cumulative_rolling_full;
mod cumulative_rolling_sum;
mod distribution;
mod full;
mod last;
mod lazy_binary_computed_distribution;
mod lazy_binary_computed_full;
mod lazy_binary_computed_last;
mod lazy_binary_computed_sum_cum;
mod lazy_computed_full;
mod lazy_computed_sum_cum;
mod lazy_full;
mod lazy_last;
mod lazy_sum_cum;
mod lazy_value;
mod percentiles;
mod price;
mod ratio;
mod stddev;
mod stored_value_last;
mod sum_cum;
mod value_change;
mod value_ema;
mod value_full;
mod value_last;
mod value_lazy_binary_last;
mod value_lazy_computed_cum;
mod value_lazy_computed_cumulative;
mod value_lazy_last;
mod value_lazy_sum_cum;
mod value_sum_cum;
mod value_sum_cumulative;
pub use binary_last::*;
pub use constant::*;
pub use cum::*;
pub use cum_rolling_full::*;
pub use cum_rolling_sum::*;
pub use cumulative::*;
pub use cumulative_rolling_full::*;
pub use cumulative_rolling_sum::*;
pub use distribution::*;
pub use full::*;
pub use last::*;
pub use lazy_binary_computed_distribution::*;
pub use lazy_binary_computed_full::*;
pub use lazy_binary_computed_last::*;
pub use lazy_binary_computed_sum_cum::*;
pub use lazy_computed_full::*;
pub use lazy_computed_sum_cum::*;
pub use lazy_full::*;
pub use lazy_last::*;
pub use lazy_sum_cum::*;
pub use lazy_value::*;
pub use percentiles::*;
pub use price::*;
pub use ratio::*;
pub use stddev::*;
pub use stored_value_last::*;
pub use sum_cum::*;
pub use value_change::*;
pub use value_ema::*;
pub use value_full::*;
pub use value_last::*;
pub use value_lazy_binary_last::*;
pub use value_lazy_computed_cum::*;
pub use value_lazy_computed_cumulative::*;
pub use value_lazy_last::*;
pub use value_lazy_sum_cum::*;
pub use value_sum_cum::*;
pub use value_sum_cumulative::*;

View File

@@ -1,12 +1,10 @@
use brk_error::Result;
use brk_traversable::{Traversable, TreeNode};
use brk_types::{Dollars, Height, StoredF32, Version};
use vecdb::{
AnyExportableVec, Database, ReadOnlyClone, Ro, Rw, StorageMode, WritableVec,
};
use vecdb::{AnyExportableVec, Database, ReadOnlyClone, Ro, Rw, StorageMode, WritableVec};
use crate::indexes;
use crate::internal::{ComputedFromHeightLast, Price, PriceFromHeight};
use crate::internal::{ComputedFromHeightLast, Price};
pub const PERCENTILES: [u8; 19] = [
5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95,
@@ -15,7 +13,10 @@ pub const PERCENTILES_LEN: usize = PERCENTILES.len();
/// Compute spot percentile rank by interpolating within percentile bands.
/// Returns a value between 0 and 100 indicating where spot sits in the distribution.
pub(crate) fn compute_spot_percentile_rank(percentile_prices: &[Dollars; PERCENTILES_LEN], spot: Dollars) -> StoredF32 {
pub(crate) fn compute_spot_percentile_rank(
percentile_prices: &[Dollars; PERCENTILES_LEN],
spot: Dollars,
) -> StoredF32 {
if spot.is_nan() || percentile_prices[0].is_nan() {
return StoredF32::NAN;
}
@@ -83,7 +84,8 @@ impl PercentilesVecs {
let vecs = PERCENTILES.map(|p| {
compute.then(|| {
let metric_name = format!("{prefix}_pct{p:02}");
PriceFromHeight::forced_import(db, &metric_name, version + VERSION, indexes).unwrap()
Price::forced_import(db, &metric_name, version + VERSION, indexes)
.unwrap()
})
});
@@ -98,7 +100,7 @@ impl PercentilesVecs {
) -> Result<()> {
for (i, vec) in self.vecs.iter_mut().enumerate() {
if let Some(v) = vec {
v.height.truncate_push(height, percentile_prices[i])?;
v.usd.height.truncate_push(height, percentile_prices[i])?;
}
}
Ok(())
@@ -107,7 +109,7 @@ impl PercentilesVecs {
/// Validate computed versions or reset if mismatched.
pub(crate) fn validate_computed_version_or_reset(&mut self, version: Version) -> Result<()> {
for vec in self.vecs.iter_mut().flatten() {
vec.height.validate_computed_version_or_reset(version)?;
vec.usd.height.validate_computed_version_or_reset(version)?;
}
Ok(())
}
@@ -118,7 +120,10 @@ impl ReadOnlyClone for PercentilesVecs {
fn read_only_clone(&self) -> Self::ReadOnly {
PercentilesVecs {
vecs: self.vecs.each_ref().map(|v| v.as_ref().map(|p| p.read_only_clone())),
vecs: self
.vecs
.each_ref()
.map(|v| v.as_ref().map(|p| p.read_only_clone())),
}
}
}

View File

@@ -5,35 +5,25 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Cents, Dollars, SatsFract, Version};
use derive_more::{Deref, DerefMut};
use brk_types::{Dollars, SatsFract, Version};
use schemars::JsonSchema;
use vecdb::{BinaryTransform, Database, ReadableCloneableVec, UnaryTransform};
use vecdb::{Database, ReadableCloneableVec, UnaryTransform};
use super::{ComputedFromHeightLast, LazyBinaryFromHeightLast, LazyFromHeightLast};
use super::{ComputedFromHeightLast, LazyFromHeightLast};
use crate::{
indexes,
internal::{ComputedVecValue, DollarsToSatsFract, NumericValue},
};
/// Generic price metric with both USD and sats representations.
///
/// Derefs to the usd metric, so existing code works unchanged.
/// Access `.sats` for the sats exchange rate version.
#[derive(Clone, Deref, DerefMut, Traversable)]
#[derive(Clone, Traversable)]
#[traversable(merge)]
pub struct Price<U> {
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub usd: U,
pub sats: LazyFromHeightLast<SatsFract, Dollars>,
}
// --- PriceFromHeight ---
pub type PriceFromHeight = Price<ComputedFromHeightLast<Dollars>>;
impl Price<ComputedFromHeightLast<Dollars>> {
pub(crate) fn forced_import(
db: &Database,
@@ -42,28 +32,16 @@ impl Price<ComputedFromHeightLast<Dollars>> {
indexes: &indexes::Vecs,
) -> Result<Self> {
let usd = ComputedFromHeightLast::forced_import(db, name, version, indexes)?;
Ok(Self::from_computed(name, version, usd))
}
pub(crate) fn from_computed(
name: &str,
version: Version,
usd: ComputedFromHeightLast<Dollars>,
) -> Self {
let sats = LazyFromHeightLast::from_computed::<DollarsToSatsFract>(
&format!("{name}_sats"),
version,
usd.height.read_only_boxed_clone(),
&usd,
);
Self { usd, sats }
Ok(Self { usd, sats })
}
}
// --- LazyPriceFromHeight ---
pub type LazyPriceFromHeight<ST> = Price<LazyFromHeightLast<Dollars, ST>>;
impl<ST> Price<LazyFromHeightLast<Dollars, ST>>
where
ST: ComputedVecValue + NumericValue + JsonSchema + 'static,
@@ -88,106 +66,3 @@ where
}
}
// --- LazyPriceFromCents ---
pub type LazyPriceFromCents = Price<LazyFromHeightLast<Dollars, Cents>>;
// --- LazyBinaryPriceFromHeight ---
pub type LazyBinaryPriceFromHeight = Price<LazyBinaryFromHeightLast<Dollars, Dollars, Dollars>>;
impl Price<LazyBinaryFromHeightLast<Dollars, Dollars, Dollars>> {
/// Create from a PriceFromHeight (source1) and a LazyPriceFromCents (source2).
pub(crate) fn from_price_and_lazy_price<F: BinaryTransform<Dollars, Dollars, Dollars>>(
name: &str,
version: Version,
source1: &PriceFromHeight,
source2: &LazyPriceFromCents,
) -> Self {
let usd = LazyBinaryFromHeightLast::from_block_last_and_lazy_block_last::<F, Cents>(
name,
version,
&source1.usd,
&source2.usd,
);
let sats = LazyFromHeightLast::from_binary::<DollarsToSatsFract, _, _>(
&format!("{name}_sats"),
version,
&usd,
);
Self { usd, sats }
}
/// Create from a LazyPriceFromCents (source1) and a PriceFromHeight (source2).
pub(crate) fn from_lazy_price_and_price<F: BinaryTransform<Dollars, Dollars, Dollars>>(
name: &str,
version: Version,
source1: &LazyPriceFromCents,
source2: &PriceFromHeight,
) -> Self {
let usd = LazyBinaryFromHeightLast::from_lazy_block_last_and_block_last::<F, Cents>(
name,
version,
&source1.usd,
&source2.usd,
);
let sats = LazyFromHeightLast::from_binary::<DollarsToSatsFract, _, _>(
&format!("{name}_sats"),
version,
&usd,
);
Self { usd, sats }
}
}
// --- Price bands (for stddev/ratio) ---
impl<S2T> Price<LazyBinaryFromHeightLast<Dollars, Dollars, S2T>>
where
S2T: ComputedVecValue + NumericValue + JsonSchema,
{
/// Create a price band from a computed price and a computed band.
pub(crate) fn from_computed_price_and_band<F: BinaryTransform<Dollars, S2T, Dollars>>(
name: &str,
version: Version,
price: &ComputedFromHeightLast<Dollars>,
band: &ComputedFromHeightLast<S2T>,
) -> Self {
let usd = LazyBinaryFromHeightLast::from_computed_last::<F>(name, version, price, band);
let sats = LazyFromHeightLast::from_binary::<DollarsToSatsFract, _, _>(
&format!("{name}_sats"),
version,
&usd,
);
Self { usd, sats }
}
/// Create a price band from a lazy price and a computed band.
pub(crate) fn from_lazy_price_and_band<F: BinaryTransform<Dollars, S2T, Dollars>, S1T>(
name: &str,
version: Version,
price: &LazyFromHeightLast<Dollars, S1T>,
band: &ComputedFromHeightLast<S2T>,
) -> Self
where
S1T: ComputedVecValue + JsonSchema,
{
let usd = LazyBinaryFromHeightLast::from_lazy_block_last_and_block_last::<F, S1T>(
name, version, price, band,
);
let sats = LazyFromHeightLast::from_binary::<DollarsToSatsFract, _, _>(
&format!("{name}_sats"),
version,
&usd,
);
Self { usd, sats }
}
}

View File

@@ -1,23 +1,19 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Dollars, Height, StoredF32, Version};
use schemars::JsonSchema;
use vecdb::{
AnyStoredVec, AnyVec, Database, EagerVec, Exit, WritableVec, ReadableVec,
PcoVec, Rw, StorageMode, VecIndex,
AnyStoredVec, AnyVec, Database, EagerVec, Exit, PcoVec, ReadableVec, Rw, StorageMode, VecIndex,
WritableVec,
};
use crate::{
blocks, indexes, ComputeIndexes,
internal::{
ComputedFromHeightStdDev, ComputedVecValue, LazyBinaryFromHeightLast,
LazyFromHeightLast, Price, PriceTimesRatio, StandardDeviationVecsOptions,
},
ComputeIndexes, blocks, indexes,
internal::{ComputedFromHeightStdDev, Price, StandardDeviationVecsOptions},
prices,
utils::get_percentile,
};
use super::{ComputedFromHeightLast, PriceFromHeight};
use super::ComputedFromHeightLast;
#[derive(Traversable)]
pub struct ComputedFromHeightRatio<M: StorageMode = Rw> {
@@ -32,12 +28,12 @@ pub struct ComputedFromHeightRatio<M: StorageMode = Rw> {
pub ratio_pct5: Option<ComputedFromHeightLast<StoredF32, M>>,
pub ratio_pct2: Option<ComputedFromHeightLast<StoredF32, M>>,
pub ratio_pct1: Option<ComputedFromHeightLast<StoredF32, M>>,
pub ratio_pct99_usd: Option<Price<LazyBinaryFromHeightLast<Dollars, Dollars, StoredF32>>>,
pub ratio_pct98_usd: Option<Price<LazyBinaryFromHeightLast<Dollars, Dollars, StoredF32>>>,
pub ratio_pct95_usd: Option<Price<LazyBinaryFromHeightLast<Dollars, Dollars, StoredF32>>>,
pub ratio_pct5_usd: Option<Price<LazyBinaryFromHeightLast<Dollars, Dollars, StoredF32>>>,
pub ratio_pct2_usd: Option<Price<LazyBinaryFromHeightLast<Dollars, Dollars, StoredF32>>>,
pub ratio_pct1_usd: Option<Price<LazyBinaryFromHeightLast<Dollars, Dollars, StoredF32>>>,
pub ratio_pct99_usd: Option<Price<ComputedFromHeightLast<Dollars, M>>>,
pub ratio_pct98_usd: Option<Price<ComputedFromHeightLast<Dollars, M>>>,
pub ratio_pct95_usd: Option<Price<ComputedFromHeightLast<Dollars, M>>>,
pub ratio_pct5_usd: Option<Price<ComputedFromHeightLast<Dollars, M>>>,
pub ratio_pct2_usd: Option<Price<ComputedFromHeightLast<Dollars, M>>>,
pub ratio_pct1_usd: Option<Price<ComputedFromHeightLast<Dollars, M>>>,
pub ratio_sd: Option<ComputedFromHeightStdDev<M>>,
pub ratio_4y_sd: Option<ComputedFromHeightStdDev<M>>,
@@ -74,10 +70,7 @@ impl ComputedFromHeightRatio {
// Only compute price internally when metric_price is None
let price = metric_price
.is_none()
.then(|| PriceFromHeight::forced_import(db, name, v, indexes).unwrap());
// Use provided metric_price, falling back to internally computed price
let effective_price = metric_price.or(price.as_ref().map(|p| &p.usd));
.then(|| Price::forced_import(db, name, v, indexes).unwrap());
macro_rules! import_sd {
($suffix:expr, $days:expr) => {
@@ -88,7 +81,6 @@ impl ComputedFromHeightRatio {
v,
indexes,
StandardDeviationVecsOptions::default().add_all(),
effective_price,
)
.unwrap()
};
@@ -103,14 +95,19 @@ impl ComputedFromHeightRatio {
macro_rules! lazy_usd {
($ratio:expr, $suffix:expr) => {
effective_price.zip($ratio.as_ref()).map(|(mp, r)| {
Price::from_computed_price_and_band::<PriceTimesRatio>(
&format!("{name}_{}", $suffix),
v,
mp,
r,
)
})
if !extended {
None
} else {
$ratio.as_ref().map(|_| {
Price::forced_import(
db,
&format!("{name}_{}", $suffix),
v,
indexes,
)
.unwrap()
})
}
};
}
@@ -138,10 +135,9 @@ impl ComputedFromHeightRatio {
})
}
pub(crate) fn forced_import_from_lazy<S1T: ComputedVecValue + JsonSchema>(
pub(crate) fn forced_import_from_lazy(
db: &Database,
name: &str,
metric_price: &LazyFromHeightLast<Dollars, S1T>,
version: Version,
indexes: &indexes::Vecs,
extended: bool,
@@ -169,7 +165,6 @@ impl ComputedFromHeightRatio {
v,
indexes,
StandardDeviationVecsOptions::default().add_all(),
Some(metric_price),
)
.unwrap()
};
@@ -184,13 +179,9 @@ impl ComputedFromHeightRatio {
macro_rules! lazy_usd {
($ratio:expr, $suffix:expr) => {
$ratio.as_ref().map(|r| {
Price::from_lazy_price_and_band::<PriceTimesRatio, S1T>(
&format!("{name}_{}", $suffix),
v,
metric_price,
r,
)
$ratio.as_ref().map(|_| {
Price::forced_import(db, &format!("{name}_{}", $suffix), v, indexes)
.unwrap()
})
};
}
@@ -398,6 +389,51 @@ impl ComputedFromHeightRatio {
Ok(())
}
/// Compute USD ratio bands: usd_band = metric_price * ratio_percentile
pub(crate) fn compute_usd_bands(
&mut self,
starting_indexes: &ComputeIndexes,
metric_price: &impl ReadableVec<Height, Dollars>,
exit: &Exit,
) -> Result<()> {
use crate::internal::PriceTimesRatio;
macro_rules! compute_band {
($usd_field:ident, $band_field:ident) => {
if let Some(usd) = self.$usd_field.as_mut() {
if let Some(band) = self.$band_field.as_ref() {
usd.usd
.compute_binary::<Dollars, StoredF32, PriceTimesRatio>(
starting_indexes.height,
metric_price,
&band.height,
exit,
)?;
}
}
};
}
compute_band!(ratio_pct99_usd, ratio_pct99);
compute_band!(ratio_pct98_usd, ratio_pct98);
compute_band!(ratio_pct95_usd, ratio_pct95);
compute_band!(ratio_pct5_usd, ratio_pct5);
compute_band!(ratio_pct2_usd, ratio_pct2);
compute_band!(ratio_pct1_usd, ratio_pct1);
// Stddev USD bands
macro_rules! compute_sd_usd {
($($field:ident),*) => {
$(if let Some(sd) = self.$field.as_mut() {
sd.compute_usd_bands(starting_indexes, metric_price, exit)?;
})*
};
}
compute_sd_usd!(ratio_sd, ratio_4y_sd, ratio_2y_sd, ratio_1y_sd);
Ok(())
}
fn mut_ratio_vecs(&mut self) -> Vec<&mut EagerVec<PcoVec<Height, StoredF32>>> {
macro_rules! collect_vecs {
($($field:ident),*) => {{

View File

@@ -3,18 +3,14 @@ use std::mem;
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Dollars, Height, StoredF32, Version};
use schemars::JsonSchema;
use vecdb::{
AnyStoredVec, AnyVec, Database, EagerVec, Exit, WritableVec, ReadableVec,
PcoVec, Rw, StorageMode, VecIndex,
AnyStoredVec, AnyVec, Database, EagerVec, Exit, PcoVec, ReadableVec, Rw, StorageMode, VecIndex,
WritableVec,
};
use crate::{blocks, indexes, ComputeIndexes};
use crate::{ComputeIndexes, blocks, indexes};
use crate::internal::{
ComputedFromHeightLast, ComputedVecValue, LazyBinaryFromHeightLast, LazyFromHeightLast,
Price, PriceTimesRatio,
};
use crate::internal::{ComputedFromHeightLast, Price};
#[derive(Default)]
pub struct StandardDeviationVecsOptions {
@@ -67,19 +63,19 @@ pub struct ComputedFromHeightStdDev<M: StorageMode = Rw> {
pub m2_5sd: Option<ComputedFromHeightLast<StoredF32, M>>,
pub m3sd: Option<ComputedFromHeightLast<StoredF32, M>>,
pub _0sd_usd: Option<Price<LazyBinaryFromHeightLast<Dollars, Dollars, StoredF32>>>,
pub p0_5sd_usd: Option<Price<LazyBinaryFromHeightLast<Dollars, Dollars, StoredF32>>>,
pub p1sd_usd: Option<Price<LazyBinaryFromHeightLast<Dollars, Dollars, StoredF32>>>,
pub p1_5sd_usd: Option<Price<LazyBinaryFromHeightLast<Dollars, Dollars, StoredF32>>>,
pub p2sd_usd: Option<Price<LazyBinaryFromHeightLast<Dollars, Dollars, StoredF32>>>,
pub p2_5sd_usd: Option<Price<LazyBinaryFromHeightLast<Dollars, Dollars, StoredF32>>>,
pub p3sd_usd: Option<Price<LazyBinaryFromHeightLast<Dollars, Dollars, StoredF32>>>,
pub m0_5sd_usd: Option<Price<LazyBinaryFromHeightLast<Dollars, Dollars, StoredF32>>>,
pub m1sd_usd: Option<Price<LazyBinaryFromHeightLast<Dollars, Dollars, StoredF32>>>,
pub m1_5sd_usd: Option<Price<LazyBinaryFromHeightLast<Dollars, Dollars, StoredF32>>>,
pub m2sd_usd: Option<Price<LazyBinaryFromHeightLast<Dollars, Dollars, StoredF32>>>,
pub m2_5sd_usd: Option<Price<LazyBinaryFromHeightLast<Dollars, Dollars, StoredF32>>>,
pub m3sd_usd: Option<Price<LazyBinaryFromHeightLast<Dollars, Dollars, StoredF32>>>,
pub _0sd_usd: Option<Price<ComputedFromHeightLast<Dollars, M>>>,
pub p0_5sd_usd: Option<Price<ComputedFromHeightLast<Dollars, M>>>,
pub p1sd_usd: Option<Price<ComputedFromHeightLast<Dollars, M>>>,
pub p1_5sd_usd: Option<Price<ComputedFromHeightLast<Dollars, M>>>,
pub p2sd_usd: Option<Price<ComputedFromHeightLast<Dollars, M>>>,
pub p2_5sd_usd: Option<Price<ComputedFromHeightLast<Dollars, M>>>,
pub p3sd_usd: Option<Price<ComputedFromHeightLast<Dollars, M>>>,
pub m0_5sd_usd: Option<Price<ComputedFromHeightLast<Dollars, M>>>,
pub m1sd_usd: Option<Price<ComputedFromHeightLast<Dollars, M>>>,
pub m1_5sd_usd: Option<Price<ComputedFromHeightLast<Dollars, M>>>,
pub m2sd_usd: Option<Price<ComputedFromHeightLast<Dollars, M>>>,
pub m2_5sd_usd: Option<Price<ComputedFromHeightLast<Dollars, M>>>,
pub m3sd_usd: Option<Price<ComputedFromHeightLast<Dollars, M>>>,
}
impl ComputedFromHeightStdDev {
@@ -91,7 +87,6 @@ impl ComputedFromHeightStdDev {
parent_version: Version,
indexes: &indexes::Vecs,
options: StandardDeviationVecsOptions,
metric_price: Option<&ComputedFromHeightLast<Dollars>>,
) -> Result<Self> {
let version = parent_version + Version::TWO;
@@ -121,23 +116,21 @@ impl ComputedFromHeightStdDev {
let m2_5sd = options.bands().then(|| import!("m2_5sd"));
let m3sd = options.bands().then(|| import!("m3sd"));
// Create USD bands using the metric price (the denominator of the ratio).
// This converts ratio bands back to USD: usd_band = metric_price * ratio_band
// Import USD price band vecs (computed eagerly at compute time)
macro_rules! lazy_usd {
($band:expr, $suffix:expr) => {
if !options.price_bands() {
None
} else if let Some(mp) = metric_price {
$band.as_ref().map(|b| {
Price::from_computed_price_and_band::<PriceTimesRatio>(
} else {
$band.as_ref().map(|_| {
Price::forced_import(
db,
&format!("{name}_{}", $suffix),
version,
mp,
b,
indexes,
)
.unwrap()
})
} else {
None
}
};
}
@@ -177,15 +170,13 @@ impl ComputedFromHeightStdDev {
})
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn forced_import_from_lazy<S1T: ComputedVecValue + JsonSchema>(
pub(crate) fn forced_import_from_lazy(
db: &Database,
name: &str,
days: usize,
parent_version: Version,
indexes: &indexes::Vecs,
options: StandardDeviationVecsOptions,
metric_price: Option<&LazyFromHeightLast<Dollars, S1T>>,
) -> Result<Self> {
let version = parent_version + Version::TWO;
@@ -216,21 +207,21 @@ impl ComputedFromHeightStdDev {
let m3sd = options.bands().then(|| import!("m3sd"));
// For lazy metric price, use from_lazy_block_last_and_block_last.
// PriceTimesRatio: BinaryTransform<Dollars, StoredF32, Dollars>
// source1 = metric_price (Dollars, lazy), source2 = band (StoredF32, computed)
macro_rules! lazy_usd {
($band:expr, $suffix:expr) => {
metric_price
.zip($band.as_ref())
.filter(|_| options.price_bands())
.map(|(mp, b)| {
Price::from_lazy_price_and_band::<PriceTimesRatio, S1T>(
if !options.price_bands() {
None
} else {
$band.as_ref().map(|_| {
Price::forced_import(
db,
&format!("{name}_{}", $suffix),
version,
mp,
b,
indexes,
)
.unwrap()
})
}
};
}
@@ -277,29 +268,21 @@ impl ComputedFromHeightStdDev {
// 1. Compute SMA using the appropriate lookback vec (or full-history SMA)
if self.days != usize::MAX {
let window_starts = blocks.count.start_vec(self.days);
self.sma
.as_mut()
.unwrap()
.height
.compute_rolling_average(
starting_indexes.height,
window_starts,
source,
exit,
)?;
self.sma.as_mut().unwrap().height.compute_rolling_average(
starting_indexes.height,
window_starts,
source,
exit,
)?;
} else {
// Full history SMA (days == usize::MAX)
self.sma
.as_mut()
.unwrap()
.height
.compute_sma_(
starting_indexes.height,
source,
self.days,
exit,
None,
)?;
self.sma.as_mut().unwrap().height.compute_sma_(
starting_indexes.height,
source,
self.days,
exit,
None,
)?;
}
let sma_opt: Option<&EagerVec<PcoVec<Height, StoredF32>>> = None;
@@ -407,7 +390,8 @@ impl ComputedFromHeightStdDev {
// This is the population SD of all daily values relative to the current SMA
let sd = if n > 0 {
let nf = n as f64;
let variance = welford_sum_sq / nf - 2.0 * avg_f64 * welford_sum / nf + avg_f64 * avg_f64;
let variance =
welford_sum_sq / nf - 2.0 * avg_f64 * welford_sum / nf + avg_f64 * avg_f64;
StoredF32::from(variance.max(0.0).sqrt() as f32)
} else {
StoredF32::from(0.0_f32)
@@ -471,6 +455,48 @@ impl ComputedFromHeightStdDev {
Ok(())
}
/// Compute USD price bands: usd_band = metric_price * band_ratio
pub(crate) fn compute_usd_bands(
&mut self,
starting_indexes: &ComputeIndexes,
metric_price: &impl ReadableVec<Height, Dollars>,
exit: &Exit,
) -> Result<()> {
use crate::internal::PriceTimesRatio;
macro_rules! compute_band {
($usd_field:ident, $band_field:ident) => {
if let Some(usd) = self.$usd_field.as_mut() {
if let Some(band) = self.$band_field.as_ref() {
usd.usd
.compute_binary::<Dollars, StoredF32, PriceTimesRatio>(
starting_indexes.height,
metric_price,
&band.height,
exit,
)?;
}
}
};
}
compute_band!(_0sd_usd, sma);
compute_band!(p0_5sd_usd, p0_5sd);
compute_band!(p1sd_usd, p1sd);
compute_band!(p1_5sd_usd, p1_5sd);
compute_band!(p2sd_usd, p2sd);
compute_band!(p2_5sd_usd, p2_5sd);
compute_band!(p3sd_usd, p3sd);
compute_band!(m0_5sd_usd, m0_5sd);
compute_band!(m1sd_usd, m1sd);
compute_band!(m1_5sd_usd, m1_5sd);
compute_band!(m2sd_usd, m2sd);
compute_band!(m2_5sd_usd, m2_5sd);
compute_band!(m3sd_usd, m3sd);
Ok(())
}
fn mut_stateful_computed(
&mut self,
) -> impl Iterator<Item = &mut ComputedFromHeightLast<StoredF32>> {

View File

@@ -1,71 +0,0 @@
//! ComputedFromHeight using SumCum aggregation.
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Height, Version};
use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use vecdb::{
Database, EagerVec, Exit, ImportableVec, PcoVec, ReadableCloneableVec, Rw, StorageMode,
};
use crate::{ComputeIndexes, indexes};
use crate::internal::{ComputedHeightDerivedSumCum, ComputedVecValue, NumericValue};
#[derive(Deref, DerefMut, Traversable)]
#[traversable(merge)]
pub struct ComputedFromHeightSumCum<T, M: StorageMode = Rw>
where
T: ComputedVecValue + PartialOrd + JsonSchema,
{
#[traversable(rename = "sum")]
pub height: M::Stored<EagerVec<PcoVec<Height, T>>>,
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub rest: Box<ComputedHeightDerivedSumCum<T, M>>,
}
const VERSION: Version = Version::ZERO;
impl<T> ComputedFromHeightSumCum<T>
where
T: NumericValue + JsonSchema,
{
pub(crate) fn forced_import(
db: &Database,
name: &str,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
let v = version + VERSION;
let height: EagerVec<PcoVec<Height, T>> = EagerVec::forced_import(db, name, v)?;
let rest =
ComputedHeightDerivedSumCum::forced_import(db, name, height.read_only_boxed_clone(), v, indexes)?;
Ok(Self { height, rest: Box::new(rest) })
}
/// Compute height_cumulative from self.height.
pub(crate) fn compute_cumulative(
&mut self,
starting_indexes: &ComputeIndexes,
exit: &Exit,
) -> Result<()> {
self.rest.derive_from(starting_indexes, &self.height, exit)
}
pub(crate) fn compute(
&mut self,
starting_indexes: &ComputeIndexes,
exit: &Exit,
mut compute: impl FnMut(&mut EagerVec<PcoVec<Height, T>>) -> Result<()>,
) -> Result<()> {
compute(&mut self.height)?;
self.compute_cumulative(starting_indexes, exit)
}
}

View File

@@ -1,31 +1,27 @@
//! Value type for Full pattern from Height.
//!
//! Height-level USD stats are lazy: `sats * price`.
//! Cumulative and day1 stats are stored since they require aggregation
//! across heights with varying prices.
//! Height-level USD stats are stored (eagerly computed from sats × price).
//! Uses CumFull: stored base + cumulative + rolling windows.
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Bitcoin, Dollars, Height, Sats, Version};
use vecdb::{Database, EagerVec, Exit, ReadableCloneableVec, PcoVec, Rw, StorageMode};
use vecdb::{Database, EagerVec, Exit, PcoVec, ReadableCloneableVec, Rw, StorageMode};
use crate::{
ComputeIndexes, indexes,
internal::{
ComputedFromHeightFull, LazyBinaryComputedFromHeightFull, LazyFromHeightFull,
SatsTimesPrice, SatsToBitcoin,
},
indexes,
internal::{ComputedFromHeightCumulativeFull, LazyFromHeightLast, SatsToBitcoin, WindowStarts},
prices,
};
#[derive(Traversable)]
pub struct ValueFromHeightFull<M: StorageMode = Rw> {
pub sats: ComputedFromHeightFull<Sats, M>,
pub btc: LazyFromHeightFull<Bitcoin, Sats>,
pub usd: LazyBinaryComputedFromHeightFull<Dollars, Sats, Dollars, M>,
pub sats: ComputedFromHeightCumulativeFull<Sats, M>,
pub btc: LazyFromHeightLast<Bitcoin, Sats>,
pub usd: ComputedFromHeightCumulativeFull<Dollars, M>,
}
const VERSION: Version = Version::ONE; // Bumped for lazy height dollars
const VERSION: Version = Version::TWO; // Bumped for stored height dollars
impl ValueFromHeightFull {
pub(crate) fn forced_import(
@@ -33,44 +29,45 @@ impl ValueFromHeightFull {
name: &str,
version: Version,
indexes: &indexes::Vecs,
prices: &prices::Vecs,
) -> Result<Self> {
let v = version + VERSION;
let sats = ComputedFromHeightFull::forced_import(db, name, v, indexes)?;
let sats = ComputedFromHeightCumulativeFull::forced_import(db, name, v, indexes)?;
let btc = LazyFromHeightFull::from_computed::<SatsToBitcoin>(
let btc = LazyFromHeightLast::from_height_source::<SatsToBitcoin>(
&format!("{name}_btc"),
v,
sats.height.read_only_boxed_clone(),
&sats,
indexes,
);
let usd = LazyBinaryComputedFromHeightFull::forced_import::<SatsTimesPrice>(
db,
&format!("{name}_usd"),
v,
sats.height.read_only_boxed_clone(),
prices.usd.price.read_only_boxed_clone(),
indexes,
)?;
let usd =
ComputedFromHeightCumulativeFull::forced_import(db, &format!("{name}_usd"), v, indexes)?;
Ok(Self {
sats,
btc,
usd,
})
Ok(Self { sats, btc, usd })
}
pub(crate) fn compute(
&mut self,
starting_indexes: &ComputeIndexes,
max_from: Height,
windows: &WindowStarts<'_>,
prices: &prices::Vecs,
exit: &Exit,
mut compute: impl FnMut(&mut EagerVec<PcoVec<Height, Sats>>) -> Result<()>,
compute_sats: impl FnOnce(&mut EagerVec<PcoVec<Height, Sats>>) -> Result<()>,
) -> Result<()> {
compute(&mut self.sats.height)?;
self.sats.rest.compute_cumulative(starting_indexes, &self.sats.height, exit)?;
self.usd.compute_cumulative(starting_indexes, exit)?;
Ok(())
self.sats.compute(max_from, windows, exit, compute_sats)?;
self.usd.compute(max_from, windows, exit, |vec| {
Ok(vec.compute_transform2(
max_from,
&self.sats.height,
&prices.usd.price,
|(h, sats, price, ..)| {
let btc = *sats as f64 / 100_000_000.0;
(h, Dollars::from(*price * btc))
},
exit,
)?)
})
}
}

View File

@@ -1,30 +1,26 @@
//! Value type for Last pattern from Height.
//!
//! Height-level USD value is lazy: `sats * price`.
//! Height-level USD value is stored (eagerly computed from sats × price).
//! Day1 last is stored since it requires finding the last value within each date.
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Bitcoin, Dollars, Sats, Version};
use vecdb::{Database, ReadableCloneableVec, Rw, StorageMode};
use brk_types::{Bitcoin, Dollars, Height, Sats, Version};
use vecdb::{Database, Exit, ReadableCloneableVec, Rw, StorageMode};
use crate::{
indexes,
internal::{
ComputedFromHeightLast, LazyBinaryComputedFromHeightLast, LazyFromHeightLast,
SatsTimesPrice, SatsToBitcoin,
},
prices,
indexes, prices,
internal::{ComputedFromHeightLast, LazyFromHeightLast, SatsToBitcoin},
};
#[derive(Traversable)]
pub struct ValueFromHeightLast<M: StorageMode = Rw> {
pub sats: ComputedFromHeightLast<Sats, M>,
pub btc: LazyFromHeightLast<Bitcoin, Sats>,
pub usd: LazyBinaryComputedFromHeightLast<Dollars, Sats, Dollars>,
pub usd: ComputedFromHeightLast<Dollars, M>,
}
const VERSION: Version = Version::ONE; // Bumped for lazy height dollars
const VERSION: Version = Version::TWO; // Bumped for stored height dollars
impl ValueFromHeightLast {
pub(crate) fn forced_import(
@@ -32,7 +28,6 @@ impl ValueFromHeightLast {
name: &str,
version: Version,
indexes: &indexes::Vecs,
prices: &prices::Vecs,
) -> Result<Self> {
let v = version + VERSION;
@@ -45,13 +40,7 @@ impl ValueFromHeightLast {
&sats,
);
let usd = LazyBinaryComputedFromHeightLast::forced_import::<SatsTimesPrice>(
&format!("{name}_usd"),
v,
sats.height.read_only_boxed_clone(),
prices.usd.price.read_only_boxed_clone(),
indexes,
);
let usd = ComputedFromHeightLast::forced_import(db, &format!("{name}_usd"), v, indexes)?;
Ok(Self {
sats,
@@ -59,4 +48,24 @@ impl ValueFromHeightLast {
usd,
})
}
/// Eagerly compute USD height values: sats[h] * price[h].
pub(crate) fn compute(
&mut self,
prices: &prices::Vecs,
max_from: Height,
exit: &Exit,
) -> Result<()> {
self.usd.height.compute_transform2(
max_from,
&self.sats.height,
&prices.usd.price,
|(h, sats, price, ..)| {
let btc = *sats as f64 / 100_000_000.0;
(h, Dollars::from(*price * btc))
},
exit,
)?;
Ok(())
}
}

View File

@@ -1,67 +0,0 @@
//! Lazy binary value wrapper combining height (with price) + all derived last transforms.
use brk_traversable::Traversable;
use brk_types::{Bitcoin, Dollars, Sats, Version};
use derive_more::{Deref, DerefMut};
use vecdb::{BinaryTransform, ReadableCloneableVec, UnaryTransform};
use super::LazyFromHeightValue;
use crate::internal::{LazyValueHeightDerivedLast, ValueFromHeightLast};
use crate::prices;
const VERSION: Version = Version::ZERO;
/// Lazy binary value wrapper with height (using price binary transform) + all derived last transforms.
///
/// Use this when the height-level dollars need a binary transform (e.g., price * sats)
/// rather than a unary transform from existing dollars.
///
/// All coarser-than-height periods (minute1 through difficultyepoch) use unary transforms
/// on the pre-computed values from the source.
#[derive(Clone, Deref, DerefMut, Traversable)]
#[traversable(merge)]
pub struct LazyBinaryValueFromHeightLast {
#[traversable(flatten)]
pub height: LazyFromHeightValue,
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub rest: Box<LazyValueHeightDerivedLast>,
}
impl LazyBinaryValueFromHeightLast {
pub(crate) fn from_block_source<
SatsTransform,
BitcoinTransform,
HeightDollarsTransform,
DateDollarsTransform,
>(
name: &str,
source: &ValueFromHeightLast,
prices: &prices::Vecs,
version: Version,
) -> Self
where
SatsTransform: UnaryTransform<Sats, Sats>,
BitcoinTransform: UnaryTransform<Sats, Bitcoin>,
HeightDollarsTransform: BinaryTransform<Dollars, Sats, Dollars>,
DateDollarsTransform: UnaryTransform<Dollars, Dollars>,
{
let v = version + VERSION;
let price_source = prices.usd.price.read_only_boxed_clone();
let height = LazyFromHeightValue::from_sources::<
SatsTransform,
BitcoinTransform,
HeightDollarsTransform,
>(name, source.sats.height.read_only_boxed_clone(), price_source, v);
let rest =
LazyValueHeightDerivedLast::from_block_source::<SatsTransform, BitcoinTransform, DateDollarsTransform>(
name, source, v,
);
Self { height, rest: Box::new(rest) }
}
}

View File

@@ -1,71 +0,0 @@
//! Value type with stored sats height + cumulative, lazy btc + lazy dollars.
//!
//! Like LazyComputedValueFromHeightSumCum but with Cum (no old period aggregations).
//! - Sats: stored height + cumulative (ComputedFromHeightCum)
//! - BTC: lazy transform from sats (LazyFromHeightLast)
//! - USD: lazy binary (price × sats), LazyLast per index (no stored cumulative)
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Bitcoin, Dollars, Height, Sats, Version};
use vecdb::{Database, Exit, ReadableCloneableVec, Rw, StorageMode};
use crate::{
indexes,
internal::{
ComputedFromHeightCum, LazyBinaryComputedFromHeightLast, LazyFromHeightLast,
PriceTimesSats, SatsToBitcoin,
},
prices,
};
/// Value wrapper with stored sats height + cumulative, lazy btc + lazy usd.
#[derive(Traversable)]
pub struct LazyComputedValueFromHeightCum<M: StorageMode = Rw> {
pub sats: ComputedFromHeightCum<Sats, M>,
pub btc: LazyFromHeightLast<Bitcoin, Sats>,
pub usd: LazyBinaryComputedFromHeightLast<Dollars, Dollars, Sats>,
}
const VERSION: Version = Version::ZERO;
impl LazyComputedValueFromHeightCum {
pub(crate) fn forced_import(
db: &Database,
name: &str,
version: Version,
indexes: &indexes::Vecs,
prices: &prices::Vecs,
) -> Result<Self> {
let v = version + VERSION;
let sats = ComputedFromHeightCum::forced_import(db, name, v, indexes)?;
let btc = LazyFromHeightLast::from_computed::<SatsToBitcoin>(
&format!("{name}_btc"),
v,
sats.height.read_only_boxed_clone(),
&sats,
);
let usd = LazyBinaryComputedFromHeightLast::forced_import::<PriceTimesSats>(
&format!("{name}_usd"),
v,
prices.usd.price.read_only_boxed_clone(),
sats.height.read_only_boxed_clone(),
indexes,
);
Ok(Self { sats, btc, usd })
}
/// Compute cumulative from already-filled sats height vec.
pub(crate) fn compute_cumulative(
&mut self,
max_from: Height,
exit: &Exit,
) -> Result<()> {
self.sats.compute_cumulative(max_from, exit)?;
Ok(())
}
}

View File

@@ -0,0 +1,72 @@
//! Value type with stored sats height + cumulative, stored usd, lazy btc.
//!
//! - Sats: stored height + cumulative (ComputedFromHeightCumulative)
//! - BTC: lazy transform from sats (LazyFromHeightLast)
//! - USD: stored (eagerly computed from price × sats)
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Bitcoin, Dollars, Height, Sats, Version};
use vecdb::{Database, Exit, ReadableCloneableVec, Rw, StorageMode};
use crate::{
indexes,
internal::{ComputedFromHeightCumulative, ComputedFromHeightLast, LazyFromHeightLast, SatsToBitcoin},
prices,
};
/// Value wrapper with stored sats height + cumulative, lazy btc + stored usd.
#[derive(Traversable)]
pub struct LazyComputedValueFromHeightCumulative<M: StorageMode = Rw> {
pub sats: ComputedFromHeightCumulative<Sats, M>,
pub btc: LazyFromHeightLast<Bitcoin, Sats>,
pub usd: ComputedFromHeightLast<Dollars, M>,
}
const VERSION: Version = Version::ONE; // Bumped for stored height dollars
impl LazyComputedValueFromHeightCumulative {
pub(crate) fn forced_import(
db: &Database,
name: &str,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
let v = version + VERSION;
let sats = ComputedFromHeightCumulative::forced_import(db, name, v, indexes)?;
let btc = LazyFromHeightLast::from_height_source::<SatsToBitcoin>(
&format!("{name}_btc"),
v,
sats.height.read_only_boxed_clone(),
indexes,
);
let usd = ComputedFromHeightLast::forced_import(db, &format!("{name}_usd"), v, indexes)?;
Ok(Self { sats, btc, usd })
}
/// Compute cumulative + USD from already-filled sats height vec.
pub(crate) fn compute(
&mut self,
prices: &prices::Vecs,
max_from: Height,
exit: &Exit,
) -> Result<()> {
self.sats.compute_rest(max_from, exit)?;
self.usd.height.compute_transform2(
max_from,
&prices.usd.price,
&self.sats.height,
|(h, price, sats, ..)| {
let btc = *sats as f64 / 100_000_000.0;
(h, Dollars::from(*price * btc))
},
exit,
)?;
Ok(())
}
}

View File

@@ -1,13 +1,11 @@
//! Lazy value wrapper for ValueFromHeightLast - all transforms are lazy.
use brk_traversable::Traversable;
use brk_types::{Dollars, Sats, Version};
use brk_types::{Bitcoin, Dollars, Sats, Version};
use derive_more::{Deref, DerefMut};
use vecdb::UnaryTransform;
use crate::internal::{
LazyValueHeight, LazyValueHeightDerivedLast, SatsToBitcoin, ValueFromHeightLast,
};
use crate::internal::{LazyValueHeight, LazyValueHeightDerivedLast, ValueFromHeightLast};
const VERSION: Version = Version::ZERO;
@@ -24,22 +22,23 @@ pub struct LazyValueFromHeightLast {
}
impl LazyValueFromHeightLast {
pub(crate) fn from_block_source<SatsTransform, DollarsTransform>(
pub(crate) fn from_block_source<SatsTransform, BitcoinTransform, DollarsTransform>(
name: &str,
source: &ValueFromHeightLast,
version: Version,
) -> Self
where
SatsTransform: UnaryTransform<Sats, Sats>,
BitcoinTransform: UnaryTransform<Sats, Bitcoin>,
DollarsTransform: UnaryTransform<Dollars, Dollars>,
{
let v = version + VERSION;
let height =
LazyValueHeight::from_block_source::<SatsTransform, DollarsTransform>(name, source, v);
LazyValueHeight::from_block_source::<SatsTransform, BitcoinTransform, DollarsTransform>(name, source, v);
let rest =
LazyValueHeightDerivedLast::from_block_source::<SatsTransform, SatsToBitcoin, DollarsTransform>(
LazyValueHeightDerivedLast::from_block_source::<SatsTransform, BitcoinTransform, DollarsTransform>(
name, source, v,
);

View File

@@ -1,101 +0,0 @@
//! Value type with lazy binary height + stored derived SumCum.
//!
//! Use this when the height-level sats is a lazy binary transform (e.g., mask × source).
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Bitcoin, Dollars, Height, Sats, Version};
use schemars::JsonSchema;
use vecdb::{
BinaryTransform, Database, Exit, ReadableBoxedVec, ReadableCloneableVec, LazyVecFrom2, Rw,
StorageMode,
};
use crate::{
ComputeIndexes, indexes,
internal::{
ComputedVecValue, LazyComputedFromHeightSumCum, LazyFromHeightSumCum, PriceTimesSats,
SatsToBitcoin,
},
prices,
};
/// Value wrapper with lazy binary height + stored derived SumCum.
///
/// Sats height is a lazy binary transform (e.g., mask × source).
/// Dollars height is also lazy (price × sats).
/// Cumulative and day1 are stored.
#[derive(Traversable)]
pub struct LazyValueFromHeightSumCum<S1T, S2T, M: StorageMode = Rw>
where
S1T: ComputedVecValue + JsonSchema,
S2T: ComputedVecValue + JsonSchema,
{
pub sats: LazyComputedFromHeightSumCum<Sats, S1T, S2T, M>,
pub btc: LazyFromHeightSumCum<Bitcoin, Sats>,
pub usd: LazyComputedFromHeightSumCum<Dollars, Dollars, Sats, M>,
}
const VERSION: Version = Version::ZERO;
impl<S1T, S2T> LazyValueFromHeightSumCum<S1T, S2T>
where
S1T: ComputedVecValue + JsonSchema,
S2T: ComputedVecValue + JsonSchema,
{
pub(crate) fn forced_import<F>(
db: &Database,
name: &str,
version: Version,
indexes: &indexes::Vecs,
source1: ReadableBoxedVec<Height, S1T>,
source2: ReadableBoxedVec<Height, S2T>,
prices: &prices::Vecs,
) -> Result<Self>
where
F: BinaryTransform<S1T, S2T, Sats>,
{
let v = version + VERSION;
let sats_height = LazyVecFrom2::transformed::<F>(name, v, source1, source2);
let sats = LazyComputedFromHeightSumCum::forced_import(db, name, v, indexes, sats_height)?;
let btc = LazyFromHeightSumCum::from_derived::<SatsToBitcoin>(
&format!("{name}_btc"),
v,
sats.height.read_only_boxed_clone(),
&sats.rest,
);
let usd_height = LazyVecFrom2::transformed::<PriceTimesSats>(
&format!("{name}_usd"),
v,
prices.usd.price.read_only_boxed_clone(),
sats.height.read_only_boxed_clone(),
);
let usd = LazyComputedFromHeightSumCum::forced_import(
db,
&format!("{name}_usd"),
v,
indexes,
usd_height,
)?;
Ok(Self {
sats,
btc,
usd,
})
}
pub(crate) fn compute_cumulative(
&mut self,
starting_indexes: &ComputeIndexes,
exit: &Exit,
) -> Result<()> {
self.sats.compute_cumulative(starting_indexes, exit)?;
self.usd.compute_cumulative(starting_indexes, exit)?;
Ok(())
}
}

View File

@@ -1,78 +0,0 @@
//! Value type for SumCum pattern from Height.
//!
//! Height-level USD sum is lazy: `sats * price`.
//! Cumulative and day1 stats are stored since they require aggregation
//! across heights with varying prices.
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Bitcoin, Dollars, Height, Sats, Version};
use vecdb::{Database, EagerVec, Exit, ReadableCloneableVec, PcoVec, Rw, StorageMode};
use crate::{
ComputeIndexes,
indexes,
internal::{
ComputedFromHeightSumCum, LazyBinaryComputedFromHeightSumCum, LazyFromHeightSumCum,
SatsTimesPrice, SatsToBitcoin,
},
prices,
};
#[derive(Traversable)]
pub struct ValueFromHeightSumCum<M: StorageMode = Rw> {
pub sats: ComputedFromHeightSumCum<Sats, M>,
pub btc: LazyFromHeightSumCum<Bitcoin, Sats>,
pub usd: LazyBinaryComputedFromHeightSumCum<Dollars, Sats, Dollars, M>,
}
const VERSION: Version = Version::ONE; // Bumped for lazy height dollars
impl ValueFromHeightSumCum {
pub(crate) fn forced_import(
db: &Database,
name: &str,
version: Version,
indexes: &indexes::Vecs,
prices: &prices::Vecs,
) -> Result<Self> {
let v = version + VERSION;
let sats = ComputedFromHeightSumCum::forced_import(db, name, v, indexes)?;
let btc = LazyFromHeightSumCum::from_computed::<SatsToBitcoin>(
&format!("{name}_btc"),
v,
sats.height.read_only_boxed_clone(),
&sats,
);
let usd = LazyBinaryComputedFromHeightSumCum::forced_import::<SatsTimesPrice>(
db,
&format!("{name}_usd"),
v,
sats.height.read_only_boxed_clone(),
prices.usd.price.read_only_boxed_clone(),
indexes,
)?;
Ok(Self {
sats,
btc,
usd,
})
}
pub(crate) fn compute(
&mut self,
starting_indexes: &ComputeIndexes,
exit: &Exit,
mut compute: impl FnMut(&mut EagerVec<PcoVec<Height, Sats>>) -> Result<()>,
) -> Result<()> {
compute(&mut self.sats.height)?;
self.sats.compute_cumulative(starting_indexes, exit)?;
self.usd.compute_cumulative(starting_indexes, exit)?;
Ok(())
}
}

View File

@@ -0,0 +1,72 @@
//! Value type for SumCumulative pattern from Height.
//!
//! Height-level USD sum is stored (eagerly computed from sats × price).
//! Uses CumSum: stored base + cumulative + rolling sum windows.
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Bitcoin, Dollars, Height, Sats, Version};
use vecdb::{Database, EagerVec, Exit, PcoVec, ReadableCloneableVec, Rw, StorageMode};
use crate::{
indexes, prices,
internal::{ComputedFromHeightCumulativeSum, LazyFromHeightLast, SatsToBitcoin, WindowStarts},
};
#[derive(Traversable)]
pub struct ValueFromHeightSumCumulative<M: StorageMode = Rw> {
pub sats: ComputedFromHeightCumulativeSum<Sats, M>,
pub btc: LazyFromHeightLast<Bitcoin, Sats>,
pub usd: ComputedFromHeightCumulativeSum<Dollars, M>,
}
const VERSION: Version = Version::TWO; // Bumped for stored height dollars
impl ValueFromHeightSumCumulative {
pub(crate) fn forced_import(
db: &Database,
name: &str,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
let v = version + VERSION;
let sats = ComputedFromHeightCumulativeSum::forced_import(db, name, v, indexes)?;
let btc = LazyFromHeightLast::from_height_source::<SatsToBitcoin>(
&format!("{name}_btc"),
v,
sats.height.read_only_boxed_clone(),
indexes,
);
let usd =
ComputedFromHeightCumulativeSum::forced_import(db, &format!("{name}_usd"), v, indexes)?;
Ok(Self { sats, btc, usd })
}
pub(crate) fn compute(
&mut self,
max_from: Height,
windows: &WindowStarts<'_>,
prices: &prices::Vecs,
exit: &Exit,
compute_sats: impl FnOnce(&mut EagerVec<PcoVec<Height, Sats>>) -> Result<()>,
) -> Result<()> {
self.sats.compute(max_from, windows, exit, compute_sats)?;
self.usd.compute(max_from, windows, exit, |vec| {
Ok(vec.compute_transform2(
max_from,
&self.sats.height,
&prices.usd.price,
|(h, sats, price, ..)| {
let btc = *sats as f64 / 100_000_000.0;
(h, Dollars::from(*price * btc))
},
exit,
)?)
})
}
}

View File

@@ -3,19 +3,16 @@
use brk_error::Result;
use brk_indexer::Indexer;
use brk_traversable::Traversable;
use brk_types::{TxIndex, Version};
use derive_more::{Deref, DerefMut};
use brk_types::TxIndex;
use schemars::JsonSchema;
use vecdb::{Database, Exit, LazyVecFrom2, ReadableVec, Rw, StorageMode};
use vecdb::{Database, Exit, LazyVecFrom2, ReadableVec, Rw, StorageMode, Version};
use crate::{
ComputeIndexes, indexes,
internal::{ComputedVecValue, TxDerivedDistribution, NumericValue},
internal::{BlockWindowStarts, ComputedVecValue, NumericValue, TxDerivedDistribution},
};
const VERSION: Version = Version::ZERO;
#[derive(Deref, DerefMut, Traversable)]
#[derive(Traversable)]
#[traversable(merge)]
pub struct LazyFromTxDistribution<T, S1, S2, M: StorageMode = Rw>
where
@@ -24,8 +21,6 @@ where
S2: ComputedVecValue,
{
pub txindex: LazyVecFrom2<TxIndex, T, TxIndex, S1, TxIndex, S2>,
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub distribution: TxDerivedDistribution<T, M>,
}
@@ -41,10 +36,8 @@ where
name: &str,
version: Version,
txindex: LazyVecFrom2<TxIndex, T, TxIndex, S1, TxIndex, S2>,
indexes: &indexes::Vecs,
) -> Result<Self> {
let v = version + VERSION;
let distribution = TxDerivedDistribution::forced_import(db, name, v, indexes)?;
let distribution = TxDerivedDistribution::forced_import(db, name, version)?;
Ok(Self {
txindex,
distribution,
@@ -56,12 +49,21 @@ where
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &ComputeIndexes,
block_windows: &BlockWindowStarts<'_>,
exit: &Exit,
) -> Result<()>
where
T: Copy + Ord + From<f64> + Default,
f64: From<T>,
LazyVecFrom2<TxIndex, T, TxIndex, S1, TxIndex, S2>: ReadableVec<TxIndex, T>,
{
self.distribution
.derive_from(indexer, indexes, starting_indexes, &self.txindex, exit)
self.distribution.derive_from(
indexer,
indexes,
starting_indexes,
block_windows,
&self.txindex,
exit,
)
}
}

View File

@@ -1,3 +1,3 @@
mod lazy_distribution;
mod distribution;
pub use lazy_distribution::*;
pub use distribution::*;

View File

@@ -1,165 +0,0 @@
//! Lazy binary transform for derived block with Last aggregation only.
//!
//! Newtype on `Indexes` with `LazyBinaryTransformLast` per field.
use brk_traversable::Traversable;
use brk_types::{
Day1, Day3, DifficultyEpoch, HalvingEpoch, Hour1, Hour12, Hour4, Minute1, Minute10, Minute30,
Minute5, Month1, Month3, Month6, Version, Week1, Year1, Year10,
};
use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use vecdb::{BinaryTransform, ReadableCloneableVec};
use crate::{
indexes_from,
internal::{
ComputedFromHeightLast, ComputedFromHeightSumCum, ComputedVecValue, Indexes,
LazyBinaryTransformLast, LazyFromHeightLast, NumericValue,
},
};
pub type LazyBinaryHeightDerivedLastInner<T, S1T, S2T> = Indexes<
LazyBinaryTransformLast<Minute1, T, S1T, S2T>,
LazyBinaryTransformLast<Minute5, T, S1T, S2T>,
LazyBinaryTransformLast<Minute10, T, S1T, S2T>,
LazyBinaryTransformLast<Minute30, T, S1T, S2T>,
LazyBinaryTransformLast<Hour1, T, S1T, S2T>,
LazyBinaryTransformLast<Hour4, T, S1T, S2T>,
LazyBinaryTransformLast<Hour12, T, S1T, S2T>,
LazyBinaryTransformLast<Day1, T, S1T, S2T>,
LazyBinaryTransformLast<Day3, T, S1T, S2T>,
LazyBinaryTransformLast<Week1, T, S1T, S2T>,
LazyBinaryTransformLast<Month1, T, S1T, S2T>,
LazyBinaryTransformLast<Month3, T, S1T, S2T>,
LazyBinaryTransformLast<Month6, T, S1T, S2T>,
LazyBinaryTransformLast<Year1, T, S1T, S2T>,
LazyBinaryTransformLast<Year10, T, S1T, S2T>,
LazyBinaryTransformLast<HalvingEpoch, T, S1T, S2T>,
LazyBinaryTransformLast<DifficultyEpoch, T, S1T, S2T>,
>;
#[derive(Clone, Deref, DerefMut, Traversable)]
#[traversable(transparent)]
pub struct LazyBinaryHeightDerivedLast<T, S1T = T, S2T = T>(
pub LazyBinaryHeightDerivedLastInner<T, S1T, S2T>,
)
where
T: ComputedVecValue + PartialOrd + JsonSchema,
S1T: ComputedVecValue,
S2T: ComputedVecValue;
const VERSION: Version = Version::ZERO;
impl<T, S1T, S2T> LazyBinaryHeightDerivedLast<T, S1T, S2T>
where
T: ComputedVecValue + JsonSchema + 'static,
S1T: ComputedVecValue + JsonSchema,
S2T: ComputedVecValue + JsonSchema,
{
pub(crate) fn from_computed_sum_cum<F: BinaryTransform<S1T, S2T, T>>(
name: &str,
version: Version,
source1: &ComputedFromHeightSumCum<S1T>,
source2: &ComputedFromHeightSumCum<S2T>,
) -> Self
where
S1T: PartialOrd,
S2T: PartialOrd,
{
let v = version + VERSION;
macro_rules! period {
($p:ident) => {
LazyBinaryTransformLast::from_vecs::<F>(
name,
v,
source1.$p.cumulative.read_only_boxed_clone(),
source2.$p.cumulative.read_only_boxed_clone(),
)
};
}
Self(indexes_from!(period))
}
pub(crate) fn from_computed_last<F: BinaryTransform<S1T, S2T, T>>(
name: &str,
version: Version,
source1: &ComputedFromHeightLast<S1T>,
source2: &ComputedFromHeightLast<S2T>,
) -> Self
where
S1T: NumericValue,
S2T: NumericValue,
{
let v = version + VERSION;
macro_rules! period {
($p:ident) => {
LazyBinaryTransformLast::from_lazy_last::<F, _, _, _, _>(
name,
v,
&source1.$p,
&source2.$p,
)
};
}
Self(indexes_from!(period))
}
pub(crate) fn from_lazy_block_last_and_block_last<F, S1SourceT>(
name: &str,
version: Version,
source1: &LazyFromHeightLast<S1T, S1SourceT>,
source2: &ComputedFromHeightLast<S2T>,
) -> Self
where
F: BinaryTransform<S1T, S2T, T>,
S2T: NumericValue,
S1SourceT: ComputedVecValue + JsonSchema,
{
let v = version + VERSION;
macro_rules! period {
($p:ident) => {
LazyBinaryTransformLast::from_vecs::<F>(
name,
v,
source1.$p.read_only_boxed_clone(),
source2.$p.read_only_boxed_clone(),
)
};
}
Self(indexes_from!(period))
}
pub(crate) fn from_block_last_and_lazy_block_last<F, S2SourceT>(
name: &str,
version: Version,
source1: &ComputedFromHeightLast<S1T>,
source2: &LazyFromHeightLast<S2T, S2SourceT>,
) -> Self
where
F: BinaryTransform<S1T, S2T, T>,
S1T: NumericValue,
S2SourceT: ComputedVecValue + JsonSchema,
{
let v = version + VERSION;
macro_rules! period {
($p:ident) => {
LazyBinaryTransformLast::from_vecs::<F>(
name,
v,
source1.$p.read_only_boxed_clone(),
source2.$p.read_only_boxed_clone(),
)
};
}
Self(indexes_from!(period))
}
}

View File

@@ -1,7 +1,7 @@
//! ComputedHeightDerivedCumFull - LazyLast index views + cumulative (from height) + RollingFull.
//! ComputedHeightDerivedCumulativeFull - LazyAggVec index views + cumulative (from height) + RollingFull.
//!
//! For metrics derived from indexer sources (no stored height vec).
//! Cumulative gets its own ComputedFromHeightLast so it has LazyLast index views too.
//! Cumulative gets its own ComputedFromHeightLast so it has LazyAggVec index views too.
use std::ops::SubAssign;
@@ -9,23 +9,19 @@ use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Height, Version};
use schemars::JsonSchema;
use vecdb::{Database, Exit, ReadableBoxedVec, ReadableVec, Rw, StorageMode};
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode};
use crate::{
indexes,
internal::{
ComputedFromHeightLast, ComputedHeightDerivedLast, NumericValue, RollingFull, WindowStarts,
},
internal::{ComputedFromHeightLast, NumericValue, RollingFull, WindowStarts},
};
#[derive(Traversable)]
#[traversable(merge)]
pub struct ComputedHeightDerivedCumFull<T, M: StorageMode = Rw>
pub struct ComputedHeightDerivedCumulativeFull<T, M: StorageMode = Rw>
where
T: NumericValue + JsonSchema,
{
#[traversable(flatten)]
pub last: ComputedHeightDerivedLast<T>,
#[traversable(flatten)]
pub cumulative: ComputedFromHeightLast<T, M>,
#[traversable(flatten)]
@@ -34,30 +30,23 @@ where
const VERSION: Version = Version::ZERO;
impl<T> ComputedHeightDerivedCumFull<T>
impl<T> ComputedHeightDerivedCumulativeFull<T>
where
T: NumericValue + JsonSchema,
{
pub(crate) fn forced_import(
db: &Database,
name: &str,
height_source: ReadableBoxedVec<Height, T>,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
let v = version + VERSION;
let last = ComputedHeightDerivedLast::forced_import(name, height_source, v, indexes);
let cumulative = ComputedFromHeightLast::forced_import(
db,
&format!("{name}_cumulative"),
v,
indexes,
)?;
let cumulative =
ComputedFromHeightLast::forced_import(db, &format!("{name}_cumulative"), v, indexes)?;
let rolling = RollingFull::forced_import(db, name, v, indexes)?;
Ok(Self {
last,
cumulative,
rolling,
})
@@ -77,7 +66,8 @@ where
self.cumulative
.height
.compute_cumulative(max_from, height_source, exit)?;
self.rolling.compute(max_from, windows, height_source, exit)?;
self.rolling
.compute(max_from, windows, height_source, exit)?;
Ok(())
}
}

View File

@@ -1,97 +0,0 @@
//! ComputedHeightDerivedDistribution - lazy time periods + epochs.
use brk_traversable::Traversable;
use brk_types::{
Day1, Day3, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour12, Hour4, Minute1, Minute10,
Minute30, Minute5, Month1, Month3, Month6, Version, Week1, Year1, Year10,
};
use schemars::JsonSchema;
use vecdb::{ReadableBoxedVec, ReadableCloneableVec};
use crate::{
indexes,
internal::{ComputedVecValue, LazyDistribution, NumericValue},
};
#[derive(Clone, Traversable)]
#[traversable(merge)]
pub struct ComputedHeightDerivedDistribution<T>
where
T: ComputedVecValue + PartialOrd + JsonSchema,
{
pub minute1: LazyDistribution<Minute1, T, Height, Height>,
pub minute5: LazyDistribution<Minute5, T, Height, Height>,
pub minute10: LazyDistribution<Minute10, T, Height, Height>,
pub minute30: LazyDistribution<Minute30, T, Height, Height>,
pub hour1: LazyDistribution<Hour1, T, Height, Height>,
pub hour4: LazyDistribution<Hour4, T, Height, Height>,
pub hour12: LazyDistribution<Hour12, T, Height, Height>,
pub day1: LazyDistribution<Day1, T, Height, Height>,
pub day3: LazyDistribution<Day3, T, Height, Height>,
pub week1: LazyDistribution<Week1, T, Height, Height>,
pub month1: LazyDistribution<Month1, T, Height, Height>,
pub month3: LazyDistribution<Month3, T, Height, Height>,
pub month6: LazyDistribution<Month6, T, Height, Height>,
pub year1: LazyDistribution<Year1, T, Height, Height>,
pub year10: LazyDistribution<Year10, T, Height, Height>,
pub halvingepoch: LazyDistribution<HalvingEpoch, T, Height, HalvingEpoch>,
pub difficultyepoch: LazyDistribution<DifficultyEpoch, T, Height, DifficultyEpoch>,
}
const VERSION: Version = Version::ZERO;
impl<T> ComputedHeightDerivedDistribution<T>
where
T: NumericValue + JsonSchema,
{
pub(crate) fn forced_import(
name: &str,
height_source: ReadableBoxedVec<Height, T>,
version: Version,
indexes: &indexes::Vecs,
) -> Self {
let v = version + VERSION;
macro_rules! period {
($idx:ident) => {
LazyDistribution::from_height_source(
name,
v,
height_source.clone(),
indexes.$idx.first_height.read_only_boxed_clone(),
)
};
}
macro_rules! epoch {
($idx:ident) => {
LazyDistribution::from_source(
name,
v,
height_source.clone(),
indexes.$idx.identity.read_only_boxed_clone(),
)
};
}
Self {
minute1: period!(minute1),
minute5: period!(minute5),
minute10: period!(minute10),
minute30: period!(minute30),
hour1: period!(hour1),
hour4: period!(hour4),
hour12: period!(hour12),
day1: period!(day1),
day3: period!(day3),
week1: period!(week1),
month1: period!(month1),
month3: period!(month3),
month6: period!(month6),
year1: period!(year1),
year10: period!(year10),
halvingepoch: epoch!(halvingepoch),
difficultyepoch: epoch!(difficultyepoch),
}
}
}

View File

@@ -1,140 +0,0 @@
//! ComputedHeightDerivedFull - height_cumulative (stored) + lazy time periods + epochs.
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{
Day1, Day3, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour12, Hour4, Minute1, Minute10,
Minute30, Minute5, Month1, Month3, Month6, Version, Week1, Year1, Year10,
};
use schemars::JsonSchema;
use vecdb::{Database, Exit, ReadableBoxedVec, ReadableCloneableVec, ReadableVec, Rw, StorageMode};
use crate::{
indexes,
internal::{ComputedVecValue, CumulativeVec, LazyFull, NumericValue},
ComputeIndexes,
};
#[derive(Traversable)]
#[traversable(merge)]
pub struct ComputedHeightDerivedFull<T, M: StorageMode = Rw>
where
T: ComputedVecValue + PartialOrd + JsonSchema,
{
#[traversable(rename = "cumulative")]
pub height_cumulative: CumulativeVec<Height, T, M>,
pub minute1: LazyFull<Minute1, T, Height, Height>,
pub minute5: LazyFull<Minute5, T, Height, Height>,
pub minute10: LazyFull<Minute10, T, Height, Height>,
pub minute30: LazyFull<Minute30, T, Height, Height>,
pub hour1: LazyFull<Hour1, T, Height, Height>,
pub hour4: LazyFull<Hour4, T, Height, Height>,
pub hour12: LazyFull<Hour12, T, Height, Height>,
pub day1: LazyFull<Day1, T, Height, Height>,
pub day3: LazyFull<Day3, T, Height, Height>,
pub week1: LazyFull<Week1, T, Height, Height>,
pub month1: LazyFull<Month1, T, Height, Height>,
pub month3: LazyFull<Month3, T, Height, Height>,
pub month6: LazyFull<Month6, T, Height, Height>,
pub year1: LazyFull<Year1, T, Height, Height>,
pub year10: LazyFull<Year10, T, Height, Height>,
pub halvingepoch: LazyFull<HalvingEpoch, T, Height, HalvingEpoch>,
pub difficultyepoch: LazyFull<DifficultyEpoch, T, Height, DifficultyEpoch>,
}
const VERSION: Version = Version::ZERO;
impl<T> ComputedHeightDerivedFull<T>
where
T: NumericValue + JsonSchema,
{
pub(crate) fn forced_import(
db: &Database,
name: &str,
height_source: ReadableBoxedVec<Height, T>,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
let v = version + VERSION;
let height_cumulative = CumulativeVec::forced_import(db, name, v)?;
macro_rules! period {
($idx:ident) => {
LazyFull::from_height_source(
name,
v,
height_source.clone(),
height_cumulative.read_only_boxed_clone(),
indexes.$idx.first_height.read_only_boxed_clone(),
)
};
}
macro_rules! epoch {
($idx:ident) => {
LazyFull::from_stats_aggregate(
name,
v,
height_source.clone(),
height_source.clone(),
height_source.clone(),
height_source.clone(),
height_cumulative.read_only_boxed_clone(),
height_source.clone(),
indexes.$idx.identity.read_only_boxed_clone(),
)
};
}
let minute1 = period!(minute1);
let minute5 = period!(minute5);
let minute10 = period!(minute10);
let minute30 = period!(minute30);
let hour1 = period!(hour1);
let hour4 = period!(hour4);
let hour12 = period!(hour12);
let day1 = period!(day1);
let day3 = period!(day3);
let week1 = period!(week1);
let month1 = period!(month1);
let month3 = period!(month3);
let month6 = period!(month6);
let year1 = period!(year1);
let year10 = period!(year10);
let halvingepoch = epoch!(halvingepoch);
let difficultyepoch = epoch!(difficultyepoch);
Ok(Self {
height_cumulative,
minute1,
minute5,
minute10,
minute30,
hour1,
hour4,
hour12,
day1,
day3,
week1,
month1,
month3,
month6,
year1,
year10,
halvingepoch,
difficultyepoch,
})
}
pub(crate) fn compute_cumulative(
&mut self,
starting_indexes: &ComputeIndexes,
height_source: &impl ReadableVec<Height, T>,
exit: &Exit,
) -> Result<()> {
Ok(self.height_cumulative
.0
.compute_cumulative(starting_indexes.height, height_source, exit)?)
}
}

View File

@@ -1,46 +1,43 @@
//! ComputedHeightDerivedLast - lazy time periods + epochs (last value).
//!
//! Newtype on `Indexes` with `LazyLast` per field.
//! ComputedHeightDerivedLast — sparse time periods + dense epochs (last value).
use brk_traversable::Traversable;
use brk_types::{
Day1, Day3, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour12, Hour4, Minute1, Minute10,
Minute30, Minute5, Month1, Month3, Month6, Version, Week1, Year1, Year10,
Day1, Day3, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour4, Hour12, Minute1, Minute5,
Minute10, Minute30, Month1, Month3, Month6, Version, Week1, Year1, Year10,
};
use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use vecdb::{ReadableBoxedVec, ReadableCloneableVec};
use vecdb::{LazyAggVec, ReadableBoxedVec, ReadableCloneableVec};
use crate::{
indexes,
indexes_from,
internal::{ComputedVecValue, Indexes, LazyLast, NumericValue},
indexes, indexes_from,
internal::{ComputedVecValue, Indexes, NumericValue},
};
/// All 17 time-period/epoch `LazyLast` vecs, packed as a newtype on `Indexes`.
pub type ComputedHeightDerivedLastInner<T> = Indexes<
LazyLast<Minute1, T, Height, Height>,
LazyLast<Minute5, T, Height, Height>,
LazyLast<Minute10, T, Height, Height>,
LazyLast<Minute30, T, Height, Height>,
LazyLast<Hour1, T, Height, Height>,
LazyLast<Hour4, T, Height, Height>,
LazyLast<Hour12, T, Height, Height>,
LazyLast<Day1, T, Height, Height>,
LazyLast<Day3, T, Height, Height>,
LazyLast<Week1, T, Height, Height>,
LazyLast<Month1, T, Height, Height>,
LazyLast<Month3, T, Height, Height>,
LazyLast<Month6, T, Height, Height>,
LazyLast<Year1, T, Height, Height>,
LazyLast<Year10, T, Height, Height>,
LazyLast<HalvingEpoch, T, Height, HalvingEpoch>,
LazyLast<DifficultyEpoch, T, Height, DifficultyEpoch>,
>;
#[derive(Clone, Deref, DerefMut, Traversable)]
#[traversable(transparent)]
pub struct ComputedHeightDerivedLast<T>(pub ComputedHeightDerivedLastInner<T>)
pub struct ComputedHeightDerivedLast<T>(
#[allow(clippy::type_complexity)]
pub Indexes<
LazyAggVec<Minute1, Option<T>, Height, Height, T>,
LazyAggVec<Minute5, Option<T>, Height, Height, T>,
LazyAggVec<Minute10, Option<T>, Height, Height, T>,
LazyAggVec<Minute30, Option<T>, Height, Height, T>,
LazyAggVec<Hour1, Option<T>, Height, Height, T>,
LazyAggVec<Hour4, Option<T>, Height, Height, T>,
LazyAggVec<Hour12, Option<T>, Height, Height, T>,
LazyAggVec<Day1, Option<T>, Height, Height, T>,
LazyAggVec<Day3, Option<T>, Height, Height, T>,
LazyAggVec<Week1, Option<T>, Height, Height, T>,
LazyAggVec<Month1, Option<T>, Height, Height, T>,
LazyAggVec<Month3, Option<T>, Height, Height, T>,
LazyAggVec<Month6, Option<T>, Height, Height, T>,
LazyAggVec<Year1, Option<T>, Height, Height, T>,
LazyAggVec<Year10, Option<T>, Height, Height, T>,
LazyAggVec<HalvingEpoch, T, Height, HalvingEpoch>,
LazyAggVec<DifficultyEpoch, T, Height, DifficultyEpoch>,
>,
)
where
T: ComputedVecValue + PartialOrd + JsonSchema;
@@ -60,7 +57,7 @@ where
macro_rules! period {
($idx:ident) => {
LazyLast::from_height_source(
LazyAggVec::sparse_from_first_index(
name,
v,
height_source.clone(),
@@ -71,7 +68,7 @@ where
macro_rules! epoch {
($idx:ident) => {
LazyLast::from_source(
LazyAggVec::from_source(
name,
v,
height_source.clone(),

View File

@@ -1,97 +0,0 @@
//! Lazy aggregated Full for block-level sources.
use brk_traversable::Traversable;
use brk_types::{
Day1, Day3, DifficultyEpoch, HalvingEpoch, Hour1, Hour12, Hour4, Minute1, Minute10, Minute30,
Minute5, Month1, Month3, Month6, Version, Week1, Year1, Year10,
};
use schemars::JsonSchema;
use vecdb::{ReadableCloneableVec, UnaryTransform};
use crate::internal::{
ComputedHeightDerivedFull, ComputedVecValue, LazyTransformFull, NumericValue,
};
#[derive(Clone, Traversable)]
#[traversable(merge)]
pub struct LazyHeightDerivedFull<T, S1T = T>
where
T: ComputedVecValue + PartialOrd + JsonSchema,
S1T: ComputedVecValue,
{
pub minute1: LazyTransformFull<Minute1, T, S1T>,
pub minute5: LazyTransformFull<Minute5, T, S1T>,
pub minute10: LazyTransformFull<Minute10, T, S1T>,
pub minute30: LazyTransformFull<Minute30, T, S1T>,
pub hour1: LazyTransformFull<Hour1, T, S1T>,
pub hour4: LazyTransformFull<Hour4, T, S1T>,
pub hour12: LazyTransformFull<Hour12, T, S1T>,
pub day1: LazyTransformFull<Day1, T, S1T>,
pub day3: LazyTransformFull<Day3, T, S1T>,
pub week1: LazyTransformFull<Week1, T, S1T>,
pub month1: LazyTransformFull<Month1, T, S1T>,
pub month3: LazyTransformFull<Month3, T, S1T>,
pub month6: LazyTransformFull<Month6, T, S1T>,
pub year1: LazyTransformFull<Year1, T, S1T>,
pub year10: LazyTransformFull<Year10, T, S1T>,
pub halvingepoch: LazyTransformFull<HalvingEpoch, T, S1T>,
pub difficultyepoch: LazyTransformFull<DifficultyEpoch, T, S1T>,
}
const VERSION: Version = Version::ZERO;
impl<T, S1T> LazyHeightDerivedFull<T, S1T>
where
T: ComputedVecValue + JsonSchema + 'static,
S1T: ComputedVecValue + JsonSchema,
{
pub(crate) fn from_derived_computed<F: UnaryTransform<S1T, T>>(
name: &str,
version: Version,
source: &ComputedHeightDerivedFull<S1T>,
) -> Self
where
S1T: NumericValue,
{
let v = version + VERSION;
macro_rules! period {
($p:ident) => {
LazyTransformFull::from_boxed::<F>(
name,
v,
source.$p.average.read_only_boxed_clone(),
source.$p.min.read_only_boxed_clone(),
source.$p.max.read_only_boxed_clone(),
source.$p.percentiles.pct10.read_only_boxed_clone(),
source.$p.percentiles.pct25.read_only_boxed_clone(),
source.$p.percentiles.median.read_only_boxed_clone(),
source.$p.percentiles.pct75.read_only_boxed_clone(),
source.$p.percentiles.pct90.read_only_boxed_clone(),
source.$p.sum.read_only_boxed_clone(),
source.$p.cumulative.read_only_boxed_clone(),
)
};
}
Self {
minute1: period!(minute1),
minute5: period!(minute5),
minute10: period!(minute10),
minute30: period!(minute30),
hour1: period!(hour1),
hour4: period!(hour4),
hour12: period!(hour12),
day1: period!(day1),
day3: period!(day3),
week1: period!(week1),
month1: period!(month1),
month3: period!(month3),
month6: period!(month6),
year1: period!(year1),
year10: period!(year10),
halvingepoch: period!(halvingepoch),
difficultyepoch: period!(difficultyepoch),
}
}
}

View File

@@ -1,58 +1,92 @@
//! Lazy aggregated Last for block-level sources.
//!
//! Newtype on `Indexes` with `LazyTransformLast` per field.
//! LazyHeightDerivedLast — unary transform of height-derived last values.
use std::marker::PhantomData;
use brk_traversable::Traversable;
use brk_types::{
Day1, Day3, DifficultyEpoch, HalvingEpoch, Hour1, Hour4, Hour12, Minute1, Minute5, Minute10,
Minute30, Month1, Month3, Month6, Version, Week1, Year1, Year10,
Day1, Day3, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour4, Hour12, Minute1, Minute5,
Minute10, Minute30, Month1, Month3, Month6, Version, Week1, Year1, Year10,
};
use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use vecdb::{ReadableCloneableVec, UnaryTransform};
use vecdb::{LazyVecFrom1, ReadableBoxedVec, ReadableCloneableVec, UnaryTransform, VecIndex, VecValue};
use crate::{
indexes_from,
indexes, indexes_from,
internal::{
ComputedFromHeightLast, ComputedHeightDerivedLast, ComputedVecValue, Indexes,
LazyBinaryHeightDerivedLast, LazyTransformLast, NumericValue,
ComputedFromHeightLast, ComputedHeightDerivedLast, ComputedVecValue, Indexes, NumericValue,
},
};
#[derive(Clone, Deref, DerefMut, Traversable)]
#[traversable(transparent)]
pub struct LazyTransformLast<I, T, S1T = T>(pub LazyVecFrom1<I, T, I, S1T>)
where
I: VecIndex,
T: VecValue + PartialOrd + JsonSchema,
S1T: VecValue;
impl<I, T, S1T> LazyTransformLast<I, T, S1T>
where
I: VecIndex,
T: VecValue + PartialOrd + JsonSchema + 'static,
S1T: VecValue + JsonSchema,
{
fn from_boxed<F: UnaryTransform<S1T, T>>(
name: &str,
version: Version,
source: ReadableBoxedVec<I, S1T>,
) -> Self {
Self(LazyVecFrom1::transformed::<F>(name, version, source))
}
}
struct MapOption<F>(PhantomData<F>);
impl<F, S, T> UnaryTransform<Option<S>, Option<T>> for MapOption<F>
where
F: UnaryTransform<S, T>,
{
#[inline(always)]
fn apply(value: Option<S>) -> Option<T> {
value.map(F::apply)
}
}
#[derive(Clone, Deref, DerefMut, Traversable)]
#[traversable(transparent)]
pub struct LazyHeightDerivedLast<T, S1T = T>(
#[allow(clippy::type_complexity)]
pub Indexes<
LazyTransformLast<Minute1, T, S1T>,
LazyTransformLast<Minute5, T, S1T>,
LazyTransformLast<Minute10, T, S1T>,
LazyTransformLast<Minute30, T, S1T>,
LazyTransformLast<Hour1, T, S1T>,
LazyTransformLast<Hour4, T, S1T>,
LazyTransformLast<Hour12, T, S1T>,
LazyTransformLast<Day1, T, S1T>,
LazyTransformLast<Day3, T, S1T>,
LazyTransformLast<Week1, T, S1T>,
LazyTransformLast<Month1, T, S1T>,
LazyTransformLast<Month3, T, S1T>,
LazyTransformLast<Month6, T, S1T>,
LazyTransformLast<Year1, T, S1T>,
LazyTransformLast<Year10, T, S1T>,
LazyTransformLast<Minute1, Option<T>, Option<S1T>>,
LazyTransformLast<Minute5, Option<T>, Option<S1T>>,
LazyTransformLast<Minute10, Option<T>, Option<S1T>>,
LazyTransformLast<Minute30, Option<T>, Option<S1T>>,
LazyTransformLast<Hour1, Option<T>, Option<S1T>>,
LazyTransformLast<Hour4, Option<T>, Option<S1T>>,
LazyTransformLast<Hour12, Option<T>, Option<S1T>>,
LazyTransformLast<Day1, Option<T>, Option<S1T>>,
LazyTransformLast<Day3, Option<T>, Option<S1T>>,
LazyTransformLast<Week1, Option<T>, Option<S1T>>,
LazyTransformLast<Month1, Option<T>, Option<S1T>>,
LazyTransformLast<Month3, Option<T>, Option<S1T>>,
LazyTransformLast<Month6, Option<T>, Option<S1T>>,
LazyTransformLast<Year1, Option<T>, Option<S1T>>,
LazyTransformLast<Year10, Option<T>, Option<S1T>>,
LazyTransformLast<HalvingEpoch, T, S1T>,
LazyTransformLast<DifficultyEpoch, T, S1T>,
>,
)
where
T: ComputedVecValue + PartialOrd + JsonSchema,
S1T: ComputedVecValue;
T: VecValue + PartialOrd + JsonSchema,
S1T: VecValue;
const VERSION: Version = Version::ZERO;
impl<T, S1T> LazyHeightDerivedLast<T, S1T>
where
T: ComputedVecValue + JsonSchema + 'static,
S1T: ComputedVecValue + JsonSchema,
T: VecValue + PartialOrd + JsonSchema + 'static,
S1T: VecValue + PartialOrd + JsonSchema,
{
pub(crate) fn from_computed<F: UnaryTransform<S1T, T>>(
name: &str,
@@ -62,15 +96,20 @@ where
where
S1T: NumericValue,
{
let v = version + VERSION;
Self::from_derived_computed::<F>(name, version, &source.rest)
}
macro_rules! period {
($p:ident) => {
LazyTransformLast::from_boxed::<F>(name, v, source.rest.$p.read_only_boxed_clone())
};
}
Self(indexes_from!(period))
pub(crate) fn from_height_source<F: UnaryTransform<S1T, T>>(
name: &str,
version: Version,
height_source: ReadableBoxedVec<Height, S1T>,
indexes: &indexes::Vecs,
) -> Self
where
S1T: NumericValue,
{
let derived = ComputedHeightDerivedLast::forced_import(name, height_source, version, indexes);
Self::from_derived_computed::<F>(name, version, &derived)
}
pub(crate) fn from_derived_computed<F: UnaryTransform<S1T, T>>(
@@ -84,15 +123,24 @@ where
let v = version + VERSION;
macro_rules! period {
($p:ident) => {
LazyTransformLast::from_boxed::<MapOption<F>>(
name,
v,
source.$p.read_only_boxed_clone(),
)
};
}
macro_rules! epoch {
($p:ident) => {
LazyTransformLast::from_boxed::<F>(name, v, source.$p.read_only_boxed_clone())
};
}
Self(indexes_from!(period))
Self(indexes_from!(period, epoch))
}
/// Create by unary-transforming a LazyHeightDerivedLast source.
pub(crate) fn from_lazy<F, S2T>(
name: &str,
version: Version,
@@ -106,32 +154,20 @@ where
macro_rules! period {
($p:ident) => {
LazyTransformLast::from_boxed::<F>(name, v, source.$p.read_only_boxed_clone())
LazyTransformLast::from_boxed::<MapOption<F>>(
name,
v,
source.$p.read_only_boxed_clone(),
)
};
}
Self(indexes_from!(period))
}
/// Create by unary-transforming a LazyBinaryHeightDerivedLast source.
pub(crate) fn from_binary<F, S1aT, S1bT>(
name: &str,
version: Version,
source: &LazyBinaryHeightDerivedLast<S1T, S1aT, S1bT>,
) -> Self
where
F: UnaryTransform<S1T, T>,
S1aT: ComputedVecValue + JsonSchema,
S1bT: ComputedVecValue + JsonSchema,
{
let v = version + VERSION;
macro_rules! period {
macro_rules! epoch {
($p:ident) => {
LazyTransformLast::from_boxed::<F>(name, v, source.$p.read_only_boxed_clone())
};
}
Self(indexes_from!(period))
Self(indexes_from!(period, epoch))
}
}

View File

@@ -1,89 +0,0 @@
//! Lazy aggregated SumCum for block-level sources.
use brk_traversable::Traversable;
use brk_types::{
Day1, Day3, DifficultyEpoch, HalvingEpoch, Hour1, Hour12, Hour4, Minute1, Minute10, Minute30,
Minute5, Month1, Month3, Month6, Version, Week1, Year1, Year10,
};
use schemars::JsonSchema;
use vecdb::{ReadableCloneableVec, UnaryTransform};
use crate::internal::{
ComputedHeightDerivedSumCum, ComputedVecValue, LazyTransformSumCum, NumericValue,
};
#[derive(Clone, Traversable)]
#[traversable(merge)]
pub struct LazyHeightDerivedSumCum<T, S1T = T>
where
T: ComputedVecValue + PartialOrd + JsonSchema,
S1T: ComputedVecValue,
{
pub minute1: LazyTransformSumCum<Minute1, T, S1T>,
pub minute5: LazyTransformSumCum<Minute5, T, S1T>,
pub minute10: LazyTransformSumCum<Minute10, T, S1T>,
pub minute30: LazyTransformSumCum<Minute30, T, S1T>,
pub hour1: LazyTransformSumCum<Hour1, T, S1T>,
pub hour4: LazyTransformSumCum<Hour4, T, S1T>,
pub hour12: LazyTransformSumCum<Hour12, T, S1T>,
pub day1: LazyTransformSumCum<Day1, T, S1T>,
pub day3: LazyTransformSumCum<Day3, T, S1T>,
pub week1: LazyTransformSumCum<Week1, T, S1T>,
pub month1: LazyTransformSumCum<Month1, T, S1T>,
pub month3: LazyTransformSumCum<Month3, T, S1T>,
pub month6: LazyTransformSumCum<Month6, T, S1T>,
pub year1: LazyTransformSumCum<Year1, T, S1T>,
pub year10: LazyTransformSumCum<Year10, T, S1T>,
pub halvingepoch: LazyTransformSumCum<HalvingEpoch, T, S1T>,
pub difficultyepoch: LazyTransformSumCum<DifficultyEpoch, T, S1T>,
}
const VERSION: Version = Version::ZERO;
impl<T, S1T> LazyHeightDerivedSumCum<T, S1T>
where
T: ComputedVecValue + JsonSchema + 'static,
S1T: ComputedVecValue + JsonSchema,
{
pub(crate) fn from_derived_computed<F: UnaryTransform<S1T, T>>(
name: &str,
version: Version,
source: &ComputedHeightDerivedSumCum<S1T>,
) -> Self
where
S1T: NumericValue,
{
let v = version + VERSION;
macro_rules! period {
($p:ident) => {
LazyTransformSumCum::from_boxed_sum_raw::<F>(
name,
v,
source.$p.sum.read_only_boxed_clone(),
source.$p.cumulative.read_only_boxed_clone(),
)
};
}
Self {
minute1: period!(minute1),
minute5: period!(minute5),
minute10: period!(minute10),
minute30: period!(minute30),
hour1: period!(hour1),
hour4: period!(hour4),
hour12: period!(hour12),
day1: period!(day1),
day3: period!(day3),
week1: period!(week1),
month1: period!(month1),
month3: period!(month3),
month6: period!(month6),
year1: period!(year1),
year10: period!(year10),
halvingepoch: period!(halvingepoch),
difficultyepoch: period!(difficultyepoch),
}
}
}

View File

@@ -1,21 +1,9 @@
mod binary_last;
mod cum_full;
mod distribution;
mod full;
mod cumulative_full;
mod last;
mod lazy_full;
mod lazy_last;
mod lazy_sum_cum;
mod sum_cum;
mod value_lazy_last;
pub use binary_last::*;
pub use cum_full::*;
pub use distribution::*;
pub use full::*;
pub use cumulative_full::*;
pub use last::*;
pub use lazy_full::*;
pub use lazy_last::*;
pub use lazy_sum_cum::*;
pub use sum_cum::*;
pub use value_lazy_last::*;

View File

@@ -1,138 +0,0 @@
//! ComputedHeightDerivedSumCum - height cumulative (stored) + lazy time periods + epochs.
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{
Day1, Day3, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour12, Hour4, Minute1, Minute10,
Minute30, Minute5, Month1, Month3, Month6, Version, Week1, Year1, Year10,
};
use schemars::JsonSchema;
use vecdb::{Database, Exit, ReadableBoxedVec, ReadableCloneableVec, ReadableVec, Rw, StorageMode};
use crate::{
indexes,
internal::{ComputedVecValue, CumulativeVec, LazySumCum, NumericValue},
ComputeIndexes,
};
#[derive(Traversable)]
#[traversable(merge)]
pub struct ComputedHeightDerivedSumCum<T, M: StorageMode = Rw>
where
T: ComputedVecValue + PartialOrd + JsonSchema,
{
#[traversable(rename = "cumulative")]
pub height_cumulative: CumulativeVec<Height, T, M>,
pub minute1: LazySumCum<Minute1, T, Height, Height>,
pub minute5: LazySumCum<Minute5, T, Height, Height>,
pub minute10: LazySumCum<Minute10, T, Height, Height>,
pub minute30: LazySumCum<Minute30, T, Height, Height>,
pub hour1: LazySumCum<Hour1, T, Height, Height>,
pub hour4: LazySumCum<Hour4, T, Height, Height>,
pub hour12: LazySumCum<Hour12, T, Height, Height>,
pub day1: LazySumCum<Day1, T, Height, Height>,
pub day3: LazySumCum<Day3, T, Height, Height>,
pub week1: LazySumCum<Week1, T, Height, Height>,
pub month1: LazySumCum<Month1, T, Height, Height>,
pub month3: LazySumCum<Month3, T, Height, Height>,
pub month6: LazySumCum<Month6, T, Height, Height>,
pub year1: LazySumCum<Year1, T, Height, Height>,
pub year10: LazySumCum<Year10, T, Height, Height>,
pub halvingepoch: LazySumCum<HalvingEpoch, T, Height, HalvingEpoch>,
pub difficultyepoch: LazySumCum<DifficultyEpoch, T, Height, DifficultyEpoch>,
}
const VERSION: Version = Version::ZERO;
impl<T> ComputedHeightDerivedSumCum<T>
where
T: NumericValue + JsonSchema,
{
pub(crate) fn forced_import(
db: &Database,
name: &str,
height_source: ReadableBoxedVec<Height, T>,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
let v = version + VERSION;
let height_cumulative = CumulativeVec::forced_import(db, name, v)?;
macro_rules! period {
($idx:ident) => {
LazySumCum::from_height_sources_sum_raw(
name,
v,
height_source.clone(),
height_cumulative.read_only_boxed_clone(),
indexes.$idx.first_height.read_only_boxed_clone(),
)
};
}
macro_rules! epoch {
($idx:ident) => {
LazySumCum::from_sources_sum_raw(
name,
v,
height_source.clone(),
height_cumulative.read_only_boxed_clone(),
indexes.$idx.identity.read_only_boxed_clone(),
)
};
}
let minute1 = period!(minute1);
let minute5 = period!(minute5);
let minute10 = period!(minute10);
let minute30 = period!(minute30);
let hour1 = period!(hour1);
let hour4 = period!(hour4);
let hour12 = period!(hour12);
let day1 = period!(day1);
let day3 = period!(day3);
let week1 = period!(week1);
let month1 = period!(month1);
let month3 = period!(month3);
let month6 = period!(month6);
let year1 = period!(year1);
let year10 = period!(year10);
let halvingepoch = epoch!(halvingepoch);
let difficultyepoch = epoch!(difficultyepoch);
Ok(Self {
height_cumulative,
minute1,
minute5,
minute10,
minute30,
hour1,
hour4,
hour12,
day1,
day3,
week1,
month1,
month3,
month6,
year1,
year10,
halvingepoch,
difficultyepoch,
})
}
pub(crate) fn derive_from(
&mut self,
starting_indexes: &ComputeIndexes,
height_source: &impl ReadableVec<Height, T>,
exit: &Exit,
) -> Result<()> {
self.height_cumulative
.0
.compute_cumulative(starting_indexes.height, height_source, exit)?;
Ok(())
}
}

View File

@@ -1,19 +1,19 @@
//! TxDerivedDistribution - computes TxIndex data to height Distribution + lazy time periods + epochs.
//! TxDerivedDistribution - per-block + rolling window distribution stats from tx-level data.
//!
//! Computes true distribution stats (average, min, max, median, percentiles) by reading
//! actual tx values for each scope: current block, last 1h, last 24h.
use brk_error::Result;
use brk_indexer::Indexer;
use brk_traversable::Traversable;
use brk_types::{
Day1, Day3, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour12, Hour4, Minute1, Minute10,
Minute30, Minute5, Month1, Month3, Month6, TxIndex, Version, Week1, Year1, Year10,
};
use brk_types::{Height, TxIndex};
use schemars::JsonSchema;
use vecdb::{Database, Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode};
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode, Version};
use crate::{
ComputeIndexes, indexes,
internal::{ComputedVecValue, Distribution, LazyDistribution, NumericValue},
internal::{BlockRollingDistribution, BlockWindowStarts, ComputedVecValue, Distribution, NumericValue},
};
#[derive(Traversable)]
@@ -22,28 +22,11 @@ pub struct TxDerivedDistribution<T, M: StorageMode = Rw>
where
T: ComputedVecValue + PartialOrd + JsonSchema,
{
pub height: Distribution<Height, T, M>,
pub minute1: LazyDistribution<Minute1, T, Height, Height>,
pub minute5: LazyDistribution<Minute5, T, Height, Height>,
pub minute10: LazyDistribution<Minute10, T, Height, Height>,
pub minute30: LazyDistribution<Minute30, T, Height, Height>,
pub hour1: LazyDistribution<Hour1, T, Height, Height>,
pub hour4: LazyDistribution<Hour4, T, Height, Height>,
pub hour12: LazyDistribution<Hour12, T, Height, Height>,
pub day1: LazyDistribution<Day1, T, Height, Height>,
pub day3: LazyDistribution<Day3, T, Height, Height>,
pub week1: LazyDistribution<Week1, T, Height, Height>,
pub month1: LazyDistribution<Month1, T, Height, Height>,
pub month3: LazyDistribution<Month3, T, Height, Height>,
pub month6: LazyDistribution<Month6, T, Height, Height>,
pub year1: LazyDistribution<Year1, T, Height, Height>,
pub year10: LazyDistribution<Year10, T, Height, Height>,
pub halvingepoch: LazyDistribution<HalvingEpoch, T, Height, HalvingEpoch>,
pub difficultyepoch: LazyDistribution<DifficultyEpoch, T, Height, DifficultyEpoch>,
pub block: Distribution<Height, T, M>,
#[traversable(flatten)]
pub rolling: BlockRollingDistribution<T, M>,
}
const VERSION: Version = Version::ZERO;
impl<T> TxDerivedDistribution<T>
where
T: NumericValue + JsonSchema,
@@ -52,71 +35,11 @@ where
db: &Database,
name: &str,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
let height = Distribution::forced_import(db, name, version + VERSION)?;
let v = version + VERSION;
let block = Distribution::forced_import(db, name, version)?;
let rolling = BlockRollingDistribution::forced_import(db, name, version)?;
macro_rules! period {
($idx:ident) => {
LazyDistribution::from_height_source(
name,
v,
height.boxed_average(),
indexes.$idx.first_height.read_only_boxed_clone(),
)
};
}
macro_rules! epoch {
($idx:ident) => {
LazyDistribution::from_source(
name,
v,
height.boxed_average(),
indexes.$idx.identity.read_only_boxed_clone(),
)
};
}
let minute1 = period!(minute1);
let minute5 = period!(minute5);
let minute10 = period!(minute10);
let minute30 = period!(minute30);
let hour1 = period!(hour1);
let hour4 = period!(hour4);
let hour12 = period!(hour12);
let day1 = period!(day1);
let day3 = period!(day3);
let week1 = period!(week1);
let month1 = period!(month1);
let month3 = period!(month3);
let month6 = period!(month6);
let year1 = period!(year1);
let year10 = period!(year10);
let halvingepoch = epoch!(halvingepoch);
let difficultyepoch = epoch!(difficultyepoch);
Ok(Self {
height,
minute1,
minute5,
minute10,
minute30,
hour1,
hour4,
hour12,
day1,
day3,
week1,
month1,
month3,
month6,
year1,
year10,
halvingepoch,
difficultyepoch,
})
Ok(Self { block, rolling })
}
pub(crate) fn derive_from(
@@ -124,25 +47,46 @@ where
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &ComputeIndexes,
block_windows: &BlockWindowStarts<'_>,
txindex_source: &impl ReadableVec<TxIndex, T>,
exit: &Exit,
) -> Result<()> {
self.derive_from_with_skip(indexer, indexes, starting_indexes, txindex_source, exit, 0)
) -> Result<()>
where
T: Copy + Ord + From<f64> + Default,
f64: From<T>,
{
self.derive_from_with_skip(
indexer,
indexes,
starting_indexes,
block_windows,
txindex_source,
exit,
0,
)
}
/// Derive from source, skipping first N transactions per block from all calculations.
/// Derive from source, skipping first N transactions per block from per-block stats.
///
/// Use `skip_count: 1` to exclude coinbase transactions from fee/feerate stats.
/// Rolling window distributions do NOT skip (negligible impact over many blocks).
#[allow(clippy::too_many_arguments)]
pub(crate) fn derive_from_with_skip(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &ComputeIndexes,
block_windows: &BlockWindowStarts<'_>,
txindex_source: &impl ReadableVec<TxIndex, T>,
exit: &Exit,
skip_count: usize,
) -> Result<()> {
self.height.compute_with_skip(
) -> Result<()>
where
T: Copy + Ord + From<f64> + Default,
f64: From<T>,
{
// Per-block distribution (supports skip for coinbase exclusion)
self.block.compute_with_skip(
starting_indexes.height,
txindex_source,
&indexer.vecs.transactions.first_txindex,
@@ -151,6 +95,26 @@ where
skip_count,
)?;
// 1h rolling: true distribution from all txs in last hour
self.rolling._1h.compute_from_window(
starting_indexes.height,
txindex_source,
&indexer.vecs.transactions.first_txindex,
&indexes.height.txindex_count,
block_windows._1h,
exit,
)?;
// 24h rolling: true distribution from all txs in last 24 hours
self.rolling._24h.compute_from_window(
starting_indexes.height,
txindex_source,
&indexer.vecs.transactions.first_txindex,
&indexes.height.txindex_count,
block_windows._24h,
exit,
)?;
Ok(())
}
}