diff --git a/bitset.go b/bitset.go index 09b9d4d..4bda6a2 100644 --- a/bitset.go +++ b/bitset.go @@ -1,8 +1,7 @@ - package ga import ( - // "fmt" +// "fmt" ) type Bitset struct { @@ -10,56 +9,56 @@ type Bitset struct { bits []int } -func ( b *Bitset ) Create( size int ) { +func (b *Bitset) Create(size int) { b.size = size - b.bits = make( []int, size ) + b.bits = make([]int, size) } -func ( b *Bitset ) GetSize() int { +func (b *Bitset) GetSize() int { return b.size } -func ( b *Bitset ) Get( index int ) int { - if ( index < b.size ) { +func (b *Bitset) Get(index int) int { + if index < b.size { return b.bits[index] } return -1 } -func ( b *Bitset ) GetAll() []int { +func (b *Bitset) GetAll() []int { return b.bits } -func ( b *Bitset ) setImpl( index, value int ) { +func (b *Bitset) setImpl(index, value int) { b.bits[index] = value } -func ( b *Bitset ) Set( index, value int ) bool { - if ( index < b.size ) { - b.setImpl( index, value ) +func (b *Bitset) Set(index, value int) bool { + if index < b.size { + b.setImpl(index, value) return true } return false } -func ( b *Bitset ) SetAll( value int ) { +func (b *Bitset) SetAll(value int) { for i := 0; i < b.size; i++ { - b.setImpl( i, value ) + b.setImpl(i, value) } } -func ( b *Bitset ) CreateCopy() Bitset { +func (b *Bitset) CreateCopy() Bitset { newBitset := Bitset{} - newBitset.Create( b.size ) + newBitset.Create(b.size) for i := 0; i < b.size; i++ { - newBitset.Set( i, b.Get( i ) ) + newBitset.Set(i, b.Get(i)) } return newBitset } -func ( b *Bitset ) Slice( startingBit, size int ) Bitset { +func (b *Bitset) Slice(startingBit, size int) Bitset { ret := Bitset{} - ret.Create( size ) - ret.bits = b.bits[startingBit:startingBit + size] + ret.Create(size) + ret.bits = b.bits[startingBit : startingBit+size] return ret -} \ No newline at end of file +} diff --git a/bitset_create.go b/bitset_create.go index 0a8ca61..dd5b9ca 100644 --- a/bitset_create.go +++ b/bitset_create.go @@ -1,4 +1,3 @@ - package ga type IBitsetCreate interface { @@ -8,6 +7,6 @@ type IBitsetCreate interface { type NullBitsetCreate struct { } -func ( ngc *NullBitsetCreate ) Go() Bitset { +func (ngc *NullBitsetCreate) Go() Bitset { return Bitset{} -} \ No newline at end of file +} diff --git a/bitset_parse.go b/bitset_parse.go index 34616dd..c9ae561 100644 --- a/bitset_parse.go +++ b/bitset_parse.go @@ -1,25 +1,24 @@ - package ga import ( - // "fmt" +// "fmt" ) type IBitsetParse interface { - SetFormat( []int ) - Process( *Bitset ) []uint64 + SetFormat([]int) + Process(*Bitset) []uint64 } type bitsetParse struct { expectedBitsetSize int - format []int + format []int } func CreateBitsetParse() IBitsetParse { return &bitsetParse{} } -func ( bp *bitsetParse ) SetFormat( format []int ) { +func (bp *bitsetParse) SetFormat(format []int) { bp.expectedBitsetSize = 0 for _, i := range format { bp.expectedBitsetSize += i @@ -27,23 +26,23 @@ func ( bp *bitsetParse ) SetFormat( format []int ) { bp.format = format } -func ( bp *bitsetParse ) Process( bitset *Bitset ) []uint64 { +func (bp *bitsetParse) Process(bitset *Bitset) []uint64 { if bitset.GetSize() != bp.expectedBitsetSize { panic("Input format does not match bitset size") } - ret := make( []uint64, len( bp.format ) ) + ret := make([]uint64, len(bp.format)) runningBits := 0 for retIndex, numBits := range bp.format { ret[retIndex] = 0 - for i:= 0; i < numBits; i++ { - if bitset.Get( i + runningBits ) == 1 { - ret[retIndex] |= ( 1 << uint( i ) ) + for i := 0; i < numBits; i++ { + if bitset.Get(i+runningBits) == 1 { + ret[retIndex] |= (1 << uint(i)) } } runningBits += numBits } return ret -} \ No newline at end of file +} diff --git a/bitset_parse_test.go b/bitset_parse_test.go index 82af99e..04a429c 100644 --- a/bitset_parse_test.go +++ b/bitset_parse_test.go @@ -1,53 +1,54 @@ - package ga_test import ( + "github.com/tomcraven/goga" . "gopkg.in/check.v1" "math/rand" - "github.com/tomcraven/goga" ) type BitsetParseSuite struct { bp ga.IBitsetParse } -func ( s *BitsetParseSuite ) SetUpTest( t *C ) { + +func (s *BitsetParseSuite) SetUpTest(t *C) { s.bp = ga.CreateBitsetParse() } -func ( s *BitsetParseSuite ) TearDownTest( t *C ) { +func (s *BitsetParseSuite) TearDownTest(t *C) { s.bp = nil } -var _ = Suite( &BitsetParseSuite{} ) -func ( s *BitsetParseSuite ) TestShouldInstantiate( t *C ) { +var _ = Suite(&BitsetParseSuite{}) + +func (s *BitsetParseSuite) TestShouldInstantiate(t *C) { // tested as part of suite setup } -func ( s *BitsetParseSuite ) TestShouldSetFormat( t *C ) { - s.bp.SetFormat( []int{ 1, 2, 3, 4, 5 } ) +func (s *BitsetParseSuite) TestShouldSetFormat(t *C) { + s.bp.SetFormat([]int{1, 2, 3, 4, 5}) } -func ( s *BitsetParseSuite ) TestShouldPanicWithMismatchedFormatAndBitsetSize( t *C ) { - inputFormat := []int { +func (s *BitsetParseSuite) TestShouldPanicWithMismatchedFormatAndBitsetSize(t *C) { + inputFormat := []int{ 1, 5, 3, 9, 10, 1, } - s.bp.SetFormat( inputFormat ) + s.bp.SetFormat(inputFormat) inputBitset := ga.Bitset{} - inputBitset.Create( 1 ) // Size should equal sum of all formats + inputBitset.Create(1) // Size should equal sum of all formats - t.Assert( func() { s.bp.Process( &inputBitset ) }, Panics, "Input format does not match bitset size" ) + t.Assert(func() { s.bp.Process(&inputBitset) }, Panics, "Input format does not match bitset size") } -func ( s *BitsetParseSuite ) TestShouldNotPanicWithCorrectFormatAndBitsetSize( t *C ) { - inputFormat := []int { - rand.Intn( 10 ), - rand.Intn( 10 ), - rand.Intn( 10 ), - rand.Intn( 10 ), - rand.Intn( 10 ), - rand.Intn( 10 ), +func (s *BitsetParseSuite) TestShouldNotPanicWithCorrectFormatAndBitsetSize(t *C) { + inputFormat := []int{ + rand.Intn(10), + rand.Intn(10), + rand.Intn(10), + rand.Intn(10), + rand.Intn(10), + rand.Intn(10), } - s.bp.SetFormat( inputFormat ) + s.bp.SetFormat(inputFormat) bitsetSize := 0 for _, i := range inputFormat { @@ -55,53 +56,53 @@ func ( s *BitsetParseSuite ) TestShouldNotPanicWithCorrectFormatAndBitsetSize( t } inputBitset := ga.Bitset{} - inputBitset.Create( bitsetSize ) // Size should equal sum of all formats + inputBitset.Create(bitsetSize) // Size should equal sum of all formats - s.bp.Process( &inputBitset ) + s.bp.Process(&inputBitset) } -func ( s *BitsetParseSuite ) TestShouldProcessSingleFormat( t *C ) { - inputFormat := []int { +func (s *BitsetParseSuite) TestShouldProcessSingleFormat(t *C) { + inputFormat := []int{ 16, } - s.bp.SetFormat( inputFormat ) + s.bp.SetFormat(inputFormat) inputBitset := ga.Bitset{} - inputBitset.Create( 16 ) + inputBitset.Create(16) for i := 0; i < 16; i++ { - inputBitset.Set( i, 1 ) + inputBitset.Set(i, 1) } - t.Assert( s.bp.Process( &inputBitset ), DeepEquals, []uint64{ 65535 } ) + t.Assert(s.bp.Process(&inputBitset), DeepEquals, []uint64{65535}) for i := 0; i < 16; i++ { - inputBitset.Set( i, 0 ) + inputBitset.Set(i, 0) } - t.Assert( s.bp.Process( &inputBitset ), DeepEquals, []uint64{ 0 } ) + t.Assert(s.bp.Process(&inputBitset), DeepEquals, []uint64{0}) } -func ( s *BitsetParseSuite ) TestShouldProcessMultipleFormat( t *C ) { - inputFormat := []int { +func (s *BitsetParseSuite) TestShouldProcessMultipleFormat(t *C) { + inputFormat := []int{ 8, 8, } - s.bp.SetFormat( inputFormat ) + s.bp.SetFormat(inputFormat) inputBitset := ga.Bitset{} - inputBitset.Create( 16 ) + inputBitset.Create(16) for i := 0; i < 8; i++ { - inputBitset.Set( i, 1 ) + inputBitset.Set(i, 1) } for i := 8; i < 16; i++ { - inputBitset.Set( i, 0 ) + inputBitset.Set(i, 0) } - t.Assert( s.bp.Process( &inputBitset ), DeepEquals, []uint64{ 255, 0 } ) + t.Assert(s.bp.Process(&inputBitset), DeepEquals, []uint64{255, 0}) for i := 0; i < 8; i++ { - inputBitset.Set( i, 0 ) + inputBitset.Set(i, 0) } for i := 8; i < 16; i++ { - inputBitset.Set( i, 1 ) + inputBitset.Set(i, 1) } - t.Assert( s.bp.Process( &inputBitset ), DeepEquals, []uint64{ 0, 255 } ) -} \ No newline at end of file + t.Assert(s.bp.Process(&inputBitset), DeepEquals, []uint64{0, 255}) +} diff --git a/bitset_test.go b/bitset_test.go index a5b674f..6932c59 100644 --- a/bitset_test.go +++ b/bitset_test.go @@ -1,101 +1,102 @@ - package ga_test import ( - . "gopkg.in/check.v1" "github.com/tomcraven/goga" + . "gopkg.in/check.v1" ) type BitsetSuite struct { bitset *ga.Bitset } -func ( s *BitsetSuite ) SetUpTest( t *C ) { + +func (s *BitsetSuite) SetUpTest(t *C) { s.bitset = &ga.Bitset{} } -func ( s *BitsetSuite ) TearDownTest( t *C ) { +func (s *BitsetSuite) TearDownTest(t *C) { s.bitset = nil } -var _ = Suite( &BitsetSuite{} ) -func ( s *BitsetSuite ) TestShouldInstantiate( t *C ) { +var _ = Suite(&BitsetSuite{}) + +func (s *BitsetSuite) TestShouldInstantiate(t *C) { // Tested as part of fixture setup } -func ( s *BitsetSuite ) TestShouldCreate( t *C ) { - s.bitset.Create( 10 ) +func (s *BitsetSuite) TestShouldCreate(t *C) { + s.bitset.Create(10) } -func ( s *BitsetSuite ) TestShouldGetSize( t *C ) { - t.Assert( 0, Equals, s.bitset.GetSize() ) +func (s *BitsetSuite) TestShouldGetSize(t *C) { + t.Assert(0, Equals, s.bitset.GetSize()) - s.bitset.Create( 10 ) - t.Assert( 10, Equals, s.bitset.GetSize() ) + s.bitset.Create(10) + t.Assert(10, Equals, s.bitset.GetSize()) b := ga.Bitset{} - b.Create( 100 ) - t.Assert( 100, Equals, b.GetSize() ) - t.Assert( b.Set( 99, 1 ), IsTrue ) + b.Create(100) + t.Assert(100, Equals, b.GetSize()) + t.Assert(b.Set(99, 1), IsTrue) } -func ( s *BitsetSuite ) TestShouldSetAndGet( t *C ) { - s.bitset.Create( 10 ) +func (s *BitsetSuite) TestShouldSetAndGet(t *C) { + s.bitset.Create(10) index := 0 value := 1 - t.Assert( s.bitset.Set( index, value ), IsTrue ) - t.Assert( value, Equals, s.bitset.Get( index ) ) + t.Assert(s.bitset.Set(index, value), IsTrue) + t.Assert(value, Equals, s.bitset.Get(index)) index = 1 value = 0 - t.Assert( s.bitset.Set( index, value), IsTrue ) - t.Assert( value, Equals, s.bitset.Get( index ) ) + t.Assert(s.bitset.Set(index, value), IsTrue) + t.Assert(value, Equals, s.bitset.Get(index)) } -func ( s *BitsetSuite ) TestShouldFailSetAndGetWhenNotCreated( t *C ) { - t.Assert( s.bitset.Set( 0, 1 ), IsFalse ) - t.Assert( s.bitset.Get( 0 ), Equals, -1 ) +func (s *BitsetSuite) TestShouldFailSetAndGetWhenNotCreated(t *C) { + t.Assert(s.bitset.Set(0, 1), IsFalse) + t.Assert(s.bitset.Get(0), Equals, -1) - s.bitset.Create( 10 ) - t.Assert( s.bitset.Set( 10, 1), IsFalse ) + s.bitset.Create(10) + t.Assert(s.bitset.Set(10, 1), IsFalse) } -func ( s *BitsetSuite ) TestShouldSetAll( t *C ) { +func (s *BitsetSuite) TestShouldSetAll(t *C) { bitsetSize := 10 - s.bitset.Create( bitsetSize ) + s.bitset.Create(bitsetSize) for i := 0; i < bitsetSize; i++ { - t.Assert( s.bitset.Get( i ), Equals, 0 ) + t.Assert(s.bitset.Get(i), Equals, 0) } - s.bitset.SetAll( 1 ) + s.bitset.SetAll(1) for i := 0; i < bitsetSize; i++ { - t.Assert( s.bitset.Get( i ), Equals, 1 ) + t.Assert(s.bitset.Get(i), Equals, 1) } } -func (s *BitsetSuite ) TestShouldSlice( t *C ) { - s.bitset.Create( 10 ) - s.bitset.SetAll( 1 ) +func (s *BitsetSuite) TestShouldSlice(t *C) { + s.bitset.Create(10) + s.bitset.SetAll(1) - slice := s.bitset.Slice( 0, 3 ) - t.Assert( slice, FitsTypeOf, ga.Bitset{} ) - t.Assert( slice.GetSize(), Equals, 3 ) + slice := s.bitset.Slice(0, 3) + t.Assert(slice, FitsTypeOf, ga.Bitset{}) + t.Assert(slice.GetSize(), Equals, 3) for i := 0; i < 3; i++ { - t.Assert( slice.Get( i ), Equals, 1 ) + t.Assert(slice.Get(i), Equals, 1) } } -func (s *BitsetSuite ) TestShouldGetAll( t *C ) { +func (s *BitsetSuite) TestShouldGetAll(t *C) { const kBitsetSize = 10 - s.bitset.Create( kBitsetSize ) - s.bitset.SetAll( 1 ) + s.bitset.Create(kBitsetSize) + s.bitset.SetAll(1) bits := s.bitset.GetAll() - t.Assert( len( bits ), Equals, kBitsetSize ) + t.Assert(len(bits), Equals, kBitsetSize) for i := 0; i < kBitsetSize; i++ { - t.Assert( bits[ i ], Equals, 1 ) + t.Assert(bits[i], Equals, 1) } -} \ No newline at end of file +} diff --git a/examples/image_matcher.go b/examples/image_matcher.go index 163a6d8..12b89ef 100644 --- a/examples/image_matcher.go +++ b/examples/image_matcher.go @@ -1,131 +1,130 @@ - package main import ( - "github.com/tomcraven/goga" "fmt" - "math/rand" - "time" + "github.com/tomcraven/goga" "image" "image/color" - "image/png" "image/draw" - "os" _ "image/jpeg" + "image/png" "math" + "math/rand" + "os" "runtime" + "time" ) const ( // Fiddle with these - kNumShapes = 100 - kPopulationSize = 100 - kMaxIterations = 9999999 + kNumShapes = 100 + kPopulationSize = 100 + kMaxIterations = 9999999 kBitsPerCoordinateNumber = 9 - kParallelSimulations = 24 - kMaxCircleRadiusFactor = 3 // larger == smaller max circle size relative to image dimensions + kParallelSimulations = 24 + kMaxCircleRadiusFactor = 3 // larger == smaller max circle size relative to image dimensions // Don't fiddle with these... - kMaxBoxCornerCoordinateNumber = ( 1 << kBitsPerCoordinateNumber ) - 1 - kBitsPerColourChannel = 8 // 0 - 255 - kBitsPerRect = ( kBitsPerCoordinateNumber * 4 ) + ( kBitsPerColourChannel * 4 ) - kBitsPerCircle = ( kBitsPerCoordinateNumber * 3 ) + ( kBitsPerColourChannel * 4 ) - kBitsToDescribeWhichShape = 1 + kMaxBoxCornerCoordinateNumber = (1 << kBitsPerCoordinateNumber) - 1 + kBitsPerColourChannel = 8 // 0 - 255 + kBitsPerRect = (kBitsPerCoordinateNumber * 4) + (kBitsPerColourChannel * 4) + kBitsPerCircle = (kBitsPerCoordinateNumber * 3) + (kBitsPerColourChannel * 4) + kBitsToDescribeWhichShape = 1 ) // http://blog.golang.org/go-imagedraw-package type circle struct { - p image.Point - r int - alpha uint8 + p image.Point + r int + alpha uint8 } func (c *circle) ColorModel() color.Model { - return color.AlphaModel + return color.AlphaModel } func (c *circle) Bounds() image.Rectangle { - return image.Rect(c.p.X-c.r, c.p.Y-c.r, c.p.X+c.r, c.p.Y+c.r) + return image.Rect(c.p.X-c.r, c.p.Y-c.r, c.p.X+c.r, c.p.Y+c.r) } func (c *circle) At(x, y int) color.Color { - xx, yy, rr := float64(x-c.p.X)+0.5, float64(y-c.p.Y)+0.5, float64(c.r) - if xx*xx+yy*yy < rr*rr { - return color.Alpha{c.alpha} - } - return color.Alpha{0} + xx, yy, rr := float64(x-c.p.X)+0.5, float64(y-c.p.Y)+0.5, float64(c.r) + if xx*xx+yy*yy < rr*rr { + return color.Alpha{c.alpha} + } + return color.Alpha{0} } -func createImageFromBitset( bits *ga.Bitset ) draw.Image { +func createImageFromBitset(bits *ga.Bitset) draw.Image { inputImageBounds := inputImage.Bounds() - newImage := image.NewRGBA( inputImageBounds ) - draw.Draw(newImage, newImage.Bounds(), &image.Uniform{ color.RGBA{ 0, 0, 0, 255 } }, image.ZP, draw.Over) + newImage := image.NewRGBA(inputImageBounds) + draw.Draw(newImage, newImage.Bounds(), &image.Uniform{color.RGBA{0, 0, 0, 255}}, image.ZP, draw.Over) - for i := 0; i < bits.GetSize() / kLargestShapeBits; i++ { - shapeBitset := bits.Slice( i * kLargestShapeBits, kLargestShapeBits ) + for i := 0; i < bits.GetSize()/kLargestShapeBits; i++ { + shapeBitset := bits.Slice(i*kLargestShapeBits, kLargestShapeBits) - shapeType := shapeBitset.Get( 0 ) - if ( shapeType == 0 ) { - rectBitset := shapeBitset.Slice( 1, kBitsPerRect ) - parsedBits := rectBitsetFormat.Process( &rectBitset ) + shapeType := shapeBitset.Get(0) + if shapeType == 0 { + rectBitset := shapeBitset.Slice(1, kBitsPerRect) + parsedBits := rectBitsetFormat.Process(&rectBitset) colour := color.RGBA{ - uint8( parsedBits[4] ), - uint8( parsedBits[5] ), - uint8( parsedBits[6] ), + uint8(parsedBits[4]), + uint8(parsedBits[5]), + uint8(parsedBits[6]), 255, } alpha := color.RGBA{ 255, 255, 255, - uint8( parsedBits[7] ), + uint8(parsedBits[7]), } - x1 := int( ( float64( parsedBits[0] ) / float64( kMaxBoxCornerCoordinateNumber ) ) * float64( inputImageBounds.Max.X ) ) - y1 := int( ( float64( parsedBits[1] ) / float64( kMaxBoxCornerCoordinateNumber ) ) * float64( inputImageBounds.Max.Y ) ) - x2 := int( ( float64( parsedBits[2] ) / float64( kMaxBoxCornerCoordinateNumber ) ) * float64( inputImageBounds.Max.X ) ) - y2 := int( ( float64( parsedBits[3] ) / float64( kMaxBoxCornerCoordinateNumber ) ) * float64( inputImageBounds.Max.Y ) ) + x1 := int((float64(parsedBits[0]) / float64(kMaxBoxCornerCoordinateNumber)) * float64(inputImageBounds.Max.X)) + y1 := int((float64(parsedBits[1]) / float64(kMaxBoxCornerCoordinateNumber)) * float64(inputImageBounds.Max.Y)) + x2 := int((float64(parsedBits[2]) / float64(kMaxBoxCornerCoordinateNumber)) * float64(inputImageBounds.Max.X)) + y2 := int((float64(parsedBits[3]) / float64(kMaxBoxCornerCoordinateNumber)) * float64(inputImageBounds.Max.Y)) - draw.DrawMask(newImage, image.Rect( x1, y1, x2, y2 ), - &image.Uniform{ colour }, image.ZP, - &image.Uniform{ alpha }, image.ZP, + draw.DrawMask(newImage, image.Rect(x1, y1, x2, y2), + &image.Uniform{colour}, image.ZP, + &image.Uniform{alpha}, image.ZP, draw.Over) } else { - circleBitset := shapeBitset.Slice( 1, kBitsPerCircle ) - parsedBits := circleBitsetFormat.Process( &circleBitset ) + circleBitset := shapeBitset.Slice(1, kBitsPerCircle) + parsedBits := circleBitsetFormat.Process(&circleBitset) colour := color.RGBA{ - uint8( parsedBits[3] ), - uint8( parsedBits[4] ), - uint8( parsedBits[5] ), + uint8(parsedBits[3]), + uint8(parsedBits[4]), + uint8(parsedBits[5]), 255, } - normalisedX := float64( parsedBits[0] ) / float64( kMaxBoxCornerCoordinateNumber ) - normalisedY := float64( parsedBits[1] ) / float64( kMaxBoxCornerCoordinateNumber ) + normalisedX := float64(parsedBits[0]) / float64(kMaxBoxCornerCoordinateNumber) + normalisedY := float64(parsedBits[1]) / float64(kMaxBoxCornerCoordinateNumber) - xMin := float64( -inputImageBounds.Max.X ) - yMin := float64( -inputImageBounds.Max.Y ) + xMin := float64(-inputImageBounds.Max.X) + yMin := float64(-inputImageBounds.Max.Y) - xMax := float64( inputImageBounds.Max.X + inputImageBounds.Max.X ) - yMax := float64( inputImageBounds.Max.Y + inputImageBounds.Max.Y ) + xMax := float64(inputImageBounds.Max.X + inputImageBounds.Max.X) + yMax := float64(inputImageBounds.Max.Y + inputImageBounds.Max.Y) xRange := xMax - xMin yRange := yMax - yMin - x := int( xMin + ( normalisedX * xRange ) ) - y := int( yMin + ( normalisedY * yRange ) ) + x := int(xMin + (normalisedX * xRange)) + y := int(yMin + (normalisedY * yRange)) - normalisedR := float64( parsedBits[2] ) / float64( kMaxBoxCornerCoordinateNumber ) - maxR := math.Max( float64( inputImageBounds.Max.X ), float64( inputImageBounds.Max.Y ) ) - r := int( normalisedR * maxR ) / kMaxCircleRadiusFactor + normalisedR := float64(parsedBits[2]) / float64(kMaxBoxCornerCoordinateNumber) + maxR := math.Max(float64(inputImageBounds.Max.X), float64(inputImageBounds.Max.Y)) + r := int(normalisedR*maxR) / kMaxCircleRadiusFactor - c := circle{ image.Point{ x, y }, r, uint8( parsedBits[6] )} + c := circle{image.Point{x, y}, r, uint8(parsedBits[6])} - draw.DrawMask( newImage, inputImageBounds, - &image.Uniform{ colour }, image.ZP, + draw.DrawMask(newImage, inputImageBounds, + &image.Uniform{colour}, image.ZP, &c, image.ZP, draw.Over) } @@ -135,25 +134,25 @@ func createImageFromBitset( bits *ga.Bitset ) draw.Image { } // http://www.easyrgb.com/index.php?X=MATH -func rgbToXyz( r, g, b uint32 ) ( float64, float64, float64 ) { - normalizedR := float64( r ) / 0xFFFF - normalizedG := float64( g ) / 0xFFFF - normalizedB := float64( b ) / 0xFFFF +func rgbToXyz(r, g, b uint32) (float64, float64, float64) { + normalizedR := float64(r) / 0xFFFF + normalizedG := float64(g) / 0xFFFF + normalizedB := float64(b) / 0xFFFF - if ( normalizedR > 0.04045 ) { - normalizedR = math.Pow( ( ( normalizedR + 0.055 ) / 1.055 ), 2.4 ) + if normalizedR > 0.04045 { + normalizedR = math.Pow(((normalizedR + 0.055) / 1.055), 2.4) } else { normalizedR = normalizedR / 12.92 } - if ( normalizedG > 0.04045 ) { - normalizedG = math.Pow( ( ( normalizedG + 0.055 ) / 1.055 ), 2.4 ) + if normalizedG > 0.04045 { + normalizedG = math.Pow(((normalizedG + 0.055) / 1.055), 2.4) } else { normalizedG = normalizedG / 12.92 } - if ( normalizedB > 0.04045 ) { - normalizedB = math.Pow( ( ( normalizedB + 0.055 ) / 1.055 ), 2.4 ) + if normalizedB > 0.04045 { + normalizedB = math.Pow(((normalizedB + 0.055) / 1.055), 2.4) } else { normalizedB = normalizedB / 12.92 } @@ -162,148 +161,152 @@ func rgbToXyz( r, g, b uint32 ) ( float64, float64, float64 ) { normalizedG *= 100 normalizedB *= 100 - x := normalizedR * 0.4124 + normalizedG * 0.3576 + normalizedB * 0.1805 - y := normalizedR * 0.2126 + normalizedG * 0.7152 + normalizedB * 0.0722 - z := normalizedR * 0.0193 + normalizedG * 0.1192 + normalizedB * 0.9505 + x := normalizedR*0.4124 + normalizedG*0.3576 + normalizedB*0.1805 + y := normalizedR*0.2126 + normalizedG*0.7152 + normalizedB*0.0722 + z := normalizedR*0.0193 + normalizedG*0.1192 + normalizedB*0.9505 return x, y, z } // http://www.easyrgb.com/index.php?X=MATH -func xyzToLabAB( x, y, z float64 ) ( float64, float64, float64 ) { +func xyzToLabAB(x, y, z float64) (float64, float64, float64) { normalizedX := x / 95.047 normalizedY := y / 100.0 normalizedZ := z / 108.883 - if ( normalizedX > 0.008856 ) { - normalizedX = math.Pow( normalizedX, ( 1.0 / 3.0 ) ) + if normalizedX > 0.008856 { + normalizedX = math.Pow(normalizedX, (1.0 / 3.0)) } else { - normalizedX = ( 7.787 * normalizedX ) + ( 16.0 / 116.0 ) + normalizedX = (7.787 * normalizedX) + (16.0 / 116.0) } - if ( normalizedY > 0.008856 ) { - normalizedY = math.Pow( normalizedY, ( 1.0 / 3.0 ) ) + if normalizedY > 0.008856 { + normalizedY = math.Pow(normalizedY, (1.0 / 3.0)) } else { - normalizedY = ( 7.787 * normalizedY ) + ( 16.0 / 116.0 ) + normalizedY = (7.787 * normalizedY) + (16.0 / 116.0) } - if ( normalizedZ > 0.008856 ) { - normalizedZ = math.Pow( normalizedZ, ( 1.0 / 3.0 ) ) + if normalizedZ > 0.008856 { + normalizedZ = math.Pow(normalizedZ, (1.0 / 3.0)) } else { - normalizedZ = ( 7.787 * normalizedZ ) + ( 16.0 / 116.0 ) + normalizedZ = (7.787 * normalizedZ) + (16.0 / 116.0) } - l := ( 116 * normalizedY ) - 16 - a := 500 * ( normalizedX - normalizedY ) - b := 200 * ( normalizedY - normalizedZ ) + l := (116 * normalizedY) - 16 + a := 500 * (normalizedX - normalizedY) + b := 200 * (normalizedY - normalizedZ) return l, a, b } -func distance( a, b float64 ) float64 { - return ( a - b ) * ( a - b ); +func distance(a, b float64) float64 { + return (a - b) * (a - b) } -func calculateColourDifference( red1, green1, blue1, red2, green2, blue2 uint32 ) float64 { +func calculateColourDifference(red1, green1, blue1, red2, green2, blue2 uint32) float64 { // First calculate XYZ - x1, y1, z1 := rgbToXyz( red1, green1, blue1 ) - x2, y2, z2 := rgbToXyz( red2, green2, blue2 ) + x1, y1, z1 := rgbToXyz(red1, green1, blue1) + x2, y2, z2 := rgbToXyz(red2, green2, blue2) // Then calculate CIE-L*ab - l1, a1, b1 := xyzToLabAB( x1, y1, z1 ) - l2, a2, b2 := xyzToLabAB( x2, y2, z2 ) + l1, a1, b1 := xyzToLabAB(x1, y1, z1) + l2, a2, b2 := xyzToLabAB(x2, y2, z2) // Calculate difference - differences := distance( l1, l2 ) + distance( a1, a2 ) + distance( b1, b2 ); - return math.Pow( differences, 0.5 ) + differences := distance(l1, l2) + distance(a1, a2) + distance(b1, b2) + return math.Pow(differences, 0.5) } + type ImageMatcherSimulator struct { totalIterations int } -func ( simulator *ImageMatcherSimulator ) OnBeginSimulation() { + +func (simulator *ImageMatcherSimulator) OnBeginSimulation() { } -func ( simulator *ImageMatcherSimulator ) OnEndSimulation() { +func (simulator *ImageMatcherSimulator) OnEndSimulation() { simulator.totalIterations++ } -func ( simulator *ImageMatcherSimulator ) Simulate( g *ga.IGenome ) { +func (simulator *ImageMatcherSimulator) Simulate(g *ga.IGenome) { bits := (*g).GetBits() - newImage := createImageFromBitset( bits ) + newImage := createImageFromBitset(bits) inputImageBounds := inputImage.Bounds() fitness := 0.0 for y := 0; y < inputImageBounds.Max.Y; y++ { for x := 0; x < inputImageBounds.Max.X; x++ { - inputR, inputG, inputB, _ := inputImage.At( x, y ).RGBA() - createdR, createdG, createdB, _ := newImage.At( x, y ).RGBA() + inputR, inputG, inputB, _ := inputImage.At(x, y).RGBA() + createdR, createdG, createdB, _ := newImage.At(x, y).RGBA() - colourDifference := calculateColourDifference( inputR, inputG, inputB, createdR, createdG, createdB ) + colourDifference := calculateColourDifference(inputR, inputG, inputB, createdR, createdG, createdB) - fitness += ( 500.0 - colourDifference ) + fitness += (500.0 - colourDifference) } } - (*g).SetFitness( int( fitness ) ) + (*g).SetFitness(int(fitness)) } -func ( simulator *ImageMatcherSimulator ) ExitFunc( g *ga.IGenome ) bool { +func (simulator *ImageMatcherSimulator) ExitFunc(g *ga.IGenome) bool { return simulator.totalIterations >= kMaxIterations } type MyBitsetCreate struct { } -func ( bc *MyBitsetCreate ) Go() ga.Bitset { + +func (bc *MyBitsetCreate) Go() ga.Bitset { b := ga.Bitset{} - b.Create( kNumShapes * kLargestShapeBits ) + b.Create(kNumShapes * kLargestShapeBits) for i := 0; i < b.GetSize(); i++ { - b.Set( i, rand.Intn( 2 ) ) + b.Set(i, rand.Intn(2)) } return b } type MyEliteConsumer struct { - currentIter int + currentIter int previousFitness int } -func ( ec *MyEliteConsumer ) OnElite( g *ga.IGenome ) { + +func (ec *MyEliteConsumer) OnElite(g *ga.IGenome) { bits := (*g).GetBits() - newImage := createImageFromBitset( bits ) + newImage := createImageFromBitset(bits) // Output elite - outputImageFile, _ := os.Create( "elite.png" ) - png.Encode( outputImageFile, newImage ) - outputImageFile.Close() + outputImageFile, _ := os.Create("elite.png") + png.Encode(outputImageFile, newImage) + outputImageFile.Close() - // Output elite with input image blended over the top - outputImageFileAlphaBlended, _ := os.Create( "elite_with_original.png" ) + // Output elite with input image blended over the top + outputImageFileAlphaBlended, _ := os.Create("elite_with_original.png") draw.DrawMask(newImage, newImage.Bounds(), - inputImage, image.ZP, - &image.Uniform{ color.RGBA{ 0, 0, 0, 255 / 4 } }, image.ZP, - draw.Over) - png.Encode( outputImageFileAlphaBlended, newImage ) - outputImageFileAlphaBlended.Close() + inputImage, image.ZP, + &image.Uniform{color.RGBA{0, 0, 0, 255 / 4}}, image.ZP, + draw.Over) + png.Encode(outputImageFileAlphaBlended, newImage) + outputImageFileAlphaBlended.Close() ec.currentIter++ fitness := (*g).GetFitness() - fmt.Println( ec.currentIter, "\t", fitness, "\t", fitness - ec.previousFitness ) + fmt.Println(ec.currentIter, "\t", fitness, "\t", fitness-ec.previousFitness) ec.previousFitness = fitness - time.Sleep( 10 * time.Millisecond ) + time.Sleep(10 * time.Millisecond) } var ( - kLargestShapeBits int + kLargestShapeBits int kTotalBitsPerGenome int inputImage image.Image circleBitsetFormat ga.IBitsetParse - rectBitsetFormat ga.IBitsetParse + rectBitsetFormat ga.IBitsetParse ) func init() { kLargestShapeBits = kBitsToDescribeWhichShape - if ( kBitsPerRect > kBitsPerCircle ) { + if kBitsPerRect > kBitsPerCircle { kLargestShapeBits += kBitsPerRect } else { kLargestShapeBits += kBitsPerCircle @@ -312,62 +315,62 @@ func init() { kTotalBitsPerGenome = kLargestShapeBits * kNumShapes } -func getImageFromFile( filename string ) image.Image { - inputImageFile, _ := os.Open( filename ) +func getImageFromFile(filename string) image.Image { + inputImageFile, _ := os.Open(filename) defer inputImageFile.Close() - inputImage, _, _ := image.Decode( inputImageFile ) + inputImage, _, _ := image.Decode(inputImageFile) return inputImage } func main() { - runtime.GOMAXPROCS( runtime.NumCPU() ) + runtime.GOMAXPROCS(runtime.NumCPU()) // Get the input image - inputImage = getImageFromFile( os.Args[ 1 ] ) + inputImage = getImageFromFile(os.Args[1]) rectBitsetFormat = ga.CreateBitsetParse() - rectBitsetFormat.SetFormat( []int{ - kBitsPerCoordinateNumber, kBitsPerCoordinateNumber, kBitsPerCoordinateNumber, kBitsPerCoordinateNumber, - kBitsPerColourChannel, kBitsPerColourChannel, kBitsPerColourChannel, kBitsPerColourChannel, - }) + rectBitsetFormat.SetFormat([]int{ + kBitsPerCoordinateNumber, kBitsPerCoordinateNumber, kBitsPerCoordinateNumber, kBitsPerCoordinateNumber, + kBitsPerColourChannel, kBitsPerColourChannel, kBitsPerColourChannel, kBitsPerColourChannel, + }) circleBitsetFormat = ga.CreateBitsetParse() - circleBitsetFormat.SetFormat( []int{ - kBitsPerCoordinateNumber, kBitsPerCoordinateNumber, kBitsPerCoordinateNumber, - kBitsPerColourChannel, kBitsPerColourChannel, kBitsPerColourChannel, kBitsPerColourChannel, - }) + circleBitsetFormat.SetFormat([]int{ + kBitsPerCoordinateNumber, kBitsPerCoordinateNumber, kBitsPerCoordinateNumber, + kBitsPerColourChannel, kBitsPerColourChannel, kBitsPerColourChannel, kBitsPerColourChannel, + }) genAlgo := ga.NewGeneticAlgorithm() genAlgo.Simulator = &ImageMatcherSimulator{} genAlgo.BitsetCreate = &MyBitsetCreate{} genAlgo.EliteConsumer = &MyEliteConsumer{} - genAlgo.Mater = ga.NewMater( + genAlgo.Mater = ga.NewMater( []ga.MaterFunctionProbability{ - { P : 1.0, F : ga.UniformCrossover, UseElite : true }, - { P : 1.0, F : ga.Mutate }, - { P : 1.0, F : ga.Mutate }, - { P : 1.0, F : ga.Mutate }, - { P : 1.0, F : ga.Mutate }, - { P : 1.0, F : ga.Mutate }, - { P : 1.0, F : ga.Mutate }, - { P : 1.0, F : ga.Mutate }, - { P : 1.0, F : ga.Mutate }, - { P : 1.0, F : ga.Mutate }, - { P : 1.0, F : ga.Mutate }, - { P : 1.0, F : ga.Mutate }, - { P : 1.0, F : ga.Mutate }, + {P: 1.0, F: ga.UniformCrossover, UseElite: true}, + {P: 1.0, F: ga.Mutate}, + {P: 1.0, F: ga.Mutate}, + {P: 1.0, F: ga.Mutate}, + {P: 1.0, F: ga.Mutate}, + {P: 1.0, F: ga.Mutate}, + {P: 1.0, F: ga.Mutate}, + {P: 1.0, F: ga.Mutate}, + {P: 1.0, F: ga.Mutate}, + {P: 1.0, F: ga.Mutate}, + {P: 1.0, F: ga.Mutate}, + {P: 1.0, F: ga.Mutate}, + {P: 1.0, F: ga.Mutate}, }, ) genAlgo.Selector = ga.NewSelector( - []ga.SelectorFunctionProbability { - { P : 1.0, F : ga.Roulette }, + []ga.SelectorFunctionProbability{ + {P: 1.0, F: ga.Roulette}, }, ) - genAlgo.Init( kPopulationSize, kParallelSimulations ) + genAlgo.Init(kPopulationSize, kParallelSimulations) startTime := time.Now() genAlgo.Simulate() - fmt.Println( time.Since( startTime ) ) -} \ No newline at end of file + fmt.Println(time.Since(startTime)) +} diff --git a/examples/string_matcher.go b/examples/string_matcher.go index 7c326ac..56fc1ea 100644 --- a/examples/string_matcher.go +++ b/examples/string_matcher.go @@ -1,115 +1,115 @@ -package main - -import ( - "fmt" - ga "github.com/tomcraven/goga" - "math/rand" - "os" - "runtime" - "time" -) - -type StringMaterSimulator struct { -} - -func (sms *StringMaterSimulator) OnBeginSimulation() { -} -func (sms *StringMaterSimulator) OnEndSimulation() { -} -func (sms *StringMaterSimulator) Simulate(g *ga.IGenome) { - bits := (*g).GetBits() - for i, character := range targetString { - for j := 0; j < 8; j++ { - targetBit := character & (1 << uint(j)) - bit := bits.Get((i * 8) + j) - if targetBit != 0 && bit == 1 { - (*g).SetFitness((*g).GetFitness() + 1) - } else if targetBit == 0 && bit == 0 { - (*g).SetFitness((*g).GetFitness() + 1) - } - } - } -} -func (sms *StringMaterSimulator) ExitFunc(g *ga.IGenome) bool { - return (*g).GetFitness() == targetLength -} - -type MyBitsetCreate struct { -} - -func (bc *MyBitsetCreate) Go() ga.Bitset { - b := ga.Bitset{} - b.Create(targetLength) - for i := 0; i < targetLength; i++ { - b.Set(i, rand.Intn(2)) - } - return b -} - -type MyEliteConsumer struct { - currentIter int -} - -func (ec *MyEliteConsumer) OnElite(g *ga.IGenome) { - gBits := (*g).GetBits() - ec.currentIter++ - var genomeString string - for i := 0; i < gBits.GetSize(); i += 8 { - c := int(0) - for j := 0; j < 8; j++ { - bit := gBits.Get(i + j) - if bit != 0 { - c |= 1 << uint(j) - } - } - genomeString += string(c) - } - - fmt.Println(ec.currentIter, "\t", genomeString, "\t", (*g).GetFitness()) -} - -const ( - kPopulationSize = 600 -) - -var ( - targetString = "abcdefghijklmnopqrstuvwxyz" - targetLength int -) - -func init() { - if len(os.Args) > 1 { - targetString = os.Args[1] - } - targetLength = len(targetString) * 8 -} - -func main() { - - numThreads := 4 - runtime.GOMAXPROCS(numThreads) - - genAlgo := ga.NewGeneticAlgorithm() - - genAlgo.Simulator = &StringMaterSimulator{} - genAlgo.BitsetCreate = &MyBitsetCreate{} - genAlgo.EliteConsumer = &MyEliteConsumer{} - genAlgo.Mater = ga.NewMater( - []ga.MaterFunctionProbability{ - {P: 1.0, F: ga.TwoPointCrossover}, - {P: 1.0, F: ga.Mutate}, - {P: 1.0, F: ga.UniformCrossover, UseElite: true}, - }, - ) - genAlgo.Selector = ga.NewSelector( - []ga.SelectorFunctionProbability{ - {P: 1.0, F: ga.Roulette}, - }, - ) - - genAlgo.Init(kPopulationSize, numThreads) - - startTime := time.Now() - genAlgo.Simulate() - fmt.Println(time.Since(startTime)) -} +package main + +import ( + "fmt" + ga "github.com/tomcraven/goga" + "math/rand" + "os" + "runtime" + "time" +) + +type StringMaterSimulator struct { +} + +func (sms *StringMaterSimulator) OnBeginSimulation() { +} +func (sms *StringMaterSimulator) OnEndSimulation() { +} +func (sms *StringMaterSimulator) Simulate(g *ga.IGenome) { + bits := (*g).GetBits() + for i, character := range targetString { + for j := 0; j < 8; j++ { + targetBit := character & (1 << uint(j)) + bit := bits.Get((i * 8) + j) + if targetBit != 0 && bit == 1 { + (*g).SetFitness((*g).GetFitness() + 1) + } else if targetBit == 0 && bit == 0 { + (*g).SetFitness((*g).GetFitness() + 1) + } + } + } +} +func (sms *StringMaterSimulator) ExitFunc(g *ga.IGenome) bool { + return (*g).GetFitness() == targetLength +} + +type MyBitsetCreate struct { +} + +func (bc *MyBitsetCreate) Go() ga.Bitset { + b := ga.Bitset{} + b.Create(targetLength) + for i := 0; i < targetLength; i++ { + b.Set(i, rand.Intn(2)) + } + return b +} + +type MyEliteConsumer struct { + currentIter int +} + +func (ec *MyEliteConsumer) OnElite(g *ga.IGenome) { + gBits := (*g).GetBits() + ec.currentIter++ + var genomeString string + for i := 0; i < gBits.GetSize(); i += 8 { + c := int(0) + for j := 0; j < 8; j++ { + bit := gBits.Get(i + j) + if bit != 0 { + c |= 1 << uint(j) + } + } + genomeString += string(c) + } + + fmt.Println(ec.currentIter, "\t", genomeString, "\t", (*g).GetFitness()) +} + +const ( + kPopulationSize = 600 +) + +var ( + targetString = "abcdefghijklmnopqrstuvwxyz" + targetLength int +) + +func init() { + if len(os.Args) > 1 { + targetString = os.Args[1] + } + targetLength = len(targetString) * 8 +} + +func main() { + + numThreads := 4 + runtime.GOMAXPROCS(numThreads) + + genAlgo := ga.NewGeneticAlgorithm() + + genAlgo.Simulator = &StringMaterSimulator{} + genAlgo.BitsetCreate = &MyBitsetCreate{} + genAlgo.EliteConsumer = &MyEliteConsumer{} + genAlgo.Mater = ga.NewMater( + []ga.MaterFunctionProbability{ + {P: 1.0, F: ga.TwoPointCrossover}, + {P: 1.0, F: ga.Mutate}, + {P: 1.0, F: ga.UniformCrossover, UseElite: true}, + }, + ) + genAlgo.Selector = ga.NewSelector( + []ga.SelectorFunctionProbability{ + {P: 1.0, F: ga.Roulette}, + }, + ) + + genAlgo.Init(kPopulationSize, numThreads) + + startTime := time.Now() + genAlgo.Simulate() + fmt.Println(time.Since(startTime)) +} diff --git a/genetic_algorithm.go b/genetic_algorithm.go index b07f9c0..ee217e3 100644 --- a/genetic_algorithm.go +++ b/genetic_algorithm.go @@ -1,86 +1,85 @@ - package ga import ( // "fmt" - "time" "sync" + "time" ) -type GeneticAlgorithm struct { - Mater IMater +type GeneticAlgorithm struct { + Mater IMater EliteConsumer IEliteConsumer - Simulator ISimulator - Selector ISelector - BitsetCreate IBitsetCreate + Simulator ISimulator + Selector ISelector + BitsetCreate IBitsetCreate - populationSize int - population []IGenome - totalFitness int + populationSize int + population []IGenome + totalFitness int genomeSimulationChannel chan *IGenome - exitFunc func( *IGenome ) bool - waitGroup *sync.WaitGroup - parallelSimulations int + exitFunc func(*IGenome) bool + waitGroup *sync.WaitGroup + parallelSimulations int } func NewGeneticAlgorithm() GeneticAlgorithm { - return GeneticAlgorithm { - EliteConsumer : &NullEliteConsumer{}, - Mater : &NullMater{}, - Simulator : &NullSimulator{}, - Selector : &NullSelector{}, - BitsetCreate : &NullBitsetCreate{}, + return GeneticAlgorithm{ + EliteConsumer: &NullEliteConsumer{}, + Mater: &NullMater{}, + Simulator: &NullSimulator{}, + Selector: &NullSelector{}, + BitsetCreate: &NullBitsetCreate{}, } } -func ( ga *GeneticAlgorithm ) createPopulation() []IGenome { - ret := make( []IGenome, ga.populationSize ) +func (ga *GeneticAlgorithm) createPopulation() []IGenome { + ret := make([]IGenome, ga.populationSize) for i := 0; i < ga.populationSize; i++ { - ret[i] = NewGenome( ga.BitsetCreate.Go() ) + ret[i] = NewGenome(ga.BitsetCreate.Go()) } return ret } -func ( ga *GeneticAlgorithm ) Init( populationSize, parallelSimulations int ) { +func (ga *GeneticAlgorithm) Init(populationSize, parallelSimulations int) { ga.populationSize = populationSize ga.population = ga.createPopulation() ga.parallelSimulations = parallelSimulations - ga.waitGroup = new( sync.WaitGroup ) - + ga.waitGroup = new(sync.WaitGroup) + } -func ( ga *GeneticAlgorithm ) beginSimulation() { +func (ga *GeneticAlgorithm) beginSimulation() { ga.Simulator.OnBeginSimulation() ga.totalFitness = 0 - ga.genomeSimulationChannel = make( chan *IGenome ) + ga.genomeSimulationChannel = make(chan *IGenome) // todo: make configurable for i := 0; i < ga.parallelSimulations; i++ { - go func ( genomeSimulationChannel chan *IGenome, - waitGroup *sync.WaitGroup, simulator ISimulator ) { + go func(genomeSimulationChannel chan *IGenome, + waitGroup *sync.WaitGroup, simulator ISimulator) { for genome := range genomeSimulationChannel { defer waitGroup.Done() - simulator.Simulate( genome ) + simulator.Simulate(genome) } - }( ga.genomeSimulationChannel, ga.waitGroup, ga.Simulator ) + }(ga.genomeSimulationChannel, ga.waitGroup, ga.Simulator) } - ga.waitGroup.Add( ga.populationSize ) + ga.waitGroup.Add(ga.populationSize) } -func ( ga *GeneticAlgorithm ) onNewGenomeToSimulate( g *IGenome ) { +func (ga *GeneticAlgorithm) onNewGenomeToSimulate(g *IGenome) { ga.genomeSimulationChannel <- g } -func ( ga *GeneticAlgorithm ) syncSimulatingGenomes() { - close( ga.genomeSimulationChannel ) +func (ga *GeneticAlgorithm) syncSimulatingGenomes() { + close(ga.genomeSimulationChannel) ga.waitGroup.Wait() } -func ( ga *GeneticAlgorithm ) getElite() *IGenome { +func (ga *GeneticAlgorithm) getElite() *IGenome { var ret *IGenome = nil for i := 0; i < ga.populationSize; i++ { if ret == nil || ga.population[i].GetFitness() > (*ret).GetFitness() { @@ -90,56 +89,56 @@ func ( ga *GeneticAlgorithm ) getElite() *IGenome { return ret } -func ( ga *GeneticAlgorithm ) SimulateUntil( exitFunc func( *IGenome ) bool ) bool { +func (ga *GeneticAlgorithm) SimulateUntil(exitFunc func(*IGenome) bool) bool { ga.exitFunc = exitFunc return ga.Simulate() } -func ( ga *GeneticAlgorithm ) shouldExit( elite *IGenome ) bool { +func (ga *GeneticAlgorithm) shouldExit(elite *IGenome) bool { if ga.exitFunc == nil { - return ga.Simulator.ExitFunc( elite ) + return ga.Simulator.ExitFunc(elite) } - return ga.exitFunc( elite ) + return ga.exitFunc(elite) } -func ( ga *GeneticAlgorithm ) Simulate() bool { +func (ga *GeneticAlgorithm) Simulate() bool { - if ( ga.populationSize == 0 ) { + if ga.populationSize == 0 { return false } ga.beginSimulation() for i := 0; i < ga.populationSize; i++ { - ga.onNewGenomeToSimulate( &ga.population[i] ) + ga.onNewGenomeToSimulate(&ga.population[i]) } ga.syncSimulatingGenomes() ga.Simulator.OnEndSimulation() for { elite := ga.getElite() - ga.Mater.OnElite( elite ) - ga.EliteConsumer.OnElite( elite ) - if ga.shouldExit( elite ) { + ga.Mater.OnElite(elite) + ga.EliteConsumer.OnElite(elite) + if ga.shouldExit(elite) { break } - time.Sleep( 1 * time.Microsecond ) + time.Sleep(1 * time.Microsecond) ga.beginSimulation() newPopulation := ga.createPopulation() for i := 0; i < ga.populationSize; i += 2 { - g1 := ga.Selector.Go( ga.population, ga.totalFitness ) - g2 := ga.Selector.Go( ga.population, ga.totalFitness ) + g1 := ga.Selector.Go(ga.population, ga.totalFitness) + g2 := ga.Selector.Go(ga.population, ga.totalFitness) g3, g4 := ga.Mater.Go(g1, g2) newPopulation[i] = g3 - ga.onNewGenomeToSimulate( &newPopulation[i] ) + ga.onNewGenomeToSimulate(&newPopulation[i]) - if ( i + 1 ) < ga.populationSize { - newPopulation[i + 1] = g4 - ga.onNewGenomeToSimulate( &newPopulation[i + 1] ) + if (i + 1) < ga.populationSize { + newPopulation[i+1] = g4 + ga.onNewGenomeToSimulate(&newPopulation[i+1]) } } ga.population = newPopulation @@ -150,6 +149,6 @@ func ( ga *GeneticAlgorithm ) Simulate() bool { return true } -func ( ga *GeneticAlgorithm ) GetPopulation() ( []IGenome ) { +func (ga *GeneticAlgorithm) GetPopulation() []IGenome { return ga.population -} \ No newline at end of file +} diff --git a/genetic_algorithm_test.go b/genetic_algorithm_test.go index b2b6526..a7a8751 100644 --- a/genetic_algorithm_test.go +++ b/genetic_algorithm_test.go @@ -1,580 +1,586 @@ - -package ga_test - -import ( - . "gopkg.in/check.v1" - - "github.com/tomcraven/goga" - // "fmt" - "sync" - "math/rand" - "time" - ) - -const kNumThreads = 4 - -type GeneticAlgorithmSuite struct { -} -var _ = Suite( &GeneticAlgorithmSuite{} ) - -func helperGenerateExitFunction( numIterations int ) func ( *ga.IGenome ) bool { - totalIterations := 0 - return func ( *ga.IGenome ) bool { - totalIterations++ - if totalIterations >= numIterations { - return true - } - return false - } -} - -func ( s *GeneticAlgorithmSuite ) TestShouldSimulateUntil( t *C ) { - - callCount := 0 - exitFunc := func( g *ga.IGenome ) bool { - callCount++ - return true - } - - genAlgo := ga.NewGeneticAlgorithm() - genAlgo.Init( 1, kNumThreads ) - ret := genAlgo.SimulateUntil( exitFunc ) - t.Assert( ret, IsTrue ) - t.Assert( callCount, Equals, 1 ) - - callCount = 0 - exitFunc2 := func( g *ga.IGenome ) bool { - callCount++ - if callCount >= 2 { - return true - } - return false - } - ret = genAlgo.SimulateUntil( exitFunc2 ) - t.Assert( ret, IsTrue ) - t.Assert( callCount, Equals, 2 ) -} - -func ( s *GeneticAlgorithmSuite ) TestShouldCallMaterAppropriately_1( t *C ) { - - numCalls1 := 0 - mateFunc1 := func ( a, b *ga.IGenome ) ( ga.IGenome, ga.IGenome ) { - numCalls1++ - return *a, *b - } - - numCalls2 := 0 - mateFunc2 := func ( a, b *ga.IGenome ) ( ga.IGenome, ga.IGenome ) { - numCalls2++ - return *a, *b - } - - m := ga.NewMater( - []ga.MaterFunctionProbability{ - { P : 0.5, F : mateFunc1 }, - { P : 0.75, F : mateFunc2 }, - }, - ) - - genAlgo := ga.NewGeneticAlgorithm() - genAlgo.Init( 2, kNumThreads ) - genAlgo.Mater = m - - numIterations := 1000 - ret := genAlgo.SimulateUntil( helperGenerateExitFunction( numIterations ) ) - t.Assert( ret, IsTrue ) - - sixtyPercent := ( numIterations / 100 ) * 60 - fourtyPercent := ( numIterations / 100 ) * 40 - t.Assert( numCalls1 < sixtyPercent, IsTrue, Commentf( "Num calls [%v] percent [%v]", numCalls1, sixtyPercent ) ) - t.Assert( numCalls1 > fourtyPercent, IsTrue, Commentf( "Num calls [%v] percent [%v]", numCalls1, fourtyPercent ) ) - - sixtyFivePercent := ( numIterations / 100 ) * 65 - eightyFivePercent := ( numIterations / 100 ) * 85 - t.Assert( numCalls2 < eightyFivePercent, IsTrue, Commentf( "Num calls [%v] percent [%v]", numCalls2, sixtyPercent ) ) - t.Assert( numCalls2 > sixtyFivePercent, IsTrue, Commentf( "Num calls [%v] percent [%v]", numCalls2, fourtyPercent ) ) -} - -func ( s *GeneticAlgorithmSuite ) TestShouldCallMaterAppropriately_2( t *C ) { - - numCalls := 0 - mateFunc := func ( a, b *ga.IGenome ) ( ga.IGenome, ga.IGenome ) { - numCalls++ - return *a, *b - } - - m := ga.NewMater( - []ga.MaterFunctionProbability { - { P : 1, F : mateFunc }, - }, - ) - - genAlgo := ga.NewGeneticAlgorithm() - populationSize := 100 - genAlgo.Init( populationSize, kNumThreads ) - genAlgo.Mater = m - - numIterations := 1000 - genAlgo.SimulateUntil( helperGenerateExitFunction( numIterations ) ) - - expectedNumIterations := ( numIterations * ( populationSize / 2 ) ) - expectedNumIterations -= ( populationSize / 2 ) - t.Assert( numCalls, Equals, expectedNumIterations ) -} - -func ( s *GeneticAlgorithmSuite ) TestShouldCallMaterAppropriately_OddSizedPopulation( t *C ) { - - numCalls := 0 - mateFunc := func ( a, b *ga.IGenome ) ( ga.IGenome, ga.IGenome ) { - numCalls++ - return *a, *b - } - - m := ga.NewMater( - []ga.MaterFunctionProbability { - { P : 1, F : mateFunc }, - }, - ) - - genAlgo := ga.NewGeneticAlgorithm() - populationSize := 99 - genAlgo.Init( populationSize, kNumThreads ) - genAlgo.Mater = m - - numIterations := 1000 - genAlgo.SimulateUntil( helperGenerateExitFunction( numIterations ) ) - - resultantPopulationSize := len( genAlgo.GetPopulation() ) - t.Assert( resultantPopulationSize, Equals, populationSize ) -} - -type MyEliteConsumerCounter struct { - NumCalls int -} -func ( ec * MyEliteConsumerCounter ) OnElite( g *ga.IGenome ) { - ec.NumCalls++ -} - -func ( s *GeneticAlgorithmSuite ) TestShouldCallIntoEliteConsumer( t *C ) { - - ec := MyEliteConsumerCounter{} - genAlgo := ga.NewGeneticAlgorithm() - genAlgo.Init( 1, kNumThreads ) - genAlgo.EliteConsumer = &ec - - numIterations := 42 - ret := genAlgo.SimulateUntil( helperGenerateExitFunction( numIterations ) ) - t.Assert( ret, IsTrue ) - t.Assert( ec.NumCalls, Equals, numIterations ) -} - -func ( s *GeneticAlgorithmSuite ) TestShouldNotSimulateWithNoPopulation( t *C ) { - - genAlgo := ga.NewGeneticAlgorithm() - - callCount := 0 - exitFunc := func( g *ga.IGenome ) bool { - callCount++ - return true - } - ret := genAlgo.SimulateUntil( exitFunc ) - - t.Assert( ret, IsFalse ) - t.Assert( callCount, Equals, 0 ) - - genAlgo.Init( 0, kNumThreads ) - ret = genAlgo.SimulateUntil( exitFunc ) - t.Assert( ret, IsFalse ) - t.Assert( callCount, Equals, 0 ) - - genAlgo.Init( 1, kNumThreads ) - ret = genAlgo.SimulateUntil( exitFunc ) - t.Assert( ret, IsTrue ) - t.Assert( callCount, Equals, 1 ) -} - -func ( s *GeneticAlgorithmSuite ) TestShouldGetPopulation( t *C ) { - - genAlgo := ga.NewGeneticAlgorithm() - - t.Assert( genAlgo.GetPopulation(), HasLen, 0 ) - - genAlgo.Init( 1, kNumThreads ) - pop := genAlgo.GetPopulation() - t.Assert( pop, HasLen, 1 ) - - g := ga.NewGenome( ga.Bitset{} ) - t.Assert( pop[0], FitsTypeOf, g ) - - genAlgo.Init( 123, kNumThreads ) - t.Assert( genAlgo.GetPopulation(), HasLen, 123 ) - - p1 := genAlgo.GetPopulation() - p2 := genAlgo.GetPopulation() - t.Assert( len( p1 ), Equals, len( p2 ) ) - for i := 0; i < len( p1 ); i++ { - t.Assert( p1[i], Equals, p2[i] ) - } -} - -type MySimulatorCounter struct { - NumCalls int - m sync.Mutex -} -func ( ms *MySimulatorCounter ) Simulate( *ga.IGenome ) { - ms.m.Lock() - ms.NumCalls++ - ms.m.Unlock() -} -func ( ms *MySimulatorCounter ) OnBeginSimulation() { -} -func ( ms *MySimulatorCounter ) OnEndSimulation() { -} -func ( ms *MySimulatorCounter ) ExitFunc( *ga.IGenome ) bool { - return false -} - -func ( s *GeneticAlgorithmSuite ) TestShouldSimulatePopulatonCounter( t *C ) { - genAlgo := ga.NewGeneticAlgorithm() - - ms := MySimulatorCounter{} - genAlgo.Simulator = &ms - t.Assert( ms.NumCalls, Equals, 0 ) - - populationSize := 100 - genAlgo.Init( populationSize, kNumThreads ); - - numIterations := 10 - genAlgo.SimulateUntil( helperGenerateExitFunction( numIterations ) ) - t.Assert( ms.NumCalls, Equals, numIterations * populationSize ) -} - -type MySimulatorFitness struct { - NumIterations int - LargestFitnessess []int - - currentLargestFitness int - m sync.Mutex -} -func ( ms* MySimulatorFitness ) Simulate( g *ga.IGenome ) { - ms.m.Lock() - randomFitness := rand.Intn( 1000 ) - if randomFitness > ms.currentLargestFitness { - ms.currentLargestFitness = randomFitness - } - (*g).SetFitness( randomFitness ) - ms.m.Unlock() -} -func ( ms *MySimulatorFitness ) OnBeginSimulation() { - ms.currentLargestFitness = 0 -} -func ( ms *MySimulatorFitness ) OnEndSimulation() { - ms.LargestFitnessess = append( ms.LargestFitnessess, ms.currentLargestFitness ) -} -func ( ms *MySimulatorFitness ) ExitFunc( *ga.IGenome ) bool { - return false -} - -type MyEliteConsumerFitness struct { - EliteFitnesses []int -} -func ( ec *MyEliteConsumerFitness ) OnElite( g *ga.IGenome ) { - ec.EliteFitnesses = append( ec.EliteFitnesses, (*g).GetFitness() ) -} - -func ( s *GeneticAlgorithmSuite ) TestShouldSimulatePopulationAndPassEliteToConsumer( t *C ) { - genAlgo := ga.NewGeneticAlgorithm() - - numIterations := 100 - ms := MySimulatorFitness{ NumIterations : numIterations } - genAlgo.Simulator = &ms - - ec := MyEliteConsumerFitness{} - genAlgo.EliteConsumer = &ec - - genAlgo.Init( 100, kNumThreads ); - - genAlgo.SimulateUntil( helperGenerateExitFunction( numIterations ) ) - - t.Assert( ec.EliteFitnesses, DeepEquals, ms.LargestFitnessess ) -} - -type MySimulatorOrder struct { - Order []int - - BeginCalled bool - SimulateCalled bool - EndCalled bool -} -func ( ms *MySimulatorOrder ) OnBeginSimulation() { - ms.Order = append( ms.Order, 1 ) - ms.SimulateCalled = true -} -func ( ms *MySimulatorOrder ) Simulate( g *ga.IGenome ) { - ms.Order = append( ms.Order, 2 ) - ms.BeginCalled = true -} -func ( ms *MySimulatorOrder ) OnEndSimulation() { - ms.Order = append( ms.Order, 3 ) - ms.EndCalled = true -} -func ( ms *MySimulatorOrder ) ExitFunc( *ga.IGenome ) bool { - return false -} - -func ( s *GeneticAlgorithmSuite ) TestShouldCallOnBeginEndSimulation( t *C ) { - genAlgo := ga.NewGeneticAlgorithm() - - ms := MySimulatorOrder{} - genAlgo.Simulator = &ms - - t.Assert( ms.BeginCalled, Equals, false ) - t.Assert( ms.SimulateCalled, Equals, false ) - t.Assert( ms.Order, HasLen, 0 ) - - genAlgo.Init( 1, kNumThreads ); - genAlgo.SimulateUntil( helperGenerateExitFunction( 1 ) ) - - // Sleep and give time for threads to start up - time.Sleep( 100 * time.Millisecond ) - - t.Assert( ms.BeginCalled, Equals, true ); - t.Assert( ms.SimulateCalled, Equals, true ); - t.Assert( ms.Order, HasLen, 3 ); - t.Assert( ms.Order, DeepEquals, []int{ 1, 2, 3 } ); -} - -func ( s* GeneticAlgorithmSuite ) TestShouldPassEliteToExitFunc( t *C ) { - genAlgo := ga.NewGeneticAlgorithm() - - numIterations := 10 - ms := MySimulatorFitness{ NumIterations : numIterations } - genAlgo.Simulator = &ms - - ec := MyEliteConsumerFitness{} - genAlgo.EliteConsumer = &ec - - populationSize := 10 - genAlgo.Init( populationSize, kNumThreads ); - - passedGenomeFitnesses := make([]int, populationSize ) - callCount := 0 - exitFunc := func( g *ga.IGenome ) bool { - passedGenomeFitnesses[callCount] = (*g).GetFitness() - - callCount++ - if callCount >= numIterations { - return true - } - return false - } - - genAlgo.SimulateUntil( exitFunc ) - - t.Assert( passedGenomeFitnesses, DeepEquals, ms.LargestFitnessess ) -} - -func ( s* GeneticAlgorithmSuite ) TestShouldNotCallMaterWithGenomesFromPopulation( t *C ) { - - genAlgo := ga.NewGeneticAlgorithm() - - mateFunc := func ( a, b *ga.IGenome ) ( ga.IGenome, ga.IGenome ) { - population := genAlgo.GetPopulation() - aFound, bFound := false, false - for i, _ := range population { - if a == &population[i] { - aFound = true - if aFound && bFound { - break - } - } else if b == &population[i] { - bFound = true - if aFound && bFound { - break - } - } - } - t.Assert( aFound, IsFalse ) - t.Assert( bFound, IsFalse ) - return *a, *b - } - - m := ga.NewMater( - []ga.MaterFunctionProbability { - { P : 1, F : mateFunc }, - }, - ) - - genAlgo.Init( 10, kNumThreads ) - genAlgo.Mater = m - - numIterations := 1000 - genAlgo.SimulateUntil( helperGenerateExitFunction( numIterations ) ) -} - -type MySelectorCounter struct { - CallCount int -} - -func ( ms *MySelectorCounter ) Go( genomes []ga.IGenome, totalFitness int ) *ga.IGenome { - ms.CallCount++ - return &genomes[0] -} - -func ( s* GeneticAlgorithmSuite ) TestShouldCallSelectorAppropriately( t *C ) { - - genAlgo := ga.NewGeneticAlgorithm() - - selector := MySelectorCounter{} - genAlgo.Selector = &selector - - populationSize := 100 - genAlgo.Init( populationSize, kNumThreads ) - t.Assert( selector.CallCount, Equals, 0 ) - - numIterations := 100 - genAlgo.SimulateUntil( helperGenerateExitFunction( numIterations ) ) - t.Assert( selector.CallCount, Equals, ( populationSize * numIterations ) - populationSize ) -} - -type MySelectorPassCache struct { - PassedGenomes []*ga.IGenome -} - -func ( ms *MySelectorPassCache ) Go( genomes []ga.IGenome, totalFitness int ) *ga.IGenome { - randomGenome := &genomes[rand.Intn( len( genomes ) )] - ms.PassedGenomes = append( ms.PassedGenomes, randomGenome ) - return randomGenome -} - -type MyMaterPassCache struct { - PassedGenomes []*ga.IGenome -} - -func ( ms *MyMaterPassCache ) Go( a, b *ga.IGenome) ( ga.IGenome, ga.IGenome ) { - ms.PassedGenomes = append(ms.PassedGenomes, a) - ms.PassedGenomes = append(ms.PassedGenomes, b) - return *a, *b -} -func ( ms *MyMaterPassCache ) OnElite( *ga.IGenome ) { -} - -func ( s* GeneticAlgorithmSuite ) TestShouldPassSelectedGenomesToMater( t *C ) { - - genAlgo := ga.NewGeneticAlgorithm() - - selector := MySelectorPassCache{} - genAlgo.Selector = &selector - - mater := MyMaterPassCache{} - genAlgo.Mater = &mater - genAlgo.Simulator = &MySimulatorFitness{} - - genAlgo.Init( 100, kNumThreads ) - genAlgo.SimulateUntil( helperGenerateExitFunction( 100 ) ) - - t.Assert( len( mater.PassedGenomes ), Equals, len( selector.PassedGenomes ) ) - t.Assert( mater.PassedGenomes, DeepEquals, selector.PassedGenomes ) -} - -type MyBitsetCreateCounter struct { - NumCalls int -} - -func ( gc *MyBitsetCreateCounter ) Go() ga.Bitset { - gc.NumCalls++ - return ga.Bitset{} -} - -func ( s* GeneticAlgorithmSuite ) TestShouldCallIntoBitsetCreate( t *C ) { - - genAlgo := ga.NewGeneticAlgorithm() - - bitsetCreate := MyBitsetCreateCounter{} - genAlgo.BitsetCreate = &bitsetCreate - - numGenomes := 100 - genAlgo.Init( numGenomes, kNumThreads ) - - t.Assert( bitsetCreate.NumCalls, Equals, numGenomes ) -} - -type MyMaterPassCache2 struct { - PassedGenomes []ga.IGenome - runningFitness int -} - -func ( ms *MyMaterPassCache2 ) Go( a, b *ga.IGenome) ( ga.IGenome, ga.IGenome ) { - - g1, g2 := ga.NewGenome( ga.Bitset{} ), ga.NewGenome( ga.Bitset{} ) - - ms.PassedGenomes = append(ms.PassedGenomes, g1) - ms.PassedGenomes = append(ms.PassedGenomes, g2) - - g1.SetFitness( ms.runningFitness ) - ms.runningFitness++ - g2.SetFitness( ms.runningFitness ) - ms.runningFitness++ - - return g1, g2 -} -func ( ms *MyMaterPassCache2 ) OnElite( *ga.IGenome ) { -} - -func ( s* GeneticAlgorithmSuite ) TestShouldReplaceOldPopulationWithMatedOne( t *C ) { - - mater := MyMaterPassCache2{} - - genAlgo := ga.NewGeneticAlgorithm() - genAlgo.Mater = &mater - populationSize := 10 - genAlgo.Init( populationSize, kNumThreads ) - genAlgo.SimulateUntil( helperGenerateExitFunction( 2 ) ) - - genAlgoPopulation := genAlgo.GetPopulation() - t.Assert( mater.PassedGenomes, HasLen, populationSize ) - t.Assert( genAlgoPopulation, HasLen, populationSize ) - - for i := 0; i < populationSize; i++ { - t.Assert( mater.PassedGenomes[i].GetFitness(), Equals, genAlgoPopulation[i].GetFitness() ) - t.Assert( mater.PassedGenomes[i], Equals, genAlgoPopulation[i] ) - } -} - -type MySimulatorCallTracker struct { - NumBeginSimulationsUntilExit int - - NumBeginSimulationCalls int - NumSimulateCalls int - m sync.Mutex -} -func ( ms *MySimulatorCallTracker ) Simulate( *ga.IGenome ) { - ms.m.Lock() - ms.NumSimulateCalls++ - ms.m.Unlock() -} -func ( ms *MySimulatorCallTracker ) OnBeginSimulation() { - ms.NumBeginSimulationCalls++ -} -func ( ms *MySimulatorCallTracker ) OnEndSimulation() { -} -func ( ms *MySimulatorCallTracker ) ExitFunc( *ga.IGenome ) bool { - return ( ms.NumBeginSimulationCalls >= ms.NumBeginSimulationsUntilExit ) -} - -func ( s *GeneticAlgorithmSuite ) TestShouldSimulateUsingSimulatorExitFunction( t *C ) { - genAlgo := ga.NewGeneticAlgorithm() - - ms := MySimulatorCallTracker{} - ms.NumBeginSimulationsUntilExit = 5 - genAlgo.Simulator = &ms - t.Assert( ms.NumBeginSimulationCalls, Equals, 0 ) - t.Assert( ms.NumSimulateCalls, Equals, 0 ) - - populationSize := 100 - genAlgo.Init( populationSize, kNumThreads ); - genAlgo.Simulate() - - t.Assert( ms.NumSimulateCalls, Equals, ms.NumBeginSimulationsUntilExit * populationSize ) - t.Assert( ms.NumBeginSimulationCalls, Equals, ms.NumBeginSimulationsUntilExit ) -} \ No newline at end of file +package ga_test + +import ( + . "gopkg.in/check.v1" + + "github.com/tomcraven/goga" + // "fmt" + "math/rand" + "sync" + "time" +) + +const kNumThreads = 4 + +type GeneticAlgorithmSuite struct { +} + +var _ = Suite(&GeneticAlgorithmSuite{}) + +func helperGenerateExitFunction(numIterations int) func(*ga.IGenome) bool { + totalIterations := 0 + return func(*ga.IGenome) bool { + totalIterations++ + if totalIterations >= numIterations { + return true + } + return false + } +} + +func (s *GeneticAlgorithmSuite) TestShouldSimulateUntil(t *C) { + + callCount := 0 + exitFunc := func(g *ga.IGenome) bool { + callCount++ + return true + } + + genAlgo := ga.NewGeneticAlgorithm() + genAlgo.Init(1, kNumThreads) + ret := genAlgo.SimulateUntil(exitFunc) + t.Assert(ret, IsTrue) + t.Assert(callCount, Equals, 1) + + callCount = 0 + exitFunc2 := func(g *ga.IGenome) bool { + callCount++ + if callCount >= 2 { + return true + } + return false + } + ret = genAlgo.SimulateUntil(exitFunc2) + t.Assert(ret, IsTrue) + t.Assert(callCount, Equals, 2) +} + +func (s *GeneticAlgorithmSuite) TestShouldCallMaterAppropriately_1(t *C) { + + numCalls1 := 0 + mateFunc1 := func(a, b *ga.IGenome) (ga.IGenome, ga.IGenome) { + numCalls1++ + return *a, *b + } + + numCalls2 := 0 + mateFunc2 := func(a, b *ga.IGenome) (ga.IGenome, ga.IGenome) { + numCalls2++ + return *a, *b + } + + m := ga.NewMater( + []ga.MaterFunctionProbability{ + {P: 0.5, F: mateFunc1}, + {P: 0.75, F: mateFunc2}, + }, + ) + + genAlgo := ga.NewGeneticAlgorithm() + genAlgo.Init(2, kNumThreads) + genAlgo.Mater = m + + numIterations := 1000 + ret := genAlgo.SimulateUntil(helperGenerateExitFunction(numIterations)) + t.Assert(ret, IsTrue) + + sixtyPercent := (numIterations / 100) * 60 + fourtyPercent := (numIterations / 100) * 40 + t.Assert(numCalls1 < sixtyPercent, IsTrue, Commentf("Num calls [%v] percent [%v]", numCalls1, sixtyPercent)) + t.Assert(numCalls1 > fourtyPercent, IsTrue, Commentf("Num calls [%v] percent [%v]", numCalls1, fourtyPercent)) + + sixtyFivePercent := (numIterations / 100) * 65 + eightyFivePercent := (numIterations / 100) * 85 + t.Assert(numCalls2 < eightyFivePercent, IsTrue, Commentf("Num calls [%v] percent [%v]", numCalls2, sixtyPercent)) + t.Assert(numCalls2 > sixtyFivePercent, IsTrue, Commentf("Num calls [%v] percent [%v]", numCalls2, fourtyPercent)) +} + +func (s *GeneticAlgorithmSuite) TestShouldCallMaterAppropriately_2(t *C) { + + numCalls := 0 + mateFunc := func(a, b *ga.IGenome) (ga.IGenome, ga.IGenome) { + numCalls++ + return *a, *b + } + + m := ga.NewMater( + []ga.MaterFunctionProbability{ + {P: 1, F: mateFunc}, + }, + ) + + genAlgo := ga.NewGeneticAlgorithm() + populationSize := 100 + genAlgo.Init(populationSize, kNumThreads) + genAlgo.Mater = m + + numIterations := 1000 + genAlgo.SimulateUntil(helperGenerateExitFunction(numIterations)) + + expectedNumIterations := (numIterations * (populationSize / 2)) + expectedNumIterations -= (populationSize / 2) + t.Assert(numCalls, Equals, expectedNumIterations) +} + +func (s *GeneticAlgorithmSuite) TestShouldCallMaterAppropriately_OddSizedPopulation(t *C) { + + numCalls := 0 + mateFunc := func(a, b *ga.IGenome) (ga.IGenome, ga.IGenome) { + numCalls++ + return *a, *b + } + + m := ga.NewMater( + []ga.MaterFunctionProbability{ + {P: 1, F: mateFunc}, + }, + ) + + genAlgo := ga.NewGeneticAlgorithm() + populationSize := 99 + genAlgo.Init(populationSize, kNumThreads) + genAlgo.Mater = m + + numIterations := 1000 + genAlgo.SimulateUntil(helperGenerateExitFunction(numIterations)) + + resultantPopulationSize := len(genAlgo.GetPopulation()) + t.Assert(resultantPopulationSize, Equals, populationSize) +} + +type MyEliteConsumerCounter struct { + NumCalls int +} + +func (ec *MyEliteConsumerCounter) OnElite(g *ga.IGenome) { + ec.NumCalls++ +} + +func (s *GeneticAlgorithmSuite) TestShouldCallIntoEliteConsumer(t *C) { + + ec := MyEliteConsumerCounter{} + genAlgo := ga.NewGeneticAlgorithm() + genAlgo.Init(1, kNumThreads) + genAlgo.EliteConsumer = &ec + + numIterations := 42 + ret := genAlgo.SimulateUntil(helperGenerateExitFunction(numIterations)) + t.Assert(ret, IsTrue) + t.Assert(ec.NumCalls, Equals, numIterations) +} + +func (s *GeneticAlgorithmSuite) TestShouldNotSimulateWithNoPopulation(t *C) { + + genAlgo := ga.NewGeneticAlgorithm() + + callCount := 0 + exitFunc := func(g *ga.IGenome) bool { + callCount++ + return true + } + ret := genAlgo.SimulateUntil(exitFunc) + + t.Assert(ret, IsFalse) + t.Assert(callCount, Equals, 0) + + genAlgo.Init(0, kNumThreads) + ret = genAlgo.SimulateUntil(exitFunc) + t.Assert(ret, IsFalse) + t.Assert(callCount, Equals, 0) + + genAlgo.Init(1, kNumThreads) + ret = genAlgo.SimulateUntil(exitFunc) + t.Assert(ret, IsTrue) + t.Assert(callCount, Equals, 1) +} + +func (s *GeneticAlgorithmSuite) TestShouldGetPopulation(t *C) { + + genAlgo := ga.NewGeneticAlgorithm() + + t.Assert(genAlgo.GetPopulation(), HasLen, 0) + + genAlgo.Init(1, kNumThreads) + pop := genAlgo.GetPopulation() + t.Assert(pop, HasLen, 1) + + g := ga.NewGenome(ga.Bitset{}) + t.Assert(pop[0], FitsTypeOf, g) + + genAlgo.Init(123, kNumThreads) + t.Assert(genAlgo.GetPopulation(), HasLen, 123) + + p1 := genAlgo.GetPopulation() + p2 := genAlgo.GetPopulation() + t.Assert(len(p1), Equals, len(p2)) + for i := 0; i < len(p1); i++ { + t.Assert(p1[i], Equals, p2[i]) + } +} + +type MySimulatorCounter struct { + NumCalls int + m sync.Mutex +} + +func (ms *MySimulatorCounter) Simulate(*ga.IGenome) { + ms.m.Lock() + ms.NumCalls++ + ms.m.Unlock() +} +func (ms *MySimulatorCounter) OnBeginSimulation() { +} +func (ms *MySimulatorCounter) OnEndSimulation() { +} +func (ms *MySimulatorCounter) ExitFunc(*ga.IGenome) bool { + return false +} + +func (s *GeneticAlgorithmSuite) TestShouldSimulatePopulatonCounter(t *C) { + genAlgo := ga.NewGeneticAlgorithm() + + ms := MySimulatorCounter{} + genAlgo.Simulator = &ms + t.Assert(ms.NumCalls, Equals, 0) + + populationSize := 100 + genAlgo.Init(populationSize, kNumThreads) + + numIterations := 10 + genAlgo.SimulateUntil(helperGenerateExitFunction(numIterations)) + t.Assert(ms.NumCalls, Equals, numIterations*populationSize) +} + +type MySimulatorFitness struct { + NumIterations int + LargestFitnessess []int + + currentLargestFitness int + m sync.Mutex +} + +func (ms *MySimulatorFitness) Simulate(g *ga.IGenome) { + ms.m.Lock() + randomFitness := rand.Intn(1000) + if randomFitness > ms.currentLargestFitness { + ms.currentLargestFitness = randomFitness + } + (*g).SetFitness(randomFitness) + ms.m.Unlock() +} +func (ms *MySimulatorFitness) OnBeginSimulation() { + ms.currentLargestFitness = 0 +} +func (ms *MySimulatorFitness) OnEndSimulation() { + ms.LargestFitnessess = append(ms.LargestFitnessess, ms.currentLargestFitness) +} +func (ms *MySimulatorFitness) ExitFunc(*ga.IGenome) bool { + return false +} + +type MyEliteConsumerFitness struct { + EliteFitnesses []int +} + +func (ec *MyEliteConsumerFitness) OnElite(g *ga.IGenome) { + ec.EliteFitnesses = append(ec.EliteFitnesses, (*g).GetFitness()) +} + +func (s *GeneticAlgorithmSuite) TestShouldSimulatePopulationAndPassEliteToConsumer(t *C) { + genAlgo := ga.NewGeneticAlgorithm() + + numIterations := 100 + ms := MySimulatorFitness{NumIterations: numIterations} + genAlgo.Simulator = &ms + + ec := MyEliteConsumerFitness{} + genAlgo.EliteConsumer = &ec + + genAlgo.Init(100, kNumThreads) + + genAlgo.SimulateUntil(helperGenerateExitFunction(numIterations)) + + t.Assert(ec.EliteFitnesses, DeepEquals, ms.LargestFitnessess) +} + +type MySimulatorOrder struct { + Order []int + + BeginCalled bool + SimulateCalled bool + EndCalled bool +} + +func (ms *MySimulatorOrder) OnBeginSimulation() { + ms.Order = append(ms.Order, 1) + ms.SimulateCalled = true +} +func (ms *MySimulatorOrder) Simulate(g *ga.IGenome) { + ms.Order = append(ms.Order, 2) + ms.BeginCalled = true +} +func (ms *MySimulatorOrder) OnEndSimulation() { + ms.Order = append(ms.Order, 3) + ms.EndCalled = true +} +func (ms *MySimulatorOrder) ExitFunc(*ga.IGenome) bool { + return false +} + +func (s *GeneticAlgorithmSuite) TestShouldCallOnBeginEndSimulation(t *C) { + genAlgo := ga.NewGeneticAlgorithm() + + ms := MySimulatorOrder{} + genAlgo.Simulator = &ms + + t.Assert(ms.BeginCalled, Equals, false) + t.Assert(ms.SimulateCalled, Equals, false) + t.Assert(ms.Order, HasLen, 0) + + genAlgo.Init(1, kNumThreads) + genAlgo.SimulateUntil(helperGenerateExitFunction(1)) + + // Sleep and give time for threads to start up + time.Sleep(100 * time.Millisecond) + + t.Assert(ms.BeginCalled, Equals, true) + t.Assert(ms.SimulateCalled, Equals, true) + t.Assert(ms.Order, HasLen, 3) + t.Assert(ms.Order, DeepEquals, []int{1, 2, 3}) +} + +func (s *GeneticAlgorithmSuite) TestShouldPassEliteToExitFunc(t *C) { + genAlgo := ga.NewGeneticAlgorithm() + + numIterations := 10 + ms := MySimulatorFitness{NumIterations: numIterations} + genAlgo.Simulator = &ms + + ec := MyEliteConsumerFitness{} + genAlgo.EliteConsumer = &ec + + populationSize := 10 + genAlgo.Init(populationSize, kNumThreads) + + passedGenomeFitnesses := make([]int, populationSize) + callCount := 0 + exitFunc := func(g *ga.IGenome) bool { + passedGenomeFitnesses[callCount] = (*g).GetFitness() + + callCount++ + if callCount >= numIterations { + return true + } + return false + } + + genAlgo.SimulateUntil(exitFunc) + + t.Assert(passedGenomeFitnesses, DeepEquals, ms.LargestFitnessess) +} + +func (s *GeneticAlgorithmSuite) TestShouldNotCallMaterWithGenomesFromPopulation(t *C) { + + genAlgo := ga.NewGeneticAlgorithm() + + mateFunc := func(a, b *ga.IGenome) (ga.IGenome, ga.IGenome) { + population := genAlgo.GetPopulation() + aFound, bFound := false, false + for i := range population { + if a == &population[i] { + aFound = true + if aFound && bFound { + break + } + } else if b == &population[i] { + bFound = true + if aFound && bFound { + break + } + } + } + t.Assert(aFound, IsFalse) + t.Assert(bFound, IsFalse) + return *a, *b + } + + m := ga.NewMater( + []ga.MaterFunctionProbability{ + {P: 1, F: mateFunc}, + }, + ) + + genAlgo.Init(10, kNumThreads) + genAlgo.Mater = m + + numIterations := 1000 + genAlgo.SimulateUntil(helperGenerateExitFunction(numIterations)) +} + +type MySelectorCounter struct { + CallCount int +} + +func (ms *MySelectorCounter) Go(genomes []ga.IGenome, totalFitness int) *ga.IGenome { + ms.CallCount++ + return &genomes[0] +} + +func (s *GeneticAlgorithmSuite) TestShouldCallSelectorAppropriately(t *C) { + + genAlgo := ga.NewGeneticAlgorithm() + + selector := MySelectorCounter{} + genAlgo.Selector = &selector + + populationSize := 100 + genAlgo.Init(populationSize, kNumThreads) + t.Assert(selector.CallCount, Equals, 0) + + numIterations := 100 + genAlgo.SimulateUntil(helperGenerateExitFunction(numIterations)) + t.Assert(selector.CallCount, Equals, (populationSize*numIterations)-populationSize) +} + +type MySelectorPassCache struct { + PassedGenomes []*ga.IGenome +} + +func (ms *MySelectorPassCache) Go(genomes []ga.IGenome, totalFitness int) *ga.IGenome { + randomGenome := &genomes[rand.Intn(len(genomes))] + ms.PassedGenomes = append(ms.PassedGenomes, randomGenome) + return randomGenome +} + +type MyMaterPassCache struct { + PassedGenomes []*ga.IGenome +} + +func (ms *MyMaterPassCache) Go(a, b *ga.IGenome) (ga.IGenome, ga.IGenome) { + ms.PassedGenomes = append(ms.PassedGenomes, a) + ms.PassedGenomes = append(ms.PassedGenomes, b) + return *a, *b +} +func (ms *MyMaterPassCache) OnElite(*ga.IGenome) { +} + +func (s *GeneticAlgorithmSuite) TestShouldPassSelectedGenomesToMater(t *C) { + + genAlgo := ga.NewGeneticAlgorithm() + + selector := MySelectorPassCache{} + genAlgo.Selector = &selector + + mater := MyMaterPassCache{} + genAlgo.Mater = &mater + genAlgo.Simulator = &MySimulatorFitness{} + + genAlgo.Init(100, kNumThreads) + genAlgo.SimulateUntil(helperGenerateExitFunction(100)) + + t.Assert(len(mater.PassedGenomes), Equals, len(selector.PassedGenomes)) + t.Assert(mater.PassedGenomes, DeepEquals, selector.PassedGenomes) +} + +type MyBitsetCreateCounter struct { + NumCalls int +} + +func (gc *MyBitsetCreateCounter) Go() ga.Bitset { + gc.NumCalls++ + return ga.Bitset{} +} + +func (s *GeneticAlgorithmSuite) TestShouldCallIntoBitsetCreate(t *C) { + + genAlgo := ga.NewGeneticAlgorithm() + + bitsetCreate := MyBitsetCreateCounter{} + genAlgo.BitsetCreate = &bitsetCreate + + numGenomes := 100 + genAlgo.Init(numGenomes, kNumThreads) + + t.Assert(bitsetCreate.NumCalls, Equals, numGenomes) +} + +type MyMaterPassCache2 struct { + PassedGenomes []ga.IGenome + runningFitness int +} + +func (ms *MyMaterPassCache2) Go(a, b *ga.IGenome) (ga.IGenome, ga.IGenome) { + + g1, g2 := ga.NewGenome(ga.Bitset{}), ga.NewGenome(ga.Bitset{}) + + ms.PassedGenomes = append(ms.PassedGenomes, g1) + ms.PassedGenomes = append(ms.PassedGenomes, g2) + + g1.SetFitness(ms.runningFitness) + ms.runningFitness++ + g2.SetFitness(ms.runningFitness) + ms.runningFitness++ + + return g1, g2 +} +func (ms *MyMaterPassCache2) OnElite(*ga.IGenome) { +} + +func (s *GeneticAlgorithmSuite) TestShouldReplaceOldPopulationWithMatedOne(t *C) { + + mater := MyMaterPassCache2{} + + genAlgo := ga.NewGeneticAlgorithm() + genAlgo.Mater = &mater + populationSize := 10 + genAlgo.Init(populationSize, kNumThreads) + genAlgo.SimulateUntil(helperGenerateExitFunction(2)) + + genAlgoPopulation := genAlgo.GetPopulation() + t.Assert(mater.PassedGenomes, HasLen, populationSize) + t.Assert(genAlgoPopulation, HasLen, populationSize) + + for i := 0; i < populationSize; i++ { + t.Assert(mater.PassedGenomes[i].GetFitness(), Equals, genAlgoPopulation[i].GetFitness()) + t.Assert(mater.PassedGenomes[i], Equals, genAlgoPopulation[i]) + } +} + +type MySimulatorCallTracker struct { + NumBeginSimulationsUntilExit int + + NumBeginSimulationCalls int + NumSimulateCalls int + m sync.Mutex +} + +func (ms *MySimulatorCallTracker) Simulate(*ga.IGenome) { + ms.m.Lock() + ms.NumSimulateCalls++ + ms.m.Unlock() +} +func (ms *MySimulatorCallTracker) OnBeginSimulation() { + ms.NumBeginSimulationCalls++ +} +func (ms *MySimulatorCallTracker) OnEndSimulation() { +} +func (ms *MySimulatorCallTracker) ExitFunc(*ga.IGenome) bool { + return (ms.NumBeginSimulationCalls >= ms.NumBeginSimulationsUntilExit) +} + +func (s *GeneticAlgorithmSuite) TestShouldSimulateUsingSimulatorExitFunction(t *C) { + genAlgo := ga.NewGeneticAlgorithm() + + ms := MySimulatorCallTracker{} + ms.NumBeginSimulationsUntilExit = 5 + genAlgo.Simulator = &ms + t.Assert(ms.NumBeginSimulationCalls, Equals, 0) + t.Assert(ms.NumSimulateCalls, Equals, 0) + + populationSize := 100 + genAlgo.Init(populationSize, kNumThreads) + genAlgo.Simulate() + + t.Assert(ms.NumSimulateCalls, Equals, ms.NumBeginSimulationsUntilExit*populationSize) + t.Assert(ms.NumBeginSimulationCalls, Equals, ms.NumBeginSimulationsUntilExit) +} diff --git a/genome.go b/genome.go index e88f8cf..1814f27 100644 --- a/genome.go +++ b/genome.go @@ -1,29 +1,28 @@ - package ga type IGenome interface { GetFitness() int - SetFitness( int ) + SetFitness(int) GetBits() *Bitset } type genome struct { fitness int - bitset Bitset + bitset Bitset } -func NewGenome( bitset Bitset ) IGenome { - return &genome{ bitset : bitset } +func NewGenome(bitset Bitset) IGenome { + return &genome{bitset: bitset} } -func ( g* genome ) GetFitness() int { +func (g *genome) GetFitness() int { return g.fitness } -func ( g* genome ) SetFitness( fitness int ) { +func (g *genome) SetFitness(fitness int) { g.fitness = fitness } -func ( g* genome ) GetBits() *Bitset { +func (g *genome) GetBits() *Bitset { return &g.bitset -} \ No newline at end of file +} diff --git a/genome_test.go b/genome_test.go index 0232c91..fdee80e 100644 --- a/genome_test.go +++ b/genome_test.go @@ -1,40 +1,41 @@ - -package ga_test - -import ( - . "gopkg.in/check.v1" - - "github.com/tomcraven/goga" - ) - -type GenomeSuite struct { - genome ga.IGenome -} -func ( s *GenomeSuite ) SetUpTest( t *C ) { - s.genome = ga.NewGenome( ga.Bitset{} ) -} -func ( s *GenomeSuite ) TearDownTest( t *C ) { - s.genome = nil -} -var _ = Suite( &GenomeSuite{} ) - -func ( s *GenomeSuite ) TestShouldInstantiate( t *C ) { - // Tested as part of fixture setup -} - -func ( s *GenomeSuite ) TestShouldSetGetFitness( t *C ) { - t.Assert( s.genome.GetFitness(), Equals, 0 ) - - s.genome.SetFitness( 100 ) - t.Assert( s.genome.GetFitness(), Equals, 100 ) -} - -func ( s *GenomeSuite ) TestShouldGetBits( t *C ) { - b := ga.Bitset{} - b.Create( 10 ) - b.Set( 1, 1 ) - b.Set( 9, 1 ) - - g := ga.NewGenome( b ) - t.Assert( &b, DeepEquals, g.GetBits() ) -} \ No newline at end of file +package ga_test + +import ( + . "gopkg.in/check.v1" + + "github.com/tomcraven/goga" +) + +type GenomeSuite struct { + genome ga.IGenome +} + +func (s *GenomeSuite) SetUpTest(t *C) { + s.genome = ga.NewGenome(ga.Bitset{}) +} +func (s *GenomeSuite) TearDownTest(t *C) { + s.genome = nil +} + +var _ = Suite(&GenomeSuite{}) + +func (s *GenomeSuite) TestShouldInstantiate(t *C) { + // Tested as part of fixture setup +} + +func (s *GenomeSuite) TestShouldSetGetFitness(t *C) { + t.Assert(s.genome.GetFitness(), Equals, 0) + + s.genome.SetFitness(100) + t.Assert(s.genome.GetFitness(), Equals, 100) +} + +func (s *GenomeSuite) TestShouldGetBits(t *C) { + b := ga.Bitset{} + b.Create(10) + b.Set(1, 1) + b.Set(9, 1) + + g := ga.NewGenome(b) + t.Assert(&b, DeepEquals, g.GetBits()) +} diff --git a/ielite_consumer.go b/ielite_consumer.go index eb7d94f..2740f25 100644 --- a/ielite_consumer.go +++ b/ielite_consumer.go @@ -1,12 +1,11 @@ - package ga type IEliteConsumer interface { - OnElite( *IGenome ) + OnElite(*IGenome) } type NullEliteConsumer struct { } -func ( nec *NullEliteConsumer ) OnElite( *IGenome ) { -} \ No newline at end of file +func (nec *NullEliteConsumer) OnElite(*IGenome) { +} diff --git a/mater.go b/mater.go index 7053b26..1d608bf 100644 --- a/mater.go +++ b/mater.go @@ -1,4 +1,3 @@ - package ga import ( @@ -10,46 +9,46 @@ import ( ) type IMater interface { - Go( *IGenome, *IGenome ) ( IGenome, IGenome ) - OnElite( *IGenome ) + Go(*IGenome, *IGenome) (IGenome, IGenome) + OnElite(*IGenome) } type NullMater struct { } -func ( nm *NullMater ) Go( a, b *IGenome ) ( IGenome, IGenome ) { - return NewGenome( *(*a).GetBits() ), NewGenome( *(*b).GetBits() ) +func (nm *NullMater) Go(a, b *IGenome) (IGenome, IGenome) { + return NewGenome(*(*a).GetBits()), NewGenome(*(*b).GetBits()) } -func ( nm *NullMater ) OnElite( a *IGenome ) { +func (nm *NullMater) OnElite(a *IGenome) { } type MaterFunctionProbability struct { - P float32 - F func( *IGenome, *IGenome ) ( IGenome, IGenome ) + P float32 + F func(*IGenome, *IGenome) (IGenome, IGenome) UseElite bool } type mater struct { materConfig []MaterFunctionProbability - elite *IGenome + elite *IGenome } -func NewMater( materConfig []MaterFunctionProbability ) IMater { - return &mater { - materConfig : materConfig, +func NewMater(materConfig []MaterFunctionProbability) IMater { + return &mater{ + materConfig: materConfig, } } -func ( m *mater ) Go( g1, g2 *IGenome ) ( IGenome, IGenome ) { +func (m *mater) Go(g1, g2 *IGenome) (IGenome, IGenome) { - newG1 := NewGenome( *(*g1).GetBits() ) - newG2 := NewGenome( *(*g2).GetBits() ) + newG1 := NewGenome(*(*g1).GetBits()) + newG2 := NewGenome(*(*g2).GetBits()) for _, config := range m.materConfig { if rand.Float32() < config.P { if config.UseElite { - newG1, newG2 = config.F( &newG1, m.elite ) + newG1, newG2 = config.F(&newG1, m.elite) } else { - newG1, newG2 = config.F( &newG1, &newG2 ) + newG1, newG2 = config.F(&newG1, &newG2) } } } @@ -57,78 +56,78 @@ func ( m *mater ) Go( g1, g2 *IGenome ) ( IGenome, IGenome ) { return newG1, newG2 } -func ( m *mater ) OnElite( elite *IGenome ) { +func (m *mater) OnElite(elite *IGenome) { m.elite = elite } -func max( a, b int ) int { +func max(a, b int) int { if a > b { return a } return b } -func min( a, b int ) int { +func min(a, b int) int { if a < b { return a } return b } -func OnePointCrossover( g1, g2 *IGenome ) ( IGenome, IGenome ) { +func OnePointCrossover(g1, g2 *IGenome) (IGenome, IGenome) { g1Bits, g2Bits := (*g1).GetBits(), (*g2).GetBits() b1, b2 := Bitset{}, Bitset{} g1Size := g1Bits.GetSize() g2Size := g2Bits.GetSize() - b1.Create( g1Size ) - b2.Create( g2Size ) + b1.Create(g1Size) + b2.Create(g2Size) - maxSize := max( g1Size, g2Size ) - minSize := min( g1Size, g2Size ) - randIndex := rand.Intn( minSize - 1 ) + 1 + maxSize := max(g1Size, g2Size) + minSize := min(g1Size, g2Size) + randIndex := rand.Intn(minSize-1) + 1 for i := 0; i < randIndex; i++ { - b1.Set( i, g1Bits.Get( i ) ) - b2.Set( i, g2Bits.Get( i ) ) + b1.Set(i, g1Bits.Get(i)) + b2.Set(i, g2Bits.Get(i)) } for i := randIndex; i < minSize; i++ { - b2.Set( i, g1Bits.Get( i ) ) - b1.Set( i, g2Bits.Get( i ) ) + b2.Set(i, g1Bits.Get(i)) + b1.Set(i, g2Bits.Get(i)) } if g1Size > g2Size { for i := minSize; i < maxSize; i++ { - b2.Set( i, g1Bits.Get( i ) ) + b2.Set(i, g1Bits.Get(i)) } } else { for i := minSize; i < maxSize; i++ { - b1.Set( i, g2Bits.Get( i ) ) + b1.Set(i, g2Bits.Get(i)) } } - return NewGenome( b1 ), NewGenome( b2 ) + return NewGenome(b1), NewGenome(b2) } -func TwoPointCrossover( g1, g2 *IGenome ) ( IGenome, IGenome ) { +func TwoPointCrossover(g1, g2 *IGenome) (IGenome, IGenome) { g1Bits, g2Bits := (*g1).GetBits(), (*g2).GetBits() b1, b2 := Bitset{}, Bitset{} g1Size := g1Bits.GetSize() g2Size := g2Bits.GetSize() - b1.Create( g1Size ) - b2.Create( g2Size ) + b1.Create(g1Size) + b2.Create(g2Size) - maxSize := max( g1Size, g2Size ) - minSize := min( g1Size, g2Size ) - randIndex1 := rand.Intn( minSize - 1 ) + 1 + maxSize := max(g1Size, g2Size) + minSize := min(g1Size, g2Size) + randIndex1 := rand.Intn(minSize-1) + 1 randIndex2 := randIndex1 for randIndex1 == randIndex2 { - randIndex2 = rand.Intn( minSize - 1 ) + 1 + randIndex2 = rand.Intn(minSize-1) + 1 } // Note: cannot be same value @@ -137,74 +136,74 @@ func TwoPointCrossover( g1, g2 *IGenome ) ( IGenome, IGenome ) { } for i := 0; i < randIndex1; i++ { - b1.Set( i, g1Bits.Get( i ) ) - b2.Set( i, g2Bits.Get( i ) ) + b1.Set(i, g1Bits.Get(i)) + b2.Set(i, g2Bits.Get(i)) } for i := randIndex1; i < randIndex2; i++ { - b2.Set( i, g1Bits.Get( i ) ) - b1.Set( i, g2Bits.Get( i ) ) + b2.Set(i, g1Bits.Get(i)) + b1.Set(i, g2Bits.Get(i)) } for i := randIndex2; i < minSize; i++ { - b1.Set( i, g1Bits.Get( i ) ) - b2.Set( i, g2Bits.Get( i ) ) + b1.Set(i, g1Bits.Get(i)) + b2.Set(i, g2Bits.Get(i)) } if g1Size > g2Size { for i := minSize; i < maxSize; i++ { - b2.Set( i, g1Bits.Get( i ) ) + b2.Set(i, g1Bits.Get(i)) } } else { for i := minSize; i < maxSize; i++ { - b1.Set( i, g2Bits.Get( i ) ) + b1.Set(i, g2Bits.Get(i)) } } - return NewGenome( b1 ), NewGenome( b2 ) + return NewGenome(b1), NewGenome(b2) } -func UniformCrossover( g1, g2 *IGenome ) ( IGenome, IGenome ) { +func UniformCrossover(g1, g2 *IGenome) (IGenome, IGenome) { g1Bits, g2Bits := (*g1).GetBits(), (*g2).GetBits() b1, b2 := Bitset{}, Bitset{} g1Size := g1Bits.GetSize() g2Size := g2Bits.GetSize() - b1.Create( g1Size ) - b2.Create( g2Size ) + b1.Create(g1Size) + b2.Create(g2Size) - maxSize := max( g1Size, g2Size ) - minSize := min( g1Size, g2Size ) + maxSize := max(g1Size, g2Size) + minSize := min(g1Size, g2Size) for i := 0; i < minSize; i++ { if rand.Float32() > 0.5 { - b1.Set( i, g1Bits.Get( i ) ) - b2.Set( i, g2Bits.Get( i ) ) + b1.Set(i, g1Bits.Get(i)) + b2.Set(i, g2Bits.Get(i)) } else { - b2.Set( i, g1Bits.Get( i ) ) - b1.Set( i, g2Bits.Get( i ) ) + b2.Set(i, g1Bits.Get(i)) + b1.Set(i, g2Bits.Get(i)) } } if g1Size > g2Size { for i := minSize; i < maxSize; i++ { - b2.Set( i, g1Bits.Get( i ) ) + b2.Set(i, g1Bits.Get(i)) } } else { for i := minSize; i < maxSize; i++ { - b1.Set( i, g2Bits.Get( i ) ) + b1.Set(i, g2Bits.Get(i)) } } - return NewGenome( b1 ), NewGenome( b2 ) + return NewGenome(b1), NewGenome(b2) } -func Mutate( g1, g2 *IGenome ) ( IGenome, IGenome ) { +func Mutate(g1, g2 *IGenome) (IGenome, IGenome) { g1BitsOrig := (*g1).GetBits() - g1Bits :=g1BitsOrig.CreateCopy() - randomBit := rand.Intn( g1Bits.GetSize() ) - g1Bits.Set( randomBit, 1 - g1Bits.Get( randomBit ) ) + g1Bits := g1BitsOrig.CreateCopy() + randomBit := rand.Intn(g1Bits.GetSize()) + g1Bits.Set(randomBit, 1-g1Bits.Get(randomBit)) - return NewGenome( g1Bits ), NewGenome( *(*g2).GetBits() ) -} \ No newline at end of file + return NewGenome(g1Bits), NewGenome(*(*g2).GetBits()) +} diff --git a/mater_test.go b/mater_test.go index fa97690..2b829e2 100644 --- a/mater_test.go +++ b/mater_test.go @@ -1,402 +1,403 @@ - -package ga_test - -import ( - . "gopkg.in/check.v1" - - "github.com/tomcraven/goga" - // "fmt" - ) - -type MaterSuite struct { - mater ga.IMater -} -func ( s *MaterSuite ) SetUpTest( t *C ) { - s.mater = ga.NewMater( []ga.MaterFunctionProbability{} ) -} -func ( s *MaterSuite ) TearDownTest( t *C ) { - s.mater = nil -} -var _ = Suite( &MaterSuite{} ) - -func ( s *MaterSuite ) TestShouldInstantiate( t *C ) { - // Tested as part of fixture -} - -func ( s *MaterSuite ) TestGoShouldAccept2GenomePointers( t *C ) { - g1, g2 := ga.NewGenome( ga.Bitset{} ), ga.NewGenome( ga.Bitset{} ) - s.mater.Go( &g1, &g2 ) -} - -func ( s *MaterSuite ) TestGoShouldReturn2NewGenomes( t *C ) { - - b1, b2 := ga.Bitset{}, ga.Bitset{} - b1.Create( 10 ) - b2.Create( 10 ) - b1.SetAll( 0 ) - b2.SetAll( 1 ) - - g1, g2 := ga.NewGenome( b1 ), ga.NewGenome( b2 ) - t.Assert( g1, Not( DeepEquals ), g2 ) - - c1, c2 := s.mater.Go( &g1, &g2 ) - - var iGenome ga.IGenome - t.Assert( c1, Implements, &iGenome ) - t.Assert( c2, Implements, &iGenome ) - - t.Assert( g1, DeepEquals, c1 ) - t.Assert( g2, DeepEquals, c2 ) -} - -func ( s *MaterSuite ) TestShouldOnePointCrossover_DifferentBitset( t *C ) { - - for i := 0; i < 100; i ++ { - b1, b2 := ga.Bitset{}, ga.Bitset{} - genomeSize := 10 - b1.Create( genomeSize ) - b2.Create( genomeSize ) - b1.SetAll( 0 ) - b2.SetAll( 1 ) - - g1, g2 := ga.NewGenome( b1 ), ga.NewGenome( b2 ) - c1, c2 := ga.OnePointCrossover( &g1, &g2 ) - - var iGenome ga.IGenome - t.Assert( c1, Implements, &iGenome ) - t.Assert( c2, Implements, &iGenome ) - - t.Assert( g1, Not( DeepEquals ), c1 ) - t.Assert( g1, Not( DeepEquals ), c2 ) - t.Assert( g2, Not( DeepEquals ), c1 ) - t.Assert( g2, Not( DeepEquals ), c2 ) - - crossoverPoints := 0 - c1Bits, c2Bits := c1.GetBits(), c2.GetBits() - startingBitValue := c1Bits.Get( 0 ) - for i := 0; i < genomeSize; i++ { - t.Assert( c1Bits.Get( i ), Not( Equals ), c2Bits.Get( i ), Commentf( "Index [%v]", i ) ) - - // Find the crossover point - if ( startingBitValue != c1Bits.Get( i ) ) { - crossoverPoints++; - startingBitValue = c1Bits.Get( i ) - } - } - t.Assert( crossoverPoints, Equals, 1 ) - } -} - -func ( s *MaterSuite ) TestShouldTwoPointCrossOver_DifferentBitset( t *C ) { - - for i := 0; i < 100; i ++ { - b1, b2 := ga.Bitset{}, ga.Bitset{} - genomeSize := 10 - b1.Create( genomeSize ) - b2.Create( genomeSize ) - b1.SetAll( 0 ) - b2.SetAll( 1 ) - - g1, g2 := ga.NewGenome( b1 ), ga.NewGenome( b2 ) - c1, c2 := ga.TwoPointCrossover( &g1, &g2 ) - - var iGenome ga.IGenome - t.Assert( c1, Implements, &iGenome ) - t.Assert( c2, Implements, &iGenome ) - - t.Assert( g1, Not( DeepEquals ), c1 ) - t.Assert( g1, Not( DeepEquals ), c2 ) - t.Assert( g2, Not( DeepEquals ), c1 ) - t.Assert( g2, Not( DeepEquals ), c2 ) - - crossoverPoints := 0 - c1Bits, c2Bits := c1.GetBits(), c2.GetBits() - startingBitValue := c1Bits.Get( 0 ) - for i := 0; i < genomeSize; i++ { - t.Assert( c1Bits.Get( i ), Not( Equals ), c2Bits.Get( i ), Commentf( "Index [%v]", i ) ) - - // Find the crossover point - if ( startingBitValue != c1Bits.Get( i ) ) { - crossoverPoints++; - startingBitValue = c1Bits.Get( i ) - } - } - t.Assert( crossoverPoints, Equals, 2 ) - } -} - -func ( s *MaterSuite ) TestShouldUniformCrossover( t *C ) { - - for i := 0; i < 10; i ++ { - b1, b2 := ga.Bitset{}, ga.Bitset{} - genomeSize := 1000 - b1.Create( genomeSize ) - b2.Create( genomeSize ) - b1.SetAll( 0 ) - b2.SetAll( 1 ) - - g1, g2 := ga.NewGenome( b1 ), ga.NewGenome( b2 ) - c1, c2 := ga.UniformCrossover( &g1, &g2 ) - - c1Bits, c2Bits := c1.GetBits(), c2.GetBits() - crossoverPoints := 0 - startingBitValue := c1Bits.Get( 0 ) - for i := 0; i < genomeSize; i++ { - t.Assert( c1Bits.Get( i ), Not( Equals ), c2Bits.Get( i ), Commentf( "Index [%v]", i ) ) - - // Find the crossover point - if ( startingBitValue != c1Bits.Get( i ) ) { - crossoverPoints++; - startingBitValue = c1Bits.Get( i ) - } - } - - sixtyPercent := ( genomeSize / 100 ) * 60 - fourtyPercent := ( genomeSize / 100 ) * 40 - t.Assert( crossoverPoints > fourtyPercent, IsTrue ); - t.Assert( crossoverPoints < sixtyPercent, IsTrue ); - } -} - -func ( s *MaterSuite ) TestShouldOnePointCrossover_DifferentSizedBitsets( t *C ) { - - for i := 0; i < 100; i++ { - b1, b2 := ga.Bitset{}, ga.Bitset{} - genomeSize1 := 10 - genomeSize2 := 5 - b1.Create( genomeSize1 ) - b2.Create( genomeSize2 ) - b1.SetAll( 0 ) - b2.SetAll( 1 ) - - g1, g2 := ga.NewGenome( b1 ), ga.NewGenome( b2 ) - c1, c2 := ga.OnePointCrossover( &g1, &g2 ) - - c1Bits, c2Bits := c1.GetBits(), c2.GetBits() - oneHasSize10 := ( c1Bits.GetSize() == 10 ) || ( c2Bits.GetSize() == 10 ) - t.Assert( oneHasSize10, IsTrue ) - oneHasSize5 := ( c1Bits.GetSize() == 5 ) || ( c2Bits.GetSize() == 5 ) - t.Assert( oneHasSize5, IsTrue ) - } - - for i := 0; i < 100; i++ { - b1, b2 := ga.Bitset{}, ga.Bitset{} - genomeSize1 := 5 - genomeSize2 := 10 - b1.Create( genomeSize1 ) - b2.Create( genomeSize2 ) - b1.SetAll( 0 ) - b2.SetAll( 1 ) - - g1, g2 := ga.NewGenome( b1 ), ga.NewGenome( b2 ) - c1, c2 := ga.OnePointCrossover( &g1, &g2 ) - - c1Bits, c2Bits := c1.GetBits(), c2.GetBits() - oneHasSize10 := ( c1Bits.GetSize() == 10 ) || ( c2Bits.GetSize() == 10 ) - t.Assert( oneHasSize10, IsTrue ) - oneHasSize5 := ( c1Bits.GetSize() == 5 ) || ( c2Bits.GetSize() == 5 ) - t.Assert( oneHasSize5, IsTrue ) - } -} - -func ( s *MaterSuite ) TestShouldTwoPointCrossover_DifferentSizedBitsets( t *C ) { - - for i := 0; i < 100; i++ { - b1, b2 := ga.Bitset{}, ga.Bitset{} - genomeSize1 := 10 - genomeSize2 := 5 - b1.Create( genomeSize1 ) - b2.Create( genomeSize2 ) - b1.SetAll( 0 ) - b2.SetAll( 1 ) - - g1, g2 := ga.NewGenome( b1 ), ga.NewGenome( b2 ) - c1, c2 := ga.TwoPointCrossover( &g1, &g2 ) - - c1Bits, c2Bits := c1.GetBits(), c2.GetBits() - - oneHasSize10 := ( c1Bits.GetSize() == 10 ) || ( c2Bits.GetSize() == 10 ) - t.Assert( oneHasSize10, IsTrue ) - oneHasSize5 := ( c1Bits.GetSize() == 5 ) || ( c2Bits.GetSize() == 5 ) - t.Assert( oneHasSize5, IsTrue ) - } - - for i := 0; i < 100; i++ { - b1, b2 := ga.Bitset{}, ga.Bitset{} - genomeSize1 := 5 - genomeSize2 := 10 - b1.Create( genomeSize1 ) - b2.Create( genomeSize2 ) - b1.SetAll( 0 ) - b2.SetAll( 1 ) - - g1, g2 := ga.NewGenome( b1 ), ga.NewGenome( b2 ) - c1, c2 := ga.TwoPointCrossover( &g1, &g2 ) - - c1Bits, c2Bits := c1.GetBits(), c2.GetBits() - - oneHasSize10 := ( c1Bits.GetSize() == 10 ) || ( c2Bits.GetSize() == 10 ) - t.Assert( oneHasSize10, IsTrue ) - oneHasSize5 := ( c1Bits.GetSize() == 5 ) || ( c2Bits.GetSize() == 5 ) - t.Assert( oneHasSize5, IsTrue ) - } -} - -func ( s *MaterSuite ) TestShouldUniformCrossover_DifferentSizedBitsets( t *C ) { - - for i := 0; i < 10; i ++ { - b1, b2 := ga.Bitset{}, ga.Bitset{} - genomeSize1 := 20 - genomeSize2 := 10 - b1.Create( genomeSize1 ) - b2.Create( genomeSize2 ) - b1.SetAll( 0 ) - b2.SetAll( 1 ) - - g1, g2 := ga.NewGenome( b1 ), ga.NewGenome( b2 ) - c1, c2 := ga.UniformCrossover( &g1, &g2 ) - - c1Bits, c2Bits := c1.GetBits(), c2.GetBits() - oneSizedGenomeSize1 := ( c1Bits.GetSize() == genomeSize1 ) || ( c2Bits.GetSize() == genomeSize1 ) - t.Assert( oneSizedGenomeSize1, IsTrue ) - oneSizedGenomeSize2 := ( c1Bits.GetSize() == genomeSize2 ) || ( c2Bits.GetSize() == genomeSize2 ) - t.Assert( oneSizedGenomeSize2, IsTrue ) - } - - for i := 0; i < 10; i ++ { - b1, b2 := ga.Bitset{}, ga.Bitset{} - genomeSize1 := 10 - genomeSize2 := 20 - b1.Create( genomeSize1 ) - b2.Create( genomeSize2 ) - b1.SetAll( 0 ) - b2.SetAll( 1 ) - - g1, g2 := ga.NewGenome( b1 ), ga.NewGenome( b2 ) - c1, c2 := ga.UniformCrossover( &g1, &g2 ) - - c1Bits, c2Bits := c1.GetBits(), c2.GetBits() - oneSizedGenomeSize1 := ( c1Bits.GetSize() == genomeSize1 ) || ( c2Bits.GetSize() == genomeSize1 ) - t.Assert( oneSizedGenomeSize1, IsTrue ) - oneSizedGenomeSize2 := ( c1Bits.GetSize() == genomeSize2 ) || ( c2Bits.GetSize() == genomeSize2 ) - t.Assert( oneSizedGenomeSize2, IsTrue ) - } -} - -func (s *MaterSuite ) TestShouldConfig_Single( t *C ) { - - numCalls := 0 - myFunc := func ( a, b *ga.IGenome ) ( ga.IGenome, ga.IGenome ) { - numCalls++ - return *a, *b - } - - m := ga.NewMater( - []ga.MaterFunctionProbability { - { P : 1.0, F : myFunc }, - }, - ) - - numIterations := 100 - b1, b2 := ga.Bitset{}, ga.Bitset{} - b1.Create( 10 ) - b2.Create( 10 ) - for i := 0; i < numIterations; i++ { - g1, g2 := ga.NewGenome( b1 ), ga.NewGenome( b2 ) - m.Go( &g1, &g2 ) - } - - t.Assert( numCalls, Equals, numIterations ) -} - -func (s *MaterSuite ) TestShouldConfig_Multiple ( t *C ) { - - for i := 0; i < 100; i++ { - numCalls1 := 0 - numCalls2 := 0 - myFunc1 := func ( a, b *ga.IGenome ) ( ga.IGenome, ga.IGenome ) { - numCalls1++ - return *a, *b - } - myFunc2 := func ( a, b *ga.IGenome ) ( ga.IGenome, ga.IGenome ) { - numCalls2++ - return *a, *b - } - - m := ga.NewMater( - []ga.MaterFunctionProbability { - { P : 0.5, F : myFunc1 }, - { P : 0.5, F : myFunc2 }, - }, - ) - - numIterations := 1000 - b1, b2 := ga.Bitset{}, ga.Bitset{} - b1.Create( 10 ) - b2.Create( 10 ) - for i := 0; i < numIterations; i++ { - g1, g2 := ga.NewGenome( b1 ), ga.NewGenome( b2 ) - m.Go( &g1, &g2 ) - } - - sixtyPercent := ( numIterations / 100 ) * 60 - fourtyPercent := ( numIterations / 100 ) * 40 - t.Assert( numCalls1 < sixtyPercent, IsTrue, Commentf( "Num calls [%v] sixty percent [%v]", numCalls1, sixtyPercent ) ) - t.Assert( numCalls2 < sixtyPercent, IsTrue, Commentf( "Num calls [%v] sixty percent [%v]", numCalls2, sixtyPercent ) ) - t.Assert( numCalls1 > fourtyPercent, IsTrue, Commentf( "Num calls [%v] fourty percent [%v]", numCalls1, fourtyPercent ) ) - t.Assert( numCalls2 > fourtyPercent, IsTrue, Commentf( "Num calls [%v] fourty percent [%v]", numCalls2, fourtyPercent ) ) - } -} - -func ( s *MaterSuite ) TestShouldMutate( t *C ) { - - genomeSize := 10 - for i := 0; i < 100; i ++ { - b1 := ga.Bitset{} - b1.Create( genomeSize ) - b1.SetAll( 0 ) - - g1, g2 := ga.NewGenome( b1 ), ga.NewGenome( b1 ) - c1, c2 := ga.Mutate( &g1, &g2 ) - - var iGenome ga.IGenome - t.Assert( c1, Implements, &iGenome ) - t.Assert( c2, Implements, &iGenome ) - - differringPointsC1 := 0 - differringPointsC2 := 0 - c1Bits, c2Bits := c1.GetBits(), c2.GetBits() - for i := 0; i < genomeSize; i++ { - if c1Bits.Get( i ) != b1.Get( i ) { - differringPointsC1++ - } - if c2Bits.Get( i ) != b1.Get( i ) { - differringPointsC2++ - } - } - oneIsDifferent := ( differringPointsC1 == 1 ) || ( differringPointsC2 == 1 ) - bothDiffernet := ( differringPointsC1 == 1 ) && ( differringPointsC2 == 1 ) - t.Assert( oneIsDifferent, IsTrue ) - t.Assert( bothDiffernet, IsFalse ) - } -} - -func (s *MaterSuite ) TestShouldUseEliteFromConfigSettings( t *C ) { - - elite := ga.NewGenome( ga.Bitset{} ) - myFunc := func ( a, b *ga.IGenome ) ( ga.IGenome, ga.IGenome ) { - t.Assert( b, Equals, &elite ) - return *a, *b - } - - m := ga.NewMater( - []ga.MaterFunctionProbability { - { P : 1.0, F : myFunc, UseElite : true }, - }, - ) - - m.OnElite( &elite ) - - g1, g2 := ga.NewGenome( ga.Bitset{} ), ga.NewGenome( ga.Bitset{} ) - m.Go( &g1, &g2 ) -} \ No newline at end of file +package ga_test + +import ( + . "gopkg.in/check.v1" + + "github.com/tomcraven/goga" + // "fmt" +) + +type MaterSuite struct { + mater ga.IMater +} + +func (s *MaterSuite) SetUpTest(t *C) { + s.mater = ga.NewMater([]ga.MaterFunctionProbability{}) +} +func (s *MaterSuite) TearDownTest(t *C) { + s.mater = nil +} + +var _ = Suite(&MaterSuite{}) + +func (s *MaterSuite) TestShouldInstantiate(t *C) { + // Tested as part of fixture +} + +func (s *MaterSuite) TestGoShouldAccept2GenomePointers(t *C) { + g1, g2 := ga.NewGenome(ga.Bitset{}), ga.NewGenome(ga.Bitset{}) + s.mater.Go(&g1, &g2) +} + +func (s *MaterSuite) TestGoShouldReturn2NewGenomes(t *C) { + + b1, b2 := ga.Bitset{}, ga.Bitset{} + b1.Create(10) + b2.Create(10) + b1.SetAll(0) + b2.SetAll(1) + + g1, g2 := ga.NewGenome(b1), ga.NewGenome(b2) + t.Assert(g1, Not(DeepEquals), g2) + + c1, c2 := s.mater.Go(&g1, &g2) + + var iGenome ga.IGenome + t.Assert(c1, Implements, &iGenome) + t.Assert(c2, Implements, &iGenome) + + t.Assert(g1, DeepEquals, c1) + t.Assert(g2, DeepEquals, c2) +} + +func (s *MaterSuite) TestShouldOnePointCrossover_DifferentBitset(t *C) { + + for i := 0; i < 100; i++ { + b1, b2 := ga.Bitset{}, ga.Bitset{} + genomeSize := 10 + b1.Create(genomeSize) + b2.Create(genomeSize) + b1.SetAll(0) + b2.SetAll(1) + + g1, g2 := ga.NewGenome(b1), ga.NewGenome(b2) + c1, c2 := ga.OnePointCrossover(&g1, &g2) + + var iGenome ga.IGenome + t.Assert(c1, Implements, &iGenome) + t.Assert(c2, Implements, &iGenome) + + t.Assert(g1, Not(DeepEquals), c1) + t.Assert(g1, Not(DeepEquals), c2) + t.Assert(g2, Not(DeepEquals), c1) + t.Assert(g2, Not(DeepEquals), c2) + + crossoverPoints := 0 + c1Bits, c2Bits := c1.GetBits(), c2.GetBits() + startingBitValue := c1Bits.Get(0) + for i := 0; i < genomeSize; i++ { + t.Assert(c1Bits.Get(i), Not(Equals), c2Bits.Get(i), Commentf("Index [%v]", i)) + + // Find the crossover point + if startingBitValue != c1Bits.Get(i) { + crossoverPoints++ + startingBitValue = c1Bits.Get(i) + } + } + t.Assert(crossoverPoints, Equals, 1) + } +} + +func (s *MaterSuite) TestShouldTwoPointCrossOver_DifferentBitset(t *C) { + + for i := 0; i < 100; i++ { + b1, b2 := ga.Bitset{}, ga.Bitset{} + genomeSize := 10 + b1.Create(genomeSize) + b2.Create(genomeSize) + b1.SetAll(0) + b2.SetAll(1) + + g1, g2 := ga.NewGenome(b1), ga.NewGenome(b2) + c1, c2 := ga.TwoPointCrossover(&g1, &g2) + + var iGenome ga.IGenome + t.Assert(c1, Implements, &iGenome) + t.Assert(c2, Implements, &iGenome) + + t.Assert(g1, Not(DeepEquals), c1) + t.Assert(g1, Not(DeepEquals), c2) + t.Assert(g2, Not(DeepEquals), c1) + t.Assert(g2, Not(DeepEquals), c2) + + crossoverPoints := 0 + c1Bits, c2Bits := c1.GetBits(), c2.GetBits() + startingBitValue := c1Bits.Get(0) + for i := 0; i < genomeSize; i++ { + t.Assert(c1Bits.Get(i), Not(Equals), c2Bits.Get(i), Commentf("Index [%v]", i)) + + // Find the crossover point + if startingBitValue != c1Bits.Get(i) { + crossoverPoints++ + startingBitValue = c1Bits.Get(i) + } + } + t.Assert(crossoverPoints, Equals, 2) + } +} + +func (s *MaterSuite) TestShouldUniformCrossover(t *C) { + + for i := 0; i < 10; i++ { + b1, b2 := ga.Bitset{}, ga.Bitset{} + genomeSize := 1000 + b1.Create(genomeSize) + b2.Create(genomeSize) + b1.SetAll(0) + b2.SetAll(1) + + g1, g2 := ga.NewGenome(b1), ga.NewGenome(b2) + c1, c2 := ga.UniformCrossover(&g1, &g2) + + c1Bits, c2Bits := c1.GetBits(), c2.GetBits() + crossoverPoints := 0 + startingBitValue := c1Bits.Get(0) + for i := 0; i < genomeSize; i++ { + t.Assert(c1Bits.Get(i), Not(Equals), c2Bits.Get(i), Commentf("Index [%v]", i)) + + // Find the crossover point + if startingBitValue != c1Bits.Get(i) { + crossoverPoints++ + startingBitValue = c1Bits.Get(i) + } + } + + sixtyPercent := (genomeSize / 100) * 60 + fourtyPercent := (genomeSize / 100) * 40 + t.Assert(crossoverPoints > fourtyPercent, IsTrue) + t.Assert(crossoverPoints < sixtyPercent, IsTrue) + } +} + +func (s *MaterSuite) TestShouldOnePointCrossover_DifferentSizedBitsets(t *C) { + + for i := 0; i < 100; i++ { + b1, b2 := ga.Bitset{}, ga.Bitset{} + genomeSize1 := 10 + genomeSize2 := 5 + b1.Create(genomeSize1) + b2.Create(genomeSize2) + b1.SetAll(0) + b2.SetAll(1) + + g1, g2 := ga.NewGenome(b1), ga.NewGenome(b2) + c1, c2 := ga.OnePointCrossover(&g1, &g2) + + c1Bits, c2Bits := c1.GetBits(), c2.GetBits() + oneHasSize10 := (c1Bits.GetSize() == 10) || (c2Bits.GetSize() == 10) + t.Assert(oneHasSize10, IsTrue) + oneHasSize5 := (c1Bits.GetSize() == 5) || (c2Bits.GetSize() == 5) + t.Assert(oneHasSize5, IsTrue) + } + + for i := 0; i < 100; i++ { + b1, b2 := ga.Bitset{}, ga.Bitset{} + genomeSize1 := 5 + genomeSize2 := 10 + b1.Create(genomeSize1) + b2.Create(genomeSize2) + b1.SetAll(0) + b2.SetAll(1) + + g1, g2 := ga.NewGenome(b1), ga.NewGenome(b2) + c1, c2 := ga.OnePointCrossover(&g1, &g2) + + c1Bits, c2Bits := c1.GetBits(), c2.GetBits() + oneHasSize10 := (c1Bits.GetSize() == 10) || (c2Bits.GetSize() == 10) + t.Assert(oneHasSize10, IsTrue) + oneHasSize5 := (c1Bits.GetSize() == 5) || (c2Bits.GetSize() == 5) + t.Assert(oneHasSize5, IsTrue) + } +} + +func (s *MaterSuite) TestShouldTwoPointCrossover_DifferentSizedBitsets(t *C) { + + for i := 0; i < 100; i++ { + b1, b2 := ga.Bitset{}, ga.Bitset{} + genomeSize1 := 10 + genomeSize2 := 5 + b1.Create(genomeSize1) + b2.Create(genomeSize2) + b1.SetAll(0) + b2.SetAll(1) + + g1, g2 := ga.NewGenome(b1), ga.NewGenome(b2) + c1, c2 := ga.TwoPointCrossover(&g1, &g2) + + c1Bits, c2Bits := c1.GetBits(), c2.GetBits() + + oneHasSize10 := (c1Bits.GetSize() == 10) || (c2Bits.GetSize() == 10) + t.Assert(oneHasSize10, IsTrue) + oneHasSize5 := (c1Bits.GetSize() == 5) || (c2Bits.GetSize() == 5) + t.Assert(oneHasSize5, IsTrue) + } + + for i := 0; i < 100; i++ { + b1, b2 := ga.Bitset{}, ga.Bitset{} + genomeSize1 := 5 + genomeSize2 := 10 + b1.Create(genomeSize1) + b2.Create(genomeSize2) + b1.SetAll(0) + b2.SetAll(1) + + g1, g2 := ga.NewGenome(b1), ga.NewGenome(b2) + c1, c2 := ga.TwoPointCrossover(&g1, &g2) + + c1Bits, c2Bits := c1.GetBits(), c2.GetBits() + + oneHasSize10 := (c1Bits.GetSize() == 10) || (c2Bits.GetSize() == 10) + t.Assert(oneHasSize10, IsTrue) + oneHasSize5 := (c1Bits.GetSize() == 5) || (c2Bits.GetSize() == 5) + t.Assert(oneHasSize5, IsTrue) + } +} + +func (s *MaterSuite) TestShouldUniformCrossover_DifferentSizedBitsets(t *C) { + + for i := 0; i < 10; i++ { + b1, b2 := ga.Bitset{}, ga.Bitset{} + genomeSize1 := 20 + genomeSize2 := 10 + b1.Create(genomeSize1) + b2.Create(genomeSize2) + b1.SetAll(0) + b2.SetAll(1) + + g1, g2 := ga.NewGenome(b1), ga.NewGenome(b2) + c1, c2 := ga.UniformCrossover(&g1, &g2) + + c1Bits, c2Bits := c1.GetBits(), c2.GetBits() + oneSizedGenomeSize1 := (c1Bits.GetSize() == genomeSize1) || (c2Bits.GetSize() == genomeSize1) + t.Assert(oneSizedGenomeSize1, IsTrue) + oneSizedGenomeSize2 := (c1Bits.GetSize() == genomeSize2) || (c2Bits.GetSize() == genomeSize2) + t.Assert(oneSizedGenomeSize2, IsTrue) + } + + for i := 0; i < 10; i++ { + b1, b2 := ga.Bitset{}, ga.Bitset{} + genomeSize1 := 10 + genomeSize2 := 20 + b1.Create(genomeSize1) + b2.Create(genomeSize2) + b1.SetAll(0) + b2.SetAll(1) + + g1, g2 := ga.NewGenome(b1), ga.NewGenome(b2) + c1, c2 := ga.UniformCrossover(&g1, &g2) + + c1Bits, c2Bits := c1.GetBits(), c2.GetBits() + oneSizedGenomeSize1 := (c1Bits.GetSize() == genomeSize1) || (c2Bits.GetSize() == genomeSize1) + t.Assert(oneSizedGenomeSize1, IsTrue) + oneSizedGenomeSize2 := (c1Bits.GetSize() == genomeSize2) || (c2Bits.GetSize() == genomeSize2) + t.Assert(oneSizedGenomeSize2, IsTrue) + } +} + +func (s *MaterSuite) TestShouldConfig_Single(t *C) { + + numCalls := 0 + myFunc := func(a, b *ga.IGenome) (ga.IGenome, ga.IGenome) { + numCalls++ + return *a, *b + } + + m := ga.NewMater( + []ga.MaterFunctionProbability{ + {P: 1.0, F: myFunc}, + }, + ) + + numIterations := 100 + b1, b2 := ga.Bitset{}, ga.Bitset{} + b1.Create(10) + b2.Create(10) + for i := 0; i < numIterations; i++ { + g1, g2 := ga.NewGenome(b1), ga.NewGenome(b2) + m.Go(&g1, &g2) + } + + t.Assert(numCalls, Equals, numIterations) +} + +func (s *MaterSuite) TestShouldConfig_Multiple(t *C) { + + for i := 0; i < 100; i++ { + numCalls1 := 0 + numCalls2 := 0 + myFunc1 := func(a, b *ga.IGenome) (ga.IGenome, ga.IGenome) { + numCalls1++ + return *a, *b + } + myFunc2 := func(a, b *ga.IGenome) (ga.IGenome, ga.IGenome) { + numCalls2++ + return *a, *b + } + + m := ga.NewMater( + []ga.MaterFunctionProbability{ + {P: 0.5, F: myFunc1}, + {P: 0.5, F: myFunc2}, + }, + ) + + numIterations := 1000 + b1, b2 := ga.Bitset{}, ga.Bitset{} + b1.Create(10) + b2.Create(10) + for i := 0; i < numIterations; i++ { + g1, g2 := ga.NewGenome(b1), ga.NewGenome(b2) + m.Go(&g1, &g2) + } + + sixtyPercent := (numIterations / 100) * 60 + fourtyPercent := (numIterations / 100) * 40 + t.Assert(numCalls1 < sixtyPercent, IsTrue, Commentf("Num calls [%v] sixty percent [%v]", numCalls1, sixtyPercent)) + t.Assert(numCalls2 < sixtyPercent, IsTrue, Commentf("Num calls [%v] sixty percent [%v]", numCalls2, sixtyPercent)) + t.Assert(numCalls1 > fourtyPercent, IsTrue, Commentf("Num calls [%v] fourty percent [%v]", numCalls1, fourtyPercent)) + t.Assert(numCalls2 > fourtyPercent, IsTrue, Commentf("Num calls [%v] fourty percent [%v]", numCalls2, fourtyPercent)) + } +} + +func (s *MaterSuite) TestShouldMutate(t *C) { + + genomeSize := 10 + for i := 0; i < 100; i++ { + b1 := ga.Bitset{} + b1.Create(genomeSize) + b1.SetAll(0) + + g1, g2 := ga.NewGenome(b1), ga.NewGenome(b1) + c1, c2 := ga.Mutate(&g1, &g2) + + var iGenome ga.IGenome + t.Assert(c1, Implements, &iGenome) + t.Assert(c2, Implements, &iGenome) + + differringPointsC1 := 0 + differringPointsC2 := 0 + c1Bits, c2Bits := c1.GetBits(), c2.GetBits() + for i := 0; i < genomeSize; i++ { + if c1Bits.Get(i) != b1.Get(i) { + differringPointsC1++ + } + if c2Bits.Get(i) != b1.Get(i) { + differringPointsC2++ + } + } + oneIsDifferent := (differringPointsC1 == 1) || (differringPointsC2 == 1) + bothDiffernet := (differringPointsC1 == 1) && (differringPointsC2 == 1) + t.Assert(oneIsDifferent, IsTrue) + t.Assert(bothDiffernet, IsFalse) + } +} + +func (s *MaterSuite) TestShouldUseEliteFromConfigSettings(t *C) { + + elite := ga.NewGenome(ga.Bitset{}) + myFunc := func(a, b *ga.IGenome) (ga.IGenome, ga.IGenome) { + t.Assert(b, Equals, &elite) + return *a, *b + } + + m := ga.NewMater( + []ga.MaterFunctionProbability{ + {P: 1.0, F: myFunc, UseElite: true}, + }, + ) + + m.OnElite(&elite) + + g1, g2 := ga.NewGenome(ga.Bitset{}), ga.NewGenome(ga.Bitset{}) + m.Go(&g1, &g2) +} diff --git a/selector.go b/selector.go index 3413eab..20fddff 100644 --- a/selector.go +++ b/selector.go @@ -1,4 +1,3 @@ - package ga import ( @@ -7,58 +6,59 @@ import ( ) type ISelector interface { - Go( []IGenome, int ) *IGenome + Go([]IGenome, int) *IGenome } type NullSelector struct { } -func ( ns *NullSelector ) Go( genomes []IGenome, totalFitness int) *IGenome { + +func (ns *NullSelector) Go(genomes []IGenome, totalFitness int) *IGenome { return &genomes[0] } type SelectorFunctionProbability struct { P float32 - F func( []IGenome, int ) *IGenome + F func([]IGenome, int) *IGenome } type selector struct { selectorConfig []SelectorFunctionProbability } -func NewSelector( selectorConfig []SelectorFunctionProbability ) ISelector { - return &selector { - selectorConfig : selectorConfig, +func NewSelector(selectorConfig []SelectorFunctionProbability) ISelector { + return &selector{ + selectorConfig: selectorConfig, } } -func ( s *selector ) Go( genomeArray []IGenome, totalFitness int ) *IGenome { +func (s *selector) Go(genomeArray []IGenome, totalFitness int) *IGenome { for { for _, config := range s.selectorConfig { if rand.Float32() < config.P { - return config.F( genomeArray, totalFitness ) + return config.F(genomeArray, totalFitness) } } } } -func Roulette( genomeArray []IGenome, totalFitness int ) *IGenome { +func Roulette(genomeArray []IGenome, totalFitness int) *IGenome { - if len( genomeArray ) == 0 { - panic( "genome array contains no elements" ) + if len(genomeArray) == 0 { + panic("genome array contains no elements") } - if ( totalFitness == 0 ) { - randomIndex := rand.Intn( len( genomeArray ) ) + if totalFitness == 0 { + randomIndex := rand.Intn(len(genomeArray)) return &genomeArray[randomIndex] } - randomFitness := rand.Intn( totalFitness ) - for i, _ := range genomeArray { + randomFitness := rand.Intn(totalFitness) + for i := range genomeArray { randomFitness -= genomeArray[i].GetFitness() if randomFitness <= 0 { return &genomeArray[i] } } - panic( "total fitness is too large" ) -} \ No newline at end of file + panic("total fitness is too large") +} diff --git a/selector_test.go b/selector_test.go index 7f42d8c..0c00514 100644 --- a/selector_test.go +++ b/selector_test.go @@ -1,141 +1,141 @@ - -package ga_test - -import ( - . "gopkg.in/check.v1" - - "github.com/tomcraven/goga" - "math" - // "fmt" -) - -type SelectorSuite struct { - selector ga.ISelector -} -var _ = Suite( &SelectorSuite{} ) - -func ( s *SelectorSuite ) TestShouldInstantiate( t *C ) { - // Tested as part of fixture setup -} - -func ( s *SelectorSuite ) TestShouldRoulette( t *C ) { - - // for i := 0; i < 100; i++ { - // numGenomes := 100 - // genomeArray := make( []ga.IGenome, numGenomes ) - // totalFitness := 0 - // for i := 0; i < numGenomes; i++ { - // genomeArray[i] = ga.NewGenome( ga.Bitset{} ) - // genomeArray[i].SetFitness( i ) - // totalFitness += i - // } - - // numIterations := 100000 - // pickedGenomeFrequency := make( []int, numGenomes ) - - // for i := 0; i < numIterations; i++ { - // g := s.selector.Roulette( genomeArray, totalFitness ) - // pickedGenomeFrequency[g.GetFitness()]++ - // } - - // comparisonJump := 20 - // for i := 0; i < numGenomes - comparisonJump; i++ { - // t.Assert( pickedGenomeFrequency[i] <= pickedGenomeFrequency[i + comparisonJump], IsTrue, - // Commentf( "Piced freq [%v], comparing [%v] < [%v]", - // pickedGenomeFrequency, - // pickedGenomeFrequency[i], - // pickedGenomeFrequency[i + comparisonJump] ) ) - // } - // } -} - -func ( s *SelectorSuite ) TestShouldRouletteWhenTotalFitnessIs0( t *C ) { - - numGenomes := 10 - genomeArray := make( []ga.IGenome, numGenomes ) - for i := 0; i < numGenomes; i++ { - genomeArray[i] = ga.NewGenome( ga.Bitset{} ) - genomeArray[i].SetFitness( i ) - } - - ga.Roulette( genomeArray, 0 ) -} - -func ( s *SelectorSuite ) TestShouldPanicWithMismatchedFitness( t *C ) { - numGenomes := 10 - genomeArray := make( []ga.IGenome, numGenomes ) - for i := 0; i < numGenomes; i++ { - genomeArray[i] = ga.NewGenome( ga.Bitset{} ) - genomeArray[i].SetFitness( 1 ) - } - - // Note: not guaranteed (sp?) to fail, but pretty likely - t.Assert( func() { ga.Roulette( genomeArray, math.MaxInt32 ) }, Panics, "total fitness is too large" ) -} - -func ( s *SelectorSuite ) TestShouldPanicWhenGenomeArrayLengthIs0( t *C ) { - genomeArray := []ga.IGenome{} - t.Assert( len( genomeArray ), Equals, 0 ) - t.Assert( func() { ga.Roulette( genomeArray, 0 ) }, Panics, "genome array contains no elements") -} - -func ( s *SelectorSuite ) TestShouldPassBackGenomeFromGenomeArray( t *C ) { - numGenomes := 10 - genomeArray := make( []ga.IGenome, numGenomes ) - - for i, _ := range genomeArray { - genomeArray[i] = ga.NewGenome( ga.Bitset{} ) - genomeArray[i].SetFitness( 1 ) - } - - totalFitness := numGenomes - for i := 0; i < 100; i++ { - selectedGenome := ga.Roulette( genomeArray, totalFitness ) - - found := false - for i, _ := range genomeArray { - if &genomeArray[i] == selectedGenome { - found = true - break - } - } - - t.Assert( found, IsTrue ) - } -} - -func (s *SelectorSuite ) TestShouldConfig_Multiple ( t *C ) { - - for i := 0; i < 100; i++ { - numCalls1 := 0 - numCalls2 := 0 - myFunc1 := func ( array []ga.IGenome, totalFitness int ) ( *ga.IGenome ) { - numCalls1++ - return &array[0] - } - myFunc2 := func ( array []ga.IGenome, totalFitness int ) ( *ga.IGenome ) { - numCalls2++ - return &array[0] - } - - s := ga.NewSelector( - []ga.SelectorFunctionProbability { - { P : 0.1, F : myFunc1 }, // Note probabilities don't add up to 1 - { P : 0.1, F : myFunc2 }, - }, - ) - - numIterations := 1000 - genomeArray := make( []ga.IGenome, 10 ) - for i := 0; i < numIterations; i++ { - s.Go( genomeArray, 100 ) - } - - sixtyPercent := ( numIterations / 100 ) * 60 - fourtyPercent := ( numIterations / 100 ) * 40 - t.Assert( numCalls1 < sixtyPercent, IsTrue, Commentf( "Num calls [%v] sixty percent [%v]", numCalls1, sixtyPercent ) ) - t.Assert( numCalls2 < sixtyPercent, IsTrue, Commentf( "Num calls [%v] sixty percent [%v]", numCalls2, sixtyPercent ) ) - t.Assert( numCalls1 > fourtyPercent, IsTrue, Commentf( "Num calls [%v] fourty percent [%v]", numCalls1, fourtyPercent ) ) - t.Assert( numCalls2 > fourtyPercent, IsTrue, Commentf( "Num calls [%v] fourty percent [%v]", numCalls2, fourtyPercent ) ) - } -} \ No newline at end of file +package ga_test + +import ( + . "gopkg.in/check.v1" + + "github.com/tomcraven/goga" + "math" + // "fmt" +) + +type SelectorSuite struct { + selector ga.ISelector +} + +var _ = Suite(&SelectorSuite{}) + +func (s *SelectorSuite) TestShouldInstantiate(t *C) { + // Tested as part of fixture setup +} + +func (s *SelectorSuite) TestShouldRoulette(t *C) { + + // for i := 0; i < 100; i++ { + // numGenomes := 100 + // genomeArray := make( []ga.IGenome, numGenomes ) + // totalFitness := 0 + // for i := 0; i < numGenomes; i++ { + // genomeArray[i] = ga.NewGenome( ga.Bitset{} ) + // genomeArray[i].SetFitness( i ) + // totalFitness += i + // } + + // numIterations := 100000 + // pickedGenomeFrequency := make( []int, numGenomes ) + + // for i := 0; i < numIterations; i++ { + // g := s.selector.Roulette( genomeArray, totalFitness ) + // pickedGenomeFrequency[g.GetFitness()]++ + // } + + // comparisonJump := 20 + // for i := 0; i < numGenomes - comparisonJump; i++ { + // t.Assert( pickedGenomeFrequency[i] <= pickedGenomeFrequency[i + comparisonJump], IsTrue, + // Commentf( "Piced freq [%v], comparing [%v] < [%v]", + // pickedGenomeFrequency, + // pickedGenomeFrequency[i], + // pickedGenomeFrequency[i + comparisonJump] ) ) + // } + // } +} + +func (s *SelectorSuite) TestShouldRouletteWhenTotalFitnessIs0(t *C) { + + numGenomes := 10 + genomeArray := make([]ga.IGenome, numGenomes) + for i := 0; i < numGenomes; i++ { + genomeArray[i] = ga.NewGenome(ga.Bitset{}) + genomeArray[i].SetFitness(i) + } + + ga.Roulette(genomeArray, 0) +} + +func (s *SelectorSuite) TestShouldPanicWithMismatchedFitness(t *C) { + numGenomes := 10 + genomeArray := make([]ga.IGenome, numGenomes) + for i := 0; i < numGenomes; i++ { + genomeArray[i] = ga.NewGenome(ga.Bitset{}) + genomeArray[i].SetFitness(1) + } + + // Note: not guaranteed (sp?) to fail, but pretty likely + t.Assert(func() { ga.Roulette(genomeArray, math.MaxInt32) }, Panics, "total fitness is too large") +} + +func (s *SelectorSuite) TestShouldPanicWhenGenomeArrayLengthIs0(t *C) { + genomeArray := []ga.IGenome{} + t.Assert(len(genomeArray), Equals, 0) + t.Assert(func() { ga.Roulette(genomeArray, 0) }, Panics, "genome array contains no elements") +} + +func (s *SelectorSuite) TestShouldPassBackGenomeFromGenomeArray(t *C) { + numGenomes := 10 + genomeArray := make([]ga.IGenome, numGenomes) + + for i := range genomeArray { + genomeArray[i] = ga.NewGenome(ga.Bitset{}) + genomeArray[i].SetFitness(1) + } + + totalFitness := numGenomes + for i := 0; i < 100; i++ { + selectedGenome := ga.Roulette(genomeArray, totalFitness) + + found := false + for i := range genomeArray { + if &genomeArray[i] == selectedGenome { + found = true + break + } + } + + t.Assert(found, IsTrue) + } +} + +func (s *SelectorSuite) TestShouldConfig_Multiple(t *C) { + + for i := 0; i < 100; i++ { + numCalls1 := 0 + numCalls2 := 0 + myFunc1 := func(array []ga.IGenome, totalFitness int) *ga.IGenome { + numCalls1++ + return &array[0] + } + myFunc2 := func(array []ga.IGenome, totalFitness int) *ga.IGenome { + numCalls2++ + return &array[0] + } + + s := ga.NewSelector( + []ga.SelectorFunctionProbability{ + {P: 0.1, F: myFunc1}, // Note probabilities don't add up to 1 + {P: 0.1, F: myFunc2}, + }, + ) + + numIterations := 1000 + genomeArray := make([]ga.IGenome, 10) + for i := 0; i < numIterations; i++ { + s.Go(genomeArray, 100) + } + + sixtyPercent := (numIterations / 100) * 60 + fourtyPercent := (numIterations / 100) * 40 + t.Assert(numCalls1 < sixtyPercent, IsTrue, Commentf("Num calls [%v] sixty percent [%v]", numCalls1, sixtyPercent)) + t.Assert(numCalls2 < sixtyPercent, IsTrue, Commentf("Num calls [%v] sixty percent [%v]", numCalls2, sixtyPercent)) + t.Assert(numCalls1 > fourtyPercent, IsTrue, Commentf("Num calls [%v] fourty percent [%v]", numCalls1, fourtyPercent)) + t.Assert(numCalls2 > fourtyPercent, IsTrue, Commentf("Num calls [%v] fourty percent [%v]", numCalls2, fourtyPercent)) + } +} diff --git a/setup_test.go b/setup_test.go index 43f7afb..b0ec610 100644 --- a/setup_test.go +++ b/setup_test.go @@ -1,4 +1,3 @@ - package ga_test import ( @@ -6,6 +5,6 @@ import ( "testing" ) -func Test( t *testing.T ) { - TestingT( t ) -} \ No newline at end of file +func Test(t *testing.T) { + TestingT(t) +} diff --git a/simulator.go b/simulator.go index 51f90de..1d98897 100644 --- a/simulator.go +++ b/simulator.go @@ -1,21 +1,21 @@ - package ga type ISimulator interface { OnBeginSimulation() - Simulate( *IGenome ) + Simulate(*IGenome) OnEndSimulation() - ExitFunc( *IGenome ) bool + ExitFunc(*IGenome) bool } type NullSimulator struct { } -func ( ns *NullSimulator ) Simulate( *IGenome ) { + +func (ns *NullSimulator) Simulate(*IGenome) { +} +func (ns *NullSimulator) OnBeginSimulation() { } -func ( ns *NullSimulator ) OnBeginSimulation() { +func (ns *NullSimulator) OnEndSimulation() { } -func ( ns *NullSimulator ) OnEndSimulation() { +func (ns *NullSimulator) ExitFunc(*IGenome) bool { + return false } -func ( ns *NullSimulator ) ExitFunc( *IGenome ) bool { - return false; -} \ No newline at end of file diff --git a/simulator_test.go b/simulator_test.go index dc3315c..b30b41a 100644 --- a/simulator_test.go +++ b/simulator_test.go @@ -1,21 +1,22 @@ - package ga_test import ( - . "gopkg.in/check.v1" "github.com/tomcraven/goga" + . "gopkg.in/check.v1" ) type SimulatorTestSuite struct { } -func ( s *SimulatorTestSuite ) SetUpTest( t *C ) { + +func (s *SimulatorTestSuite) SetUpTest(t *C) { } -func ( s *SimulatorTestSuite ) TearDownTest( t *C ) { +func (s *SimulatorTestSuite) TearDownTest(t *C) { } -var _ = Suite( &SimulatorTestSuite{} ) -func ( s *SimulatorTestSuite ) TestShouldReturnFalseFromExitFunctionFromNullSimulator( t *C ) { +var _ = Suite(&SimulatorTestSuite{}) + +func (s *SimulatorTestSuite) TestShouldReturnFalseFromExitFunctionFromNullSimulator(t *C) { nullSimulator := ga.NullSimulator{} - genome := ga.NewGenome( ga.Bitset{} ) - t.Assert( nullSimulator.ExitFunc( &genome ), IsFalse ) -} \ No newline at end of file + genome := ga.NewGenome(ga.Bitset{}) + t.Assert(nullSimulator.ExitFunc(&genome), IsFalse) +} diff --git a/utils_test.go b/utils_test.go index f71e7dd..c729cc1 100644 --- a/utils_test.go +++ b/utils_test.go @@ -26,7 +26,7 @@ func (checker *isTrueChecker) Check(params []interface{}, names []string) (resul } func isTrue(obtained interface{}) (result bool) { - return ( obtained == true ) + return (obtained == true) } // ----------------------------------------------------------------------- @@ -51,5 +51,5 @@ func (checker *isFalseChecker) Check(params []interface{}, names []string) (resu } func isFalse(obtained interface{}) (result bool) { - return ( obtained == false ) -} \ No newline at end of file + return (obtained == false) +}