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

Trip with Fixed Start and End points (TFSE) #3408

Merged
merged 3 commits into from
Feb 10, 2017
Merged

Conversation

ghoshkaj
Copy link
Member

@ghoshkaj ghoshkaj commented Dec 6, 2016

Issue

#1623

Tasklist

  • Work with Chau to figure out algorithm for roundtrip with fixed start and end points
    (We're going to implement @chaupow's algorithm described here)
  • Figure out API design
    (@chaupow and @TheMarex and I have settled on:
    coordinates: list of coordinates
    source: the index of the start coordinate
    destination: the index of the end coordinate )
  • Write failing unit tests for new parameters
  • Make unit tests pass
  • Write failing cuke tests
  • Write code
  • Review
  • Adjust for comments

Code Review Checklist - author check these when done, reviewer verify

  • Code formatted with scripts/format.sh
  • Changes have test coverage
  • New exceptions, logging, errors - are messages distinct enough to track down in the code if they get thrown in production on non-debug builds?
  • The PR is one logically integrated piece of work. If there are unrelated changes, are they at least separate commits?
  • Commit messages - are they clear enough to understand the intent of the change if we have to look at them later?
  • Code comments - are there comments explaining the intent?
  • Relevant docs updated
  • Changelog entry if required
  • Impact on the API surface
    • If HTTP/libosrm.o is backward compatible features, bump the minor version
    • File format changes require at minor release
    • If old clients can't use the API after changes, bump the major version

If something doesn't apply, please cross it out

Requirements / Relations

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

@ghoshkaj ghoshkaj force-pushed the fixed-start-and-end-trip branch 4 times, most recently from dd8b537 to 0e76783 Compare December 13, 2016 15:41
@ghoshkaj ghoshkaj force-pushed the fixed-start-and-end-trip branch 4 times, most recently from cccaf3b to 3b296fe Compare December 22, 2016 08:35
@ghoshkaj ghoshkaj force-pushed the fixed-start-and-end-trip branch from 3b296fe to 653fc54 Compare December 23, 2016 15:35
@ghoshkaj ghoshkaj force-pushed the fixed-start-and-end-trip branch 2 times, most recently from 0138488 to de7f762 Compare January 4, 2017 14:48
@ghoshkaj ghoshkaj force-pushed the fixed-start-and-end-trip branch from de7f762 to 038fc66 Compare January 9, 2017 15:57
@ghoshkaj ghoshkaj force-pushed the fixed-start-and-end-trip branch from 038fc66 to b3410ee Compare January 17, 2017 20:27
@danpat
Copy link
Member

danpat commented Jan 19, 2017

Capturing from chat today:

The complexity seems quite high with the approach of creating the tfse_ table_, performing the FA/brute search, then mapping the results back to the original node IDs.

An alternative could be just to munge certain values in the result_table. If A is our start point, and D is our designated endpoint, we can do something like set all X->A cell values to INT_MAX, and all D->X values to INT_MAX, and D->A to 0, and A->D to INT_MAX. This should be basically equivalent to the tfse_table_, but without needing to perform that step.

Of course, with any heuristic, it's possible that we'd calculate a result that includes an INT_MAX edge, and this could cause all kinds of integer overflow problems. To make the result correct, you can update the brute force and FA algorithms to fast-fail a candidate route if it touches an INT_MAX edge - i.e. INT_MAX is treated as a special value that means "no connection".

@chaupow Thoughts on the above? The creation of the tfse_table_ makes sense, but it adds some complexity that I think we could avoid. Can you see anything fundamentally wrong with the approach above?

@chaupow
Copy link
Member

chaupow commented Jan 19, 2017

@chaupow Thoughts on the above? The creation of the tfse_table_ makes sense, but it adds some complexity that I think we could avoid. Can you see anything fundamentally wrong with the approach above?

If I'm not wrong, this should work as well and result in the same effect of forcing a round trip that visits A after D. Also, Julien from vroom does the same #1623 (comment)

I'm 👍

@ghoshkaj
Copy link
Member Author

ghoshkaj commented Jan 19, 2017

This is the table that @danpat and I came up with from our conversation. Putting it here for the record as I work through the cucumber test scenarios that use this and so that everyone is on the same page about new table.

source: a. destination: c.

original table:

  a  b  c  d  e
a 0  15 36 34 30 
b 15 0  25 30 34 
c 36 25 0  18 32 
d 34 30 18 0  15 
e 30 34 32 15 0 

manipulated table:

  a      b      c      d      e
a 0      15     10000  34     30 
b 10000  0      25     30     34 
c 0      10000  0      10000  10000 
d 10000  30     18     0      15 
e 10000  34     32     15     0

@ghoshkaj ghoshkaj force-pushed the fixed-start-and-end-trip branch 2 times, most recently from 0abc87f to f45d9b3 Compare January 23, 2017 21:47
@ghoshkaj
Copy link
Member Author

@danpat @chaupow and anyone else on directions, review please?

@ghoshkaj ghoshkaj force-pushed the fixed-start-and-end-trip branch 2 times, most recently from d38a71d to a2364bd Compare January 25, 2017 22:22
// parameters.source column
if (f_counter % result_table.GetNumberOfNodes() == (unsigned long)parameters.source)
{
tfse_table_[f_counter] = std::numeric_limits<EdgeWeight>::max();
Copy link
Member

Choose a reason for hiding this comment

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

Given that the FI and BruteForce searches are looking for INVALID_EDGE_WEIGHT, that's what you should set here, not ::max(). Practically, they're the same thing, but if the INvALID_EDGE_WEIGHT value changes for some reason, the if() logic later on will break.

f_counter < result_table.GetNumberOfNodes() * parameters.destination +
result_table.GetNumberOfNodes())
{
tfse_table_[f_counter] = std::numeric_limits<EdgeWeight>::max();
Copy link
Member

Choose a reason for hiding this comment

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

Same here.

tfse_table_[parameters.destination * result_table.GetNumberOfNodes() +
parameters.destination] = 0;
tfse_table_[parameters.source * result_table.GetNumberOfNodes() + parameters.destination] =
std::numeric_limits<EdgeWeight>::max();
Copy link
Member

Choose a reason for hiding this comment

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

And here.

@danpat
Copy link
Member

danpat commented Jan 26, 2017

@ghoshkaj For routes >10 waypoints, we will need to make the same logic change to the FarthestInsertion algorithm that got made to BruteForce. A test for that scenario would be great too.

@ghoshkaj ghoshkaj requested a review from daniel-j-h January 26, 2017 16:06
@ghoshkaj ghoshkaj force-pushed the fixed-start-and-end-trip branch 2 times, most recently from e8c6c9b to adc5e22 Compare January 27, 2017 22:27
docs/http.md Outdated
@@ -329,6 +330,30 @@ In addition to the [general options](#general-options) the following options are
|geometries |`polyline` (default), `polyline6`, `geojson` |Returned route geometry format (influences overview and per step) |
|overview |`simplified` (default), `full`, `false` |Add overview geometry either full, simplified according to highest zoom level it could be display on, or not at all.|

A second feature of the trip plugin returns the optimal route from a source to a destination while visiting all the other input locations in the middle.
As with the roundtrip service, for locations 10 nodes of less, the brute force algorithm is used, while for more than 10 nodes, the farthest insertion heuristic is used.
Copy link
Member

@danpat danpat Jan 30, 2017

Choose a reason for hiding this comment

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

"for fewer than 10 waypoints, the brute force algorithm is used, while for more than 10 waypoints ..."

docs/http.md Outdated

|Element |Values |
|------------|-----------------------------|
|index |`0 <= integer < #locations` |
Copy link
Member

Choose a reason for hiding this comment

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

either coordinates or waypoints, not locations


Scenario: Testbot - Trip planning with illegal source
Given the query options
| source | 10 |
Copy link
Member

Choose a reason for hiding this comment

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

source and destination should be columns in the "When I plan a trip I should get" columns, not a separate "Given", allowing per-query adjustment. This will allow some consolidation of these test cases.

@ghoshkaj ghoshkaj force-pushed the fixed-start-and-end-trip branch 2 times, most recently from 3d96909 to dd174c4 Compare January 30, 2017 23:45
docs/http.md Outdated
@@ -311,7 +311,7 @@ All other properties might be undefined.

### Trip service

The trip plugin solves the Traveling Salesman Problem using a greedy heuristic (farthest-insertion algorithm).
The trip plugin solves the Traveling Salesman Problem using a greedy heuristic (farthest-insertion algorithm) for more than ten nodes and uses brute force for 10 nodes or less.
Copy link
Member

Choose a reason for hiding this comment

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

That's not true: < 10 is brute force

if (component_size < BF_MAX_FEASABLE)

docs/http.md Outdated
@@ -329,6 +329,30 @@ In addition to the [general options](#general-options) the following options are
|geometries |`polyline` (default), `polyline6`, `geojson` |Returned route geometry format (influences overview and per step) |
|overview |`simplified` (default), `full`, `false` |Add overview geometry either full, simplified according to highest zoom level it could be display on, or not at all.|

A second feature of the trip plugin returns the route from a source to a destination while visiting all the other waypoints in the middle.
As with the roundtrip service, for fewer than 10 waypoints, the brute force algorithm is used, while for more than 10 waypoints the farthest insertion heuristic is used.
Copy link
Member

Choose a reason for hiding this comment

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

Same here:

  • < 10 brute force
  • >= 10 farthest insertion

docs/http.md Outdated

|Option |Values |Description |
|------------|------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------|
|source |`{index of coordinate in coordinates provided}` |Will error if destionation is not provided as well. Returns trip from source to destination routing through all other locations provided.|
Copy link
Member

Choose a reason for hiding this comment

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

destination - grammar

@@ -35,11 +34,12 @@ module.exports = function () {
}

if (headers.has('status')) {
got.status = json.status.toString();
got.status = json.code;
Copy link
Member

Choose a reason for hiding this comment

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

Why the change from the status message to the error code here?

Copy link
Member Author

Choose a reason for hiding this comment

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

The status.toString() code was copy pasted from another cucumber test but wasn't really being used in the trip context (it was broken code essentially with no way to trigger it to check), so I changed it so that it does work.


When I plan a trip I should get
| waypoints | status | message |
| a,b,c | InvalidInputs | Source or destination indices are greater number of coordinates provided. |
Copy link
Member

Choose a reason for hiding this comment

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

All these tests should be unit tests - check the unit tests dir and the library tests there, e.g. for route.

@@ -46,6 +46,30 @@ template <typename T> class DistTableWrapper
return table_[index];
}

void InvalidateRoute(NodeID from, NodeID to)
Copy link
Member

Choose a reason for hiding this comment

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

The wrapper holds Ts so you probably should accept Ts to index the vector.

Copy link
Member Author

Choose a reason for hiding this comment

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

The DistTableWrapper is a wrapper around a vector that holds , in the trip case the is an EdgeWeight. This method here simply accepts NodeIDs to access the correct position of the necessary EdgeWeight in the table vector of EdgeWeights. So keeping the function as-is should be fine in this case.

if (parameters.source >= static_cast<int>(parameters.coordinates.size()) ||
parameters.destination >= static_cast<int>(parameters.coordinates.size()))
{
return Error("InvalidInputs",
Copy link
Member

Choose a reason for hiding this comment

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

Not a documented v5 error code.

// b 10000 0 25 30 34
// c 0 10000 0 10000 10000
// d 10000 30 18 0 15
// e 10000 34 32 15 0
Copy link
Member

Choose a reason for hiding this comment

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

So what does it do?

Copy link
Member

Choose a reason for hiding this comment

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

also, replace the 10000 with MAX_DISTANCE or something in that manner :)

{
// parameters.source column
for (NodeID i = 0; i < result_table.GetNumberOfNodes(); i++) {
if (i == (NodeID)parameters.source) continue;
Copy link
Member

Choose a reason for hiding this comment

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

format all files you're touching

BOOST_CHECK_EQUAL(reference_2.source, result_2->source);
BOOST_CHECK_EQUAL(reference_2.destination, result_2->destination);
CHECK_EQUAL_RANGE(reference_2.radiuses, result_2->radiuses);
CHECK_EQUAL_RANGE(reference_2.coordinates, result_2->coordinates);
Copy link
Member

Choose a reason for hiding this comment

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

More tests please. For parsing but also library tests for responses.

Copy link
Member

Choose a reason for hiding this comment

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

other unit tests we should have and cover for:

  • source == destination
  • source == -1 && destination != -1
  • source != -1 && destination == -1

@ghoshkaj ghoshkaj force-pushed the fixed-start-and-end-trip branch from dd174c4 to dda3ba3 Compare January 31, 2017 23:09
CHANGELOG.md Outdated
@@ -27,6 +27,8 @@
- libOSRM now creates an own watcher thread then used in shared memory mode to listen for data updates
- Tools:
- Added osrm-extract-conditionals tool for checking conditional values in OSM data
- Trip Plugin
- Added a new feature that finds the optimal route given a list of location, a start and destination locations. This does not return a roundtrip, but instead gives the optimal route given fixed start and end points
Copy link
Member

Choose a reason for hiding this comment

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

given a list of locations, a start and a destination or something like that? looks like a typo :D

{
// trip comes out to be something like 0 1 4 3 2, so the sizes don't
BOOST_ASSERT(min_route.segment_end_coordinates.size() == trip.size() - 1);
}
Copy link
Member

Choose a reason for hiding this comment

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

better write this such that there are no if/else checks when in release mode:

A statement a -> b can be checked with !a || b instead, so do

BOOST_ASSERT(!roundtrip || min_route.segment_end_coordinates.size() == trip.size());
BOOST_ASSERT(roundtrip || min_route.segment_end_coordinates.size() == trip.size() - 1);

or something like that

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 did this, but it got a bit confusing for && / || noobs like me to keep the logic straight. So I reverted back to the if statements for clarity and simplicity's sake.

// b 10000 0 25 30 34
// c 0 10000 0 10000 10000
// d 10000 30 18 0 15
// e 10000 34 32 15 0
Copy link
Member

Choose a reason for hiding this comment

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

also, replace the 10000 with MAX_DISTANCE or something in that manner :)

BOOST_CHECK_EQUAL(reference_2.source, result_2->source);
BOOST_CHECK_EQUAL(reference_2.destination, result_2->destination);
CHECK_EQUAL_RANGE(reference_2.radiuses, result_2->radiuses);
CHECK_EQUAL_RANGE(reference_2.coordinates, result_2->coordinates);
Copy link
Member

Choose a reason for hiding this comment

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

other unit tests we should have and cover for:

  • source == destination
  • source == -1 && destination != -1
  • source != -1 && destination == -1

table_[index] = INVALID_EDGE_WEIGHT;
}

void ShortcutRoute(NodeID from, NodeID to)
Copy link
Member

Choose a reason for hiding this comment

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

I'm not totally convinced that ShortcutRoute and InvalidateRoute are good names. If you want to keep them more general as they are now, can you add a comment why we do this here? so something like
force the roundtrip to start at source and end at destination by virtually squashing them together

or you can maybe name them squashSourceAndDestination and separateDestination

SCC_Component scc = SplitUnaccessibleLocations(number_of_locations, result_table);
SCC_Component scc = SplitUnaccessibleLocations(result_table.GetNumberOfNodes(), result_table);

if (parameters.source > -1 && parameters.destination > -1) // check if fixed start and end
Copy link
Member

Choose a reason for hiding this comment

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

later you're checking this to set bool roundtrip. you could also set the boolean already here and use it.

@daniel-j-h
Copy link
Member

Tasks for node-osrm ticketed here: Project-OSRM/node-osrm#294.

@ghoshkaj ghoshkaj force-pushed the fixed-start-and-end-trip branch 3 times, most recently from 53ef7ed to ab5965b Compare February 4, 2017 05:43
@ghoshkaj ghoshkaj force-pushed the fixed-start-and-end-trip branch from 012a362 to a9ee2e3 Compare February 7, 2017 07:21
@ghoshkaj
Copy link
Member Author

ghoshkaj commented Feb 7, 2017

To Do (@chaupow if you want to get started on any of these)

  • Figure out what to do for scc.component > 1 and fix error handling accordingly
  • Add roundtrip parameter parser test(s) and unit tests
  • Add the source={first|any} and destination={last|any} parameters
  • Add parameter parser tests, unit tests and cucumber tests for the scenarios involving fixed start and fixed end parameters

Copy link
Member

@TheMarex TheMarex left a comment

Choose a reason for hiding this comment

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

Some minor naming and style adjustment. Otherwise 💯

docs/http.md Outdated

- `code` if the request was successful `Ok` otherwise see the service dependent and general status codes.
It is possible to explicitely set the start or end point of the trip. Depending on whether `source` or `destination` is set to `any|first` or `any|last` the resulting output will start/end at the first/last coordinate.
Copy link
Member

Choose a reason for hiding this comment

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

What about making it a little bit more explicit:

When source is set to first the first coordinate is used as source of the trip. When destination is set to last the last coordinate will be used as destination of the trip. If you specify any, any of the coordinates can be used.

docs/http.md Outdated

However, if `source=any&destination=any` the returned round-trip will still start at the first coordinate by default.

Currently, not all combinations of roundtrip, source and destination are supported.
Copy link
Member

Choose a reason for hiding this comment

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

source, roudtrip and destination should be put in code blocks.

| la |

When I plan a trip I should get
| waypoints | trips | source |
Copy link
Member

Choose a reason for hiding this comment

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

Why is source a result column? This should be a query parameter like in https://github.com/Project-OSRM/osrm-backend/pull/3408/files#diff-19534b2b92b1d620a3a6390c0f0b378dR100 no?

Copy link
Member

@danpat danpat Feb 9, 2017

Choose a reason for hiding this comment

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

@TheMarex I asked @ghoshkaj to move source and desttinaion into the I should get table - they're query parameters in the same way that waypoints are.

Having these in the When table allows multiple combinations for the same scenario - putting them in the Given the query options clause limits us to one set per scenario.

We should put them on the left-hand-side though, next to the waypoints.

Copy link
Member

Choose a reason for hiding this comment

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

Note that there is precedence for this style in the testbot/matching.feature where we supply timestamps.

Copy link
Member

Choose a reason for hiding this comment

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

@TheMarex @danpat: and now... - fight! 😄
kidding. I actually agree with @danpat but in most of these cases we only test one parameter combination so the argument is just semi-valid.

If you both don't mind and there are no further opinions on these, I'd leave it as it is just because it's less work.


When I plan a trip I should get
| waypoints | source | destination | roundtrip | status | message |
| a,b,c,d | first | last | false | NoTrips | No trip visiting all destinations possible. |
Copy link
Member

Choose a reason for hiding this comment

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

Same here: source and destination should be query parameters not part of the result table.

Copy link
Member Author

Choose a reason for hiding this comment

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

Leaving this as is due to comment above.

| waypoints | trips |
| a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p | defghijklabcd,mnopm |
| waypoints | source | destination |roundtrip | trips | durations | distance |
| a,b,d,e,c | first | last | false | abedc | 8.200000000000001 | 81.6 |
Copy link
Member

Choose a reason for hiding this comment

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

Same here.

Copy link
Member Author

Choose a reason for hiding this comment

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

Leaving this as is due to comment above.

@@ -46,6 +46,30 @@ template <typename T> class DistTableWrapper
return table_[index];
}

void InvalidateRoute(NodeID from, NodeID to)
Copy link
Member

Choose a reason for hiding this comment

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

Should these functions be part of the DistTableWrapper? This class seems very generic and the functions are only relevant in the context of the trip plugin.

Another way to do it would be to have two functions invalidateRoute(DistanceTableWrapper &dist, NodeID from, NodeID to) and shortcutRoute(DistanceTableWrapper &dist, NodeID from, NodeID to) in the trip plugin.

@@ -60,6 +60,8 @@ using NameID = std::uint32_t;
using EdgeWeight = std::int32_t;
using TurnPenalty = std::int16_t; // turn penalty in 100ms units

static const std::size_t INVALID_SIZE_T = std::numeric_limits<std::size_t>::max();
Copy link
Member

Choose a reason for hiding this comment

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

INVALID_INDEX would probably be a more fitting name, since that is what it is used to denote in the using code.

Copy link
Member

Choose a reason for hiding this comment

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

HAHAHA. True. Thanks. invalid_size_t is wrong indeed

}
bool fixed_start = (source_id == 0);
bool fixed_end = (destination_id == number_of_locations - 1);
bool fixed_start_and_end = fixed_start && fixed_end;
Copy link
Member

Choose a reason for hiding this comment

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

It might be less confusing to not pre-compute fixed_start_and_end, because in the code below it was not clear if this is somehow different then fixed_start && fixed_end.

routes.reserve(trips.size());
for (const auto &trip : trips)
// rotate result such that roundtrip starts at node with index 0
if (!(fixed_end && !fixed_start_and_end))
Copy link
Member

Choose a reason for hiding this comment

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

Same as !fixed_end || fixed_start_and_end == !fixed_end && fixed_start || !fixed_end && fixed_end == fixed_start && !fixed_end

Copy link
Member Author

@ghoshkaj ghoshkaj Feb 10, 2017

Choose a reason for hiding this comment

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

!(fixed_end && !fixed_start_and_end) == !fixed_end || fixed_start_and_end == !fixed_end || (fixed_start && fixed_end) == (!fixed_end || fixed_start) && (!fixed_end || fixed_end) == !fixed_end || fixed_start

Copy link
Member Author

Choose a reason for hiding this comment

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

No !fixed_end || fixed_start_and_end == !fixed_end || (fixed_start && fixed_end) is wrong from my comment above. Ugh it's so late, I can't keep the logic straight :/

In any case, using fixed_start && !fixed_end from Patrick's comment makes a test fail :/

Copy link
Member Author

@ghoshkaj ghoshkaj Feb 10, 2017

Choose a reason for hiding this comment

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

While using !fixed_end || fixed_start lets them all pass.

Copy link
Contributor

Choose a reason for hiding this comment

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

hm, can it be simplified? There are only 16 2-variable boolean functions

Copy link
Member Author

Choose a reason for hiding this comment

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

Okay no matter how many times I work it out, I always get to !fixed_end || fixed_start and this lets the tests pass happily so this is what I'll keep it as.

Copy link
Member Author

Choose a reason for hiding this comment

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

Realistically, what this case is taking care of are the following scenarios:
!fixed_end OR
fixed_start OR
fixed_start && fixed_end
so I'll either write all these cases out or comment with this.

Copy link
Contributor

Choose a reason for hiding this comment

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

!fixed_end || fixed_start is the same as !fixed_end OR fixed_start OR fixed_start && fixed_end, because fixed_start OR fixed_start && fixed_end is equal to fixed_start

}
else if (fixed_end && !fixed_start_and_end && parameters.roundtrip)
Copy link
Member

Choose a reason for hiding this comment

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

Same as fixed_end && !fixed_start && parameters.roundtrip

@ghoshkaj ghoshkaj force-pushed the fixed-start-and-end-trip branch from 25e2451 to fb85f93 Compare February 10, 2017 05:45
@ghoshkaj ghoshkaj force-pushed the fixed-start-and-end-trip branch from 34d676b to 8971b5c Compare February 10, 2017 08:48
@ghoshkaj ghoshkaj merged commit 2218658 into master Feb 10, 2017
@ghoshkaj ghoshkaj deleted the fixed-start-and-end-trip branch February 10, 2017 10:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants