mod common;
use common::compile_fixture;
#[test]
fn test_balanced_integrator() {
let result = compile_fixture("integrator", "Integrator").unwrap();
assert!(result.is_balanced(), "Integrator should be balanced");
assert!(result.balance_status().contains("balanced"));
assert_eq!(result.balance.num_equations, 1);
assert_eq!(result.balance.num_unknowns, 1);
assert_eq!(result.balance.num_states, 1);
}
#[test]
fn test_balanced_bouncing_ball() {
let result = compile_fixture("bouncing_ball", "BouncingBall").unwrap();
assert!(result.is_balanced(), "BouncingBall should be balanced");
assert_eq!(result.balance.num_states, 2);
}
#[test]
fn test_over_determined_model() {
let result = compile_fixture("unbalanced_overdetermined", "UnbalancedOverdetermined").unwrap();
assert!(
!result.is_balanced(),
"Over-determined model should not be balanced"
);
assert!(result.balance_status().contains("over-determined"));
assert!(result.balance.num_equations > result.balance.num_unknowns);
}
#[test]
fn test_under_determined_model() {
let result =
compile_fixture("unbalanced_underdetermined", "UnbalancedUnderdetermined").unwrap();
assert!(
!result.is_balanced(),
"Under-determined model should not be balanced"
);
assert!(result.balance_status().contains("under-determined"));
assert!(result.balance.num_unknowns > result.balance.num_equations);
}
#[test]
fn test_balance_difference() {
let result = compile_fixture("unbalanced_overdetermined", "UnbalancedOverdetermined").unwrap();
let diff = result.balance.difference();
assert!(
diff > 0,
"Over-determined model should have positive difference"
);
let result =
compile_fixture("unbalanced_underdetermined", "UnbalancedUnderdetermined").unwrap();
let diff = result.balance.difference();
assert!(
diff < 0,
"Under-determined model should have negative difference"
);
}
#[test]
fn test_type_causality_propagation() {
let result = compile_fixture("type_causality", "Der").unwrap();
assert!(
result.is_balanced(),
"Der block should be balanced when type causality is applied: {} equations, {} unknowns, {} inputs",
result.balance.num_equations,
result.balance.num_unknowns,
result.balance.num_inputs
);
assert_eq!(result.balance.num_equations, 1, "Should have 1 equation");
assert_eq!(result.balance.num_unknowns, 1, "Should have 1 unknown (y)");
assert_eq!(result.balance.num_inputs, 1, "Should have 1 input (u)");
}
#[test]
fn test_integrator_variants_balance() {
let result = compile_fixture("integrator_simple", "SimpleIntegrator").unwrap();
println!(
"SimpleIntegrator: {} eq, {} unk, {} inputs, {} states",
result.balance.num_equations,
result.balance.num_unknowns,
result.balance.num_inputs,
result.balance.num_states
);
assert!(
result.is_balanced(),
"SimpleIntegrator should be balanced: {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
let result = compile_fixture("integrator_simple", "IntegratorWithProtected").unwrap();
println!(
"IntegratorWithProtected: {} eq, {} unk, {} inputs, {} states",
result.balance.num_equations,
result.balance.num_unknowns,
result.balance.num_inputs,
result.balance.num_states
);
assert!(
result.is_balanced(),
"IntegratorWithProtected should be balanced: {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
let result = compile_fixture("integrator_simple", "IntegratorWithIf").unwrap();
println!(
"IntegratorWithIf: {} eq, {} unk, {} inputs, {} states",
result.balance.num_equations,
result.balance.num_unknowns,
result.balance.num_inputs,
result.balance.num_states
);
assert!(
result.is_balanced(),
"IntegratorWithIf should be balanced: {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
}
#[test]
fn test_array_balance() {
let result = compile_fixture("array_balance", "ArrayBalance.FixedArrayState").unwrap();
println!(
"FixedArrayState: {} eq, {} unk, {} states",
result.balance.num_equations, result.balance.num_unknowns, result.balance.num_states
);
assert!(
result.is_balanced(),
"FixedArrayState should be balanced: {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
assert_eq!(result.balance.num_states, 3, "Should have 3 states");
let result = compile_fixture("array_balance", "ArrayBalance.ForLoopArrayState").unwrap();
println!(
"ForLoopArrayState: {} eq, {} unk, {} states",
result.balance.num_equations, result.balance.num_unknowns, result.balance.num_states
);
assert!(
result.is_balanced(),
"ForLoopArrayState should be balanced: {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
assert_eq!(
result.balance.num_states, 3,
"Should have 3 states from for loop"
);
let result = compile_fixture("array_balance", "ArrayBalance.VectorEquation").unwrap();
println!(
"VectorEquation: {} eq, {} unk, {} states, {} algebraic",
result.balance.num_equations,
result.balance.num_unknowns,
result.balance.num_states,
result.balance.num_algebraic
);
assert!(
result.is_balanced(),
"VectorEquation should be balanced: {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
assert_eq!(result.balance.num_states, 3, "Should have 3 states (y[3])");
assert_eq!(
result.balance.num_algebraic, 3,
"Should have 3 algebraic (x[3])"
);
assert_eq!(
result.balance.num_equations, 6,
"Should have 6 equations (2 vector eqs * 3)"
);
}
#[test]
fn test_conditional_components() {
let result = compile_fixture(
"conditional_components",
"ConditionalComponents.SimpleNoConditional",
)
.unwrap();
println!(
"SimpleNoConditional: {} eq, {} unk, {} inputs",
result.balance.num_equations, result.balance.num_unknowns, result.balance.num_inputs
);
assert!(
result.is_balanced(),
"SimpleNoConditional should be balanced: {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
let result = compile_fixture(
"conditional_components",
"ConditionalComponents.ConditionalInputFalse",
)
.unwrap();
println!(
"ConditionalInputFalse: {} eq, {} unk, {} inputs",
result.balance.num_equations, result.balance.num_unknowns, result.balance.num_inputs
);
assert!(
result.is_balanced(),
"ConditionalInputFalse should be balanced (reset filtered out): {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
let result = compile_fixture(
"conditional_components",
"ConditionalComponents.ConditionalInputTrue",
)
.unwrap();
println!(
"ConditionalInputTrue: {} eq, {} unk, {} inputs",
result.balance.num_equations, result.balance.num_unknowns, result.balance.num_inputs
);
assert_eq!(
result.balance.num_inputs, 2,
"ConditionalInputTrue should have 2 inputs (u and reset)"
);
let result = compile_fixture(
"conditional_components",
"ConditionalComponents.MultipleConditionalsFalse",
)
.unwrap();
println!(
"MultipleConditionalsFalse: {} eq, {} unk, {} inputs",
result.balance.num_equations, result.balance.num_unknowns, result.balance.num_inputs
);
assert!(
result.is_balanced(),
"MultipleConditionalsFalse should be balanced (both conditionals filtered): {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
let result = compile_fixture(
"conditional_components",
"ConditionalComponents.ConditionalWithAnd",
)
.unwrap();
println!(
"ConditionalWithAnd: {} eq, {} unk, {} inputs",
result.balance.num_equations, result.balance.num_unknowns, result.balance.num_inputs
);
assert!(
result.is_balanced(),
"ConditionalWithAnd should be balanced (AND condition evaluates to false): {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
}
#[test]
fn test_parameter_arrays() {
let result =
compile_fixture("parameter_arrays", "ParameterArrays.SimpleParameterForLoop").unwrap();
println!(
"SimpleParameterForLoop: {} eq, {} unk, {} states",
result.balance.num_equations, result.balance.num_unknowns, result.balance.num_states
);
assert!(
result.is_balanced(),
"SimpleParameterForLoop should be balanced: {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
assert_eq!(result.balance.num_equations, 3, "Should have 3 equations");
assert_eq!(result.balance.num_unknowns, 3, "Should have 3 unknowns");
let result =
compile_fixture("parameter_arrays", "ParameterArrays.ParameterArithmetic").unwrap();
println!(
"ParameterArithmetic: {} eq, {} unk, {} states",
result.balance.num_equations, result.balance.num_unknowns, result.balance.num_states
);
assert!(
result.is_balanced(),
"ParameterArithmetic should be balanced: {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
assert_eq!(result.balance.num_equations, 4, "Should have 4 equations");
assert_eq!(result.balance.num_unknowns, 4, "Should have 4 unknowns");
let result = compile_fixture("parameter_arrays", "ParameterArrays.MultipleParameters").unwrap();
println!(
"MultipleParameters: {} eq, {} unk, {} states",
result.balance.num_equations, result.balance.num_unknowns, result.balance.num_states
);
assert!(
result.is_balanced(),
"MultipleParameters should be balanced: {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
assert_eq!(result.balance.num_equations, 5, "Should have 5 equations");
assert_eq!(result.balance.num_unknowns, 5, "Should have 5 unknowns");
let result = compile_fixture("parameter_arrays", "ParameterArrays.NestedForLoop").unwrap();
println!(
"NestedForLoop: {} eq, {} unk, {} states",
result.balance.num_equations, result.balance.num_unknowns, result.balance.num_states
);
assert!(
result.is_balanced(),
"NestedForLoop should be balanced: {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
assert_eq!(result.balance.num_equations, 4, "Should have 4 equations");
assert_eq!(result.balance.num_unknowns, 4, "Should have 4 unknowns");
let result = compile_fixture("parameter_arrays", "ParameterArrays.OuterWithInner").unwrap();
println!(
"OuterWithInner: {} eq, {} unk, {} states",
result.balance.num_equations, result.balance.num_unknowns, result.balance.num_states
);
assert!(
result.is_balanced(),
"OuterWithInner should be balanced: {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
assert_eq!(result.balance.num_equations, 2, "Should have 2 equations");
assert_eq!(result.balance.num_unknowns, 2, "Should have 2 unknowns");
}
#[test]
fn test_size_function() {
let result = compile_fixture("size_function", "SizeFunction.SimpleSizeFunction").unwrap();
println!(
"SimpleSizeFunction: {} eq, {} unk, {} states",
result.balance.num_equations, result.balance.num_unknowns, result.balance.num_states
);
assert!(
result.is_balanced(),
"SimpleSizeFunction should be balanced: {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
assert_eq!(result.balance.num_equations, 2, "Should have 2 equations");
assert_eq!(result.balance.num_unknowns, 2, "Should have 2 unknowns");
let result = compile_fixture("size_function", "SizeFunction.MultipleSizeCalls").unwrap();
println!(
"MultipleSizeCalls: {} eq, {} unk, {} states",
result.balance.num_equations, result.balance.num_unknowns, result.balance.num_states
);
assert!(
result.is_balanced(),
"MultipleSizeCalls should be balanced: {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
assert_eq!(result.balance.num_equations, 4, "Should have 4 equations");
assert_eq!(result.balance.num_unknowns, 4, "Should have 4 unknowns");
}
#[test]
fn test_comparison_operators() {
let result =
compile_fixture("comparison_operators", "ComparisonOperators.EqualityTrue").unwrap();
println!(
"EqualityTrue: {} eq, {} unk",
result.balance.num_equations, result.balance.num_unknowns
);
assert!(
result.is_balanced(),
"EqualityTrue should be balanced: {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
assert_eq!(result.balance.num_equations, 1, "Should have 1 equation");
let result =
compile_fixture("comparison_operators", "ComparisonOperators.EqualityFalse").unwrap();
println!(
"EqualityFalse: {} eq, {} unk",
result.balance.num_equations, result.balance.num_unknowns
);
assert!(
result.is_balanced(),
"EqualityFalse should be balanced: {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
assert_eq!(result.balance.num_equations, 1, "Should have 1 equation");
let result =
compile_fixture("comparison_operators", "ComparisonOperators.LessThanTrue").unwrap();
println!(
"LessThanTrue: {} eq, {} unk",
result.balance.num_equations, result.balance.num_unknowns
);
assert!(result.is_balanced());
assert_eq!(result.balance.num_equations, 1);
let result = compile_fixture(
"comparison_operators",
"ComparisonOperators.GreaterThanTrue",
)
.unwrap();
println!(
"GreaterThanTrue: {} eq, {} unk",
result.balance.num_equations, result.balance.num_unknowns
);
assert!(result.is_balanced());
assert_eq!(result.balance.num_equations, 1);
let result = compile_fixture(
"comparison_operators",
"ComparisonOperators.SizeComparisonTrue",
)
.unwrap();
println!(
"SizeComparisonTrue: {} eq, {} unk",
result.balance.num_equations, result.balance.num_unknowns
);
assert!(
result.is_balanced(),
"SizeComparisonTrue should be balanced: {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
assert_eq!(result.balance.num_equations, 1, "Should have 1 equation");
let result = compile_fixture(
"comparison_operators",
"ComparisonOperators.SizeComparisonFalse",
)
.unwrap();
println!(
"SizeComparisonFalse: {} eq, {} unk, {} states",
result.balance.num_equations, result.balance.num_unknowns, result.balance.num_states
);
assert!(
result.is_balanced(),
"SizeComparisonFalse should be balanced: {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
assert_eq!(result.balance.num_equations, 2, "Should have 2 equations");
assert_eq!(result.balance.num_unknowns, 2, "Should have 2 unknowns");
let result = compile_fixture(
"comparison_operators",
"ComparisonOperators.ProtectedParamTest",
)
.unwrap();
println!(
"ProtectedParamTest: {} eq, {} unk",
result.balance.num_equations, result.balance.num_unknowns
);
assert!(
result.is_balanced(),
"ProtectedParamTest should be balanced: {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
assert_eq!(result.balance.num_equations, 1, "Should have 1 equation");
let result = compile_fixture(
"comparison_operators",
"ComparisonOperators.TransferFunctionLike",
)
.unwrap();
println!(
"TransferFunctionLike: {} eq, {} unk, {} states, {} inputs",
result.balance.num_equations,
result.balance.num_unknowns,
result.balance.num_states,
result.balance.num_inputs
);
assert!(
result.is_balanced(),
"TransferFunctionLike should be balanced: {} eq, {} unk (expected 1 eq, 1 unk)",
result.balance.num_equations,
result.balance.num_unknowns
);
}
#[test]
fn test_binding_equations() {
let result = compile_fixture("binding_test", "BindingTest.SlewLike").unwrap();
println!(
"SlewLike: {} eq, {} unk, {} states, {} alg",
result.balance.num_equations,
result.balance.num_unknowns,
result.balance.num_states,
result.balance.num_algebraic
);
assert!(
result.is_balanced(),
"SlewLike should be balanced: {} eq, {} unk (expected 2 eq, 2 unk)",
result.balance.num_equations,
result.balance.num_unknowns
);
assert_eq!(result.balance.num_states, 1, "Should have 1 state (y)");
assert_eq!(
result.balance.num_algebraic, 1,
"Should have 1 algebraic (val)"
);
let result = compile_fixture("binding_test", "BindingTest.ExplicitEquation").unwrap();
println!(
"ExplicitEquation: {} eq, {} unk, {} states, {} alg",
result.balance.num_equations,
result.balance.num_unknowns,
result.balance.num_states,
result.balance.num_algebraic
);
assert!(
result.is_balanced(),
"ExplicitEquation should be balanced: {} eq, {} unk (expected 2 eq, 2 unk)",
result.balance.num_equations,
result.balance.num_unknowns
);
}
#[test]
fn test_nonlinear_blocks() {
let result = compile_fixture("nonlinear_blocks", "NonlinearBlocks.Limiter").unwrap();
println!(
"Limiter: {} eq, {} unk, {} states, {} alg, {} inputs",
result.balance.num_equations,
result.balance.num_unknowns,
result.balance.num_states,
result.balance.num_algebraic,
result.balance.num_inputs
);
assert!(
result.is_balanced(),
"Limiter should be balanced: {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
assert_eq!(result.balance.num_inputs, 1, "Should have 1 input (u)");
assert_eq!(
result.balance.num_algebraic, 2,
"Should have 2 algebraic (y, simplifiedExpr)"
);
let result = compile_fixture("nonlinear_blocks", "NonlinearBlocks.VariableLimiter").unwrap();
println!(
"VariableLimiter: {} eq, {} unk, {} states, {} alg, {} inputs",
result.balance.num_equations,
result.balance.num_unknowns,
result.balance.num_states,
result.balance.num_algebraic,
result.balance.num_inputs
);
assert!(
result.is_balanced(),
"VariableLimiter should be balanced: {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
assert_eq!(
result.balance.num_inputs, 3,
"Should have 3 inputs (u, limit1, limit2)"
);
let result = compile_fixture("nonlinear_blocks", "NonlinearBlocks.SlewRateLimiter").unwrap();
println!(
"SlewRateLimiter: {} eq, {} unk, {} states, {} alg, {} inputs",
result.balance.num_equations,
result.balance.num_unknowns,
result.balance.num_states,
result.balance.num_algebraic,
result.balance.num_inputs
);
assert!(
result.is_balanced(),
"SlewRateLimiter should be balanced: {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
assert_eq!(
result.balance.num_states, 1,
"Should have 1 state (y from der(y))"
);
assert_eq!(
result.balance.num_algebraic, 1,
"Should have 1 algebraic (val)"
);
let result = compile_fixture("nonlinear_blocks", "NonlinearBlocks.DeadZone").unwrap();
println!(
"DeadZone: {} eq, {} unk, {} states, {} alg, {} inputs",
result.balance.num_equations,
result.balance.num_unknowns,
result.balance.num_states,
result.balance.num_algebraic,
result.balance.num_inputs
);
assert!(
result.is_balanced(),
"DeadZone should be balanced: {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
assert_eq!(result.balance.num_equations, 1, "Should have 1 equation");
assert_eq!(result.balance.num_unknowns, 1, "Should have 1 unknown (y)");
}
#[test]
fn test_when_equations() {
let result = compile_fixture("when_equations", "WhenEquations.SimpleWhen").unwrap();
println!(
"SimpleWhen: {} eq, {} unk, {} states, {} alg, {} inputs",
result.balance.num_equations,
result.balance.num_unknowns,
result.balance.num_states,
result.balance.num_algebraic,
result.balance.num_inputs
);
assert!(
result.is_balanced(),
"SimpleWhen should be balanced: {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
assert_eq!(result.balance.num_states, 1, "Should have 1 state (x)");
let result = compile_fixture("when_equations", "WhenEquations.MultipleDiscreteWhen").unwrap();
println!(
"MultipleDiscreteWhen: {} eq, {} unk, {} states, {} alg",
result.balance.num_equations,
result.balance.num_unknowns,
result.balance.num_states,
result.balance.num_algebraic
);
assert!(
result.is_balanced(),
"MultipleDiscreteWhen should be balanced: {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
let result = compile_fixture("when_equations", "WhenEquations.WhenElsewhen").unwrap();
println!(
"WhenElsewhen: {} eq, {} unk",
result.balance.num_equations, result.balance.num_unknowns
);
assert!(
result.is_balanced(),
"WhenElsewhen should be balanced: {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
let result = compile_fixture("when_equations", "WhenEquations.ExtremaLike").unwrap();
println!(
"ExtremaLike: {} eq, {} unk, {} states, {} alg",
result.balance.num_equations,
result.balance.num_unknowns,
result.balance.num_states,
result.balance.num_algebraic
);
assert!(
result.is_balanced(),
"ExtremaLike should be balanced: {} eq, {} unk (expected 5 eq, 5 unk)",
result.balance.num_equations,
result.balance.num_unknowns
);
}
#[test]
fn test_connector_equations() {
let result = compile_fixture("connectors", "Connectors.SingleResistor");
match result {
Ok(res) => {
println!(
"SingleResistor: {} eq, {} unk, {} states, {} alg",
res.balance.num_equations,
res.balance.num_unknowns,
res.balance.num_states,
res.balance.num_algebraic
);
}
Err(e) => {
println!("SingleResistor compile error: {:?}", e);
}
}
let result = compile_fixture("connectors", "Connectors.TwoResistors");
match result {
Ok(res) => {
println!(
"TwoResistors: {} eq, {} unk, {} states, {} alg",
res.balance.num_equations,
res.balance.num_unknowns,
res.balance.num_states,
res.balance.num_algebraic
);
}
Err(e) => {
println!("TwoResistors compile error: {:?}", e);
}
}
}
#[test]
fn test_causal_blocks() {
let result = compile_fixture("connectors", "Connectors.JustOutput");
match result {
Ok(res) => {
println!(
"JustOutput: {} eq, {} unk, {} inputs",
res.balance.num_equations, res.balance.num_unknowns, res.balance.num_inputs
);
assert!(
res.is_balanced(),
"JustOutput should be balanced: {} eq, {} unk",
res.balance.num_equations,
res.balance.num_unknowns
);
}
Err(e) => {
println!("JustOutput compile error: {:?}", e);
}
}
let result = compile_fixture("connectors", "Connectors.JustOutputAlias");
match result {
Ok(res) => {
println!(
"JustOutputAlias: {} eq, {} unk, {} inputs",
res.balance.num_equations, res.balance.num_unknowns, res.balance.num_inputs
);
assert!(
res.is_balanced(),
"JustOutputAlias should be balanced: {} eq, {} unk",
res.balance.num_equations,
res.balance.num_unknowns
);
}
Err(e) => {
println!("JustOutputAlias compile error: {:?}", e);
}
}
let result = compile_fixture("connectors", "Connectors.SimpleGain");
match result {
Ok(res) => {
println!(
"SimpleGain: {} eq, {} unk, {} inputs",
res.balance.num_equations, res.balance.num_unknowns, res.balance.num_inputs
);
assert!(
res.is_balanced(),
"SimpleGain should be balanced: {} eq, {} unk",
res.balance.num_equations,
res.balance.num_unknowns
);
assert_eq!(res.balance.num_inputs, 1, "Should have 1 input (u)");
}
Err(e) => {
println!("SimpleGain compile error: {:?}", e);
}
}
let result = compile_fixture("connectors", "Connectors.VectorizedGain");
match result {
Ok(res) => {
println!(
"VectorizedGain: {} eq, {} unk, {} inputs (n=2)",
res.balance.num_equations, res.balance.num_unknowns, res.balance.num_inputs
);
assert!(
res.is_balanced(),
"VectorizedGain should be balanced: {} eq, {} unk",
res.balance.num_equations,
res.balance.num_unknowns
);
}
Err(e) => {
println!("VectorizedGain compile error: {:?}", e);
}
}
let result = compile_fixture("connectors", "Connectors.EmptyArrayPassthrough");
match result {
Ok(res) => {
println!(
"EmptyArrayPassthrough: {} eq, {} unk, {} inputs (n=0)",
res.balance.num_equations, res.balance.num_unknowns, res.balance.num_inputs
);
assert!(
res.is_balanced(),
"EmptyArrayPassthrough should be balanced: {} eq, {} unk",
res.balance.num_equations,
res.balance.num_unknowns
);
assert_eq!(
res.balance.num_equations, 0,
"Empty array should have 0 equations"
);
assert_eq!(
res.balance.num_unknowns, 0,
"Empty array should have 0 unknowns"
);
}
Err(e) => {
panic!("EmptyArrayPassthrough compile error: {:?}", e);
}
}
}
#[test]
fn test_algorithm_sections() {
let result = compile_fixture("algorithms", "Algorithms.SimpleAlgorithm");
match result {
Ok(res) => {
println!(
"SimpleAlgorithm: {} eq, {} unk, {} inputs",
res.balance.num_equations, res.balance.num_unknowns, res.balance.num_inputs
);
assert!(
res.is_balanced(),
"SimpleAlgorithm should be balanced: {} eq, {} unk",
res.balance.num_equations,
res.balance.num_unknowns
);
assert_eq!(
res.balance.num_equations, 1,
"Should have 1 equation from algorithm"
);
assert_eq!(res.balance.num_unknowns, 1, "Should have 1 unknown (y)");
}
Err(e) => {
panic!("SimpleAlgorithm compile error: {:?}", e);
}
}
let result = compile_fixture("algorithms", "Algorithms.MultipleOutputs");
match result {
Ok(res) => {
println!(
"MultipleOutputs: {} eq, {} unk, {} inputs",
res.balance.num_equations, res.balance.num_unknowns, res.balance.num_inputs
);
assert!(
res.is_balanced(),
"MultipleOutputs should be balanced: {} eq, {} unk",
res.balance.num_equations,
res.balance.num_unknowns
);
assert_eq!(
res.balance.num_equations, 2,
"Should have 2 equations from algorithm"
);
}
Err(e) => {
panic!("MultipleOutputs compile error: {:?}", e);
}
}
let result = compile_fixture("algorithms", "Algorithms.AlgorithmWithIf");
match result {
Ok(res) => {
println!(
"AlgorithmWithIf: {} eq, {} unk",
res.balance.num_equations, res.balance.num_unknowns
);
assert!(
res.is_balanced(),
"AlgorithmWithIf should be balanced: {} eq, {} unk",
res.balance.num_equations,
res.balance.num_unknowns
);
}
Err(e) => {
panic!("AlgorithmWithIf compile error: {:?}", e);
}
}
let result = compile_fixture("algorithms", "Algorithms.MixedEquationAlgorithm");
match result {
Ok(res) => {
println!(
"MixedEquationAlgorithm: {} eq, {} unk",
res.balance.num_equations, res.balance.num_unknowns
);
assert!(
res.is_balanced(),
"MixedEquationAlgorithm should be balanced: {} eq, {} unk",
res.balance.num_equations,
res.balance.num_unknowns
);
}
Err(e) => {
panic!("MixedEquationAlgorithm compile error: {:?}", e);
}
}
}
#[test]
fn test_complex_type_causality() {
let result = compile_fixture("complex_causality", "ComplexCausality.ComplexGain").unwrap();
assert!(
result.is_balanced(),
"ComplexGain should be balanced when causality is propagated: {} eq, {} unk, {} inputs",
result.balance.num_equations,
result.balance.num_unknowns,
result.balance.num_inputs
);
assert_eq!(
result.balance.num_inputs, 2,
"Should have 2 inputs (u.re, u.im)"
);
assert_eq!(
result.balance.num_unknowns, 2,
"Should have 2 unknowns (y.re, y.im)"
);
let result =
compile_fixture("complex_causality", "ComplexCausality.ComplexArrayInput").unwrap();
assert!(
result.is_balanced(),
"ComplexArrayInput should be balanced when array causality is propagated: {} eq, {} unk, {} inputs",
result.balance.num_equations,
result.balance.num_unknowns,
result.balance.num_inputs
);
assert_eq!(
result.balance.num_inputs, 6,
"Should have 6 inputs (u.re[3], u.im[3])"
);
assert_eq!(
result.balance.num_unknowns, 2,
"Should have 2 unknowns (y[2])"
);
let result = compile_fixture("complex_causality", "ComplexCausality.ComplexAdd").unwrap();
println!(
"ComplexAdd: {} eq, {} unk, {} inputs",
result.balance.num_equations, result.balance.num_unknowns, result.balance.num_inputs
);
assert!(
result.is_balanced(),
"ComplexAdd should be balanced when Complex binding equations are expanded: {} eq, {} unk, {} inputs",
result.balance.num_equations,
result.balance.num_unknowns,
result.balance.num_inputs
);
assert_eq!(
result.balance.num_inputs, 4,
"Should have 4 inputs (u1.re, u1.im, u2.re, u2.im)"
);
assert_eq!(result.balance.num_unknowns, 6, "Should have 6 unknowns");
assert_eq!(result.balance.num_equations, 6, "Should have 6 equations");
let result = compile_fixture(
"complex_causality",
"ComplexCausality.ComplexAddConditional",
)
.unwrap();
println!(
"ComplexAddConditional: {} eq, {} unk, {} inputs",
result.balance.num_equations, result.balance.num_unknowns, result.balance.num_inputs
);
assert!(
result.is_balanced(),
"ComplexAddConditional should be balanced: {} eq, {} unk, {} inputs",
result.balance.num_equations,
result.balance.num_unknowns,
result.balance.num_inputs
);
assert_eq!(result.balance.num_inputs, 4, "Should have 4 inputs");
assert_eq!(result.balance.num_unknowns, 6, "Should have 6 unknowns");
assert_eq!(result.balance.num_equations, 6, "Should have 6 equations");
let result =
compile_fixture("complex_causality", "ComplexCausality.BuiltinComplexAdd").unwrap();
println!(
"BuiltinComplexAdd: {} eq, {} unk, {} inputs",
result.balance.num_equations, result.balance.num_unknowns, result.balance.num_inputs
);
assert!(
result.is_balanced(),
"BuiltinComplexAdd should be balanced: {} eq, {} unk, {} inputs",
result.balance.num_equations,
result.balance.num_unknowns,
result.balance.num_inputs
);
assert_eq!(result.balance.num_inputs, 4, "Should have 4 inputs");
assert_eq!(result.balance.num_unknowns, 6, "Should have 6 unknowns");
assert_eq!(result.balance.num_equations, 6, "Should have 6 equations");
let result = compile_fixture(
"complex_causality",
"ComplexCausality.ParenthesizedComplexAdd",
)
.unwrap();
println!(
"ParenthesizedComplexAdd: {} eq, {} unk, {} inputs",
result.balance.num_equations, result.balance.num_unknowns, result.balance.num_inputs
);
assert!(
result.is_balanced(),
"ParenthesizedComplexAdd should be balanced: {} eq, {} unk, {} inputs",
result.balance.num_equations,
result.balance.num_unknowns,
result.balance.num_inputs
);
assert_eq!(result.balance.num_inputs, 4, "Should have 4 inputs");
assert_eq!(result.balance.num_unknowns, 6, "Should have 6 unknowns");
assert_eq!(result.balance.num_equations, 6, "Should have 6 equations");
let result = compile_fixture("complex_causality", "ComplexCausality.ConjComplexAdd").unwrap();
println!(
"ConjComplexAdd: {} eq, {} unk, {} inputs",
result.balance.num_equations, result.balance.num_unknowns, result.balance.num_inputs
);
assert!(
result.is_balanced(),
"ConjComplexAdd should be balanced: {} eq, {} unk, {} inputs",
result.balance.num_equations,
result.balance.num_unknowns,
result.balance.num_inputs
);
assert_eq!(result.balance.num_inputs, 4, "Should have 4 inputs");
assert_eq!(result.balance.num_unknowns, 6, "Should have 6 unknowns");
assert_eq!(result.balance.num_equations, 6, "Should have 6 equations");
}
#[test]
fn test_conditional_input_causality() {
let result = compile_fixture(
"conditional_input",
"ConditionalInput.ConditionalInputBlock",
)
.unwrap();
println!(
"ConditionalInputBlock: {} eq, {} unk, {} inputs",
result.balance.num_equations, result.balance.num_unknowns, result.balance.num_inputs
);
assert!(
result.is_balanced(),
"ConditionalInputBlock should be balanced when causality is propagated: {} eq, {} unk, {} inputs",
result.balance.num_equations,
result.balance.num_unknowns,
result.balance.num_inputs
);
assert_eq!(
result.balance.num_inputs, 1,
"Should have 1 input (numberPort)"
);
assert_eq!(
result.balance.num_unknowns, 1,
"Should have 1 unknown (showNumber)"
);
let result = compile_fixture(
"conditional_input",
"ConditionalInput.ConditionalInputBlockFalse",
)
.unwrap();
println!(
"ConditionalInputBlockFalse: {} eq, {} unk, {} inputs",
result.balance.num_equations, result.balance.num_unknowns, result.balance.num_inputs
);
assert!(
result.is_balanced(),
"ConditionalInputBlockFalse should be balanced: {} eq, {} unk, {} inputs",
result.balance.num_equations,
result.balance.num_unknowns,
result.balance.num_inputs
);
assert_eq!(
result.balance.num_inputs, 0,
"Should have 0 inputs (numberPort filtered out)"
);
assert_eq!(
result.balance.num_unknowns, 1,
"Should have 1 unknown (showNumber)"
);
}
#[test]
fn test_expression_blocks() {
let result =
compile_fixture("expression_blocks", "ExpressionBlocks.RealExpressionLike").unwrap();
println!(
"RealExpressionLike: {} eq, {} unk",
result.balance.num_equations, result.balance.num_unknowns
);
assert!(
result.is_balanced(),
"RealExpressionLike should be balanced: {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
assert_eq!(
result.balance.num_equations, 1,
"Should have 1 equation (from binding)"
);
assert_eq!(result.balance.num_unknowns, 1, "Should have 1 unknown (y)");
let result = compile_fixture(
"expression_blocks",
"ExpressionBlocks.RealExpressionNonDefault",
)
.unwrap();
println!(
"RealExpressionNonDefault: {} eq, {} unk",
result.balance.num_equations, result.balance.num_unknowns
);
assert!(
result.is_balanced(),
"RealExpressionNonDefault should be balanced: {} eq, {} unk",
result.balance.num_equations,
result.balance.num_unknowns
);
let result =
compile_fixture("expression_blocks", "ExpressionBlocks.OutputWithEquation").unwrap();
println!(
"OutputWithEquation: {} eq, {} unk (KNOWN ISSUE: should be 1 eq)",
result.balance.num_equations, result.balance.num_unknowns
);
assert_eq!(
result.balance.num_equations, 2,
"Currently 2 equations (needs fix)"
);
let result = compile_fixture("expression_blocks", "ExpressionBlocks.OutputNoBind").unwrap();
println!(
"OutputNoBind: {} eq, {} unk, {} ext conn",
result.balance.num_equations,
result.balance.num_unknowns,
result.balance.num_external_connectors
);
assert_eq!(
result.balance.status,
rumoca::dae::balance::BalanceStatus::Unbalanced,
"OutputNoBind should be Unbalanced (under-determined - missing equation for y)"
);
assert_eq!(result.balance.num_equations, 0, "Should have 0 equations");
assert_eq!(result.balance.num_unknowns, 1, "Should have 1 unknown (y)");
}
#[test]
fn test_demultiplex_pattern() {
let result = compile_fixture(
"demultiplex_balance",
"DemultiplexBalance.SimplePassthrough",
)
.unwrap();
println!(
"SimplePassthrough: {} eq, {} unk, {} inputs",
result.balance.num_equations, result.balance.num_unknowns, result.balance.num_inputs
);
assert!(
result.is_balanced(),
"SimplePassthrough should be balanced: {} eq, {} unk, {} inputs",
result.balance.num_equations,
result.balance.num_unknowns,
result.balance.num_inputs
);
assert_eq!(result.balance.num_equations, 1, "Should have 1 equation");
assert_eq!(result.balance.num_unknowns, 1, "Should have 1 unknown (y)");
assert_eq!(result.balance.num_inputs, 1, "Should have 1 input (u)");
let result = compile_fixture(
"demultiplex_balance",
"DemultiplexBalance.SimplePassthroughNormal",
)
.unwrap();
println!(
"SimplePassthroughNormal: {} eq, {} unk, {} inputs",
result.balance.num_equations, result.balance.num_unknowns, result.balance.num_inputs
);
assert!(
result.is_balanced(),
"SimplePassthroughNormal should be balanced: {} eq, {} unk, {} inputs",
result.balance.num_equations,
result.balance.num_unknowns,
result.balance.num_inputs
);
let result =
compile_fixture("demultiplex_balance", "DemultiplexBalance.DeMultiplex2Like").unwrap();
println!(
"DeMultiplex2Like: {} eq, {} unk, {} inputs",
result.balance.num_equations, result.balance.num_unknowns, result.balance.num_inputs
);
assert!(
result.is_balanced(),
"DeMultiplex2Like should be balanced: {} eq, {} unk, {} inputs",
result.balance.num_equations,
result.balance.num_unknowns,
result.balance.num_inputs
);
assert_eq!(result.balance.num_equations, 2, "Should have 2 equations");
assert_eq!(
result.balance.num_unknowns, 2,
"Should have 2 unknowns (y1[1], y2[1])"
);
assert_eq!(
result.balance.num_inputs, 2,
"Should have 2 inputs (u[1], u[2])"
);
let result = compile_fixture(
"demultiplex_balance",
"DemultiplexBalance.DeMultiplex2Explicit",
)
.unwrap();
println!(
"DeMultiplex2Explicit: {} eq, {} unk, {} inputs",
result.balance.num_equations, result.balance.num_unknowns, result.balance.num_inputs
);
assert!(
result.is_balanced(),
"DeMultiplex2Explicit should be balanced: {} eq, {} unk, {} inputs",
result.balance.num_equations,
result.balance.num_unknowns,
result.balance.num_inputs
);
assert_eq!(result.balance.num_equations, 2, "Should have 2 equations");
assert_eq!(result.balance.num_unknowns, 2, "Should have 2 unknowns");
assert_eq!(result.balance.num_inputs, 2, "Should have 2 inputs");
}