gonum.org/v1/gonum@v0.14.0/graph/complement.go (about)

     1  // Copyright ©2019 The Gonum Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package graph
     6  
     7  // Complement provides the complement of a graph. The complement will not include
     8  // self-edges, and edges within the complement will not hold any information other
     9  // than the nodes in the original graph and the connection topology. Nodes returned
    10  // by the Complement directly or via queries to returned Edges will be those stored
    11  // in the original graph.
    12  type Complement struct {
    13  	Graph
    14  }
    15  
    16  // Edge returns the edge from u to v if such an edge exists and nil otherwise.
    17  // The node v must be directly reachable from u as defined by the From method.
    18  func (g Complement) Edge(uid, vid int64) Edge {
    19  	if g.Graph.Edge(uid, vid) != nil || uid == vid {
    20  		return nil
    21  	}
    22  	u := g.Node(uid)
    23  	v := g.Node(vid)
    24  	if u == nil || v == nil {
    25  		return nil
    26  	}
    27  	return shadow{F: u, T: v}
    28  }
    29  
    30  // From returns all nodes in g that can be reached directly from u in
    31  // the complement.
    32  func (g Complement) From(uid int64) Nodes {
    33  	if g.Node(uid) == nil {
    34  		return Empty
    35  	}
    36  	// At this point, we guarantee that g.Graph.From(uid) returns a set of
    37  	// nodes in g.Nodes(), and that uid corresponds to a node in g.Nodes().
    38  	return newNodeFilterIterator(g.Nodes(), g.Graph.From(uid), uid)
    39  }
    40  
    41  // HasEdgeBetween returns whether an edge exists between nodes x and y.
    42  func (g Complement) HasEdgeBetween(xid, yid int64) bool {
    43  	return xid != yid &&
    44  		g.Node(xid) != nil && g.Node(yid) != nil &&
    45  		!g.Graph.HasEdgeBetween(xid, yid)
    46  }
    47  
    48  // shadow is an edge that is not exposed to the user.
    49  type shadow struct{ F, T Node }
    50  
    51  func (e shadow) From() Node         { return e.F }
    52  func (e shadow) To() Node           { return e.T }
    53  func (e shadow) ReversedEdge() Edge { return shadow{F: e.T, T: e.F} }
    54  
    55  // nodeFilterIterator combines Nodes to produce a single stream of
    56  // filtered nodes.
    57  type nodeFilterIterator struct {
    58  	src Nodes
    59  
    60  	// filter indicates the node in n with the key ID should be filtered out.
    61  	filter map[int64]bool
    62  }
    63  
    64  // newNodeFilterIterator returns a new nodeFilterIterator. The nodes in filter and
    65  // the nodes corresponding the root node ID must be in the src set of nodes. This
    66  // invariant is not checked.
    67  func newNodeFilterIterator(src, filter Nodes, root int64) *nodeFilterIterator {
    68  	n := nodeFilterIterator{src: src, filter: map[int64]bool{root: true}}
    69  	for filter.Next() {
    70  		n.filter[filter.Node().ID()] = true
    71  	}
    72  	filter.Reset()
    73  	n.src.Reset()
    74  	return &n
    75  }
    76  
    77  func (n *nodeFilterIterator) Len() int {
    78  	return n.src.Len() - len(n.filter)
    79  }
    80  
    81  func (n *nodeFilterIterator) Next() bool {
    82  	for n.src.Next() {
    83  		if !n.filter[n.src.Node().ID()] {
    84  			return true
    85  		}
    86  	}
    87  	return false
    88  }
    89  
    90  func (n *nodeFilterIterator) Node() Node {
    91  	return n.src.Node()
    92  }
    93  
    94  func (n *nodeFilterIterator) Reset() {
    95  	n.src.Reset()
    96  }