use super::*;
#[derive(Clone, Copy, Debug)]
pub struct RoutingRows {
pub first: u64,
pub end: u64,
pub stride: u64,
}
pub trait RoutingMechanism {
type Value: Clone;
type Rows;
type Error: std::error::Error + 'static;
fn policy(&self) -> Result<(TopKGroupSelectionSpec, bool), Self::Error>;
fn token_rows(&self, input: &Self::Value) -> Result<u64, Self::Error>;
fn rows(&self, selection: RoutingRows, tokens: u64) -> Result<Self::Rows, Self::Error>;
fn project(&mut self, input: &Self::Value) -> Result<Self::Value, Self::Error>;
fn transform(&self, raw: &Self::Value) -> Result<Self::Value, Self::Error>;
fn ranking(&self, scores: &Self::Value) -> Result<Self::Value, Self::Error>;
fn select(&self, ranking: &Self::Value) -> Result<Self::Value, Self::Error>;
fn weights(
&self,
scores: &Self::Value,
ids: Self::Value,
) -> Result<GroupSelection<Self::Value>, Self::Error>;
fn add_columns(
&self,
value: &Self::Value,
ids: &[u32],
values: &[f32],
rows: &Self::Rows,
) -> Result<Self::Value, Self::Error>;
fn fill_columns(
&self,
value: &Self::Value,
ids: &[u32],
fill: f32,
rows: &Self::Rows,
) -> Result<Self::Value, Self::Error>;
fn replace_rows(
&self,
indices: &Self::Value,
ids: &[u32],
rows: &Self::Rows,
) -> Result<Self::Value, Self::Error>;
fn fill_gathered(
&self,
value: &Self::Value,
indices: &Self::Value,
ids: &[u32],
fill: f32,
rows: &Self::Rows,
) -> Result<Self::Value, Self::Error>;
fn excludes(
&self,
indices: &Self::Value,
ids: &[u32],
rows: &Self::Rows,
) -> Result<bool, Self::Error>;
fn finite(&self, value: &Self::Value) -> Result<bool, Self::Error>;
fn nonnegative(&self, value: &Self::Value) -> Result<bool, Self::Error>;
fn positive_row_sums(&self, value: &Self::Value) -> Result<bool, Self::Error>;
}
#[derive(Debug, thiserror::Error)]
pub enum RoutingExecutionError<E: std::error::Error + 'static> {
#[error(transparent)]
Invalid(#[from] Error),
#[error("native routing operation failed: {0}")]
Native(E),
}
pub fn execute_routing_intervention<M: RoutingMechanism>(
native: &mut M,
input: &M::Value,
control: &GroupSelectionControl,
) -> Result<IntervenedGroupSelection<M::Value>, RoutingExecutionError<M::Error>> {
use RoutingExecutionError::Native;
let (policy, learned) = native.policy().map_err(Native)?;
let tokens = native.token_rows(input).map_err(Native)?;
control.validate(policy, learned, tokens)?;
let rows = native
.rows(
RoutingRows {
first: control.first_row,
end: control.end_row,
stride: control.row_stride,
},
tokens,
)
.map_err(Native)?;
let raw = native.project(input).map_err(Native)?;
let ordinary = if control.capture_original
|| !matches!(
control.action,
GroupSelectionAction::Bias {
stage: GroupScoreStage::RawLogits,
..
}
) {
let scores = native.transform(&raw).map_err(Native)?;
let ranking = native.ranking(&scores).map_err(Native)?;
Some((scores, ranking))
} else {
None
};
let original = match (&ordinary, control.capture_original) {
(Some((scores, ranking)), true) => {
let ids = native.select(ranking).map_err(Native)?;
Some(native.weights(scores, ids).map_err(Native)?)
}
_ => None,
};
let add = |value: &M::Value,
ids: &[u32],
values: &[f32]|
-> Result<M::Value, RoutingExecutionError<M::Error>> {
let biased = native
.add_columns(value, ids, values, &rows)
.map_err(Native)?;
if !native.finite(&biased).map_err(Native)? {
return Err(Error::backend("routing bias produced non-finite scores").into());
}
Ok(biased)
};
let (scores, mut ranking) = match &control.action {
GroupSelectionAction::Bias { stage, ids, values } => match stage {
GroupScoreStage::RawLogits => {
let scores = native.transform(&add(&raw, ids, values)?).map_err(Native)?;
let ranking = native.ranking(&scores).map_err(Native)?;
(scores, ranking)
}
GroupScoreStage::TransformedScores => {
let (ordinary_scores, _) = ordinary.as_ref().expect("ordinary score path");
let scores = add(ordinary_scores, ids, values)?;
let ranking = native.ranking(&scores).map_err(Native)?;
(scores, ranking)
}
GroupScoreStage::RankingScores => {
let (ordinary_scores, ordinary_ranking) =
ordinary.as_ref().expect("ordinary score path");
(ordinary_scores.clone(), add(ordinary_ranking, ids, values)?)
}
},
_ => ordinary.expect("ordinary score path"),
};
if let GroupSelectionAction::Exclude(ids) = &control.action {
ranking = native
.fill_columns(&ranking, ids, f32::NEG_INFINITY, &rows)
.map_err(Native)?;
}
let mut ids = native.select(&ranking).map_err(Native)?;
if let GroupSelectionAction::Force(forced) = &control.action {
ids = native.replace_rows(&ids, forced, &rows).map_err(Native)?;
}
if let GroupSelectionAction::Exclude(excluded) = &control.action {
if !native.excludes(&ids, excluded, &rows).map_err(Native)? {
return Err(Error::backend("excluded expert selected by native router").into());
}
}
let (ids, selected_scores, mut weights) =
native.weights(&scores, ids).map_err(Native)?.into_parts();
if let GroupSelectionAction::ZeroContribution(excluded) = &control.action {
weights = native
.fill_gathered(&weights, &ids, excluded, 0.0, &rows)
.map_err(Native)?;
}
if !native.finite(&weights).map_err(Native)?
|| !native.nonnegative(&weights).map_err(Native)?
|| !native.finite(&selected_scores).map_err(Native)?
|| !native.nonnegative(&selected_scores).map_err(Native)?
{
return Err(Error::backend(
"routing intervention produced non-finite or negative coefficients",
)
.into());
}
if !matches!(control.action, GroupSelectionAction::ZeroContribution(_))
&& !native.positive_row_sums(&weights).map_err(Native)?
{
return Err(Error::backend("routing intervention produced a zero coefficient sum").into());
}
Ok(IntervenedGroupSelection {
original,
effective: GroupSelection::new(ids, selected_scores, weights),
})
}