sim-lib-interference-runtime 0.1.0

Tensor-backed Citizen records and Shape contracts for coherent interference studies.
Documentation
use std::sync::Arc;

use sim_citizen::CitizenField;
use sim_kernel::{Args, Cx, DefaultFactory, EagerPolicy, Expr, Symbol, Value};
use sim_lib_interference_runtime::{
    InterferenceLib, InterferenceRecordsLib, StudyDescriptor, problem_function_symbol,
    sampling_plane_function_symbol, solve_function_symbol,
};

fn main() -> sim_kernel::Result<()> {
    let mut cx = Cx::new(Arc::new(EagerPolicy), Arc::new(DefaultFactory));
    cx.load_lib(&InterferenceRecordsLib)?;
    cx.load_lib(&InterferenceLib)?;

    let problem_spec = value(
        &mut cx,
        map([
            ("frequency-hz", field(&1_000.0)),
            ("speed-m-s", field(&343.0)),
            ("attenuation-np-m", field(&0.0)),
            ("singularity-radius-m", field(&0.01)),
            (
                "sources",
                Expr::List(vec![
                    map([
                        ("kind", Expr::Symbol(Symbol::new("point"))),
                        ("id", Expr::Symbol(Symbol::new("left"))),
                        ("position-m", vector([-0.25, 0.0, 0.0])),
                        ("amplitude-at-reference", field(&1.0)),
                        ("phase-rad", field(&0.0)),
                    ]),
                    map([
                        ("kind", Expr::Symbol(Symbol::new("point"))),
                        ("id", Expr::Symbol(Symbol::new("right"))),
                        ("position-m", vector([0.25, 0.0, 0.0])),
                        ("amplitude-at-reference", field(&1.0)),
                        ("phase-rad", field(&std::f64::consts::PI)),
                    ]),
                ]),
            ),
        ]),
    )?;
    let problem = cx.call_function(&problem_function_symbol(), Args::new(vec![problem_spec]))?;

    let plane_spec = value(
        &mut cx,
        map([
            ("origin-m", vector([-1.0, -1.0, 0.5])),
            ("u-axis", vector([1.0, 0.0, 0.0])),
            ("v-axis", vector([0.0, 1.0, 0.0])),
            ("extent-u-m", field(&2.0)),
            ("extent-v-m", field(&2.0)),
            ("rows", field(&1_024_usize)),
            ("cols", field(&1_024_usize)),
        ]),
    )?;
    let plane = cx.call_function(
        &sampling_plane_function_symbol(),
        Args::new(vec![plane_spec]),
    )?;
    let options = value(
        &mut cx,
        map([
            ("sampling", Expr::Symbol(Symbol::new("strict"))),
            ("work-budget", Expr::Symbol(Symbol::new("default"))),
        ]),
    )?;
    let study = cx.call_function(
        &solve_function_symbol(),
        Args::new(vec![problem, plane, options]),
    )?;
    let study = study
        .object()
        .downcast_ref::<StudyDescriptor>()
        .expect("interference/solve result Shape");
    println!(
        "interference/Study rows={} cols={} emitters={} cells={} evaluations={} verdict={}",
        study.field.rows,
        study.field.cols,
        study.evidence.work.emitters,
        study.evidence.work.cells,
        study.evidence.work.emitter_evaluations,
        study.evidence.sampling.verdict.name
    );
    Ok(())
}

fn value(cx: &mut Cx, expr: Expr) -> sim_kernel::Result<Value> {
    sim_citizen::value_from_expr(cx, &expr)
}

fn field<T: CitizenField>(value: &T) -> Expr {
    value.encode_field()
}

fn vector<const N: usize>(values: [f64; N]) -> Expr {
    Expr::List(values.into_iter().map(|value| field(&value)).collect())
}

fn map<const N: usize>(entries: [(&str, Expr); N]) -> Expr {
    Expr::Map(
        entries
            .into_iter()
            .map(|(key, value)| (Expr::Symbol(Symbol::new(key)), value))
            .collect(),
    )
}