func (g LabeledAdjacencyList) AStarAPath(start, end NI, h Heuristic, w WeightFunc) ([]NI, float64) {
	f, _, d, _ := g.AStarA(w, start, end, h)
	return f.PathTo(end, nil), d
}
AStarAPath finds a shortest path using the AStarA algorithm.

This is a convenience method with a simpler result than the AStarA method.
See documentation on the AStarA method.

If a path is found, the non-nil node path is returned with the total path
distance.  Otherwise the returned path will be nil.
package graph
import (
	"container/heap"
	"fmt"
	"math"
)
type rNode struct {
	nx    NI
	state int8     
	f     float64  
	fx    int      
}
const (
	unreached = 0
	reached   = 1
	open      = 1
	closed    = 2
)
type openHeap []*rNode
type Heuristic func(from NI) float64
func (h Heuristic) Admissible(g LabeledAdjacencyList, w WeightFunc, end NI) (bool, string) {
	inv := make(LabeledAdjacencyList, len(g))
	for from, nbs := range g {
		for _, nb := range nbs {
			inv[nb.To] = append(inv[nb.To],
				Half{To: NI(from), Label: nb.Label})
		}
	}
	f, dist, _ := inv.Dijkstra(end, -1, w)
	for n := range inv {
		if f.Paths[n].Len == 0 {
			continue  
		}
		if !(h(NI(n)) <= dist[n]) {
			return false, fmt.Sprintf("h(%d) = %g, "+
				"required to be <= found shortest path (%g)",
				n, h(NI(n)), dist[n])
		}
	}
	return true, ""
}
func (h Heuristic) Monotonic(g LabeledAdjacencyList, w WeightFunc) (bool, string) {
	hv := make([]float64, len(g))
	for n := range g {
		hv[n] = h(NI(n))
	}
	for from, nbs := range g {
		for _, nb := range nbs {
			arcWeight := w(nb.Label)
			if !(hv[from] <= arcWeight+hv[nb.To]) {
				return false, fmt.Sprintf("h(%d) = %g, "+
					"required to be <= arc weight + h(%d) (= %g + %g = %g)",
					from, hv[from],
					nb.To, arcWeight, hv[nb.To], arcWeight+hv[nb.To])
			}
		}
	}
	return true, ""
}
func (g LabeledAdjacencyList) AStarA(w WeightFunc, start, end NI, h Heuristic) (f FromList, labels []LI, dist float64, ok bool) {
	f = NewFromList(len(g))
	labels = make([]LI, len(g))
	d := make([]float64, len(g))
	r := make([]rNode, len(g))
	for i := range r {
		r[i].nx = NI(i)
	}
	cr := &r[start]
	cr.state = reached
	cr.f = h(start)  
	rp := f.Paths
	rp[start] = PathEnd{Len: 1, From: -1}  
	oh := openHeap{cr}
	for len(oh) > 0 {
		bestPath := heap.Pop(&oh).(*rNode)
		bestNode := bestPath.nx
		if bestNode == end {
			return f, labels, d[end], true
		}
		bp := &rp[bestNode]
		nextLen := bp.Len + 1
		for _, nb := range g[bestNode] {
			alt := &r[nb.To]
			ap := &rp[alt.nx]
			g := d[bestNode] + w(nb.Label)
			if alt.state == reached {
				if g > d[nb.To] {
					continue
				}
				if g == d[nb.To] && nextLen >= ap.Len {
					continue
				}
				*ap = PathEnd{From: bestNode, Len: nextLen}
				labels[nb.To] = nb.Label
				d[nb.To] = g
				alt.f = g + h(nb.To)
				if alt.fx < 0 {
					heap.Push(&oh, alt)
				} else {
					heap.Fix(&oh, alt.fx)
				}
			} else {
				*ap = PathEnd{From: bestNode, Len: nextLen}
				labels[nb.To] = nb.Label
				d[nb.To] = g
				alt.f = g + h(nb.To)
				alt.state = reached
				heap.Push(&oh, alt)  
			}
		}
	}
	return  
}