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

Rjf/state model #136

Merged
merged 44 commits into from
Mar 11, 2024
Merged

Rjf/state model #136

merged 44 commits into from
Mar 11, 2024

Conversation

robfitzgerald
Copy link
Collaborator

This PR adds a StateModel to Compass which manages the creation and inspection of search state vectors. along the way,

  • traversal model updates were transitioned to mutable updates
  • removed RwLock wrappers in SearchApp
  • some changes to how summaries look

Closes #134.
Closes #115.

@robfitzgerald
Copy link
Collaborator Author

@nreinicke I am with Sarah for a baby appt., but just wanted to message that I think I omitted unit conversion handling. I forget. I'll try and review it when we get home.

@nreinicke
Copy link
Collaborator

just wanted to message that I think I omitted unit conversion handling. I forget. I'll try and review it when we get home.

That sounds good.

I was also wondering if you have an example of a config that is working for this update, when I tried to load one of the tomtom denver configs I get:

[2024-03-08T21:42:54Z ERROR routee_compass] Could not build CompassApp from config file: expected field state for TOML not found
Error: CompassConfigurationError(ExpectedFieldForComponent("state", "TOML"))

I think I just need to add a section to configure the state but not exactly sure what that looks like. l'll also look in the code for more details but thought you might have a ready example.

@robfitzgerald
Copy link
Collaborator Author

robfitzgerald commented Mar 8, 2024 via email

Copy link
Collaborator

@nreinicke nreinicke left a comment

Choose a reason for hiding this comment

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

This looks great! I like how it centralizes the state information and makes it more intuitive. I left a few comments that we can discuss but overall this looks really good.

})
})
.unwrap_or(Ok((prev_state.to_owned(), Cost::ZERO)))?;
let ac = si
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would it make more sense to compute access cost before traversal cost? If we're defining access as the cost to "enter" a link, would it be possible that the result of that would then trigger some behavior in the traversal model? Like, a PHEV is at 0.001% SOC and then takes a turn into a link such that it only uses gasoline for the entirety of the link.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

we do compute access cost before traversal cost, line 73 then line 89 respectively. 😬

Copy link
Collaborator

Choose a reason for hiding this comment

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

oh lordy I totally misread that, you're right!

use serde_json::json;
use std::collections::HashMap;

pub struct StateModel(HashMap<String, StateModelEntry>);
Copy link
Collaborator

Choose a reason for hiding this comment

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

This can be a future work idea but I tested out storing 3 state model entries as a vector and then just scanning the vector to find the right entry and it's about 4x faster to get the last entry and 8x faster to get the first entry (over 1M iterations). I wonder if we could either default to storing the entries as a vector that we scan or expand the internal store such that if we have a large number of state variables (maybe >10) than we use a hash map but if we have a small number than we use a vector.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

totally. that's how Scala implements Map. for Map instances with 4 or less elements, they rely on a scan, and don't actually instantiate a hashmap until 5+. that could make sense, and perhaps we pull it off by turning StateModel into:

pub enum StateModel {
  OneFeature {
    name: String,
    entry: StateModelEntry
  },
  TwoFeatures { 
    name1: String,
    name2: String,
    entry1: StateModelEntry,
    entry2: StateModelEntry,
  },
  ...
  NFeatures(HashMap<String, StateModelEntry>),
}

Copy link
Collaborator

@nreinicke nreinicke Mar 8, 2024

Choose a reason for hiding this comment

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

yeah that's a good idea, and then getting it would be simple and performant like:

fn get(&self, name: &str) -> StateModelEntry {
 match self {
   StateModel::OneFeature => self.entry,
   StateModel::TwoFeatures => {
    if self.name1 == name {
     self.entry1
    } else if self.name2 == name {
     self.entry2
    } else { // err },
    // and so forth
   }
 }
}

let search_algorithm = SearchAlgorithm::try_from(&alg_params)?;

let state_params =
Copy link
Collaborator

Choose a reason for hiding this comment

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

I wonder if we could nest the state parameters within a toml section? I think this setup would require us to put the state key at the top of the toml file since if it's not then it will get nested inside another section. For example if we have the config:

[graph]
edge_list_input_file = "../data/tomtom_denver/edges-compass.csv.gz"
vertex_list_input_file = "../data/tomtom_denver/vertices-compass.csv.gz"
verbose = true

state = [
    { distance_unit = "kilometers", initial = 0.0 },
    { time_unit = "minutes", initial = 0.0 },
]

state would get nested under the graph key. Maybe the config could look something like:

[state_model]
state = [
    { distance_unit = "kilometers", initial = 0.0 },
    { time_unit = "minutes", initial = 0.0 },
]

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ya, you're right, and i thought this was awkward too. i like your suggestion and i think it's a simple change.

@robfitzgerald
Copy link
Collaborator Author

@nreinicke GOT IT. (i think)

Copy link
Collaborator

@nreinicke nreinicke left a comment

Choose a reason for hiding this comment

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

Cool, I'm down to bring these changes in. I built some new issues: #137 and #138 based on our discussions in this PR.

@robfitzgerald robfitzgerald merged commit 8d51b8f into main Mar 11, 2024
5 checks passed
@robfitzgerald robfitzgerald deleted the rjf/state-model branch March 11, 2024 19:19
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.

replace RwLock with Arc Abstraction for TraversalState
2 participants