func (graph adjacencyGraph) IsDag() bool {
	return graph.IsDirected() && !graph.HasCycles()
}
Ask whether the graph is a directed acyclic graph
package graph
import (
	"github.com/jesand/numgo/container"
	"github.com/jesand/numgo/matrix"
	"math"
	"strings"
)
func NewDenseAdjacencyGraph(directed bool, maxNodes int) Graph {
	return &adjacencyGraph{
		directed: directed,
		edges:    matrix.Dense(maxNodes, maxNodes).M(),
	}
}
func NewSparseAdjacencyGraph(directed bool, maxNodes int) Graph {
	return &adjacencyGraph{
		directed: directed,
		edges:    matrix.SparseCoo(maxNodes, maxNodes),
	}
}
type adjacencyGraph struct {
	directed bool
	nodes []Node
	edges matrix.Matrix
}
func (graph *adjacencyGraph) AddEdge(from, to NodeID) {
	graph.AddEdgeWithWeight(from, to, 1)
}
func (graph *adjacencyGraph) AddEdgeWithWeight(from, to NodeID, weight float64) {
	if int(from) >= len(graph.nodes) || int(to) >= len(graph.nodes) {
		panic(ErrInvalidNode{})
	}
	graph.edges.ItemSet(weight, int(from), int(to))
	graph.nodes[from].OutDegree++
	graph.nodes[to].InDegree++
	if !graph.directed {
		graph.edges.ItemSet(weight, int(to), int(from))
		graph.nodes[to].OutDegree++
		graph.nodes[from].InDegree++
	}
}
func (graph *adjacencyGraph) AddNode(name string) NodeID {
	if len(graph.nodes) >= graph.edges.Rows() {
		panic(ErrGraphCapacity{})
	}
	id := NodeID(len(graph.nodes))
	graph.nodes = append(graph.nodes, Node{
		ID:        id,
		Name:      name,
		InDegree:  0,
		OutDegree: 0,
	})
	return id
}
func (graph adjacencyGraph) Children(of NodeID) (children []Node) {
	if int(of) >= len(graph.nodes) {
		panic(ErrInvalidNode{})
	}
	for child := 0; child < len(graph.nodes); child++ {
		if graph.edges.Item(int(of), int(child)) != 0 {
			children = append(children, graph.nodes[child])
		}
	}
	return
}
func (graph adjacencyGraph) ChildrenWithWeights(of NodeID) (children []Node, weights []float64) {
	if int(of) >= len(graph.nodes) {
		panic(ErrInvalidNode{})
	}
	for child := 0; child < len(graph.nodes); child++ {
		weight := graph.edges.Item(int(of), int(child))
		if weight != 0 {
			children = append(children, graph.nodes[child])
			weights = append(weights, weight)
		}
	}
	return
}
func (graph adjacencyGraph) Copy() Graph {
	result := &adjacencyGraph{
		directed: graph.directed,
		nodes:    make([]Node, len(graph.nodes)),
		edges:    graph.edges.Copy().M(),
	}
	copy(result.nodes[:], graph.nodes[:])
	return result
}
func (graph adjacencyGraph) HasEdge(from, to NodeID) bool {
	if int(from) >= len(graph.nodes) || int(to) >= len(graph.nodes) {
		panic(ErrInvalidNode{})
	}
	return graph.edges.Item(int(from), int(to)) != 0
}
func (graph adjacencyGraph) HasEdges() bool {
	return graph.edges.CountNonzero() > 0
}
func (graph adjacencyGraph) HasCycles() bool {
	_, err := graph.TopologicalSort()
	return err != nil
}
func (graph adjacencyGraph) HasNodes() bool {
	return len(graph.nodes) > 0
}
func (graph adjacencyGraph) HasPath(from, to NodeID) bool {
	if int(from) >= len(graph.nodes) || int(to) >= len(graph.nodes) {
		panic(ErrInvalidNode{})
	}
	p, _ := graph.ShortestPath(from, to)
	return len(p) > 0
}