runmat-runtime 0.6.0

Core runtime for RunMat with builtins, BLAS/LAPACK integration, and execution APIs
Documentation
use runmat_builtins::Value;
use runmat_macros::runtime_builtin;

use crate::BuiltinResult;

use super::{
    any_type, gather_args, layer_object, numeric_scalar, numeric_vector, positive_usize,
    tensor_value,
};

fn is_numeric_scalar(value: &Value) -> bool {
    match value {
        Value::Num(n) => n.is_finite(),
        Value::Int(_) => true,
        Value::Tensor(t) => t.data.len() == 1 && t.data[0].is_finite(),
        _ => false,
    }
}

#[runtime_builtin(
    name = "fullyConnectedLayer",
    category = "deep_learning",
    summary = "Create a fully connected layer compatibility object.",
    keywords = "fullyConnectedLayer,deep learning,layer,neural network",
    type_resolver(any_type),
    descriptor(crate::builtins::deep_learning::OBJECT_DESCRIPTOR),
    builtin_path = "crate::builtins::deep_learning::layers"
)]
pub(super) async fn fully_connected_layer_builtin(
    output_size: Value,
    rest: Vec<Value>,
) -> BuiltinResult<Value> {
    let output_size = positive_usize(&output_size, "fullyConnectedLayer", "outputSize")?;
    layer_object(
        "nnet.cnn.layer.FullyConnectedLayer",
        "Fully Connected",
        vec![("OutputSize", Value::Num(output_size as f64))],
        gather_args(rest).await?,
        "fullyConnectedLayer",
    )
}

#[runtime_builtin(
    name = "featureInputLayer",
    category = "deep_learning",
    summary = "Create a feature input layer compatibility object.",
    keywords = "featureInputLayer,deep learning,input layer,features",
    type_resolver(any_type),
    descriptor(crate::builtins::deep_learning::OBJECT_DESCRIPTOR),
    builtin_path = "crate::builtins::deep_learning::layers"
)]
pub(super) async fn feature_input_layer_builtin(
    input_size: Value,
    rest: Vec<Value>,
) -> BuiltinResult<Value> {
    let input_size = numeric_vector(&input_size, "featureInputLayer", "inputSize")?;
    layer_object(
        "nnet.cnn.layer.FeatureInputLayer",
        "Feature Input",
        vec![(
            "InputSize",
            tensor_value(
                input_size.iter().map(|v| *v as f64).collect(),
                vec![1, input_size.len()],
                "featureInputLayer",
            )?,
        )],
        gather_args(rest).await?,
        "featureInputLayer",
    )
}

#[runtime_builtin(
    name = "sequenceInputLayer",
    category = "deep_learning",
    summary = "Create a sequence input layer compatibility object.",
    keywords = "sequenceInputLayer,deep learning,sequence,input layer",
    type_resolver(any_type),
    descriptor(crate::builtins::deep_learning::OBJECT_DESCRIPTOR),
    builtin_path = "crate::builtins::deep_learning::layers"
)]
pub(super) async fn sequence_input_layer_builtin(
    input_size: Value,
    rest: Vec<Value>,
) -> BuiltinResult<Value> {
    let input_size = numeric_vector(&input_size, "sequenceInputLayer", "inputSize")?;
    layer_object(
        "nnet.cnn.layer.SequenceInputLayer",
        "Sequence Input",
        vec![(
            "InputSize",
            tensor_value(
                input_size.iter().map(|v| *v as f64).collect(),
                vec![1, input_size.len()],
                "sequenceInputLayer",
            )?,
        )],
        gather_args(rest).await?,
        "sequenceInputLayer",
    )
}

#[runtime_builtin(
    name = "reluLayer",
    category = "deep_learning",
    summary = "Create a ReLU layer compatibility object.",
    keywords = "reluLayer,deep learning,activation,layer",
    type_resolver(any_type),
    descriptor(crate::builtins::deep_learning::OBJECT_DESCRIPTOR),
    builtin_path = "crate::builtins::deep_learning::layers"
)]
pub(super) async fn relu_layer_builtin(rest: Vec<Value>) -> BuiltinResult<Value> {
    layer_object(
        "nnet.cnn.layer.ReLULayer",
        "ReLU",
        vec![],
        gather_args(rest).await?,
        "reluLayer",
    )
}

#[runtime_builtin(
    name = "eluLayer",
    category = "deep_learning",
    summary = "Create an ELU layer compatibility object.",
    keywords = "eluLayer,deep learning,activation,layer",
    type_resolver(any_type),
    descriptor(crate::builtins::deep_learning::OBJECT_DESCRIPTOR),
    builtin_path = "crate::builtins::deep_learning::layers"
)]
pub(super) async fn elu_layer_builtin(rest: Vec<Value>) -> BuiltinResult<Value> {
    let mut args = gather_args(rest).await?;
    let alpha = if args.first().is_some_and(is_numeric_scalar) {
        numeric_scalar(&args.remove(0), "eluLayer", "alpha")?
    } else {
        1.0
    };
    layer_object(
        "nnet.cnn.layer.ELULayer",
        "ELU",
        vec![("Alpha", Value::Num(alpha))],
        args,
        "eluLayer",
    )
}

#[runtime_builtin(
    name = "softmaxLayer",
    category = "deep_learning",
    summary = "Create a softmax layer compatibility object.",
    keywords = "softmaxLayer,deep learning,softmax,layer",
    type_resolver(any_type),
    descriptor(crate::builtins::deep_learning::OBJECT_DESCRIPTOR),
    builtin_path = "crate::builtins::deep_learning::layers"
)]
pub(super) async fn softmax_layer_builtin(rest: Vec<Value>) -> BuiltinResult<Value> {
    layer_object(
        "nnet.cnn.layer.SoftmaxLayer",
        "Softmax",
        vec![],
        gather_args(rest).await?,
        "softmaxLayer",
    )
}

#[runtime_builtin(
    name = "classificationLayer",
    category = "deep_learning",
    summary = "Create a classification output layer compatibility object.",
    keywords = "classificationLayer,deep learning,classification,output layer",
    type_resolver(any_type),
    descriptor(crate::builtins::deep_learning::OBJECT_DESCRIPTOR),
    builtin_path = "crate::builtins::deep_learning::layers"
)]
pub(super) async fn classification_layer_builtin(rest: Vec<Value>) -> BuiltinResult<Value> {
    layer_object(
        "nnet.cnn.layer.ClassificationOutputLayer",
        "Classification Output",
        vec![("Classes", Value::String("auto".into()))],
        gather_args(rest).await?,
        "classificationLayer",
    )
}

#[runtime_builtin(
    name = "regressionLayer",
    category = "deep_learning",
    summary = "Create a regression output layer compatibility object.",
    keywords = "regressionLayer,deep learning,regression,output layer",
    type_resolver(any_type),
    descriptor(crate::builtins::deep_learning::OBJECT_DESCRIPTOR),
    builtin_path = "crate::builtins::deep_learning::layers"
)]
pub(super) async fn regression_layer_builtin(rest: Vec<Value>) -> BuiltinResult<Value> {
    layer_object(
        "nnet.cnn.layer.RegressionOutputLayer",
        "Regression Output",
        vec![],
        gather_args(rest).await?,
        "regressionLayer",
    )
}

#[runtime_builtin(
    name = "layerNormalizationLayer",
    category = "deep_learning",
    summary = "Create a layer normalization layer compatibility object.",
    keywords = "layerNormalizationLayer,deep learning,normalization,layer",
    type_resolver(any_type),
    descriptor(crate::builtins::deep_learning::OBJECT_DESCRIPTOR),
    builtin_path = "crate::builtins::deep_learning::layers"
)]
pub(super) async fn layer_normalization_layer_builtin(rest: Vec<Value>) -> BuiltinResult<Value> {
    layer_object(
        "nnet.cnn.layer.LayerNormalizationLayer",
        "Layer Normalization",
        vec![("Epsilon", Value::Num(1.0e-5))],
        gather_args(rest).await?,
        "layerNormalizationLayer",
    )
}

#[runtime_builtin(
    name = "globalAveragePooling1dLayer",
    category = "deep_learning",
    summary = "Create a global average pooling 1-D layer compatibility object.",
    keywords = "globalAveragePooling1dLayer,deep learning,pooling,layer",
    type_resolver(any_type),
    descriptor(crate::builtins::deep_learning::OBJECT_DESCRIPTOR),
    builtin_path = "crate::builtins::deep_learning::layers"
)]
pub(super) async fn global_average_pooling_1d_layer_builtin(
    rest: Vec<Value>,
) -> BuiltinResult<Value> {
    layer_object(
        "nnet.cnn.layer.GlobalAveragePooling1DLayer",
        "Global Average Pooling 1D",
        vec![],
        gather_args(rest).await?,
        "globalAveragePooling1dLayer",
    )
}

#[runtime_builtin(
    name = "lstmLayer",
    category = "deep_learning",
    summary = "Create an LSTM layer compatibility object.",
    keywords = "lstmLayer,deep learning,lstm,recurrent,layer",
    type_resolver(any_type),
    descriptor(crate::builtins::deep_learning::OBJECT_DESCRIPTOR),
    builtin_path = "crate::builtins::deep_learning::layers"
)]
pub(super) async fn lstm_layer_builtin(
    num_hidden_units: Value,
    rest: Vec<Value>,
) -> BuiltinResult<Value> {
    recurrent_layer(
        "lstmLayer",
        "nnet.cnn.layer.LSTMLayer",
        "LSTM",
        num_hidden_units,
        rest,
    )
    .await
}

#[runtime_builtin(
    name = "bilstmLayer",
    category = "deep_learning",
    summary = "Create a bidirectional LSTM layer compatibility object.",
    keywords = "bilstmLayer,deep learning,lstm,bidirectional,recurrent,layer",
    type_resolver(any_type),
    descriptor(crate::builtins::deep_learning::OBJECT_DESCRIPTOR),
    builtin_path = "crate::builtins::deep_learning::layers"
)]
pub(super) async fn bilstm_layer_builtin(
    num_hidden_units: Value,
    rest: Vec<Value>,
) -> BuiltinResult<Value> {
    recurrent_layer(
        "bilstmLayer",
        "nnet.cnn.layer.BiLSTMLayer",
        "BiLSTM",
        num_hidden_units,
        rest,
    )
    .await
}

pub(super) async fn recurrent_layer(
    function: &'static str,
    class_name: &str,
    type_name: &str,
    num_hidden_units: Value,
    rest: Vec<Value>,
) -> BuiltinResult<Value> {
    let units = positive_usize(&num_hidden_units, function, "numHiddenUnits")?;
    layer_object(
        class_name,
        type_name,
        vec![
            ("NumHiddenUnits", Value::Num(units as f64)),
            ("OutputMode", Value::String("last".into())),
        ],
        gather_args(rest).await?,
        function,
    )
}

#[runtime_builtin(
    name = "convolution1dLayer",
    category = "deep_learning",
    summary = "Create a 1-D convolution layer compatibility object.",
    keywords = "convolution1dLayer,deep learning,convolution,layer",
    type_resolver(any_type),
    descriptor(crate::builtins::deep_learning::OBJECT_DESCRIPTOR),
    builtin_path = "crate::builtins::deep_learning::layers"
)]
pub(super) async fn convolution_1d_layer_builtin(
    filter_size: Value,
    num_filters: Value,
    rest: Vec<Value>,
) -> BuiltinResult<Value> {
    let filter_size = positive_usize(&filter_size, "convolution1dLayer", "filterSize")?;
    let num_filters = positive_usize(&num_filters, "convolution1dLayer", "numFilters")?;
    layer_object(
        "nnet.cnn.layer.Convolution1DLayer",
        "Convolution 1D",
        vec![
            ("FilterSize", Value::Num(filter_size as f64)),
            ("NumFilters", Value::Num(num_filters as f64)),
            ("Stride", Value::Num(1.0)),
            ("Padding", Value::String("same".into())),
        ],
        gather_args(rest).await?,
        "convolution1dLayer",
    )
}