Skip to content

Commit

Permalink
hybrid TU strategy
Browse files Browse the repository at this point in the history
  • Loading branch information
nuclearkatie committed Jun 13, 2024
1 parent d0e16e8 commit 2f4f845
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 38 deletions.
3 changes: 1 addition & 2 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Since last release
====================

**Added:**
* Added TransportUnits (#1570)
* Added TransportUnits (#1750)

**Changed:**

Expand All @@ -16,7 +16,6 @@ Since last release
* Consistently use hyphens in ``install.py`` flags (#1748)
* Material sell policy can package materials (#1749)
* Use miniforge for conda CI builds instead of miniconda (#1763)
* Added TransportUnits (#1570)

**Removed:**

Expand Down
32 changes: 25 additions & 7 deletions src/package.cc
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ Package::Package(std::string name, double fill_min, double fill_max,
throw ValueError("can't create a new package with name 'unpackaged'");
}
}
if (strategy != "first" && strategy != "equal") {
throw ValueError("Invalid strategy for package: " + strategy_);
}
}

TransportUnit::Ptr TransportUnit::unrestricted_ = NULL;
Expand Down Expand Up @@ -93,7 +96,7 @@ int TransportUnit::GetTransportUnitFill(int qty) {

if (strategy_ == "first") {
return fill_max_;
} else if (strategy_ == "equal") {
} else if (strategy_ == "equal" || strategy_ == "hybrid") {
// int division automatically rounds down. don't need floor in min, and
// get ceil by hand instead
int num_at_min_fill = qty / fill_min_;
Expand All @@ -116,16 +119,28 @@ int TransportUnit::MaxShippablePackages(int pkgs) {
int TU_fill;
int shippable = 0;

if (pkgs == 0 && pkgs < fill_min_) {
if (pkgs == 0 || pkgs < fill_min_) {
return 0;
}

while ((pkgs > 0) && (pkgs >= fill_min_)) {
} else if (name_ == unrestricted_name_) {
return pkgs;

} else if (strategy_ == "first" || strategy_ == "equal") {
TU_fill = GetTransportUnitFill(pkgs);
shippable += TU_fill;
pkgs -= TU_fill;
if (TU_fill == 0) {
return 0;
}
shippable = std::min(pkgs, (pkgs / TU_fill) * TU_fill);
return shippable;

} else if (strategy_ == "hybrid") {
while ((pkgs > 0) && (pkgs >= fill_min_)) {
TU_fill = GetTransportUnitFill(pkgs);
shippable += TU_fill;
pkgs -= TU_fill;
}
return shippable;
}
return shippable;
}

TransportUnit::TransportUnit(std::string name, int fill_min, int fill_max, std::string strategy) :
Expand All @@ -135,6 +150,9 @@ TransportUnit::TransportUnit(std::string name, int fill_min, int fill_max, std::
throw ValueError("can't create a new transport unit with name 'unrestricted'");
}
}
if (strategy != "first" && strategy != "equal" && strategy != "hybrid") {
throw ValueError("Invalid strategy for transport unit: " + strategy_);
}
}

} // namespace cyclus
9 changes: 6 additions & 3 deletions src/package.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ class Package {
/// simply applied at the response to request for bids phase and then the trade
/// execution to determine whether the available number of packages is
/// allowable given the TransportUnit parameters. Default is unrestricted
/// Strategy "first" simply fill transport units one by one to max fill
/// Strategy "equal" tries to fill all transport units with the
/// Strategy "hybrid" is iterative, recursively filling transport units
/// with the max fill until the remaining quantity can be filled with the
/// at least the min fill. This is the most efficient strategy
class TransportUnit {
public:
typedef boost::shared_ptr<TransportUnit> Ptr;
Expand All @@ -88,8 +93,6 @@ class TransportUnit {
std::string strategy = "first");

/// Returns number of packages for each transport unit.
/// Strategy "first" simply fill transport units one by one to max fill
/// Strategy "equal" tries to fill all transport units with the
/// same number of packages
int GetTransportUnitFill(int qty);

Expand Down Expand Up @@ -119,7 +122,7 @@ class TransportUnit {
TransportUnit(std::string name,
int fill_min = 0,
int fill_max = std::numeric_limits<int>::max(),
std::string strategy = "first");
std::string strategy = "hybrid");

static const int unrestricted_id_ = 1;
static constexpr char unrestricted_name_[13] = "unrestricted";
Expand Down
4 changes: 2 additions & 2 deletions src/toolkit/matl_sell_policy.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ void MatlSellPolicy::set_package(std::string x) {
Package::Ptr pkg = manager()->context()->GetPackage(x);
double pkg_fill = pkg->GetFillMass(quantize_);
if ((pkg->name() != Package::unpackaged_name()) && (quantize_ > 0) &&
(std::fmod(quantize_, pkg_fill) > 0)) {
(std::fmod(quantize_, pkg_fill) > 0)) {
std::stringstream ss;
ss << "Quantize " << quantize_ << " is not fully packagable based on fill min/max values ("
<< pkg->fill_min() << ", " << pkg->fill_max() << ")";
<< pkg->fill_min() << ", " << pkg->fill_max() << ")";
throw ValueError(ss.str());
}
package_ = pkg;
Expand Down
71 changes: 47 additions & 24 deletions tests/package_tests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -159,35 +159,58 @@ TEST(PackageTests, GetTransportUnitFillMass) {
}

TEST(PackageTests, MaxShippablePackages) {
int pq_min = 3;
int pq_max = 4;
int r_min = 6;
int r_max = 8;
TransportUnit::Ptr p = TransportUnit::Create("foo", pq_min, pq_max, "first");
TransportUnit::Ptr q = TransportUnit::Create("bar", pq_min, pq_max, "equal");
TransportUnit::Ptr r = TransportUnit::Create("baz", r_min, r_max, "equal");

int p_min = 3;
int p_max = 4;
int q_min = 6;
int q_max = 8;
TransportUnit::Ptr p_first = TransportUnit::Create("foo", p_min, p_max, "first");
TransportUnit::Ptr p_equal = TransportUnit::Create("bar", p_min, p_max, "equal");
TransportUnit::Ptr p_hybrid = TransportUnit::Create("baz", p_min, p_max, "hybrid");

TransportUnit::Ptr q_first = TransportUnit::Create("foobar", q_min, q_max, "first");
TransportUnit::Ptr q_equal = TransportUnit::Create("foobaz", q_min, q_max, "equal");
TransportUnit::Ptr q_hybrid = TransportUnit::Create("foobaz", q_min, q_max, "hybrid");

int exp;

int none_fit = 2;
EXPECT_EQ(0, p->MaxShippablePackages(none_fit));
EXPECT_EQ(0, q->MaxShippablePackages(none_fit));
EXPECT_EQ(0, r->MaxShippablePackages(none_fit));
EXPECT_EQ(0, p_first->MaxShippablePackages(none_fit));
EXPECT_EQ(0, p_equal->MaxShippablePackages(none_fit));
EXPECT_EQ(0, p_hybrid->MaxShippablePackages(none_fit));
EXPECT_EQ(0, q_first->MaxShippablePackages(none_fit));
EXPECT_EQ(0, q_equal->MaxShippablePackages(none_fit));
EXPECT_EQ(0, q_hybrid->MaxShippablePackages(none_fit));

int all_fit = 8;
EXPECT_EQ(all_fit, p->MaxShippablePackages(all_fit));
EXPECT_EQ(all_fit, q->MaxShippablePackages(all_fit));
EXPECT_EQ(all_fit, r->MaxShippablePackages(all_fit));
EXPECT_EQ(all_fit, p_first->MaxShippablePackages(all_fit));
EXPECT_EQ(all_fit, p_equal->MaxShippablePackages(all_fit));
EXPECT_EQ(all_fit, q_first->MaxShippablePackages(all_fit));
EXPECT_EQ(all_fit, q_equal->MaxShippablePackages(all_fit));
EXPECT_EQ(all_fit, q_hybrid->MaxShippablePackages(all_fit));

// all can ship for p/q, but will go 4-3-3, only 8 ship for r
// all can ship for p_hybrid, but will go 4-3-3. Only 8 ship for other
int partial = 10;
EXPECT_EQ(pq_max * 2, p->MaxShippablePackages(partial));
EXPECT_EQ(partial, q->MaxShippablePackages(partial));
EXPECT_EQ(r_max, r->MaxShippablePackages(partial));

int partial2 = 14;
EXPECT_EQ(pq_max * 3, p->MaxShippablePackages(partial2));
EXPECT_EQ(partial2, q->MaxShippablePackages(partial2));
EXPECT_EQ(partial2, r->MaxShippablePackages(partial2));

EXPECT_EQ(p_max * 2, p_first->MaxShippablePackages(partial));
EXPECT_EQ(p_min * 3, p_equal->MaxShippablePackages(partial));
EXPECT_EQ(partial, p_hybrid->MaxShippablePackages(partial));
EXPECT_EQ(q_max, q_first->MaxShippablePackages(partial));
EXPECT_EQ(q_max, q_equal->MaxShippablePackages(partial));
EXPECT_EQ(q_max, q_hybrid->MaxShippablePackages(partial));

int partial2 = 14; // all ship p_hybrid. q, others ship 12. q_equal and
// q_hybrid can ship all
EXPECT_EQ(p_max * 3, p_first->MaxShippablePackages(partial2));
EXPECT_EQ(p_max * 3, p_equal->MaxShippablePackages(partial2));
EXPECT_EQ(partial2, p_hybrid->MaxShippablePackages(partial2));
EXPECT_EQ(q_max, q_first->MaxShippablePackages(partial2));
EXPECT_EQ(partial2, q_equal->MaxShippablePackages(partial2));
EXPECT_EQ(partial2, q_hybrid->MaxShippablePackages(partial2));

int partial3 = 15; // all ship in hybrid and p_equal
EXPECT_EQ(p_max * 3, p_first->MaxShippablePackages(partial3));
EXPECT_EQ(partial3, p_equal->MaxShippablePackages(partial3));
EXPECT_EQ(partial3, p_hybrid->MaxShippablePackages(partial3));
EXPECT_EQ(q_max, q_first->MaxShippablePackages(partial3));
EXPECT_EQ((q_max-1) * 2, q_equal->MaxShippablePackages(partial3));
EXPECT_EQ(partial3, q_hybrid->MaxShippablePackages(partial3));
}

0 comments on commit 2f4f845

Please sign in to comment.