pub(crate) fn ownership_constraints<P>(
        circuit: &Circuit<P>,
    ) -> Result<Vec<(NodeId, NodeId)>, Error> {
        // Compute successors of each node in the circuit.  Note: we index successors by
        // origin id, not local node id, since the former uniquely identifies a
        // stream, but the latter doesn't, since a subcircuit node can have
        // multiple output streams.
        let num_nodes = circuit.num_nodes();
        let mut successors: HashMap<GlobalNodeId, Vec<(NodeId, Option<OwnershipPreference>)>> =
            HashMap::with_capacity(num_nodes);

        for edge in circuit.edges().deref().iter() {
            successors
                .entry(edge.origin.clone())
                .or_insert_with(Vec::new)
                .push((edge.to, edge.ownership_preference));
        }

        let mut constraints = Vec::new();

        for (origin, succ) in successors.into_iter() {
            // Find all strong successors of a node.
            let strong_successors: Vec<_> = succ
                .iter()
                .enumerate()
                .filter(|(_i, (_, pref))| {
                    pref.is_some() && pref.unwrap() >= OwnershipPreference::STRONGLY_PREFER_OWNED
                })
                .collect();

            // Declare conflict if there's more than one strong successor.
            if strong_successors.len() > 1 {
                return Err(Error::OwnershipConflict {
                    origin,
                    consumers: strong_successors
                        .into_iter()
                        .map(|(_, (suc, _))| GlobalNodeId::child_of(circuit, *suc))
                        .collect(),
                });
            };

            // No strong successors -- nothing to do for this node.
            if strong_successors.is_empty() {
                continue;
            }

            // A unique strong successor found; add edges from all other successors to it.
            let strong_successor_index = strong_successors[0].0;
            for (i, successor) in succ.iter().enumerate() {
                // Ignore dependency edges.
                if i != strong_successor_index && successor.1.is_some() {
                    constraints.push((successor.0, succ[strong_successor_index].0));
                }
            }
        }

        Ok(constraints)
    }
/// Helper function used by schedulers to enforce ownership preferences.
///
/// Individual schedulers can implement their own algorithms to enforce (or
/// ignore) ownership preferences.  This helper function can optionally
/// used by schedulers that wish to implement one particular approach.
/// The idea is to treat **strong** ownership preferences
/// (`OwnershipPreference::STRONGLY_PREFER_OWNED` and above) as scheduling
/// constraints: assuming an operator has exactly one successor with a
/// strong ownership preference ("strong successor"), we can enforce
/// this preference by scheduling this successor last. This scheduling
/// constraint can in turn be enforced by adding a dependency edge from
/// all other successors to the strong successor node to the circuit graph.
/// This function computes the set of dependency edges needed to enforce
/// all such constraints in the circuit.
///
/// # Caveat
///
/// The additional edges computed by this function can introduce cycles to
/// the circuit graph making it unschedulable.  Schedulers must check
/// for cycles before adding these constraints and either fail or drop
/// some of the constraints to eliminate cycles.
///
/// (Current scheduler implementations fail if there is a cycle).
///
/// # Errors
///
/// The function fails with [`Error::OwnershipConflict`] if the circuit has
/// at least one node with multiple strong successors.
Helper function used by schedulers to enforce ownership preferences.
Individual schedulers can implement their own algorithms to enforce (or
ignore) ownership preferences.  This helper function can optionally
used by schedulers that wish to implement one particular approach.
The idea is to treat **strong** ownership preferences
(`OwnershipPreference::STRONGLY_PREFER_OWNED` and above) as scheduling
constraints: assuming an operator has exactly one successor with a
strong ownership preference ("strong successor"), we can enforce
this preference by scheduling this successor last. This scheduling
constraint can in turn be enforced by adding a dependency edge from
all other successors to the strong successor node to the circuit graph.
This function computes the set of dependency edges needed to enforce
all such constraints in the circuit.
Helper function used by schedulers to enforce ownership preferences . Individual schedulers can implement their own algorithms to enforce ( or ignore ) ownership preferences . This helper function can optionally used by schedulers that wish to implement one particular approach . The idea is to treat ** strong ** ownership preferences ( ` OwnershipPreference :: STRONGLY_PREFER_OWNED ` and above ) as scheduling constraints : assuming an operator has exactly one successor with a strong ownership preference ( " strong successor " ) we can enforce this preference by scheduling this successor last . This scheduling constraint can in turn be enforced by adding a dependency edge from all other successors to the strong successor node to the circuit graph . This function computes the set of dependency edges needed to enforce all such constraints in the circuit .
pub(crate) fn ownership_constraints<P>(
        circuit: &Circuit<P>,
    ) -> Result<Vec<(NodeId, NodeId)>, Error> {
        // Compute successors of each node in the circuit.  Note: we index successors by
        // origin id, not local node id, since the former uniquely identifies a
        // stream, but the latter doesn't, since a subcircuit node can have
        // multiple output streams.
        let num_nodes = circuit.num_nodes();
        let mut successors: HashMap<GlobalNodeId, Vec<(NodeId, Option<OwnershipPreference>)>> =
            HashMap::with_capacity(num_nodes);
        for edge in circuit.edges().deref().iter() {
            successors
                .entry(edge.origin.clone())
                .or_insert_with(Vec::new)
                .push((edge.to, edge.ownership_preference));
        }
        let mut constraints = Vec::new();
        for (origin, succ) in successors.into_iter() {
            // Find all strong successors of a node.
            let strong_successors: Vec<_> = succ
                .iter()
                .enumerate()
                .filter(|(_i, (_, pref))| {
                    pref.is_some() && pref.unwrap() >= OwnershipPreference::STRONGLY_PREFER_OWNED
                })
                .collect();
            // Declare conflict if there's more than one strong successor.
            if strong_successors.len() > 1 {
                return Err(Error::OwnershipConflict {
                    origin,
                    consumers: strong_successors
                        .into_iter()
                        .map(|(_, (suc, _))| GlobalNodeId::child_of(circuit, *suc))
                        .collect(),
                });
            };
            // No strong successors -- nothing to do for this node.
            if strong_successors.is_empty() {
                continue;
            }
            // A unique strong successor found; add edges from all other successors to it.
            let strong_successor_index = strong_successors[0].0;
            for (i, successor) in succ.iter().enumerate() {
                // Ignore dependency edges.
                if i != strong_successor_index && successor.1.is_some() {
                    constraints.push((successor.0, succ[strong_successor_index].0));
                }
            }
        }
        Ok(constraints)
    }
pub ( crate ) fn ownership_constraints < P > ( circuit : & Circuit < P > , ) -> Result < Vec < ( NodeId , NodeId ) > , Error > { // Compute successors of each node in the circuit.  Note: we index successors by // origin id, not local node id, since the former uniquely identifies a // stream, but the latter doesn't, since a subcircuit node can have // multiple output streams. let num_nodes = circuit . num_nodes ( ) ; let mut successors : HashMap < GlobalNodeId , Vec < ( NodeId , Option < OwnershipPreference > ) > > = HashMap :: with_capacity ( num_nodes ) ; for edge in circuit . edges ( ) . deref ( ) . iter ( ) { successors . entry ( edge . origin . clone ( ) ) . or_insert_with ( Vec :: new ) . push ( ( edge . to , edge . ownership_preference ) ) ; } let mut constraints = Vec :: new ( ) ; for ( origin , succ ) in successors . into_iter ( ) { // Find all strong successors of a node. let strong_successors : Vec < _ > = succ . iter ( ) . enumerate ( ) . filter ( | ( _i , ( _ , pref ) ) | { pref . is_some ( ) && pref . unwrap ( ) >= OwnershipPreference :: STRONGLY_PREFER_OWNED } ) . collect ( ) ; // Declare conflict if there's more than one strong successor. if strong_successors . len ( ) > 1 { return Err ( Error :: OwnershipConflict { origin , consumers : strong_successors . into_iter ( ) . map ( | ( _ , ( suc , _ ) ) | GlobalNodeId :: child_of ( circuit , * suc ) ) . collect ( ) , } ) ; } ; // No strong successors -- nothing to do for this node. if strong_successors . is_empty ( ) { continue ; } // A unique strong successor found; add edges from all other successors to it. let strong_successor_index = strong_successors [ 0 ] . 0 ; for ( i , successor ) in succ . iter ( ) . enumerate ( ) { // Ignore dependency edges. if i != strong_successor_index && successor . 1 . is_some ( ) { constraints . push ( ( successor . 0 , succ [ strong_successor_index ] . 0 ) ) ; } } } Ok ( constraints ) }
Helper function used by schedulers to enforce ownership preferences.
Helper function used by schedulers to enforce ownership preferences .
circuit
&Circuit<P>
caveat
The additional edges computed by this function can introduce cycles to
the circuit graph making it unschedulable.  Schedulers must check
for cycles before adding these constraints and either fail or drop
some of the constraints to eliminate cycles.

(Current scheduler implementations fail if there is a cycle).
The additional edges computed by this function can introduce cycles to the circuit graph making it unschedulable . Schedulers must check for cycles before adding these constraints and either fail or drop some of the constraints to eliminate cycles . ( Current scheduler implementations fail if there is a cycle ) .
errors
The function fails with [`Error::OwnershipConflict`] if the circuit has
at least one node with multiple strong successors.
The function fails with [ ` Error :: OwnershipConflict ` ] if the circuit has at least one node with multiple strong successors .