use std::sync::Arc;
use scirs2_core::ndarray::Array2;
use crate::error::KernelError;
use crate::multitask::{ICMKernel, TaskInput};
use crate::types::Kernel;
use super::trait_def::MultiOutputKernel;
type Result<T> = std::result::Result<T, KernelError>;
pub struct KroneckerICMKernel {
inner: Arc<ICMKernel>,
}
impl KroneckerICMKernel {
pub fn new(inner: ICMKernel) -> Self {
Self {
inner: Arc::new(inner),
}
}
pub fn from_base(base: Box<dyn Kernel>, task_covariance: Vec<Vec<f64>>) -> Result<Self> {
let inner = ICMKernel::new(base, task_covariance).map_err(|e| {
KernelError::ComputationError(format!("ICMKernel construction failed: {}", e))
})?;
Ok(Self {
inner: Arc::new(inner),
})
}
}
impl MultiOutputKernel for KroneckerICMKernel {
fn n_outputs(&self) -> usize {
self.inner.num_tasks()
}
fn compute_block(&self, x: &[f64], y: &[f64]) -> Result<Array2<f64>> {
let p = self.inner.num_tasks();
let mut block = Array2::<f64>::zeros((p, p));
for i in 0..p {
for j in 0..p {
let xi = TaskInput::from_slice(x, i);
let yj = TaskInput::from_slice(y, j);
block[[i, j]] = self.inner.compute_tasks(&xi, &yj).map_err(|e| {
KernelError::ComputationError(format!(
"ICM compute_tasks({}, {}) failed: {}",
i, j, e
))
})?;
}
}
Ok(block)
}
fn name(&self) -> &str {
"KroneckerICM"
}
}