mod coalesce_attention;
pub(crate) mod constant_fold;
mod constant_shape;
mod dead_nodes;
mod idempotent;
mod identity_element;
mod permute_reshape;
mod redundant_nodes;
use std::{cell::RefCell, rc::Rc};
use crate::{
graph_state::GraphState,
ir::{Argument, RawNode},
};
use coalesce_attention::coalesce_attention;
use constant_fold::fold_constants;
use constant_shape::simplify_constant_shape;
use dead_nodes::eliminate_dead_nodes;
use idempotent::eliminate_idempotent_ops;
use identity_element::eliminate_identity_elements;
use permute_reshape::simplify_permute_reshape;
use redundant_nodes::eliminate_redundant_nodes;
const MAX_ITERATIONS: usize = 10;
pub(crate) fn simplify_graph(
mut nodes: Vec<RawNode>,
inputs: Vec<Argument>,
mut outputs: Vec<Argument>,
_state: &Rc<RefCell<GraphState>>,
) -> (Vec<RawNode>, Vec<Argument>, Vec<Argument>) {
for iteration in 0..MAX_ITERATIONS {
let node_count_before = nodes.len();
nodes = coalesce_attention(nodes);
nodes = simplify_permute_reshape(nodes);
nodes = simplify_constant_shape(nodes, &mut outputs, _state);
nodes = fold_constants(nodes, &mut outputs, _state);
nodes = eliminate_idempotent_ops(nodes);
nodes = eliminate_identity_elements(nodes);
nodes = eliminate_redundant_nodes(nodes);
nodes = eliminate_dead_nodes(nodes, &outputs);
let removed = node_count_before - nodes.len();
if removed == 0 {
log::debug!(
"Simplification: converged after {} iteration(s)",
iteration + 1
);
break;
}
log::info!(
"Simplification: iteration {} removed {} node(s)",
iteration + 1,
removed
);
}
(nodes, inputs, outputs)
}
pub(super) fn update_constant_references(
nodes: &mut [RawNode],
graph_outputs: &mut [Argument],
constant_outputs: &[String],
) {
use crate::ir::ValueSource;
let mut store_map: std::collections::HashMap<String, crate::tensor_store::ValueStore> =
std::collections::HashMap::new();
for node in nodes.iter() {
for output in &node.outputs {
if output.value_source == ValueSource::Constant
&& let Some(ref store) = output.value_store
{
store_map.insert(output.name.clone(), store.clone());
}
}
}
let constant_set: std::collections::HashSet<&str> =
constant_outputs.iter().map(|s| s.as_str()).collect();
for node in nodes.iter_mut() {
for input in &mut node.inputs {
if input.value_source == ValueSource::Dynamic
&& constant_set.contains(input.name.as_str())
{
input.value_source = ValueSource::Constant;
input.value_store = store_map.get(input.name.as_str()).cloned();
}
}
}
for output in graph_outputs.iter_mut() {
if output.value_source == ValueSource::Dynamic
&& constant_set.contains(output.name.as_str())
{
output.value_source = ValueSource::Constant;
output.value_store = store_map.get(output.name.as_str()).cloned();
}
}
}
#[cfg(test)]
pub(crate) mod tests {
use crate::ir::{ArgType, Argument, DType, NodeType, RawNode, TensorType, ValueSource};
pub fn arg(name: &str) -> Argument {
Argument {
name: name.to_string(),
ty: ArgType::Tensor(TensorType {
dtype: DType::F32,
rank: 2,
static_shape: None,
}),
value_source: ValueSource::Dynamic,
value_store: None,
}
}
pub fn node(name: &str, node_type: NodeType, inputs: &[&str], outputs: &[&str]) -> RawNode {
RawNode {
node_type,
name: name.to_string(),
inputs: inputs.iter().map(|n| arg(n)).collect(),
outputs: outputs.iter().map(|n| arg(n)).collect(),
attrs: Default::default(),
}
}
}