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

     1  package neat
     2  
     3  import (
     4  	"fmt"
     5  	"math/rand"
     6  	"errors"
     7  	"github.com/yaricom/goNEAT/neat/utils"
     8  )
     9  
    10  // The number of parameters used in neurons that learn through habituation,
    11  // sensitization, or Hebbian-type processes
    12  const Num_trait_params = 8
    13  
    14  var (
    15  	ErrTraitsParametersCountMismatch = errors.New("traits parameters number mismatch")
    16  )
    17  
    18  // TRAIT: A Trait is a group of parameters that can be expressed as a group more than one time. Traits save a genetic
    19  // algorithm from having to search vast parameter landscapes on every node. Instead, each node can simply point to a trait
    20  // and those traits can evolve on their own.
    21  type Trait struct {
    22  	// The trait ID
    23  	Id     int
    24  	// The learned trait parameters
    25  	Params []float64
    26  }
    27  
    28  func NewTrait() *Trait {
    29  	trait := newTrait(Num_trait_params)
    30  	return trait
    31  }
    32  
    33  // The copy constructor
    34  func NewTraitCopy(t *Trait) *Trait {
    35  	nt := newTrait(len(t.Params))
    36  	nt.Id = t.Id
    37  	for i, p := range t.Params {
    38  		nt.Params[i] = p
    39  	}
    40  	return nt
    41  }
    42  
    43  // Special Constructor creates a new Trait which is the average of two existing traits passed in
    44  func NewTraitAvrg(t1, t2 *Trait) (*Trait, error) {
    45  	if len(t1.Params) != len(t2.Params) {
    46  		return nil, ErrTraitsParametersCountMismatch
    47  	}
    48  	nt := newTrait(len(t1.Params))
    49  	nt.Id = t1.Id
    50  	for i := 0; i < len(t1.Params); i++ {
    51  		nt.Params[i] = (t1.Params[i] + t2.Params[i]) / 2.0
    52  	}
    53  	return nt, nil
    54  }
    55  
    56  // The default private constructor
    57  func newTrait(lenght int) *Trait {
    58  	return &Trait{
    59  		Params:make([]float64, lenght),
    60  	}
    61  }
    62  
    63  // Perturb the trait parameters slightly
    64  func (t *Trait) Mutate(trait_mutation_power, trait_param_mut_prob float64) {
    65  	for i := 0; i < len(t.Params); i++ {
    66  		if rand.Float64() > trait_param_mut_prob {
    67  			t.Params[i] += float64(utils.RandSign()) * rand.Float64() * trait_mutation_power
    68  			if t.Params[i] < 0 {
    69  				t.Params[i] = 0
    70  			}
    71  		}
    72  	}
    73  }
    74  
    75  func (t *Trait) String() string {
    76  	s := fmt.Sprintf("Trait #%d (", t.Id)
    77  	for _, p := range t.Params {
    78  		s = fmt.Sprintf("%s %f", s, p)
    79  	}
    80  	s = fmt.Sprintf("%s )", s)
    81  	return s
    82  }