diff --git a/src/main.odin b/src/main.odin index 1f00267..6545ac7 100644 --- a/src/main.odin +++ b/src/main.odin @@ -43,7 +43,7 @@ distance :: proc(x, y: int) -> int { } penalize :: proc(d: int) -> int { - return math.min(-3 * d, 0) + return math.min(d, 0) } // side-effect: reads global `items` @@ -71,6 +71,7 @@ generate_population :: proc() -> (res: Population) { destroy_population :: proc(pop: ^Population) { for &chrom in pop { + if chrom.free_pointer {continue} bit_array.destroy(&chrom) } } @@ -233,28 +234,42 @@ elitism_survivor_selection :: proc( offspring: ^Population, parent_fitnesses: []int, offspring_fitnesses: []int, -) -> ( - res: Population, -) { +) -> Population { + Index_Fitness :: struct { + idx: int, + fitness: int, + is_parent: bool, + } + combined_size := POPULATION_SIZE * 2 - combined_fitnesses := make([]int, combined_size) - defer delete(combined_fitnesses) + combined := make([]Index_Fitness, combined_size) + defer delete(combined) - copy(combined_fitnesses[:POPULATION_SIZE], parent_fitnesses) - copy(combined_fitnesses[POPULATION_SIZE:], offspring_fitnesses) + for i in 0 ..< POPULATION_SIZE { + combined[i] = {i, parent_fitnesses[i], true} + combined[POPULATION_SIZE + i] = {i, offspring_fitnesses[i], false} + } - slice.sort(combined_fitnesses) + slice.sort_by(combined[:], proc(a, b: Index_Fitness) -> bool { + return a.fitness > b.fitness + }) - for &s, i in res { - if i < POPULATION_SIZE { - s = parents[i] - } else { - s = offspring[i - POPULATION_SIZE] + survivors: Population + for i in 0 ..< POPULATION_SIZE { + entry := combined[i] + source := entry.is_parent ? &parents[entry.idx] : &offspring[entry.idx] + + // Create NEW bit array and copy bits + survivors[i] = bit_array.create(NUMBER_OF_ITEMS)^ + for j in 0 ..< NUMBER_OF_ITEMS { + bit_array.set(&survivors[i], j, bit_array.get(source, j)) } } - return + + return survivors } + run_ga :: proc() { population := generate_population() defer destroy_population(&population) @@ -279,7 +294,7 @@ run_ga :: proc() { tot_weight += items[idx].weight } fmt.printfln( - "gen %d: best fitness=%d, profit=%d (capacity=%d)", + "gen %d: best fitness=%d, profit=%d, weight=%d (capacity=%d)", gen, f, tot_profit, @@ -336,11 +351,12 @@ run_ga :: proc() { } main :: proc() { - items, ok := read_data(DATA_FILE) + data, ok := read_data(DATA_FILE) if !ok { fmt.eprintln("failed to read data from", DATA_FILE) return } + items = data fmt.println("running genetic algorithm for binary knapsack problem.") fmt.printfln(