use crate::numerical::Nonlinear_systems::symbolic::{
PreparedSymbolicNonlinearAotProblem, SymbolicDenseAotOptions, SymbolicNonlinearProblem,
};
use crate::symbolic::codegen::codegen_aot_driver::generated_aot_crate_from_prepared_problem;
use crate::symbolic::codegen::rust_backend::codegen_aot_build::{
AotBuildProfile, AotBuildRequest, AotBuildResult, AotCompileConfig,
};
use crate::symbolic::codegen::rust_backend::codegen_aot_crate::GeneratedAotCrate;
use log::info;
use std::io;
use std::path::Path;
pub fn prepared_problem_from_symbolic_nonlinear_problem<'a>(
problem: &'a SymbolicNonlinearProblem,
options: SymbolicDenseAotOptions,
) -> PreparedSymbolicNonlinearAotProblem<'a> {
problem.prepare_dense_aot_problem(options)
}
pub fn generated_aot_crate_from_symbolic_nonlinear_problem(
crate_name: &str,
module_name: &str,
problem: &SymbolicNonlinearProblem,
options: SymbolicDenseAotOptions,
) -> GeneratedAotCrate {
let prepared = prepared_problem_from_symbolic_nonlinear_problem(problem, options);
let prepared_problem = crate::symbolic::codegen::codegen_provider_api::PreparedProblem::dense(
prepared.as_prepared_problem(),
);
info!(
"Assembling nonlinear symbolic dense AOT crate '{}' from prepared problem",
crate_name
);
generated_aot_crate_from_prepared_problem(crate_name, module_name, &prepared_problem)
}
pub fn materialize_symbolic_nonlinear_aot_build(
crate_name: &str,
module_name: &str,
problem: &SymbolicNonlinearProblem,
options: SymbolicDenseAotOptions,
output_parent_dir: &Path,
profile: AotBuildProfile,
) -> io::Result<AotBuildResult> {
materialize_symbolic_nonlinear_aot_build_with_compile_config(
crate_name,
module_name,
problem,
options,
output_parent_dir,
profile,
AotCompileConfig::default(),
)
}
pub fn materialize_symbolic_nonlinear_aot_build_with_compile_config(
crate_name: &str,
module_name: &str,
problem: &SymbolicNonlinearProblem,
options: SymbolicDenseAotOptions,
output_parent_dir: &Path,
profile: AotBuildProfile,
compile_config: AotCompileConfig,
) -> io::Result<AotBuildResult> {
let crate_spec = generated_aot_crate_from_symbolic_nonlinear_problem(
crate_name,
module_name,
problem,
options,
);
AotBuildRequest::new(crate_spec, output_parent_dir, profile)
.with_compile_config(compile_config)
.materialize()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::numerical::Nonlinear_systems::symbolic::SymbolicProblemOptions;
use crate::symbolic::symbolic_engine::Expr;
use tempfile::tempdir;
fn elementary_problem() -> SymbolicNonlinearProblem {
SymbolicNonlinearProblem::from_expressions_with_options(
vec![
Expr::parse_expression("x^2+y^2-10"),
Expr::parse_expression("x-y-4"),
],
SymbolicProblemOptions::new().with_variables(vec!["x".to_string(), "y".to_string()]),
)
.expect("problem should build")
}
#[test]
fn nonlinear_symbolic_aot_bridge_builds_prepared_problem_with_aot_backend() {
let problem = elementary_problem();
let prepared = prepared_problem_from_symbolic_nonlinear_problem(
&problem,
SymbolicDenseAotOptions::default(),
);
let generic = prepared.as_prepared_problem();
assert_eq!(
generic.backend_kind,
crate::symbolic::codegen::codegen_provider_api::BackendKind::Aot
);
assert_eq!(
generic.matrix_backend,
crate::symbolic::codegen::codegen_provider_api::MatrixBackend::Dense
);
assert_eq!(prepared.residual_len(), 2);
assert_eq!(prepared.jacobian_shape(), (2, 2));
}
#[test]
fn nonlinear_symbolic_aot_bridge_builds_generated_crate() {
let problem = elementary_problem();
let crate_spec = generated_aot_crate_from_symbolic_nonlinear_problem(
"generated_nonlinear_symbolic_fixture",
"generated_nonlinear_symbolic_module",
&problem,
SymbolicDenseAotOptions::default(),
);
assert_eq!(
crate_spec.crate_name,
"generated_nonlinear_symbolic_fixture"
);
assert_eq!(crate_spec.manifest.backend_kind.as_str(), "aot");
assert_eq!(crate_spec.manifest.matrix_backend.as_str(), "dense");
assert!(
crate_spec
.module_source
.contains("pub mod generated_nonlinear_symbolic_module")
);
assert!(
crate_spec
.module_source
.contains("pub fn eval_nonlinear_residual")
);
assert!(
crate_spec
.module_source
.contains("pub fn eval_nonlinear_jacobian")
);
}
#[test]
fn nonlinear_symbolic_aot_bridge_materializes_release_build_request() {
let problem = elementary_problem();
let dir = tempdir().expect("tempdir should exist");
let result = materialize_symbolic_nonlinear_aot_build(
"generated_nonlinear_symbolic_build",
"generated_nonlinear_symbolic_build_module",
&problem,
SymbolicDenseAotOptions::default(),
dir.path(),
AotBuildProfile::Release,
)
.expect("build request should materialize");
assert_eq!(result.cargo_command_line(), "cargo build --release");
assert!(result.written.cargo_toml.exists());
assert!(result.written.generated_rs.exists());
assert_eq!(
result
.expected_rlib
.file_name()
.and_then(|name| name.to_str()),
Some("libgenerated_nonlinear_symbolic_build.rlib")
);
}
#[test]
fn nonlinear_symbolic_aot_bridge_exposes_explicit_fast_build_profile() {
let problem = elementary_problem();
let dir = tempdir().expect("tempdir should exist");
let result = materialize_symbolic_nonlinear_aot_build_with_compile_config(
"generated_nonlinear_symbolic_fast_build",
"generated_nonlinear_symbolic_fast_build_module",
&problem,
SymbolicDenseAotOptions::default(),
dir.path(),
AotBuildProfile::Release,
AotCompileConfig::fast_build(),
)
.expect("fast AOT build request should materialize");
assert_eq!(
result.cargo_env,
vec![(
"RUSTFLAGS".to_string(),
"-C opt-level=1 -C codegen-units=16".to_string()
)]
);
assert_eq!(result.cargo_command_line(), "cargo build --release");
}
}