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 a multiplier to the matrix #5298

Merged
merged 10 commits into from
Dec 10, 2018
Merged

Add a multiplier to the matrix #5298

merged 10 commits into from
Dec 10, 2018

Conversation

ghoshkaj
Copy link
Member

@ghoshkaj ghoshkaj commented Dec 8, 2018

Issue

Route optimization solvers often require custom inputs when feeding in the matrix. This is a simple dumb multiplier of table duration values.

Tasklist

Requirements / Relations

Link any requirements here. Other pull requests this PR is based on?

@ghoshkaj ghoshkaj force-pushed the ghoshkaj-scale_factor branch from e9390bc to 5a7f05d Compare December 8, 2018 01:28
@@ -127,6 +128,12 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
result_tables_pair.second[table_index] = distance_estimate;
}
}
if (params.scale_factor > 1.0 &&
result_tables_pair.first[table_index] != MAXIMAL_EDGE_DURATION)
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm should scale_factor also scale the fallback speed result?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes fallback speeds should mirror real speeds. Scaling one and not the other is questionable when feeding into a optimzation solver.

@@ -135,6 +140,9 @@ struct TableParameters : public BaseParameters
if (fallback_speed < 0)
return false;

if (scale_factor < 1)
Copy link
Member

Choose a reason for hiding this comment

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

Docs say > 0, but code enforces > 1.

I think any value should be allowed - scale_factor=-0.5 is weird, but possible to imagine.

Copy link
Member Author

Choose a reason for hiding this comment

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

So we shouldn't really enforce anything here?

Copy link
Member

Choose a reason for hiding this comment

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

Yeah - I can’t think of a reason to restrict this, who knows how people might want to use it.

Copy link
Member Author

Choose a reason for hiding this comment

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

@danpat I'm actually going to clamp to >0. See #5298 (comment) for overflow checks and #5298 (comment) for why doubling the number of overflow checks would trigger computation growth.

Nan::ThrowError("scale_factor must be a number");
return table_parameters_ptr();
}
else if (scale_factor->NumberValue() < 1)
Copy link
Member

Choose a reason for hiding this comment

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

Same again - docs say > 0, code enforces >= 1 (not the same as above btw, which does > 1, not >=).

Should allow any number I think, no need to restrict this, it doesn't trigger any computation growth if it's large.

@@ -96,15 +96,16 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
}

// Scan table for null results - if any exist, replace with distance estimates
if (params.fallback_speed > 0)
if (params.fallback_speed > 0 || params.scale_factor > 1.0)
Copy link
Member

Choose a reason for hiding this comment

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

Should be != 1

result_tables_pair.first[table_index] != MAXIMAL_EDGE_DURATION)
{
result_tables_pair.first[table_index] =
result_tables_pair.first[table_index] * (double)params.scale_factor;
Copy link
Member

Choose a reason for hiding this comment

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

Should probably check for overflow here, and clamp the result to some very large number. - if value * scale_factor ends up > MAXIMAL_EDGE_DURATION (i.e. overflows), we should set value to MAXIMAL_EDGE_DURATION-1.

The value of MAXIMAL_EDGE_DURATION is reserved to indicate "noroute", so we have to clamp slightly lower than that.

Something like:

double result = result_tables_pair.first[table_index] * params.scale_factor;
if (double > MAXIMAL_EDGE_DURATION) {
  result_tables_pair.first[table_index] = MAXIMAL_EDGE_DURATION - 1;
} else {
  result_tables_pair.first[table_index] = result;
}

Copy link
Member

Choose a reason for hiding this comment

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

Also note - no need to cast params.scale_factor to double - it's already one of those. Also, it's preferred in C++ to use static_cast<double>(thingy) instead of C-style (double)thing casts - the C++ style has better defined behaviour, which makes it easier to debug if something goes wrong.

Copy link
Member Author

Choose a reason for hiding this comment

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

👍

Copy link
Member Author

Choose a reason for hiding this comment

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

@danpat after applying a clamp, should we return an error? Or return the raw really large value? For instance in this test case below, the really large unexplained number gets piped through.

Also, we need a clamp for a negative multiplier too, yes?

 ✔ Given the profile "testbot"
  ✔ And the partition extra arguments "--small-component-size 1 --max-cell-sizes 2,4,8,16"
  ✔ Given the query options
      | scale_factor | 2147483647 |
  ✔ Given the node map
      """
      a b
      """
  ✔ And the ways
      | nodes |
      | ab    |
  ✖ When I request a travel time matrix I should get
      |   | a  | b  |
      | a | 0  | 20 |
      | b | 20 | 0  |

Failures:

1) Scenario: Testbot - Travel time matrix of minimal network with scale factor - features/testbot/duration_matrix.feature:611
   Step: When I request a travel time matrix I should get - features/testbot/duration_matrix.feature:624
   Step Definition: features/step_definitions/distance_matrix.js:10
   Message:
     Tables were not identical:
     |   |     a  |     b  |
     | a |     0  | (-) 20 |
     | a |     0  | (+) 214748364.6 |
     | b | (-) 20 |     0  |
     | b | (+) 214748364.6 |     0  |

Copy link
Member Author

@ghoshkaj ghoshkaj Dec 8, 2018

Choose a reason for hiding this comment

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

Hm I think we should clamp down the scale_factor itself. Try to clamp the result down after an overflow has occured is too late, and to check every element before doing the multiplication to prevent an overflow will be expensive.

This is the kind of check that would happen before every multiplication:

EdgeDuration diff = MAXIMAL_EDGE_DURATION / result_tables_pair.first[table_index];
       if (params.scale_factor > diff) {
            // overflow will happen for std::lround(result_tables_pair.first[table_index] * params.scale_factor) so error
       }
result_tables_pair.first[table_index] =  std::lround(result_tables_pair.first[table_index] * params.scale_factor);

Copy link
Member Author

Choose a reason for hiding this comment

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

I've gone with return the raw really large value.

@jcoupey
Copy link

jcoupey commented Dec 8, 2018

Is there a reason to forbid scale_factor values under 1 in table_service.cpp? Being able to shorten durations could also be useful.

@ghoshkaj
Copy link
Member Author

ghoshkaj commented Dec 8, 2018

@jcoupey there is not a reason. I'm removing the greater than 1 restriction now.

@jcoupey
Copy link

jcoupey commented Dec 8, 2018

@ghoshkaj I think you want to keep a parameters.scale_factor > 0 check in table_service.cpp.

@ghoshkaj
Copy link
Member Author

ghoshkaj commented Dec 8, 2018

@ghoshkaj I think you want to keep a parameters.scale_factor > 0 check in table_service.cpp.

@jcoupey I'm coming to same conclusion as I'm trying to figure out checking for overflows. Doing two multiplications for each overflow is quite expensive and I don't think a negative durations matrix is useful.

So @danpat I'm going with @jcoupey's suggestion of clamping parameters.scale_factor > 0.

@ghoshkaj ghoshkaj force-pushed the ghoshkaj-scale_factor branch from e9a5471 to 8786ad4 Compare December 8, 2018 18:55
@ghoshkaj
Copy link
Member Author

ghoshkaj commented Dec 8, 2018

Okay I ran a number of requests with 1280 coordinates so 1280*1280 elements. It took exactly 3 seconds. I don't see any significant user of resources in the TableRequest Handler with coming from the division or the rounding.

I've confirmed that the values are being properly scaled.

screen shot 2018-12-08 at 2 30 10 pm

@ghoshkaj
Copy link
Member Author

ghoshkaj commented Dec 8, 2018

Without scale_factor the same request takes 2.98 s.
screen shot 2018-12-08 at 2 39 59 pm

@@ -61,6 +61,11 @@ std::string getWrongOptionHelp(const engine::api::TableParameters &parameters)
help = "fallback_speed must be > 0";
}

if (parameters.scale_factor < 0)
Copy link
Member

Choose a reason for hiding this comment

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

This tests for < 0 but the error message says it must be > 0.

The if should probably be <= to match the message.

@danpat
Copy link
Member

danpat commented Dec 9, 2018

@ghoshkaj So we're failing on coverage.

One more request: add some tests that exercise the failure conditions - scale_factor=0 and scale_factor=-1. This should increase coverage, and verify that our limit rules on the parameter are correct.

@ghoshkaj ghoshkaj force-pushed the ghoshkaj-scale_factor branch from b9ccb53 to b805233 Compare December 9, 2018 23:54
@ghoshkaj ghoshkaj force-pushed the ghoshkaj-scale_factor branch from 8df15e5 to c23461b Compare December 10, 2018 16:33
@ghoshkaj ghoshkaj merged commit 2e17f30 into master Dec 10, 2018
@ghoshkaj ghoshkaj deleted the ghoshkaj-scale_factor branch December 10, 2018 18:41
ghoshkaj added a commit that referenced this pull request Dec 10, 2018
* add a multiplier to the matrix

* add rounding

* remove scale_factor restrictions

* clamp for overflow error

* update check to match error message

* enforce clamping on < 0 and increase test coverage

* add an invalid scale_factor value to node tests

* increase test coverage

* changelog
datendelphin added a commit to fossgis-routing-server/osrm-backend that referenced this pull request Nov 19, 2020
  - Changes from 5.20.0
    - Features:
      - ADDED: all waypoints in responses now contain a distance property between the original coordinate and the snapped location. [Project-OSRM#5255](Project-OSRM#5255)
      - ADDED: if `fallback_speed` is used, a new structure `fallback_speed_cells` will describe which cells contain estimated values [Project-OSRM#5259](Project-OSRM#5259)
    - Table:
      - ADDED: new parameter `scale_factor` which will scale the cell `duration` values by this factor. [Project-OSRM#5298](Project-OSRM#5298)
      - FIXED: only trigger `scale_factor` code to scan matrix when necessary. [Project-OSRM#5303](Project-OSRM#5303)
datendelphin added a commit to fossgis-routing-server/osrm-backend that referenced this pull request Nov 19, 2020
  - Changes from 5.20.0
    - Features:
      - ADDED: all waypoints in responses now contain a distance property between the original coordinate and the snapped location. [Project-OSRM#5255](Project-OSRM#5255)
      - ADDED: if `fallback_speed` is used, a new structure `fallback_speed_cells` will describe which cells contain estimated values [Project-OSRM#5259](Project-OSRM#5259)
      - REMOVED: we no longer publish Node 4 or 6 binary modules (they are still buildable from source) [Project-OSRM#5314](Project-OSRM#5314)
    - Table:
      - ADDED: new parameter `scale_factor` which will scale the cell `duration` values by this factor. [Project-OSRM#5298](Project-OSRM#5298)
      - FIXED: only trigger `scale_factor` code to scan matrix when necessary. [Project-OSRM#5303](Project-OSRM#5303)
      - FIXED: fix bug in reverse offset calculation that sometimes lead to negative (and other incorrect) values in distance table results [Project-OSRM#5315](Project-OSRM#5315)
    - Docker:
      - FIXED: use consistent boost version between build and runtime [Project-OSRM#5311](Project-OSRM#5311)
      - FIXED: don't override default permissions on /opt [Project-OSRM#5311](Project-OSRM#5311)
    - Matching:
      - CHANGED: matching will now consider edges marked with is_startpoint=false, allowing matching over ferries and other previously non-matchable edge types. [Project-OSRM#5297](Project-OSRM#5297)
    - Profile:
      - ADDED: Parse `source:maxspeed` and `maxspeed:type` tags to apply maxspeeds and add belgian flanders rural speed limit. [Project-OSRM#5217](Project-OSRM#5217)
      - CHANGED: Refactor maxspeed parsing to use common library. [Project-OSRM#5144](Project-OSRM#5144)
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.

4 participants