github.com/yaricom/goNEAT@v0.0.0-20210507221059-e2110b885482/neat/genetics/genome_reader.go (about)

     1  package genetics
     2  
     3  import (
     4  	"io"
     5  	"fmt"
     6  	"bufio"
     7  	"errors"
     8  	"strings"
     9  	"strconv"
    10  	"gopkg.in/yaml.v2"
    11  	"github.com/spf13/cast"
    12  	"github.com/yaricom/goNEAT/neat"
    13  	"github.com/yaricom/goNEAT/neat/utils"
    14  	"github.com/yaricom/goNEAT/neat/network"
    15  )
    16  
    17  
    18  // The interface to define genome reader
    19  type GenomeReader interface {
    20  	// Reads one Genome record
    21  	Read() (*Genome, error)
    22  }
    23  
    24  // Creates reader for Genome data with specified encoding format.
    25  func NewGenomeReader(r io.Reader, encoding GenomeEncoding) (GenomeReader, error) {
    26  	switch encoding {
    27  	case PlainGenomeEncoding:
    28  		return &plainGenomeReader{r: bufio.NewReader(r)}, nil
    29  	case YAMLGenomeEncoding:
    30  		return &yamlGenomeReader{r: bufio.NewReader(r)}, nil
    31  	default:
    32  		return nil, ErrUnsupportedGenomeEncoding
    33  	}
    34  }
    35  
    36  // A PlainGenomeReader reads genome data from plain text file.
    37  type plainGenomeReader struct {
    38  	r *bufio.Reader
    39  }
    40  
    41  func (pgr *plainGenomeReader) Read() (*Genome, error) {
    42  	gnome := Genome{
    43  		Traits:make([]*neat.Trait, 0),
    44  		Nodes:make([]*network.NNode, 0),
    45  		Genes:make([]*Gene, 0),
    46  	}
    47  
    48  	var g_id int
    49  	// Loop until file is finished, parsing each line
    50  	scanner := bufio.NewScanner(pgr.r)
    51  	scanner.Split(bufio.ScanLines)
    52  	for scanner.Scan() {
    53  		line := scanner.Text()
    54  		parts := strings.SplitN(line, " ", 2)
    55  		if len(parts) < 2 {
    56  			return nil, errors.New(fmt.Sprintf("Line: [%s] can not be split when reading Genome", line))
    57  		}
    58  		lr := strings.NewReader(parts[1])
    59  
    60  		switch parts[0] {
    61  		case "trait":
    62  			// Read a Trait
    63  			new_trait, err := readPlainTrait(lr)
    64  			if err != nil {
    65  				return nil, err
    66  			}
    67  			// check that trait ID is unique
    68  			if prev_trait := traitWithId(new_trait.Id, gnome.Traits); prev_trait != nil {
    69  				return nil, errors.New(
    70  					fmt.Sprintf("Trait ID: %d is not unique", new_trait.Id))
    71  			}
    72  			gnome.Traits = append(gnome.Traits, new_trait)
    73  
    74  		case "node":
    75  			// Read a Network Node
    76  			new_node, err := readPlainNetworkNode(lr, gnome.Traits)
    77  			if err != nil {
    78  				return nil, err
    79  			}
    80  			// check that node ID is unique
    81  			if prev_node := nodeWithId(new_node.Id, gnome.Nodes); prev_node != nil {
    82  				return nil, errors.New(
    83  					fmt.Sprintf("Node ID: %d is not unique", new_node.Id))
    84  			}
    85  			gnome.Nodes = append(gnome.Nodes, new_node)
    86  
    87  		case "gene":
    88  			// Read a Gene
    89  			new_gene, err := readPlainConnectionGene(lr, gnome.Traits, gnome.Nodes)
    90  			if err != nil {
    91  				return nil, err
    92  			}
    93  			gnome.Genes = append(gnome.Genes, new_gene)
    94  
    95  		case "genomeend":
    96  			// Read Genome ID
    97  			_, err := fmt.Fscanf(lr, "%d", &g_id)
    98  			if err != nil {
    99  				return nil, err
   100  			}
   101  			// save genome ID
   102  			gnome.Id = g_id
   103  
   104  		case "/*":
   105  			// read all comments and print it
   106  			neat.InfoLog(line)
   107  		}
   108  	}
   109  	return &gnome, nil
   110  }
   111  
   112  // The method to read Trait in plain text format
   113  func readPlainTrait(r io.Reader) (*neat.Trait, error) {
   114  	nt := neat.NewTrait()
   115  	_, err := fmt.Fscanf(r, "%d ", &nt.Id)
   116  	if err == nil {
   117  		for i := 0; i < neat.Num_trait_params; i++ {
   118  			if _, err = fmt.Fscanf(r, "%g ", &nt.Params[i]); err != nil {
   119  				return nil, err
   120  			}
   121  		}
   122  	}
   123  
   124  	return nt, err
   125  }
   126  
   127  // Read a Network Node from specified Reader in plain text format
   128  // and applies corresponding trait to it from a list of traits provided
   129  func readPlainNetworkNode(r io.Reader, traits []*neat.Trait) (*network.NNode, error) {
   130  	n := network.NewNetworkNode()
   131  	buf_r := bufio.NewReader(r)
   132  	line, _, err := buf_r.ReadLine()
   133  	if err != nil {
   134  		return nil, err
   135  	}
   136  	parts := strings.Split(string(line), " ")
   137  	if len(parts) < 4 {
   138  		return nil, errors.New(fmt.Sprintf("node line is too short: %d (%s)", len(parts), parts))
   139  	}
   140  	if n_Id, err := strconv.ParseInt(parts[0], 10, 32); err != nil {
   141  		return nil, err
   142  	} else {
   143  		n.Id = int(n_Id)
   144  	}
   145  	if trait_id, err := strconv.ParseInt(parts[1], 10, 32); err != nil {
   146  		return nil, err
   147  	} else {
   148  		n.Trait = traitWithId(int(trait_id), traits)
   149  	}
   150  
   151  	if n_NeuronType, err := strconv.ParseInt(parts[3], 10, 32); err != nil {
   152  		return nil, err
   153  	} else {
   154  		n.NeuronType = network.NodeNeuronType(n_NeuronType)
   155  	}
   156  
   157  	if len(parts) == 5 {
   158  		n.ActivationType, err = utils.NodeActivators.ActivationTypeFromName(parts[4])
   159  	}
   160  
   161  	return n, err
   162  }
   163  
   164  // Reads Gene from reader in plain text format
   165  func readPlainConnectionGene(r io.Reader, traits []*neat.Trait, nodes []*network.NNode) (*Gene, error) {
   166  	var traitId, inNodeId, outNodeId int
   167  	var inov_num int64
   168  	var weight, mut_num float64
   169  	var recurrent, enabled bool
   170  	_, err := fmt.Fscanf(r, "%d %d %d %g %t %d %g %t ",
   171  		&traitId, &inNodeId, &outNodeId, &weight, &recurrent, &inov_num, &mut_num, &enabled)
   172  	if err != nil {
   173  		return nil, err
   174  	}
   175  
   176  	trait := traitWithId(traitId, traits)
   177  	var inNode, outNode *network.NNode
   178  	for _, np := range nodes {
   179  		if np.Id == inNodeId {
   180  			inNode = np
   181  		}
   182  		if np.Id == outNodeId {
   183  			outNode = np
   184  		}
   185  	}
   186  	if trait != nil {
   187  		return newGene(network.NewLinkWithTrait(trait, weight, inNode, outNode, recurrent), inov_num, mut_num, enabled), nil
   188  	} else {
   189  		return newGene(network.NewLink(weight, inNode, outNode, recurrent), inov_num, mut_num, enabled), nil
   190  	}
   191  }
   192  
   193  // A YAMLGenomeReader reads genome data from YAML encoded text file
   194  type yamlGenomeReader struct {
   195  	r *bufio.Reader
   196  }
   197  
   198  func (ygr *yamlGenomeReader) Read() (*Genome, error) {
   199  	m := make(map[interface{}]interface{})
   200  	dec := yaml.NewDecoder(ygr.r)
   201  	err := dec.Decode(&m)
   202  	if err != nil {
   203  		return nil, err
   204  	}
   205  
   206  	gm, ok := m["genome"].(map[interface{}]interface{})
   207  	if ok == false {
   208  		return nil, errors.New("failed to parse YAML configuration")
   209  	}
   210  
   211  	// read Genome
   212  	gen_id, err := cast.ToIntE(gm["id"])
   213  	if err != nil {
   214  		return nil, err
   215  	}
   216  	gnome := &Genome{
   217  		Id:gen_id,
   218  		Traits:make([]*neat.Trait, 0),
   219  		Nodes:make([]*network.NNode, 0),
   220  		Genes:make([]*Gene, 0),
   221  		ControlGenes:make([]*MIMOControlGene, 0),
   222  	}
   223  
   224  	// read traits
   225  	traits := gm["traits"].([]interface{})
   226  	for _, tr := range traits {
   227  		trait, err := readTrait(tr.(map[interface{}]interface{}))
   228  		if err != nil {
   229  			return nil, err
   230  		}
   231  		// check that trait ID is unique
   232  		if prev_trait := traitWithId(trait.Id, gnome.Traits); prev_trait != nil {
   233  			return nil, errors.New(
   234  				fmt.Sprintf("Trait ID: %d is not unique", trait.Id))
   235  		}
   236  		gnome.Traits = append(gnome.Traits, trait)
   237  	}
   238  
   239  	// read nodes
   240  	nodes := gm["nodes"].([]interface{})
   241  	for _, nd := range nodes {
   242  		node, err := readNNode(nd.(map[interface{}]interface{}), gnome.Traits)
   243  		if err != nil {
   244  			return nil, err
   245  		}
   246  		// check that node ID is unique
   247  		if prev_node := nodeWithId(node.Id, gnome.Nodes); prev_node != nil {
   248  			return nil, errors.New(
   249  				fmt.Sprintf("Node ID: %d is not unique", node.Id))
   250  		}
   251  		gnome.Nodes = append(gnome.Nodes, node)
   252  	}
   253  
   254  	// read Genes
   255  	genes := gm["genes"].([]interface{})
   256  	for _, g := range genes {
   257  		gene, err := readGene(g.(map[interface{}]interface{}), gnome.Traits, gnome.Nodes)
   258  		if err != nil {
   259  			return nil, err
   260  		}
   261  		gnome.Genes = append(gnome.Genes, gene)
   262  	}
   263  
   264  	// read MIMO control genes
   265  	mimoGenes := gm["modules"]
   266  	if mimoGenes != nil {
   267  		for _, mg := range mimoGenes.([]interface{}) {
   268  			mGene, err := readMIMOControlGene(mg.(map[interface{}]interface{}), gnome.Traits, gnome.Nodes)
   269  			if err != nil {
   270  				return nil, err
   271  			}
   272  			// check that control node ID is unique
   273  			if prev_node := nodeWithId(mGene.ControlNode.Id, gnome.Nodes); prev_node != nil {
   274  				return nil, errors.New(
   275  					fmt.Sprintf("Control node ID: %d is not unique", mGene.ControlNode.Id))
   276  			}
   277  			gnome.ControlGenes = append(gnome.ControlGenes, mGene)
   278  		}
   279  	}
   280  
   281  	return gnome, nil
   282  }
   283  
   284  // Reads gene configuration
   285  func readGene(conf map[interface{}]interface{}, traits []*neat.Trait, nodes []*network.NNode) (*Gene, error) {
   286  	traitId := conf["trait_id"].(int)
   287  	inNodeId := conf["src_id"].(int)
   288  	outNodeId := conf["tgt_id"].(int)
   289  	inov_num, err := cast.ToInt64E(conf["innov_num"])
   290  	if err != nil {
   291  		return nil, err
   292  	}
   293  	weight, err := cast.ToFloat64E(conf["weight"])
   294  	if err != nil {
   295  		return nil, err
   296  	}
   297  	mut_num, err := cast.ToFloat64E(conf["mut_num"])
   298  	if err != nil {
   299  		return nil, err
   300  	}
   301  	recurrent, err := cast.ToBoolE(conf["recurrent"])
   302  	if err != nil {
   303  		return nil, err
   304  	}
   305  	enabled, err := cast.ToBoolE(conf["enabled"])
   306  	if err != nil {
   307  		return nil, err
   308  	}
   309  
   310  	trait := traitWithId(traitId, traits)
   311  	var inNode, outNode *network.NNode
   312  	for _, np := range nodes {
   313  		if np.Id == inNodeId {
   314  			inNode = np
   315  		}
   316  		if np.Id == outNodeId {
   317  			outNode = np
   318  		}
   319  	}
   320  	if trait != nil {
   321  		return newGene(network.NewLinkWithTrait(trait, weight, inNode, outNode, recurrent), inov_num, mut_num, enabled), nil
   322  	} else {
   323  		return newGene(network.NewLink(weight, inNode, outNode, recurrent), inov_num, mut_num, enabled), nil
   324  	}
   325  }
   326  
   327  // Reads MIMOControlGene configuration
   328  func readMIMOControlGene(conf map[interface{}]interface{}, traits []*neat.Trait, nodes []*network.NNode) (gene *MIMOControlGene, err error) {
   329  	// read control node parameters
   330  	control_node := network.NewNetworkNode()
   331  	control_node.Id = conf["id"].(int)
   332  	control_node.NeuronType = network.HiddenNeuron
   333  	// set activation function
   334  	activation := conf["activation"].(string)
   335  	control_node.ActivationType, err = utils.NodeActivators.ActivationTypeFromName(activation)
   336  	if err != nil {
   337  		return nil, err
   338  	}
   339  	// set associated Trait
   340  	traitId := conf["trait_id"].(int)
   341  	trait := traitWithId(traitId, traits)
   342  	control_node.Trait = trait
   343  
   344  	// read MIMO gene parameters
   345  	inov_num, err := cast.ToInt64E(conf["innov_num"])
   346  	if err != nil {
   347  		return nil, err
   348  	}
   349  	mut_num, err := cast.ToFloat64E(conf["mut_num"])
   350  	if err != nil {
   351  		return nil, err
   352  	}
   353  	enabled, err := cast.ToBoolE(conf["enabled"])
   354  	if err != nil {
   355  		return nil, err
   356  	}
   357  
   358  	// read input links
   359  	inNodes, err := cast.ToSliceE(conf["inputs"])
   360  	if err != nil {
   361  		return nil, err
   362  	}
   363  	control_node.Incoming = make([]*network.Link, len(inNodes))
   364  	for i, mn := range inNodes {
   365  		n := mn.(map[interface{}]interface{})
   366  		node_id, err := cast.ToIntE(n["id"])
   367  		if err != nil {
   368  			return nil, err
   369  		}
   370  		node := nodeWithId(node_id, nodes)
   371  		if node != nil {
   372  			control_node.Incoming[i] = network.NewLink(1.0, node, control_node, false)
   373  		} else {
   374  			return nil, errors.New(fmt.Sprintf("no MIMO input node with id: %d can be found for module: %d",
   375  				node_id, control_node.Id))
   376  		}
   377  	}
   378  
   379  	// read output links
   380  	outNodes, err := cast.ToSliceE(conf["outputs"])
   381  	if err != nil {
   382  		return nil, err
   383  	}
   384  	control_node.Outgoing = make([]*network.Link, len(outNodes))
   385  	for i, mn := range outNodes {
   386  		n := mn.(map[interface{}]interface{})
   387  		node_id, err := cast.ToIntE(n["id"])
   388  		if err != nil {
   389  			return nil, err
   390  		}
   391  		node := nodeWithId(node_id, nodes)
   392  		if node != nil {
   393  			control_node.Outgoing[i] = network.NewLink(1.0, control_node, node, false)
   394  		} else {
   395  			return nil, errors.New(fmt.Sprintf("no MIMO output node with id: %d can be found for module: %d",
   396  				node_id, control_node.Id))
   397  		}
   398  	}
   399  
   400  	// build gene
   401  	gene = NewMIMOGene(control_node, inov_num, mut_num, enabled)
   402  
   403  	return gene, nil
   404  }
   405  
   406  // Reads NNode configuration
   407  func readNNode(conf map[interface{}]interface{}, traits []*neat.Trait) (*network.NNode, error) {
   408  	nd := network.NewNetworkNode()
   409  	nd.Id = conf["id"].(int)
   410  	trait_id := conf["trait_id"].(int)
   411  	nd.Trait = traitWithId(trait_id, traits)
   412  	type_name := conf["type"].(string)
   413  	var err error
   414  	nd.NeuronType, err = network.NeuronTypeByName(type_name)
   415  	if err != nil {
   416  		return nil, err
   417  	}
   418  	activation := conf["activation"].(string)
   419  	nd.ActivationType, err = utils.NodeActivators.ActivationTypeFromName(activation)
   420  	return nd, err
   421  }
   422  
   423  // Reads Trait configuration
   424  func readTrait(conf map[interface{}]interface{}) (*neat.Trait, error) {
   425  	nt := neat.NewTrait()
   426  	nt.Id = conf["id"].(int)
   427  	params_c := cast.ToSlice(conf["params"])
   428  	var err error
   429  	for i, p := range params_c {
   430  		nt.Params[i], err = cast.ToFloat64E(p)
   431  		if err != nil {
   432  			return nil, err
   433  		}
   434  	}
   435  	return nt, nil
   436  }
   437