Skip to content

Commit

Permalink
Allow nested calls to uninterpreted functions (#52)
Browse files Browse the repository at this point in the history
* Remove old deprecated code.

* Add initial support for nested function calls.

* A new, crazier, but more comprehensive inlining mechanism.

* Resolve solver translation issue.

* New, more reasonable semantics for `BooleanNetwork::infer_valid_graph`.

* Extend the new semantics to `inline_constants` and `inline_inputs`.

* Handle inlining edge case with eliminated parameters.
  • Loading branch information
daemontus authored Dec 12, 2023
1 parent 354cd36 commit 60ea437
Show file tree
Hide file tree
Showing 37 changed files with 1,277 additions and 2,149 deletions.
17 changes: 13 additions & 4 deletions src/_aeon_parser/_from_string_for_boolean_network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ impl TryFrom<&str> for BooleanNetwork {
variable_names.insert(reg.regulator.clone());
variable_names.insert(reg.target.clone());
}
for (name, _) in &update_functions {
variable_names.insert(name.clone());
}
let mut variable_names: Vec<String> = variable_names.into_iter().collect();
variable_names.sort();

Expand Down Expand Up @@ -113,7 +116,10 @@ mod tests {
Box::new(FnUpdate::Var(VariableId(0))),
Box::new(FnUpdate::Binary(
Imp,
Box::new(FnUpdate::Param(ParameterId(1), vec![VariableId(2)])),
Box::new(FnUpdate::Param(
ParameterId(1),
vec![FnUpdate::Var(VariableId(2))],
)),
Box::new(FnUpdate::Binary(
Or,
Box::new(FnUpdate::Var(VariableId(2))),
Expand All @@ -124,18 +130,21 @@ mod tests {

let f2 = FnUpdate::Binary(
Iff,
Box::new(FnUpdate::Param(ParameterId(1), vec![VariableId(0)])),
Box::new(FnUpdate::Param(
ParameterId(1),
vec![FnUpdate::Var(VariableId(0))],
)),
Box::new(FnUpdate::Param(
ParameterId(2),
vec![VariableId(0), VariableId(0)],
vec![FnUpdate::Var(VariableId(0)), FnUpdate::Var(VariableId(0))],
)),
);

let f3 = FnUpdate::Binary(
Imp,
Box::new(FnUpdate::Param(
ParameterId(2),
vec![VariableId(1), VariableId(1)],
vec![FnUpdate::Var(VariableId(1)), FnUpdate::Var(VariableId(1))],
)),
Box::new(FnUpdate::Not(Box::new(FnUpdate::Binary(
Xor,
Expand Down
31 changes: 13 additions & 18 deletions src/_aeon_parser/_from_string_for_fn_update_temp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,29 +203,24 @@ fn terminal(data: &[Token]) -> Result<Box<FnUpdateTemp>, String> {
}
}

/// **(internal)** Parse a list of function arguments. All arguments must be names separated
/// **(internal)** Parse a list of function arguments. All arguments must be expressions separated
/// by commas.
fn read_args(data: &[Token]) -> Result<Vec<String>, String> {
///
/// Note that commas *have to* separate individual arguments, because any comma which is a part
/// of a "lower level" function call has to be enclosed in parentheses.
fn read_args(data: &[Token]) -> Result<Vec<FnUpdateTemp>, String> {
if data.is_empty() {
return Ok(Vec::new());
}
let mut result = Vec::new();
let mut i = 0;
while let Token::Name(name) = &data[i] {
result.push(name.clone());
i += 1;
if data.len() == i {
return Ok(result);
}
if data[i] != Token::Comma {
return Err(format!("Expected ',', found {:?}.", data[i]));
}
i += 1;
if data.len() == i {
return Err("Unexpected ',' at the end of an argument list.".to_string());
for arg in data.split(|it| *it == Token::Comma) {
if arg.is_empty() {
return Err("Found empty function argument.".to_string());
}
let arg = parse_update_function(arg)?;
result.push(*arg);
}
Err(format!("Unexpected token {:?} in argument list.", data[i]))
Ok(result)
}

#[cfg(test)]
Expand All @@ -245,6 +240,8 @@ mod tests {
"(a => b)",
"(a <=> b)",
"(a <=> !(f(a, b) => (c ^ d)))",
"f(a, f(b), c)",
"f((a & c))",
];
for str in inputs {
assert_eq!(str, format!("{}", FnUpdateTemp::try_from(str).unwrap()))
Expand Down Expand Up @@ -292,9 +289,7 @@ mod tests {
fn test_malformed_args() {
assert!(FnUpdateTemp::try_from("f(a b c)").is_err());
assert!(FnUpdateTemp::try_from("f(a, b, c,)").is_err());
assert!(FnUpdateTemp::try_from("f(a & c)").is_err());
assert!(FnUpdateTemp::try_from("f(a, & c)").is_err());
assert!(FnUpdateTemp::try_from("f(a, f(b), c)").is_err());
}

#[test]
Expand Down
19 changes: 15 additions & 4 deletions src/_aeon_parser/_impl_fn_update_temp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,14 @@ impl FnUpdateTemp {
r.unknown_variables_to_parameters(rg),
),
Not(inner) => Not(inner.unknown_variables_to_parameters(rg)),
Param(name, args) => Param(name, args),
Param(name, args) => {
let args: Vec<FnUpdateTemp> = args
.into_iter()
.map(|it| *it.unknown_variables_to_parameters(rg))
.collect();

Param(name, args)
}
Var(name) => {
if rg.find_variable(&name).is_some() {
Var(name)
Expand All @@ -43,6 +50,10 @@ impl FnUpdateTemp {
Param(name, args) => {
let arity = u32::try_from(args.len()).unwrap();
result.insert(Parameter::new(name, arity));

for arg in args {
arg.dump_parameters(result);
}
}
}
}
Expand All @@ -61,7 +72,7 @@ impl FnUpdateTemp {
Const(_) => {}
Param(_, args) => {
for arg in args {
result.insert(arg.clone());
arg.dump_variables(result);
}
}
}
Expand All @@ -82,7 +93,7 @@ impl FnUpdateTemp {
Self::check_parameter_arity(&bn[parameter_id], &args)?;
let mut arguments = Vec::with_capacity(args.len());
for arg in args {
arguments.push(Self::get_variable(bn, &arg)?);
arguments.push(*arg.into_fn_update(bn)?);
}
FnUpdate::Param(parameter_id, arguments)
}
Expand All @@ -106,7 +117,7 @@ impl FnUpdateTemp {

/// **(internal)** Generate an error message if the given `parameter` does not have
/// arity matching the given `args` list.
fn check_parameter_arity(parameter: &Parameter, args: &[String]) -> Result<(), String> {
fn check_parameter_arity(parameter: &Parameter, args: &[FnUpdateTemp]) -> Result<(), String> {
if parameter.get_arity() != u32::try_from(args.len()).unwrap() {
Err(format!(
"`{}` has arity {}, but is used with {} arguments.",
Expand Down
2 changes: 1 addition & 1 deletion src/_aeon_parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ pub(crate) struct RegulationTemp {
pub(crate) enum FnUpdateTemp {
Const(bool),
Var(String),
Param(String, Vec<String>),
Param(String, Vec<FnUpdateTemp>),
Not(Box<FnUpdateTemp>),
Binary(BinaryOp, Box<FnUpdateTemp>, Box<FnUpdateTemp>),
}
Loading

0 comments on commit 60ea437

Please sign in to comment.