Skip to content

Commit

Permalink
Feature/552 eval constant terms (#564)
Browse files Browse the repository at this point in the history
Adds the function `reduce` to all `Terms` in the rule model, which
simplifies constant expressions within `Operation`s
  • Loading branch information
aannleax authored Jan 7, 2025
2 parents 25e6137 + 245a5b9 commit 4a892be
Show file tree
Hide file tree
Showing 22 changed files with 524 additions and 129 deletions.
2 changes: 1 addition & 1 deletion nemo-physical/src/function.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! This module contains data structures and implementations
//! for realizing the evaluation of functions on columnar data.
pub mod evaluation;
pub mod tree;

pub(crate) mod definitions;
pub(crate) mod evaluation;
8 changes: 4 additions & 4 deletions nemo-physical/src/function/evaluation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub(crate) enum StackOperation {

/// Representation of a [FunctionTree] as a stack program
#[derive(Debug, Clone)]
pub(crate) struct StackProgram {
pub struct StackProgram {
/// Maximmum size of the stack
size: usize,
/// List of instructions
Expand Down Expand Up @@ -115,7 +115,7 @@ impl StackProgram {
}

/// Construct a [StackProgram] from [FunctionTree].
pub(crate) fn from_function_tree<ReferenceType: Hash + Eq + Debug + Clone>(
pub fn from_function_tree<ReferenceType: Hash + Eq + Debug + Clone>(
tree: &FunctionTree<ReferenceType>,
reference_map: &HashMap<ReferenceType, usize>,
this: Option<ReferenceType>,
Expand Down Expand Up @@ -263,7 +263,7 @@ impl StackProgram {
///
/// # Panics
/// Panics if the [StackProgram] is not valid.
pub(crate) fn evaluate_data(&self, referenced_values: &[AnyDataValue]) -> Option<AnyDataValue> {
pub fn evaluate_data(&self, referenced_values: &[AnyDataValue]) -> Option<AnyDataValue> {
self.evaluate(referenced_values, None)
}

Expand All @@ -274,7 +274,7 @@ impl StackProgram {
///
/// # Panics
/// Panics if the [StackProgram] is not valid.
pub(crate) fn evaluate_bool(
pub fn evaluate_bool(
&self,
referenced_values: &[AnyDataValue],
this: Option<AnyDataValue>,
Expand Down
4 changes: 2 additions & 2 deletions nemo-python/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use nemo::{
rule_model::{
components::{fact::Fact, tag::Tag, term::primitive::Primitive, ProgramComponent},
error::ValidationErrorBuilder,
term_map::PrimitiveTermMap,
substitution::Substitution,
},
};

Expand Down Expand Up @@ -269,7 +269,7 @@ impl NemoTrace {
}
}

fn assignement_to_dict(assignment: &PrimitiveTermMap, py: Python) -> PyResult<PyObject> {
fn assignement_to_dict(assignment: &Substitution, py: Python) -> PyResult<PyObject> {
let dict = PyDict::new_bound(py);
for (variable, term) in assignment {
if let Primitive::Ground(ground) = term {
Expand Down
8 changes: 4 additions & 4 deletions nemo/src/execution/execution_engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use crate::{
term::primitive::{ground::GroundTerm, variable::Variable, Primitive},
},
program::Program,
term_map::PrimitiveTermMap,
substitution::Substitution,
},
table_manager::{MemoryUsage, SubtableExecutionPlan, TableManager},
};
Expand Down Expand Up @@ -452,9 +452,9 @@ impl<Strategy: RuleSelectionStrategy> ExecutionEngine<Strategy> {

let rule_application = TraceRuleApplication::new(
rule_index,
PrimitiveTermMap::new(variable_assignment.into_iter().map(
|(variable, value)| (Primitive::from(variable), Primitive::from(value)),
)),
Substitution::new(variable_assignment.into_iter().map(|(variable, value)| {
(Primitive::from(variable), Primitive::from(value))
})),
head_index,
);

Expand Down
2 changes: 1 addition & 1 deletion nemo/src/execution/planning/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ pub(crate) mod filter;
pub(crate) mod functions;
pub(crate) mod join;
pub(crate) mod negation;
pub(super) mod operation;
pub(crate) mod operation;
pub(crate) mod union;
4 changes: 2 additions & 2 deletions nemo/src/execution/planning/operations/operation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{
};

/// Helper function to translate a [OperationTerm] into a [FunctionTree].
pub(super) fn operation_term_to_function_tree(
pub(crate) fn operation_term_to_function_tree(
translation: &VariableTranslation,
operation_term: &OperationTerm,
) -> FunctionTree<OperationColumnMarker> {
Expand Down Expand Up @@ -56,7 +56,7 @@ macro_rules! unary {
}

/// Helper function to translate a [Operation] into a [FunctionTree].
pub(super) fn operation_to_function_tree(
pub(crate) fn operation_to_function_tree(
translation: &VariableTranslation,
operation: &Operation,
) -> FunctionTree<OperationColumnMarker> {
Expand Down
12 changes: 6 additions & 6 deletions nemo/src/execution/tracing/trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::{
rule_model::{
components::{fact::Fact, rule::Rule},
program::Program,
term_map::PrimitiveTermMap,
substitution::Substitution,
},
};

Expand Down Expand Up @@ -49,14 +49,14 @@ pub(crate) struct TraceRuleApplication {
/// Index of the rule that was applied
rule_index: RuleIndex,
/// Variable assignment used during the rule application
assignment: PrimitiveTermMap,
assignment: Substitution,
/// Index of the head atom which produced the fact under consideration
_position: usize,
}

impl TraceRuleApplication {
/// Create new [TraceRuleApplication].
pub fn new(rule_index: RuleIndex, assignment: PrimitiveTermMap, _position: usize) -> Self {
pub fn new(rule_index: RuleIndex, assignment: Substitution, _position: usize) -> Self {
Self {
rule_index,
assignment,
Expand Down Expand Up @@ -201,7 +201,7 @@ pub struct TraceTreeRuleApplication {
/// Rule that was applied
pub rule: Rule,
/// Variable assignment used during the rule application
pub assignment: PrimitiveTermMap,
pub assignment: Substitution,
/// Index of the head atom which produced the fact under consideration
_position: usize,
}
Expand Down Expand Up @@ -562,7 +562,7 @@ mod test {
ProgramComponent,
},
program::ProgramBuilder,
term_map::PrimitiveTermMap,
substitution::Substitution,
},
};

Expand All @@ -579,7 +579,7 @@ mod test {
)
});

PrimitiveTermMap::new(terms)
Substitution::new(terms)
}};
}

Expand Down
2 changes: 1 addition & 1 deletion nemo/src/rule_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ pub mod components;
pub mod error;
pub mod origin;
pub mod program;
pub mod term_map;
pub mod substitution;
pub mod translation;
58 changes: 32 additions & 26 deletions nemo/src/rule_model/components/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,35 +23,41 @@ impl Display for ComponentParseError {

#[macro_export]
macro_rules! parse_component {
($string:expr, $parser:expr, $builder:expr) => {{
use nom::InputLength;

let input = $crate::parser::input::ParserInput::new(
$string,
$crate::parser::ParserState::default(),
);
let ast = match $parser(input) {
Ok((input, ast)) => {
if input.input_len() == 0 {
ast
} else {
return Err(
($string:expr, $parser:expr, $builder:expr) => {
'parse: {
use nom::InputLength;

let input = $crate::parser::input::ParserInput::new(
$string,
$crate::parser::ParserState::default(),
);
let ast = match $parser(input) {
Ok((input, ast)) => {
if input.input_len() == 0 {
ast
} else {
break 'parse Err(
$crate::rule_model::components::parse::ComponentParseError::ParseError,
);
}
}
Err(_) => {
break 'parse Err(
$crate::rule_model::components::parse::ComponentParseError::ParseError,
);
)
}
}
Err(_) => {
return Err($crate::rule_model::components::parse::ComponentParseError::ParseError)
}
};
};

let mut translation = ASTProgramTranslation::initialize($string, String::default());
let mut translation = ASTProgramTranslation::initialize($string, String::default());

match $builder(&mut translation, &ast) {
Ok(component) => Ok(component),
Err(error) => Err(
$crate::rule_model::components::parse::ComponentParseError::TranslationError(error),
),
match $builder(&mut translation, &ast) {
Ok(component) => Ok(component),
Err(error) => Err(
$crate::rule_model::components::parse::ComponentParseError::TranslationError(
error,
),
),
}
}
}};
};
}
5 changes: 5 additions & 0 deletions nemo/src/rule_model/components/tag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ impl Tag {
self.origin = origin;
self
}

/// Return the name of [Tag].
pub fn name(&self) -> &str {
&self.tag
}
}

impl Display for Tag {
Expand Down
77 changes: 75 additions & 2 deletions nemo/src/rule_model/components/term.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,16 @@ use tuple::Tuple;
use value_type::ValueType;

use crate::{
chase_model::translation::ProgramChaseTranslation,
execution::{
planning::operations::operation::operation_term_to_function_tree,
rule_execution::VariableTranslation,
},
parse_component,
parser::ast::ProgramAST,
rule_model::{
error::ValidationErrorBuilder, origin::Origin, translation::ASTProgramTranslation,
error::ValidationErrorBuilder, origin::Origin, substitution::Substitution,
translation::ASTProgramTranslation,
},
};

Expand Down Expand Up @@ -132,6 +139,43 @@ impl Term {
Term::Tuple(term) => Box::new(term.arguments()),
}
}

/// Return whether this term is ground,
/// i.e. whether it does not contain any variables.
pub fn is_ground(&self) -> bool {
match self {
Term::Primitive(term) => term.is_ground(),
Term::Aggregate(term) => term.is_ground(),
Term::FunctionTerm(term) => term.is_gound(),
Term::Map(term) => term.is_gound(),
Term::Operation(term) => term.is_gound(),
Term::Tuple(term) => term.is_gound(),
}
}

/// Reduce (potential) constant expressions contained and return a copy of the resulting [Term].
pub fn reduce(&self) -> Term {
match self {
Term::Operation(operation) => operation.reduce(),
Term::Primitive(_) => self.clone(),
Term::Aggregate(term) => Term::Aggregate(term.reduce()),
Term::FunctionTerm(term) => Term::FunctionTerm(term.reduce()),
Term::Map(term) => Term::Map(term.reduce()),
Term::Tuple(term) => Term::Tuple(term.reduce()),
}
}

/// Reduce (potential) constant expressions
/// contained while replacing terms according to the provided substition
/// and return a copy of the resulting reduced [Term]
pub fn reduce_substitution(&self, substitution: &Substitution) -> Term {
// TODO: A more efficient implementation would propagate the substituion
// into the subterms and reduce grounded subterms
let mut cloned = self.clone();
substitution.apply(&mut cloned);

cloned.reduce()
}
}

impl From<Variable> for Term {
Expand Down Expand Up @@ -250,7 +294,7 @@ impl ProgramComponent for Term {
{
parse_component!(
string,
crate::parser::ast::expression::Expression::parse_complex,
crate::parser::ast::expression::Expression::parse,
ASTProgramTranslation::build_inner_term
)
}
Expand Down Expand Up @@ -353,3 +397,32 @@ impl IterablePrimitives for Term {
}
}
}

#[cfg(test)]
mod test {
use crate::rule_model::components::ProgramComponent;

use super::Term;

#[test]
fn term_reduce_ground() {
let constant = Term::parse("2 * (3 + 7)").unwrap();
let term = Term::from(tuple!(5, constant));

let reduced = term.reduce();
let expected_term = Term::from(tuple!(5, 20));

assert_eq!(reduced, expected_term);
}

#[test]
fn term_reduce_nonground() {
let expression = Term::parse("?x * (3 + 7)").unwrap();
let term = Term::from(tuple!(5, expression));

let reduced = term.reduce();
let expected_term = Term::parse("(5, ?x * 10)").unwrap();

assert_eq!(reduced, expected_term);
}
}
Loading

0 comments on commit 4a892be

Please sign in to comment.