Skip to content

Commit

Permalink
working and generating trial csv
Browse files Browse the repository at this point in the history
  • Loading branch information
LordMendes committed Oct 16, 2023
1 parent 9eb12b6 commit 20ff234
Show file tree
Hide file tree
Showing 62 changed files with 511 additions and 15 deletions.
199 changes: 199 additions & 0 deletions Go/GA/GA.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
package GA

import (
"cardioid"
"fmt"
"gencsv"
"individual"
"math"
"math/rand"
"os"
"sort"
"sync"
"time"

"gocv.io/x/gocv"
)

type GA struct {
Population []individual.Individual
}

const POPULATION_SIZE = 20
const GENERATIONS = 50
const ELITE_PERCENTAGE = 0.1
const MUTATION_RATE = 0.02
const ARRAY_SIZE = 10

func (ga *GA) GetIndividual(index int) individual.Individual {
return ga.Population[index]
}

func (ga *GA) GetTop5() []individual.Individual {
return ga.Population[:5]
}

func (ga *GA) GetBest() individual.Individual {
return ga.Population[0]
}

func (ga *GA) SortPopulation() {
sort.Slice(ga.Population, func(i, j int) bool {
return ga.Population[i].Score > ga.Population[j].Score
})
}

func (ga *GA) CreateRandomIndividual(img gocv.Mat) individual.Individual {
var ind individual.Individual
ind.InitIndividual(img)
return ind
}

func (ga *GA) InitPopulation(img gocv.Mat) {
for i := 0; i < POPULATION_SIZE; i++ {
ga.Population = append(ga.Population, individual.Individual{})
ga.Population[i].InitIndividual(img)
}
}

func (ga *GA) GetPopulation() []individual.Individual {
return ga.Population
}

func (ga *GA) GetPopulationSize() int {
return len(ga.Population)
}

func (ga *GA) SliceBinaryString(binaryString string, sliceIndex int) (string, string) {
return binaryString[:sliceIndex], binaryString[sliceIndex:]
}

func (ga *GA) FitnessAll() {
var wg sync.WaitGroup
wg.Add(len(ga.Population))

for i := 0; i < len(ga.Population); i++ {
go func(index int) {
defer wg.Done()
ga.Population[index].Fitness()
}(i)
}

wg.Wait()
}

func (ga *GA) GrayToDecimal(gray string) int {
var decimal int
for i := 0; i < len(gray); i++ {
if gray[i] == '1' {
decimal = decimal + int(math.Pow(2, float64(len(gray)-i-1)))
}
}
return decimal
}

func (ga *GA) Crossover(ind1 individual.Individual, ind2 individual.Individual, img gocv.Mat) (individual.Individual, individual.Individual) {
xSliceIndex := rand.Intn(ARRAY_SIZE - 1)
ySliceIndex := rand.Intn(ARRAY_SIZE - 1)
sizeSliceIndex := rand.Intn(ARRAY_SIZE - 1)

ind1x1, ind1x2 := ga.SliceBinaryString(ind1.Cardioid.GetXCoordinate().GetGray(), xSliceIndex)
ind2x1, ind2x2 := ga.SliceBinaryString(ind2.Cardioid.GetXCoordinate().GetGray(), xSliceIndex)
ind1y1, ind1y2 := ga.SliceBinaryString(ind1.Cardioid.GetYCoordinate().GetGray(), ySliceIndex)
ind2y1, ind2y2 := ga.SliceBinaryString(ind2.Cardioid.GetYCoordinate().GetGray(), ySliceIndex)
ind1size1, ind1size2 := ga.SliceBinaryString(ind1.Cardioid.GetSize().GetGray(), sizeSliceIndex)
ind2size1, ind2size2 := ga.SliceBinaryString(ind2.Cardioid.GetSize().GetGray(), sizeSliceIndex)

child1Cardioid := cardioid.NewCardioid(
ga.GrayToDecimal(ind1x1+ind2x2),
ga.GrayToDecimal(ind1y1+ind2y2),
ga.GrayToDecimal(ind1size1+ind2size2),
)

child2Cardioid := cardioid.NewCardioid(
ga.GrayToDecimal(ind2x1+ind1x2),
ga.GrayToDecimal(ind2y1+ind1y2),
ga.GrayToDecimal(ind2size1+ind1size2),
)

child1 := individual.NewIndividual(child1Cardioid, img)
child2 := individual.NewIndividual(child2Cardioid, img)

return child1, child2
}

func (ga *GA) TournamentSelection() (individual.Individual, individual.Individual) {
var parent1, parent2 individual.Individual
tournamentSize := 2
for i := 0; i < tournamentSize; i++ {
randomIndex := rand.Intn(len(ga.Population))
if i == 0 {
parent1 = ga.Population[randomIndex]
} else {
parent2 = ga.Population[randomIndex]
}
}
return parent1, parent2
}

func (ga *GA) Mutate(ind individual.Individual) individual.Individual {
ind.Mutate()
return ind
}

func (ga *GA) Evolve(img gocv.Mat) {
var newPopulation []individual.Individual
eliteSize := int(ELITE_PERCENTAGE * float64(len(ga.Population)))
for i := 0; i < eliteSize; i++ {
newPopulation = append(newPopulation, ga.Population[i])
}
for len(newPopulation) < POPULATION_SIZE-1 {
parent1, parent2 := ga.TournamentSelection()
child1, child2 := ga.Crossover(parent1, parent2, img)
if child1.Cardioid.WillMutate() {
child1 = ga.Mutate(child1)
}
if child2.Cardioid.WillMutate() {
child2 = ga.Mutate(child2)
}
newPopulation = append(newPopulation, child1)
newPopulation = append(newPopulation, child2)
}
ga.Population = newPopulation
}

func (ga *GA) PrintPopulation() {
for i := 0; i < len(ga.Population); i++ {
fmt.Println(i, " : ", ga.Population[i].Score)
}
}

func (ga *GA) Run(img gocv.Mat) {
trialFolder := "tests/trial1"
os.Mkdir(trialFolder, os.ModePerm)

ga.InitPopulation(img)
ga.FitnessAll()
data := []gencsv.Data{}
for i := 0; i < GENERATIONS; i++ {
start := time.Now()
fmt.Println("Generation: ", i, " Score: ", ga.GetBest().Score, "Population Size: ", ga.GetPopulationSize())
bestIndividual := ga.GetBest()
bestIndividual.SaveToFile(trialFolder + "/gen" + fmt.Sprint(i) + ".jpg")
ga.FitnessAll()
ga.SortPopulation()
ga.Evolve(img)
duration := time.Since(start)
data = append(data, gencsv.Data{
Gen: i,
X: bestIndividual.Cardioid.GetXCoordinate().GetDecimal(),
Y: bestIndividual.Cardioid.GetYCoordinate().GetDecimal(),
Size: bestIndividual.Cardioid.GetSize().GetDecimal(),
Score: int(bestIndividual.Score),
Time: duration.Milliseconds(),
})
}
gencsv.GenerateCSV(trialFolder+"/data.csv", data)
ga.FitnessAll()
ga.SortPopulation()
}
1 change: 1 addition & 0 deletions Go/GA/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module GA
Binary file added Go/best.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 21 additions & 3 deletions Go/cardioid/cardioid.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,24 @@ import (
"math/rand"
)

var MUTATION_RATE = 0.5
var MUTATION_RATE = 0.25

type Cardioid struct {
XCoordinate coordinate.Coordinate
YCoordinate coordinate.Coordinate
Size coordinate.Coordinate
}

func NewCardioid(x int, y int, size int) Cardioid {
return Cardioid{coordinate.NewCoordinate(x), coordinate.NewCoordinate(y), coordinate.NewCoordinate(size)}
}

func (c *Cardioid) InitCardioid(maxX int, maxY int, maxSize int) {
c.XCoordinate.SetCoordinate(rand.Intn(maxX))
c.YCoordinate.SetCoordinate(rand.Intn(maxY))
c.Size.SetCoordinate(rand.Intn(maxSize))
}

func (c *Cardioid) GetXCoordinate() *coordinate.Coordinate {
return &c.XCoordinate
}
Expand All @@ -39,11 +49,19 @@ func (c *Cardioid) SetSize(size int) {
}

func (c *Cardioid) IsInsideCardioid(x int, y int) bool {
return (x-c.XCoordinate.GetDecimal())*(x-c.XCoordinate.GetDecimal())+(y-c.YCoordinate.GetDecimal())*(y-c.YCoordinate.GetDecimal()) <= int(math.Pow(2, float64(c.Size.GetDecimal())))
size := c.Size.GetDecimal()
x_c := c.XCoordinate.GetDecimal()
y_c := c.YCoordinate.GetDecimal()
r := float64(size / 2)

distance := math.Sqrt(math.Pow(float64(x-x_c), 2) + math.Pow(float64(y-y_c), 2))
theta := math.Atan2(float64(y-y_c), float64(x-x_c))
cardioidEquation := math.Pow(distance, 2) <= math.Pow(r, 2)*(1-math.Sin(theta))
return cardioidEquation
}

func (c *Cardioid) WillMutate() bool {
return rand.Float64() < MUTATION_RATE
return rand.Float64() <= MUTATION_RATE
}

func (c *Cardioid) Mutate() {
Expand Down
21 changes: 16 additions & 5 deletions Go/coordinate/coordinate.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ type Coordinate struct {

const ARRAY_MAX_SIZE = 10

func NewCoordinate(decimal int) Coordinate {
newCoordinate := Coordinate{decimal, "", ""}
newCoordinate.SetCoordinate(decimal)
return newCoordinate
}

func (c *Coordinate) SetDecimal(decimal int) {
c.decimal = decimal
}
Expand Down Expand Up @@ -52,11 +58,10 @@ func (c *Coordinate) GetCoordinate() (int, string, string) {
}

func (c *Coordinate) DecimalToBinary(decimal int) string {
var binary string
for decimal > 0 {
remainder := decimal % 2
binary = strconv.Itoa(remainder) + binary
decimal = decimal / 2
binary := strconv.FormatInt(int64(decimal), 2)
// Pad the binary string with leading zeros if necessary
for len(binary) < ARRAY_MAX_SIZE {
binary = "0" + binary
}
return binary
}
Expand Down Expand Up @@ -103,6 +108,12 @@ func (c *Coordinate) BinaryToDecimal(binary string) int {
return decimal
}

func (c *Coordinate) GrayToDecimal(gray string) int {
binary := c.GrayToBinary(gray)
decimal := c.BinaryToDecimal(binary)
return decimal
}

func (c *Coordinate) FlipBit(binary string, index int) string {
var newBinary string
for i := 0; i < len(binary); i++ {
Expand Down
52 changes: 52 additions & 0 deletions Go/gencsv/gencsv.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package gencsv

import (
"encoding/csv"
"os"
"strconv"
)

// Data structure
type Data struct {
Gen int
X int
Y int
Size int
Score int
Time int64
}

// Method to generate CSV
func GenerateCSV(filename string, data []Data) error {
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()

writer := csv.NewWriter(file)
defer writer.Flush()

// Writing header
header := []string{"Gen", "X", "Y", "Size", "Score", "Time"}
err = writer.Write(header)
if err != nil {
return err
}

// Writing data
for _, d := range data {
record := []string{
strconv.Itoa(d.Gen),
strconv.Itoa(d.X),
strconv.Itoa(d.Y),
strconv.Itoa(d.Size),
strconv.Itoa(d.Score),
strconv.FormatInt(d.Time, 10)}

if err := writer.Write(record); err != nil {
return err
}
}
return nil
}
1 change: 1 addition & 0 deletions Go/gencsv/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module gencsv
2 changes: 2 additions & 0 deletions Go/individual/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module individual

Loading

0 comments on commit 20ff234

Please sign in to comment.