diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index e44d90e..5d60383 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ruby-version: ['2.6'] + ruby-version: ['3.0'] steps: - uses: actions/checkout@v2 - name: Set up Ruby @@ -32,7 +32,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ruby-version: ['2.6', '2.7', '3.0', '3.1'] + ruby-version: ['3.0', '3.1', '3.2'] steps: - uses: actions/checkout@v2 diff --git a/.rubocop.yml b/.rubocop.yml index a1fb4cc..e39181b 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -6,7 +6,7 @@ require: - rubocop-rake AllCops: - TargetRubyVersion: 2.6 + TargetRubyVersion: 3.0 NewCops: enable DefaultFormatter: progress DisplayCopNames: true diff --git a/Gemfile b/Gemfile index 81c0ea8..583e6e1 100644 --- a/Gemfile +++ b/Gemfile @@ -7,8 +7,8 @@ gemspec gem "debug", ">= 1.0.0", require: false gem "minitest", "~> 5.0" -gem "rake", "~> 13.0", ">= 13.0.6" -gem "rubocop", "~> 1.23" -gem "rubocop-minitest", "~> 0.17.0" -gem "rubocop-performance", "~> 1.12" +gem "rake", "~> 13.0.0", ">= 13.0.6" +gem "rubocop", "~> 1.48.0" +gem "rubocop-minitest", "~> 0.29.0" +gem "rubocop-performance", "~> 1.16.0" gem "rubocop-rake", "~> 0.6.0" diff --git a/Gemfile.lock b/Gemfile.lock index c2202c2..e26a7ea 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - annealing (0.3.0) + annealing (0.4.0) GEM remote: https://rubygems.org/ @@ -10,40 +10,42 @@ GEM debug (1.4.0) irb (>= 1.3.6) reline (>= 0.2.7) - io-console (0.5.11) - irb (1.4.1) + io-console (0.6.0) + irb (1.6.3) reline (>= 0.3.0) - minitest (5.14.4) - parallel (1.21.0) - parser (3.0.3.2) + json (2.6.3) + minitest (5.18.0) + parallel (1.22.1) + parser (3.2.1.1) ast (~> 2.4.1) - rainbow (3.0.0) + rainbow (3.1.1) rake (13.0.6) - regexp_parser (2.2.0) - reline (0.3.1) + regexp_parser (2.7.0) + reline (0.3.2) io-console (~> 0.5) rexml (3.2.5) - rubocop (1.23.0) + rubocop (1.48.0) + json (~> 2.3) parallel (~> 1.10) - parser (>= 3.0.0.0) + parser (>= 3.2.0.0) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 1.8, < 3.0) - rexml - rubocop-ast (>= 1.12.0, < 2.0) + rexml (>= 3.2.5, < 4.0) + rubocop-ast (>= 1.26.0, < 2.0) ruby-progressbar (~> 1.7) - unicode-display_width (>= 1.4.0, < 3.0) - rubocop-ast (1.14.0) - parser (>= 3.0.1.1) - rubocop-minitest (0.17.0) - rubocop (>= 0.90, < 2.0) - rubocop-performance (1.12.0) + unicode-display_width (>= 2.4.0, < 3.0) + rubocop-ast (1.27.0) + parser (>= 3.2.1.0) + rubocop-minitest (0.29.0) + rubocop (>= 1.39, < 2.0) + rubocop-performance (1.16.0) rubocop (>= 1.7.0, < 2.0) rubocop-ast (>= 0.4.0) rubocop-rake (0.6.0) rubocop (~> 1.0) - ruby-prof (1.4.3) - ruby-progressbar (1.11.0) - unicode-display_width (2.1.0) + ruby-prof (1.6.1) + ruby-progressbar (1.13.0) + unicode-display_width (2.4.2) PLATFORMS ruby @@ -52,12 +54,12 @@ DEPENDENCIES annealing! debug (>= 1.0.0) minitest (~> 5.0) - rake (~> 13.0, >= 13.0.6) - rubocop (~> 1.23) - rubocop-minitest (~> 0.17.0) - rubocop-performance (~> 1.12) + rake (~> 13.0.0, >= 13.0.6) + rubocop (~> 1.48.0) + rubocop-minitest (~> 0.29.0) + rubocop-performance (~> 1.16.0) rubocop-rake (~> 0.6.0) - ruby-prof (~> 1.4, >= 1.4.3) + ruby-prof (~> 1.6, >= 1.6.1) BUNDLED WITH - 2.1.4 + 2.4.4 diff --git a/annealing.gemspec b/annealing.gemspec index 55929c9..ad61307 100644 --- a/annealing.gemspec +++ b/annealing.gemspec @@ -12,7 +12,7 @@ Gem::Specification.new do |spec| spec.summary = "Simulated Annealing" spec.description = "Simulated Annealing algoritm implementation." spec.homepage = "https://github.com/3zcurdia/annealing" - spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0") + spec.required_ruby_version = Gem::Requirement.new(">= 3.0.0") # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'" @@ -29,6 +29,6 @@ Gem::Specification.new do |spec| spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } spec.require_paths = ["lib"] - spec.add_development_dependency "ruby-prof", "~> 1.4", ">= 1.4.3" + spec.add_development_dependency "ruby-prof", "~> 1.6", ">= 1.6.1" spec.metadata["rubygems_mfa_required"] = "true" end diff --git a/bin/run b/bin/run index 268e652..0a0b941 100755 --- a/bin/run +++ b/bin/run @@ -45,13 +45,13 @@ solution = simulator.run(locations, state_change: state_change) puts "\nInitial itinerary:" -locations.each_cons(2).each_with_index do |(location1, location2), index| +locations.each_cons(2).with_index do |(location1, location2), index| puts "Stop ##{index + 1}: #{location1.name} -> #{location2.name} (#{location1.distance(location2)})" end puts "-------\nEnergy: #{energy_calculator.call(locations)}" puts "\nAnnealed itinerary:" -solution.state.each_cons(2).each_with_index do |(location1, location2), index| +solution.state.each_cons(2).with_index do |(location1, location2), index| puts "Stop ##{index + 1}: #{location1.name} -> #{location2.name} (#{location1.distance(location2)})" end puts "-------\nEnergy: #{solution.energy}" diff --git a/lib/annealing/version.rb b/lib/annealing/version.rb index e2e00aa..d37757b 100644 --- a/lib/annealing/version.rb +++ b/lib/annealing/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Annealing - VERSION = "0.3.0" + VERSION = "0.4.0" end diff --git a/test/annealing/configuration/coolers_test.rb b/test/annealing/configuration/coolers_test.rb index b751f1b..3c3ef9b 100644 --- a/test/annealing/configuration/coolers_test.rb +++ b/test/annealing/configuration/coolers_test.rb @@ -15,6 +15,7 @@ def setup def test_linear_cooler_reduces_temperature_linearly cooler = @coolers.linear cooled_temp = cooler.call(nil, @temperature, @cooling_rate, @step) + assert_in_delta @temperature - @cooling_rate, cooled_temp end @@ -22,6 +23,7 @@ def test_linear_cooler_reduces_temperature_linearly def test_exponential_cooler_reduces_temperature_exponentially cooler = @coolers.exponential cooled_temp = cooler.call(nil, @temperature, @cooling_rate, @step) + assert_in_delta @temperature - (Math.exp(@step - 1) * @cooling_rate), cooled_temp end @@ -30,6 +32,7 @@ def test_geometric_cooler_reduces_temperature_geometrically ratio = 3 cooler = @coolers.geometric(ratio) cooled_temp = cooler.call(nil, @temperature, @cooling_rate, @step) + assert_in_delta @temperature - (@cooling_rate * (ratio**(@step - 1))), cooled_temp end diff --git a/test/annealing/configuration/terminators_test.rb b/test/annealing/configuration/terminators_test.rb index dee8fb3..e173708 100644 --- a/test/annealing/configuration/terminators_test.rb +++ b/test/annealing/configuration/terminators_test.rb @@ -11,6 +11,7 @@ def setup def test_zero_temperature_terminator_true_when_temperature_is_zero terminator = @terminators.temp_is_zero? + assert terminator.call(nil, nil, 0) assert terminator.call(nil, nil, -1) refute terminator.call(nil, nil, 1) @@ -18,6 +19,7 @@ def test_zero_temperature_terminator_true_when_temperature_is_zero def test_zero_energy_terminator_true_when_energy_or_temperature_is_zero terminator = @terminators.energy_or_temp_is_zero? + assert terminator.call(nil, 0, 0) assert terminator.call(nil, 0, 1) assert terminator.call(nil, 1, 0) diff --git a/test/annealing/configuration_test.rb b/test/annealing/configuration_test.rb index 457d6bb..bf11101 100644 --- a/test/annealing/configuration_test.rb +++ b/test/annealing/configuration_test.rb @@ -15,6 +15,7 @@ def setup def test_sets_a_default_linear_cool_down_function cool_down = @subject.new.cool_down + assert_respond_to cool_down, :call assert_equal 1, cool_down.call(nil, 2, 1, nil) end @@ -31,6 +32,7 @@ def test_sets_a_default_initial_temperature def test_sets_a_default_termination_condition_function termination_condition = @subject.new.termination_condition + assert_respond_to termination_condition, :call refute termination_condition.call(nil, nil, 1) assert termination_condition.call(nil, nil, 0) @@ -47,12 +49,14 @@ def test_does_not_set_a_default_state_change_function def test_forces_cooling_rate_to_float configuration = @subject.new(cooling_rate: 99) + assert_kind_of Float, configuration.cooling_rate assert_in_delta 99.0, configuration.cooling_rate end def test_forces_temperature_to_float configuration = @subject.new(temperature: 999) + assert_kind_of Float, configuration.temperature assert_in_delta 999.0, configuration.temperature end @@ -60,6 +64,7 @@ def test_forces_temperature_to_float def test_merge_creates_new_configuration_from_config_hash new_temperature = 3000 new_config = @valid_configuration.merge(temperature: new_temperature) + refute_equal @valid_configuration.object_id, new_config.object_id assert_equal new_config.temperature, new_temperature refute_equal @valid_configuration.temperature, new_config.temperature @@ -67,6 +72,7 @@ def test_merge_creates_new_configuration_from_config_hash def test_merge_inherits_current_configuration_attributes new_config = @valid_configuration.merge({}) + assert_equal @valid_configuration.cool_down, new_config.cool_down assert_equal @valid_configuration.cooling_rate, @@ -85,6 +91,7 @@ def test_merge_changing_new_configuration_does_not_affect_original new_config = @valid_configuration.merge({}) new_config.cooling_rate += 0.005 new_config.temperature -= 100 + refute_equal @valid_configuration.cooling_rate, new_config.cooling_rate refute_equal @valid_configuration.temperature, @@ -93,48 +100,48 @@ def test_merge_changing_new_configuration_does_not_affect_original def test_validates_temperature_is_not_negative @valid_configuration.validate! + @valid_configuration.temperature = -100 assert_raises(@error_class, "Initial temperature cannot be negative") do - @valid_configuration.temperature = -100 @valid_configuration.validate! end end def test_validates_cooling_rate_is_not_negative @valid_configuration.validate! + @valid_configuration.cooling_rate = -0.005 assert_raises(@error_class, "Cooling rate cannot be negative") do - @valid_configuration.cooling_rate = -0.005 @valid_configuration.validate! end end def test_validates_cool_down_funtion_is_callable @valid_configuration.validate! + @valid_configuration.cool_down = nil assert_raises(@error_class, "Missing cool down function") do - @valid_configuration.cool_down = nil @valid_configuration.validate! end end def test_validates_energy_calculator_is_callable @valid_configuration.validate! + @valid_configuration.termination_condition = nil assert_raises(@error_class, "Missing energy calculator function") do - @valid_configuration.termination_condition = nil @valid_configuration.validate! end end def test_validates_state_change_is_callable @valid_configuration.validate! + @valid_configuration.energy_calculator = nil assert_raises(@error_class, "Missing state change function") do - @valid_configuration.energy_calculator = nil @valid_configuration.validate! end end def test_validates_termination_condition_is_callable @valid_configuration.validate! + @valid_configuration.state_change = nil assert_raises(@error_class, "Missing termination condition function") do - @valid_configuration.state_change = nil @valid_configuration.validate! end end diff --git a/test/annealing/metal_test.rb b/test/annealing/metal_test.rb index 3afc38a..142c1fc 100644 --- a/test/annealing/metal_test.rb +++ b/test/annealing/metal_test.rb @@ -22,6 +22,7 @@ def test_energy_calls_energy_calculator_with_current_state custom_calculator.expect(:call, 42, [@collection]) local_config = @global_config.merge(energy_calculator: custom_calculator) metal = Annealing::Metal.new(@collection, @temperature, local_config) + assert_equal 42, metal.energy end @@ -29,6 +30,7 @@ def test_cooled_returns_metal_instance_with_new_temperature metal = Annealing::Metal.new(@collection, @temperature) new_temperature = @temperature - 1 cooled_metal = metal.cool!(new_temperature) + assert_instance_of Annealing::Metal, cooled_metal assert_equal new_temperature, cooled_metal.temperature end @@ -48,6 +50,7 @@ def test_cooled_returns_cooled_metal_when_preferred cooled_metal = metal.stub(:prefer?, true) do metal.cool!(new_temperature) end + refute_same metal, cooled_metal refute_equal new_temperature, metal.temperature end @@ -58,6 +61,7 @@ def test_cooled_returns_the_original_metal_when_not_preferred cooled_metal = metal.stub(:prefer?, false) do metal.cool!(new_temperature) end + assert_same metal, cooled_metal assert_equal new_temperature, metal.temperature end diff --git a/test/annealing/simulator_test.rb b/test/annealing/simulator_test.rb index 910a243..bd44abd 100644 --- a/test/annealing/simulator_test.rb +++ b/test/annealing/simulator_test.rb @@ -24,6 +24,7 @@ def setup def test_inherits_global_configuration_by_default simulator_config = @simulator.configuration + assert_equal @global_config.cool_down, simulator_config.cool_down assert_equal @global_config.cooling_rate, @@ -45,6 +46,7 @@ def test_can_specify_custom_configuration_values_on_initialization state_change: ->(state) { state.shuffle }, temperature: 99 ).configuration + refute_equal @global_config.cooling_rate, simulator_config.cooling_rate refute_equal @global_config.energy_calculator, @@ -61,6 +63,7 @@ def test_can_specify_custom_configuration_values_on_run } state = @simulator.run(@collection, termination_condition: termination_condition) + assert_equal @temperature - 10, state.temperature end @@ -86,6 +89,7 @@ def test_runs_simulation_until_termination_condition_is_met final_temp]) state = @simulator.run(@collection, termination_condition: termination_condition) + assert_equal final_temp, state.temperature termination_condition.verify end @@ -99,6 +103,7 @@ def test_uses_cool_down_function_to_reduce_temperature_at_each_step @cooling_rate, step + 1]) end state = @simulator.run(@collection, cool_down: cool_down) + assert_equal 0, state.temperature cool_down.verify end