Skip to content

Commit

Permalink
Start working on update functions processing.
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrej33 committed Sep 4, 2024
1 parent 7ec416f commit 41eeb37
Show file tree
Hide file tree
Showing 7 changed files with 211 additions and 1 deletion.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ rand = "0.8.5"
regex = "1.10.2"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde-xml-rs = "0.6.0"
serde-xml-rs = "0.6.0"
num-rational = "0.4.2"
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
pub mod bma_model;
pub mod json_model;
pub mod traits;
pub mod update_fn;
pub mod xml_model;

mod _impl_bma_model;
Expand Down
120 changes: 120 additions & 0 deletions src/update_fn/bma_fn_tree.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
use crate::update_fn::enums::{AggregateOp, ArithOp, Literal, UnaryOp};
use crate::update_fn::tokenizer::BmaFnToken;
use std::cmp;
use std::fmt;

/// Enum of possible node types in a BMA expression syntax tree.
///
/// In particular, a node type can be:
/// - A "terminal" node containing a literal (variable, constant).
/// - A "unary" node with a `UnaryOp` and a sub-expression.
/// - A binary "arithmetic" node, with a `BinaryOp` and two sub-expressions.
/// - An "aggregation" node with a `AggregateOp` op and a list of sub-expressions.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum Expression {
Terminal(Literal),
Unary(UnaryOp, Box<BmaFnNode>),
Arithmetic(ArithOp, Box<BmaFnNode>, Box<BmaFnNode>),
Aggregation(AggregateOp, Vec<Box<BmaFnNode>>),
}

/// A single node in a syntax tree of a FOL formula.
///
/// Each node tracks its:
/// - `height`; A positive integer starting from 0 (for term nodes).
/// - `expression_tree`; A parse tree for the expression`.
/// - `function_str`; A canonical string representation of the expression.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct BmaFnNode {
pub function_str: String,
pub height: u32,
pub expression_tree: Expression,
}

impl BmaFnNode {
/// "Parse" a new [BmaFnNode] from a list of [BmaFnToken] objects.
pub fn from_tokens(_tokens: &[BmaFnToken]) -> Result<BmaFnNode, String> {
todo!()
}

/// Create a "unary" [BmaFnNode] from the given arguments.
///
/// See also [Expression::Unary].
pub fn mk_unary(child: BmaFnNode, op: UnaryOp) -> BmaFnNode {
let subform_str = format!("{op}({child})");
BmaFnNode {
function_str: subform_str,
height: child.height + 1,
expression_tree: Expression::Unary(op, Box::new(child)),
}
}

/// Create a "binary" arithmetic [BmaFnNode] from the given arguments.
///
/// See also [Expression::Binary].
pub fn mk_arithmetic(left: BmaFnNode, right: BmaFnNode, op: ArithOp) -> BmaFnNode {
BmaFnNode {
function_str: format!("({left} {op} {right})"),
height: cmp::max(left.height, right.height) + 1,
expression_tree: Expression::Arithmetic(op, Box::new(left), Box::new(right)),
}
}

/// Create a [BmaFnNode] representing a Boolean constant.
///
/// See also [Expression::Terminal] and [Atomic::True] / [Atomic::False].
pub fn mk_constant(constant_val: i32) -> BmaFnNode {
Self::mk_literal(Literal::Int(constant_val))
}

/// Create a [BmaFnNode] representing a variable.
///
/// See also [Expression::Terminal] and [Literal::Str].
pub fn mk_variable(var_name: &str) -> BmaFnNode {
Self::mk_literal(Literal::Str(var_name.to_string()))
}

/// A helper function which creates a new [BmaFnNode] for the given [Literal] value.
fn mk_literal(literal: Literal) -> BmaFnNode {
BmaFnNode {
function_str: literal.to_string(),
height: 0,
expression_tree: Expression::Terminal(literal),
}
}

/// Create a [BmaFnNode] representing an aggregation operator applied to given arguments.
pub fn mk_aggregation(op: AggregateOp, inner_nodes: Vec<BmaFnNode>) -> BmaFnNode {
let max_height = inner_nodes
.iter()
.map(|node| node.height)
.max()
.unwrap_or(0);
let child_expressions: Vec<String> = inner_nodes
.iter()
.map(|child| child.function_str.clone())
.collect();
let args_str = child_expressions.join(", ");
let function_str = format!("{}({})", op, args_str);

let inner_boxed_nodes = inner_nodes.into_iter().map(Box::new).collect();

BmaFnNode {
function_str,
height: max_height + 1,
expression_tree: Expression::Aggregation(op, inner_boxed_nodes),
}
}
}

impl BmaFnNode {
pub fn as_str(&self) -> &str {
self.function_str.as_str()
}
}

impl fmt::Display for BmaFnNode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.function_str)
}
}
70 changes: 70 additions & 0 deletions src/update_fn/enums.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use serde::{Deserialize, Serialize};
use std::fmt;

#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum Literal {
Int(i32),
Str(String),
}

impl fmt::Display for Literal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Literal::Int(value) => write!(f, "{}", value),
Literal::Str(value) => write!(f, "{}", value),
}
}
}

#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum ArithOp {
Add,
Minus,
Times,
Div,
}

impl fmt::Display for ArithOp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ArithOp::Add => write!(f, "+"),
ArithOp::Minus => write!(f, "-"),
ArithOp::Times => write!(f, "*"),
ArithOp::Div => write!(f, "/"),
}
}
}

#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum UnaryOp {
Ceil,
Floor,
Abs,
}

impl fmt::Display for UnaryOp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
UnaryOp::Ceil => write!(f, "ceil"),
UnaryOp::Floor => write!(f, "floor"),
UnaryOp::Abs => write!(f, "abs"),
}
}
}

#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum AggregateOp {
Min,
Max,
Avg,
}

impl fmt::Display for AggregateOp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
AggregateOp::Min => write!(f, "min"),
AggregateOp::Max => write!(f, "max"),
AggregateOp::Avg => write!(f, "avg"),
}
}
}
4 changes: 4 additions & 0 deletions src/update_fn/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pub mod bma_fn_tree;
mod enums;
mod parser;
mod tokenizer;
1 change: 1 addition & 0 deletions src/update_fn/parser.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// todo
13 changes: 13 additions & 0 deletions src/update_fn/tokenizer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use crate::update_fn::enums::{AggregateOp, ArithOp, Literal, UnaryOp};

/// Enum of all possible tokens occurring in a BMA function string.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum BmaFnToken {
Atomic(Literal),
Unary(UnaryOp),
Binary(ArithOp),
Aggregate(AggregateOp, Vec<BmaFnToken>),
TokenList(Vec<BmaFnToken>),
}

// todo

0 comments on commit 41eeb37

Please sign in to comment.