Skip to content

Commit

Permalink
Merge pull request #2933 from junli1026/jun/dev
Browse files Browse the repository at this point in the history
Apply monotonic function to range filter
  • Loading branch information
BohuTANG authored Nov 24, 2021
2 parents 518fdfa + fbac235 commit 5eec227
Show file tree
Hide file tree
Showing 14 changed files with 754 additions and 236 deletions.
10 changes: 7 additions & 3 deletions common/functions/src/scalars/arithmetics/arithmetic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use common_datavalues::DataValueArithmeticOperator;
use common_exception::Result;

use crate::scalars::dates::IntervalFunctionFactory;
use crate::scalars::function::MonotonicityNode;
use crate::scalars::function::Monotonicity;
use crate::scalars::function_factory::FunctionFactory;
use crate::scalars::ArithmeticDivFunction;
use crate::scalars::ArithmeticMinusFunction;
Expand Down Expand Up @@ -50,7 +50,11 @@ impl ArithmeticFunction {
}

pub fn try_create_func(op: DataValueArithmeticOperator) -> Result<Box<dyn Function>> {
Ok(Box::new(ArithmeticFunction { op }))
Ok(Box::new(ArithmeticFunction::new(op)))
}

pub fn new(op: DataValueArithmeticOperator) -> Self {
ArithmeticFunction { op }
}
}

Expand Down Expand Up @@ -114,7 +118,7 @@ impl Function for ArithmeticFunction {
Some((1, 2))
}

fn get_monotonicity(&self, args: &[MonotonicityNode]) -> Result<MonotonicityNode> {
fn get_monotonicity(&self, args: &[Monotonicity]) -> Result<Monotonicity> {
match self.op {
Plus => ArithmeticPlusFunction::get_monotonicity(args),
Minus => ArithmeticMinusFunction::get_monotonicity(args),
Expand Down
7 changes: 3 additions & 4 deletions common/functions/src/scalars/arithmetics/arithmetic_div.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ use crate::scalars::function_factory::FunctionFeatures;
use crate::scalars::ArithmeticFunction;
use crate::scalars::Function;
use crate::scalars::Monotonicity;
use crate::scalars::MonotonicityNode;

pub struct ArithmeticDivFunction;

Expand All @@ -34,8 +33,8 @@ impl ArithmeticDivFunction {
.features(FunctionFeatures::default().deterministic())
}

pub fn get_monotonicity(_args: &[MonotonicityNode]) -> Result<MonotonicityNode> {
//TODO: implement
Ok(MonotonicityNode::Function(Monotonicity::default(), None))
pub fn get_monotonicity(_args: &[Monotonicity]) -> Result<Monotonicity> {
// TODO
Ok(Monotonicity::default())
}
}
69 changes: 65 additions & 4 deletions common/functions/src/scalars/arithmetics/arithmetic_minus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@
// limitations under the License.

use common_datavalues::DataValueArithmeticOperator;
use common_exception::ErrorCode;
use common_exception::Result;

use crate::scalars::function_factory::FunctionDescription;
use crate::scalars::function_factory::FunctionFeatures;
use crate::scalars::ArithmeticFunction;
use crate::scalars::Function;
use crate::scalars::Monotonicity;
use crate::scalars::MonotonicityNode;

pub struct ArithmeticMinusFunction;

Expand All @@ -34,8 +34,69 @@ impl ArithmeticMinusFunction {
.features(FunctionFeatures::default().deterministic())
}

pub fn get_monotonicity(_args: &[MonotonicityNode]) -> Result<MonotonicityNode> {
//TODO: implement
Ok(MonotonicityNode::Function(Monotonicity::default(), None))
pub fn get_monotonicity(args: &[Monotonicity]) -> Result<Monotonicity> {
if args.is_empty() || args.len() > 2 {
return Err(ErrorCode::BadArguments(format!(
"Invalid argument lengths {} for get_monotonicity",
args.len()
)));
}

// unary operation like '-f(x)', just flip the is_positive.
// also pass the is_constant, in case the input is a constant value.
if args.len() == 1 {
return Ok(Monotonicity {
is_monotonic: args[0].is_monotonic || args[0].is_constant,
is_positive: !args[0].is_positive,
is_constant: args[0].is_constant,
left: None,
right: None,
});
}

// For expression f(x) - g(x), only when both f(x) and g(x) are monotonic and have
// opposite 'is_positive' can we get a monotonic expression.
let f_x = &args[0];
let g_x = &args[1];

// case of 12 - g(x)
if f_x.is_constant {
return Ok(Monotonicity {
is_monotonic: g_x.is_monotonic || g_x.is_constant,
is_positive: !g_x.is_positive,
is_constant: g_x.is_constant,
left: None,
right: None,
});
}

// case of f(x) - 12
if g_x.is_constant {
return Ok(Monotonicity {
is_monotonic: f_x.is_monotonic,
is_positive: f_x.is_positive,
is_constant: f_x.is_constant,
left: None,
right: None,
});
}

// if either one is non-monotonic, return non-monotonic
if !f_x.is_monotonic || !g_x.is_monotonic {
return Ok(Monotonicity::default());
}

// when both are monotonic, and have same 'is_positive', we can't determine the monotonicity
if f_x.is_positive == g_x.is_positive {
return Ok(Monotonicity::default());
}

Ok(Monotonicity {
is_monotonic: true,
is_positive: f_x.is_positive,
is_constant: false,
left: None,
right: None,
})
}
}
7 changes: 3 additions & 4 deletions common/functions/src/scalars/arithmetics/arithmetic_modulo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ use crate::scalars::function_factory::FunctionFeatures;
use crate::scalars::ArithmeticFunction;
use crate::scalars::Function;
use crate::scalars::Monotonicity;
use crate::scalars::MonotonicityNode;

pub struct ArithmeticModuloFunction;

Expand All @@ -34,8 +33,8 @@ impl ArithmeticModuloFunction {
.features(FunctionFeatures::default().deterministic())
}

pub fn get_monotonicity(_args: &[MonotonicityNode]) -> Result<MonotonicityNode> {
//TODO: implement
Ok(MonotonicityNode::Function(Monotonicity::default(), None))
pub fn get_monotonicity(_args: &[Monotonicity]) -> Result<Monotonicity> {
//TODO
Ok(Monotonicity::default())
}
}
7 changes: 3 additions & 4 deletions common/functions/src/scalars/arithmetics/arithmetic_mul.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ use crate::scalars::function_factory::FunctionFeatures;
use crate::scalars::ArithmeticFunction;
use crate::scalars::Function;
use crate::scalars::Monotonicity;
use crate::scalars::MonotonicityNode;

pub struct ArithmeticMulFunction;

Expand All @@ -34,8 +33,8 @@ impl ArithmeticMulFunction {
.features(FunctionFeatures::default().deterministic())
}

pub fn get_monotonicity(_args: &[MonotonicityNode]) -> Result<MonotonicityNode> {
//TODO: implement
Ok(MonotonicityNode::Function(Monotonicity::default(), None))
pub fn get_monotonicity(_args: &[Monotonicity]) -> Result<Monotonicity> {
//TODO
Ok(Monotonicity::default())
}
}
104 changes: 41 additions & 63 deletions common/functions/src/scalars/arithmetics/arithmetic_plus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ use common_datavalues::DataValueArithmeticOperator;
use common_exception::ErrorCode;
use common_exception::Result;

use crate::scalars::function::MonotonicityNode;
use crate::scalars::function_factory::FunctionDescription;
use crate::scalars::function_factory::FunctionFeatures;
use crate::scalars::ArithmeticFunction;
Expand All @@ -35,7 +34,7 @@ impl ArithmeticPlusFunction {
.features(FunctionFeatures::default().deterministic())
}

pub fn get_monotonicity(args: &[MonotonicityNode]) -> Result<MonotonicityNode> {
pub fn get_monotonicity(args: &[Monotonicity]) -> Result<Monotonicity> {
if args.is_empty() || args.len() > 2 {
return Err(ErrorCode::BadArguments(format!(
"Invalid argument lengths {} for get_monotonicity",
Expand All @@ -47,71 +46,50 @@ impl ArithmeticPlusFunction {
return Ok(args[0].clone());
}

// TODO: handle input with data range
match (&args[0], &args[1]) {
// a constant value plus a function, like 12 + f(x), the monotonicity should be the same as f
(MonotonicityNode::Function(mono, None), MonotonicityNode::Constant(_))
| (MonotonicityNode::Constant(_), MonotonicityNode::Function(mono, None)) => {
Ok(MonotonicityNode::Function(mono.clone(), None))
}
// For expression f(x) + g(x), only when both f(x) and g(x) are monotonic and have
// same 'is_positive' can we get a monotonic expression.
let f_x = &args[0];
let g_x = &args[1];

// a constant value plus a variable, like x + 12 should be monotonically increasing
(MonotonicityNode::Constant(_), MonotonicityNode::Variable(_, None))
| (MonotonicityNode::Variable(_, None), MonotonicityNode::Constant(_)) => {
Ok(MonotonicityNode::Function(
Monotonicity {
is_monotonic: true,
is_positive: true,
is_always_monotonic: true,
},
None,
))
}

// two function plus, f(x) + g(x) , if they have same monotonicity, then should return that monotonicity
(MonotonicityNode::Function(mono1, None), MonotonicityNode::Function(mono2, None)) => {
if mono1.is_monotonic
&& mono2.is_monotonic
&& mono1.is_positive == mono2.is_positive
{
return Ok(MonotonicityNode::Function(
Monotonicity {
is_monotonic: true,
is_positive: mono1.is_positive,
is_always_monotonic: mono1.is_always_monotonic
&& mono2.is_always_monotonic,
},
None,
));
}
Ok(MonotonicityNode::Function(Monotonicity::default(), None))
}
// if either one is non-monotonic, return non-monotonic
if !f_x.is_monotonic || !g_x.is_monotonic {
return Ok(Monotonicity::default());
}

// two variable plus(we assume only one variable exists), like x+x, should be monotonically increasing
(MonotonicityNode::Variable(var1, None), MonotonicityNode::Variable(var2, None)) => {
if var1 == var2 {
return Ok(MonotonicityNode::Function(
Monotonicity {
is_monotonic: true,
is_positive: true,
is_always_monotonic: true,
},
None,
));
}
Ok(MonotonicityNode::Function(Monotonicity::default(), None))
}
// if f(x) is a constant value, return the monotonicity of g(x)
if f_x.is_constant {
return Ok(Monotonicity {
is_monotonic: g_x.is_monotonic,
is_positive: g_x.is_positive,
is_constant: g_x.is_constant,
left: None,
right: None,
});
}

// a function plus the variable, like f(x) + x, if f(x) is monotonically increasing, return it.
(MonotonicityNode::Function(mono, None), MonotonicityNode::Variable(_, None))
| (MonotonicityNode::Variable(_, None), MonotonicityNode::Function(mono, None)) => {
if mono.is_monotonic && mono.is_positive {
return Ok(MonotonicityNode::Function(mono.clone(), None));
}
Ok(MonotonicityNode::Function(Monotonicity::default(), None))
}
// if g(x) is a constant value, return the monotonicity of f(x)
if g_x.is_constant {
return Ok(Monotonicity {
is_monotonic: f_x.is_monotonic,
is_positive: f_x.is_positive,
is_constant: f_x.is_constant,
left: None,
right: None,
});
}

_ => Ok(MonotonicityNode::Function(Monotonicity::default(), None)),
// Now we have f(x) and g(x) both are non-constant.
// When both are monotonic, but have different 'is_positive', we can't determine the monotonicity
if f_x.is_positive != g_x.is_positive {
return Ok(Monotonicity::default());
}

Ok(Monotonicity {
is_monotonic: true,
is_positive: f_x.is_positive,
is_constant: false,
left: None,
right: None,
})
}
}
Loading

0 comments on commit 5eec227

Please sign in to comment.