Compare commits
	
		
			No commits in common. "main" and "vns-perturbations" have entirely different histories.
		
	
	
		
			main
			...
			vns-pertur
		
	
		
| @ -19,7 +19,7 @@ jobs: | ||||
|         ports: | ||||
|           - 5432 | ||||
|     steps: | ||||
|       - uses: actions/checkout@v5 | ||||
|       - uses: actions/checkout@v4 | ||||
|         with: | ||||
|           token: ${{ secrets.GITHUB_TOKEN }} | ||||
|           ref: ${{ github.head_ref }} # Checkout the actual branch, not the result if merged into the base | ||||
| @ -68,7 +68,7 @@ jobs: | ||||
|     if: github.event_name == 'pull_request' | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: actions/checkout@v5 | ||||
|       - uses: actions/checkout@v4 | ||||
|         with: | ||||
|           token: ${{ secrets.GITHUB_TOKEN }} | ||||
|       - uses: ruby/setup-ruby@v1 | ||||
| @ -78,7 +78,7 @@ jobs: | ||||
|     if: github.event_name == 'pull_request' | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|         - uses: actions/checkout@v5 | ||||
|         - uses: actions/checkout@v4 | ||||
|           with: | ||||
|             token: ${{ secrets.GITHUB_TOKEN }} | ||||
|         - uses: ruby/setup-ruby@v1 | ||||
| @ -90,7 +90,7 @@ jobs: | ||||
|     if: github.event_name == 'pull_request' | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: actions/checkout@v5 | ||||
|       - uses: actions/checkout@v4 | ||||
|         with: | ||||
|           token: ${{ secrets.ACTIONS_TOKEN }} | ||||
|           ref: ${{ github.head_ref }} | ||||
| @ -125,7 +125,7 @@ jobs: | ||||
|     needs: | ||||
|       - unit_tests | ||||
|     steps: | ||||
|       - uses: actions/checkout@v5 | ||||
|       - uses: actions/checkout@v4 | ||||
|         with: | ||||
|           token: ${{ secrets.GITHUB_TOKEN }} | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										250
									
								
								Gemfile.lock
									
									
									
									
									
								
							
							
						
						
									
										250
									
								
								Gemfile.lock
									
									
									
									
									
								
							| @ -1,29 +1,29 @@ | ||||
| GEM | ||||
|   remote: https://rubygems.org/ | ||||
|   specs: | ||||
|     actioncable (8.0.2.1) | ||||
|       actionpack (= 8.0.2.1) | ||||
|       activesupport (= 8.0.2.1) | ||||
|     actioncable (8.0.2) | ||||
|       actionpack (= 8.0.2) | ||||
|       activesupport (= 8.0.2) | ||||
|       nio4r (~> 2.0) | ||||
|       websocket-driver (>= 0.6.1) | ||||
|       zeitwerk (~> 2.6) | ||||
|     actionmailbox (8.0.2.1) | ||||
|       actionpack (= 8.0.2.1) | ||||
|       activejob (= 8.0.2.1) | ||||
|       activerecord (= 8.0.2.1) | ||||
|       activestorage (= 8.0.2.1) | ||||
|       activesupport (= 8.0.2.1) | ||||
|     actionmailbox (8.0.2) | ||||
|       actionpack (= 8.0.2) | ||||
|       activejob (= 8.0.2) | ||||
|       activerecord (= 8.0.2) | ||||
|       activestorage (= 8.0.2) | ||||
|       activesupport (= 8.0.2) | ||||
|       mail (>= 2.8.0) | ||||
|     actionmailer (8.0.2.1) | ||||
|       actionpack (= 8.0.2.1) | ||||
|       actionview (= 8.0.2.1) | ||||
|       activejob (= 8.0.2.1) | ||||
|       activesupport (= 8.0.2.1) | ||||
|     actionmailer (8.0.2) | ||||
|       actionpack (= 8.0.2) | ||||
|       actionview (= 8.0.2) | ||||
|       activejob (= 8.0.2) | ||||
|       activesupport (= 8.0.2) | ||||
|       mail (>= 2.8.0) | ||||
|       rails-dom-testing (~> 2.2) | ||||
|     actionpack (8.0.2.1) | ||||
|       actionview (= 8.0.2.1) | ||||
|       activesupport (= 8.0.2.1) | ||||
|     actionpack (8.0.2) | ||||
|       actionview (= 8.0.2) | ||||
|       activesupport (= 8.0.2) | ||||
|       nokogiri (>= 1.8.5) | ||||
|       rack (>= 2.2.4) | ||||
|       rack-session (>= 1.0.1) | ||||
| @ -31,35 +31,35 @@ GEM | ||||
|       rails-dom-testing (~> 2.2) | ||||
|       rails-html-sanitizer (~> 1.6) | ||||
|       useragent (~> 0.16) | ||||
|     actiontext (8.0.2.1) | ||||
|       actionpack (= 8.0.2.1) | ||||
|       activerecord (= 8.0.2.1) | ||||
|       activestorage (= 8.0.2.1) | ||||
|       activesupport (= 8.0.2.1) | ||||
|     actiontext (8.0.2) | ||||
|       actionpack (= 8.0.2) | ||||
|       activerecord (= 8.0.2) | ||||
|       activestorage (= 8.0.2) | ||||
|       activesupport (= 8.0.2) | ||||
|       globalid (>= 0.6.0) | ||||
|       nokogiri (>= 1.8.5) | ||||
|     actionview (8.0.2.1) | ||||
|       activesupport (= 8.0.2.1) | ||||
|     actionview (8.0.2) | ||||
|       activesupport (= 8.0.2) | ||||
|       builder (~> 3.1) | ||||
|       erubi (~> 1.11) | ||||
|       rails-dom-testing (~> 2.2) | ||||
|       rails-html-sanitizer (~> 1.6) | ||||
|     activejob (8.0.2.1) | ||||
|       activesupport (= 8.0.2.1) | ||||
|     activejob (8.0.2) | ||||
|       activesupport (= 8.0.2) | ||||
|       globalid (>= 0.3.6) | ||||
|     activemodel (8.0.2.1) | ||||
|       activesupport (= 8.0.2.1) | ||||
|     activerecord (8.0.2.1) | ||||
|       activemodel (= 8.0.2.1) | ||||
|       activesupport (= 8.0.2.1) | ||||
|     activemodel (8.0.2) | ||||
|       activesupport (= 8.0.2) | ||||
|     activerecord (8.0.2) | ||||
|       activemodel (= 8.0.2) | ||||
|       activesupport (= 8.0.2) | ||||
|       timeout (>= 0.4.0) | ||||
|     activestorage (8.0.2.1) | ||||
|       actionpack (= 8.0.2.1) | ||||
|       activejob (= 8.0.2.1) | ||||
|       activerecord (= 8.0.2.1) | ||||
|       activesupport (= 8.0.2.1) | ||||
|     activestorage (8.0.2) | ||||
|       actionpack (= 8.0.2) | ||||
|       activejob (= 8.0.2) | ||||
|       activerecord (= 8.0.2) | ||||
|       activesupport (= 8.0.2) | ||||
|       marcel (~> 1.0) | ||||
|     activesupport (8.0.2.1) | ||||
|     activesupport (8.0.2) | ||||
|       base64 | ||||
|       benchmark (>= 0.3) | ||||
|       bigdecimal | ||||
| @ -76,7 +76,7 @@ GEM | ||||
|       rails (>= 6.0) | ||||
|     addressable (2.8.7) | ||||
|       public_suffix (>= 2.0.2, < 7.0) | ||||
|     annotaterb (4.19.0) | ||||
|     annotaterb (4.17.0) | ||||
|       activerecord (>= 6.0.0) | ||||
|       activesupport (>= 6.0.0) | ||||
|     ast (2.4.3) | ||||
| @ -87,7 +87,7 @@ GEM | ||||
|     base64 (0.3.0) | ||||
|     bcrypt (3.1.20) | ||||
|     benchmark (0.4.1) | ||||
|     bigdecimal (3.2.3) | ||||
|     bigdecimal (3.2.2) | ||||
|     bindex (0.8.1) | ||||
|     bootsnap (1.18.6) | ||||
|       msgpack (~> 1.2) | ||||
| @ -98,7 +98,7 @@ GEM | ||||
|     chunky_png (1.4.0) | ||||
|     coderay (1.1.3) | ||||
|     concurrent-ruby (1.3.5) | ||||
|     connection_pool (2.5.4) | ||||
|     connection_pool (2.5.3) | ||||
|     crass (1.0.6) | ||||
|     csv (3.3.5) | ||||
|     date (3.4.1) | ||||
| @ -118,9 +118,9 @@ GEM | ||||
|     et-orbi (1.2.11) | ||||
|       tzinfo | ||||
|     execjs (2.9.1) | ||||
|     factory_bot (6.5.5) | ||||
|     factory_bot (6.5.4) | ||||
|       activesupport (>= 6.1.0) | ||||
|     factory_bot_rails (6.5.1) | ||||
|     factory_bot_rails (6.5.0) | ||||
|       factory_bot (~> 6.5) | ||||
|       railties (>= 6.1.0) | ||||
|     faker (3.5.2) | ||||
| @ -136,7 +136,7 @@ GEM | ||||
|       multi_xml (>= 0.5.2) | ||||
|     i18n (1.14.7) | ||||
|       concurrent-ruby (~> 1.0) | ||||
|     importmap-rails (2.2.2) | ||||
|     importmap-rails (2.1.0) | ||||
|       actionpack (>= 6.0.0) | ||||
|       activesupport (>= 6.0.0) | ||||
|       railties (>= 6.0.0) | ||||
| @ -148,7 +148,7 @@ GEM | ||||
|     jbuilder (2.13.0) | ||||
|       actionview (>= 5.0.0) | ||||
|       activesupport (>= 5.0.0) | ||||
|     json (2.13.2) | ||||
|     json (2.12.2) | ||||
|     json-schema (5.0.1) | ||||
|       addressable (~> 2.8) | ||||
|     jsonapi-deserializable (0.2.0) | ||||
| @ -201,7 +201,7 @@ GEM | ||||
|     msgpack (1.7.5) | ||||
|     multi_xml (0.7.1) | ||||
|       bigdecimal (~> 3.1) | ||||
|     net-imap (0.5.10) | ||||
|     net-imap (0.5.6) | ||||
|       date | ||||
|       net-protocol | ||||
|     net-pop (0.1.2) | ||||
| @ -211,37 +211,33 @@ GEM | ||||
|     net-smtp (0.5.1) | ||||
|       net-protocol | ||||
|     nio4r (2.7.4) | ||||
|     nokogiri (1.18.10) | ||||
|     nokogiri (1.18.9) | ||||
|       mini_portile2 (~> 2.8.2) | ||||
|       racc (~> 1.4) | ||||
|     nokogiri (1.18.10-aarch64-linux-gnu) | ||||
|     nokogiri (1.18.9-aarch64-linux-gnu) | ||||
|       racc (~> 1.4) | ||||
|     nokogiri (1.18.10-arm-linux-gnu) | ||||
|     nokogiri (1.18.9-arm-linux-gnu) | ||||
|       racc (~> 1.4) | ||||
|     nokogiri (1.18.10-arm64-darwin) | ||||
|     nokogiri (1.18.9-arm64-darwin) | ||||
|       racc (~> 1.4) | ||||
|     nokogiri (1.18.10-x86_64-darwin) | ||||
|     nokogiri (1.18.9-x86_64-darwin) | ||||
|       racc (~> 1.4) | ||||
|     nokogiri (1.18.10-x86_64-linux-gnu) | ||||
|     nokogiri (1.18.9-x86_64-linux-gnu) | ||||
|       racc (~> 1.4) | ||||
|     orm_adapter (0.5.0) | ||||
|     ostruct (0.6.2) | ||||
|     parallel (1.27.0) | ||||
|     parser (3.3.9.0) | ||||
|     parser (3.3.8.0) | ||||
|       ast (~> 2.4.1) | ||||
|       racc | ||||
|     pg (1.6.2) | ||||
|     pg (1.6.2-aarch64-linux) | ||||
|     pg (1.6.2-arm64-darwin) | ||||
|     pg (1.6.2-x86_64-darwin) | ||||
|     pg (1.6.2-x86_64-linux) | ||||
|     pg (1.5.9) | ||||
|     pluck_to_hash (1.0.2) | ||||
|       activerecord (>= 4.0.2) | ||||
|       activesupport (>= 4.0.2) | ||||
|     pp (0.6.2) | ||||
|       prettyprint | ||||
|     prettyprint (0.2.0) | ||||
|     prism (1.5.1) | ||||
|     prism (1.4.0) | ||||
|     pry (0.15.2) | ||||
|       coderay (~> 1.1) | ||||
|       method_source (~> 1.0) | ||||
| @ -249,11 +245,11 @@ GEM | ||||
|       date | ||||
|       stringio | ||||
|     public_suffix (6.0.1) | ||||
|     puma (6.6.1) | ||||
|     puma (6.6.0) | ||||
|       nio4r (~> 2.0) | ||||
|     raabro (1.4.0) | ||||
|     racc (1.8.1) | ||||
|     rack (3.2.1) | ||||
|     rack (3.1.16) | ||||
|     rack-cors (3.0.0) | ||||
|       logger | ||||
|       rack (>= 3.0.14) | ||||
| @ -264,20 +260,20 @@ GEM | ||||
|       rack (>= 1.3) | ||||
|     rackup (2.2.1) | ||||
|       rack (>= 3) | ||||
|     rails (8.0.2.1) | ||||
|       actioncable (= 8.0.2.1) | ||||
|       actionmailbox (= 8.0.2.1) | ||||
|       actionmailer (= 8.0.2.1) | ||||
|       actionpack (= 8.0.2.1) | ||||
|       actiontext (= 8.0.2.1) | ||||
|       actionview (= 8.0.2.1) | ||||
|       activejob (= 8.0.2.1) | ||||
|       activemodel (= 8.0.2.1) | ||||
|       activerecord (= 8.0.2.1) | ||||
|       activestorage (= 8.0.2.1) | ||||
|       activesupport (= 8.0.2.1) | ||||
|     rails (8.0.2) | ||||
|       actioncable (= 8.0.2) | ||||
|       actionmailbox (= 8.0.2) | ||||
|       actionmailer (= 8.0.2) | ||||
|       actionpack (= 8.0.2) | ||||
|       actiontext (= 8.0.2) | ||||
|       actionview (= 8.0.2) | ||||
|       activejob (= 8.0.2) | ||||
|       activemodel (= 8.0.2) | ||||
|       activerecord (= 8.0.2) | ||||
|       activestorage (= 8.0.2) | ||||
|       activesupport (= 8.0.2) | ||||
|       bundler (>= 1.15.0) | ||||
|       railties (= 8.0.2.1) | ||||
|       railties (= 8.0.2) | ||||
|     rails-dom-testing (2.3.0) | ||||
|       activesupport (>= 5.0.0) | ||||
|       minitest | ||||
| @ -285,9 +281,9 @@ GEM | ||||
|     rails-html-sanitizer (1.6.2) | ||||
|       loofah (~> 2.21) | ||||
|       nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) | ||||
|     railties (8.0.2.1) | ||||
|       actionpack (= 8.0.2.1) | ||||
|       activesupport (= 8.0.2.1) | ||||
|     railties (8.0.2) | ||||
|       actionpack (= 8.0.2) | ||||
|       activesupport (= 8.0.2) | ||||
|       irb (~> 1.13) | ||||
|       rackup (>= 1.0.0) | ||||
|       rake (>= 12.2) | ||||
| @ -308,7 +304,7 @@ GEM | ||||
|       redis-client (>= 0.22.0) | ||||
|     redis-client (0.23.2) | ||||
|       connection_pool | ||||
|     regexp_parser (2.11.3) | ||||
|     regexp_parser (2.10.0) | ||||
|     reline (0.6.2) | ||||
|       io-console (~> 0.5) | ||||
|     responders (3.1.1) | ||||
| @ -319,7 +315,7 @@ GEM | ||||
|       chunky_png (~> 1.0) | ||||
|       rqrcode_core (~> 2.0) | ||||
|     rqrcode_core (2.0.0) | ||||
|     rspec-core (3.13.5) | ||||
|     rspec-core (3.13.4) | ||||
|       rspec-support (~> 3.13.0) | ||||
|     rspec-expectations (3.13.5) | ||||
|       diff-lcs (>= 1.2.0, < 2.0) | ||||
| @ -327,7 +323,7 @@ GEM | ||||
|     rspec-mocks (3.13.5) | ||||
|       diff-lcs (>= 1.2.0, < 2.0) | ||||
|       rspec-support (~> 3.13.0) | ||||
|     rspec-rails (8.0.2) | ||||
|     rspec-rails (8.0.1) | ||||
|       actionpack (>= 7.2) | ||||
|       activesupport (>= 7.2) | ||||
|       railties (>= 7.2) | ||||
| @ -335,7 +331,7 @@ GEM | ||||
|       rspec-expectations (~> 3.13) | ||||
|       rspec-mocks (~> 3.13) | ||||
|       rspec-support (~> 3.13) | ||||
|     rspec-support (3.13.5) | ||||
|     rspec-support (3.13.4) | ||||
|     rswag (2.16.0) | ||||
|       rswag-api (= 2.16.0) | ||||
|       rswag-specs (= 2.16.0) | ||||
| @ -351,7 +347,7 @@ GEM | ||||
|     rswag-ui (2.16.0) | ||||
|       actionpack (>= 5.2, < 8.1) | ||||
|       railties (>= 5.2, < 8.1) | ||||
|     rubocop (1.80.2) | ||||
|     rubocop (1.78.0) | ||||
|       json (~> 2.3) | ||||
|       language_server-protocol (~> 3.17.0.2) | ||||
|       lint_roller (~> 1.1.0) | ||||
| @ -359,16 +355,16 @@ GEM | ||||
|       parser (>= 3.3.0.2) | ||||
|       rainbow (>= 2.2.2, < 4.0) | ||||
|       regexp_parser (>= 2.9.3, < 3.0) | ||||
|       rubocop-ast (>= 1.46.0, < 2.0) | ||||
|       rubocop-ast (>= 1.45.1, < 2.0) | ||||
|       ruby-progressbar (~> 1.7) | ||||
|       unicode-display_width (>= 2.4.0, < 4.0) | ||||
|     rubocop-ast (1.46.0) | ||||
|     rubocop-ast (1.45.1) | ||||
|       parser (>= 3.3.7.2) | ||||
|       prism (~> 1.4) | ||||
|     rubocop-factory_bot (2.27.1) | ||||
|       lint_roller (~> 1.1) | ||||
|       rubocop (~> 1.72, >= 1.72.1) | ||||
|     rubocop-rails (2.33.3) | ||||
|     rubocop-rails (2.32.0) | ||||
|       activesupport (>= 4.2.0) | ||||
|       lint_roller (~> 1.1) | ||||
|       rack (>= 1.1) | ||||
| @ -405,7 +401,7 @@ GEM | ||||
|     stimulus-rails (1.3.4) | ||||
|       railties (>= 6.0.0) | ||||
|     stringio (3.1.7) | ||||
|     thor (1.4.0) | ||||
|     thor (1.3.2) | ||||
|     tilt (2.4.0) | ||||
|     timeout (0.4.3) | ||||
|     tomlrb (2.0.3) | ||||
| @ -488,27 +484,27 @@ DEPENDENCIES | ||||
|   wicked_pdf (~> 2.8) | ||||
| 
 | ||||
| CHECKSUMS | ||||
|   actioncable (8.0.2.1) sha256=6f1cb20db39fba28a93569e8d5dab42b2749d7ddd4baebb5bbecd4217e49d6a2 | ||||
|   actionmailbox (8.0.2.1) sha256=8ea8c6e31e448961c06fc1d6282775b32aff1c009f232d4564e07e54850a6cad | ||||
|   actionmailer (8.0.2.1) sha256=0de14d8d04541eab130858cb2f0697266be42de1afe1104bc43d7998137ddb9c | ||||
|   actionpack (8.0.2.1) sha256=61e7e11a31dbe5152ca57221788bdca42ef302c4cc53b4c8993d68dce8982b0a | ||||
|   actiontext (8.0.2.1) sha256=0cc4b3b5cfb9d915c6697b05b013dad7f4eaf074d9989700b6a0a55cf620d6b8 | ||||
|   actionview (8.0.2.1) sha256=2ea6d20ccb0b7b84a221a940ac06853ce99235e4ecb4947815839c7c5ecbf347 | ||||
|   activejob (8.0.2.1) sha256=d6e5f2da07ec8efac13a38af1752416770dc74e95783f7b252506d707aa32b89 | ||||
|   activemodel (8.0.2.1) sha256=17bab6cdb86531844113df22f864480a89a276bf0318246e628f99e0ac077ec4 | ||||
|   activerecord (8.0.2.1) sha256=a6556e7bdd53f3889d18d2aa3a7ff115fd6c5e1463dd06f97fb88d06b58c6df1 | ||||
|   activestorage (8.0.2.1) sha256=43bb3d9e115471e201e6a66813810c1d15b607a321f29d62efdf9d90ffaf76f8 | ||||
|   activesupport (8.0.2.1) sha256=0405a76fd1ca989975d9ae00d46a4d3979bdf3817482d846b63affa84bd561c6 | ||||
|   actioncable (8.0.2) sha256=7bcce2df62e91a80143592600e16583c273e98aab50ae40a9f6a2604bb3289a0 | ||||
|   actionmailbox (8.0.2) sha256=3d8fb3453913e6257da4d02004bbfa2b997dfd10672f8d990e95013983e2cedb | ||||
|   actionmailer (8.0.2) sha256=b0c968b38576ec56a3dc2795931818e0aaae6a18cc9801f53f175c12d4b277d0 | ||||
|   actionpack (8.0.2) sha256=93e703064f3815295ccf820f57acbca719aec836749597da9262781c9b2f4b78 | ||||
|   actiontext (8.0.2) sha256=a40db32032ee2fbb479d5d69318c4284344c1cda73836fd73ffcdb917d203abf | ||||
|   actionview (8.0.2) sha256=e038e1405cdfc18f04f17243da4fb8eeda3a4992f63a6d70a7281d255cf7cebb | ||||
|   activejob (8.0.2) sha256=b0228b45e36b1ef3a081c684e81494147e094a6baf729018756ccf125b1853ca | ||||
|   activemodel (8.0.2) sha256=0ae1fb7fa1fae0699ba041a9e97702df42ea3b13f2d39f2d0fde51fca5f0656c | ||||
|   activerecord (8.0.2) sha256=793470b92c44e4198d0262ac60086b7822f0ea585079ad67e32a6e4c86f2d90a | ||||
|   activestorage (8.0.2) sha256=f83d221e0f06ae38f2200e55490bd155c76d0add330f6e300e8646048d672977 | ||||
|   activesupport (8.0.2) sha256=8565cddba31b900cdc17682fd66ecd020441e3eef320a9930285394e8c07a45e | ||||
|   acts_as_tenant (1.0.1) sha256=6944e4d64533337938a8817a6b4ff9b11189c9dcc0b1333bb89f3821a4c14c53 | ||||
|   addressable (2.8.7) sha256=462986537cf3735ab5f3c0f557f14155d778f4b43ea4f485a9deb9c8f7c58232 | ||||
|   annotaterb (4.19.0) sha256=c951df62059b3ac1ae383f4140bf935a140a15b6461f8d9a97d34b38ce2c7208 | ||||
|   annotaterb (4.17.0) sha256=f0338f8aaadd5c47fa3deaccb560a54abcdde29aca6f69f4b94726ea9256b4bd | ||||
|   ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383 | ||||
|   babel-source (5.8.35) sha256=79ef222a9dcb867ac2efa3b0da35b4bcb15a4bfa67b6b2dcbf1e9a29104498d9 | ||||
|   babel-transpiler (0.7.0) sha256=4c06f4ad9e8e1cabe94f99e11df2f140bb72aca9ba067dbb49dc14d9b98d1570 | ||||
|   base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b | ||||
|   bcrypt (3.1.20) sha256=8410f8c7b3ed54a3c00cd2456bf13917d695117f033218e2483b2e40b0784099 | ||||
|   benchmark (0.4.1) sha256=d4ef40037bba27f03b28013e219b950b82bace296549ec15a78016552f8d2cce | ||||
|   bigdecimal (3.2.3) sha256=ffd11d1ac67a0d3b2f44aec0a6487210b3f813f363dd11f1fcccf5ba00da4e1b | ||||
|   bigdecimal (3.2.2) sha256=39085f76b495eb39a79ce07af716f3a6829bc35eb44f2195e2753749f2fa5adc | ||||
|   bindex (0.8.1) sha256=7b1ecc9dc539ed8bccfc8cb4d2732046227b09d6f37582ff12e50a5047ceb17e | ||||
|   bootsnap (1.18.6) sha256=0ae2393c1e911e38be0f24e9173e7be570c3650128251bf06240046f84a07d00 | ||||
|   builder (3.3.0) sha256=497918d2f9dca528fdca4b88d84e4ef4387256d984b8154e9d5d3fe5a9c8835f | ||||
| @ -517,7 +513,7 @@ CHECKSUMS | ||||
|   chunky_png (1.4.0) sha256=89d5b31b55c0cf4da3cf89a2b4ebc3178d8abe8cbaf116a1dba95668502fdcfe | ||||
|   coderay (1.1.3) sha256=dc530018a4684512f8f38143cd2a096c9f02a1fc2459edcfe534787a7fc77d4b | ||||
|   concurrent-ruby (1.3.5) sha256=813b3e37aca6df2a21a3b9f1d497f8cbab24a2b94cab325bffe65ee0f6cbebc6 | ||||
|   connection_pool (2.5.4) sha256=e9e1922327416091f3f6542f5f4446c2a20745276b9aa796dd0bb2fd0ea1e70a | ||||
|   connection_pool (2.5.3) sha256=cfd74a82b9b094d1ce30c4f1a346da23ee19dc8a062a16a85f58eab1ced4305b | ||||
|   crass (1.0.6) sha256=dc516022a56e7b3b156099abc81b6d2b08ea1ed12676ac7a5657617f012bd45d | ||||
|   csv (3.3.5) sha256=6e5134ac3383ef728b7f02725d9872934f523cb40b961479f69cf3afa6c8e73f | ||||
|   date (3.4.1) sha256=bf268e14ef7158009bfeaec40b5fa3c7271906e88b196d958a89d4b408abe64f | ||||
| @ -529,18 +525,18 @@ CHECKSUMS | ||||
|   erubi (1.13.1) sha256=a082103b0885dbc5ecf1172fede897f9ebdb745a4b97a5e8dc63953db1ee4ad9 | ||||
|   et-orbi (1.2.11) sha256=d26e868cc21db88280a9ec1a50aa3da5d267eb9b2037ba7b831d6c2731f5df64 | ||||
|   execjs (2.9.1) sha256=e8fd066f6df60c8e8fbebc32c6fb356b5212c77374e8416a9019ca4bb154dcfb | ||||
|   factory_bot (6.5.5) sha256=ce59295daee1b4704dab8a2fee6816f513d467c6aa3bc587860767d74a66efbe | ||||
|   factory_bot_rails (6.5.1) sha256=d3cc4851eae4dea8a665ec4a4516895045e710554d2b5ac9e68b94d351bc6d68 | ||||
|   factory_bot (6.5.4) sha256=4707fb7d80a7c14d71feb069460587bfc342e4ff1ef28097e0ad69d5ddfce613 | ||||
|   factory_bot_rails (6.5.0) sha256=4a7b61635424a57cc60412a18b72b9dcfb02fabfce2c930447a01dce8b37c0a2 | ||||
|   faker (3.5.2) sha256=f9a80291b2e3f259801d1dd552f0732fe04dce5d1f74e798365bc0413789c473 | ||||
|   fugit (1.11.1) sha256=e89485e7be22226d8e9c6da411664d0660284b4b1c08cacb540f505907869868 | ||||
|   globalid (1.2.1) sha256=70bf76711871f843dbba72beb8613229a49429d1866828476f9c9d6ccc327ce9 | ||||
|   httparty (0.23.1) sha256=3ac1dd62f2010f6ece551716f5ceec2b2012011d89f1751917ab7f724e966b55 | ||||
|   i18n (1.14.7) sha256=ceba573f8138ff2c0915427f1fc5bdf4aa3ab8ae88c8ce255eb3ecf0a11a5d0f | ||||
|   importmap-rails (2.2.2) sha256=729f5b1092f832780829ade1d0b46c7e53d91c556f06da7254da2977e93fe614 | ||||
|   importmap-rails (2.1.0) sha256=9f10c67d60651a547579f448100d033df311c5d5db578301374aeb774faae741 | ||||
|   io-console (0.8.1) sha256=1e15440a6b2f67b6ea496df7c474ed62c860ad11237f29b3bd187f054b925fcb | ||||
|   irb (1.15.2) sha256=222f32952e278da34b58ffe45e8634bf4afc2dc7aa9da23fed67e581aa50fdba | ||||
|   jbuilder (2.13.0) sha256=7200a38a1c0081aa81b7a9757e7a299db75bc58cf1fd45ca7919a91627d227d6 | ||||
|   json (2.13.2) sha256=02e1f118d434c6b230a64ffa5c8dee07e3ec96244335c392eaed39e1199dbb68 | ||||
|   json (2.12.2) sha256=ba94a48ad265605c8fa9a50a5892f3ba6a02661aa010f638211f3cb36f44abf4 | ||||
|   json-schema (5.0.1) sha256=bef71a82c600a42594911553522e143f7634affc198ed507ef3ded2f920a74a9 | ||||
|   jsonapi-deserializable (0.2.0) sha256=5f0ca2d3f8404cce1584a314e8a3753be32a56054c942adfe997b87e92bce147 | ||||
|   jsonapi-parser (0.1.1) sha256=9ee0dc031e88fc7548d56fab66f9716d1e1c06f972b529b8c4617bc42a097020 | ||||
| @ -565,70 +561,66 @@ CHECKSUMS | ||||
|   money (6.19.0) sha256=ec936fa1e42f2783719241ed9fd52725d0efa628f928feea1eb5c37d5de7daf3 | ||||
|   msgpack (1.7.5) sha256=ffb04979f51e6406823c03abe50e1da2c825c55a37dee138518cdd09d9d3aea8 | ||||
|   multi_xml (0.7.1) sha256=4fce100c68af588ff91b8ba90a0bb3f0466f06c909f21a32f4962059140ba61b | ||||
|   net-imap (0.5.10) sha256=f84d206a296bff48a3a10507567fc38b050d2a40c92ea0d448164f64e60d6205 | ||||
|   net-imap (0.5.6) sha256=1ede8048ee688a14206060bf37a716d18cb6ea00855f6c9b15daee97ee51fbe5 | ||||
|   net-pop (0.1.2) sha256=848b4e982013c15b2f0382792268763b748cce91c9e91e36b0f27ed26420dff3 | ||||
|   net-protocol (0.2.2) sha256=aa73e0cba6a125369de9837b8d8ef82a61849360eba0521900e2c3713aa162a8 | ||||
|   net-smtp (0.5.1) sha256=ed96a0af63c524fceb4b29b0d352195c30d82dd916a42f03c62a3a70e5b70736 | ||||
|   nio4r (2.7.4) sha256=d95dee68e0bb251b8ff90ac3423a511e3b784124e5db7ff5f4813a220ae73ca9 | ||||
|   nokogiri (1.18.10) sha256=d5cc0731008aa3b3a87b361203ea3d19b2069628cb55e46ac7d84a0445e69cc1 | ||||
|   nokogiri (1.18.10-aarch64-linux-gnu) sha256=7fb87235d729c74a2be635376d82b1d459230cc17c50300f8e4fcaabc6195344 | ||||
|   nokogiri (1.18.10-arm-linux-gnu) sha256=51f4f25ab5d5ba1012d6b16aad96b840a10b067b93f35af6a55a2c104a7ee322 | ||||
|   nokogiri (1.18.10-arm64-darwin) sha256=c2b0de30770f50b92c9323fa34a4e1cf5a0af322afcacd239cd66ee1c1b22c85 | ||||
|   nokogiri (1.18.10-x86_64-darwin) sha256=536e74bed6db2b5076769cab5e5f5af0cd1dccbbd75f1b3e1fa69d1f5c2d79e2 | ||||
|   nokogiri (1.18.10-x86_64-linux-gnu) sha256=ff5ba26ba2dbce5c04b9ea200777fd225061d7a3930548806f31db907e500f72 | ||||
|   nokogiri (1.18.9) sha256=ac5a7d93fd0e3cef388800b037407890882413feccca79eb0272a2715a82fa33 | ||||
|   nokogiri (1.18.9-aarch64-linux-gnu) sha256=5bcfdf7aa8d1056a7ad5e52e1adffc64ef53d12d0724fbc6f458a3af1a4b9e32 | ||||
|   nokogiri (1.18.9-arm-linux-gnu) sha256=fe611ae65880e445a9c0f650d52327db239f3488626df4173c05beafd161d46e | ||||
|   nokogiri (1.18.9-arm64-darwin) sha256=eea3f1f06463ff6309d3ff5b88033c4948d0da1ab3cc0a3a24f63c4d4a763979 | ||||
|   nokogiri (1.18.9-x86_64-darwin) sha256=e0d2deb03d3d7af8016e8c9df5ff4a7d692159cefb135cbb6a4109f265652348 | ||||
|   nokogiri (1.18.9-x86_64-linux-gnu) sha256=b52f5defedc53d14f71eeaaf990da66b077e1918a2e13088b6a96d0230f44360 | ||||
|   orm_adapter (0.5.0) sha256=aa5d0be5d540cbb46d3a93e88061f4ece6a25f6e97d6a47122beb84fe595e9b9 | ||||
|   ostruct (0.6.2) sha256=6d7302a299e400a2c248d6ce0dad18fc3a5714e8096facc25ffd0c54ee57cfc0 | ||||
|   parallel (1.27.0) sha256=4ac151e1806b755fb4e2dc2332cbf0e54f2e24ba821ff2d3dcf86bf6dc4ae130 | ||||
|   parser (3.3.9.0) sha256=94d6929354b1a6e3e1f89d79d4d302cc8f5aa814431a6c9c7e0623335d7687f2 | ||||
|   pg (1.6.2) sha256=58614afd405cc9c2c9e15bffe8432e0d6cfc58b722344ad4a47c73a85189c875 | ||||
|   pg (1.6.2-aarch64-linux) sha256=0503c6be5b0ca5ca3aaf91f2ed638f90843313cb81e8e7d7b60ad4bb62c3d131 | ||||
|   pg (1.6.2-arm64-darwin) sha256=4d44500b28d5193b26674583d199a6484f80f1f2ea9cf54f7d7d06a1b7e316b6 | ||||
|   pg (1.6.2-x86_64-darwin) sha256=c441a55723584e2ae41749bf26024d7ffdfe1841b442308ed50cd6b7fda04115 | ||||
|   pg (1.6.2-x86_64-linux) sha256=525f438137f2d1411a1ebcc4208ec35cb526b5a3b285a629355c73208506a8ea | ||||
|   parser (3.3.8.0) sha256=2476364142b307fa5a1b1ece44f260728be23858a9c71078e956131a75453c45 | ||||
|   pg (1.5.9) sha256=761efbdf73b66516f0c26fcbe6515dc7500c3f0aa1a1b853feae245433c64fdc | ||||
|   pluck_to_hash (1.0.2) sha256=1599906239716f98262a41493dd7d4cb72e8d83ad3d76d666deacfc5de50a47e | ||||
|   pp (0.6.2) sha256=947ec3120c6f92195f8ee8aa25a7b2c5297bb106d83b41baa02983686577b6ff | ||||
|   prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193 | ||||
|   prism (1.5.1) sha256=b40c1b76ccb9fcccc3d1553967cda6e79fa7274d8bfea0d98b15d27a6d187134 | ||||
|   prism (1.4.0) sha256=dc0e3e00e93160213dc2a65519d9002a4a1e7b962db57d444cf1a71565bb703e | ||||
|   pry (0.15.2) sha256=12d54b8640d3fa29c9211dd4ffb08f3fd8bf7a4fd9b5a73ce5b59c8709385b6b | ||||
|   psych (5.2.6) sha256=814328aa5dcb6d604d32126a20bc1cbcf05521a5b49dbb1a8b30a07e580f316e | ||||
|   public_suffix (6.0.1) sha256=61d44e1cab5cbbbe5b31068481cf16976dd0dc1b6b07bd95617ef8c5e3e00c6f | ||||
|   puma (6.6.1) sha256=b9b56e4a4ea75d1bfa6d9e1972ee2c9f43d0883f011826d914e8e37b3694ea1e | ||||
|   puma (6.6.0) sha256=f25c06873eb3d5de5f0a4ebc783acc81a4ccfe580c760cfe323497798018ad87 | ||||
|   raabro (1.4.0) sha256=d4fa9ff5172391edb92b242eed8be802d1934b1464061ae5e70d80962c5da882 | ||||
|   racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f | ||||
|   rack (3.2.1) sha256=30af3f7e5ec21b0d14d822cf24446048dba5f651b617c7e97405b604f20a9e33 | ||||
|   rack (3.1.16) sha256=efb5606c351efc56b85b10c3493055d0d35209d23f44792ec4e1183eb0234635 | ||||
|   rack-cors (3.0.0) sha256=7b95be61db39606906b61b83bd7203fa802b0ceaaad8fcb2fef39e097bf53f68 | ||||
|   rack-session (2.1.1) sha256=0b6dc07dea7e4b583f58a48e8b806d4c9f1c6c9214ebc202ec94562cbea2e4e9 | ||||
|   rack-test (2.2.0) sha256=005a36692c306ac0b4a9350355ee080fd09ddef1148a5f8b2ac636c720f5c463 | ||||
|   rackup (2.2.1) sha256=f737191fd5c5b348b7f0a4412a3b86383f88c43e13b8217b63d4c8d90b9e798d | ||||
|   rails (8.0.2.1) sha256=13ab95615569e74e364384b346b1d83e4795dbde83d9edf584e8768e8049b3ac | ||||
|   rails (8.0.2) sha256=fdfaa5a83ec0388e02864e88d515959caedc88053b5f701c4deb1652d8f164c6 | ||||
|   rails-dom-testing (2.3.0) sha256=8acc7953a7b911ca44588bf08737bc16719f431a1cc3091a292bca7317925c1d | ||||
|   rails-html-sanitizer (1.6.2) sha256=35fce2ca8242da8775c83b6ba9c1bcaad6751d9eb73c1abaa8403475ab89a560 | ||||
|   railties (8.0.2.1) sha256=54e40e1771fc2878f572d5a4e076cddb057ba8d4d471f8b7d9bfc61bc1301d4c | ||||
|   railties (8.0.2) sha256=0d7c3f40c49ba74980f1bac1d4bb153a9331c5ee8a9631d89c7bf79db82e5cf9 | ||||
|   rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a | ||||
|   rake (13.3.0) sha256=96f5092d786ff412c62fde76f793cc0541bd84d2eb579caa529aa8a059934493 | ||||
|   rdoc (6.14.2) sha256=9fdd44df130f856ae70cc9a264dfd659b9b40de369b16581f4ab746e42439226 | ||||
|   react-rails (3.2.1) sha256=2235db0b240517596b1cb3e26177ab5bc64d3a56579b0415ee242b1691f81f64 | ||||
|   redis (5.4.1) sha256=b5e675b57ad22b15c9bcc765d5ac26f60b675408af916d31527af9bd5a81faae | ||||
|   redis-client (0.23.2) sha256=e33bab6682c8155cfef95e6dd296936bb9c2981a89fb578ace27a076fa2836fa | ||||
|   regexp_parser (2.11.3) sha256=ca13f381a173b7a93450e53459075c9b76a10433caadcb2f1180f2c741fc55a4 | ||||
|   regexp_parser (2.10.0) sha256=cb6f0ddde88772cd64bff1dbbf68df66d376043fe2e66a9ef77fcb1b0c548c61 | ||||
|   reline (0.6.2) sha256=1dad26a6008872d59c8e05244b119347c9f2ddaf4a53dce97856cd5f30a02846 | ||||
|   responders (3.1.1) sha256=92f2a87e09028347368639cfb468f5fefa745cb0dc2377ef060db1cdd79a341a | ||||
|   rexml (3.3.9) sha256=d71875b85299f341edf47d44df0212e7658cbdf35aeb69cefdb63f57af3137c9 | ||||
|   rqrcode (3.1.0) sha256=e2d5996375f6e9a013823c289ed575dbea678b8e0388574302c1fac563f098af | ||||
|   rqrcode_core (2.0.0) sha256=1e40b823ab57a96482a417fff5dd5c33645a00cea6ef5d9e342fecc5ef91d9ab | ||||
|   rspec-core (3.13.5) sha256=ab3f682897c6131c67f9a17cfee5022a597f283aebe654d329a565f9937a4fa3 | ||||
|   rspec-core (3.13.4) sha256=f9da156b7b775c82610a7b580624df51a55102f8c8e4a103b98f5d7a9fa23958 | ||||
|   rspec-expectations (3.13.5) sha256=33a4d3a1d95060aea4c94e9f237030a8f9eae5615e9bd85718fe3a09e4b58836 | ||||
|   rspec-mocks (3.13.5) sha256=e4338a6f285ada9fe56f5893f5457783af8194f5d08884d17a87321d5195ea81 | ||||
|   rspec-rails (8.0.2) sha256=113139a53f5d068d4f48d1c29ad5f982013ed9b0daa69d7f7b266eda5d433ace | ||||
|   rspec-support (3.13.5) sha256=add745af535dd14b18f1209ab41ef987fdfad12786176b6a3b3619b9a7279fbf | ||||
|   rspec-rails (8.0.1) sha256=0c3700b10ab6d7c648c4cd554023d8c2b5b07e7f01205f7608f0c511cf686505 | ||||
|   rspec-support (3.13.4) sha256=184b1814f6a968102b57df631892c7f1990a91c9a3b9e80ef892a0fc2a71a3f7 | ||||
|   rswag (2.16.0) sha256=f07ce41548b9bb51464c38bc7b95af22fee84b90f2d1197a515a623906353086 | ||||
|   rswag-api (2.16.0) sha256=b653f7bd92e98be18b01ab4525d88950d7b0960e293a99f856b9efcee3ae6074 | ||||
|   rswag-specs (2.16.0) sha256=8ba26085c408b0bd2ed21dc8015c80f417c7d34c63720ab7133c2549b5bd2a91 | ||||
|   rswag-ui (2.16.0) sha256=a1f49e927dceda92e6e6e7c1000f1e217ee66c565f69e28131dc98b33cd3a04f | ||||
|   rubocop (1.80.2) sha256=6485f30fefcf5c199db3b91e5e253b1ef43f7e564784e2315255809a3dd9abf4 | ||||
|   rubocop-ast (1.46.0) sha256=0da7f6ad5b98614f89b74f11873c191059c823eae07d6ffd40a42a3338f2232b | ||||
|   rubocop (1.78.0) sha256=8b74a6f912eb4fd3e6878851f7f7f45dcad8c7185c34250d4f952b0ee80d6bc0 | ||||
|   rubocop-ast (1.45.1) sha256=94042e49adc17f187ba037b33f941ba7398fede77cdf4bffafba95190a473a3e | ||||
|   rubocop-factory_bot (2.27.1) sha256=9d744b5916778c1848e5fe6777cc69855bd96548853554ec239ba9961b8573fe | ||||
|   rubocop-rails (2.33.3) sha256=848c011b58c1292f3066246c9eb18abf6ffcfbce28bc57c4ab888bbec79af74b | ||||
|   rubocop-rails (2.32.0) sha256=9fcc623c8722fe71e835e99c4a18b740b5b0d3fb69915d7f0777f00794b30490 | ||||
|   rubocop-rspec (3.6.0) sha256=c0e4205871776727e54dee9cc91af5fd74578001551ba40e1fe1a1ab4b404479 | ||||
|   rubocop-rspec_rails (2.31.0) sha256=775375e18a26a1184a812ef3054b79d218e85601b9ae897f38f8be24dddf1f45 | ||||
|   ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33 | ||||
| @ -641,7 +633,7 @@ CHECKSUMS | ||||
|   sprockets-rails (3.5.2) sha256=a9e88e6ce9f8c912d349aa5401509165ec42326baf9e942a85de4b76dbc4119e | ||||
|   stimulus-rails (1.3.4) sha256=765676ffa1f33af64ce026d26b48e8ffb2e0b94e0f50e9119e11d6107d67cb06 | ||||
|   stringio (3.1.7) sha256=5b78b7cb242a315fb4fca61a8255d62ec438f58da2b90be66048546ade4507fa | ||||
|   thor (1.4.0) sha256=8763e822ccb0f1d7bee88cde131b19a65606657b847cc7b7b4b82e772bcd8a3d | ||||
|   thor (1.3.2) sha256=eef0293b9e24158ccad7ab383ae83534b7ad4ed99c09f96f1a6b036550abbeda | ||||
|   tilt (2.4.0) sha256=df74f29a451daed26591a85e8e0cebb198892cb75b6573394303acda273fba4d | ||||
|   timeout (0.4.3) sha256=9509f079b2b55fe4236d79633bd75e34c1c1e7e3fb4b56cb5fda61f80a0fe30e | ||||
|   tomlrb (2.0.3) sha256=c2736acf24919f793334023a4ff396c0647d93fce702a73c9d348deaa815d4f7 | ||||
|  | ||||
| @ -9,10 +9,10 @@ class TablesArrangementsController < ApplicationController | ||||
|     render json: TablesArrangement | ||||
|       .order(valid: :desc) | ||||
|       .order(discomfort: :asc) | ||||
|       .select(:id, :name, :discomfort, :status, :progress) | ||||
|       .select("digest = '#{current_digest}'::uuid OR discomfort IS NULL as valid") | ||||
|       .select(:id, :name, :discomfort) | ||||
|       .select("digest = '#{current_digest}'::uuid as valid") | ||||
|       .limit(20) | ||||
|       .as_json(only: %i[id name discomfort valid status progress]) | ||||
|       .as_json(only: %i[id name discomfort valid]) | ||||
|   end | ||||
| 
 | ||||
|   def show | ||||
| @ -25,10 +25,7 @@ class TablesArrangementsController < ApplicationController | ||||
|   end | ||||
| 
 | ||||
|   def create | ||||
|     ActiveRecord::Base.transaction do | ||||
|       tables_arrangement = TablesArrangement.create!(status: :not_started) | ||||
|       TableSimulatorJob.perform_later(current_tenant.id, tables_arrangement.id) | ||||
|     end | ||||
|     TableSimulatorJob.perform_later(current_tenant.id) | ||||
| 
 | ||||
|     render json: {}, status: :created | ||||
|   end | ||||
|  | ||||
| @ -8,35 +8,16 @@ class TableSimulatorJob < ApplicationJob | ||||
|   MIN_PER_TABLE = 8 | ||||
|   MAX_PER_TABLE = 10 | ||||
| 
 | ||||
|   def perform(wedding_id, tables_arrangement_id) # rubocop:disable Metrics/MethodLength | ||||
|     Rails.logger.info "Starting table simulation #{tables_arrangement_id} for wedding #{wedding_id}" | ||||
|   def perform(wedding_id) | ||||
|     ActsAsTenant.with_tenant(Wedding.find(wedding_id)) do | ||||
|       engine = VNS::Engine.new | ||||
| 
 | ||||
|       engine.add_optimization(Tables::Swap) | ||||
|       engine.add_optimization(Tables::Shift) | ||||
| 
 | ||||
|       tables_arrangement = TablesArrangement.find(tables_arrangement_id) | ||||
| 
 | ||||
|       initial_solution = Tables::Distribution.new( | ||||
|         min_per_table: MIN_PER_TABLE, | ||||
|         max_per_table: MAX_PER_TABLE, | ||||
|         tables_arrangement_id: | ||||
|       ) | ||||
| 
 | ||||
|       initial_solution = Tables::Distribution.new(min_per_table: MIN_PER_TABLE, max_per_table: MAX_PER_TABLE) | ||||
|       initial_solution.random_distribution(Guest.potential.shuffle) | ||||
| 
 | ||||
|       initial_solution.save! | ||||
| 
 | ||||
|       engine.notify_progress do |current_progress| | ||||
|         tables_arrangement.update_columns(status: :in_progress, progress: current_progress) | ||||
|       end | ||||
| 
 | ||||
|       engine.on_better_solution do |better_solution| | ||||
|         better_solution.save! | ||||
|         tables_arrangement.update_columns(discomfort: better_solution.discomfort) # TODO: remove? | ||||
|       end | ||||
| 
 | ||||
|       engine.initial_solution = initial_solution | ||||
| 
 | ||||
|       engine.target_function(&:discomfort) | ||||
| @ -44,8 +25,6 @@ class TableSimulatorJob < ApplicationJob | ||||
|       best_solution = engine.run | ||||
| 
 | ||||
|       best_solution.save! | ||||
| 
 | ||||
|       tables_arrangement.update_columns(status: :completed) | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | ||||
| @ -29,5 +29,5 @@ | ||||
| class Seat < ApplicationRecord | ||||
|   acts_as_tenant :wedding | ||||
|   belongs_to :guest | ||||
|   belongs_to :tables_arrangement | ||||
|   belongs_to :table_arrangement | ||||
| end | ||||
|  | ||||
| @ -10,8 +10,6 @@ | ||||
| #  digest     :uuid             not null | ||||
| #  discomfort :integer | ||||
| #  name       :string           not null | ||||
| #  progress   :float            default(0.0), not null | ||||
| #  status     :string           default("complete"), not null | ||||
| #  created_at :datetime         not null | ||||
| #  updated_at :datetime         not null | ||||
| #  wedding_id :uuid             not null | ||||
|  | ||||
| @ -12,14 +12,13 @@ module Tables | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     attr_accessor :tables, :min_per_table, :max_per_table, :hierarchy, :tables_arrangement_id | ||||
|     attr_accessor :tables, :min_per_table, :max_per_table, :hierarchy | ||||
| 
 | ||||
|     def initialize(min_per_table:, max_per_table:, tables_arrangement_id:, hierarchy: AffinityGroupsHierarchy.new) | ||||
|     def initialize(min_per_table:, max_per_table:, hierarchy: AffinityGroupsHierarchy.new) | ||||
|       @min_per_table = min_per_table | ||||
|       @max_per_table = max_per_table | ||||
|       @hierarchy = hierarchy | ||||
|       @tables = [] | ||||
|       @tables_arrangement_id = tables_arrangement_id | ||||
|     end | ||||
| 
 | ||||
|     def random_distribution(people, random: Random.new) | ||||
| @ -43,23 +42,15 @@ module Tables | ||||
|     end | ||||
| 
 | ||||
|     def deep_dup | ||||
|       self.class.new( | ||||
|         min_per_table: @min_per_table, | ||||
|         max_per_table: @max_per_table, | ||||
|         hierarchy: @hierarchy, | ||||
|         tables_arrangement_id: @tables_arrangement_id | ||||
|       ).tap do |new_distribution| | ||||
|       self.class.new(min_per_table: @min_per_table, max_per_table: @max_per_table, | ||||
|                      hierarchy: @hierarchy).tap do |new_distribution| | ||||
|         new_distribution.tables = @tables.map(&:dup) | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     def save! | ||||
|       ActiveRecord::Base.transaction do | ||||
|         arrangement = TablesArrangement.find(tables_arrangement_id) | ||||
| 
 | ||||
|         self.tables_arrangement_id = arrangement.id | ||||
| 
 | ||||
|         arrangement.seats.delete_all | ||||
|         arrangement = TablesArrangement.create! | ||||
| 
 | ||||
|         records_to_store = [] | ||||
| 
 | ||||
|  | ||||
| @ -5,7 +5,6 @@ | ||||
| module VNS | ||||
|   class Engine | ||||
|     PERTURBATION_SIZES = [1, 1, 1, 2, 2, 3].freeze | ||||
|     ITERATIONS = 50 | ||||
|     class << self | ||||
|       def sequence(elements) | ||||
|         elements = elements.to_a | ||||
| @ -13,10 +12,6 @@ module VNS | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     def initialize | ||||
|       @perturbations = Set.new | ||||
|     end | ||||
| 
 | ||||
|     def target_function(&function) | ||||
|       @target_function = function | ||||
|     end | ||||
| @ -27,45 +22,36 @@ module VNS | ||||
|     end | ||||
| 
 | ||||
|     def add_perturbation(klass) | ||||
|       @perturbations ||= Set.new | ||||
|       @perturbations << klass | ||||
|     end | ||||
| 
 | ||||
|     def notify_progress(&block) | ||||
|       @progress_notifier = block | ||||
|     end | ||||
| 
 | ||||
|     def on_better_solution(&block) | ||||
|       @better_solution_notifier = block | ||||
|     end | ||||
| 
 | ||||
|     attr_writer :initial_solution | ||||
| 
 | ||||
|     def run | ||||
|       check_preconditions! | ||||
|       raise 'No target function defined' unless @target_function | ||||
|       raise 'No optimizations defined' unless @optimizations | ||||
|       raise 'No initial solution defined' unless @initial_solution | ||||
| 
 | ||||
|       @perturbations ||= Set.new | ||||
| 
 | ||||
|       @current_solution = @initial_solution | ||||
|       @best_score = @target_function.call(@current_solution) | ||||
| 
 | ||||
|       run_all_optimizations | ||||
| 
 | ||||
|       @progress_notifier&.call(Rational(1, ITERATIONS + 1)) | ||||
| 
 | ||||
|       best_solution = @current_solution | ||||
| 
 | ||||
|       (1..ITERATIONS).each do |iteration| | ||||
|       50.times do | ||||
|         @current_solution = Tables::WheelSwap.new(best_solution).call(PERTURBATION_SIZES.sample) | ||||
|         @best_score = @target_function.call(@current_solution) | ||||
|         Rails.logger.debug { "After perturbation: #{@best_score}" } | ||||
| 
 | ||||
|         run_all_optimizations | ||||
| 
 | ||||
|         @progress_notifier&.call(Rational(iteration + 1, ITERATIONS + 1)) | ||||
| 
 | ||||
|         next unless best_solution.discomfort > @current_solution.discomfort | ||||
| 
 | ||||
|         best_solution = @current_solution | ||||
|         @better_solution_notifier&.call(best_solution) | ||||
| 
 | ||||
|         Rails.logger.debug do | ||||
|           "Found better solution after perturbation optimization: #{@current_solution.discomfort}" | ||||
|         end | ||||
| @ -76,12 +62,6 @@ module VNS | ||||
| 
 | ||||
|     private | ||||
| 
 | ||||
|     def check_preconditions! | ||||
|       raise 'No target function defined' unless @target_function | ||||
|       raise 'No optimizations defined' unless @optimizations | ||||
|       raise 'No initial solution defined' unless @initial_solution | ||||
|     end | ||||
| 
 | ||||
|     def run_all_optimizations | ||||
|       self.class.sequence(@optimizations).each do |optimization| | ||||
|         optimize(optimization) | ||||
|  | ||||
							
								
								
									
										1
									
								
								bin/jobs
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								bin/jobs
									
									
									
									
									
								
							| @ -3,5 +3,4 @@ | ||||
| require_relative "../config/environment" | ||||
| require "solid_queue/cli" | ||||
| 
 | ||||
| SolidQueue.logger = ActiveSupport::Logger.new($stdout) | ||||
| SolidQueue::Cli.start(ARGV) | ||||
|  | ||||
| @ -1,5 +0,0 @@ | ||||
| class AddStatusColumnToTablesArrangements < ActiveRecord::Migration[8.0] | ||||
|   def change | ||||
|     add_column :tables_arrangements, :status, :string, default: :complete, null: false | ||||
|   end | ||||
| end | ||||
| @ -1,5 +0,0 @@ | ||||
| class AddProgressToTablesArrangements < ActiveRecord::Migration[8.0] | ||||
|   def change | ||||
|     add_column :tables_arrangements, :progress, :float, default: 0, null: false | ||||
|   end | ||||
| end | ||||
							
								
								
									
										4
									
								
								db/schema.rb
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4
									
								
								db/schema.rb
									
									
									
										generated
									
									
									
								
							| @ -10,7 +10,7 @@ | ||||
| # | ||||
| # It's strongly recommended that you check this file into your version control system. | ||||
| 
 | ||||
| ActiveRecord::Schema[8.0].define(version: 2025_09_08_145119) do | ||||
| ActiveRecord::Schema[8.0].define(version: 2025_06_08_181054) do | ||||
|   # These are extensions that must be enabled in order to support this database | ||||
|   enable_extension "pg_catalog.plpgsql" | ||||
| 
 | ||||
| @ -216,8 +216,6 @@ ActiveRecord::Schema[8.0].define(version: 2025_09_08_145119) do | ||||
|     t.string "name", null: false | ||||
|     t.uuid "wedding_id", null: false | ||||
|     t.uuid "digest", default: -> { "gen_random_uuid()" }, null: false | ||||
|     t.string "status", default: "complete", null: false | ||||
|     t.float "progress", default: 0.0, null: false | ||||
|     t.index ["wedding_id"], name: "index_tables_arrangements_on_wedding_id" | ||||
|   end | ||||
| 
 | ||||
|  | ||||
| @ -86,9 +86,7 @@ ActsAsTenant.with_tenant(wedding) do | ||||
| 
 | ||||
|   # TODO: Clean up invitations with no guests | ||||
| 
 | ||||
|   3.times { TablesArrangement.create! } | ||||
|     .map { |arrangement| TableSimulatorJob.new(wedding.id, arrangement.id) } | ||||
|     .then { |jobs| ActiveJob.perform_all_later } | ||||
|   ActiveJob.perform_all_later(3.times.map { TableSimulatorJob.new(wedding.id) }) | ||||
| 
 | ||||
|   "red".dup.paint.palette.triad(as: :hex).zip(Group.roots).each { |(color, group)| group.update!(color: color.paint.desaturate(40)) } | ||||
| 
 | ||||
|  | ||||
| @ -21,14 +21,6 @@ namespace :vns do | ||||
| 
 | ||||
|       engine.target_function(&:discomfort) | ||||
| 
 | ||||
|       engine.notify_progress do |current_progress| | ||||
|         Rails.logger.info "Progress: #{(current_progress * 100.0).round(2)}%" | ||||
|       end | ||||
| 
 | ||||
|       engine.on_better_solution do |better_solution| | ||||
|         Rails.logger.info "New best solution found with discomfort: #{better_solution.discomfort}" | ||||
|       end | ||||
| 
 | ||||
|       solution = Rails.benchmark('VNS Benchmarking') { engine.run } | ||||
| 
 | ||||
|       Rails.logger.info "Best solution found with discomfort: #{solution.discomfort}" | ||||
|  | ||||
| @ -12,11 +12,6 @@ server { | ||||
|         proxy_set_header Host $http_host; | ||||
|     } | ||||
| 
 | ||||
|     location /jobs/ { | ||||
|         proxy_pass http://backend:3000/jobs/; | ||||
|         proxy_set_header Host $http_host; | ||||
|     } | ||||
| 
 | ||||
|     location /captcha/v2/media/ { | ||||
|         proxy_pass http://libre-captcha:8888/v2/media/; | ||||
|         proxy_set_header Host $http_host; | ||||
|  | ||||
| @ -19,8 +19,7 @@ RSpec.describe 'tables_arrangements' do | ||||
|                    id: { type: :string, format: :uuid }, | ||||
|                    name: { type: :string }, | ||||
|                    discomfort: { type: :integer }, | ||||
|                    valid: { type: :boolean }, | ||||
|                    status: { type: :string, enum: %w[complete in_progress] } | ||||
|                    valid: { type: :boolean } | ||||
|                  } | ||||
|                } | ||||
|         xit | ||||
|  | ||||
| @ -6,43 +6,8 @@ require 'rails_helper' | ||||
| 
 | ||||
| module Tables | ||||
|   RSpec.describe Distribution do | ||||
|     let(:tables_arrangement) { TablesArrangement.create! } | ||||
| 
 | ||||
|     around do |example| | ||||
|       ActsAsTenant.with_tenant(create(:wedding)) do | ||||
|         example.run | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     describe '#save!' do | ||||
|       let(:people) { create_list(:guest, 2, status: :invited) } | ||||
|       let(:distribution) do | ||||
|         described_class.new(min_per_table: 5, max_per_table: 10, tables_arrangement_id: tables_arrangement.id) | ||||
|                        .tap { |d| d.random_distribution(people) } | ||||
|       end | ||||
| 
 | ||||
|       context 'when tables_arrangement_id is nil' do | ||||
|         it { expect { distribution.save! }.to change(TablesArrangement, :count).by(1) } | ||||
|         it { expect { distribution.save! }.to change(Seat, :count).by(2) } | ||||
|       end | ||||
| 
 | ||||
|       context 'when tables_arrangement_id is set' do | ||||
|         before do | ||||
|           existing_arrangement = TablesArrangement.create! | ||||
| 
 | ||||
|           existing_arrangement.seats.create!(guest: people.first, table_number: 1) | ||||
|           distribution.tables_arrangement_id = existing_arrangement.id | ||||
|         end | ||||
| 
 | ||||
|         it { expect { distribution.save! }.not_to(change(TablesArrangement, :count)) } | ||||
|         it { expect { distribution.save! }.to change(Seat, :count).by(1) } | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     describe '#random_distribution' do | ||||
|       subject(:distribution) do | ||||
|         described_class.new(min_per_table: 5, max_per_table: 10, tables_arrangement_id: tables_arrangement.id) | ||||
|       end | ||||
|       subject(:distribution) { described_class.new(min_per_table: 5, max_per_table: 10) } | ||||
| 
 | ||||
|       context 'when there are fewer people than the minimum per table' do | ||||
|         it 'creates one table' do | ||||
|  | ||||
| @ -17,7 +17,7 @@ module Tables | ||||
| 
 | ||||
|       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, tables_arrangement_id: nil).tap do |distribution| | ||||
|           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 | ||||
| @ -35,7 +35,7 @@ module Tables | ||||
| 
 | ||||
|       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, tables_arrangement_id: nil).tap do |distribution| | ||||
|           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 | ||||
|  | ||||
| @ -17,7 +17,7 @@ module Tables | ||||
| 
 | ||||
|       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, tables_arrangement_id: nil).tap do |distribution| | ||||
|           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 | ||||
| @ -35,7 +35,7 @@ module Tables | ||||
| 
 | ||||
|       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, tables_arrangement_id: nil).tap do |distribution| | ||||
|           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 | ||||
| @ -58,7 +58,7 @@ module Tables | ||||
| 
 | ||||
|       context 'when there are three tables with two people each' do | ||||
|         let(:initial_solution) do | ||||
|           Distribution.new(min_per_table: 2, max_per_table: 2, tables_arrangement_id: nil).tap do |distribution| | ||||
|           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 | ||||
|             distribution.tables << Set[:e, :f].to_table | ||||
|  | ||||
| @ -8,7 +8,7 @@ module Tables | ||||
|   RSpec.describe WheelSwap do | ||||
|     context 'when the solution has three tables' do | ||||
|       let(:initial_solution) do | ||||
|         Distribution.new(min_per_table: 3, max_per_table: 3, tables_arrangement_id: nil).tap do |distribution| | ||||
|         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 | ||||
|           distribution.tables << Set[:g, :h, :i].to_table | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user