Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add data structure for asset pool #388

Merged
merged 10 commits into from
Feb 17, 2025
Merged

Add data structure for asset pool #388

merged 10 commits into from
Feb 17, 2025

Conversation

alexdewar
Copy link
Collaborator

Description

Currently AssetPool is just a type alias for a Vec<Asset> and in order to get the currently commissioned assets we just filter this Vec. However, going forward we will want to be able to modify this data structure as we go along: assets are commissioned and decommissioned based on the milestone year and agents can also select from among them in the agent investment step. So I think it makes sense to have a dedicated struct for this with some methods.

It has the following functionality:

  • Commission and decommission assets based on year
  • Iterate over the currently active assets
  • Get an active asset based on its ID (I've made a separate type for asset IDs too)

After I implemented the decommissioning step I noticed I was getting error messages from the optimiser about it being an empty problem: this is because all of the assets have been commissioned by the time of the last milestone year. To fix this I just moved the milestone year, but at some point we probably want to figure out how to handle this scenario cleanly.

Closes #313. Closes #335.

Type of change

  • Bug fix (non-breaking change to fix an issue)
  • New feature (non-breaking change to add functionality)
  • Refactoring (non-breaking, non-functional change to improve maintainability)
  • Optimization (non-breaking change to speed up the code)
  • Breaking change (whatever its nature)
  • Documentation (improve or add documentation)

Key checklist

  • All tests pass: $ cargo test
  • The documentation builds and looks OK: $ cargo doc

Further checks

  • Code is commented, particularly in hard-to-understand areas
  • Tests added that prove fix is effective or that feature works

There is currently a problem in that the last milestone year is after all of the assets have been decommissioned, meaning that there will be no assets available for the last milestone year, which seems pretty nonsensical (albeit theoretically possible) and it causes the optimiser to barf. Let's fix this by changing the last milestone year.
@alexdewar alexdewar requested a review from TinyMarsh February 10, 2025 18:30
Copy link

codecov bot commented Feb 10, 2025

Codecov Report

Attention: Patch coverage is 98.79518% with 2 lines in your changes missing coverage. Please review.

Project coverage is 95.42%. Comparing base (2ce9730) to head (0895010).
Report is 11 commits behind head on main.

Files with missing lines Patch % Lines
src/agent.rs 98.52% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #388      +/-   ##
==========================================
+ Coverage   95.33%   95.42%   +0.09%     
==========================================
  Files          31       31              
  Lines        3882     4004     +122     
  Branches     3882     4004     +122     
==========================================
+ Hits         3701     3821     +120     
- Misses         94       96       +2     
  Partials       87       87              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

We need to do this otherwise the problem is infeasible: there is not sufficient supply to meet service demands for RSHEAT in the final milestone year.
Copy link
Collaborator

@TinyMarsh TinyMarsh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving because the code makes sense to me. I just have a couple of question which, to be honest, may be born out of me not understanding the use scenario of assets becoming active/inactive;

When an asset becomes inactive, i.e. setting the AssetID to INACTIVE, do we not lose the ability to lookup that Asset by its unique identifier (AssetID) in the future? Or perhaps it doesn't matter because it gets dropped from the AssetPool anyway?

Just checking I understand the logic really.

Comment on lines +178 to +194
pub fn commission_new(&mut self, year: u32) {
assert!(
year >= self.current_year,
"Assets have already been commissioned for year {year}"
);
self.current_year = year;
}

/// Decommission old assets for the specified milestone year
pub fn decomission_old(&mut self, year: u32) {
assert!(
year >= self.current_year,
"Cannot decommission assets in the past (current year: {})",
self.current_year
);
self.assets.retain(|asset| asset.decommission_year() > year);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just so I understand; So all commission_new() is doing is updating the current_year for the AssetPool. decommission_old is doing the important bit by making sure that only assets whose decommission year is in the future is kept in AssetPool.

Do we not want to set the id field of the Asset to AssetID::INVALID here also? Or is that not the intended use of that value? Does "decommissioned" have a different meaning to "inactive"?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just so I understand; So all commission_new() is doing is updating the current_year for the AssetPool. decommission_old is doing the important bit by making sure that only assets whose decommission year is in the future is kept in AssetPool.

Yep, exactly. Because the assets are sorted by commission year, to get the active assets we can then just iterate over the Vec until we find a commission year > current_year.

Decommissioned assets are just deleted from the Vec for now, though we could potentially just mark them as inactive in some way instead (maybe replace them with None?), which would have the advantage that we wouldn't have to move memory around every time we decommission things. But I just went for deleting them for now because that seemed easier.

Do we not want to set the id field of the Asset to AssetID::INVALID here also? Or is that not the intended use of that value? Does "decommissioned" have a different meaning to "inactive"?

I've noticed that the doc comments are a bit confusing here. AssetID::INVALID is just the ID that every Asset is given when it's created. When we move the assets into the AssetPool, then at that point they're all given a unique ID. The reason for doing it at this point is so that we can sort the assets by commission year and then give them IDs in that same order, which will make it faster to look up assets by ID. We could also just sort the assets when we load them in, but it seemed a bit fragile for AssetPool to rely on this (we might refactor the input code and subtly break it).

@alexdewar alexdewar enabled auto-merge February 17, 2025 10:00
@alexdewar alexdewar merged commit 0e82e39 into main Feb 17, 2025
7 checks passed
@alexdewar alexdewar deleted the asset-pool branch February 17, 2025 10:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add data structure + methods for managing assets Decommission assets that have reached end of life
2 participants