use super::super::types::OptLevel;
use super::super::Session;
use super::super::SessionBuilder;
use crate::graph::{Attributes, Graph, Node, OpKind};
use crate::tensor::Tensor;
use std::collections::HashMap;
#[test]
fn test_phase_f_execute_into_slots_relu() {
let node = Node {
op: OpKind::Relu,
name: "relu_slot".to_string(),
inputs: vec!["x".to_string()],
outputs: vec!["y".to_string()],
attrs: Attributes::default(),
};
let graph = Graph {
nodes: vec![node],
input_names: vec!["x".to_string()],
output_names: vec!["y".to_string()],
..Default::default()
};
let session = SessionBuilder::new()
.with_optimization_level(OptLevel::None)
.with_memory_pool(true)
.build_from_graph(graph, HashMap::new())
.expect("build session for Phase F test");
let input = Tensor::new(vec![-3.0, -1.0, 0.0, 2.0, 5.0], vec![1, 5]);
let result = session.run_one("x", input).expect("run Phase F relu");
let y = result.get("y").expect("output y");
assert_eq!(y.data, vec![0.0, 0.0, 0.0, 2.0, 5.0]);
assert_eq!(y.shape, vec![1, 5]);
}
#[test]
fn test_io_binding_take_put_helpers() {
use crate::IoBinding;
let mut binding = IoBinding::new();
let t = Tensor::new(vec![1.0, 2.0], vec![1, 2]);
binding.bind_output("out", t.clone());
let taken = binding.take_output_buffer("out");
assert!(taken.is_some());
assert_eq!(taken.as_ref().map(|t| &t.data), Some(&t.data));
assert!(binding.take_output_buffer("out").is_none());
binding.put_output_buffer("out".to_string(), t.clone());
assert!(binding.get_output("out").is_some());
}
#[test]
fn test_run_with_binding_uses_new_helpers() {
use crate::IoBinding;
let node = Node {
op: OpKind::Relu,
name: "relu_binding".to_string(),
inputs: vec!["x".to_string()],
outputs: vec!["y".to_string()],
attrs: Attributes::default(),
};
let graph = Graph {
nodes: vec![node],
input_names: vec!["x".to_string()],
output_names: vec!["y".to_string()],
..Default::default()
};
let session = SessionBuilder::new()
.with_optimization_level(OptLevel::None)
.build_from_graph(graph, HashMap::new())
.expect("build");
let mut binding = IoBinding::new();
binding.bind_input("x", Tensor::new(vec![-1.0, 3.0, -2.0], vec![1, 3]));
binding.bind_output("y", Tensor::new(vec![0.0; 3], vec![1, 3]));
session
.run_with_binding(&mut binding)
.expect("run_with_binding");
let y = binding.get_output("y").expect("output");
assert_eq!(y.data, vec![0.0, 3.0, 0.0]);
}
fn single_op_pooled_session(op: OpKind, input_name: &str, output_name: &str) -> Session {
let node = Node {
name: format!("{:?}_slot_test", op),
op,
inputs: vec![input_name.to_string()],
outputs: vec![output_name.to_string()],
attrs: Attributes::default(),
};
let graph = Graph {
nodes: vec![node],
input_names: vec![input_name.to_string()],
output_names: vec![output_name.to_string()],
..Default::default()
};
SessionBuilder::new()
.with_optimization_level(OptLevel::None)
.with_memory_pool(true)
.build_from_graph(graph, HashMap::new())
.expect("build single-op pooled session")
}
fn binary_op_pooled_session(
op: OpKind,
input_a: &str,
input_b: &str,
output_name: &str,
) -> Session {
let node = Node {
name: format!("{:?}_slot_test", op),
op,
inputs: vec![input_a.to_string(), input_b.to_string()],
outputs: vec![output_name.to_string()],
attrs: Attributes::default(),
};
let graph = Graph {
nodes: vec![node],
input_names: vec![input_a.to_string()],
output_names: vec![output_name.to_string()],
..Default::default()
};
let mut weights = HashMap::new();
weights.insert(
input_b.to_string(),
Tensor::new(vec![1.0, 2.0, 3.0], vec![3]),
);
SessionBuilder::new()
.with_optimization_level(OptLevel::None)
.with_memory_pool(true)
.build_from_graph(graph, weights)
.expect("build binary-op pooled session")
}
#[test]
fn test_phase_f_execute_into_slots_sigmoid() {
let session = single_op_pooled_session(OpKind::Sigmoid, "x", "y");
let input = Tensor::new(vec![0.0f32, 2.0, -2.0], vec![3]);
let result = session.run_one("x", input).expect("run Phase F sigmoid");
let y = result.get("y").expect("output y");
assert_eq!(y.shape, vec![3]);
assert!((y.data[0] - 0.5f32).abs() < 1e-5, "sigmoid(0) ≈ 0.5");
assert!(
(y.data[1] - 0.880_797f32).abs() < 1e-4,
"sigmoid(2) ≈ 0.8808"
);
for &v in &y.data {
assert!(
(0.0..=1.0).contains(&v),
"sigmoid output must be in [0, 1], got {v}"
);
}
}
#[test]
fn test_phase_f_execute_into_slots_tanh() {
let session = single_op_pooled_session(OpKind::Tanh, "x", "y");
let input = Tensor::new(vec![0.0f32, 1.0, -1.0], vec![3]);
let result = session.run_one("x", input).expect("run Phase F tanh");
let y = result.get("y").expect("output y");
assert_eq!(y.shape, vec![3]);
assert!((y.data[0] - 0.0f32).abs() < 1e-6, "tanh(0) = 0");
assert!((y.data[1] - 0.761_594f32).abs() < 1e-4, "tanh(1) ≈ 0.7616");
assert!(
(y.data[2] + 0.761_594f32).abs() < 1e-4,
"tanh(-1) ≈ -0.7616"
);
}
#[test]
fn test_phase_f_execute_into_slots_identity() {
let session = single_op_pooled_session(OpKind::Identity, "x", "y");
let input = Tensor::new(vec![10.0f32, 20.0, 30.0, 40.0], vec![2, 2]);
let result = session
.run_one("x", input.clone())
.expect("run Phase F identity");
let y = result.get("y").expect("output y");
assert_eq!(y.data, input.data);
assert_eq!(y.shape, vec![2, 2]);
}
#[test]
fn test_phase_f_execute_into_slots_add() {
let session = binary_op_pooled_session(OpKind::Add, "x", "w", "y");
let input = Tensor::new(vec![1.0f32, 2.0, 3.0], vec![3]);
let result = session.run_one("x", input).expect("run Phase F add");
let y = result.get("y").expect("output y");
assert_eq!(y.data, vec![2.0, 4.0, 6.0]);
assert_eq!(y.shape, vec![3]);
}
#[test]
fn test_phase_f_execute_into_slots_mul() {
let session = binary_op_pooled_session(OpKind::Mul, "x", "w", "y");
let input = Tensor::new(vec![2.0f32, 3.0, 4.0], vec![3]);
let result = session.run_one("x", input).expect("run Phase F mul");
let y = result.get("y").expect("output y");
assert_eq!(y.data, vec![2.0, 6.0, 12.0]);
}
#[test]
fn test_phase_f_execute_into_slots_abs() {
let session = single_op_pooled_session(OpKind::Abs, "x", "y");
let input = Tensor::new(vec![-3.0f32, 0.0, 4.0, -7.5], vec![4]);
let result = session.run_one("x", input).expect("run Phase F abs");
let y = result.get("y").expect("output y");
assert_eq!(y.data, vec![3.0, 0.0, 4.0, 7.5]);
}
#[test]
fn test_phase_f_execute_into_slots_exp() {
let session = single_op_pooled_session(OpKind::Exp, "x", "y");
let input = Tensor::new(vec![0.0f32, 1.0, -1.0], vec![3]);
let result = session.run_one("x", input).expect("run Phase F exp");
let y = result.get("y").expect("output y");
assert_eq!(y.shape, vec![3]);
assert!(
(y.data[0] - 1.0f32).abs() < 1e-6,
"exp(0) = 1, got {}",
y.data[0]
);
assert!((y.data[1] - std::f32::consts::E).abs() < 1e-5, "exp(1) ≈ e");
assert!(
(y.data[2] - 1.0 / std::f32::consts::E).abs() < 1e-5,
"exp(-1) ≈ 1/e"
);
}
#[test]
fn test_phase_f_slot_shape_mismatch_reallocates() {
let session = single_op_pooled_session(OpKind::Relu, "x", "y");
let large_data: Vec<f32> = (0..1000).map(|i| i as f32 - 500.0).collect();
let input = Tensor::new(large_data, vec![100, 10]);
let result = session
.run_one("x", input)
.expect("run Phase F slot mismatch");
let y = result.get("y").expect("output y");
assert_eq!(y.shape, vec![100, 10]);
for (i, &v) in y.data.iter().enumerate() {
let original = i as f32 - 500.0;
let expected = if original < 0.0 { 0.0 } else { original };
assert!(
(v - expected).abs() < 1e-6,
"relu mismatch at index {i}: got {v}, expected {expected}"
);
}
}
#[test]
fn test_phase_f_slot_chain_relu_sigmoid() {
let relu = Node {
op: OpKind::Relu,
name: "relu".to_string(),
inputs: vec!["x".to_string()],
outputs: vec!["mid".to_string()],
attrs: Attributes::default(),
};
let sigmoid = Node {
op: OpKind::Sigmoid,
name: "sigmoid".to_string(),
inputs: vec!["mid".to_string()],
outputs: vec!["y".to_string()],
attrs: Attributes::default(),
};
let graph = Graph {
nodes: vec![relu, sigmoid],
input_names: vec!["x".to_string()],
output_names: vec!["y".to_string()],
..Default::default()
};
let session = SessionBuilder::new()
.with_optimization_level(OptLevel::None)
.with_memory_pool(true)
.build_from_graph(graph, HashMap::new())
.expect("build relu→sigmoid chain session");
let input = Tensor::new(vec![-2.0f32, 0.0, 2.0], vec![3]);
let result = session.run_one("x", input).expect("run Phase F chain");
let y = result.get("y").expect("output y");
assert_eq!(y.shape, vec![3]);
assert!((y.data[0] - 0.5f32).abs() < 1e-5, "sigmoid(relu(-2)) ≈ 0.5");
assert!((y.data[1] - 0.5f32).abs() < 1e-5, "sigmoid(relu(0)) ≈ 0.5");
assert!(
(y.data[2] - 0.880_797f32).abs() < 1e-4,
"sigmoid(relu(2)) ≈ 0.8808"
);
}
#[test]
fn test_phase_f_slot_path_profiling() {
let session = SessionBuilder::new()
.with_optimization_level(OptLevel::None)
.with_memory_pool(true)
.with_profiling()
.build_from_graph(
Graph {
nodes: vec![Node {
op: OpKind::Relu,
name: "relu_profiled".to_string(),
inputs: vec!["x".to_string()],
outputs: vec!["y".to_string()],
attrs: Attributes::default(),
}],
input_names: vec!["x".to_string()],
output_names: vec!["y".to_string()],
..Default::default()
},
HashMap::new(),
)
.expect("build profiled slot session");
let input = Tensor::new(vec![-1.0f32, 2.0, -3.0], vec![3]);
session.run_one("x", input).expect("run");
let profiles = session.profiling_results().expect("profiling enabled");
assert!(!profiles.is_empty(), "profiles must not be empty after run");
let relu_profile = profiles
.iter()
.find(|p| p.node_name == "relu_profiled")
.expect("relu_profiled must appear in profiles");
assert!(
!relu_profile.op_type.is_empty(),
"op_type must be non-empty"
);
}