#![allow(unused_imports)]
use super::helpers::simple_op_flex;
use super::helpers::*;
use crate::proto;
use crate::{CoremlError, Result};
use rlx_ir::op::{Activation, CmpOp, MaskKind, ReduceOp};
use rlx_ir::quant::QuantScheme;
use rlx_ir::{DType, Dim, Graph, NodeId, Op, Shape};
use std::collections::HashMap;
use super::*;
impl<'a> LowerCtx<'a> {
pub(crate) fn lower_topk(&mut self, id: NodeId, k: usize, out_name: &str) -> Result<()> {
let node = self.graph.node(id);
let shape = node.shape.clone(); let x = self.val(node.inputs[0]);
let axis = (shape.rank() - 1) as i32;
let values = format!("{out_name}_vals");
let indices = format!("{out_name}_idx_i32");
let vals_ty = named_value_type(&values, &shape)?;
let idx_ty = named_value_type(&indices, &shape.clone().with_dtype(DType::I32))?;
let mut inputs = HashMap::new();
inputs.insert("x".to_string(), bind_name(&x));
inputs.insert("k".to_string(), bind_value(scalar_i32(k as i32)));
inputs.insert("axis".to_string(), bind_value(scalar_i32(axis)));
inputs.insert("ascending".to_string(), bind_value(scalar_bool(false)));
let mut attributes = HashMap::new();
attributes.insert("name".to_string(), scalar_str(out_name));
self.operations.push(proto::Operation {
r#type: "topk".to_string(),
inputs,
outputs: vec![vals_ty, idx_ty],
blocks: vec![],
attributes,
});
self.emit(
"cast",
out_name,
&shape,
vec![
("x", bind_name(&indices)),
("dtype", bind_value(scalar_str("fp32"))),
],
)?;
self.names.insert(id.0, out_name.to_string());
Ok(())
}
pub(crate) fn lower_argreduce(
&mut self,
id: NodeId,
axis: usize,
keep_dim: bool,
is_max: bool,
out_name: &str,
) -> Result<()> {
let node = self.graph.node(id);
let in_shape = self.graph.shape(node.inputs[0]).clone();
let rank = in_shape.rank();
let ax = axis as i32;
let _ = rank;
let mut x = self.val(node.inputs[0]);
if !is_max {
let neg = format!("{out_name}_neg");
self.emit(
"mul",
&neg,
&in_shape,
vec![("x", bind_name(&x)), ("y", bind_value(scalar_f32(-1.0)))],
)?;
x = neg;
}
let idx_i32 = format!("{out_name}_idx_i32");
let idx_shape = node.shape.clone().with_dtype(DType::I32);
self.emit(
"reduce_argmax",
&idx_i32,
&idx_shape,
vec![
("x", bind_name(&x)),
("axis", bind_value(scalar_i32(ax))),
("keep_dims", bind_value(scalar_bool(keep_dim))),
],
)?;
self.emit(
"cast",
out_name,
&node.shape,
vec![
("x", bind_name(&idx_i32)),
("dtype", bind_value(scalar_str("fp32"))),
],
)?;
self.names.insert(id.0, out_name.to_string());
Ok(())
}
pub(crate) fn lower_reverse(
&mut self,
id: NodeId,
axes: &[usize],
out_name: &str,
) -> Result<()> {
let node = self.graph.node(id);
let in_shape = self.graph.shape(node.inputs[0]).clone();
if axes.is_empty() {
let x = self.val(node.inputs[0]);
self.names.insert(id.0, x);
return Ok(());
}
let mut cur = self.val(node.inputs[0]);
let shape = in_shape.clone();
for &ax in axes {
let d = dim_static(&shape, ax)?;
let idx_f: Vec<f32> = (0..d).rev().map(|i| i as f32).collect();
let idx_name = format!("{out_name}_rev_{ax}");
self.operations.push(make_const(
&mut self.blob,
&idx_name,
&Shape::new(&[d], DType::F32),
&idx_f,
)?);
let idx_i32 = format!("{idx_name}_i32");
self.emit(
"cast",
&idx_i32,
&Shape::new(&[d], DType::I32),
vec![
("x", bind_name(&idx_name)),
("dtype", bind_value(scalar_str("int32"))),
],
)?;
let next = format!("{out_name}_g{ax}");
self.emit(
"gather",
&next,
&shape,
vec![
("x", bind_name(&cur)),
("indices", bind_name(&idx_i32)),
("axis", bind_value(scalar_i32(ax as i32))),
],
)?;
cur = next;
}
self.names.insert(id.0, cur);
Ok(())
}
}