Stabilize beacon sorting and sort only once #256
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Context
The current beacon candidate sorting algorithm does not yield consistent results, i.e. there is no absolute ordering.
factorio-blueprint-editor/packages/editor/src/core/generators/beacon.ts
Lines 176 to 183 in 83343e6
The comparer implemented appears to differ in absolute ordering based on which comparisons are selected by the array sorting algorithm (a traditional comparison sort). I believe the core of the problem is the
a.effectsGiven === 1 || b.effectsGiven === 1
part since it violates the transitivity requirement in comparison sorting algorithms. To demonstrate what I mean, I made a little sample app.Consider these beacon candidates:
They may sort as
b c a
orc b a
depending on the original ordering of the array. My sample app has this output, showing some comparisons performs to yield these two alternate orderings:Sample app:
Run on JSFiddle
This means that to maintain current (unpredictable) behavior, the sorting must be done inside the loop instead of once at the beginning since the sorting effectively shuffles in addition to sorting. I don't imagine this is intentional.
Proposed change
I propose an alternate implementation that has 3 main differences:
nrOfOverlaps
is preferred for sorting overavgDistToEntities
even for candidates with only 1 effect given (to resolve the stability issue). I tried to maintain the "spirit" of the original implementation while attaining transitivity.Regarding the quality of the results, my data set of 759 oil field blueprints:
However, I don't want to oversell the improvement because the average effect count over the whole data set before and after the change goes from 147 effects given to 151 effects given (pretty incremental).
All in all, I think the main virtue of this change is providing consistent results no matter what the order of the pumpjacks is in a given blueprint.
Example performance diff:
0eJyUmttu2zAMht/F17nQ0bLyKsNQ9GAM3ho3SNJhRZF3n2lR2dAW8KfLpulXSeRPUqTeu4fn1/F4muZLt3/vpseX+dztv7135+nHfP8sn833h7Hbd8fXw/Hn/eOvbtdd3o7yyXQZD911103z0/in29vr9103zpfpMo2Fsf7wdje/Hh7G0/KF3Res48t5+YOXWf7TAnEx7Lq35bt+AT9Np/Gx/NJcd594DvHcynN2m+cJL/jCA+sLiJcwL7bwhm1eT3i9WXnebfMSskc5vwDsMaD9lvUFcH4Z8YbCC9s8a9ABFgcMGQCRQvqikEhWiCTi+gKMAIg04m0B9gAYGowSEwDGBq+OxCh9w5Z7A4BIJ6FYuQe6s0goyXAgU4puGbiNI0rRyJXAAh0Rilce0IkjOglFJunDft1XPCITzUwDWR9SSYmsAxCJi9weA8gkEkE2eRI7Fl4m6yMS0UxsDXFAIhFvyo6tAWHBEY14o2u0IC54lE6y1kcWyESC0vYxViDIoB7lk5QaiCihRAUCS3silVSkbC3IUB4llJSVCFzHE7UM6jmOeE7i4dCiShhllEFP0RFXRCklqaFRdU3kUl3RgSAr+WwTmE0DkKjF1hDhgC9KyAPEvoFI5OKNbSASvXipWTAR6aUaBqQXyWzbS9Sy2HogGClQt5dYgSCMBZZeAidGopeh1CTWA7NEopdeBehBXJSCCJglNhCJXvQ+ZQOItNKdAM5dicBzYmypTAIItZHIxcvlFROJXpLGMXITj0gudc8g1MbcZBcQI3pWjaleAmm3EL0MGmlJu0A6C9tAlUsE3t2jYmzQU4zAu0Vb2zlVPScCV+xRNTZodiE9kh5llwoEcVFCHlC0aSASuaS6ROI5ucEVCVCaC9srrKH74xX6SyJRS5LGghAHEHQSkUuqWZ9cyyXkbRMl8a5EECMSur3UK9tALEMEk2o5lsk5ooaY2G8lEluj/KL9A0ZEFxiR/koEGpQLHgg8mROlYgXeo1mQtE1EsWDX1TLAH6UeBP6YG4hIM/WymoGHSz4C3lNijzPAwyVngjX6BiKbtZRzdIbYmtVkpoHILv06TyM9MlEDiLiBE+X6DfxRd026bhnlGe11O9LSkpoQ6LrEHmdBnpECCTdPHGlqSRcR52tGRPeYqhnShMpEM0kaS5iYWvyRNKEy6itL93klgsyViWaCtBAp0UqpiS9HjkyOrTSEcAdlGY4RJLr96/gYIoluwm0CD+xtpeOyjbxtHJkHDWN0wOhIZ2btAIJ5VhMSjWS0MnWeTGoNSzgqHo/8EvUBbqskSDTl9zIlXpFozI/Uo0NviETq0bE3RBL1eK1Pl3cYBInUo4U+RCL11GxLOnLLVAhtXJ2I9Lssmvn/O0u/PWK2aOpf23zLcwKySqQemXxiJJv81yQeSLxkw/8aL0mvb5lgIfX4FiTKPTWdkf7hMnNCZ6kWJw0/ix4C3M6SdPyWiU7D/Gd5DkaQLfMah94xsQcBtcxCL5nYi4B6k0BI9CTAa4MJIlnlpn6JHkihVwFeviXInoQN9CzAy5h6RaKXa2h0o498XPrkl8vj1vXB6/6/F7O77vd4OusXrn8BAAD//wMAiiYBsw==
Timer: Beacon generation finished in 292 ms
Timer: Beacon generation finished in 198 ms