From 1fcca3857627b12a0e5666db34a71071aebc41c7 Mon Sep 17 00:00:00 2001 From: Manuel Bustillo Date: Sun, 10 Nov 2024 12:35:41 +0100 Subject: [PATCH 1/2] Implement shift perturbation --- app/jobs/table_simulator_job.rb | 1 + app/services/tables/shift.rb | 30 +++++++++++++++++ spec/services/tables/shift_spec.rb | 53 ++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 app/services/tables/shift.rb create mode 100644 spec/services/tables/shift_spec.rb diff --git a/app/jobs/table_simulator_job.rb b/app/jobs/table_simulator_job.rb index 0b90396..ef91719 100644 --- a/app/jobs/table_simulator_job.rb +++ b/app/jobs/table_simulator_job.rb @@ -7,6 +7,7 @@ class TableSimulatorJob < ApplicationJob engine = VNS::Engine.new engine.add_perturbation(Tables::Swap) + engine.add_perturbation(Tables::Shift) initial_solution = Tables::Distribution.new(min_per_table: 8, max_per_table: 10) initial_solution.random_distribution(Guest.potential.shuffle) diff --git a/app/services/tables/shift.rb b/app/services/tables/shift.rb new file mode 100644 index 0000000..6ae7c94 --- /dev/null +++ b/app/services/tables/shift.rb @@ -0,0 +1,30 @@ +# Copyright (C) 2024 Manuel Bustillo + +module Tables + class Shift + private attr_reader :initial_solution + def initialize(initial_solution) + @initial_solution = initial_solution + end + + 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 + + table_a.delete(person) + table_b << person + + yield(@initial_solution) + ensure + table_b.delete(person) + table_a << person + + table_a.discomfort = original_discomfort_a + table_b.discomfort = original_discomfort_b + end + end + end + end +end diff --git a/spec/services/tables/shift_spec.rb b/spec/services/tables/shift_spec.rb new file mode 100644 index 0000000..4c24927 --- /dev/null +++ b/spec/services/tables/shift_spec.rb @@ -0,0 +1,53 @@ +require 'rails_helper' + +module Tables + RSpec.describe Shift do + describe '#each' do + let(:shifts) do + acc = [] + described_class.new(initial_solution).each do |solution| + acc << solution.tables.map(&:dup) + end + acc + end + + context 'when there are two tables with two people each' do + let(:initial_solution) do + Distribution.new(min_per_table: 2, max_per_table: 2).tap do |distribution| + distribution.tables << Set[:a, :b].to_table + distribution.tables << Set[:c, :d].to_table + end + end + + it 'yields all possible shifts between the tables' do + expect(shifts).to contain_exactly( + [Set[:b], Set[:c, :d, :a]], + [Set[:a], Set[:c, :d, :b]], + [Set[:b, :a, :d], Set[:c]], + [Set[:b, :a, :c], Set[:d]] + ) + end + end + + context 'when there are two tables with three people each' do + let(:initial_solution) do + Distribution.new(min_per_table: 3, max_per_table: 3).tap do |distribution| + distribution.tables << Set[:a, :b, :c].to_table + distribution.tables << Set[:d, :e, :f].to_table + end + end + + it 'yields all possible shifts between the tables' do + expect(shifts).to contain_exactly( + [Set[:b, :c], Set[:d, :e, :f, :a]], + [Set[:c, :a], Set[:d, :e, :f, :b]], + [Set[:a, :b], Set[:d, :e, :f, :c]], + [Set[:a, :b, :c, :d], Set[:e, :f]], + [Set[:a, :b, :c, :e], Set[:d, :f]], + [Set[:a, :b, :c, :f], Set[:d, :e]] + ) + end + end + end + end +end From bcf00fabf0668b07507a014c4b46efe1284a254e Mon Sep 17 00:00:00 2001 From: Manuel Bustillo Date: Sun, 10 Nov 2024 17:01:57 +0000 Subject: [PATCH 2/2] Add copyright notice --- spec/services/tables/shift_spec.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/services/tables/shift_spec.rb b/spec/services/tables/shift_spec.rb index 4c24927..e4c48af 100644 --- a/spec/services/tables/shift_spec.rb +++ b/spec/services/tables/shift_spec.rb @@ -1,3 +1,5 @@ +# Copyright (C) 2024 Manuel Bustillo + require 'rails_helper' module Tables