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

package graph

// undir.go has methods specific to undirected graphs, Undirected and
// LabeledUndirected.

import (
	"fmt"

	"github.com/soniakeys/bits"
)

// AddEdge adds an edge to a graph.
//
// It can be useful for constructing undirected graphs.
//
// When n1 and n2 are distinct, it adds the arc n1->n2 and the reciprocal
// n2->n1.  When n1 and n2 are the same, it adds a single arc loop.
//
// The pointer receiver allows the method to expand the graph as needed
// to include the values n1 and n2.  If n1 or n2 happen to be greater than
// len(*p) the method does not panic, but simply expands the graph.
//
// If you know or can compute the final graph order however, consider
// preallocating to avoid any overhead of expanding the graph.
// See second example, "More".
func (p *Undirected) AddEdge(n1, n2 NI) {
	// Similar code in LabeledAdjacencyList.AddEdge.

	// determine max of the two end points
	max := n1
	if n2 > max {
		max = n2
	}
	// expand graph if needed, to include both
	g := p.AdjacencyList
	if int(max) >= len(g) {
		p.AdjacencyList = make(AdjacencyList, max+1)
		copy(p.AdjacencyList, g)
		g = p.AdjacencyList
	}
	// create one half-arc,
	g[n1] = append(g[n1], n2)
	// and except for loops, create the reciprocal
	if n1 != n2 {
		g[n2] = append(g[n2], n1)
	}
}

// RemoveEdge removes a single edge between nodes n1 and n2.
//
// It removes reciprocal arcs in the case of distinct n1 and n2 or removes
// a single arc loop in the case of n1 == n2.
//
// Returns true if the specified edge is found and successfully removed,
// false if the edge does not exist.
func (g Undirected) RemoveEdge(n1, n2 NI) (ok bool) {
	ok, x1, x2 := g.HasEdge(n1, n2)
	if !ok {
		return
	}
	a := g.AdjacencyList
	to := a[n1]
	last := len(to) - 1
	to[x1] = to[last]
	a[n1] = to[:last]
	if n1 == n2 {
		return
	}
	to = a[n2]
	last = len(to) - 1
	to[x2] = to[last]
	a[n2] = to[:last]
	return
}

// ArcDensity returns density for a simple directed graph.
//
// Parameter n is order, or number of nodes of a simple directed graph.
// Parameter a is the arc size, or number of directed arcs.
//
// Returned density is the fraction `a` over the total possible number of arcs
// or a / (n * (n-1)).
//
// See also Density for density of a simple undirected graph.
//
// See also the corresponding methods AdjacencyList.ArcDensity and
// LabeledAdjacencyList.ArcDensity.
func ArcDensity(n, a int) float64 {
	return float64(a) / (float64(n) * float64(n-1))
}

// Density returns density for a simple undirected graph.
//
// Parameter n is order, or number of nodes of a simple undirected graph.
// Parameter m is the size, or number of undirected edges.
//
// Returned density is the fraction m over the total possible number of edges
// or m / ((n * (n-1))/2).
//
// See also ArcDensity for simple directed graphs.
//
// See also the corresponding methods AdjacencyList.Density and
// LabeledAdjacencyList.Density.
func Density(n, m int) float64 {
	return float64(m) * 2 / (float64(n) * float64(n-1))
}

// An EdgeVisitor is an argument to some traversal methods.
//
// Traversal methods call the visitor function for each edge visited.
// Argument e is the edge being visited.
type EdgeVisitor func(e Edge)

// Edges iterates over the edges of an undirected graph.
//
// Edge visitor v is called for each edge of the graph.  That is, it is called
// once for each reciprocal arc pair and once for each loop.
//
// See also LabeledUndirected.Edges for a labeled version.
// See also Undirected.SimpleEdges for a version that emits only the simple
// subgraph.
func (g Undirected) Edges(v EdgeVisitor) {
	a := g.AdjacencyList
	unpaired := make(AdjacencyList, len(a))
	for fr, to := range a {
	arc: // for each arc in a
		for _, to := range to {
			if to == NI(fr) {
				v(Edge{NI(fr), to}) // output loop
				continue
			}
			// search unpaired arcs
			ut := unpaired[to]
			for i, u := range ut {
				if u == NI(fr) { // found reciprocal
					v(Edge{u, to}) // output edge
					last := len(ut) - 1
					ut[i] = ut[last]
					unpaired[to] = ut[:last]
					continue arc
				}
			}
			// reciprocal not found
			unpaired[fr] = append(unpaired[fr], to)
		}
	}
	// undefined behavior is that unpaired arcs are silently ignored.
}

// FromList builds a forest with a tree spanning each connected component.
//
// For each component a root is chosen and spanning is done with the method
// Undirected.SpanTree, and so is breadth-first.  Returned is a FromList with
// all spanned trees, a list of roots chosen, and a bool indicating if the
// receiver graph g was found to be a simple graph connected as a forest.
// Any cycles, loops, or parallel edges in any component will cause
// simpleForest to be false, but FromList f will still be populated with
// a valid and complete spanning forest.
func (g Undirected) FromList() (f FromList, roots []NI, simpleForest bool) {
	p := make([]PathEnd, g.Order())
	for i := range p {
		p[i].From = -1
	}
	f.Paths = p
	simpleForest = true
	ts := 0
	for n := range g.AdjacencyList {
		if p[n].From >= 0 {
			continue
		}
		roots = append(roots, NI(n))
		ns, st := g.SpanTree(NI(n), &f)
		if !st {
			simpleForest = false
		}
		ts += ns
		if ts == len(p) {
			break
		}
	}
	return
}

// HasEdge returns true if g has any edge between nodes n1 and n2.
//
// Also returned are indexes x1 and x2 such that g[n1][x1] == n2
// and g[n2][x2] == n1.  If no edge between n1 and n2 is present HasArc
// returns `has` == false.
//
// See also HasArc.  If you are interested only in the boolean result and
// g is a well formed (passes IsUndirected) then HasArc is an adequate test.
func (g Undirected) HasEdge(n1, n2 NI) (has bool, x1, x2 int) {
	if has, x1 = g.HasArc(n1, n2); !has {
		return has, x1, x1
	}
	has, x2 = g.HasArc(n2, n1)
	return
}

// SimpleEdges iterates over the edges of the simple subgraph of an undirected
// graph.
//
// Edge visitor v is called for each pair of distinct nodes that is connected
// with an edge.  That is, loops are ignored and parallel edges are reduced to
// a single edge.
//
// See also Undirected.Edges for a version that emits all edges.
func (g Undirected) SimpleEdges(v EdgeVisitor) {
	for fr, to := range g.AdjacencyList {
		e := bits.New(len(g.AdjacencyList))
		for _, to := range to {
			if to > NI(fr) && e.Bit(int(to)) == 0 {
				e.SetBit(int(to), 1)
				v(Edge{NI(fr), to})
			}
		}
	}
	// undefined behavior is that unpaired arcs may or may not be emitted.
}

// SpanTree builds a tree spanning a connected component.
//
// The component is spanned by breadth-first search from the given root.
// The resulting spanning tree in stored a FromList.
//
// If FromList.Paths is not the same length as g, it is allocated and
// initialized. This allows a zero value FromList to be passed as f.
// If FromList.Paths is the same length as g, it is used as is and is not
// reinitialized. This allows multiple trees to be spanned in the same
// FromList with successive calls.
//
// For nodes spanned, the Path member of the returned FromList is populated
// with both From and Len values.  The MaxLen member will be updated but
// not Leaves.
//
// Returned is the number of nodes spanned, which will be the number of nodes
// in the component, and a bool indicating if the component was found to be a
// simply connected unrooted tree in the receiver graph g.  Any cycles, loops,
// or parallel edges in the component will cause simpleTree to be false, but
// FromList f will still be populated with a valid and complete spanning tree.
func (g Undirected) SpanTree(root NI, f *FromList) (nSpanned int, simpleTree bool) {
	a := g.AdjacencyList
	p := f.Paths
	if len(p) != len(a) {
		p = make([]PathEnd, len(a))
		for i := range p {
			p[i].From = -1
		}
		f.Paths = p
	}
	simpleTree = true
	p[root] = PathEnd{From: -1, Len: 1}
	type arc struct {
		from NI
		half NI
	}
	var next []arc
	frontier := []arc{{-1, root}}
	for len(frontier) > 0 {
		for _, fa := range frontier { // fa frontier arc
			nSpanned++
			l := p[fa.half].Len + 1
			for _, to := range a[fa.half] {
				if to == fa.from {
					continue
				}
				if p[to].Len > 0 {
					simpleTree = false
					continue
				}
				p[to] = PathEnd{From: fa.half, Len: l}
				if l > f.MaxLen {
					f.MaxLen = l
				}
				next = append(next, arc{fa.half, to})
			}
		}
		frontier, next = next, frontier[:0]
	}
	return
}

// TarjanBiconnectedComponents decomposes a graph into maximal biconnected
// components, components for which if any node were removed the component
// would remain connected.
//
// The receiver g must be a simple graph.  The method calls the emit argument
// for each component identified, as long as emit returns true.  If emit
// returns false, TarjanBiconnectedComponents returns immediately.
//
// See also the eqivalent labeled TarjanBiconnectedComponents.
func (g Undirected) TarjanBiconnectedComponents(emit func([]Edge) bool) {
	// Implemented closely to pseudocode in "Depth-first search and linear
	// graph algorithms", Robert Tarjan, SIAM J. Comput. Vol. 1, No. 2,
	// June 1972.
	//
	// Note Tarjan's "adjacency structure" is graph.AdjacencyList,
	// His "adjacency list" is an element of a graph.AdjacencyList, also
	// termed a "to-list", "neighbor list", or "child list."
	a := g.AdjacencyList
	number := make([]int, len(a))
	lowpt := make([]int, len(a))
	var stack []Edge
	var i int
	var biconnect func(NI, NI) bool
	biconnect = func(v, u NI) bool {
		i++
		number[v] = i
		lowpt[v] = i
		for _, w := range a[v] {
			if number[w] == 0 {
				stack = append(stack, Edge{v, w})
				if !biconnect(w, v) {
					return false
				}
				if lowpt[w] < lowpt[v] {
					lowpt[v] = lowpt[w]
				}
				if lowpt[w] >= number[v] {
					var bcc []Edge
					top := len(stack) - 1
					for number[stack[top].N1] >= number[w] {
						bcc = append(bcc, stack[top])
						stack = stack[:top]
						top--
					}
					bcc = append(bcc, stack[top])
					stack = stack[:top]
					top--
					if !emit(bcc) {
						return false
					}
				}
			} else if number[w] < number[v] && w != u {
				stack = append(stack, Edge{v, w})
				if number[w] < lowpt[v] {
					lowpt[v] = number[w]
				}
			}
		}
		return true
	}
	for w := range a {
		if number[w] == 0 && !biconnect(NI(w), -1) {
			return
		}
	}
}

func (g Undirected) BlockCut(block func([]Edge) bool, cut func(NI) bool, isolated func(NI) bool) {
	a := g.AdjacencyList
	number := make([]int, len(a))
	lowpt := make([]int, len(a))
	var stack []Edge
	var i, rc int
	var biconnect func(NI, NI) bool
	biconnect = func(v, u NI) bool {
		i++
		number[v] = i
		lowpt[v] = i
		for _, w := range a[v] {
			if number[w] == 0 {
				if u < 0 {
					rc++
				}
				stack = append(stack, Edge{v, w})
				if !biconnect(w, v) {
					return false
				}
				if lowpt[w] < lowpt[v] {
					lowpt[v] = lowpt[w]
				}
				if lowpt[w] >= number[v] {
					if u >= 0 && !cut(v) {
						return false
					}
					var bcc []Edge
					top := len(stack) - 1
					for number[stack[top].N1] >= number[w] {
						bcc = append(bcc, stack[top])
						stack = stack[:top]
						top--
					}
					bcc = append(bcc, stack[top])
					stack = stack[:top]
					top--
					if !block(bcc) {
						return false
					}
				}
			} else if number[w] < number[v] && w != u {
				stack = append(stack, Edge{v, w})
				if number[w] < lowpt[v] {
					lowpt[v] = number[w]
				}
			}
		}
		if u < 0 && rc > 1 {
			return cut(v)
		}
		return true
	}
	for w := range a {
		if number[w] > 0 {
			continue
		}
		if len(a[w]) == 0 {
			if !isolated(NI(w)) {
				return
			}
			continue
		}
		rc = 0
		if !biconnect(NI(w), -1) {
			return
		}
	}
}

// AddEdge adds an edge to a labeled graph.
//
// It can be useful for constructing undirected graphs.
//
// When n1 and n2 are distinct, it adds the arc n1->n2 and the reciprocal
// n2->n1.  When n1 and n2 are the same, it adds a single arc loop.
//
// If the edge already exists in *p, a parallel edge is added.
//
// The pointer receiver allows the method to expand the graph as needed
// to include the values n1 and n2.  If n1 or n2 happen to be greater than
// len(*p) the method does not panic, but simply expands the graph.
func (p *LabeledUndirected) AddEdge(e Edge, l LI) {
	// Similar code in AdjacencyList.AddEdge.

	// determine max of the two end points
	max := e.N1
	if e.N2 > max {
		max = e.N2
	}
	// expand graph if needed, to include both
	g := p.LabeledAdjacencyList
	if max >= NI(len(g)) {
		p.LabeledAdjacencyList = make(LabeledAdjacencyList, max+1)
		copy(p.LabeledAdjacencyList, g)
		g = p.LabeledAdjacencyList
	}
	// create one half-arc,
	g[e.N1] = append(g[e.N1], Half{To: e.N2, Label: l})
	// and except for loops, create the reciprocal
	if e.N1 != e.N2 {
		g[e.N2] = append(g[e.N2], Half{To: e.N1, Label: l})
	}
}

// A LabeledEdgeVisitor is an argument to some traversal methods.
//
// Traversal methods call the visitor function for each edge visited.
// Argument e is the edge being visited.
type LabeledEdgeVisitor func(e LabeledEdge)

// Edges iterates over the edges of a labeled undirected graph.
//
// Edge visitor v is called for each edge of the graph.  That is, it is called
// once for each reciprocal arc pair and once for each loop.
//
// See also Undirected.Edges for an unlabeled version.
// See also the more simplistic LabeledAdjacencyList.ArcsAsEdges.
func (g LabeledUndirected) Edges(v LabeledEdgeVisitor) {
	// similar code in LabeledAdjacencyList.InUndirected
	a := g.LabeledAdjacencyList
	unpaired := make(LabeledAdjacencyList, len(a))
	for fr, to := range a {
	arc: // for each arc in a
		for _, to := range to {
			if to.To == NI(fr) {
				v(LabeledEdge{Edge{NI(fr), to.To}, to.Label}) // output loop
				continue
			}
			// search unpaired arcs
			ut := unpaired[to.To]
			for i, u := range ut {
				if u.To == NI(fr) && u.Label == to.Label { // found reciprocal
					v(LabeledEdge{Edge{NI(fr), to.To}, to.Label}) // output edge
					last := len(ut) - 1
					ut[i] = ut[last]
					unpaired[to.To] = ut[:last]
					continue arc
				}
			}
			// reciprocal not found
			unpaired[fr] = append(unpaired[fr], to)
		}
	}
}

// FromList builds a forest with a tree spanning each connected component in g.
//
// A root is chosen and spanning is done with the LabeledUndirected.SpanTree
// method, and so is breadth-first.  Returned is a FromList with all spanned
// trees, labels corresponding to arcs in f,
// a list of roots chosen, and a bool indicating if the receiver graph g was
// found to be a simple graph connected as a forest.  Any cycles, loops, or
// parallel edges in any component will cause simpleForest to be false, but
// FromList f will still be populated with a valid and complete spanning forest.

// FromList builds a forest with a tree spanning each connected component.
//
// For each component a root is chosen and spanning is done with the method
// Undirected.SpanTree, and so is breadth-first.  Returned is a FromList with
// all spanned trees, labels corresponding to arcs in f, a list of roots
// chosen, and a bool indicating if the receiver graph g was found to be a
// simple graph connected as a forest.  Any cycles, loops, or parallel edges
// in any component will cause simpleForest to be false, but FromList f will
// still be populated with a valid and complete spanning forest.
func (g LabeledUndirected) FromList() (f FromList, labels []LI, roots []NI, simpleForest bool) {
	p := make([]PathEnd, g.Order())
	for i := range p {
		p[i].From = -1
	}
	f.Paths = p
	labels = make([]LI, len(p))
	simpleForest = true
	ts := 0
	for n := range g.LabeledAdjacencyList {
		if p[n].From >= 0 {
			continue
		}
		roots = append(roots, NI(n))
		ns, st := g.SpanTree(NI(n), &f, labels)
		if !st {
			simpleForest = false
		}
		ts += ns
		if ts == len(p) {
			break
		}
	}
	return
}

// SpanTree builds a tree spanning a connected component.
//
// The component is spanned by breadth-first search from the given root.
// The resulting spanning tree in stored a FromList, and arc labels optionally
// stored in a slice.
//
// If FromList.Paths is not the same length as g, it is allocated and
// initialized.  This allows a zero value FromList to be passed as f.
// If FromList.Paths is the same length as g, it is used as is and is not
// reinitialized.  This allows multiple trees to be spanned in the same
// FromList with successive calls.
//
// For nodes spanned, the Path member of returned FromList f is populated
// populated with both From and Len values.  The MaxLen member will be
// updated but not Leaves.
//
// The labels slice will be populated only if it is same length as g.
// Nil can be passed for example if labels are not needed.
//
// Returned is the number of nodes spanned, which will be the number of nodes
// in the component, and a bool indicating if the component was found to be a
// simply connected unrooted tree in the receiver graph g.  Any cycles, loops,
// or parallel edges in the component will cause simpleTree to be false, but
// FromList f will still be populated with a valid and complete spanning tree.
func (g LabeledUndirected) SpanTree(root NI, f *FromList, labels []LI) (nSpanned int, simple bool) {
	a := g.LabeledAdjacencyList
	p := f.Paths
	if len(p) != len(a) {
		p = make([]PathEnd, len(a))
		for i := range p {
			p[i].From = -1
		}
		f.Paths = p
	}
	simple = true
	p[root].Len = 1
	type arc struct {
		from NI
		half Half
	}
	var next []arc
	frontier := []arc{{-1, Half{root, -1}}}
	for len(frontier) > 0 {
		for _, fa := range frontier { // fa frontier arc
			nSpanned++
			l := p[fa.half.To].Len + 1
			for _, to := range a[fa.half.To] {
				if to.To == fa.from && to.Label == fa.half.Label {
					continue
				}
				if p[to.To].Len > 0 {
					simple = false
					continue
				}
				p[to.To] = PathEnd{From: fa.half.To, Len: l}
				if len(labels) == len(p) {
					labels[to.To] = to.Label
				}
				if l > f.MaxLen {
					f.MaxLen = l
				}
				next = append(next, arc{fa.half.To, to})
			}
		}
		frontier, next = next, frontier[:0]
	}
	return
}

// HasEdge returns true if g has any edge between nodes n1 and n2.
//
// Also returned are indexes x1 and x2 such that g[n1][x1] == Half{n2, l}
// and g[n2][x2] == {n1, l} for some label l.  If no edge between n1 and n2
// exists, HasArc returns `has` == false.
//
// See also HasArc.  If you are only interested in the boolean result then
// HasArc is an adequate test.
func (g LabeledUndirected) HasEdge(n1, n2 NI) (has bool, x1, x2 int) {
	if has, x1 = g.HasArc(n1, n2); !has {
		return has, x1, x1
	}
	has, x2 = g.HasArcLabel(n2, n1, g.LabeledAdjacencyList[n1][x1].Label)
	return
}

// HasEdgeLabel returns true if g has any edge between nodes n1 and n2 with
// label l.
//
// Also returned are indexes x1 and x2 such that g[n1][x1] == Half{n2, l}
// and g[n2][x2] == Half{n1, l}.  If no edge between n1 and n2 with label l
// is present HasArc returns `has` == false.
func (g LabeledUndirected) HasEdgeLabel(n1, n2 NI, l LI) (has bool, x1, x2 int) {
	if has, x1 = g.HasArcLabel(n1, n2, l); !has {
		return has, x1, x1
	}
	has, x2 = g.HasArcLabel(n2, n1, l)
	return
}

// RemoveEdge removes a single edge between nodes n1 and n2.
//
// It removes reciprocal arcs in the case of distinct n1 and n2 or removes
// a single arc loop in the case of n1 == n2.
//
// If the specified edge is found and successfully removed, RemoveEdge returns
// true and the label of the edge removed.  If no edge exists between n1 and n2,
// RemoveEdge returns false, 0.
func (g LabeledUndirected) RemoveEdge(n1, n2 NI) (ok bool, label LI) {
	ok, x1, x2 := g.HasEdge(n1, n2)
	if !ok {
		return
	}
	a := g.LabeledAdjacencyList
	to := a[n1]
	label = to[x1].Label // return value
	last := len(to) - 1
	to[x1] = to[last]
	a[n1] = to[:last]
	if n1 == n2 {
		return
	}
	to = a[n2]
	last = len(to) - 1
	to[x2] = to[last]
	a[n2] = to[:last]
	return
}

// RemoveEdgeLabel removes a single edge between nodes n1 and n2 with label l.
//
// It removes reciprocal arcs in the case of distinct n1 and n2 or removes
// a single arc loop in the case of n1 == n2.
//
// Returns true if the specified edge is found and successfully removed,
// false if the edge does not exist.
func (g LabeledUndirected) RemoveEdgeLabel(n1, n2 NI, l LI) (ok bool) {
	ok, x1, x2 := g.HasEdgeLabel(n1, n2, l)
	if !ok {
		return
	}
	a := g.LabeledAdjacencyList
	to := a[n1]
	last := len(to) - 1
	to[x1] = to[last]
	a[n1] = to[:last]
	if n1 == n2 {
		return
	}
	to = a[n2]
	last = len(to) - 1
	to[x2] = to[last]
	a[n2] = to[:last]
	return
}

// TarjanBiconnectedComponents decomposes a graph into maximal biconnected
// components, components for which if any node were removed the component
// would remain connected.
//
// The receiver g must be a simple graph.  The method calls the emit argument
// for each component identified, as long as emit returns true.  If emit
// returns false, TarjanBiconnectedComponents returns immediately.
//
// See also the eqivalent unlabeled TarjanBiconnectedComponents.
func (g LabeledUndirected) TarjanBiconnectedComponents(emit func([]LabeledEdge) bool) {
	// Code nearly identical to unlabled version.
	number := make([]int, g.Order())
	lowpt := make([]int, g.Order())
	var stack []LabeledEdge
	var i int
	var biconnect func(NI, NI) bool
	biconnect = func(v, u NI) bool {
		i++
		number[v] = i
		lowpt[v] = i
		for _, w := range g.LabeledAdjacencyList[v] {
			if number[w.To] == 0 {
				stack = append(stack, LabeledEdge{Edge{v, w.To}, w.Label})
				if !biconnect(w.To, v) {
					return false
				}
				if lowpt[w.To] < lowpt[v] {
					lowpt[v] = lowpt[w.To]
				}
				if lowpt[w.To] >= number[v] {
					var bcc []LabeledEdge
					top := len(stack) - 1
					for number[stack[top].N1] >= number[w.To] {
						bcc = append(bcc, stack[top])
						stack = stack[:top]
						top--
					}
					bcc = append(bcc, stack[top])
					stack = stack[:top]
					top--
					if !emit(bcc) {
						return false
					}
				}
			} else if number[w.To] < number[v] && w.To != u {
				stack = append(stack, LabeledEdge{Edge{v, w.To}, w.Label})
				if number[w.To] < lowpt[v] {
					lowpt[v] = number[w.To]
				}
			}
		}
		return true
	}
	for w := range g.LabeledAdjacencyList {
		if number[w] == 0 && !biconnect(NI(w), -1) {
			return
		}
	}
}

func (e *eulerian) pushUndir() error {
	for u := e.top(); ; {
		e.uv.SetBit(int(u), 0)
		arcs := e.g[u]
		if len(arcs) == 0 {
			return nil
		}
		w := arcs[0]
		e.s++
		e.p[e.s] = w
		e.g[u] = arcs[1:] // consume arc
		// difference from directed counterpart in dir.go:
		// as long as it's not a loop, consume reciprocal arc as well
		if w != u {
			a2 := e.g[w]
			for x, rx := range a2 {
				if rx == u { // here it is
					last := len(a2) - 1
					a2[x] = a2[last]   // someone else gets the seat
					e.g[w] = a2[:last] // and it's gone.
					goto l
				}
			}
			return fmt.Errorf("graph not undirected.  %d -> %d reciprocal not found", u, w)
		}
	l:
		u = w
	}
}

func (e *labEulerian) pushUndir() error {
	for u := e.top(); ; {
		e.uv.SetBit(int(u.To), 0)
		arcs := e.g[u.To]
		if len(arcs) == 0 {
			return nil
		}
		w := arcs[0]
		e.s++
		e.p[e.s] = w
		e.g[u.To] = arcs[1:] // consume arc
		// difference from directed counterpart in dir.go:
		// as long as it's not a loop, consume reciprocal arc as well
		if w.To != u.To {
			a2 := e.g[w.To]
			for x, rx := range a2 {
				if rx.To == u.To && rx.Label == w.Label { // here it is
					last := len(a2) - 1
					a2[x] = a2[last]      // someone else can have the seat
					e.g[w.To] = a2[:last] // and it's gone.
					goto l
				}
			}
			return fmt.Errorf("graph not undirected.  %d -> %v reciprocal not found", u.To, w)
		}
	l:
		u = w
	}
}