// Copyright 2014 Sonia Keys
// License MIT: http://opensource.org/licenses/MIT

package graph

// adj_RO.go is code generated from adj_cg.go by directives in graph.go.
// Editing adj_cg.go is okay.
// DO NOT EDIT adj_RO.go.  The RO is for Read Only.

import (
	"errors"
	"fmt"
	"math/rand"

	"github.com/soniakeys/bits"
)

// ArcDensity returns density for an simple directed graph.
//
// See also ArcDensity function.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g AdjacencyList) ArcDensity() float64 {
	return ArcDensity(len(g), g.ArcSize())
}

// ArcSize returns the number of arcs in g.
//
// Note that for an undirected graph without loops, the number of undirected
// edges -- the traditional meaning of graph size -- will be ArcSize()/2.
// On the other hand, if g is an undirected graph that has or may have loops,
// g.ArcSize()/2 is not a meaningful quantity.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g AdjacencyList) ArcSize() int {
	m := 0
	for _, to := range g {
		m += len(to)
	}
	return m
}

// BoundsOk validates that all arcs in g stay within the slice bounds of g.
//
// BoundsOk returns true when no arcs point outside the bounds of g.
// Otherwise it returns false and an example arc that points outside of g.
//
// Most methods of this package assume the BoundsOk condition and may
// panic when they encounter an arc pointing outside of the graph.  This
// function can be used to validate a graph when the BoundsOk condition
// is unknown.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g AdjacencyList) BoundsOk() (ok bool, fr NI, to NI) {
	for fr, to := range g {
		for _, to := range to {
			if to < 0 || to >= NI(len(g)) {
				return false, NI(fr), to
			}
		}
	}
	return true, -1, to
}

// BreadthFirst traverses a directed or undirected graph in breadth
// first order.
//
// Traversal starts at node start and visits the nodes reachable from
// start.  The function visit is called for each node visited.  Nodes
// not reachable from start are not visited.
//
// There are equivalent labeled and unlabeled versions of this method.
//
// See also alt.BreadthFirst, a variant with more options, and
// alt.BreadthFirst2, a direction optimizing variant.
func (g AdjacencyList) BreadthFirst(start NI, visit func(NI)) {
	v := bits.New(len(g))
	v.SetBit(int(start), 1)
	visit(start)
	var next []NI
	for frontier := []NI{start}; len(frontier) > 0; {
		for _, n := range frontier {
			for _, nb := range g[n] {
				if v.Bit(int(nb)) == 0 {
					v.SetBit(int(nb), 1)
					visit(nb)
					next = append(next, nb)
				}
			}
		}
		frontier, next = next, frontier[:0]
	}
}

// Copy makes a deep copy of g.
// Copy also computes the arc size ma, the number of arcs.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g AdjacencyList) Copy() (c AdjacencyList, ma int) {
	c = make(AdjacencyList, len(g))
	for n, to := range g {
		c[n] = append([]NI{}, to...)
		ma += len(to)
	}
	return
}

// DepthFirst traverses a directed or undirected graph in depth
// first order.
//
// Traversal starts at node start and visits the nodes reachable from
// start.  The function visit is called for each node visited.  Nodes
// not reachable from start are not visited.
//
// There are equivalent labeled and unlabeled versions of this method.
//
// See also alt.DepthFirst, a variant with more options.
func (g AdjacencyList) DepthFirst(start NI, visit func(NI)) {
	v := bits.New(len(g))
	var f func(NI)
	f = func(n NI) {
		visit(n)
		v.SetBit(int(n), 1)
		for _, to := range g[n] {
			if v.Bit(int(to)) == 0 {
				f(to)
			}
		}
	}
	f(start)
}

// HasArc returns true if g has any arc from node `fr` to node `to`.
//
// Also returned is the index within the slice of arcs from node `fr`.
// If no arc from `fr` to `to` is present, HasArc returns false, -1.
//
// There are equivalent labeled and unlabeled versions of this method.
//
// See also the method ParallelArcs, which finds all parallel arcs from
// `fr` to `to`.
func (g AdjacencyList) HasArc(fr, to NI) (bool, int) {
	for x, h := range g[fr] {
		if h == to {
			return true, x
		}
	}
	return false, -1
}

// AnyLoop identifies if a graph contains a loop, an arc that leads from a
// a node back to the same node.
//
// If g contains a loop, the method returns true and an example of a node
// with a loop.  If there are no loops in g, the method returns false, -1.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g AdjacencyList) AnyLoop() (bool, NI) {
	for fr, to := range g {
		for _, to := range to {
			if NI(fr) == to {
				return true, to
			}
		}
	}
	return false, -1
}

// AddNode maps a node in a supergraph to a subgraph node.
//
// Argument p must be an NI in supergraph s.Super.  AddNode panics if
// p is not a valid node index of s.Super.
//
// AddNode is idempotent in that it does not add a new node to the subgraph if
// a subgraph node already exists mapped to supergraph node p.
//
// The mapped subgraph NI is returned.
func (s *Subgraph) AddNode(p NI) (b NI) {
	if int(p) < 0 || int(p) >= s.Super.Order() {
		panic(fmt.Sprint("AddNode: NI ", p, " not in supergraph"))
	}
	if b, ok := s.SubNI[p]; ok {
		return b
	}
	a := s.AdjacencyList
	b = NI(len(a))
	s.AdjacencyList = append(a, nil)
	s.SuperNI = append(s.SuperNI, p)
	s.SubNI[p] = b
	return
}

// AddArc adds an arc to a subgraph.
//
// Arguments fr, to must be NIs in supergraph s.Super.  As with AddNode,
// AddArc panics if fr and to are not valid node indexes of s.Super.
//
// The arc specfied by fr, to must exist in s.Super.  Further, the number of
// parallel arcs in the subgraph cannot exceed the number of corresponding
// parallel arcs in the supergraph.  That is, each arc already added to the
// subgraph counts against the arcs available in the supergraph.  If a matching
// arc is not available, AddArc returns an error.
//
// If a matching arc is available, subgraph nodes are added as needed, the
// subgraph arc is added, and the method returns nil.
func (s *Subgraph) AddArc(fr NI, to NI) error {
	// verify supergraph NIs first, but without adding subgraph nodes just yet.
	if int(fr) < 0 || int(fr) >= s.Super.Order() {
		panic(fmt.Sprint("AddArc: NI ", fr, " not in supergraph"))
	}
	if int(to) < 0 || int(to) >= s.Super.Order() {
		panic(fmt.Sprint("AddArc: NI ", to, " not in supergraph"))
	}
	// count existing matching arcs in subgraph
	n := 0
	a := s.AdjacencyList
	if bf, ok := s.SubNI[fr]; ok {
		if bt, ok := s.SubNI[to]; ok {
			// both NIs already exist in subgraph, need to count arcs
			bTo := to
			bTo = bt
			for _, t := range a[bf] {
				if t == bTo {
					n++
				}
			}
		}
	}
	// verify matching arcs are available in supergraph
	for _, t := range (*s.Super)[fr] {
		if t == to {
			if n > 0 {
				n-- // match existing arc
				continue
			}
			// no more existing arcs need to be matched.  nodes can finally
			// be added as needed and then the arc can be added.
			bf := s.AddNode(fr)
			to = s.AddNode(to)
			s.AdjacencyList[bf] = append(s.AdjacencyList[bf], to)
			return nil // success
		}
	}
	return errors.New("arc not available in supergraph")
}

func (super AdjacencyList) induceArcs(sub map[NI]NI, sup []NI) AdjacencyList {
	s := make(AdjacencyList, len(sup))
	for b, p := range sup {
		var a []NI
		for _, to := range super[p] {
			if bt, ok := sub[to]; ok {
				to = bt
				a = append(a, to)
			}
		}
		s[b] = a
	}
	return s
}

// InduceList constructs a node-induced subgraph.
//
// The subgraph is induced on receiver graph g.  Argument l must be a list of
// NIs in receiver graph g.  Receiver g becomes the supergraph of the induced
// subgraph.
//
// Duplicate NIs are allowed in list l.  The duplicates are effectively removed
// and only a single corresponding node is created in the subgraph.  Subgraph
// NIs are mapped in the order of list l, execpt for ignoring duplicates.
// NIs in l that are not in g will panic.
//
// Returned is the constructed Subgraph object containing the induced subgraph
// and the mappings to the supergraph.
func (g *AdjacencyList) InduceList(l []NI) *Subgraph {
	sub, sup := mapList(l)
	return &Subgraph{
		Super:   g,
		SubNI:   sub,
		SuperNI: sup,

		AdjacencyList: g.induceArcs(sub, sup)}
}

// InduceBits constructs a node-induced subgraph.
//
// The subgraph is induced on receiver graph g.  Argument t must be a bitmap
// representing NIs in receiver graph g.  Receiver g becomes the supergraph
// of the induced subgraph.  NIs in t that are not in g will panic.
//
// Returned is the constructed Subgraph object containing the induced subgraph
// and the mappings to the supergraph.
func (g *AdjacencyList) InduceBits(t bits.Bits) *Subgraph {
	sub, sup := mapBits(t)
	return &Subgraph{
		Super:   g,
		SubNI:   sub,
		SuperNI: sup,

		AdjacencyList: g.induceArcs(sub, sup)}
}

// IsSimple checks for loops and parallel arcs.
//
// A graph is "simple" if it has no loops or parallel arcs.
//
// IsSimple returns true, -1 for simple graphs.  If a loop or parallel arc is
// found, simple returns false and a node that represents a counterexample
// to the graph being simple.
//
// See also separate methods AnyLoop and AnyParallel.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g AdjacencyList) IsSimple() (ok bool, n NI) {
	if lp, n := g.AnyLoop(); lp {
		return false, n
	}
	if pa, n, _ := g.AnyParallel(); pa {
		return false, n
	}
	return true, -1
}

// IsolatedNodes returns a bitmap of isolated nodes in receiver graph g.
//
// An isolated node is one with no arcs going to or from it.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g AdjacencyList) IsolatedNodes() (i bits.Bits) {
	i = bits.New(len(g))
	i.SetAll()
	for fr, to := range g {
		if len(to) > 0 {
			i.SetBit(fr, 0)
			for _, to := range to {
				i.SetBit(int(to), 0)
			}
		}
	}
	return
}

// Order is the number of nodes in receiver g.
//
// It is simply a wrapper method for the Go builtin len().
//
// There are equivalent labeled and unlabeled versions of this method.
func (g AdjacencyList) Order() int {
	// Why a wrapper for len()?  Mostly for Directed and Undirected.
	// u.Order() is a little nicer than len(u.LabeledAdjacencyList).
	return len(g)
}

// ParallelArcs identifies all arcs from node `fr` to node `to`.
//
// The returned slice contains an element for each arc from node `fr` to node `to`.
// The element value is the index within the slice of arcs from node `fr`.
//
// There are equivalent labeled and unlabeled versions of this method.
//
// See also the method HasArc, which stops after finding a single arc.
func (g AdjacencyList) ParallelArcs(fr, to NI) (p []int) {
	for x, h := range g[fr] {
		if h == to {
			p = append(p, x)
		}
	}
	return
}

// Permute permutes the node labeling of receiver g.
//
// Argument p must be a permutation of the node numbers of the graph,
// 0 through len(g)-1.  A permutation returned by rand.Perm(len(g)) for
// example is acceptable.
//
// The graph is permuted in place.  The graph keeps the same underlying
// memory but values of the graph representation are permuted to produce
// an isomorphic graph.  The node previously labeled 0 becomes p[0] and so on.
// See example (or the code) for clarification.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g AdjacencyList) Permute(p []int) {
	old := append(AdjacencyList{}, g...) // shallow copy
	for fr, arcs := range old {
		for i, to := range arcs {
			arcs[i] = NI(p[to])
		}
		g[p[fr]] = arcs
	}
}

// ShuffleArcLists shuffles the arc lists of each node of receiver g.
//
// For example a node with arcs leading to nodes 3 and 7 might have an
// arc list of either [3 7] or [7 3] after calling this method.  The
// connectivity of the graph is not changed.  The resulting graph stays
// equivalent but a traversal will encounter arcs in a different
// order.
//
// If Rand r is nil, the rand package default shared source is used.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g AdjacencyList) ShuffleArcLists(r *rand.Rand) {
	ri := rand.Intn
	if r != nil {
		ri = r.Intn
	}
	// Knuth-Fisher-Yates
	for _, to := range g {
		for i := len(to); i > 1; {
			j := ri(i)
			i--
			to[i], to[j] = to[j], to[i]
		}
	}
}
