From be4d09cc4bd27a911ec8f8e772c349f0929fd1b2 Mon Sep 17 00:00:00 2001 From: Brandon Vrooman Date: Sun, 19 Nov 2023 22:09:03 -0500 Subject: [PATCH] Use linear regression when quadratic --- benches/src/collect/costs.rs | 99 ++++++++++++++++++++++++------------ 1 file changed, 67 insertions(+), 32 deletions(-) diff --git a/benches/src/collect/costs.rs b/benches/src/collect/costs.rs index b289e561522..6ed3a03f04b 100644 --- a/benches/src/collect/costs.rs +++ b/benches/src/collect/costs.rs @@ -1,5 +1,7 @@ use crate::{ estimate_model, + regression::linear_regression, + LinearCoefficients, Model, }; use serde::{ @@ -35,7 +37,6 @@ pub fn dependent_cost( points: Vec<(f64, f64)>, ) -> anyhow::Result { let model = estimate_model(&points)?; - let cost = match model { Model::Zero => { // Zero @@ -63,34 +64,13 @@ pub fn dependent_cost( } } Model::Linear(coefficients) => { - match coefficients.slope { - slope if slope > 0.0 && slope < 1.0 => { - // Slope is between (0.0, 1.0) - // Light operation - let base = coefficients.intercept; - let base = base.max(0.0); - let base = base.round() as u64; - let inverse_slope = 1.0 / slope; - let units_per_gas = inverse_slope.round() as u64; - DependentCost::LightOperation { - base, - units_per_gas, - } - } - slope if slope >= 1.0 => { - // Slope is greater than 1.0 - // Heavy operation - let base = coefficients.intercept; - let base = base.max(0.0); - let base = base.round() as u64; - let gas_per_unit = slope.round() as u64; - DependentCost::HeavyOperation { base, gas_per_unit } - } - _ => { - // Slope is negative + let cost = coefficients.try_into(); + match cost { + Ok(cost) => cost, + Err(DependentCostError::NegativeSlope(slope)) => { let warning = format!("Warning: \ - Evaluating the regression on the dataset for `{name}` produced a negative slope. \ - This implies a negative cost behavior and is not supported in a dependent context.", name = name); + Evaluating the regression on the dataset for `{name}` produced a negative slope: {slope}. \ + This implies a negative cost behavior and is not supported in a dependent context.", slope = slope, name = name); eprintln!("{}", warning); let base = coefficients.intercept; let base = base.round() as u64; @@ -105,11 +85,24 @@ pub fn dependent_cost( // Quadratic let warning = format!("Warning: \ Evaluating the regression on the dataset for `{name}` produced a quadratic function({:?}). \ - Quadratic behavior is not supported in a dependent context. Points: {points:?}", coefficients, name = name, points = points); + Quadratic behavior is not supported in a dependent context. Points: {points:?}. Defaulting to linear model", coefficients, name = name, points = points); eprintln!("{}", warning); - DependentCost::HeavyOperation { - base: 0, - gas_per_unit: 0, + let coefficients = linear_regression(&points); + let cost = coefficients.try_into(); + match cost { + Ok(cost) => cost, + Err(DependentCostError::NegativeSlope(slope)) => { + let warning = format!("Warning: \ + Evaluating the regression on the dataset for `{name}` produced a negative slope: {slope}. \ + This implies a negative cost behavior and is not supported in a dependent context.", slope = slope, name = name); + eprintln!("{}", warning); + let base = coefficients.intercept; + let base = base.round() as u64; + DependentCost::HeavyOperation { + base, + gas_per_unit: 0, + } + } } } Model::Other => { @@ -127,3 +120,45 @@ pub fn dependent_cost( }; Ok(cost) } + +#[derive(Debug)] +pub enum DependentCostError { + NegativeSlope(f64), +} + +impl TryFrom for DependentCost { + type Error = DependentCostError; + + fn try_from(coefficients: LinearCoefficients) -> Result { + match coefficients.slope { + slope if slope > 0.0 && slope < 1.0 => { + // Slope is between (0.0, 1.0) + // Light operation + let base = coefficients.intercept; + let base = base.max(0.0); + let base = base.round() as u64; + let inverse_slope = 1.0 / slope; + let units_per_gas = inverse_slope.round() as u64; + let cost = DependentCost::LightOperation { + base, + units_per_gas, + }; + Ok(cost) + } + slope if slope >= 1.0 => { + // Slope is greater than 1.0 + // Heavy operation + let base = coefficients.intercept; + let base = base.max(0.0); + let base = base.round() as u64; + let gas_per_unit = slope.round() as u64; + let cost = DependentCost::HeavyOperation { base, gas_per_unit }; + Ok(cost) + } + slope => { + // Slope is negative + Err(DependentCostError::NegativeSlope(slope)) + } + } + } +}