github.com/yaricom/goNEAT@v0.0.0-20210507221059-e2110b885482/neat/genetics/genome.go (about) 1 package genetics 2 3 import ( 4 "github.com/yaricom/goNEAT/neat/utils" 5 "github.com/yaricom/goNEAT/neat/network" 6 "github.com/yaricom/goNEAT/neat" 7 "math/rand" 8 "io" 9 "fmt" 10 "errors" 11 "math" 12 "reflect" 13 ) 14 15 // A Genome is the primary source of genotype information used to create a phenotype. 16 // It contains 3 major constituents: 17 // 1) A Vector of Traits 18 // 2) A List of NNodes pointing to a Trait from (1) 19 // 3) A List of Genes with Links that point to Traits from (1) 20 // 4) A List of MIMO Control Genes with Links to different genome modules 21 // 22 // (1) Reserved parameter space for future use. 23 // (2) NNode specifications. 24 // (3) Is the primary source of innovation in the evolutionary Genome. 25 // (4) Control genes allows to receive inputs from multiple independent genome modules and output processed signal to the 26 // multitude of output locations 27 // 28 // Each Gene in (3) has a marker telling when it arose historically. Thus, these Genes can be used to speciate the 29 // population, and the list of Genes provide an evolutionary history of innovation and link-building. 30 type Genome struct { 31 // The genome ID 32 Id int 33 // The parameters conglomerations 34 Traits []*neat.Trait 35 // List of NNodes for the Network 36 Nodes []*network.NNode 37 // List of innovation-tracking genes 38 Genes []*Gene 39 // List of MIMO control genes 40 ControlGenes []*MIMOControlGene 41 42 // Allows Genome to be matched with its Network 43 Phenotype *network.Network 44 } 45 46 // Constructor which takes full genome specs and puts them into the new one 47 func NewGenome(id int, t []*neat.Trait, n []*network.NNode, g []*Gene) *Genome { 48 return &Genome{ 49 Id:id, 50 Traits:t, 51 Nodes:n, 52 Genes:g, 53 } 54 } 55 56 // Constructs new modular genome 57 func NewModularGenome(id int, t []*neat.Trait, n []*network.NNode, g []*Gene, mimoG []*MIMOControlGene) *Genome { 58 return &Genome{ 59 Id:id, 60 Traits:t, 61 Nodes:n, 62 Genes:g, 63 ControlGenes:mimoG, 64 } 65 } 66 67 // This special constructor creates a Genome with in inputs, out outputs, n out of nmax hidden units, and random 68 // connectivity. If rec is true then recurrent connections will be included. The last input is a bias 69 // link_prob is the probability of a link. The created genome is not modular. 70 func newGenomeRand(new_id, in, out, n, nmax int, recurrent bool, link_prob float64) *Genome { 71 total_nodes := in + out + nmax 72 matrix_dim := total_nodes * total_nodes 73 // The connection matrix which will be randomized 74 cm := make([]bool, matrix_dim) //Dimension the connection matrix 75 76 // No nodes above this number for this genome 77 max_node := in + n 78 first_output := total_nodes - out + 1 79 80 // For creating the new genes 81 var new_node, in_node, out_node *network.NNode 82 var new_gene *Gene 83 var new_trait *neat.Trait 84 85 // Create a dummy trait (this is for future expansion of the system) 86 new_trait = neat.NewTrait() 87 new_trait.Id = 1 88 new_trait.Params = make([]float64, neat.Num_trait_params) 89 90 // Create empty genome 91 gnome := Genome{ 92 Id:new_id, 93 Traits:[]*neat.Trait{new_trait}, 94 Nodes:make([]*network.NNode, 0), 95 Genes:make([]*Gene, 0), 96 } 97 98 // Step through the connection matrix, randomly assigning bits 99 for count := 0; count < matrix_dim; count++ { 100 cm[count] = (rand.Float64() < link_prob) 101 } 102 103 // Build the input nodes 104 for ncount := 1; ncount <= in; ncount++ { 105 if ncount < in { 106 new_node = network.NewNNode(ncount, network.InputNeuron) 107 } else { 108 new_node = network.NewNNode(ncount, network.BiasNeuron) 109 } 110 new_node.Trait = new_trait 111 gnome.Nodes = append(gnome.Nodes, new_node) 112 } 113 114 // Build the hidden nodes 115 for ncount := in + 1; ncount <= in + n; ncount++ { 116 new_node = network.NewNNode(ncount, network.HiddenNeuron) 117 new_node.Trait = new_trait 118 gnome.Nodes = append(gnome.Nodes, new_node) 119 } 120 121 // Build the output nodes 122 for ncount := first_output; ncount <= total_nodes; ncount++ { 123 new_node = network.NewNNode(ncount, network.OutputNeuron) 124 new_node.Trait = new_trait 125 gnome.Nodes = append(gnome.Nodes, new_node) 126 } 127 128 // 129 // i i i n n n n n n n n n n n n n n n n . . . . . . . . o o o o 130 // | | ^ | 131 // |<----------- max_node ------------>| | | 132 // | | | 133 // |<-----------------------total_nodes -----------------|---->| 134 // | 135 // | 136 // first_output ----------------------------------------+ 137 // 138 // 139 140 // Step through the connection matrix, creating connection genes 141 count := 0 142 var create_gene, flag_recurrent bool 143 for col := 1; col <= total_nodes; col++ { 144 for row := 1; row <= total_nodes; row++ { 145 // Only try to create a link if it is in the matrix and not leading into a sensor 146 if cm[count] && col > in && 147 (col <= max_node || col >= first_output) && 148 (row <= max_node || row >= first_output) { 149 150 // If it's recurrent, create the connection (gene) no matter what 151 create_gene = true 152 if col > row { 153 flag_recurrent = false 154 } else { 155 flag_recurrent = true 156 if !recurrent { 157 // skip recurrent connections 158 create_gene = false 159 } 160 } 161 162 // Introduce new connection (gene) into genome 163 if create_gene { 164 // Retrieve in_node and out_node 165 for i := 0; i < len(gnome.Nodes) && (in_node == nil || out_node == nil); i++ { 166 node_id := gnome.Nodes[i].Id 167 if node_id == row { 168 in_node = gnome.Nodes[i] 169 } 170 if node_id == col { 171 out_node = gnome.Nodes[i] 172 } 173 } 174 175 // Create the gene 176 new_weight := float64(utils.RandSign()) * rand.Float64() 177 new_gene = NewGeneWithTrait(new_trait, new_weight, in_node, out_node, flag_recurrent, int64(count), new_weight) 178 179 //Add the gene to the genome 180 gnome.Genes = append(gnome.Genes, new_gene) 181 } 182 183 } 184 185 count++ //increment counter 186 // reset nodes 187 in_node, out_node = nil, nil 188 } 189 } 190 return &gnome 191 } 192 193 // Reads Genome from reader 194 func ReadGenome(ir io.Reader, id int) (*Genome, error) { 195 // stub for backward compatibility 196 // the new implementations should use GenomeReader to decode genome data in variety of formats 197 r, err := NewGenomeReader(ir, PlainGenomeEncoding) 198 if err != nil { 199 return nil, err 200 } 201 gnome, err := r.Read() 202 return gnome, err 203 } 204 205 // Writes this genome into provided writer 206 func (g *Genome) Write(w io.Writer) error { 207 // stub for backward compatibility 208 // the new implementations should use GenomeWriter to decode genome data in variety of formats 209 wr, err := NewGenomeWriter(w, PlainGenomeEncoding) 210 if err == nil { 211 err = wr.WriteGenome(g) 212 } 213 214 return err 215 } 216 217 // Stringer 218 func (g *Genome) String() string { 219 str := "GENOME START\nNodes:\n" 220 for _, n := range g.Nodes { 221 n_type := "" 222 switch n.NeuronType { 223 case network.InputNeuron: 224 n_type = "I" 225 case network.OutputNeuron: 226 n_type = "O" 227 case network.BiasNeuron: 228 n_type = "B" 229 case network.HiddenNeuron: 230 n_type = "H" 231 } 232 str += fmt.Sprintf("\t%s%s \n", n_type, n) 233 } 234 str += "Genes:\n" 235 for _, gn := range g.Genes { 236 str += fmt.Sprintf("\t%s\n", gn) 237 } 238 str += "Traits:\n" 239 for _, t := range g.Traits { 240 str += fmt.Sprintf("\t%s\n", t) 241 } 242 str += "GENOME END" 243 return str 244 } 245 246 // Return # of non-disabled genes 247 func (g *Genome) Extrons() int { 248 total := 0 249 for _, gene := range g.Genes { 250 if gene.IsEnabled { 251 total++ 252 } 253 } 254 return total 255 } 256 257 // Tests if given genome is equal to this one genetically and phenotypically. This method will check that both genomes has the same traits, nodes and genes. 258 // If mismatch detected the error will be returned with mismatch details. 259 func (g *Genome) IsEqual(og *Genome) (bool, error) { 260 if len(g.Traits) != len(og.Traits) { 261 return false, errors.New(fmt.Sprintf("traits count mismatch: %d != %d", 262 len(g.Traits), len(og.Traits))) 263 } 264 for i, tr := range og.Traits { 265 if !reflect.DeepEqual(tr, g.Traits[i]) { 266 return false, errors.New( 267 fmt.Sprintf("traits mismatch, expected: %s, but found: %s", tr, g.Traits[i])) 268 } 269 } 270 271 if len(g.Nodes) != len(og.Nodes) { 272 return false, errors.New(fmt.Sprintf("nodes count mismatch: %d != %d", 273 len(g.Nodes), len(og.Nodes))) 274 } 275 for i, nd := range og.Nodes { 276 if !reflect.DeepEqual(nd, g.Nodes[i]) { 277 return false, errors.New( 278 fmt.Sprintf("node mismatch, expected: %s\nfound: %s", nd, g.Nodes[i])) 279 } 280 } 281 282 if len(g.Genes) != len(og.Genes) { 283 return false, errors.New(fmt.Sprintf("genes count mismatch: %d != %d", 284 len(g.Genes), len(og.Genes))) 285 } 286 for i, gen := range og.Genes { 287 if !reflect.DeepEqual(gen, g.Genes[i]) { 288 return false, errors.New( 289 fmt.Sprintf("gene mismatch, expected: %s\nfound: %s", gen, g.Genes[i])) 290 } 291 } 292 293 if len(g.ControlGenes) != len(og.ControlGenes) { 294 return false, errors.New(fmt.Sprintf("control genes count mismatch: %d != %d", 295 len(g.ControlGenes), len(og.ControlGenes))) 296 } 297 for i, cg := range og.ControlGenes { 298 if !reflect.DeepEqual(cg, g.ControlGenes[i]) { 299 return false, errors.New( 300 fmt.Sprintf("control gene mismatch, expected: %s\nfound: %s", cg, g.ControlGenes[i])) 301 } 302 } 303 304 return true, nil 305 } 306 307 // Return id of final NNode in Genome 308 func (g *Genome) getLastNodeId() (int, error) { 309 if len(g.Nodes) == 0 { 310 return -1, errors.New("Genome has no nodes") 311 } 312 id := g.Nodes[len(g.Nodes) - 1].Id 313 // check control genes 314 for _, cg := range g.ControlGenes { 315 if cg.ControlNode.Id > id { 316 id = cg.ControlNode.Id 317 } 318 } 319 return id, nil 320 } 321 322 // Return innovation number of last gene in Genome + 1 323 func (g *Genome) getNextGeneInnovNum() (int64, error) { 324 inn_num := int64(0) 325 // check connection genes 326 if len(g.Genes) > 0 { 327 inn_num = g.Genes[len(g.Genes) - 1].InnovationNum 328 } else { 329 return -1, errors.New("Genome has no Genes") 330 } 331 // check control genes if any 332 if len(g.ControlGenes) > 0 { 333 c_inn_num := g.ControlGenes[len(g.ControlGenes) - 1].InnovationNum 334 if c_inn_num > inn_num { 335 inn_num = c_inn_num 336 } 337 } 338 return inn_num + int64(1), nil 339 } 340 341 // Returns true if this Genome already includes provided node 342 func (g *Genome) hasNode(node *network.NNode) bool { 343 if id, _ := g.getLastNodeId(); node.Id > id { 344 return false // not found 345 } 346 for _, n := range g.Nodes { 347 if n.Id == node.Id { 348 return true 349 } 350 } 351 return false 352 } 353 354 // Returns true if this Genome already includes provided gene 355 func (g *Genome) hasGene(gene *Gene) bool { 356 if inn, _ := g.getNextGeneInnovNum(); gene.InnovationNum >= inn { 357 return false 358 } 359 360 // Find genetically equal link in this genome to the provided gene 361 for _, g := range g.Genes { 362 if g.Link.IsEqualGenetically(gene.Link) { 363 return true 364 } 365 } 366 return false 367 } 368 369 // Generate a Network phenotype from this Genome with specified id 370 func (g *Genome) Genesis(net_id int) (*network.Network, error) { 371 // Inputs and outputs will be collected here for the network. 372 // All nodes are collected in an all_list - 373 // this is useful for network traversing routines 374 in_list := make([]*network.NNode, 0) 375 out_list := make([]*network.NNode, 0) 376 all_list := make([]*network.NNode, 0) 377 378 var new_node *network.NNode 379 // Create the network nodes 380 for _, n := range g.Nodes { 381 new_node = network.NewNNodeCopy(n, n.Trait) 382 383 // Check for input or output designation of node 384 if n.NeuronType == network.InputNeuron || n.NeuronType == network.BiasNeuron { 385 in_list = append(in_list, new_node) 386 } else if n.NeuronType == network.OutputNeuron { 387 out_list = append(out_list, new_node) 388 } 389 390 // Keep track of all nodes in one place for convenience 391 all_list = append(all_list, new_node) 392 393 // Have the node specifier point to the node it generated 394 n.PhenotypeAnalogue = new_node 395 } 396 397 if len(g.Genes) == 0 { 398 return nil, errors.New("The network built whitout GENES; the result can be unpredictable") 399 } 400 401 if len(out_list) == 0 { 402 return nil, errors.New(fmt.Sprintf("The network whitout OUTPUTS; the result can be unpredictable. Genome: %s", g)) 403 } 404 405 var in_node, out_node *network.NNode 406 var cur_link, new_link *network.Link 407 // Create the links by iterating through the genes 408 for _, gn := range g.Genes { 409 // Only create the link if the gene is enabled 410 if gn.IsEnabled { 411 cur_link = gn.Link 412 in_node = cur_link.InNode.PhenotypeAnalogue 413 out_node = cur_link.OutNode.PhenotypeAnalogue 414 415 // NOTE: This line could be run through a recurrency check if desired 416 // (no need to in the current implementation of NEAT) 417 new_link = network.NewLinkWithTrait(cur_link.Trait, cur_link.Weight, in_node, out_node, cur_link.IsRecurrent) 418 419 // Add link to the connected nodes 420 out_node.Incoming = append(out_node.Incoming, new_link) 421 in_node.Outgoing = append(in_node.Outgoing, new_link) 422 } 423 } 424 425 var new_net *network.Network 426 if len(g.ControlGenes) == 0 { 427 // Create the new network 428 new_net = network.NewNetwork(in_list, out_list, all_list, net_id) 429 } else { 430 // Create MIMO control genes 431 c_nodes := make([]*network.NNode, 0) 432 for _, cg := range g.ControlGenes { 433 // Only process enabled genes 434 if cg.IsEnabled { 435 new_c_node := network.NewNNodeCopy(cg.ControlNode, cg.ControlNode.Trait) 436 437 // connect inputs 438 for _, l := range cg.ControlNode.Incoming { 439 in_node = l.InNode.PhenotypeAnalogue 440 out_node = new_c_node 441 new_link = network.NewLink(l.Weight, in_node, out_node, false) 442 // only incoming to control node 443 out_node.Incoming = append(out_node.Incoming, new_link) 444 } 445 446 // connect outputs 447 for _, l := range cg.ControlNode.Outgoing { 448 in_node = new_c_node 449 out_node = l.OutNode.PhenotypeAnalogue 450 new_link = network.NewLink(l.Weight, in_node, out_node, false) 451 // only outgoing from control node 452 in_node.Outgoing = append(in_node.Outgoing, new_link) 453 } 454 455 // store control node 456 c_nodes = append(c_nodes, new_c_node) 457 } 458 } 459 new_net = network.NewModularNetwork(in_list, out_list, all_list, c_nodes, net_id) 460 } 461 462 // Attach genotype and phenotype together: 463 // genotype points to owner phenotype (new_net) 464 g.Phenotype = new_net 465 466 return new_net, nil 467 } 468 469 // Duplicate this Genome to create a new one with the specified id 470 func (g *Genome) duplicate(new_id int) (*Genome, error) { 471 472 // Duplicate the traits 473 traits_dup := make([]*neat.Trait, 0) 474 for _, tr := range g.Traits { 475 new_trait := neat.NewTraitCopy(tr) 476 traits_dup = append(traits_dup, new_trait) 477 } 478 479 // Duplicate NNodes 480 nodes_dup := make([]*network.NNode, 0) 481 for _, nd := range g.Nodes { 482 // First, find the duplicate of the trait that this node points to 483 assoc_trait := nd.Trait 484 if assoc_trait != nil { 485 assoc_trait = traitWithId(assoc_trait.Id, traits_dup) 486 } 487 new_node := network.NewNNodeCopy(nd, assoc_trait) 488 489 nodes_dup = append(nodes_dup, new_node) 490 } 491 492 // Duplicate Genes 493 genes_dup := make([]*Gene, 0) 494 for _, gn := range g.Genes { 495 // First find the nodes connected by the gene's link 496 in_node := nodeWithId(gn.Link.InNode.Id, nodes_dup) 497 if in_node == nil { 498 return nil, errors.New( 499 fmt.Sprintf("incoming node: %d not found for gene %s", 500 gn.Link.InNode.Id, gn.String())) 501 } 502 out_node := nodeWithId(gn.Link.OutNode.Id, nodes_dup) 503 if out_node == nil { 504 return nil, errors.New( 505 fmt.Sprintf("outgoing node: %d not found for gene %s", 506 gn.Link.OutNode.Id, gn.String())) 507 } 508 509 // Find the duplicate of trait associated with this gene 510 assoc_trait := gn.Link.Trait 511 if assoc_trait != nil { 512 assoc_trait = traitWithId(assoc_trait.Id, traits_dup) 513 } 514 515 new_gene := NewGeneCopy(gn, assoc_trait, in_node, out_node) 516 genes_dup = append(genes_dup, new_gene) 517 } 518 519 if len(g.ControlGenes) == 0 { 520 // If no MIMO control genes return plain genome 521 return NewGenome(new_id, traits_dup, nodes_dup, genes_dup), nil 522 } else { 523 // Duplicate MIMO Control Genes and build modular genome 524 control_genes_dup := make([]*MIMOControlGene, 0) 525 for _, cg := range g.ControlGenes { 526 // duplicate control node 527 c_node := cg.ControlNode 528 // find duplicate of trait associated with control node 529 assoc_trait := c_node.Trait 530 if assoc_trait != nil { 531 assoc_trait = traitWithId(assoc_trait.Id, traits_dup) 532 } 533 new_c_node := network.NewNNodeCopy(c_node, assoc_trait) 534 // add incoming links 535 for _, l := range c_node.Incoming { 536 in_node := nodeWithId(l.InNode.Id, nodes_dup) 537 if in_node == nil { 538 return nil, errors.New( 539 fmt.Sprintf("incoming node: %d not found for control node: %d", 540 l.InNode.Id, c_node.Id)) 541 } 542 new_in_link := network.NewLinkCopy(l, in_node, new_c_node) 543 new_c_node.Incoming = append(new_c_node.Incoming, new_in_link) 544 } 545 546 // add outgoing links 547 for _, l := range c_node.Outgoing { 548 out_node := nodeWithId(l.OutNode.Id, nodes_dup) 549 if out_node == nil { 550 return nil, errors.New( 551 fmt.Sprintf("outgoing node: %d not found for control node: %d", 552 l.InNode.Id, c_node.Id)) 553 } 554 new_out_link := network.NewLinkCopy(l, new_c_node, out_node) 555 new_c_node.Outgoing = append(new_c_node.Outgoing, new_out_link) 556 } 557 558 // add MIMO control gene 559 new_cg := NewMIMOGeneCopy(cg, new_c_node) 560 control_genes_dup = append(control_genes_dup, new_cg) 561 } 562 563 return NewModularGenome(new_id, traits_dup, nodes_dup, genes_dup, control_genes_dup), nil 564 } 565 } 566 567 // For debugging: A number of tests can be run on a genome to check its integrity. 568 // Note: Some of these tests do not indicate a bug, but rather are meant to be used to detect specific system states. 569 func (g *Genome) verify() (bool, error) { 570 if len(g.Genes) == 0 { 571 return false, errors.New("Genome has no Genes") 572 } 573 if len(g.Nodes) == 0 { 574 return false, errors.New("Genome has no Nodes") 575 } 576 if len(g.Traits) == 0 { 577 return false, errors.New("Genome has no Traits") 578 } 579 580 581 // Check each gene's nodes 582 for _, gn := range g.Genes { 583 inode := gn.Link.InNode 584 onode := gn.Link.OutNode 585 i_found, o_found := false, false 586 for i := 0; i < len(g.Nodes) && (!i_found || !o_found); i++ { 587 if inode.Id == g.Nodes[i].Id { 588 i_found = true 589 } 590 if onode.Id == g.Nodes[i].Id { 591 o_found = true 592 } 593 } 594 595 // check results 596 if !i_found { 597 return false, errors.New("Missing input node of gene in the genome nodes") 598 } 599 if !o_found { 600 return false, errors.New("Missing output node of gene in the genome nodes") 601 } 602 } 603 604 // Check for NNodes being out of order 605 last_id := 0 606 for _, n := range g.Nodes { 607 if n.Id < last_id { 608 return false, errors.New("Nodes out of order in genome") 609 } 610 last_id = n.Id 611 } 612 613 // Make sure there are no duplicate genes 614 for _, gn := range g.Genes { 615 for _, gn2 := range g.Genes { 616 if gn != gn2 && gn.Link.IsEqualGenetically(gn2.Link) { 617 return false, errors.New(fmt.Sprintf("Duplicate genes found. %s == %s", gn, gn2)) 618 } 619 } 620 } 621 // Check for 2 disables in a row 622 // Note: Again, this is not necessarily a bad sign 623 if len(g.Nodes) > 500 { 624 disab := false 625 for _, gn := range g.Genes { 626 if gn.IsEnabled == false && disab { 627 return false, errors.New("Two gene disables in a row") 628 } 629 disab = !gn.IsEnabled 630 } 631 } 632 return true, nil 633 } 634 635 // Inserts a NNode into a given ordered list of NNodes in ascending order by NNode ID 636 func nodeInsert(nodes[]*network.NNode, n *network.NNode) []*network.NNode { 637 index := len(nodes) 638 // quick insert at the end or beginning (we assume that nodes is already ordered) 639 if index == 0 || n.Id >= nodes[index - 1].Id { 640 // append last 641 nodes = append(nodes, n) 642 return nodes 643 } else if n.Id <= nodes[0].Id { 644 // insert first 645 index = 0 646 } 647 // find split index 648 for i := index - 1; i >= 0; i-- { 649 if n.Id == nodes[i].Id { 650 index = i 651 break 652 } else if n.Id > nodes[i].Id { 653 index = i + 1 // previous 654 break 655 } 656 } 657 first := make([]*network.NNode, index + 1) 658 copy(first, nodes[0:index]) 659 first[index] = n 660 second := nodes[index:] 661 662 nodes = append(first, second...) 663 return nodes 664 } 665 666 // Inserts a new gene that has been created through a mutation in the 667 // *correct order* into the list of genes in the genome, i.e. ordered by innovation number ascending 668 func geneInsert(genes[]*Gene, g *Gene) []*Gene { 669 index := len(genes) // to make sure that greater IDs appended at the end 670 // quick insert at the end or beginning (we assume that nodes is already ordered) 671 if index == 0 || g.InnovationNum >= genes[index - 1].InnovationNum { 672 // append last 673 genes = append(genes, g) 674 return genes 675 } else if g.InnovationNum <= genes[0].InnovationNum { 676 // insert first 677 index = 0 678 } 679 // find split index 680 for i := index - 1; i >= 0; i-- { 681 if g.InnovationNum == genes[i].InnovationNum { 682 index = i 683 break 684 } else if g.InnovationNum > genes[i].InnovationNum { 685 index = i + 1 // previous 686 break 687 } 688 } 689 690 first := make([]*Gene, index + 1) 691 copy(first, genes[0:index]) 692 first[index] = g 693 second := genes[index:] 694 genes = append(first, second...) 695 return genes 696 697 } 698 699 /* ******* MUTATORS ******* */ 700 701 // Mutate the genome by adding connections to disconnected sensors (input, bias type neurons). 702 // The reason this mutator is important is that if we can start NEAT with some inputs disconnected, 703 // then we can allow NEAT to decide which inputs are important. 704 // This process has two good effects: 705 // (1) You can start minimally even in problems with many inputs and 706 // (2) you don't need to know a priori what the important features of the domain are. 707 // If all sensors already connected than do nothing. 708 func (g *Genome) mutateConnectSensors(pop *Population, context *neat.NeatContext) (bool, error) { 709 710 if len(g.Genes) == 0 { 711 return false, errors.New("Genome has no genes") 712 } 713 714 // Find all the sensors and outputs 715 sensors := make([]*network.NNode, 0) 716 outputs := make([]*network.NNode, 0) 717 for _, n := range g.Nodes { 718 if n.IsSensor() { 719 sensors = append(sensors, n) 720 } else { 721 outputs = append(outputs, n) 722 } 723 } 724 725 // Find not connected sensors if any 726 disconnected_sensors := make([]*network.NNode, 0) 727 for _, sensor := range sensors { 728 connected := false 729 730 // iterate over all genes and count number of output connections from given sensor 731 for _, gene := range g.Genes { 732 if gene.Link.InNode.Id == sensor.Id { 733 connected = true 734 break 735 } 736 } 737 738 if !connected { 739 // store found disconnected sensor 740 disconnected_sensors = append(disconnected_sensors, sensor) 741 } 742 } 743 744 // if all sensors are connected - stop 745 if len(disconnected_sensors) == 0 { 746 return false, nil 747 } 748 749 // pick randomly from disconnected sensors 750 sensor := disconnected_sensors[rand.Intn(len(disconnected_sensors))] 751 // add new links to chosen sensor, avoiding redundancy 752 link_added := false 753 for _, output := range outputs { 754 found := false 755 for _, gene := range g.Genes { 756 if gene.Link.InNode == sensor && gene.Link.OutNode == output { 757 found = true 758 break 759 } 760 } 761 762 if !found { 763 var new_gene *Gene 764 // Check to see if this innovation already occurred in the population 765 innovation_found := false 766 for _, inn := range pop.Innovations { 767 if inn.innovationType == newLinkInnType && 768 inn.InNodeId == sensor.Id && 769 inn.OutNodeId == output.Id && 770 inn.IsRecurrent == false { 771 772 new_gene = NewGeneWithTrait(g.Traits[inn.NewTraitNum], inn.NewWeight, 773 sensor, output, false, inn.InnovationNum, 0) 774 775 innovation_found = true 776 break 777 } 778 } 779 780 // The innovation is totally novel 781 if !innovation_found { 782 // Choose a random trait 783 trait_num := rand.Intn(len(g.Traits)) 784 // Choose the new weight 785 new_weight := float64(utils.RandSign()) * rand.Float64() * 10.0 786 // read next innovation id 787 next_innov_id := pop.getNextInnovationNumberAndIncrement() 788 789 790 // Create the new gene 791 new_gene = NewGeneWithTrait(g.Traits[trait_num], new_weight, sensor, output, 792 false, next_innov_id, new_weight) 793 794 // Add the innovation for created link 795 new_innov := NewInnovationForLink(sensor.Id, output.Id, next_innov_id, 796 new_weight, trait_num) 797 pop.addInnovationSynced(new_innov) 798 } else if g.hasGene(new_gene) { 799 // The gene for already occurred innovation already in this genome. 800 // This may happen as result of parent genome mutation in current epoch which is 801 // repeated in the child after parent's genome transferred to child during mating 802 neat.InfoLog( 803 fmt.Sprintf("GENOME: Connect sensors innovation found [%t] in the same genome [%d] for gene: %s\n%s", 804 innovation_found, g.Id, new_gene, g)) 805 return false, nil 806 } 807 808 // Now add the new Gene to the Genome 809 g.Genes = geneInsert(g.Genes, new_gene) 810 link_added = true 811 } 812 } 813 return link_added, nil 814 } 815 816 // Mutate the genome by adding a new link between two random NNodes, 817 // if NNodes are already connected, keep trying conf.NewLinkTries times 818 func (g *Genome) mutateAddLink(pop *Population, context *neat.NeatContext) (bool, error) { 819 // If the phenotype does not exist, exit on false, print error 820 // Note: This should never happen - if it does there is a bug 821 if g.Phenotype == nil { 822 return false, errors.New("Attempt to add link to genome with no phenotype") 823 } else if len(g.Nodes) == 0 { 824 return false, errors.New("Genome has no nodes to be connected by new link") 825 } 826 827 nodes_len := len(g.Nodes) 828 829 // Decide whether to make link recurrent 830 do_recur := false 831 if rand.Float64() < context.RecurOnlyProb { 832 do_recur = true 833 } 834 835 // Find the first non-sensor so that the to-node won't look at sensors as possible destinations 836 first_non_sensor := 0 837 for _, n := range g.Nodes { 838 if n.IsSensor() { 839 first_non_sensor++ 840 } else { 841 break 842 } 843 } 844 845 // Made attempts to find an unconnected pair 846 try_count := 0 847 848 // Iterate over nodes and try to add new link 849 var node_1, node_2 *network.NNode 850 found := false 851 for try_count < context.NewLinkTries { 852 node_num_1, node_num_2 := 0, 0 853 if do_recur { 854 // 50% of prob to decide create a recurrent link (node X to node X) 855 // 50% of a normal link (node X to node Y) 856 loop_recur := false 857 if rand.Float64() > 0.5 { 858 loop_recur = true 859 } 860 if loop_recur { 861 node_num_1 = first_non_sensor + rand.Intn(nodes_len - first_non_sensor) // only NON SENSOR 862 node_num_2 = node_num_1 863 } else { 864 for node_num_1 == node_num_2 { 865 node_num_1 = rand.Intn(nodes_len) 866 node_num_2 = first_non_sensor + rand.Intn(nodes_len - first_non_sensor) // only NON SENSOR 867 } 868 } 869 } else { 870 for node_num_1 == node_num_2 { 871 node_num_1 = rand.Intn(nodes_len) 872 node_num_2 = first_non_sensor + rand.Intn(nodes_len - first_non_sensor) // only NON SENSOR 873 } 874 } 875 876 // get corresponding nodes 877 node_1 = g.Nodes[node_num_1] 878 node_2 = g.Nodes[node_num_2] 879 880 // See if a link already exists ALSO STOP AT END OF GENES!!!! 881 link_exists := false 882 if node_2.IsSensor() { 883 // Don't allow SENSORS to get input 884 link_exists = true 885 } else { 886 for _, gene := range g.Genes { 887 if gene.Link.InNode.Id == node_1.Id && 888 gene.Link.OutNode.Id == node_2.Id && 889 gene.Link.IsRecurrent == do_recur { 890 // link already exists 891 link_exists = true; 892 break; 893 } 894 895 } 896 } 897 898 if !link_exists { 899 // These are used to avoid getting stuck in an infinite loop checking for recursion 900 // Note that we check for recursion to control the frequency of adding recurrent links rather 901 // than to prevent any particular kind of error 902 thresh := nodes_len * nodes_len 903 count := 0 904 recur_flag := g.Phenotype.IsRecurrent(node_1.PhenotypeAnalogue, node_2.PhenotypeAnalogue, &count, thresh) 905 906 // NOTE: A loop doesn't really matter - just debug output it 907 if count > thresh { 908 neat.DebugLog( 909 fmt.Sprintf("GENOME: LOOP DETECTED DURING A RECURRENCY CHECK -> " + 910 "node in: %s <-> node out: %s", node_1.PhenotypeAnalogue, node_2.PhenotypeAnalogue)) 911 } 912 913 // Make sure it finds the right kind of link (recurrent or not) 914 if (!recur_flag && do_recur) || (recur_flag && !do_recur) { 915 try_count++ 916 } else { 917 // The open link found 918 try_count = context.NewLinkTries 919 found = true 920 } 921 } else { 922 try_count++ 923 } 924 925 } 926 // Continue only if an open link was found 927 if found { 928 var new_gene *Gene 929 // Check to see if this innovation already occurred in the population 930 innovation_found := false 931 for _, inn := range pop.Innovations { 932 // match the innovation in the innovations list 933 if inn.innovationType == newLinkInnType && 934 inn.InNodeId == node_1.Id && 935 inn.OutNodeId == node_2.Id && 936 inn.IsRecurrent == do_recur { 937 938 // Create new gene 939 new_gene = NewGeneWithTrait(g.Traits[inn.NewTraitNum], inn.NewWeight, node_1, node_2, do_recur, inn.InnovationNum, 0) 940 941 innovation_found = true 942 break 943 } 944 } 945 // The innovation is totally novel 946 if !innovation_found { 947 // Choose a random trait 948 trait_num := rand.Intn(len(g.Traits)) 949 // Choose the new weight 950 new_weight := float64(utils.RandSign()) * rand.Float64() * 10.0 951 // read next innovation id 952 next_innov_id := pop.getNextInnovationNumberAndIncrement() 953 954 // Create the new gene 955 new_gene = NewGeneWithTrait(g.Traits[trait_num], new_weight, node_1, node_2, 956 do_recur, next_innov_id, new_weight) 957 958 // Add the innovation 959 new_innov := NewInnovationForRecurrentLink(node_1.Id, node_2.Id, next_innov_id, 960 new_weight, trait_num, do_recur) 961 pop.addInnovationSynced(new_innov) 962 } else if g.hasGene(new_gene) { 963 // The gene for already occurred innovation already in this genome. 964 // This may happen as result of parent genome mutation in current epoch which is 965 // repeated in the child after parent's genome transferred to child during mating 966 neat.InfoLog( 967 fmt.Sprintf("GENOME: Mutate add link innovation found [%t] in the same genome [%d] for gene: %s\n%s", 968 innovation_found, g.Id, new_gene, g)) 969 return false, nil 970 } 971 972 // sanity check 973 if new_gene.Link.InNode.Id == new_gene.Link.OutNode.Id && !do_recur { 974 neat.DebugLog(fmt.Sprintf("Recurent link created when recurency is not enabled: %s", new_gene)) 975 return false, errors.New(fmt.Sprintf("GENOME: Wrong gene created!\n%s", g)) 976 } 977 978 // Now add the new Gene to the Genome 979 g.Genes = geneInsert(g.Genes, new_gene) 980 } 981 982 return found, nil 983 } 984 985 // This mutator adds a node to a Genome by inserting it in the middle of an existing link between two nodes. 986 // This broken link will be disabled and now represented by two links with the new node between them. 987 // The innovations list from population is used to compare the innovation with other innovations in the list and see 988 // whether they match. If they do, the same innovation numbers will be assigned to the new genes. If a disabled link 989 // is chosen, then the method just exits with false. 990 func (g *Genome) mutateAddNode(pop *Population, context *neat.NeatContext) (bool, error) { 991 if len(g.Genes) == 0 { 992 return false, nil // it's possible to have such a network without any link 993 } 994 995 // First, find a random gene already in the genome 996 found := false 997 var gene *Gene 998 999 // For a very small genome, we need to bias splitting towards older links to avoid a "chaining" effect which is likely 1000 // to occur when we keep splitting between the same two nodes over and over again (on newer and newer connections) 1001 if len(g.Genes) < 15 { 1002 for _, gn := range g.Genes { 1003 // Now randomize which gene is chosen. 1004 if gn.IsEnabled && gn.Link.InNode.NeuronType != network.BiasNeuron && rand.Float32() >= 0.3 { 1005 gene = gn 1006 found = true 1007 break 1008 } 1009 } 1010 } else { 1011 try_count := 0 1012 // Alternative uniform random choice of genes. When the genome is not tiny, it is safe to choose randomly. 1013 for try_count < 20 && !found { 1014 gene_num := rand.Intn(len(g.Genes)) 1015 gene = g.Genes[gene_num] 1016 if gene.IsEnabled && gene.Link.InNode.NeuronType != network.BiasNeuron { 1017 found = true 1018 } 1019 try_count++ 1020 } 1021 } 1022 if !found { 1023 // Failed to find appropriate gene 1024 return false, nil 1025 } 1026 1027 gene.IsEnabled = false; 1028 1029 // Extract the link 1030 link := gene.Link 1031 // Extract the weight 1032 old_weight := link.Weight 1033 // Get the old link's trait 1034 trait := link.Trait 1035 1036 // Extract the nodes 1037 in_node, out_node := link.InNode, link.OutNode 1038 if in_node == nil || out_node == nil { 1039 return false, errors.New( 1040 fmt.Sprintf("Genome:mutateAddNode: Anomalous link found with either IN or OUT node not set. %s", link)) 1041 } 1042 1043 var new_gene_1, new_gene_2 *Gene 1044 var new_node *network.NNode 1045 1046 // Check to see if this innovation already occurred in the population 1047 innovation_found := false 1048 for _, inn := range pop.Innovations { 1049 /* We check to see if an innovation already occurred that was: 1050 -A new node 1051 -Stuck between the same nodes as were chosen for this mutation 1052 -Splitting the same gene as chosen for this mutation 1053 If so, we know this mutation is not a novel innovation in this generation 1054 so we make it match the original, identical mutation which occurred 1055 elsewhere in the population by coincidence */ 1056 if inn.innovationType == newNodeInnType && 1057 inn.InNodeId == in_node.Id && 1058 inn.OutNodeId == out_node.Id && 1059 inn.OldInnovNum == gene.InnovationNum { 1060 1061 // Create the new NNode 1062 new_node = network.NewNNode(inn.NewNodeId, network.HiddenNeuron) 1063 // By convention, it will point to the first trait 1064 // Note: In future may want to change this 1065 new_node.Trait = g.Traits[0] 1066 1067 // Create the new Genes 1068 new_gene_1 = NewGeneWithTrait(trait, 1.0, in_node, new_node, link.IsRecurrent, inn.InnovationNum, 0) 1069 new_gene_2 = NewGeneWithTrait(trait, old_weight, new_node, out_node, false, inn.InnovationNum2, 0) 1070 1071 innovation_found = true 1072 break 1073 } 1074 } 1075 // The innovation is totally novel 1076 if !innovation_found { 1077 // Get the current node id with post increment 1078 new_node_id := int(pop.getNextNodeIdAndIncrement()) 1079 1080 // Create the new NNode 1081 new_node = network.NewNNode(new_node_id, network.HiddenNeuron) 1082 // By convention, it will point to the first trait 1083 new_node.Trait = g.Traits[0] 1084 // Set node activation function as random from a list of types registered with context 1085 if act_type, err := context.RandomNodeActivationType(); err != nil { 1086 return false, err 1087 } else { 1088 new_node.ActivationType = act_type 1089 } 1090 1091 // get the next innovation id for gene 1 1092 gene_innov_1 := pop.getNextInnovationNumberAndIncrement() 1093 // create gene with the current gene innovation 1094 new_gene_1 = NewGeneWithTrait(trait, 1.0, in_node, new_node, link.IsRecurrent, gene_innov_1, 0); 1095 1096 // get the next innovation id for gene 2 1097 gene_innov_2 := pop.getNextInnovationNumberAndIncrement() 1098 // create the second gene with this innovation incremented 1099 new_gene_2 = NewGeneWithTrait(trait, old_weight, new_node, out_node, false, gene_innov_2, 0); 1100 1101 // Store innovation 1102 innov := NewInnovationForNode(in_node.Id, out_node.Id, gene_innov_1, gene_innov_2, new_node.Id, gene.InnovationNum) 1103 pop.addInnovationSynced(innov) 1104 } else if g.hasNode(new_node) { 1105 // The same add node innovation occurred in the same genome (parent) - just skip. 1106 // This may happen when parent of this organism experienced the same mutation in current epoch earlier 1107 // and after that parent's genome was duplicated to child by mating and the same mutation parameters 1108 // was selected again (in_node.Id, out_node.Id, gene.InnovationNum). As result the innovation with given 1109 // parameters will be found and new node will be created with ID which alredy exists in child genome. 1110 // If proceed than we will have duplicated Node and genes - so we're skipping this. 1111 neat.InfoLog( 1112 fmt.Sprintf("GENOME: Add node innovation found [%t] in the same genome [%d] for node [%d]\n%s", 1113 innovation_found, g.Id, new_node.Id, g)) 1114 return false, nil 1115 } 1116 1117 1118 // Now add the new NNode and new Genes to the Genome 1119 g.Genes = geneInsert(g.Genes, new_gene_1) 1120 g.Genes = geneInsert(g.Genes, new_gene_2) 1121 g.Nodes = nodeInsert(g.Nodes, new_node) 1122 1123 return true, nil 1124 } 1125 1126 // Adds Gaussian noise to link weights either GAUSSIAN or COLD_GAUSSIAN (from zero). 1127 // The COLD_GAUSSIAN means ALL connection weights will be given completely new values 1128 func (g *Genome) mutateLinkWeights(power, rate float64, mutation_type mutatorType) (bool, error) { 1129 if len(g.Genes) == 0 { 1130 return false, errors.New("Genome has no genes") 1131 } 1132 1133 // Once in a while really shake things up 1134 severe := false 1135 if rand.Float64() > 0.5 { 1136 severe = true 1137 } 1138 1139 // Go through all the Genes and perturb their link's weights 1140 num, gene_total := 0.0, float64(len(g.Genes)) 1141 end_part := gene_total * 0.8 1142 var gauss_point, cold_gauss_point float64 1143 1144 for _, gene := range g.Genes { 1145 // The following if determines the probabilities of doing cold gaussian 1146 // mutation, meaning the probability of replacing a link weight with 1147 // another, entirely random weight. It is meant to bias such mutations 1148 // to the tail of a genome, because that is where less time-tested genes 1149 // reside. The gauss_point and cold_gauss_point represent values above 1150 // which a random float will signify that kind of mutation. 1151 if severe { 1152 gauss_point = 0.3 1153 cold_gauss_point = 0.1 1154 } else if gene_total >= 10.0 && num > end_part { 1155 gauss_point = 0.5 // Mutate by modification % of connections 1156 cold_gauss_point = 0.3 // Mutate the rest by replacement % of the time 1157 } else { 1158 // Half the time don't do any cold mutations 1159 if rand.Float64() > 0.5 { 1160 gauss_point = 1.0 - rate 1161 cold_gauss_point = gauss_point - 0.1 1162 } else { 1163 gauss_point = 1.0 - rate 1164 cold_gauss_point = gauss_point // no cold mutation possible (see later) 1165 } 1166 } 1167 1168 rand_val := float64(utils.RandSign()) * rand.Float64() * power 1169 if mutation_type == gaussianMutator { 1170 rand_choice := rand.Float64() 1171 if rand_choice > gauss_point { 1172 gene.Link.Weight += rand_val 1173 } else if rand_choice > cold_gauss_point { 1174 gene.Link.Weight = rand_val 1175 } 1176 } else if mutation_type == goldGaussianMutator { 1177 gene.Link.Weight = rand_val 1178 } 1179 1180 // Record the innovation 1181 gene.MutationNum = gene.Link.Weight 1182 1183 num += 1.0 1184 } 1185 1186 return true, nil 1187 } 1188 1189 // Perturb params in one trait 1190 func (g *Genome) mutateRandomTrait(context *neat.NeatContext) (bool, error) { 1191 if len(g.Traits) == 0 { 1192 return false, errors.New("Genome has no traits") 1193 } 1194 // Choose a random trait number 1195 trait_num := rand.Intn(len(g.Traits)) 1196 1197 // Retrieve the trait and mutate it 1198 g.Traits[trait_num].Mutate(context.TraitMutationPower, context.TraitParamMutProb) 1199 1200 return true, nil 1201 } 1202 1203 // This chooses a random gene, extracts the link from it and re-points the link to a random trait 1204 func (g *Genome) mutateLinkTrait(times int) (bool, error) { 1205 if len(g.Traits) == 0 || len(g.Genes) == 0 { 1206 return false, errors.New("Genome has either no traits od genes") 1207 } 1208 for loop := 0; loop < times; loop++ { 1209 // Choose a random trait number 1210 trait_num := rand.Intn(len(g.Traits)) 1211 1212 // Choose a random link number 1213 gene_num := rand.Intn(len(g.Genes)) 1214 1215 // set the link to point to the new trait 1216 g.Genes[gene_num].Link.Trait = g.Traits[trait_num] 1217 1218 } 1219 return true, nil 1220 } 1221 1222 // This chooses a random node and re-points the node to a random trait specified number of times 1223 func (g *Genome) mutateNodeTrait(times int) (bool, error) { 1224 if len(g.Traits) == 0 || len(g.Nodes) == 0 { 1225 return false, errors.New("Genome has either no traits or nodes") 1226 } 1227 for loop := 0; loop < times; loop++ { 1228 // Choose a random trait number 1229 trait_num := rand.Intn(len(g.Traits)) 1230 1231 // Choose a random node number 1232 node_num := rand.Intn(len(g.Nodes)) 1233 1234 // set the node to point to the new trait 1235 g.Nodes[node_num].Trait = g.Traits[trait_num] 1236 } 1237 return true, nil 1238 } 1239 1240 // Toggle genes from enable on to enable off or vice versa. Do it specified number of times. 1241 func (g *Genome) mutateToggleEnable(times int) (bool, error) { 1242 if len(g.Genes) == 0 { 1243 return false, errors.New("Genome has no genes to toggle") 1244 } 1245 for loop := 0; loop < times; loop++ { 1246 // Choose a random gene number 1247 gene_num := rand.Intn(len(g.Genes)) 1248 1249 gene := g.Genes[gene_num] 1250 if gene.IsEnabled { 1251 // We need to make sure that another gene connects out of the in-node. 1252 // Because if not a section of network will break off and become isolated. 1253 for _, check_gene := range g.Genes { 1254 if check_gene.Link.InNode.Id == gene.Link.InNode.Id && 1255 check_gene.IsEnabled && check_gene.InnovationNum != gene.InnovationNum { 1256 gene.IsEnabled = false 1257 break 1258 } 1259 } 1260 } else { 1261 gene.IsEnabled = true 1262 } 1263 1264 } 1265 return true, nil 1266 } 1267 // Finds first disabled gene and enable it 1268 func (g *Genome) mutateGeneReenable() (bool, error) { 1269 if len(g.Genes) == 0 { 1270 return false, errors.New("Genome has no genes to re-enable") 1271 } 1272 for _, gene := range g.Genes { 1273 if !gene.IsEnabled { 1274 gene.IsEnabled = true 1275 break 1276 } 1277 } 1278 return true, nil 1279 } 1280 1281 // Applies all non-structural mutations to this genome 1282 func (g *Genome) mutateAllNonstructural(context *neat.NeatContext) (bool, error) { 1283 res := false 1284 var err error 1285 if rand.Float64() < context.MutateRandomTraitProb { 1286 // mutate random trait 1287 res, err = g.mutateRandomTrait(context) 1288 } 1289 1290 if err == nil && rand.Float64() < context.MutateLinkTraitProb { 1291 // mutate link trait 1292 res, err = g.mutateLinkTrait(1) 1293 } 1294 1295 if err == nil && rand.Float64() < context.MutateNodeTraitProb { 1296 // mutate node trait 1297 res, err = g.mutateNodeTrait(1) 1298 } 1299 1300 if err == nil && rand.Float64() < context.MutateLinkWeightsProb { 1301 // mutate link weight 1302 res, err = g.mutateLinkWeights(context.WeightMutPower, 1.0, gaussianMutator) 1303 } 1304 1305 if err == nil && rand.Float64() < context.MutateToggleEnableProb { 1306 // mutate toggle enable 1307 res, err = g.mutateToggleEnable(1) 1308 } 1309 1310 if err == nil && rand.Float64() < context.MutateGeneReenableProb { 1311 // mutate gene reenable 1312 res, err = g.mutateGeneReenable(); 1313 } 1314 return res, err 1315 } 1316 1317 /* ****** MATING METHODS ***** */ 1318 1319 // This method mates this Genome with another Genome g. For every point in each Genome, where each Genome shares 1320 // the innovation number, the Gene is chosen randomly from either parent. If one parent has an innovation absent in 1321 // the other, the baby may inherit the innovation if it is from the more fit parent. 1322 // The new Genome is given the id in the genomeid argument. 1323 func (gen *Genome) mateMultipoint(og *Genome, genomeid int, fitness1, fitness2 float64) (*Genome, error) { 1324 // Check if genomes has equal number of traits 1325 if len(gen.Traits) != len(og.Traits) { 1326 return nil, errors.New(fmt.Sprintf("Genomes has different traits count, %d != %d", len(gen.Traits), len(og.Traits))) 1327 } 1328 1329 // First, average the Traits from the 2 parents to form the baby's Traits. It is assumed that trait vectors are 1330 // the same length. In the future, may decide on a different method for trait mating. 1331 new_traits, err := gen.mateTraits(og) 1332 if err != nil { 1333 return nil, err 1334 } 1335 1336 // The new genes and nodes created 1337 new_genes := make([]*Gene, 0) 1338 new_nodes := make([]*network.NNode, 0) 1339 child_nodes_map := make(map[int]*network.NNode) 1340 1341 // NEW: Make sure all sensors and outputs are included (in case some inputs are disconnected) 1342 for _, curr_node := range og.Nodes { 1343 if curr_node.NeuronType == network.InputNeuron || 1344 curr_node.NeuronType == network.BiasNeuron || 1345 curr_node.NeuronType == network.OutputNeuron { 1346 node_trait_num := 0 1347 if curr_node.Trait != nil { 1348 node_trait_num = curr_node.Trait.Id - gen.Traits[0].Id 1349 } 1350 // Create a new node off the sensor or output 1351 new_onode := network.NewNNodeCopy(curr_node, new_traits[node_trait_num]) 1352 1353 // Add the new node 1354 new_nodes = nodeInsert(new_nodes, new_onode) 1355 child_nodes_map[new_onode.Id] = new_onode 1356 } 1357 } 1358 1359 // Figure out which genome is better. The worse genome should not be allowed to add extra structural baggage. 1360 // If they are the same, use the smaller one's disjoint and excess genes only. 1361 p1better := false // Tells if the first genome (this one) has better fitness or not 1362 if fitness1 > fitness2 || 1363 (fitness1 == fitness2 && len(gen.Genes) < len(og.Genes)) { 1364 p1better = true 1365 } 1366 1367 // Now loop through the Genes of each parent 1368 i1, i2, size1, size2 := 0, 0, len(gen.Genes), len(og.Genes) 1369 var chosen_gene *Gene 1370 for i1 < size1 || i2 < size2 { 1371 skip, disable := false, false 1372 1373 // choose best gene 1374 if i1 >= size1 { 1375 chosen_gene = og.Genes[i2] 1376 i2++ 1377 if p1better { 1378 skip = true // Skip excess from the worse genome 1379 } 1380 } else if i2 >= size2 { 1381 chosen_gene = gen.Genes[i1] 1382 i1++ 1383 if !p1better { 1384 skip = true // Skip excess from the worse genome 1385 } 1386 } else { 1387 p1gene := gen.Genes[i1] 1388 p2gene := og.Genes[i2] 1389 1390 // Extract current innovation numbers 1391 p1innov := p1gene.InnovationNum 1392 p2innov := p2gene.InnovationNum 1393 1394 if p1innov == p2innov { 1395 if rand.Float64() < 0.5 { 1396 chosen_gene = p1gene 1397 } else { 1398 chosen_gene = p2gene 1399 } 1400 1401 // If one is disabled, the corresponding gene in the offspring will likely be disabled 1402 if !p1gene.IsEnabled || !p2gene.IsEnabled && rand.Float64() < 0.75 { 1403 disable = true 1404 } 1405 i1++ 1406 i2++ 1407 } else if p1innov < p2innov { 1408 chosen_gene = p1gene 1409 i1++ 1410 if !p1better { 1411 skip = true // Skip excess from the worse genome 1412 } 1413 } else { 1414 chosen_gene = p2gene 1415 i2++ 1416 if p1better { 1417 skip = true // Skip excess from the worse genome 1418 } 1419 } 1420 } 1421 1422 // Uncomment this line to let growth go faster (from both parents excesses) 1423 // skip=false 1424 1425 // Check to see if the chosen gene conflicts with an already chosen gene i.e. do they represent the same link 1426 for _, new_gene := range new_genes { 1427 if new_gene.Link.IsEqualGenetically(chosen_gene.Link) { 1428 skip = true; 1429 break; 1430 } 1431 } 1432 1433 // Now add the chosen gene to the baby 1434 if (!skip) { 1435 // Check for the nodes, add them if not in the baby Genome already 1436 in_node := chosen_gene.Link.InNode 1437 out_node := chosen_gene.Link.OutNode 1438 1439 // Checking for inode's existence 1440 var new_in_node *network.NNode 1441 for _, node := range new_nodes { 1442 if node.Id == in_node.Id { 1443 new_in_node = node 1444 break 1445 } 1446 } 1447 if new_in_node == nil { 1448 // Here we know the node doesn't exist so we have to add it normalized trait 1449 // number for new NNode 1450 in_node_trait_num := 0 1451 if in_node.Trait != nil { 1452 in_node_trait_num = in_node.Trait.Id - gen.Traits[0].Id 1453 } 1454 new_in_node = network.NewNNodeCopy(in_node, new_traits[in_node_trait_num]) 1455 new_nodes = nodeInsert(new_nodes, new_in_node) 1456 child_nodes_map[new_in_node.Id] = new_in_node 1457 } 1458 1459 // Checking for onode's existence 1460 var new_out_node *network.NNode 1461 for _, node := range new_nodes { 1462 if node.Id == out_node.Id { 1463 new_out_node = node 1464 break 1465 } 1466 } 1467 if new_out_node == nil { 1468 // Here we know the node doesn't exist so we have to add it normalized trait 1469 // number for new NNode 1470 out_node_trait_num := 0 1471 if out_node.Trait != nil { 1472 out_node_trait_num = out_node.Trait.Id - gen.Traits[0].Id 1473 } 1474 new_out_node = network.NewNNodeCopy(out_node, new_traits[out_node_trait_num]) 1475 new_nodes = nodeInsert(new_nodes, new_out_node) 1476 child_nodes_map[new_out_node.Id] = new_out_node 1477 } 1478 1479 1480 // Add the Gene 1481 gene_trait_num := 0 1482 if chosen_gene.Link.Trait != nil { 1483 // The subtracted number normalizes depending on whether traits start counting at 1 or 0 1484 gene_trait_num = chosen_gene.Link.Trait.Id - gen.Traits[0].Id 1485 } 1486 newgene := NewGeneCopy(chosen_gene, new_traits[gene_trait_num], new_in_node, new_out_node) 1487 if disable { 1488 newgene.IsEnabled = false 1489 } 1490 new_genes = append(new_genes, newgene) 1491 } // end SKIP 1492 } // end FOR 1493 // check if parent's MIMO control genes should be inherited 1494 if len(gen.ControlGenes) != 0 || len(og.ControlGenes) != 0 { 1495 // MIMO control genes found at least in one parent - append it to child if appropriate 1496 if extra_nodes, modules := gen.mateModules(child_nodes_map, og); modules != nil { 1497 if len(extra_nodes) > 0 { 1498 // append extra IO nodes of MIMO genes not found in child 1499 new_nodes = append(new_nodes, extra_nodes...) 1500 } 1501 1502 // Return modular baby genome 1503 return NewModularGenome(genomeid, new_traits, new_nodes, new_genes, modules), nil 1504 } 1505 } 1506 // Return plain baby Genome 1507 return NewGenome(genomeid, new_traits, new_nodes, new_genes), nil 1508 } 1509 1510 // This method mates like multipoint but instead of selecting one or the other when the innovation numbers match, 1511 // it averages their weights. 1512 func (gen *Genome) mateMultipointAvg(og *Genome, genomeid int, fitness1, fitness2 float64) (*Genome, error) { 1513 // Check if genomes has equal number of traits 1514 if len(gen.Traits) != len(og.Traits) { 1515 return nil, errors.New(fmt.Sprintf("Genomes has different traits count, %d != %d", len(gen.Traits), len(og.Traits))) 1516 } 1517 1518 // First, average the Traits from the 2 parents to form the baby's Traits. It is assumed that trait vectors are 1519 // the same length. In the future, may decide on a different method for trait mating. 1520 new_traits, err := gen.mateTraits(og) 1521 if err != nil { 1522 return nil, err 1523 } 1524 1525 1526 // The new genes and nodes created 1527 new_genes := make([]*Gene, 0) 1528 new_nodes := make([]*network.NNode, 0) 1529 child_nodes_map := make(map[int]*network.NNode) 1530 1531 // NEW: Make sure all sensors and outputs are included (in case some inputs are disconnected) 1532 for _, curr_node := range og.Nodes { 1533 if curr_node.NeuronType == network.InputNeuron || 1534 curr_node.NeuronType == network.BiasNeuron || 1535 curr_node.NeuronType == network.OutputNeuron { 1536 node_trait_num := 0 1537 if curr_node.Trait != nil { 1538 node_trait_num = curr_node.Trait.Id - gen.Traits[0].Id 1539 } 1540 // Create a new node off the sensor or output 1541 new_onode := network.NewNNodeCopy(curr_node, new_traits[node_trait_num]) 1542 1543 // Add the new node 1544 new_nodes = nodeInsert(new_nodes, new_onode) 1545 child_nodes_map[new_onode.Id] = new_onode 1546 } 1547 } 1548 1549 // Figure out which genome is better. The worse genome should not be allowed to add extra structural baggage. 1550 // If they are the same, use the smaller one's disjoint and excess genes only. 1551 p1better := false // Tells if the first genome (this one) has better fitness or not 1552 if fitness1 > fitness2 || 1553 (fitness1 == fitness2 && len(gen.Genes) < len(og.Genes)) { 1554 p1better = true 1555 } 1556 1557 // Set up the avgene - this Gene is used to hold the average of the two genes to be averaged 1558 avg_gene := NewGeneWithTrait(nil, 0.0, nil, nil, false, 0, 0.0); 1559 1560 // Now loop through the Genes of each parent 1561 i1, i2, size1, size2 := 0, 0, len(gen.Genes), len(og.Genes) 1562 var chosen_gene *Gene 1563 for i1 < size1 || i2 < size2 { 1564 skip := false 1565 avg_gene.IsEnabled = true // Default to enabled 1566 1567 // choose best gene 1568 if i1 >= size1 { 1569 chosen_gene = og.Genes[i2] 1570 i2++ 1571 if p1better { 1572 skip = true // Skip excess from the worse genome 1573 } 1574 } else if i2 >= size2 { 1575 chosen_gene = gen.Genes[i1] 1576 i1++ 1577 if !p1better { 1578 skip = true // Skip excess from the worse genome 1579 } 1580 } else { 1581 p1gene := gen.Genes[i1] 1582 p2gene := og.Genes[i2] 1583 1584 // Extract current innovation numbers 1585 p1innov := p1gene.InnovationNum 1586 p2innov := p2gene.InnovationNum 1587 1588 if p1innov == p2innov { 1589 // Average them into the avg_gene 1590 if rand.Float64() > 0.5 { 1591 avg_gene.Link.Trait = p1gene.Link.Trait 1592 } else { 1593 avg_gene.Link.Trait = p2gene.Link.Trait 1594 } 1595 avg_gene.Link.Weight = (p1gene.Link.Weight + p2gene.Link.Weight) / 2.0 // WEIGHTS AVERAGED HERE 1596 1597 if rand.Float64() > 0.5 { 1598 avg_gene.Link.InNode = p1gene.Link.InNode 1599 } else { 1600 avg_gene.Link.InNode = p2gene.Link.InNode 1601 } 1602 if rand.Float64() > 0.5 { 1603 avg_gene.Link.OutNode = p1gene.Link.OutNode 1604 } else { 1605 avg_gene.Link.OutNode = p2gene.Link.OutNode 1606 } 1607 if rand.Float64() > 0.5 { 1608 avg_gene.Link.IsRecurrent = p1gene.Link.IsRecurrent 1609 } else { 1610 avg_gene.Link.IsRecurrent = p2gene.Link.IsRecurrent 1611 } 1612 1613 avg_gene.InnovationNum = p1innov 1614 avg_gene.MutationNum = (p1gene.MutationNum + p2gene.MutationNum) / 2.0 1615 if !p1gene.IsEnabled || !p2gene.IsEnabled && rand.Float64() < 0.75 { 1616 avg_gene.IsEnabled = false 1617 } 1618 1619 chosen_gene = avg_gene 1620 i1++ 1621 i2++ 1622 } else if p1innov < p2innov { 1623 chosen_gene = p1gene 1624 i1++ 1625 if !p1better { 1626 skip = true // Skip excess from the worse genome 1627 } 1628 } else { 1629 chosen_gene = p2gene 1630 i2++ 1631 if p1better { 1632 skip = true // Skip excess from the worse genome 1633 } 1634 } 1635 } 1636 1637 // Uncomment this line to let growth go faster (from both parents excesses) 1638 // skip=false 1639 1640 // Check to see if the chosen gene conflicts with an already chosen gene i.e. do they represent the same link 1641 for _, new_gene := range new_genes { 1642 if new_gene.Link.IsEqualGenetically(chosen_gene.Link) { 1643 skip = true; 1644 break; 1645 } 1646 } 1647 1648 if (!skip) { 1649 // Now add the chosen gene to the baby 1650 1651 // Check for the nodes, add them if not in the baby Genome already 1652 in_node := chosen_gene.Link.InNode 1653 out_node := chosen_gene.Link.OutNode 1654 1655 // Checking for inode's existence 1656 var new_in_node *network.NNode 1657 for _, node := range new_nodes { 1658 if node.Id == in_node.Id { 1659 new_in_node = node 1660 break 1661 } 1662 } 1663 if new_in_node == nil { 1664 // Here we know the node doesn't exist so we have to add it normalized trait 1665 // number for new NNode 1666 in_node_trait_num := 0 1667 if in_node.Trait != nil { 1668 in_node_trait_num = in_node.Trait.Id - gen.Traits[0].Id 1669 } 1670 new_in_node = network.NewNNodeCopy(in_node, new_traits[in_node_trait_num]) 1671 new_nodes = nodeInsert(new_nodes, new_in_node) 1672 child_nodes_map[new_in_node.Id] = new_in_node 1673 } 1674 1675 // Checking for onode's existence 1676 var new_out_node *network.NNode 1677 for _, node := range new_nodes { 1678 if node.Id == out_node.Id { 1679 new_out_node = node 1680 break 1681 } 1682 } 1683 if new_out_node == nil { 1684 // Here we know the node doesn't exist so we have to add it normalized trait 1685 // number for new NNode 1686 out_node_trait_num := 0 1687 if out_node.Trait != nil { 1688 out_node_trait_num = out_node.Trait.Id - gen.Traits[0].Id 1689 } 1690 new_out_node = network.NewNNodeCopy(out_node, new_traits[out_node_trait_num]) 1691 new_nodes = nodeInsert(new_nodes, new_out_node) 1692 child_nodes_map[new_out_node.Id] = new_out_node 1693 } 1694 1695 // Add the Gene 1696 gene_trait_num := 0 1697 if chosen_gene.Link.Trait != nil { 1698 // The subtracted number normalizes depending on whether traits start counting at 1 or 0 1699 gene_trait_num = chosen_gene.Link.Trait.Id - gen.Traits[0].Id 1700 } 1701 new_gene := NewGeneCopy(chosen_gene, new_traits[gene_trait_num], new_in_node, new_out_node) 1702 new_genes = append(new_genes, new_gene) 1703 } // end SKIP 1704 } // end FOR 1705 // check if parent's MIMO control genes should be inherited 1706 if len(gen.ControlGenes) != 0 || len(og.ControlGenes) != 0 { 1707 // MIMO control genes found at least in one parent - append it to child if appropriate 1708 if extra_nodes, modules := gen.mateModules(child_nodes_map, og); modules != nil { 1709 if len(extra_nodes) > 0 { 1710 // append extra IO nodes of MIMO genes not found in child 1711 new_nodes = append(new_nodes, extra_nodes...) 1712 } 1713 1714 // Return modular baby genome 1715 return NewModularGenome(genomeid, new_traits, new_nodes, new_genes, modules), nil 1716 } 1717 } 1718 // Return plain baby Genome 1719 return NewGenome(genomeid, new_traits, new_nodes, new_genes), nil 1720 } 1721 1722 // This method is similar to a standard single point CROSSOVER operator. Traits are averaged as in the previous two 1723 // mating methods. A Gene is chosen in the smaller Genome for splitting. When the Gene is reached, it is averaged with 1724 // the matching Gene from the larger Genome, if one exists. Then every other Gene is taken from the larger Genome. 1725 func (gen *Genome) mateSinglepoint(og *Genome, genomeid int) (*Genome, error) { 1726 // Check if genomes has equal number of traits 1727 if len(gen.Traits) != len(og.Traits) { 1728 return nil, errors.New(fmt.Sprintf("Genomes has different traits count, %d != %d", len(gen.Traits), len(og.Traits))) 1729 } 1730 1731 // First, average the Traits from the 2 parents to form the baby's Traits. It is assumed that trait vectors are 1732 // the same length. In the future, may decide on a different method for trait mating. 1733 new_traits, err := gen.mateTraits(og) 1734 if err != nil { 1735 return nil, err 1736 } 1737 1738 // The new genes and nodes created 1739 new_genes := make([]*Gene, 0) 1740 new_nodes := make([]*network.NNode, 0) 1741 child_nodes_map := make(map[int]*network.NNode) 1742 1743 // NEW: Make sure all sensors and outputs are included (in case some inputs are disconnected) 1744 for _, curr_node := range og.Nodes { 1745 if curr_node.NeuronType == network.InputNeuron || 1746 curr_node.NeuronType == network.BiasNeuron || 1747 curr_node.NeuronType == network.OutputNeuron { 1748 node_trait_num := 0 1749 if curr_node.Trait != nil { 1750 node_trait_num = curr_node.Trait.Id - gen.Traits[0].Id 1751 } 1752 // Create a new node off the sensor or output 1753 new_onode := network.NewNNodeCopy(curr_node, new_traits[node_trait_num]) 1754 1755 // Add the new node 1756 new_nodes = nodeInsert(new_nodes, new_onode) 1757 child_nodes_map[new_onode.Id] = new_onode 1758 } 1759 } 1760 1761 // Set up the avg_gene - this Gene is used to hold the average of the two genes to be averaged 1762 avg_gene := NewGeneWithTrait(nil, 0.0, nil, nil, false, 0, 0.0); 1763 1764 p1stop, p2stop, stopper, crosspoint := 0, 0, 0, 0 1765 var p1genes, p2genes []*Gene 1766 size1, size2 := len(gen.Genes), len(og.Genes) 1767 if size1 < size2 { 1768 crosspoint = rand.Intn(size1) 1769 p1stop = size1 1770 p2stop = size2 1771 stopper = size2 1772 p1genes = gen.Genes 1773 p2genes = og.Genes 1774 } else { 1775 crosspoint = rand.Intn(size2) 1776 p1stop = size2 1777 p2stop = size1 1778 stopper = size1 1779 p1genes = og.Genes 1780 p2genes = gen.Genes 1781 } 1782 1783 var chosen_gene *Gene 1784 gene_counter, i1, i2 := 0, 0, 0 1785 // Now move through the Genes of each parent until both genomes end 1786 for i2 < stopper { 1787 skip := false 1788 avg_gene.IsEnabled = true // Default to true 1789 if i1 == p1stop { 1790 chosen_gene = p2genes[i2] 1791 i2++ 1792 } else if i2 == p2stop { 1793 chosen_gene = p1genes[i1] 1794 i1++ 1795 } else { 1796 p1gene := p1genes[i1] 1797 p2gene := p2genes[i2] 1798 1799 // Extract current innovation numbers 1800 p1innov := p1gene.InnovationNum 1801 p2innov := p2gene.InnovationNum 1802 1803 if p1innov == p2innov { 1804 //Pick the chosen gene depending on whether we've crossed yet 1805 if gene_counter < crosspoint { 1806 chosen_gene = p1gene 1807 } else if gene_counter > crosspoint { 1808 chosen_gene = p2gene 1809 } else { 1810 // We are at the crosspoint here - average genes into the avgene 1811 if rand.Float64() > 0.5 { 1812 avg_gene.Link.Trait = p1gene.Link.Trait 1813 } else { 1814 avg_gene.Link.Trait = p2gene.Link.Trait 1815 } 1816 avg_gene.Link.Weight = (p1gene.Link.Weight + p2gene.Link.Weight) / 2.0 // WEIGHTS AVERAGED HERE 1817 1818 if rand.Float64() > 0.5 { 1819 avg_gene.Link.InNode = p1gene.Link.InNode 1820 } else { 1821 avg_gene.Link.InNode = p2gene.Link.InNode 1822 } 1823 if rand.Float64() > 0.5 { 1824 avg_gene.Link.OutNode = p1gene.Link.OutNode 1825 } else { 1826 avg_gene.Link.OutNode = p2gene.Link.OutNode 1827 } 1828 if rand.Float64() > 0.5 { 1829 avg_gene.Link.IsRecurrent = p1gene.Link.IsRecurrent 1830 } else { 1831 avg_gene.Link.IsRecurrent = p2gene.Link.IsRecurrent 1832 } 1833 1834 avg_gene.InnovationNum = p1innov 1835 avg_gene.MutationNum = (p1gene.MutationNum + p2gene.MutationNum) / 2.0 1836 if !p1gene.IsEnabled || !p2gene.IsEnabled && rand.Float64() < 0.75 { 1837 avg_gene.IsEnabled = false 1838 } 1839 1840 chosen_gene = avg_gene 1841 } 1842 i1++ 1843 i2++ 1844 gene_counter++ 1845 } else if p1innov < p2innov { 1846 if (gene_counter < crosspoint) { 1847 chosen_gene = p1gene 1848 i1++ 1849 gene_counter++ 1850 } else { 1851 chosen_gene = p2gene 1852 i2++ 1853 } 1854 } else { 1855 // p2innov < p1innov 1856 i2++ 1857 // Special case: we need to skip to the next iteration 1858 // because this Gene is before the crosspoint on the wrong Genome 1859 skip = true 1860 } 1861 } 1862 // Check to see if the chosen gene conflicts with an already chosen gene i.e. do they represent the same link 1863 for _, new_gene := range new_genes { 1864 if new_gene.Link.IsEqualGenetically(chosen_gene.Link) { 1865 skip = true; 1866 break; 1867 } 1868 } 1869 1870 //Now add the chosen gene to the baby 1871 if (!skip) { 1872 // Check for the nodes, add them if not in the baby Genome already 1873 in_node := chosen_gene.Link.InNode 1874 out_node := chosen_gene.Link.OutNode 1875 1876 // Checking for inode's existence 1877 var new_in_node *network.NNode 1878 for _, node := range new_nodes { 1879 if node.Id == in_node.Id { 1880 new_in_node = node 1881 break 1882 } 1883 } 1884 if new_in_node == nil { 1885 // Here we know the node doesn't exist so we have to add it normalized trait 1886 // number for new NNode 1887 in_node_trait_num := 0 1888 if in_node.Trait != nil { 1889 in_node_trait_num = in_node.Trait.Id - gen.Traits[0].Id 1890 } 1891 new_in_node = network.NewNNodeCopy(in_node, new_traits[in_node_trait_num]) 1892 new_nodes = nodeInsert(new_nodes, new_in_node) 1893 child_nodes_map[new_in_node.Id] = new_in_node 1894 } 1895 1896 // Checking for onode's existence 1897 var new_out_node *network.NNode 1898 for _, node := range new_nodes { 1899 if node.Id == out_node.Id { 1900 new_out_node = node 1901 break 1902 } 1903 } 1904 if new_out_node == nil { 1905 // Here we know the node doesn't exist so we have to add it normalized trait 1906 // number for new NNode 1907 out_node_trait_num := 0 1908 if out_node.Trait != nil { 1909 out_node_trait_num = out_node.Trait.Id - gen.Traits[0].Id 1910 } 1911 new_out_node = network.NewNNodeCopy(out_node, new_traits[out_node_trait_num]) 1912 new_nodes = nodeInsert(new_nodes, new_out_node) 1913 child_nodes_map[new_out_node.Id] = new_out_node 1914 } 1915 1916 // Add the Gene 1917 gene_trait_num := 0 1918 if chosen_gene.Link.Trait != nil { 1919 // The subtracted number normalizes depending on whether traits start counting at 1 or 0 1920 gene_trait_num = chosen_gene.Link.Trait.Id - gen.Traits[0].Id 1921 } 1922 new_gene := NewGeneCopy(chosen_gene, new_traits[gene_trait_num], new_in_node, new_out_node) 1923 new_genes = append(new_genes, new_gene) 1924 }// end SKIP 1925 } // end FOR 1926 // check if parent's MIMO control genes should be inherited 1927 if len(gen.ControlGenes) != 0 || len(og.ControlGenes) != 0 { 1928 // MIMO control genes found at least in one parent - append it to child if appropriate 1929 if extra_nodes, modules := gen.mateModules(child_nodes_map, og); modules != nil { 1930 if len(extra_nodes) > 0 { 1931 // append extra IO nodes of MIMO genes not found in child 1932 new_nodes = append(new_nodes, extra_nodes...) 1933 } 1934 1935 // Return modular baby genome 1936 return NewModularGenome(genomeid, new_traits, new_nodes, new_genes, modules), nil 1937 } 1938 } 1939 // Return plain baby Genome 1940 return NewGenome(genomeid, new_traits, new_nodes, new_genes), nil 1941 } 1942 1943 // Builds an array of modules to be added to the child during crossover. 1944 // If any or both parents has module and at least one modular endpoint node already inherited by child genome than make 1945 // sure that child get all associated module nodes 1946 func (g *Genome) mateModules(child_nodes map[int]*network.NNode, og *Genome) ([]*network.NNode, []*MIMOControlGene) { 1947 parent_modules := make([]*MIMOControlGene, 0) 1948 g_modules := findModulesIntersection(child_nodes, g.ControlGenes) 1949 if len(g_modules) > 0 { 1950 parent_modules = append(parent_modules, g_modules...) 1951 } 1952 og_modules := findModulesIntersection(child_nodes, og.ControlGenes) 1953 if len(og_modules) > 0 { 1954 parent_modules = append(parent_modules, og_modules...) 1955 } 1956 if len(parent_modules) == 0 { 1957 return nil, nil 1958 } 1959 1960 // collect IO nodes from all included modules and add return it as extra ones 1961 extra_nodes := make([]*network.NNode, 0) 1962 for _, cg := range parent_modules { 1963 for _, n := range cg.ioNodes { 1964 if _, ok := child_nodes[n.Id]; !ok { 1965 // not found in known child nodes - collect it 1966 extra_nodes = append(extra_nodes, n) 1967 } 1968 } 1969 } 1970 1971 return extra_nodes, parent_modules 1972 } 1973 1974 // Finds intersection of provided nodes with IO nodes from control genes and returns list of control genes found. 1975 // If no intersection found empty list returned. 1976 func findModulesIntersection(nodes map[int]*network.NNode, genes []*MIMOControlGene) []*MIMOControlGene { 1977 modules := make([]*MIMOControlGene, 0) 1978 for _, cg := range genes { 1979 if cg.hasIntersection(nodes) { 1980 modules = append(modules, cg) 1981 } 1982 } 1983 return modules 1984 } 1985 1986 // Builds array of traits for child genome during crossover 1987 func (g *Genome) mateTraits(og *Genome) ([]*neat.Trait, error) { 1988 new_traits := make([]*neat.Trait, len(g.Traits)) 1989 var err error 1990 for i, tr := range g.Traits { 1991 new_traits[i], err = neat.NewTraitAvrg(tr, og.Traits[i]) // construct by averaging 1992 if err != nil { 1993 return nil, err 1994 } 1995 } 1996 return new_traits, nil 1997 } 1998 1999 /* ******** COMPATIBILITY CHECKING METHODS * ********/ 2000 2001 // This function gives a measure of compatibility between two Genomes by computing a linear combination of three 2002 // characterizing variables of their compatibility. The three variables represent PERCENT DISJOINT GENES, 2003 // PERCENT EXCESS GENES, MUTATIONAL DIFFERENCE WITHIN MATCHING GENES. So the formula for compatibility 2004 // is: disjoint_coeff * pdg + excess_coeff * peg + mutdiff_coeff * mdmg 2005 // The three coefficients are global system parameters. 2006 // The bigger returned value the less compatible the genomes. Fully compatible genomes has 0.0 returned. 2007 func (g *Genome) compatibility(og *Genome, context *neat.NeatContext) float64 { 2008 if context.GenCompatMethod == 0 { 2009 return g.compatLinear(og, context) 2010 } else { 2011 return g.compatFast(og, context) 2012 } 2013 } 2014 2015 // The compatibility checking method with linear performance depending on the size of the lognest genome in comparison. 2016 // When genomes are small this method is compatible in performance with Genome#compatFast method. 2017 // The compatibility formula remains the same: disjoint_coeff * pdg + excess_coeff * peg + mutdiff_coeff * mdmg 2018 // where: pdg - PERCENT DISJOINT GENES, peg - PERCENT EXCESS GENES, and mdmg - MUTATIONAL DIFFERENCE WITHIN MATCHING GENES 2019 func (g *Genome) compatLinear(og *Genome, context *neat.NeatContext) float64 { 2020 num_disjoint, num_excess, mut_diff_total, num_matching := 0.0, 0.0, 0.0, 0.0 2021 size1, size2 := len(g.Genes), len(og.Genes) 2022 max_genome_size := size2 2023 if size1 > size2 { 2024 max_genome_size = size1 2025 } 2026 var gene1, gene2 *Gene 2027 for i, i1, i2 := 0, 0, 0; i < max_genome_size; i++ { 2028 if i1 >= size1 { 2029 num_excess += 1.0 2030 i2++ 2031 } else if i2 >= size2 { 2032 num_excess += 1.0 2033 i1++ 2034 } else { 2035 gene1 = g.Genes[i1] 2036 gene2 = og.Genes[i2] 2037 p1innov := gene1.InnovationNum 2038 p2innov := gene2.InnovationNum 2039 2040 if p1innov == p2innov { 2041 num_matching += 1.0 2042 mut_diff := math.Abs(gene1.MutationNum - gene2.MutationNum) 2043 mut_diff_total += mut_diff 2044 i1++ 2045 i2++ 2046 } else if p1innov < p2innov { 2047 i1++ 2048 num_disjoint += 1.0 2049 } else if p2innov < p1innov { 2050 i2++ 2051 num_disjoint += 1.0 2052 } 2053 } 2054 } 2055 2056 //fmt.Printf("num_disjoint: %.f num_excess: %.f mut_diff_total: %.f num_matching: %.f\n", num_disjoint, num_excess, mut_diff_total, num_matching) 2057 2058 // Return the compatibility number using compatibility formula 2059 // Note that mut_diff_total/num_matching gives the AVERAGE difference between mutation_nums for any two matching 2060 // Genes in the Genome. Look at disjointedness and excess in the absolute (ignoring size) 2061 comp := context.DisjointCoeff * num_disjoint + context.ExcessCoeff * num_excess + 2062 context.MutdiffCoeff * (mut_diff_total / num_matching) 2063 2064 return comp 2065 } 2066 2067 2068 // The faster version of genome compatibility checking. The compatibility check will start from the end of genome where 2069 // the most of disparities are located - the novel genes with greater innovation ID are always attached at the end (see geneInsert). 2070 // This has the result of complicating the routine because we must now invoke additional logic to determine which genes 2071 // are excess and when the first disjoint gene is found. This is done with an extra integer: 2072 // * excessGenesSwitch=0 // indicates to the loop that it is handling the first gene. 2073 // * excessGenesSwitch=1 // Indicates that the first gene was excess and on genome 1. 2074 // * excessGenesSwitch=2 // Indicates that the first gene was excess and on genome 2. 2075 // * excessGenesSwitch=3 // Indicates that there are no more excess genes. 2076 // 2077 // The compatibility formula remains the same: disjoint_coeff * pdg + excess_coeff * peg + mutdiff_coeff * mdmg 2078 // where: pdg - PERCENT DISJOINT GENES, peg - PERCENT EXCESS GENES, and mdmg - MUTATIONAL DIFFERENCE WITHIN MATCHING GENES 2079 func (g *Genome) compatFast(og *Genome, context *neat.NeatContext) float64 { 2080 list1_count, list2_count := len(g.Genes), len(og.Genes) 2081 // First test edge cases 2082 if list1_count == 0 && list2_count == 0 { 2083 // Both lists are empty! No disparities, therefore the genomes are compatible! 2084 return 0.0 2085 } 2086 if list1_count == 0 { 2087 // All list2 genes are excess. 2088 return float64(list2_count) * context.ExcessCoeff 2089 } 2090 2091 if list2_count == 0 { 2092 // All list1 genes are excess. 2093 return float64(list1_count) * context.ExcessCoeff 2094 } 2095 2096 excess_genes_switch, num_matching := 0, 0 2097 compatibility, mut_diff := 0.0, 0.0 2098 list1_idx, list2_idx := list1_count - 1, list2_count - 1 2099 gene1, gene2 := g.Genes[list1_idx], og.Genes[list2_idx] 2100 2101 for { 2102 if gene2.InnovationNum > gene1.InnovationNum { 2103 // Most common test case(s) at top for efficiency. 2104 if excess_genes_switch == 3 { 2105 // No more excess genes. Therefore this mismatch is disjoint. 2106 compatibility += context.DisjointCoeff 2107 } else if excess_genes_switch == 2 { 2108 // Another excess gene on genome 2. 2109 compatibility += context.ExcessCoeff 2110 } else if excess_genes_switch == 1 { 2111 // We have found the first non-excess gene. 2112 excess_genes_switch = 3 2113 compatibility += context.DisjointCoeff 2114 } else { 2115 // First gene is excess, and is on genome 2. 2116 excess_genes_switch = 2 2117 compatibility += context.ExcessCoeff 2118 } 2119 2120 // Move to the next gene in list2. 2121 list2_idx-- 2122 } else if gene1.InnovationNum == gene2.InnovationNum { 2123 // No more excess genes. It's quicker to set this every time than to test if is not yet 3. 2124 excess_genes_switch = 3 2125 2126 // Matching genes. Increase compatibility by MutationNum difference * coeff. 2127 mut_diff += math.Abs(gene1.MutationNum - gene2.MutationNum) 2128 num_matching++ 2129 2130 // Move to the next gene in both lists. 2131 list1_idx-- 2132 list2_idx-- 2133 } else { 2134 // Most common test case(s) at top for efficiency. 2135 if excess_genes_switch == 3 { 2136 // No more excess genes. Therefore this mismatch is disjoint. 2137 compatibility += context.DisjointCoeff 2138 } else if (excess_genes_switch == 1) { 2139 // Another excess gene on genome 1. 2140 compatibility += context.ExcessCoeff 2141 } else if excess_genes_switch == 2 { 2142 // We have found the first non-excess gene. 2143 excess_genes_switch = 3 2144 compatibility += context.DisjointCoeff 2145 } else { 2146 // First gene is excess, and is on genome 1. 2147 excess_genes_switch = 1 2148 compatibility += context.ExcessCoeff 2149 } 2150 2151 // Move to the next gene in list1. 2152 list1_idx-- 2153 } 2154 2155 // Check if we have reached the end of one (or both) of the lists. If we have reached the end of both then 2156 // we execute the first 'if' block - but it doesn't matter since the loop is not entered if both lists have 2157 // been exhausted. 2158 if list1_idx < 0 { 2159 // All remaining list2 genes are disjoint. 2160 compatibility += float64(list2_idx + 1) * context.DisjointCoeff 2161 break 2162 2163 } 2164 2165 if list2_idx < 0 { 2166 // All remaining list1 genes are disjoint. 2167 compatibility += float64(list1_idx + 1) * context.DisjointCoeff 2168 break 2169 } 2170 2171 gene1, gene2 = g.Genes[list1_idx], og.Genes[list2_idx] 2172 } 2173 if num_matching > 0 { 2174 compatibility += mut_diff * context.MutdiffCoeff / float64(num_matching) 2175 } 2176 return compatibility 2177 } 2178