From d8e60f2c849d5bf199aab8bdfd79b7006d9caa7b Mon Sep 17 00:00:00 2001 From: Katie Mummah Date: Wed, 28 Aug 2024 14:51:14 -0500 Subject: [PATCH] package GetFillMass also returns number of packages at that fill mass --- CHANGELOG.rst | 1 + src/package.cc | 14 +++++++--- src/package.h | 11 +++++--- src/resource.h | 5 ++-- src/toolkit/matl_sell_policy.cc | 13 ++++++--- tests/package_tests.cc | 48 ++++++++++++++++++++++++++------- 6 files changed, 70 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4bd4784af3..3f3de705bf 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -21,6 +21,7 @@ Since last release * Define constants ``CY_LARGE_DOUBLE``, ``CY_LARGE_INT``, and ``CY_NEAR_ZERO`` (#1757) * Warning and limits on number of packages that can be created from a resource at once (#1771) * Use keep_packaging instead of unpackaged in ResBuf (#1778) +* Package GetFillMass returns fill mass and number of packages filled at that mass (#1790) **Removed:** diff --git a/src/package.cc b/src/package.cc index 5fcef9c107..baa7dbd8b0 100644 --- a/src/package.cc +++ b/src/package.cc @@ -29,13 +29,15 @@ Package::Ptr& Package::unpackaged() { return unpackaged_; } -double Package::GetFillMass(double qty) { +std::pair Package::GetFillMass(double qty) { if (qty < fill_min_) { // less than one pkg of material available - return 0; + return std::pair (0, 0); } double fill_mass; + int num_at_fill_mass; + if (strategy_ == "first") { fill_mass = fill_max_; } else if (strategy_ == "equal") { @@ -49,7 +51,13 @@ double Package::GetFillMass(double qty) { fill_mass = fill_max_; } } - return std::min(qty, fill_mass); + fill_mass = std::min(qty, fill_mass); + if (fill_mass >= fill_min_) { + num_at_fill_mass = static_cast(std::floor(qty / fill_mass)); + return std::pair(fill_mass, num_at_fill_mass); + } else { + return std::pair(0, 0); + } } Package::Package(std::string name, double fill_min, double fill_max, diff --git a/src/package.h b/src/package.h index 30dca3177a..6448ab56a3 100644 --- a/src/package.h +++ b/src/package.h @@ -26,9 +26,12 @@ class Package { double fill_max = std::numeric_limits::max(), std::string strategy = "first"); - /// Returns optimal fill mass for a resource to be packaged. Can be used - /// to determine how to respond to requests for material, and to actually - /// package and send off trades. + /// Returns optimal fill mass for a resource to be packaged, and number of + /// packages that can be crated at that fill mass (note that up to one + /// additional package may be possible to create with a lower fill mass, + /// which much be checked separately). + /// Can be used to determine how to respond to requests for material, and + /// to actually package and send off trades. /// Packaging strategy "first" simply fills the packages one by one to the /// maximum fill. Therefore, it should always try to max fill. /// Packaging strategy "equal" tries to fill all packages to the same mass. @@ -41,7 +44,7 @@ class Package { /// quantity = 5, fill_min = 3, fill_max = 4. num_min_fill = floor(5/3) = 1, /// num_max_fill = ceil(5/4) = 2. num_min_fill < num_max_fill, so fill to /// the max. - double GetFillMass(double qty); + std::pair GetFillMass(double qty); // returns package name std::string name() const { return name_; } diff --git a/src/resource.h b/src/resource.h index 61949e7a56..919a36a323 100644 --- a/src/resource.h +++ b/src/resource.h @@ -132,14 +132,15 @@ std::vector Resource::Package(Package::Ptr pkg) { std::vector ts_pkgd; typename T::Ptr t_pkgd; - double fill_mass = pkg->GetFillMass(quantity()); + std::pair fill = pkg->GetFillMass(quantity()); + double fill_mass = fill.first; if (fill_mass == 0) { return ts_pkgd; } // Check if the number of packages is within the limits, including if // int overflow is reached - int approx_num_pkgs = quantity() / fill_mass; + int approx_num_pkgs = fill.second; Package::ExceedsSplitLimits(approx_num_pkgs); while (quantity() > 0 && quantity() >= pkg->fill_min()) { diff --git a/src/toolkit/matl_sell_policy.cc b/src/toolkit/matl_sell_policy.cc index 4fd6b6f47a..3f4ea62d7c 100644 --- a/src/toolkit/matl_sell_policy.cc +++ b/src/toolkit/matl_sell_policy.cc @@ -47,7 +47,8 @@ void MatlSellPolicy::set_package(std::string x) { // if no real context, only unpackaged can be used (keep default) if (manager() != NULL) { Package::Ptr pkg = manager()->context()->GetPackage(x); - double pkg_fill = pkg->GetFillMass(quantize_); + std::pair fill = pkg->GetFillMass(quantize_); + double pkg_fill = fill.first; if ((pkg->name() != Package::unpackaged_name()) && (quantize_ > 0) && (std::fmod(quantize_, pkg_fill) > 0)) { std::stringstream ss; @@ -63,7 +64,8 @@ void MatlSellPolicy::set_transport_unit(std::string x) { if (manager() != NULL) { TransportUnit::Ptr tu = manager()->context()->GetTransportUnit(x); - int num_pkgs = quantize_ / (package_->GetFillMass(quantize_)); + std::pair fill = package_->GetFillMass(quantize_); + int num_pkgs = fill.second; int max_shippable = tu->MaxShippablePackages(num_pkgs); if ((tu->name() != TransportUnit::unrestricted_name()) && quantize_ > 0 && @@ -197,9 +199,12 @@ std::set::Ptr> MatlSellPolicy::GetMatlBids( for (rit = requests.begin(); rit != requests.end(); ++rit) { req = *rit; qty = std::min(req->target()->quantity(), limit); - bid_qty = excl ? quantize_ : package_->GetFillMass(qty); + std::pair fill = package_->GetFillMass(qty); + bid_qty = excl ? quantize_ : fill.first; if (bid_qty != 0) { - n_full_bids = static_cast(std::floor(qty / bid_qty)); + std::cerr << "bid_qty: " << bid_qty << std::endl; + std::cerr << "full bids: " << fill.second << std::endl; + n_full_bids = excl ? std::floor(qty / quantize_) : fill.second; // Throw if number of bids above limit or if casting to int caused // overflow to negative int limit diff --git a/tests/package_tests.cc b/tests/package_tests.cc index a0cefa452b..64e6961987 100644 --- a/tests/package_tests.cc +++ b/tests/package_tests.cc @@ -56,26 +56,56 @@ TEST(PackageTests, GetPackageFillMass) { Package::Ptr q = Package::Create("bar", min, max, "equal"); Package::Ptr r = Package::Create("baz", tight_min, max, "equal"); + std::pair p_fill, q_fill, r_fill; + double exp; + // no fit double no_fit = 0.05; - EXPECT_EQ(0, p->GetFillMass(no_fit)); - EXPECT_EQ(0, q->GetFillMass(no_fit)); + p_fill = p->GetFillMass(no_fit);; + EXPECT_EQ(0, p_fill.first); + EXPECT_EQ(0, p_fill.second); + + q_fill = q->GetFillMass(no_fit); + EXPECT_EQ(0, q_fill.first); + EXPECT_EQ(0, q_fill.second); + // perfect fit double perfect_fit = 0.9; - EXPECT_EQ(perfect_fit, p->GetFillMass(perfect_fit)); - EXPECT_EQ(perfect_fit, q->GetFillMass(perfect_fit)); + p_fill = p->GetFillMass(perfect_fit); + EXPECT_EQ(perfect_fit, p_fill.first); + EXPECT_EQ(1, p_fill.second); + q_fill = q->GetFillMass(perfect_fit); + EXPECT_EQ(perfect_fit, q_fill.first); + EXPECT_EQ(1, q_fill.second); + + // partial fit double partial_fit = 1; - EXPECT_EQ(max, p->GetFillMass(partial_fit)); + + p_fill = p->GetFillMass(partial_fit); + EXPECT_EQ(max, p_fill.first); + EXPECT_EQ(1, p_fill.second); + + q_fill = q->GetFillMass(partial_fit); exp = partial_fit / 2; - EXPECT_EQ(exp, q->GetFillMass(partial_fit)); - EXPECT_EQ(max, r->GetFillMass(partial_fit)); + EXPECT_EQ(exp, q_fill.first); + EXPECT_EQ(2, q_fill.second); + + r_fill = r->GetFillMass(partial_fit); + EXPECT_EQ(max, r_fill.first); + EXPECT_EQ(1, r_fill.second); + // two full packages for equal, only one for double two_packages = 1.4; - EXPECT_EQ(max, p->GetFillMass(two_packages)); + + p_fill = p->GetFillMass(two_packages); + EXPECT_EQ(max, p_fill.first); + EXPECT_EQ(1, p_fill.second); + + q_fill = q->GetFillMass(two_packages); exp = two_packages / 2; - EXPECT_EQ(exp, q->GetFillMass(two_packages)); + EXPECT_EQ(exp, q_fill.first); } TEST(PackageTests, CreateTransportUnit) {