Skip to content

Commit 554c4cd

Browse files
committed
Backport 3.x
1 parent 041630f commit 554c4cd

File tree

3 files changed

+30
-62
lines changed

3 files changed

+30
-62
lines changed

src/WeightRedistributor.php

+20-20
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public function redistributeWeight(PackedBoxList $originalBoxes)
5353
/** @var PackedBox[] $boxes */
5454
$boxes = iterator_to_array($originalBoxes);
5555

56-
usort($boxes, function (PackedBox $boxA, PackedBox $boxB) {
56+
usort($boxes, static function (PackedBox $boxA, PackedBox $boxB) {
5757
return $boxB->getWeight() - $boxA->getWeight();
5858
});
5959

@@ -109,7 +109,7 @@ private function equaliseWeight(PackedBox &$boxA, PackedBox &$boxB, $targetWeigh
109109
$underWeightBoxItems = $underWeightBox->getItems()->asArray();
110110

111111
foreach ($overWeightBoxItems as $key => $overWeightItem) {
112-
if ($overWeightItem->getWeight() + $underWeightBox->getItemWeight() > $targetWeight) {
112+
if (!static::wouldRepackActuallyHelp($overWeightBoxItems, $overWeightItem, $underWeightBoxItems, $targetWeight)) {
113113
continue; // moving this item would harm more than help
114114
}
115115

@@ -133,12 +133,10 @@ private function equaliseWeight(PackedBox &$boxA, PackedBox &$boxB, $targetWeigh
133133
continue; //this should never happen, if we can pack n+1 into the box, we should be able to pack n
134134
}
135135

136-
if (static::didRepackActuallyHelp($boxA, $boxB, $newHeavierBoxes->top(), $newLighterBoxes->top())) {
137-
$underWeightBox = $boxB = $newLighterBoxes->top();
138-
$boxA = $newHeavierBoxes->top();
136+
$underWeightBox = $boxB = $newLighterBoxes->top();
137+
$boxA = $newHeavierBoxes->top();
139138

140-
$anyIterationSuccessful = true;
141-
}
139+
$anyIterationSuccessful = true;
142140
}
143141

144142
return $anyIterationSuccessful;
@@ -164,22 +162,24 @@ private function doVolumeRepack($items)
164162
* Not every attempted repack is actually helpful - sometimes moving an item between two otherwise identical
165163
* boxes, or sometimes the box used for the now lighter set of items actually weighs more when empty causing
166164
* an increase in total weight.
167-
*
168-
* @param PackedBox $oldBoxA
169-
* @param PackedBox $oldBoxB
170-
* @param PackedBox $newBoxA
171-
* @param PackedBox $newBoxB
172-
*
173-
* @return bool
174165
*/
175-
private static function didRepackActuallyHelp(PackedBox $oldBoxA, PackedBox $oldBoxB, PackedBox $newBoxA, PackedBox $newBoxB)
166+
private static function wouldRepackActuallyHelp(array $overWeightBoxItems, Item $overWeightItem, array $underWeightBoxItems, $targetWeight)
176167
{
177-
$oldList = new PackedBoxList();
178-
$oldList->insertFromArray([$oldBoxA, $oldBoxB]);
168+
$overWeightItemsWeight = array_sum(array_map(static function (Item $item) {return $item->getWeight(); }, $overWeightBoxItems));
169+
$underWeightItemsWeight = array_sum(array_map(static function (Item $item) {return $item->getWeight(); }, $underWeightBoxItems));
170+
171+
if ($overWeightItem->getWeight() + $underWeightItemsWeight > $targetWeight) {
172+
return false;
173+
}
174+
175+
$oldVariance = static::calculateVariance($overWeightItemsWeight, $underWeightItemsWeight);
176+
$newVariance = static::calculateVariance($overWeightItemsWeight - $overWeightItem->getWeight(), $underWeightItemsWeight + $overWeightItem->getWeight());
179177

180-
$newList = new PackedBoxList();
181-
$newList->insertFromArray([$newBoxA, $newBoxB]);
178+
return $newVariance < $oldVariance;
179+
}
182180

183-
return $newList->getWeightVariance() < $oldList->getWeightVariance();
181+
private static function calculateVariance($boxAWeight, $boxBWeight)
182+
{
183+
return pow($boxAWeight - (($boxAWeight + $boxBWeight) / 2), 2); //don't need to calculate B and ÷ 2, for a 2-item population the difference from mean is the same for each box
184184
}
185185
}

tests/WeightRedistributorTest.php

-32
Original file line numberDiff line numberDiff line change
@@ -61,36 +61,4 @@ public function testWeightDistributionWorks()
6161

6262
self::assertEquals(0, $packedBoxes->getWeightVariance());
6363
}
64-
65-
/**
66-
* Test a case where a weight balancing repack is actually 1 box less than before the repack.
67-
* Not ideal that this happens, but while it does it can be used for code coverage.
68-
*/
69-
public function testACaseWhereABoxIsEliminated()
70-
{
71-
// first no repack case
72-
$packer = new Packer();
73-
$packer->setMaxBoxesToBalanceWeight(0);
74-
$packer->addBox(new TestBox('Option 1', 230, 300, 240, 160, 230, 300, 240, 15000));
75-
$packer->addBox(new TestBox('Option 2', 370, 375, 60, 140, 364, 374, 40, 3000));
76-
77-
$packer->addItem(new TestItem('Item 1', 220, 310, 12, 679, true), 4);
78-
$packer->addItem(new TestItem('Item 2', 210, 297, 5, 242, true), 4);
79-
80-
$packedBoxes = $packer->pack();
81-
82-
self::assertCount(3, $packedBoxes);
83-
84-
// and the repack case
85-
$packer = new Packer();
86-
$packer->addBox(new TestBox('Option 1', 230, 300, 240, 160, 230, 300, 240, 15000));
87-
$packer->addBox(new TestBox('Option 2', 370, 375, 60, 140, 364, 374, 40, 3000));
88-
89-
$packer->addItem(new TestItem('Item 1', 220, 310, 12, 679, true), 4);
90-
$packer->addItem(new TestItem('Item 2', 210, 297, 5, 242, true), 4);
91-
92-
$packedBoxes = $packer->pack();
93-
94-
self::assertCount(2, $packedBoxes);
95-
}
9664
}

tests/data/expected.csv

+10-10
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@
244244
0d1983784732e45a55b1040a82db07c1,1,0,48.1,1,0,48.1
245245
0d36d441ceb0caec57d77547730409a8,2,2601,25.4,1,0,7.6
246246
0d3c2338df7cc72f5fd90c4b315d4ff0,2,1410156.3,34.8,1,0,21.1
247-
0d41f4783eeeb20337d3d1f7f058cfe2,2,38025,41.5,1,0,12.4
247+
0d41f4783eeeb20337d3d1f7f058cfe2,3,333578,27.7,1,0,12.4
248248
0d66c19661114ec65fb923367d0988fd,1,0,26.5,1,0,26.5
249249
0d6b0374f997b7d434c9a1dc10da2d46,1,0,32.8,1,0,32.8
250250
0d786a2440a68c348fa1761614cdf441,1,0,44.3,1,0,44.3
@@ -393,7 +393,7 @@
393393
1672e9897bfb16f7f644365da8d6992c,1,0,26.4,1,0,26.4
394394
167db38fa514a30e70f167f70d19f214,1,0,16.2,1,0,16.2
395395
168065302d10d2f4b683e3d5e7475594,2,536556.3,32.7,1,0,19.8
396-
1680b70ba864c313d28c9386ce54ac25,4,5476556.5,45.9,3,4493.6,38.5
396+
1680b70ba864c313d28c9386ce54ac25,4,5476556.5,45.9,3,6570.9,38.5
397397
1694662b95ac32661ee2b45826bb54f6,1,0,42.4,1,0,42.4
398398
16a2283358cddda00bf2e47e5ad746d3,1,0,24,1,0,24
399399
16a59c72d05be053c19e4b32ceafaef0,1,0,29.2,1,0,29.2
@@ -507,7 +507,7 @@
507507
1bb2791024268994225848fbb9cbc3d3,1,0,35.3,1,0,35.3
508508
1bb54c648802eecd24f028e8b6142ae7,4,42137.7,42.2,1,0,25.3
509509
1bc4006c4dd0d71e507869bb2733a0ba,2,1936,31.7,1,0,9.5
510-
1bd069f31bde829dfe0cd46d82ea770e,2,27060.3,42.3,1,0,12.7
510+
1bd069f31bde829dfe0cd46d82ea770e,3,313990.2,28.2,1,0,12.7
511511
1bd0f6a2ed9e36c28d630bbce77c1d61,3,0,41.8,1,0,18.8
512512
1bde839ae62529764cef435c02aa18fc,1,0,33.6,1,0,33.6
513513
1be064ca4930df0249218f93619f4cde,1,0,22.8,1,0,22.8
@@ -816,7 +816,7 @@
816816
2f40c5cd89da22e706e4c2893c2dccb3,1,0,16.4,1,0,16.4
817817
2f419dab07b92225fa941d15b83f8314,1,0,33.2,1,0,33.2
818818
2f465e9076de95b96b927208b46705f2,1,0,40.4,1,0,40.4
819-
2f537fcb5df6f785082d9548928e3d9b,7,1759160.5,41,2,88209,46.7
819+
2f537fcb5df6f785082d9548928e3d9b,7,1744064.5,41,2,88209,46.7
820820
2f59969c2f5d7f75ec3b78396d271b87,1,0,38.3,1,0,38.3
821821
2f5f3f5bdd74b62412f2f6245d78f6ef,1,0,32.6,1,0,32.6
822822
2f777d3848d7dc6920ae742578dcb053,2,16512.3,30.8,1,0,9.2
@@ -1010,7 +1010,7 @@
10101010
3a37c4a592a4be22a8d8d5e4ee80d7e9,1,0,39.7,1,0,39.7
10111011
3a3dc364bfebd251baf6c465c212ed1c,1,0,15.6,1,0,15.6
10121012
3a3f7d42355f64485a59cb25fd4f6eb2,2,1205604,36.2,1,0,21.9
1013-
3a41ed4b08d3bbc912a4f4aaecee9dd0,3,14816216.2,79.9,3,463611.6,44.4
1013+
3a41ed4b08d3bbc912a4f4aaecee9dd0,3,14816216.2,79.9,3,440547.6,44.4
10141014
3a505cd384cc4eb05934e959fad8185e,2,16900,31.3,1,0,9.4
10151015
3a5f312bc61069dfbada3bea35595687,1,0,38.8,1,0,38.8
10161016
3a8f892aefcf1c1de6b1b126fc6b22e2,1,0,35.1,1,0,35.1
@@ -1037,15 +1037,15 @@
10371037
3bd6564e4bffc131afe76760e02db797,3,7224.9,36.7,1,0,16.5
10381038
3bda69c3fe4e30d6944a02d696661fe3,1,0,29.2,1,0,29.2
10391039
3bdea76452dfd0a2dd349e05688ceea7,1,0,36.2,1,0,36.2
1040-
3bec6daa3c92aab45d0db63b688bad9e,5,90020,34.3,2,3543806.3,18.1
1040+
3bec6daa3c92aab45d0db63b688bad9e,5,89240,34.3,2,3543806.3,18.1
10411041
3becb246809835f192b15039849f3528,1,0,27.5,1,0,27.5
10421042
3bee0a82a9098c92945daac991fca070,2,12.3,23.7,1,0,7.1
10431043
3c1b74fc52f870503d59c3327da6d203,2,607620.3,40,1,0,24.2
10441044
3c29ccbdb900b4ade8f05884d9bafb1c,1,0,38.1,1,0,38.1
10451045
3c2bc39429c8d1a0db6369149f454d65,2,2916,39.5,1,0,11.9
10461046
3c47276e13a1bf073b7f2987f09b21d9,1,0,48,1,0,48
10471047
3c4f92d98c4e7792e46c0269daab7d6d,2,400,28.5,1,0,8.5
1048-
3c51cd3b2b4b213f076ba27e90d04225,3,6253450.7,48.3,2,835396,25.1
1048+
3c51cd3b2b4b213f076ba27e90d04225,3,6251648,48.3,2,835396,25.1
10491049
3c583eb716f36fa0ebe89e3573c733c0,1,0,28.5,1,0,28.5
10501050
3c58eba0522266abecca9b20aad46677,1,0,17.5,1,0,17.5
10511051
3c63070dfe31a39510ed0fdc001cd339,1,0,41.2,1,0,41.2
@@ -2790,7 +2790,7 @@ a3ce775d26ac8be3439ad24b24289f7e,2,87025,25.4,1,0,7.6
27902790
a3dddf09e71c503bc692f33ed332e5d1,1,0,27.5,1,0,27.5
27912791
a3e3c130372bee11d670de991210c9af,1,0,77.1,1,0,77.1
27922792
a3f95b935375913e85f66e3cb6480a9d,1,0,48.5,1,0,48.5
2793-
a403a7d8ed1e7ba344e9a814dc938960,2,1521,44.8,2,1521,32.6
2793+
a403a7d8ed1e7ba344e9a814dc938960,2,1521,44.8,2,1521,44.8
27942794
a413a12acaf8fc5b8cc5118d76c0ebce,1,0,36.5,1,0,36.5
27952795
a4158880f12e267d4120f1c99e90b04b,1,0,5.8,1,0,5.8
27962796
a41d7001551662ca358cf917b4fa71f5,1,0,46.3,1,0,46.3
@@ -2877,7 +2877,7 @@ a8b400d8aef6c488703249becd9b293b,3,18288456.2,62.7,2,11448072.3,32.6
28772877
a8baa80336a3f7799f67d75b56706f88,1,0,26.8,1,0,26.8
28782878
a8ce07dfcf68918f62fe006fdd4e2123,1,0,18.3,1,0,18.3
28792879
a8d355a97fe9359f998901899125564b,1,0,29,1,0,29
2880-
a8df0a7e00e3627fef599719af67e8d0,7,3914818.8,53.1,3,11164.2,29.3
2880+
a8df0a7e00e3627fef599719af67e8d0,7,3914818.8,53.1,3,3914.9,24
28812881
a8f4cfc856ccdba7fac54d706cae29a3,1,0,75.9,1,0,75.9
28822882
a8f9f349cc3a30cb703a9158e52647f3,3,36440.9,31.5,1,0,23.8
28832883
a90a1512baefad9a2c28efde1435ac06,2,961,38.2,1,0,11.4
@@ -3512,7 +3512,7 @@ cee89834047195f849ace58d7900c0b8,1,0,18.5,1,0,18.5
35123512
cefae75274dc3e1ffeaff5635eee0f62,1,0,26.2,1,0,26.2
35133513
cf2c2f8e58511b48193186d0a858d7ff,1,0,33.2,1,0,33.2
35143514
cf3a7710faef1cc4d63d1fda9cdeac25,1,0,31,1,0,31
3515-
cf4d33f33f88d177476780cf0f4d4136,3,71846,39.6,1,0,17.8
3515+
cf4d33f33f88d177476780cf0f4d4136,3,69568.7,39.6,1,0,17.8
35163516
cf52f354e99094e4f1280c80ab97f289,1,0,66.1,1,0,66.1
35173517
cf5d3efee1d5996ff670eccefdd8c8c4,1,0,34.2,1,0,34.2
35183518
cf6c9e450532cd18a8ee0e3186336947,1,0,37.3,1,0,37.3

0 commit comments

Comments
 (0)