From 25bd53600eb53360841e862329cfba12ead02c39 Mon Sep 17 00:00:00 2001 From: bustikiller Date: Fri, 18 Jul 2025 18:12:53 +0200 Subject: [PATCH] Use frozen versions of tables --- app/services/tables/discomfort_calculator.rb | 1 + app/services/tables/distribution.rb | 2 + app/services/tables/shift.rb | 38 ++++++++++++---- app/services/tables/swap.rb | 48 ++++++++++++++------ app/services/vns/engine.rb | 35 +++++++++++++- 5 files changed, 98 insertions(+), 26 deletions(-) diff --git a/app/services/tables/discomfort_calculator.rb b/app/services/tables/discomfort_calculator.rb index 6a7ebcf..e91a8a4 100644 --- a/app/services/tables/discomfort_calculator.rb +++ b/app/services/tables/discomfort_calculator.rb @@ -11,6 +11,7 @@ module Tables end def calculate + # Rails.logger.info "Calculating discomfort of table with id #{table.object_id}" breakdown.values.sum end diff --git a/app/services/tables/distribution.rb b/app/services/tables/distribution.rb index 4751cf8..b574161 100644 --- a/app/services/tables/distribution.rb +++ b/app/services/tables/distribution.rb @@ -73,6 +73,8 @@ module Tables def local_discomfort(table) table.discomfort ||= DiscomfortCalculator.new(table:, hierarchy:).calculate + table.freeze + table.discomfort end end end diff --git a/app/services/tables/shift.rb b/app/services/tables/shift.rb index d5592d9..ebe2bd7 100644 --- a/app/services/tables/shift.rb +++ b/app/services/tables/shift.rb @@ -12,19 +12,37 @@ module Tables def each @initial_solution.tables.permutation(2) do |table_a, table_b| table_a.dup.each do |person| - original_discomfort_a = table_a.reset - original_discomfort_b = table_b.reset + + new_solution = Distribution.new( + min_per_table: @initial_solution.min_per_table, + max_per_table: @initial_solution.max_per_table, + hierarchy: @initial_solution.hierarchy + ) - table_a.delete(person) - table_b << person + new_solution.tables = @initial_solution.tables.dup - yield(@initial_solution) - ensure - table_b.delete(person) - table_a << person + new_solution.tables.delete(table_a) + new_solution.tables.delete(table_b) - table_a.discomfort = original_discomfort_a - table_b.discomfort = original_discomfort_b + modified_table_a = table_a.dup.tap(&:reset) + modified_table_b = table_b.dup.tap(&:reset) + + new_solution.tables << modified_table_a + new_solution.tables << modified_table_b + + # original_discomfort_a = table_a.reset + # original_discomfort_b = table_b.reset + + modified_table_a.delete(person) + modified_table_b << person + + yield(new_solution) + # ensure + # table_b.delete(person) + # table_a << person + + # table_a.discomfort = original_discomfort_a + # table_b.discomfort = original_discomfort_b end end end diff --git a/app/services/tables/swap.rb b/app/services/tables/swap.rb index 04abc18..b62d4f9 100644 --- a/app/services/tables/swap.rb +++ b/app/services/tables/swap.rb @@ -12,25 +12,45 @@ module Tables def each @initial_solution.tables.combination(2) do |table_a, table_b| table_a.to_a.product(table_b.to_a).each do |(person_a, person_b)| - original_discomfort_a = table_a.reset - original_discomfort_b = table_b.reset + + new_solution = Distribution.new( + min_per_table: @initial_solution.min_per_table, + max_per_table: @initial_solution.max_per_table, + hierarchy: @initial_solution.hierarchy + ) + + new_solution.tables = @initial_solution.tables.dup - table_a.delete(person_a) - table_b.delete(person_b) + new_solution.tables.delete(table_a) + new_solution.tables.delete(table_b) - table_a << person_b - table_b << person_a - yield(@initial_solution) - ensure - table_a.delete(person_b) - table_b.delete(person_a) + modified_table_a = table_a.dup.tap(&:reset) + modified_table_b = table_b.dup.tap(&:reset) - table_a << person_a - table_b << person_b + new_solution.tables << modified_table_a + new_solution.tables << modified_table_b - table_a.discomfort = original_discomfort_a - table_b.discomfort = original_discomfort_b + + # original_discomfort_a = table_a.reset + # original_discomfort_b = table_b.reset + + modified_table_a.delete(person_a) + modified_table_b.delete(person_b) + + modified_table_a << person_b + modified_table_b << person_a + + yield(new_solution) + # ensure + # table_a.delete(person_b) + # table_b.delete(person_a) + + # table_a << person_a + # table_b << person_b + + # table_a.discomfort = original_discomfort_a + # table_b.discomfort = original_discomfort_b end end end diff --git a/app/services/vns/engine.rb b/app/services/vns/engine.rb index d66c80b..1ff884c 100644 --- a/app/services/vns/engine.rb +++ b/app/services/vns/engine.rb @@ -20,7 +20,16 @@ module VNS @perturbations << klass end - attr_writer :initial_solution + def initialize_ractors(count: Concurrent.processor_count) + @ractors = count.times.map do |i| + Ractor.new(name: "VNS Ractor #{i}") do + # @target_function.call(Ractor.receive) + Ractor.receive.discomfort # Hard-coded for now, should be dynamic + end + end.cycle + end + + attr_writer :initial_solution, :ractors def run raise 'No target function defined' unless @target_function @@ -30,6 +39,10 @@ module VNS @best_solution = @initial_solution @best_score = @target_function.call(@best_solution) + @best_solution.freeze + @best_solution.tables.freeze + # @best_solution.tables.each(&:freeze) + self.class.sequence(@perturbations).each do |perturbation| optimize(perturbation) end @@ -44,9 +57,27 @@ module VNS optimized = false perturbation_klass.new(@best_solution).each do |alternative_solution| - score = @target_function.call(alternative_solution) + # original_score = + + # ractor = @ractors.next + # Rails.logger.info("Processed by ractor #{ractor.name}") + + # ractor.send(alternative_solution) + + # new_score = ractor.take + + # binding.pry if new_score != original_score + + # score = new_score + + score = @target_function.call(alternative_solution) + + # Rails.logger.info("Evaluating alternative solution with score: #{score}") + next if score >= @best_score + # Rails.logger.info("Found better solution with score: #{score} (previous: #{@best_score})") + @best_solution = alternative_solution.deep_dup @best_score = score optimized = true