diff --git a/CMakeLists.txt b/CMakeLists.txt index 38e4f2c..6b3b16f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.25) -project(blt-gp VERSION 0.1.4) +project(blt-gp VERSION 0.1.5) include(CTest) diff --git a/examples/symbolic_regression.cpp b/examples/symbolic_regression.cpp index 7bc43b8..f61ce8a 100644 --- a/examples/symbolic_regression.cpp +++ b/examples/symbolic_regression.cpp @@ -39,7 +39,7 @@ blt::gp::prog_config_t config = blt::gp::prog_config_t() .set_mutation_chance(0.1) .set_reproduction_chance(0) .set_max_generations(50) - .set_pop_size(50000) + .set_pop_size(500) .set_thread_count(0); blt::gp::type_provider type_system; @@ -117,15 +117,15 @@ int main() program.set_operations(builder.build()); BLT_DEBUG("Generate Initial Population"); - program.generate_population(type_system.get_type().id(), fitness_function); + auto sel = blt::gp::select_fitness_proportionate_t{}; + program.generate_population(type_system.get_type().id(), fitness_function, sel, sel, sel); BLT_DEBUG("Begin Generation Loop"); while (!program.should_terminate()) { BLT_TRACE("------------{Begin Generation %ld}------------", program.get_current_generation()); BLT_START_INTERVAL("Symbolic Regression", "Gen"); - auto sel = blt::gp::select_fitness_proportionate_t{}; - program.create_next_generation(sel, sel, sel); + program.create_next_generation(); BLT_END_INTERVAL("Symbolic Regression", "Gen"); BLT_TRACE("Move to next generation"); BLT_START_INTERVAL("Symbolic Regression", "Fitness"); diff --git a/include/blt/gp/program.h b/include/blt/gp/program.h index 6a41def..75cf3dd 100644 --- a/include/blt/gp/program.h +++ b/include/blt/gp/program.h @@ -264,19 +264,12 @@ namespace blt::gp system(system), seed(seed), config(config) { create_threads(); } - template)> - void create_next_generation(Crossover&& crossover_selection, Mutation&& mutation_selection, Reproduction&& reproduction_selection, - CreationFunc& func = default_next_pop_creator) + void create_next_generation() { // should already be empty next_pop.clear(); - crossover_selection.pre_process(*this, current_pop, current_stats); - mutation_selection.pre_process(*this, current_pop, current_stats); - reproduction_selection.pre_process(*this, current_pop, current_stats); - - auto args = get_selector_args(); - func(args, std::forward(crossover_selection), std::forward(mutation_selection), - std::forward(reproduction_selection)); + thread_helper.next_gen_left.store(config.population_size, std::memory_order_release); + (*thread_execution_service)(0); } void evaluate_fitness() @@ -294,8 +287,10 @@ namespace blt::gp * * NOTE: 0 is considered the best, in terms of standardized fitness */ - template - void generate_population(type_id root_type, FitnessFunc& fitness_function, bool eval_fitness_now = true) + template)> + void generate_population(type_id root_type, FitnessFunc& fitness_function, + Crossover& crossover_selection, Mutation& mutation_selection, Reproduction& reproduction_selection, + CreationFunc& func = default_next_pop_creator, bool eval_fitness_now = true) { using LambdaReturn = typename decltype(blt::meta::lambda_helper(fitness_function))::Return; current_pop = config.pop_initializer.get().generate( @@ -303,107 +298,157 @@ namespace blt::gp if (config.threads == 1) { BLT_INFO("Starting with single thread variant!"); - thread_execution_service = new std::function([this, &fitness_function](blt::size_t) { - for (const auto& ind : blt::enumerate(current_pop.get_individuals())) - { - if constexpr (std::is_same_v || std::is_convertible_v) - { - auto result = fitness_function(ind.second.tree, ind.second.fitness, ind.first); - if (result) - fitness_should_exit = true; - } else - { - fitness_function(ind.second.tree, ind.second.fitness, ind.first); - } - - if (ind.second.fitness.adjusted_fitness > current_stats.best_fitness) - current_stats.best_fitness = ind.second.fitness.adjusted_fitness; - - if (ind.second.fitness.adjusted_fitness < current_stats.worst_fitness) - current_stats.worst_fitness = ind.second.fitness.adjusted_fitness; - - current_stats.overall_fitness = current_stats.overall_fitness + ind.second.fitness.adjusted_fitness; - } - }); + thread_execution_service = new std::function( + [this, &fitness_function, &crossover_selection, &mutation_selection, &reproduction_selection, &func](blt::size_t) { + if (thread_helper.evaluation_left > 0) + { + for (const auto& ind : blt::enumerate(current_pop.get_individuals())) + { + if constexpr (std::is_same_v || std::is_convertible_v) + { + auto result = fitness_function(ind.second.tree, ind.second.fitness, ind.first); + if (result) + fitness_should_exit = true; + } else + { + fitness_function(ind.second.tree, ind.second.fitness, ind.first); + } + + if (ind.second.fitness.adjusted_fitness > current_stats.best_fitness) + current_stats.best_fitness = ind.second.fitness.adjusted_fitness; + + if (ind.second.fitness.adjusted_fitness < current_stats.worst_fitness) + current_stats.worst_fitness = ind.second.fitness.adjusted_fitness; + + current_stats.overall_fitness = current_stats.overall_fitness + ind.second.fitness.adjusted_fitness; + } + thread_helper.evaluation_left = 0; + } + if (thread_helper.next_gen_left > 0) + { + static thread_local std::vector new_children; + new_children.clear(); + auto args = get_selector_args(new_children); + + crossover_selection.pre_process(*this, current_pop, current_stats); + mutation_selection.pre_process(*this, current_pop, current_stats); + reproduction_selection.pre_process(*this, current_pop, current_stats); + + perform_elitism(args); + + while (new_children.size() < config.population_size) + func(args, crossover_selection, mutation_selection, reproduction_selection); + + for (auto& i : new_children) + next_pop.get_individuals().emplace_back(std::move(i)); + + thread_helper.next_gen_left = 0; + } + }); } else { BLT_INFO("Starting thread execution service!"); std::scoped_lock lock(thread_helper.thread_function_control); - thread_execution_service = new std::function([this, &fitness_function](blt::size_t) { - thread_helper.barrier.wait(); - if (thread_helper.evaluation_left > 0) - { - while (thread_helper.evaluation_left > 0) - { - blt::size_t size = 0; - blt::size_t begin = 0; - blt::size_t end = thread_helper.evaluation_left.load(std::memory_order_relaxed); - do + thread_execution_service = new std::function( + [this, &fitness_function, &crossover_selection, &mutation_selection, &reproduction_selection, &func](blt::size_t id) { + thread_helper.barrier.wait(); + if (thread_helper.evaluation_left > 0) { - size = std::min(end, config.evaluation_size); - begin = end - size; - } while (!thread_helper.evaluation_left.compare_exchange_weak(end, end - size, - std::memory_order::memory_order_relaxed, - std::memory_order::memory_order_relaxed)); - for (blt::size_t i = begin; i < end; i++) - { - auto& ind = current_pop.get_individuals()[i]; - - - if constexpr (std::is_same_v || std::is_convertible_v) + while (thread_helper.evaluation_left > 0) { - auto result = fitness_function(ind.tree, ind.fitness, i); - if (result) - fitness_should_exit = true; - } else - { - fitness_function(ind.tree, ind.fitness, i); + blt::size_t size = 0; + blt::size_t begin = 0; + blt::size_t end = thread_helper.evaluation_left.load(std::memory_order_relaxed); + do + { + size = std::min(end, config.evaluation_size); + begin = end - size; + } while (!thread_helper.evaluation_left.compare_exchange_weak(end, end - size, + std::memory_order::memory_order_relaxed, + std::memory_order::memory_order_relaxed)); + for (blt::size_t i = begin; i < end; i++) + { + auto& ind = current_pop.get_individuals()[i]; + + + if constexpr (std::is_same_v || std::is_convertible_v) + { + auto result = fitness_function(ind.tree, ind.fitness, i); + if (result) + fitness_should_exit = true; + } else + { + fitness_function(ind.tree, ind.fitness, i); + } + + auto old_best = current_stats.best_fitness.load(std::memory_order_relaxed); + while (ind.fitness.adjusted_fitness > old_best && + !current_stats.best_fitness.compare_exchange_weak(old_best, ind.fitness.adjusted_fitness, + std::memory_order_relaxed, + std::memory_order_relaxed)); + + auto old_worst = current_stats.worst_fitness.load(std::memory_order_relaxed); + while (ind.fitness.adjusted_fitness < old_worst && + !current_stats.worst_fitness.compare_exchange_weak(old_worst, ind.fitness.adjusted_fitness, + std::memory_order_relaxed, + std::memory_order_relaxed)); + + auto old_overall = current_stats.overall_fitness.load(std::memory_order_relaxed); + while (!current_stats.overall_fitness.compare_exchange_weak(old_overall, + ind.fitness.adjusted_fitness + old_overall, + std::memory_order_relaxed, + std::memory_order_relaxed)); + } } - - auto old_best = current_stats.best_fitness.load(std::memory_order_relaxed); - while (ind.fitness.adjusted_fitness > old_best && - !current_stats.best_fitness.compare_exchange_weak(old_best, ind.fitness.adjusted_fitness, - std::memory_order_relaxed, std::memory_order_relaxed)); - - auto old_worst = current_stats.worst_fitness.load(std::memory_order_relaxed); - while (ind.fitness.adjusted_fitness < old_worst && - !current_stats.worst_fitness.compare_exchange_weak(old_worst, ind.fitness.adjusted_fitness, - std::memory_order_relaxed, std::memory_order_relaxed)); - - auto old_overall = current_stats.overall_fitness.load(std::memory_order_relaxed); - while (!current_stats.overall_fitness.compare_exchange_weak(old_overall, - ind.fitness.adjusted_fitness + old_overall, - std::memory_order_relaxed, - std::memory_order_relaxed)); } - } - } - if (thread_helper.next_gen_left > 0) - { - while (thread_helper.next_gen_left > 0) - { - blt::size_t size = 0; - blt::size_t begin = 0; - blt::size_t end = thread_helper.next_gen_left.load(std::memory_order_relaxed); - do - { - size = std::min(end, config.evaluation_size); - begin = end - size; - } while (!thread_helper.next_gen_left.compare_exchange_weak(end, end - size, - std::memory_order::memory_order_relaxed, - std::memory_order::memory_order_relaxed)); - - static thread_local std::vector new_children; - new_children.clear(); - - for (blt::size_t i = begin; i < end; i++) + if (thread_helper.next_gen_left > 0) { + static thread_local std::vector new_children; + new_children.clear(); + auto args = get_selector_args(new_children); + if (id == 0) + { + crossover_selection.pre_process(*this, current_pop, current_stats); + mutation_selection.pre_process(*this, current_pop, current_stats); + reproduction_selection.pre_process(*this, current_pop, current_stats); + + perform_elitism(args); + + for (auto& i : new_children) + next_pop.get_individuals().emplace_back(std::move(i)); + thread_helper.next_gen_left -= new_children.size(); + new_children.clear(); + } + thread_helper.barrier.wait(); + while (thread_helper.next_gen_left > 0) + { + blt::size_t size = 0; + blt::size_t begin = 0; + blt::size_t end = thread_helper.next_gen_left.load(std::memory_order_relaxed); + do + { + size = std::min(end, config.evaluation_size); + begin = end - size; + } while (!thread_helper.next_gen_left.compare_exchange_weak(end, end - size, + std::memory_order::memory_order_relaxed, + std::memory_order::memory_order_relaxed)); + + for (blt::size_t i = begin; i < end; i++) + func(args, crossover_selection, mutation_selection, reproduction_selection); + + { + std::scoped_lock lock(thread_helper.thread_generation_lock); + for (auto& i : new_children) + { + if (next_pop.get_individuals().size() < config.population_size) + next_pop.get_individuals().emplace_back(i); + } + } + } } - } - } - thread_helper.barrier.wait(); - }); + thread_helper.barrier.wait(); + }); thread_helper.thread_function_condition.notify_all(); } if (eval_fitness_now) @@ -605,6 +650,7 @@ namespace blt::gp std::vector> threads; std::mutex thread_function_control; + std::mutex thread_generation_lock; std::condition_variable thread_function_condition{}; std::atomic_uint64_t evaluation_left = 0; @@ -620,9 +666,9 @@ namespace blt::gp // for convenience, shouldn't decrease performance too much std::atomic*> thread_execution_service = nullptr; - inline selector_args get_selector_args() + inline selector_args get_selector_args(std::vector& next_pop_trees) { - return {*this, next_pop, current_pop, current_stats, config, get_random()}; + return {*this, next_pop_trees, current_pop, current_stats, config, get_random()}; } template @@ -637,8 +683,7 @@ namespace blt::gp void evaluate_fitness_internal() { current_stats.clear(); - if (config.threads != 1) - thread_helper.evaluation_left.store(current_pop.get_individuals().size(), std::memory_order_release); + thread_helper.evaluation_left.store(current_pop.get_individuals().size(), std::memory_order_release); (*thread_execution_service)(0); current_stats.average_fitness = current_stats.overall_fitness / static_cast(config.population_size); diff --git a/include/blt/gp/selection.h b/include/blt/gp/selection.h index 940172c..db6a197 100644 --- a/include/blt/gp/selection.h +++ b/include/blt/gp/selection.h @@ -31,7 +31,7 @@ namespace blt::gp struct selector_args { gp_program& program; - population_t& next_pop; + std::vector& next_pop; population_t& current_pop; population_stats& current_stats; prog_config_t& config; @@ -70,119 +70,58 @@ namespace blt::gp } for (blt::size_t i = 0; i < config.elites; i++) - next_pop.get_individuals().push_back(current_pop.get_individuals()[values[i].first]); - } - }; - - template - constexpr inline auto proportionate_next_pop_creator = []( - const selector_args& args, Crossover crossover_selection, Mutation mutation_selection, Reproduction reproduction_selection) { - auto& [program, next_pop, current_pop, current_stats, config, random] = args; - - double total_prob = config.mutation_chance + config.crossover_chance; - double crossover_chance = config.crossover_chance / total_prob; - double mutation_chance = crossover_chance + config.mutation_chance / total_prob; - - perform_elitism(args); - - while (next_pop.get_individuals().size() < config.population_size) - { - auto type = random.get_double(); - if (type > crossover_chance && type < mutation_chance) - { - // crossover - auto& p1 = crossover_selection.select(program, current_pop, current_stats); - auto& p2 = crossover_selection.select(program, current_pop, current_stats); - - auto results = config.crossover.get().apply(program, p1, p2); - - // if crossover fails, we can check for mutation on these guys. otherwise straight copy them into the next pop - if (results) - { - next_pop.get_individuals().emplace_back(std::move(results->child1)); - // annoying check - if (next_pop.get_individuals().size() < config.population_size) - next_pop.get_individuals().emplace_back(std::move(results->child2)); - } else - { - if (config.try_mutation_on_crossover_failure && random.choice(config.mutation_chance)) - next_pop.get_individuals().emplace_back(std::move(config.mutator.get().apply(program, p1))); - else - next_pop.get_individuals().push_back(individual{p1}); - // annoying check. - if (next_pop.get_individuals().size() < config.population_size) - { - if (config.try_mutation_on_crossover_failure && random.choice(config.mutation_chance)) - next_pop.get_individuals().emplace_back(std::move(config.mutator.get().apply(program, p2))); - else - next_pop.get_individuals().push_back(individual{p2}); - } - } - } else if (type > mutation_chance) - { - // mutation - auto& p = mutation_selection.select(program, current_pop, current_stats); - next_pop.get_individuals().emplace_back(std::move(config.mutator.get().apply(program, p))); - } else - { - // reproduction - auto& p = reproduction_selection.select(program, current_pop, current_stats); - next_pop.get_individuals().push_back(individual{p}); - } + next_pop.push_back(current_pop.get_individuals()[values[i].first].tree); } }; template constexpr inline auto default_next_pop_creator = []( - const blt::gp::selector_args& args, Crossover crossover_selection, Mutation mutation_selection, Reproduction reproduction_selection) { + blt::gp::selector_args& args, Crossover& crossover_selection, Mutation& mutation_selection, Reproduction& reproduction_selection) { auto& [program, next_pop, current_pop, current_stats, config, random] = args; - perform_elitism(args); - - while (next_pop.get_individuals().size() < config.population_size) + int sel = random.get_i32(0, 3); + switch (sel) { - int sel = random.get_i32(0, 3); - switch (sel) - { - case 0: - // everyone gets a chance once per loop. - if (random.choice(config.crossover_chance)) + case 0: + // everyone gets a chance once per loop. + if (random.choice(config.crossover_chance)) + { + // crossover + auto& p1 = crossover_selection.select(program, current_pop, current_stats); + auto& p2 = crossover_selection.select(program, current_pop, current_stats); + + auto results = config.crossover.get().apply(program, p1, p2); + + // if crossover fails, we can check for mutation on these guys. otherwise straight copy them into the next pop + if (results) { - // crossover - auto& p1 = crossover_selection.select(program, current_pop, current_stats); - auto& p2 = crossover_selection.select(program, current_pop, current_stats); - - auto results = config.crossover.get().apply(program, p1, p2); - - // if crossover fails, we can check for mutation on these guys. otherwise straight copy them into the next pop - if (results) - { - next_pop.get_individuals().emplace_back(std::move(results->child1)); - // annoying check - if (next_pop.get_individuals().size() < config.population_size) - next_pop.get_individuals().emplace_back(std::move(results->child2)); - } + next_pop.push_back(std::move(results->child1)); + next_pop.push_back(std::move(results->child2)); } - break; - case 1: - if (random.choice(config.mutation_chance)) - { - // mutation - auto& p = mutation_selection.select(program, current_pop, current_stats); - next_pop.get_individuals().emplace_back(std::move(config.mutator.get().apply(program, p))); - } - break; - case 2: - if (config.reproduction_chance > 0 && random.choice(config.reproduction_chance)) - { - // reproduction - auto& p = reproduction_selection.select(program, current_pop, current_stats); - next_pop.get_individuals().push_back(individual{p}); - } - break; - default: - BLT_ABORT("This is not possible!"); - } + } + break; + case 1: + if (random.choice(config.mutation_chance)) + { + // mutation + auto& p = mutation_selection.select(program, current_pop, current_stats); + next_pop.push_back(std::move(config.mutator.get().apply(program, p))); + } + break; + case 2: + if (config.reproduction_chance > 0 && random.choice(config.reproduction_chance)) + { + // reproduction + auto& p = reproduction_selection.select(program, current_pop, current_stats); + next_pop.push_back(p); + } + break; + default: +#if BLT_DEBUG_LEVEL > 0 + BLT_ABORT("This is not possible!"); +#else + BLT_UNREACHABLE; +#endif } }; diff --git a/include/blt/gp/stack.h b/include/blt/gp/stack.h index ad5b80f..beff92a 100644 --- a/include/blt/gp/stack.h +++ b/include/blt/gp/stack.h @@ -54,37 +54,14 @@ namespace blt::gp blt::size_t total_size_bytes = 0; blt::size_t total_used_bytes = 0; blt::size_t total_remaining_bytes = 0; - blt::size_t total_no_meta_bytes = 0; - - blt::size_t total_dealloc = 0; - blt::size_t total_dealloc_used = 0; - blt::size_t total_dealloc_remaining = 0; - blt::size_t total_dealloc_no_meta = 0; - - blt::size_t blocks = 0; friend std::ostream& operator<<(std::ostream& stream, const size_data_t& data) { stream << "["; - stream << data.total_used_bytes << "/"; - stream << data.total_size_bytes << "("; - stream << (static_cast(data.total_used_bytes) / static_cast(data.total_size_bytes) * 100) << "%), "; - stream << data.total_used_bytes << "/"; - stream << data.total_no_meta_bytes << "("; - stream << (static_cast(data.total_used_bytes) / static_cast(data.total_no_meta_bytes) * 100) - << "%), (empty space: "; - stream << data.total_remaining_bytes << ") blocks: " << data.blocks << " || unallocated space: "; - stream << data.total_dealloc_used << "/"; - stream << data.total_dealloc; - if (static_cast(data.total_dealloc) > 0) - stream << "(" << (static_cast(data.total_dealloc_used) / static_cast(data.total_dealloc) * 100) << "%)"; - stream << ", "; - stream << data.total_dealloc_used << "/"; - stream << data.total_dealloc_no_meta; - if (data.total_dealloc_no_meta > 0) - stream << "(" << (static_cast(data.total_dealloc_used) / static_cast(data.total_dealloc_no_meta * 100)) - << "%)"; - stream << ", (empty space: " << data.total_dealloc_remaining << ")]"; + stream << data.total_used_bytes << " / " << data.total_size_bytes; + stream << " (" + << (data.total_size_bytes != 0 ? (static_cast(data.total_used_bytes) / static_cast(data.total_size_bytes) * + 100) : 0) << "%); space left: " << data.total_remaining_bytes << "]"; return stream; } }; @@ -132,6 +109,10 @@ namespace blt::gp void insert(const stack_allocator& stack) { +#if BLT_DEBUG_LEVEL > 1 + if (stack.empty()) + BLT_WARN("Insert called on an empty stack!"); +#endif if (size_ < stack.bytes_stored + bytes_stored) expand(stack.bytes_stored + bytes_stored); std::memcpy(data_ + bytes_stored, stack.data_, stack.bytes_stored); @@ -140,6 +121,12 @@ namespace blt::gp void copy_from(const stack_allocator& stack, blt::size_t bytes) { +#if BLT_DEBUG_LEVEL > 0 + if (stack.empty()) + BLT_WARN("Copy From called on an empty stack"); + if (bytes == 0) + BLT_WARN("Requested 0 bytes to be copied. This seems to be an error!"); +#endif if (size_ < bytes + bytes_stored) expand(bytes + bytes_stored); std::memcpy(data_ + bytes_stored, stack.data_ + (stack.bytes_stored - bytes), bytes); @@ -148,6 +135,12 @@ namespace blt::gp void copy_from(blt::u8* data, blt::size_t bytes) { +#if BLT_DEBUG_LEVEL > 0 + if (data == nullptr) + BLT_ABORT("Nullptr provided to copy_from function!"); + if (bytes == 0) + BLT_WARN("Requested 0 bytes to be copied from, nothing will happen."); +#endif if (size_ < bytes + bytes_stored) expand(bytes + bytes_stored); std::memcpy(data_ + bytes_stored, data, bytes); @@ -156,6 +149,12 @@ namespace blt::gp void copy_to(blt::u8* data, blt::size_t bytes) { +#if BLT_DEBUG_LEVEL > 0 + if (data == nullptr) + BLT_ABORT("Nullptr provided to copy_to function!"); + if (bytes == 0) + BLT_WARN("Requested 0 to be copied to, nothing will happen!"); +#endif std::memcpy(data, data_ + (bytes_stored - bytes), bytes); } @@ -174,6 +173,10 @@ namespace blt::gp static_assert(std::is_trivially_copyable_v && "Type must be bitwise copyable!"); static_assert(alignof(NO_REF) <= MAX_ALIGNMENT && "Type alignment must not be greater than the max alignment!"); constexpr auto size = aligned_size(sizeof(NO_REF)); +#if BLT_DEBUG_LEVEL > 0 + if (bytes_stored < size) + BLT_ABORT("Not enough bytes left to pop!"); +#endif bytes_stored -= size; return *reinterpret_cast(data_ + bytes_stored); } @@ -184,16 +187,31 @@ namespace blt::gp static_assert(std::is_trivially_copyable_v && "Type must be bitwise copyable!"); static_assert(alignof(NO_REF) <= MAX_ALIGNMENT && "Type alignment must not be greater than the max alignment!"); auto size = aligned_size(sizeof(NO_REF)) + bytes; +#if BLT_DEBUG_LEVEL > 0 + if (bytes_stored < size) + BLT_ABORT(("Not enough bytes in stack to reference " + std::to_string(size) + " bytes requested but " + std::to_string(bytes) + + " bytes stored!").c_str()); +#endif return *reinterpret_cast(data_ + bytes_stored - size); } void pop_bytes(blt::size_t bytes) { +#if BLT_DEBUG_LEVEL > 0 + if (bytes_stored < bytes) + BLT_ABORT(("Not enough bytes in stack to pop " + std::to_string(bytes) + " bytes requested but " + std::to_string(bytes) + + " bytes stored!").c_str()); +#endif bytes_stored -= bytes; } void transfer_bytes(stack_allocator& to, blt::size_t bytes) { +#if BLT_DEBUG_LEVEL > 0 + if (bytes_stored < bytes) + BLT_ABORT(("Not enough bytes in stack to transfer " + std::to_string(bytes) + " bytes requested but " + std::to_string(bytes) + + " bytes stored!").c_str()); +#endif to.copy_from(*this, aligned_size(bytes)); pop_bytes(bytes); } @@ -297,7 +315,7 @@ namespace blt::gp if (!mask_r[index]) return; } - from>(offset).drop(); + from>(offset).drop(); } } diff --git a/src/transformers.cpp b/src/transformers.cpp index c13df5d..5b255a0 100644 --- a/src/transformers.cpp +++ b/src/transformers.cpp @@ -243,7 +243,7 @@ namespace blt::gp vals_r.pop_bytes(static_cast(total_bytes_after + accumulate_type_sizes(begin_itr, end_itr))); // insert the new tree then move back the data from after the original mutation point. - vals_r.insert(std::move(new_vals_r)); + vals_r.insert(new_vals_r); vals_r.copy_from(stack_after_data, total_bytes_after); auto before = begin_itr - 1; @@ -252,7 +252,7 @@ namespace blt::gp // this will check to make sure that the tree is in a correct and executable state. it requires that the evaluation is context free! #if BLT_DEBUG_LEVEL >= 2 - BLT_ASSERT(new_vals_r.empty()); +// BLT_ASSERT(new_vals_r.empty()); //BLT_ASSERT(stack_after.empty()); blt::size_t bytes_expected = 0; auto bytes_size = vals_r.size().total_used_bytes; @@ -690,7 +690,7 @@ namespace blt::gp vals.copy_from(from_ptr, from_bytes); vals.copy_from(after_ptr, after_to_bytes); - static std::vector op_copy; + static thread_local std::vector op_copy; op_copy.clear(); op_copy.insert(op_copy.begin(), ops.begin() + from_child.start, ops.begin() + from_child.end);