From 8611d69f62821d3e1c04b7cf432dd54160e7e1c0 Mon Sep 17 00:00:00 2001 From: bibenga <{ID}+{username}@users.noreply.github.com> Date: Sat, 22 Nov 2025 09:13:19 +0000 Subject: [PATCH 1/7] remove rake --- Gemfile | 1 - Gemfile.lock | 2 -- 2 files changed, 3 deletions(-) diff --git a/Gemfile b/Gemfile index f989e32..18abf8b 100644 --- a/Gemfile +++ b/Gemfile @@ -5,7 +5,6 @@ source 'https://rubygems.org' group :development, :test do gem 'bundler-audit', require: false gem 'minitest', '~> 5.26' - gem 'rake', '~> 13.3', require: false gem 'rubocop', '~> 1.81', require: false end diff --git a/Gemfile.lock b/Gemfile.lock index 2f97c7e..1a9eb6f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -16,7 +16,6 @@ GEM prism (1.6.0) racc (1.8.1) rainbow (3.1.1) - rake (13.3.1) regexp_parser (2.11.3) rubocop (1.81.7) json (~> 2.3) @@ -45,7 +44,6 @@ PLATFORMS DEPENDENCIES bundler-audit minitest (~> 5.26) - rake (~> 13.3) rubocop (~> 1.81) BUNDLED WITH From 2ab5c64a639a84f055200658d7b67780d1cb35e7 Mon Sep 17 00:00:00 2001 From: bibenga <{ID}+{username}@users.noreply.github.com> Date: Sat, 22 Nov 2025 09:13:34 +0000 Subject: [PATCH 2/7] add a secure random proxy class --- examples/tsp.rb | 16 ++++++++++++++-- lib/alns/random/random.rb | 17 +++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 lib/alns/random/random.rb diff --git a/examples/tsp.rb b/examples/tsp.rb index 1a22729..f52f29f 100644 --- a/examples/tsp.rb +++ b/examples/tsp.rb @@ -10,23 +10,35 @@ require 'alns/select/roulette_wheel' require 'alns/stop/max_iterations' require 'alns/stop/max_runtime' +require 'alns/random/random' module TSP def self.solve write_dot = false + secure_random = false OptionParser.new do |parser| parser.banner = 'Usage: tsp.rb [options]' - parser.on('-d', '--dot', 'write a dot file with result') do |v| + parser.on('-d', '--dot', 'write a dot file with result') do write_dot = true end + + parser.on('-s', '--secure-random', 'use secure random') do + secure_random = true + end end.parse! nodes = make_nodes(COORDS) dists = make_dists(COORDS) - solver = ALNS::Solver.new(Random.new(1234)) + rnd = if secure_random + ALNS::Random::Random.new + else + Random.new(1234) + end + + solver = ALNS::Solver.new(rnd) init_sol = TspState.new(nodes, {}, dists) init_sol = greedy_repair(init_sol, solver.rnd) diff --git a/lib/alns/random/random.rb b/lib/alns/random/random.rb new file mode 100644 index 0000000..cb95301 --- /dev/null +++ b/lib/alns/random/random.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require 'securerandom' + +module ALNS + module Random + class Random + def rand(max = nil) + if max.nil? + SecureRandom.random_number + else + SecureRandom.random_number(max) + end + end + end + end +end From bbdb72f2600e6f668318c4c43a5612f5612f73db Mon Sep 17 00:00:00 2001 From: bibenga <{ID}+{username}@users.noreply.github.com> Date: Sat, 22 Nov 2025 09:20:39 +0000 Subject: [PATCH 3/7] add a seed as parameter --- examples/tsp.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/examples/tsp.rb b/examples/tsp.rb index f52f29f..f8928fb 100644 --- a/examples/tsp.rb +++ b/examples/tsp.rb @@ -15,6 +15,7 @@ module TSP def self.solve write_dot = false + seed = 1234 secure_random = false OptionParser.new do |parser| @@ -24,7 +25,11 @@ def self.solve write_dot = true end - parser.on('-s', '--secure-random', 'use secure random') do + parser.on('-sSEED', '--seed=SEED', Integer, 'specify seed') do |v| + seed = v + end + + parser.on('-r', '--secure-random', 'use secure random') do secure_random = true end end.parse! @@ -35,7 +40,7 @@ def self.solve rnd = if secure_random ALNS::Random::Random.new else - Random.new(1234) + Random.new(seed) end solver = ALNS::Solver.new(rnd) From 640e5b108de7136f0431744816648a4b7b2016fe Mon Sep 17 00:00:00 2001 From: bibenga <{ID}+{username}@users.noreply.github.com> Date: Sat, 22 Nov 2025 09:22:57 +0000 Subject: [PATCH 4/7] revert a dependency --- Gemfile | 1 + Gemfile.lock | 2 ++ 2 files changed, 3 insertions(+) diff --git a/Gemfile b/Gemfile index 18abf8b..f989e32 100644 --- a/Gemfile +++ b/Gemfile @@ -5,6 +5,7 @@ source 'https://rubygems.org' group :development, :test do gem 'bundler-audit', require: false gem 'minitest', '~> 5.26' + gem 'rake', '~> 13.3', require: false gem 'rubocop', '~> 1.81', require: false end diff --git a/Gemfile.lock b/Gemfile.lock index 1a9eb6f..2f97c7e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -16,6 +16,7 @@ GEM prism (1.6.0) racc (1.8.1) rainbow (3.1.1) + rake (13.3.1) regexp_parser (2.11.3) rubocop (1.81.7) json (~> 2.3) @@ -44,6 +45,7 @@ PLATFORMS DEPENDENCIES bundler-audit minitest (~> 5.26) + rake (~> 13.3) rubocop (~> 1.81) BUNDLED WITH From 2fa48970abf5a0cf0edf02a2493afee2ac286eaf Mon Sep 17 00:00:00 2001 From: bibenga <{ID}+{username}@users.noreply.github.com> Date: Sat, 22 Nov 2025 09:25:47 +0000 Subject: [PATCH 5/7] fix text --- examples/tsp.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/tsp.rb b/examples/tsp.rb index f8928fb..157a4c0 100644 --- a/examples/tsp.rb +++ b/examples/tsp.rb @@ -21,7 +21,7 @@ def self.solve OptionParser.new do |parser| parser.banner = 'Usage: tsp.rb [options]' - parser.on('-d', '--dot', 'write a dot file with result') do + parser.on('-d', '--dot', 'write a dot file with the result') do write_dot = true end From b3a819415e33e86cdad88ed0f8bf3e7db800a03e Mon Sep 17 00:00:00 2001 From: bibenga <{ID}+{username}@users.noreply.github.com> Date: Sat, 22 Nov 2025 09:34:03 +0000 Subject: [PATCH 6/7] add minor optimizations --- examples/tsp.rb | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/examples/tsp.rb b/examples/tsp.rb index 157a4c0..a94630c 100644 --- a/examples/tsp.rb +++ b/examples/tsp.rb @@ -273,17 +273,21 @@ def initialize(nodes, edges, dists) def initialize_copy(original) super - @nodes = original.nodes + # @nodes is frozen @edges = original.edges.dup - @dists = original.dists + # @dists is frozen + @objective = nil end def objective - total_dist = 0.0 - @edges.each do |from, to| - total_dist += @dists[from][to] + if @objective.nil? + total_dist = 0.0 + @edges.each do |from, to| + total_dist += @dists[from][to] + end + @objective = total_dist end - total_dist + @objective end end From fe8e615417c74f5504c1d433073c7c4cbdf17864 Mon Sep 17 00:00:00 2001 From: bibenga <{ID}+{username}@users.noreply.github.com> Date: Sat, 22 Nov 2025 19:05:04 +0000 Subject: [PATCH 7/7] delete close? --- lib/alns/math.rb | 11 +++-------- test/math_test.rb | 5 ----- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/lib/alns/math.rb b/lib/alns/math.rb index f6d5492..e8d07eb 100644 --- a/lib/alns/math.rb +++ b/lib/alns/math.rb @@ -1,12 +1,6 @@ # frozen_string_literal: true module ALNS - EPSILON = 1e-9 - - def self.close?(a, b, epsilon = EPSILON) # rubocop:disable Naming/MethodParameterName - (a - b).abs <= epsilon - end - def self.weighted_random_index(rnd, weights) raise 'Invalid weights: Array is empty' if weights.empty? return 0 if weights.size == 1 @@ -17,9 +11,10 @@ def self.weighted_random_index(rnd, weights) weights.each_with_index do |weight, index| adjusted_value -= weight - return index if adjusted_value <= 0 || close?(adjusted_value, 0) + return index if adjusted_value <= 0 end - raise "Arithmetic error: sum=#{total_sum}, adjusted_value=#{adjusted_value}, weights=#{weights.inspect}" + # we will only be here when errors accumulate + weights.length - 1 end end diff --git a/test/math_test.rb b/test/math_test.rb index 84a87dc..8eecb16 100644 --- a/test/math_test.rb +++ b/test/math_test.rb @@ -9,11 +9,6 @@ def setup @rnd = Random.new(123) end - def test_close - assert ALNS.close?(1, 1.0000000001) - assert !ALNS.close?(1, 1.0000001) - end - def test_weighted_random_index tests = [ { weights: [1.0], want: 0 }, # one element