use crate::candle::nn::linear::logsumexp_forward;
use crate::candle::traits::model::DecoderModuleT;
use candle_core::{Result, Tensor, Var};
use candle_nn::ops;
#[derive(Default)]
pub struct TopicRefinementConfig {
pub num_steps: usize,
pub learning_rate: f64,
pub regularization: f64,
}
pub fn refine_topic_proportions<Dec: DecoderModuleT>(
log_z_nk: &Tensor,
x_nd: &Tensor,
decoder: &Dec,
config: &TopicRefinementConfig,
) -> Result<Tensor> {
let log_dict_dk = decoder.get_dictionary()?.detach(); let log_dict_kd = log_dict_dk.t()?.contiguous()?;
let z_logits_init = log_z_nk.detach();
let z_var = Var::from_tensor(&z_logits_init)?;
let x_pos = x_nd.clamp(0.0, f64::INFINITY)?;
for _step in 0..config.num_steps {
let log_z = ops::log_softmax(z_var.as_tensor(), 1)?;
let log_recon_nd = logsumexp_forward(&log_z, &log_dict_kd)?;
let llik = x_pos.mul(&log_recon_nd)?.sum(1)?;
let diff = (z_var.as_tensor() - &z_logits_init)?;
let reg = (&diff * &diff)?.sum_all()?;
let loss = ((reg * config.regularization)? - llik.mean_all()?)?;
let grad = loss.backward()?;
let z_grad = grad.get(z_var.as_tensor()).unwrap();
let updated = (z_var.as_tensor() - (z_grad * config.learning_rate)?)?;
z_var.set(&updated)?;
}
ops::log_softmax(z_var.as_tensor(), 1)
}