! tie it all together
This commit is contained in:
112
src/main.odin
112
src/main.odin
@@ -13,6 +13,10 @@ DATA_FILE :: "res/knapPI_12_500_1000_82.csv"
|
||||
NUMBER_OF_ITEMS :: 500
|
||||
CAPACITY :: 280785
|
||||
POPULATION_SIZE :: 100
|
||||
GENERATIONS :: 100
|
||||
TOURNAMENT_SIZE :: 3
|
||||
CROSSOVER_RATE :: 0.8
|
||||
MUTATION_RATE :: 0.01
|
||||
|
||||
Item :: struct {
|
||||
profit, weight: int,
|
||||
@@ -71,7 +75,18 @@ destroy_population :: proc(pop: ^Population) {
|
||||
}
|
||||
}
|
||||
|
||||
tournament_selection :: proc(pop: ^Population, fitnesses: []int, k: int = 3) -> ^Chromosome {
|
||||
evaluate_population :: proc(pop: ^Population) -> (res: [POPULATION_SIZE]int) {
|
||||
for &chrom, i in pop {
|
||||
res[i] = fitness(&chrom)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
tournament_selection :: proc(
|
||||
pop: ^Population,
|
||||
fitnesses: []int,
|
||||
k: int = TOURNAMENT_SIZE,
|
||||
) -> ^Chromosome {
|
||||
best_idx := rand.int_max(POPULATION_SIZE)
|
||||
best_fitness := fitnesses[best_idx]
|
||||
|
||||
@@ -173,7 +188,7 @@ uniform_crossover :: proc(
|
||||
return
|
||||
}
|
||||
|
||||
bit_flip_mutation :: proc(chrom: ^Chromosome, mutation_rate: f32 = 0.01) {
|
||||
bit_flip_mutation :: proc(chrom: ^Chromosome, mutation_rate: f32 = MUTATION_RATE) {
|
||||
for i in 0 ..< NUMBER_OF_ITEMS {
|
||||
if rand.float32() < mutation_rate {
|
||||
current := bit_array.get(chrom, i)
|
||||
@@ -240,11 +255,102 @@ elitism_survivor_selection :: proc(
|
||||
return
|
||||
}
|
||||
|
||||
run_ga :: proc() {
|
||||
population := generate_population()
|
||||
defer destroy_population(&population)
|
||||
|
||||
best_fitness := math.min(int)
|
||||
best_generation := 0
|
||||
|
||||
for gen in 0 ..< GENERATIONS {
|
||||
fitnesses := evaluate_population(&population)
|
||||
|
||||
// log best fitnesses
|
||||
for f, i in fitnesses {
|
||||
if f <= best_fitness {continue}
|
||||
best_fitness = f
|
||||
best_generation = gen
|
||||
|
||||
chrom := &population[i]
|
||||
tot_profit, tot_weight := 0, 0
|
||||
for idx in 0 ..< bit_array.len(chrom) {
|
||||
if !bit_array.get(chrom, idx) {continue}
|
||||
tot_profit += items[idx].profit
|
||||
tot_weight += items[idx].weight
|
||||
}
|
||||
fmt.printfln(
|
||||
"gen %d: best fitness=%d, profit=%d (capacity=%d)",
|
||||
gen,
|
||||
f,
|
||||
tot_profit,
|
||||
tot_weight,
|
||||
CAPACITY,
|
||||
)
|
||||
}
|
||||
|
||||
// create offspring
|
||||
offspring: Population
|
||||
for i := 0; i < POPULATION_SIZE; i += 2 {
|
||||
parent1 := tournament_selection(&population, fitnesses[:])
|
||||
parent2 := tournament_selection(&population, fitnesses[:])
|
||||
|
||||
child1, child2: Chromosome
|
||||
if rand.float32() < CROSSOVER_RATE {
|
||||
child1, child2 = single_point_crossover(parent1, parent2)
|
||||
} else {
|
||||
child1 = bit_array.create(NUMBER_OF_ITEMS)^
|
||||
child2 = bit_array.create(NUMBER_OF_ITEMS)^
|
||||
for j in 0 ..< NUMBER_OF_ITEMS {
|
||||
bit_array.set(&child1, j, bit_array.get(parent1, j))
|
||||
bit_array.set(&child2, j, bit_array.get(parent2, j))
|
||||
}
|
||||
}
|
||||
|
||||
bit_flip_mutation(&child1)
|
||||
bit_flip_mutation(&child2)
|
||||
|
||||
offspring[i] = child1
|
||||
if i + 1 < POPULATION_SIZE {
|
||||
offspring[i + 1] = child2
|
||||
}
|
||||
}
|
||||
|
||||
// survivor selection
|
||||
offspring_fitnesses := evaluate_population(&offspring)
|
||||
new_population := elitism_survivor_selection(
|
||||
&population,
|
||||
&offspring,
|
||||
fitnesses[:],
|
||||
offspring_fitnesses[:],
|
||||
)
|
||||
|
||||
// clean-up
|
||||
destroy_population(&population)
|
||||
destroy_population(&offspring)
|
||||
|
||||
population = new_population
|
||||
}
|
||||
|
||||
fmt.println()
|
||||
fmt.printfln("final best: fitness=%d (found at generation %d)", best_fitness, best_generation)
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
items, ok := read_data(DATA_FILE)
|
||||
if !ok {
|
||||
fmt.eprintln("failed to read data from", DATA_FILE)
|
||||
return
|
||||
}
|
||||
fmt.println(items)
|
||||
|
||||
fmt.println("running genetic algorithm for binary knapsack problem.")
|
||||
fmt.printfln(
|
||||
"items: %d, capacity: %d, population: %d, generations: %d",
|
||||
NUMBER_OF_ITEMS,
|
||||
CAPACITY,
|
||||
POPULATION_SIZE,
|
||||
GENERATIONS,
|
||||
)
|
||||
fmt.println()
|
||||
|
||||
run_ga()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user