func nodeInsert(nodes []*network.NNode, n *network.NNode) []*network.NNode {
	if n == nil {
		neat.WarnLog("GENOME: attempting to insert NIL node into genome nodes, recovered")
		return nodes
	}
	index := len(nodes)
	if index == 0 || n.Id >= nodes[index-1].Id {
		nodes = append(nodes, n)
		return nodes
	} else if n.Id <= nodes[0].Id {
		index = 0
	}
	for i := index - 1; i >= 0; i-- {
		if n.Id == nodes[i].Id {
			index = i
			break
		} else if n.Id > nodes[i].Id {
			index = i + 1  
			break
		}
	}
	first := make([]*network.NNode, index+1)
	copy(first, nodes[0:index])
	first[index] = n
	second := nodes[index:]
	nodes = append(first, second...)
	return nodes
}
Inserts a NNode into a given ordered list of NNodes in ascending order by NNode ID
package genetics
import (
	"errors"
	"fmt"
	"github.com/yaricom/goNEAT/v2/neat"
	"github.com/yaricom/goNEAT/v2/neat/math"
	"github.com/yaricom/goNEAT/v2/neat/network"
	"io"
	"math/rand"
	"reflect"
)
type Genome struct {
	Id int `yaml:"id"`
	Traits []*neat.Trait `yaml:"traits"`
	Nodes []*network.NNode `yaml:"nodes"`
	Genes []*Gene `yaml:"genes"`
	ControlGenes []*MIMOControlGene `yaml:"modules"`
	Phenotype *network.Network `yaml:""`
}
func NewGenome(id int, t []*neat.Trait, n []*network.NNode, g []*Gene) *Genome {
	return &Genome{
		Id:     id,
		Traits: t,
		Nodes:  n,
		Genes:  g,
	}
}
func NewModularGenome(id int, t []*neat.Trait, n []*network.NNode, g []*Gene, mimoG []*MIMOControlGene) *Genome {
	return &Genome{
		Id:           id,
		Traits:       t,
		Nodes:        n,
		Genes:        g,
		ControlGenes: mimoG,
	}
}
func newGenomeRand(newId, in, out, n, maxHidden int, recurrent bool, linkProb float64) *Genome {
	totalNodes := in + out + maxHidden
	matrixDim := totalNodes * totalNodes
	cm := make([]bool, matrixDim)  
	maxNode := in + n
	firstOutput := totalNodes - out + 1
	newTrait := neat.NewTrait()
	newTrait.Id = 1
	newTrait.Params = make([]float64, neat.NumTraitParams)
	gnome := Genome{
		Id:     newId,
		Traits: []*neat.Trait{newTrait},
		Nodes:  make([]*network.NNode, 0),
		Genes:  make([]*Gene, 0),
	}
	for count := 0; count < matrixDim; count++ {
		cm[count] = rand.Float64() < linkProb
	}
	for i := 1; i <= in; i++ {
		var newNode *network.NNode
		if i < in {
			newNode = network.NewNNode(i, network.InputNeuron)
		} else {
			newNode = network.NewNNode(i, network.BiasNeuron)
		}
		newNode.Trait = newTrait
		gnome.Nodes = append(gnome.Nodes, newNode)
	}
	for i := in + 1; i <= in+n; i++ {
		newNode := network.NewNNode(i, network.HiddenNeuron)
		newNode.Trait = newTrait
		gnome.Nodes = append(gnome.Nodes, newNode)
	}
	for i := firstOutput; i <= totalNodes; i++ {
		newNode := network.NewNNode(i, network.OutputNeuron)
		newNode.Trait = newTrait
		gnome.Nodes = append(gnome.Nodes, newNode)
	}
	var inNode, outNode *network.NNode
	count := 0
	var flagRecurrent bool
	for col := 1; col <= totalNodes; col++ {
		for row := 1; row <= totalNodes; row++ {
			if cm[count] && col > in &&
				(col <= maxNode || col >= firstOutput) &&
				(row <= maxNode || row >= firstOutput) {
				createGene := true
				if col > row {
					flagRecurrent = false
				} else {
					flagRecurrent = true
					if !recurrent {
						createGene = false
					}
				}
				if createGene {
					for i := 0; i < len(gnome.Nodes) && (inNode == nil || outNode == nil); i++ {
						nodeId := gnome.Nodes[i].Id
						if nodeId == row {
							inNode = gnome.Nodes[i]
						}
						if nodeId == col {
							outNode = gnome.Nodes[i]
						}
					}
					weight := float64(math.RandSign()) * rand.Float64()
					gene := NewGeneWithTrait(newTrait, weight, inNode, outNode, flagRecurrent, int64(count), weight)
					gnome.Genes = append(gnome.Genes, gene)
				}
			}
			count++  
			inNode, outNode = nil, nil
		}
	}
	return &gnome
}
func ReadGenome(ir io.Reader, id int) (*Genome, error) {
	r, err := NewGenomeReader(ir, PlainGenomeEncoding)
	if err != nil {
		return nil, err
	}
	if gnome, err := r.Read(); err != nil {
		return nil, err
	} else {
		gnome.Id = id
		return gnome, err
	}
}
func (g *Genome) Write(w io.Writer) error {
	wr, err := NewGenomeWriter(w, PlainGenomeEncoding)
	if err == nil {
		err = wr.WriteGenome(g)
	}
	return err
}
func (g *Genome) String() string {
	str := "GENOME START\nNodes:\n"
	for _, n := range g.Nodes {
		nodeType := ""
		switch n.NeuronType {
		case network.InputNeuron:
			nodeType = "I"
		case network.OutputNeuron:
			nodeType = "O"
		case network.BiasNeuron:
			nodeType = "B"
		case network.HiddenNeuron:
			nodeType = "H"
		}
		str += fmt.Sprintf("\t%s%s \n", nodeType, n)
	}
	str += "Genes:\n"
	for _, gn := range g.Genes {
		str += fmt.Sprintf("\t%s\n", gn)
	}
	str += "Traits:\n"
	for _, t := range g.Traits {
		str += fmt.Sprintf("\t%s\n", t)
	}
	str += "GENOME END"
	return str
}
func (g *Genome) Extrons() int {
	total := 0
	for _, gene := range g.Genes {
		if gene.IsEnabled {
			total++
		}
	}
	return total
}
func (g *Genome) IsEqual(og *Genome) (bool, error) {
	if len(g.Traits) != len(og.Traits) {
		return false, fmt.Errorf("traits count mismatch: %d != %d",
			len(g.Traits), len(og.Traits))
	}
	for i, tr := range og.Traits {
		if !reflect.DeepEqual(tr, g.Traits[i]) {
			return false, fmt.Errorf("traits mismatch, expected: %s, but found: %s", tr, g.Traits[i])
		}
	}
	if len(g.Nodes) != len(og.Nodes) {
		return false, fmt.Errorf("nodes count mismatch: %d != %d",
			len(g.Nodes), len(og.Nodes))
	}
	for i, nd := range og.Nodes {
		if !reflect.DeepEqual(nd, g.Nodes[i]) {
			return false, fmt.Errorf("node mismatch, expected: %s\nfound: %s", nd, g.Nodes[i])
		}
	}
	if len(g.Genes) != len(og.Genes) {
		return false, fmt.Errorf("genes count mismatch: %d != %d",
			len(g.Genes), len(og.Genes))
	}
	for i, gen := range og.Genes {
		if !reflect.DeepEqual(gen, g.Genes[i]) {
			return false, fmt.Errorf("gene mismatch, expected: %s\nfound: %s", gen, g.Genes[i])
		}
	}
	if len(g.ControlGenes) != len(og.ControlGenes) {
		return false, fmt.Errorf("control genes count mismatch: %d != %d",
			len(g.ControlGenes), len(og.ControlGenes))
	}
	for i, cg := range og.ControlGenes {
		if !reflect.DeepEqual(cg, g.ControlGenes[i]) {
			return false, fmt.Errorf("control gene mismatch, expected: %s\nfound: %s", cg, g.ControlGenes[i])
		}
	}
	return true, nil
}
func (g *Genome) getLastNodeId() (int, error) {
	if len(g.Nodes) == 0 {
		return -1, errors.New("genome has no nodes")
	}
	id := g.Nodes[len(g.Nodes)-1].Id
	for _, cg := range g.ControlGenes {
		if cg.ControlNode.Id > id {
			id = cg.ControlNode.Id
		}
	}
	return id, nil
}
func (g *Genome) getNextGeneInnovNum() (int64, error) {
	innNum := int64(0)
	if len(g.Genes) > 0 {
		innNum = g.Genes[len(g.Genes)-1].InnovationNum
	} else {
		return -1, errors.New("genome has no Genes")
	}
	if len(g.ControlGenes) > 0 {
		cInnNum := g.ControlGenes[len(g.ControlGenes)-1].InnovationNum
		if cInnNum > innNum {
			innNum = cInnNum
		}
	}
	return innNum + int64(1), nil
}
func (g *Genome) hasNode(node *network.NNode) bool {
	if node == nil {
		return false
	}
	if id, _ := g.getLastNodeId(); node.Id > id {
		return false  
	}
	for _, n := range g.Nodes {
		if n.Id == node.Id {
			return true
		}
	}
	return false
}
func (g *Genome) hasGene(gene *Gene) bool {
	if inn, _ := g.getNextGeneInnovNum(); gene.InnovationNum >= inn {
		return false
	}
	for _, g := range g.Genes {
		if g.Link.IsEqualGenetically(gene.Link) {
			return true
		}
	}
	return false
}
func (g *Genome) Genesis(netId int) (*network.Network, error) {
	inList := make([]*network.NNode, 0)
	outList := make([]*network.NNode, 0)
	allList := make([]*network.NNode, 0)
	var newNode *network.NNode
	for _, n := range g.Nodes {
		newNode = network.NewNNodeCopy(n, n.Trait)
		if n.NeuronType == network.InputNeuron || n.NeuronType == network.BiasNeuron {
			inList = append(inList, newNode)
		} else if n.NeuronType == network.OutputNeuron {
			outList = append(outList, newNode)
		}
		allList = append(allList, newNode)
		n.PhenotypeAnalogue = newNode
	}
	if len(g.Genes) == 0 {
		return nil, errors.New("network built without GENES; the result can be unpredictable")
	}
	if len(outList) == 0 {
		return nil, fmt.Errorf("network without OUTPUTS; the result can be unpredictable. Genome: %s", g)
	}
	var inNode, outNode *network.NNode
	var curLink, newLink *network.Link
	for _, gn := range g.Genes {
		if gn.IsEnabled {
			curLink = gn.Link
			inNode = curLink.InNode.PhenotypeAnalogue
			outNode = curLink.OutNode.PhenotypeAnalogue
			newLink = network.NewLinkWithTrait(curLink.Trait, curLink.ConnectionWeight, inNode, outNode, curLink.IsRecurrent)
			outNode.Incoming = append(outNode.Incoming, newLink)
			inNode.Outgoing = append(inNode.Outgoing, newLink)
		}
	}
	var newNet *network.Network
	if len(g.ControlGenes) == 0 {
		newNet = network.NewNetwork(inList, outList, allList, netId)
	} else {
		cNodes := make([]*network.NNode, 0)
		for _, cg := range g.ControlGenes {
			if cg.IsEnabled {
				newCopyNode := network.NewNNodeCopy(cg.ControlNode, cg.ControlNode.Trait)
				for _, l := range cg.ControlNode.Incoming {
					inNode = l.InNode.PhenotypeAnalogue
					outNode = newCopyNode
					newLink = network.NewLink(l.ConnectionWeight, inNode, outNode, false)
					outNode.Incoming = append(outNode.Incoming, newLink)
				}
				for _, l := range cg.ControlNode.Outgoing {
					inNode = newCopyNode
					outNode = l.OutNode.PhenotypeAnalogue
					newLink = network.NewLink(l.ConnectionWeight, inNode, outNode, false)
					inNode.Outgoing = append(inNode.Outgoing, newLink)
				}
				cNodes = append(cNodes, newCopyNode)
			}
		}
		newNet = network.NewModularNetwork(inList, outList, allList, cNodes, netId)
	}
	g.Phenotype = newNet
	return newNet, nil
}
func (g *Genome) duplicate(newId int) (*Genome, error) {
	traitsDup := make([]*neat.Trait, len(g.Traits))
	for i, tr := range g.Traits {
		traitsDup[i] = neat.NewTraitCopy(tr)
	}
	nodesDup := make([]*network.NNode, len(g.Nodes))
	for i, nd := range g.Nodes {
		assocTrait := nd.Trait
		if assocTrait != nil {
			assocTrait = TraitWithId(assocTrait.Id, traitsDup)
		}
		nodesDup[i] = network.NewNNodeCopy(nd, assocTrait)
	}
	genesDup := make([]*Gene, len(g.Genes))
	for i, gn := range g.Genes {
		inNode := NodeWithId(gn.Link.InNode.Id, nodesDup)
		if inNode == nil {
			return nil, fmt.Errorf("incoming node: %d not found for gene %s",
				gn.Link.InNode.Id, gn.String())
		}
		outNode := NodeWithId(gn.Link.OutNode.Id, nodesDup)
		if outNode == nil {
			return nil, fmt.Errorf("outgoing node: %d not found for gene %s",
				gn.Link.OutNode.Id, gn.String())
		}
		assocTrait := gn.Link.Trait
		if assocTrait != nil {
			assocTrait = TraitWithId(assocTrait.Id, traitsDup)
		}
		genesDup[i] = NewGeneCopy(gn, assocTrait, inNode, outNode)
	}
	if len(g.ControlGenes) == 0 {
		return NewGenome(newId, traitsDup, nodesDup, genesDup), nil
	} else {
		controlGenesDup := make([]*MIMOControlGene, len(g.ControlGenes))
		for i, cg := range g.ControlGenes {
			controlNode := cg.ControlNode
			assocTrait := controlNode.Trait
			if assocTrait != nil {
				assocTrait = TraitWithId(assocTrait.Id, traitsDup)
			}
			nodeCopy := network.NewNNodeCopy(controlNode, assocTrait)
			for _, l := range controlNode.Incoming {
				inNode := NodeWithId(l.InNode.Id, nodesDup)
				if inNode == nil {
					return nil, fmt.Errorf("incoming node: %d not found for control node: %d",
						l.InNode.Id, controlNode.Id)
				}
				newInLink := network.NewLinkCopy(l, inNode, nodeCopy)
				nodeCopy.Incoming = append(nodeCopy.Incoming, newInLink)
			}
			for _, l := range controlNode.Outgoing {
				outNode := NodeWithId(l.OutNode.Id, nodesDup)
				if outNode == nil {
					return nil, fmt.Errorf("outgoing node: %d not found for control node: %d",
						l.InNode.Id, controlNode.Id)
				}
				newOutLink := network.NewLinkCopy(l, nodeCopy, outNode)
				nodeCopy.Outgoing = append(nodeCopy.Outgoing, newOutLink)
			}
			controlGenesDup[i] = NewMIMOGeneCopy(cg, nodeCopy)
		}
		return NewModularGenome(newId, traitsDup, nodesDup, genesDup, controlGenesDup), nil
	}
}
func (g *Genome) verify() (bool, error) {
	if len(g.Genes) == 0 {
		return false, errors.New("genome has no Genes")
	}
	if len(g.Nodes) == 0 {
		return false, errors.New("genome has no Nodes")
	}
	if len(g.Traits) == 0 {
		return false, errors.New("genome has no Traits")
	}
	for _, gn := range g.Genes {
		inNode := gn.Link.InNode
		outNode := gn.Link.OutNode
		inputFound, outFound := false, false
		for i := 0; i < len(g.Nodes) && (!inputFound || !outFound); i++ {
			if inNode.Id == g.Nodes[i].Id {
				inputFound = true
			}
			if outNode.Id == g.Nodes[i].Id {
				outFound = true
			}
		}
		if !inputFound {
			return false, errors.New("missing input node of gene in the genome nodes list")
		}
		if !outFound {
			return false, errors.New("missing output node of gene in the genome nodes list")
		}
	}
	lastId := 0
	for _, n := range g.Nodes {
		if n.Id < lastId {
			return false, errors.New("nodes out of order in genome")
		}
		lastId = n.Id
	}
	for _, gn := range g.Genes {
		for _, gn2 := range g.Genes {
			if gn != gn2 && gn.Link.IsEqualGenetically(gn2.Link) {
				return false, fmt.Errorf("duplicate genes found: %s == %s", gn, gn2)
			}
		}
	}
	if len(g.Nodes) > 500 {
		disabled := false
		for _, gn := range g.Genes {
			if !gn.IsEnabled && disabled {
				return false, errors.New("two gene disables in a row")
			}
			disabled = !gn.IsEnabled
		}
	}
	return true, nil
}