pub fn propagate_constants<M: Borrow<Model>>(analyser: &mut Analyser<M>) -> TractResult<()> {
    let components: Vec<Component> = connected_components(analyser)?;
    info!("Detected {:?} connected components.", components.len());

    let mut const_int_nodes = HashMap::new();

    for component in components {
        for i in component.outputs {
            let tensor = analyser.edges[i].fact.value.concretize().unwrap();

            let const_node_id: usize = if let Some(tensor) = tensor.clone().take_i32s() {
                *const_int_nodes.entry(tensor.clone()).or_insert_with(|| {
                    let node_id = analyser.nodes.len();
                    let node_name = format!("generated_{}", node_id).to_string();
                    let node = build_const_node(node_id, node_name, tensor.into());
                    analyser.nodes.push(node);
                    node_id
                })
            } else {
                let node_id = analyser.nodes.len();
                let node_name = format!("generated_{}", node_id).to_string();
                let node = build_const_node(node_id, node_name, tensor);
                analyser.nodes.push(node);
                node_id
            };
            let edge = &mut analyser.edges[i];
            let old_node_id = edge.from.unwrap().node;

            // Detach the edge from its previous source.
            {
                let successors = &mut analyser.next_edges[old_node_id];
                let position = successors.iter().position(|&i| i == edge.id).unwrap();
                successors.remove(position);
            };

            // Detach the target node from its previous source.
            {
                let predecessors = &mut analyser.nodes[edge.to_node.unwrap()].inputs;
                let position = predecessors
                    .iter()
                    .position(|outlet| outlet.node == old_node_id)
                    .unwrap();
                predecessors[position] = OutletId::new(const_node_id, 0);
            }

            // Attach the edge to its new source.
            edge.from = Some(OutletId::new(const_node_id, 0));
            analyser.prev_edges.push(vec![]);
            analyser.next_edges.push(vec![edge.id]);
        }
    }

    analyser.reset_plan()?;

    Ok(())
}
/// Detaches the constant nodes and edges from the given graph.
///
/// The following algorithm is used:
/// 1. Compute the constant underlying graph of the given graph.
/// 2. Compute the undirected connected components of that underlying graph.
/// 3. Choose a pruning strategy and apply it to each connected component.
///
/// There are several pruning strategies to choose from:
/// - The simplest is to prune all nodes but the sinks of each component, and
///   to replace the latter with Const nodes. This might however increase the
///   size of the model dramatically in cases like the one below, where we'll
///   end up storing two large constants instead of one while only getting a
///   neglectible performance boost from the operation.
///
/// ```text
///                                     +---------------------+
///                                 +--^+ Simple operation 1  +-->
///             +---------------+   |   +---------------------+
///             | Const (large) +---+
///             +---------------+   |   +---------------------+
///                                 +--^+ Simple operation 2  +-->
///                                     +---------------------+
/// ```
///
/// - We could also search for the lowest common ancestor of all the sinks in
///   each connected component, and prune every node and edge that isn't part
///   of a path between that ancestor and a sink. If no such ancestor exists,
///   we don't do anything. This way we guarantee that we don't increase the
///   size of the model, but we might miss some optimisations.
///
/// - Ideally, we would use a heuristic to find a middle ground between the
///   two strategies. This would allow the duplication of constants if the
///   size or performance gained from pruning compensates the size loss.
Detaches the constant nodes and edges from the given graph.
The following algorithm is used:
1. Compute the constant underlying graph of the given graph.
2. Compute the undirected connected components of that underlying graph.
3. Choose a pruning strategy and apply it to each connected component.

There are several pruning strategies to choose from:
The simplest is to prune all nodes but the sinks of each component, and
to replace the latter with Const nodes. This might however increase the
size of the model dramatically in cases like the one below, where we'll
end up storing two large constants instead of one while only getting a
neglectible performance boost from the operation.



We could also search for the lowest common ancestor of all the sinks in
each connected component, and prune every node and edge that isn't part
of a path between that ancestor and a sink. If no such ancestor exists,
we don't do anything. This way we guarantee that we don't increase the
size of the model, but we might miss some optimisations.

Ideally, we would use a heuristic to find a middle ground between the
two strategies. This would allow the duplication of constants if the
size or performance gained from pruning compensates the size loss.
Detaches the constant nodes and edges from the given graph . The following algorithm is used : 1 . Compute the constant underlying graph of the given graph . 2 . Compute the undirected connected components of that underlying graph . 3 . Choose a pruning strategy and apply it to each connected component . There are several pruning strategies to choose from : The simplest is to prune all nodes but the sinks of each component and to replace the latter with Const nodes . This might however increase the size of the model dramatically in cases like the one below where we ' ll end up storing two large constants instead of one while only getting a neglectible performance boost from the operation . We could also search for the lowest common ancestor of all the sinks in each connected component and prune every node and edge that isn ' t part of a path between that ancestor and a sink . If no such ancestor exists we don ' t do anything . This way we guarantee that we don ' t increase the size of the model but we might miss some optimisations . Ideally we would use a heuristic to find a middle ground between the two strategies . This would allow the duplication of constants if the size or performance gained from pruning compensates the size loss .
pub fn propagate_constants<M: Borrow<Model>>(analyser: &mut Analyser<M>) -> TractResult<()> {
    let components: Vec<Component> = connected_components(analyser)?;
    info!("Detected {:?} connected components.", components.len());
    let mut const_int_nodes = HashMap::new();
    for component in components {
        for i in component.outputs {
            let tensor = analyser.edges[i].fact.value.concretize().unwrap();
            let const_node_id: usize = if let Some(tensor) = tensor.clone().take_i32s() {
                *const_int_nodes.entry(tensor.clone()).or_insert_with(|| {
                    let node_id = analyser.nodes.len();
                    let node_name = format!("generated_{}", node_id).to_string();
                    let node = build_const_node(node_id, node_name, tensor.into());
                    analyser.nodes.push(node);
                    node_id
                })
            } else {
                let node_id = analyser.nodes.len();
                let node_name = format!("generated_{}", node_id).to_string();
                let node = build_const_node(node_id, node_name, tensor);
                analyser.nodes.push(node);
                node_id
            };
            let edge = &mut analyser.edges[i];
            let old_node_id = edge.from.unwrap().node;
            // Detach the edge from its previous source.
            {
                let successors = &mut analyser.next_edges[old_node_id];
                let position = successors.iter().position(|&i| i == edge.id).unwrap();
                successors.remove(position);
            };
            // Detach the target node from its previous source.
            {
                let predecessors = &mut analyser.nodes[edge.to_node.unwrap()].inputs;
                let position = predecessors
                    .iter()
                    .position(|outlet| outlet.node == old_node_id)
                    .unwrap();
                predecessors[position] = OutletId::new(const_node_id, 0);
            }
            // Attach the edge to its new source.
            edge.from = Some(OutletId::new(const_node_id, 0));
            analyser.prev_edges.push(vec![]);
            analyser.next_edges.push(vec![edge.id]);
        }
    }
    analyser.reset_plan()?;
    Ok(())
}
pub fn propagate_constants < M : Borrow < Model > > ( analyser : & mut Analyser < M > ) -> TractResult < ( ) > { let components : Vec < Component > = connected_components ( analyser ) ? ; info ! ( " " components len ( ) ) ; let mut const_int_nodes = HashMap :: new ( ) ; for component in components { for i in component . outputs { let tensor = analyser . edges [ i ] . fact . value . concretize ( ) . unwrap ( ) ; let const_node_id : usize = if let Some ( tensor ) = tensor . clone ( ) . take_i32s ( ) { * const_int_nodes . entry ( tensor . clone ( ) ) . or_insert_with ( | | { let node_id = analyser . nodes . len ( ) ; let node_name = format ! ( " " node_id ) . to_string ( ) ; let node = build_const_node ( node_id , node_name , tensor . into ( ) ) ; analyser . nodes . push ( node ) ; node_id } ) } else { let node_id = analyser . nodes . len ( ) ; let node_name = format ! ( " " node_id ) . to_string ( ) ; let node = build_const_node ( node_id , node_name , tensor ) ; analyser . nodes . push ( node ) ; node_id } ; let edge = & mut analyser . edges [ i ] ; let old_node_id = edge . from . unwrap ( ) . node ; // Detach the edge from its previous source. { let successors = & mut analyser . next_edges [ old_node_id ] ; let position = successors . iter ( ) . position ( | & i | i == edge . id ) . unwrap ( ) ; successors . remove ( position ) ; } ; // Detach the target node from its previous source. { let predecessors = & mut analyser . nodes [ edge . to_node . unwrap ( ) ] . inputs ; let position = predecessors . iter ( ) . position ( | outlet | outlet . node == old_node_id ) . unwrap ( ) ; predecessors [ position ] = OutletId :: new ( const_node_id , 0 ) ; } // Attach the edge to its new source. edge . from = Some ( OutletId :: new ( const_node_id , 0 ) ) ; analyser . prev_edges . push ( vec ! [ ] ) ; analyser . next_edges . push ( vec ! [ edge id ] ) ; } } analyser . reset_plan ( ) ? ; Ok ( ( ) ) }
Detaches the constant nodes and edges from the given graph.
Detaches the constant nodes and edges from the given graph .
analyser
&mut Analyser<M>