use tensorlogic_ir::{
serialization::{VersionedExpr, VersionedGraph},
EinsumGraph, EinsumNode, IrError, TLExpr, Term, FORMAT_VERSION,
};
fn main() -> Result<(), IrError> {
println!("=== TensorLogic IR: Serialization ===\n");
println!("1. Expression Serialization to JSON:");
let person = TLExpr::pred("Person", vec![Term::var("x")]);
let mortal = TLExpr::pred("Mortal", vec![Term::var("x")]);
let rule = TLExpr::imply(person, mortal);
let json = serde_json::to_string(&rule).expect("Failed to serialize to JSON");
println!(" Compact JSON:");
println!(" {}", json);
let pretty_json =
serde_json::to_string_pretty(&rule).expect("Failed to serialize to pretty JSON");
println!("\n Pretty JSON:");
println!("{}", pretty_json);
println!("\n2. Expression Deserialization from JSON:");
let restored: TLExpr = serde_json::from_str(&json).expect("Failed to deserialize from JSON");
println!(" Original: {:?}", rule);
println!(" Restored: {:?}", restored);
let original_json = serde_json::to_string(&rule).expect("Failed to serialize to JSON");
let restored_json = serde_json::to_string(&restored).expect("Failed to serialize to JSON");
if original_json == restored_json {
println!(" ✓ Roundtrip successful!");
}
println!("\n3. Versioned Expression Serialization:");
let expr = TLExpr::forall(
"x",
"Person",
TLExpr::imply(
TLExpr::pred("Person", vec![Term::var("x")]),
TLExpr::exists(
"y",
"City",
TLExpr::pred("livesIn", vec![Term::var("x"), Term::var("y")]),
),
),
);
let mut metadata = serde_json::Map::new();
metadata.insert("author".to_string(), serde_json::json!("alice"));
metadata.insert("purpose".to_string(), serde_json::json!("residency_rule"));
let versioned = VersionedExpr::with_metadata(expr.clone(), metadata);
let versioned_json =
serde_json::to_string_pretty(&versioned).expect("Failed to serialize to JSON");
println!(" Versioned Expression JSON:");
println!("{}", versioned_json);
println!("\n Metadata:");
println!(" - Format version: {}", FORMAT_VERSION);
println!(
" - Created at: {}",
versioned.created_at.as_ref().unwrap_or(&"N/A".to_string())
);
println!(" - Custom metadata: {:?}", versioned.metadata);
println!("\n4. Graph Serialization:");
let mut graph = EinsumGraph::new();
let input_a = graph.add_tensor("input_a");
let input_b = graph.add_tensor("input_b");
let intermediate = graph.add_tensor("intermediate");
let output = graph.add_tensor("output");
graph.add_node(EinsumNode::einsum(
"ik,kj->ij",
vec![input_a, input_b],
vec![intermediate],
))?;
graph.add_node(EinsumNode::elem_unary("relu", intermediate, output))?;
graph.add_output(output)?;
let graph_json =
serde_json::to_string_pretty(&graph).expect("Failed to serialize graph to JSON");
println!(" Graph JSON:");
println!("{}", graph_json);
println!("\n5. Graph Deserialization:");
let restored_graph: EinsumGraph =
serde_json::from_str(&graph_json).expect("Failed to deserialize graph from JSON");
println!(" Original graph:");
println!(" - Tensors: {}", graph.tensors.len());
println!(" - Nodes: {}", graph.nodes.len());
println!(" - Outputs: {}", graph.outputs.len());
println!(" Restored graph:");
println!(" - Tensors: {}", restored_graph.tensors.len());
println!(" - Nodes: {}", restored_graph.nodes.len());
println!(" - Outputs: {}", restored_graph.outputs.len());
match restored_graph.validate() {
Ok(_) => println!(" ✓ Restored graph is valid"),
Err(e) => println!(" ✗ Validation error: {:?}", e),
}
println!("\n6. Versioned Graph Serialization:");
let mut graph_metadata = serde_json::Map::new();
graph_metadata.insert("model_name".to_string(), serde_json::json!("simple_mlp"));
graph_metadata.insert(
"architecture".to_string(),
serde_json::json!("2_layer_relu"),
);
let versioned_graph = VersionedGraph::with_metadata(graph.clone(), graph_metadata);
let versioned_graph_json = serde_json::to_string_pretty(&versioned_graph)
.expect("Failed to serialize versioned graph");
println!(" Versioned Graph JSON (truncated):");
let lines: Vec<&str> = versioned_graph_json.lines().take(20).collect();
for line in lines {
println!("{}", line);
}
println!(" ...");
println!("\n7. Binary Serialization:");
let expr = TLExpr::and(
TLExpr::pred("P", vec![Term::var("x")]),
TLExpr::pred("Q", vec![Term::var("y")]),
);
let binary_data = oxicode::serde::encode_to_vec(&expr, oxicode::config::standard())
.expect("Failed to serialize to binary");
println!(" Expression binary size: {} bytes", binary_data.len());
let (_restored_expr, _): (TLExpr, usize) =
oxicode::serde::decode_from_slice(&binary_data, oxicode::config::standard())
.expect("Failed to deserialize from binary");
println!(" ✓ Binary roundtrip successful");
let json_size = serde_json::to_string(&expr)
.expect("Failed to serialize to JSON")
.len();
println!(" JSON size: {} bytes", json_size);
println!(" Binary size: {} bytes", binary_data.len());
println!(
" Binary is {:.1}% of JSON size",
(binary_data.len() as f64 / json_size as f64) * 100.0
);
println!("\n8. Graph Binary Serialization:");
let mut large_graph = EinsumGraph::new();
let mut current_tensor = large_graph.add_tensor("input");
for i in 0..10 {
let next_tensor = large_graph.add_tensor(format!("layer_{}", i));
large_graph.add_node(EinsumNode::elem_unary("relu", current_tensor, next_tensor))?;
current_tensor = next_tensor;
}
large_graph.add_output(current_tensor)?;
let graph_binary = oxicode::serde::encode_to_vec(&large_graph, oxicode::config::standard())
.expect("Failed to serialize graph to binary");
let graph_json =
serde_json::to_string(&large_graph).expect("Failed to serialize graph to JSON");
println!(" Large graph (10 layers):");
println!(" - JSON size: {} bytes", graph_json.len());
println!(" - Binary size: {} bytes", graph_binary.len());
println!(
" - Compression: {:.1}%",
(graph_binary.len() as f64 / graph_json.len() as f64) * 100.0
);
println!("\n9. Saving to Files:");
use std::env;
use std::fs;
let temp_dir = env::temp_dir();
let expr_json_path = temp_dir.join("tensorlogic_expr.json");
let versioned_expr = VersionedExpr::new(expr.clone());
let json_content =
serde_json::to_string_pretty(&versioned_expr).expect("Failed to serialize to JSON");
fs::write(&expr_json_path, json_content).expect("Failed to write JSON file");
println!(" ✓ Saved expression to: {:?}", expr_json_path);
let graph_bin_path = temp_dir.join("tensorlogic_graph.bin");
let versioned_graph = VersionedGraph::new(large_graph.clone());
let binary_content =
oxicode::serde::encode_to_vec(&versioned_graph, oxicode::config::standard())
.expect("Failed to serialize to binary");
fs::write(&graph_bin_path, binary_content).expect("Failed to write binary file");
println!(" ✓ Saved graph to: {:?}", graph_bin_path);
println!("\n10. Loading from Files:");
let loaded_json = fs::read_to_string(&expr_json_path).expect("Failed to read JSON file");
let loaded_expr: VersionedExpr =
serde_json::from_str(&loaded_json).expect("Failed to deserialize JSON");
println!(" ✓ Loaded expression from JSON");
println!(" - Format version: {}", loaded_expr.version);
println!(
" - Created at: {}",
loaded_expr
.created_at
.as_ref()
.unwrap_or(&"N/A".to_string())
);
let loaded_binary = fs::read(&graph_bin_path).expect("Failed to read binary file");
let (loaded_graph, _): (VersionedGraph, usize) =
oxicode::serde::decode_from_slice(&loaded_binary, oxicode::config::standard())
.expect("Failed to deserialize binary");
println!(" ✓ Loaded graph from binary");
println!(
" - Graph has {} tensors",
loaded_graph.graph.tensors.len()
);
fs::remove_file(&expr_json_path).ok();
fs::remove_file(&graph_bin_path).ok();
println!(" ✓ Cleaned up temporary files");
println!("\n11. Version Compatibility:");
let v1_expr = VersionedExpr::new(TLExpr::pred("P", vec![Term::var("x")]));
println!(" Current format version: {}", v1_expr.version);
println!(" ✓ Version information preserved for compatibility checks");
println!("\n12. Metadata Preservation:");
let mut metadata_map = serde_json::Map::new();
metadata_map.insert("rule_id".to_string(), serde_json::json!("mortality_axiom"));
metadata_map.insert("confidence".to_string(), serde_json::json!("1.0"));
metadata_map.insert("source".to_string(), serde_json::json!("knowledge_base.kb"));
let metadata_expr = VersionedExpr::with_metadata(
TLExpr::forall("x", "Person", TLExpr::pred("Mortal", vec![Term::var("x")])),
metadata_map,
);
let meta_json =
serde_json::to_string_pretty(&metadata_expr).expect("Failed to serialize to JSON");
println!(" Expression with metadata:");
println!("{}", meta_json);
println!("\n=== Example Complete ===");
Ok(())
}